From: Al Viro Date: Mon, 2 Oct 2023 02:33:44 +0000 (+0100) Subject: gfs2: fix an oops in gfs2_permission X-Git-Tag: v6.1.68~656 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=e2ccedd4d182def14811cb039677bba15e6bda5d;p=platform%2Fkernel%2Flinux-starfive.git gfs2: fix an oops in gfs2_permission [ Upstream commit 0abd1557e21c617bd13fc18f7725fc6363c05913 ] In RCU mode, we might race with gfs2_evict_inode(), which zeroes ->i_gl. Freeing of the object it points to is RCU-delayed, so if we manage to fetch the pointer before it's been replaced with NULL, we are fine. Check if we'd fetched NULL and treat that as "bail out and tell the caller to get out of RCU mode". Signed-off-by: Al Viro Signed-off-by: Andreas Gruenbacher Signed-off-by: Sasha Levin --- diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 04a2015..d126b02 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -1847,14 +1847,21 @@ int gfs2_permission(struct user_namespace *mnt_userns, struct inode *inode, { struct gfs2_inode *ip; struct gfs2_holder i_gh; + struct gfs2_glock *gl; int error; gfs2_holder_mark_uninitialized(&i_gh); ip = GFS2_I(inode); - if (gfs2_glock_is_locked_by_me(ip->i_gl) == NULL) { + gl = rcu_dereference(ip->i_gl); + if (unlikely(!gl)) { + /* inode is getting torn down, must be RCU mode */ + WARN_ON_ONCE(!(mask & MAY_NOT_BLOCK)); + return -ECHILD; + } + if (gfs2_glock_is_locked_by_me(gl) == NULL) { if (mask & MAY_NOT_BLOCK) return -ECHILD; - error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh); + error = gfs2_glock_nq_init(gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh); if (error) return error; } diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index 44c564f..302d1e4 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -1435,7 +1435,7 @@ out: wait_on_bit_io(&ip->i_flags, GIF_GLOP_PENDING, TASK_UNINTERRUPTIBLE); gfs2_glock_add_to_lru(ip->i_gl); gfs2_glock_put_eventually(ip->i_gl); - ip->i_gl = NULL; + rcu_assign_pointer(ip->i_gl, NULL); } }