Skip to content

Commit 3d36e57

Browse files
author
Andreas Gruenbacher
committed
gfs2: gfs2_create_inode rework
When gfs2_lookup_by_inum() calls gfs2_inode_lookup() for an uncached inode, gfs2_inode_lookup() will place a new tentative inode into the inode cache before verifying that there is a valid inode at the given address. This can race with gfs2_create_inode() which doesn't check for duplicates inodes. gfs2_create_inode() will try to assign the new inode to the corresponding inode glock, and glock_set_object() will complain that the glock is still in use by gfs2_inode_lookup's tentative inode. We noticed this bug after adding commit 486408d ("gfs2: Cancel remote delete work asynchronously") which allowed delete_work_func() to race with gfs2_create_inode(), but the same race exists for open-by-handle. Fix that by switching from insert_inode_hash() to insert_inode_locked4(), which does check for duplicate inodes. We know we've just managed to to allocate the new inode, so an inode tentatively created by gfs2_inode_lookup() will eventually go away and insert_inode_locked4() will always succeed. In addition, don't flush the inode glock work anymore (this can now only make things worse) and clean up glock_{set,clear}_object for the inode glock somewhat. Signed-off-by: Andreas Gruenbacher <[email protected]>
1 parent 5f6e13b commit 3d36e57

File tree

1 file changed

+10
-6
lines changed

1 file changed

+10
-6
lines changed

fs/gfs2/inode.c

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -707,18 +707,19 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
707707
error = gfs2_glock_get(sdp, ip->i_no_addr, &gfs2_inode_glops, CREATE, &ip->i_gl);
708708
if (error)
709709
goto fail_free_inode;
710-
flush_delayed_work(&ip->i_gl->gl_work);
711710

712711
error = gfs2_glock_get(sdp, ip->i_no_addr, &gfs2_iopen_glops, CREATE, &io_gl);
713712
if (error)
714713
goto fail_free_inode;
715714
gfs2_cancel_delete_work(io_gl);
716715

716+
error = insert_inode_locked4(inode, ip->i_no_addr, iget_test, &ip->i_no_addr);
717+
BUG_ON(error);
718+
717719
error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, GL_SKIP, ghs + 1);
718720
if (error)
719721
goto fail_gunlock2;
720722

721-
glock_set_object(ip->i_gl, ip);
722723
error = gfs2_trans_begin(sdp, blocks, 0);
723724
if (error)
724725
goto fail_gunlock2;
@@ -734,9 +735,9 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
734735
if (error)
735736
goto fail_gunlock2;
736737

738+
glock_set_object(ip->i_gl, ip);
737739
glock_set_object(io_gl, ip);
738740
gfs2_set_iop(inode);
739-
insert_inode_hash(inode);
740741

741742
free_vfs_inode = 0; /* After this point, the inode is no longer
742743
considered free. Any failures need to undo
@@ -778,17 +779,17 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
778779
gfs2_glock_dq_uninit(ghs + 1);
779780
gfs2_glock_put(io_gl);
780781
gfs2_qa_put(dip);
782+
unlock_new_inode(inode);
781783
return error;
782784

783785
fail_gunlock3:
786+
glock_clear_object(ip->i_gl, ip);
784787
glock_clear_object(io_gl, ip);
785788
gfs2_glock_dq_uninit(&ip->i_iopen_gh);
786789
fail_gunlock2:
787-
glock_clear_object(io_gl, ip);
788790
gfs2_glock_put(io_gl);
789791
fail_free_inode:
790792
if (ip->i_gl) {
791-
glock_clear_object(ip->i_gl, ip);
792793
if (free_vfs_inode) /* else evict will do the put for us */
793794
gfs2_glock_put(ip->i_gl);
794795
}
@@ -806,7 +807,10 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
806807
mark_inode_dirty(inode);
807808
set_bit(free_vfs_inode ? GIF_FREE_VFS_INODE : GIF_ALLOC_FAILED,
808809
&GFS2_I(inode)->i_flags);
809-
iput(inode);
810+
if (inode->i_state & I_NEW)
811+
iget_failed(inode);
812+
else
813+
iput(inode);
810814
}
811815
if (gfs2_holder_initialized(ghs + 1))
812816
gfs2_glock_dq_uninit(ghs + 1);

0 commit comments

Comments
 (0)