mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-10-31 16:38:12 +00:00
gfs2: fix an oops in gfs2_permission
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@zeniv.linux.org.uk> Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
This commit is contained in:
parent
4c6a08125f
commit
0abd1557e2
2 changed files with 10 additions and 3 deletions
|
@ -1868,14 +1868,21 @@ int gfs2_permission(struct mnt_idmap *idmap, 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;
|
||||
}
|
||||
|
|
|
@ -1540,7 +1540,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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue