bcachefs: Correctly reattach subvolumes
authorKent Overstreet <kent.overstreet@linux.dev>
Fri, 9 Feb 2024 21:04:50 +0000 (16:04 -0500)
committerKent Overstreet <kent.overstreet@linux.dev>
Thu, 14 Mar 2024 01:22:24 +0000 (21:22 -0400)
Subvolumes need special handling to reattach - we always reattach them
in the root subvolume's lost+found, and they need a slightly different
kind of dirent.

Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
fs/bcachefs/dirent.c
fs/bcachefs/dirent.h
fs/bcachefs/fsck.c

index 0dfcb194cb1efcd11a520d9c993fbb61a730e34b..882b2a217b513fc9d68a689b621f220b595cbeba 100644 (file)
@@ -201,17 +201,17 @@ static struct bkey_i_dirent *dirent_create_key(struct btree_trans *trans,
 }
 
 int bch2_dirent_create_snapshot(struct btree_trans *trans,
-                       u64 dir, u32 snapshot,
+                       u32 dir_subvol, u64 dir, u32 snapshot,
                        const struct bch_hash_info *hash_info,
                        u8 type, const struct qstr *name, u64 dst_inum,
                        u64 *dir_offset,
                        bch_str_hash_flags_t str_hash_flags)
 {
-       subvol_inum zero_inum = { 0 };
+       subvol_inum dir_inum = { .subvol = dir_subvol, .inum = dir };
        struct bkey_i_dirent *dirent;
        int ret;
 
-       dirent = dirent_create_key(trans, zero_inum, type, name, dst_inum);
+       dirent = dirent_create_key(trans, dir_inum, type, name, dst_inum);
        ret = PTR_ERR_OR_ZERO(dirent);
        if (ret)
                return ret;
@@ -220,7 +220,7 @@ int bch2_dirent_create_snapshot(struct btree_trans *trans,
        dirent->k.p.snapshot    = snapshot;
 
        ret = bch2_hash_set_in_snapshot(trans, bch2_dirent_hash_desc, hash_info,
-                                       zero_inum, snapshot,
+                                       dir_inum, snapshot,
                                        &dirent->k_i, str_hash_flags,
                                        BTREE_UPDATE_INTERNAL_SNAPSHOT_NODE);
        *dir_offset = dirent->k.p.offset;
index 1cd033fbc58a6c9e95c9e55d527a694ad5fb5d31..bee55cca2aa0dd303599a095753508137708fc90 100644 (file)
@@ -35,7 +35,7 @@ static inline unsigned dirent_val_u64s(unsigned len)
 int bch2_dirent_read_target(struct btree_trans *, subvol_inum,
                            struct bkey_s_c_dirent, subvol_inum *);
 
-int bch2_dirent_create_snapshot(struct btree_trans *, u64, u32,
+int bch2_dirent_create_snapshot(struct btree_trans *, u32, u64, u32,
                        const struct bch_hash_info *, u8,
                        const struct qstr *, u64, u64 *,
                        bch_str_hash_flags_t);
index 412a196263eae0da0f6c25b0ee1c67aff3d15b00..572ff61c036d7f05066f7759b175d849e1ed5ef4 100644 (file)
@@ -252,7 +252,7 @@ create_lostfound:
                goto err;
 
        ret =   bch2_dirent_create_snapshot(trans,
-                               root_inode.bi_inum, snapshot, &root_hash_info,
+                               0, root_inode.bi_inum, snapshot, &root_hash_info,
                                mode_to_type(lostfound->bi_mode),
                                &lostfound_str,
                                lostfound->bi_inum,
@@ -275,9 +275,24 @@ static int reattach_inode(struct btree_trans *trans,
        char name_buf[20];
        struct qstr name;
        u64 dir_offset = 0;
+       u32 dirent_snapshot = inode_snapshot;
        int ret;
 
-       ret = lookup_lostfound(trans, inode_snapshot, &lostfound);
+       if (inode->bi_subvol) {
+               inode->bi_parent_subvol = BCACHEFS_ROOT_SUBVOL;
+
+               u64 root_inum;
+               ret = subvol_lookup(trans, inode->bi_parent_subvol,
+                                   &dirent_snapshot, &root_inum);
+               if (ret)
+                       return ret;
+
+               snprintf(name_buf, sizeof(name_buf), "subvol-%u", inode->bi_subvol);
+       } else {
+               snprintf(name_buf, sizeof(name_buf), "%llu", inode->bi_inum);
+       }
+
+       ret = lookup_lostfound(trans, dirent_snapshot, &lostfound);
        if (ret)
                return ret;
 
@@ -291,14 +306,16 @@ static int reattach_inode(struct btree_trans *trans,
 
        dir_hash = bch2_hash_info_init(trans->c, &lostfound);
 
-       snprintf(name_buf, sizeof(name_buf), "%llu", inode->bi_inum);
        name = (struct qstr) QSTR(name_buf);
 
        ret = bch2_dirent_create_snapshot(trans,
-                               lostfound.bi_inum, inode_snapshot,
+                               inode->bi_parent_subvol, lostfound.bi_inum,
+                               dirent_snapshot,
                                &dir_hash,
                                inode_d_type(inode),
-                               &name, inode->bi_inum, &dir_offset,
+                               &name,
+                               inode->bi_subvol ?: inode->bi_inum,
+                               &dir_offset,
                                BCH_HASH_SET_MUST_CREATE);
        if (ret)
                return ret;
@@ -2135,6 +2152,7 @@ static int check_path(struct btree_trans *trans, pathbuf *p, struct bkey_s_c ino
                }
 
                if (bch2_err_matches(ret, ENOENT)) {
+                       ret = 0;
                        if (fsck_err(c, inode_unreachable,
                                     "unreachable inode\n%s",
                                     (printbuf_reset(&buf),