aboutsummaryrefslogtreecommitdiffstats
path: root/fs/fs-writeback.c
diff options
context:
space:
mode:
authorWu Fengguang <fengguang.wu@intel.com>2010-06-06 12:38:15 -0400
committerWu Fengguang <fengguang.wu@intel.com>2011-06-07 20:25:20 -0400
commit6e6938b6d3130305a5960c86b1a9b21e58cf6144 (patch)
treede5546e8390ce31cd31412d2ef78ce732a42191c /fs/fs-writeback.c
parent59c5f46fbe01a00eedf54a23789634438bb80603 (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.c17
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));