diff options
author | Martin Wilck <mwilck@suse.com> | 2018-07-25 17:15:09 -0400 |
---|---|---|
committer | Jens Axboe <axboe@kernel.dk> | 2018-07-26 13:52:36 -0400 |
commit | 17d51b10d7773e4618bcac64648f30f12d4078fb (patch) | |
tree | c6b76e08ffb36ffac6e7e82047333316935bf0a4 | |
parent | 9362dd1109f87a9d0a798fbc890cb339c171ed35 (diff) |
block: bio_iov_iter_get_pages: pin more pages for multi-segment IOs
bio_iov_iter_get_pages() currently only adds pages for the next non-zero
segment from the iov_iter to the bio. That's suboptimal for callers,
which typically try to pin as many pages as fit into the bio. This patch
converts the current bio_iov_iter_get_pages() into a static helper, and
introduces a new helper that allocates as many pages as
1) fit into the bio,
2) are present in the iov_iter,
3) and can be pinned by MM.
Error is returned only if zero pages could be pinned. Because of 3), a
zero return value doesn't necessarily mean all pages have been pinned.
Callers that have to pin every page in the iov_iter must still call this
function in a loop (this is currently the case).
This change matters most for __blkdev_direct_IO_simple(), which calls
bio_iov_iter_get_pages() only once. If it obtains less pages than
requested, it returns a "short write" or "short read", and
__generic_file_write_iter() falls back to buffered writes, which may
lead to data corruption.
Fixes: 72ecad22d9f1 ("block: support a full bio worth of IO for simplified bdev direct-io")
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Martin Wilck <mwilck@suse.com>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
-rw-r--r-- | block/bio.c | 35 |
1 files changed, 32 insertions, 3 deletions
diff --git a/block/bio.c b/block/bio.c index cd55ea6bd47c..dc07a427e782 100644 --- a/block/bio.c +++ b/block/bio.c | |||
@@ -903,14 +903,16 @@ int bio_add_page(struct bio *bio, struct page *page, | |||
903 | EXPORT_SYMBOL(bio_add_page); | 903 | EXPORT_SYMBOL(bio_add_page); |
904 | 904 | ||
905 | /** | 905 | /** |
906 | * bio_iov_iter_get_pages - pin user or kernel pages and add them to a bio | 906 | * __bio_iov_iter_get_pages - pin user or kernel pages and add them to a bio |
907 | * @bio: bio to add pages to | 907 | * @bio: bio to add pages to |
908 | * @iter: iov iterator describing the region to be mapped | 908 | * @iter: iov iterator describing the region to be mapped |
909 | * | 909 | * |
910 | * Pins as many pages from *iter and appends them to @bio's bvec array. The | 910 | * Pins pages from *iter and appends them to @bio's bvec array. The |
911 | * pages will have to be released using put_page() when done. | 911 | * pages will have to be released using put_page() when done. |
912 | * For multi-segment *iter, this function only adds pages from the | ||
913 | * the next non-empty segment of the iov iterator. | ||
912 | */ | 914 | */ |
913 | int bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter) | 915 | static int __bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter) |
914 | { | 916 | { |
915 | unsigned short nr_pages = bio->bi_max_vecs - bio->bi_vcnt, idx; | 917 | unsigned short nr_pages = bio->bi_max_vecs - bio->bi_vcnt, idx; |
916 | struct bio_vec *bv = bio->bi_io_vec + bio->bi_vcnt; | 918 | struct bio_vec *bv = bio->bi_io_vec + bio->bi_vcnt; |
@@ -947,6 +949,33 @@ int bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter) | |||
947 | iov_iter_advance(iter, size); | 949 | iov_iter_advance(iter, size); |
948 | return 0; | 950 | return 0; |
949 | } | 951 | } |
952 | |||
953 | /** | ||
954 | * bio_iov_iter_get_pages - pin user or kernel pages and add them to a bio | ||
955 | * @bio: bio to add pages to | ||
956 | * @iter: iov iterator describing the region to be mapped | ||
957 | * | ||
958 | * Pins pages from *iter and appends them to @bio's bvec array. The | ||
959 | * pages will have to be released using put_page() when done. | ||
960 | * The function tries, but does not guarantee, to pin as many pages as | ||
961 | * fit into the bio, or are requested in *iter, whatever is smaller. | ||
962 | * If MM encounters an error pinning the requested pages, it stops. | ||
963 | * Error is returned only if 0 pages could be pinned. | ||
964 | */ | ||
965 | int bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter) | ||
966 | { | ||
967 | unsigned short orig_vcnt = bio->bi_vcnt; | ||
968 | |||
969 | do { | ||
970 | int ret = __bio_iov_iter_get_pages(bio, iter); | ||
971 | |||
972 | if (unlikely(ret)) | ||
973 | return bio->bi_vcnt > orig_vcnt ? 0 : ret; | ||
974 | |||
975 | } while (iov_iter_count(iter) && !bio_full(bio)); | ||
976 | |||
977 | return 0; | ||
978 | } | ||
950 | EXPORT_SYMBOL_GPL(bio_iov_iter_get_pages); | 979 | EXPORT_SYMBOL_GPL(bio_iov_iter_get_pages); |
951 | 980 | ||
952 | static void submit_bio_wait_endio(struct bio *bio) | 981 | static void submit_bio_wait_endio(struct bio *bio) |