summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@gmail.com>2021-04-19 23:31:40 -0400
committerKent Overstreet <kent.overstreet@gmail.com>2021-09-26 19:48:43 -0400
commitda0d1dd0dfe1ba2a394e9c1791f8ef7f692230b4 (patch)
treec6305fb005f85b6bbe00b13e335a8df7cd2384d8
parent81329309c1a7ad7032bfdbc0f71339f9ca03adad (diff)
bcachefs: Per subvolume lost+found
On existing filesystems, we have a single global lost+found. Introducing subvolumes means we need to introduce per subvolume lost+found directories, because inodes are added to lost+found by their inode number, and inode numbers are now only unique within a subvolume. This patch adds support to fsck for per subvolume lost+found. Signed-off-by: Kent Overstreet <kent.overstreet@gmail.com>
-rw-r--r--fs/bcachefs/fsck.c94
1 files changed, 84 insertions, 10 deletions
diff --git a/fs/bcachefs/fsck.c b/fs/bcachefs/fsck.c
index dca4abda2c41..e4ca05aae76c 100644
--- a/fs/bcachefs/fsck.c
+++ b/fs/bcachefs/fsck.c
@@ -39,6 +39,71 @@ static s64 bch2_count_inode_sectors(struct btree_trans *trans, u64 inum)
return ret ?: sectors;
}
+static int __snapshot_lookup_subvol(struct btree_trans *trans, u32 snapshot,
+ u32 *subvol)
+{
+ struct btree_iter iter;
+ struct bkey_s_c k;
+ int ret;
+
+ bch2_trans_iter_init(trans, &iter, BTREE_ID_snapshots,
+ POS(0, snapshot), 0);
+ k = bch2_btree_iter_peek_slot(&iter);
+ ret = bkey_err(k);
+ if (ret)
+ goto err;
+
+ if (k.k->type != KEY_TYPE_snapshot) {
+ bch_err(trans->c, "snapshot %u not fonud", snapshot);
+ ret = -ENOENT;
+ goto err;
+ }
+
+ *subvol = le32_to_cpu(bkey_s_c_to_snapshot(k).v->subvol);
+err:
+ bch2_trans_iter_exit(trans, &iter);
+ return ret;
+
+}
+
+static int snapshot_lookup_subvol(struct btree_trans *trans, u32 snapshot,
+ u32 *subvol)
+{
+ return lockrestart_do(trans, __snapshot_lookup_subvol(trans, snapshot, subvol));
+}
+
+static int __subvol_lookup_root(struct btree_trans *trans, u32 subvol,
+ u64 *inum)
+{
+ struct btree_iter iter;
+ struct bkey_s_c k;
+ int ret;
+
+ bch2_trans_iter_init(trans, &iter, BTREE_ID_subvolumes,
+ POS(0, subvol), 0);
+ k = bch2_btree_iter_peek_slot(&iter);
+ ret = bkey_err(k);
+ if (ret)
+ goto err;
+
+ if (k.k->type != KEY_TYPE_subvolume) {
+ bch_err(trans->c, "subvolume %u not fonud", subvol);
+ ret = -ENOENT;
+ goto err;
+ }
+
+ *inum = le64_to_cpu(bkey_s_c_to_subvolume(k).v->inode);
+err:
+ bch2_trans_iter_exit(trans, &iter);
+ return ret;
+
+}
+
+static int subvol_lookup_root(struct btree_trans *trans, u32 subvol, u64 *inum)
+{
+ return lockrestart_do(trans, __subvol_lookup_root(trans, subvol, inum));
+}
+
static int __lookup_inode(struct btree_trans *trans, u64 inode_nr,
struct bch_inode_unpacked *inode,
u32 *snapshot)
@@ -136,6 +201,7 @@ static int remove_dirent(struct btree_trans *trans, struct bpos pos)
/* Get lost+found, create if it doesn't exist: */
static int lookup_lostfound(struct btree_trans *trans,
+ u32 subvol,
struct bch_inode_unpacked *lostfound)
{
struct bch_fs *c = trans->c;
@@ -146,12 +212,14 @@ static int lookup_lostfound(struct btree_trans *trans,
u32 snapshot;
int ret;
- ret = lookup_inode(trans, BCACHEFS_ROOT_INO, &root, &snapshot);
+ ret = subvol_lookup_root(trans, subvol, &inum);
+
+ ret = lookup_inode(trans, inum, &root, &snapshot);
if (ret && ret != -ENOENT)
return ret;
root_hash_info = bch2_hash_info_init(c, &root);
- inum = bch2_dirent_lookup(c, BCACHEFS_ROOT_INO, &root_hash_info,
+ inum = bch2_dirent_lookup(c, root.bi_inum, &root_hash_info,
&lostfound_str);
if (!inum) {
bch_notice(c, "creating lost+found");
@@ -188,16 +256,22 @@ create_lostfound:
}
static int reattach_inode(struct btree_trans *trans,
- struct bch_inode_unpacked *inode)
+ struct bch_inode_unpacked *inode,
+ u32 snapshot)
{
struct bch_hash_info dir_hash;
struct bch_inode_unpacked lostfound;
char name_buf[20];
struct qstr name;
u64 dir_offset = 0;
+ u32 subvol;
int ret;
- ret = lookup_lostfound(trans, &lostfound);
+ ret = snapshot_lookup_subvol(trans, snapshot, &subvol);
+ if (ret)
+ return ret;
+
+ ret = lookup_lostfound(trans, subvol, &lostfound);
if (ret)
return ret;
@@ -1063,10 +1137,10 @@ static int path_down(struct pathbuf *p, u64 inum)
static int check_path(struct btree_trans *trans,
struct pathbuf *p,
- struct bch_inode_unpacked *inode)
+ struct bch_inode_unpacked *inode,
+ u32 snapshot)
{
struct bch_fs *c = trans->c;
- u32 snapshot;
size_t i;
int ret = 0;
@@ -1085,7 +1159,7 @@ static int check_path(struct btree_trans *trans,
inode->bi_nlink,
inode->bi_dir,
inode->bi_dir_offset))
- ret = reattach_inode(trans, inode);
+ ret = reattach_inode(trans, inode, snapshot);
break;
}
ret = 0;
@@ -1108,13 +1182,13 @@ static int check_path(struct btree_trans *trans,
return 0;
ret = lockrestart_do(trans,
- remove_backpointer(trans, inode));
+ remove_backpointer(trans, inode));
if (ret) {
bch_err(c, "error removing dirent: %i", ret);
break;
}
- ret = reattach_inode(trans, inode);
+ ret = reattach_inode(trans, inode, snapshot);
break;
}
@@ -1160,7 +1234,7 @@ static int check_directory_structure(struct bch_fs *c)
break;
}
- ret = check_path(&trans, &path, &u);
+ ret = check_path(&trans, &path, &u, iter.pos.snapshot);
if (ret)
break;
}