Commit f9de14bc authored by Jens Axboe's avatar Jens Axboe

loop: handle short DIO reads

We ran into an issue with loop and btrfs, where btrfs would complain about
checksum errors. It turns out that is because we don't handle short reads
at all, we just zero fill the remainder. Worse than that, we don't handle
the filling properly, which results in loop trying to advance a single
bio by much more than its size, since it doesn't take chaining into
account.

Handle short reads appropriately, by simply retrying at the new correct
offset. End the remainder of the request with EIO, if we get a 0 read.

Fixes: bc07c10a ("block: loop: support DIO & AIO")
Reviewed-by: default avatarMing Lei <ming.lei@redhat.com>
Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
parent 1894e916
...@@ -451,16 +451,36 @@ static int lo_req_flush(struct loop_device *lo, struct request *rq) ...@@ -451,16 +451,36 @@ static int lo_req_flush(struct loop_device *lo, struct request *rq)
static void lo_complete_rq(struct request *rq) static void lo_complete_rq(struct request *rq)
{ {
struct loop_cmd *cmd = blk_mq_rq_to_pdu(rq); struct loop_cmd *cmd = blk_mq_rq_to_pdu(rq);
blk_status_t ret = BLK_STS_OK;
if (unlikely(req_op(rq) == REQ_OP_READ && cmd->use_aio && if (!cmd->use_aio || cmd->ret < 0 || cmd->ret == blk_rq_bytes(rq) ||
cmd->ret >= 0 && cmd->ret < blk_rq_bytes(rq))) { req_op(rq) != REQ_OP_READ) {
if (cmd->ret < 0)
ret = BLK_STS_IOERR;
goto end_io;
}
/*
* Short READ - if we got some data, advance our request and
* retry it. If we got no data, end the rest with EIO.
*/
if (cmd->ret) {
blk_update_request(rq, BLK_STS_OK, cmd->ret);
cmd->ret = 0;
blk_mq_requeue_request(rq, true);
} else {
if (cmd->use_aio) {
struct bio *bio = rq->bio; struct bio *bio = rq->bio;
bio_advance(bio, cmd->ret); while (bio) {
zero_fill_bio(bio); zero_fill_bio(bio);
bio = bio->bi_next;
}
}
ret = BLK_STS_IOERR;
end_io:
blk_mq_end_request(rq, ret);
} }
blk_mq_end_request(rq, cmd->ret < 0 ? BLK_STS_IOERR : BLK_STS_OK);
} }
static void lo_rw_aio_do_completion(struct loop_cmd *cmd) static void lo_rw_aio_do_completion(struct loop_cmd *cmd)
......
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