All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC PATCH 0/8] btrfs: convert to fscontext
@ 2020-08-12 16:36 Marcos Paulo de Souza
  2020-08-12 16:36 ` [RFC PATCH 1/8] btrfs: fs_context: Add initial fscontext parameters Marcos Paulo de Souza
                   ` (8 more replies)
  0 siblings, 9 replies; 15+ messages in thread
From: Marcos Paulo de Souza @ 2020-08-12 16:36 UTC (permalink / raw)
  To: dsterba, linux-btrfs; +Cc: Marcos Paulo de Souza

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

These patches aim to convert btrfs to new fscontext API. I used the approach of
creating a new parsing function and then switching to this new function, instead
of creating a huge change patch. Please let me know if you think this is a
better approach.

The most notable changes come form the fact that now we parse the mount options
before having a fs_info, in the same way that David Howells did in his POC[1]
some time ago.

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

Marcos Paulo de Souza (8):
  btrfs: fs_context: Add initial fscontext parameters
  btrfs: super: Introduce fs_context ops, init and free functions
  btrfs: super: Introduce btrfs_fc_parse_param and
    btrfs_apply_configuration
  btrfs: super: Introduce btrfs_fc_validate
  btrfs: super: Introduce btrfs_dup_fc
  btrfs: super: Introduce btrfs_mount_root_fc
  btrfs: Convert to fs_context
  btrfs: Remove leftover code from fscontext conversion

 fs/btrfs/ctree.h       |   29 +
 fs/btrfs/dev-replace.c |    2 +-
 fs/btrfs/disk-io.c     |   10 +-
 fs/btrfs/disk-io.h     |    4 +-
 fs/btrfs/super.c       | 1819 +++++++++++++++++++++-------------------
 fs/btrfs/volumes.c     |    6 +-
 6 files changed, 974 insertions(+), 896 deletions(-)

-- 
2.28.0


^ permalink raw reply	[flat|nested] 15+ messages in thread

* [RFC PATCH 1/8] btrfs: fs_context: Add initial fscontext parameters
  2020-08-12 16:36 [RFC PATCH 0/8] btrfs: convert to fscontext Marcos Paulo de Souza
@ 2020-08-12 16:36 ` 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
                   ` (7 subsequent siblings)
  8 siblings, 0 replies; 15+ messages in thread
From: Marcos Paulo de Souza @ 2020-08-12 16:36 UTC (permalink / raw)
  To: dsterba, linux-btrfs; +Cc: Marcos Paulo de Souza

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

The same old parameters but now using the fs_parameter_spec form. As
the fscontext has a flag_no variant we don't need to map the Opt_no*
version of the same flags.

Opt_fragment is added as a generic entry point for all fragment type to
be used only in fscontext argument parser.

Signed-off-by: Marcos Paulo de Souza <mpdesouza@suse.com>
---
 fs/btrfs/super.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 63 insertions(+)

diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index 53639de3a064..4e6654af90ea 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -6,6 +6,7 @@
 #include <linux/blkdev.h>
 #include <linux/module.h>
 #include <linux/fs.h>
+#include <linux/fs_parser.h>
 #include <linux/pagemap.h>
 #include <linux/highmem.h>
 #include <linux/time.h>
@@ -370,6 +371,7 @@ enum {
 	Opt_check_integrity_print_mask,
 	Opt_enospc_debug, Opt_noenospc_debug,
 #ifdef CONFIG_BTRFS_DEBUG
+	Opt_fragment,
 	Opt_fragment_data, Opt_fragment_metadata, Opt_fragment_all,
 #endif
 #ifdef CONFIG_BTRFS_FS_REF_VERIFY
@@ -458,6 +460,65 @@ static const match_table_t rescue_tokens = {
 	{Opt_err, NULL},
 };
 
+static const struct fs_parameter_spec btrfs_fs_parameters[] = {
+	fsparam_flag_no("acl", Opt_acl),
+	fsparam_flag_no("autodefrag", Opt_defrag),
+	fsparam_flag_no("barrier", Opt_barrier),
+	fsparam_flag("clear_cache", Opt_clear_cache),
+	fsparam_u32("commit", Opt_commit_interval),
+	fsparam_flag("compress", Opt_compress),
+	fsparam_string("compress", Opt_compress_type),
+	fsparam_flag("compress-force", Opt_compress_force),
+	fsparam_string("compress-force", Opt_compress_force_type),
+	fsparam_flag_no("datacow", Opt_datacow),
+	fsparam_flag_no("datasum", Opt_datasum),
+	fsparam_flag("degraded", Opt_degraded),
+	fsparam_string("device", Opt_device),
+	fsparam_flag_no("discard", Opt_discard),
+	fsparam_string("discard", Opt_discard_mode),
+	fsparam_string("fatal_errors", Opt_fatal_errors),
+	fsparam_flag_no("flushoncommit", Opt_flushoncommit),
+	fsparam_flag_no("inode_cache", Opt_inode_cache),
+	fsparam_string("max_inline", Opt_max_inline),
+	fsparam_u32("metadata_ratio", Opt_ratio),
+	fsparam_flag("norecovery", Opt_norecovery),
+	fsparam_flag("rescan_uuid_tree", Opt_rescan_uuid_tree),
+	fsparam_flag("skip_balance", Opt_skip_balance),
+	fsparam_flag_no("space_cache", Opt_space_cache),
+	fsparam_string("space_cache", Opt_space_cache_version),
+	fsparam_string("subvol", Opt_subvol),
+	fsparam_u64("subvolid", Opt_subvolid),
+	fsparam_flag_no("ssd", Opt_ssd),
+	fsparam_flag_no("ssd_spread", Opt_ssd_spread),
+	fsparam_u32("thread_pool", Opt_thread_pool),
+	fsparam_flag_no("treelog", Opt_treelog),
+	fsparam_flag("user_subvol_rm_allowed", Opt_user_subvol_rm_allowed),
+
+	/* Debugging options */
+	fsparam_flag("check_int", Opt_check_integrity),
+	fsparam_flag("check_int_data", Opt_check_integrity_including_extent_data),
+	fsparam_u32("check_int_print_mask", Opt_check_integrity_print_mask),
+
+	/* Rescue options */
+	fsparam_string("rescue", Opt_rescue),
+	/* Deprecated, with alias rescue=nologreplay */
+	fsparam_flag("nologreplay", Opt_nologreplay),
+	/* Deprecated, with alias rescue=usebackuproot */
+	fsparam_flag("usebackuproot", Opt_usebackuproot),
+
+	/* Deprecated options */
+	fsparam_flag("recovery", Opt_recovery),
+	fsparam_flag_no("enospc_debug", Opt_enospc_debug),
+
+ #ifdef CONFIG_BTRFS_DEBUG
+	fsparam_string("fragment", Opt_fragment),
+ #endif
+ #ifdef CONFIG_BTRFS_FS_REF_VERIFY
+	fsparam_flag("ref_verify", Opt_ref_verify),
+ #endif
+	{}
+};
+
 static int parse_rescue_options(struct btrfs_fs_info *info, const char *options)
 {
 	char *opts;
@@ -2269,6 +2330,7 @@ static struct file_system_type btrfs_fs_type = {
 	.owner		= THIS_MODULE,
 	.name		= "btrfs",
 	.mount		= btrfs_mount,
+	.parameters	= btrfs_fs_parameters,
 	.kill_sb	= btrfs_kill_super,
 	.fs_flags	= FS_REQUIRES_DEV | FS_BINARY_MOUNTDATA,
 };
@@ -2277,6 +2339,7 @@ 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,
 };
-- 
2.28.0


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [RFC PATCH 2/8] btrfs: super: Introduce fs_context ops, init and free functions
  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 ` 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
                   ` (6 subsequent siblings)
  8 siblings, 1 reply; 15+ messages in thread
From: Marcos Paulo de Souza @ 2020-08-12 16:36 UTC (permalink / raw)
  To: dsterba, linux-btrfs; +Cc: Marcos Paulo de Souza

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

Create a btrfs_fs_context struct that will be used as fs_private between
the fs context calls, holding options to be later assigned to fs_info,
since we don't have a proper btrfs_fs_info at the parse_args phase.

fs_context is still not being used since the init function isn't being
assigned in btrfs_fs_type.

Signed-off-by: Marcos Paulo de Souza <mpdesouza@suse.com>
---
 fs/btrfs/ctree.h | 27 +++++++++++++++++++++++++++
 fs/btrfs/super.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 72 insertions(+)

diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index 9c7e466f27a9..b7e3962a0941 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -28,6 +28,7 @@
 #include <linux/dynamic_debug.h>
 #include <linux/refcount.h>
 #include <linux/crc32c.h>
+#include "compression.h"
 #include "extent-io-tree.h"
 #include "extent_io.h"
 #include "extent_map.h"
@@ -35,6 +36,32 @@
 #include "block-rsv.h"
 #include "locking.h"
 
+struct btrfs_fs_context {
+	char **devices;
+	char *subvol_name;
+	u64 subvolid;
+
+	int nr_devices;
+	unsigned long mount_opt;
+	unsigned long mount_opt_explicity;
+	unsigned long pending_changes;
+	enum btrfs_compression_type	compress_type;
+	unsigned int			compress_level;
+
+	u64				max_inline;
+	u32				metadata_ratio;
+	u32				thread_pool_size;
+	u32				commit_interval;
+#ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY
+	u32				check_integrity_print_mask;
+#endif
+
+	struct vfsmount *root_mnt;
+	bool root;
+	bool nospace_cache;
+	bool no_compress;
+};
+
 struct btrfs_trans_handle;
 struct btrfs_transaction;
 struct btrfs_pending_snapshot;
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index 4e6654af90ea..fe19ffe962c6 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -2326,6 +2326,51 @@ static void btrfs_kill_super(struct super_block *sb)
 	btrfs_free_fs_info(fs_info);
 }
 
