Skip to content

Commit f66af88

Browse files
author
Andreas Gruenbacher
committed
gfs2: Stop using gfs2_make_fs_ro for withdraw
[ 81.372851][ T5532] CPU: 1 PID: 5532 Comm: syz-executor.0 Not tainted 6.2.0-rc1-syzkaller-dirty #0 [ 81.382080][ T5532] Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/12/2023 [ 81.392343][ T5532] Call Trace: [ 81.395654][ T5532] <TASK> [ 81.398603][ T5532] dump_stack_lvl+0x1b1/0x290 [ 81.418421][ T5532] gfs2_assert_warn_i+0x19a/0x2e0 [ 81.423480][ T5532] gfs2_quota_cleanup+0x4c6/0x6b0 [ 81.428611][ T5532] gfs2_make_fs_ro+0x517/0x610 [ 81.457802][ T5532] gfs2_withdraw+0x609/0x1540 [ 81.481452][ T5532] gfs2_inode_refresh+0xb2d/0xf60 [ 81.506658][ T5532] gfs2_instantiate+0x15e/0x220 [ 81.511504][ T5532] gfs2_glock_wait+0x1d9/0x2a0 [ 81.516352][ T5532] do_sync+0x485/0xc80 [ 81.554943][ T5532] gfs2_quota_sync+0x3da/0x8b0 [ 81.559738][ T5532] gfs2_sync_fs+0x49/0xb0 [ 81.564063][ T5532] sync_filesystem+0xe8/0x220 [ 81.568740][ T5532] generic_shutdown_super+0x6b/0x310 [ 81.574112][ T5532] kill_block_super+0x79/0xd0 [ 81.578779][ T5532] deactivate_locked_super+0xa7/0xf0 [ 81.584064][ T5532] cleanup_mnt+0x494/0x520 [ 81.593753][ T5532] task_work_run+0x243/0x300 [ 81.608837][ T5532] exit_to_user_mode_loop+0x124/0x150 [ 81.614232][ T5532] exit_to_user_mode_prepare+0xb2/0x140 [ 81.619820][ T5532] syscall_exit_to_user_mode+0x26/0x60 [ 81.625287][ T5532] do_syscall_64+0x49/0xb0 [ 81.629710][ T5532] entry_SYSCALL_64_after_hwframe+0x63/0xcd In this backtrace, gfs2_quota_sync() takes quota data references and then calls do_sync(). Function do_sync() encounters filesystem corruption and withdraws the filesystem, which (among other things) calls gfs2_quota_cleanup(). Function gfs2_quota_cleanup() wrongly assumes that nobody is holding any quota data references anymore, and destroys all quota data objects. When gfs2_quota_sync() then resumes and dereferences the quota data objects it is holding, those objects are no longer there. Function gfs2_quota_cleanup() deals with resource deallocation and can easily be delayed until gfs2_put_super() in the case of a filesystem withdraw. In fact, most of the other work gfs2_make_fs_ro() does is unnecessary during a withdraw as well, so change signal_our_withdraw() to skip gfs2_make_fs_ro() and perform the necessary steps directly instead. Thanks to Edward Adam Davis <[email protected]> for the initial patches. Link: https://lore.kernel.org/all/[email protected] Reported-by: [email protected] Signed-off-by: Andreas Gruenbacher <[email protected]>
1 parent a475c5d commit f66af88

File tree

2 files changed

+20
-8
lines changed

2 files changed

+20
-8
lines changed

fs/gfs2/super.c

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -580,15 +580,8 @@ void gfs2_make_fs_ro(struct gfs2_sbd *sdp)
580580
gfs2_log_is_empty(sdp),
581581
HZ * 5);
582582
gfs2_assert_warn(sdp, gfs2_log_is_empty(sdp));
583-
} else {
584-
wait_event_timeout(sdp->sd_log_waitq,
585-
gfs2_log_is_empty(sdp),
586-
HZ * 5);
587583
}
588584
gfs2_quota_cleanup(sdp);
589-
590-
if (!log_write_allowed)
591-
sdp->sd_vfs->s_flags |= SB_RDONLY;
592585
}
593586

594587
/**
@@ -622,6 +615,8 @@ static void gfs2_put_super(struct super_block *sb)
622615
if (!sb_rdonly(sb)) {
623616
gfs2_make_fs_ro(sdp);
624617
}
618+
if (gfs2_withdrawn(sdp))
619+
gfs2_quota_cleanup(sdp);
625620
WARN_ON(gfs2_withdrawing(sdp));
626621

627622
/* At this point, we're through modifying the disk */

fs/gfs2/util.c

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <linux/spinlock.h>
1010
#include <linux/completion.h>
1111
#include <linux/buffer_head.h>
12+
#include <linux/kthread.h>
1213
#include <linux/crc32.h>
1314
#include <linux/gfs2_ondisk.h>
1415
#include <linux/delay.h>
@@ -150,7 +151,23 @@ static void signal_our_withdraw(struct gfs2_sbd *sdp)
150151
if (!sb_rdonly(sdp->sd_vfs)) {
151152
bool locked = mutex_trylock(&sdp->sd_freeze_mutex);
152153

153-
gfs2_make_fs_ro(sdp);
154+
if (sdp->sd_quotad_process &&
155+
current != sdp->sd_quotad_process) {
156+
kthread_stop(sdp->sd_quotad_process);
157+
sdp->sd_quotad_process = NULL;
158+
}
159+
160+
if (sdp->sd_logd_process &&
161+
current != sdp->sd_logd_process) {
162+
kthread_stop(sdp->sd_logd_process);
163+
sdp->sd_logd_process = NULL;
164+
}
165+
166+
wait_event_timeout(sdp->sd_log_waitq,
167+
gfs2_log_is_empty(sdp),
168+
HZ * 5);
169+
170+
sdp->sd_vfs->s_flags |= SB_RDONLY;
154171

155172
if (locked)
156173
mutex_unlock(&sdp->sd_freeze_mutex);

0 commit comments

Comments
 (0)