Commit 0e175a1835ffc979e55787774e58ec79e41957d7

Authored by Curt Wohlgemuth
Committed by Wu Fengguang
1 parent ad4e38dd6a

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>

Showing 13 changed files with 88 additions and 34 deletions Side-by-side Diff

fs/btrfs/extent-tree.c
... ... @@ -3340,7 +3340,8 @@
3340 3340 smp_mb();
3341 3341 nr_pages = min_t(unsigned long, nr_pages,
3342 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 3346 spin_lock(&space_info->lock);
3346 3347 if (reserved > space_info->bytes_reserved)
... ... @@ -285,7 +285,7 @@
285 285 struct zone *zone;
286 286 int nid;
287 287  
288   - wakeup_flusher_threads(1024);
  288 + wakeup_flusher_threads(1024, WB_REASON_FREE_MORE_MEM);
289 289 yield();
290 290  
291 291 for_each_online_node(nid) {
... ... @@ -2241,7 +2241,7 @@
2241 2241 * start pushing delalloc when 1/2 of free blocks are dirty.
2242 2242 */
2243 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 2246 return 0;
2247 2247 }
... ... @@ -41,11 +41,23 @@
41 41 unsigned int for_kupdate:1;
42 42 unsigned int range_cyclic:1;
43 43 unsigned int for_background:1;
  44 + enum wb_reason reason; /* why was writeback initiated? */
44 45  
45 46 struct list_head list; /* pending work list */
46 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 62 * Include the creation of the trace points after defining the
51 63 * wb_writeback_work structure so that the definition remains local to this
... ... @@ -115,7 +127,7 @@
115 127  
116 128 static void
117 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 132 struct wb_writeback_work *work;
121 133  
... ... @@ -135,6 +147,7 @@
135 147 work->sync_mode = WB_SYNC_NONE;
136 148 work->nr_pages = nr_pages;
137 149 work->range_cyclic = range_cyclic;
  150 + work->reason = reason;
138 151  
139 152 bdi_queue_work(bdi, work);
140 153 }
141 154  
... ... @@ -150,9 +163,10 @@
150 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 /**
159 173  
... ... @@ -641,12 +655,14 @@
641 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 661 struct wb_writeback_work work = {
647 662 .nr_pages = nr_pages,
648 663 .sync_mode = WB_SYNC_NONE,
649 664 .range_cyclic = 1,
  665 + .reason = reason,
650 666 };
651 667  
652 668 spin_lock(&wb->list_lock);
... ... @@ -825,6 +841,7 @@
825 841 .sync_mode = WB_SYNC_NONE,
826 842 .for_background = 1,
827 843 .range_cyclic = 1,
  844 + .reason = WB_REASON_BACKGROUND,
828 845 };
829 846  
830 847 return wb_writeback(wb, &work);
... ... @@ -858,6 +875,7 @@
858 875 .sync_mode = WB_SYNC_NONE,
859 876 .for_kupdate = 1,
860 877 .range_cyclic = 1,
  878 + .reason = WB_REASON_PERIODIC,
861 879 };
862 880  
863 881 return wb_writeback(wb, &work);
... ... @@ -976,7 +994,7 @@
976 994 * Start writeback of `nr_pages' pages. If `nr_pages' is zero, write back
977 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 999 struct backing_dev_info *bdi;
982 1000  
... ... @@ -989,7 +1007,7 @@
989 1007 list_for_each_entry_rcu(bdi, &bdi_list, bdi_list) {
990 1008 if (!bdi_has_dirty_io(bdi))
991 1009 continue;
992   - __bdi_start_writeback(bdi, nr_pages, false);
  1010 + __bdi_start_writeback(bdi, nr_pages, false, reason);
993 1011 }
994 1012 rcu_read_unlock();
995 1013 }
... ... @@ -1210,7 +1228,9 @@
1210 1228 * on how many (if any) will be written, and this function does not wait
1211 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 1235 DECLARE_COMPLETION_ONSTACK(done);
1216 1236 struct wb_writeback_work work = {
... ... @@ -1219,6 +1239,7 @@
1219 1239 .tagged_writepages = 1,
1220 1240 .done = &done,
1221 1241 .nr_pages = nr,
  1242 + .reason = reason,
1222 1243 };
1223 1244  
1224 1245 WARN_ON(!rwsem_is_locked(&sb->s_umount));
1225 1246  
... ... @@ -1235,9 +1256,9 @@
1235 1256 * on how many (if any) will be written, and this function does not wait
1236 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 1263 EXPORT_SYMBOL(writeback_inodes_sb);
1243 1264  
1244 1265  
... ... @@ -1248,11 +1269,11 @@
1248 1269 * Invoke writeback_inodes_sb if no writeback is currently underway.
1249 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 1274 if (!writeback_in_progress(sb->s_bdi)) {
1254 1275 down_read(&sb->s_umount);
1255   - writeback_inodes_sb(sb);
  1276 + writeback_inodes_sb(sb, reason);
1256 1277 up_read(&sb->s_umount);
1257 1278 return 1;
1258 1279 } else
1259 1280  
... ... @@ -1269,11 +1290,12 @@
1269 1290 * Returns 1 if writeback was started, 0 if not.
1270 1291 */
1271 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 1296 if (!writeback_in_progress(sb->s_bdi)) {
1275 1297 down_read(&sb->s_umount);
1276   - writeback_inodes_sb_nr(sb, nr);
  1298 + writeback_inodes_sb_nr(sb, nr, reason);
1277 1299 up_read(&sb->s_umount);
1278 1300 return 1;
1279 1301 } else
... ... @@ -1297,6 +1319,7 @@
1297 1319 .nr_pages = LONG_MAX,
1298 1320 .range_cyclic = 0,
1299 1321 .done = &done,
  1322 + .reason = WB_REASON_SYNC,
1300 1323 };
1301 1324  
1302 1325 WARN_ON(!rwsem_is_locked(&sb->s_umount));
... ... @@ -286,7 +286,7 @@
286 286 /* caller already holds s_umount */
287 287 if (sb->s_flags & MS_RDONLY)
288 288 return -EROFS;
289   - writeback_inodes_sb(sb);
  289 + writeback_inodes_sb(sb, WB_REASON_SYNC);
290 290 return 0;
291 291 default:
292 292 return -EINVAL;
... ... @@ -43,7 +43,7 @@
43 43 if (wait)
44 44 sync_inodes_sb(sb);
45 45 else
46   - writeback_inodes_sb(sb);
  46 + writeback_inodes_sb(sb, WB_REASON_SYNC);
47 47  
48 48 if (sb->s_op->sync_fs)
49 49 sb->s_op->sync_fs(sb, wait);
... ... @@ -98,7 +98,7 @@
98 98 */
99 99 SYSCALL_DEFINE0(sync)
100 100 {
101   - wakeup_flusher_threads(0);
  101 + wakeup_flusher_threads(0, WB_REASON_SYNC);
102 102 sync_filesystems(0);
103 103 sync_filesystems(1);
104 104 if (unlikely(laptop_mode))
... ... @@ -63,7 +63,7 @@
63 63 static void shrink_liability(struct ubifs_info *c, int nr_to_write)
64 64 {
65 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 67 up_read(&c->vfs_sb->s_umount);
68 68 }
69 69  
include/linux/backing-dev.h
... ... @@ -118,7 +118,8 @@
118 118 int bdi_register_dev(struct backing_dev_info *bdi, dev_t dev);
119 119 void bdi_unregister(struct backing_dev_info *bdi);
120 120 int bdi_setup_and_register(struct backing_dev_info *, char *, unsigned int);
121   -void bdi_start_writeback(struct backing_dev_info *bdi, long nr_pages);
  121 +void bdi_start_writeback(struct backing_dev_info *bdi, long nr_pages,
  122 + enum wb_reason reason);
122 123 void bdi_start_background_writeback(struct backing_dev_info *bdi);
123 124 int bdi_writeback_thread(void *data);
124 125 int bdi_has_dirty_io(struct backing_dev_info *bdi);
include/linux/writeback.h
... ... @@ -39,6 +39,23 @@
39 39 };
40 40  
41 41 /*
  42 + * why some writeback work was initiated
  43 + */
  44 +enum wb_reason {
  45 + WB_REASON_BACKGROUND,
  46 + WB_REASON_TRY_TO_FREE_PAGES,
  47 + WB_REASON_SYNC,
  48 + WB_REASON_PERIODIC,
  49 + WB_REASON_LAPTOP_TIMER,
  50 + WB_REASON_FREE_MORE_MEM,
  51 + WB_REASON_FS_FREE_SPACE,
  52 + WB_REASON_FORKER_THREAD,
  53 +
  54 + WB_REASON_MAX,
  55 +};
  56 +extern const char *wb_reason_name[];
  57 +
  58 +/*
42 59 * A control structure which tells the writeback code what to do. These are
43 60 * always on the stack, and hence need no locking. They are always initialised
44 61 * in a manner such that unspecified fields are set to zero.
45 62  
46 63  
... ... @@ -69,14 +86,17 @@
69 86 */
70 87 struct bdi_writeback;
71 88 int inode_wait(void *);
72   -void writeback_inodes_sb(struct super_block *);
73   -void writeback_inodes_sb_nr(struct super_block *, unsigned long nr);
74   -int writeback_inodes_sb_if_idle(struct super_block *);
75   -int writeback_inodes_sb_nr_if_idle(struct super_block *, unsigned long nr);
  89 +void writeback_inodes_sb(struct super_block *, enum wb_reason reason);
  90 +void writeback_inodes_sb_nr(struct super_block *, unsigned long nr,
  91 + enum wb_reason reason);
  92 +int writeback_inodes_sb_if_idle(struct super_block *, enum wb_reason reason);
  93 +int writeback_inodes_sb_nr_if_idle(struct super_block *, unsigned long nr,
  94 + enum wb_reason reason);
