linux-btrfs.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Marcos Paulo de Souza <marcos@mpdesouza.com>
To: dsterba@suse.com, linux-btrfs@vger.kernel.org
Cc: Marcos Paulo de Souza <mpdesouza@suse.com>
Subject: [RFC PATCH 7/8] btrfs: Convert to fs_context
Date: Wed, 12 Aug 2020 13:36:53 -0300	[thread overview]
Message-ID: <20200812163654.17080-8-marcos@mpdesouza.com> (raw)
In-Reply-To: <20200812163654.17080-1-marcos@mpdesouza.com>

From: Marcos Paulo de Souza <mpdesouza@suse.com>

This commit makes btrfs full use of the fs_context API. It's heavily
based in David Howells POC when fs_context was introduced[1]. As
fs_context divides the mount procedure into different steps, the btrfs
code needed to be rearranged in order to store the mount points and
other properties without having a fs_info already allocated.

The btrfs_fs_context struct is the responsible struct for storing the
options used to mount the fs, and these options are set to
fs_info->mount_opts in btrfs_apply_configuration.

Some notable changes:
* There is no need for a second file_system_type anymore. Now we use a
  special flag in btrfs_fs_context to identify the mount of the root
  subvol before mounting the specified subvol.
* With the introduction of fs_context all mount options are parsed
  _before_ doing the mount procedure. In our case, btrfs_fc_parse_param
  is the function being called to parse all options, making
  btrfs_parse_device_options, btrfs_parse_subvol_options
  btrfs_parse_options obsolete.
* Function btrfs_mount_root was renamed to btrfs_root_get_tree to
  reflect that fs_context is being used.
* Function btrfs_remount was renamed to btrfs_reconfigure by the same
  reason from above.
* Function btrfs_mount was renamed to btrfs_get_tree, and this function
  is called by vfs after all the mount options are parsed.
* There is no need for btrfs_root_fs_type anymore, and so fs_info->bdev_holder
  can also be removed.

Functions like open_ctree and btrfs_fill_super are now using a
fs_context argument instead of other btrfs related structs, since
the fs_context->fs_private contains a btrfs_fs_context that holds
the necessary data.

[1]: https://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs.git/commit/?h=Q46&id=554cb2019cda83e1aba10bd9eea485afd2ddb983

Signed-off-by: Marcos Paulo de Souza <mpdesouza@suse.com>
---
 fs/btrfs/ctree.h       |   1 +
 fs/btrfs/dev-replace.c |   2 +-
 fs/btrfs/disk-io.c     |  10 +-
 fs/btrfs/disk-io.h     |   4 +-
 fs/btrfs/super.c       | 347 ++++++++++++++++++++---------------------
 fs/btrfs/volumes.c     |   6 +-
 6 files changed, 178 insertions(+), 192 deletions(-)

diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index d96bce2ea5bb..9060be6a6c6e 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -3100,6 +3100,7 @@ int btrfs_defrag_leaves(struct btrfs_trans_handle *trans,
 			struct btrfs_root *root);
 
 /* super.c */
+extern struct file_system_type btrfs_fs_type;
 int btrfs_parse_options(struct btrfs_fs_info *info, char *options,
 			unsigned long new_flags);
 int btrfs_apply_configuration(struct fs_context *fc, struct super_block *sb);
diff --git a/fs/btrfs/dev-replace.c b/fs/btrfs/dev-replace.c
index db93909b25e0..9a3275845b13 100644
--- a/fs/btrfs/dev-replace.c
+++ b/fs/btrfs/dev-replace.c
@@ -236,7 +236,7 @@ static int btrfs_init_dev_replace_tgtdev(struct btrfs_fs_info *fs_info,
 	}
 
 	bdev = blkdev_get_by_path(device_path, FMODE_WRITE | FMODE_EXCL,
-				  fs_info->bdev_holder);
+				  &btrfs_fs_type);
 	if (IS_ERR(bdev)) {
 		btrfs_err(fs_info, "target device %s is invalid!", device_path);
 		return PTR_ERR(bdev);
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index c850d7f44fbe..f2e7543e9913 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -2894,8 +2894,7 @@ static int btrfs_check_uuid_tree(struct btrfs_fs_info *fs_info)
 	return 0;
 }
 
