Skip to content

Commit 576ed91

Browse files
Christoph Hellwigaxboe
authored andcommitted
block: use bio_add_page in bio_iov_iter_get_pages
Replace a nasty hack with a different nasty hack to prepare for multipage bio_vecs. By moving the temporary page array as far up as possible in the space allocated for the bio_vec array we can iterate forward over it and thus use bio_add_page. Using bio_add_page means we'll be able to merge physically contiguous pages once support for multipath bio_vecs is merged. Signed-off-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Jens Axboe <axboe@kernel.dk>
1 parent c8765de commit 576ed91

File tree

1 file changed

+20
-21
lines changed

1 file changed

+20
-21
lines changed

block/bio.c

Lines changed: 20 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -827,6 +827,8 @@ int bio_add_page(struct bio *bio, struct page *page,
827827
}
828828
EXPORT_SYMBOL(bio_add_page);
829829

830+
#define PAGE_PTRS_PER_BVEC (sizeof(struct bio_vec) / sizeof(struct page *))
831+
830832
/**
831833
* __bio_iov_iter_get_pages - pin user or kernel pages and add them to a bio
832834
* @bio: bio to add pages to
@@ -839,38 +841,35 @@ EXPORT_SYMBOL(bio_add_page);
839841
*/
840842
static int __bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter)
841843
{
842-
unsigned short nr_pages = bio->bi_max_vecs - bio->bi_vcnt, idx;
844+
unsigned short nr_pages = bio->bi_max_vecs - bio->bi_vcnt;
845+
unsigned short entries_left = bio->bi_max_vecs - bio->bi_vcnt;
843846
struct bio_vec *bv = bio->bi_io_vec + bio->bi_vcnt;
844847
struct page **pages = (struct page **)bv;
848+
ssize_t size, left;
849+
unsigned len, i;
845850
size_t offset;
846-
ssize_t size;
851+
852+
/*
853+
* Move page array up in the allocated memory for the bio vecs as far as
854+
* possible so that we can start filling biovecs from the beginning
855+
* without overwriting the temporary page array.
856+
*/
857+
BUILD_BUG_ON(PAGE_PTRS_PER_BVEC < 2);
858+
pages += entries_left * (PAGE_PTRS_PER_BVEC - 1);
847859

848860
size = iov_iter_get_pages(iter, pages, LONG_MAX, nr_pages, &offset);
849861
if (unlikely(size <= 0))
850862
return size ? size : -EFAULT;
851-
idx = nr_pages = (size + offset + PAGE_SIZE - 1) / PAGE_SIZE;
852863

853-
/*
854-
* Deep magic below: We need to walk the pinned pages backwards
855-
* because we are abusing the space allocated for the bio_vecs
856-
* for the page array. Because the bio_vecs are larger than the
857-
* page pointers by definition this will always work. But it also
858-
* means we can't use bio_add_page, so any changes to it's semantics
859-
* need to be reflected here as well.
860-
*/
861-
bio->bi_iter.bi_size += size;
862-
bio->bi_vcnt += nr_pages;
864+
for (left = size, i = 0; left > 0; left -= len, i++) {
865+
struct page *page = pages[i];
863866

864-
while (idx--) {
865-
bv[idx].bv_page = pages[idx];
866-
bv[idx].bv_len = PAGE_SIZE;
867-
bv[idx].bv_offset = 0;
867+
len = min_t(size_t, PAGE_SIZE - offset, left);
868+
if (WARN_ON_ONCE(bio_add_page(bio, page, len, offset) != len))
869+
return -EINVAL;
870+
offset = 0;
868871
}
869872

870-
bv[0].bv_offset += offset;
871-
bv[0].bv_len -= offset;
872-
bv[nr_pages - 1].bv_len -= nr_pages * PAGE_SIZE - offset - size;
873-
874873
iov_iter_advance(iter, size);
875874
return 0;
876875
}

0 commit comments

Comments
 (0)