summaryrefslogtreecommitdiffstats
path: root/block
diff options
context:
space:
mode:
authorMartin Wilck <mwilck@suse.com>2018-07-25 17:15:07 -0400
committerJens Axboe <axboe@kernel.dk>2018-07-26 13:52:29 -0400
commitb403ea2404889e1227812fa9657667a1deb9c694 (patch)
treebbe37dba31a278aaaa897261576248d51e5dc7ff /block
parent78e18063a9696c508dc95581fb8ec1aee539c4ee (diff)
block: bio_iov_iter_get_pages: fix size of last iovec
If the last page of the bio is not "full", the length of the last vector slot needs to be corrected. This slot has the index (bio->bi_vcnt - 1), but only in bio->bi_io_vec. In the "bv" helper array, which is shifted by the value of bio->bi_vcnt at function invocation, the correct index is (nr_pages - 1). v2: improved readability following suggestions from Ming Lei. v3: followed a formatting suggestion from Christoph Hellwig. Fixes: 2cefe4dbaadf ("block: add bio_iov_iter_get_pages()") Reviewed-by: Hannes Reinecke <hare@suse.com> Reviewed-by: Ming Lei <ming.lei@redhat.com> Reviewed-by: Jan Kara <jack@suse.cz> Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Martin Wilck <mwilck@suse.com> Signed-off-by: Jens Axboe <axboe@kernel.dk>
Diffstat (limited to 'block')
-rw-r--r--block/bio.c18
1 files changed, 8 insertions, 10 deletions
diff --git a/block/bio.c b/block/bio.c
index f7e3d88bd0b6..cd55ea6bd47c 100644
--- a/block/bio.c
+++ b/block/bio.c
@@ -912,16 +912,16 @@ EXPORT_SYMBOL(bio_add_page);
912 */ 912 */
913int bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter) 913int bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter)
914{ 914{
915 unsigned short nr_pages = bio->bi_max_vecs - bio->bi_vcnt; 915 unsigned short nr_pages = bio->bi_max_vecs - bio->bi_vcnt, idx;
916 struct bio_vec *bv = bio->bi_io_vec + bio->bi_vcnt; 916 struct bio_vec *bv = bio->bi_io_vec + bio->bi_vcnt;
917 struct page **pages = (struct page **)bv; 917 struct page **pages = (struct page **)bv;
918 size_t offset, diff; 918 size_t offset;
919 ssize_t size; 919 ssize_t size;
920 920
921 size = iov_iter_get_pages(iter, pages, LONG_MAX, nr_pages, &offset); 921 size = iov_iter_get_pages(iter, pages, LONG_MAX, nr_pages, &offset);
922 if (unlikely(size <= 0)) 922 if (unlikely(size <= 0))
923 return size ? size : -EFAULT; 923 return size ? size : -EFAULT;
924 nr_pages = (size + offset + PAGE_SIZE - 1) / PAGE_SIZE; 924 idx = nr_pages = (size + offset + PAGE_SIZE - 1) / PAGE_SIZE;
925 925
926 /* 926 /*
927 * Deep magic below: We need to walk the pinned pages backwards 927 * Deep magic below: We need to walk the pinned pages backwards
@@ -934,17 +934,15 @@ int bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter)
934 bio->bi_iter.bi_size += size; 934 bio->bi_iter.bi_size += size;
935 bio->bi_vcnt += nr_pages; 935 bio->bi_vcnt += nr_pages;
936 936
937 diff = (nr_pages * PAGE_SIZE - offset) - size; 937 while (idx--) {
938 while (nr_pages--) { 938 bv[idx].bv_page = pages[idx];
939 bv[nr_pages].bv_page = pages[nr_pages]; 939 bv[idx].bv_len = PAGE_SIZE;
940 bv[nr_pages].bv_len = PAGE_SIZE; 940 bv[idx].bv_offset = 0;
941 bv[nr_pages].bv_offset = 0;
942 } 941 }
943 942
944 bv[0].bv_offset += offset; 943 bv[0].bv_offset += offset;
945 bv[0].bv_len -= offset; 944 bv[0].bv_len -= offset;
946 if (diff) 945 bv[nr_pages - 1].bv_len -= nr_pages * PAGE_SIZE - offset - size;
947 bv[bio->bi_vcnt - 1].bv_len -= diff;
948 946
949 iov_iter_advance(iter, size); 947 iov_iter_advance(iter, size);
950 return 0; 948 return 0;