aboutsummaryrefslogtreecommitdiffstats
path: root/fs/gfs2
diff options
context:
space:
mode:
authorAbhi Das <adas@redhat.com>2019-04-30 17:53:47 -0400
committerAndreas Gruenbacher <agruenba@redhat.com>2019-05-07 17:39:14 -0400
commit8f91821990fd6f170a5dca79697a441181a41b16 (patch)
tree6efd729419e769c9a86681b5a8aca56e6c3e5995 /fs/gfs2
parentfbb27873f21d5fb9bf556edcaa67e9891636e5d4 (diff)
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 <adas@redhat.com> Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Diffstat (limited to 'fs/gfs2')
-rw-r--r--fs/gfs2/incore.h1
-rw-r--r--fs/gfs2/super.c8
2 files changed, 6 insertions, 3 deletions
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 {
621 SDF_SKIP_DLM_UNLOCK = 8, 621 SDF_SKIP_DLM_UNLOCK = 8,
622 SDF_FORCE_AIL_FLUSH = 9, 622 SDF_FORCE_AIL_FLUSH = 9,
623 SDF_AIL1_IO_ERROR = 10, 623 SDF_AIL1_IO_ERROR = 10,
624 SDF_FS_FROZEN = 11,
624}; 625};
625 626
626enum gfs2_freeze_state { 627enum 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)
973 if (error) { 973 if (error) {
974 printk(KERN_INFO "GFS2: couldn't get freeze lock : %d\n", error); 974 printk(KERN_INFO "GFS2: couldn't get freeze lock : %d\n", error);
975 gfs2_assert_withdraw(sdp, 0); 975 gfs2_assert_withdraw(sdp, 0);
976 } 976 } else {
977 else {
978 atomic_set(&sdp->sd_freeze_state, SFS_UNFROZEN); 977 atomic_set(&sdp->sd_freeze_state, SFS_UNFROZEN);
979 error = thaw_super(sb); 978 error = thaw_super(sb);
980 if (error) { 979 if (error) {
@@ -987,6 +986,8 @@ void gfs2_freeze_func(struct work_struct *work)
987 gfs2_glock_dq_uninit(&freeze_gh); 986 gfs2_glock_dq_uninit(&freeze_gh);
988 } 987 }
989 deactivate_super(sb); 988 deactivate_super(sb);
989 clear_bit_unlock(SDF_FS_FROZEN, &sdp->sd_flags);
990 wake_up_bit(&sdp->sd_flags, SDF_FS_FROZEN);
990 return; 991 return;
991} 992}
992 993
@@ -1029,6 +1030,7 @@ static int gfs2_freeze(struct super_block *sb)
1029 msleep(1000); 1030 msleep(1000);
1030 } 1031 }
1031 error = 0; 1032 error = 0;
1033 set_bit(SDF_FS_FROZEN, &sdp->sd_flags);
1032out: 1034out:
1033 mutex_unlock(&sdp->sd_freeze_mutex); 1035 mutex_unlock(&sdp->sd_freeze_mutex);
1034 return error; 1036 return error;
@@ -1053,7 +1055,7 @@ static int gfs2_unfreeze(struct super_block *sb)
1053 1055
1054 gfs2_glock_dq_uninit(&sdp->sd_freeze_gh); 1056 gfs2_glock_dq_uninit(&sdp->sd_freeze_gh);
1055 mutex_unlock(&sdp->sd_freeze_mutex); 1057 mutex_unlock(&sdp->sd_freeze_mutex);
1056 return 0; 1058 return wait_on_bit(&sdp->sd_flags, SDF_FS_FROZEN, TASK_INTERRUPTIBLE);
1057} 1059}
1058 1060
1059/** 1061/**