summaryrefslogtreecommitdiff
path: root/fs/gfs2/inode.c
diff options
context:
space:
mode:
authorAndreas Gruenbacher <agruenba@redhat.com>2023-01-23 20:58:27 +0300
committerAndreas Gruenbacher <agruenba@redhat.com>2023-01-27 17:55:48 +0300
commit9ffa18884cceb2e5731e422140fad06292de0577 (patch)
tree46a9312352bb91d1f8f6d41da5be6e7b456f2057 /fs/gfs2/inode.c
parent63510d9f2f6e6337960499a3d72d5a457b19c287 (diff)
downloadlinux-9ffa18884cceb2e5731e422140fad06292de0577.tar.xz
gfs2: gl_object races fix
Function glock_clear_object() checks if the specified glock is still pointing at the right object and clears the gl_object pointer. To handle the case of incompletely constructed inodes, glock_clear_object() also allows gl_object to be NULL. However, in the teardown case, when iget_failed() is called and the inode is removed from the inode hash, by the time we get to the glock_clear_object() calls in gfs2_put_super() and its helpers, we don't have exclusion against concurrent gfs2_inode_lookup() and gfs2_create_inode() calls, and the inode and iopen glocks may already be pointing at another inode, so the checks in glock_clear_object() are incorrect. To better handle this case, always completely disassociate an inode from its glocks before tearing it down. In addition, get rid of a duplicate glock_clear_object() call in gfs2_evict_inode(). That way, glock_clear_object() will only ever be called when the glock points at the current inode, and the NULL check in glock_clear_object() can be removed. Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Diffstat (limited to 'fs/gfs2/inode.c')
-rw-r--r--fs/gfs2/inode.c8
1 files changed, 8 insertions, 0 deletions
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
index 614db3055c02..c76fdb8f951f 100644
--- a/fs/gfs2/inode.c
+++ b/fs/gfs2/inode.c
@@ -225,6 +225,10 @@ fail:
gfs2_glock_dq_uninit(&ip->i_iopen_gh);
if (gfs2_holder_initialized(&i_gh))
gfs2_glock_dq_uninit(&i_gh);
+ if (ip->i_gl) {
+ gfs2_glock_put(ip->i_gl);
+ ip->i_gl = NULL;
+ }
iget_failed(inode);
return ERR_PTR(error);
}
@@ -816,6 +820,10 @@ fail_gunlock3:
fail_gunlock2:
gfs2_glock_put(io_gl);
fail_free_inode:
+ if (ip->i_gl) {
+ gfs2_glock_put(ip->i_gl);
+ ip->i_gl = NULL;
+ }
gfs2_rs_deltree(&ip->i_res);
gfs2_qa_put(ip);
fail_free_acls: