Right now freeze_super()  and thaw_super() are called with
different locking contexts. To expand on this is messy, so
just unify the requirement to require grabbing an active
reference and keep the superblock locked.

Suggested-by: Christoph Hellwig <[email protected]>
Signed-off-by: Luis Chamberlain <[email protected]>
---
 block/bdev.c    |  5 ++++-
 fs/f2fs/gc.c    |  5 +++++
 fs/gfs2/super.c |  9 +++++++--
 fs/gfs2/sys.c   |  6 ++++++
 fs/gfs2/util.c  |  5 +++++
 fs/ioctl.c      | 12 ++++++++++--
 fs/super.c      | 51 ++++++++++++++-----------------------------------
 7 files changed, 51 insertions(+), 42 deletions(-)

diff --git a/block/bdev.c b/block/bdev.c
index edc110d90df4..8fd3a7991c02 100644
--- a/block/bdev.c
+++ b/block/bdev.c
@@ -251,7 +251,7 @@ int freeze_bdev(struct block_device *bdev)
                error = sb->s_op->freeze_super(sb);
        else
                error = freeze_super(sb);
-       deactivate_super(sb);
+       deactivate_locked_super(sb);
 
        if (error) {
                bdev->bd_fsfreeze_count--;
@@ -289,6 +289,8 @@ int thaw_bdev(struct block_device *bdev)
        sb = bdev->bd_fsfreeze_sb;
        if (!sb)
                goto out;
+       if (!get_active_super(bdev))
+               goto out;
 
        if (sb->s_op->thaw_super)
                error = sb->s_op->thaw_super(sb);
@@ -298,6 +300,7 @@ int thaw_bdev(struct block_device *bdev)
                bdev->bd_fsfreeze_count++;
        else
                bdev->bd_fsfreeze_sb = NULL;
+       deactivate_locked_super(sb);
 out:
        mutex_unlock(&bdev->bd_fsfreeze_mutex);
        return error;
diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c
index 7444c392eab1..4c681fe487ee 100644
--- a/fs/f2fs/gc.c
+++ b/fs/f2fs/gc.c
@@ -2139,7 +2139,10 @@ int f2fs_resize_fs(struct f2fs_sb_info *sbi, __u64 
block_count)
        if (err)
                return err;
 
+       if (!get_active_super(sbi->sb->s_bdev))
+               return -ENOTTY;
        freeze_super(sbi->sb);
+
        f2fs_down_write(&sbi->gc_lock);
        f2fs_down_write(&sbi->cp_global_sem);
 
@@ -2190,6 +2193,8 @@ int f2fs_resize_fs(struct f2fs_sb_info *sbi, __u64 
block_count)
 out_err:
        f2fs_up_write(&sbi->cp_global_sem);
        f2fs_up_write(&sbi->gc_lock);
+       /* We use the same active reference from freeze */
        thaw_super(sbi->sb);
+       deactivate_locked_super(sbi->sb);
        return err;
 }
diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c
index 999cc146d708..48df7b276b64 100644
--- a/fs/gfs2/super.c
+++ b/fs/gfs2/super.c
@@ -661,7 +661,12 @@ void gfs2_freeze_func(struct work_struct *work)
        struct gfs2_sbd *sdp = container_of(work, struct gfs2_sbd, 
sd_freeze_work);
        struct super_block *sb = sdp->sd_vfs;
 
-       atomic_inc(&sb->s_active);
+       if (!get_active_super(sb->s_bdev)) {
+               fs_info(sdp, "GFS2: couldn't grap super for thaw for 
filesystem\n");
+               gfs2_assert_withdraw(sdp, 0);
+               return;
+       }
+
        error = gfs2_freeze_lock(sdp, &freeze_gh, 0);
        if (error) {
                gfs2_assert_withdraw(sdp, 0);
@@ -675,7 +680,7 @@ void gfs2_freeze_func(struct work_struct *work)
                }
                gfs2_freeze_unlock(&freeze_gh);
        }
-       deactivate_super(sb);
+       deactivate_locked_super(sb);
        clear_bit_unlock(SDF_FS_FROZEN, &sdp->sd_flags);
        wake_up_bit(&sdp->sd_flags, SDF_FS_FROZEN);
        return;
