]> git.proxmox.com Git - mirror_ubuntu-disco-kernel.git/commitdiff
gfs2: fix race between gfs2_freeze_func and unmount
authorAbhi Das <adas@redhat.com>
Tue, 30 Apr 2019 21:53:47 +0000 (16:53 -0500)
committerStefan Bader <stefan.bader@canonical.com>
Tue, 13 Aug 2019 12:11:36 +0000 (14:11 +0200)
BugLink: https://bugs.launchpad.net/bugs/1837517
[ Upstream commit 8f91821990fd6f170a5dca79697a441181a41b16 ]

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>
Signed-off-by: Sasha Levin <sashal@kernel.org>
Signed-off-by: Khalid Elmously <khalid.elmously@canonical.com>
Signed-off-by: Stefan Bader <stefan.bader@canonical.com>
fs/gfs2/incore.h
fs/gfs2/super.c

index e10e0b0a7cd58e513e4798b2ee3ef8184d9d8bad..e1a33d288121341c66787eb1a305aec19d485892 100644 (file)
@@ -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 {
index ca71163ff7cfda20234c434a1932ecbff72ed267..360206704a14c748052fea8cd244229ee7940781 100644 (file)
@@ -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);
 }
 
 /**