From 8f91821990fd6f170a5dca79697a441181a41b16 Mon Sep 17 00:00:00 2001 From: Abhi Das Date: Tue, 30 Apr 2019 16:53:47 -0500 Subject: gfs2: fix race between gfs2_freeze_func and unmount As part of the freeze operation, gfs2_freeze_func() is left blocking on a request to hold the sd_freeze_gl in SH. This glock is held in EX by the gfs2_freeze() code. A subsequent call to gfs2_unfreeze() releases the EXclusively held sd_freeze_gl, which allows gfs2_freeze_func() to acquire it in SH and resume its operation. gfs2_unfreeze(), however, doesn't wait for gfs2_freeze_func() to complete. If a umount is issued right after unfreeze, it could result in an inconsistent filesystem because some journal data (statfs update) isn't written out. Refer to commit 24972557b12c for a more detailed explanation of how freeze/unfreeze work. This patch causes gfs2_unfreeze() to wait for gfs2_freeze_func() to complete before returning to the user. Signed-off-by: Abhi Das Signed-off-by: Andreas Gruenbacher --- fs/gfs2/incore.h | 1 + fs/gfs2/super.c | 8 +++++--- 2 files changed, 6 insertions(+), 3 deletions(-) (limited to 'fs/gfs2') diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 78c8e761b321..b15755068593 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -621,6 +621,7 @@ enum { SDF_SKIP_DLM_UNLOCK = 8, SDF_FORCE_AIL_FLUSH = 9, SDF_AIL1_IO_ERROR = 10, + SDF_FS_FROZEN = 11, }; enum gfs2_freeze_state { diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index 6d89d0ecec2a..5b148cf03293 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -973,8 +973,7 @@ void gfs2_freeze_func(struct work_struct *work) if (error) { printk(KERN_INFO "GFS2: couldn't get freeze lock : %d\n", error); gfs2_assert_withdraw(sdp, 0); - } - else { + } else { atomic_set(&sdp->sd_freeze_state, SFS_UNFROZEN); error = thaw_super(sb); if (error) { @@ -987,6 +986,8 @@ void gfs2_freeze_func(struct work_struct *work) gfs2_glock_dq_uninit(&freeze_gh); } deactivate_super(sb); + clear_bit_unlock(SDF_FS_FROZEN, &sdp->sd_flags); + wake_up_bit(&sdp->sd_flags, SDF_FS_FROZEN); return; } @@ -1029,6 +1030,7 @@ static int gfs2_freeze(struct super_block *sb) msleep(1000); } error = 0; + set_bit(SDF_FS_FROZEN, &sdp->sd_flags); out: mutex_unlock(&sdp->sd_freeze_mutex); return error; @@ -1053,7 +1055,7 @@ static int gfs2_unfreeze(struct super_block *sb) gfs2_glock_dq_uninit(&sdp->sd_freeze_gh); mutex_unlock(&sdp->sd_freeze_mutex); - return 0; + return wait_on_bit(&sdp->sd_flags, SDF_FS_FROZEN, TASK_INTERRUPTIBLE); } /** -- cgit v1.2.3