diff --git a/fs/gfs2/sys.c b/fs/gfs2/sys.c
index d87ea98cf535..d0b80552a678 100644
--- a/fs/gfs2/sys.c
+++ b/fs/gfs2/sys.c
@@ -162,6 +162,9 @@ static ssize_t freeze_store(struct gfs2_sbd *sdp, const 
char *buf, size_t len)
        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
 
+       if (!get_active_super(sb->s_bdev))
+               return -ENOTTY;
+
        switch (n) {
        case 0:
                error = thaw_super(sdp->sd_vfs);
@@ -170,9 +173,12 @@ static ssize_t freeze_store(struct gfs2_sbd *sdp, const 
char *buf, size_t len)
                error = freeze_super(sdp->sd_vfs);
                break;
        default:
+               deactivate_locked_super(sb);
                return -EINVAL;
        }
 
+       deactivate_locked_super(sb);
+
        if (error) {
                fs_warn(sdp, "freeze %d error %d\n", n, error);
                return error;
diff --git a/fs/gfs2/util.c b/fs/gfs2/util.c
index 7a6aeffcdf5c..3a0cd5e9ad84 100644
--- a/fs/gfs2/util.c
+++ b/fs/gfs2/util.c
@@ -345,10 +345,15 @@ int gfs2_withdraw(struct gfs2_sbd *sdp)
        set_bit(SDF_WITHDRAW_IN_PROG, &sdp->sd_flags);
 
        if (sdp->sd_args.ar_errors == GFS2_ERRORS_WITHDRAW) {
+               if (!get_active_super(sb->s_bdev)) {
+                       fs_err(sdp, "could not grab super on withdraw for file 
system\n");
+                       return -1;
+               }
                fs_err(sdp, "about to withdraw this file system\n");
                BUG_ON(sdp->sd_args.ar_debug);
 
                signal_our_withdraw(sdp);
+               deactivate_locked_super(sb);
 
                kobject_uevent(&sdp->sd_kobj, KOBJ_OFFLINE);
 
diff --git a/fs/ioctl.c b/fs/ioctl.c
index 80ac36aea913..3d2536e1ea58 100644
--- a/fs/ioctl.c
+++ b/fs/ioctl.c
@@ -386,6 +386,7 @@ static int ioctl_fioasync(unsigned int fd, struct file 
*filp,
 static int ioctl_fsfreeze(struct file *filp)
 {
        struct super_block *sb = file_inode(filp)->i_sb;
+       int ret;
 
        if (!ns_capable(sb->s_user_ns, CAP_SYS_ADMIN))
                return -EPERM;
@@ -394,10 +395,17 @@ static int ioctl_fsfreeze(struct file *filp)
        if (sb->s_op->freeze_fs == NULL && sb->s_op->freeze_super == NULL)
                return -EOPNOTSUPP;
 
+       if (!get_active_super(sb->s_bdev))
+               return -ENOTTY;
+
        /* Freeze */
        if (sb->s_op->freeze_super)
-               return sb->s_op->freeze_super(sb);
-       return freeze_super(sb);
+               ret = sb->s_op->freeze_super(sb);
+       ret = freeze_super(sb);
+
+       deactivate_locked_super(sb);
+
+       return ret;
 }
 
 static int ioctl_fsthaw(struct file *filp)
diff --git a/fs/super.c b/fs/super.c
index 12c08cb20405..a31a41b313f3 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -39,8 +39,6 @@
 #include <uapi/linux/mount.h>
 #include "internal.h"
 
-static int thaw_super_locked(struct super_block *sb);
-
 static LIST_HEAD(super_blocks);
 static DEFINE_SPINLOCK(sb_lock);
 
@@ -830,7 +828,6 @@ struct super_block *get_active_super(struct block_device 
*bdev)
                if (sb->s_bdev == bdev) {
                        if (!grab_super(sb))
                                goto restart;
-                       up_write(&sb->s_umount);
                        return sb;
                }
        }
@@ -1003,13 +1000,13 @@ void emergency_remount(void)
 
 static void do_thaw_all_callback(struct super_block *sb)
 {
-       down_write(&sb->s_umount);
+       if (!get_active_super(sb->s_bdev))
+               return;
        if (sb->s_root && sb->s_flags & SB_BORN) {
                emergency_thaw_bdev(sb);
-               thaw_super_locked(sb);
-       } else {
-               up_write(&sb->s_umount);
+               thaw_super(sb);
        }
+       deactivate_locked_super(sb);
 }
 
 static void do_thaw_all(struct work_struct *work)
@@ -1651,22 +1648,15 @@ int freeze_super(struct super_block *sb)
 {
        int ret;
 
-       atomic_inc(&sb->s_active);
-       down_write(&sb->s_umount);
-       if (sb->s_writers.frozen != SB_UNFROZEN) {
-               deactivate_locked_super(sb);
+       if (sb->s_writers.frozen != SB_UNFROZEN)
                return -EBUSY;
-       }
 
-       if (!(sb->s_flags & SB_BORN)) {
-               up_write(&sb->s_umount);
+       if (!(sb->s_flags & SB_BORN))
                return 0;       /* sic - it's "nothing to do" */
-       }
 
        if (sb_rdonly(sb)) {
                /* Nothing to do really... */
                sb->s_writers.frozen = SB_FREEZE_COMPLETE;
-               up_write(&sb->s_umount);
                return 0;
        }
 
@@ -1686,7 +1676,6 @@ int freeze_super(struct super_block *sb)
                sb->s_writers.frozen = SB_UNFROZEN;
                sb_freeze_unlock(sb, SB_FREEZE_PAGEFAULT);
                wake_up(&sb->s_writers.wait_unfrozen);
-               deactivate_locked_super(sb);
                return ret;
        }
 
@@ -1702,7 +1691,6 @@ int freeze_super(struct super_block *sb)
                        sb->s_writers.frozen = SB_UNFROZEN;
                        sb_freeze_unlock(sb, SB_FREEZE_FS);
                        wake_up(&sb->s_writers.wait_unfrozen);
-                       deactivate_locked_super(sb);
                        return ret;
                }
        }
@@ -1712,19 +1700,22 @@ int freeze_super(struct super_block *sb)
         */
        sb->s_writers.frozen = SB_FREEZE_COMPLETE;
        lockdep_sb_freeze_release(sb);
-       up_write(&sb->s_umount);
        return 0;
 }
 EXPORT_SYMBOL(freeze_super);
 