-int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_devices,
-		      char *options)
+int __cold open_ctree(struct fs_context *fc, struct super_block *sb)
 {
 	u32 sectorsize;
 	u32 nodesize;
@@ -2905,6 +2904,7 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device
 	u16 csum_type;
 	struct btrfs_super_block *disk_super;
 	struct btrfs_fs_info *fs_info = btrfs_sb(sb);
+	struct btrfs_fs_devices *fs_devices = fs_info->fs_devices;
 	struct btrfs_root *tree_root;
 	struct btrfs_root *chunk_root;
 	int ret;
@@ -3030,11 +3030,9 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device
 	 */
 	fs_info->compress_type = BTRFS_COMPRESS_ZLIB;
 
-	ret = btrfs_parse_options(fs_info, options, sb->s_flags);
-	if (ret) {
-		err = ret;
+	err = btrfs_apply_configuration(fc, sb);
+	if (err)
 		goto fail_alloc;
-	}
 
 	features = btrfs_super_incompat_flags(disk_super) &
 		~BTRFS_FEATURE_INCOMPAT_SUPP;
diff --git a/fs/btrfs/disk-io.h b/fs/btrfs/disk-io.h
index 00dc39d47ed3..712ea61ffdfe 100644
--- a/fs/btrfs/disk-io.h
+++ b/fs/btrfs/disk-io.h
@@ -50,9 +50,7 @@ struct extent_buffer *btrfs_find_create_tree_block(
 						struct btrfs_fs_info *fs_info,
 						u64 bytenr);
 void btrfs_clean_tree_block(struct extent_buffer *buf);
-int __cold open_ctree(struct super_block *sb,
-	       struct btrfs_fs_devices *fs_devices,
-	       char *options);
+int __cold open_ctree(struct fs_context *fc, struct super_block *sb);
 void __cold close_ctree(struct btrfs_fs_info *fs_info);
 int write_all_supers(struct btrfs_fs_info *fs_info, int max_mirrors);
 struct btrfs_super_block *btrfs_read_dev_super(struct block_device *bdev);
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index 5bbf4b947125..d9a0faea8c88 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -63,10 +63,9 @@ static const struct super_operations btrfs_super_ops;
  *
  * The new btrfs_root_fs_type also servers as a tag for the bdev_holder.
  */
-static struct file_system_type btrfs_fs_type;
 static struct file_system_type btrfs_root_fs_type;
 
-static int btrfs_remount(struct super_block *sb, int *flags, char *data);
+static int btrfs_reconfigure(struct fs_context *fc);
 
 /*
  * Generally the error codes correspond to their respective errors, but there
@@ -1542,7 +1541,7 @@ static int btrfs_parse_device_options(const char *options, fmode_t flags,
 				goto out;
 			}
 			device = btrfs_scan_one_device(device_name, flags,
-					holder);
+							&btrfs_fs_type);
 			kfree(device_name);
 			if (IS_ERR(device)) {
 				error = PTR_ERR(device);
@@ -1795,13 +1794,13 @@ static int get_default_subvol_objectid(struct btrfs_fs_info *fs_info, u64 *objec
 	return 0;
 }
 
-static int btrfs_fill_super(struct super_block *sb,
-			    struct btrfs_fs_devices *fs_devices,
-			    void *data)
+static int btrfs_fill_super(struct fs_context *fc,
+			struct super_block *sb,
+			struct btrfs_fs_devices *fs_devices)
 {
+	int err;
 	struct inode *inode;
 	struct btrfs_fs_info *fs_info = btrfs_sb(sb);
-	int err;
 
 	sb->s_maxbytes = MAX_LFS_FILESIZE;
 	sb->s_magic = BTRFS_SUPER_MAGIC;
@@ -1810,9 +1809,6 @@ static int btrfs_fill_super(struct super_block *sb,
 	sb->s_export_op = &btrfs_export_ops;
 	sb->s_xattr = btrfs_xattr_handlers;
 	sb->s_time_gran = 1;
-#ifdef CONFIG_BTRFS_FS_POSIX_ACL
-	sb->s_flags |= SB_POSIXACL;
-#endif
 	sb->s_flags |= SB_I_VERSION;
 	sb->s_iflags |= SB_I_CGROUPWB;
 
@@ -1822,7 +1818,7 @@ static int btrfs_fill_super(struct super_block *sb,
 		return err;
 	}
 
-	err = open_ctree(sb, fs_devices, (char *)data);
+	err = open_ctree(fc, sb);
 	if (err) {
 		btrfs_err(fs_info, "open_ctree failed");
 		return err;
@@ -1951,19 +1947,20 @@ int btrfs_apply_configuration(struct fs_context *fc,
 #endif
 
 #ifdef CONFIG_BTRFS_FS_REF_VERIFY
-       if (btrfs_test_exp_opt(ctx, REF_VERIFY))
-               btrfs_info(info, "doing ref verification");
+	if (btrfs_test_exp_opt(ctx, REF_VERIFY))
+		btrfs_info(info, "doing ref verification");
 #endif
 
+	info->pending_changes = ctx->pending_changes;
 	if (btrfs_test_exp_opt(ctx, INODE_MAP_CACHE)) {
-		if (btrfs_opt_map[Opt_inode_cache].enabled) {
-		       btrfs_clear_pending_and_info(info, INODE_MAP_CACHE,
-				       "disabling inode map caching");
+		if (!btrfs_opt_map[Opt_inode_cache].enabled) {
+			btrfs_clear_pending_and_info(info, INODE_MAP_CACHE,
+						"disabling inode map caching");
 		} else {
 			btrfs_info(info,
 				"the 'inode_cache' option is deprecated and will have no effect from 5.11");
 			btrfs_set_pending_and_info(info, INODE_MAP_CACHE,
-				       "enabling inode map caching");
+						"enabling inode map caching");
 		}
 	}
 
@@ -2015,10 +2012,9 @@ int btrfs_apply_configuration(struct fs_context *fc,
 	if (btrfs_fs_compat_ro(info, FREE_SPACE_TREE)) {
 		bool opt_clear = btrfs_test_opt(ctx, CLEAR_CACHE);
 		bool opt_cache_v1 = btrfs_test_opt(ctx, SPACE_CACHE);
-		bool no_space_cache = ctx->nospace_cache;
 
-		if ((no_space_cache && !opt_clear) || (opt_cache_v1 && !opt_clear)) {
-			btrfs_err(info, "cannot disable free space tree XX");
+		if ((ctx->nospace_cache && !opt_clear) || (opt_cache_v1 && !opt_clear)) {
+			btrfs_err(info, "cannot disable free space tree");
 			return -EINVAL;
 		}
 	}
@@ -2063,7 +2059,6 @@ int btrfs_apply_configuration(struct fs_context *fc,
 
 	info->compress_type = ctx->compress_type;
 	info->compress_level = ctx->compress_level;
-	info->pending_changes = ctx->pending_changes;
 	info->mount_opt = ctx->mount_opt;
 
 	return 0;
@@ -2213,9 +2208,9 @@ static int btrfs_show_options(struct seq_file *seq, struct dentry *dentry)
 	return 0;
 }
 
-static int btrfs_test_super(struct super_block *s, void *data)
+static int btrfs_test_super(struct super_block *s, struct fs_context *fc)
 {
-	struct btrfs_fs_info *p = data;
+	struct btrfs_fs_info *p = fc->s_fs_info;
 	struct btrfs_fs_info *fs_info = btrfs_sb(s);
 
 	return fs_info->fs_devices == p->fs_devices;
@@ -2239,34 +2234,34 @@ static inline int is_subvolume_inode(struct inode *inode)
 	return 0;
 }
 
-static struct dentry *mount_subvol(const char *subvol_name, u64 subvol_objectid,
-				   struct vfsmount *mnt)
+static int mount_subvol(struct fs_context *fc)
 {
+	struct btrfs_fs_context *ctx = fc->fs_private;
+	struct vfsmount *mnt = ctx->root_mnt;
 	struct dentry *root;
 	int ret;
 
-	if (!subvol_name) {
-		if (!subvol_objectid) {
+	if (!ctx->subvol_name) {
+		char *subvol_name;
+
+		if (!ctx->subvolid) {
 			ret = get_default_subvol_objectid(btrfs_sb(mnt->mnt_sb),
-							  &subvol_objectid);
-			if (ret) {
-				root = ERR_PTR(ret);
-				goto out;
-			}
+							  &ctx->subvolid);
+			if (ret)
+				return ret;
 		}
 		subvol_name = btrfs_get_subvol_name_from_objectid(
-					btrfs_sb(mnt->mnt_sb), subvol_objectid);
-		if (IS_ERR(subvol_name)) {
-			root = ERR_CAST(subvol_name);
-			subvol_name = NULL;
-			goto out;
-		}
+							btrfs_sb(mnt->mnt_sb),
+							ctx->subvolid);
+		if (IS_ERR(subvol_name))
+			return PTR_ERR(subvol_name);
 
+		ctx->subvol_name = subvol_name;
 	}
 
-	root = mount_subtree(mnt, subvol_name);
-	/* mount_subtree() drops our reference on the vfsmount. */
-	mnt = NULL;
+	root = mount_subtree(mnt, ctx->subvol_name);
+	/* mount_subtree() dropped our reference on the vfsmount. */
+	ctx->root_mnt = NULL;
 
 	if (!IS_ERR(root)) {
 		struct super_block *s = root->d_sb;
@@ -2277,10 +2272,10 @@ static struct dentry *mount_subvol(const char *subvol_name, u64 subvol_objectid,
 		ret = 0;
 		if (!is_subvolume_inode(root_inode)) {
 			btrfs_err(fs_info, "'%s' is not a valid subvolume",
-			       subvol_name);
+			       ctx->subvol_name);
 			ret = -EINVAL;
 		}
-		if (subvol_objectid && root_objectid != subvol_objectid) {
+		if (ctx->subvolid && root_objectid != ctx->subvolid) {
 			/*
 			 * This will also catch a race condition where a
 			 * subvolume which was passed by ID is renamed and
@@ -2288,20 +2283,23 @@ static struct dentry *mount_subvol(const char *subvol_name, u64 subvol_objectid,
 			 */
 			btrfs_err(fs_info,
 				  "subvol '%s' does not match subvolid %llu",
-				  subvol_name, subvol_objectid);
+				  ctx->subvol_name, ctx->subvolid);
 			ret = -EINVAL;
 		}
 		if (ret) {
 			dput(root);
-			root = ERR_PTR(ret);
 			deactivate_locked_super(s);
+			goto out;
 		}
+	} else {
+		return PTR_ERR(root);
 	}
 
+	fc->root = root;
+	ret = 0;
+
 out:
-	mntput(mnt);
-	kfree(subvol_name);
-	return root;
+	return ret;
 }
 
 /*
@@ -2310,27 +2308,20 @@ static struct dentry *mount_subvol(const char *subvol_name, u64 subvol_objectid,
  * Note: This is based on mount_bdev from fs/super.c with a few additions
  *       for multiple device setup.  Make sure to keep it in sync.
  */
