diff options
Diffstat (limited to 'fs/fs-writeback.c')
-rw-r--r-- | fs/fs-writeback.c | 48 |
1 files changed, 20 insertions, 28 deletions
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index 1f4a10ece2f1..d754e3cf99a8 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c | |||
@@ -40,18 +40,13 @@ | |||
40 | struct wb_writeback_work { | 40 | struct wb_writeback_work { |
41 | long nr_pages; | 41 | long nr_pages; |
42 | struct super_block *sb; | 42 | struct super_block *sb; |
43 | /* | 43 | unsigned long *older_than_this; |
44 | * Write only inodes dirtied before this time. Don't forget to set | ||
45 | * older_than_this_is_set when you set this. | ||
46 | */ | ||
47 | unsigned long older_than_this; | ||
48 | enum writeback_sync_modes sync_mode; | 44 | enum writeback_sync_modes sync_mode; |
49 | unsigned int tagged_writepages:1; | 45 | unsigned int tagged_writepages:1; |
50 | unsigned int for_kupdate:1; | 46 | unsigned int for_kupdate:1; |
51 | unsigned int range_cyclic:1; | 47 | unsigned int range_cyclic:1; |
52 | unsigned int for_background:1; | 48 | unsigned int for_background:1; |
53 | unsigned int for_sync:1; /* sync(2) WB_SYNC_ALL writeback */ | 49 | unsigned int for_sync:1; /* sync(2) WB_SYNC_ALL writeback */ |
54 | unsigned int older_than_this_is_set:1; | ||
55 | enum wb_reason reason; /* why was writeback initiated? */ | 50 | enum wb_reason reason; /* why was writeback initiated? */ |
56 | 51 | ||
57 | struct list_head list; /* pending work list */ | 52 | struct list_head list; /* pending work list */ |
@@ -252,10 +247,10 @@ static int move_expired_inodes(struct list_head *delaying_queue, | |||
252 | int do_sb_sort = 0; | 247 | int do_sb_sort = 0; |
253 | int moved = 0; | 248 | int moved = 0; |
254 | 249 | ||
255 | WARN_ON_ONCE(!work->older_than_this_is_set); | ||
256 | while (!list_empty(delaying_queue)) { | 250 | while (!list_empty(delaying_queue)) { |
257 | inode = wb_inode(delaying_queue->prev); | 251 | inode = wb_inode(delaying_queue->prev); |
258 | if (inode_dirtied_after(inode, work->older_than_this)) | 252 | if (work->older_than_this && |
253 | inode_dirtied_after(inode, *work->older_than_this)) | ||
259 | break; | 254 | break; |
260 | list_move(&inode->i_wb_list, &tmp); | 255 | list_move(&inode->i_wb_list, &tmp); |
261 | moved++; | 256 | moved++; |
@@ -516,13 +511,16 @@ writeback_single_inode(struct inode *inode, struct bdi_writeback *wb, | |||
516 | } | 511 | } |
517 | WARN_ON(inode->i_state & I_SYNC); | 512 | WARN_ON(inode->i_state & I_SYNC); |
518 | /* | 513 | /* |
519 | * Skip inode if it is clean. We don't want to mess with writeback | 514 | * Skip inode if it is clean and we have no outstanding writeback in |
520 | * lists in this function since flusher thread may be doing for example | 515 | * WB_SYNC_ALL mode. We don't want to mess with writeback lists in this |
521 | * sync in parallel and if we move the inode, it could get skipped. So | 516 | * function since flusher thread may be doing for example sync in |
522 | * here we make sure inode is on some writeback list and leave it there | 517 | * parallel and if we move the inode, it could get skipped. So here we |
523 | * unless we have completely cleaned the inode. | 518 | * make sure inode is on some writeback list and leave it there unless |
519 | * we have completely cleaned the inode. | ||
524 | */ | 520 | */ |
525 | if (!(inode->i_state & I_DIRTY)) | 521 | if (!(inode->i_state & I_DIRTY) && |
522 | (wbc->sync_mode != WB_SYNC_ALL || | ||
523 | !mapping_tagged(inode->i_mapping, PAGECACHE_TAG_WRITEBACK))) | ||
526 | goto out; | 524 | goto out; |
527 | inode->i_state |= I_SYNC; | 525 | inode->i_state |= I_SYNC; |
528 | spin_unlock(&inode->i_lock); | 526 | spin_unlock(&inode->i_lock); |
@@ -739,8 +737,6 @@ static long writeback_inodes_wb(struct bdi_writeback *wb, long nr_pages, | |||
739 | .sync_mode = WB_SYNC_NONE, | 737 | .sync_mode = WB_SYNC_NONE, |
740 | .range_cyclic = 1, | 738 | .range_cyclic = 1, |
741 | .reason = reason, | 739 | .reason = reason, |
742 | .older_than_this = jiffies, | ||
743 | .older_than_this_is_set = 1, | ||
744 | }; | 740 | }; |
745 | 741 | ||
746 | spin_lock(&wb->list_lock); | 742 | spin_lock(&wb->list_lock); |
@@ -799,13 +795,12 @@ static long wb_writeback(struct bdi_writeback *wb, | |||
799 | { | 795 | { |
800 | unsigned long wb_start = jiffies; | 796 | unsigned long wb_start = jiffies; |
801 | long nr_pages = work->nr_pages; | 797 | long nr_pages = work->nr_pages; |
798 | unsigned long oldest_jif; | ||
802 | struct inode *inode; | 799 | struct inode *inode; |
803 | long progress; | 800 | long progress; |
804 | 801 | ||
805 | if (!work->older_than_this_is_set) { | 802 | oldest_jif = jiffies; |
806 | work->older_than_this = jiffies; | 803 | work->older_than_this = &oldest_jif; |
807 | work->older_than_this_is_set = 1; | ||
808 | } | ||
809 | 804 | ||
810 | spin_lock(&wb->list_lock); | 805 | spin_lock(&wb->list_lock); |
811 | for (;;) { | 806 | for (;;) { |
@@ -839,10 +834,10 @@ static long wb_writeback(struct bdi_writeback *wb, | |||
839 | * safe. | 834 | * safe. |
840 | */ | 835 | */ |
841 | if (work->for_kupdate) { | 836 | if (work->for_kupdate) { |
842 | work->older_than_this = jiffies - | 837 | oldest_jif = jiffies - |
843 | msecs_to_jiffies(dirty_expire_interval * 10); | 838 | msecs_to_jiffies(dirty_expire_interval * 10); |
844 | } else if (work->for_background) | 839 | } else if (work->for_background) |
845 | work->older_than_this = jiffies; | 840 | oldest_jif = jiffies; |
846 | 841 | ||
847 | trace_writeback_start(wb->bdi, work); | 842 | trace_writeback_start(wb->bdi, work); |
848 | if (list_empty(&wb->b_io)) | 843 | if (list_empty(&wb->b_io)) |
@@ -1354,21 +1349,18 @@ EXPORT_SYMBOL(try_to_writeback_inodes_sb); | |||
1354 | 1349 | ||
1355 | /** | 1350 | /** |
1356 | * sync_inodes_sb - sync sb inode pages | 1351 | * sync_inodes_sb - sync sb inode pages |
1357 | * @sb: the superblock | 1352 | * @sb: the superblock |
1358 | * @older_than_this: timestamp | ||
1359 | * | 1353 | * |
1360 | * This function writes and waits on any dirty inode belonging to this | 1354 | * This function writes and waits on any dirty inode belonging to this |
1361 | * superblock that has been dirtied before given timestamp. | 1355 | * super_block. |
1362 | */ | 1356 | */ |
1363 | void sync_inodes_sb(struct super_block *sb, unsigned long older_than_this) | 1357 | void sync_inodes_sb(struct super_block *sb) |
1364 | { | 1358 | { |
1365 | DECLARE_COMPLETION_ONSTACK(done); | 1359 | DECLARE_COMPLETION_ONSTACK(done); |
1366 | struct wb_writeback_work work = { | 1360 | struct wb_writeback_work work = { |
1367 | .sb = sb, | 1361 | .sb = sb, |
1368 | .sync_mode = WB_SYNC_ALL, | 1362 | .sync_mode = WB_SYNC_ALL, |
1369 | .nr_pages = LONG_MAX, | 1363 | .nr_pages = LONG_MAX, |
1370 | .older_than_this = older_than_this, | ||
1371 | .older_than_this_is_set = 1, | ||
1372 | .range_cyclic = 0, | 1364 | .range_cyclic = 0, |
1373 | .done = &done, | 1365 | .done = &done, |
1374 | .reason = WB_REASON_SYNC, | 1366 | .reason = WB_REASON_SYNC, |