Skip to content

Commit 9d87ea1

Browse files
author
Andreas Gruenbacher
committed
gfs2: deallocate inodes in gfs2_create_inode
JIRA: https://issues.redhat.com/browse/RHEL-88093 Upstream Status: https://git.kernel.org/pub/scm/linux/kernel/git/gfs2/linux-gfs2.git When creating and destroying inodes, we are relying on the inode hash table to make sure that for a given inode number, only a single inode will exist. We then link that inode to its inode and iopen glock and let those glocks point back at the inode. However, when iget_failed() is called, the inode is removed from the inode hash table before gfs_evict_inode() is called, and uniqueness is no longer guaranteed. Commit f1046a472b70 ("gfs2: gl_object races fix") was trying to work around that problem by detaching the inode glock from the inode before calling iget_failed(), but that broke the inode deallocation code in gfs_evict_inode(). To fix that, deallocate partially created inodes in gfs2_create_inode() instead of relying on gfs_evict_inode() for doing that. This means that gfs2_evict_inode() and its helper functions will no longer see partially created inodes, and so some simplifications are possible there. Fixes: 9ffa188 ("gfs2: gl_object races fix") Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com> (cherry picked from commit 2c63986)
1 parent 647e72f commit 9d87ea1

File tree

2 files changed

+20
-13
lines changed

2 files changed

+20
-13
lines changed

fs/gfs2/inode.c

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -689,10 +689,11 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
689689
struct gfs2_inode *dip = GFS2_I(dir), *ip;
690690
struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
691691
struct gfs2_glock *io_gl;
692-
int error;
692+
int error, dealloc_error;
693693
u32 aflags = 0;
694694
unsigned blocks = 1;
695695
struct gfs2_diradd da = { .bh = NULL, .save_loc = 1, };
696+
bool xattr_initialized = false;
696697

697698
if (!name->len || name->len > GFS2_FNAMESIZE)
698699
return -ENAMETOOLONG;
@@ -805,11 +806,11 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
805806

806807
error = gfs2_glock_get(sdp, ip->i_no_addr, &gfs2_inode_glops, CREATE, &ip->i_gl);
807808
if (error)
808-
goto fail_free_inode;
809+
goto fail_dealloc_inode;
809810

810811
error = gfs2_glock_get(sdp, ip->i_no_addr, &gfs2_iopen_glops, CREATE, &io_gl);
811812
if (error)
812-
goto fail_free_inode;
813+
goto fail_dealloc_inode;
813814
gfs2_cancel_delete_work(io_gl);
814815
io_gl->gl_no_formal_ino = ip->i_no_formal_ino;
815816

@@ -834,8 +835,10 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
834835
if (error)
835836
goto fail_gunlock3;
836837

837-
if (blocks > 1)
838+
if (blocks > 1) {
838839
gfs2_init_xattr(ip);
840+
xattr_initialized = true;
841+
}
839842
init_dinode(dip, ip, symname);
840843
gfs2_trans_end(sdp);
841844

@@ -890,6 +893,18 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
890893
gfs2_glock_dq_uninit(&ip->i_iopen_gh);
891894
fail_gunlock2:
892895
gfs2_glock_put(io_gl);
896+
fail_dealloc_inode:
897+
set_bit(GIF_ALLOC_FAILED, &ip->i_flags);
898+
dealloc_error = 0;
899+
if (ip->i_eattr)
900+
dealloc_error = gfs2_ea_dealloc(ip, xattr_initialized);
901+
clear_nlink(inode);
902+
mark_inode_dirty(inode);
903+
if (!dealloc_error)
904+
dealloc_error = gfs2_dinode_dealloc(ip);
905+
if (dealloc_error)
906+
fs_warn(sdp, "%s: %d\n", __func__, dealloc_error);
907+
ip->i_no_addr = 0;
893908
fail_free_inode:
894909
if (ip->i_gl) {
895910
gfs2_glock_put(ip->i_gl);
@@ -904,10 +919,6 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
904919
gfs2_dir_no_add(&da);
905920
gfs2_glock_dq_uninit(&d_gh);
906921
if (!IS_ERR_OR_NULL(inode)) {
907-
set_bit(GIF_ALLOC_FAILED, &ip->i_flags);
908-
clear_nlink(inode);
909-
if (ip->i_no_addr)
910-
mark_inode_dirty(inode);
911922
if (inode->i_state & I_NEW)
912923
iget_failed(inode);
913924
else

fs/gfs2/super.c

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1272,9 +1272,6 @@ static enum evict_behavior evict_should_delete(struct inode *inode,
12721272
struct gfs2_sbd *sdp = sb->s_fs_info;
12731273
int ret;
12741274

1275-
if (unlikely(test_bit(GIF_ALLOC_FAILED, &ip->i_flags)))
1276-
goto should_delete;
1277-
12781275
if (gfs2_holder_initialized(&ip->i_iopen_gh) &&
12791276
test_bit(GLF_DEFER_DELETE, &ip->i_iopen_gh.gh_gl->gl_flags))
12801277
return EVICT_SHOULD_DEFER_DELETE;
@@ -1306,7 +1303,6 @@ static enum evict_behavior evict_should_delete(struct inode *inode,
13061303
if (inode->i_nlink)
13071304
return EVICT_SHOULD_SKIP_DELETE;
13081305

1309-
should_delete:
13101306
if (gfs2_holder_initialized(&ip->i_iopen_gh) &&
13111307
test_bit(HIF_HOLDER, &ip->i_iopen_gh.gh_iflags))
13121308
return gfs2_upgrade_iopen_glock(inode);
@@ -1330,7 +1326,7 @@ static int evict_unlinked_inode(struct inode *inode)
13301326
}
13311327

13321328
if (ip->i_eattr) {
1333-
ret = gfs2_ea_dealloc(ip, !test_bit(GIF_ALLOC_FAILED, &ip->i_flags));
1329+
ret = gfs2_ea_dealloc(ip, true);
13341330
if (ret)
13351331
goto out;
13361332
}

0 commit comments

Comments
 (0)