-static struct dentry *btrfs_mount_root(struct file_system_type *fs_type,
-		int flags, const char *device_name, void *data)
+static int btrfs_root_get_tree(struct fs_context *fc)
 {
-	struct block_device *bdev = NULL;
+	struct block_device *bdev;
 	struct super_block *s;
+	struct btrfs_fs_context *ctx = fc->fs_private;
 	struct btrfs_device *device = NULL;
 	struct btrfs_fs_devices *fs_devices = NULL;
 	struct btrfs_fs_info *fs_info = NULL;
-	void *new_sec_opts = NULL;
 	fmode_t mode = FMODE_READ;
-	int error = 0;
+	int error = 0, i;
 
-	if (!(flags & SB_RDONLY))
+	if (!(fc->sb_flags & SB_RDONLY))
 		mode |= FMODE_WRITE;
 
-	if (data) {
-		error = security_sb_eat_lsm_opts(data, &new_sec_opts);
-		if (error)
-			return ERR_PTR(error);
-	}
-
 	/*
 	 * Setup a dummy root and fs_info for test/set super.  This is because
 	 * we don't actually fill this stuff out until open_ctree, but we need
@@ -2340,10 +2331,9 @@ static struct dentry *btrfs_mount_root(struct file_system_type *fs_type,
 	 * superblock with our given fs_devices later on at sget() time.
 	 */
 	fs_info = kvzalloc(sizeof(struct btrfs_fs_info), GFP_KERNEL);
-	if (!fs_info) {
-		error = -ENOMEM;
-		goto error_sec_opts;
-	}
+	if (!fs_info)
+		return -ENOMEM;
+
 	btrfs_init_fs_info(fs_info);
 
 	fs_info->super_copy = kzalloc(BTRFS_SUPER_INFO_SIZE, GFP_KERNEL);
@@ -2354,13 +2344,20 @@ static struct dentry *btrfs_mount_root(struct file_system_type *fs_type,
 	}
 
 	mutex_lock(&uuid_mutex);
-	error = btrfs_parse_device_options(data, mode, fs_type);
-	if (error) {
-		mutex_unlock(&uuid_mutex);
-		goto error_fs_info;
+
+	if (ctx->devices) {
+		for (i = 0; i < ctx->nr_devices; i++) {
+			device = btrfs_scan_one_device(ctx->devices[i], mode,
+							&btrfs_fs_type);
+			if (IS_ERR(device)) {
+				mutex_unlock(&uuid_mutex);
+				error = PTR_ERR(device);
+				goto error_fs_info;
+			}
+		}
 	}
 
-	device = btrfs_scan_one_device(device_name, mode, fs_type);
+	device = btrfs_scan_one_device(fc->source, mode, &btrfs_fs_type);
 	if (IS_ERR(device)) {
 		mutex_unlock(&uuid_mutex);
 		error = PTR_ERR(device);
@@ -2370,53 +2367,49 @@ static struct dentry *btrfs_mount_root(struct file_system_type *fs_type,
 	fs_devices = device->fs_devices;
 	fs_info->fs_devices = fs_devices;
 
-	error = btrfs_open_devices(fs_devices, mode, fs_type);
+	error = btrfs_open_devices(fs_devices, mode, &btrfs_fs_type);
 	mutex_unlock(&uuid_mutex);
 	if (error)
 		goto error_fs_info;
 
-	if (!(flags & SB_RDONLY) && fs_devices->rw_devices == 0) {
+
+	if (!(fc->sb_flags & SB_RDONLY) && fs_devices->rw_devices == 0) {
 		error = -EACCES;
 		goto error_close_devices;
 	}
 
 	bdev = fs_devices->latest_bdev;
-	s = sget(fs_type, btrfs_test_super, btrfs_set_super, flags | SB_NOSEC,
-		 fs_info);
+
+	fc->s_fs_info = fs_info;
+	s = sget_fc(fc, btrfs_test_super, set_anon_super_fc);
 	if (IS_ERR(s)) {
 		error = PTR_ERR(s);
 		goto error_close_devices;
 	}
 
+	 /* sget_fc returned a previously allocated superblocl. */
 	if (s->s_root) {
-		btrfs_close_devices(fs_devices);
-		btrfs_free_fs_info(fs_info);
-		if ((flags ^ s->s_flags) & SB_RDONLY)
+		btrfs_close_devices(fs_info->fs_devices);
+		if ((fc->sb_flags ^ s->s_flags) & SB_RDONLY)
 			error = -EBUSY;
 	} else {
 		snprintf(s->s_id, sizeof(s->s_id), "%pg", bdev);
-		btrfs_sb(s)->bdev_holder = fs_type;
-		if (!strstr(crc32c_impl(), "generic"))
-			set_bit(BTRFS_FS_CSUM_IMPL_FAST, &fs_info->flags);
-		error = btrfs_fill_super(s, fs_devices, data);
-	}
-	if (!error)
-		error = security_sb_set_mnt_opts(s, new_sec_opts, 0, NULL);
-	security_free_mnt_opts(&new_sec_opts);
-	if (error) {
-		deactivate_locked_super(s);
-		return ERR_PTR(error);
+		error = btrfs_fill_super(fc, s, fs_devices);
 	}
 
-	return dget(s->s_root);
+	if (error)
+		goto error_super;
+
+	fc->root = dget(s->s_root);
+	return 0;
 
+error_super:
+	deactivate_locked_super(s);
 error_close_devices:
 	btrfs_close_devices(fs_devices);
 error_fs_info:
-	btrfs_free_fs_info(fs_info);
-error_sec_opts:
-	security_free_mnt_opts(&new_sec_opts);
-	return ERR_PTR(error);
+	/*btrfs_free_fs_info(fs_info);*/
+	return error;
 }
 
 /*
@@ -2424,7 +2417,7 @@ static struct dentry *btrfs_mount_root(struct file_system_type *fs_type,
  * btrfs_get_tree will be called recursively, but then will check for the
  * ctx->root being set and call btrfs_root_get_tree.
  */
-static int btrfs_mount_root_fc(struct fs_context *fc, unsigned int rdonly)
+int btrfs_mount_root_fc(struct fs_context *fc, unsigned int rdonly)
 {
 	struct btrfs_fs_context *ctx, *root_ctx;
 	struct fs_context *root_fc;
@@ -2460,81 +2453,76 @@ static int btrfs_mount_root_fc(struct fs_context *fc, unsigned int rdonly)
 	return ret;
 }
 
+static int btrfs_reconfigure_root_to_rw(struct fs_context *fc,
+					struct super_block *sb)
+{
+	int error;
+	struct fs_context root_fc = {
+		.purpose	= FS_CONTEXT_FOR_RECONFIGURE,
+		.fs_type	= sb->s_type,
+		.root		= sb->s_root,
+		.log		= fc->log,
+		.sb_flags	= 0,
+		.sb_flags_mask	= SB_RDONLY,
+	};
+
+	down_write(&sb->s_umount);
+	error = btrfs_reconfigure(&root_fc);
+	up_write(&sb->s_umount);
+	return error;
+}
+
 /*
- * Mount function which is called by VFS layer.
+ * Mount function which is called by VFS layer after the argument parsing.
  *
  * In order to allow mounting a subvolume directly, btrfs uses mount_subtree()
  * which needs vfsmount* of device's root (/).  This means device's root has to
  * be mounted internally in any case.
  *
  * Operation flow:
- *   1. Parse subvol id related options for later use in mount_subvol().
- *
- *   2. Mount device's root (/) by calling vfs_kern_mount().
+ *   1. Mount device's root (/) by calling btrfs_mount_root_fc.
  *
- *      NOTE: vfs_kern_mount() is used by VFS to call btrfs_mount() in the
- *      first place. In order to avoid calling btrfs_mount() again, we use
- *      different file_system_type which is not registered to VFS by
- *      register_filesystem() (btrfs_root_fs_type). As a result,
- *      btrfs_mount_root() is called. The return value will be used by
- *      mount_subtree() in mount_subvol().
+ *   2. btrfs_get_tree is called recursively by btrfs_mount_fc -> fc_mount ->
+ *      btrfs_get_tree, because we use the same file_system_type for both root and
+ *      subvol mounts. We avoid the infinite recursive calls by checking the
+ *      ctx->root member being set, which shows that we are trying to mount the
+ *      root fs.
  *
  *   3. Call mount_subvol() to get the dentry of subvolume. Since there is
  *      "btrfs subvolume set-default", mount_subvol() is called always.
  */
-static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags,
-		const char *device_name, void *data)
+static int btrfs_get_tree(struct fs_context *fc)
 {
-	struct vfsmount *mnt_root;
-	struct dentry *root;
-	char *subvol_name = NULL;
-	u64 subvol_objectid = 0;
-	int error = 0;
+	struct btrfs_fs_context *ctx = fc->fs_private;
+	int error = btrfs_fc_validate(fc);
 
-	error = btrfs_parse_subvol_options(data, &subvol_name,
-					&subvol_objectid);
-	if (error) {
-		kfree(subvol_name);
-		return ERR_PTR(error);
-	}
+	if (error)
+		return error;
 
-	/* mount device's root (/) */
-	mnt_root = vfs_kern_mount(&btrfs_root_fs_type, flags, device_name, data);
-	if (PTR_ERR_OR_ZERO(mnt_root) == -EBUSY) {
-		if (flags & SB_RDONLY) {
-			mnt_root = vfs_kern_mount(&btrfs_root_fs_type,
-				flags & ~SB_RDONLY, device_name, data);
-		} else {
-			mnt_root = vfs_kern_mount(&btrfs_root_fs_type,
-				flags | SB_RDONLY, device_name, data);
-			if (IS_ERR(mnt_root)) {
-				root = ERR_CAST(mnt_root);
-				kfree(subvol_name);
-				goto out;
-			}
+	if (!fc->source)
+		return invalf(fc, "No source specified");
 
-			down_write(&mnt_root->mnt_sb->s_umount);
-			error = btrfs_remount(mnt_root->mnt_sb, &flags, NULL);
-			up_write(&mnt_root->mnt_sb->s_umount);
-			if (error < 0) {
-				root = ERR_PTR(error);
-				mntput(mnt_root);
-				kfree(subvol_name);
-				goto out;
-			}
+	if (ctx->root)
+		return btrfs_root_get_tree(fc);
+
+	/* mount device's root (/) */
+	error = btrfs_mount_root_fc(fc, fc->sb_flags & SB_RDONLY);
+	if (error == -EBUSY) {
+		/*
+		 * If returned EBUSY, try again the mount inverting the rdonly
+		 * argument of btrfs_mount_root.
+		 */
+		error = btrfs_mount_root_fc(fc, (fc->sb_flags & SB_RDONLY) ^ SB_RDONLY);
+		if (!error && !(fc->sb_flags & SB_RDONLY)) {
+			error = btrfs_reconfigure_root_to_rw(fc,
+						ctx->root_mnt->mnt_sb);
 		}
 	}
-	if (IS_ERR(mnt_root)) {
-		root = ERR_CAST(mnt_root);
-		kfree(subvol_name);
-		goto out;
-	}
 
-	/* mount_subvol() will free subvol_name and mnt_root */
-	root = mount_subvol(subvol_name, subvol_objectid, mnt_root);
+	if (error < 0)
+		return error;
 
-out:
-	return root;
+	return mount_subvol(fc);
 }
 
 static void btrfs_resize_thread_pool(struct btrfs_fs_info *fs_info,
@@ -2598,8 +2586,16 @@ static inline void btrfs_remount_cleanup(struct btrfs_fs_info *fs_info,
 		btrfs_discard_cleanup(fs_info);
 }
 
-static int btrfs_remount(struct super_block *sb, int *flags, char *data)
+/*
+ * Change the configuration of an active superblock according to the supplied
+ * parameters.  Note that the parameter pointer (fc->fs_private) may be NULL in
+ * the case of umount detach, emergency remount R/O and get_tree remounting as
+ * R/W.
+ */
+int btrfs_reconfigure(struct fs_context *fc)
 {
+	struct btrfs_fs_context *ctx = fc->fs_private;
+	struct super_block *sb = fc->root->d_sb;
 	struct btrfs_fs_info *fs_info = btrfs_sb(sb);
 	struct btrfs_root *root = fs_info->tree_root;
 	unsigned old_flags = sb->s_flags;
@@ -2608,34 +2604,28 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data)
 	u64 old_max_inline = fs_info->max_inline;
 	u32 old_thread_pool_size = fs_info->thread_pool_size;
 	u32 old_metadata_ratio = fs_info->metadata_ratio;
-	int ret;
+	int ret = btrfs_fc_validate(fc);
+
+	if (ret)
+		return ret;
 
 	sync_filesystem(sb);
 	set_bit(BTRFS_FS_STATE_REMOUNTING, &fs_info->fs_state);
-
-	if (data) {
-		void *new_sec_opts = NULL;
-
-		ret = security_sb_eat_lsm_opts(data, &new_sec_opts);
-		if (!ret)
-			ret = security_sb_remount(sb, new_sec_opts);
-		security_free_mnt_opts(&new_sec_opts);
+	if (ctx) {
+		ret = btrfs_apply_configuration(fc, sb);
 		if (ret)
 			goto restore;
 	}
 
-	ret = btrfs_parse_options(fs_info, data, *flags);
-	if (ret)
-		goto restore;
+	btrfs_remount_begin(fs_info, old_opts, fc->sb_flags);
+	if (ctx && ctx->thread_pool_size)
+		btrfs_resize_thread_pool(fs_info, ctx->thread_pool_size,
+					old_thread_pool_size);
 
-	btrfs_remount_begin(fs_info, old_opts, *flags);
-	btrfs_resize_thread_pool(fs_info,
-		fs_info->thread_pool_size, old_thread_pool_size);
-
-	if ((bool)(*flags & SB_RDONLY) == sb_rdonly(sb))
+	if ((bool)(fc->sb_flags & SB_RDONLY) == sb_rdonly(sb))
 		goto out;
 
-	if (*flags & SB_RDONLY) {
+	if (fc->sb_flags & SB_RDONLY) {
 		/*
 		 * this also happens on 'umount -rf' or on shutdown, when
 		 * the filesystem is busy.
@@ -2735,7 +2725,7 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data)
 	 * We need to set SB_I_VERSION here otherwise it'll get cleared by VFS,
 	 * since the absence of the flag means it can be toggled off by remount.
 	 */
-	*flags |= SB_I_VERSION;
+	fc->sb_flags |= SB_I_VERSION;
 
 	wake_up_process(fs_info->transaction_kthread);
 	btrfs_remount_cleanup(fs_info, old_opts);
@@ -3058,9 +3048,11 @@ static void btrfs_fc_free(struct fs_context *fc)
 }
 
 static const struct fs_context_operations btrfs_context_ops = {
-	.dup = btrfs_dup_fc,
-	.free = btrfs_fc_free,
-	.parse_param = btrfs_fc_parse_param,
+	.dup		= btrfs_dup_fc,
+	.free		= btrfs_fc_free,
+	.get_tree	= btrfs_get_tree,
+	.parse_param	= btrfs_fc_parse_param,
+	.reconfigure	= btrfs_reconfigure,
 };
 
 static int btrfs_init_fs_context(struct fs_context *fc)
@@ -3072,7 +3064,6 @@ static int btrfs_init_fs_context(struct fs_context *fc)
 		return -ENOMEM;
 
 	/* currently default options */
-	btrfs_set_opt(ctx->mount_opt, SPACE_CACHE);
 #ifdef CONFIG_BTRFS_FS_POSIX_ACL
 	fc->sb_flags |= SB_POSIXACL;
 #endif
@@ -3083,19 +3074,18 @@ static int btrfs_init_fs_context(struct fs_context *fc)
 	return 0;
 }
 
-static struct file_system_type btrfs_fs_type = {
+struct file_system_type btrfs_fs_type = {
 	.owner		= THIS_MODULE,
 	.name		= "btrfs",
-	.mount		= btrfs_mount,
 	.parameters	= btrfs_fs_parameters,
+	.init_fs_context = btrfs_init_fs_context,
 	.kill_sb	= btrfs_kill_super,
 	.fs_flags	= FS_REQUIRES_DEV | FS_BINARY_MOUNTDATA,
-};
+	};
 
 static struct file_system_type btrfs_root_fs_type = {
 	.owner		= THIS_MODULE,
 	.name		= "btrfs",
-	.mount		= btrfs_mount_root,
 	.parameters	= btrfs_fs_parameters,
 	.kill_sb	= btrfs_kill_super,
 	.fs_flags	= FS_REQUIRES_DEV | FS_BINARY_MOUNTDATA,
@@ -3136,7 +3126,7 @@ static long btrfs_control_ioctl(struct file *file, unsigned int cmd,
 	case BTRFS_IOC_SCAN_DEV:
 		mutex_lock(&uuid_mutex);
 		device = btrfs_scan_one_device(vol->name, FMODE_READ,
-					       &btrfs_root_fs_type);
+							&btrfs_fs_type);
 		ret = PTR_ERR_OR_ZERO(device);
 		mutex_unlock(&uuid_mutex);
 		break;
@@ -3146,7 +3136,7 @@ static long btrfs_control_ioctl(struct file *file, unsigned int cmd,
 	case BTRFS_IOC_DEVICES_READY:
 		mutex_lock(&uuid_mutex);
 		device = btrfs_scan_one_device(vol->name, FMODE_READ,
-					       &btrfs_root_fs_type);
+							&btrfs_fs_type);
 		if (IS_ERR(device)) {
 			mutex_unlock(&uuid_mutex);
 			ret = PTR_ERR(device);
@@ -3237,7 +3227,6 @@ static const struct super_operations btrfs_super_ops = {
 	.destroy_inode	= btrfs_destroy_inode,
 	.free_inode	= btrfs_free_inode,
 	.statfs		= btrfs_statfs,
-	.remount_fs	= btrfs_remount,
 	.freeze_fs	= btrfs_freeze,
 	.unfreeze_fs	= btrfs_unfreeze,
 };
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index d7670e2a9f39..59ba27e82615 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -2304,7 +2304,7 @@ static struct btrfs_device *btrfs_find_device_by_path(
 	struct btrfs_device *device;
 
 	ret = btrfs_get_bdev_and_sb(device_path, FMODE_READ,
-				    fs_info->bdev_holder, 0, &bdev, &disk_super);
+				    &btrfs_fs_type, 0, &bdev, &disk_super);
 	if (ret)
 		return ERR_PTR(ret);
 
@@ -2516,7 +2516,7 @@ int btrfs_init_new_device(struct btrfs_fs_info *fs_info, const char *device_path
 		return -EROFS;
 
 	bdev = blkdev_get_by_path(device_path, FMODE_WRITE | FMODE_EXCL,
-				  fs_info->bdev_holder);
+				  &btrfs_fs_type);
 	if (IS_ERR(bdev))
 		return PTR_ERR(bdev);
 
@@ -6739,7 +6739,7 @@ static struct btrfs_fs_devices *open_seed_devices(struct btrfs_fs_info *fs_info,
 	if (IS_ERR(fs_devices))
 		return fs_devices;
 
-	ret = open_fs_devices(fs_devices, FMODE_READ, fs_info->bdev_holder);
+	ret = open_fs_devices(fs_devices, FMODE_READ, &btrfs_fs_type);
 	if (ret) {
 		free_fs_devices(fs_devices);
 		fs_devices = ERR_PTR(ret);
-- 
2.28.0


  parent reply	other threads:[~2020-08-12 16:59 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-08-12 16:36 [RFC PATCH 0/8] btrfs: convert to fscontext Marcos Paulo de Souza
2020-08-12 16:36 ` [RFC PATCH 1/8] btrfs: fs_context: Add initial fscontext parameters Marcos Paulo de Souza
2020-08-12 16:36 ` [RFC PATCH 2/8] btrfs: super: Introduce fs_context ops, init and free functions Marcos Paulo de Souza
2020-08-17 12:50   ` David Sterba
2020-08-12 16:36 ` [RFC PATCH 3/8] btrfs: super: Introduce btrfs_fc_parse_param and btrfs_apply_configuration Marcos Paulo de Souza
2020-08-17 13:09   ` David Sterba
2020-08-12 16:36 ` [RFC PATCH 4/8] btrfs: super: Introduce btrfs_fc_validate Marcos Paulo de Souza
2020-08-12 16:36 ` [RFC PATCH 5/8] btrfs: super: Introduce btrfs_dup_fc Marcos Paulo de Souza
2020-08-12 16:36 ` [RFC PATCH 6/8] btrfs: super: Introduce btrfs_mount_root_fc Marcos Paulo de Souza
2020-08-17 13:14   ` David Sterba
2020-08-12 16:36 ` Marcos Paulo de Souza [this message]
2020-08-17 13:26   ` [RFC PATCH 7/8] btrfs: Convert to fs_context David Sterba
2020-08-12 16:36 ` [RFC PATCH 8/8] btrfs: Remove leftover code from fscontext conversion Marcos Paulo de Souza
2020-08-17 12:44 ` [RFC PATCH 0/8] btrfs: convert to fscontext David Sterba

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200812163654.17080-8-marcos@mpdesouza.com \
    --to=marcos@mpdesouza.com \
    --cc=dsterba@suse.com \
    --cc=linux-btrfs@vger.kernel.org \
    --cc=mpdesouza@suse.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).