Commit 15a2015f authored by Sage Weil's avatar Sage Weil

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: default avatarAmon Ott <a.ott@m-privacy.de>
Signed-off-by: default avatarSage Weil <sage@newdream.net>
parent 0c6d4b4e
...@@ -1328,12 +1328,13 @@ int ceph_inode_set_size(struct inode *inode, loff_t size) ...@@ -1328,12 +1328,13 @@ int ceph_inode_set_size(struct inode *inode, loff_t size)
*/ */
void ceph_queue_writeback(struct inode *inode) void ceph_queue_writeback(struct inode *inode)
{ {
ihold(inode);
if (queue_work(ceph_inode_to_client(inode)->wb_wq, if (queue_work(ceph_inode_to_client(inode)->wb_wq,
&ceph_inode(inode)->i_wb_work)) { &ceph_inode(inode)->i_wb_work)) {
dout("ceph_queue_writeback %p\n", inode); dout("ceph_queue_writeback %p\n", inode);
ihold(inode);
} else { } else {
dout("ceph_queue_writeback %p failed\n", inode); dout("ceph_queue_writeback %p failed\n", inode);
iput(inode);
} }
} }
...@@ -1353,12 +1354,13 @@ static void ceph_writeback_work(struct work_struct *work) ...@@ -1353,12 +1354,13 @@ static void ceph_writeback_work(struct work_struct *work)
*/ */
void ceph_queue_invalidate(struct inode *inode) void ceph_queue_invalidate(struct inode *inode)
{ {
ihold(inode);
if (queue_work(ceph_inode_to_client(inode)->pg_inv_wq, if (queue_work(ceph_inode_to_client(inode)->pg_inv_wq,
&ceph_inode(inode)->i_pg_inv_work)) { &ceph_inode(inode)->i_pg_inv_work)) {
dout("ceph_queue_invalidate %p\n", inode); dout("ceph_queue_invalidate %p\n", inode);
ihold(inode);
} else { } else {
dout("ceph_queue_invalidate %p failed\n", inode); dout("ceph_queue_invalidate %p failed\n", inode);
iput(inode);
} }
} }
...@@ -1434,13 +1436,14 @@ void ceph_queue_vmtruncate(struct inode *inode) ...@@ -1434,13 +1436,14 @@ void ceph_queue_vmtruncate(struct inode *inode)
{ {
struct ceph_inode_info *ci = ceph_inode(inode); struct ceph_inode_info *ci = ceph_inode(inode);
ihold(inode);
if (queue_work(ceph_sb_to_client(inode->i_sb)->trunc_wq, if (queue_work(ceph_sb_to_client(inode->i_sb)->trunc_wq,
&ci->i_vmtruncate_work)) { &ci->i_vmtruncate_work)) {
dout("ceph_queue_vmtruncate %p\n", inode); dout("ceph_queue_vmtruncate %p\n", inode);
ihold(inode);
} else { } else {
dout("ceph_queue_vmtruncate %p failed, pending=%d\n", dout("ceph_queue_vmtruncate %p failed, pending=%d\n",
inode, ci->i_truncate_pending); inode, ci->i_truncate_pending);
iput(inode);
} }
} }
......
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