Merge tag 'fs_for_v6.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jack...
[platform/kernel/linux-starfive.git] / fs / super.c
index 6283cea..e781226 100644 (file)
@@ -54,7 +54,7 @@ static char *sb_writers_name[SB_FREEZE_LEVELS] = {
  * One thing we have to be careful of with a per-sb shrinker is that we don't
  * drop the last active reference to the superblock from within the shrinker.
  * If that happens we could trigger unregistering the shrinker from within the
- * shrinker path and that leads to deadlock on the shrinker_mutex. Hence we
+ * shrinker path and that leads to deadlock on the shrinker_rwsem. Hence we
  * take a passive reference to the superblock to avoid this from occurring.
  */
 static unsigned long super_cache_scan(struct shrinker *shrink,
@@ -594,7 +594,7 @@ retry:
        fc->s_fs_info = NULL;
        s->s_type = fc->fs_type;
        s->s_iflags |= fc->s_iflags;
-       strlcpy(s->s_id, s->s_type->name, sizeof(s->s_id));
+       strscpy(s->s_id, s->s_type->name, sizeof(s->s_id));
        list_add_tail(&s->s_list, &super_blocks);
        hlist_add_head(&s->s_instances, &s->s_type->fs_supers);
        spin_unlock(&sb_lock);
@@ -673,7 +673,7 @@ retry:
                return ERR_PTR(err);
        }
        s->s_type = type;
-       strlcpy(s->s_id, type->name, sizeof(s->s_id));
+       strscpy(s->s_id, type->name, sizeof(s->s_id));
        list_add_tail(&s->s_list, &super_blocks);
        hlist_add_head(&s->s_instances, &type->fs_supers);
        spin_unlock(&sb_lock);
@@ -902,6 +902,7 @@ int reconfigure_super(struct fs_context *fc)
        struct super_block *sb = fc->root->d_sb;
        int retval;
        bool remount_ro = false;
+       bool remount_rw = false;
        bool force = fc->sb_flags & SB_FORCE;
 
        if (fc->sb_flags_mask & ~MS_RMT_MASK)
@@ -919,7 +920,7 @@ int reconfigure_super(struct fs_context *fc)
                    bdev_read_only(sb->s_bdev))
                        return -EACCES;
 #endif
-
+               remount_rw = !(fc->sb_flags & SB_RDONLY) && sb_rdonly(sb);
                remount_ro = (fc->sb_flags & SB_RDONLY) && !sb_rdonly(sb);
        }
 
