[PATCH 5/6] gfs2: annotate i_gl with __rcu

Andreas Gruenbacher <[email protected]>
Newsgroups dev.linux.lists.gfs2
Message-ID <[email protected]>
ip->i_gl is always set over the lifetime of a gfs2 inode; it is initialized at
inode create time and torn down during evict.

However, gfs2_permission() can be called on an inode in non-blocking mode, when
the inode may already be undergoing evict.  So far, to make that work, we have
been using rcu_dereference_check() in gfs2_permission() and
rcu_assign_pointer() in gfs2_evict_inode().

However, ip->i_gl wasn't marked as __rcu so far.  rcu_dereference_check() and
rcu_assign_pointer() expect __rcu pointer arguments, and sparse complains when
regular pointers are passed to those functions:

fs/gfs2/super.c:1516:17: error: incompatible types in comparison expression (different address spaces):
fs/gfs2/super.c:1516:17:    struct gfs2_glock [noderef] __rcu *
fs/gfs2/super.c:1516:17:    struct gfs2_glock *
fs/gfs2/inode.c:1988:14: error: incompatible types in comparison expression (different address spaces):
fs/gfs2/inode.c:1988:14:    struct gfs2_glock [noderef] __rcu *
fs/gfs2/inode.c:1988:14:    struct gfs2_glock *

To fix those errors, turn ip->i_gl into a __rcu variable.  Use
rcu_assign_pointer() to assign to it, and rcu_dereference_protected() to access
it when the pointer is known to be valid.

Make sure not to use gfs2_inode_glock() in gfs2_permission().

Based on a patch from Adrian Garcia Casado <[email protected]>.

Signed-off-by: Andreas Gruenbacher <[email protected]>
---
 fs/gfs2/incore.h | 4 ++--
 fs/gfs2/inode.c  | 8 ++++----
 2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h
index 3ae8e2be486c..0a48f8e8ed6c 100644
--- a/fs/gfs2/incore.h
+++ b/fs/gfs2/incore.h
@@ -391,7 +391,7 @@ struct gfs2_inode {
 	u64 i_generation;
 	u64 i_eattr;
 	unsigned long i_flags;		/* GIF_... */
-	struct gfs2_glock *i_gl;
+	struct gfs2_glock __rcu *i_gl;
 	struct gfs2_holder i_iopen_gh;
 	struct gfs2_qadata *i_qadata; /* quota allocation data */
 	struct gfs2_holder i_rgd_gh;
@@ -881,6 +881,6 @@ static inline unsigned gfs2_max_stuffed_size(const struct gfs2_inode *ip)
 
 static inline struct gfs2_glock *gfs2_inode_glock(struct inode *inode)
 {
-       return GFS2_I(inode)->i_gl;
+       return rcu_dereference_protected(GFS2_I(inode)->i_gl, 1);
 }
 #endif /* __INCORE_DOT_H__ */
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
index 5aaed0018fb3..d4e1e443391e 100644
--- a/fs/gfs2/inode.c
+++ b/fs/gfs2/inode.c
@@ -151,7 +151,7 @@ struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned int type,
 				       &gl);
 		if (unlikely(error))
 			goto fail;
-		ip->i_gl = gl;
+		rcu_assign_pointer(ip->i_gl, gl);
 
 		error = gfs2_glock_get(sdp, no_addr, &gfs2_iopen_glops, CREATE,
 				       &io_gl);
@@ -244,7 +244,7 @@ struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned int type,
 		gfs2_glock_dq_uninit(&i_gh);
 	if (gl) {
 		gfs2_glock_put(gl);
-		ip->i_gl = NULL;
+		rcu_assign_pointer(ip->i_gl, NULL);
 	}
 	iget_failed(inode);
 	return ERR_PTR(error);
@@ -840,7 +840,7 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
 	error = gfs2_glock_get(sdp, ip->i_no_addr, &gfs2_inode_glops, CREATE, &gl);
 	if (error)
 		goto fail_dealloc_inode;
-	ip->i_gl = gl;
+	rcu_assign_pointer(ip->i_gl, gl);
 
 	error = gfs2_glock_get(sdp, ip->i_no_addr, &gfs2_iopen_glops, CREATE, &io_gl);
 	if (error)
@@ -940,7 +940,7 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
 fail_free_inode:
 	if (gl) {
 		gfs2_glock_put(gl);
-		ip->i_gl = NULL;
+		rcu_assign_pointer(ip->i_gl, NULL);
 	}
 	gfs2_rs_deltree(&ip->i_res);
 	gfs2_qa_put(ip);
-- 
2.55.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.