]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
block: add size alignment to bio_iov_iter_get_pages
authorKeith Busch <kbusch@kernel.org>
Wed, 27 Aug 2025 14:12:52 +0000 (07:12 -0700)
committerJens Axboe <axboe@kernel.dk>
Tue, 9 Sep 2025 16:27:01 +0000 (10:27 -0600)
The block layer tries to align bio vectors to the block device's logical
block size. Some cases don't have a block device, or we may need to
align to something larger, which we can't derive it from the queue
limits. Have the caller specify what they want, or allow any length
alignment if nothing was specified. Since the most common use case
relies on the block device's limits, a helper function is provided.

Signed-off-by: Keith Busch <kbusch@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
block/bio.c
block/fops.c
fs/iomap/direct-io.c
include/linux/bio.h
include/linux/blkdev.h

index 971d96afaf8d0e56199fc547570de5974c75c5f6..f91dc9f32bdcba3ec56c398d0d7e80fc4a65f4f3 100644 (file)
@@ -1208,7 +1208,8 @@ static unsigned int get_contig_folio_len(unsigned int *num_pages,
  * For a multi-segment *iter, this function only adds pages from the next
  * non-empty segment of the iov iterator.
  */
-static int __bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter)
+static int __bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter,
+                                   unsigned len_align_mask)
 {
        iov_iter_extraction_t extraction_flags = 0;
        unsigned short nr_pages = bio->bi_max_vecs - bio->bi_vcnt;
@@ -1217,7 +1218,7 @@ static int __bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter)
        struct page **pages = (struct page **)bv;
        ssize_t size;
        unsigned int num_pages, i = 0;
-       size_t offset, folio_offset, left, len;
+       size_t offset, folio_offset, left, len, trim;
        int ret = 0;
 
        /*
@@ -1246,8 +1247,8 @@ static int __bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter)
 
        nr_pages = DIV_ROUND_UP(offset + size, PAGE_SIZE);
 
-       if (bio->bi_bdev) {
-               size_t trim = size & (bdev_logical_block_size(bio->bi_bdev) - 1);
+       trim = size & len_align_mask;
+       if (trim) {
                iov_iter_revert(iter, trim);
                size -= trim;
        }
@@ -1302,9 +1303,10 @@ out:
 }
 
 /**
- * bio_iov_iter_get_pages - add user or kernel pages to a bio
+ * bio_iov_iter_get_pages_aligned - add user or kernel pages to a bio
  * @bio: bio to add pages to
  * @iter: iov iterator describing the region to be added
+ * @len_align_mask: the mask to align each vector size to, 0 for any length
  *
  * This takes either an iterator pointing to user memory, or one pointing to
  * kernel pages (BVEC iterator). If we're adding user pages, we pin them and
@@ -1321,7 +1323,8 @@ out:
  * MM encounters an error pinning the requested pages, it stops. Error
  * is returned only if 0 pages could be pinned.
  */
-int bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter)
+int bio_iov_iter_get_pages_aligned(struct bio *bio, struct iov_iter *iter,
+                          unsigned len_align_mask)
 {
        int ret = 0;
 
@@ -1337,12 +1340,12 @@ int bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter)
        if (iov_iter_extract_will_pin(iter))
                bio_set_flag(bio, BIO_PAGE_PINNED);
        do {
-               ret = __bio_iov_iter_get_pages(bio, iter);
+               ret = __bio_iov_iter_get_pages(bio, iter, len_align_mask);
        } while (!ret && iov_iter_count(iter) && !bio_full(bio, 0));
 
        return bio->bi_vcnt ? 0 : ret;
 }
