On Thu, Aug 24, 2017 at 10:57:39AM -0700, Omar Sandoval wrote: > On Wed, Aug 23, 2017 at 04:49:24PM -0700, Shaohua Li wrote: > > From: Shaohua Li <shli@xxxxxx> > > > > Currently loop disables merge. While it makes sense for buffer IO mode, > > directio mode can benefit from request merge. Without merge, loop could > > send small size IO to underlayer disk and harm performance. > > A couple of nits on comments below, besides that > > Reviewed-by: Omar Sandoval <osandov@xxxxxx> > > > Signed-off-by: Shaohua Li <shli@xxxxxx> > > --- > > drivers/block/loop.c | 43 +++++++++++++++++++++++++++++++++++-------- > > drivers/block/loop.h | 1 + > > 2 files changed, 36 insertions(+), 8 deletions(-) > > > > diff --git a/drivers/block/loop.c b/drivers/block/loop.c > > index 428da07..1bfa3ff 100644 > > --- a/drivers/block/loop.c > > +++ b/drivers/block/loop.c > > @@ -213,10 +213,13 @@ static void __loop_update_dio(struct loop_device *lo, bool dio) > > */ > > blk_mq_freeze_queue(lo->lo_queue); > > lo->use_dio = use_dio; > > - if (use_dio) > > + if (use_dio) { > > + queue_flag_clear_unlocked(QUEUE_FLAG_NOMERGES, lo->lo_queue); > > lo->lo_flags |= LO_FLAGS_DIRECT_IO; > > - else > > + } else { > > + queue_flag_set_unlocked(QUEUE_FLAG_NOMERGES, lo->lo_queue); > > lo->lo_flags &= ~LO_FLAGS_DIRECT_IO; > > + } > > Could you please also update the comment in loop_add() where we set > QUEUE_FLAG_NOMERGES to say something like > > /* > * By default we do buffered I/O, so it doesn't make sense to > * enable merging because the I/O submitted to backing file is > * handled page by page. We enable merging when switching to > * direct I/O mode. > */ sure, will add > > blk_mq_unfreeze_queue(lo->lo_queue); > > } > > > > @@ -464,6 +467,8 @@ static void lo_rw_aio_complete(struct kiocb *iocb, long ret, long ret2) > > { > > struct loop_cmd *cmd = container_of(iocb, struct loop_cmd, iocb); > > > > + kfree(cmd->bvec); > > + cmd->bvec = NULL; > > cmd->ret = ret; > > blk_mq_complete_request(cmd->rq); > > } > > @@ -473,22 +478,44 @@ static int lo_rw_aio(struct loop_device *lo, struct loop_cmd *cmd, > > { > > struct iov_iter iter; > > struct bio_vec *bvec; > > - struct bio *bio = cmd->rq->bio; > > + struct request *rq = cmd->rq; > > + struct bio *bio = rq->bio; > > struct file *file = lo->lo_backing_file; > > + unsigned int offset; > > + int segments = 0; > > int ret; > > > > - /* nomerge for loop request queue */ > > - WARN_ON(cmd->rq->bio != cmd->rq->biotail); > > + if (rq->bio != rq->biotail) { > > + struct req_iterator iter; > > + struct bio_vec tmp; > > + > > + __rq_for_each_bio(bio, rq) > > + segments += bio_segments(bio); > > + bvec = kmalloc(sizeof(struct bio_vec) * segments, GFP_KERNEL); > > + if (!bvec) > > + return -EIO; > > + cmd->bvec = bvec; > > + > > + rq_for_each_segment(tmp, rq, iter) { > > + *bvec = tmp; > > + bvec++; > > + } > > + bvec = cmd->bvec; > > + offset = 0; > > + } else { > > + offset = bio->bi_iter.bi_bvec_done; > > + bvec = __bvec_iter_bvec(bio->bi_io_vec, bio->bi_iter); > > + segments = bio_segments(bio); > > + } > > > > - bvec = __bvec_iter_bvec(bio->bi_io_vec, bio->bi_iter); > > iov_iter_bvec(&iter, ITER_BVEC | rw, bvec, > > - bio_segments(bio), blk_rq_bytes(cmd->rq)); > > + segments, blk_rq_bytes(rq)); > > /* > > * This bio may be started from the middle of the 'bvec' > > * because of bio splitting, so offset from the bvec must > > * be passed to iov iterator > > */ > > This comment should be moved above to where you do > > offset = bio->bi_iter.bi_bvec_done; This comment actually applies to 'rq->bio != rq->biotail' case too for each bio of the request. That's why I don't just copy bio->bi_io_vec. I'll explain this in different way. Thanks, Shaohua