All of lore.kernel.org
 help / color / mirror / Atom feed
From: Josef Bacik <josef@toxicpanda.com>
To: linux-btrfs@vger.kernel.org, kernel-team@fb.com,
	linux-fsdevel@vger.kernel.org, brauner@kernel.org
Subject: [PATCH v2 11/18] btrfs: add reconfigure callback for fs_context
Date: Wed,  8 Nov 2023 14:08:46 -0500	[thread overview]
Message-ID: <0c2885bd48e23b46d4e60e6874c1e4f95e0e1ce8.1699470345.git.josef@toxicpanda.com> (raw)
In-Reply-To: <cover.1699470345.git.josef@toxicpanda.com>

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


  parent reply	other threads:[~2023-11-08 19:09 UTC|newest]

Thread overview: 33+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
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-14  6:32   ` Anand Jain
2023-11-14 17:35     ` David Sterba
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 ` [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
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
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 ` [PATCH v2 07/18] btrfs: add a NOSPACECACHE mount option flag Josef Bacik
2023-11-08 19:08 ` [PATCH v2 08/18] btrfs: add fs_parameter definitions 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
2023-11-14 18:13   ` David Sterba
2023-11-22 16:12     ` Josef Bacik
2023-11-08 19:08 ` [PATCH v2 10/18] btrfs: add fs context handling functions Josef Bacik
2023-11-08 19:08 ` Josef Bacik [this message]
2023-11-14 18:23   ` [PATCH v2 11/18] btrfs: add reconfigure callback for fs_context David Sterba
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
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 ` [PATCH v2 14/18] btrfs: switch to the new mount API Josef Bacik
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 ` [PATCH v2 16/18] btrfs: remove old mount API code Josef Bacik
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 ` [PATCH v2 18/18] btrfs: set clear_cache if we use usebackuproot Josef Bacik
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

Reply instructions:

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

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

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

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

  git send-email \
    --in-reply-to=0c2885bd48e23b46d4e60e6874c1e4f95e0e1ce8.1699470345.git.josef@toxicpanda.com \
    --to=josef@toxicpanda.com \
    --cc=brauner@kernel.org \
    --cc=kernel-team@fb.com \
    --cc=linux-btrfs@vger.kernel.org \
    --cc=linux-fsdevel@vger.kernel.org \
    /path/to/YOUR_REPLY

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

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.