summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2019-08-02 15:08:13 -0400
committerJens Axboe <axboe@kernel.dk>2019-08-15 15:30:46 -0400
commit6444f47eb8678a43d5260c67b89c18b1ea09e79e (patch)
tree8ad4e7d6831c77414208f33e5dfeb729ab5dcc4c
parent55a694dffb7fd126b1e047aa46c437731d2700bb (diff)
writeback, cgroup: inode_switch_wbs() shouldn't give up on wb_switch_rwsem trylock fail
As inode wb switching may make sync(2) miss some inodes, they're synchronized using wb_switch_rwsem so that no wb switching happens while sync(2) is in progress. In addition to synchronizing the actual switching, the rwsem is also used to prevent queueing new switch attempts while sync(2) is in progress. This is to avoid queueing too many instances while the rwsem is held by sync(2). Unfortunately, this is too agressive and can block wb switching for a long time if sync(2) is frequent. The goal is avoiding expolding the number of scheduled switches, not avoiding scheduling anything. Let's use wb_switch_rwsem only for synchronizing the actual switching and sync(2) and use isw_nr_in_flight instead for limiting the maximum number of scheduled switches. The limit is set to 1024 which should be more than enough while still avoiding extreme situations. Reviewed-by: Jan Kara <jack@suse.cz> Signed-off-by: Tejun Heo <tj@kernel.org> Signed-off-by: Jens Axboe <axboe@kernel.dk>
-rw-r--r--fs/fs-writeback.c17
1 files changed, 5 insertions, 12 deletions
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
index 025a63894cf0..fddd8abd839a 100644
--- a/fs/fs-writeback.c
+++ b/fs/fs-writeback.c
@@ -255,6 +255,7 @@ static void wb_wait_for_completion(struct backing_dev_info *bdi,
255 /* if foreign slots >= 8, switch */ 255 /* if foreign slots >= 8, switch */
256#define WB_FRN_HIST_MAX_SLOTS (WB_FRN_HIST_THR_SLOTS / 2 + 1) 256#define WB_FRN_HIST_MAX_SLOTS (WB_FRN_HIST_THR_SLOTS / 2 + 1)
257 /* one round can affect upto 5 slots */ 257 /* one round can affect upto 5 slots */
258#define WB_FRN_MAX_IN_FLIGHT 1024 /* don't queue too many concurrently */
258 259
259static atomic_t isw_nr_in_flight = ATOMIC_INIT(0); 260static atomic_t isw_nr_in_flight = ATOMIC_INIT(0);
260static struct workqueue_struct *isw_wq; 261static struct workqueue_struct *isw_wq;
@@ -507,18 +508,13 @@ static void inode_switch_wbs(struct inode *inode, int new_wb_id)
507 if (inode->i_state & I_WB_SWITCH) 508 if (inode->i_state & I_WB_SWITCH)
508 return; 509 return;
509 510
510 /* 511 /* avoid queueing a new switch if too many are already in flight */
511 * Avoid starting new switches while sync_inodes_sb() is in 512 if (atomic_read(&isw_nr_in_flight) > WB_FRN_MAX_IN_FLIGHT)
512 * progress. Otherwise, if the down_write protected issue path
513 * blocks heavily, we might end up starting a large number of
514 * switches which will block on the rwsem.
515 */
516 if (!down_read_trylock(&bdi->wb_switch_rwsem))
517 return; 513 return;
518 514
519 isw = kzalloc(sizeof(*isw), GFP_ATOMIC); 515 isw = kzalloc(sizeof(*isw), GFP_ATOMIC);
520 if (!isw) 516 if (!isw)
521 goto out_unlock; 517 return;
522 518
523 /* find and pin the new wb */ 519 /* find and pin the new wb */
524 rcu_read_lock(); 520 rcu_read_lock();
@@ -552,15 +548,12 @@ static void inode_switch_wbs(struct inode *inode, int new_wb_id)
552 call_rcu(&isw->rcu_head, inode_switch_wbs_rcu_fn); 548 call_rcu(&isw->rcu_head, inode_switch_wbs_rcu_fn);
553 549
554 atomic_inc(&isw_nr_in_flight); 550 atomic_inc(&isw_nr_in_flight);
555 551 return;
556 goto out_unlock;
557 552
558out_free: 553out_free:
559 if (isw->new_wb) 554 if (isw->new_wb)
560 wb_put(isw->new_wb); 555 wb_put(isw->new_wb);
561 kfree(isw); 556 kfree(isw);
562out_unlock:
563 up_read(&bdi->wb_switch_rwsem);
564} 557}
565 558
566/** 559/**