gfs2: check gl_object in rgrp glops
Function gfs2_clear_rgrpd() is called during unmount to free all rgrps and their sub-objects. If the rgrp glock is held (e.g. in SH) it calls gfs2_glock_cb() to unlock, then calls flush_delayed_work() to make sure any glock work is finished. However, there is a race with other cluster nodes who may request the rgrp glock in another mode (say, EX). Func gfs2_clear_rgrpd() calls glock_clear_object() which sets gl_object to NULL but that's done without holding the gl_lockref spin_lock. While the lock is not held Another node's demote request can cause the state machine to run again, and since the gl_lockref is released in do_xmote, the second process's call to do_xmote can call go_inval (rgrp_go_inval) after the gl_object has been cleared, which results in NULL pointer reference of the rgrp glock's gl_object. Other go_inval glops functions don't require the gl_object to exist, as evidenced by function inode_go_inval() which explicitly checks for if (ip) before referencing gl_object. This patch does the same thing for rgrp glocks. Both the go_inval and go_sync ops are patched to check the existence of gl_object (rgd) before trying to dereference it. Signed-off-by: Bob Peterson <rpeterso@redhat.com> Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
This commit is contained in:
parent
f0e56edc2e
commit
fd5f446f0b
@ -193,7 +193,7 @@ static int rgrp_go_sync(struct gfs2_glock *gl)
|
||||
struct gfs2_rgrpd *rgd = gfs2_glock2rgrp(gl);
|
||||
int error;
|
||||
|
||||
if (!test_and_clear_bit(GLF_DIRTY, &gl->gl_flags))
|
||||
if (!rgd || !test_and_clear_bit(GLF_DIRTY, &gl->gl_flags))
|
||||
return 0;
|
||||
GLOCK_BUG_ON(gl, gl->gl_state != LM_ST_EXCLUSIVE);
|
||||
|
||||
@ -222,9 +222,12 @@ static void rgrp_go_inval(struct gfs2_glock *gl, int flags)
|
||||
struct address_space *mapping = &sdp->sd_aspace;
|
||||
struct gfs2_rgrpd *rgd = gfs2_glock2rgrp(gl);
|
||||
const unsigned bsize = sdp->sd_sb.sb_bsize;
|
||||
loff_t start = (rgd->rd_addr * bsize) & PAGE_MASK;
|
||||
loff_t end = PAGE_ALIGN((rgd->rd_addr + rgd->rd_length) * bsize) - 1;
|
||||
loff_t start, end;
|
||||
|
||||
if (!rgd)
|
||||
return;
|
||||
start = (rgd->rd_addr * bsize) & PAGE_MASK;
|
||||
end = PAGE_ALIGN((rgd->rd_addr + rgd->rd_length) * bsize) - 1;
|
||||
gfs2_rgrp_brelse(rgd);
|
||||
WARN_ON_ONCE(!(flags & DIO_METADATA));
|
||||
truncate_inode_pages_range(mapping, start, end);
|
||||
|
Loading…
x
Reference in New Issue
Block a user