* [PATCHSET 0/2] loop: dio fixup @ 2018-04-13 22:30 Jens Axboe 2018-04-13 22:30 ` [PATCH 1/2] loop: remove cmd->rq member Jens Axboe 2018-04-13 22:30 ` [PATCH 2/2] loop: handle short DIO reads Jens Axboe 0 siblings, 2 replies; 5+ messages in thread From: Jens Axboe @ 2018-04-13 22:30 UTC (permalink / raw) To: linux-block; +Cc: ming.lei Wanted to do a v2 of the loop dio short read fix, since I figured we should retain the zero fill for if we have to give up doing reads. Also noticed that we have cmd->rq for some reason, so killed that off as a cleanup. -- Jens Axboe ^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 1/2] loop: remove cmd->rq member 2018-04-13 22:30 [PATCHSET 0/2] loop: dio fixup Jens Axboe @ 2018-04-13 22:30 ` Jens Axboe 2018-04-15 2:14 ` Ming Lei 2018-04-13 22:30 ` [PATCH 2/2] loop: handle short DIO reads Jens Axboe 1 sibling, 1 reply; 5+ messages in thread From: Jens Axboe @ 2018-04-13 22:30 UTC (permalink / raw) To: linux-block; +Cc: ming.lei, Jens Axboe We can always get at the request from the payload, no need to store a pointer to it. Signed-off-by: Jens Axboe <axboe@kernel.dk> --- drivers/block/loop.c | 36 +++++++++++++++++++----------------- drivers/block/loop.h | 1 - 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/drivers/block/loop.c b/drivers/block/loop.c index c9d04497a415..8b2fde2109fc 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -452,9 +452,9 @@ static void lo_complete_rq(struct request *rq) { struct loop_cmd *cmd = blk_mq_rq_to_pdu(rq); - if (unlikely(req_op(cmd->rq) == REQ_OP_READ && cmd->use_aio && - cmd->ret >= 0 && cmd->ret < blk_rq_bytes(cmd->rq))) { - struct bio *bio = cmd->rq->bio; + if (unlikely(req_op(rq) == REQ_OP_READ && cmd->use_aio && + cmd->ret >= 0 && cmd->ret < blk_rq_bytes(rq))) { + struct bio *bio = rq->bio; bio_advance(bio, cmd->ret); zero_fill_bio(bio); @@ -465,11 +465,13 @@ static void lo_complete_rq(struct request *rq) static void lo_rw_aio_do_completion(struct loop_cmd *cmd) { + struct request *rq = blk_mq_rq_from_pdu(cmd); + if (!atomic_dec_and_test(&cmd->ref)) return; kfree(cmd->bvec); cmd->bvec = NULL; - blk_mq_complete_request(cmd->rq); + blk_mq_complete_request(rq); } static void lo_rw_aio_complete(struct kiocb *iocb, long ret, long ret2) @@ -487,7 +489,7 @@ static int lo_rw_aio(struct loop_device *lo, struct loop_cmd *cmd, { struct iov_iter iter; struct bio_vec *bvec; - struct request *rq = cmd->rq; + struct request *rq = blk_mq_rq_from_pdu(cmd); struct bio *bio = rq->bio; struct file *file = lo->lo_backing_file; unsigned int offset; @@ -1702,15 +1704,16 @@ EXPORT_SYMBOL(loop_unregister_transfer); static blk_status_t loop_queue_rq(struct blk_mq_hw_ctx *hctx, const struct blk_mq_queue_data *bd) { - struct loop_cmd *cmd = blk_mq_rq_to_pdu(bd->rq); - struct loop_device *lo = cmd->rq->q->queuedata; + struct request *rq = bd->rq; + struct loop_cmd *cmd = blk_mq_rq_to_pdu(rq); + struct loop_device *lo = rq->q->queuedata; - blk_mq_start_request(bd->rq); + blk_mq_start_request(rq); if (lo->lo_state != Lo_bound) return BLK_STS_IOERR; - switch (req_op(cmd->rq)) { + switch (req_op(rq)) { case REQ_OP_FLUSH: case REQ_OP_DISCARD: case REQ_OP_WRITE_ZEROES: @@ -1723,8 +1726,8 @@ static blk_status_t loop_queue_rq(struct blk_mq_hw_ctx *hctx, /* always use the first bio's css */ #ifdef CONFIG_BLK_CGROUP - if (cmd->use_aio && cmd->rq->bio && cmd->rq->bio->bi_css) { - cmd->css = cmd->rq->bio->bi_css; + if (cmd->use_aio && rq->bio && rq->bio->bi_css) { + cmd->css = rq->bio->bi_css; css_get(cmd->css); } else #endif @@ -1736,8 +1739,9 @@ static blk_status_t loop_queue_rq(struct blk_mq_hw_ctx *hctx, static void loop_handle_cmd(struct loop_cmd *cmd) { - const bool write = op_is_write(req_op(cmd->rq)); - struct loop_device *lo = cmd->rq->q->queuedata; + struct request *rq = blk_mq_rq_from_pdu(cmd); + const bool write = op_is_write(req_op(rq)); + struct loop_device *lo = rq->q->queuedata; int ret = 0; if (write && (lo->lo_flags & LO_FLAGS_READ_ONLY)) { @@ -1745,12 +1749,12 @@ static void loop_handle_cmd(struct loop_cmd *cmd) goto failed; } - ret = do_req_filebacked(lo, cmd->rq); + ret = do_req_filebacked(lo, rq); failed: /* complete non-aio request */ if (!cmd->use_aio || ret) { cmd->ret = ret ? -EIO : 0; - blk_mq_complete_request(cmd->rq); + blk_mq_complete_request(rq); } } @@ -1767,9 +1771,7 @@ static int loop_init_request(struct blk_mq_tag_set *set, struct request *rq, { struct loop_cmd *cmd = blk_mq_rq_to_pdu(rq); - cmd->rq = rq; kthread_init_work(&cmd->work, loop_queue_work); - return 0; } diff --git a/drivers/block/loop.h b/drivers/block/loop.h index 0f45416e4fcf..b78de9879f4f 100644 --- a/drivers/block/loop.h +++ b/drivers/block/loop.h @@ -66,7 +66,6 @@ struct loop_device { struct loop_cmd { struct kthread_work work; - struct request *rq; bool use_aio; /* use AIO interface to handle I/O */ atomic_t ref; /* only for aio */ long ret; -- 2.7.4 ^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH 1/2] loop: remove cmd->rq member 2018-04-13 22:30 ` [PATCH 1/2] loop: remove cmd->rq member Jens Axboe @ 2018-04-15 2:14 ` Ming Lei 0 siblings, 0 replies; 5+ messages in thread From: Ming Lei @ 2018-04-15 2:14 UTC (permalink / raw) To: Jens Axboe; +Cc: linux-block On Fri, Apr 13, 2018 at 04:30:35PM -0600, Jens Axboe wrote: > We can always get at the request from the payload, no need to store > a pointer to it. > > Signed-off-by: Jens Axboe <axboe@kernel.dk> > --- > drivers/block/loop.c | 36 +++++++++++++++++++----------------- > drivers/block/loop.h | 1 - > 2 files changed, 19 insertions(+), 18 deletions(-) > > diff --git a/drivers/block/loop.c b/drivers/block/loop.c > index c9d04497a415..8b2fde2109fc 100644 > --- a/drivers/block/loop.c > +++ b/drivers/block/loop.c > @@ -452,9 +452,9 @@ static void lo_complete_rq(struct request *rq) > { > struct loop_cmd *cmd = blk_mq_rq_to_pdu(rq); > > - if (unlikely(req_op(cmd->rq) == REQ_OP_READ && cmd->use_aio && > - cmd->ret >= 0 && cmd->ret < blk_rq_bytes(cmd->rq))) { > - struct bio *bio = cmd->rq->bio; > + if (unlikely(req_op(rq) == REQ_OP_READ && cmd->use_aio && > + cmd->ret >= 0 && cmd->ret < blk_rq_bytes(rq))) { > + struct bio *bio = rq->bio; > > bio_advance(bio, cmd->ret); > zero_fill_bio(bio); > @@ -465,11 +465,13 @@ static void lo_complete_rq(struct request *rq) > > static void lo_rw_aio_do_completion(struct loop_cmd *cmd) > { > + struct request *rq = blk_mq_rq_from_pdu(cmd); > + > if (!atomic_dec_and_test(&cmd->ref)) > return; > kfree(cmd->bvec); > cmd->bvec = NULL; > - blk_mq_complete_request(cmd->rq); > + blk_mq_complete_request(rq); > } > > static void lo_rw_aio_complete(struct kiocb *iocb, long ret, long ret2) > @@ -487,7 +489,7 @@ static int lo_rw_aio(struct loop_device *lo, struct loop_cmd *cmd, > { > struct iov_iter iter; > struct bio_vec *bvec; > - struct request *rq = cmd->rq; > + struct request *rq = blk_mq_rq_from_pdu(cmd); > struct bio *bio = rq->bio; > struct file *file = lo->lo_backing_file; > unsigned int offset; > @@ -1702,15 +1704,16 @@ EXPORT_SYMBOL(loop_unregister_transfer); > static blk_status_t loop_queue_rq(struct blk_mq_hw_ctx *hctx, > const struct blk_mq_queue_data *bd) > { > - struct loop_cmd *cmd = blk_mq_rq_to_pdu(bd->rq); > - struct loop_device *lo = cmd->rq->q->queuedata; > + struct request *rq = bd->rq; > + struct loop_cmd *cmd = blk_mq_rq_to_pdu(rq); > + struct loop_device *lo = rq->q->queuedata; > > - blk_mq_start_request(bd->rq); > + blk_mq_start_request(rq); > > if (lo->lo_state != Lo_bound) > return BLK_STS_IOERR; > > - switch (req_op(cmd->rq)) { > + switch (req_op(rq)) { > case REQ_OP_FLUSH: > case REQ_OP_DISCARD: > case REQ_OP_WRITE_ZEROES: > @@ -1723,8 +1726,8 @@ static blk_status_t loop_queue_rq(struct blk_mq_hw_ctx *hctx, > > /* always use the first bio's css */ > #ifdef CONFIG_BLK_CGROUP > - if (cmd->use_aio && cmd->rq->bio && cmd->rq->bio->bi_css) { > - cmd->css = cmd->rq->bio->bi_css; > + if (cmd->use_aio && rq->bio && rq->bio->bi_css) { > + cmd->css = rq->bio->bi_css; > css_get(cmd->css); > } else > #endif > @@ -1736,8 +1739,9 @@ static blk_status_t loop_queue_rq(struct blk_mq_hw_ctx *hctx, > > static void loop_handle_cmd(struct loop_cmd *cmd) > { > - const bool write = op_is_write(req_op(cmd->rq)); > - struct loop_device *lo = cmd->rq->q->queuedata; > + struct request *rq = blk_mq_rq_from_pdu(cmd); > + const bool write = op_is_write(req_op(rq)); > + struct loop_device *lo = rq->q->queuedata; > int ret = 0; > > if (write && (lo->lo_flags & LO_FLAGS_READ_ONLY)) { > @@ -1745,12 +1749,12 @@ static void loop_handle_cmd(struct loop_cmd *cmd) > goto failed; > } > > - ret = do_req_filebacked(lo, cmd->rq); > + ret = do_req_filebacked(lo, rq); > failed: > /* complete non-aio request */ > if (!cmd->use_aio || ret) { > cmd->ret = ret ? -EIO : 0; > - blk_mq_complete_request(cmd->rq); > + blk_mq_complete_request(rq); > } > } > > @@ -1767,9 +1771,7 @@ static int loop_init_request(struct blk_mq_tag_set *set, struct request *rq, > { > struct loop_cmd *cmd = blk_mq_rq_to_pdu(rq); > > - cmd->rq = rq; > kthread_init_work(&cmd->work, loop_queue_work); > - > return 0; > } > > diff --git a/drivers/block/loop.h b/drivers/block/loop.h > index 0f45416e4fcf..b78de9879f4f 100644 > --- a/drivers/block/loop.h > +++ b/drivers/block/loop.h > @@ -66,7 +66,6 @@ struct loop_device { > > struct loop_cmd { > struct kthread_work work; > - struct request *rq; > bool use_aio; /* use AIO interface to handle I/O */ > atomic_t ref; /* only for aio */ > long ret; > -- > 2.7.4 > Reviewed-by: Ming Lei <ming.lei@redhat.com> -- Ming ^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 2/2] loop: handle short DIO reads 2018-04-13 22:30 [PATCHSET 0/2] loop: dio fixup Jens Axboe 2018-04-13 22:30 ` [PATCH 1/2] loop: remove cmd->rq member Jens Axboe @ 2018-04-13 22:30 ` Jens Axboe 2018-04-15 2:16 ` Ming Lei 1 sibling, 1 reply; 5+ messages in thread From: Jens Axboe @ 2018-04-13 22:30 UTC (permalink / raw) To: linux-block; +Cc: ming.lei, Jens Axboe 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. Signed-off-by: Jens Axboe <axboe@kernel.dk> --- drivers/block/loop.c | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 8b2fde2109fc..5d4e31655d96 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -451,16 +451,36 @@ static int lo_req_flush(struct loop_device *lo, struct request *rq) static void lo_complete_rq(struct request *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 && - cmd->ret >= 0 && cmd->ret < blk_rq_bytes(rq))) { - struct bio *bio = rq->bio; - - bio_advance(bio, cmd->ret); - zero_fill_bio(bio); + if (!cmd->use_aio || 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; } - blk_mq_end_request(rq, cmd->ret < 0 ? BLK_STS_IOERR : BLK_STS_OK); + /* + * 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; + + while (bio) { + zero_fill_bio(bio); + bio = bio->bi_next; + } + } + ret = BLK_STS_IOERR; +end_io: + blk_mq_end_request(rq, ret); + } } static void lo_rw_aio_do_completion(struct loop_cmd *cmd) -- 2.7.4 ^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH 2/2] loop: handle short DIO reads 2018-04-13 22:30 ` [PATCH 2/2] loop: handle short DIO reads Jens Axboe @ 2018-04-15 2:16 ` Ming Lei 0 siblings, 0 replies; 5+ messages in thread From: Ming Lei @ 2018-04-15 2:16 UTC (permalink / raw) To: Jens Axboe; +Cc: linux-block On Fri, Apr 13, 2018 at 04:30:36PM -0600, Jens Axboe wrote: > 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. > > Signed-off-by: Jens Axboe <axboe@kernel.dk> > --- > drivers/block/loop.c | 34 +++++++++++++++++++++++++++------- > 1 file changed, 27 insertions(+), 7 deletions(-) > > diff --git a/drivers/block/loop.c b/drivers/block/loop.c > index 8b2fde2109fc..5d4e31655d96 100644 > --- a/drivers/block/loop.c > +++ b/drivers/block/loop.c > @@ -451,16 +451,36 @@ static int lo_req_flush(struct loop_device *lo, struct request *rq) > static void lo_complete_rq(struct request *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 && > - cmd->ret >= 0 && cmd->ret < blk_rq_bytes(rq))) { > - struct bio *bio = rq->bio; > - > - bio_advance(bio, cmd->ret); > - zero_fill_bio(bio); > + if (!cmd->use_aio || 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; > } > > - blk_mq_end_request(rq, cmd->ret < 0 ? BLK_STS_IOERR : BLK_STS_OK); > + /* > + * 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; > + > + while (bio) { > + zero_fill_bio(bio); > + bio = bio->bi_next; > + } > + } > + ret = BLK_STS_IOERR; > +end_io: > + blk_mq_end_request(rq, ret); > + } > } > > static void lo_rw_aio_do_completion(struct loop_cmd *cmd) > -- > 2.7.4 > Looks fine, short read will be guaranteed to complete when zero read is triggered. Reviewed-by: Ming Lei <ming.lei@redhat.com> -- Ming ^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2018-04-15 2:16 UTC | newest] Thread overview: 5+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2018-04-13 22:30 [PATCHSET 0/2] loop: dio fixup Jens Axboe 2018-04-13 22:30 ` [PATCH 1/2] loop: remove cmd->rq member Jens Axboe 2018-04-15 2:14 ` Ming Lei 2018-04-13 22:30 ` [PATCH 2/2] loop: handle short DIO reads Jens Axboe 2018-04-15 2:16 ` Ming Lei
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).