mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-08 14:23:19 +00:00
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: Kent Overstreet <kent.overstreet@linux.dev>
This commit is contained in:
parent
c558c577cb
commit
d296e7b185
@ -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:
|
||||
bch2_inode_init_early(c, 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));
|
||||
|
||||
ret = bch2_create_trans(trans, root_inum, &root,
|
||||
lostfound, &lostfound_str,
|
||||
0, 0, S_IFDIR|0700, 0, NULL, NULL,
|
||||
(subvol_inum) { }, 0);
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user