mirror of
				git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
				synced 2025-10-31 16:54:21 +00:00 
			
		
		
		
	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/20190429024108.54150-1-jiufei.xue@linux.alibaba.com
Signed-off-by: Jiufei Xue <jiufei.xue@linux.alibaba.com>
Acked-by: Tejun Heo <tj@kernel.org>
Suggested-by: Tejun Heo <tj@kernel.org>
Cc: <stable@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
			
			
This commit is contained in:
		
							parent
							
								
									60fce36afa
								
							
						
					
					
						commit
						ec084de929
					
				
					 1 changed files with 8 additions and 3 deletions
				
			
		|  | @ -523,8 +523,6 @@ static void inode_switch_wbs(struct inode *inode, int new_wb_id) | |||
| 
 | ||||
| 	isw->inode = inode; | ||||
| 
 | ||||
| 	atomic_inc(&isw_nr_in_flight); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * In addition to synchronizing among switchers, I_WB_SWITCH tells | ||||
| 	 * the RCU protected stat update paths to grab the i_page | ||||
|  | @ -532,6 +530,9 @@ static void inode_switch_wbs(struct inode *inode, int new_wb_id) | |||
| 	 * Let's continue after I_WB_SWITCH is guaranteed to be visible. | ||||
| 	 */ | ||||
| 	call_rcu(&isw->rcu_head, inode_switch_wbs_rcu_fn); | ||||
| 
 | ||||
| 	atomic_inc(&isw_nr_in_flight); | ||||
| 
 | ||||
| 	goto out_unlock; | ||||
| 
 | ||||
| out_free: | ||||
|  | @ -901,7 +902,11 @@ restart: | |||
| void cgroup_writeback_umount(void) | ||||
| { | ||||
| 	if (atomic_read(&isw_nr_in_flight)) { | ||||
| 		synchronize_rcu(); | ||||
| 		/*
 | ||||
| 		 * Use rcu_barrier() to wait for all pending callbacks to | ||||
| 		 * ensure that all in-flight wb switches are in the workqueue. | ||||
| 		 */ | ||||
| 		rcu_barrier(); | ||||
| 		flush_workqueue(isw_wq); | ||||
| 	} | ||||
| } | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 Jiufei Xue
						Jiufei Xue