Commit b403ea24 authored by Martin Wilck's avatar Martin Wilck Committed by Jens Axboe

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: 2cefe4db ("block: add bio_iov_iter_get_pages()")
Reviewed-by: default avatarHannes Reinecke <hare@suse.com>
Reviewed-by: default avatarMing Lei <ming.lei@redhat.com>
Reviewed-by: default avatarJan Kara <jack@suse.cz>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
Signed-off-by: default avatarMartin Wilck <mwilck@suse.com>
Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
parent 78e18063
...@@ -912,16 +912,16 @@ EXPORT_SYMBOL(bio_add_page); ...@@ -912,16 +912,16 @@ EXPORT_SYMBOL(bio_add_page);
*/ */
int bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter) int bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter)
{ {
unsigned short nr_pages = bio->bi_max_vecs - bio->bi_vcnt; unsigned short nr_pages = bio->bi_max_vecs - bio->bi_vcnt, idx;
struct bio_vec *bv = bio->bi_io_vec + bio->bi_vcnt; struct bio_vec *bv = bio->bi_io_vec + bio->bi_vcnt;
struct page **pages = (struct page **)bv; struct page **pages = (struct page **)bv;
size_t offset, diff; size_t offset;
ssize_t size; ssize_t size;
size = iov_iter_get_pages(iter, pages, LONG_MAX, nr_pages, &offset); size = iov_iter_get_pages(iter, pages, LONG_MAX, nr_pages, &offset);
if (unlikely(size <= 0)) if (unlikely(size <= 0))
return size ? size : -EFAULT; return size ? size : -EFAULT;
nr_pages = (size + offset + PAGE_SIZE - 1) / PAGE_SIZE; idx = nr_pages = (size + offset + PAGE_SIZE - 1) / PAGE_SIZE;
/* /*
* Deep magic below: We need to walk the pinned pages backwards * 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,17 +934,15 @@ int bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter)
bio->bi_iter.bi_size += size; bio->bi_iter.bi_size += size;
bio->bi_vcnt += nr_pages; bio->bi_vcnt += nr_pages;
diff = (nr_pages * PAGE_SIZE - offset) - size; while (idx--) {
while (nr_pages--) { bv[idx].bv_page = pages[idx];
bv[nr_pages].bv_page = pages[nr_pages]; bv[idx].bv_len = PAGE_SIZE;
bv[nr_pages].bv_len = PAGE_SIZE; bv[idx].bv_offset = 0;
bv[nr_pages].bv_offset = 0;
} }
bv[0].bv_offset += offset; bv[0].bv_offset += offset;
bv[0].bv_len -= offset; bv[0].bv_len -= offset;
if (diff) bv[nr_pages - 1].bv_len -= nr_pages * PAGE_SIZE - offset - size;
bv[bio->bi_vcnt - 1].bv_len -= diff;
iov_iter_advance(iter, size); iov_iter_advance(iter, size);
return 0; return 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment