Skip to content

Commit 0e175a1

Browse files
Curt WohlgemuthWu Fengguang
authored andcommitted
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 <[email protected]> Signed-off-by: Curt Wohlgemuth <[email protected]> Signed-off-by: Wu Fengguang <[email protected]>
1 parent ad4e38d commit 0e175a1

File tree

13 files changed

+88
-34
lines changed

13 files changed

+88
-34
lines changed

fs/btrfs/extent-tree.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3340,7 +3340,8 @@ static int shrink_delalloc(struct btrfs_trans_handle *trans,
33403340
smp_mb();
33413341
nr_pages = min_t(unsigned long, nr_pages,
33423342
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);
33443345

33453346
spin_lock(&space_info->lock);
33463347
if (reserved > space_info->bytes_reserved)

fs/buffer.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,7 @@ static void free_more_memory(void)
285285
struct zone *zone;
286286
int nid;
287287

288-
wakeup_flusher_threads(1024);
288+
wakeup_flusher_threads(1024, WB_REASON_FREE_MORE_MEM);
289289
yield();
290290

291291
for_each_online_node(nid) {

fs/ext4/inode.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2241,7 +2241,7 @@ static int ext4_nonda_switch(struct super_block *sb)
22412241
* start pushing delalloc when 1/2 of free blocks are dirty.
22422242
*/
22432243
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);
22452245

22462246
return 0;
22472247
}

fs/fs-writeback.c

Lines changed: 36 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,23 @@ struct wb_writeback_work {
4141
unsigned int for_kupdate:1;
4242
unsigned int range_cyclic:1;
4343
unsigned int for_background:1;
44+
enum wb_reason reason; /* why was writeback initiated? */
4445

4546
struct list_head list; /* pending work list */
4647
struct completion *done; /* set if the caller waits */
4748
};
4849

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+
4961
/*
5062
* Include the creation of the trace points after defining the
5163
* 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,
115127

116128
static void
117129
__bdi_start_writeback(struct backing_dev_info *bdi, long nr_pages,
118-
bool range_cyclic)
130+
bool range_cyclic, enum wb_reason reason)
119131
{
120132
struct wb_writeback_work *work;
121133

@@ -135,6 +147,7 @@ __bdi_start_writeback(struct backing_dev_info *bdi, long nr_pages,
135147
work->sync_mode = WB_SYNC_NONE;
136148
work->nr_pages = nr_pages;
137149
work->range_cyclic = range_cyclic;
150+
work->reason = reason;
138151

139152
bdi_queue_work(bdi, work);
140153
}
@@ -150,9 +163,10 @@ __bdi_start_writeback(struct backing_dev_info *bdi, long nr_pages,
150163
* completion. Caller need not hold sb s_umount semaphore.
151164
*
152165
*/
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)
154168
{
155-
__bdi_start_writeback(bdi, nr_pages, true);
169+
__bdi_start_writeback(bdi, nr_pages, true, reason);
156170
}
157171

158172
/**
@@ -641,12 +655,14 @@ static long __writeback_inodes_wb(struct bdi_writeback *wb,
641655
return wrote;
642656
}
643657

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)
645660
{
646661
struct wb_writeback_work work = {
647662
.nr_pages = nr_pages,
648663
.sync_mode = WB_SYNC_NONE,
649664
.range_cyclic = 1,
665+
.reason = reason,
650666
};
651667

652668
spin_lock(&wb->list_lock);
@@ -825,6 +841,7 @@ static long wb_check_background_flush(struct bdi_writeback *wb)
825841
.sync_mode = WB_SYNC_NONE,
826842
.for_background = 1,
827843
.range_cyclic = 1,
844+
.reason = WB_REASON_BACKGROUND,
828845
};
829846

830847
return wb_writeback(wb, &work);
@@ -858,6 +875,7 @@ static long wb_check_old_data_flush(struct bdi_writeback *wb)
858875
.sync_mode = WB_SYNC_NONE,
859876
.for_kupdate = 1,
860877
.range_cyclic = 1,
878+
.reason = WB_REASON_PERIODIC,
861879
};
862880

863881
return wb_writeback(wb, &work);
@@ -976,7 +994,7 @@ int bdi_writeback_thread(void *data)
976994
* Start writeback of `nr_pages' pages. If `nr_pages' is zero, write back
977995
* the whole world.
978996
*/
979-
void wakeup_flusher_threads(long nr_pages)
997+
void wakeup_flusher_threads(long nr_pages, enum wb_reason reason)
980998
{
981999
struct backing_dev_info *bdi;
9821000

@@ -989,7 +1007,7 @@ void wakeup_flusher_threads(long nr_pages)
9891007
list_for_each_entry_rcu(bdi, &bdi_list, bdi_list) {
9901008
if (!bdi_has_dirty_io(bdi))
9911009
continue;
992-
__bdi_start_writeback(bdi, nr_pages, false);
1010+
__bdi_start_writeback(bdi, nr_pages, false, reason);
9931011
}
9941012
rcu_read_unlock();
9951013
}
@@ -1210,7 +1228,9 @@ static void wait_sb_inodes(struct super_block *sb)
12101228
* on how many (if any) will be written, and this function does not wait
12111229
* for IO completion of submitted IO.
12121230
*/
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)
12141234
{
12151235
DECLARE_COMPLETION_ONSTACK(done);
12161236
struct wb_writeback_work work = {
@@ -1219,6 +1239,7 @@ void writeback_inodes_sb_nr(struct super_block *sb, unsigned long nr)
12191239
.tagged_writepages = 1,
12201240
.done = &done,
12211241
.nr_pages = nr,
1242+
.reason = reason,
12221243
};
12231244

12241245
WARN_ON(!rwsem_is_locked(&sb->s_umount));
@@ -1235,9 +1256,9 @@ EXPORT_SYMBOL(writeback_inodes_sb_nr);
12351256
* on how many (if any) will be written, and this function does not wait
12361257
* for IO completion of submitted IO.
12371258
*/
1238-
void writeback_inodes_sb(struct super_block *sb)
1259+
void writeback_inodes_sb(struct super_block *sb, enum wb_reason reason)
12391260
{
1240-
return writeback_inodes_sb_nr(sb, get_nr_dirty_pages());
1261+
return writeback_inodes_sb_nr(sb, get_nr_dirty_pages(), reason);
12411262
}
12421263
EXPORT_SYMBOL(writeback_inodes_sb);
12431264

@@ -1248,11 +1269,11 @@ EXPORT_SYMBOL(writeback_inodes_sb);
12481269
* Invoke writeback_inodes_sb if no writeback is currently underway.
12491270
* Returns 1 if writeback was started, 0 if not.
12501271
*/
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)
12521273
{
12531274
if (!writeback_in_progress(sb->s_bdi)) {
12541275
down_read(&sb->s_umount);
1255-
writeback_inodes_sb(sb);
1276+
writeback_inodes_sb(sb, reason);
12561277
up_read(&sb->s_umount);
12571278
return 1;
12581279
} else
@@ -1269,11 +1290,12 @@ EXPORT_SYMBOL(writeback_inodes_sb_if_idle);
12691290
* Returns 1 if writeback was started, 0 if not.
12701291
*/
12711292
int writeback_inodes_sb_nr_if_idle(struct super_block *sb,
1272-
unsigned long nr)
1293+
unsigned long nr,
1294+
enum wb_reason reason)
12731295
{
12741296
if (!writeback_in_progress(sb->s_bdi)) {
12751297
down_read(&sb->s_umount);
1276-
writeback_inodes_sb_nr(sb, nr);
1298+
writeback_inodes_sb_nr(sb, nr, reason);
12771299
up_read(&sb->s_umount);
12781300
return 1;
12791301
} else
@@ -1297,6 +1319,7 @@ void sync_inodes_sb(struct super_block *sb)
12971319
.nr_pages = LONG_MAX,
12981320
.range_cyclic = 0,
12991321
.done = &done,
1322+
.reason = WB_REASON_SYNC,
13001323
};
13011324

13021325
WARN_ON(!rwsem_is_locked(&sb->s_umount));

fs/quota/quota.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,7 @@ static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id,
286286
/* caller already holds s_umount */
287287
if (sb->s_flags & MS_RDONLY)
288288
return -EROFS;
289-
writeback_inodes_sb(sb);
289+
writeback_inodes_sb(sb, WB_REASON_SYNC);
290290
return 0;
291291
default:
292292
return -EINVAL;

fs/sync.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ static int __sync_filesystem(struct super_block *sb, int wait)
4343
if (wait)
4444
sync_inodes_sb(sb);
4545
else
46-
writeback_inodes_sb(sb);
46+
writeback_inodes_sb(sb, WB_REASON_SYNC);
4747

4848
if (sb->s_op->sync_fs)
4949
sb->s_op->sync_fs(sb, wait);
@@ -98,7 +98,7 @@ static void sync_filesystems(int wait)
9898
*/
9999
SYSCALL_DEFINE0(sync)
100100
{
101-
wakeup_flusher_threads(0);
101+
wakeup_flusher_threads(0, WB_REASON_SYNC);
102102
sync_filesystems(0);
103103
sync_filesystems(1);
104104
if (unlikely(laptop_mode))

fs/ubifs/budget.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@
6363
static void shrink_liability(struct ubifs_info *c, int nr_to_write)
6464
{
6565
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);
6767
up_read(&c->vfs_sb->s_umount);
6868
}
6969