-EXPORT_SYMBOL_GPL(bio_iov_iter_get_pages);
+EXPORT_SYMBOL_GPL(bio_iov_iter_get_pages_aligned);
 
 static void submit_bio_wait_endio(struct bio *bio)
 {
index 82451ac8ff25dd5a8540f1684d621d9b788e29ff..d136fb5f6b6ab7e1d5fefd6fd741fe9cf3437b2a 100644 (file)
@@ -78,7 +78,7 @@ static ssize_t __blkdev_direct_IO_simple(struct kiocb *iocb,
        if (iocb->ki_flags & IOCB_ATOMIC)
                bio.bi_opf |= REQ_ATOMIC;
 
-       ret = bio_iov_iter_get_pages(&bio, iter);
+       ret = bio_iov_iter_get_bdev_pages(&bio, iter, bdev);
        if (unlikely(ret))
                goto out;
        ret = bio.bi_iter.bi_size;
@@ -212,7 +212,7 @@ static ssize_t __blkdev_direct_IO(struct kiocb *iocb, struct iov_iter *iter,
                bio->bi_end_io = blkdev_bio_end_io;
                bio->bi_ioprio = iocb->ki_ioprio;
 
-               ret = bio_iov_iter_get_pages(bio, iter);
+               ret = bio_iov_iter_get_bdev_pages(bio, iter, bdev);
                if (unlikely(ret)) {
                        bio->bi_status = BLK_STS_IOERR;
                        bio_endio(bio);
@@ -348,7 +348,7 @@ static ssize_t __blkdev_direct_IO_async(struct kiocb *iocb,
                 */
                bio_iov_bvec_set(bio, iter);
        } else {
-               ret = bio_iov_iter_get_pages(bio, iter);
+               ret = bio_iov_iter_get_bdev_pages(bio, iter, bdev);
                if (unlikely(ret))
                        goto out_bio_put;
        }
index b84f6af2eb4c88cc28ff8ea7a6f471d4e2b4121c..fea23fa6a402fdbc353ebb96b12e9579c24d56fa 100644 (file)
@@ -434,7 +434,7 @@ static int iomap_dio_bio_iter(struct iomap_iter *iter, struct iomap_dio *dio)
                bio->bi_private = dio;
                bio->bi_end_io = iomap_dio_bio_end_io;
 
-               ret = bio_iov_iter_get_pages(bio, dio->submit.iter);
+               ret = bio_iov_iter_get_bdev_pages(bio, dio->submit.iter, iomap->bdev);
                if (unlikely(ret)) {
                        /*
                         * We have to stop part way through an IO. We must fall
index 13d1df02656a8e0dd5ed3156021c5e61f887caea..a64a30131031337d8c32a7b4ca53bbc7891c9002 100644 (file)
@@ -446,7 +446,14 @@ int submit_bio_wait(struct bio *bio);
 int bdev_rw_virt(struct block_device *bdev, sector_t sector, void *data,
                size_t len, enum req_op op);
 
-int bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter);
+int bio_iov_iter_get_pages_aligned(struct bio *bio, struct iov_iter *iter,
+               unsigned len_align_mask);
+
+static inline int bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter)
+{
+       return bio_iov_iter_get_pages_aligned(bio, iter, 0);
+}
+
 void bio_iov_bvec_set(struct bio *bio, const struct iov_iter *iter);
 void __bio_release_pages(struct bio *bio, bool mark_dirty);
 extern void bio_set_pages_dirty(struct bio *bio);
index 9efacabaa2f73bab2c9facf86893c7da6d999578..44e1066f7446fbbd649b5ff19d64c29ee5e95ea2 100644 (file)
@@ -1877,6 +1877,13 @@ static inline int bio_split_rw_at(struct bio *bio,
        return bio_split_io_at(bio, lim, segs, max_bytes, lim->dma_alignment);
 }
 
+static inline int bio_iov_iter_get_bdev_pages(struct bio *bio,
+               struct iov_iter *iter, struct block_device *bdev)
+{
+       return bio_iov_iter_get_pages_aligned(bio, iter,
+                                       bdev_logical_block_size(bdev) - 1);
+}
+
 #define DEFINE_IO_COMP_BATCH(name)     struct io_comp_batch name = { }
 
 #endif /* _LINUX_BLKDEV_H */