Skip to content

Commit ec084de

Browse files
Jiufei Xuetorvalds
authored andcommitted
fs/writeback.c: use rcu_barrier() to wait for inflight wb switches going into workqueue when umount
synchronize_rcu() didn't wait for call_rcu() callbacks, so inode wb switch may not go to the workqueue after synchronize_rcu(). Thus previous scheduled switches was not finished even flushing the workqueue, which will cause a NULL pointer dereferenced followed below. VFS: Busy inodes after unmount of vdd. Self-destruct in 5 seconds. Have a nice day... BUG: unable to handle kernel NULL pointer dereference at 0000000000000278 evict+0xb3/0x180 iput+0x1b0/0x230 inode_switch_wbs_work_fn+0x3c0/0x6a0 worker_thread+0x4e/0x490 ? process_one_work+0x410/0x410 kthread+0xe6/0x100 ret_from_fork+0x39/0x50 Replace the synchronize_rcu() call with a rcu_barrier() to wait for all pending callbacks to finish. And inc isw_nr_in_flight after call_rcu() in inode_switch_wbs() to make more sense. Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Jiufei Xue <[email protected]> Acked-by: Tejun Heo <[email protected]> Suggested-by: Tejun Heo <[email protected]> Cc: <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent 60fce36 commit ec084de

File tree

1 file changed

+8
-3
lines changed

1 file changed

+8
-3
lines changed

fs/fs-writeback.c

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -523,15 +523,16 @@ static void inode_switch_wbs(struct inode *inode, int new_wb_id)
523523

524524
isw->inode = inode;
525525

526-
atomic_inc(&isw_nr_in_flight);
527-
528526
/*
529527
* In addition to synchronizing among switchers, I_WB_SWITCH tells
530528
* the RCU protected stat update paths to grab the i_page
531529
* lock so that stat transfer can synchronize against them.
532530
* Let's continue after I_WB_SWITCH is guaranteed to be visible.
533531
*/
534532
call_rcu(&isw->rcu_head, inode_switch_wbs_rcu_fn);
533+
534+
atomic_inc(&isw_nr_in_flight);
535+
535536
goto out_unlock;
536537

537538
out_free:
@@ -901,7 +902,11 @@ static void bdi_split_work_to_wbs(struct backing_dev_info *bdi,
901902
void cgroup_writeback_umount(void)
902903
{
903904
if (atomic_read(&isw_nr_in_flight)) {
904-
synchronize_rcu();
905+
/*
906+
* Use rcu_barrier() to wait for all pending callbacks to
907+
* ensure that all in-flight wb switches are in the workqueue.
908+
*/
909+
rcu_barrier();
905910
flush_workqueue(isw_wq);
906911
}
907912
}

0 commit comments

Comments
 (0)