include/linux/backing-dev.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,8 @@ int bdi_register(struct backing_dev_info *bdi, struct device *parent,
118118
int bdi_register_dev(struct backing_dev_info *bdi, dev_t dev);
119119
void bdi_unregister(struct backing_dev_info *bdi);
120120
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);
122123
void bdi_start_background_writeback(struct backing_dev_info *bdi);
123124
int bdi_writeback_thread(void *data);
124125
int bdi_has_dirty_io(struct backing_dev_info *bdi);

include/linux/writeback.h

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,23 @@ enum writeback_sync_modes {
3838
WB_SYNC_ALL, /* Wait on every mapping */
3939
};
4040

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+
4158
/*
4259
* A control structure which tells the writeback code what to do. These are
4360
* always on the stack, and hence need no locking. They are always initialised
@@ -69,14 +86,17 @@ struct writeback_control {
6986
*/
7087
struct bdi_writeback;
7188
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);
7695
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);
7898
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);
80100

81101
/* writeback.h requires fs.h; it, too, is not included from here. */
82102
static inline void wait_on_inode(struct inode *inode)

include/trace/events/writeback.h

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ DECLARE_EVENT_CLASS(writeback_work_class,
3434
__field(int, for_kupdate)
3535
__field(int, range_cyclic)
3636
__field(int, for_background)
37+
__field(int, reason)
3738
),
3839
TP_fast_assign(
3940
strncpy(__entry->name, dev_name(bdi->dev), 32);
@@ -43,16 +44,18 @@ DECLARE_EVENT_CLASS(writeback_work_class,
4344
__entry->for_kupdate = work->for_kupdate;
4445
__entry->range_cyclic = work->range_cyclic;
4546
__entry->for_background = work->for_background;
47+
__entry->reason = work->reason;
4648
),
4749
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",
4951
__entry->name,
5052
MAJOR(__entry->sb_dev), MINOR(__entry->sb_dev),
5153
__entry->nr_pages,
5254
__entry->sync_mode,
5355
__entry->for_kupdate,
5456
__entry->range_cyclic,
55-
__entry->for_background
57+
__entry->for_background,
58+
wb_reason_name[__entry->reason]
5659
)
5760
);
5861
#define DEFINE_WRITEBACK_WORK_EVENT(name) \
@@ -165,6 +168,7 @@ TRACE_EVENT(writeback_queue_io,
165168
__field(unsigned long, older)
166169
__field(long, age)
167170
__field(int, moved)
171+
__field(int, reason)
168172
),
169173
TP_fast_assign(
170174
unsigned long *older_than_this = work->older_than_this;
@@ -173,12 +177,14 @@ TRACE_EVENT(writeback_queue_io,
173177
__entry->age = older_than_this ?
174178
(jiffies - *older_than_this) * 1000 / HZ : -1;
175179
__entry->moved = moved;
180+
__entry->reason = work->reason;
176181
),
177-
TP_printk("bdi %s: older=%lu age=%ld enqueue=%d",
182+
TP_printk("bdi %s: older=%lu age=%ld enqueue=%d reason=%s",
178183
__entry->name,
179184
__entry->older, /* older_than_this in jiffies */
180185
__entry->age, /* older_than_this in relative milliseconds */
181-
__entry->moved)
186+
__entry->moved,
187+
wb_reason_name[__entry->reason])
182188
);
183189

184190
TRACE_EVENT(global_dirty_state,

mm/backing-dev.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -476,7 +476,8 @@ static int bdi_forker_thread(void *ptr)
476476
* the bdi from the thread. Hopefully 1024 is
477477
* large enough for efficient IO.
478478
*/
479-
writeback_inodes_wb(&bdi->wb, 1024);
479+
writeback_inodes_wb(&bdi->wb, 1024,
480+
WB_REASON_FORKER_THREAD);
480481
} else {
481482
/*
482483
* The spinlock makes sure we do not lose

mm/page-writeback.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1301,7 +1301,8 @@ void laptop_mode_timer_fn(unsigned long data)
13011301
* threshold
13021302
*/
13031303
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);
13051306
}
13061307

13071308
/*

mm/vmscan.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2181,7 +2181,8 @@ static unsigned long do_try_to_free_pages(struct zonelist *zonelist,
21812181
*/
21822182
writeback_threshold = sc->nr_to_reclaim + sc->nr_to_reclaim / 2;
21832183
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);
21852186
sc->may_writepage = 1;
21862187
}
21872188

0 commit comments

Comments
 (0)