+static void btrfs_fc_free(struct fs_context *fc)
+{
+	struct btrfs_fs_context *ctx = fc->fs_private;
+	struct btrfs_fs_info *info = fc->s_fs_info;
+
+	if (info)
+		btrfs_free_fs_info(info);
+	if (ctx) {
+		mntput(ctx->root_mnt);
+		if (ctx->devices) {
+			int i;
+
+			for (i = 0; i < ctx->nr_devices; i++)
+				kfree(ctx->devices[i]);
+			kfree(ctx->devices);
+		}
+		kfree(ctx->subvol_name);
+		kfree(ctx);
+	}
+}
+
+static const struct fs_context_operations btrfs_context_ops = {
+	.free = btrfs_fc_free,
+};
+
+static int btrfs_init_fs_context(struct fs_context *fc)
+{
+	struct btrfs_fs_context *ctx;
+
+	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+	if (!ctx)
+		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
+	ctx->commit_interval = BTRFS_DEFAULT_COMMIT_INTERVAL;
+
+	fc->fs_private = ctx;
+	fc->ops = &btrfs_context_ops;
+	return 0;
+}
+
 static struct file_system_type btrfs_fs_type = {
 	.owner		= THIS_MODULE,
 	.name		= "btrfs",
-- 
2.28.0


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [RFC PATCH 3/8] btrfs: super: Introduce btrfs_fc_parse_param and btrfs_apply_configuration
  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-12 16:36 ` 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
                   ` (5 subsequent siblings)
  8 siblings, 1 reply; 15+ messages in thread
From: Marcos Paulo de Souza @ 2020-08-12 16:36 UTC (permalink / raw)
  To: dsterba, linux-btrfs; +Cc: Marcos Paulo de Souza

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

The first function will parse the arguments using the new fs_context API
saving the arguments in btrfs_fs_context, while the second one populate
the settings of btrfs_fs_info using the context previously set.

Signed-off-by: Marcos Paulo de Souza <mpdesouza@suse.com>
---
 fs/btrfs/ctree.h |   1 +
 fs/btrfs/super.c | 609 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 610 insertions(+)

diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index b7e3962a0941..d96bce2ea5bb 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -3102,6 +3102,7 @@ int btrfs_defrag_leaves(struct btrfs_trans_handle *trans,
 /* super.c */
 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);
 int btrfs_sync_fs(struct super_block *sb, int wait);
 char *btrfs_get_subvol_name_from_objectid(struct btrfs_fs_info *fs_info,
 					  u64 subvol_objectid);
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index fe19ffe962c6..3425a77ecd57 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -1051,6 +1051,394 @@ int btrfs_parse_options(struct btrfs_fs_info *info, char *options,
 	return ret;
 }
 
+struct btrfs_flag_map {
+       int bit;
+       bool enabled;
+};
+
+#define INIT_MAP(OPT) { BTRFS_MOUNT_##OPT, false }
+#define btrfs_test_exp_opt(fs_info, opt) \
+	((fs_info)->mount_opt_explicity & BTRFS_MOUNT_##opt)
+
+/* Opt_err is the latest option */
+static struct btrfs_flag_map btrfs_opt_map[Opt_err] = {
+	[Opt_barrier] = INIT_MAP(NOBARRIER),
+	[Opt_check_integrity] = INIT_MAP(CHECK_INTEGRITY),
+	[Opt_check_integrity_including_extent_data] =
+		INIT_MAP(CHECK_INTEGRITY_INCLUDING_EXTENT_DATA),
+	[Opt_datacow] = INIT_MAP(NODATACOW),
+	[Opt_datasum] = INIT_MAP(NODATASUM),
+	[Opt_discard] = INIT_MAP(DISCARD_SYNC),
+	[Opt_defrag] = INIT_MAP(AUTO_DEFRAG),
+	[Opt_degraded] = INIT_MAP(DEGRADED),
+	[Opt_flushoncommit] = INIT_MAP(FLUSHONCOMMIT),
+	[Opt_inode_cache] = INIT_MAP(INODE_MAP_CACHE),
+	[Opt_nologreplay] = INIT_MAP(NOLOGREPLAY),
+	[Opt_ssd] = INIT_MAP(SSD),
+	[Opt_ssd_spread] = INIT_MAP(SSD_SPREAD),
+	[Opt_treelog] = INIT_MAP(NOTREELOG),
+	[Opt_ref_verify] = INIT_MAP(REF_VERIFY),
+};
+
+static int btrfs_fc_parse_param(struct fs_context *fc, struct fs_parameter *param)
+{
+	int opt;
+	char *compress_type;
+	char **devs;
+	bool compress_force = false;
+	enum btrfs_compression_type saved_compress_type;
+	bool saved_compress_force;
+	struct fs_parse_result result;
+	struct btrfs_fs_context *ctx = fc->fs_private;
+
+	opt = fs_parse(fc, btrfs_fs_parameters, param, &result);
+	if (opt < 0)
+		return opt;
+
+	/*
+	 * Store the option parsed to avoid being too noisy in
+	 * btrfs_apply_configuration.
+	 */
+	ctx->mount_opt_explicity |= btrfs_opt_map[opt].bit;
+	btrfs_opt_map[opt].enabled = !result.negated;
+
+	switch (opt) {
+	case Opt_acl:
+		if (result.negated) {
+			fc->sb_flags &= ~SB_POSIXACL;
+		} else {
+#ifndef CONFIG_BTRFS_FS_POSIX_ACL
+			return invalf(fc, "support for ACL not compiled in!");
+#else
+			fc->sb_flags |= SB_POSIXACL;
+#endif
+		}
+		break;
+	case Opt_barrier:
+		if (result.negated)
+			btrfs_set_opt(ctx->mount_opt, NOBARRIER);
+		else
+			btrfs_clear_opt(ctx->mount_opt, NOBARRIER);
+		break;
+	case Opt_clear_cache:
+		btrfs_set_opt(ctx->mount_opt, CLEAR_CACHE);
+		break;
+	case Opt_commit_interval:
+		ctx->commit_interval = result.uint_32;
+		break;
+	case Opt_compress_force:
+	case Opt_compress_force_type:
+		compress_force = true;
+		fallthrough;
+	case Opt_compress:
+	case Opt_compress_type:
+		saved_compress_type = btrfs_test_opt(ctx, COMPRESS) ?
+			ctx->compress_type : BTRFS_COMPRESS_NONE;
+		saved_compress_force =
+			btrfs_test_opt(ctx, FORCE_COMPRESS);
+		if (opt == Opt_compress ||
+		    opt == Opt_compress_force ||
+		    strncmp(param->string, "zlib", 4) == 0) {
+			compress_type = "zlib";
+
+			ctx->compress_type = BTRFS_COMPRESS_ZLIB;
+			ctx->compress_level = BTRFS_ZLIB_DEFAULT_LEVEL;
+			/*
+			 * param->string contains uninitialized data since
+			 * for these options we don't expect any
+			 * parameter.
+			 */
+			if (opt != Opt_compress &&
+			    opt != Opt_compress_force)
+				ctx->compress_level =
+				  btrfs_compress_str2level(
+						BTRFS_COMPRESS_ZLIB,
+						param->string + 4);
+			btrfs_set_opt(ctx->mount_opt, COMPRESS);
+			btrfs_clear_opt(ctx->mount_opt, NODATACOW);
+			btrfs_clear_opt(ctx->mount_opt, NODATASUM);
+			ctx->no_compress = false;
+		} else if (strncmp(param->string, "lzo", 3) == 0) {
+			compress_type = "lzo";
+			ctx->compress_type = BTRFS_COMPRESS_LZO;
+			/* btrfs does not exposes lzo compression levels */
+			ctx->compress_level = 0;
+			btrfs_set_opt(ctx->mount_opt, COMPRESS);
+			btrfs_clear_opt(ctx->mount_opt, NODATACOW);
+			btrfs_clear_opt(ctx->mount_opt, NODATASUM);
+			ctx->no_compress = false;
+		} else if (strncmp(param->string, "zstd", 4) == 0) {
+			compress_type = "zstd";
+			ctx->compress_type = BTRFS_COMPRESS_ZSTD;
+			ctx->compress_level =
+				btrfs_compress_str2level(
+						 BTRFS_COMPRESS_ZSTD,
+						 param->string + 4);
+			btrfs_set_opt(ctx->mount_opt, COMPRESS);
+			btrfs_clear_opt(ctx->mount_opt, NODATACOW);
+			btrfs_clear_opt(ctx->mount_opt, NODATASUM);
+			ctx->no_compress = false;
+		} else if (strncmp(param->string, "no", 2) == 0) {
+			compress_type = "no";
+			ctx->compress_level = 0;
+			btrfs_clear_opt(ctx->mount_opt, COMPRESS);
+			btrfs_clear_opt(ctx->mount_opt, FORCE_COMPRESS);
+			compress_force = false;
+			ctx->no_compress = true;
+		} else {
+			return invalf(fc, "Invalid compression option: %s",
+								param->string);
+		}
+
+		if (compress_force) {
+			btrfs_set_opt(ctx->mount_opt, FORCE_COMPRESS);
+		} else {
+			/*
+			 * If we reconfigure from compress-force=xxx to
+			 * compress=xxx, we need clear FORCE_COMPRESS
+			 * flag, otherwise, there is no way for users
+			 * to disable forcible compression separately.
+			 */
+			btrfs_clear_opt(ctx->mount_opt, FORCE_COMPRESS);
+		}
+		break;
+	case Opt_degraded:
+		btrfs_set_opt(ctx->mount_opt, DEGRADED);
+		break;
+	case Opt_device:
+		devs = krealloc(ctx->devices,
+				sizeof(char *) * (ctx->nr_devices + 1),
+				GFP_KERNEL);
+		if (!devs)
+			return -ENOMEM;
+		devs[ctx->nr_devices] = param->string;
+		param->string = NULL;
+		ctx->devices = devs;
+		ctx->nr_devices++;
+		break;
+	case Opt_datacow:
+		if (result.negated) {
+			btrfs_clear_opt(ctx->mount_opt, COMPRESS);
+			btrfs_clear_opt(ctx->mount_opt, FORCE_COMPRESS);
+			btrfs_set_opt(ctx->mount_opt, NODATACOW);
+			btrfs_set_opt(ctx->mount_opt, NODATASUM);
+		} else {
+			btrfs_clear_opt(ctx->mount_opt, NODATACOW);
+		}
+		break;
+	case Opt_datasum:
+		if (result.negated) {
+			btrfs_set_opt(ctx->mount_opt, NODATASUM);
+		} else {
+			btrfs_clear_opt(ctx->mount_opt, NODATACOW);
+			btrfs_clear_opt(ctx->mount_opt, NODATASUM);
+		}
+		break;
+	case Opt_defrag:
+		if (result.negated)
+			btrfs_clear_opt(ctx->mount_opt, AUTO_DEFRAG);
+		else
+			btrfs_set_opt(ctx->mount_opt, AUTO_DEFRAG);
+		break;
+	case Opt_discard:
+		if (result.negated) {
+			btrfs_clear_opt(ctx->mount_opt, DISCARD_SYNC);
+			btrfs_clear_opt(ctx->mount_opt, DISCARD_ASYNC);
+		} else {
+			btrfs_clear_opt(ctx->mount_opt, DISCARD_ASYNC);
+			btrfs_set_opt(ctx->mount_opt, DISCARD_SYNC);
+		}
+		break;
+	case Opt_discard_mode:
+		if (strcmp(param->string, "sync") == 0) {
+			btrfs_clear_opt(ctx->mount_opt, DISCARD_ASYNC);
+			btrfs_set_opt(ctx->mount_opt, DISCARD_SYNC);
+		} else if (strcmp(param->string, "async") == 0) {
+			btrfs_clear_opt(ctx->mount_opt, DISCARD_SYNC);
+			btrfs_set_opt(ctx->mount_opt, DISCARD_ASYNC);
+		} else {
+			return invalf(fc, "Invalid discard mode: %s",
+								param->string);
+		}
+		break;
+	case Opt_enospc_debug:
+		if (result.negated)
+			btrfs_clear_opt(ctx->mount_opt, ENOSPC_DEBUG);
+		else
+			btrfs_set_opt(ctx->mount_opt, ENOSPC_DEBUG);
+		break;
+	case Opt_fatal_errors:
+		if (strcmp(param->string, "panic") == 0)
+			btrfs_set_opt(ctx->mount_opt, PANIC_ON_FATAL_ERROR);
+		else if (strcmp(param->string, "bug") == 0)
+			btrfs_clear_opt(ctx->mount_opt, PANIC_ON_FATAL_ERROR);
+		else
+			return invalf(fc, "Invalid fatal_errors option: %s",
+								param->string);
+		break;
+	case Opt_flushoncommit:
+		if (result.negated)
+			btrfs_clear_opt(ctx->mount_opt, FLUSHONCOMMIT);
+		else
+			btrfs_set_opt(ctx->mount_opt, FLUSHONCOMMIT);
+		break;
+#ifdef CONFIG_BTRFS_DEBUG
+	case Opt_fragment:
+		if (strcmp(param->string, "all") == 0) {
+			btrfs_set_opt(ctx->mount_opt, FRAGMENT_DATA);
+			btrfs_set_opt(ctx->mount_opt, FRAGMENT_METADATA);
+		} else if (strcmp(param->string, "metadata") == 0) {
+			btrfs_set_opt(ctx->mount_opt, FRAGMENT_METADATA);
+		} else if (strcmp(param->string, "data") == 0) {
+			btrfs_set_opt(ctx->mount_opt, FRAGMENT_DATA);
+		} else {
+			return invalf(fc, "Invalid fragment option: %s",
+					param->string);
+		}
+		break;
+#endif
+#ifdef CONFIG_BTRFS_FS_REF_VERIFY
+	case Opt_ref_verify:
+		btrfs_set_opt(ctx->mount_opt, REF_VERIFY);
+		break;
+#endif
+	case Opt_inode_cache:
+		/* handled in btrfs_apply_configuration */
+		break;
+	case Opt_max_inline:
+		ctx->max_inline = memparse(param->string, NULL);
+		break;
+	case Opt_norecovery:
+	case Opt_nologreplay:
+		warnf(fc, "'%s' is deprecated, use 'rescue=nologreplay' instead",
+				opt == Opt_norecovery ? "norecovery"
+							: "nologreplay");
+		btrfs_set_opt(ctx->mount_opt, NOLOGREPLAY);
+		break;
+	case Opt_ratio:
+		ctx->metadata_ratio = result.uint_32;
+		break;
+	case Opt_rescue:
+		if (strcmp(param->string, "usebackuproot") == 0) {
+			btrfs_set_opt(ctx->mount_opt, USEBACKUPROOT);
+		} else if (strcmp(param->string, "nologreplay") == 0) {
+			btrfs_set_opt(ctx->mount_opt, NOLOGREPLAY);
+		} else {
+			return invalf(fc, "unrecognized rescue option '%s'",
+					param->string);
+		}
+		break;
+	case Opt_skip_balance:
+		btrfs_set_opt(ctx->mount_opt, SKIP_BALANCE);
+		break;
+	case Opt_rescan_uuid_tree:
+		btrfs_set_opt(ctx->mount_opt, RESCAN_UUID_TREE);
+		break;
+	case Opt_space_cache:
+		if (result.negated) {
+			if (btrfs_test_opt(ctx, SPACE_CACHE))
+				btrfs_clear_opt(ctx->mount_opt, SPACE_CACHE);
+			if (btrfs_test_opt(ctx, FREE_SPACE_TREE))
+				btrfs_clear_opt(ctx->mount_opt, FREE_SPACE_TREE);
+			ctx->nospace_cache = true;
+		} else {
+			btrfs_clear_opt(ctx->mount_opt, FREE_SPACE_TREE);
+			btrfs_set_opt(ctx->mount_opt, SPACE_CACHE);
+			ctx->nospace_cache = false;
+		}
+		break;
+	case Opt_space_cache_version:
+		ctx->nospace_cache = false;
+		if (strcmp(param->string, "v1") == 0) {
+			btrfs_clear_opt(ctx->mount_opt, FREE_SPACE_TREE);
+			btrfs_set_opt(ctx->mount_opt, SPACE_CACHE);
+		} else if (strcmp(param->string, "v2") == 0) {
+			btrfs_clear_opt(ctx->mount_opt, SPACE_CACHE);
+			btrfs_set_opt(ctx->mount_opt, FREE_SPACE_TREE);
+		} else {
+			return invalf(fc, "Invalid space_cache version: %s",
+								param->string);
+		}
+		break;
+	case Opt_ssd:
+		if (result.negated) {
+			btrfs_set_opt(ctx->mount_opt, NOSSD);
+			btrfs_clear_opt(ctx->mount_opt, SSD);
+			btrfs_clear_opt(ctx->mount_opt, SSD_SPREAD);
+		} else {
+			btrfs_clear_opt(ctx->mount_opt, NOSSD);
+			btrfs_set_opt(ctx->mount_opt, SSD);
+		}
+		break;
+	case Opt_ssd_spread:
+		if (result.negated) {
+			btrfs_clear_opt(ctx->mount_opt, SSD_SPREAD);
+		} else {
+			btrfs_set_opt(ctx->mount_opt, SSD);
+			btrfs_set_opt(ctx->mount_opt, SSD_SPREAD);
+			btrfs_clear_opt(ctx->mount_opt, NOSSD);
+		}
+		break;
+	case Opt_subvol:
+		kfree(ctx->subvol_name);
+		ctx->subvol_name = param->string;
+		param->string = NULL;
+		break;
+	case Opt_subvolid:
+		ctx->subvolid = result.uint_64;
+
+		/* we want the original fs_tree */
+		if (ctx->subvolid == 0)
+			ctx->subvolid = BTRFS_FS_TREE_OBJECTID;
+		break;
+	case Opt_thread_pool:
+		if (result.uint_32 == 0)
+			return invalf(fc, "Invalid thread_pool value: 0");
+
+		ctx->thread_pool_size = result.uint_32;
+		break;
+	case Opt_treelog:
+		if (result.negated)
+			btrfs_set_opt(ctx->mount_opt, NOTREELOG);
+		else
+			btrfs_clear_opt(ctx->mount_opt, NOTREELOG);
+		break;
+#ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY
+	case Opt_check_integrity_including_extent_data:
+		btrfs_set_opt(ctx->mount_opt,
+			      CHECK_INTEGRITY_INCLUDING_EXTENT_DATA);
+		btrfs_set_opt(ctx->mount_opt, CHECK_INTEGRITY);
+		break;
+	case Opt_check_integrity:
+		btrfs_set_opt(ctx->mount_opt, CHECK_INTEGRITY);
+		break;
+	case Opt_check_integrity_print_mask:
+		ctx->check_integrity_print_mask = result.uint_32;
+		break;
+#else
+	case Opt_check_integrity_including_extent_data:
+	case Opt_check_integrity:
+	case Opt_check_integrity_print_mask:
+		return invalf(fc, "support for check_integrity* not compiled in!");
+#endif
+	case Opt_user_subvol_rm_allowed:
+		btrfs_set_opt(ctx->mount_opt, USER_SUBVOL_RM_ALLOWED);
+		break;
+	case Opt_recovery:
+		fallthrough;
+	case Opt_usebackuproot:
+		warnf(fc, "'%s' is deprecated, use 'rescue=usebackuproot' instead",
+			opt == Opt_recovery ? "recovery" :
+			"usebackuproot");
+		btrfs_set_opt(ctx->mount_opt, USEBACKUPROOT);
+		break;
+	default:
+		return invalf(fc, "Invalid mount option: %s", param->key);
+	}
+
+	return 0;
+}
+
 /*
  * Parse mount options that are required early in the mount process.
  *
@@ -1400,6 +1788,226 @@ static int btrfs_fill_super(struct super_block *sb,
 	return err;
 }
 
+int btrfs_apply_configuration(struct fs_context *fc,
+				struct super_block *sb)
+{
+	struct btrfs_fs_context *ctx = fc->fs_private;
+	struct btrfs_fs_info *info = sb->s_fs_info;
+
+#ifdef CONFIG_BTRFS_FS_POSIX_ACL
+	if (!(fc->sb_flags & SB_POSIXACL))
+		sb->s_flags &= ~SB_POSIXACL;
+	else
+		sb->s_flags |= SB_POSIXACL;
+#endif
+
+	if (btrfs_test_exp_opt(ctx, NOBARRIER))
+		btrfs_info(info, "turning %s barriers",
+				btrfs_opt_map[Opt_barrier].enabled ? "on" : "off");
+
+	if (btrfs_test_exp_opt(ctx, CLEAR_CACHE))
+		btrfs_info(info, "force clearing of disk cache");
+
+	if (ctx->commit_interval == 0) {
+		btrfs_info(info, "using default commit interval %us",
+			   BTRFS_DEFAULT_COMMIT_INTERVAL);
+		ctx->commit_interval = BTRFS_DEFAULT_COMMIT_INTERVAL;
+	} else if (ctx->commit_interval > 300) {
+		btrfs_warn(info, "excessive commit interval %d",
+					ctx->commit_interval);
+	}
+	info->commit_interval = ctx->commit_interval;
+
+	if (btrfs_test_opt(ctx, COMPRESS) || ctx->no_compress) {
+		btrfs_info(info, "%s %s compression, level %d",
+				btrfs_test_opt(ctx, FORCE_COMPRESS) ? "force" : "use",
+				ctx->no_compress ? "no"
+				: btrfs_compress_type2str(ctx->compress_type),
+				ctx->compress_level);
+
+		if (ctx->compress_type == BTRFS_COMPRESS_LZO)
+			btrfs_set_fs_incompat(info, COMPRESS_LZO);
+		else if (ctx->compress_type == BTRFS_COMPRESS_ZSTD)
+			btrfs_set_fs_incompat(info, COMPRESS_ZSTD);
+	}
+
+	if (btrfs_test_exp_opt(ctx, DEGRADED))
+		btrfs_info(info, "allowing degraded mounts");
+
+	if (btrfs_test_exp_opt(ctx, NODATACOW)) {
+		if (btrfs_opt_map[Opt_datacow].enabled) {
+			btrfs_info(info, "setting datacow");
+		} else {
+			if (!btrfs_test_opt(ctx, COMPRESS) ||
+					!btrfs_test_opt(ctx, FORCE_COMPRESS)) {
+				btrfs_info(info, "setting nodatacow, compression disabled");
+			} else {
+				btrfs_info(info, "setting nodatacow");
+			}
+		}
+	}
+
+	if (btrfs_test_exp_opt(ctx, NODATASUM)) {
+		if (!btrfs_opt_map[Opt_datasum].enabled) {
+			btrfs_info(info, "setting nodatasum");
+		} else {
+			if (btrfs_test_opt(ctx, NODATASUM)) {
+				if (btrfs_test_opt(ctx, NODATACOW))
+					btrfs_info(info, "setting datasum, datacow enabled");
+				else
+					btrfs_info(info, "setting datasum");
+			}
+		}
+	}
+
+	if (btrfs_test_exp_opt(ctx, AUTO_DEFRAG))
+		btrfs_info(info, "%s auto defrag",
+				btrfs_opt_map[Opt_barrier].enabled ? "enabling"
+				: "disabling");
+
+	if (btrfs_test_opt(ctx, DISCARD_ASYNC)) {
+		btrfs_info(info, "turning on async discard");
+	} else if (btrfs_test_exp_opt(ctx, DISCARD_SYNC)) {
+		if (!btrfs_opt_map[Opt_discard].enabled) {
+			btrfs_info(info, "turning off discard");
+			btrfs_info(info, "turning off async discard");
+		} else {
+			btrfs_info(info, "turning on sync discard");
+		}
+	}
+
+	if (btrfs_test_exp_opt(ctx, FLUSHONCOMMIT))
+		btrfs_info(info, "turning %s flush-on-commit",
+				btrfs_opt_map[Opt_flushoncommit].enabled ? "on" : "off");
+
+#ifdef CONFIG_BTRFS_DEBUG
+	if (btrfs_test_opt(ctx, FRAGMENT_DATA) && btrfs_test_opt(ctx, FRAGMENT_METADATA))
+		btrfs_info(info, "fragmenting all space");
+	else if (btrfs_test_opt(ctx, FRAGMENT_METADATA))
+		btrfs_info(info, "fragmenting metadata");
+	else if (btrfs_test_opt(ctx, FRAGMENT_DATA))
+		btrfs_info(info, "fragmenting data");
+#endif
+
+#ifdef CONFIG_BTRFS_FS_REF_VERIFY
+       if (btrfs_test_exp_opt(ctx, REF_VERIFY))
+               btrfs_info(info, "doing ref verification");
+#endif
+
+	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");
+		} 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");
+		}
+	}
+
+	if (ctx->max_inline) {
+		ctx->max_inline = min_t(u64, ctx->max_inline, info->sectorsize);
+		if (ctx->max_inline != info->max_inline)
+			btrfs_info(info, "max_inline at %llu", ctx->max_inline);
+		info->max_inline = ctx->max_inline;
+	}
+
+       if (btrfs_test_exp_opt(ctx, NOLOGREPLAY))
+               btrfs_info(info, "disabling log replay at mount time");
+
+	info->metadata_ratio = ctx->metadata_ratio;
+	if (ctx->metadata_ratio)
+		btrfs_info(info, "Metadata ratio %u", ctx->metadata_ratio);
+
+	if (btrfs_test_opt(ctx, USEBACKUPROOT))
+		btrfs_info(info, "trying to use backup root at mount time");
+
+	/* set a default space_cache value if none was specified */
+	if (!ctx->nospace_cache && !btrfs_test_opt(ctx, SPACE_CACHE) &&
+			!btrfs_test_opt(ctx, FREE_SPACE_TREE)) {
+		if (btrfs_fs_compat_ro(info, FREE_SPACE_TREE))
+			btrfs_set_opt(ctx->mount_opt, FREE_SPACE_TREE);
+		else
+			btrfs_set_opt(ctx->mount_opt, SPACE_CACHE);
+	}
+
+	if (ctx->nospace_cache) {
+		if (btrfs_test_opt(ctx, SPACE_CACHE))
+			btrfs_info(info, "disabling disk space caching");
+		if (btrfs_test_opt(ctx, FREE_SPACE_TREE))
+			btrfs_info(info, "disabling free space tree");
+	} else if (btrfs_test_opt(ctx, SPACE_CACHE))  {
+		btrfs_info(info, "enabling disk space caching");
+	} else if (btrfs_test_opt(ctx, FREE_SPACE_TREE)) {
+		btrfs_info(info, "enabling free space tree");
+	}
+
+	/*
+	 * When the free space tree is enabled:
+	 * -o nospace_cache, -o space_cache=v1: error
+	 * no options, -o space_cache=v2: keep using the free space tree
+	 * -o clear_cache, -o clear_cache,space_cache=v2: clear and recreate the free space tree
+	 * -o clear_cache,nospace_cache: clear the free space tree
+	 * -o clear_cache,space_cache=v1: clear the free space tree, enable the free space cache
+	 */
+	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");
+			return -EINVAL;
+		}
+	}
+
+	if (btrfs_test_exp_opt(ctx, SSD_SPREAD)) {
+		if (!btrfs_opt_map[Opt_ssd_spread].enabled) {
+			btrfs_info(info, "not using spread ssd allocation scheme");
+		} else {
+			btrfs_info(info, "enabling ssd optimizations");
+			btrfs_info(info, "using spread ssd allocation scheme");
+		}
+	}
+
+	if (btrfs_test_exp_opt(ctx, SSD)) {
+		if (!btrfs_opt_map[Opt_ssd].enabled) {
+			btrfs_info(info, "not using ssd optimizations");
+			btrfs_info(info, "not using spread ssd allocation scheme");
+		} else {
+			btrfs_info(info, "enabling ssd optimizations");
+		}
+	}
+
+	if (ctx->thread_pool_size)
+		info->thread_pool_size = ctx->thread_pool_size;
+
+	if (btrfs_test_exp_opt(ctx, NOTREELOG))
+		btrfs_info(info, "%s tree log",
+				btrfs_opt_map[Opt_notreelog].enabled ? "enabling"
+				: "disabling");
+
+#ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY
+       if (btrfs_test_exp_opt(ctx, CHECK_INTEGRITY_INCLUDING_EXTENT_DATA))
+               btrfs_info(info, "disabling log replay at mount time");
+       else if (btrfs_test_exp_opt(ctx, CHECK_INTEGRITY))
+               btrfs_info(info, "enabling check integrity");
+       if (ctx->check_integrity_print_mask != info->check_integrity_print_mask) {
+               info->check_integrity_print_mask = ctx->check_integrity_print_mask;
+               btrfs_info(info, "check_integrity_print_mask 0x%x",
+                  info->check_integrity_print_mask);
+       }
+#endif
+
+	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;
+}
+
 int btrfs_sync_fs(struct super_block *sb, int wait)
 {
 	struct btrfs_trans_handle *trans;
@@ -2349,6 +2957,7 @@ static void btrfs_fc_free(struct fs_context *fc)
 
 static const struct fs_context_operations btrfs_context_ops = {
 	.free = btrfs_fc_free,
+	.parse_param = btrfs_fc_parse_param,
 };
 
 static int btrfs_init_fs_context(struct fs_context *fc)
-- 
2.28.0


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [RFC PATCH 4/8] btrfs: super: Introduce btrfs_fc_validate
  2020-08-12 16:36 [RFC PATCH 0/8] btrfs: convert to fscontext Marcos Paulo de Souza
                   ` (2 preceding siblings ...)
  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-12 16:36 ` Marcos Paulo de Souza
  2020-08-12 16:36 ` [RFC PATCH 5/8] btrfs: super: Introduce btrfs_dup_fc Marcos Paulo de Souza
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 15+ messages in thread
From: Marcos Paulo de Souza @ 2020-08-12 16:36 UTC (permalink / raw)
  To: dsterba, linux-btrfs; +Cc: Marcos Paulo de Souza

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

This function will be used in later patches in get_tree and in
remount to ensure that we don't mount btrfs using nologreplay with a
writable fs.

Signed-off-by: Marcos Paulo de Souza <mpdesouza@suse.com>
---
 fs/btrfs/super.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index 3425a77ecd57..88221d1d8bae 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -1080,6 +1080,17 @@ static struct btrfs_flag_map btrfs_opt_map[Opt_err] = {
 	[Opt_ref_verify] = INIT_MAP(REF_VERIFY),
 };
 
+static int btrfs_fc_validate(struct fs_context *fc)
+{
+	struct btrfs_fs_context *ctx = fc->fs_private;
+
+	 /* Check for current option against current flag */
+	if (btrfs_test_opt(ctx, NOLOGREPLAY) && !(fc->sb_flags & SB_RDONLY))
+		return invalf(fc, "nologreplay must be used with ro mount option");
+
+	return 0;
+}
+
 static int btrfs_fc_parse_param(struct fs_context *fc, struct fs_parameter *param)
 {
 	int opt;
-- 
2.28.0


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [RFC PATCH 5/8] btrfs: super: Introduce btrfs_dup_fc
  2020-08-12 16:36 [RFC PATCH 0/8] btrfs: convert to fscontext Marcos Paulo de Souza
                   ` (3 preceding siblings ...)
  2020-08-12 16:36 ` [RFC PATCH 4/8] btrfs: super: Introduce btrfs_fc_validate Marcos Paulo de Souza
@ 2020-08-12 16:36 ` Marcos Paulo de Souza
  2020-08-12 16:36 ` [RFC PATCH 6/8] btrfs: super: Introduce btrfs_mount_root_fc Marcos Paulo de Souza
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 15+ messages in thread
From: Marcos Paulo de Souza @ 2020-08-12 16:36 UTC (permalink / raw)
  To: dsterba, linux-btrfs; +Cc: Marcos Paulo de Souza

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

This function will be used in a future patch when mounting root filesystem
before mounting a subvolume.

Signed-off-by: Marcos Paulo de Souza <mpdesouza@suse.com>
---
 fs/btrfs/super.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 51 insertions(+)

diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index 88221d1d8bae..6b70fb73a1ea 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -1091,6 +1091,56 @@ static int btrfs_fc_validate(struct fs_context *fc)
 	return 0;
 }
 
+static int btrfs_dup_fc(struct fs_context *fc, struct fs_context *src_fc)
+{
+	int i;
+	struct btrfs_fs_context *ctx, *src = src_fc->fs_private;
+
+	ctx = kmemdup(src, sizeof(*ctx), GFP_KERNEL);
+	if (!ctx)
+		return -ENOMEM;
+
+	ctx->subvol_name = NULL;
+	ctx->devices = NULL;
+	ctx->root_mnt = NULL;
+
+	if (src->subvol_name) {
+		ctx->subvol_name = kstrdup(src->subvol_name, GFP_KERNEL);
+		if (!ctx->subvol_name)
+			goto nomem_ctx;
+	}
+
+	if (ctx->nr_devices) {
+		ctx->devices = kcalloc(ctx->nr_devices, sizeof(char *), GFP_KERNEL);
+		if (!ctx->devices)
+			goto nomem_sub;
+		for (i = 0; i < ctx->nr_devices; i++) {
+			ctx->devices[i] = kstrdup(src->devices[i], GFP_KERNEL);
+			if (!ctx->devices[i])
+				goto nomem_devs;
+		}
+	}
+
+	if (src_fc->source) {
+		fc->source = kstrdup(src_fc->source, GFP_KERNEL);
+		if (!fc->source)
+			goto nomem_devs;
+	}
+
+	fc->fs_private = ctx;
+	return 0;
+
+nomem_devs:
+	for (i = 0; i < ctx->nr_devices; i++)
+		kfree(ctx->devices[i]);
+	kfree(ctx->devices);
+nomem_sub:
+	kfree(ctx->subvol_name);
+nomem_ctx:
+	kfree(ctx);
+	return -ENOMEM;
+}
+
 static int btrfs_fc_parse_param(struct fs_context *fc, struct fs_parameter *param)
 {
 	int opt;
@@ -2967,6 +3017,7 @@ 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,
 };
-- 
2.28.0


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [RFC PATCH 6/8] btrfs: super: Introduce btrfs_mount_root_fc
  2020-08-12 16:36 [RFC PATCH 0/8] btrfs: convert to fscontext Marcos Paulo de Souza
                   ` (4 preceding siblings ...)
  2020-08-12 16:36 ` [RFC PATCH 5/8] btrfs: super: Introduce btrfs_dup_fc Marcos Paulo de Souza
@ 2020-08-12 16:36 ` Marcos Paulo de Souza
  2020-08-17 13:14   ` David Sterba
  2020-08-12 16:36 ` [RFC PATCH 7/8] btrfs: Convert to fs_context Marcos Paulo de Souza
                   ` (2 subsequent siblings)
  8 siblings, 1 reply; 15+ messages in thread
From: Marcos Paulo de Souza @ 2020-08-12 16:36 UTC (permalink / raw)
  To: dsterba, linux-btrfs; +Cc: Marcos Paulo de Souza

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

This function will be used by the following patches to mount the root fs
before mounting a subvolume.

Signed-off-by: Marcos Paulo de Souza <mpdesouza@suse.com>
---
 fs/btrfs/super.c | 41 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 41 insertions(+)

diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index 6b70fb73a1ea..5bbf4b947125 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -2419,6 +2419,47 @@ static struct dentry *btrfs_mount_root(struct file_system_type *fs_type,
 	return ERR_PTR(error);
 }
 
+/*
+ * Duplicate the current fc and prepare for mounting the root.
+ * 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)
+{
+	struct btrfs_fs_context *ctx, *root_ctx;
+	struct fs_context *root_fc;
+	struct vfsmount *root_mnt;
+	int ret;
+
+	root_fc = vfs_dup_fs_context(fc);
+	if (IS_ERR(root_fc))
+		return PTR_ERR(root_fc);
+
+	root_fc->sb_flags &= ~SB_RDONLY;
+	root_fc->sb_flags |= rdonly | SB_NOSEC;
+	root_ctx = root_fc->fs_private;
+	root_ctx->root_mnt = NULL;
+	root_ctx->root = true;
+
+	/*
+	 * fc_mount will call btrfs_get_tree again, and by checking ctx->root
+	 * being true it'll call btrfs_root_get_tree to avoid infinite recursion.
+	 */
+	root_mnt = fc_mount(root_fc);
+	if (IS_ERR(root_mnt)) {
+		ret = PTR_ERR(root_mnt);
+		goto error_fc;
+	}
+
+	ctx = fc->fs_private;
+	ctx->root_mnt = root_mnt;
+	ret = 0;
+
+error_fc:
+	put_fs_context(root_fc);
+	return ret;
+}
+
 /*
  * Mount function which is called by VFS layer.
  *
-- 
2.28.0


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [RFC PATCH 7/8] btrfs: Convert to fs_context
  2020-08-12 16:36 [RFC PATCH 0/8] btrfs: convert to fscontext Marcos Paulo de Souza
                   ` (5 preceding siblings ...)
  2020-08-12 16:36 ` [RFC PATCH 6/8] btrfs: super: Introduce btrfs_mount_root_fc Marcos Paulo de Souza
@ 2020-08-12 16:36 ` Marcos Paulo de Souza
  2020-08-13 10:22   ` kernel test robot
  2020-08-17 13:26   ` 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
  8 siblings, 2 replies; 15+ messages in thread
From: Marcos Paulo de Souza @ 2020-08-12 16:36 UTC (permalink / raw)
  To: dsterba, linux-btrfs; +Cc: Marcos Paulo de Souza

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


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [RFC PATCH 8/8] btrfs: Remove leftover code from fscontext conversion
  2020-08-12 16:36 [RFC PATCH 0/8] btrfs: convert to fscontext Marcos Paulo de Souza
                   ` (6 preceding siblings ...)
  2020-08-12 16:36 ` [RFC PATCH 7/8] btrfs: Convert to fs_context Marcos Paulo de Souza
@ 2020-08-12 16:36 ` Marcos Paulo de Souza
  2020-08-17 12:44 ` [RFC PATCH 0/8] btrfs: convert to fscontext David Sterba
  8 siblings, 0 replies; 15+ messages in thread
From: Marcos Paulo de Souza @ 2020-08-12 16:36 UTC (permalink / raw)
  To: dsterba, linux-btrfs; +Cc: Marcos Paulo de Souza

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

* Remove all Opt_no* options, since the fscontext have a flag_no version
  which also handles this option variation.

* Remove all old parse_* function, since now btrfs_fc_parse_param
  handles all options.

* Remove the btrfs_root_fs_type now that btrfs_fs_type handles both root
  fs and subvolumes.

Signed-off-by: Marcos Paulo de Souza <mpdesouza@suse.com>
---
 fs/btrfs/super.c | 784 +----------------------------------------------
 1 file changed, 14 insertions(+), 770 deletions(-)

diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index d9a0faea8c88..8e2feef075c9 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -55,16 +55,6 @@
 
 static const struct super_operations btrfs_super_ops;
 
-/*
- * Types for mounting the default subvolume and a subvolume explicitly
- * requested by subvol=/path. That way the callchain is straightforward and we
- * don't have to play tricks with the mount options and recursive calls to
- * btrfs_mount.
- *
- * The new btrfs_root_fs_type also servers as a tag for the bdev_holder.
- */
-static struct file_system_type btrfs_root_fs_type;
-
 static int btrfs_reconfigure(struct fs_context *fc);
 
 /*
@@ -322,7 +312,7 @@ static void btrfs_put_super(struct super_block *sb)
 }
 
 enum {
-	Opt_acl, Opt_noacl,
+	Opt_acl,
 	Opt_clear_cache,
 	Opt_commit_interval,
 	Opt_compress,
@@ -332,28 +322,28 @@ enum {
 	Opt_degraded,
 	Opt_device,
 	Opt_fatal_errors,
-	Opt_flushoncommit, Opt_noflushoncommit,
-	Opt_inode_cache, Opt_noinode_cache,
+	Opt_flushoncommit,
+	Opt_inode_cache,
 	Opt_max_inline,
-	Opt_barrier, Opt_nobarrier,
-	Opt_datacow, Opt_nodatacow,
-	Opt_datasum, Opt_nodatasum,
-	Opt_defrag, Opt_nodefrag,
-	Opt_discard, Opt_nodiscard,
+	Opt_barrier,
+	Opt_datacow,
+	Opt_datasum,
+	Opt_defrag,
+	Opt_discard,
 	Opt_discard_mode,
 	Opt_norecovery,
 	Opt_ratio,
 	Opt_rescan_uuid_tree,
 	Opt_skip_balance,
-	Opt_space_cache, Opt_no_space_cache,
+	Opt_space_cache,
 	Opt_space_cache_version,
-	Opt_ssd, Opt_nossd,
-	Opt_ssd_spread, Opt_nossd_spread,
+	Opt_ssd,
+	Opt_ssd_spread,
 	Opt_subvol,
 	Opt_subvol_empty,
 	Opt_subvolid,
 	Opt_thread_pool,
-	Opt_treelog, Opt_notreelog,
+	Opt_treelog,
 	Opt_user_subvol_rm_allowed,
 
 	/* Rescue options */
@@ -368,10 +358,9 @@ enum {
 	Opt_check_integrity,
 	Opt_check_integrity_including_extent_data,
 	Opt_check_integrity_print_mask,
-	Opt_enospc_debug, Opt_noenospc_debug,
+	Opt_enospc_debug,
 #ifdef CONFIG_BTRFS_DEBUG
 	Opt_fragment,
-	Opt_fragment_data, Opt_fragment_metadata, Opt_fragment_all,
 #endif
 #ifdef CONFIG_BTRFS_FS_REF_VERIFY
 	Opt_ref_verify,
@@ -379,86 +368,6 @@ enum {
 	Opt_err,
 };
 
-static const match_table_t tokens = {
-	{Opt_acl, "acl"},
-	{Opt_noacl, "noacl"},
-	{Opt_clear_cache, "clear_cache"},
-	{Opt_commit_interval, "commit=%u"},
-	{Opt_compress, "compress"},
-	{Opt_compress_type, "compress=%s"},
-	{Opt_compress_force, "compress-force"},
-	{Opt_compress_force_type, "compress-force=%s"},
-	{Opt_degraded, "degraded"},
-	{Opt_device, "device=%s"},
-	{Opt_fatal_errors, "fatal_errors=%s"},
-	{Opt_flushoncommit, "flushoncommit"},
-	{Opt_noflushoncommit, "noflushoncommit"},
-	{Opt_inode_cache, "inode_cache"},
-	{Opt_noinode_cache, "noinode_cache"},
-	{Opt_max_inline, "max_inline=%s"},
-	{Opt_barrier, "barrier"},
-	{Opt_nobarrier, "nobarrier"},
-	{Opt_datacow, "datacow"},
-	{Opt_nodatacow, "nodatacow"},
-	{Opt_datasum, "datasum"},
-	{Opt_nodatasum, "nodatasum"},
-	{Opt_defrag, "autodefrag"},
-	{Opt_nodefrag, "noautodefrag"},
-	{Opt_discard, "discard"},
-	{Opt_discard_mode, "discard=%s"},
-	{Opt_nodiscard, "nodiscard"},
-	{Opt_norecovery, "norecovery"},
-	{Opt_ratio, "metadata_ratio=%u"},
-	{Opt_rescan_uuid_tree, "rescan_uuid_tree"},
-	{Opt_skip_balance, "skip_balance"},
-	{Opt_space_cache, "space_cache"},
-	{Opt_no_space_cache, "nospace_cache"},
-	{Opt_space_cache_version, "space_cache=%s"},
-	{Opt_ssd, "ssd"},
-	{Opt_nossd, "nossd"},
-	{Opt_ssd_spread, "ssd_spread"},
-	{Opt_nossd_spread, "nossd_spread"},
-	{Opt_subvol, "subvol=%s"},
-	{Opt_subvol_empty, "subvol="},
-	{Opt_subvolid, "subvolid=%s"},
-	{Opt_thread_pool, "thread_pool=%u"},
-	{Opt_treelog, "treelog"},
-	{Opt_notreelog, "notreelog"},
-	{Opt_user_subvol_rm_allowed, "user_subvol_rm_allowed"},
-
-	/* Rescue options */
-	{Opt_rescue, "rescue=%s"},
-	/* Deprecated, with alias rescue=nologreplay */
-	{Opt_nologreplay, "nologreplay"},
-	/* Deprecated, with alias rescue=usebackuproot */
-	{Opt_usebackuproot, "usebackuproot"},
-
-	/* Deprecated options */
-	{Opt_recovery, "recovery"},
-
-	/* Debugging options */
-	{Opt_check_integrity, "check_int"},
-	{Opt_check_integrity_including_extent_data, "check_int_data"},
-	{Opt_check_integrity_print_mask, "check_int_print_mask=%u"},
-	{Opt_enospc_debug, "enospc_debug"},
-	{Opt_noenospc_debug, "noenospc_debug"},
-#ifdef CONFIG_BTRFS_DEBUG
-	{Opt_fragment_data, "fragment=data"},
-	{Opt_fragment_metadata, "fragment=metadata"},
-	{Opt_fragment_all, "fragment=all"},
-#endif
-#ifdef CONFIG_BTRFS_FS_REF_VERIFY
-	{Opt_ref_verify, "ref_verify"},
-#endif
-	{Opt_err, NULL},
-};
-
-static const match_table_t rescue_tokens = {
-	{Opt_usebackuproot, "usebackuproot"},
-	{Opt_nologreplay, "nologreplay"},
-	{Opt_err, NULL},
-};
-
 static const struct fs_parameter_spec btrfs_fs_parameters[] = {
 	fsparam_flag_no("acl", Opt_acl),
 	fsparam_flag_no("autodefrag", Opt_defrag),
@@ -518,538 +427,6 @@ static const struct fs_parameter_spec btrfs_fs_parameters[] = {
 	{}
 };
 
-static int parse_rescue_options(struct btrfs_fs_info *info, const char *options)
-{
-	char *opts;
-	char *orig;
-	char *p;
-	substring_t args[MAX_OPT_ARGS];
-	int ret = 0;
-
-	opts = kstrdup(options, GFP_KERNEL);
-	if (!opts)
-		return -ENOMEM;
-	orig = opts;
-
-	while ((p = strsep(&opts, ":")) != NULL) {
-		int token;
-
-		if (!*p)
-			continue;
-		token = match_token(p, rescue_tokens, args);
-		switch (token){
-		case Opt_usebackuproot:
-			btrfs_info(info,
-				   "trying to use backup root at mount time");
-			btrfs_set_opt(info->mount_opt, USEBACKUPROOT);
-			break;
-		case Opt_nologreplay:
-			btrfs_set_and_info(info, NOLOGREPLAY,
-					   "disabling log replay at mount time");
-			break;
-		case Opt_err:
-			btrfs_info(info, "unrecognized rescue option '%s'", p);
-			ret = -EINVAL;
-			goto out;
-		default:
-			break;
-		}
-
-	}
-out:
-	kfree(orig);
-	return ret;
-}
-
-/*
- * Regular mount options parser.  Everything that is needed only when
- * reading in a new superblock is parsed here.
- * XXX JDM: This needs to be cleaned up for remount.
- */
-int btrfs_parse_options(struct btrfs_fs_info *info, char *options,
-			unsigned long new_flags)
-{
-	substring_t args[MAX_OPT_ARGS];
-	char *p, *num;
-	u64 cache_gen;
-	int intarg;
-	int ret = 0;
-	char *compress_type;
-	bool compress_force = false;
-	enum btrfs_compression_type saved_compress_type;
-	int saved_compress_level;
-	bool saved_compress_force;
-	int no_compress = 0;
-
-	cache_gen = btrfs_super_cache_generation(info->super_copy);
-	if (btrfs_fs_compat_ro(info, FREE_SPACE_TREE))
-		btrfs_set_opt(info->mount_opt, FREE_SPACE_TREE);
-	else if (cache_gen)
-		btrfs_set_opt(info->mount_opt, SPACE_CACHE);
-
-	/*
-	 * Even the options are empty, we still need to do extra check
-	 * against new flags
-	 */
-	if (!options)
-		goto check;
-
-	while ((p = strsep(&options, ",")) != NULL) {
-		int token;
-		if (!*p)
-			continue;
-
-		token = match_token(p, tokens, args);
-		switch (token) {
-		case Opt_degraded:
-			btrfs_info(info, "allowing degraded mounts");
-			btrfs_set_opt(info->mount_opt, DEGRADED);
-			break;
-		case Opt_subvol:
-		case Opt_subvol_empty:
-		case Opt_subvolid:
-		case Opt_device:
-			/*
-			 * These are parsed by btrfs_parse_subvol_options or
-			 * btrfs_parse_device_options and can be ignored here.
-			 */
-			break;
-		case Opt_nodatasum:
-			btrfs_set_and_info(info, NODATASUM,
-					   "setting nodatasum");
-			break;
-		case Opt_datasum:
-			if (btrfs_test_opt(info, NODATASUM)) {
-				if (btrfs_test_opt(info, NODATACOW))
-					btrfs_info(info,
-						   "setting datasum, datacow enabled");
-				else
-					btrfs_info(info, "setting datasum");
-			}
-			btrfs_clear_opt(info->mount_opt, NODATACOW);
-			btrfs_clear_opt(info->mount_opt, NODATASUM);
-			break;
-		case Opt_nodatacow:
-			if (!btrfs_test_opt(info, NODATACOW)) {
-				if (!btrfs_test_opt(info, COMPRESS) ||
-				    !btrfs_test_opt(info, FORCE_COMPRESS)) {
-					btrfs_info(info,
-						   "setting nodatacow, compression disabled");
-				} else {
-					btrfs_info(info, "setting nodatacow");
-				}
-			}
-			btrfs_clear_opt(info->mount_opt, COMPRESS);
-			btrfs_clear_opt(info->mount_opt, FORCE_COMPRESS);
-			btrfs_set_opt(info->mount_opt, NODATACOW);
-			btrfs_set_opt(info->mount_opt, NODATASUM);
-			break;
-		case Opt_datacow:
-			btrfs_clear_and_info(info, NODATACOW,
-					     "setting datacow");
-			break;
-		case Opt_compress_force:
-		case Opt_compress_force_type:
-			compress_force = true;
-			fallthrough;
-		case Opt_compress:
-		case Opt_compress_type:
-			saved_compress_type = btrfs_test_opt(info,
-							     COMPRESS) ?
-				info->compress_type : BTRFS_COMPRESS_NONE;
-			saved_compress_force =
-				btrfs_test_opt(info, FORCE_COMPRESS);
-			saved_compress_level = info->compress_level;
-			if (token == Opt_compress ||
-			    token == Opt_compress_force ||
-			    strncmp(args[0].from, "zlib", 4) == 0) {
-				compress_type = "zlib";
-
-				info->compress_type = BTRFS_COMPRESS_ZLIB;
-				info->compress_level = BTRFS_ZLIB_DEFAULT_LEVEL;
-				/*
-				 * args[0] contains uninitialized data since
-				 * for these tokens we don't expect any
-				 * parameter.
-				 */
-				if (token != Opt_compress &&
-				    token != Opt_compress_force)
-					info->compress_level =
-					  btrfs_compress_str2level(
-							BTRFS_COMPRESS_ZLIB,
-							args[0].from + 4);
-				btrfs_set_opt(info->mount_opt, COMPRESS);
-				btrfs_clear_opt(info->mount_opt, NODATACOW);
-				btrfs_clear_opt(info->mount_opt, NODATASUM);
-				no_compress = 0;
-			} else if (strncmp(args[0].from, "lzo", 3) == 0) {
-				compress_type = "lzo";
-				info->compress_type = BTRFS_COMPRESS_LZO;
-				btrfs_set_opt(info->mount_opt, COMPRESS);
-				btrfs_clear_opt(info->mount_opt, NODATACOW);
-				btrfs_clear_opt(info->mount_opt, NODATASUM);
-				btrfs_set_fs_incompat(info, COMPRESS_LZO);
-				no_compress = 0;
-			} else if (strncmp(args[0].from, "zstd", 4) == 0) {
-				compress_type = "zstd";
-				info->compress_type = BTRFS_COMPRESS_ZSTD;
-				info->compress_level =
-					btrfs_compress_str2level(
-							 BTRFS_COMPRESS_ZSTD,
-							 args[0].from + 4);
-				btrfs_set_opt(info->mount_opt, COMPRESS);
-				btrfs_clear_opt(info->mount_opt, NODATACOW);
-				btrfs_clear_opt(info->mount_opt, NODATASUM);
-				btrfs_set_fs_incompat(info, COMPRESS_ZSTD);
-				no_compress = 0;
-			} else if (strncmp(args[0].from, "no", 2) == 0) {
-				compress_type = "no";
-				info->compress_level = 0;
-				info->compress_type = 0;
-				btrfs_clear_opt(info->mount_opt, COMPRESS);
-				btrfs_clear_opt(info->mount_opt, FORCE_COMPRESS);
-				compress_force = false;
-				no_compress++;
-			} else {
-				ret = -EINVAL;
-				goto out;
-			}
-
-			if (compress_force) {
-				btrfs_set_opt(info->mount_opt, FORCE_COMPRESS);
-			} else {
-				/*
-				 * If we remount from compress-force=xxx to
-				 * compress=xxx, we need clear FORCE_COMPRESS
-				 * flag, otherwise, there is no way for users
-				 * to disable forcible compression separately.
-				 */
-				btrfs_clear_opt(info->mount_opt, FORCE_COMPRESS);
-			}
-			if (no_compress == 1) {
-				btrfs_info(info, "use no compression");
-			} else if ((info->compress_type != saved_compress_type) ||
-				   (compress_force != saved_compress_force) ||
-				   (info->compress_level != saved_compress_level)) {
-				btrfs_info(info, "%s %s compression, level %d",
-					   (compress_force) ? "force" : "use",
-					   compress_type, info->compress_level);
-			}
-			compress_force = false;
-			break;
-		case Opt_ssd:
-			btrfs_set_and_info(info, SSD,
-					   "enabling ssd optimizations");
-			btrfs_clear_opt(info->mount_opt, NOSSD);
-			break;
-		case Opt_ssd_spread:
-			btrfs_set_and_info(info, SSD,
-					   "enabling ssd optimizations");
-			btrfs_set_and_info(info, SSD_SPREAD,
-					   "using spread ssd allocation scheme");
-			btrfs_clear_opt(info->mount_opt, NOSSD);
-			break;
-		case Opt_nossd:
-			btrfs_set_opt(info->mount_opt, NOSSD);
-			btrfs_clear_and_info(info, SSD,
-					     "not using ssd optimizations");
-			fallthrough;
-		case Opt_nossd_spread:
-			btrfs_clear_and_info(info, SSD_SPREAD,
-					     "not using spread ssd allocation scheme");
-			break;
-		case Opt_barrier:
-			btrfs_clear_and_info(info, NOBARRIER,
-					     "turning on barriers");
-			break;
-		case Opt_nobarrier:
-			btrfs_set_and_info(info, NOBARRIER,
-					   "turning off barriers");
-			break;
-		case Opt_thread_pool:
-			ret = match_int(&args[0], &intarg);
-			if (ret) {
-				goto out;
-			} else if (intarg == 0) {
-				ret = -EINVAL;
-				goto out;
-			}
-			info->thread_pool_size = intarg;
-			break;
-		case Opt_max_inline:
-			num = match_strdup(&args[0]);
-			if (num) {
-				info->max_inline = memparse(num, NULL);
-				kfree(num);
-
-				if (info->max_inline) {
-					info->max_inline = min_t(u64,
-						info->max_inline,
-						info->sectorsize);
-				}
-				btrfs_info(info, "max_inline at %llu",
-					   info->max_inline);
-			} else {
-				ret = -ENOMEM;
-				goto out;
-			}
-			break;
-		case Opt_acl:
-#ifdef CONFIG_BTRFS_FS_POSIX_ACL
-			info->sb->s_flags |= SB_POSIXACL;
-			break;
-#else
-			btrfs_err(info, "support for ACL not compiled in!");
-			ret = -EINVAL;
-			goto out;
-#endif
-		case Opt_noacl:
-			info->sb->s_flags &= ~SB_POSIXACL;
-			break;
-		case Opt_notreelog:
-			btrfs_set_and_info(info, NOTREELOG,
-					   "disabling tree log");
-			break;
-		case Opt_treelog:
-			btrfs_clear_and_info(info, NOTREELOG,
-					     "enabling tree log");
-			break;
-		case Opt_norecovery:
-		case Opt_nologreplay:
-			btrfs_warn(info,
-		"'nologreplay' is deprecated, use 'rescue=nologreplay' instead");
-			btrfs_set_and_info(info, NOLOGREPLAY,
-					   "disabling log replay at mount time");
-			break;
-		case Opt_flushoncommit:
-			btrfs_set_and_info(info, FLUSHONCOMMIT,
-					   "turning on flush-on-commit");
-			break;
-		case Opt_noflushoncommit:
-			btrfs_clear_and_info(info, FLUSHONCOMMIT,
-					     "turning off flush-on-commit");
-			break;
-		case Opt_ratio:
-			ret = match_int(&args[0], &intarg);
-			if (ret)
-				goto out;
-			info->metadata_ratio = intarg;
-			btrfs_info(info, "metadata ratio %u",
-				   info->metadata_ratio);
-			break;
-		case Opt_discard:
-		case Opt_discard_mode:
-			if (token == Opt_discard ||
-			    strcmp(args[0].from, "sync") == 0) {
-				btrfs_clear_opt(info->mount_opt, DISCARD_ASYNC);
-				btrfs_set_and_info(info, DISCARD_SYNC,
-						   "turning on sync discard");
-			} else if (strcmp(args[0].from, "async") == 0) {
-				btrfs_clear_opt(info->mount_opt, DISCARD_SYNC);
-				btrfs_set_and_info(info, DISCARD_ASYNC,
-						   "turning on async discard");
-			} else {
-				ret = -EINVAL;
-				goto out;
-			}
-			break;
-		case Opt_nodiscard:
-			btrfs_clear_and_info(info, DISCARD_SYNC,
-					     "turning off discard");
-			btrfs_clear_and_info(info, DISCARD_ASYNC,
-					     "turning off async discard");
-			break;
-		case Opt_space_cache:
-		case Opt_space_cache_version:
-			if (token == Opt_space_cache ||
-			    strcmp(args[0].from, "v1") == 0) {
-				btrfs_clear_opt(info->mount_opt,
-						FREE_SPACE_TREE);
-				btrfs_set_and_info(info, SPACE_CACHE,
-					   "enabling disk space caching");
-			} else if (strcmp(args[0].from, "v2") == 0) {
-				btrfs_clear_opt(info->mount_opt,
-						SPACE_CACHE);
-				btrfs_set_and_info(info, FREE_SPACE_TREE,
-						   "enabling free space tree");
-			} else {
-				ret = -EINVAL;
-				goto out;
-			}
-			break;
-		case Opt_rescan_uuid_tree:
-			btrfs_set_opt(info->mount_opt, RESCAN_UUID_TREE);
-			break;
-		case Opt_no_space_cache:
-			if (btrfs_test_opt(info, SPACE_CACHE)) {
-				btrfs_clear_and_info(info, SPACE_CACHE,
-					     "disabling disk space caching");
-			}
-			if (btrfs_test_opt(info, FREE_SPACE_TREE)) {
-				btrfs_clear_and_info(info, FREE_SPACE_TREE,
-					     "disabling free space tree");
-			}
-			break;
-		case Opt_inode_cache:
-			btrfs_warn(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");
-			break;
-		case Opt_noinode_cache:
-			btrfs_clear_pending_and_info(info, INODE_MAP_CACHE,
-					     "disabling inode map caching");
-			break;
-		case Opt_clear_cache:
-			btrfs_set_and_info(info, CLEAR_CACHE,
-					   "force clearing of disk cache");
-			break;
-		case Opt_user_subvol_rm_allowed:
-			btrfs_set_opt(info->mount_opt, USER_SUBVOL_RM_ALLOWED);
-			break;
-		case Opt_enospc_debug:
-			btrfs_set_opt(info->mount_opt, ENOSPC_DEBUG);
-			break;
-		case Opt_noenospc_debug:
-			btrfs_clear_opt(info->mount_opt, ENOSPC_DEBUG);
-			break;
-		case Opt_defrag:
-			btrfs_set_and_info(info, AUTO_DEFRAG,
-					   "enabling auto defrag");
-			break;
-		case Opt_nodefrag:
-			btrfs_clear_and_info(info, AUTO_DEFRAG,
-					     "disabling auto defrag");
-			break;
-		case Opt_recovery:
-		case Opt_usebackuproot:
-			btrfs_warn(info,
-			"'%s' is deprecated, use 'rescue=usebackuproot' instead",
-				   token == Opt_recovery ? "recovery" :
-				   "usebackuproot");
-			btrfs_info(info,
-				   "trying to use backup root at mount time");
-			btrfs_set_opt(info->mount_opt, USEBACKUPROOT);
-			break;
-		case Opt_skip_balance:
-			btrfs_set_opt(info->mount_opt, SKIP_BALANCE);
-			break;
-#ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY
-		case Opt_check_integrity_including_extent_data:
-			btrfs_info(info,
-				   "enabling check integrity including extent data");
-			btrfs_set_opt(info->mount_opt,
-				      CHECK_INTEGRITY_INCLUDING_EXTENT_DATA);
-			btrfs_set_opt(info->mount_opt, CHECK_INTEGRITY);
-			break;
-		case Opt_check_integrity:
-			btrfs_info(info, "enabling check integrity");
-			btrfs_set_opt(info->mount_opt, CHECK_INTEGRITY);
-			break;
-		case Opt_check_integrity_print_mask:
-			ret = match_int(&args[0], &intarg);
-			if (ret)
-				goto out;
-			info->check_integrity_print_mask = intarg;
-			btrfs_info(info, "check_integrity_print_mask 0x%x",
-				   info->check_integrity_print_mask);
-			break;
-#else
-		case Opt_check_integrity_including_extent_data:
-		case Opt_check_integrity:
-		case Opt_check_integrity_print_mask:
-			btrfs_err(info,
-				  "support for check_integrity* not compiled in!");
-			ret = -EINVAL;
-			goto out;
-#endif
-		case Opt_fatal_errors:
-			if (strcmp(args[0].from, "panic") == 0)
-				btrfs_set_opt(info->mount_opt,
-					      PANIC_ON_FATAL_ERROR);
-			else if (strcmp(args[0].from, "bug") == 0)
-				btrfs_clear_opt(info->mount_opt,
-					      PANIC_ON_FATAL_ERROR);
-			else {
-				ret = -EINVAL;
-				goto out;
-			}
-			break;
-		case Opt_commit_interval:
-			intarg = 0;
-			ret = match_int(&args[0], &intarg);
-			if (ret)
-				goto out;
-			if (intarg == 0) {
-				btrfs_info(info,
-					   "using default commit interval %us",
-					   BTRFS_DEFAULT_COMMIT_INTERVAL);
-				intarg = BTRFS_DEFAULT_COMMIT_INTERVAL;
-			} else if (intarg > 300) {
-				btrfs_warn(info, "excessive commit interval %d",
-					   intarg);
-			}
-			info->commit_interval = intarg;
-			break;
-		case Opt_rescue:
-			ret = parse_rescue_options(info, args[0].from);
-			if (ret < 0)
-				goto out;
-			break;
-#ifdef CONFIG_BTRFS_DEBUG
-		case Opt_fragment_all:
-			btrfs_info(info, "fragmenting all space");
-			btrfs_set_opt(info->mount_opt, FRAGMENT_DATA);
-			btrfs_set_opt(info->mount_opt, FRAGMENT_METADATA);
-			break;
-		case Opt_fragment_metadata:
-			btrfs_info(info, "fragmenting metadata");
-			btrfs_set_opt(info->mount_opt,
-				      FRAGMENT_METADATA);
-			break;
-		case Opt_fragment_data:
-			btrfs_info(info, "fragmenting data");
-			btrfs_set_opt(info->mount_opt, FRAGMENT_DATA);
-			break;
-#endif
-#ifdef CONFIG_BTRFS_FS_REF_VERIFY
-		case Opt_ref_verify:
-			btrfs_info(info, "doing ref verification");
-			btrfs_set_opt(info->mount_opt, REF_VERIFY);
-			break;
-#endif
-		case Opt_err:
-			btrfs_err(info, "unrecognized mount option '%s'", p);
-			ret = -EINVAL;
-			goto out;
-		default:
-			break;
-		}
-	}
-check:
-	/*
-	 * Extra check for current option against current flag
-	 */
-	if (btrfs_test_opt(info, NOLOGREPLAY) && !(new_flags & SB_RDONLY)) {
-		btrfs_err(info,
-			  "nologreplay must be used with ro mount option");
-		ret = -EINVAL;
-	}
-out:
-	if (btrfs_fs_compat_ro(info, FREE_SPACE_TREE) &&
-	    !btrfs_test_opt(info, FREE_SPACE_TREE) &&
-	    !btrfs_test_opt(info, CLEAR_CACHE)) {
-		btrfs_err(info, "cannot disable free space tree");
-		ret = -EINVAL;
-
-	}
-	if (!ret && btrfs_test_opt(info, SPACE_CACHE))
-		btrfs_info(info, "disk space caching is enabled");
-	if (!ret && btrfs_test_opt(info, FREE_SPACE_TREE))
-		btrfs_info(info, "using free space tree");
-	return ret;
-}
-
 struct btrfs_flag_map {
        int bit;
        bool enabled;
@@ -1499,123 +876,6 @@ static int btrfs_fc_parse_param(struct fs_context *fc, struct fs_parameter *para
 	return 0;
 }
 
-/*
- * Parse mount options that are required early in the mount process.
- *
- * All other options will be parsed on much later in the mount process and
- * only when we need to allocate a new super block.
- */
-static int btrfs_parse_device_options(const char *options, fmode_t flags,
-				      void *holder)
-{
-	substring_t args[MAX_OPT_ARGS];
-	char *device_name, *opts, *orig, *p;
-	struct btrfs_device *device = NULL;
-	int error = 0;
-
-	lockdep_assert_held(&uuid_mutex);
-
-	if (!options)
-		return 0;
-
-	/*
-	 * strsep changes the string, duplicate it because btrfs_parse_options
-	 * gets called later
-	 */
-	opts = kstrdup(options, GFP_KERNEL);
-	if (!opts)
-		return -ENOMEM;
-	orig = opts;
-
-	while ((p = strsep(&opts, ",")) != NULL) {
-		int token;
-
-		if (!*p)
-			continue;
-
-		token = match_token(p, tokens, args);
-		if (token == Opt_device) {
-			device_name = match_strdup(&args[0]);
-			if (!device_name) {
-				error = -ENOMEM;
-				goto out;
-			}
-			device = btrfs_scan_one_device(device_name, flags,
-							&btrfs_fs_type);
-			kfree(device_name);
-			if (IS_ERR(device)) {
-				error = PTR_ERR(device);
-				goto out;
-			}
-		}
-	}
-
-out:
-	kfree(orig);
-	return error;
-}
-
-/*
- * Parse mount options that are related to subvolume id
- *
- * The value is later passed to mount_subvol()
- */
-static int btrfs_parse_subvol_options(const char *options, char **subvol_name,
-		u64 *subvol_objectid)
-{
-	substring_t args[MAX_OPT_ARGS];
-	char *opts, *orig, *p;
-	int error = 0;
-	u64 subvolid;
-
-	if (!options)
-		return 0;
-
-	/*
-	 * strsep changes the string, duplicate it because
-	 * btrfs_parse_device_options gets called later
-	 */
-	opts = kstrdup(options, GFP_KERNEL);
-	if (!opts)
-		return -ENOMEM;
-	orig = opts;
-
-	while ((p = strsep(&opts, ",")) != NULL) {
-		int token;
-		if (!*p)
-			continue;
-
-		token = match_token(p, tokens, args);
-		switch (token) {
-		case Opt_subvol:
-			kfree(*subvol_name);
-			*subvol_name = match_strdup(&args[0]);
-			if (!*subvol_name) {
-				error = -ENOMEM;
-				goto out;
-			}
-			break;
-		case Opt_subvolid:
-			error = match_u64(&args[0], &subvolid);
-			if (error)
-				goto out;
-
-			/* we want the original fs_tree */
-			if (subvolid == 0)
-				subvolid = BTRFS_FS_TREE_OBJECTID;
-
-			*subvol_objectid = subvolid;
-			break;
-		default:
-			break;
-		}
-	}
-
-out:
-	kfree(orig);
-	return error;
-}
-
 char *btrfs_get_subvol_name_from_objectid(struct btrfs_fs_info *fs_info,
 					  u64 subvol_objectid)
 {
@@ -2042,7 +1302,7 @@ int btrfs_apply_configuration(struct fs_context *fc,
 
 	if (btrfs_test_exp_opt(ctx, NOTREELOG))
 		btrfs_info(info, "%s tree log",
-				btrfs_opt_map[Opt_notreelog].enabled ? "enabling"
+				btrfs_opt_map[Opt_treelog].enabled ? "enabling"
 				: "disabling");
 
 #ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY
@@ -2216,14 +1476,6 @@ static int btrfs_test_super(struct super_block *s, struct fs_context *fc)
 	return fs_info->fs_devices == p->fs_devices;
 }
 
-static int btrfs_set_super(struct super_block *s, void *data)
-{
-	int err = set_anon_super(s, data);
-	if (!err)
-		s->s_fs_info = data;
-	return err;
-}
-
 /*
  * subvolumes are identified by ino 256
  */
@@ -3081,14 +2333,6 @@ struct file_system_type btrfs_fs_type = {
 	.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",
-	.parameters	= btrfs_fs_parameters,
-	.kill_sb	= btrfs_kill_super,
-	.fs_flags	= FS_REQUIRES_DEV | FS_BINARY_MOUNTDATA,
 };
 
 MODULE_ALIAS_FS("btrfs");
-- 
2.28.0


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [RFC PATCH 7/8] btrfs: Convert to fs_context
  2020-08-12 16:36 ` [RFC PATCH 7/8] btrfs: Convert to fs_context Marcos Paulo de Souza
@ 2020-08-13 10:22   ` kernel test robot
  2020-08-17 13:26   ` David Sterba
  1 sibling, 0 replies; 15+ messages in thread
From: kernel test robot @ 2020-08-13 10:22 UTC (permalink / raw)
  To: kbuild-all

[-- Attachment #1: Type: text/plain, Size: 4584 bytes --]

Hi Marcos,

[FYI, it's a private test report for your RFC patch.]
[auto build test WARNING on kdave/for-next]
[also build test WARNING on next-20200812]
[cannot apply to v5.8]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Marcos-Paulo-de-Souza/btrfs-convert-to-fscontext/20200813-012641
base:   https://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux.git for-next
config: mips-randconfig-r031-20200813 (attached as .config)
compiler: clang version 12.0.0 (https://github.com/llvm/llvm-project 62ef1cb2079123b86878e4bfed3c14db448f1373)
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # install mips cross compiling tool for clang build
        # apt-get install binutils-mips-linux-gnu
        # save the attached .config to linux build tree
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross ARCH=mips 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

   In file included from fs/btrfs/super.c:31:
   In file included from fs/btrfs/delayed-inode.h:17:
   fs/btrfs/ctree.h:2292:8: warning: 'const' type qualifier on return type has no effect [-Wignored-qualifiers]
   size_t __const btrfs_get_num_csums(void);
          ^~~~~~~~
   In file included from fs/btrfs/super.c:47:
   fs/btrfs/sysfs.h:16:14: warning: 'const' type qualifier on return type has no effect [-Wignored-qualifiers]
   const char * const btrfs_feature_set_name(enum btrfs_feature_set set);
                ^~~~~~
>> fs/btrfs/super.c:2420:5: warning: no previous prototype for function 'btrfs_mount_root_fc' [-Wmissing-prototypes]
   int btrfs_mount_root_fc(struct fs_context *fc, unsigned int rdonly)
       ^
   fs/btrfs/super.c:2420:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
   int btrfs_mount_root_fc(struct fs_context *fc, unsigned int rdonly)
   ^
   static 
   fs/btrfs/super.c:3086:32: warning: unused variable 'btrfs_root_fs_type' [-Wunused-variable]
   static struct file_system_type btrfs_root_fs_type = {
                                  ^
   fs/btrfs/super.c:1508:12: warning: unused function 'btrfs_parse_device_options' [-Wunused-function]
   static int btrfs_parse_device_options(const char *options, fmode_t flags,
              ^
   fs/btrfs/super.c:1563:12: warning: unused function 'btrfs_parse_subvol_options' [-Wunused-function]
   static int btrfs_parse_subvol_options(const char *options, char **subvol_name,
              ^
   fs/btrfs/super.c:2219:12: warning: unused function 'btrfs_set_super' [-Wunused-function]
   static int btrfs_set_super(struct super_block *s, void *data)
              ^
   7 warnings generated.

vim +/btrfs_mount_root_fc +2420 fs/btrfs/super.c

  2414	
  2415	/*
  2416	 * Duplicate the current fc and prepare for mounting the root.
  2417	 * btrfs_get_tree will be called recursively, but then will check for the
  2418	 * ctx->root being set and call btrfs_root_get_tree.
  2419	 */
> 2420	int btrfs_mount_root_fc(struct fs_context *fc, unsigned int rdonly)
  2421	{
  2422		struct btrfs_fs_context *ctx, *root_ctx;
  2423		struct fs_context *root_fc;
  2424		struct vfsmount *root_mnt;
  2425		int ret;
  2426	
  2427		root_fc = vfs_dup_fs_context(fc);
  2428		if (IS_ERR(root_fc))
  2429			return PTR_ERR(root_fc);
  2430	
  2431		root_fc->sb_flags &= ~SB_RDONLY;
  2432		root_fc->sb_flags |= rdonly | SB_NOSEC;
  2433		root_ctx = root_fc->fs_private;
  2434		root_ctx->root_mnt = NULL;
  2435		root_ctx->root = true;
  2436	
  2437		/*
  2438		 * fc_mount will call btrfs_get_tree again, and by checking ctx->root
  2439		 * being true it'll call btrfs_root_get_tree to avoid infinite recursion.
  2440		 */
  2441		root_mnt = fc_mount(root_fc);
  2442		if (IS_ERR(root_mnt)) {
  2443			ret = PTR_ERR(root_mnt);
  2444			goto error_fc;
  2445		}
  2446	
  2447		ctx = fc->fs_private;
  2448		ctx->root_mnt = root_mnt;
  2449		ret = 0;
  2450	
  2451	error_fc:
  2452		put_fs_context(root_fc);
  2453		return ret;
  2454	}
  2455	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org

[-- Attachment #2: config.gz --]
[-- Type: application/gzip, Size: 30112 bytes --]

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFC PATCH 0/8] btrfs: convert to fscontext
  2020-08-12 16:36 [RFC PATCH 0/8] btrfs: convert to fscontext Marcos Paulo de Souza
                   ` (7 preceding siblings ...)
  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 ` David Sterba
  8 siblings, 0 replies; 15+ messages in thread
From: David Sterba @ 2020-08-17 12:44 UTC (permalink / raw)
  To: Marcos Paulo de Souza
  Cc: dsterba, linux-btrfs, Marcos Paulo de Souza, dhowells

On Wed, Aug 12, 2020 at 01:36:46PM -0300, Marcos Paulo de Souza wrote:
> From: Marcos Paulo de Souza <mpdesouza@suse.com>
> 
> These patches aim to convert btrfs to new fscontext API. I used the approach of
> creating a new parsing function and then switching to this new function, instead
> of creating a huge change patch. Please let me know if you think this is a
> better approach.

A huge patch would be unreviewable, incremental addition of the
callbacks and then 1 patch switch is what we want. Also we want the
whole series to be bisectable, I'm not sure if adding the callbacks like
.parameters will not take some path in the fs context and mixing it
together with the previous mount way.

This could be avoided by adding all the callbacks first and then
switching just the callbacks, without any other changes. The way you do
it in patch "btrfs: Convert to fs_context" feels too much. Temporary
code duplication is ok, removing unused functions as post-cleanups is
preferred.

> The most notable changes come form the fact that now we parse the mount options
> before having a fs_info, in the same way that David Howells did in his POC[1]
> some time ago.

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

Adding David H. to CC.

> Marcos Paulo de Souza (8):
>   btrfs: fs_context: Add initial fscontext parameters
>   btrfs: super: Introduce fs_context ops, init and free functions
>   btrfs: super: Introduce btrfs_fc_parse_param and
>     btrfs_apply_configuration
>   btrfs: super: Introduce btrfs_fc_validate
>   btrfs: super: Introduce btrfs_dup_fc
>   btrfs: super: Introduce btrfs_mount_root_fc
>   btrfs: Convert to fs_context
>   btrfs: Remove leftover code from fscontext conversion

Please change the subjects to "btrfs: fs_context: ...", this is not
about super block.

I'll reply with more specific comments under the patches.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFC PATCH 2/8] btrfs: super: Introduce fs_context ops, init and free functions
  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
  0 siblings, 0 replies; 15+ messages in thread
From: David Sterba @ 2020-08-17 12:50 UTC (permalink / raw)
  To: Marcos Paulo de Souza; +Cc: dsterba, linux-btrfs, Marcos Paulo de Souza

On Wed, Aug 12, 2020 at 01:36:48PM -0300, Marcos Paulo de Souza wrote:
> From: Marcos Paulo de Souza <mpdesouza@suse.com>
> 
> Create a btrfs_fs_context struct that will be used as fs_private between
> the fs context calls, holding options to be later assigned to fs_info,
> since we don't have a proper btrfs_fs_info at the parse_args phase.
> 
> fs_context is still not being used since the init function isn't being
> assigned in btrfs_fs_type.
> 
> Signed-off-by: Marcos Paulo de Souza <mpdesouza@suse.com>
> ---
>  fs/btrfs/ctree.h | 27 +++++++++++++++++++++++++++
>  fs/btrfs/super.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 72 insertions(+)
> 
> diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
> index 9c7e466f27a9..b7e3962a0941 100644
> --- a/fs/btrfs/ctree.h
> +++ b/fs/btrfs/ctree.h
> @@ -28,6 +28,7 @@
>  #include <linux/dynamic_debug.h>
>  #include <linux/refcount.h>
>  #include <linux/crc32c.h>
> +#include "compression.h"
>  #include "extent-io-tree.h"
>  #include "extent_io.h"
>  #include "extent_map.h"
> @@ -35,6 +36,32 @@
>  #include "block-rsv.h"
>  #include "locking.h"
>  
> +struct btrfs_fs_context {
> +	char **devices;
> +	char *subvol_name;
> +	u64 subvolid;
> +
> +	int nr_devices;
> +	unsigned long mount_opt;
> +	unsigned long mount_opt_explicity;

What does 'explicity' mean here?

> +	unsigned long pending_changes;
> +	enum btrfs_compression_type	compress_type;
> +	unsigned int			compress_level;
> +
> +	u64				max_inline;
> +	u32				metadata_ratio;
> +	u32				thread_pool_size;
> +	u32				commit_interval;
> +#ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY
> +	u32				check_integrity_print_mask;
> +#endif

Please change the indentation to the single space.

> +
> +	struct vfsmount *root_mnt;
> +	bool root;
> +	bool nospace_cache;
> +	bool no_compress;
> +};
> +
>  struct btrfs_trans_handle;
>  struct btrfs_transaction;
>  struct btrfs_pending_snapshot;
> diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
> index 4e6654af90ea..fe19ffe962c6 100644
> --- a/fs/btrfs/super.c
> +++ b/fs/btrfs/super.c
> @@ -2326,6 +2326,51 @@ static void btrfs_kill_super(struct super_block *sb)
>  	btrfs_free_fs_info(fs_info);
>  }
>  
> +static void btrfs_fc_free(struct fs_context *fc)
> +{
> +	struct btrfs_fs_context *ctx = fc->fs_private;
> +	struct btrfs_fs_info *info = fc->s_fs_info;
> +
> +	if (info)
> +		btrfs_free_fs_info(info);
> +	if (ctx) {
> +		mntput(ctx->root_mnt);
> +		if (ctx->devices) {
> +			int i;
> +
> +			for (i = 0; i < ctx->nr_devices; i++)
> +				kfree(ctx->devices[i]);
> +			kfree(ctx->devices);
> +		}
> +		kfree(ctx->subvol_name);
> +		kfree(ctx);
> +	}
> +}
> +
> +static const struct fs_context_operations btrfs_context_ops = {
> +	.free = btrfs_fc_free,
> +};
> +
> +static int btrfs_init_fs_context(struct fs_context *fc)
> +{
> +	struct btrfs_fs_context *ctx;
> +
> +	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
> +	if (!ctx)
> +		return -ENOMEM;
> +
> +	/* currently default options */

Please update all comments to uppercase first letter, unless it's an
identifier.

> +	btrfs_set_opt(ctx->mount_opt, SPACE_CACHE);
> +#ifdef CONFIG_BTRFS_FS_POSIX_ACL
> +	fc->sb_flags |= SB_POSIXACL;
> +#endif
> +	ctx->commit_interval = BTRFS_DEFAULT_COMMIT_INTERVAL;
> +
> +	fc->fs_private = ctx;
> +	fc->ops = &btrfs_context_ops;

So here the fc->ops are initialized but there are still unimplemented
callbacks in btrfs_context_ops.

Looking to fs/fs_context.c alloc_fs_context, this will assume that
support fc exists and does not use the wrappers, legacy_init_fs_context.
This would probably break bisection.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFC PATCH 3/8] btrfs: super: Introduce btrfs_fc_parse_param and btrfs_apply_configuration
  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
  0 siblings, 0 replies; 15+ messages in thread
From: David Sterba @ 2020-08-17 13:09 UTC (permalink / raw)
  To: Marcos Paulo de Souza; +Cc: dsterba, linux-btrfs, Marcos Paulo de Souza

On Wed, Aug 12, 2020 at 01:36:49PM -0300, Marcos Paulo de Souza wrote:
> From: Marcos Paulo de Souza <mpdesouza@suse.com>
> 
> The first function will parse the arguments using the new fs_context API
> saving the arguments in btrfs_fs_context, while the second one populate
> the settings of btrfs_fs_info using the context previously set.
> 
> Signed-off-by: Marcos Paulo de Souza <mpdesouza@suse.com>
> ---
>  fs/btrfs/ctree.h |   1 +
>  fs/btrfs/super.c | 609 +++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 610 insertions(+)
> 
> diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
> index b7e3962a0941..d96bce2ea5bb 100644
> --- a/fs/btrfs/ctree.h
> +++ b/fs/btrfs/ctree.h
> @@ -3102,6 +3102,7 @@ int btrfs_defrag_leaves(struct btrfs_trans_handle *trans,
>  /* super.c */
>  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);
>  int btrfs_sync_fs(struct super_block *sb, int wait);
>  char *btrfs_get_subvol_name_from_objectid(struct btrfs_fs_info *fs_info,
>  					  u64 subvol_objectid);
> diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
> index fe19ffe962c6..3425a77ecd57 100644
> --- a/fs/btrfs/super.c
> +++ b/fs/btrfs/super.c
> @@ -1051,6 +1051,394 @@ int btrfs_parse_options(struct btrfs_fs_info *info, char *options,
>  	return ret;
>  }
>  
> +struct btrfs_flag_map {
> +       int bit;
> +       bool enabled;
> +};
> +
> +#define INIT_MAP(OPT) { BTRFS_MOUNT_##OPT, false }
> +#define btrfs_test_exp_opt(fs_info, opt) \
> +	((fs_info)->mount_opt_explicity & BTRFS_MOUNT_##opt)
> +
> +/* Opt_err is the latest option */
> +static struct btrfs_flag_map btrfs_opt_map[Opt_err] = {
> +	[Opt_barrier] = INIT_MAP(NOBARRIER),
> +	[Opt_check_integrity] = INIT_MAP(CHECK_INTEGRITY),
> +	[Opt_check_integrity_including_extent_data] =
> +		INIT_MAP(CHECK_INTEGRITY_INCLUDING_EXTENT_DATA),
> +	[Opt_datacow] = INIT_MAP(NODATACOW),
> +	[Opt_datasum] = INIT_MAP(NODATASUM),
> +	[Opt_discard] = INIT_MAP(DISCARD_SYNC),
> +	[Opt_defrag] = INIT_MAP(AUTO_DEFRAG),
> +	[Opt_degraded] = INIT_MAP(DEGRADED),
> +	[Opt_flushoncommit] = INIT_MAP(FLUSHONCOMMIT),
> +	[Opt_inode_cache] = INIT_MAP(INODE_MAP_CACHE),
> +	[Opt_nologreplay] = INIT_MAP(NOLOGREPLAY),
> +	[Opt_ssd] = INIT_MAP(SSD),
> +	[Opt_ssd_spread] = INIT_MAP(SSD_SPREAD),
> +	[Opt_treelog] = INIT_MAP(NOTREELOG),
> +	[Opt_ref_verify] = INIT_MAP(REF_VERIFY),
> +};
> +
> +static int btrfs_fc_parse_param(struct fs_context *fc, struct fs_parameter *param)
> +{
> +	int opt;
> +	char *compress_type;
> +	char **devs;
> +	bool compress_force = false;
> +	enum btrfs_compression_type saved_compress_type;
> +	bool saved_compress_force;
> +	struct fs_parse_result result;
> +	struct btrfs_fs_context *ctx = fc->fs_private;
> +
> +	opt = fs_parse(fc, btrfs_fs_parameters, param, &result);
> +	if (opt < 0)
> +		return opt;
> +
> +	/*
> +	 * Store the option parsed to avoid being too noisy in
> +	 * btrfs_apply_configuration.
> +	 */
> +	ctx->mount_opt_explicity |= btrfs_opt_map[opt].bit;
> +	btrfs_opt_map[opt].enabled = !result.negated;
> +
> +	switch (opt) {
> +	case Opt_acl:
> +		if (result.negated) {
> +			fc->sb_flags &= ~SB_POSIXACL;
> +		} else {
> +#ifndef CONFIG_BTRFS_FS_POSIX_ACL
> +			return invalf(fc, "support for ACL not compiled in!");
> +#else
> +			fc->sb_flags |= SB_POSIXACL;
> +#endif
> +		}
> +		break;
> +	case Opt_barrier:
> +		if (result.negated)
> +			btrfs_set_opt(ctx->mount_opt, NOBARRIER);
> +		else
> +			btrfs_clear_opt(ctx->mount_opt, NOBARRIER);
> +		break;

Take this as an example: there's a lot of boilerplate code that does the

	if (negated)
		set(something)
	else
		clear(something)

> +	case Opt_clear_cache:
> +		btrfs_set_opt(ctx->mount_opt, CLEAR_CACHE);
> +		break;
> +	case Opt_commit_interval:
> +		ctx->commit_interval = result.uint_32;
> +		break;
> +	case Opt_compress_force:
> +	case Opt_compress_force_type:
> +		compress_force = true;
> +		fallthrough;
> +	case Opt_compress:
> +	case Opt_compress_type:
> +		saved_compress_type = btrfs_test_opt(ctx, COMPRESS) ?
> +			ctx->compress_type : BTRFS_COMPRESS_NONE;
> +		saved_compress_force =
> +			btrfs_test_opt(ctx, FORCE_COMPRESS);
> +		if (opt == Opt_compress ||
> +		    opt == Opt_compress_force ||
> +		    strncmp(param->string, "zlib", 4) == 0) {
> +			compress_type = "zlib";
> +
> +			ctx->compress_type = BTRFS_COMPRESS_ZLIB;
> +			ctx->compress_level = BTRFS_ZLIB_DEFAULT_LEVEL;
> +			/*
> +			 * param->string contains uninitialized data since
> +			 * for these options we don't expect any
> +			 * parameter.
> +			 */
> +			if (opt != Opt_compress &&
> +			    opt != Opt_compress_force)
> +				ctx->compress_level =
> +				  btrfs_compress_str2level(
> +						BTRFS_COMPRESS_ZLIB,
> +						param->string + 4);
> +			btrfs_set_opt(ctx->mount_opt, COMPRESS);
> +			btrfs_clear_opt(ctx->mount_opt, NODATACOW);
> +			btrfs_clear_opt(ctx->mount_opt, NODATASUM);
> +			ctx->no_compress = false;
> +		} else if (strncmp(param->string, "lzo", 3) == 0) {
> +			compress_type = "lzo";
> +			ctx->compress_type = BTRFS_COMPRESS_LZO;
> +			/* btrfs does not exposes lzo compression levels */
> +			ctx->compress_level = 0;
> +			btrfs_set_opt(ctx->mount_opt, COMPRESS);
> +			btrfs_clear_opt(ctx->mount_opt, NODATACOW);
> +			btrfs_clear_opt(ctx->mount_opt, NODATASUM);
> +			ctx->no_compress = false;
> +		} else if (strncmp(param->string, "zstd", 4) == 0) {
> +			compress_type = "zstd";
> +			ctx->compress_type = BTRFS_COMPRESS_ZSTD;
> +			ctx->compress_level =
> +				btrfs_compress_str2level(
> +						 BTRFS_COMPRESS_ZSTD,
> +						 param->string + 4);
> +			btrfs_set_opt(ctx->mount_opt, COMPRESS);
> +			btrfs_clear_opt(ctx->mount_opt, NODATACOW);
> +			btrfs_clear_opt(ctx->mount_opt, NODATASUM);
> +			ctx->no_compress = false;
> +		} else if (strncmp(param->string, "no", 2) == 0) {
> +			compress_type = "no";
> +			ctx->compress_level = 0;
> +			btrfs_clear_opt(ctx->mount_opt, COMPRESS);
> +			btrfs_clear_opt(ctx->mount_opt, FORCE_COMPRESS);
> +			compress_force = false;
> +			ctx->no_compress = true;
> +		} else {
> +			return invalf(fc, "Invalid compression option: %s",
> +								param->string);
> +		}
> +
> +		if (compress_force) {
> +			btrfs_set_opt(ctx->mount_opt, FORCE_COMPRESS);
> +		} else {
> +			/*
> +			 * If we reconfigure from compress-force=xxx to
> +			 * compress=xxx, we need clear FORCE_COMPRESS
> +			 * flag, otherwise, there is no way for users
> +			 * to disable forcible compression separately.
> +			 */
> +			btrfs_clear_opt(ctx->mount_opt, FORCE_COMPRESS);
> +		}
> +		break;
> +	case Opt_degraded:
> +		btrfs_set_opt(ctx->mount_opt, DEGRADED);
> +		break;
> +	case Opt_device:
> +		devs = krealloc(ctx->devices,
> +				sizeof(char *) * (ctx->nr_devices + 1),
> +				GFP_KERNEL);
> +		if (!devs)
> +			return -ENOMEM;
> +		devs[ctx->nr_devices] = param->string;
> +		param->string = NULL;
> +		ctx->devices = devs;
> +		ctx->nr_devices++;
> +		break;
> +	case Opt_datacow:
> +		if (result.negated) {
> +			btrfs_clear_opt(ctx->mount_opt, COMPRESS);
> +			btrfs_clear_opt(ctx->mount_opt, FORCE_COMPRESS);
> +			btrfs_set_opt(ctx->mount_opt, NODATACOW);
> +			btrfs_set_opt(ctx->mount_opt, NODATASUM);
> +		} else {
> +			btrfs_clear_opt(ctx->mount_opt, NODATACOW);
> +		}
> +		break;

Another pattern that both sets and clears for each negated branch.

> +	case Opt_datasum:
> +		if (result.negated) {
> +			btrfs_set_opt(ctx->mount_opt, NODATASUM);
> +		} else {
> +			btrfs_clear_opt(ctx->mount_opt, NODATACOW);
> +			btrfs_clear_opt(ctx->mount_opt, NODATASUM);
> +		}
> +		break;
> +	case Opt_defrag:
> +		if (result.negated)
> +			btrfs_clear_opt(ctx->mount_opt, AUTO_DEFRAG);
> +		else
> +			btrfs_set_opt(ctx->mount_opt, AUTO_DEFRAG);
> +		break;
> +	case Opt_discard:
> +		if (result.negated) {
> +			btrfs_clear_opt(ctx->mount_opt, DISCARD_SYNC);
> +			btrfs_clear_opt(ctx->mount_opt, DISCARD_ASYNC);
> +		} else {
> +			btrfs_clear_opt(ctx->mount_opt, DISCARD_ASYNC);
> +			btrfs_set_opt(ctx->mount_opt, DISCARD_SYNC);
> +		}
> +		break;
> +	case Opt_discard_mode:
> +		if (strcmp(param->string, "sync") == 0) {
> +			btrfs_clear_opt(ctx->mount_opt, DISCARD_ASYNC);
> +			btrfs_set_opt(ctx->mount_opt, DISCARD_SYNC);
> +		} else if (strcmp(param->string, "async") == 0) {
> +			btrfs_clear_opt(ctx->mount_opt, DISCARD_SYNC);
> +			btrfs_set_opt(ctx->mount_opt, DISCARD_ASYNC);
> +		} else {
> +			return invalf(fc, "Invalid discard mode: %s",
> +								param->string);
> +		}
> +		break;
> +	case Opt_enospc_debug:
> +		if (result.negated)
> +			btrfs_clear_opt(ctx->mount_opt, ENOSPC_DEBUG);
> +		else
> +			btrfs_set_opt(ctx->mount_opt, ENOSPC_DEBUG);
> +		break;
> +	case Opt_fatal_errors:
> +		if (strcmp(param->string, "panic") == 0)
> +			btrfs_set_opt(ctx->mount_opt, PANIC_ON_FATAL_ERROR);
> +		else if (strcmp(param->string, "bug") == 0)
> +			btrfs_clear_opt(ctx->mount_opt, PANIC_ON_FATAL_ERROR);
> +		else
> +			return invalf(fc, "Invalid fatal_errors option: %s",
> +								param->string);
> +		break;
> +	case Opt_flushoncommit:
> +		if (result.negated)
> +			btrfs_clear_opt(ctx->mount_opt, FLUSHONCOMMIT);
> +		else
> +			btrfs_set_opt(ctx->mount_opt, FLUSHONCOMMIT);
> +		break;
> +#ifdef CONFIG_BTRFS_DEBUG
> +	case Opt_fragment:
> +		if (strcmp(param->string, "all") == 0) {
> +			btrfs_set_opt(ctx->mount_opt, FRAGMENT_DATA);
> +			btrfs_set_opt(ctx->mount_opt, FRAGMENT_METADATA);
> +		} else if (strcmp(param->string, "metadata") == 0) {
> +			btrfs_set_opt(ctx->mount_opt, FRAGMENT_METADATA);
> +		} else if (strcmp(param->string, "data") == 0) {
> +			btrfs_set_opt(ctx->mount_opt, FRAGMENT_DATA);
> +		} else {
> +			return invalf(fc, "Invalid fragment option: %s",
> +					param->string);
> +		}
> +		break;
> +#endif
> +#ifdef CONFIG_BTRFS_FS_REF_VERIFY
> +	case Opt_ref_verify:
> +		btrfs_set_opt(ctx->mount_opt, REF_VERIFY);
> +		break;
> +#endif
> +	case Opt_inode_cache:
> +		/* handled in btrfs_apply_configuration */
> +		break;
> +	case Opt_max_inline:
> +		ctx->max_inline = memparse(param->string, NULL);
> +		break;
> +	case Opt_norecovery:
> +	case Opt_nologreplay:
> +		warnf(fc, "'%s' is deprecated, use 'rescue=nologreplay' instead",
> +				opt == Opt_norecovery ? "norecovery"
> +							: "nologreplay");
> +		btrfs_set_opt(ctx->mount_opt, NOLOGREPLAY);
> +		break;
> +	case Opt_ratio:
> +		ctx->metadata_ratio = result.uint_32;
> +		break;
> +	case Opt_rescue:
> +		if (strcmp(param->string, "usebackuproot") == 0) {
> +			btrfs_set_opt(ctx->mount_opt, USEBACKUPROOT);
> +		} else if (strcmp(param->string, "nologreplay") == 0) {
> +			btrfs_set_opt(ctx->mount_opt, NOLOGREPLAY);
> +		} else {
> +			return invalf(fc, "unrecognized rescue option '%s'",
> +					param->string);
> +		}
> +		break;
> +	case Opt_skip_balance:
> +		btrfs_set_opt(ctx->mount_opt, SKIP_BALANCE);
> +		break;
> +	case Opt_rescan_uuid_tree:
> +		btrfs_set_opt(ctx->mount_opt, RESCAN_UUID_TREE);
> +		break;
> +	case Opt_space_cache:
> +		if (result.negated) {
> +			if (btrfs_test_opt(ctx, SPACE_CACHE))
> +				btrfs_clear_opt(ctx->mount_opt, SPACE_CACHE);
> +			if (btrfs_test_opt(ctx, FREE_SPACE_TREE))
> +				btrfs_clear_opt(ctx->mount_opt, FREE_SPACE_TREE);
> +			ctx->nospace_cache = true;
> +		} else {
> +			btrfs_clear_opt(ctx->mount_opt, FREE_SPACE_TREE);
> +			btrfs_set_opt(ctx->mount_opt, SPACE_CACHE);
> +			ctx->nospace_cache = false;
> +		}
> +		break;
> +	case Opt_space_cache_version:
> +		ctx->nospace_cache = false;
> +		if (strcmp(param->string, "v1") == 0) {
> +			btrfs_clear_opt(ctx->mount_opt, FREE_SPACE_TREE);
> +			btrfs_set_opt(ctx->mount_opt, SPACE_CACHE);
> +		} else if (strcmp(param->string, "v2") == 0) {
> +			btrfs_clear_opt(ctx->mount_opt, SPACE_CACHE);
> +			btrfs_set_opt(ctx->mount_opt, FREE_SPACE_TREE);
> +		} else {
> +			return invalf(fc, "Invalid space_cache version: %s",
> +								param->string);
> +		}
> +		break;
> +	case Opt_ssd:
> +		if (result.negated) {
> +			btrfs_set_opt(ctx->mount_opt, NOSSD);
> +			btrfs_clear_opt(ctx->mount_opt, SSD);
> +			btrfs_clear_opt(ctx->mount_opt, SSD_SPREAD);
> +		} else {
> +			btrfs_clear_opt(ctx->mount_opt, NOSSD);
> +			btrfs_set_opt(ctx->mount_opt, SSD);
> +		}
> +		break;
> +	case Opt_ssd_spread:
> +		if (result.negated) {
> +			btrfs_clear_opt(ctx->mount_opt, SSD_SPREAD);
> +		} else {
> +			btrfs_set_opt(ctx->mount_opt, SSD);
> +			btrfs_set_opt(ctx->mount_opt, SSD_SPREAD);
> +			btrfs_clear_opt(ctx->mount_opt, NOSSD);
> +		}
> +		break;
> +	case Opt_subvol:
> +		kfree(ctx->subvol_name);
> +		ctx->subvol_name = param->string;
> +		param->string = NULL;
> +		break;
> +	case Opt_subvolid:
> +		ctx->subvolid = result.uint_64;
> +
> +		/* we want the original fs_tree */
> +		if (ctx->subvolid == 0)
> +			ctx->subvolid = BTRFS_FS_TREE_OBJECTID;
> +		break;
> +	case Opt_thread_pool:
> +		if (result.uint_32 == 0)
> +			return invalf(fc, "Invalid thread_pool value: 0");
> +
> +		ctx->thread_pool_size = result.uint_32;
> +		break;
> +	case Opt_treelog:
> +		if (result.negated)
> +			btrfs_set_opt(ctx->mount_opt, NOTREELOG);
> +		else
> +			btrfs_clear_opt(ctx->mount_opt, NOTREELOG);
> +		break;
> +#ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY
> +	case Opt_check_integrity_including_extent_data:
> +		btrfs_set_opt(ctx->mount_opt,
> +			      CHECK_INTEGRITY_INCLUDING_EXTENT_DATA);
> +		btrfs_set_opt(ctx->mount_opt, CHECK_INTEGRITY);
> +		break;
> +	case Opt_check_integrity:
> +		btrfs_set_opt(ctx->mount_opt, CHECK_INTEGRITY);
> +		break;
> +	case Opt_check_integrity_print_mask:
> +		ctx->check_integrity_print_mask = result.uint_32;
> +		break;
> +#else
> +	case Opt_check_integrity_including_extent_data:
> +	case Opt_check_integrity:
> +	case Opt_check_integrity_print_mask:
> +		return invalf(fc, "support for check_integrity* not compiled in!");
> +#endif
> +	case Opt_user_subvol_rm_allowed:
> +		btrfs_set_opt(ctx->mount_opt, USER_SUBVOL_RM_ALLOWED);
> +		break;
> +	case Opt_recovery:
> +		fallthrough;
> +	case Opt_usebackuproot:
> +		warnf(fc, "'%s' is deprecated, use 'rescue=usebackuproot' instead",
> +			opt == Opt_recovery ? "recovery" :
> +			"usebackuproot");
> +		btrfs_set_opt(ctx->mount_opt, USEBACKUPROOT);
> +		break;
> +	default:
> +		return invalf(fc, "Invalid mount option: %s", param->key);
> +	}
> +
> +	return 0;
> +}

The table based option definition could be enhanced to simplify the two
easy cases so that we only need to call the same helper and merge the
options into one case:

	switch (option) {
	case Opt_a:
	case Opt_b:
	case Opt_c:
	case Opt_d:
	case Opt_e:
	case Opt_f:
		handle_simple_option(result, option);
		break;
	...
	}

	struct btrfs_flag_map {
	       int option_bit;
	       unsigned set_bits;
	       unsigned clear_bits;
	       unsigned set_bits_if_neg;
	       unsigned clear_bits_if_neg;
	       bool enabled;
	};

and handle_simple_option(result, int option) does 

	if (result.negated) {
		set bits(btrfs_opt_map[option]->set_bits_if_neg);
		clear bits(btrfs_opt_map[option]->set_bits_if_neg);
	} else {
		set bits(btrfs_opt_map[option]->set_bits);
		clear bits(btrfs_opt_map[option]->set_bits);
	}

Then the table looks like

	[Opt_datacow] {
		.set_bits		= 0,
		.clear_bits		= NODATACOW,
		.set_bits_if_neg	= NODATACOW | NODATASUM,
		.clear_bits_if_neg	= COMPRESS | FORCE_COMPRESS,
	},

Other options that need to do specific settings can opencode what they
need but the helper can also deal with compression and setting/clearing
the nodatasum/nodatacow bits.

> +
>  /*
>   * Parse mount options that are required early in the mount process.
>   *
> @@ -1400,6 +1788,226 @@ static int btrfs_fill_super(struct super_block *sb,
>  	return err;
>  }
>  
> +int btrfs_apply_configuration(struct fs_context *fc,
> +				struct super_block *sb)
> +{
> +	struct btrfs_fs_context *ctx = fc->fs_private;
> +	struct btrfs_fs_info *info = sb->s_fs_info;
> +
> +#ifdef CONFIG_BTRFS_FS_POSIX_ACL
> +	if (!(fc->sb_flags & SB_POSIXACL))
> +		sb->s_flags &= ~SB_POSIXACL;
> +	else
> +		sb->s_flags |= SB_POSIXACL;
> +#endif
> +
> +	if (btrfs_test_exp_opt(ctx, NOBARRIER))
> +		btrfs_info(info, "turning %s barriers",
> +				btrfs_opt_map[Opt_barrier].enabled ? "on" : "off");
> +
> +	if (btrfs_test_exp_opt(ctx, CLEAR_CACHE))
> +		btrfs_info(info, "force clearing of disk cache");
> +
> +	if (ctx->commit_interval == 0) {
> +		btrfs_info(info, "using default commit interval %us",
> +			   BTRFS_DEFAULT_COMMIT_INTERVAL);
> +		ctx->commit_interval = BTRFS_DEFAULT_COMMIT_INTERVAL;
> +	} else if (ctx->commit_interval > 300) {
> +		btrfs_warn(info, "excessive commit interval %d",
> +					ctx->commit_interval);
> +	}
> +	info->commit_interval = ctx->commit_interval;
> +
> +	if (btrfs_test_opt(ctx, COMPRESS) || ctx->no_compress) {
> +		btrfs_info(info, "%s %s compression, level %d",
> +				btrfs_test_opt(ctx, FORCE_COMPRESS) ? "force" : "use",
> +				ctx->no_compress ? "no"
> +				: btrfs_compress_type2str(ctx->compress_type),
> +				ctx->compress_level);
> +
> +		if (ctx->compress_type == BTRFS_COMPRESS_LZO)
> +			btrfs_set_fs_incompat(info, COMPRESS_LZO);
> +		else if (ctx->compress_type == BTRFS_COMPRESS_ZSTD)
> +			btrfs_set_fs_incompat(info, COMPRESS_ZSTD);
> +	}
> +
> +	if (btrfs_test_exp_opt(ctx, DEGRADED))
> +		btrfs_info(info, "allowing degraded mounts");
> +
> +	if (btrfs_test_exp_opt(ctx, NODATACOW)) {
> +		if (btrfs_opt_map[Opt_datacow].enabled) {
> +			btrfs_info(info, "setting datacow");
> +		} else {
> +			if (!btrfs_test_opt(ctx, COMPRESS) ||
> +					!btrfs_test_opt(ctx, FORCE_COMPRESS)) {
> +				btrfs_info(info, "setting nodatacow, compression disabled");
> +			} else {
> +				btrfs_info(info, "setting nodatacow");
> +			}
> +		}
> +	}
> +
> +	if (btrfs_test_exp_opt(ctx, NODATASUM)) {
> +		if (!btrfs_opt_map[Opt_datasum].enabled) {
> +			btrfs_info(info, "setting nodatasum");
> +		} else {
> +			if (btrfs_test_opt(ctx, NODATASUM)) {
> +				if (btrfs_test_opt(ctx, NODATACOW))
> +					btrfs_info(info, "setting datasum, datacow enabled");
> +				else
> +					btrfs_info(info, "setting datasum");
> +			}
> +		}
> +	}
> +
> +	if (btrfs_test_exp_opt(ctx, AUTO_DEFRAG))
> +		btrfs_info(info, "%s auto defrag",
> +				btrfs_opt_map[Opt_barrier].enabled ? "enabling"
> +				: "disabling");
> +
> +	if (btrfs_test_opt(ctx, DISCARD_ASYNC)) {
> +		btrfs_info(info, "turning on async discard");
> +	} else if (btrfs_test_exp_opt(ctx, DISCARD_SYNC)) {
> +		if (!btrfs_opt_map[Opt_discard].enabled) {
> +			btrfs_info(info, "turning off discard");
> +			btrfs_info(info, "turning off async discard");
> +		} else {
> +			btrfs_info(info, "turning on sync discard");
> +		}
> +	}
> +
> +	if (btrfs_test_exp_opt(ctx, FLUSHONCOMMIT))
> +		btrfs_info(info, "turning %s flush-on-commit",
> +				btrfs_opt_map[Opt_flushoncommit].enabled ? "on" : "off");
> +
> +#ifdef CONFIG_BTRFS_DEBUG
> +	if (btrfs_test_opt(ctx, FRAGMENT_DATA) && btrfs_test_opt(ctx, FRAGMENT_METADATA))

Line too long, break it after &&

> +		btrfs_info(info, "fragmenting all space");
> +	else if (btrfs_test_opt(ctx, FRAGMENT_METADATA))
> +		btrfs_info(info, "fragmenting metadata");
> +	else if (btrfs_test_opt(ctx, FRAGMENT_DATA))
> +		btrfs_info(info, "fragmenting data");
> +#endif
> +
> +#ifdef CONFIG_BTRFS_FS_REF_VERIFY
> +       if (btrfs_test_exp_opt(ctx, REF_VERIFY))
> +               btrfs_info(info, "doing ref verification");
> +#endif
> +
> +	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");
> +		} else {
> +			btrfs_info(info,
> +				"the 'inode_cache' option is deprecated and will have no effect from 5.11");

strings to messages should be un-indented so they fit to 80 cols

> +			btrfs_set_pending_and_info(info, INODE_MAP_CACHE,
> +				       "enabling inode map caching");
> +		}
> +	}
> +
> +	if (ctx->max_inline) {
> +		ctx->max_inline = min_t(u64, ctx->max_inline, info->sectorsize);
> +		if (ctx->max_inline != info->max_inline)
> +			btrfs_info(info, "max_inline at %llu", ctx->max_inline);
> +		info->max_inline = ctx->max_inline;
> +	}
> +
> +       if (btrfs_test_exp_opt(ctx, NOLOGREPLAY))
> +               btrfs_info(info, "disabling log replay at mount time");
> +
> +	info->metadata_ratio = ctx->metadata_ratio;
> +	if (ctx->metadata_ratio)
> +		btrfs_info(info, "Metadata ratio %u", ctx->metadata_ratio);

first letter is lowercase (as it appears after the prefix message)

> +
> +	if (btrfs_test_opt(ctx, USEBACKUPROOT))
> +		btrfs_info(info, "trying to use backup root at mount time");
> +
> +	/* set a default space_cache value if none was specified */
> +	if (!ctx->nospace_cache && !btrfs_test_opt(ctx, SPACE_CACHE) &&
> +			!btrfs_test_opt(ctx, FREE_SPACE_TREE)) {
> +		if (btrfs_fs_compat_ro(info, FREE_SPACE_TREE))
> +			btrfs_set_opt(ctx->mount_opt, FREE_SPACE_TREE);
> +		else
> +			btrfs_set_opt(ctx->mount_opt, SPACE_CACHE);
> +	}
> +
> +	if (ctx->nospace_cache) {
> +		if (btrfs_test_opt(ctx, SPACE_CACHE))
> +			btrfs_info(info, "disabling disk space caching");
> +		if (btrfs_test_opt(ctx, FREE_SPACE_TREE))
> +			btrfs_info(info, "disabling free space tree");
> +	} else if (btrfs_test_opt(ctx, SPACE_CACHE))  {
> +		btrfs_info(info, "enabling disk space caching");
> +	} else if (btrfs_test_opt(ctx, FREE_SPACE_TREE)) {
> +		btrfs_info(info, "enabling free space tree");
> +	}
> +
> +	/*
> +	 * When the free space tree is enabled:
> +	 * -o nospace_cache, -o space_cache=v1: error
> +	 * no options, -o space_cache=v2: keep using the free space tree
> +	 * -o clear_cache, -o clear_cache,space_cache=v2: clear and recreate the free space tree
> +	 * -o clear_cache,nospace_cache: clear the free space tree
> +	 * -o clear_cache,space_cache=v1: clear the free space tree, enable the free space cache
> +	 */
> +	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");
> +			return -EINVAL;
> +		}
> +	}
> +
> +	if (btrfs_test_exp_opt(ctx, SSD_SPREAD)) {
> +		if (!btrfs_opt_map[Opt_ssd_spread].enabled) {
> +			btrfs_info(info, "not using spread ssd allocation scheme");
> +		} else {
> +			btrfs_info(info, "enabling ssd optimizations");
> +			btrfs_info(info, "using spread ssd allocation scheme");
> +		}
> +	}
> +
> +	if (btrfs_test_exp_opt(ctx, SSD)) {

I think SSD and SSD_SPRREAD need to be handled in one go, other wise
this would lead to duplicated messages.

> +		if (!btrfs_opt_map[Opt_ssd].enabled) {
> +			btrfs_info(info, "not using ssd optimizations");
> +			btrfs_info(info, "not using spread ssd allocation scheme");
> +		} else {
> +			btrfs_info(info, "enabling ssd optimizations");
> +		}
> +	}
> +
> +	if (ctx->thread_pool_size)
> +		info->thread_pool_size = ctx->thread_pool_size;
> +
> +	if (btrfs_test_exp_opt(ctx, NOTREELOG))
> +		btrfs_info(info, "%s tree log",
> +				btrfs_opt_map[Opt_notreelog].enabled ? "enabling"
> +				: "disabling");
> +
> +#ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY
> +       if (btrfs_test_exp_opt(ctx, CHECK_INTEGRITY_INCLUDING_EXTENT_DATA))
> +               btrfs_info(info, "disabling log replay at mount time");
> +       else if (btrfs_test_exp_opt(ctx, CHECK_INTEGRITY))
> +               btrfs_info(info, "enabling check integrity");
> +       if (ctx->check_integrity_print_mask != info->check_integrity_print_mask) {
> +               info->check_integrity_print_mask = ctx->check_integrity_print_mask;
> +               btrfs_info(info, "check_integrity_print_mask 0x%x",
> +                  info->check_integrity_print_mask);
> +       }
> +#endif
> +
> +	info->compress_type = ctx->compress_type;
> +	info->compress_level = ctx->compress_level;
> +	info->pending_changes = ctx->pending_changes;

The pending changes handles mount options that must be enabled/disabled
at commit time so it affects a complete transaction. For ordinary mount
this is not relevant but for remount it is. So, is
btrfs_apply_configuration also called for remount?

> +	info->mount_opt = ctx->mount_opt;
> +
> +	return 0;
> +}
> +
>  int btrfs_sync_fs(struct super_block *sb, int wait)
>  {
>  	struct btrfs_trans_handle *trans;
> @@ -2349,6 +2957,7 @@ static void btrfs_fc_free(struct fs_context *fc)
>  
>  static const struct fs_context_operations btrfs_context_ops = {
>  	.free = btrfs_fc_free,
> +	.parse_param = btrfs_fc_parse_param,
>  };
>  
>  static int btrfs_init_fs_context(struct fs_context *fc)
> -- 
> 2.28.0

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFC PATCH 6/8] btrfs: super: Introduce btrfs_mount_root_fc
  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
  0 siblings, 0 replies; 15+ messages in thread
From: David Sterba @ 2020-08-17 13:14 UTC (permalink / raw)
  To: Marcos Paulo de Souza; +Cc: dsterba, linux-btrfs, Marcos Paulo de Souza

On Wed, Aug 12, 2020 at 01:36:52PM -0300, Marcos Paulo de Souza wrote:
> From: Marcos Paulo de Souza <mpdesouza@suse.com>
> 
> This function will be used by the following patches to mount the root fs
> before mounting a subvolume.
> 
> Signed-off-by: Marcos Paulo de Souza <mpdesouza@suse.com>
> ---
>  fs/btrfs/super.c | 41 +++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 41 insertions(+)
> 
> diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
> index 6b70fb73a1ea..5bbf4b947125 100644
> --- a/fs/btrfs/super.c
> +++ b/fs/btrfs/super.c
> @@ -2419,6 +2419,47 @@ static struct dentry *btrfs_mount_root(struct file_system_type *fs_type,
>  	return ERR_PTR(error);
>  }
>  
> +/*
> + * Duplicate the current fc and prepare for mounting the root.
> + * btrfs_get_tree will be called recursively, but then will check for the
> + * ctx->root being set and call btrfs_root_get_tree.

This sounds like the adding back recursive mount with -o subvol= that
was removed.

> + */
> +static int btrfs_mount_root_fc(struct fs_context *fc, unsigned int rdonly)
> +{
> +	struct btrfs_fs_context *ctx, *root_ctx;
> +	struct fs_context *root_fc;
> +	struct vfsmount *root_mnt;
> +	int ret;
> +
> +	root_fc = vfs_dup_fs_context(fc);
> +	if (IS_ERR(root_fc))
> +		return PTR_ERR(root_fc);
> +
> +	root_fc->sb_flags &= ~SB_RDONLY;
> +	root_fc->sb_flags |= rdonly | SB_NOSEC;
> +	root_ctx = root_fc->fs_private;
> +	root_ctx->root_mnt = NULL;
> +	root_ctx->root = true;
> +
> +	/*
> +	 * fc_mount will call btrfs_get_tree again, and by checking ctx->root
> +	 * being true it'll call btrfs_root_get_tree to avoid infinite recursion.
> +	 */

Can this race somehow? If there are several parallel mounts called eg.
for a set of system subvolumes.

> +	root_mnt = fc_mount(root_fc);
> +	if (IS_ERR(root_mnt)) {
> +		ret = PTR_ERR(root_mnt);
> +		goto error_fc;
> +	}
> +
> +	ctx = fc->fs_private;
> +	ctx->root_mnt = root_mnt;
> +	ret = 0;
> +
> +error_fc:
> +	put_fs_context(root_fc);
> +	return ret;
> +}
> +
>  /*
>   * Mount function which is called by VFS layer.
>   *
> -- 
> 2.28.0

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFC PATCH 7/8] btrfs: Convert to fs_context
  2020-08-12 16:36 ` [RFC PATCH 7/8] btrfs: Convert to fs_context Marcos Paulo de Souza
  2020-08-13 10:22   ` kernel test robot
@ 2020-08-17 13:26   ` David Sterba
  1 sibling, 0 replies; 15+ messages in thread
From: David Sterba @ 2020-08-17 13:26 UTC (permalink / raw)
  To: Marcos Paulo de Souza; +Cc: dsterba, linux-btrfs, Marcos Paulo de Souza

On Wed, Aug 12, 2020 at 01:36:53PM -0300, Marcos Paulo de Souza wrote:
> 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;

This and the related changes shouldn't be in this patch.

>  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);

So clean the bdev_holder in a separate patch.

>  	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");

Whitespace-only change

>  		}
>  	}
>  
> @@ -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)

The new naming is confusing as we use 'get' for reference counting in
connection with 'root' and 'tree'. You can keep btrfs_mount_root as it's
clear it's for mount.

>  {
> -	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. */

Typo '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);*/

Stray comment

> +	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)

Please keep 'mount' somewhere in the function name.

>  {
> -	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)

For some reason I don't like referring to mount-related things by terms
with overloaded meaning. Keeping btrfs_remount would be just fine.

>  {
> +	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,

You should use the final indentation when the callbacks are added and
not at the end.

>  };
>  
>  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

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2020-08-17 13:27 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
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 ` [RFC PATCH 7/8] btrfs: Convert to fs_context Marcos Paulo de Souza
2020-08-13 10:22   ` kernel test robot
2020-08-17 13:26   ` 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

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.