Allow the file system to limit the size processed in a single
bounce operation.  This is needed when generating integrity data
so that the size of a single integrity segment can't overflow.

Signed-off-by: Christoph Hellwig <[email protected]>
---
 block/bio.c          | 17 ++++++++++-------
 fs/iomap/direct-io.c |  2 +-
 include/linux/bio.h  |  2 +-
 3 files changed, 12 insertions(+), 9 deletions(-)

diff --git a/block/bio.c b/block/bio.c
index da795b1df52a..e89b24dc0283 100644
--- a/block/bio.c
+++ b/block/bio.c
@@ -1293,9 +1293,10 @@ static void bio_free_folios(struct bio *bio)
        }
 }
 
-static int bio_iov_iter_bounce_write(struct bio *bio, struct iov_iter *iter)
+static int bio_iov_iter_bounce_write(struct bio *bio, struct iov_iter *iter,
+               size_t maxlen)
 {
-       size_t total_len = iov_iter_count(iter);
+       size_t total_len = min(maxlen, iov_iter_count(iter));
 
        if (WARN_ON_ONCE(bio_flagged(bio, BIO_CLONED)))
                return -EINVAL;
@@ -1333,9 +1334,10 @@ static int bio_iov_iter_bounce_write(struct bio *bio, 
struct iov_iter *iter)
        return 0;
 }
 
-static int bio_iov_iter_bounce_read(struct bio *bio, struct iov_iter *iter)
+static int bio_iov_iter_bounce_read(struct bio *bio, struct iov_iter *iter,
+               size_t maxlen)
 {
-       size_t len = min(iov_iter_count(iter), SZ_1M);
+       size_t len = min3(iov_iter_count(iter), maxlen, SZ_1M);
        struct folio *folio;
 
        folio = folio_alloc_greedy(GFP_KERNEL, &len);
@@ -1372,6 +1374,7 @@ static int bio_iov_iter_bounce_read(struct bio *bio, 
struct iov_iter *iter)
  * bio_iov_iter_bounce - bounce buffer data from an iter into a bio
  * @bio:       bio to send
  * @iter:      iter to read from / write into
+ * @maxlen:    maximum size to bounce
  *
  * Helper for direct I/O implementations that need to bounce buffer because
  * we need to checksum the data or perform other operations that require
@@ -1379,11 +1382,11 @@ static int bio_iov_iter_bounce_read(struct bio *bio, 
struct iov_iter *iter)
  * copies the data into it.  Needs to be paired with bio_iov_iter_unbounce()
  * called on completion.
  */
-int bio_iov_iter_bounce(struct bio *bio, struct iov_iter *iter)
+int bio_iov_iter_bounce(struct bio *bio, struct iov_iter *iter, size_t maxlen)
 {
        if (op_is_write(bio_op(bio)))
-               return bio_iov_iter_bounce_write(bio, iter);
-       return bio_iov_iter_bounce_read(bio, iter);
+               return bio_iov_iter_bounce_write(bio, iter, maxlen);
+       return bio_iov_iter_bounce_read(bio, iter, maxlen);
 }
 
 static void bvec_unpin(struct bio_vec *bv, bool mark_dirty)
diff --git a/fs/iomap/direct-io.c b/fs/iomap/direct-io.c
index 9c572de0d596..842fc7fecb2d 100644
--- a/fs/iomap/direct-io.c
+++ b/fs/iomap/direct-io.c
@@ -326,7 +326,7 @@ static ssize_t iomap_dio_bio_iter_one(struct iomap_iter 
*iter,
        bio->bi_end_io = iomap_dio_bio_end_io;
 
        if (dio->flags & IOMAP_DIO_BOUNCE)
-               ret = bio_iov_iter_bounce(bio, dio->submit.iter);
+               ret = bio_iov_iter_bounce(bio, dio->submit.iter, UINT_MAX);
        else
                ret = bio_iov_iter_get_pages(bio, dio->submit.iter,
                                             alignment - 1);
diff --git a/include/linux/bio.h b/include/linux/bio.h
index 95cfc79b88b8..df0d7e71372a 100644
--- a/include/linux/bio.h
+++ b/include/linux/bio.h
@@ -479,7 +479,7 @@ void __bio_release_pages(struct bio *bio, bool mark_dirty);
 extern void bio_set_pages_dirty(struct bio *bio);
 extern void bio_check_pages_dirty(struct bio *bio);
 
-int bio_iov_iter_bounce(struct bio *bio, struct iov_iter *iter);
+int bio_iov_iter_bounce(struct bio *bio, struct iov_iter *iter, size_t maxlen);
 void bio_iov_iter_unbounce(struct bio *bio, bool is_error, bool mark_dirty);
 
 extern void bio_copy_data_iter(struct bio *dst, struct bvec_iter *dst_iter,
-- 
2.47.3


Reply via email to