From: Keith Busch <kbusch@xxxxxxxxxx> Enable direct io to read partial sectors if the block device supports bit buckets. Signed-off-by: Keith Busch <kbusch@xxxxxxxxxx> --- fs/iomap/direct-io.c | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/fs/iomap/direct-io.c b/fs/iomap/direct-io.c index 10a113358365..212e63b78950 100644 --- a/fs/iomap/direct-io.c +++ b/fs/iomap/direct-io.c @@ -251,9 +251,12 @@ static loff_t iomap_dio_bio_iter(const struct iomap_iter *iter, int nr_pages, ret = 0; size_t copied = 0; size_t orig_count; + u16 skip = 0, trunc = 0; if (blkdev_dio_unaligned(bdev, pos | length, dio->submit.iter)) - return -EINVAL; + if (!blkdev_bit_bucket(bdev, pos, length, dio->submit.iter, + &skip, &trunc)) + return -EINVAL; if (iomap->type == IOMAP_UNWRITTEN) { dio->flags |= IOMAP_DIO_UNWRITTEN; @@ -310,9 +313,10 @@ static loff_t iomap_dio_bio_iter(const struct iomap_iter *iter, */ bio_opf = iomap_dio_bio_opflags(dio, iomap, use_fua); - nr_pages = bio_iov_vecs_to_alloc(dio->submit.iter, BIO_MAX_VECS); + nr_pages = bio_iov_vecs_to_alloc_partial(dio->submit.iter, BIO_MAX_VECS, + skip, trunc); do { - size_t n; + size_t n, bucket_bytes = 0; if (dio->error) { iov_iter_revert(dio->submit.iter, copied); copied = ret = 0; @@ -327,6 +331,15 @@ static loff_t iomap_dio_bio_iter(const struct iomap_iter *iter, bio->bi_private = dio; bio->bi_end_io = iomap_dio_bio_end_io; + if (skip || trunc) { + bio_set_flag(bio, BIO_BIT_BUCKET); + if (skip) { + bucket_bytes += skip; + blk_add_bb_page(bio, skip); + skip = 0; + } + } + ret = bio_iov_iter_get_pages(bio, dio->submit.iter); if (unlikely(ret)) { /* @@ -339,6 +352,12 @@ static loff_t iomap_dio_bio_iter(const struct iomap_iter *iter, goto zero_tail; } + if (trunc && !iov_iter_count(dio->submit.iter)) { + blk_add_bb_page(bio, trunc); + bucket_bytes += trunc; + trunc = 0; + } + n = bio->bi_iter.bi_size; if (dio->flags & IOMAP_DIO_WRITE) { task_io_account_write(n); @@ -347,18 +366,19 @@ static loff_t iomap_dio_bio_iter(const struct iomap_iter *iter, bio_set_pages_dirty(bio); } - dio->size += n; - copied += n; + dio->size += n - bucket_bytes; + copied += n - bucket_bytes; - nr_pages = bio_iov_vecs_to_alloc(dio->submit.iter, - BIO_MAX_VECS); + nr_pages = bio_iov_vecs_to_alloc_partial(dio->submit.iter, + BIO_MAX_VECS, skip, + trunc); /* * We can only poll for single bio I/Os. */ if (nr_pages) dio->iocb->ki_flags &= ~IOCB_HIPRI; iomap_dio_submit_bio(iter, dio, bio, pos); - pos += n; + pos += n - bucket_bytes; } while (nr_pages); /* -- 2.30.2