From fd5f446f0b3d529e55cf2f81f3b994a7216808ca Mon Sep 17 00:00:00 2001 From: Bob Peterson Date: Tue, 24 Jan 2023 14:55:18 -0500 Subject: 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 Signed-off-by: Andreas Gruenbacher --- fs/gfs2/glops.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'fs/gfs2') diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c index e4c585f16ddd..007cd59d0e47 100644 --- a/fs/gfs2/glops.c +++ b/fs/gfs2/glops.c @@ -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); -- cgit v1.2.3-58-ga151