Patch "gfs2: fix an oops in gfs2_permission" has been added to the 5.15-stable tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is a note to let you know that I've just added the patch titled

    gfs2: fix an oops in gfs2_permission

to the 5.15-stable tree which can be found at:
    http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     gfs2-fix-an-oops-in-gfs2_permission.patch
and it can be found in the queue-5.15 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@xxxxxxxxxxxxxxx> know about it.



commit 31854e05a9f2aca3e62f210376488a15a67959d8
Author: Al Viro <viro@xxxxxxxxxxxxxxxxxx>
Date:   Mon Oct 2 03:33:44 2023 +0100

    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 <viro@xxxxxxxxxxxxxxxxxx>
    Signed-off-by: Andreas Gruenbacher <agruenba@xxxxxxxxxx>
    Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>

diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
index 97ee17843b4d0..682418d9c8e72 100644
--- a/fs/gfs2/inode.c
+++ b/fs/gfs2/inode.c
@@ -1850,14 +1850,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 51b44da4a0d64..268651ac9fc84 100644
--- a/fs/gfs2/super.c
+++ b/fs/gfs2/super.c
@@ -1436,7 +1436,7 @@ static void gfs2_evict_inode(struct inode *inode)
 		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);
 	}
 }
 



[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux