[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