diff options
Diffstat (limited to 'block/bio.c')
-rw-r--r-- | block/bio.c | 38 |
1 files changed, 24 insertions, 14 deletions
diff --git a/block/bio.c b/block/bio.c index cbd202250a32..7ab7060a0e6c 100644 --- a/block/bio.c +++ b/block/bio.c @@ -647,6 +647,24 @@ struct bio *bio_clone_fast(struct bio *bio, gfp_t gfp_mask, struct bio_set *bs) } EXPORT_SYMBOL(bio_clone_fast); +static inline bool page_is_mergeable(const struct bio_vec *bv, + struct page *page, unsigned int len, unsigned int off, + bool same_page) +{ + phys_addr_t vec_end_addr = page_to_phys(bv->bv_page) + + bv->bv_offset + bv->bv_len - 1; + phys_addr_t page_addr = page_to_phys(page); + + if (vec_end_addr + 1 != page_addr + off) + return false; + if (xen_domain() && !xen_biovec_phys_mergeable(bv, page)) + return false; + if (same_page && (vec_end_addr & PAGE_MASK) != page_addr) + return false; + + return true; +} + /** * bio_add_pc_page - attempt to add page to passthrough bio * @q: the target queue @@ -770,20 +788,12 @@ bool __bio_try_merge_page(struct bio *bio, struct page *page, if (bio->bi_vcnt > 0) { struct bio_vec *bv = &bio->bi_io_vec[bio->bi_vcnt - 1]; - phys_addr_t vec_end_addr = page_to_phys(bv->bv_page) + - bv->bv_offset + bv->bv_len - 1; - phys_addr_t page_addr = page_to_phys(page); - - if (vec_end_addr + 1 != page_addr + off) - return false; - if (xen_domain() && !xen_biovec_phys_mergeable(bv, page)) - return false; - if (same_page && (vec_end_addr & PAGE_MASK) != page_addr) - return false; - - bv->bv_len += len; - bio->bi_iter.bi_size += len; - return true; + + if (page_is_mergeable(bv, page, len, off, same_page)) { + bv->bv_len += len; + bio->bi_iter.bi_size += len; + return true; + } } return false; } |