When mTHP is enabled, IO can contain larger folios instead of pages. In such cases add a larger size to the bio instead of looping through pages. This reduces the overhead of iterating through pages for larger block sizes. perf diff before and after this change: Perf diff for write I/O with 128K block size: 1.22% -0.97% [kernel.kallsyms] [k] bio_iov_iter_get_pages Perf diff for read I/O with 128K block size: 4.13% -3.26% [kernel.kallsyms] [k] bio_iov_iter_get_pages Signed-off-by: Kundan Kumar <kundan.kumar@xxxxxxxxxxx> --- block/bio.c | 37 ++++++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/block/bio.c b/block/bio.c index 38baedb39c6f..c507e47e3c46 100644 --- a/block/bio.c +++ b/block/bio.c @@ -1247,8 +1247,10 @@ static int __bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter) struct page **pages = (struct page **)bv; ssize_t size, left; unsigned len, i = 0; - size_t offset; + size_t offset, folio_offset, size_folio; int ret = 0; + unsigned short num_pages; + struct folio *folio; /* * Move page array up in the allocated memory for the bio vecs as far as @@ -1289,16 +1291,33 @@ static int __bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter) for (left = size, i = 0; left > 0; left -= len, i++) { struct page *page = pages[i]; + folio = page_folio(page); + + if (!folio_test_large(folio) || + (bio_op(bio) == REQ_OP_ZONE_APPEND)) { + len = min_t(size_t, PAGE_SIZE - offset, left); + if (bio_op(bio) == REQ_OP_ZONE_APPEND) { + ret = bio_iov_add_zone_append_page(bio, page, + len, offset); + if (ret) + break; + } else + bio_iov_add_page(bio, page, len, offset); + } else { + /* See the offset of folio and the size */ + folio_offset = (folio_page_idx(folio, page) + << PAGE_SHIFT) + offset; + size_folio = folio_size(folio); - len = min_t(size_t, PAGE_SIZE - offset, left); - if (bio_op(bio) == REQ_OP_ZONE_APPEND) { - ret = bio_iov_add_zone_append_page(bio, page, len, - offset); - if (ret) - break; - } else - bio_iov_add_page(bio, page, len, offset); + /* Calculate the length of folio to be added */ + len = min_t(size_t, (size_folio - folio_offset), left); + + num_pages = DIV_ROUND_UP(offset + len, PAGE_SIZE); + bio_iov_add_page(bio, page, len, offset); + /* Skip the pages which got added */ + i = i + (num_pages - 1); + } offset = 0; } -- 2.25.1