We have to properly decrease all related bio's counters, especially bi_size in order to merge_bvec_fn return right result. Usually this result in false merge rejects for two absolutely valid bio_vecs. This may cause significant performance penalty for example Itanium: page_size == 16k, fs_block_size == 1k and block device is raid with small chunk_size. Signed-off-by: Dmitri Monakhov <dmonakhov@xxxxxxxxxx> --- fs/bio.c | 16 ++++++++++++---- 1 files changed, 12 insertions(+), 4 deletions(-) diff --git a/fs/bio.c b/fs/bio.c index 7856257..d713074 100644 --- a/fs/bio.c +++ b/fs/bio.c @@ -332,14 +332,21 @@ static int __bio_add_page(struct request_queue *q, struct bio *bio, struct page if (page == prev->bv_page && offset == prev->bv_offset + prev->bv_len) { + /* Temprory detacth last bio_vec. */ + bio->bi_size -= prev->bv_len; + bio->bi_vcnt--; + bio->bi_phys_segments--; + bio->bi_hw_segments--; + prev->bv_len += len; if (q->merge_bvec_fn && q->merge_bvec_fn(q, bio, prev) < len) { prev->bv_len -= len; - return 0; + len = 0; } - goto done; + bio->bi_size += prev->bv_len; + goto out_add_bvec; } } @@ -394,11 +401,12 @@ static int __bio_add_page(struct request_queue *q, struct bio *bio, struct page BIOVEC_VIRT_MERGEABLE(bvec-1, bvec))) bio->bi_flags &= ~(1 << BIO_SEG_VALID); + bio->bi_size += len; +out_add_bvec: bio->bi_vcnt++; bio->bi_phys_segments++; bio->bi_hw_segments++; - done: - bio->bi_size += len; return len; } -- 1.5.4.rc4 -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html