Skip to content

Commit fee468f

Browse files
jankaratorvalds
authored andcommitted
writeback: reliably update bandwidth estimation
Currently we trigger writeback bandwidth estimation from balance_dirty_pages() and from wb_writeback(). However neither of these need to trigger when the system is relatively idle and writeback is triggered e.g. from fsync(2). Make sure writeback estimates happen reliably by triggering them from do_writepages(). Link: https://lkml.kernel.org/r/[email protected] Signed-off-by: Jan Kara <[email protected]> Cc: Michael Stapelberg <[email protected]> Cc: Wu Fengguang <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent 633a2ab commit fee468f

File tree

4 files changed

+46
-16
lines changed

4 files changed

+46
-16
lines changed

fs/fs-writeback.c

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2004,7 +2004,6 @@ static long writeback_inodes_wb(struct bdi_writeback *wb, long nr_pages,
20042004
static long wb_writeback(struct bdi_writeback *wb,
20052005
struct wb_writeback_work *work)
20062006
{
2007-
unsigned long wb_start = jiffies;
20082007
long nr_pages = work->nr_pages;
20092008
unsigned long dirtied_before = jiffies;
20102009
struct inode *inode;
@@ -2058,8 +2057,6 @@ static long wb_writeback(struct bdi_writeback *wb,
20582057
progress = __writeback_inodes_wb(wb, work);
20592058
trace_writeback_written(wb, work);
20602059

2061-
wb_update_bandwidth(wb, wb_start);
2062-
20632060
/*
20642061
* Did we write something? Try for more
20652062
*

include/linux/backing-dev.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,17 @@ static inline struct bdi_writeback *inode_to_wb(const struct inode *inode)
288288
return inode->i_wb;
289289
}
290290

291+
static inline struct bdi_writeback *inode_to_wb_wbc(
292+
struct inode *inode,
293+
struct writeback_control *wbc)
294+
{
295+
/*
296+
* If wbc does not have inode attached, it means cgroup writeback was
297+
* disabled when wbc started. Just use the default wb in that case.
298+
*/
299+
return wbc->wb ? wbc->wb : &inode_to_bdi(inode)->wb;
300+
}
301+
291302
/**
292303
* unlocked_inode_to_wb_begin - begin unlocked inode wb access transaction
293304
* @inode: target inode
@@ -366,6 +377,14 @@ static inline struct bdi_writeback *inode_to_wb(struct inode *inode)
366377
return &inode_to_bdi(inode)->wb;
367378
}
368379

380+
static inline struct bdi_writeback *inode_to_wb_wbc(
381+
struct inode *inode,
382+
struct writeback_control *wbc)
383+
{
384+
return inode_to_wb(inode);
385+
}
386+
387+
369388
static inline struct bdi_writeback *
370389
unlocked_inode_to_wb_begin(struct inode *inode, struct wb_lock_cookie *cookie)
371390
{

include/linux/writeback.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -379,7 +379,6 @@ int dirty_writeback_centisecs_handler(struct ctl_table *table, int write,
379379
void global_dirty_limits(unsigned long *pbackground, unsigned long *pdirty);
380380
unsigned long wb_calc_thresh(struct bdi_writeback *wb, unsigned long thresh);
381381

382-
void wb_update_bandwidth(struct bdi_writeback *wb, unsigned long start_time);
383382
void balance_dirty_pages_ratelimited(struct address_space *mapping);
384383
bool wb_over_bg_thresh(struct bdi_writeback *wb);
385384

mm/page-writeback.c

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1332,7 +1332,6 @@ static void wb_update_dirty_ratelimit(struct dirty_throttle_control *dtc,
13321332

13331333
static void __wb_update_bandwidth(struct dirty_throttle_control *gdtc,
13341334
struct dirty_throttle_control *mdtc,
1335-
unsigned long start_time,
13361335
bool update_ratelimit)
13371336
{
13381337
struct bdi_writeback *wb = gdtc->wb;
@@ -1352,13 +1351,6 @@ static void __wb_update_bandwidth(struct dirty_throttle_control *gdtc,
13521351
dirtied = percpu_counter_read(&wb->stat[WB_DIRTIED]);
13531352
written = percpu_counter_read(&wb->stat[WB_WRITTEN]);
13541353

1355-
/*
1356-
* Skip quiet periods when disk bandwidth is under-utilized.
1357-
* (at least 1s idle time between two flusher runs)
1358-
*/
1359-
if (elapsed > HZ && time_before(wb->bw_time_stamp, start_time))
1360-
goto snapshot;
1361-
13621354
if (update_ratelimit) {
13631355
domain_update_bandwidth(gdtc, now);
13641356
wb_update_dirty_ratelimit(gdtc, dirtied, elapsed);
@@ -1374,17 +1366,36 @@ static void __wb_update_bandwidth(struct dirty_throttle_control *gdtc,
13741366
}
13751367
wb_update_write_bandwidth(wb, elapsed, written);
13761368

1377-
snapshot:
13781369
wb->dirtied_stamp = dirtied;
13791370
wb->written_stamp = written;
13801371
wb->bw_time_stamp = now;
13811372
}
13821373

1383-
void wb_update_bandwidth(struct bdi_writeback *wb, unsigned long start_time)
1374+
static void wb_update_bandwidth(struct bdi_writeback *wb)
13841375
{
13851376
struct dirty_throttle_control gdtc = { GDTC_INIT(wb) };
13861377

1387-
__wb_update_bandwidth(&gdtc, NULL, start_time, false);
1378+
spin_lock(&wb->list_lock);
1379+
__wb_update_bandwidth(&gdtc, NULL, false);
1380+
spin_unlock(&wb->list_lock);
1381+
}
1382+
1383+
/* Interval after which we consider wb idle and don't estimate bandwidth */
1384+
#define WB_BANDWIDTH_IDLE_JIF (HZ)
1385+
1386+
static void wb_bandwidth_estimate_start(struct bdi_writeback *wb)
1387+
{
1388+
unsigned long now = jiffies;
1389+
unsigned long elapsed = now - READ_ONCE(wb->bw_time_stamp);
1390+
1391+
if (elapsed > WB_BANDWIDTH_IDLE_JIF &&
1392+
!atomic_read(&wb->writeback_inodes)) {
1393+
spin_lock(&wb->list_lock);
1394+
wb->dirtied_stamp = wb_stat(wb, WB_DIRTIED);
1395+
wb->written_stamp = wb_stat(wb, WB_WRITTEN);
1396+
wb->bw_time_stamp = now;
1397+
spin_unlock(&wb->list_lock);
1398+
}
13881399
}
13891400

13901401
/*
@@ -1713,7 +1724,7 @@ static void balance_dirty_pages(struct bdi_writeback *wb,
17131724
if (time_is_before_jiffies(wb->bw_time_stamp +
17141725
BANDWIDTH_INTERVAL)) {
17151726
spin_lock(&wb->list_lock);
1716-
__wb_update_bandwidth(gdtc, mdtc, start_time, true);
1727+
__wb_update_bandwidth(gdtc, mdtc, true);
17171728
spin_unlock(&wb->list_lock);
17181729
}
17191730

@@ -2347,9 +2358,12 @@ EXPORT_SYMBOL(generic_writepages);
23472358
int do_writepages(struct address_space *mapping, struct writeback_control *wbc)
23482359
{
23492360
int ret;
2361+
struct bdi_writeback *wb;
23502362

23512363
if (wbc->nr_to_write <= 0)
23522364
return 0;
2365+
wb = inode_to_wb_wbc(mapping->host, wbc);
2366+
wb_bandwidth_estimate_start(wb);
23532367
while (1) {
23542368
if (mapping->a_ops->writepages)
23552369
ret = mapping->a_ops->writepages(mapping, wbc);
@@ -2360,6 +2374,7 @@ int do_writepages(struct address_space *mapping, struct writeback_control *wbc)
23602374
cond_resched();
23612375
congestion_wait(BLK_RW_ASYNC, HZ/50);
23622376
}
2377+
wb_update_bandwidth(wb);
23632378
return ret;
23642379
}
23652380

0 commit comments

Comments
 (0)