ceph: fix iput race when queueing inode work
If we queue a work item that calls iput(), make sure we ihold() before attempting to queue work. Otherwise our queued work might miraculously run before we notice the queue_work() succeeded and call ihold(), allowing the inode to be destroyed. That is, instead of if (queue_work(...)) ihold(); we need to do ihold(); if (!queue_work(...)) iput(); Reported-by: Amon Ott <a.ott@m-privacy.de> Signed-off-by: Sage Weil <sage@newdream.net>
This commit is contained in:
		
							parent
							
								
									0c6d4b4e22
								
							
						
					
					
						commit
						15a2015fbc
					
				| @ -1328,12 +1328,13 @@ int ceph_inode_set_size(struct inode *inode, loff_t size) | ||||
|  */ | ||||
| void ceph_queue_writeback(struct inode *inode) | ||||
| { | ||||
| 	ihold(inode); | ||||
| 	if (queue_work(ceph_inode_to_client(inode)->wb_wq, | ||||
| 		       &ceph_inode(inode)->i_wb_work)) { | ||||
| 		dout("ceph_queue_writeback %p\n", inode); | ||||
| 		ihold(inode); | ||||
| 	} else { | ||||
| 		dout("ceph_queue_writeback %p failed\n", inode); | ||||
| 		iput(inode); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| @ -1353,12 +1354,13 @@ static void ceph_writeback_work(struct work_struct *work) | ||||
|  */ | ||||
| void ceph_queue_invalidate(struct inode *inode) | ||||
| { | ||||
| 	ihold(inode); | ||||
| 	if (queue_work(ceph_inode_to_client(inode)->pg_inv_wq, | ||||
| 		       &ceph_inode(inode)->i_pg_inv_work)) { | ||||
| 		dout("ceph_queue_invalidate %p\n", inode); | ||||
| 		ihold(inode); | ||||
| 	} else { | ||||
| 		dout("ceph_queue_invalidate %p failed\n", inode); | ||||
| 		iput(inode); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| @ -1434,13 +1436,14 @@ void ceph_queue_vmtruncate(struct inode *inode) | ||||
| { | ||||
| 	struct ceph_inode_info *ci = ceph_inode(inode); | ||||
| 
 | ||||
| 	ihold(inode); | ||||
| 	if (queue_work(ceph_sb_to_client(inode->i_sb)->trunc_wq, | ||||
| 		       &ci->i_vmtruncate_work)) { | ||||
| 		dout("ceph_queue_vmtruncate %p\n", inode); | ||||
| 		ihold(inode); | ||||
| 	} else { | ||||
| 		dout("ceph_queue_vmtruncate %p failed, pending=%d\n", | ||||
| 		     inode, ci->i_truncate_pending); | ||||
| 		iput(inode); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user