bcachefs: Single device mode
authorKent Overstreet <kent.overstreet@linux.dev>
Wed, 2 Apr 2025 19:12:49 +0000 (15:12 -0400)
committerKent Overstreet <kent.overstreet@linux.dev>
Thu, 22 May 2025 00:14:15 +0000 (20:14 -0400)
Single device filesystems are now identified by the block device name,
not the UUID - and single device filesystems with the same UUID can be
mounted simultaneously, without any special options.

This allocates a new bit in the superblock, BCH_SB_MULTI_DEVICE, which
indicates whether a filesystem has ever been multi device.

Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
fs/bcachefs/bcachefs.h
fs/bcachefs/bcachefs_format.h
fs/bcachefs/debug.c
fs/bcachefs/errcode.h
fs/bcachefs/fs.c
fs/bcachefs/opts.h
fs/bcachefs/super-io.c
fs/bcachefs/super.c

index 1e40ad2a7bce7fd913290db62d304f43673b715b..7782e311b6e2163ca8442295d6374f3045615ff4 100644 (file)
@@ -780,6 +780,7 @@ struct bch_fs {
 
                u8              nr_devices;
                u8              clean;
+               bool            multi_device; /* true if we've ever had more than one device */
 
                u8              encryption_type;
 
index 6cbc267445b7ba22b2de44273acc06e05c99d907..22ee49408d11077fe976868d85783bed8bac85e5 100644 (file)
@@ -846,7 +846,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_MULTI_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);
index 2c52a2c6502b18639811606a8709a2c3c08fc988..312f5ce7cba9a06fc69d7b5e2a96173166063a6f 100644 (file)
@@ -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->sb.multi_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;
index 768b176f6ea8e222afb9b274e7e065dccfe99de5..051938657cc991dd0dd7139722ed09667d5850ad 100644 (file)
        x(EINVAL,                       device_has_been_removed)                \
        x(EINVAL,                       device_splitbrain)                      \
        x(EINVAL,                       device_already_online)                  \
+       x(EINVAL,                       filesystem_uuid_already_open)           \
        x(EINVAL,                       insufficient_devices_to_start)          \
        x(EINVAL,                       invalid)                                \
        x(EINVAL,                       internal_fsck_err)                      \
index 47f1a64c5c8d838b1415293ce604a2ac2498336a..672326693f733ceb372ad9b3f62934c13d26e75c 100644 (file)
@@ -2514,7 +2514,12 @@ got_sb:
        sb->s_time_min          = div_s64(S64_MIN, c->sb.time_units_per_sec) + 1;
        sb->s_time_max          = div_s64(S64_MAX, c->sb.time_units_per_sec);
        super_set_uuid(sb, c->sb.user_uuid.b, sizeof(c->sb.user_uuid));
-       super_set_sysfs_name_uuid(sb);
+
+       if (c->sb.multi_device)
+               super_set_sysfs_name_uuid(sb);
+       else
+               strscpy(sb->s_sysfs_name, c->name, sizeof(sb->s_sysfs_name));
+
        sb->s_shrink->seeks     = 0;
        c->vfs_sb               = sb;
        strscpy(sb->s_id, c->name, sizeof(sb->s_id));
index cbb13e91789df29e8804be4a5808de33767287e8..c97f2a6ad29f5c13e9409c74099138bb1f06ec2b 100644 (file)
@@ -518,7 +518,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")                  \
@@ -526,7 +526,7 @@ 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"\
+         NULL,         "BTREE_ITER_prefetch causes btree nodes to be\n"\
          " prefetched sequentially")
 
 struct bch_opts {
index adfcd8a92b9305cd73037d7bc4909628101f61e0..2435e114cad9148631400719db0893eebecdffb3 100644 (file)
@@ -468,6 +468,9 @@ int bch2_sb_validate(struct bch_sb *sb, u64 read_offset,
                        SET_BCH_SB_VERSION_INCOMPAT_ALLOWED(sb, BCH_SB_VERSION_INCOMPAT(sb));
        }
 
+       if (sb->nr_devices > 1)
+               SET_BCH_SB_MULTI_DEVICE(sb, true);
+
        if (!flags) {
                /*
                 * Been seeing a bug where these are getting inexplicably
@@ -612,6 +615,7 @@ static void bch2_sb_update(struct bch_fs *c)
 
        c->sb.features          = le64_to_cpu(src->features[0]);
        c->sb.compat            = le64_to_cpu(src->compat[0]);
+       c->sb.multi_device      = BCH_SB_MULTI_DEVICE(src);
 
        memset(c->sb.errors_silent, 0, sizeof(c->sb.errors_silent));
 
index 75287aa2ae7f9c5ea803532f59d52718495f1541..1c3a20d096a389b5c181a9adb43d0e9faf77e932 100644 (file)
@@ -699,9 +699,10 @@ 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->sb.multi_device &&
+           __bch2_uuid_to_fs(c->sb.uuid)) {
                bch_err(c, "filesystem UUID already open");
-               return -EINVAL;
+               return -BCH_ERR_filesystem_uuid_already_open;
        }
 
        ret = bch2_fs_chardev_init(c);
@@ -712,7 +713,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->sb.multi_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
@@ -902,7 +905,7 @@ static struct bch_fs *bch2_fs_alloc(struct bch_sb *sb, struct bch_opts opts,
                goto err;
        }
 
-       if (sbs->nr != 1)
+       if (c->sb.multi_device)
                pr_uuid(&name, c->sb.user_uuid.b);
        else
                prt_bdevname(&name, sbs->data[0].bdev);
@@ -1792,11 +1795,11 @@ 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;
-       int ret;
+       int ret = 0;
 
        ret = bch2_read_super(path, &opts, &sb);
        bch_err_msg(c, ret, "reading super");
@@ -1813,6 +1816,20 @@ int bch2_dev_add(struct bch_fs *c, const char *path)
                }
        }
 
+       if (list_empty(&c->list)) {
+               mutex_lock(&bch_fs_list_lock);
+               if (__bch2_uuid_to_fs(c->sb.uuid))
+                       ret = -BCH_ERR_filesystem_uuid_already_open;
+               else
+                       list_add(&c->list, &bch_fs_list);
+               mutex_unlock(&bch_fs_list_lock);
+
+               if (ret) {
+                       bch_err(c, "filesystem UUID already open");
+                       goto err;
+               }
+       }
+
        ret = bch2_dev_may_add(sb.sb, c);
        if (ret)
                goto err;
@@ -1829,6 +1846,7 @@ int bch2_dev_add(struct bch_fs *c, const char *path)
 
        down_write(&c->state_lock);
        mutex_lock(&c->sb_lock);
+       SET_BCH_SB_MULTI_DEVICE(c->disk_sb.sb, true);
 
        ret = bch2_sb_from_fs(c, ca);
        bch_err_msg(c, ret, "setting up new superblock");