diff options
author | Kent Overstreet <kent.overstreet@linux.dev> | 2024-02-09 22:04:50 +0100 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@linux.dev> | 2024-03-14 02:22:24 +0100 |
commit | 56e230473d395c953cfab78b876fcf0f62b455b1 (patch) | |
tree | a3b4d390728447bd11b8fe4b8d622a4d36e1dffc /fs | |
parent | bcachefs: check_path() now prints full inode when reattaching (diff) | |
download | linux-56e230473d395c953cfab78b876fcf0f62b455b1.tar.xz linux-56e230473d395c953cfab78b876fcf0f62b455b1.zip |
bcachefs: Correctly reattach subvolumes
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>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/bcachefs/dirent.c | 8 | ||||
-rw-r--r-- | fs/bcachefs/dirent.h | 2 | ||||
-rw-r--r-- | fs/bcachefs/fsck.c | 28 |
3 files changed, 28 insertions, 10 deletions
diff --git a/fs/bcachefs/dirent.c b/fs/bcachefs/dirent.c index 0dfcb194cb1e..882b2a217b51 100644 --- a/fs/bcachefs/dirent.c +++ b/fs/bcachefs/dirent.c @@ -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; diff --git a/fs/bcachefs/dirent.h b/fs/bcachefs/dirent.h index 1cd033fbc58a..bee55cca2aa0 100644 --- a/fs/bcachefs/dirent.h +++ b/fs/bcachefs/dirent.h @@ -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); diff --git a/fs/bcachefs/fsck.c b/fs/bcachefs/fsck.c index 412a196263ea..572ff61c036d 100644 --- a/fs/bcachefs/fsck.c +++ b/fs/bcachefs/fsck.c @@ -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), |