-static int thaw_super_locked(struct super_block *sb)
+/**
+ * thaw_super -- unlock filesystem
+ * @sb: the super to thaw
+ *
+ * Unlocks the filesystem and marks it writeable again after freeze_super().
+ */
+int thaw_super(struct super_block *sb)
 {
        int error;
 
-       if (sb->s_writers.frozen != SB_FREEZE_COMPLETE) {
-               up_write(&sb->s_umount);
+       if (sb->s_writers.frozen != SB_FREEZE_COMPLETE)
                return -EINVAL;
-       }
 
        if (sb_rdonly(sb)) {
                sb->s_writers.frozen = SB_UNFROZEN;
@@ -1739,7 +1730,6 @@ static int thaw_super_locked(struct super_block *sb)
                        printk(KERN_ERR
                                "VFS:Filesystem thaw failed\n");
                        lockdep_sb_freeze_release(sb);
-                       up_write(&sb->s_umount);
                        return error;
                }
        }
@@ -1748,19 +1738,6 @@ static int thaw_super_locked(struct super_block *sb)
        sb_freeze_unlock(sb, SB_FREEZE_FS);
 out:
        wake_up(&sb->s_writers.wait_unfrozen);
-       deactivate_locked_super(sb);
        return 0;
 }
-
-/**
- * thaw_super -- unlock filesystem
- * @sb: the super to thaw
- *
- * Unlocks the filesystem and marks it writeable again after freeze_super().
- */
-int thaw_super(struct super_block *sb)
-{
-       down_write(&sb->s_umount);
-       return thaw_super_locked(sb);
-}
 EXPORT_SYMBOL(thaw_super);
-- 
2.35.1


_______________________________________________
kexec mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/kexec

Reply via email to