Commit 6444f47e authored by Tejun Heo's avatar Tejun Heo Committed by Jens Axboe

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: default avatarJan Kara <jack@suse.cz>
Signed-off-by: default avatarTejun Heo <tj@kernel.org>
Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
parent 55a694df
...@@ -255,6 +255,7 @@ static void wb_wait_for_completion(struct backing_dev_info *bdi, ...@@ -255,6 +255,7 @@ static void wb_wait_for_completion(struct backing_dev_info *bdi,
/* if foreign slots >= 8, switch */ /* if foreign slots >= 8, switch */
#define WB_FRN_HIST_MAX_SLOTS (WB_FRN_HIST_THR_SLOTS / 2 + 1) #define WB_FRN_HIST_MAX_SLOTS (WB_FRN_HIST_THR_SLOTS / 2 + 1)
/* one round can affect upto 5 slots */ /* one round can affect upto 5 slots */
#define WB_FRN_MAX_IN_FLIGHT 1024 /* don't queue too many concurrently */
static atomic_t isw_nr_in_flight = ATOMIC_INIT(0); static atomic_t isw_nr_in_flight = ATOMIC_INIT(0);
static struct workqueue_struct *isw_wq; static struct workqueue_struct *isw_wq;
...@@ -507,18 +508,13 @@ static void inode_switch_wbs(struct inode *inode, int new_wb_id) ...@@ -507,18 +508,13 @@ static void inode_switch_wbs(struct inode *inode, int new_wb_id)
if (inode->i_state & I_WB_SWITCH) if (inode->i_state & I_WB_SWITCH)
return; return;
/* /* avoid queueing a new switch if too many are already in flight */
* Avoid starting new switches while sync_inodes_sb() is in if (atomic_read(&isw_nr_in_flight) > WB_FRN_MAX_IN_FLIGHT)
* progress. Otherwise, if the down_write protected issue path
* blocks heavily, we might end up starting a large number of
* switches which will block on the rwsem.
*/
if (!down_read_trylock(&bdi->wb_switch_rwsem))
return; return;
isw = kzalloc(sizeof(*isw), GFP_ATOMIC); isw = kzalloc(sizeof(*isw), GFP_ATOMIC);
if (!isw) if (!isw)
goto out_unlock; return;
/* find and pin the new wb */ /* find and pin the new wb */
rcu_read_lock(); rcu_read_lock();
...@@ -552,15 +548,12 @@ static void inode_switch_wbs(struct inode *inode, int new_wb_id) ...@@ -552,15 +548,12 @@ static void inode_switch_wbs(struct inode *inode, int new_wb_id)
call_rcu(&isw->rcu_head, inode_switch_wbs_rcu_fn); call_rcu(&isw->rcu_head, inode_switch_wbs_rcu_fn);
atomic_inc(&isw_nr_in_flight); atomic_inc(&isw_nr_in_flight);
return;
goto out_unlock;
out_free: out_free:
if (isw->new_wb) if (isw->new_wb)
wb_put(isw->new_wb); wb_put(isw->new_wb);
kfree(isw); kfree(isw);
out_unlock:
up_read(&bdi->wb_switch_rwsem);
} }
/** /**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment