diff options
author | Wu Fengguang <fengguang.wu@intel.com> | 2010-06-06 12:38:15 -0400 |
---|---|---|
committer | Wu Fengguang <fengguang.wu@intel.com> | 2011-06-07 20:25:20 -0400 |
commit | 6e6938b6d3130305a5960c86b1a9b21e58cf6144 (patch) | |
tree | de5546e8390ce31cd31412d2ef78ce732a42191c /fs/fs-writeback.c | |
parent | 59c5f46fbe01a00eedf54a23789634438bb80603 (diff) |
writeback: introduce .tagged_writepages for the WB_SYNC_NONE sync stage
sync(2) is performed in two stages: the WB_SYNC_NONE sync and the
WB_SYNC_ALL sync. Identify the first stage with .tagged_writepages and
do livelock prevention for it, too.
Jan's commit f446daaea9 ("mm: implement writeback livelock avoidance
using page tagging") is a partial fix in that it only fixed the
WB_SYNC_ALL phase livelock.
Although ext4 is tested to no longer livelock with commit f446daaea9,
it may due to some "redirty_tail() after pages_skipped" effect which
is by no means a guarantee for _all_ the file systems.
Note that writeback_inodes_sb() is called by not only sync(), they are
treated the same because the other callers also need livelock prevention.
Impact: It changes the order in which pages/inodes are synced to disk.
Now in the WB_SYNC_NONE stage, it won't proceed to write the next inode
until finished with the current inode.
Acked-by: Jan Kara <jack@suse.cz>
CC: Dave Chinner <david@fromorbit.com>
Signed-off-by: Wu Fengguang <fengguang.wu@intel.com>
Diffstat (limited to 'fs/fs-writeback.c')
-rw-r--r-- | fs/fs-writeback.c | 17 |
1 files changed, 9 insertions, 8 deletions
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index 0f015a0468de..5ed2ce9a28d0 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c | |||
@@ -36,6 +36,7 @@ struct wb_writeback_work { | |||
36 | long nr_pages; | 36 | long nr_pages; |
37 | struct super_block *sb; | 37 | struct super_block *sb; |
38 | enum writeback_sync_modes sync_mode; | 38 | enum writeback_sync_modes sync_mode; |
39 | unsigned int tagged_writepages:1; | ||
39 | unsigned int for_kupdate:1; | 40 | unsigned int for_kupdate:1; |
40 | unsigned int range_cyclic:1; | 41 | unsigned int range_cyclic:1; |
41 | unsigned int for_background:1; | 42 | unsigned int for_background:1; |
@@ -650,6 +651,7 @@ static long wb_writeback(struct bdi_writeback *wb, | |||
650 | { | 651 | { |
651 | struct writeback_control wbc = { | 652 | struct writeback_control wbc = { |
652 | .sync_mode = work->sync_mode, | 653 | .sync_mode = work->sync_mode, |
654 | .tagged_writepages = work->tagged_writepages, | ||
653 | .older_than_this = NULL, | 655 | .older_than_this = NULL, |
654 | .for_kupdate = work->for_kupdate, | 656 | .for_kupdate = work->for_kupdate, |
655 | .for_background = work->for_background, | 657 | .for_background = work->for_background, |
@@ -657,7 +659,7 @@ static long wb_writeback(struct bdi_writeback *wb, | |||
657 | }; | 659 | }; |
658 | unsigned long oldest_jif; | 660 | unsigned long oldest_jif; |
659 | long wrote = 0; | 661 | long wrote = 0; |
660 | long write_chunk; | 662 | long write_chunk = MAX_WRITEBACK_PAGES; |
661 | struct inode *inode; | 663 | struct inode *inode; |
662 | 664 | ||
663 | if (wbc.for_kupdate) { | 665 | if (wbc.for_kupdate) { |
@@ -683,9 +685,7 @@ static long wb_writeback(struct bdi_writeback *wb, | |||
683 | * (quickly) tag currently dirty pages | 685 | * (quickly) tag currently dirty pages |
684 | * (maybe slowly) sync all tagged pages | 686 | * (maybe slowly) sync all tagged pages |
685 | */ | 687 | */ |
686 | if (wbc.sync_mode == WB_SYNC_NONE) | 688 | if (wbc.sync_mode == WB_SYNC_ALL || wbc.tagged_writepages) |
687 | write_chunk = MAX_WRITEBACK_PAGES; | ||
688 | else | ||
689 | write_chunk = LONG_MAX; | 689 | write_chunk = LONG_MAX; |
690 | 690 | ||
691 | wbc.wb_start = jiffies; /* livelock avoidance */ | 691 | wbc.wb_start = jiffies; /* livelock avoidance */ |
@@ -1188,10 +1188,11 @@ void writeback_inodes_sb_nr(struct super_block *sb, unsigned long nr) | |||
1188 | { | 1188 | { |
1189 | DECLARE_COMPLETION_ONSTACK(done); | 1189 | DECLARE_COMPLETION_ONSTACK(done); |
1190 | struct wb_writeback_work work = { | 1190 | struct wb_writeback_work work = { |
1191 | .sb = sb, | 1191 | .sb = sb, |
1192 | .sync_mode = WB_SYNC_NONE, | 1192 | .sync_mode = WB_SYNC_NONE, |
1193 | .done = &done, | 1193 | .tagged_writepages = 1, |
1194 | .nr_pages = nr, | 1194 | .done = &done, |
1195 | .nr_pages = nr, | ||
1195 | }; | 1196 | }; |
1196 | 1197 | ||
1197 | WARN_ON(!rwsem_is_locked(&sb->s_umount)); | 1198 | WARN_ON(!rwsem_is_locked(&sb->s_umount)); |