Commit d296e7b1 authored by Kent Overstreet's avatar Kent Overstreet
Browse files

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
Loading
Loading
Loading
Loading
+28 −0
Original line number Diff line number Diff line
@@ -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,
+4 −0
Original line number Diff line number Diff line
@@ -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 *,
+60 −46
Original line number Diff line number Diff line
@@ -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;

	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);
	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");
	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,11 +333,8 @@ 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,
				 },
	ret = bch2_dirent_create_snapshot(trans,
				lostfound.bi_inum, inode_snapshot,
				&dir_hash,
				inode_d_type(inode),
				&name, inode->bi_inum, &dir_offset,