aboutsummaryrefslogtreecommitdiffstats
path: root/mm/page-writeback.c
diff options
context:
space:
mode:
authorDave Chinner <dchinner@redhat.com>2016-07-26 18:21:50 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2016-07-26 19:19:19 -0400
commit6c60d2b5746cf23025ffe71bd7ff9075048fc90c (patch)
tree6794888cf362aa86c079ed5697c1ef7a6c117a1a /mm/page-writeback.c
parent7d65b27448a90e08270537234819563e07936f76 (diff)
fs/fs-writeback.c: add a new writeback list for sync
wait_sb_inodes() currently does a walk of all inodes in the filesystem to find dirty one to wait on during sync. This is highly inefficient and wastes a lot of CPU when there are lots of clean cached inodes that we don't need to wait on. To avoid this "all inode" walk, we need to track inodes that are currently under writeback that we need to wait for. We do this by adding inodes to a writeback list on the sb when the mapping is first tagged as having pages under writeback. wait_sb_inodes() can then walk this list of "inodes under IO" and wait specifically just for the inodes that the current sync(2) needs to wait for. Define a couple helpers to add/remove an inode from the writeback list and call them when the overall mapping is tagged for or cleared from writeback. Update wait_sb_inodes() to walk only the inodes under writeback due to the sync. With this change, filesystem sync times are significantly reduced for fs' with largely populated inode caches and otherwise no other work to do. For example, on a 16xcpu 2GHz x86-64 server, 10TB XFS filesystem with a ~10m entry inode cache, sync times are reduced from ~7.3s to less than 0.1s when the filesystem is fully clean. Link: http://lkml.kernel.org/r/1466594593-6757-2-git-send-email-bfoster@redhat.com Signed-off-by: Dave Chinner <dchinner@redhat.com> Signed-off-by: Josef Bacik <jbacik@fb.com> Signed-off-by: Brian Foster <bfoster@redhat.com> Reviewed-by: Jan Kara <jack@suse.cz> Tested-by: Holger Hoffstätte <holger.hoffstaette@applied-asynchrony.com> Cc: Al Viro <viro@ZenIV.linux.org.uk> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm/page-writeback.c')
-rw-r--r--mm/page-writeback.c18
1 files changed, 18 insertions, 0 deletions
diff --git a/mm/page-writeback.c b/mm/page-writeback.c
index e2481949494c..8195eb454411 100644
--- a/mm/page-writeback.c
+++ b/mm/page-writeback.c
@@ -2747,6 +2747,11 @@ int test_clear_page_writeback(struct page *page)
2747 __wb_writeout_inc(wb); 2747 __wb_writeout_inc(wb);
2748 } 2748 }
2749 } 2749 }
2750
2751 if (mapping->host && !mapping_tagged(mapping,
2752 PAGECACHE_TAG_WRITEBACK))
2753 sb_clear_inode_writeback(mapping->host);
2754
2750 spin_unlock_irqrestore(&mapping->tree_lock, flags); 2755 spin_unlock_irqrestore(&mapping->tree_lock, flags);
2751 } else { 2756 } else {
2752 ret = TestClearPageWriteback(page); 2757 ret = TestClearPageWriteback(page);
@@ -2774,11 +2779,24 @@ int __test_set_page_writeback(struct page *page, bool keep_write)
2774 spin_lock_irqsave(&mapping->tree_lock, flags); 2779 spin_lock_irqsave(&mapping->tree_lock, flags);
2775 ret = TestSetPageWriteback(page); 2780 ret = TestSetPageWriteback(page);
2776 if (!ret) { 2781 if (!ret) {
2782 bool on_wblist;
2783
2784 on_wblist = mapping_tagged(mapping,
2785 PAGECACHE_TAG_WRITEBACK);
2786
2777 radix_tree_tag_set(&mapping->page_tree, 2787 radix_tree_tag_set(&mapping->page_tree,
2778 page_index(page), 2788 page_index(page),
2779 PAGECACHE_TAG_WRITEBACK); 2789 PAGECACHE_TAG_WRITEBACK);
2780 if (bdi_cap_account_writeback(bdi)) 2790 if (bdi_cap_account_writeback(bdi))
2781 __inc_wb_stat(inode_to_wb(inode), WB_WRITEBACK); 2791 __inc_wb_stat(inode_to_wb(inode), WB_WRITEBACK);
2792
2793 /*
2794 * We can come through here when swapping anonymous
2795 * pages, so we don't necessarily have an inode to track
2796 * for sync.
2797 */
2798 if (mapping->host && !on_wblist)
2799 sb_mark_inode_writeback(mapping->host);
2782 } 2800 }
2783 if (!PageDirty(page)) 2801 if (!PageDirty(page))
2784 radix_tree_tag_clear(&mapping->page_tree, 2802 radix_tree_tag_clear(&mapping->page_tree,