gfs2: Fix deadlock between gfs2_{create_inode,inode_lookup} and delete_work_func
In gfs2_create_inode and gfs2_inode_lookup, make sure to cancel any pending
delete work before taking the inode glock. Otherwise, gfs2_cancel_delete_work
may block waiting for delete_work_func to complete, and delete_work_func may
block trying to acquire the inode glock in gfs2_inode_lookup.
Reported-by: Alexander Aring <aahringo@redhat.com>
Fixes: a0e3cc65fa
("gfs2: Turn gl_delete into a delayed work")
Cc: stable@vger.kernel.org # v5.8+
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
This commit is contained in:
parent
82e938bd53
commit
dd0ecf5441
|
@ -150,6 +150,8 @@ struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned int type,
|
|||
error = gfs2_glock_get(sdp, no_addr, &gfs2_iopen_glops, CREATE, &io_gl);
|
||||
if (unlikely(error))
|
||||
goto fail;
|
||||
if (blktype != GFS2_BLKST_UNLINKED)
|
||||
gfs2_cancel_delete_work(io_gl);
|
||||
|
||||
if (type == DT_UNKNOWN || blktype != GFS2_BLKST_FREE) {
|
||||
/*
|
||||
|
@ -180,8 +182,6 @@ struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned int type,
|
|||
error = gfs2_glock_nq_init(io_gl, LM_ST_SHARED, GL_EXACT, &ip->i_iopen_gh);
|
||||
if (unlikely(error))
|
||||
goto fail;
|
||||
if (blktype != GFS2_BLKST_UNLINKED)
|
||||
gfs2_cancel_delete_work(ip->i_iopen_gh.gh_gl);
|
||||
glock_set_object(ip->i_iopen_gh.gh_gl, ip);
|
||||
gfs2_glock_put(io_gl);
|
||||
io_gl = NULL;
|
||||
|
@ -725,13 +725,19 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
|
|||
flush_delayed_work(&ip->i_gl->gl_work);
|
||||
glock_set_object(ip->i_gl, ip);
|
||||
|
||||
error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, GL_SKIP, ghs + 1);
|
||||
error = gfs2_glock_get(sdp, ip->i_no_addr, &gfs2_iopen_glops, CREATE, &io_gl);
|
||||
if (error)
|
||||
goto fail_free_inode;
|
||||
gfs2_cancel_delete_work(io_gl);
|
||||
glock_set_object(io_gl, ip);
|
||||
|
||||
error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, GL_SKIP, ghs + 1);
|
||||
if (error)
|
||||
goto fail_gunlock2;
|
||||
|
||||
error = gfs2_trans_begin(sdp, blocks, 0);
|
||||
if (error)
|
||||
goto fail_free_inode;
|
||||
goto fail_gunlock2;
|
||||
|
||||
if (blocks > 1) {
|
||||
ip->i_eattr = ip->i_no_addr + 1;
|
||||
|
@ -740,18 +746,12 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
|
|||
init_dinode(dip, ip, symname);
|
||||
gfs2_trans_end(sdp);
|
||||
|
||||
error = gfs2_glock_get(sdp, ip->i_no_addr, &gfs2_iopen_glops, CREATE, &io_gl);
|
||||
if (error)
|
||||
goto fail_free_inode;
|
||||
|
||||
BUG_ON(test_and_set_bit(GLF_INODE_CREATING, &io_gl->gl_flags));
|
||||
|
||||
error = gfs2_glock_nq_init(io_gl, LM_ST_SHARED, GL_EXACT, &ip->i_iopen_gh);
|
||||
if (error)
|
||||
goto fail_gunlock2;
|
||||
|
||||
gfs2_cancel_delete_work(ip->i_iopen_gh.gh_gl);
|
||||
glock_set_object(ip->i_iopen_gh.gh_gl, ip);
|
||||
gfs2_set_iop(inode);
|
||||
insert_inode_hash(inode);
|
||||
|
||||
|
@ -803,6 +803,7 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
|
|||
gfs2_glock_dq_uninit(&ip->i_iopen_gh);
|
||||
fail_gunlock2:
|
||||
clear_bit(GLF_INODE_CREATING, &io_gl->gl_flags);
|
||||
glock_clear_object(io_gl, ip);
|
||||
gfs2_glock_put(io_gl);
|
||||
fail_free_inode:
|
||||
if (ip->i_gl) {
|
||||
|
|
Loading…
Reference in New Issue
Block a user