* [PATCH v2 01/18] fs: indicate request originates from old mount api
2023-11-08 19:08 [PATCH v2 00/18] btrfs: convert to the new mount API Josef Bacik
@ 2023-11-08 19:08 ` Josef Bacik
2023-11-08 19:08 ` [PATCH v2 02/18] btrfs: split out the mount option validation code into its own helper Josef Bacik
` (19 subsequent siblings)
20 siblings, 0 replies; 33+ messages in thread
From: Josef Bacik @ 2023-11-08 19:08 UTC (permalink / raw)
To: linux-btrfs, kernel-team, linux-fsdevel, brauner; +Cc: Christoph Hellwig
From: Christian Brauner <brauner@kernel.org>
We already communicate to filesystems when a remount request comes from
the old mount api as some filesystems choose to implement different
behavior in the new mount api than the old mount api to e.g., take the
chance to fix significant api bugs. Allow the same for regular mount
requests.
Fixes: b330966f79fb ("fuse: reject options on reconfigure via fsconfig(2)")
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Christian Brauner <brauner@kernel.org>
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
fs/namespace.c | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/fs/namespace.c b/fs/namespace.c
index e157efc54023..bfc5cff0e196 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -2873,7 +2873,12 @@ static int do_remount(struct path *path, int ms_flags, int sb_flags,
if (IS_ERR(fc))
return PTR_ERR(fc);
+ /*
+ * Indicate to the filesystem that the remount request is coming
+ * from the legacy mount system call.
+ */
fc->oldapi = true;
+
err = parse_monolithic_mount_data(fc, data);
if (!err) {
down_write(&sb->s_umount);
@@ -3322,6 +3327,12 @@ static int do_new_mount(struct path *path, const char *fstype, int sb_flags,
if (IS_ERR(fc))
return PTR_ERR(fc);
+ /*
+ * Indicate to the filesystem that the mount request is coming
+ * from the legacy mount system call.
+ */
+ fc->oldapi = true;
+
if (subtype)
err = vfs_parse_fs_string(fc, "subtype",
subtype, strlen(subtype));
--
2.41.0
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCH v2 02/18] btrfs: split out the mount option validation code into its own helper
2023-11-08 19:08 [PATCH v2 00/18] btrfs: convert to the new mount API Josef Bacik
2023-11-08 19:08 ` [PATCH v2 01/18] fs: indicate request originates from old mount api Josef Bacik
@ 2023-11-08 19:08 ` Josef Bacik
2023-11-14 6:32 ` Anand Jain
2023-11-08 19:08 ` [PATCH v2 03/18] btrfs: set default compress type at btrfs_init_fs_info time Josef Bacik
` (18 subsequent siblings)
20 siblings, 1 reply; 33+ messages in thread
From: Josef Bacik @ 2023-11-08 19:08 UTC (permalink / raw)
To: linux-btrfs, kernel-team, linux-fsdevel, brauner
We're going to need to validate mount options after they're all parsed
with the new mount api, split this code out into its own helper so we
can use it when we swap over to the new mount api.
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
fs/btrfs/super.c | 64 ++++++++++++++++++++++++++----------------------
1 file changed, 35 insertions(+), 29 deletions(-)
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index 6ecf78d09694..639601d346d0 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -233,6 +233,39 @@ static bool check_ro_option(struct btrfs_fs_info *fs_info, unsigned long opt,
return false;
}
+static bool check_options(struct btrfs_fs_info *info, unsigned long flags)
+{
+ if (!(flags & SB_RDONLY) &&
+ (check_ro_option(info, BTRFS_MOUNT_NOLOGREPLAY, "nologreplay") ||
+ check_ro_option(info, BTRFS_MOUNT_IGNOREBADROOTS, "ignorebadroots") ||
+ check_ro_option(info, BTRFS_MOUNT_IGNOREDATACSUMS, "ignoredatacsums")))
+ return false;
+
+ 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");
+ return false;
+ }
+ if (btrfs_fs_compat_ro(info, BLOCK_GROUP_TREE) &&
+ !btrfs_test_opt(info, FREE_SPACE_TREE)) {
+ btrfs_err(info, "cannot disable free space tree with block-group-tree feature");
+ return false;
+ }
+
+ if (btrfs_check_mountopts_zoned(info))
+ return false;
+
+ if (!test_bit(BTRFS_FS_STATE_REMOUNTING, &info->fs_state)) {
+ if (btrfs_test_opt(info, SPACE_CACHE))
+ btrfs_info(info, "disk space caching is enabled");
+ if (btrfs_test_opt(info, FREE_SPACE_TREE))
+ btrfs_info(info, "using free space tree");
+ }
+
+ return true;
+}
+
static int parse_rescue_options(struct btrfs_fs_info *info, const char *options)
{
char *opts;
@@ -311,7 +344,6 @@ int btrfs_parse_options(struct btrfs_fs_info *info, char *options,
int saved_compress_level;
bool saved_compress_force;
int no_compress = 0;
- const bool remounting = test_bit(BTRFS_FS_STATE_REMOUNTING, &info->fs_state);
if (btrfs_fs_compat_ro(info, FREE_SPACE_TREE))
btrfs_set_opt(info->mount_opt, FREE_SPACE_TREE);
@@ -330,7 +362,7 @@ int btrfs_parse_options(struct btrfs_fs_info *info, char *options,
* against new flags
*/
if (!options)
- goto check;
+ goto out;
while ((p = strsep(&options, ",")) != NULL) {
int token;
@@ -774,35 +806,9 @@ int btrfs_parse_options(struct btrfs_fs_info *info, char *options,
break;
}
}
-check:
- /* We're read-only, don't have to check. */
- if (new_flags & SB_RDONLY)
- goto out;
-
- if (check_ro_option(info, BTRFS_MOUNT_NOLOGREPLAY, "nologreplay") ||
- check_ro_option(info, BTRFS_MOUNT_IGNOREBADROOTS, "ignorebadroots") ||
- check_ro_option(info, BTRFS_MOUNT_IGNOREDATACSUMS, "ignoredatacsums"))
- 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");
+ if (!ret && !check_options(info, new_flags))
ret = -EINVAL;
- }
- if (btrfs_fs_compat_ro(info, BLOCK_GROUP_TREE) &&
- !btrfs_test_opt(info, FREE_SPACE_TREE)) {
- btrfs_err(info, "cannot disable free space tree with block-group-tree feature");
- ret = -EINVAL;
- }
- if (!ret)
- ret = btrfs_check_mountopts_zoned(info);
- if (!ret && !remounting) {
- if (btrfs_test_opt(info, SPACE_CACHE))
- btrfs_info(info, "disk space caching is enabled");
- if (btrfs_test_opt(info, FREE_SPACE_TREE))
- btrfs_info(info, "using free space tree");
- }
return ret;
}
--
2.41.0
^ permalink raw reply related [flat|nested] 33+ messages in thread
* Re: [PATCH v2 02/18] btrfs: split out the mount option validation code into its own helper
2023-11-08 19:08 ` [PATCH v2 02/18] btrfs: split out the mount option validation code into its own helper Josef Bacik
@ 2023-11-14 6:32 ` Anand Jain
2023-11-14 17:35 ` David Sterba
0 siblings, 1 reply; 33+ messages in thread
From: Anand Jain @ 2023-11-14 6:32 UTC (permalink / raw)
To: Josef Bacik, linux-btrfs, kernel-team, linux-fsdevel, brauner
> +static bool check_options(struct btrfs_fs_info *info, unsigned long flags)
> +{
> + if (!(flags & SB_RDONLY) &&
> + (check_ro_option(info, BTRFS_MOUNT_NOLOGREPLAY, "nologreplay") ||
> + check_ro_option(info, BTRFS_MOUNT_IGNOREBADROOTS, "ignorebadroots") ||
> + check_ro_option(info, BTRFS_MOUNT_IGNOREDATACSUMS, "ignoredatacsums")))
> + return false;
> +
> + 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");
> + return false;
> + }
> + if (btrfs_fs_compat_ro(info, BLOCK_GROUP_TREE) &&
> + !btrfs_test_opt(info, FREE_SPACE_TREE)) {
> + btrfs_err(info, "cannot disable free space tree with block-group-tree feature");
> + return false;
> + }
> +
> + if (btrfs_check_mountopts_zoned(info))
> + return false;
> +
<snip>
> -check:
> - /* We're read-only, don't have to check. */
> - if (new_flags & SB_RDONLY)
> - goto out;
> -
> - if (check_ro_option(info, BTRFS_MOUNT_NOLOGREPLAY, "nologreplay") ||
> - check_ro_option(info, BTRFS_MOUNT_IGNOREBADROOTS, "ignorebadroots") ||
> - check_ro_option(info, BTRFS_MOUNT_IGNOREDATACSUMS, "ignoredatacsums"))
> - 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");
> + if (!ret && !check_options(info, new_flags))
> ret = -EINVAL;
> - }
> - if (btrfs_fs_compat_ro(info, BLOCK_GROUP_TREE) &&
> - !btrfs_test_opt(info, FREE_SPACE_TREE)) {
> - btrfs_err(info, "cannot disable free space tree with block-group-tree feature");
> - ret = -EINVAL;
> - }
> - if (!ret)
> - ret = btrfs_check_mountopts_zoned(info);
> - if (!ret && !remounting) {
> - if (btrfs_test_opt(info, SPACE_CACHE))
> - btrfs_info(info, "disk space caching is enabled");
> - if (btrfs_test_opt(info, FREE_SPACE_TREE))
> - btrfs_info(info, "using free space tree");
> - }
> return ret;
> }
Before this patch, we verified all the above checks simultaneously.
Now, for each error, we return without checking the rest.
As a result, if there are multiple failures in the above checks,
we report them sequentially. This is not a bug, but the optimization
we had earlier has been traded off for cleaner code.
IMO it is good to keep the optimization.
Thanks, Anand
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH v2 02/18] btrfs: split out the mount option validation code into its own helper
2023-11-14 6:32 ` Anand Jain
@ 2023-11-14 17:35 ` David Sterba
0 siblings, 0 replies; 33+ messages in thread
From: David Sterba @ 2023-11-14 17:35 UTC (permalink / raw)
To: Anand Jain; +Cc: Josef Bacik, linux-btrfs, kernel-team, linux-fsdevel, brauner
On Tue, Nov 14, 2023 at 02:32:16PM +0800, Anand Jain wrote:
>
> > +static bool check_options(struct btrfs_fs_info *info, unsigned long flags)
> > +{
> > + if (!(flags & SB_RDONLY) &&
> > + (check_ro_option(info, BTRFS_MOUNT_NOLOGREPLAY, "nologreplay") ||
> > + check_ro_option(info, BTRFS_MOUNT_IGNOREBADROOTS, "ignorebadroots") ||
> > + check_ro_option(info, BTRFS_MOUNT_IGNOREDATACSUMS, "ignoredatacsums")))
> > + return false;
> > +
> > + 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");
> > + return false;
> > + }
> > + if (btrfs_fs_compat_ro(info, BLOCK_GROUP_TREE) &&
> > + !btrfs_test_opt(info, FREE_SPACE_TREE)) {
> > + btrfs_err(info, "cannot disable free space tree with block-group-tree feature");
> > + return false;
> > + }
> > +
> > + if (btrfs_check_mountopts_zoned(info))
> > + return false;
> > +
>
>
> <snip>
>
> > -check:
> > - /* We're read-only, don't have to check. */
> > - if (new_flags & SB_RDONLY)
> > - goto out;
> > -
> > - if (check_ro_option(info, BTRFS_MOUNT_NOLOGREPLAY, "nologreplay") ||
> > - check_ro_option(info, BTRFS_MOUNT_IGNOREBADROOTS, "ignorebadroots") ||
> > - check_ro_option(info, BTRFS_MOUNT_IGNOREDATACSUMS, "ignoredatacsums"))
> > - 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");
> > + if (!ret && !check_options(info, new_flags))
> > ret = -EINVAL;
> > - }
> > - if (btrfs_fs_compat_ro(info, BLOCK_GROUP_TREE) &&
> > - !btrfs_test_opt(info, FREE_SPACE_TREE)) {
> > - btrfs_err(info, "cannot disable free space tree with block-group-tree feature");
> > - ret = -EINVAL;
> > - }
> > - if (!ret)
> > - ret = btrfs_check_mountopts_zoned(info);
> > - if (!ret && !remounting) {
> > - if (btrfs_test_opt(info, SPACE_CACHE))
> > - btrfs_info(info, "disk space caching is enabled");
> > - if (btrfs_test_opt(info, FREE_SPACE_TREE))
> > - btrfs_info(info, "using free space tree");
> > - }
> > return ret;
> > }
>
>
> Before this patch, we verified all the above checks simultaneously.
> Now, for each error, we return without checking the rest.
> As a result, if there are multiple failures in the above checks,
> we report them sequentially. This is not a bug, but the optimization
> we had earlier has been traded off for cleaner code.
> IMO it is good to keep the optimization.
I would not say it's cleaner code, it's doing something else than
before. I think we should keep the behaviour 1:1 unless there's a reason
for that, the changelog does not say.
^ permalink raw reply [flat|nested] 33+ messages in thread
* [PATCH v2 03/18] btrfs: set default compress type at btrfs_init_fs_info time
2023-11-08 19:08 [PATCH v2 00/18] btrfs: convert to the new mount API Josef Bacik
2023-11-08 19:08 ` [PATCH v2 01/18] fs: indicate request originates from old mount api Josef Bacik
2023-11-08 19:08 ` [PATCH v2 02/18] btrfs: split out the mount option validation code into its own helper Josef Bacik
@ 2023-11-08 19:08 ` Josef Bacik
2023-11-08 19:08 ` [PATCH v2 04/18] btrfs: move space cache settings into open_ctree Josef Bacik
` (17 subsequent siblings)
20 siblings, 0 replies; 33+ messages in thread
From: Josef Bacik @ 2023-11-08 19:08 UTC (permalink / raw)
To: linux-btrfs, kernel-team, linux-fsdevel, brauner
With the new mount API we'll be setting our compression well before we
call open_ctree. We don't want to overwrite our settings, so set the
default in btrfs_init_fs_info instead of open_ctree.
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
fs/btrfs/disk-io.c | 10 +++-------
1 file changed, 3 insertions(+), 7 deletions(-)
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 350e1b02cc8e..27bbe0164425 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -2790,6 +2790,9 @@ void btrfs_init_fs_info(struct btrfs_fs_info *fs_info)
fs_info->sectorsize_bits = ilog2(4096);
fs_info->stripesize = 4096;
+ /* Default compress algorithm when user does -o compress */
+ fs_info->compress_type = BTRFS_COMPRESS_ZLIB;
+
fs_info->max_extent_size = BTRFS_MAX_EXTENT_SIZE;
spin_lock_init(&fs_info->swapfile_pins_lock);
@@ -3271,13 +3274,6 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device
if (btrfs_super_flags(disk_super) & BTRFS_SUPER_FLAG_ERROR)
WRITE_ONCE(fs_info->fs_error, -EUCLEAN);
- /*
- * In the long term, we'll store the compression type in the super
- * block, and it'll be used for per file compression control.
- */
- fs_info->compress_type = BTRFS_COMPRESS_ZLIB;
-
-
/* Set up fs_info before parsing mount options */
nodesize = btrfs_super_nodesize(disk_super);
sectorsize = btrfs_super_sectorsize(disk_super);
--
2.41.0
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCH v2 04/18] btrfs: move space cache settings into open_ctree
2023-11-08 19:08 [PATCH v2 00/18] btrfs: convert to the new mount API Josef Bacik
` (2 preceding siblings ...)
2023-11-08 19:08 ` [PATCH v2 03/18] btrfs: set default compress type at btrfs_init_fs_info time Josef Bacik
@ 2023-11-08 19:08 ` Josef Bacik
2023-11-15 0:06 ` Anand Jain
2023-11-08 19:08 ` [PATCH v2 05/18] btrfs: do not allow free space tree rebuild on extent tree v2 Josef Bacik
` (16 subsequent siblings)
20 siblings, 1 reply; 33+ messages in thread
From: Josef Bacik @ 2023-11-08 19:08 UTC (permalink / raw)
To: linux-btrfs, kernel-team, linux-fsdevel, brauner
Currently we pre-load the space cache settings in btrfs_parse_options,
however when we switch to the new mount API the mount option parsing
will happen before we have the super block loaded. Add a helper to set
the appropriate options based on the fs settings, this will allow us to
have consistent free space cache settings.
This also folds in the space cache related decisions we make for subpage
sectorsize support, so all of this is done in one place.
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
fs/btrfs/disk-io.c | 17 ++++++-----------
fs/btrfs/super.c | 44 +++++++++++++++++++++++++++++++-------------
fs/btrfs/super.h | 1 +
3 files changed, 38 insertions(+), 24 deletions(-)
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 27bbe0164425..b486cbec492b 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -3287,6 +3287,12 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device
fs_info->csums_per_leaf = BTRFS_MAX_ITEM_SIZE(fs_info) / fs_info->csum_size;
fs_info->stripesize = stripesize;
+ /*
+ * Handle the space caching options appropriately now that we have the
+ * super loaded and validated.
+ */
+ btrfs_set_free_space_cache_settings(fs_info);
+
ret = btrfs_parse_options(fs_info, options, sb->s_flags);
if (ret)
goto fail_alloc;
@@ -3298,17 +3304,6 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device
if (sectorsize < PAGE_SIZE) {
struct btrfs_subpage_info *subpage_info;
- /*
- * V1 space cache has some hardcoded PAGE_SIZE usage, and is
- * going to be deprecated.
- *
- * Force to use v2 cache for subpage case.
- */
- btrfs_clear_opt(fs_info->mount_opt, SPACE_CACHE);
- btrfs_set_and_info(fs_info, FREE_SPACE_TREE,
- "forcing free space tree for sector size %u with page size %lu",
- sectorsize, PAGE_SIZE);
-
btrfs_warn(fs_info,
"read-write for sector size %u with page size %lu is experimental",
sectorsize, PAGE_SIZE);
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index 639601d346d0..aef7e67538a3 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -266,6 +266,31 @@ static bool check_options(struct btrfs_fs_info *info, unsigned long flags)
return true;
}
+void btrfs_set_free_space_cache_settings(struct btrfs_fs_info *fs_info)
+{
+ if (btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE))
+ btrfs_set_opt(fs_info->mount_opt, FREE_SPACE_TREE);
+ else if (btrfs_free_space_cache_v1_active(fs_info)) {
+ if (btrfs_is_zoned(fs_info)) {
+ btrfs_info(fs_info,
+ "zoned: clearing existing space cache");
+ btrfs_set_super_cache_generation(fs_info->super_copy, 0);
+ } else {
+ btrfs_set_opt(fs_info->mount_opt, SPACE_CACHE);
+ }
+ }
+
+ if (fs_info->sectorsize < PAGE_SIZE) {
+ btrfs_clear_opt(fs_info->mount_opt, SPACE_CACHE);
+ if (!btrfs_test_opt(fs_info, FREE_SPACE_TREE)) {
+ btrfs_info(fs_info,
+ "forcing free space tree for sector size %u with page size %lu",
+ fs_info->sectorsize, PAGE_SIZE);
+ btrfs_set_opt(fs_info->mount_opt, FREE_SPACE_TREE);
+ }
+ }
+}
+
static int parse_rescue_options(struct btrfs_fs_info *info, const char *options)
{
char *opts;
@@ -345,18 +370,6 @@ int btrfs_parse_options(struct btrfs_fs_info *info, char *options,
bool saved_compress_force;
int no_compress = 0;
- if (btrfs_fs_compat_ro(info, FREE_SPACE_TREE))
- btrfs_set_opt(info->mount_opt, FREE_SPACE_TREE);
- else if (btrfs_free_space_cache_v1_active(info)) {
- if (btrfs_is_zoned(info)) {
- btrfs_info(info,
- "zoned: clearing existing space cache");
- btrfs_set_super_cache_generation(info->super_copy, 0);
- } else {
- btrfs_set_opt(info->mount_opt, SPACE_CACHE);
- }
- }
-
/*
* Even the options are empty, we still need to do extra check
* against new flags
@@ -649,8 +662,13 @@ int btrfs_parse_options(struct btrfs_fs_info *info, char *options,
* compat_ro(FREE_SPACE_TREE) set, and we aren't going
* to allow v1 to be set for extent tree v2, simply
* ignore this setting if we're extent tree v2.
+ *
+ * For subpage blocksize we don't allow space cache v1,
+ * and we'll turn on v2, so we can skip the settings
+ * here as well.
*/
- if (btrfs_fs_incompat(info, EXTENT_TREE_V2))
+ if (btrfs_fs_incompat(info, EXTENT_TREE_V2) ||
+ info->sectorsize < PAGE_SIZE)
break;
if (token == Opt_space_cache ||
strcmp(args[0].from, "v1") == 0) {
diff --git a/fs/btrfs/super.h b/fs/btrfs/super.h
index 8dbb909b364f..7c1cd7527e76 100644
--- a/fs/btrfs/super.h
+++ b/fs/btrfs/super.h
@@ -8,6 +8,7 @@ int btrfs_parse_options(struct btrfs_fs_info *info, char *options,
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);
+void btrfs_set_free_space_cache_settings(struct btrfs_fs_info *fs_info);
static inline struct btrfs_fs_info *btrfs_sb(struct super_block *sb)
{
--
2.41.0
^ permalink raw reply related [flat|nested] 33+ messages in thread
* Re: [PATCH v2 04/18] btrfs: move space cache settings into open_ctree
2023-11-08 19:08 ` [PATCH v2 04/18] btrfs: move space cache settings into open_ctree Josef Bacik
@ 2023-11-15 0:06 ` Anand Jain
2023-11-20 21:54 ` Josef Bacik
0 siblings, 1 reply; 33+ messages in thread
From: Anand Jain @ 2023-11-15 0:06 UTC (permalink / raw)
To: Josef Bacik, linux-btrfs, kernel-team, linux-fsdevel, brauner
> @@ -3287,6 +3287,12 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device
> fs_info->csums_per_leaf = BTRFS_MAX_ITEM_SIZE(fs_info) / fs_info->csum_size;
> fs_info->stripesize = stripesize;
>
> + /*
> + * Handle the space caching options appropriately now that we have the
> + * super loaded and validated.
> + */
> + btrfs_set_free_space_cache_settings(fs_info);
> +
> ret = btrfs_parse_options(fs_info, options, sb->s_flags);
> if (ret)
> goto fail_alloc;
> @@ -3298,17 +3304,6 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device
> if (sectorsize < PAGE_SIZE) {
> struct btrfs_subpage_info *subpage_info;
>
> - /*
> - * V1 space cache has some hardcoded PAGE_SIZE usage, and is
> - * going to be deprecated.
> - *
> - * Force to use v2 cache for subpage case.
> - */
> - btrfs_clear_opt(fs_info->mount_opt, SPACE_CACHE);
> - btrfs_set_and_info(fs_info, FREE_SPACE_TREE,
> - "forcing free space tree for sector size %u with page size %lu",
> - sectorsize, PAGE_SIZE);
> -
> btrfs_warn(fs_info,
> "read-write for sector size %u with page size %lu is experimental",
> sectorsize, PAGE_SIZE);
> diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
> index 639601d346d0..aef7e67538a3 100644
> --- a/fs/btrfs/super.c
> +++ b/fs/btrfs/super.c
> @@ -266,6 +266,31 @@ static bool check_options(struct btrfs_fs_info *info, unsigned long flags)
> return true;
> }
>
> +void btrfs_set_free_space_cache_settings(struct btrfs_fs_info *fs_info)
> +{
> + if (btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE))
> + btrfs_set_opt(fs_info->mount_opt, FREE_SPACE_TREE);
> + else if (btrfs_free_space_cache_v1_active(fs_info)) {
> + if (btrfs_is_zoned(fs_info)) {
> + btrfs_info(fs_info,
> + "zoned: clearing existing space cache");
> + btrfs_set_super_cache_generation(fs_info->super_copy, 0);
> + } else {
> + btrfs_set_opt(fs_info->mount_opt, SPACE_CACHE);
> + }
> + }
> +
> + if (fs_info->sectorsize < PAGE_SIZE) {
> + btrfs_clear_opt(fs_info->mount_opt, SPACE_CACHE);
> + if (!btrfs_test_opt(fs_info, FREE_SPACE_TREE)) {
> + btrfs_info(fs_info,
> + "forcing free space tree for sector size %u with page size %lu",
> + fs_info->sectorsize, PAGE_SIZE);
> + btrfs_set_opt(fs_info->mount_opt, FREE_SPACE_TREE);
> + }
> + }
> +}
> +
> static int parse_rescue_options(struct btrfs_fs_info *info, const char *options)
> {
> char *opts;
> @@ -345,18 +370,6 @@ int btrfs_parse_options(struct btrfs_fs_info *info, char *options,
> bool saved_compress_force;
> int no_compress = 0;
>
> - if (btrfs_fs_compat_ro(info, FREE_SPACE_TREE))
> - btrfs_set_opt(info->mount_opt, FREE_SPACE_TREE);
> - else if (btrfs_free_space_cache_v1_active(info)) {
> - if (btrfs_is_zoned(info)) {
> - btrfs_info(info,
> - "zoned: clearing existing space cache");
> - btrfs_set_super_cache_generation(info->super_copy, 0);
> - } else {
> - btrfs_set_opt(info->mount_opt, SPACE_CACHE);
> - }
> - }
> -
> /*
> * Even the options are empty, we still need to do extra check
> * against new flags
btrfs_remount() calls btrfs_parse_options(), which previously handled
space cache/tree flags set/reset. However, with the move of this
functionality to a separate function, btrfs_set_free_space_cache_settings(),
the btrfs_remount() thread no longer has the space cache/tree flags
set/reset. The changelog provides no explanation for this change.
Could this be a bug?
Thanks, Anand
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH v2 04/18] btrfs: move space cache settings into open_ctree
2023-11-15 0:06 ` Anand Jain
@ 2023-11-20 21:54 ` Josef Bacik
0 siblings, 0 replies; 33+ messages in thread
From: Josef Bacik @ 2023-11-20 21:54 UTC (permalink / raw)
To: Anand Jain; +Cc: linux-btrfs, kernel-team, linux-fsdevel, brauner
On Wed, Nov 15, 2023 at 08:06:02AM +0800, Anand Jain wrote:
>
> > @@ -3287,6 +3287,12 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device
> > fs_info->csums_per_leaf = BTRFS_MAX_ITEM_SIZE(fs_info) / fs_info->csum_size;
> > fs_info->stripesize = stripesize;
> > + /*
> > + * Handle the space caching options appropriately now that we have the
> > + * super loaded and validated.
> > + */
> > + btrfs_set_free_space_cache_settings(fs_info);
> > +
> > ret = btrfs_parse_options(fs_info, options, sb->s_flags);
> > if (ret)
> > goto fail_alloc;
> > @@ -3298,17 +3304,6 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device
> > if (sectorsize < PAGE_SIZE) {
> > struct btrfs_subpage_info *subpage_info;
> > - /*
> > - * V1 space cache has some hardcoded PAGE_SIZE usage, and is
> > - * going to be deprecated.
> > - *
> > - * Force to use v2 cache for subpage case.
> > - */
> > - btrfs_clear_opt(fs_info->mount_opt, SPACE_CACHE);
> > - btrfs_set_and_info(fs_info, FREE_SPACE_TREE,
> > - "forcing free space tree for sector size %u with page size %lu",
> > - sectorsize, PAGE_SIZE);
> > -
> > btrfs_warn(fs_info,
> > "read-write for sector size %u with page size %lu is experimental",
> > sectorsize, PAGE_SIZE);
> > diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
> > index 639601d346d0..aef7e67538a3 100644
> > --- a/fs/btrfs/super.c
> > +++ b/fs/btrfs/super.c
> > @@ -266,6 +266,31 @@ static bool check_options(struct btrfs_fs_info *info, unsigned long flags)
> > return true;
> > }
> > +void btrfs_set_free_space_cache_settings(struct btrfs_fs_info *fs_info)
> > +{
> > + if (btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE))
> > + btrfs_set_opt(fs_info->mount_opt, FREE_SPACE_TREE);
> > + else if (btrfs_free_space_cache_v1_active(fs_info)) {
> > + if (btrfs_is_zoned(fs_info)) {
> > + btrfs_info(fs_info,
> > + "zoned: clearing existing space cache");
> > + btrfs_set_super_cache_generation(fs_info->super_copy, 0);
> > + } else {
> > + btrfs_set_opt(fs_info->mount_opt, SPACE_CACHE);
> > + }
> > + }
> > +
> > + if (fs_info->sectorsize < PAGE_SIZE) {
> > + btrfs_clear_opt(fs_info->mount_opt, SPACE_CACHE);
> > + if (!btrfs_test_opt(fs_info, FREE_SPACE_TREE)) {
> > + btrfs_info(fs_info,
> > + "forcing free space tree for sector size %u with page size %lu",
> > + fs_info->sectorsize, PAGE_SIZE);
> > + btrfs_set_opt(fs_info->mount_opt, FREE_SPACE_TREE);
> > + }
> > + }
> > +}
> > +
> > static int parse_rescue_options(struct btrfs_fs_info *info, const char *options)
> > {
> > char *opts;
> > @@ -345,18 +370,6 @@ int btrfs_parse_options(struct btrfs_fs_info *info, char *options,
> > bool saved_compress_force;
> > int no_compress = 0;
> > - if (btrfs_fs_compat_ro(info, FREE_SPACE_TREE))
> > - btrfs_set_opt(info->mount_opt, FREE_SPACE_TREE);
> > - else if (btrfs_free_space_cache_v1_active(info)) {
> > - if (btrfs_is_zoned(info)) {
> > - btrfs_info(info,
> > - "zoned: clearing existing space cache");
> > - btrfs_set_super_cache_generation(info->super_copy, 0);
> > - } else {
> > - btrfs_set_opt(info->mount_opt, SPACE_CACHE);
> > - }
> > - }
> > -
> > /*
> > * Even the options are empty, we still need to do extra check
> > * against new flags
>
>
> btrfs_remount() calls btrfs_parse_options(), which previously handled
> space cache/tree flags set/reset. However, with the move of this
> functionality to a separate function, btrfs_set_free_space_cache_settings(),
> the btrfs_remount() thread no longer has the space cache/tree flags
> set/reset. The changelog provides no explanation for this change.
> Could this be a bug?
>
All this bit does is set the mount_opt's based on the current state of the file
system, so if we're mounting with no "-o space_cache=*" option, we'll derive it
from wether FREE_SPACE_TREE is set or btrfs_free_space_cache_v1_active() returns
true.
So in your case if we mounted -o nospace_cache then we'll have cleared the
v1_active bit and this won't do anything and we'll get -o nospace_cache again.
The same goes for the free space tree, we're only allowed to change the disk
option for this in certain cases. And in those cases it'll clear the compat
flag.
But this is definitely subtle, I'll expand the changelog. Thanks,
Josef
^ permalink raw reply [flat|nested] 33+ messages in thread
* [PATCH v2 05/18] btrfs: do not allow free space tree rebuild on extent tree v2
2023-11-08 19:08 [PATCH v2 00/18] btrfs: convert to the new mount API Josef Bacik
` (3 preceding siblings ...)
2023-11-08 19:08 ` [PATCH v2 04/18] btrfs: move space cache settings into open_ctree Josef Bacik
@ 2023-11-08 19:08 ` Josef Bacik
2023-11-15 9:49 ` Anand Jain
2023-11-08 19:08 ` [PATCH v2 06/18] btrfs: split out ro->rw and rw->ro helpers into their own functions Josef Bacik
` (15 subsequent siblings)
20 siblings, 1 reply; 33+ messages in thread
From: Josef Bacik @ 2023-11-08 19:08 UTC (permalink / raw)
To: linux-btrfs, kernel-team, linux-fsdevel, brauner
We currently don't allow these options to be set if we're extent tree v2
via the mount option parsing. However when we switch to the new mount
API we'll no longer have the super block loaded, so won't be able to
make this distinction at mount option parsing time. Address this by
checking for extent tree v2 at the point where we make the decision to
rebuild the free space tree.
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
fs/btrfs/disk-io.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index b486cbec492b..072c45811c41 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -2951,7 +2951,8 @@ int btrfs_start_pre_rw_mount(struct btrfs_fs_info *fs_info)
bool rebuild_free_space_tree = false;
if (btrfs_test_opt(fs_info, CLEAR_CACHE) &&
- btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE)) {
+ btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE) &&
+ !btrfs_fs_incompat(fs_info, EXTENT_TREE_V2)) {
rebuild_free_space_tree = true;
} else if (btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE) &&
!btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE_VALID)) {
--
2.41.0
^ permalink raw reply related [flat|nested] 33+ messages in thread
* Re: [PATCH v2 05/18] btrfs: do not allow free space tree rebuild on extent tree v2
2023-11-08 19:08 ` [PATCH v2 05/18] btrfs: do not allow free space tree rebuild on extent tree v2 Josef Bacik
@ 2023-11-15 9:49 ` Anand Jain
2023-11-16 20:09 ` David Sterba
0 siblings, 1 reply; 33+ messages in thread
From: Anand Jain @ 2023-11-15 9:49 UTC (permalink / raw)
To: Josef Bacik, linux-btrfs, kernel-team, linux-fsdevel, brauner
On 11/9/23 03:08, Josef Bacik wrote:
> We currently don't allow these options to be set if we're extent tree v2
> via the mount option parsing. However when we switch to the new mount
> API we'll no longer have the super block loaded, so won't be able to
> make this distinction at mount option parsing time. Address this by
> checking for extent tree v2 at the point where we make the decision to
> rebuild the free space tree.
>
> Signed-off-by: Josef Bacik <josef@toxicpanda.com>
> ---
> fs/btrfs/disk-io.c | 3 ++-
> 1 file changed, 2 insertions(+), 1 deletion(-)
>
> diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
> index b486cbec492b..072c45811c41 100644
> --- a/fs/btrfs/disk-io.c
> +++ b/fs/btrfs/disk-io.c
> @@ -2951,7 +2951,8 @@ int btrfs_start_pre_rw_mount(struct btrfs_fs_info *fs_info)
> bool rebuild_free_space_tree = false;
>
> if (btrfs_test_opt(fs_info, CLEAR_CACHE) &&
> - btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE)) {
> + btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE) &&
> + !btrfs_fs_incompat(fs_info, EXTENT_TREE_V2)) {
> rebuild_free_space_tree = true;
> } else if (btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE) &&
> !btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE_VALID)) {
If there is v3 you can consider to add a comment similar to that
is in btrfs_parse_options().
Also, IMO, it is a good idea to include a btrfs_info() statement
to indicate that the clear_cache option is ignored.
--------------------
case Opt_clear_cache:
/*
* We cannot clear the free space tree with
extent tree
* v2, ignore this option.
*/
if (btrfs_fs_incompat(info, EXTENT_TREE_V2))
break;
btrfs_set_and_info(info, CLEAR_CACHE,
"force clearing of disk cache");
break;
--------------------
Thanks, Anand
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH v2 05/18] btrfs: do not allow free space tree rebuild on extent tree v2
2023-11-15 9:49 ` Anand Jain
@ 2023-11-16 20:09 ` David Sterba
0 siblings, 0 replies; 33+ messages in thread
From: David Sterba @ 2023-11-16 20:09 UTC (permalink / raw)
To: Anand Jain; +Cc: Josef Bacik, linux-btrfs, kernel-team, linux-fsdevel, brauner
On Wed, Nov 15, 2023 at 05:49:48PM +0800, Anand Jain wrote:
> On 11/9/23 03:08, Josef Bacik wrote:
> > We currently don't allow these options to be set if we're extent tree v2
> > via the mount option parsing. However when we switch to the new mount
> > API we'll no longer have the super block loaded, so won't be able to
> > make this distinction at mount option parsing time. Address this by
> > checking for extent tree v2 at the point where we make the decision to
> > rebuild the free space tree.
> >
> > Signed-off-by: Josef Bacik <josef@toxicpanda.com>
> > ---
> > fs/btrfs/disk-io.c | 3 ++-
> > 1 file changed, 2 insertions(+), 1 deletion(-)
> >
> > diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
> > index b486cbec492b..072c45811c41 100644
> > --- a/fs/btrfs/disk-io.c
> > +++ b/fs/btrfs/disk-io.c
> > @@ -2951,7 +2951,8 @@ int btrfs_start_pre_rw_mount(struct btrfs_fs_info *fs_info)
> > bool rebuild_free_space_tree = false;
> >
> > if (btrfs_test_opt(fs_info, CLEAR_CACHE) &&
> > - btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE)) {
> > + btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE) &&
> > + !btrfs_fs_incompat(fs_info, EXTENT_TREE_V2)) {
> > rebuild_free_space_tree = true;
> > } else if (btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE) &&
> > !btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE_VALID)) {
>
> If there is v3 you can consider to add a comment similar to that
> is in btrfs_parse_options().
> Also, IMO, it is a good idea to include a btrfs_info() statement
> to indicate that the clear_cache option is ignored.
Agreed, we have a lot of verbosity around the mount options, if some
option combination is invalid or not working as expected a message
should pe printed.
^ permalink raw reply [flat|nested] 33+ messages in thread
* [PATCH v2 06/18] btrfs: split out ro->rw and rw->ro helpers into their own functions
2023-11-08 19:08 [PATCH v2 00/18] btrfs: convert to the new mount API Josef Bacik
` (4 preceding siblings ...)
2023-11-08 19:08 ` [PATCH v2 05/18] btrfs: do not allow free space tree rebuild on extent tree v2 Josef Bacik
@ 2023-11-08 19:08 ` Josef Bacik
2023-11-08 19:08 ` [PATCH v2 07/18] btrfs: add a NOSPACECACHE mount option flag Josef Bacik
` (14 subsequent siblings)
20 siblings, 0 replies; 33+ messages in thread
From: Josef Bacik @ 2023-11-08 19:08 UTC (permalink / raw)
To: linux-btrfs, kernel-team, linux-fsdevel, brauner
When we remount ro->rw or rw->ro we have some cleanup tasks that have to
be managed. Split these out into their own function to make
btrfs_remount smaller.
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
fs/btrfs/super.c | 233 ++++++++++++++++++++++++-----------------------
1 file changed, 120 insertions(+), 113 deletions(-)
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index aef7e67538a3..d7070269e3ea 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -1659,6 +1659,119 @@ static inline void btrfs_remount_cleanup(struct btrfs_fs_info *fs_info,
btrfs_set_free_space_cache_v1_active(fs_info, cache_opt);
}
+static int btrfs_remount_rw(struct btrfs_fs_info *fs_info)
+{
+ int ret;
+
+ if (BTRFS_FS_ERROR(fs_info)) {
+ btrfs_err(fs_info,
+ "Remounting read-write after error is not allowed");
+ return -EINVAL;
+ }
+
+ if (fs_info->fs_devices->rw_devices == 0)
+ return -EACCES;
+
+ if (!btrfs_check_rw_degradable(fs_info, NULL)) {
+ btrfs_warn(fs_info,
+ "too many missing devices, writable remount is not allowed");
+ return -EACCES;
+ }
+
+ if (btrfs_super_log_root(fs_info->super_copy) != 0) {
+ btrfs_warn(fs_info,
+ "mount required to replay tree-log, cannot remount read-write");
+ return -EINVAL;
+ }
+
+ /*
+ * NOTE: when remounting with a change that does writes, don't put it
+ * anywhere above this point, as we are not sure to be safe to write
+ * until we pass the above checks.
+ */
+ ret = btrfs_start_pre_rw_mount(fs_info);
+ if (ret)
+ return ret;
+
+ btrfs_clear_sb_rdonly(fs_info->sb);
+
+ set_bit(BTRFS_FS_OPEN, &fs_info->flags);
+
+ /*
+ * If we've gone from readonly -> read/write, we need to get our
+ * sync/async discard lists in the right state.
+ */
+ btrfs_discard_resume(fs_info);
+
+ return 0;
+}
+
+static int btrfs_remount_ro(struct btrfs_fs_info *fs_info)
+{
+ /*
+ * this also happens on 'umount -rf' or on shutdown, when
+ * the filesystem is busy.
+ */
+ cancel_work_sync(&fs_info->async_reclaim_work);
+ cancel_work_sync(&fs_info->async_data_reclaim_work);
+
+ btrfs_discard_cleanup(fs_info);
+
+ /* wait for the uuid_scan task to finish */
+ down(&fs_info->uuid_tree_rescan_sem);
+ /* avoid complains from lockdep et al. */
+ up(&fs_info->uuid_tree_rescan_sem);
+
+ btrfs_set_sb_rdonly(fs_info->sb);
+
+ /*
+ * Setting SB_RDONLY will put the cleaner thread to
+ * sleep at the next loop if it's already active.
+ * If it's already asleep, we'll leave unused block
+ * groups on disk until we're mounted read-write again
+ * unless we clean them up here.
+ */
+ btrfs_delete_unused_bgs(fs_info);
+
+ /*
+ * The cleaner task could be already running before we set the
+ * flag BTRFS_FS_STATE_RO (and SB_RDONLY in the superblock).
+ * We must make sure that after we finish the remount, i.e. after
+ * we call btrfs_commit_super(), the cleaner can no longer start
+ * a transaction - either because it was dropping a dead root,
+ * running delayed iputs or deleting an unused block group (the
+ * cleaner picked a block group from the list of unused block
+ * groups before we were able to in the previous call to
+ * btrfs_delete_unused_bgs()).
+ */
+ wait_on_bit(&fs_info->flags, BTRFS_FS_CLEANER_RUNNING,
+ TASK_UNINTERRUPTIBLE);
+
+ /*
+ * We've set the superblock to RO mode, so we might have made
+ * the cleaner task sleep without running all pending delayed
+ * iputs. Go through all the delayed iputs here, so that if an
+ * unmount happens without remounting RW we don't end up at
+ * finishing close_ctree() with a non-empty list of delayed
+ * iputs.
+ */
+ btrfs_run_delayed_iputs(fs_info);
+
+ btrfs_dev_replace_suspend_for_unmount(fs_info);
+ btrfs_scrub_cancel(fs_info);
+ btrfs_pause_balance(fs_info);
+
+ /*
+ * Pause the qgroup rescan worker if it is running. We don't want
+ * it to be still running after we are in RO mode, as after that,
+ * by the time we unmount, it might have left a transaction open,
+ * so we would leak the transaction and/or crash.
+ */
+ btrfs_qgroup_wait_for_completion(fs_info, false);
+
+ return btrfs_commit_super(fs_info);
+}
+
static int btrfs_remount(struct super_block *sb, int *flags, char *data)
{
struct btrfs_fs_info *fs_info = btrfs_sb(sb);
@@ -1712,120 +1825,14 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data)
}
}
- if ((bool)(*flags & SB_RDONLY) == sb_rdonly(sb))
- goto out;
+ ret = 0;
+ if (!sb_rdonly(sb) && (*flags & SB_RDONLY))
+ ret = btrfs_remount_ro(fs_info);
+ else if (sb_rdonly(sb) && !(*flags & SB_RDONLY))
+ ret = btrfs_remount_rw(fs_info);
+ if (ret)
+ goto restore;
- if (*flags & SB_RDONLY) {
- /*
- * this also happens on 'umount -rf' or on shutdown, when
- * the filesystem is busy.
- */
- cancel_work_sync(&fs_info->async_reclaim_work);
- cancel_work_sync(&fs_info->async_data_reclaim_work);
-
- btrfs_discard_cleanup(fs_info);
-
- /* wait for the uuid_scan task to finish */
- down(&fs_info->uuid_tree_rescan_sem);
- /* avoid complains from lockdep et al. */
- up(&fs_info->uuid_tree_rescan_sem);
-
- btrfs_set_sb_rdonly(sb);
-
- /*
- * Setting SB_RDONLY will put the cleaner thread to
- * sleep at the next loop if it's already active.
- * If it's already asleep, we'll leave unused block
- * groups on disk until we're mounted read-write again
- * unless we clean them up here.
- */
- btrfs_delete_unused_bgs(fs_info);
-
- /*
- * The cleaner task could be already running before we set the
- * flag BTRFS_FS_STATE_RO (and SB_RDONLY in the superblock).
- * We must make sure that after we finish the remount, i.e. after
- * we call btrfs_commit_super(), the cleaner can no longer start
- * a transaction - either because it was dropping a dead root,
- * running delayed iputs or deleting an unused block group (the
- * cleaner picked a block group from the list of unused block
- * groups before we were able to in the previous call to
- * btrfs_delete_unused_bgs()).
- */
- wait_on_bit(&fs_info->flags, BTRFS_FS_CLEANER_RUNNING,
- TASK_UNINTERRUPTIBLE);
-
- /*
- * We've set the superblock to RO mode, so we might have made
- * the cleaner task sleep without running all pending delayed
- * iputs. Go through all the delayed iputs here, so that if an
- * unmount happens without remounting RW we don't end up at
- * finishing close_ctree() with a non-empty list of delayed
- * iputs.
- */
- btrfs_run_delayed_iputs(fs_info);
-
- btrfs_dev_replace_suspend_for_unmount(fs_info);
- btrfs_scrub_cancel(fs_info);
- btrfs_pause_balance(fs_info);
-
- /*
- * Pause the qgroup rescan worker if it is running. We don't want
- * it to be still running after we are in RO mode, as after that,
- * by the time we unmount, it might have left a transaction open,
- * so we would leak the transaction and/or crash.
- */
- btrfs_qgroup_wait_for_completion(fs_info, false);
-
- ret = btrfs_commit_super(fs_info);
- if (ret)
- goto restore;
- } else {
- if (BTRFS_FS_ERROR(fs_info)) {
- btrfs_err(fs_info,
- "Remounting read-write after error is not allowed");
- ret = -EINVAL;
- goto restore;
- }
- if (fs_info->fs_devices->rw_devices == 0) {
- ret = -EACCES;
- goto restore;
- }
-
- if (!btrfs_check_rw_degradable(fs_info, NULL)) {
- btrfs_warn(fs_info,
- "too many missing devices, writable remount is not allowed");
- ret = -EACCES;
- goto restore;
- }
-
- if (btrfs_super_log_root(fs_info->super_copy) != 0) {
- btrfs_warn(fs_info,
- "mount required to replay tree-log, cannot remount read-write");
- ret = -EINVAL;
- goto restore;
- }
-
- /*
- * NOTE: when remounting with a change that does writes, don't
- * put it anywhere above this point, as we are not sure to be
- * safe to write until we pass the above checks.
- */
- ret = btrfs_start_pre_rw_mount(fs_info);
- if (ret)
- goto restore;
-
- btrfs_clear_sb_rdonly(sb);
-
- set_bit(BTRFS_FS_OPEN, &fs_info->flags);
-
- /*
- * If we've gone from readonly -> read/write, we need to get
- * our sync/async discard lists in the right state.
- */
- btrfs_discard_resume(fs_info);
- }
-out:
/*
* 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.
--
2.41.0
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCH v2 07/18] btrfs: add a NOSPACECACHE mount option flag
2023-11-08 19:08 [PATCH v2 00/18] btrfs: convert to the new mount API Josef Bacik
` (5 preceding siblings ...)
2023-11-08 19:08 ` [PATCH v2 06/18] btrfs: split out ro->rw and rw->ro helpers into their own functions Josef Bacik
@ 2023-11-08 19:08 ` Josef Bacik
2023-11-08 19:08 ` [PATCH v2 08/18] btrfs: add fs_parameter definitions Josef Bacik
` (13 subsequent siblings)
20 siblings, 0 replies; 33+ messages in thread
From: Josef Bacik @ 2023-11-08 19:08 UTC (permalink / raw)
To: linux-btrfs, kernel-team, linux-fsdevel, brauner
With the old mount API we'd pre-populate the mount options with the
space cache settings of the file system, and then the user toggled them
on or off with the mount options. When we switch to the new mount API
the mount options will be set before we get into opening the file
system, so we need a flag to indicate that the user explicitly asked for
-o nospace_cache so we can make the appropriate changes after the fact.
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
fs/btrfs/disk-io.c | 1 +
fs/btrfs/fs.h | 1 +
2 files changed, 2 insertions(+)
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 072c45811c41..c70e507a28d0 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -2938,6 +2938,7 @@ void btrfs_clear_oneshot_options(struct btrfs_fs_info *fs_info)
{
btrfs_clear_opt(fs_info->mount_opt, USEBACKUPROOT);
btrfs_clear_opt(fs_info->mount_opt, CLEAR_CACHE);
+ btrfs_clear_opt(fs_info->mount_opt, NOSPACECACHE);
}
/*
diff --git a/fs/btrfs/fs.h b/fs/btrfs/fs.h
index 318df6f9d9cb..ecfa13a9c2cf 100644
--- a/fs/btrfs/fs.h
+++ b/fs/btrfs/fs.h
@@ -188,6 +188,7 @@ enum {
BTRFS_MOUNT_IGNOREBADROOTS = (1UL << 27),
BTRFS_MOUNT_IGNOREDATACSUMS = (1UL << 28),
BTRFS_MOUNT_NODISCARD = (1UL << 29),
+ BTRFS_MOUNT_NOSPACECACHE = (1UL << 30),
};
/*
--
2.41.0
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCH v2 08/18] btrfs: add fs_parameter definitions
2023-11-08 19:08 [PATCH v2 00/18] btrfs: convert to the new mount API Josef Bacik
` (6 preceding siblings ...)
2023-11-08 19:08 ` [PATCH v2 07/18] btrfs: add a NOSPACECACHE mount option flag Josef Bacik
@ 2023-11-08 19:08 ` Josef Bacik
2023-11-14 17:49 ` David Sterba
2023-11-08 19:08 ` [PATCH v2 09/18] btrfs: add parse_param callback for the new mount api Josef Bacik
` (12 subsequent siblings)
20 siblings, 1 reply; 33+ messages in thread
From: Josef Bacik @ 2023-11-08 19:08 UTC (permalink / raw)
To: linux-btrfs, kernel-team, linux-fsdevel, brauner
In order to convert to the new mount api we have to change how we do the
mount option parsing. For now we're going to duplicate these helpers to
make it easier to follow, and then remove the old code once everything
is in place. This patch contains the re-definiton of all of our mount
options into the new fs_parameter_spec format.
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
fs/btrfs/super.c | 128 ++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 127 insertions(+), 1 deletion(-)
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index d7070269e3ea..0e9cb9ed6508 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -27,6 +27,7 @@
#include <linux/crc32c.h>
#include <linux/btrfs.h>
#include <linux/security.h>
+#include <linux/fs_parser.h>
#include "messages.h"
#include "delayed-inode.h"
#include "ctree.h"
@@ -132,7 +133,7 @@ enum {
/* Debugging options */
Opt_enospc_debug, Opt_noenospc_debug,
#ifdef CONFIG_BTRFS_DEBUG
- Opt_fragment_data, Opt_fragment_metadata, Opt_fragment_all,
+ Opt_fragment, Opt_fragment_data, Opt_fragment_metadata, Opt_fragment_all,
#endif
#ifdef CONFIG_BTRFS_FS_REF_VERIFY
Opt_ref_verify,
@@ -222,6 +223,131 @@ static const match_table_t rescue_tokens = {
{Opt_err, NULL},
};
+enum {
+ Opt_fatal_errors_panic,
+ Opt_fatal_errors_bug,
+};
+
+static const struct constant_table btrfs_parameter_fatal_errors[] = {
+ { "panic", Opt_fatal_errors_panic },
+ { "bug", Opt_fatal_errors_bug },
+ {}
+};
+
+enum {
+ Opt_discard_sync,
+ Opt_discard_async,
+};
+
+static const struct constant_table btrfs_parameter_discard[] = {
+ { "sync", Opt_discard_sync },
+ { "async", Opt_discard_async },
+ {}
+};
+
+enum {
+ Opt_space_cache_v1,
+ Opt_space_cache_v2,
+};
+
+static const struct constant_table btrfs_parameter_space_cache[] = {
+ { "v1", Opt_space_cache_v1 },
+ { "v2", Opt_space_cache_v2 },
+ {}
+};
+
+enum {
+ Opt_rescue_usebackuproot,
+ Opt_rescue_nologreplay,
+ Opt_rescue_ignorebadroots,
+ Opt_rescue_ignoredatacsums,
+ Opt_rescue_parameter_all,
+};
+
+static const struct constant_table btrfs_parameter_rescue[] = {
+ { "usebackuproot", Opt_rescue_usebackuproot },
+ { "nologreplay", Opt_rescue_nologreplay },
+ { "ignorebadroots", Opt_rescue_ignorebadroots },
+ { "ibadroots", Opt_rescue_ignorebadroots },
+ { "ignoredatacsums", Opt_rescue_ignoredatacsums },
+ { "idatacsums", Opt_rescue_ignoredatacsums },
+ { "all", Opt_rescue_parameter_all },
+ {}
+};
+
+#ifdef CONFIG_BTRFS_DEBUG
+enum {
+ Opt_fragment_parameter_data,
+ Opt_fragment_parameter_metadata,
+ Opt_fragment_parameter_all,
+};
+
+static const struct constant_table btrfs_parameter_fragment[] = {
+ { "data", Opt_fragment_parameter_data },
+ { "metadata", Opt_fragment_parameter_metadata },
+ { "all", Opt_fragment_parameter_all },
+ {}
+};
+#endif
+
+static const struct fs_parameter_spec btrfs_fs_parameters[] __maybe_unused = {
+ fsparam_flag_no("acl", Opt_acl),
+ 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("degraded", Opt_degraded),
+ fsparam_string("device", Opt_device),
+ fsparam_enum("fatal_errors", Opt_fatal_errors, btrfs_parameter_fatal_errors),
+ fsparam_flag_no("flushoncommit", Opt_flushoncommit),
+ fsparam_flag_no("inode_cache", Opt_inode_cache),
+ fsparam_string("max_inline", Opt_max_inline),
+ fsparam_flag_no("barrier", Opt_barrier),
+ fsparam_flag_no("datacow", Opt_datacow),
+ fsparam_flag_no("datasum", Opt_datasum),
+ fsparam_flag_no("autodefrag", Opt_defrag),
+ fsparam_flag_no("discard", Opt_discard),
+ fsparam_enum("discard", Opt_discard_mode, btrfs_parameter_discard),
+ fsparam_u32("metadata_ratio", Opt_ratio),
+ 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_enum("space_cache", Opt_space_cache_version, btrfs_parameter_space_cache),
+ fsparam_flag_no("ssd", Opt_ssd),
+ fsparam_flag_no("ssd_spread", Opt_ssd_spread),
+ fsparam_string("subvol", Opt_subvol),
+ fsparam_flag("subvol=", Opt_subvol_empty),
+ fsparam_u64("subvolid", Opt_subvolid),
+ fsparam_u32("thread_pool", Opt_thread_pool),
+ fsparam_flag_no("treelog", Opt_treelog),
+ fsparam_flag("user_subvol_rm_allowed", Opt_user_subvol_rm_allowed),
+
+ /* Rescue options */
+ fsparam_enum("rescue", Opt_rescue, btrfs_parameter_rescue),
+ /* Deprecated, with alias rescue=nologreplay */
+ __fsparam(NULL, "nologreplay", Opt_nologreplay, fs_param_deprecated,
+ NULL),
+ /* Deprecated, with alias rescue=usebackuproot */
+ __fsparam(NULL, "usebackuproot", Opt_usebackuproot, fs_param_deprecated,
+ NULL),
+
+ /* Deprecated options */
+ __fsparam(NULL, "recovery", Opt_recovery,
+ fs_param_neg_with_no|fs_param_deprecated, NULL),
+
+ /* Debugging options */
+ fsparam_flag_no("enospc_debug", Opt_enospc_debug),
+#ifdef CONFIG_BTRFS_DEBUG
+ fsparam_enum("fragment", Opt_fragment, btrfs_parameter_fragment),
+#endif
+#ifdef CONFIG_BTRFS_FS_REF_VERIFY
+ fsparam_flag("ref_verify", Opt_ref_verify),
+#endif
+ {}
+};
+
static bool check_ro_option(struct btrfs_fs_info *fs_info, unsigned long opt,
const char *opt_name)
{
--
2.41.0
^ permalink raw reply related [flat|nested] 33+ messages in thread
* Re: [PATCH v2 08/18] btrfs: add fs_parameter definitions
2023-11-08 19:08 ` [PATCH v2 08/18] btrfs: add fs_parameter definitions Josef Bacik
@ 2023-11-14 17:49 ` David Sterba
0 siblings, 0 replies; 33+ messages in thread
From: David Sterba @ 2023-11-14 17:49 UTC (permalink / raw)
To: Josef Bacik; +Cc: linux-btrfs, kernel-team, linux-fsdevel, brauner
On Wed, Nov 08, 2023 at 02:08:43PM -0500, Josef Bacik wrote:
> In order to convert to the new mount api we have to change how we do the
> mount option parsing. For now we're going to duplicate these helpers to
> make it easier to follow, and then remove the old code once everything
> is in place. This patch contains the re-definiton of all of our mount
> options into the new fs_parameter_spec format.
>
> Signed-off-by: Josef Bacik <josef@toxicpanda.com>
> ---
> fs/btrfs/super.c | 128 ++++++++++++++++++++++++++++++++++++++++++++++-
> 1 file changed, 127 insertions(+), 1 deletion(-)
>
> diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
> index d7070269e3ea..0e9cb9ed6508 100644
> --- a/fs/btrfs/super.c
> +++ b/fs/btrfs/super.c
> @@ -27,6 +27,7 @@
> #include <linux/crc32c.h>
> #include <linux/btrfs.h>
> #include <linux/security.h>
> +#include <linux/fs_parser.h>
> #include "messages.h"
> #include "delayed-inode.h"
> #include "ctree.h"
> @@ -132,7 +133,7 @@ enum {
> /* Debugging options */
> Opt_enospc_debug, Opt_noenospc_debug,
> #ifdef CONFIG_BTRFS_DEBUG
> - Opt_fragment_data, Opt_fragment_metadata, Opt_fragment_all,
> + Opt_fragment, Opt_fragment_data, Opt_fragment_metadata, Opt_fragment_all,
> #endif
> #ifdef CONFIG_BTRFS_FS_REF_VERIFY
> Opt_ref_verify,
> @@ -222,6 +223,131 @@ static const match_table_t rescue_tokens = {
> {Opt_err, NULL},
> };
>
> +enum {
> + Opt_fatal_errors_panic,
> + Opt_fatal_errors_bug,
> +};
> +
> +static const struct constant_table btrfs_parameter_fatal_errors[] = {
> + { "panic", Opt_fatal_errors_panic },
> + { "bug", Opt_fatal_errors_bug },
> + {}
> +};
> +
> +enum {
> + Opt_discard_sync,
> + Opt_discard_async,
> +};
> +
> +static const struct constant_table btrfs_parameter_discard[] = {
> + { "sync", Opt_discard_sync },
> + { "async", Opt_discard_async },
> + {}
> +};
> +
> +enum {
> + Opt_space_cache_v1,
> + Opt_space_cache_v2,
> +};
> +
> +static const struct constant_table btrfs_parameter_space_cache[] = {
> + { "v1", Opt_space_cache_v1 },
> + { "v2", Opt_space_cache_v2 },
> + {}
> +};
> +
> +enum {
> + Opt_rescue_usebackuproot,
> + Opt_rescue_nologreplay,
> + Opt_rescue_ignorebadroots,
> + Opt_rescue_ignoredatacsums,
> + Opt_rescue_parameter_all,
> +};
> +
> +static const struct constant_table btrfs_parameter_rescue[] = {
> + { "usebackuproot", Opt_rescue_usebackuproot },
> + { "nologreplay", Opt_rescue_nologreplay },
> + { "ignorebadroots", Opt_rescue_ignorebadroots },
> + { "ibadroots", Opt_rescue_ignorebadroots },
> + { "ignoredatacsums", Opt_rescue_ignoredatacsums },
> + { "idatacsums", Opt_rescue_ignoredatacsums },
> + { "all", Opt_rescue_parameter_all },
> + {}
> +};
> +
> +#ifdef CONFIG_BTRFS_DEBUG
> +enum {
> + Opt_fragment_parameter_data,
> + Opt_fragment_parameter_metadata,
> + Opt_fragment_parameter_all,
> +};
> +
> +static const struct constant_table btrfs_parameter_fragment[] = {
> + { "data", Opt_fragment_parameter_data },
> + { "metadata", Opt_fragment_parameter_metadata },
> + { "all", Opt_fragment_parameter_all },
> + {}
> +};
> +#endif
> +
> +static const struct fs_parameter_spec btrfs_fs_parameters[] __maybe_unused = {
> + fsparam_flag_no("acl", Opt_acl),
> + 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("degraded", Opt_degraded),
> + fsparam_string("device", Opt_device),
> + fsparam_enum("fatal_errors", Opt_fatal_errors, btrfs_parameter_fatal_errors),
> + fsparam_flag_no("flushoncommit", Opt_flushoncommit),
> + fsparam_flag_no("inode_cache", Opt_inode_cache),
I think it's a good opportunity to remove this option completely, its
functionality is gone since 5.11, that's eough time. I'm fine with
removing it both before or after the API switch.
> + fsparam_string("max_inline", Opt_max_inline),
> + fsparam_flag_no("barrier", Opt_barrier),
> + fsparam_flag_no("datacow", Opt_datacow),
> + fsparam_flag_no("datasum", Opt_datasum),
> + fsparam_flag_no("autodefrag", Opt_defrag),
> + fsparam_flag_no("discard", Opt_discard),
> + fsparam_enum("discard", Opt_discard_mode, btrfs_parameter_discard),
> + fsparam_u32("metadata_ratio", Opt_ratio),
> + 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_enum("space_cache", Opt_space_cache_version, btrfs_parameter_space_cache),
> + fsparam_flag_no("ssd", Opt_ssd),
> + fsparam_flag_no("ssd_spread", Opt_ssd_spread),
> + fsparam_string("subvol", Opt_subvol),
> + fsparam_flag("subvol=", Opt_subvol_empty),
> + fsparam_u64("subvolid", Opt_subvolid),
> + fsparam_u32("thread_pool", Opt_thread_pool),
> + fsparam_flag_no("treelog", Opt_treelog),
> + fsparam_flag("user_subvol_rm_allowed", Opt_user_subvol_rm_allowed),
> +
> + /* Rescue options */
> + fsparam_enum("rescue", Opt_rescue, btrfs_parameter_rescue),
> + /* Deprecated, with alias rescue=nologreplay */
> + __fsparam(NULL, "nologreplay", Opt_nologreplay, fs_param_deprecated,
> + NULL),
> + /* Deprecated, with alias rescue=usebackuproot */
> + __fsparam(NULL, "usebackuproot", Opt_usebackuproot, fs_param_deprecated,
> + NULL),
> +
> + /* Deprecated options */
> + __fsparam(NULL, "recovery", Opt_recovery,
> + fs_param_neg_with_no|fs_param_deprecated, NULL),
Same here, 'recovery' obsoleted by the rescue options in 4.5.
> +
> + /* Debugging options */
> + fsparam_flag_no("enospc_debug", Opt_enospc_debug),
> +#ifdef CONFIG_BTRFS_DEBUG
> + fsparam_enum("fragment", Opt_fragment, btrfs_parameter_fragment),
> +#endif
> +#ifdef CONFIG_BTRFS_FS_REF_VERIFY
> + fsparam_flag("ref_verify", Opt_ref_verify),
> +#endif
> + {}
> +};
> +
> static bool check_ro_option(struct btrfs_fs_info *fs_info, unsigned long opt,
> const char *opt_name)
> {
> --
> 2.41.0
>
^ permalink raw reply [flat|nested] 33+ messages in thread
* [PATCH v2 09/18] btrfs: add parse_param callback for the new mount api
2023-11-08 19:08 [PATCH v2 00/18] btrfs: convert to the new mount API Josef Bacik
` (7 preceding siblings ...)
2023-11-08 19:08 ` [PATCH v2 08/18] btrfs: add fs_parameter definitions Josef Bacik
@ 2023-11-08 19:08 ` Josef Bacik
2023-11-14 18:13 ` David Sterba
2023-11-08 19:08 ` [PATCH v2 10/18] btrfs: add fs context handling functions Josef Bacik
` (11 subsequent siblings)
20 siblings, 1 reply; 33+ messages in thread
From: Josef Bacik @ 2023-11-08 19:08 UTC (permalink / raw)
To: linux-btrfs, kernel-team, linux-fsdevel, brauner
The parse_param callback handles one parameter at a time, take our
existing mount option parsing loop and adjust it to handle one parameter
at a time, and tie it into the fs_context_operations.
Create a btrfs_fs_context object that will store the various mount
properties, we'll house this in fc->fs_private. This is necessary to
separate because remounting will use ->reconfigure, and we'll get a new
copy of the parsed parameters, so we can no longer directly mess with
the fs_info in this stage.
In the future we'll add this to the btrfs_fs_info and update the users
to use the new context object instead.
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
fs/btrfs/super.c | 390 +++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 390 insertions(+)
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index 0e9cb9ed6508..2f7ee78edd11 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -84,6 +84,19 @@ static void btrfs_put_super(struct super_block *sb)
close_ctree(btrfs_sb(sb));
}
+/* Store the mount options related information. */
+struct btrfs_fs_context {
+ char *subvol_name;
+ u64 subvol_objectid;
+ u64 max_inline;
+ u32 commit_interval;
+ u32 metadata_ratio;
+ u32 thread_pool_size;
+ unsigned long mount_opt;
+ unsigned long compress_type:4;
+ unsigned int compress_level;
+};
+
enum {
Opt_acl, Opt_noacl,
Opt_clear_cache,
@@ -348,6 +361,379 @@ static const struct fs_parameter_spec btrfs_fs_parameters[] __maybe_unused = {
{}
};
+static int btrfs_parse_param(struct fs_context *fc,
+ struct fs_parameter *param)
+{
+ struct btrfs_fs_context *ctx = fc->fs_private;
+ struct fs_parse_result result;
+ int opt;
+
+ opt = fs_parse(fc, btrfs_fs_parameters, param, &result);
+ if (opt < 0)
+ return opt;
+
+ switch (opt) {
+ case Opt_degraded:
+ btrfs_set_opt(ctx->mount_opt, DEGRADED);
+ break;
+ case Opt_subvol_empty:
+ /*
+ * This exists because we used to allow it on accident, so we're
+ * keeping it to maintain ABI. See
+ * 37becec95ac31b209eb1c8e096f1093a7db00f32.
+ */
+ break;
+ case Opt_subvol:
+ kfree(ctx->subvol_name);
+ ctx->subvol_name = kstrdup(param->string, GFP_KERNEL);
+ if (!ctx->subvol_name)
+ return -ENOMEM;
+ break;
+ case Opt_subvolid:
+ ctx->subvol_objectid = result.uint_64;
+
+ /* subvoldi=0 means give me the original fs_tree. */
+ if (!ctx->subvol_objectid)
+ ctx->subvol_objectid = BTRFS_FS_TREE_OBJECTID;
+ break;
+ case Opt_device: {
+ struct btrfs_device *device;
+ blk_mode_t mode = sb_open_mode(fc->sb_flags);
+
+ mutex_lock(&uuid_mutex);
+ device = btrfs_scan_one_device(param->string, mode, false);
+ mutex_unlock(&uuid_mutex);
+ if (IS_ERR(device))
+ return PTR_ERR(device);
+ 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_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_compress_force:
+ case Opt_compress_force_type:
+ btrfs_set_opt(ctx->mount_opt, FORCE_COMPRESS);
+ fallthrough;
+ case Opt_compress:
+ case Opt_compress_type:
+ if (opt == Opt_compress ||
+ opt == Opt_compress_force ||
+ strncmp(param->string, "zlib", 4) == 0) {
+ ctx->compress_type = BTRFS_COMPRESS_ZLIB;
+ ctx->compress_level = BTRFS_ZLIB_DEFAULT_LEVEL;
+ /*
+ * args[0] contains uninitialized data since
+ * for these tokens 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);
+ } else if (strncmp(param->string, "lzo", 3) == 0) {
+ ctx->compress_type = BTRFS_COMPRESS_LZO;
+ 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);
+ } else if (strncmp(param->string, "zstd", 4) == 0) {
+ 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);
+ } else if (strncmp(param->string, "no", 2) == 0) {
+ ctx->compress_level = 0;
+ ctx->compress_type = 0;
+ btrfs_clear_opt(ctx->mount_opt, COMPRESS);
+ btrfs_clear_opt(ctx->mount_opt, FORCE_COMPRESS);
+ } else {
+ btrfs_err(NULL, "unrecognized compression value %s",
+ param->string);
+ return -EINVAL;
+ }
+ 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_set_opt(ctx->mount_opt, SSD);
+ btrfs_clear_opt(ctx->mount_opt, NOSSD);
+ }
+ 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_barrier:
+ if (result.negated)
+ btrfs_set_opt(ctx->mount_opt, NOBARRIER);
+ else
+ btrfs_clear_opt(ctx->mount_opt, NOBARRIER);
+ break;
+ case Opt_thread_pool:
+ if (result.uint_32 == 0) {
+ btrfs_err(NULL, "invalid value 0 for thread_pool");
+ return -EINVAL;
+ }
+ ctx->thread_pool_size = result.uint_32;
+ break;
+ case Opt_max_inline:
+ ctx->max_inline = memparse(param->string, NULL);
+ break;
+ case Opt_acl:
+ if (result.negated) {
+ fc->sb_flags &= ~SB_POSIXACL;
+ } else {
+#ifdef CONFIG_BTRFS_FS_POSIX_ACL
+ fc->sb_flags |= SB_POSIXACL;
+#else
+ btrfs_err(NULL, "support for ACL not compiled in!");
+ ret = -EINVAL;
+ goto out;
+#endif
+ }
+ /*
+ * VFS limits the ability to toggle ACL on and off via remount,
+ * despite every file system allowing this. This seems to be an
+ * oversight since we all do, but it'll fail if we're
+ * remounting. So don't set the mask here, we'll check it in
+ * btrfs_reconfigure and do the toggling ourselves.
+ */
+ if (fc->purpose != FS_CONTEXT_FOR_RECONFIGURE)
+ fc->sb_flags_mask |= SB_POSIXACL;
+ break;
+ case Opt_treelog:
+ if (result.negated)
+ btrfs_set_opt(ctx->mount_opt, NOTREELOG);
+ else
+ btrfs_clear_opt(ctx->mount_opt, NOTREELOG);
+ break;
+ case Opt_recovery:
+ /*
+ * -o recovery used to be an alias for usebackuproot, and then
+ * norecovery was an alias for nologreplay, hence the different
+ * behaviors for negated and not.
+ */
+ if (result.negated) {
+ btrfs_warn(NULL,
+ "'norecovery' is deprecated, use 'rescue=nologreplay' instead");
+ btrfs_set_opt(ctx->mount_opt, NOLOGREPLAY);
+ } else {
+ btrfs_warn(NULL,
+ "'recovery' is deprecated, use 'rescue=usebackuproot' instead");
+ btrfs_set_opt(ctx->mount_opt, USEBACKUPROOT);
+ }
+ break;
+ case Opt_nologreplay:
+ btrfs_warn(NULL,
+ "'nologreplay' is deprecated, use 'rescue=nologreplay' instead");
+ btrfs_set_opt(ctx->mount_opt, NOLOGREPLAY);
+ break;
+ case Opt_flushoncommit:
+ if (result.negated)
+ btrfs_clear_opt(ctx->mount_opt, FLUSHONCOMMIT);
+ else
+ btrfs_set_opt(ctx->mount_opt, FLUSHONCOMMIT);
+ break;
+ case Opt_ratio:
+ ctx->metadata_ratio = result.uint_32;
+ break;
+ case Opt_discard:
+ if (result.negated) {
+ btrfs_clear_opt(ctx->mount_opt, DISCARD_SYNC);
+ btrfs_clear_opt(ctx->mount_opt, DISCARD_ASYNC);
+ btrfs_set_opt(ctx->mount_opt, NODISCARD);
+ } else {
+ btrfs_set_opt(ctx->mount_opt, DISCARD_SYNC);
+ btrfs_clear_opt(ctx->mount_opt, DISCARD_ASYNC);
+ }
+ break;
+ case Opt_discard_mode:
+ switch (result.uint_32) {
+ case Opt_discard_sync:
+ btrfs_clear_opt(ctx->mount_opt, DISCARD_ASYNC);
+ btrfs_set_opt(ctx->mount_opt, DISCARD_SYNC);
+ break;
+ case Opt_discard_async:
+ btrfs_clear_opt(ctx->mount_opt, DISCARD_SYNC);
+ btrfs_set_opt(ctx->mount_opt, DISCARD_ASYNC);
+ break;
+ default:
+ btrfs_err(NULL, "unrecognized discard mode value %s",
+ param->key);
+ return -EINVAL;
+ }
+ btrfs_clear_opt(ctx->mount_opt, NODISCARD);
+ break;
+ case Opt_space_cache:
+ if (result.negated) {
+ btrfs_set_opt(ctx->mount_opt, NOSPACECACHE);
+ btrfs_clear_opt(ctx->mount_opt, SPACE_CACHE);
+ btrfs_clear_opt(ctx->mount_opt, FREE_SPACE_TREE);
+ } else {
+ btrfs_clear_opt(ctx->mount_opt, FREE_SPACE_TREE);
+ btrfs_set_opt(ctx->mount_opt, SPACE_CACHE);
+ }
+ break;
+ case Opt_space_cache_version:
+ switch (result.uint_32) {
+ case Opt_space_cache_v1:
+ btrfs_set_opt(ctx->mount_opt, SPACE_CACHE);
+ btrfs_clear_opt(ctx->mount_opt, FREE_SPACE_TREE);
+ break;
+ case Opt_space_cache_v2:
+ btrfs_clear_opt(ctx->mount_opt, SPACE_CACHE);
+ btrfs_set_opt(ctx->mount_opt, FREE_SPACE_TREE);
+ break;
+ default:
+ btrfs_err(NULL, "unrecognized space_cache value %s",
+ param->key);
+ return -EINVAL;
+ }
+ break;
+ case Opt_rescan_uuid_tree:
+ btrfs_set_opt(ctx->mount_opt, RESCAN_UUID_TREE);
+ break;
+ case Opt_inode_cache:
+ btrfs_warn(NULL,
+ "the 'inode_cache' option is deprecated and has no effect since 5.11");
+ break;
+ case Opt_clear_cache:
+ btrfs_set_opt(ctx->mount_opt, CLEAR_CACHE);
+ break;
+ case Opt_user_subvol_rm_allowed:
+ btrfs_set_opt(ctx->mount_opt, USER_SUBVOL_RM_ALLOWED);
+ 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_defrag:
+ if (result.negated)
+ btrfs_clear_opt(ctx->mount_opt, AUTO_DEFRAG);
+ else
+ btrfs_set_opt(ctx->mount_opt, AUTO_DEFRAG);
+ break;
+ case Opt_usebackuproot:
+ btrfs_warn(NULL,
+ "'usebackuproot' is deprecated, use 'rescue=usebackuproot' instead");
+ btrfs_set_opt(ctx->mount_opt, USEBACKUPROOT);
+ break;
+ case Opt_skip_balance:
+ btrfs_set_opt(ctx->mount_opt, SKIP_BALANCE);
+ break;
+ case Opt_fatal_errors:
+ switch (result.uint_32) {
+ case Opt_fatal_errors_panic:
+ btrfs_set_opt(ctx->mount_opt,
+ PANIC_ON_FATAL_ERROR);
+ break;
+ case Opt_fatal_errors_bug:
+ btrfs_clear_opt(ctx->mount_opt,
+ PANIC_ON_FATAL_ERROR);
+ break;
+ default:
+ btrfs_err(NULL, "unrecognized fatal_errors value %s",
+ param->key);
+ return -EINVAL;
+ }
+ break;
+ case Opt_commit_interval:
+ ctx->commit_interval = result.uint_32;
+ if (!ctx->commit_interval)
+ ctx->commit_interval = BTRFS_DEFAULT_COMMIT_INTERVAL;
+ break;
+ case Opt_rescue:
+ switch (result.uint_32) {
+ case Opt_rescue_usebackuproot:
+ btrfs_set_opt(ctx->mount_opt, USEBACKUPROOT);
+ break;
+ case Opt_rescue_nologreplay:
+ btrfs_set_opt(ctx->mount_opt, NOLOGREPLAY);
+ break;
+ case Opt_rescue_ignorebadroots:
+ btrfs_set_opt(ctx->mount_opt, IGNOREBADROOTS);
+ break;
+ case Opt_rescue_ignoredatacsums:
+ btrfs_set_opt(ctx->mount_opt, IGNOREDATACSUMS);
+ break;
+ case Opt_rescue_parameter_all:
+ btrfs_set_opt(ctx->mount_opt, IGNOREDATACSUMS);
+ btrfs_set_opt(ctx->mount_opt, IGNOREBADROOTS);
+ btrfs_set_opt(ctx->mount_opt, NOLOGREPLAY);
+ break;
+ default:
+ btrfs_info(NULL, "unrecognized rescue option '%s'",
+ param->key);
+ return -EINVAL;
+ }
+ break;
+#ifdef CONFIG_BTRFS_DEBUG
+ case Opt_fragment:
+ switch (result.uint_32) {
+ case Opt_fragment_parameter_all:
+ btrfs_set_opt(ctx->mount_opt, FRAGMENT_DATA);
+ btrfs_set_opt(ctx->mount_opt, FRAGMENT_METADATA);
+ break;
+ case Opt_fragment_parameter_metadata:
+ btrfs_set_opt(ctx->mount_opt, FRAGMENT_METADATA);
+ break;
+ case Opt_fragment_parameter_data:
+ btrfs_set_opt(ctx->mount_opt, FRAGMENT_DATA);
+ break;
+ default:
+ btrfs_info(NULL, "unrecognized fragment option '%s'",
+ param->key);
+ return -EINVAL;
+ }
+ break;
+#endif
+#ifdef CONFIG_BTRFS_FS_REF_VERIFY
+ case Opt_ref_verify:
+ btrfs_set_opt(ctx->mount_opt, REF_VERIFY);
+ break;
+#endif
+ default:
+ btrfs_err(NULL, "unrecognized mount option '%s'", param->key);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static bool check_ro_option(struct btrfs_fs_info *fs_info, unsigned long opt,
const char *opt_name)
{
@@ -2255,6 +2641,10 @@ static void btrfs_kill_super(struct super_block *sb)
btrfs_free_fs_info(fs_info);
}
+static const struct fs_context_operations btrfs_fs_context_ops __maybe_unused = {
+ .parse_param = btrfs_parse_param,
+};
+
static struct file_system_type btrfs_fs_type = {
.owner = THIS_MODULE,
.name = "btrfs",
--
2.41.0
^ permalink raw reply related [flat|nested] 33+ messages in thread
* Re: [PATCH v2 09/18] btrfs: add parse_param callback for the new mount api
2023-11-08 19:08 ` [PATCH v2 09/18] btrfs: add parse_param callback for the new mount api Josef Bacik
@ 2023-11-14 18:13 ` David Sterba
2023-11-22 16:12 ` Josef Bacik
0 siblings, 1 reply; 33+ messages in thread
From: David Sterba @ 2023-11-14 18:13 UTC (permalink / raw)
To: Josef Bacik; +Cc: linux-btrfs, kernel-team, linux-fsdevel, brauner
On Wed, Nov 08, 2023 at 02:08:44PM -0500, Josef Bacik wrote:
> The parse_param callback handles one parameter at a time, take our
> existing mount option parsing loop and adjust it to handle one parameter
> at a time, and tie it into the fs_context_operations.
>
> Create a btrfs_fs_context object that will store the various mount
> properties, we'll house this in fc->fs_private. This is necessary to
> separate because remounting will use ->reconfigure, and we'll get a new
> copy of the parsed parameters, so we can no longer directly mess with
> the fs_info in this stage.
>
> In the future we'll add this to the btrfs_fs_info and update the users
> to use the new context object instead.
>
> Signed-off-by: Josef Bacik <josef@toxicpanda.com>
> ---
> fs/btrfs/super.c | 390 +++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 390 insertions(+)
>
> diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
> index 0e9cb9ed6508..2f7ee78edd11 100644
> --- a/fs/btrfs/super.c
> +++ b/fs/btrfs/super.c
> @@ -84,6 +84,19 @@ static void btrfs_put_super(struct super_block *sb)
> close_ctree(btrfs_sb(sb));
> }
>
> +/* Store the mount options related information. */
> +struct btrfs_fs_context {
> + char *subvol_name;
> + u64 subvol_objectid;
> + u64 max_inline;
> + u32 commit_interval;
> + u32 metadata_ratio;
> + u32 thread_pool_size;
> + unsigned long mount_opt;
> + unsigned long compress_type:4;
> + unsigned int compress_level;
> +};
> +
> enum {
> Opt_acl, Opt_noacl,
> Opt_clear_cache,
> @@ -348,6 +361,379 @@ static const struct fs_parameter_spec btrfs_fs_parameters[] __maybe_unused = {
> {}
> };
>
> +static int btrfs_parse_param(struct fs_context *fc,
> + struct fs_parameter *param)
> +{
> + struct btrfs_fs_context *ctx = fc->fs_private;
> + struct fs_parse_result result;
> + int opt;
> +
> + opt = fs_parse(fc, btrfs_fs_parameters, param, &result);
> + if (opt < 0)
> + return opt;
> +
> + switch (opt) {
> + case Opt_degraded:
> + btrfs_set_opt(ctx->mount_opt, DEGRADED);
> + break;
> + case Opt_subvol_empty:
> + /*
> + * This exists because we used to allow it on accident, so we're
> + * keeping it to maintain ABI. See
> + * 37becec95ac31b209eb1c8e096f1093a7db00f32.
Please use the full patch reference 37becec95ac3 ("Btrfs: allow empty
subvol= again"), the subject itself explains why it's here.
> + */
> + break;
> + case Opt_subvol:
> + kfree(ctx->subvol_name);
> + ctx->subvol_name = kstrdup(param->string, GFP_KERNEL);
> + if (!ctx->subvol_name)
> + return -ENOMEM;
> + break;
> + case Opt_subvolid:
> + ctx->subvol_objectid = result.uint_64;
> +
> + /* subvoldi=0 means give me the original fs_tree. */
subvolid=0
> + if (!ctx->subvol_objectid)
> + ctx->subvol_objectid = BTRFS_FS_TREE_OBJECTID;
> + break;
> + case Opt_device: {
> + struct btrfs_device *device;
> + blk_mode_t mode = sb_open_mode(fc->sb_flags);
> +
> + mutex_lock(&uuid_mutex);
> + device = btrfs_scan_one_device(param->string, mode, false);
> + mutex_unlock(&uuid_mutex);
So this changes how the device option and scan works. At this point the
option is in the simple lock/unlock sequence, while currently it's
scanning all devices under in one lock and then also opens all the
devices. This prevents any other scan to interrupt that so it's either
scanned right before (and filling the list) or after (which is a no-op).
Now it's open to the races, I haven't evaluated if this could be a
problem or not.
> + if (IS_ERR(device))
> + return PTR_ERR(device);
> + 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_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_compress_force:
> + case Opt_compress_force_type:
> + btrfs_set_opt(ctx->mount_opt, FORCE_COMPRESS);
> + fallthrough;
> + case Opt_compress:
> + case Opt_compress_type:
> + if (opt == Opt_compress ||
> + opt == Opt_compress_force ||
> + strncmp(param->string, "zlib", 4) == 0) {
> + ctx->compress_type = BTRFS_COMPRESS_ZLIB;
> + ctx->compress_level = BTRFS_ZLIB_DEFAULT_LEVEL;
> + /*
> + * args[0] contains uninitialized data since
> + * for these tokens we don't expect any
> + * parameter.
> + */
Please reformat/realign comments that you copy or move
> + if (opt != Opt_compress &&
> + opt != Opt_compress_force)
> + ctx->compress_level =
> + btrfs_compress_str2level(
> + BTRFS_COMPRESS_ZLIB,
> + param->string + 4);
This does not need to do newline after "("
> + btrfs_set_opt(ctx->mount_opt, COMPRESS);
> + btrfs_clear_opt(ctx->mount_opt, NODATACOW);
> + btrfs_clear_opt(ctx->mount_opt, NODATASUM);
> + } else if (strncmp(param->string, "lzo", 3) == 0) {
> + ctx->compress_type = BTRFS_COMPRESS_LZO;
> + 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);
> + } else if (strncmp(param->string, "zstd", 4) == 0) {
> + ctx->compress_type = BTRFS_COMPRESS_ZSTD;
> + ctx->compress_level =
> + btrfs_compress_str2level(
> + BTRFS_COMPRESS_ZSTD,
> + param->string + 4);
Same
> + btrfs_set_opt(ctx->mount_opt, COMPRESS);
> + btrfs_clear_opt(ctx->mount_opt, NODATACOW);
> + btrfs_clear_opt(ctx->mount_opt, NODATASUM);
> + } else if (strncmp(param->string, "no", 2) == 0) {
> + ctx->compress_level = 0;
> + ctx->compress_type = 0;
> + btrfs_clear_opt(ctx->mount_opt, COMPRESS);
> + btrfs_clear_opt(ctx->mount_opt, FORCE_COMPRESS);
> + } else {
> + btrfs_err(NULL, "unrecognized compression value %s",
> + param->string);
> + return -EINVAL;
> + }
> + 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_set_opt(ctx->mount_opt, SSD);
> + btrfs_clear_opt(ctx->mount_opt, NOSSD);
> + }
> + 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_barrier:
> + if (result.negated)
> + btrfs_set_opt(ctx->mount_opt, NOBARRIER);
> + else
> + btrfs_clear_opt(ctx->mount_opt, NOBARRIER);
> + break;
> + case Opt_thread_pool:
> + if (result.uint_32 == 0) {
> + btrfs_err(NULL, "invalid value 0 for thread_pool");
> + return -EINVAL;
> + }
> + ctx->thread_pool_size = result.uint_32;
It's not in current code but we should eventually clamp the value,
num_online_cpus or similar.
> + break;
> + case Opt_max_inline:
> + ctx->max_inline = memparse(param->string, NULL);
This does not match, the max_inline value is adjusted as
if (info->max_inline) {
info->max_inline = min_t(u64,
info->max_inline,
info->sectorsize);
}
and it should be validated at the time we parse it, like other options.
> + break;
> + case Opt_acl:
> + if (result.negated) {
> + fc->sb_flags &= ~SB_POSIXACL;
> + } else {
> +#ifdef CONFIG_BTRFS_FS_POSIX_ACL
> + fc->sb_flags |= SB_POSIXACL;
> +#else
> + btrfs_err(NULL, "support for ACL not compiled in!");
> + ret = -EINVAL;
> + goto out;
> +#endif
> + }
> + /*
> + * VFS limits the ability to toggle ACL on and off via remount,
> + * despite every file system allowing this. This seems to be an
> + * oversight since we all do, but it'll fail if we're
> + * remounting. So don't set the mask here, we'll check it in
> + * btrfs_reconfigure and do the toggling ourselves.
> + */
> + if (fc->purpose != FS_CONTEXT_FOR_RECONFIGURE)
> + fc->sb_flags_mask |= SB_POSIXACL;
> + break;
> + case Opt_treelog:
> + if (result.negated)
> + btrfs_set_opt(ctx->mount_opt, NOTREELOG);
> + else
> + btrfs_clear_opt(ctx->mount_opt, NOTREELOG);
> + break;
> + case Opt_recovery:
> + /*
> + * -o recovery used to be an alias for usebackuproot, and then
> + * norecovery was an alias for nologreplay, hence the different
> + * behaviors for negated and not.
> + */
> + if (result.negated) {
> + btrfs_warn(NULL,
> + "'norecovery' is deprecated, use 'rescue=nologreplay' instead");
> + btrfs_set_opt(ctx->mount_opt, NOLOGREPLAY);
> + } else {
> + btrfs_warn(NULL,
> + "'recovery' is deprecated, use 'rescue=usebackuproot' instead");
> + btrfs_set_opt(ctx->mount_opt, USEBACKUPROOT);
> + }
> + break;
> + case Opt_nologreplay:
> + btrfs_warn(NULL,
> + "'nologreplay' is deprecated, use 'rescue=nologreplay' instead");
> + btrfs_set_opt(ctx->mount_opt, NOLOGREPLAY);
> + break;
> + case Opt_flushoncommit:
> + if (result.negated)
> + btrfs_clear_opt(ctx->mount_opt, FLUSHONCOMMIT);
> + else
> + btrfs_set_opt(ctx->mount_opt, FLUSHONCOMMIT);
> + break;
> + case Opt_ratio:
> + ctx->metadata_ratio = result.uint_32;
> + break;
> + case Opt_discard:
> + if (result.negated) {
> + btrfs_clear_opt(ctx->mount_opt, DISCARD_SYNC);
> + btrfs_clear_opt(ctx->mount_opt, DISCARD_ASYNC);
> + btrfs_set_opt(ctx->mount_opt, NODISCARD);
> + } else {
> + btrfs_set_opt(ctx->mount_opt, DISCARD_SYNC);
> + btrfs_clear_opt(ctx->mount_opt, DISCARD_ASYNC);
> + }
> + break;
> + case Opt_discard_mode:
> + switch (result.uint_32) {
> + case Opt_discard_sync:
> + btrfs_clear_opt(ctx->mount_opt, DISCARD_ASYNC);
> + btrfs_set_opt(ctx->mount_opt, DISCARD_SYNC);
> + break;
> + case Opt_discard_async:
> + btrfs_clear_opt(ctx->mount_opt, DISCARD_SYNC);
> + btrfs_set_opt(ctx->mount_opt, DISCARD_ASYNC);
> + break;
> + default:
> + btrfs_err(NULL, "unrecognized discard mode value %s",
> + param->key);
> + return -EINVAL;
> + }
> + btrfs_clear_opt(ctx->mount_opt, NODISCARD);
> + break;
> + case Opt_space_cache:
> + if (result.negated) {
> + btrfs_set_opt(ctx->mount_opt, NOSPACECACHE);
> + btrfs_clear_opt(ctx->mount_opt, SPACE_CACHE);
> + btrfs_clear_opt(ctx->mount_opt, FREE_SPACE_TREE);
> + } else {
> + btrfs_clear_opt(ctx->mount_opt, FREE_SPACE_TREE);
> + btrfs_set_opt(ctx->mount_opt, SPACE_CACHE);
> + }
> + break;
> + case Opt_space_cache_version:
> + switch (result.uint_32) {
> + case Opt_space_cache_v1:
> + btrfs_set_opt(ctx->mount_opt, SPACE_CACHE);
> + btrfs_clear_opt(ctx->mount_opt, FREE_SPACE_TREE);
> + break;
> + case Opt_space_cache_v2:
> + btrfs_clear_opt(ctx->mount_opt, SPACE_CACHE);
> + btrfs_set_opt(ctx->mount_opt, FREE_SPACE_TREE);
> + break;
> + default:
> + btrfs_err(NULL, "unrecognized space_cache value %s",
> + param->key);
> + return -EINVAL;
> + }
> + break;
> + case Opt_rescan_uuid_tree:
> + btrfs_set_opt(ctx->mount_opt, RESCAN_UUID_TREE);
> + break;
> + case Opt_inode_cache:
> + btrfs_warn(NULL,
> + "the 'inode_cache' option is deprecated and has no effect since 5.11");
> + break;
> + case Opt_clear_cache:
> + btrfs_set_opt(ctx->mount_opt, CLEAR_CACHE);
> + break;
> + case Opt_user_subvol_rm_allowed:
> + btrfs_set_opt(ctx->mount_opt, USER_SUBVOL_RM_ALLOWED);
> + 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_defrag:
> + if (result.negated)
> + btrfs_clear_opt(ctx->mount_opt, AUTO_DEFRAG);
> + else
> + btrfs_set_opt(ctx->mount_opt, AUTO_DEFRAG);
> + break;
> + case Opt_usebackuproot:
> + btrfs_warn(NULL,
> + "'usebackuproot' is deprecated, use 'rescue=usebackuproot' instead");
> + btrfs_set_opt(ctx->mount_opt, USEBACKUPROOT);
> + break;
> + case Opt_skip_balance:
> + btrfs_set_opt(ctx->mount_opt, SKIP_BALANCE);
> + break;
> + case Opt_fatal_errors:
> + switch (result.uint_32) {
> + case Opt_fatal_errors_panic:
> + btrfs_set_opt(ctx->mount_opt,
> + PANIC_ON_FATAL_ERROR);
Lines can be joined
> + break;
> + case Opt_fatal_errors_bug:
> + btrfs_clear_opt(ctx->mount_opt,
> + PANIC_ON_FATAL_ERROR);
Same
> + break;
> + default:
> + btrfs_err(NULL, "unrecognized fatal_errors value %s",
> + param->key);
> + return -EINVAL;
> + }
> + break;
> + case Opt_commit_interval:
> + ctx->commit_interval = result.uint_32;
> + if (!ctx->commit_interval)
> + ctx->commit_interval = BTRFS_DEFAULT_COMMIT_INTERVAL;
And the value of commit_interval is also adjusted in current code, this
should be done here as well.
> + break;
> + case Opt_rescue:
> + switch (result.uint_32) {
> + case Opt_rescue_usebackuproot:
> + btrfs_set_opt(ctx->mount_opt, USEBACKUPROOT);
> + break;
> + case Opt_rescue_nologreplay:
> + btrfs_set_opt(ctx->mount_opt, NOLOGREPLAY);
> + break;
> + case Opt_rescue_ignorebadroots:
> + btrfs_set_opt(ctx->mount_opt, IGNOREBADROOTS);
> + break;
> + case Opt_rescue_ignoredatacsums:
> + btrfs_set_opt(ctx->mount_opt, IGNOREDATACSUMS);
> + break;
> + case Opt_rescue_parameter_all:
> + btrfs_set_opt(ctx->mount_opt, IGNOREDATACSUMS);
> + btrfs_set_opt(ctx->mount_opt, IGNOREBADROOTS);
> + btrfs_set_opt(ctx->mount_opt, NOLOGREPLAY);
> + break;
> + default:
> + btrfs_info(NULL, "unrecognized rescue option '%s'",
> + param->key);
> + return -EINVAL;
> + }
> + break;
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH v2 09/18] btrfs: add parse_param callback for the new mount api
2023-11-14 18:13 ` David Sterba
@ 2023-11-22 16:12 ` Josef Bacik
0 siblings, 0 replies; 33+ messages in thread
From: Josef Bacik @ 2023-11-22 16:12 UTC (permalink / raw)
To: David Sterba; +Cc: linux-btrfs, kernel-team, linux-fsdevel, brauner
On Tue, Nov 14, 2023 at 07:13:38PM +0100, David Sterba wrote:
> On Wed, Nov 08, 2023 at 02:08:44PM -0500, Josef Bacik wrote:
> > The parse_param callback handles one parameter at a time, take our
> > existing mount option parsing loop and adjust it to handle one parameter
> > at a time, and tie it into the fs_context_operations.
> >
> > Create a btrfs_fs_context object that will store the various mount
> > properties, we'll house this in fc->fs_private. This is necessary to
> > separate because remounting will use ->reconfigure, and we'll get a new
> > copy of the parsed parameters, so we can no longer directly mess with
> > the fs_info in this stage.
> >
> > In the future we'll add this to the btrfs_fs_info and update the users
> > to use the new context object instead.
> >
> > Signed-off-by: Josef Bacik <josef@toxicpanda.com>
> > ---
> > fs/btrfs/super.c | 390 +++++++++++++++++++++++++++++++++++++++++++++++
> > 1 file changed, 390 insertions(+)
> >
> > diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
> > index 0e9cb9ed6508..2f7ee78edd11 100644
> > --- a/fs/btrfs/super.c
> > +++ b/fs/btrfs/super.c
> > @@ -84,6 +84,19 @@ static void btrfs_put_super(struct super_block *sb)
> > close_ctree(btrfs_sb(sb));
> > }
> >
> > +/* Store the mount options related information. */
> > +struct btrfs_fs_context {
> > + char *subvol_name;
> > + u64 subvol_objectid;
> > + u64 max_inline;
> > + u32 commit_interval;
> > + u32 metadata_ratio;
> > + u32 thread_pool_size;
> > + unsigned long mount_opt;
> > + unsigned long compress_type:4;
> > + unsigned int compress_level;
> > +};
> > +
> > enum {
> > Opt_acl, Opt_noacl,
> > Opt_clear_cache,
> > @@ -348,6 +361,379 @@ static const struct fs_parameter_spec btrfs_fs_parameters[] __maybe_unused = {
> > {}
> > };
> >
> > +static int btrfs_parse_param(struct fs_context *fc,
> > + struct fs_parameter *param)
> > +{
> > + struct btrfs_fs_context *ctx = fc->fs_private;
> > + struct fs_parse_result result;
> > + int opt;
> > +
> > + opt = fs_parse(fc, btrfs_fs_parameters, param, &result);
> > + if (opt < 0)
> > + return opt;
> > +
> > + switch (opt) {
> > + case Opt_degraded:
> > + btrfs_set_opt(ctx->mount_opt, DEGRADED);
> > + break;
> > + case Opt_subvol_empty:
> > + /*
> > + * This exists because we used to allow it on accident, so we're
> > + * keeping it to maintain ABI. See
> > + * 37becec95ac31b209eb1c8e096f1093a7db00f32.
>
> Please use the full patch reference 37becec95ac3 ("Btrfs: allow empty
> subvol= again"), the subject itself explains why it's here.
>
> > + */
> > + break;
> > + case Opt_subvol:
> > + kfree(ctx->subvol_name);
> > + ctx->subvol_name = kstrdup(param->string, GFP_KERNEL);
> > + if (!ctx->subvol_name)
> > + return -ENOMEM;
> > + break;
> > + case Opt_subvolid:
> > + ctx->subvol_objectid = result.uint_64;
> > +
> > + /* subvoldi=0 means give me the original fs_tree. */
>
> subvolid=0
>
> > + if (!ctx->subvol_objectid)
> > + ctx->subvol_objectid = BTRFS_FS_TREE_OBJECTID;
> > + break;
> > + case Opt_device: {
> > + struct btrfs_device *device;
> > + blk_mode_t mode = sb_open_mode(fc->sb_flags);
> > +
> > + mutex_lock(&uuid_mutex);
> > + device = btrfs_scan_one_device(param->string, mode, false);
> > + mutex_unlock(&uuid_mutex);
>
> So this changes how the device option and scan works. At this point the
> option is in the simple lock/unlock sequence, while currently it's
> scanning all devices under in one lock and then also opens all the
> devices. This prevents any other scan to interrupt that so it's either
> scanned right before (and filling the list) or after (which is a no-op).
>
> Now it's open to the races, I haven't evaluated if this could be a
> problem or not.
>
Udev has been scanning our devices ahead of time for years, this is exactly how
it exists currently. I don't think anybody is actually using -o
device=<whatever>, but if they are this gives them the same behavior that most
people get with the udev rule and mount /dev/oneofthedisks /foo.
If we're really worried about it however I could allocate the strings and attach
them to the context here, and then at mount time scan them all to give us the
same behavior as we had before.
> > + if (IS_ERR(device))
> > + return PTR_ERR(device);
> > + 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_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_compress_force:
> > + case Opt_compress_force_type:
> > + btrfs_set_opt(ctx->mount_opt, FORCE_COMPRESS);
> > + fallthrough;
> > + case Opt_compress:
> > + case Opt_compress_type:
> > + if (opt == Opt_compress ||
> > + opt == Opt_compress_force ||
> > + strncmp(param->string, "zlib", 4) == 0) {
> > + ctx->compress_type = BTRFS_COMPRESS_ZLIB;
> > + ctx->compress_level = BTRFS_ZLIB_DEFAULT_LEVEL;
> > + /*
> > + * args[0] contains uninitialized data since
> > + * for these tokens we don't expect any
> > + * parameter.
> > + */
>
> Please reformat/realign comments that you copy or move
>
> > + if (opt != Opt_compress &&
> > + opt != Opt_compress_force)
> > + ctx->compress_level =
> > + btrfs_compress_str2level(
> > + BTRFS_COMPRESS_ZLIB,
> > + param->string + 4);
>
> This does not need to do newline after "("
>
> > + btrfs_set_opt(ctx->mount_opt, COMPRESS);
> > + btrfs_clear_opt(ctx->mount_opt, NODATACOW);
> > + btrfs_clear_opt(ctx->mount_opt, NODATASUM);
> > + } else if (strncmp(param->string, "lzo", 3) == 0) {
> > + ctx->compress_type = BTRFS_COMPRESS_LZO;
> > + 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);
> > + } else if (strncmp(param->string, "zstd", 4) == 0) {
> > + ctx->compress_type = BTRFS_COMPRESS_ZSTD;
> > + ctx->compress_level =
> > + btrfs_compress_str2level(
> > + BTRFS_COMPRESS_ZSTD,
> > + param->string + 4);
>
> Same
>
> > + btrfs_set_opt(ctx->mount_opt, COMPRESS);
> > + btrfs_clear_opt(ctx->mount_opt, NODATACOW);
> > + btrfs_clear_opt(ctx->mount_opt, NODATASUM);
> > + } else if (strncmp(param->string, "no", 2) == 0) {
> > + ctx->compress_level = 0;
> > + ctx->compress_type = 0;
> > + btrfs_clear_opt(ctx->mount_opt, COMPRESS);
> > + btrfs_clear_opt(ctx->mount_opt, FORCE_COMPRESS);
> > + } else {
> > + btrfs_err(NULL, "unrecognized compression value %s",
> > + param->string);
> > + return -EINVAL;
> > + }
> > + 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_set_opt(ctx->mount_opt, SSD);
> > + btrfs_clear_opt(ctx->mount_opt, NOSSD);
> > + }
> > + 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_barrier:
> > + if (result.negated)
> > + btrfs_set_opt(ctx->mount_opt, NOBARRIER);
> > + else
> > + btrfs_clear_opt(ctx->mount_opt, NOBARRIER);
> > + break;
> > + case Opt_thread_pool:
> > + if (result.uint_32 == 0) {
> > + btrfs_err(NULL, "invalid value 0 for thread_pool");
> > + return -EINVAL;
> > + }
> > + ctx->thread_pool_size = result.uint_32;
>
> It's not in current code but we should eventually clamp the value,
> num_online_cpus or similar.
>
> > + break;
> > + case Opt_max_inline:
> > + ctx->max_inline = memparse(param->string, NULL);
>
> This does not match, the max_inline value is adjusted as
>
> if (info->max_inline) {
> info->max_inline = min_t(u64,
> info->max_inline,
> info->sectorsize);
> }
>
> and it should be validated at the time we parse it, like other options.
>
We can't do that with the current scheme, tho I did miss clam'ing it. I've
added the clamping part to the patch where we flip over to using the new mount
API.
> > + break;
> > + case Opt_acl:
> > + if (result.negated) {
> > + fc->sb_flags &= ~SB_POSIXACL;
> > + } else {
> > +#ifdef CONFIG_BTRFS_FS_POSIX_ACL
> > + fc->sb_flags |= SB_POSIXACL;
> > +#else
> > + btrfs_err(NULL, "support for ACL not compiled in!");
> > + ret = -EINVAL;
> > + goto out;
> > +#endif
> > + }
> > + /*
> > + * VFS limits the ability to toggle ACL on and off via remount,
> > + * despite every file system allowing this. This seems to be an
> > + * oversight since we all do, but it'll fail if we're
> > + * remounting. So don't set the mask here, we'll check it in
> > + * btrfs_reconfigure and do the toggling ourselves.
> > + */
> > + if (fc->purpose != FS_CONTEXT_FOR_RECONFIGURE)
> > + fc->sb_flags_mask |= SB_POSIXACL;
> > + break;
> > + case Opt_treelog:
> > + if (result.negated)
> > + btrfs_set_opt(ctx->mount_opt, NOTREELOG);
> > + else
> > + btrfs_clear_opt(ctx->mount_opt, NOTREELOG);
> > + break;
> > + case Opt_recovery:
> > + /*
> > + * -o recovery used to be an alias for usebackuproot, and then
> > + * norecovery was an alias for nologreplay, hence the different
> > + * behaviors for negated and not.
> > + */
> > + if (result.negated) {
> > + btrfs_warn(NULL,
> > + "'norecovery' is deprecated, use 'rescue=nologreplay' instead");
> > + btrfs_set_opt(ctx->mount_opt, NOLOGREPLAY);
> > + } else {
> > + btrfs_warn(NULL,
> > + "'recovery' is deprecated, use 'rescue=usebackuproot' instead");
> > + btrfs_set_opt(ctx->mount_opt, USEBACKUPROOT);
> > + }
> > + break;
> > + case Opt_nologreplay:
> > + btrfs_warn(NULL,
> > + "'nologreplay' is deprecated, use 'rescue=nologreplay' instead");
> > + btrfs_set_opt(ctx->mount_opt, NOLOGREPLAY);
> > + break;
> > + case Opt_flushoncommit:
> > + if (result.negated)
> > + btrfs_clear_opt(ctx->mount_opt, FLUSHONCOMMIT);
> > + else
> > + btrfs_set_opt(ctx->mount_opt, FLUSHONCOMMIT);
> > + break;
> > + case Opt_ratio:
> > + ctx->metadata_ratio = result.uint_32;
> > + break;
> > + case Opt_discard:
> > + if (result.negated) {
> > + btrfs_clear_opt(ctx->mount_opt, DISCARD_SYNC);
> > + btrfs_clear_opt(ctx->mount_opt, DISCARD_ASYNC);
> > + btrfs_set_opt(ctx->mount_opt, NODISCARD);
> > + } else {
> > + btrfs_set_opt(ctx->mount_opt, DISCARD_SYNC);
> > + btrfs_clear_opt(ctx->mount_opt, DISCARD_ASYNC);
> > + }
> > + break;
> > + case Opt_discard_mode:
> > + switch (result.uint_32) {
> > + case Opt_discard_sync:
> > + btrfs_clear_opt(ctx->mount_opt, DISCARD_ASYNC);
> > + btrfs_set_opt(ctx->mount_opt, DISCARD_SYNC);
> > + break;
> > + case Opt_discard_async:
> > + btrfs_clear_opt(ctx->mount_opt, DISCARD_SYNC);
> > + btrfs_set_opt(ctx->mount_opt, DISCARD_ASYNC);
> > + break;
> > + default:
> > + btrfs_err(NULL, "unrecognized discard mode value %s",
> > + param->key);
> > + return -EINVAL;
> > + }
> > + btrfs_clear_opt(ctx->mount_opt, NODISCARD);
> > + break;
> > + case Opt_space_cache:
> > + if (result.negated) {
> > + btrfs_set_opt(ctx->mount_opt, NOSPACECACHE);
> > + btrfs_clear_opt(ctx->mount_opt, SPACE_CACHE);
> > + btrfs_clear_opt(ctx->mount_opt, FREE_SPACE_TREE);
> > + } else {
> > + btrfs_clear_opt(ctx->mount_opt, FREE_SPACE_TREE);
> > + btrfs_set_opt(ctx->mount_opt, SPACE_CACHE);
> > + }
> > + break;
> > + case Opt_space_cache_version:
> > + switch (result.uint_32) {
> > + case Opt_space_cache_v1:
> > + btrfs_set_opt(ctx->mount_opt, SPACE_CACHE);
> > + btrfs_clear_opt(ctx->mount_opt, FREE_SPACE_TREE);
> > + break;
> > + case Opt_space_cache_v2:
> > + btrfs_clear_opt(ctx->mount_opt, SPACE_CACHE);
> > + btrfs_set_opt(ctx->mount_opt, FREE_SPACE_TREE);
> > + break;
> > + default:
> > + btrfs_err(NULL, "unrecognized space_cache value %s",
> > + param->key);
> > + return -EINVAL;
> > + }
> > + break;
> > + case Opt_rescan_uuid_tree:
> > + btrfs_set_opt(ctx->mount_opt, RESCAN_UUID_TREE);
> > + break;
> > + case Opt_inode_cache:
> > + btrfs_warn(NULL,
> > + "the 'inode_cache' option is deprecated and has no effect since 5.11");
> > + break;
> > + case Opt_clear_cache:
> > + btrfs_set_opt(ctx->mount_opt, CLEAR_CACHE);
> > + break;
> > + case Opt_user_subvol_rm_allowed:
> > + btrfs_set_opt(ctx->mount_opt, USER_SUBVOL_RM_ALLOWED);
> > + 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_defrag:
> > + if (result.negated)
> > + btrfs_clear_opt(ctx->mount_opt, AUTO_DEFRAG);
> > + else
> > + btrfs_set_opt(ctx->mount_opt, AUTO_DEFRAG);
> > + break;
> > + case Opt_usebackuproot:
> > + btrfs_warn(NULL,
> > + "'usebackuproot' is deprecated, use 'rescue=usebackuproot' instead");
> > + btrfs_set_opt(ctx->mount_opt, USEBACKUPROOT);
> > + break;
> > + case Opt_skip_balance:
> > + btrfs_set_opt(ctx->mount_opt, SKIP_BALANCE);
> > + break;
> > + case Opt_fatal_errors:
> > + switch (result.uint_32) {
> > + case Opt_fatal_errors_panic:
> > + btrfs_set_opt(ctx->mount_opt,
> > + PANIC_ON_FATAL_ERROR);
>
> Lines can be joined
>
> > + break;
> > + case Opt_fatal_errors_bug:
> > + btrfs_clear_opt(ctx->mount_opt,
> > + PANIC_ON_FATAL_ERROR);
>
> Same
>
> > + break;
> > + default:
> > + btrfs_err(NULL, "unrecognized fatal_errors value %s",
> > + param->key);
> > + return -EINVAL;
> > + }
> > + break;
> > + case Opt_commit_interval:
> > + ctx->commit_interval = result.uint_32;
> > + if (!ctx->commit_interval)
> > + ctx->commit_interval = BTRFS_DEFAULT_COMMIT_INTERVAL;
>
> And the value of commit_interval is also adjusted in current code, this
> should be done here as well.
>
It isn't adjusted, we just yell if it's above 300. If you do -o
commit_interval=0 it wants the default interval, which is what I've handled
here. Thanks,
Josef
^ permalink raw reply [flat|nested] 33+ messages in thread
* [PATCH v2 10/18] btrfs: add fs context handling functions
2023-11-08 19:08 [PATCH v2 00/18] btrfs: convert to the new mount API Josef Bacik
` (8 preceding siblings ...)
2023-11-08 19:08 ` [PATCH v2 09/18] btrfs: add parse_param callback for the new mount api Josef Bacik
@ 2023-11-08 19:08 ` Josef Bacik
2023-11-08 19:08 ` [PATCH v2 11/18] btrfs: add reconfigure callback for fs_context Josef Bacik
` (10 subsequent siblings)
20 siblings, 0 replies; 33+ messages in thread
From: Josef Bacik @ 2023-11-08 19:08 UTC (permalink / raw)
To: linux-btrfs, kernel-team, linux-fsdevel, brauner
We are going to use the fs context to hold the mount options, so
allocate the btrfs_fs_context when we're asked to init the fs context,
and free it in the free callback.
Reviewed-by: Christian Brauner <brauner@kernel.org>
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
fs/btrfs/super.c | 36 +++++++++++++++++++++++++++++++++++-
1 file changed, 35 insertions(+), 1 deletion(-)
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index 2f7ee78edd11..facea4632a8d 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -2641,10 +2641,44 @@ static void btrfs_kill_super(struct super_block *sb)
btrfs_free_fs_info(fs_info);
}
-static const struct fs_context_operations btrfs_fs_context_ops __maybe_unused = {
+static void btrfs_free_fs_context(struct fs_context *fc)
+{
+ struct btrfs_fs_context *ctx = fc->fs_private;
+
+ if (!ctx)
+ return;
+
+ kfree(ctx->subvol_name);
+ kfree(ctx);
+}
+
+static const struct fs_context_operations btrfs_fs_context_ops = {
.parse_param = btrfs_parse_param,
+ .free = btrfs_free_fs_context,
};
+static int __maybe_unused btrfs_init_fs_context(struct fs_context *fc)
+{
+ struct btrfs_fs_context *ctx;
+
+ ctx = kzalloc(sizeof(struct btrfs_fs_context), GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ ctx->thread_pool_size = min_t(unsigned long, num_online_cpus() + 2, 8);
+ ctx->max_inline = BTRFS_DEFAULT_MAX_INLINE;
+ ctx->commit_interval = BTRFS_DEFAULT_COMMIT_INTERVAL;
+ ctx->subvol_objectid = BTRFS_FS_TREE_OBJECTID;
+#ifndef CONFIG_BTRFS_FS_POSIX_ACL
+ ctx->noacl = true;
+#endif
+
+ fc->fs_private = ctx;
+ fc->ops = &btrfs_fs_context_ops;
+
+ return 0;
+}
+
static struct file_system_type btrfs_fs_type = {
.owner = THIS_MODULE,
.name = "btrfs",
--
2.41.0
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCH v2 11/18] btrfs: add reconfigure callback for fs_context
2023-11-08 19:08 [PATCH v2 00/18] btrfs: convert to the new mount API Josef Bacik
` (9 preceding siblings ...)
2023-11-08 19:08 ` [PATCH v2 10/18] btrfs: add fs context handling functions Josef Bacik
@ 2023-11-08 19:08 ` Josef Bacik
2023-11-14 18:23 ` David Sterba
2023-11-08 19:08 ` [PATCH v2 12/18] btrfs: add get_tree callback for new mount API Josef Bacik
` (9 subsequent siblings)
20 siblings, 1 reply; 33+ messages in thread
From: Josef Bacik @ 2023-11-08 19:08 UTC (permalink / raw)
To: linux-btrfs, kernel-team, linux-fsdevel, brauner
This is what is used to remount the file system with the new mount API.
Because the mount options are parsed separately and one at a time I've
added a helper to emit the mount options after the fact once the mount
is configured, this matches the dmesg output for what happens with the
old mount API.
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
fs/btrfs/super.c | 243 +++++++++++++++++++++++++++++++++++++++++++----
fs/btrfs/zoned.c | 16 ++--
fs/btrfs/zoned.h | 6 +-
3 files changed, 236 insertions(+), 29 deletions(-)
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index facea4632a8d..b5067cf637a2 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -734,10 +734,11 @@ static int btrfs_parse_param(struct fs_context *fc,
return 0;
}
-static bool check_ro_option(struct btrfs_fs_info *fs_info, unsigned long opt,
+static bool check_ro_option(struct btrfs_fs_info *fs_info,
+ unsigned long mount_opt, unsigned long opt,
const char *opt_name)
{
- if (fs_info->mount_opt & opt) {
+ if (mount_opt & opt) {
btrfs_err(fs_info, "%s must be used with ro mount option",
opt_name);
return true;
@@ -745,33 +746,34 @@ static bool check_ro_option(struct btrfs_fs_info *fs_info, unsigned long opt,
return false;
}
-static bool check_options(struct btrfs_fs_info *info, unsigned long flags)
+static bool check_options(struct btrfs_fs_info *info, unsigned long *mount_opt,
+ unsigned long flags)
{
if (!(flags & SB_RDONLY) &&
- (check_ro_option(info, BTRFS_MOUNT_NOLOGREPLAY, "nologreplay") ||
- check_ro_option(info, BTRFS_MOUNT_IGNOREBADROOTS, "ignorebadroots") ||
- check_ro_option(info, BTRFS_MOUNT_IGNOREDATACSUMS, "ignoredatacsums")))
+ (check_ro_option(info, *mount_opt, BTRFS_MOUNT_NOLOGREPLAY, "nologreplay") ||
+ check_ro_option(info, *mount_opt, BTRFS_MOUNT_IGNOREBADROOTS, "ignorebadroots") ||
+ check_ro_option(info, *mount_opt, BTRFS_MOUNT_IGNOREDATACSUMS, "ignoredatacsums")))
return false;
if (btrfs_fs_compat_ro(info, FREE_SPACE_TREE) &&
- !btrfs_test_opt(info, FREE_SPACE_TREE) &&
- !btrfs_test_opt(info, CLEAR_CACHE)) {
+ !btrfs_raw_test_opt(*mount_opt, FREE_SPACE_TREE) &&
+ !btrfs_raw_test_opt(*mount_opt, CLEAR_CACHE)) {
btrfs_err(info, "cannot disable free space tree");
return false;
}
if (btrfs_fs_compat_ro(info, BLOCK_GROUP_TREE) &&
- !btrfs_test_opt(info, FREE_SPACE_TREE)) {
+ !btrfs_raw_test_opt(*mount_opt, FREE_SPACE_TREE)) {
btrfs_err(info, "cannot disable free space tree with block-group-tree feature");
return false;
}
- if (btrfs_check_mountopts_zoned(info))
+ if (btrfs_check_mountopts_zoned(info, mount_opt))
return false;
if (!test_bit(BTRFS_FS_STATE_REMOUNTING, &info->fs_state)) {
- if (btrfs_test_opt(info, SPACE_CACHE))
+ if (btrfs_raw_test_opt(*mount_opt, SPACE_CACHE))
btrfs_info(info, "disk space caching is enabled");
- if (btrfs_test_opt(info, FREE_SPACE_TREE))
+ if (btrfs_raw_test_opt(*mount_opt, FREE_SPACE_TREE))
btrfs_info(info, "using free space tree");
}
@@ -1337,7 +1339,7 @@ int btrfs_parse_options(struct btrfs_fs_info *info, char *options,
}
}
out:
- if (!ret && !check_options(info, new_flags))
+ if (!ret && !check_options(info, &info->mount_opt, new_flags))
ret = -EINVAL;
return ret;
}
@@ -2377,6 +2379,203 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data)
return ret;
}
+static void btrfs_ctx_to_info(struct btrfs_fs_info *fs_info,
+ struct btrfs_fs_context *ctx)
+{
+ fs_info->max_inline = ctx->max_inline;
+ fs_info->commit_interval = ctx->commit_interval;
+ fs_info->metadata_ratio = ctx->metadata_ratio;
+ fs_info->thread_pool_size = ctx->thread_pool_size;
+ fs_info->mount_opt = ctx->mount_opt;
+ fs_info->compress_type = ctx->compress_type;
+ fs_info->compress_level = ctx->compress_level;
+}
+
+static void btrfs_info_to_ctx(struct btrfs_fs_info *fs_info,
+ struct btrfs_fs_context *ctx)
+{
+ ctx->max_inline = fs_info->max_inline;
+ ctx->commit_interval = fs_info->commit_interval;
+ ctx->metadata_ratio = fs_info->metadata_ratio;
+ ctx->thread_pool_size = fs_info->thread_pool_size;
+ ctx->mount_opt = fs_info->mount_opt;
+ ctx->compress_type = fs_info->compress_type;
+ ctx->compress_level = fs_info->compress_level;
+}
+
+#define btrfs_info_if_set(fs_info, old_ctx, opt, fmt, args...) \
+do { \
+ if ((!old_ctx || !btrfs_raw_test_opt(old_ctx->mount_opt, opt)) && \
+ btrfs_raw_test_opt(fs_info->mount_opt, opt)) \
+ btrfs_info(fs_info, fmt, ##args); \
+} while (0)
+
+#define btrfs_info_if_unset(fs_info, old_ctx, opt, fmt, args...) \
+do { \
+ if ((old_ctx && btrfs_raw_test_opt(old_ctx->mount_opt, opt)) && \
+ !btrfs_raw_test_opt(fs_info->mount_opt, opt)) \
+ btrfs_info(fs_info, fmt, ##args); \
+} while (0)
+
+static void btrfs_emit_options(struct btrfs_fs_info *fs_info,
+ struct btrfs_fs_context *old_ctx)
+{
+ btrfs_info_if_set(fs_info, old_ctx, NODATASUM, "setting nodatasum");
+ btrfs_info_if_set(fs_info, old_ctx, DEGRADED,
+ "allowing degraded mounts");
+ btrfs_info_if_set(fs_info, old_ctx, NODATASUM, "setting nodatasum");
+ btrfs_info_if_set(fs_info, old_ctx, SSD, "enabling ssd optimizations");
+ btrfs_info_if_set(fs_info, old_ctx, SSD_SPREAD,
+ "using spread ssd allocation scheme");
+ btrfs_info_if_set(fs_info, old_ctx, NOBARRIER, "turning off barriers");
+ btrfs_info_if_set(fs_info, old_ctx, NOTREELOG, "disabling tree log");
+ btrfs_info_if_set(fs_info, old_ctx, NOLOGREPLAY,
+ "disabling log replay at mount time");
+ btrfs_info_if_set(fs_info, old_ctx, FLUSHONCOMMIT,
+ "turning on flush-on-commit");
+ btrfs_info_if_set(fs_info, old_ctx, DISCARD_SYNC,
+ "turning on sync discard");
+ btrfs_info_if_set(fs_info, old_ctx, DISCARD_ASYNC,
+ "turning on async discard");
+ btrfs_info_if_set(fs_info, old_ctx, FREE_SPACE_TREE,
+ "enabling free space tree");
+ btrfs_info_if_set(fs_info, old_ctx, SPACE_CACHE,
+ "enabling disk space caching");
+ btrfs_info_if_set(fs_info, old_ctx, CLEAR_CACHE,
+ "force clearing of disk cache");
+ btrfs_info_if_set(fs_info, old_ctx, AUTO_DEFRAG,
+ "enabling auto defrag");
+ btrfs_info_if_set(fs_info, old_ctx, FRAGMENT_DATA,
+ "fragmenting data");
+ btrfs_info_if_set(fs_info, old_ctx, FRAGMENT_METADATA,
+ "fragmenting metadata");
+ btrfs_info_if_set(fs_info, old_ctx, REF_VERIFY,
+ "doing ref verification");
+ btrfs_info_if_set(fs_info, old_ctx, USEBACKUPROOT,
+ "trying to use backup root at mount time");
+ btrfs_info_if_set(fs_info, old_ctx, IGNOREBADROOTS,
+ "ignoring bad roots");
+ btrfs_info_if_set(fs_info, old_ctx, IGNOREDATACSUMS,
+ "ignoring data csums");
+
+ btrfs_info_if_unset(fs_info, old_ctx, NODATACOW, "setting datacow");
+ btrfs_info_if_unset(fs_info, old_ctx, SSD, "not using ssd optimizations");
+ btrfs_info_if_unset(fs_info, old_ctx, SSD_SPREAD,
+ "not using spread ssd allocation scheme");
+ btrfs_info_if_unset(fs_info, old_ctx, NOBARRIER,
+ "turning off barriers");
+ btrfs_info_if_unset(fs_info, old_ctx, NOTREELOG, "enabling tree log");
+ btrfs_info_if_unset(fs_info, old_ctx, SPACE_CACHE,
+ "disabling disk space caching");
+ btrfs_info_if_unset(fs_info, old_ctx, FREE_SPACE_TREE,
+ "disabling free space tree");
+ btrfs_info_if_unset(fs_info, old_ctx, AUTO_DEFRAG,
+ "disabling auto defrag");
+ btrfs_info_if_unset(fs_info, old_ctx, COMPRESS,
+ "use no compression");
+
+ /* Did the compression settings change? */
+ if (btrfs_test_opt(fs_info, COMPRESS) &&
+ (!old_ctx ||
+ old_ctx->compress_type != fs_info->compress_type ||
+ old_ctx->compress_level != fs_info->compress_level ||
+ (!btrfs_raw_test_opt(old_ctx->mount_opt, FORCE_COMPRESS) &&
+ btrfs_raw_test_opt(fs_info->mount_opt, FORCE_COMPRESS)))) {
+ char *compress_type = "none";
+
+ switch (fs_info->compress_type) {
+ case BTRFS_COMPRESS_ZLIB:
+ compress_type = "zlib";
+ break;
+ case BTRFS_COMPRESS_LZO:
+ compress_type = "lzo";
+ break;
+ case BTRFS_COMPRESS_ZSTD:
+ compress_type = "zstd";
+ break;
+ }
+
+ btrfs_info(fs_info, "%s %s compression, level %d",
+ btrfs_test_opt(fs_info, FORCE_COMPRESS) ? "force" : "use",
+ compress_type, fs_info->compress_level);
+ }
+
+ if (fs_info->max_inline != BTRFS_DEFAULT_MAX_INLINE)
+ btrfs_info(fs_info, "max_inline at %llu",
+ fs_info->max_inline);
+}
+
+static int btrfs_reconfigure(struct fs_context *fc)
+{
+ struct super_block *sb = fc->root->d_sb;
+ struct btrfs_fs_info *fs_info = btrfs_sb(sb);
+ struct btrfs_fs_context *ctx = fc->fs_private;
+ struct btrfs_fs_context old_ctx;
+ int ret = 0;
+
+ btrfs_info_to_ctx(fs_info, &old_ctx);
+
+ sync_filesystem(sb);
+ set_bit(BTRFS_FS_STATE_REMOUNTING, &fs_info->fs_state);
+
+ if (!check_options(fs_info, &ctx->mount_opt, fc->sb_flags))
+ return -EINVAL;
+
+ ret = btrfs_check_features(fs_info, !(fc->sb_flags & SB_RDONLY));
+ if (ret < 0)
+ return ret;
+
+ btrfs_ctx_to_info(fs_info, ctx);
+ btrfs_remount_begin(fs_info, old_ctx.mount_opt, fc->sb_flags);
+ btrfs_resize_thread_pool(fs_info, fs_info->thread_pool_size,
+ old_ctx.thread_pool_size);
+
+ if ((bool)btrfs_test_opt(fs_info, FREE_SPACE_TREE) !=
+ (bool)btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE) &&
+ (!sb_rdonly(sb) || (fc->sb_flags & SB_RDONLY))) {
+ btrfs_warn(fs_info,
+ "remount supports changing free space tree only from ro to rw");
+ /* Make sure free space cache options match the state on disk */
+ if (btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE)) {
+ btrfs_set_opt(fs_info->mount_opt, FREE_SPACE_TREE);
+ btrfs_clear_opt(fs_info->mount_opt, SPACE_CACHE);
+ }
+ if (btrfs_free_space_cache_v1_active(fs_info)) {
+ btrfs_clear_opt(fs_info->mount_opt, FREE_SPACE_TREE);
+ btrfs_set_opt(fs_info->mount_opt, SPACE_CACHE);
+ }
+ }
+
+ ret = 0;
+ if (!sb_rdonly(sb) && (fc->sb_flags & SB_RDONLY))
+ ret = btrfs_remount_ro(fs_info);
+ else if (sb_rdonly(sb) && !(fc->sb_flags & SB_RDONLY))
+ ret = btrfs_remount_rw(fs_info);
+ if (ret)
+ goto restore;
+
+ /*
+ * If we set the mask during the parameter parsing vfs would reject the
+ * remount. Here we can set the mask and the value will be updated
+ * appropriately.
+ */
+ if ((fc->sb_flags & SB_POSIXACL) != (sb->s_flags & SB_POSIXACL))
+ fc->sb_flags_mask |= SB_POSIXACL;
+
+ btrfs_emit_options(fs_info, &old_ctx);
+ wake_up_process(fs_info->transaction_kthread);
+ btrfs_remount_cleanup(fs_info, old_ctx.mount_opt);
+ btrfs_clear_oneshot_options(fs_info);
+ clear_bit(BTRFS_FS_STATE_REMOUNTING, &fs_info->fs_state);
+
+ return 0;
+restore:
+ btrfs_ctx_to_info(fs_info, &old_ctx);
+ btrfs_remount_cleanup(fs_info, old_ctx.mount_opt);
+ clear_bit(BTRFS_FS_STATE_REMOUNTING, &fs_info->fs_state);
+ return ret;
+}
+
/* Used to sort the devices by max_avail(descending sort) */
static int btrfs_cmp_device_free_bytes(const void *a, const void *b)
{
@@ -2654,6 +2853,7 @@ static void btrfs_free_fs_context(struct fs_context *fc)
static const struct fs_context_operations btrfs_fs_context_ops = {
.parse_param = btrfs_parse_param,
+ .reconfigure = btrfs_reconfigure,
.free = btrfs_free_fs_context,
};
@@ -2665,17 +2865,18 @@ static int __maybe_unused btrfs_init_fs_context(struct fs_context *fc)
if (!ctx)
return -ENOMEM;
- ctx->thread_pool_size = min_t(unsigned long, num_online_cpus() + 2, 8);
- ctx->max_inline = BTRFS_DEFAULT_MAX_INLINE;
- ctx->commit_interval = BTRFS_DEFAULT_COMMIT_INTERVAL;
- ctx->subvol_objectid = BTRFS_FS_TREE_OBJECTID;
-#ifndef CONFIG_BTRFS_FS_POSIX_ACL
- ctx->noacl = true;
-#endif
-
fc->fs_private = ctx;
fc->ops = &btrfs_fs_context_ops;
+ if (fc->purpose == FS_CONTEXT_FOR_RECONFIGURE) {
+ btrfs_info_to_ctx(btrfs_sb(fc->root->d_sb), ctx);
+ } else {
+ ctx->thread_pool_size =
+ min_t(unsigned long, num_online_cpus() + 2, 8);
+ ctx->max_inline = BTRFS_DEFAULT_MAX_INLINE;
+ ctx->commit_interval = BTRFS_DEFAULT_COMMIT_INTERVAL;
+ }
+
return 0;
}
diff --git a/fs/btrfs/zoned.c b/fs/btrfs/zoned.c
index 188378ca19c7..77b065ce3ed3 100644
--- a/fs/btrfs/zoned.c
+++ b/fs/btrfs/zoned.c
@@ -781,7 +781,7 @@ int btrfs_check_zoned_mode(struct btrfs_fs_info *fs_info)
* Check mount options here, because we might change fs_info->zoned
* from fs_info->zone_size.
*/
- ret = btrfs_check_mountopts_zoned(fs_info);
+ ret = btrfs_check_mountopts_zoned(fs_info, &fs_info->mount_opt);
if (ret)
return ret;
@@ -789,7 +789,8 @@ int btrfs_check_zoned_mode(struct btrfs_fs_info *fs_info)
return 0;
}
-int btrfs_check_mountopts_zoned(struct btrfs_fs_info *info)
+int btrfs_check_mountopts_zoned(struct btrfs_fs_info *info,
+ unsigned long *mount_opt)
{
if (!btrfs_is_zoned(info))
return 0;
@@ -798,18 +799,21 @@ int btrfs_check_mountopts_zoned(struct btrfs_fs_info *info)
* Space cache writing is not COWed. Disable that to avoid write errors
* in sequential zones.
*/
- if (btrfs_test_opt(info, SPACE_CACHE)) {
+ if (btrfs_raw_test_opt(*mount_opt, SPACE_CACHE)) {
btrfs_err(info, "zoned: space cache v1 is not supported");
return -EINVAL;
}
- if (btrfs_test_opt(info, NODATACOW)) {
+ if (btrfs_raw_test_opt(*mount_opt, NODATACOW)) {
btrfs_err(info, "zoned: NODATACOW not supported");
return -EINVAL;
}
- btrfs_clear_and_info(info, DISCARD_ASYNC,
- "zoned: async discard ignored and disabled for zoned mode");
+ if (btrfs_raw_test_opt(*mount_opt, DISCARD_ASYNC)) {
+ btrfs_info(info,
+ "zoned: async discard ignored and disabled for zoned mode");
+ btrfs_clear_opt(*mount_opt, DISCARD_ASYNC);
+ }
return 0;
}
diff --git a/fs/btrfs/zoned.h b/fs/btrfs/zoned.h
index b9cec523b778..a5ed2b147f21 100644
--- a/fs/btrfs/zoned.h
+++ b/fs/btrfs/zoned.h
@@ -45,7 +45,8 @@ int btrfs_get_dev_zone_info(struct btrfs_device *device, bool populate_cache);
void btrfs_destroy_dev_zone_info(struct btrfs_device *device);
struct btrfs_zoned_device_info *btrfs_clone_dev_zone_info(struct btrfs_device *orig_dev);
int btrfs_check_zoned_mode(struct btrfs_fs_info *fs_info);
-int btrfs_check_mountopts_zoned(struct btrfs_fs_info *info);
+int btrfs_check_mountopts_zoned(struct btrfs_fs_info *info,
+ unsigned long *mount_opt);
int btrfs_sb_log_location_bdev(struct block_device *bdev, int mirror, int rw,
u64 *bytenr_ret);
int btrfs_sb_log_location(struct btrfs_device *device, int mirror, int rw,
@@ -123,7 +124,8 @@ static inline int btrfs_check_zoned_mode(const struct btrfs_fs_info *fs_info)
return -EOPNOTSUPP;
}
-static inline int btrfs_check_mountopts_zoned(struct btrfs_fs_info *info)
+static inline int btrfs_check_mountopts_zoned(struct btrfs_fs_info *info,
+ unsigned long *mount_opt)
{
return 0;
}
--
2.41.0
^ permalink raw reply related [flat|nested] 33+ messages in thread
* Re: [PATCH v2 11/18] btrfs: add reconfigure callback for fs_context
2023-11-08 19:08 ` [PATCH v2 11/18] btrfs: add reconfigure callback for fs_context Josef Bacik
@ 2023-11-14 18:23 ` David Sterba
0 siblings, 0 replies; 33+ messages in thread
From: David Sterba @ 2023-11-14 18:23 UTC (permalink / raw)
To: Josef Bacik; +Cc: linux-btrfs, kernel-team, linux-fsdevel, brauner
On Wed, Nov 08, 2023 at 02:08:46PM -0500, Josef Bacik wrote:
> This is what is used to remount the file system with the new mount API.
> Because the mount options are parsed separately and one at a time I've
> added a helper to emit the mount options after the fact once the mount
> is configured, this matches the dmesg output for what happens with the
> old mount API.
>
> Signed-off-by: Josef Bacik <josef@toxicpanda.com>
> ---
> fs/btrfs/super.c | 243 +++++++++++++++++++++++++++++++++++++++++++----
> fs/btrfs/zoned.c | 16 ++--
> fs/btrfs/zoned.h | 6 +-
> 3 files changed, 236 insertions(+), 29 deletions(-)
>
> diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
> index facea4632a8d..b5067cf637a2 100644
> --- a/fs/btrfs/super.c
> +++ b/fs/btrfs/super.c
> @@ -734,10 +734,11 @@ static int btrfs_parse_param(struct fs_context *fc,
> return 0;
> }
>
> -static bool check_ro_option(struct btrfs_fs_info *fs_info, unsigned long opt,
> +static bool check_ro_option(struct btrfs_fs_info *fs_info,
> + unsigned long mount_opt, unsigned long opt,
> const char *opt_name)
> {
> - if (fs_info->mount_opt & opt) {
> + if (mount_opt & opt) {
> btrfs_err(fs_info, "%s must be used with ro mount option",
> opt_name);
> return true;
> @@ -745,33 +746,34 @@ static bool check_ro_option(struct btrfs_fs_info *fs_info, unsigned long opt,
> return false;
> }
>
> -static bool check_options(struct btrfs_fs_info *info, unsigned long flags)
> +static bool check_options(struct btrfs_fs_info *info, unsigned long *mount_opt,
> + unsigned long flags)
> {
> if (!(flags & SB_RDONLY) &&
> - (check_ro_option(info, BTRFS_MOUNT_NOLOGREPLAY, "nologreplay") ||
> - check_ro_option(info, BTRFS_MOUNT_IGNOREBADROOTS, "ignorebadroots") ||
> - check_ro_option(info, BTRFS_MOUNT_IGNOREDATACSUMS, "ignoredatacsums")))
> + (check_ro_option(info, *mount_opt, BTRFS_MOUNT_NOLOGREPLAY, "nologreplay") ||
> + check_ro_option(info, *mount_opt, BTRFS_MOUNT_IGNOREBADROOTS, "ignorebadroots") ||
> + check_ro_option(info, *mount_opt, BTRFS_MOUNT_IGNOREDATACSUMS, "ignoredatacsums")))
> return false;
>
> if (btrfs_fs_compat_ro(info, FREE_SPACE_TREE) &&
> - !btrfs_test_opt(info, FREE_SPACE_TREE) &&
> - !btrfs_test_opt(info, CLEAR_CACHE)) {
> + !btrfs_raw_test_opt(*mount_opt, FREE_SPACE_TREE) &&
> + !btrfs_raw_test_opt(*mount_opt, CLEAR_CACHE)) {
> btrfs_err(info, "cannot disable free space tree");
> return false;
> }
> if (btrfs_fs_compat_ro(info, BLOCK_GROUP_TREE) &&
> - !btrfs_test_opt(info, FREE_SPACE_TREE)) {
> + !btrfs_raw_test_opt(*mount_opt, FREE_SPACE_TREE)) {
> btrfs_err(info, "cannot disable free space tree with block-group-tree feature");
> return false;
> }
>
> - if (btrfs_check_mountopts_zoned(info))
> + if (btrfs_check_mountopts_zoned(info, mount_opt))
> return false;
>
> if (!test_bit(BTRFS_FS_STATE_REMOUNTING, &info->fs_state)) {
> - if (btrfs_test_opt(info, SPACE_CACHE))
> + if (btrfs_raw_test_opt(*mount_opt, SPACE_CACHE))
> btrfs_info(info, "disk space caching is enabled");
> - if (btrfs_test_opt(info, FREE_SPACE_TREE))
> + if (btrfs_raw_test_opt(*mount_opt, FREE_SPACE_TREE))
> btrfs_info(info, "using free space tree");
> }
>
> @@ -1337,7 +1339,7 @@ int btrfs_parse_options(struct btrfs_fs_info *info, char *options,
> }
> }
> out:
> - if (!ret && !check_options(info, new_flags))
> + if (!ret && !check_options(info, &info->mount_opt, new_flags))
> ret = -EINVAL;
> return ret;
> }
> @@ -2377,6 +2379,203 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data)
> return ret;
> }
>
> +static void btrfs_ctx_to_info(struct btrfs_fs_info *fs_info,
> + struct btrfs_fs_context *ctx)
> +{
> + fs_info->max_inline = ctx->max_inline;
> + fs_info->commit_interval = ctx->commit_interval;
> + fs_info->metadata_ratio = ctx->metadata_ratio;
> + fs_info->thread_pool_size = ctx->thread_pool_size;
> + fs_info->mount_opt = ctx->mount_opt;
> + fs_info->compress_type = ctx->compress_type;
> + fs_info->compress_level = ctx->compress_level;
> +}
> +
> +static void btrfs_info_to_ctx(struct btrfs_fs_info *fs_info,
> + struct btrfs_fs_context *ctx)
> +{
> + ctx->max_inline = fs_info->max_inline;
> + ctx->commit_interval = fs_info->commit_interval;
> + ctx->metadata_ratio = fs_info->metadata_ratio;
> + ctx->thread_pool_size = fs_info->thread_pool_size;
> + ctx->mount_opt = fs_info->mount_opt;
> + ctx->compress_type = fs_info->compress_type;
> + ctx->compress_level = fs_info->compress_level;
> +}
> +
> +#define btrfs_info_if_set(fs_info, old_ctx, opt, fmt, args...) \
> +do { \
> + if ((!old_ctx || !btrfs_raw_test_opt(old_ctx->mount_opt, opt)) && \
> + btrfs_raw_test_opt(fs_info->mount_opt, opt)) \
> + btrfs_info(fs_info, fmt, ##args); \
> +} while (0)
> +
> +#define btrfs_info_if_unset(fs_info, old_ctx, opt, fmt, args...) \
> +do { \
> + if ((old_ctx && btrfs_raw_test_opt(old_ctx->mount_opt, opt)) && \
> + !btrfs_raw_test_opt(fs_info->mount_opt, opt)) \
> + btrfs_info(fs_info, fmt, ##args); \
> +} while (0)
> +
> +static void btrfs_emit_options(struct btrfs_fs_info *fs_info,
> + struct btrfs_fs_context *old_ctx)
> +{
> + btrfs_info_if_set(fs_info, old_ctx, NODATASUM, "setting nodatasum");
> + btrfs_info_if_set(fs_info, old_ctx, DEGRADED,
> + "allowing degraded mounts");
> + btrfs_info_if_set(fs_info, old_ctx, NODATASUM, "setting nodatasum");
> + btrfs_info_if_set(fs_info, old_ctx, SSD, "enabling ssd optimizations");
> + btrfs_info_if_set(fs_info, old_ctx, SSD_SPREAD,
> + "using spread ssd allocation scheme");
> + btrfs_info_if_set(fs_info, old_ctx, NOBARRIER, "turning off barriers");
> + btrfs_info_if_set(fs_info, old_ctx, NOTREELOG, "disabling tree log");
> + btrfs_info_if_set(fs_info, old_ctx, NOLOGREPLAY,
> + "disabling log replay at mount time");
> + btrfs_info_if_set(fs_info, old_ctx, FLUSHONCOMMIT,
> + "turning on flush-on-commit");
> + btrfs_info_if_set(fs_info, old_ctx, DISCARD_SYNC,
> + "turning on sync discard");
> + btrfs_info_if_set(fs_info, old_ctx, DISCARD_ASYNC,
> + "turning on async discard");
> + btrfs_info_if_set(fs_info, old_ctx, FREE_SPACE_TREE,
> + "enabling free space tree");
> + btrfs_info_if_set(fs_info, old_ctx, SPACE_CACHE,
> + "enabling disk space caching");
> + btrfs_info_if_set(fs_info, old_ctx, CLEAR_CACHE,
> + "force clearing of disk cache");
> + btrfs_info_if_set(fs_info, old_ctx, AUTO_DEFRAG,
> + "enabling auto defrag");
> + btrfs_info_if_set(fs_info, old_ctx, FRAGMENT_DATA,
> + "fragmenting data");
> + btrfs_info_if_set(fs_info, old_ctx, FRAGMENT_METADATA,
> + "fragmenting metadata");
> + btrfs_info_if_set(fs_info, old_ctx, REF_VERIFY,
> + "doing ref verification");
> + btrfs_info_if_set(fs_info, old_ctx, USEBACKUPROOT,
> + "trying to use backup root at mount time");
> + btrfs_info_if_set(fs_info, old_ctx, IGNOREBADROOTS,
> + "ignoring bad roots");
> + btrfs_info_if_set(fs_info, old_ctx, IGNOREDATACSUMS,
> + "ignoring data csums");
I think we can format this on >80 char lines, it would look better IMHO.
If fs_info and old_ctx are named shorter then more of the string fits.
> + btrfs_info_if_unset(fs_info, old_ctx, NODATACOW, "setting datacow");
> + btrfs_info_if_unset(fs_info, old_ctx, SSD, "not using ssd optimizations");
> + btrfs_info_if_unset(fs_info, old_ctx, SSD_SPREAD,
> + "not using spread ssd allocation scheme");
> + btrfs_info_if_unset(fs_info, old_ctx, NOBARRIER,
> + "turning off barriers");
> + btrfs_info_if_unset(fs_info, old_ctx, NOTREELOG, "enabling tree log");
> + btrfs_info_if_unset(fs_info, old_ctx, SPACE_CACHE,
> + "disabling disk space caching");
> + btrfs_info_if_unset(fs_info, old_ctx, FREE_SPACE_TREE,
> + "disabling free space tree");
> + btrfs_info_if_unset(fs_info, old_ctx, AUTO_DEFRAG,
> + "disabling auto defrag");
> + btrfs_info_if_unset(fs_info, old_ctx, COMPRESS,
> + "use no compression");
Same
> +
> + /* Did the compression settings change? */
> + if (btrfs_test_opt(fs_info, COMPRESS) &&
> + (!old_ctx ||
> + old_ctx->compress_type != fs_info->compress_type ||
> + old_ctx->compress_level != fs_info->compress_level ||
> + (!btrfs_raw_test_opt(old_ctx->mount_opt, FORCE_COMPRESS) &&
> + btrfs_raw_test_opt(fs_info->mount_opt, FORCE_COMPRESS)))) {
> + char *compress_type = "none";
> +
> + switch (fs_info->compress_type) {
> + case BTRFS_COMPRESS_ZLIB:
> + compress_type = "zlib";
> + break;
> + case BTRFS_COMPRESS_LZO:
> + compress_type = "lzo";
> + break;
> + case BTRFS_COMPRESS_ZSTD:
> + compress_type = "zstd";
> + break;
> + }
We have btrfs_compress_type2str()
> +
> + btrfs_info(fs_info, "%s %s compression, level %d",
> + btrfs_test_opt(fs_info, FORCE_COMPRESS) ? "force" : "use",
> + compress_type, fs_info->compress_level);
> + }
> +
> + if (fs_info->max_inline != BTRFS_DEFAULT_MAX_INLINE)
> + btrfs_info(fs_info, "max_inline at %llu",
> + fs_info->max_inline);
> +}
^ permalink raw reply [flat|nested] 33+ messages in thread
* [PATCH v2 12/18] btrfs: add get_tree callback for new mount API
2023-11-08 19:08 [PATCH v2 00/18] btrfs: convert to the new mount API Josef Bacik
` (10 preceding siblings ...)
2023-11-08 19:08 ` [PATCH v2 11/18] btrfs: add reconfigure callback for fs_context Josef Bacik
@ 2023-11-08 19:08 ` Josef Bacik
2023-11-14 18:35 ` David Sterba
2023-11-08 19:08 ` [PATCH v2 13/18] btrfs: handle the ro->rw transition for mounting different subovls Josef Bacik
` (8 subsequent siblings)
20 siblings, 1 reply; 33+ messages in thread
From: Josef Bacik @ 2023-11-08 19:08 UTC (permalink / raw)
To: linux-btrfs, kernel-team, linux-fsdevel, brauner
This is the actual mounting callback for the new mount API. Implement
this using our current fill super as a guideline, making the appropriate
adjustments for the new mount API.
Our old mount operation had two fs_types, one to handle the actual
opening, and the one that we called to handle the actual opening and
then did the subvol lookup for returning the actual root dentry. This
is mirrored here, but simply with different behaviors for ->get_tree.
We use the existence of ->s_fs_info to tell which part we're in. The
initial call allocates the fs_info, then call mount_fc() with a
duplicated fc to do the actual open_ctree part. Then we take that
vfsmount and use it to look up our subvolume that we're mounting and
return that as our s_root. This idea was taken from Christians attempt
to convert us to the new mount api.
References: https://lore.kernel.org/all/20230626-fs-btrfs-mount-api-v1-2-045e9735a00b@kernel.org/
Reviewed-by: Christian Brauner <brauner@kernel.org>
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
fs/btrfs/super.c | 210 ++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 206 insertions(+), 4 deletions(-)
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index b5067cf637a2..4ace42e08bff 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -95,6 +95,7 @@ struct btrfs_fs_context {
unsigned long mount_opt;
unsigned long compress_type:4;
unsigned int compress_level;
+ refcount_t refs;
};
enum {
@@ -2833,6 +2834,181 @@ static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf)
return 0;
}
+static int btrfs_fc_test_super(struct super_block *s, struct fs_context *fc)
+{
+ 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;
+}
+
+static int btrfs_get_tree_super(struct fs_context *fc)
+{
+ struct btrfs_fs_info *fs_info = fc->s_fs_info;
+ struct btrfs_fs_context *ctx = fc->fs_private;
+ struct btrfs_fs_devices *fs_devices = NULL;
+ struct block_device *bdev;
+ struct btrfs_device *device;
+ struct super_block *s;
+ blk_mode_t mode = sb_open_mode(fc->sb_flags);
+ int ret;
+
+ btrfs_ctx_to_info(fs_info, ctx);
+ mutex_lock(&uuid_mutex);
+
+ /*
+ * With 'true' passed to btrfs_scan_one_device() (mount time) we expect
+ * either a valid device or an error.
+ */
+ device = btrfs_scan_one_device(fc->source, mode, true);
+ ASSERT(device != NULL);
+ if (IS_ERR(device)) {
+ mutex_unlock(&uuid_mutex);
+ return PTR_ERR(device);
+ }
+
+ fs_devices = device->fs_devices;
+ fs_info->fs_devices = fs_devices;
+
+ ret = btrfs_open_devices(fs_devices, mode, &btrfs_fs_type);
+ mutex_unlock(&uuid_mutex);
+ if (ret)
+ return ret;
+
+ if (!(fc->sb_flags & SB_RDONLY) && fs_devices->rw_devices == 0) {
+ ret = -EACCES;
+ goto error;
+ }
+
+ bdev = fs_devices->latest_dev->bdev;
+
+ /*
+ * If successful, this will transfer the fs_info into the super block,
+ * and fc->s_fs_info will be NULL. However if there's an existing
+ * super, we'll still have fc->s_fs_info populated. If we error
+ * completely out it'll be cleaned up when we drop the fs_context,
+ * otherwise it's tied to the lifetime of the super_block.
+ *
+ * Adding this comment because I was horribly confused about the error
+ * handling from here on out.
+ */
+ s = sget_fc(fc, btrfs_fc_test_super, set_anon_super_fc);
+ if (IS_ERR(s)) {
+ ret = PTR_ERR(s);
+ goto error;
+ }
+
+ if (s->s_root) {
+ btrfs_close_devices(fs_devices);
+ if ((fc->sb_flags ^ s->s_flags) & SB_RDONLY)
+ ret = -EBUSY;
+ } else {
+ snprintf(s->s_id, sizeof(s->s_id), "%pg", bdev);
+ shrinker_debugfs_rename(&s->s_shrink, "sb-btrfs:%s", s->s_id);
+ btrfs_sb(s)->bdev_holder = &btrfs_fs_type;
+ ret = btrfs_fill_super(s, fs_devices, NULL);
+ }
+
+ if (ret) {
+ deactivate_locked_super(s);
+ return ret;
+ }
+
+ fc->root = dget(s->s_root);
+ return 0;
+
+error:
+ btrfs_close_devices(fs_devices);
+ return ret;
+}
+
+static int btrfs_get_tree_subvol(struct fs_context *fc)
+{
+ struct btrfs_fs_info *fs_info = NULL;
+ struct btrfs_fs_context *ctx = fc->fs_private;
+ struct fs_context *dup_fc;
+ struct dentry *dentry;
+ struct vfsmount *mnt;
+
+ /*
+ * 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
+ * then open_ctree will properly initialize the file system specific
+ * settings later. btrfs_init_fs_info initializes the static elements
+ * of the fs_info (locks and such) to make cleanup easier if we find a
+ * superblock with our given fs_devices later on at sget() time.
+ */
+ fs_info = kvzalloc(sizeof(struct btrfs_fs_info), GFP_KERNEL);
+ if (!fs_info)
+ return -ENOMEM;
+
+ fs_info->super_copy = kzalloc(BTRFS_SUPER_INFO_SIZE, GFP_KERNEL);
+ fs_info->super_for_commit = kzalloc(BTRFS_SUPER_INFO_SIZE, GFP_KERNEL);
+ if (!fs_info->super_copy || !fs_info->super_for_commit) {
+ btrfs_free_fs_info(fs_info);
+ return -ENOMEM;
+ }
+ btrfs_init_fs_info(fs_info);
+
+ dup_fc = vfs_dup_fs_context(fc);
+ if (IS_ERR(dup_fc)) {
+ btrfs_free_fs_info(fs_info);
+ return PTR_ERR(dup_fc);
+ }
+
+ /*
+ * When we do the sget_fc this gets transferred to the sb, so we only
+ * need to set it on the dup_fc as this is what creates the super block.
+ */
+ dup_fc->s_fs_info = fs_info;
+
+ /*
+ * We'll do the security settings in our btrfs_get_tree_super() mount
+ * loop, they were duplicated into dup_fc, we can drop the originals
+ * here.
+ */
+ security_free_mnt_opts(&fc->security);
+ fc->security = NULL;
+
+ mnt = fc_mount(dup_fc);
+ put_fs_context(dup_fc);
+ if (IS_ERR(mnt))
+ return PTR_ERR(mnt);
+
+ /*
+ * This free's ->subvol_name, because if it isn't set we have to
+ * allocate a buffer to hold the subvol_name, so we just drop our
+ * reference to it here.
+ */
+ dentry = mount_subvol(ctx->subvol_name, ctx->subvol_objectid, mnt);
+ ctx->subvol_name = NULL;
+ if (IS_ERR(dentry))
+ return PTR_ERR(dentry);
+
+ fc->root = dentry;
+ return 0;
+}
+
+static int btrfs_get_tree(struct fs_context *fc)
+{
+ /*
+ * Since we use mount_subtree to mount the default/specified subvol, we
+ * have to do mounts in two steps.
+ *
+ * First pass through we call btrfs_get_tree_subvol(), this is just a
+ * wrapper around fc_mount() to call back into here again, and this time
+ * we'll call btrfs_get_tree_super(). This will do the open_ctree() and
+ * everything to open the devices and file system. Then we return back
+ * with a fully constructed vfsmount in btrfs_get_tree_subvol(), and
+ * from there we can do our mount_subvol() call, which will lookup
+ * whichever subvol we're mounting and setup this fc with the
+ * appropriate dentry for the subvol.
+ */
+ if (fc->s_fs_info)
+ return btrfs_get_tree_super(fc);
+ return btrfs_get_tree_subvol(fc);
+}
+
static void btrfs_kill_super(struct super_block *sb)
{
struct btrfs_fs_info *fs_info = btrfs_sb(sb);
@@ -2843,17 +3019,42 @@ static void btrfs_kill_super(struct super_block *sb)
static void btrfs_free_fs_context(struct fs_context *fc)
{
struct btrfs_fs_context *ctx = fc->fs_private;
+ struct btrfs_fs_info *fs_info = fc->s_fs_info;
- if (!ctx)
- return;
+ if (fs_info)
+ btrfs_free_fs_info(fs_info);
- kfree(ctx->subvol_name);
- kfree(ctx);
+ if (ctx && refcount_dec_and_test(&ctx->refs)) {
+ kfree(ctx->subvol_name);
+ kfree(ctx);
+ }
+}
+
+static int btrfs_dup_fs_context(struct fs_context *fc,
+ struct fs_context *src_fc)
+{
+ struct btrfs_fs_context *ctx = src_fc->fs_private;
+
+ /*
+ * Give a ref to our ctx to this dup, as we want to keep it around for
+ * our original fc so we can have the subvolume name or objectid.
+ *
+ * We unset ->source in the original fc because the dup needs it for
+ * mounting, and then once we free the dup it'll free ->source, so we
+ * need to make sure we're only pointing to it in one fc.
+ */
+ refcount_inc(&ctx->refs);
+ fc->fs_private = ctx;
+ fc->source = src_fc->source;
+ src_fc->source = NULL;
+ return 0;
}
static const struct fs_context_operations btrfs_fs_context_ops = {
.parse_param = btrfs_parse_param,
.reconfigure = btrfs_reconfigure,
+ .get_tree = btrfs_get_tree,
+ .dup = btrfs_dup_fs_context,
.free = btrfs_free_fs_context,
};
@@ -2865,6 +3066,7 @@ static int __maybe_unused btrfs_init_fs_context(struct fs_context *fc)
if (!ctx)
return -ENOMEM;
+ refcount_set(&ctx->refs, 1);
fc->fs_private = ctx;
fc->ops = &btrfs_fs_context_ops;
--
2.41.0
^ permalink raw reply related [flat|nested] 33+ messages in thread
* Re: [PATCH v2 12/18] btrfs: add get_tree callback for new mount API
2023-11-08 19:08 ` [PATCH v2 12/18] btrfs: add get_tree callback for new mount API Josef Bacik
@ 2023-11-14 18:35 ` David Sterba
0 siblings, 0 replies; 33+ messages in thread
From: David Sterba @ 2023-11-14 18:35 UTC (permalink / raw)
To: Josef Bacik; +Cc: linux-btrfs, kernel-team, linux-fsdevel, brauner
On Wed, Nov 08, 2023 at 02:08:47PM -0500, Josef Bacik wrote:
> This is the actual mounting callback for the new mount API. Implement
> this using our current fill super as a guideline, making the appropriate
> adjustments for the new mount API.
>
> Our old mount operation had two fs_types, one to handle the actual
> opening, and the one that we called to handle the actual opening and
> then did the subvol lookup for returning the actual root dentry. This
> is mirrored here, but simply with different behaviors for ->get_tree.
> We use the existence of ->s_fs_info to tell which part we're in. The
> initial call allocates the fs_info, then call mount_fc() with a
> duplicated fc to do the actual open_ctree part. Then we take that
> vfsmount and use it to look up our subvolume that we're mounting and
> return that as our s_root. This idea was taken from Christians attempt
> to convert us to the new mount api.
>
> References: https://lore.kernel.org/all/20230626-fs-btrfs-mount-api-v1-2-045e9735a00b@kernel.org/
> Reviewed-by: Christian Brauner <brauner@kernel.org>
> Signed-off-by: Josef Bacik <josef@toxicpanda.com>
> ---
> fs/btrfs/super.c | 210 ++++++++++++++++++++++++++++++++++++++++++++++-
> 1 file changed, 206 insertions(+), 4 deletions(-)
>
> diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
> index b5067cf637a2..4ace42e08bff 100644
> --- a/fs/btrfs/super.c
> +++ b/fs/btrfs/super.c
> @@ -95,6 +95,7 @@ struct btrfs_fs_context {
> unsigned long mount_opt;
> unsigned long compress_type:4;
> unsigned int compress_level;
> + refcount_t refs;
> };
>
> enum {
> @@ -2833,6 +2834,181 @@ static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf)
> return 0;
> }
>
> +static int btrfs_fc_test_super(struct super_block *s, struct fs_context *fc)
> +{
> + struct btrfs_fs_info *p = fc->s_fs_info;
That's a confusing variable name
> + struct btrfs_fs_info *fs_info = btrfs_sb(s);
> +
> + return fs_info->fs_devices == p->fs_devices;
> +}
> +
> +static int btrfs_get_tree_super(struct fs_context *fc)
> +{
> + struct btrfs_fs_info *fs_info = fc->s_fs_info;
> + struct btrfs_fs_context *ctx = fc->fs_private;
> + struct btrfs_fs_devices *fs_devices = NULL;
> + struct block_device *bdev;
> + struct btrfs_device *device;
> + struct super_block *s;
Please use 'sb' for super block.
> + blk_mode_t mode = sb_open_mode(fc->sb_flags);
> + int ret;
> +
> + btrfs_ctx_to_info(fs_info, ctx);
> + mutex_lock(&uuid_mutex);
> +
> + /*
> + * With 'true' passed to btrfs_scan_one_device() (mount time) we expect
> + * either a valid device or an error.
> + */
> + device = btrfs_scan_one_device(fc->source, mode, true);
> + ASSERT(device != NULL);
> + if (IS_ERR(device)) {
> + mutex_unlock(&uuid_mutex);
> + return PTR_ERR(device);
> + }
> +
> + fs_devices = device->fs_devices;
> + fs_info->fs_devices = fs_devices;
> +
> + ret = btrfs_open_devices(fs_devices, mode, &btrfs_fs_type);
> + mutex_unlock(&uuid_mutex);
Regarding the previous comments about mount and scanning, here the
device is scanned and opened in one go, so all the other devices are
expected to be scanned independently from before.
This is not a prolbem, although it allows to something race in between
the mount option scanning and here and call 'forget' on the devices.
We've seen udev to race with mkfs to register the device, which is not a
problem here, but if there's something calling 'forget' automatically
then it will be.
Since systemd started to mess with background mounts and scans we can
never ber sure what's going to happen when triggered by system events.
> + if (ret)
> + return ret;
> +
> + if (!(fc->sb_flags & SB_RDONLY) && fs_devices->rw_devices == 0) {
> + ret = -EACCES;
> + goto error;
> + }
> +
> + bdev = fs_devices->latest_dev->bdev;
> +
> + /*
> + * If successful, this will transfer the fs_info into the super block,
> + * and fc->s_fs_info will be NULL. However if there's an existing
> + * super, we'll still have fc->s_fs_info populated. If we error
> + * completely out it'll be cleaned up when we drop the fs_context,
> + * otherwise it's tied to the lifetime of the super_block.
> + *
> + * Adding this comment because I was horribly confused about the error
> + * handling from here on out.
The last sentence does not need to be there, that we add comments to
avoid confusion is kind of implicit.
> + */
> + s = sget_fc(fc, btrfs_fc_test_super, set_anon_super_fc);
> + if (IS_ERR(s)) {
> + ret = PTR_ERR(s);
> + goto error;
> + }
> +
> + if (s->s_root) {
> + btrfs_close_devices(fs_devices);
> + if ((fc->sb_flags ^ s->s_flags) & SB_RDONLY)
> + ret = -EBUSY;
> + } else {
> + snprintf(s->s_id, sizeof(s->s_id), "%pg", bdev);
> + shrinker_debugfs_rename(&s->s_shrink, "sb-btrfs:%s", s->s_id);
In 6.7-rc1 there's a change do allocate shrinkers dynamically so this
will need to be adjusted
shrinker_debugfs_rename(s->s_shrink, ...
> + btrfs_sb(s)->bdev_holder = &btrfs_fs_type;
> + ret = btrfs_fill_super(s, fs_devices, NULL);
> + }
> +
> + if (ret) {
> + deactivate_locked_super(s);
> + return ret;
> + }
> +
> + fc->root = dget(s->s_root);
> + return 0;
> +
> +error:
> + btrfs_close_devices(fs_devices);
> + return ret;
> +}
^ permalink raw reply [flat|nested] 33+ messages in thread
* [PATCH v2 13/18] btrfs: handle the ro->rw transition for mounting different subovls
2023-11-08 19:08 [PATCH v2 00/18] btrfs: convert to the new mount API Josef Bacik
` (11 preceding siblings ...)
2023-11-08 19:08 ` [PATCH v2 12/18] btrfs: add get_tree callback for new mount API Josef Bacik
@ 2023-11-08 19:08 ` Josef Bacik
2023-11-08 19:08 ` [PATCH v2 14/18] btrfs: switch to the new mount API Josef Bacik
` (7 subsequent siblings)
20 siblings, 0 replies; 33+ messages in thread
From: Josef Bacik @ 2023-11-08 19:08 UTC (permalink / raw)
To: linux-btrfs, kernel-team, linux-fsdevel, brauner
This is an oddity that we've carried around since 0723a0473fb4 ("btrfs:
allow mounting btrfs subvolumes with different ro/rw options") where
we'll under the covers flip the file system to RW if you're mixing and
matching ro/rw options with different subvol mounts. The first mount is
what the super gets setup as, so we'd handle this by remount the super
as rw under the covers to facilitate this behavior.
With the new mount API we can't really allow this, because user space
has the ability to specify the super block settings, and the mount
settings. So if the user explicitly set the super block as read only,
and then tried to mount a rw mount with the super block we'll reject
this. However the old API was less descriptive and thus we allowed this
kind of behavior.
This patch preserves this behavior for the old api calls. This is
inspired by Christians work, and includes one of his comments, and thus
is included in the link below.
Link: https://lore.kernel.org/all/20230626-fs-btrfs-mount-api-v1-2-045e9735a00b@kernel.org/
Reviewed-by: Christian Brauner <brauner@kernel.org>
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
fs/btrfs/super.c | 133 ++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 132 insertions(+), 1 deletion(-)
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index 4ace42e08bff..7a49a61fc50a 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -2513,13 +2513,15 @@ static int btrfs_reconfigure(struct fs_context *fc)
struct btrfs_fs_context *ctx = fc->fs_private;
struct btrfs_fs_context old_ctx;
int ret = 0;
+ bool mount_reconfigure = (fc->s_fs_info != NULL);
btrfs_info_to_ctx(fs_info, &old_ctx);
sync_filesystem(sb);
set_bit(BTRFS_FS_STATE_REMOUNTING, &fs_info->fs_state);
- if (!check_options(fs_info, &ctx->mount_opt, fc->sb_flags))
+ if (!mount_reconfigure &&
+ !check_options(fs_info, &ctx->mount_opt, fc->sb_flags))
return -EINVAL;
ret = btrfs_check_features(fs_info, !(fc->sb_flags & SB_RDONLY));
@@ -2922,6 +2924,133 @@ static int btrfs_get_tree_super(struct fs_context *fc)
return ret;
}
+/*
+ * Christian wrote this long comment about what we're doing here, preserving it
+ * so the history of this change is preserved.
+ *
+ * Ever since commit 0723a0473fb4 ("btrfs: allow * mounting btrfs subvolumes
+ * with different ro/rw * options") the following works:
+ *
+ * (i) mount /dev/sda3 -o subvol=foo,ro /mnt/foo
+ * (ii) mount /dev/sda3 -o subvol=bar,rw /mnt/bar
+ *
+ * which looks nice and innocent but is actually pretty * intricate and
+ * deserves a long comment.
+ *
+ * On another filesystem a subvolume mount is close to * something like:
+ *
+ * (iii) # create rw superblock + initial mount
+ * mount -t xfs /dev/sdb /opt/
+ *
+ * # create ro bind mount
+ * mount --bind -o ro /opt/foo /mnt/foo
+ *
+ * # unmount initial mount
+ * umount /opt
+ *
+ * Of course, there's some special subvolume sauce and there's the fact that the
+ * sb->s_root dentry is really swapped after mount_subtree(). But conceptually
+ * it's very close and will help us understand the issue.
+ *
+ * The old mount api didn't cleanly distinguish between a mount being made ro
+ * and a superblock being made ro. The only way to change the ro state of
+ * either object was by passing ms_rdonly. If a new mount was created via
+ * mount(2) such as:
+ *
+ * mount("/dev/sdb", "/mnt", "xfs", ms_rdonly, null);
+ *
+ * the MS_RDONLY flag being specified had two effects:
+ *
+ * (1) MNT_READONLY was raised -> the resulting mount got
+ * @mnt->mnt_flags |= MNT_READONLY raised.
+ *
+ * (2) MS_RDONLY was passed to the filesystem's mount method and the filesystems
+ * made the superblock ro. Note, how SB_RDONLY has the same value as
+ * ms_rdonly and is raised whenever MS_RDONLY is passed through mount(2).
+ *
+ * Creating a subtree mount via (iii) ends up leaving a rw superblock with a
+ * subtree mounted ro.
+ *
+ * But consider the effect on the old mount api on btrfs subvolume mounting
+ * which combines the distinct step in (iii) into a a single step.
+ *
+ * By issuing (i) both the mount and the superblock are turned ro. Now when (ii)
+ * is issued the superblock is ro and thus even if the mount created for (ii) is
+ * rw it wouldn't help. Hence, btrfs needed to transition the superblock from ro
+ * to rw for (ii) which it did using an internal remount call (a bold
+ * choice...).
+ *
+ * IOW, subvolume mounting was inherently messy due to the ambiguity of
+ * MS_RDONLY in mount(2). Note, this ambiguity has mount(8) always translate
+ * "ro" to MS_RDONLY. IOW, in both (i) and (ii) "ro" becomes MS_RDONLY when
+ * passed by mount(8) to mount(2).
+ *
+ * Enter the new mount api. the new mount api disambiguates making a mount ro
+ * and making a superblock ro.
+ *
+ * (3) To turn a mount ro the MOUNT_ATTR_ONLY flag can be used with either
+ * fsmount() or mount_setattr() this is a pure vfs level change for a
+ * specific mount or mount tree that is never seen by the filesystem itself.
+ *
+ * (4) To turn a superblock ro the "ro" flag must be used with
+ * fsconfig(FSCONFIG_SET_FLAG, "ro"). This option is seen by the filesytem
+ * in fc->sb_flags.
+ *
+ * This disambiguation has rather positive consequences. Mounting a subvolume
+ * ro will not also turn the superblock ro. Only the mount for the subvolume
+ * will become ro.
+ *
+ * So, if the superblock creation request comes from the new mount api the
+ * caller must've explicitly done:
+ *
+ * fsconfig(FSCONFIG_SET_FLAG, "ro")
+ * fsmount/mount_setattr(MOUNT_ATTR_RDONLY)
+ *
+ * IOW, at some point the caller must have explicitly turned the whole
+ * superblock ro and we shouldn't just undo it like we did for the old mount
+ * api. In any case, it lets us avoid this nasty hack in the new mount api.
+ *
+ * Consequently, the remounting hack must only be used for requests originating
+ * from the old mount api and should be marked for full deprecation so it can be
+ * turned off in a couple of years.
+ *
+ * The new mount api has no reason to support this hack.
+ */
+static struct vfsmount *btrfs_reconfigure_for_mount(struct fs_context *fc)
+{
+ struct vfsmount *mnt;
+ int ret;
+ bool ro2rw = !(fc->sb_flags & SB_RDONLY);
+
+ /*
+ * We got an EBUSY because our SB_RDONLY flag didn't match the existing
+ * super block, so invert our setting here and re-try the mount so we
+ * can get our vfsmount.
+ */
+ if (ro2rw)
+ fc->sb_flags |= SB_RDONLY;
+ else
+ fc->sb_flags &= ~SB_RDONLY;
+
+ mnt = fc_mount(fc);
+ if (IS_ERR(mnt))
+ return mnt;
+
+ if (!fc->oldapi || !ro2rw)
+ return mnt;
+
+ /* We need to convert to rw, call reconfigure */
+ fc->sb_flags &= ~SB_RDONLY;
+ down_write(&mnt->mnt_sb->s_umount);
+ ret = btrfs_reconfigure(fc);
+ up_write(&mnt->mnt_sb->s_umount);
+ if (ret) {
+ mntput(mnt);
+ return ERR_PTR(ret);
+ }
+ return mnt;
+}
+
static int btrfs_get_tree_subvol(struct fs_context *fc)
{
struct btrfs_fs_info *fs_info = NULL;
@@ -2971,6 +3100,8 @@ static int btrfs_get_tree_subvol(struct fs_context *fc)
fc->security = NULL;
mnt = fc_mount(dup_fc);
+ if (PTR_ERR_OR_ZERO(mnt) == -EBUSY)
+ mnt = btrfs_reconfigure_for_mount(dup_fc);
put_fs_context(dup_fc);
if (IS_ERR(mnt))
return PTR_ERR(mnt);
--
2.41.0
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCH v2 14/18] btrfs: switch to the new mount API
2023-11-08 19:08 [PATCH v2 00/18] btrfs: convert to the new mount API Josef Bacik
` (12 preceding siblings ...)
2023-11-08 19:08 ` [PATCH v2 13/18] btrfs: handle the ro->rw transition for mounting different subovls Josef Bacik
@ 2023-11-08 19:08 ` Josef Bacik
2023-11-08 19:08 ` [PATCH v2 15/18] btrfs: move the device specific mount options to super.c Josef Bacik
` (6 subsequent siblings)
20 siblings, 0 replies; 33+ messages in thread
From: Josef Bacik @ 2023-11-08 19:08 UTC (permalink / raw)
To: linux-btrfs, kernel-team, linux-fsdevel, brauner
Now that we have all of the parts in place to use the new mount API,
switch our fs_type to use the new callbacks.
There are a few things that have to be done at the same time because of
the order of operations changes that come along with the new mount API.
These must be done in the same patch otherwise things will go wrong.
1. Export and use btrfs_check_options in open_ctree(). This is because
the options are done ahead of time, and we need to check them once we
have the feature flags loaded.
2. Update the free space cache settings. Since we're coming in with the
options already set we need to make sure we don't undo what the user
has asked for.
3. Set our sb_flags at init_fs_context time, the fs_context stuff is
trying to manage the sb_flagss itself, so move that into
init_fs_context and out of the fill super part.
Additionally I've marked the unused functions with __maybe_unused and
will remove them in a future patch.
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
fs/btrfs/disk-io.c | 5 +--
fs/btrfs/super.c | 88 ++++++++++++++++++++++++++--------------------
fs/btrfs/super.h | 2 ++
3 files changed, 54 insertions(+), 41 deletions(-)
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index c70e507a28d0..ce861f4baf47 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -3295,9 +3295,10 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device
*/
btrfs_set_free_space_cache_settings(fs_info);
- ret = btrfs_parse_options(fs_info, options, sb->s_flags);
- if (ret)
+ if (!btrfs_check_options(fs_info, &fs_info->mount_opt, sb->s_flags)) {
+ ret = -EINVAL;
goto fail_alloc;
+ }
ret = btrfs_check_features(fs_info, !sb_rdonly(sb));
if (ret < 0)
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index 7a49a61fc50a..4ce07d255497 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -304,7 +304,7 @@ static const struct constant_table btrfs_parameter_fragment[] = {
};
#endif
-static const struct fs_parameter_spec btrfs_fs_parameters[] __maybe_unused = {
+static const struct fs_parameter_spec btrfs_fs_parameters[] = {
fsparam_flag_no("acl", Opt_acl),
fsparam_flag("clear_cache", Opt_clear_cache),
fsparam_u32("commit", Opt_commit_interval),
@@ -747,8 +747,8 @@ static bool check_ro_option(struct btrfs_fs_info *fs_info,
return false;
}
-static bool check_options(struct btrfs_fs_info *info, unsigned long *mount_opt,
- unsigned long flags)
+bool btrfs_check_options(struct btrfs_fs_info *info, unsigned long *mount_opt,
+ unsigned long flags)
{
if (!(flags & SB_RDONLY) &&
(check_ro_option(info, *mount_opt, BTRFS_MOUNT_NOLOGREPLAY, "nologreplay") ||
@@ -783,18 +783,6 @@ static bool check_options(struct btrfs_fs_info *info, unsigned long *mount_opt,
void btrfs_set_free_space_cache_settings(struct btrfs_fs_info *fs_info)
{
- if (btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE))
- btrfs_set_opt(fs_info->mount_opt, FREE_SPACE_TREE);
- else if (btrfs_free_space_cache_v1_active(fs_info)) {
- if (btrfs_is_zoned(fs_info)) {
- btrfs_info(fs_info,
- "zoned: clearing existing space cache");
- btrfs_set_super_cache_generation(fs_info->super_copy, 0);
- } else {
- btrfs_set_opt(fs_info->mount_opt, SPACE_CACHE);
- }
- }
-
if (fs_info->sectorsize < PAGE_SIZE) {
btrfs_clear_opt(fs_info->mount_opt, SPACE_CACHE);
if (!btrfs_test_opt(fs_info, FREE_SPACE_TREE)) {
@@ -804,6 +792,35 @@ void btrfs_set_free_space_cache_settings(struct btrfs_fs_info *fs_info)
btrfs_set_opt(fs_info->mount_opt, FREE_SPACE_TREE);
}
}
+
+ /*
+ * At this point our mount options are populated, so we only mess with
+ * these settings if we don't have any settings already.
+ */
+ if (btrfs_test_opt(fs_info, FREE_SPACE_TREE))
+ return;
+
+ if (btrfs_is_zoned(fs_info) &&
+ btrfs_free_space_cache_v1_active(fs_info)) {
+ btrfs_info(fs_info, "zoned: clearing existing space cache");
+ btrfs_set_super_cache_generation(fs_info->super_copy, 0);
+ return;
+ }
+
+ if (btrfs_test_opt(fs_info, SPACE_CACHE))
+ return;
+
+ if (btrfs_test_opt(fs_info, NOSPACECACHE))
+ return;
+
+ /*
+ * At this point we don't have explicit options set by the user, set
+ * them ourselves based on the state of the file system.
+ */
+ if (btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE))
+ btrfs_set_opt(fs_info->mount_opt, FREE_SPACE_TREE);
+ else if (btrfs_free_space_cache_v1_active(fs_info))
+ btrfs_set_opt(fs_info->mount_opt, SPACE_CACHE);
}
static int parse_rescue_options(struct btrfs_fs_info *info, const char *options)
@@ -1340,7 +1357,7 @@ int btrfs_parse_options(struct btrfs_fs_info *info, char *options,
}
}
out:
- if (!ret && !check_options(info, &info->mount_opt, new_flags))
+ if (!ret && !btrfs_check_options(info, &info->mount_opt, new_flags))
ret = -EINVAL;
return ret;
}
@@ -1641,10 +1658,6 @@ static int btrfs_fill_super(struct super_block *sb,
#endif
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;
err = super_setup_bdi(sb);
@@ -1924,7 +1937,7 @@ 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,
+static __maybe_unused struct dentry *btrfs_mount_root(struct file_system_type *fs_type,
int flags, const char *device_name, void *data)
{
struct block_device *bdev = NULL;
@@ -2057,7 +2070,7 @@ static struct dentry *btrfs_mount_root(struct file_system_type *fs_type,
* 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,
+static __maybe_unused struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags,
const char *device_name, void *data)
{
struct vfsmount *mnt_root;
@@ -2521,7 +2534,7 @@ static int btrfs_reconfigure(struct fs_context *fc)
set_bit(BTRFS_FS_STATE_REMOUNTING, &fs_info->fs_state);
if (!mount_reconfigure &&
- !check_options(fs_info, &ctx->mount_opt, fc->sb_flags))
+ !btrfs_check_options(fs_info, &ctx->mount_opt, fc->sb_flags))
return -EINVAL;
ret = btrfs_check_features(fs_info, !(fc->sb_flags & SB_RDONLY));
@@ -3189,7 +3202,7 @@ static const struct fs_context_operations btrfs_fs_context_ops = {
.free = btrfs_free_fs_context,
};
-static int __maybe_unused btrfs_init_fs_context(struct fs_context *fc)
+static int btrfs_init_fs_context(struct fs_context *fc)
{
struct btrfs_fs_context *ctx;
@@ -3210,24 +3223,22 @@ static int __maybe_unused btrfs_init_fs_context(struct fs_context *fc)
ctx->commit_interval = BTRFS_DEFAULT_COMMIT_INTERVAL;
}
+#ifdef CONFIG_BTRFS_FS_POSIX_ACL
+ fc->sb_flags |= SB_POSIXACL;
+#endif
+ fc->sb_flags |= SB_I_VERSION;
+
return 0;
}
static struct file_system_type btrfs_fs_type = {
- .owner = THIS_MODULE,
- .name = "btrfs",
- .mount = btrfs_mount,
- .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,
- .kill_sb = btrfs_kill_super,
- .fs_flags = FS_REQUIRES_DEV | FS_BINARY_MOUNTDATA | FS_ALLOW_IDMAP,
-};
+ .owner = THIS_MODULE,
+ .name = "btrfs",
+ .init_fs_context = btrfs_init_fs_context,
+ .parameters = btrfs_fs_parameters,
+ .kill_sb = btrfs_kill_super,
+ .fs_flags = FS_REQUIRES_DEV | FS_BINARY_MOUNTDATA | FS_ALLOW_IDMAP,
+ };
MODULE_ALIAS_FS("btrfs");
@@ -3440,7 +3451,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/super.h b/fs/btrfs/super.h
index 7c1cd7527e76..7f6577d69902 100644
--- a/fs/btrfs/super.h
+++ b/fs/btrfs/super.h
@@ -3,6 +3,8 @@
#ifndef BTRFS_SUPER_H
#define BTRFS_SUPER_H
+bool btrfs_check_options(struct btrfs_fs_info *info, unsigned long *mount_opt,
+ unsigned long flags);
int btrfs_parse_options(struct btrfs_fs_info *info, char *options,
unsigned long new_flags);
int btrfs_sync_fs(struct super_block *sb, int wait);
--
2.41.0
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCH v2 15/18] btrfs: move the device specific mount options to super.c
2023-11-08 19:08 [PATCH v2 00/18] btrfs: convert to the new mount API Josef Bacik
` (13 preceding siblings ...)
2023-11-08 19:08 ` [PATCH v2 14/18] btrfs: switch to the new mount API Josef Bacik
@ 2023-11-08 19:08 ` Josef Bacik
2023-11-08 19:08 ` [PATCH v2 16/18] btrfs: remove old mount API code Josef Bacik
` (5 subsequent siblings)
20 siblings, 0 replies; 33+ messages in thread
From: Josef Bacik @ 2023-11-08 19:08 UTC (permalink / raw)
To: linux-btrfs, kernel-team, linux-fsdevel, brauner
We add these mount options based on the fs_devices settings, which can
be set once we've opened the fs_devices. Move these into their own
helper and call it from get_tree_super.
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
fs/btrfs/disk-io.c | 23 -----------------------
fs/btrfs/super.c | 25 +++++++++++++++++++++++++
2 files changed, 25 insertions(+), 23 deletions(-)
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index ce861f4baf47..50ed7ece0840 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -3483,29 +3483,6 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device
goto fail_cleaner;
}
- if (!btrfs_test_opt(fs_info, NOSSD) &&
- !fs_info->fs_devices->rotating) {
- btrfs_set_and_info(fs_info, SSD, "enabling ssd optimizations");
- }
-
- /*
- * For devices supporting discard turn on discard=async automatically,
- * unless it's already set or disabled. This could be turned off by
- * nodiscard for the same mount.
- *
- * The zoned mode piggy backs on the discard functionality for
- * resetting a zone. There is no reason to delay the zone reset as it is
- * fast enough. So, do not enable async discard for zoned mode.
- */
- if (!(btrfs_test_opt(fs_info, DISCARD_SYNC) ||
- btrfs_test_opt(fs_info, DISCARD_ASYNC) ||
- btrfs_test_opt(fs_info, NODISCARD)) &&
- fs_info->fs_devices->discardable &&
- !btrfs_is_zoned(fs_info)) {
- btrfs_set_and_info(fs_info, DISCARD_ASYNC,
- "auto enabling async discard");
- }
-
ret = btrfs_read_qgroup_config(fs_info);
if (ret)
goto fail_trans_kthread;
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index 4ce07d255497..c6c2bd407f90 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -823,6 +823,29 @@ void btrfs_set_free_space_cache_settings(struct btrfs_fs_info *fs_info)
btrfs_set_opt(fs_info->mount_opt, SPACE_CACHE);
}
+static void set_device_specific_options(struct btrfs_fs_info *fs_info)
+{
+ if (!btrfs_test_opt(fs_info, NOSSD) &&
+ !fs_info->fs_devices->rotating)
+ btrfs_set_opt(fs_info->mount_opt, SSD);
+
+ /*
+ * For devices supporting discard turn on discard=async automatically,
+ * unless it's already set or disabled. This could be turned off by
+ * nodiscard for the same mount.
+ *
+ * The zoned mode piggy backs on the discard functionality for
+ * resetting a zone. There is no reason to delay the zone reset as it is
+ * fast enough. So, do not enable async discard for zoned mode.
+ */
+ if (!(btrfs_test_opt(fs_info, DISCARD_SYNC) ||
+ btrfs_test_opt(fs_info, DISCARD_ASYNC) ||
+ btrfs_test_opt(fs_info, NODISCARD)) &&
+ fs_info->fs_devices->discardable &&
+ !btrfs_is_zoned(fs_info))
+ btrfs_set_opt(fs_info->mount_opt, DISCARD_ASYNC);
+}
+
static int parse_rescue_options(struct btrfs_fs_info *info, const char *options)
{
char *opts;
@@ -2913,6 +2936,8 @@ static int btrfs_get_tree_super(struct fs_context *fc)
goto error;
}
+ set_device_specific_options(fs_info);
+
if (s->s_root) {
btrfs_close_devices(fs_devices);
if ((fc->sb_flags ^ s->s_flags) & SB_RDONLY)
--
2.41.0
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCH v2 16/18] btrfs: remove old mount API code
2023-11-08 19:08 [PATCH v2 00/18] btrfs: convert to the new mount API Josef Bacik
` (14 preceding siblings ...)
2023-11-08 19:08 ` [PATCH v2 15/18] btrfs: move the device specific mount options to super.c Josef Bacik
@ 2023-11-08 19:08 ` Josef Bacik
2023-11-08 19:08 ` [PATCH v2 17/18] btrfs: move one shot mount option clearing to super.c Josef Bacik
` (4 subsequent siblings)
20 siblings, 0 replies; 33+ messages in thread
From: Josef Bacik @ 2023-11-08 19:08 UTC (permalink / raw)
To: linux-btrfs, kernel-team, linux-fsdevel, brauner
Now that we've switched to the new mount api, remove the old stuff.
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
fs/btrfs/fs.h | 14 -
fs/btrfs/super.c | 1078 +---------------------------------------------
fs/btrfs/super.h | 2 -
3 files changed, 13 insertions(+), 1081 deletions(-)
diff --git a/fs/btrfs/fs.h b/fs/btrfs/fs.h
index ecfa13a9c2cf..41be64e7c045 100644
--- a/fs/btrfs/fs.h
+++ b/fs/btrfs/fs.h
@@ -961,20 +961,6 @@ void __btrfs_clear_fs_compat_ro(struct btrfs_fs_info *fs_info, u64 flag,
#define btrfs_test_opt(fs_info, opt) ((fs_info)->mount_opt & \
BTRFS_MOUNT_##opt)
-#define btrfs_set_and_info(fs_info, opt, fmt, args...) \
-do { \
- if (!btrfs_test_opt(fs_info, opt)) \
- btrfs_info(fs_info, fmt, ##args); \
- btrfs_set_opt(fs_info->mount_opt, opt); \
-} while (0)
-
-#define btrfs_clear_and_info(fs_info, opt, fmt, args...) \
-do { \
- if (btrfs_test_opt(fs_info, opt)) \
- btrfs_info(fs_info, fmt, ##args); \
- btrfs_clear_opt(fs_info->mount_opt, opt); \
-} while (0)
-
static inline int btrfs_fs_closing(struct btrfs_fs_info *fs_info)
{
/* Do it this way so we only ever do one test_bit in the normal case. */
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index c6c2bd407f90..d99da8107677 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -65,19 +65,7 @@
#include <trace/events/btrfs.h>
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_fs_type;
-static struct file_system_type btrfs_root_fs_type;
-
-static int btrfs_remount(struct super_block *sb, int *flags, char *data);
static void btrfs_put_super(struct super_block *sb)
{
@@ -99,7 +87,7 @@ struct btrfs_fs_context {
};
enum {
- Opt_acl, Opt_noacl,
+ Opt_acl,
Opt_clear_cache,
Opt_commit_interval,
Opt_compress,
@@ -109,27 +97,26 @@ enum {
Opt_degraded,
Opt_device,
Opt_fatal_errors,
- Opt_flushoncommit, Opt_noflushoncommit,
+ Opt_flushoncommit,
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 */
@@ -142,10 +129,10 @@ enum {
/* Deprecated options */
Opt_recovery,
- Opt_inode_cache, Opt_noinode_cache,
+ Opt_inode_cache,
/* Debugging options */
- 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
@@ -155,88 +142,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_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_ignorebadroots, "ignorebadroots"},
- {Opt_ignorebadroots, "ibadroots"},
- {Opt_ignoredatacsums, "ignoredatacsums"},
- {Opt_ignoredatacsums, "idatacsums"},
- {Opt_rescue_all, "all"},
- {Opt_err, NULL},
-};
-
enum {
Opt_fatal_errors_panic,
Opt_fatal_errors_bug,
@@ -846,660 +751,6 @@ static void set_device_specific_options(struct btrfs_fs_info *fs_info)
btrfs_set_opt(fs_info->mount_opt, DISCARD_ASYNC);
}
-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_ignorebadroots:
- btrfs_set_and_info(info, IGNOREBADROOTS,
- "ignoring bad roots");
- break;
- case Opt_ignoredatacsums:
- btrfs_set_and_info(info, IGNOREDATACSUMS,
- "ignoring data csums");
- break;
- case Opt_rescue_all:
- btrfs_info(info, "enabling all of the rescue options");
- btrfs_set_and_info(info, IGNOREDATACSUMS,
- "ignoring data csums");
- btrfs_set_and_info(info, IGNOREBADROOTS,
- "ignoring bad roots");
- 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;
- 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;
-
- /*
- * Even the options are empty, we still need to do extra check
- * against new flags
- */
- if (!options)
- goto out;
-
- 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;
- info->compress_level = 0;
- 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 {
- btrfs_err(info, "unrecognized compression value %s",
- args[0].from);
- 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) {
- btrfs_err(info, "unrecognized thread_pool value %s",
- args[0].from);
- goto out;
- } else if (intarg == 0) {
- btrfs_err(info, "invalid value 0 for thread_pool");
- 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) {
- btrfs_err(info, "unrecognized metadata_ratio value %s",
- args[0].from);
- 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 {
- btrfs_err(info, "unrecognized discard mode value %s",
- args[0].from);
- ret = -EINVAL;
- goto out;
- }
- btrfs_clear_opt(info->mount_opt, NODISCARD);
- 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");
- btrfs_set_opt(info->mount_opt, NODISCARD);
- break;
- case Opt_space_cache:
- case Opt_space_cache_version:
- /*
- * We already set FREE_SPACE_TREE above because we have
- * compat_ro(FREE_SPACE_TREE) set, and we aren't going
- * to allow v1 to be set for extent tree v2, simply
- * ignore this setting if we're extent tree v2.
- *
- * For subpage blocksize we don't allow space cache v1,
- * and we'll turn on v2, so we can skip the settings
- * here as well.
- */
- if (btrfs_fs_incompat(info, EXTENT_TREE_V2) ||
- info->sectorsize < PAGE_SIZE)
- break;
- 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 {
- btrfs_err(info, "unrecognized space_cache value %s",
- args[0].from);
- 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:
- /*
- * We cannot operate without the free space tree with
- * extent tree v2, ignore this option.
- */
- if (btrfs_fs_incompat(info, EXTENT_TREE_V2))
- break;
- 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:
- case Opt_noinode_cache:
- btrfs_warn(info,
- "the 'inode_cache' option is deprecated and has no effect since 5.11");
- break;
- case Opt_clear_cache:
- /*
- * We cannot clear the free space tree with extent tree
- * v2, ignore this option.
- */
- if (btrfs_fs_incompat(info, EXTENT_TREE_V2))
- break;
- 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;
- 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 {
- btrfs_err(info, "unrecognized fatal_errors value %s",
- args[0].from);
- ret = -EINVAL;
- goto out;
- }
- break;
- case Opt_commit_interval:
- intarg = 0;
- ret = match_int(&args[0], &intarg);
- if (ret) {
- btrfs_err(info, "unrecognized commit_interval value %s",
- args[0].from);
- ret = -EINVAL;
- 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) {
- btrfs_err(info, "unrecognized rescue value %s",
- args[0].from);
- 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;
- }
- }
-out:
- if (!ret && !btrfs_check_options(info, &info->mount_opt, new_flags))
- ret = -EINVAL;
- return ret;
-}
-
-/*
- * 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, blk_mode_t flags)
-{
- 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, false);
- 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)
{
@@ -1863,22 +1114,6 @@ 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)
-{
- struct btrfs_fs_info *p = data;
- struct btrfs_fs_info *fs_info = btrfs_sb(s);
-
- 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
*/
@@ -1954,200 +1189,6 @@ static struct dentry *mount_subvol(const char *subvol_name, u64 subvol_objectid,
return root;
}
-/*
- * Find a superblock for the given device / mount point.
- *
- * 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 __maybe_unused struct dentry *btrfs_mount_root(struct file_system_type *fs_type,
- int flags, const char *device_name, void *data)
-{
- struct block_device *bdev = NULL;
- struct super_block *s;
- struct btrfs_device *device = NULL;
- struct btrfs_fs_devices *fs_devices = NULL;
- struct btrfs_fs_info *fs_info = NULL;
- void *new_sec_opts = NULL;
- blk_mode_t mode = sb_open_mode(flags);
- int error = 0;
-
- 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
- * then open_ctree will properly initialize the file system specific
- * settings later. btrfs_init_fs_info initializes the static elements
- * of the fs_info (locks and such) to make cleanup easier if we find a
- * 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;
- }
- btrfs_init_fs_info(fs_info);
-
- fs_info->super_copy = kzalloc(BTRFS_SUPER_INFO_SIZE, GFP_KERNEL);
- fs_info->super_for_commit = kzalloc(BTRFS_SUPER_INFO_SIZE, GFP_KERNEL);
- if (!fs_info->super_copy || !fs_info->super_for_commit) {
- error = -ENOMEM;
- goto error_fs_info;
- }
-
- mutex_lock(&uuid_mutex);
- error = btrfs_parse_device_options(data, mode);
- if (error) {
- mutex_unlock(&uuid_mutex);
- goto error_fs_info;
- }
-
- /*
- * With 'true' passed to btrfs_scan_one_device() (mount time) we expect
- * either a valid device or an error.
- */
- device = btrfs_scan_one_device(device_name, mode, true);
- ASSERT(device != NULL);
- if (IS_ERR(device)) {
- mutex_unlock(&uuid_mutex);
- error = PTR_ERR(device);
- goto error_fs_info;
- }
-
- fs_devices = device->fs_devices;
- fs_info->fs_devices = fs_devices;
-
- error = btrfs_open_devices(fs_devices, mode, fs_type);
- mutex_unlock(&uuid_mutex);
- if (error)
- goto error_fs_info;
-
- if (!(flags & SB_RDONLY) && fs_devices->rw_devices == 0) {
- error = -EACCES;
- goto error_close_devices;
- }
-
- bdev = fs_devices->latest_dev->bdev;
- s = sget(fs_type, btrfs_test_super, btrfs_set_super, flags | SB_NOSEC,
- fs_info);
- if (IS_ERR(s)) {
- error = PTR_ERR(s);
- goto error_close_devices;
- }
-
- if (s->s_root) {
- btrfs_close_devices(fs_devices);
- btrfs_free_fs_info(fs_info);
- if ((flags ^ s->s_flags) & SB_RDONLY)
- error = -EBUSY;
- } else {
- snprintf(s->s_id, sizeof(s->s_id), "%pg", bdev);
- shrinker_debugfs_rename(&s->s_shrink, "sb-%s:%s", fs_type->name,
- s->s_id);
- btrfs_sb(s)->bdev_holder = fs_type;
- 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);
- }
-
- return dget(s->s_root);
-
-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);
-}
-
-/*
- * Mount function which is called by VFS layer.
- *
- * 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().
- *
- * 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().
- *
- * 3. Call mount_subvol() to get the dentry of subvolume. Since there is
- * "btrfs subvolume set-default", mount_subvol() is called always.
- */
-static __maybe_unused struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags,
- const char *device_name, void *data)
-{
- struct vfsmount *mnt_root;
- struct dentry *root;
- char *subvol_name = NULL;
- u64 subvol_objectid = 0;
- int error = 0;
-
- error = btrfs_parse_subvol_options(data, &subvol_name,
- &subvol_objectid);
- if (error) {
- kfree(subvol_name);
- return ERR_PTR(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;
- }
-
- 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 (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);
-
-out:
- return root;
-}
-
static void btrfs_resize_thread_pool(struct btrfs_fs_info *fs_info,
u32 new_pool_size, u32 old_pool_size)
{
@@ -2323,99 +1364,6 @@ static int btrfs_remount_ro(struct btrfs_fs_info *fs_info)
return btrfs_commit_super(fs_info);
}
-static int btrfs_remount(struct super_block *sb, int *flags, char *data)
-{
- struct btrfs_fs_info *fs_info = btrfs_sb(sb);
- unsigned old_flags = sb->s_flags;
- unsigned long old_opts = fs_info->mount_opt;
- unsigned long old_compress_type = fs_info->compress_type;
- 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;
-
- 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 (ret)
- goto restore;
- }
-
- ret = btrfs_parse_options(fs_info, data, *flags);
- if (ret)
- goto restore;
-
- ret = btrfs_check_features(fs_info, !(*flags & SB_RDONLY));
- if (ret < 0)
- goto restore;
-
- 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)btrfs_test_opt(fs_info, FREE_SPACE_TREE) !=
- (bool)btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE) &&
- (!sb_rdonly(sb) || (*flags & SB_RDONLY))) {
- btrfs_warn(fs_info,
- "remount supports changing free space tree only from ro to rw");
- /* Make sure free space cache options match the state on disk */
- if (btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE)) {
- btrfs_set_opt(fs_info->mount_opt, FREE_SPACE_TREE);
- btrfs_clear_opt(fs_info->mount_opt, SPACE_CACHE);
- }
- if (btrfs_free_space_cache_v1_active(fs_info)) {
- btrfs_clear_opt(fs_info->mount_opt, FREE_SPACE_TREE);
- btrfs_set_opt(fs_info->mount_opt, SPACE_CACHE);
- }
- }
-
- ret = 0;
- if (!sb_rdonly(sb) && (*flags & SB_RDONLY))
- ret = btrfs_remount_ro(fs_info);
- else if (sb_rdonly(sb) && !(*flags & SB_RDONLY))
- ret = btrfs_remount_rw(fs_info);
- if (ret)
- goto restore;
-
- /*
- * 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;
-
- wake_up_process(fs_info->transaction_kthread);
- btrfs_remount_cleanup(fs_info, old_opts);
- btrfs_clear_oneshot_options(fs_info);
- clear_bit(BTRFS_FS_STATE_REMOUNTING, &fs_info->fs_state);
-
- return 0;
-
-restore:
- /* We've hit an error - don't reset SB_RDONLY */
- if (sb_rdonly(sb))
- old_flags |= SB_RDONLY;
- if (!(old_flags & SB_RDONLY))
- clear_bit(BTRFS_FS_STATE_RO, &fs_info->fs_state);
- sb->s_flags = old_flags;
- fs_info->mount_opt = old_opts;
- fs_info->compress_type = old_compress_type;
- fs_info->max_inline = old_max_inline;
- btrfs_resize_thread_pool(fs_info,
- old_thread_pool_size, fs_info->thread_pool_size);
- fs_info->metadata_ratio = old_metadata_ratio;
- btrfs_remount_cleanup(fs_info, old_opts);
- clear_bit(BTRFS_FS_STATE_REMOUNTING, &fs_info->fs_state);
-
- return ret;
-}
-
static void btrfs_ctx_to_info(struct btrfs_fs_info *fs_info,
struct btrfs_fs_context *ctx)
{
diff --git a/fs/btrfs/super.h b/fs/btrfs/super.h
index 7f6577d69902..f18253ca280d 100644
--- a/fs/btrfs/super.h
+++ b/fs/btrfs/super.h
@@ -5,8 +5,6 @@
bool btrfs_check_options(struct btrfs_fs_info *info, unsigned long *mount_opt,
unsigned long flags);
-int btrfs_parse_options(struct btrfs_fs_info *info, char *options,
- unsigned long new_flags);
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);
--
2.41.0
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCH v2 17/18] btrfs: move one shot mount option clearing to super.c
2023-11-08 19:08 [PATCH v2 00/18] btrfs: convert to the new mount API Josef Bacik
` (15 preceding siblings ...)
2023-11-08 19:08 ` [PATCH v2 16/18] btrfs: remove old mount API code Josef Bacik
@ 2023-11-08 19:08 ` Josef Bacik
2023-11-08 19:08 ` [PATCH v2 18/18] btrfs: set clear_cache if we use usebackuproot Josef Bacik
` (3 subsequent siblings)
20 siblings, 0 replies; 33+ messages in thread
From: Josef Bacik @ 2023-11-08 19:08 UTC (permalink / raw)
To: linux-btrfs, kernel-team, linux-fsdevel, brauner
There's no reason this has to happen in open_ctree, and in fact in the
old mount API we had to call this from remount. Move this to super.c,
unexport it, and call it from both mount and reconfigure.
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
fs/btrfs/disk-io.c | 16 +---------------
fs/btrfs/disk-io.h | 1 -
fs/btrfs/super.c | 15 +++++++++++++++
3 files changed, 16 insertions(+), 16 deletions(-)
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 50ed7ece0840..8f04d2d5f530 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -2929,18 +2929,6 @@ static int btrfs_cleanup_fs_roots(struct btrfs_fs_info *fs_info)
return err;
}
-/*
- * Some options only have meaning at mount time and shouldn't persist across
- * remounts, or be displayed. Clear these at the end of mount and remount
- * code paths.
- */
-void btrfs_clear_oneshot_options(struct btrfs_fs_info *fs_info)
-{
- btrfs_clear_opt(fs_info->mount_opt, USEBACKUPROOT);
- btrfs_clear_opt(fs_info->mount_opt, CLEAR_CACHE);
- btrfs_clear_opt(fs_info->mount_opt, NOSPACECACHE);
-}
-
/*
* Mounting logic specific to read-write file systems. Shared by open_ctree
* and btrfs_remount when remounting from read-only to read-write.
@@ -3508,7 +3496,7 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device
}
if (sb_rdonly(sb))
- goto clear_oneshot;
+ return 0;
ret = btrfs_start_pre_rw_mount(fs_info);
if (ret) {
@@ -3536,8 +3524,6 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device
if (test_bit(BTRFS_FS_UNFINISHED_DROPS, &fs_info->flags))
wake_up_process(fs_info->cleaner_kthread);
-clear_oneshot:
- btrfs_clear_oneshot_options(fs_info);
return 0;
fail_qgroup:
diff --git a/fs/btrfs/disk-io.h b/fs/btrfs/disk-io.h
index e589359e6a68..9413726b329b 100644
--- a/fs/btrfs/disk-io.h
+++ b/fs/btrfs/disk-io.h
@@ -37,7 +37,6 @@ struct extent_buffer *btrfs_find_create_tree_block(
struct btrfs_fs_info *fs_info,
u64 bytenr, u64 owner_root,
int level);
-void btrfs_clear_oneshot_options(struct btrfs_fs_info *fs_info);
int btrfs_start_pre_rw_mount(struct btrfs_fs_info *fs_info);
int btrfs_check_super_csum(struct btrfs_fs_info *fs_info,
const struct btrfs_super_block *disk_sb);
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index d99da8107677..f45de65c3c0b 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -640,6 +640,19 @@ static int btrfs_parse_param(struct fs_context *fc,
return 0;
}
+/*
+ * Some options only have meaning at mount time and shouldn't persist across
+ * remounts, or be displayed. Clear these at the end of mount and remount
+ * code paths.
+ */
+static void btrfs_clear_oneshot_options(struct btrfs_fs_info *fs_info)
+{
+ btrfs_clear_opt(fs_info->mount_opt, USEBACKUPROOT);
+ btrfs_clear_opt(fs_info->mount_opt, CLEAR_CACHE);
+ btrfs_clear_opt(fs_info->mount_opt, NOSPACECACHE);
+}
+
+
static bool check_ro_option(struct btrfs_fs_info *fs_info,
unsigned long mount_opt, unsigned long opt,
const char *opt_name)
@@ -1902,6 +1915,8 @@ static int btrfs_get_tree_super(struct fs_context *fc)
return ret;
}
+ btrfs_clear_oneshot_options(fs_info);
+
fc->root = dget(s->s_root);
return 0;
--
2.41.0
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCH v2 18/18] btrfs: set clear_cache if we use usebackuproot
2023-11-08 19:08 [PATCH v2 00/18] btrfs: convert to the new mount API Josef Bacik
` (16 preceding siblings ...)
2023-11-08 19:08 ` [PATCH v2 17/18] btrfs: move one shot mount option clearing to super.c Josef Bacik
@ 2023-11-08 19:08 ` Josef Bacik
2023-11-08 23:02 ` [PATCH v2 00/18] btrfs: convert to the new mount API Neal Gompa
` (2 subsequent siblings)
20 siblings, 0 replies; 33+ messages in thread
From: Josef Bacik @ 2023-11-08 19:08 UTC (permalink / raw)
To: linux-btrfs, kernel-team, linux-fsdevel, brauner
We're currently setting this when we try to load the roots and we see
that usebackuproot is set. Instead set this at mount option parsing
time.
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
fs/btrfs/disk-io.c | 3 ---
fs/btrfs/super.c | 12 ++++++++++++
2 files changed, 12 insertions(+), 3 deletions(-)
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 8f04d2d5f530..77f13543fa0e 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -2614,9 +2614,6 @@ static int __cold init_tree_roots(struct btrfs_fs_info *fs_info)
*/
btrfs_set_super_log_root(sb, 0);
- /* We can't trust the free space cache either */
- btrfs_set_opt(fs_info->mount_opt, CLEAR_CACHE);
-
btrfs_warn(fs_info, "try to load backup roots slot %d", i);
ret = read_backup_root(fs_info, i);
backup_index = ret;
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index f45de65c3c0b..fe5badc9f6a7 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -459,6 +459,12 @@ static int btrfs_parse_param(struct fs_context *fc,
btrfs_warn(NULL,
"'recovery' is deprecated, use 'rescue=usebackuproot' instead");
btrfs_set_opt(ctx->mount_opt, USEBACKUPROOT);
+
+ /*
+ * If we're loading the backup roots we can't trust the
+ * space cache.
+ */
+ btrfs_set_opt(ctx->mount_opt, CLEAR_CACHE);
}
break;
case Opt_nologreplay:
@@ -557,6 +563,12 @@ static int btrfs_parse_param(struct fs_context *fc,
btrfs_warn(NULL,
"'usebackuproot' is deprecated, use 'rescue=usebackuproot' instead");
btrfs_set_opt(ctx->mount_opt, USEBACKUPROOT);
+
+ /*
+ * If we're loading the backup roots we can't trust the space
+ * cache.
+ */
+ btrfs_set_opt(ctx->mount_opt, CLEAR_CACHE);
break;
case Opt_skip_balance:
btrfs_set_opt(ctx->mount_opt, SKIP_BALANCE);
--
2.41.0
^ permalink raw reply related [flat|nested] 33+ messages in thread
* Re: [PATCH v2 00/18] btrfs: convert to the new mount API
2023-11-08 19:08 [PATCH v2 00/18] btrfs: convert to the new mount API Josef Bacik
` (17 preceding siblings ...)
2023-11-08 19:08 ` [PATCH v2 18/18] btrfs: set clear_cache if we use usebackuproot Josef Bacik
@ 2023-11-08 23:02 ` Neal Gompa
2023-11-09 11:55 ` Johannes Thumshirn
2023-11-09 12:55 ` Christian Brauner
20 siblings, 0 replies; 33+ messages in thread
From: Neal Gompa @ 2023-11-08 23:02 UTC (permalink / raw)
To: Josef Bacik; +Cc: linux-btrfs, kernel-team, linux-fsdevel, brauner
On Wed, Nov 8, 2023 at 2:09 PM Josef Bacik <josef@toxicpanda.com> wrote:
>
> v1->v2:
> - Fixed up some nits and paste errors.
> - Fixed build failure with !ZONED.
> - Fixed accidentally dropping BINARY_MOUNTDATA flag.
> - Added Reviewed-by's collected up to this point.
>
> These have run through our CI a few times, they haven't introduced any
> regressions.
>
> --- Original email ---
> Hello,
>
> These patches convert us to use the new mount API. Christian tried to do this a
> few months ago, but ran afoul of our preference to have a bunch of small
> changes. I started this series before I knew he had tried to convert us, so
> there's a fair bit that's different, but I did copy his approach for the remount
> bit. I've linked to the original patch where I took inspiration, Christian let
> me know if you want some other annotation for credit, I wasn't really sure the
> best way to do that.
>
> There are a few preparatory patches in the beginning, and then cleanups at the
> end. I took each call back one at a time to try and make it as small as
> possible. The resulting code is less, but the diffstat shows more insertions
> that deletions. This is because there are some big comment blocks around some
> of the more subtle things that we're doing to hopefully make it more clear.
>
> This is currently running through our CI. I thought it was fine last week but
> we had a bunch of new failures when I finished up the remount behavior. However
> today I discovered this was a regression in btrfs-progs, and I'm re-running the
> tests with the fixes. If anything major breaks in the CI I'll resend with
> fixes, but I'm pretty sure these patches will pass without issue.
>
> I utilized __maybe_unused liberally to make sure everything compiled while
> applied. The only "big" patch is where I went and removed the old API. If
> requested I can break that up a bit more, but I didn't think it was necessary.
> I did make sure to keep it in its own patch, so the switch to the new mount API
> path only has things we need to support the new mount API, and then the next
> patch removes the old code. Thanks,
>
> Josef
>
> Christian Brauner (1):
> fs: indicate request originates from old mount api
>
> Josef Bacik (17):
> btrfs: split out the mount option validation code into its own helper
> btrfs: set default compress type at btrfs_init_fs_info time
> btrfs: move space cache settings into open_ctree
> btrfs: do not allow free space tree rebuild on extent tree v2
> btrfs: split out ro->rw and rw->ro helpers into their own functions
> btrfs: add a NOSPACECACHE mount option flag
> btrfs: add fs_parameter definitions
> btrfs: add parse_param callback for the new mount api
> btrfs: add fs context handling functions
> btrfs: add reconfigure callback for fs_context
> btrfs: add get_tree callback for new mount API
> btrfs: handle the ro->rw transition for mounting different subovls
> btrfs: switch to the new mount API
> btrfs: move the device specific mount options to super.c
> btrfs: remove old mount API code
> btrfs: move one shot mount option clearing to super.c
> btrfs: set clear_cache if we use usebackuproot
>
> fs/btrfs/disk-io.c | 76 +-
> fs/btrfs/disk-io.h | 1 -
> fs/btrfs/fs.h | 15 +-
> fs/btrfs/super.c | 2421 +++++++++++++++++++++++---------------------
> fs/btrfs/super.h | 5 +-
> fs/btrfs/zoned.c | 16 +-
> fs/btrfs/zoned.h | 6 +-
> fs/namespace.c | 11 +
> 8 files changed, 1317 insertions(+), 1234 deletions(-)
>
> --
> 2.41.0
>
The series looks reasonable to me. I do appreciate the extra effort in
the documents and references to give me context when looking through
it all.
Reviewed-by: Neal Gompa <neal@gompa.dev>
--
真実はいつも一つ!/ Always, there's only one truth!
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH v2 00/18] btrfs: convert to the new mount API
2023-11-08 19:08 [PATCH v2 00/18] btrfs: convert to the new mount API Josef Bacik
` (18 preceding siblings ...)
2023-11-08 23:02 ` [PATCH v2 00/18] btrfs: convert to the new mount API Neal Gompa
@ 2023-11-09 11:55 ` Johannes Thumshirn
2023-11-09 12:55 ` Christian Brauner
20 siblings, 0 replies; 33+ messages in thread
From: Johannes Thumshirn @ 2023-11-09 11:55 UTC (permalink / raw)
To: Josef Bacik, linux-btrfs@vger.kernel.org, kernel-team@fb.com,
linux-fsdevel@vger.kernel.org, brauner@kernel.org
Looks good from what I can tell,
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH v2 00/18] btrfs: convert to the new mount API
2023-11-08 19:08 [PATCH v2 00/18] btrfs: convert to the new mount API Josef Bacik
` (19 preceding siblings ...)
2023-11-09 11:55 ` Johannes Thumshirn
@ 2023-11-09 12:55 ` Christian Brauner
20 siblings, 0 replies; 33+ messages in thread
From: Christian Brauner @ 2023-11-09 12:55 UTC (permalink / raw)
To: Josef Bacik; +Cc: linux-btrfs, kernel-team, linux-fsdevel
On Wed, Nov 08, 2023 at 02:08:35PM -0500, Josef Bacik wrote:
> v1->v2:
> - Fixed up some nits and paste errors.
> - Fixed build failure with !ZONED.
> - Fixed accidentally dropping BINARY_MOUNTDATA flag.
> - Added Reviewed-by's collected up to this point.
>
> These have run through our CI a few times, they haven't introduced any
> regressions.
>
> --- Original email ---
> Hello,
>
> These patches convert us to use the new mount API. Christian tried to do this a
> few months ago, but ran afoul of our preference to have a bunch of small
> changes. I started this series before I knew he had tried to convert us, so
> there's a fair bit that's different, but I did copy his approach for the remount
> bit. I've linked to the original patch where I took inspiration, Christian let
> me know if you want some other annotation for credit, I wasn't really sure the
> best way to do that.
Thank you for pointing out the work that I did and for building on the
bits of it that you could reuse. That's enough credit for me.
Thanks for converting btrfs and I hope we can get this merged soon. This
was the last really major filesystems that hadn't been converted yet so
I'm very glad to see this done.
Acked-by: Christian Brauner <brauner@kernel.org>
^ permalink raw reply [flat|nested] 33+ messages in thread