Commit d296e7b1 authored by Kent Overstreet's avatar Kent Overstreet

bcachefs: Fix reattach_inode() for snapshots

reattach_inode() was broken w.r.t. snapshots - we'd lookup the subvolume
to look up lost+found, but if we're in an interior node snapshot that
didn't make any sense.

Instead, this adds a dirent path for creating in a specific snapshot,
skipping the subvolume; and we also make sure to create lost+found in
the root snapshot, to avoid conflicts with lost+found being created in
overlapping snapshots.
Signed-off-by: default avatarKent Overstreet <kent.overstreet@linux.dev>
parent c558c577
......@@ -198,6 +198,34 @@ static struct bkey_i_dirent *dirent_create_key(struct btree_trans *trans,
return dirent;
}
int bch2_dirent_create_snapshot(struct btree_trans *trans,
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 };
struct bkey_i_dirent *dirent;
int ret;
dirent = dirent_create_key(trans, zero_inum, type, name, dst_inum);
ret = PTR_ERR_OR_ZERO(dirent);
if (ret)
return ret;
dirent->k.p.inode = dir;
dirent->k.p.snapshot = snapshot;
ret = bch2_hash_set_snapshot(trans, bch2_dirent_hash_desc, hash_info,
zero_inum, snapshot,
&dirent->k_i, str_hash_flags,
BTREE_UPDATE_INTERNAL_SNAPSHOT_NODE);
*dir_offset = dirent->k.p.offset;
return ret;
}
int bch2_dirent_create(struct btree_trans *trans, subvol_inum dir,
const struct bch_hash_info *hash_info,
u8 type, const struct qstr *name, u64 dst_inum,
......
......@@ -35,6 +35,10 @@ 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,
const struct bch_hash_info *, u8,
const struct qstr *, u64, u64 *,
bch_str_hash_flags_t);
int bch2_dirent_create(struct btree_trans *, subvol_inum,
const struct bch_hash_info *, u8,
const struct qstr *, u64, u64 *,
......
......@@ -59,21 +59,6 @@ static s64 bch2_count_subdirs(struct btree_trans *trans, u64 inum,
return ret ?: subdirs;
}
static int __snapshot_lookup_subvol(struct btree_trans *trans, u32 snapshot,
u32 *subvol)
{
struct bch_snapshot s;
int ret = bch2_bkey_get_val_typed(trans, BTREE_ID_snapshots,
POS(0, snapshot), 0,
snapshot, &s);
if (!ret)
*subvol = le32_to_cpu(s.subvol);
else if (bch2_err_matches(ret, ENOENT))
bch_err(trans->c, "snapshot %u not found", snapshot);
return ret;
}
static int __subvol_lookup(struct btree_trans *trans, u32 subvol,
u32 *snapshot, u64 *inum)
{
......@@ -227,35 +212,42 @@ 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,
static int lookup_lostfound(struct btree_trans *trans, u32 snapshot,
struct bch_inode_unpacked *lostfound)
{
struct bch_fs *c = trans->c;
struct bch_inode_unpacked root;
struct bch_hash_info root_hash_info;
struct qstr lostfound_str = QSTR("lost+found");
subvol_inum root_inum = { .subvol = subvol };
u64 inum = 0;
unsigned d_type = 0;
u32 snapshot;
int ret;
ret = __subvol_lookup(trans, subvol, &snapshot, &root_inum.inum);
struct bch_snapshot_tree st;
ret = bch2_snapshot_tree_lookup(trans,
bch2_snapshot_tree(c, snapshot), &st);
if (ret)
return ret;
ret = __lookup_inode(trans, root_inum.inum, &root, &snapshot);
subvol_inum root_inum = { .subvol = le32_to_cpu(st.master_subvol) };
u32 subvol_snapshot;
ret = __subvol_lookup(trans, le32_to_cpu(st.master_subvol),
&subvol_snapshot, &root_inum.inum);
bch_err_msg(c, ret, "looking up root subvol");
if (ret)
return ret;
root_hash_info = bch2_hash_info_init(c, &root);
struct bch_inode_unpacked root_inode;
struct bch_hash_info root_hash_info;
ret = __lookup_inode(trans, root_inum.inum, &root_inode, &snapshot);
if (ret)
return ret;
root_hash_info = bch2_hash_info_init(c, &root_inode);
ret = __lookup_dirent(trans, root_hash_info, root_inum,
&lostfound_str, &inum, &d_type);
if (bch2_err_matches(ret, ENOENT)) {
bch_notice(c, "creating lost+found");
&lostfound_str, &inum, &d_type);
if (bch2_err_matches(ret, ENOENT))
goto create_lostfound;
}
bch_err_fn(c, ret);
if (ret)
......@@ -273,13 +265,43 @@ static int lookup_lostfound(struct btree_trans *trans, u32 subvol,
return __lookup_inode(trans, inum, lostfound, &snapshot);
create_lostfound:
/*
* XXX: we could have a nicer log message here if we had a nice way to
* walk backpointers to print a path
*/
bch_notice(c, "creating lost+found in snapshot %u", le32_to_cpu(st.root_snapshot));
u64 now = bch2_current_time(c);
struct btree_iter lostfound_iter = { NULL };
u64 cpu = raw_smp_processor_id();
bch2_inode_init_early(c, lostfound);
bch2_inode_init_late(lostfound, now, 0, 0, S_IFDIR|0700, 0, &root_inode);
lostfound->bi_dir = root_inode.bi_inum;
root_inode.bi_nlink++;
ret = bch2_inode_create(trans, &lostfound_iter, lostfound, snapshot, cpu);
if (ret)
goto err;
ret = bch2_create_trans(trans, root_inum, &root,
lostfound, &lostfound_str,
0, 0, S_IFDIR|0700, 0, NULL, NULL,
(subvol_inum) { }, 0);
bch2_btree_iter_set_snapshot(&lostfound_iter, snapshot);
ret = bch2_btree_iter_traverse(&lostfound_iter);
if (ret)
goto err;
ret = bch2_dirent_create_snapshot(trans,
root_inode.bi_inum, snapshot, &root_hash_info,
mode_to_type(lostfound->bi_mode),
&lostfound_str,
lostfound->bi_inum,
&lostfound->bi_dir_offset,
BCH_HASH_SET_MUST_CREATE) ?:
bch2_inode_write_flags(trans, &lostfound_iter, lostfound,
BTREE_UPDATE_INTERNAL_SNAPSHOT_NODE);
err:
bch_err_msg(c, ret, "creating lost+found");
bch2_trans_iter_exit(trans, &lostfound_iter);
return ret;
}
......@@ -292,14 +314,9 @@ static int __reattach_inode(struct btree_trans *trans,
char name_buf[20];
struct qstr name;
u64 dir_offset = 0;
u32 subvol;
int ret;
ret = __snapshot_lookup_subvol(trans, inode_snapshot, &subvol);
if (ret)
return ret;
ret = lookup_lostfound(trans, subvol, &lostfound);
ret = lookup_lostfound(trans, inode_snapshot, &lostfound);
if (ret)
return ret;
......@@ -316,15 +333,12 @@ static int __reattach_inode(struct btree_trans *trans,
snprintf(name_buf, sizeof(name_buf), "%llu", inode->bi_inum);
name = (struct qstr) QSTR(name_buf);
ret = bch2_dirent_create(trans,
(subvol_inum) {
.subvol = subvol,
.inum = lostfound.bi_inum,
},
&dir_hash,
inode_d_type(inode),
&name, inode->bi_inum, &dir_offset,
BCH_HASH_SET_MUST_CREATE);
ret = bch2_dirent_create_snapshot(trans,
lostfound.bi_inum, inode_snapshot,
&dir_hash,
inode_d_type(inode),
&name, inode->bi_inum, &dir_offset,
BCH_HASH_SET_MUST_CREATE);
if (ret)
return ret;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment