Commit c10f778d authored by Jan Kara's avatar Jan Kara Committed by Linus Torvalds

fs: fix performance regression in clean_bdev_aliases()

Commit e64855c6 ("fs: Add helper to clean bdev aliases under a bh
and use it") added a wrapper for clean_bdev_aliases() that invalidates
bdev aliases underlying a single buffer head.

However this has caused a performance regression for bonnie++ benchmark
on ext4 filesystem when delayed allocation is turned off (ext3 mode) -
average of 3 runs:

  Hmean SeqOut Char  164787.55 (  0.00%) 107189.06 (-34.95%)
  Hmean SeqOut Block 219883.89 (  0.00%) 168870.32 (-23.20%)

The reason for this regression is that clean_bdev_aliases() is slower
when called for a single block because pagevec_lookup() it uses will end
up iterating through the radix tree until it finds a page (which may
take a while) but we are only interested whether there's a page at a
particular index.

Fix the problem by using pagevec_lookup_range() instead which avoids the
needless iteration.

Fixes: e64855c6 ("fs: Add helper to clean bdev aliases under a bh and use it")
Link: http://lkml.kernel.org/r/20170726114704.7626-5-jack@suse.czSigned-off-by: default avatarJan Kara <jack@suse.cz>
Cc: Jens Axboe <axboe@fb.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent b947cee4
...@@ -1627,19 +1627,18 @@ void clean_bdev_aliases(struct block_device *bdev, sector_t block, sector_t len) ...@@ -1627,19 +1627,18 @@ void clean_bdev_aliases(struct block_device *bdev, sector_t block, sector_t len)
struct pagevec pvec; struct pagevec pvec;
pgoff_t index = block >> (PAGE_SHIFT - bd_inode->i_blkbits); pgoff_t index = block >> (PAGE_SHIFT - bd_inode->i_blkbits);
pgoff_t end; pgoff_t end;
int i; int i, count;
struct buffer_head *bh; struct buffer_head *bh;
struct buffer_head *head; struct buffer_head *head;
end = (block + len - 1) >> (PAGE_SHIFT - bd_inode->i_blkbits); end = (block + len - 1) >> (PAGE_SHIFT - bd_inode->i_blkbits);
pagevec_init(&pvec, 0); pagevec_init(&pvec, 0);
while (index <= end && pagevec_lookup(&pvec, bd_mapping, &index, while (pagevec_lookup_range(&pvec, bd_mapping, &index, end,
min(end - index, (pgoff_t)PAGEVEC_SIZE - 1) + 1)) { PAGEVEC_SIZE)) {
for (i = 0; i < pagevec_count(&pvec); i++) { count = pagevec_count(&pvec);
for (i = 0; i < count; i++) {
struct page *page = pvec.pages[i]; struct page *page = pvec.pages[i];
if (page->index > end)
break;
if (!page_has_buffers(page)) if (!page_has_buffers(page))
continue; continue;
/* /*
...@@ -1669,6 +1668,9 @@ void clean_bdev_aliases(struct block_device *bdev, sector_t block, sector_t len) ...@@ -1669,6 +1668,9 @@ void clean_bdev_aliases(struct block_device *bdev, sector_t block, sector_t len)
} }
pagevec_release(&pvec); pagevec_release(&pvec);
cond_resched(); cond_resched();
/* End of range already reached? */
if (index > end || !index)
break;
} }
} }
EXPORT_SYMBOL(clean_bdev_aliases); EXPORT_SYMBOL(clean_bdev_aliases);
......
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