diff options
author | Kent Overstreet <kent.overstreet@linux.dev> | 2025-04-02 15:12:49 -0400 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@linux.dev> | 2025-04-06 19:13:46 -0400 |
commit | 06d3a60e98bf6c06ce17d31a6b6dcf41eefd6203 (patch) | |
tree | 0c89f5ab14c83918246ff8e2147cd325b167685f | |
parent | 20d959e2dee9801213ac689cc8098c808eaab871 (diff) |
bcachefs: Single device mode
This provides a new option for single device mode - which allows
multiple filesystems with the same UUID to be mounted simultaneously.
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
-rw-r--r-- | fs/bcachefs/bcachefs_format.h | 2 | ||||
-rw-r--r-- | fs/bcachefs/debug.c | 6 | ||||
-rw-r--r-- | fs/bcachefs/errcode.h | 2 | ||||
-rw-r--r-- | fs/bcachefs/opts.c | 8 | ||||
-rw-r--r-- | fs/bcachefs/opts.h | 11 | ||||
-rw-r--r-- | fs/bcachefs/super.c | 14 |
6 files changed, 34 insertions, 9 deletions
diff --git a/fs/bcachefs/bcachefs_format.h b/fs/bcachefs/bcachefs_format.h index a3db328dee31..8a1366aabebd 100644 --- a/fs/bcachefs/bcachefs_format.h +++ b/fs/bcachefs/bcachefs_format.h @@ -842,7 +842,7 @@ LE64_BITMASK(BCH_SB_SHARD_INUMS, struct bch_sb, flags[3], 28, 29); LE64_BITMASK(BCH_SB_INODES_USE_KEY_CACHE,struct bch_sb, flags[3], 29, 30); LE64_BITMASK(BCH_SB_JOURNAL_FLUSH_DELAY,struct bch_sb, flags[3], 30, 62); LE64_BITMASK(BCH_SB_JOURNAL_FLUSH_DISABLED,struct bch_sb, flags[3], 62, 63); -/* one free bit */ +LE64_BITMASK(BCH_SB_SINGLE_DEVICE, struct bch_sb, flags[3], 63, 64); LE64_BITMASK(BCH_SB_JOURNAL_RECLAIM_DELAY,struct bch_sb, flags[4], 0, 32); LE64_BITMASK(BCH_SB_JOURNAL_TRANSACTION_NAMES,struct bch_sb, flags[4], 32, 33); LE64_BITMASK(BCH_SB_NOCOW, struct bch_sb, flags[4], 33, 34); diff --git a/fs/bcachefs/debug.c b/fs/bcachefs/debug.c index f4b7877c0843..09b672799ca9 100644 --- a/fs/bcachefs/debug.c +++ b/fs/bcachefs/debug.c @@ -933,7 +933,11 @@ void bch2_fs_debug_init(struct bch_fs *c) if (IS_ERR_OR_NULL(bch_debug)) return; - snprintf(name, sizeof(name), "%pU", c->sb.user_uuid.b); + if (!c->opts.single_device) + snprintf(name, sizeof(name), "%pU", c->sb.user_uuid.b); + else + strscpy(name, c->name, sizeof(name)); + c->fs_debug_dir = debugfs_create_dir(name, bch_debug); if (IS_ERR_OR_NULL(c->fs_debug_dir)) return; diff --git a/fs/bcachefs/errcode.h b/fs/bcachefs/errcode.h index c8696f01eb14..c4eb0ed9838d 100644 --- a/fs/bcachefs/errcode.h +++ b/fs/bcachefs/errcode.h @@ -192,6 +192,8 @@ x(BCH_ERR_data_update_done, data_update_done_no_rw_devs) \ x(EINVAL, device_state_not_allowed) \ x(EINVAL, member_info_missing) \ + x(EINVAL, single_device_filesystem) \ + x(EINVAL, not_single_device_filesystem) \ x(EINVAL, mismatched_block_size) \ x(EINVAL, block_size_too_small) \ x(EINVAL, bucket_size_too_small) \ diff --git a/fs/bcachefs/opts.c b/fs/bcachefs/opts.c index af3258814822..e64777ecf44f 100644 --- a/fs/bcachefs/opts.c +++ b/fs/bcachefs/opts.c @@ -498,6 +498,14 @@ int bch2_opt_check_may_set(struct bch_fs *c, struct bch_dev *ca, int id, u64 v) if (v) bch2_check_set_feature(c, BCH_FEATURE_ec); break; + case Opt_single_device: + if (v) { + mutex_lock(&c->sb_lock); + if (bch2_sb_nr_devices(c->disk_sb.sb) > 1) + ret = -BCH_ERR_not_single_device_filesystem; + mutex_unlock(&c->sb_lock); + } + break; } return ret; diff --git a/fs/bcachefs/opts.h b/fs/bcachefs/opts.h index 4d06313076ff..45b393f83776 100644 --- a/fs/bcachefs/opts.h +++ b/fs/bcachefs/opts.h @@ -517,7 +517,7 @@ enum fsck_err_opts { BCH_MEMBER_DATA_ALLOWED, BIT(BCH_DATA_journal)|BIT(BCH_DATA_btree)|BIT(BCH_DATA_user),\ "types", "Allowed data types for this device: journal, btree, and/or user")\ x(discard, u8, \ - OPT_MOUNT|OPT_DEVICE|OPT_RUNTIME, \ + OPT_MOUNT|OPT_FS|OPT_DEVICE|OPT_RUNTIME, \ OPT_BOOL(), \ BCH_MEMBER_DISCARD, true, \ NULL, "Enable discard/TRIM support") \ @@ -525,8 +525,13 @@ enum fsck_err_opts { OPT_FS|OPT_MOUNT|OPT_RUNTIME, \ OPT_BOOL(), \ BCH2_NO_SB_OPT, true, \ - NULL, "BTREE_ITER_prefetch casuse btree nodes to be\n"\ - " prefetched sequentially") + NULL, "BTREE_ITER_prefetch causes btree nodes to be\n"\ + " prefetched sequentially") \ + x(single_device, u8, \ + OPT_FS|OPT_MOUNT|OPT_RUNTIME, \ + OPT_BOOL(), \ + BCH_SB_SINGLE_DEVICE, false, \ + NULL, "Devices with the same UUID may be mounted simultaneously") struct bch_opts { #define x(_name, _bits, ...) unsigned _name##_defined:1; diff --git a/fs/bcachefs/super.c b/fs/bcachefs/super.c index 07c8149c6712..f868bc5cd19a 100644 --- a/fs/bcachefs/super.c +++ b/fs/bcachefs/super.c @@ -708,7 +708,8 @@ static int bch2_fs_online(struct bch_fs *c) lockdep_assert_held(&bch_fs_list_lock); - if (__bch2_uuid_to_fs(c->sb.uuid)) { + if (!c->opts.single_device && + __bch2_uuid_to_fs(c->sb.uuid)) { bch_err(c, "filesystem UUID already open"); return -EINVAL; } @@ -721,7 +722,9 @@ static int bch2_fs_online(struct bch_fs *c) bch2_fs_debug_init(c); - ret = kobject_add(&c->kobj, NULL, "%pU", c->sb.user_uuid.b) ?: + ret = (!c->opts.single_device + ? kobject_add(&c->kobj, NULL, "%pU", c->sb.user_uuid.b) + : kobject_add(&c->kobj, NULL, "%s", c->name)) ?: kobject_add(&c->internal, &c->kobj, "internal") ?: kobject_add(&c->opts_dir, &c->kobj, "options") ?: #ifndef CONFIG_BCACHEFS_NO_LATENCY_ACCT @@ -897,7 +900,7 @@ static struct bch_fs *bch2_fs_alloc(struct bch_sb *sb, struct bch_opts opts, goto err; } - if (sbs->nr != 1) + if (sbs->nr != 1 && !c->opts.single_device) pr_uuid(&name, c->sb.user_uuid.b); else prt_bdevname(&name, sbs->data[0].bdev); @@ -1114,6 +1117,9 @@ static int bch2_dev_may_add(struct bch_sb *sb, struct bch_fs *c) { struct bch_member m = bch2_sb_member_get(sb, sb->dev_idx); + if (c->opts.single_device) + return -BCH_ERR_single_device_filesystem; + if (le16_to_cpu(sb->block_size) != block_sectors(c)) return -BCH_ERR_mismatched_block_size; @@ -1781,7 +1787,7 @@ err: int bch2_dev_add(struct bch_fs *c, const char *path) { struct bch_opts opts = bch2_opts_empty(); - struct bch_sb_handle sb; + struct bch_sb_handle sb = {}; struct bch_dev *ca = NULL; struct printbuf errbuf = PRINTBUF; struct printbuf label = PRINTBUF; |