diff options
author | Curt Wohlgemuth <curtw@google.com> | 2011-10-07 23:54:10 -0400 |
---|---|---|
committer | Wu Fengguang <fengguang.wu@intel.com> | 2011-10-30 12:33:36 -0400 |
commit | 0e175a1835ffc979e55787774e58ec79e41957d7 (patch) | |
tree | 6ec4b65a8de4e9d1c12d26a1079079ed81d79450 /fs | |
parent | ad4e38dd6a33bb3a4882c487d7abe621e583b982 (diff) |
writeback: Add a 'reason' to wb_writeback_work
This creates a new 'reason' field in a wb_writeback_work
structure, which unambiguously identifies who initiates
writeback activity. A 'wb_reason' enumeration has been
added to writeback.h, to enumerate the possible reasons.
The 'writeback_work_class' and tracepoint event class and
'writeback_queue_io' tracepoints are updated to include the
symbolic 'reason' in all trace events.
And the 'writeback_inodes_sbXXX' family of routines has had
a wb_stats parameter added to them, so callers can specify
why writeback is being started.
Acked-by: Jan Kara <jack@suse.cz>
Signed-off-by: Curt Wohlgemuth <curtw@google.com>
Signed-off-by: Wu Fengguang <fengguang.wu@intel.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/btrfs/extent-tree.c | 3 | ||||
-rw-r--r-- | fs/buffer.c | 2 | ||||
-rw-r--r-- | fs/ext4/inode.c | 2 | ||||
-rw-r--r-- | fs/fs-writeback.c | 49 | ||||
-rw-r--r-- | fs/quota/quota.c | 2 | ||||
-rw-r--r-- | fs/sync.c | 4 | ||||
-rw-r--r-- | fs/ubifs/budget.c | 2 |
7 files changed, 44 insertions, 20 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index f5be06a2462f..c9ee0e18bbdc 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -3340,7 +3340,8 @@ static int shrink_delalloc(struct btrfs_trans_handle *trans, | |||
3340 | smp_mb(); | 3340 | smp_mb(); |
3341 | nr_pages = min_t(unsigned long, nr_pages, | 3341 | nr_pages = min_t(unsigned long, nr_pages, |
3342 | root->fs_info->delalloc_bytes >> PAGE_CACHE_SHIFT); | 3342 | root->fs_info->delalloc_bytes >> PAGE_CACHE_SHIFT); |
3343 | writeback_inodes_sb_nr_if_idle(root->fs_info->sb, nr_pages); | 3343 | writeback_inodes_sb_nr_if_idle(root->fs_info->sb, nr_pages, |
3344 | WB_REASON_FS_FREE_SPACE); | ||
3344 | 3345 | ||
3345 | spin_lock(&space_info->lock); | 3346 | spin_lock(&space_info->lock); |
3346 | if (reserved > space_info->bytes_reserved) | 3347 | if (reserved > space_info->bytes_reserved) |
diff --git a/fs/buffer.c b/fs/buffer.c index 1a80b048ade8..f5dcee6c4cfb 100644 --- a/fs/buffer.c +++ b/fs/buffer.c | |||
@@ -285,7 +285,7 @@ static void free_more_memory(void) | |||
285 | struct zone *zone; | 285 | struct zone *zone; |
286 | int nid; | 286 | int nid; |
287 | 287 | ||
288 | wakeup_flusher_threads(1024); | 288 | wakeup_flusher_threads(1024, WB_REASON_FREE_MORE_MEM); |
289 | yield(); | 289 | yield(); |
290 | 290 | ||
291 | for_each_online_node(nid) { | 291 | for_each_online_node(nid) { |
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 986e2388f031..7fa73a3b2120 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c | |||
@@ -2241,7 +2241,7 @@ static int ext4_nonda_switch(struct super_block *sb) | |||
2241 | * start pushing delalloc when 1/2 of free blocks are dirty. | 2241 | * start pushing delalloc when 1/2 of free blocks are dirty. |
2242 | */ | 2242 | */ |
2243 | if (free_blocks < 2 * dirty_blocks) | 2243 | if (free_blocks < 2 * dirty_blocks) |
2244 | writeback_inodes_sb_if_idle(sb); | 2244 | writeback_inodes_sb_if_idle(sb, WB_REASON_FS_FREE_SPACE); |
2245 | 2245 | ||
2246 | return 0; | 2246 | return 0; |
2247 | } | 2247 | } |
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index c51029693600..73c3992b2bb4 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c | |||
@@ -41,11 +41,23 @@ struct wb_writeback_work { | |||
41 | unsigned int for_kupdate:1; | 41 | unsigned int for_kupdate:1; |
42 | unsigned int range_cyclic:1; | 42 | unsigned int range_cyclic:1; |
43 | unsigned int for_background:1; | 43 | unsigned int for_background:1; |
44 | enum wb_reason reason; /* why was writeback initiated? */ | ||
44 | 45 | ||
45 | struct list_head list; /* pending work list */ | 46 | struct list_head list; /* pending work list */ |
46 | struct completion *done; /* set if the caller waits */ | 47 | struct completion *done; /* set if the caller waits */ |
47 | }; | 48 | }; |
48 | 49 | ||
50 | const char *wb_reason_name[] = { | ||
51 | [WB_REASON_BACKGROUND] = "background", | ||
52 | [WB_REASON_TRY_TO_FREE_PAGES] = "try_to_free_pages", | ||
53 | [WB_REASON_SYNC] = "sync", | ||
54 | [WB_REASON_PERIODIC] = "periodic", | ||
55 | [WB_REASON_LAPTOP_TIMER] = "laptop_timer", | ||
56 | [WB_REASON_FREE_MORE_MEM] = "free_more_memory", | ||
57 | [WB_REASON_FS_FREE_SPACE] = "fs_free_space", | ||
58 | [WB_REASON_FORKER_THREAD] = "forker_thread" | ||
59 | }; | ||
60 | |||
49 | /* | 61 | /* |
50 | * Include the creation of the trace points after defining the | 62 | * Include the creation of the trace points after defining the |
51 | * wb_writeback_work structure so that the definition remains local to this | 63 | * wb_writeback_work structure so that the definition remains local to this |
@@ -115,7 +127,7 @@ static void bdi_queue_work(struct backing_dev_info *bdi, | |||
115 | 127 | ||
116 | static void | 128 | static void |
117 | __bdi_start_writeback(struct backing_dev_info *bdi, long nr_pages, | 129 | __bdi_start_writeback(struct backing_dev_info *bdi, long nr_pages, |
118 | bool range_cyclic) | 130 | bool range_cyclic, enum wb_reason reason) |
119 | { | 131 | { |
120 | struct wb_writeback_work *work; | 132 | struct wb_writeback_work *work; |
121 | 133 | ||
@@ -135,6 +147,7 @@ __bdi_start_writeback(struct backing_dev_info *bdi, long nr_pages, | |||
135 | work->sync_mode = WB_SYNC_NONE; | 147 | work->sync_mode = WB_SYNC_NONE; |
136 | work->nr_pages = nr_pages; | 148 | work->nr_pages = nr_pages; |
137 | work->range_cyclic = range_cyclic; | 149 | work->range_cyclic = range_cyclic; |
150 | work->reason = reason; | ||
138 | 151 | ||
139 | bdi_queue_work(bdi, work); | 152 | bdi_queue_work(bdi, work); |
140 | } | 153 | } |
@@ -150,9 +163,10 @@ __bdi_start_writeback(struct backing_dev_info *bdi, long nr_pages, | |||
150 | * completion. Caller need not hold sb s_umount semaphore. | 163 | * completion. Caller need not hold sb s_umount semaphore. |
151 | * | 164 | * |
152 | */ | 165 | */ |
153 | void bdi_start_writeback(struct backing_dev_info *bdi, long nr_pages) | 166 | void bdi_start_writeback(struct backing_dev_info *bdi, long nr_pages, |
167 | enum wb_reason reason) | ||
154 | { | 168 | { |
155 | __bdi_start_writeback(bdi, nr_pages, true); | 169 | __bdi_start_writeback(bdi, nr_pages, true, reason); |
156 | } | 170 | } |
157 | 171 | ||
158 | /** | 172 | /** |
@@ -641,12 +655,14 @@ static long __writeback_inodes_wb(struct bdi_writeback *wb, | |||
641 | return wrote; | 655 | return wrote; |
642 | } | 656 | } |
643 | 657 | ||
644 | long writeback_inodes_wb(struct bdi_writeback *wb, long nr_pages) | 658 | long writeback_inodes_wb(struct bdi_writeback *wb, long nr_pages, |
659 | enum wb_reason reason) | ||
645 | { | 660 | { |
646 | struct wb_writeback_work work = { | 661 | struct wb_writeback_work work = { |
647 | .nr_pages = nr_pages, | 662 | .nr_pages = nr_pages, |
648 | .sync_mode = WB_SYNC_NONE, | 663 | .sync_mode = WB_SYNC_NONE, |
649 | .range_cyclic = 1, | 664 | .range_cyclic = 1, |
665 | .reason = reason, | ||
650 | }; | 666 | }; |
651 | 667 | ||
652 | spin_lock(&wb->list_lock); | 668 | spin_lock(&wb->list_lock); |
@@ -825,6 +841,7 @@ static long wb_check_background_flush(struct bdi_writeback *wb) | |||
825 | .sync_mode = WB_SYNC_NONE, | 841 | .sync_mode = WB_SYNC_NONE, |
826 | .for_background = 1, | 842 | .for_background = 1, |
827 | .range_cyclic = 1, | 843 | .range_cyclic = 1, |
844 | .reason = WB_REASON_BACKGROUND, | ||
828 | }; | 845 | }; |
829 | 846 | ||
830 | return wb_writeback(wb, &work); | 847 | return wb_writeback(wb, &work); |
@@ -858,6 +875,7 @@ static long wb_check_old_data_flush(struct bdi_writeback *wb) | |||
858 | .sync_mode = WB_SYNC_NONE, | 875 | .sync_mode = WB_SYNC_NONE, |
859 | .for_kupdate = 1, | 876 | .for_kupdate = 1, |
860 | .range_cyclic = 1, | 877 | .range_cyclic = 1, |
878 | .reason = WB_REASON_PERIODIC, | ||
861 | }; | 879 | }; |
862 | 880 | ||
863 | return wb_writeback(wb, &work); | 881 | return wb_writeback(wb, &work); |
@@ -976,7 +994,7 @@ int bdi_writeback_thread(void *data) | |||
976 | * Start writeback of `nr_pages' pages. If `nr_pages' is zero, write back | 994 | * Start writeback of `nr_pages' pages. If `nr_pages' is zero, write back |
977 | * the whole world. | 995 | * the whole world. |
978 | */ | 996 | */ |
979 | void wakeup_flusher_threads(long nr_pages) | 997 | void wakeup_flusher_threads(long nr_pages, enum wb_reason reason) |
980 | { | 998 | { |
981 | struct backing_dev_info *bdi; | 999 | struct backing_dev_info *bdi; |
982 | 1000 | ||
@@ -989,7 +1007,7 @@ void wakeup_flusher_threads(long nr_pages) | |||
989 | list_for_each_entry_rcu(bdi, &bdi_list, bdi_list) { | 1007 | list_for_each_entry_rcu(bdi, &bdi_list, bdi_list) { |
990 | if (!bdi_has_dirty_io(bdi)) | 1008 | if (!bdi_has_dirty_io(bdi)) |
991 | continue; | 1009 | continue; |
992 | __bdi_start_writeback(bdi, nr_pages, false); | 1010 | __bdi_start_writeback(bdi, nr_pages, false, reason); |
993 | } | 1011 | } |
994 | rcu_read_unlock(); | 1012 | rcu_read_unlock(); |
995 | } | 1013 | } |
@@ -1210,7 +1228,9 @@ static void wait_sb_inodes(struct super_block *sb) | |||
1210 | * on how many (if any) will be written, and this function does not wait | 1228 | * on how many (if any) will be written, and this function does not wait |
1211 | * for IO completion of submitted IO. | 1229 | * for IO completion of submitted IO. |
1212 | */ | 1230 | */ |
1213 | void writeback_inodes_sb_nr(struct super_block *sb, unsigned long nr) | 1231 | void writeback_inodes_sb_nr(struct super_block *sb, |
1232 | unsigned long nr, | ||
1233 | enum wb_reason reason) | ||
1214 | { | 1234 | { |
1215 | DECLARE_COMPLETION_ONSTACK(done); | 1235 | DECLARE_COMPLETION_ONSTACK(done); |
1216 | struct wb_writeback_work work = { | 1236 | struct wb_writeback_work work = { |
@@ -1219,6 +1239,7 @@ void writeback_inodes_sb_nr(struct super_block *sb, unsigned long nr) | |||
1219 | .tagged_writepages = 1, | 1239 | .tagged_writepages = 1, |
1220 | .done = &done, | 1240 | .done = &done, |
1221 | .nr_pages = nr, | 1241 | .nr_pages = nr, |
1242 | .reason = reason, | ||
1222 | }; | 1243 | }; |
1223 | 1244 | ||
1224 | WARN_ON(!rwsem_is_locked(&sb->s_umount)); | 1245 | WARN_ON(!rwsem_is_locked(&sb->s_umount)); |
@@ -1235,9 +1256,9 @@ EXPORT_SYMBOL(writeback_inodes_sb_nr); | |||
1235 | * on how many (if any) will be written, and this function does not wait | 1256 | * on how many (if any) will be written, and this function does not wait |
1236 | * for IO completion of submitted IO. | 1257 | * for IO completion of submitted IO. |
1237 | */ | 1258 | */ |
1238 | void writeback_inodes_sb(struct super_block *sb) | 1259 | void writeback_inodes_sb(struct super_block *sb, enum wb_reason reason) |
1239 | { | 1260 | { |
1240 | return writeback_inodes_sb_nr(sb, get_nr_dirty_pages()); | 1261 | return writeback_inodes_sb_nr(sb, get_nr_dirty_pages(), reason); |
1241 | } | 1262 | } |
1242 | EXPORT_SYMBOL(writeback_inodes_sb); | 1263 | EXPORT_SYMBOL(writeback_inodes_sb); |
1243 | 1264 | ||
@@ -1248,11 +1269,11 @@ EXPORT_SYMBOL(writeback_inodes_sb); | |||
1248 | * Invoke writeback_inodes_sb if no writeback is currently underway. | 1269 | * Invoke writeback_inodes_sb if no writeback is currently underway. |
1249 | * Returns 1 if writeback was started, 0 if not. | 1270 | * Returns 1 if writeback was started, 0 if not. |
1250 | */ | 1271 | */ |
1251 | int writeback_inodes_sb_if_idle(struct super_block *sb) | 1272 | int writeback_inodes_sb_if_idle(struct super_block *sb, enum wb_reason reason) |
1252 | { | 1273 | { |
1253 | if (!writeback_in_progress(sb->s_bdi)) { | 1274 | if (!writeback_in_progress(sb->s_bdi)) { |
1254 | down_read(&sb->s_umount); | 1275 | down_read(&sb->s_umount); |
1255 | writeback_inodes_sb(sb); | 1276 | writeback_inodes_sb(sb, reason); |
1256 | up_read(&sb->s_umount); | 1277 | up_read(&sb->s_umount); |
1257 | return 1; | 1278 | return 1; |
1258 | } else | 1279 | } else |
@@ -1269,11 +1290,12 @@ EXPORT_SYMBOL(writeback_inodes_sb_if_idle); | |||
1269 | * Returns 1 if writeback was started, 0 if not. | 1290 | * Returns 1 if writeback was started, 0 if not. |
1270 | */ | 1291 | */ |
1271 | int writeback_inodes_sb_nr_if_idle(struct super_block *sb, | 1292 | int writeback_inodes_sb_nr_if_idle(struct super_block *sb, |
1272 | unsigned long nr) | 1293 | unsigned long nr, |
1294 | enum wb_reason reason) | ||
1273 | { | 1295 | { |
1274 | if (!writeback_in_progress(sb->s_bdi)) { | 1296 | if (!writeback_in_progress(sb->s_bdi)) { |
1275 | down_read(&sb->s_umount); | 1297 | down_read(&sb->s_umount); |
1276 | writeback_inodes_sb_nr(sb, nr); | 1298 | writeback_inodes_sb_nr(sb, nr, reason); |
1277 | up_read(&sb->s_umount); | 1299 | up_read(&sb->s_umount); |
1278 | return 1; | 1300 | return 1; |
1279 | } else | 1301 | } else |
@@ -1297,6 +1319,7 @@ void sync_inodes_sb(struct super_block *sb) | |||
1297 | .nr_pages = LONG_MAX, | 1319 | .nr_pages = LONG_MAX, |
1298 | .range_cyclic = 0, | 1320 | .range_cyclic = 0, |
1299 | .done = &done, | 1321 | .done = &done, |
1322 | .reason = WB_REASON_SYNC, | ||
1300 | }; | 1323 | }; |
1301 | 1324 | ||
1302 | WARN_ON(!rwsem_is_locked(&sb->s_umount)); | 1325 | WARN_ON(!rwsem_is_locked(&sb->s_umount)); |
diff --git a/fs/quota/quota.c b/fs/quota/quota.c index 10b6be3ca280..4bae57fc603b 100644 --- a/fs/quota/quota.c +++ b/fs/quota/quota.c | |||
@@ -286,7 +286,7 @@ static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id, | |||
286 | /* caller already holds s_umount */ | 286 | /* caller already holds s_umount */ |
287 | if (sb->s_flags & MS_RDONLY) | 287 | if (sb->s_flags & MS_RDONLY) |
288 | return -EROFS; | 288 | return -EROFS; |
289 | writeback_inodes_sb(sb); | 289 | writeback_inodes_sb(sb, WB_REASON_SYNC); |
290 | return 0; | 290 | return 0; |
291 | default: | 291 | default: |
292 | return -EINVAL; | 292 | return -EINVAL; |
@@ -43,7 +43,7 @@ static int __sync_filesystem(struct super_block *sb, int wait) | |||
43 | if (wait) | 43 | if (wait) |
44 | sync_inodes_sb(sb); | 44 | sync_inodes_sb(sb); |
45 | else | 45 | else |
46 | writeback_inodes_sb(sb); | 46 | writeback_inodes_sb(sb, WB_REASON_SYNC); |
47 | 47 | ||
48 | if (sb->s_op->sync_fs) | 48 | if (sb->s_op->sync_fs) |
49 | sb->s_op->sync_fs(sb, wait); | 49 | sb->s_op->sync_fs(sb, wait); |
@@ -98,7 +98,7 @@ static void sync_filesystems(int wait) | |||
98 | */ | 98 | */ |
99 | SYSCALL_DEFINE0(sync) | 99 | SYSCALL_DEFINE0(sync) |
100 | { | 100 | { |
101 | wakeup_flusher_threads(0); | 101 | wakeup_flusher_threads(0, WB_REASON_SYNC); |
102 | sync_filesystems(0); | 102 | sync_filesystems(0); |
103 | sync_filesystems(1); | 103 | sync_filesystems(1); |
104 | if (unlikely(laptop_mode)) | 104 | if (unlikely(laptop_mode)) |
diff --git a/fs/ubifs/budget.c b/fs/ubifs/budget.c index 315de66e52b2..bc4f94b28706 100644 --- a/fs/ubifs/budget.c +++ b/fs/ubifs/budget.c | |||
@@ -63,7 +63,7 @@ | |||
63 | static void shrink_liability(struct ubifs_info *c, int nr_to_write) | 63 | static void shrink_liability(struct ubifs_info *c, int nr_to_write) |
64 | { | 64 | { |
65 | down_read(&c->vfs_sb->s_umount); | 65 | down_read(&c->vfs_sb->s_umount); |
66 | writeback_inodes_sb(c->vfs_sb); | 66 | writeback_inodes_sb(c->vfs_sb, WB_REASON_FS_FREE_SPACE); |
67 | up_read(&c->vfs_sb->s_umount); | 67 | up_read(&c->vfs_sb->s_umount); |
68 | } | 68 | } |
69 | 69 | ||