76 95 void sync_inodes_sb(struct super_block *);
77   -long writeback_inodes_wb(struct bdi_writeback *wb, long nr_pages);
  96 +long writeback_inodes_wb(struct bdi_writeback *wb, long nr_pages,
  97 + enum wb_reason reason);
78 98 long wb_do_writeback(struct bdi_writeback *wb, int force_wait);
79   -void wakeup_flusher_threads(long nr_pages);
  99 +void wakeup_flusher_threads(long nr_pages, enum wb_reason reason);
80 100  
81 101 /* writeback.h requires fs.h; it, too, is not included from here. */
82 102 static inline void wait_on_inode(struct inode *inode)
include/trace/events/writeback.h
... ... @@ -34,6 +34,7 @@
34 34 __field(int, for_kupdate)
35 35 __field(int, range_cyclic)
36 36 __field(int, for_background)
  37 + __field(int, reason)
37 38 ),
38 39 TP_fast_assign(
39 40 strncpy(__entry->name, dev_name(bdi->dev), 32);
40 41  
41 42  
... ... @@ -43,16 +44,18 @@
43 44 __entry->for_kupdate = work->for_kupdate;
44 45 __entry->range_cyclic = work->range_cyclic;
45 46 __entry->for_background = work->for_background;
  47 + __entry->reason = work->reason;
46 48 ),
47 49 TP_printk("bdi %s: sb_dev %d:%d nr_pages=%ld sync_mode=%d "
48   - "kupdate=%d range_cyclic=%d background=%d",
  50 + "kupdate=%d range_cyclic=%d background=%d reason=%s",
49 51 __entry->name,
50 52 MAJOR(__entry->sb_dev), MINOR(__entry->sb_dev),
51 53 __entry->nr_pages,
52 54 __entry->sync_mode,
53 55 __entry->for_kupdate,
54 56 __entry->range_cyclic,
55   - __entry->for_background
  57 + __entry->for_background,
  58 + wb_reason_name[__entry->reason]
56 59 )
57 60 );
58 61 #define DEFINE_WRITEBACK_WORK_EVENT(name) \
... ... @@ -165,6 +168,7 @@
165 168 __field(unsigned long, older)
166 169 __field(long, age)
167 170 __field(int, moved)
  171 + __field(int, reason)
168 172 ),
169 173 TP_fast_assign(
170 174 unsigned long *older_than_this = work->older_than_this;
171 175  
172 176  
... ... @@ -173,12 +177,14 @@
173 177 __entry->age = older_than_this ?
174 178 (jiffies - *older_than_this) * 1000 / HZ : -1;
175 179 __entry->moved = moved;
  180 + __entry->reason = work->reason;
176 181 ),
177   - TP_printk("bdi %s: older=%lu age=%ld enqueue=%d",
  182 + TP_printk("bdi %s: older=%lu age=%ld enqueue=%d reason=%s",
178 183 __entry->name,
179 184 __entry->older, /* older_than_this in jiffies */
180 185 __entry->age, /* older_than_this in relative milliseconds */
181   - __entry->moved)
  186 + __entry->moved,
  187 + wb_reason_name[__entry->reason])
182 188 );
183 189  
184 190 TRACE_EVENT(global_dirty_state,
... ... @@ -476,7 +476,8 @@
476 476 * the bdi from the thread. Hopefully 1024 is
477 477 * large enough for efficient IO.
478 478 */
479   - writeback_inodes_wb(&bdi->wb, 1024);
  479 + writeback_inodes_wb(&bdi->wb, 1024,
  480 + WB_REASON_FORKER_THREAD);
480 481 } else {
481 482 /*
482 483 * The spinlock makes sure we do not lose
... ... @@ -1301,7 +1301,8 @@
1301 1301 * threshold
1302 1302 */
1303 1303 if (bdi_has_dirty_io(&q->backing_dev_info))
1304   - bdi_start_writeback(&q->backing_dev_info, nr_pages);
  1304 + bdi_start_writeback(&q->backing_dev_info, nr_pages,
  1305 + WB_REASON_LAPTOP_TIMER);
1305 1306 }
1306 1307  
1307 1308 /*
... ... @@ -2181,7 +2181,8 @@
2181 2181 */
2182 2182 writeback_threshold = sc->nr_to_reclaim + sc->nr_to_reclaim / 2;
2183 2183 if (total_scanned > writeback_threshold) {
2184   - wakeup_flusher_threads(laptop_mode ? 0 : total_scanned);
  2184 + wakeup_flusher_threads(laptop_mode ? 0 : total_scanned,
  2185 + WB_REASON_TRY_TO_FREE_PAGES);
2185 2186 sc->may_writepage = 1;
2186 2187 }
2187 2188