[PATCH] gfs2: fix kernel BUG in __gfs2_ail_flush during withdraw

Morduan Zang posted 1 patch 2 months, 1 week ago
fs/gfs2/glops.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
[PATCH] gfs2: fix kernel BUG in __gfs2_ail_flush during withdraw
Posted by Morduan Zang 2 months, 1 week ago
From: Zhan Jun <zhanjun@uniontech.com>

When __gfs2_ail_flush() finds an AIL buffer in unexpected state
(dirty/pinned/locked) and fsync is false, it calls gfs2_ail_error(),
which withdraws the filesystem.

However, the code then falls through and still calls
gfs2_trans_add_revoke(). That function asserts that bd->bd_list must be
empty:

  BUG_ON(!list_empty(&bd->bd_list));

During withdraw this can be false because the same bufdata may still be
on a transaction buffer list, which triggers the reported BUG at
fs/gfs2/trans.c:321.

Fix this by skipping revoke addition after gfs2_ail_error(). Also avoid
asserting gl_ail_count==0 once the filesystem is withdrawn, because
buffers skipped for revoke can legitimately remain on the AIL list.

Reported-by: syzbot+b17a83b050e9617376f0@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=b17a83b050e9617376f0
Cc: Andreas Gruenbacher <agruenba@redhat.com>
Cc: gfs2@lists.linux.dev
Signed-off-by: Zhan Jun <zhanjun@uniontech.com>
---
 fs/gfs2/glops.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c
index ba61649368bf..70c998b80e86 100644
--- a/fs/gfs2/glops.c
+++ b/fs/gfs2/glops.c
@@ -74,11 +74,13 @@ static void __gfs2_ail_flush(struct gfs2_glock *gl, bool fsync,
 			if (fsync)
 				continue;
 			gfs2_ail_error(gl, bh);
+			continue;
 		}
 		gfs2_trans_add_revoke(sdp, bd);
 		nr_revokes--;
 	}
-	GLOCK_BUG_ON(gl, !fsync && atomic_read(&gl->gl_ail_count));
+	GLOCK_BUG_ON(gl, !fsync && !gfs2_withdrawn(sdp) &&
+		     atomic_read(&gl->gl_ail_count));
 	spin_unlock(&sdp->sd_ail_lock);
 	gfs2_log_unlock(sdp);
 }
-- 
2.50.1