Commit 17c1cc1d authored by Josh Durgin's avatar Josh Durgin Committed by Sage Weil

rbd: fix I/O error propagation for reads

When a request returns an error, the driver needs to report the entire
extent of the request as completed.  Writes already did this, since
they always set xferred = length, but reads were skipping that step if
an error other than -ENOENT occurred.  Instead, rbd would end up
passing 0 xferred to blk_end_request(), which would always report
needing more data.  This resulted in an assert failing when more data
was required by the block layer, but all the object requests were
done:

[ 1868.719077] rbd: obj_request read result -108 xferred 0
[ 1868.719077]
[ 1868.719518] end_request: I/O error, dev rbd1, sector 0
[ 1868.719739]
[ 1868.719739] Assertion failure in rbd_img_obj_callback() at line 1736:
[ 1868.719739]
[ 1868.719739]   rbd_assert(more ^ (which == img_request->obj_request_count));

Without this assert, reads that hit errors would hang forever, since
the block layer considered them incomplete.

Fixes: http://tracker.ceph.com/issues/5647
CC: stable@vger.kernel.org  # v3.10
Signed-off-by: default avatarJosh Durgin <josh.durgin@inktank.com>
Reviewed-by: default avatarAlex Elder <alex.elder@linaro.org>
parent 7d6e1f54
...@@ -1557,11 +1557,12 @@ rbd_img_obj_request_read_callback(struct rbd_obj_request *obj_request) ...@@ -1557,11 +1557,12 @@ rbd_img_obj_request_read_callback(struct rbd_obj_request *obj_request)
obj_request, obj_request->img_request, obj_request->result, obj_request, obj_request->img_request, obj_request->result,
xferred, length); xferred, length);
/* /*
* ENOENT means a hole in the image. We zero-fill the * ENOENT means a hole in the image. We zero-fill the entire
* entire length of the request. A short read also implies * length of the request. A short read also implies zero-fill
* zero-fill to the end of the request. Either way we * to the end of the request. An error requires the whole
* update the xferred count to indicate the whole request * length of the request to be reported finished with an error
* was satisfied. * to the block layer. In each case we update the xferred
* count to indicate the whole request was satisfied.
*/ */
rbd_assert(obj_request->type != OBJ_REQUEST_NODATA); rbd_assert(obj_request->type != OBJ_REQUEST_NODATA);
if (obj_request->result == -ENOENT) { if (obj_request->result == -ENOENT) {
...@@ -1570,14 +1571,13 @@ rbd_img_obj_request_read_callback(struct rbd_obj_request *obj_request) ...@@ -1570,14 +1571,13 @@ rbd_img_obj_request_read_callback(struct rbd_obj_request *obj_request)
else else
zero_pages(obj_request->pages, 0, length); zero_pages(obj_request->pages, 0, length);
obj_request->result = 0; obj_request->result = 0;
obj_request->xferred = length;
} else if (xferred < length && !obj_request->result) { } else if (xferred < length && !obj_request->result) {
if (obj_request->type == OBJ_REQUEST_BIO) if (obj_request->type == OBJ_REQUEST_BIO)
zero_bio_chain(obj_request->bio_list, xferred); zero_bio_chain(obj_request->bio_list, xferred);
else else
zero_pages(obj_request->pages, xferred, length); zero_pages(obj_request->pages, xferred, length);
obj_request->xferred = length;
} }
obj_request->xferred = length;
obj_request_done_set(obj_request); obj_request_done_set(obj_request);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment