Skip to content

Commit 66c14dc

Browse files
jankarabrauner
authored andcommitted
writeback: Avoid softlockup when switching many inodes
process_inode_switch_wbs_work() can be switching over 100 inodes to a different cgroup. Since switching an inode requires counting all dirty & under-writeback pages in the address space of each inode, this can take a significant amount of time. Add a possibility to reschedule after processing each inode to avoid softlockups. Acked-by: Tejun Heo <tj@kernel.org> Signed-off-by: Jan Kara <jack@suse.cz> Signed-off-by: Christian Brauner <brauner@kernel.org>
1 parent e1b849c commit 66c14dc

File tree

1 file changed

+10
-1
lines changed

1 file changed

+10
-1
lines changed

fs/fs-writeback.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -500,6 +500,7 @@ static void process_inode_switch_wbs(struct bdi_writeback *new_wb,
500500
*/
501501
down_read(&bdi->wb_switch_rwsem);
502502

503+
inodep = isw->inodes;
503504
/*
504505
* By the time control reaches here, RCU grace period has passed
505506
* since I_WB_SWITCH assertion and all wb stat update transactions
@@ -510,6 +511,7 @@ static void process_inode_switch_wbs(struct bdi_writeback *new_wb,
510511
* gives us exclusion against all wb related operations on @inode
511512
* including IO list manipulations and stat updates.
512513
*/
514+
relock:
513515
if (old_wb < new_wb) {
514516
spin_lock(&old_wb->list_lock);
515517
spin_lock_nested(&new_wb->list_lock, SINGLE_DEPTH_NESTING);
@@ -518,10 +520,17 @@ static void process_inode_switch_wbs(struct bdi_writeback *new_wb,
518520
spin_lock_nested(&old_wb->list_lock, SINGLE_DEPTH_NESTING);
519521
}
520522

521-
for (inodep = isw->inodes; *inodep; inodep++) {
523+
while (*inodep) {
522524
WARN_ON_ONCE((*inodep)->i_wb != old_wb);
523525
if (inode_do_switch_wbs(*inodep, old_wb, new_wb))
524526
nr_switched++;
527+
inodep++;
528+
if (*inodep && need_resched()) {
529+
spin_unlock(&new_wb->list_lock);
530+
spin_unlock(&old_wb->list_lock);
531+
cond_resched();
532+
goto relock;
533+
}
525534
}
526535

527536
spin_unlock(&new_wb->list_lock);

0 commit comments

Comments
 (0)