@@ -942,13 +943,18 @@ int reconfigure_super(struct fs_context *fc)
         */
        if (remount_ro) {
                if (force) {
-                       sb->s_readonly_remount = 1;
-                       smp_wmb();
+                       sb_start_ro_state_change(sb);
                } else {
                        retval = sb_prepare_remount_readonly(sb);
                        if (retval)
                                return retval;
                }
+       } else if (remount_rw) {
+               /*
+                * Protect filesystem's reconfigure code from writes from
+                * userspace until reconfigure finishes.
+                */
+               sb_start_ro_state_change(sb);
        }
 
        if (fc->ops->reconfigure) {
@@ -964,9 +970,7 @@ int reconfigure_super(struct fs_context *fc)
 
        WRITE_ONCE(sb->s_flags, ((sb->s_flags & ~fc->sb_flags_mask) |
                                 (fc->sb_flags & fc->sb_flags_mask)));
-       /* Needs to be ordered wrt mnt_is_readonly() */
-       smp_wmb();
-       sb->s_readonly_remount = 0;
+       sb_end_ro_state_change(sb);
 
        /*
         * Some filesystems modify their metadata via some other path than the
@@ -981,7 +985,7 @@ int reconfigure_super(struct fs_context *fc)
        return 0;
 
 cancel_readonly:
-       sb->s_readonly_remount = 0;
+       sb_end_ro_state_change(sb);
        return retval;
 }
 
@@ -1205,6 +1209,22 @@ int get_tree_keyed(struct fs_context *fc,
 EXPORT_SYMBOL(get_tree_keyed);
 
 #ifdef CONFIG_BLOCK
+static void fs_mark_dead(struct block_device *bdev)
+{
+       struct super_block *sb;
+
+       sb = get_super(bdev);
+       if (!sb)
+               return;
+
+       if (sb->s_op->shutdown)
+               sb->s_op->shutdown(sb);
+       drop_super(sb);
+}
+
+static const struct blk_holder_ops fs_holder_ops = {
+       .mark_dead              = fs_mark_dead,
+};
 
 static int set_bdev_super(struct super_block *s, void *data)
 {
@@ -1238,16 +1258,13 @@ int get_tree_bdev(struct fs_context *fc,
 {
        struct block_device *bdev;
        struct super_block *s;
-       fmode_t mode = FMODE_READ | FMODE_EXCL;
        int error = 0;
 
-       if (!(fc->sb_flags & SB_RDONLY))
-               mode |= FMODE_WRITE;
-
        if (!fc->source)
                return invalf(fc, "No source specified");
 
-       bdev = blkdev_get_by_path(fc->source, mode, fc->fs_type);
+       bdev = blkdev_get_by_path(fc->source, sb_open_mode(fc->sb_flags),
+                                 fc->fs_type, &fs_holder_ops);
        if (IS_ERR(bdev)) {
                errorf(fc, "%s: Can't open blockdev", fc->source);
                return PTR_ERR(bdev);
@@ -1261,7 +1278,7 @@ int get_tree_bdev(struct fs_context *fc,
        if (bdev->bd_fsfreeze_count > 0) {
                mutex_unlock(&bdev->bd_fsfreeze_mutex);
                warnf(fc, "%pg: Can't mount, blockdev is frozen", bdev);
-               blkdev_put(bdev, mode);
+               blkdev_put(bdev, fc->fs_type);
                return -EBUSY;
        }
 
@@ -1270,7 +1287,7 @@ int get_tree_bdev(struct fs_context *fc,
        s = sget_fc(fc, test_bdev_super_fc, set_bdev_super_fc);
        mutex_unlock(&bdev->bd_fsfreeze_mutex);
        if (IS_ERR(s)) {
-               blkdev_put(bdev, mode);
+               blkdev_put(bdev, fc->fs_type);
                return PTR_ERR(s);
        }
 
@@ -1279,7 +1296,7 @@ int get_tree_bdev(struct fs_context *fc,
                if ((fc->sb_flags ^ s->s_flags) & SB_RDONLY) {
                        warnf(fc, "%pg: Can't mount, would change RO state", bdev);
                        deactivate_locked_super(s);
-                       blkdev_put(bdev, mode);
+                       blkdev_put(bdev, fc->fs_type);
                        return -EBUSY;
                }
 
@@ -1291,10 +1308,9 @@ int get_tree_bdev(struct fs_context *fc,
                 * holding an active reference.
                 */
                up_write(&s->s_umount);
-               blkdev_put(bdev, mode);
+               blkdev_put(bdev, fc->fs_type);
                down_write(&s->s_umount);
        } else {
-               s->s_mode = mode;
                snprintf(s->s_id, sizeof(s->s_id), "%pg", bdev);
                shrinker_debugfs_rename(&s->s_shrink, "sb-%s:%s",
                                        fc->fs_type->name, s->s_id);
@@ -1326,13 +1342,10 @@ struct dentry *mount_bdev(struct file_system_type *fs_type,
 {
        struct block_device *bdev;
        struct super_block *s;
-       fmode_t mode = FMODE_READ | FMODE_EXCL;
        int error = 0;
 
-       if (!(flags & SB_RDONLY))
-               mode |= FMODE_WRITE;
-
-       bdev = blkdev_get_by_path(dev_name, mode, fs_type);
+       bdev = blkdev_get_by_path(dev_name, sb_open_mode(flags), fs_type,
+                                 &fs_holder_ops);
        if (IS_ERR(bdev))
                return ERR_CAST(bdev);
 
@@ -1368,10 +1381,9 @@ struct dentry *mount_bdev(struct file_system_type *fs_type,
                 * holding an active reference.
                 */
                up_write(&s->s_umount);
-               blkdev_put(bdev, mode);
+               blkdev_put(bdev, fs_type);
                down_write(&s->s_umount);
        } else {
-               s->s_mode = mode;
                snprintf(s->s_id, sizeof(s->s_id), "%pg", bdev);
                shrinker_debugfs_rename(&s->s_shrink, "sb-%s:%s",
                                        fs_type->name, s->s_id);
@@ -1391,7 +1403,7 @@ struct dentry *mount_bdev(struct file_system_type *fs_type,
 error_s:
        error = PTR_ERR(s);
 error_bdev:
-       blkdev_put(bdev, mode);
+       blkdev_put(bdev, fs_type);
 error:
        return ERR_PTR(error);
 }
@@ -1400,13 +1412,11 @@ EXPORT_SYMBOL(mount_bdev);
 void kill_block_super(struct super_block *sb)
 {
        struct block_device *bdev = sb->s_bdev;
-       fmode_t mode = sb->s_mode;
 
        bdev->bd_super = NULL;
        generic_shutdown_super(sb);
        sync_blockdev(bdev);
-       WARN_ON_ONCE(!(mode & FMODE_EXCL));
-       blkdev_put(bdev, mode | FMODE_EXCL);
+       blkdev_put(bdev, sb->s_type);
 }
 
 EXPORT_SYMBOL(kill_block_super);