Commit b9e1adf5 authored by Kent Overstreet's avatar Kent Overstreet Committed by Kent Overstreet
Browse files

bcachefs: Add support for dirents that point to subvolumes



Dirents currently always point to inodes. Subvolumes add a new type of
dirent, with d_type DT_SUBVOL, that instead points to an entry in the
subvolumes btree, and the subvolume has a pointer to the root inode.

This patch adds bch2_dirent_read_target() to get the inode (and
potentially subvolume) a dirent points to, and changes existing code to
use that instead of reading from d_inum directly.

Signed-off-by: default avatarKent Overstreet <kent.overstreet@gmail.com>
parent 14b393ee
Loading
Loading
Loading
Loading
+87 −18
Original line number Diff line number Diff line
@@ -177,6 +177,61 @@ static void dirent_copy_target(struct bkey_i_dirent *dst,
	dst->v.d_type = src.v->d_type;
}

int __bch2_dirent_read_target(struct btree_trans *trans,
			      struct bkey_s_c_dirent d,
			      u32 *subvol, u32 *snapshot, u64 *inum,
			      bool is_fsck)
{
	int ret = 0;

	*subvol		= 0;
	*snapshot	= d.k->p.snapshot;

	if (likely(d.v->d_type != DT_SUBVOL)) {
		*inum = le64_to_cpu(d.v->d_inum);
	} else {
		struct btree_iter iter;
		struct bkey_s_c k;
		struct bkey_s_c_subvolume s;
		int ret;

		*subvol = le64_to_cpu(d.v->d_inum);
		bch2_trans_iter_init(trans, &iter, BTREE_ID_subvolumes,
				     POS(0, *subvol),
				     BTREE_ITER_CACHED);
		k = bch2_btree_iter_peek_slot(&iter);
		ret = bkey_err(k);
		if (ret)
			goto err;

		if (k.k->type != KEY_TYPE_subvolume) {
			ret = -ENOENT;
			goto err;
		}

		s = bkey_s_c_to_subvolume(k);
		*snapshot	= le32_to_cpu(s.v->snapshot);
		*inum		= le64_to_cpu(s.v->inode);
err:
		if (ret == -ENOENT && !is_fsck)
			bch2_fs_inconsistent(trans->c, "pointer to missing subvolume %u",
					     *subvol);

		bch2_trans_iter_exit(trans, &iter);
	}

	return ret;
}

int bch2_dirent_read_target(struct btree_trans *trans,
			    struct bkey_s_c_dirent d, u64 *target)
{
	u32 subvol, snapshot;

	return __bch2_dirent_read_target(trans, d, &subvol,
					 &snapshot, target, false);
}

int bch2_dirent_rename(struct btree_trans *trans,
		       u64 src_dir, struct bch_hash_info *src_hash,
		       u64 dst_dir, struct bch_hash_info *dst_hash,
@@ -323,10 +378,32 @@ int __bch2_dirent_lookup_trans(struct btree_trans *trans,
			       struct btree_iter *iter,
			       u64 dir_inum,
			       const struct bch_hash_info *hash_info,
			       const struct qstr *name, unsigned flags)
			       const struct qstr *name, u64 *inum,
			       unsigned flags)
{
	return bch2_hash_lookup(trans, iter, bch2_dirent_hash_desc,
	struct bkey_s_c k;
	struct bkey_s_c_dirent d;
	int ret;

	ret = bch2_hash_lookup(trans, iter, bch2_dirent_hash_desc,
			       hash_info, dir_inum, name, flags);
	if (ret)
		return ret;

	k = bch2_btree_iter_peek_slot(iter);
	ret = bkey_err(k);
	if (ret) {
		bch2_trans_iter_exit(trans, iter);
		return ret;
	}

	d = bkey_s_c_to_dirent(k);

	ret = bch2_dirent_read_target(trans, d, inum);
	if (ret)
		bch2_trans_iter_exit(trans, iter);

	return ret;
}

u64 bch2_dirent_lookup(struct bch_fs *c, u64 dir_inum,
@@ -335,26 +412,18 @@ u64 bch2_dirent_lookup(struct bch_fs *c, u64 dir_inum,
{
	struct btree_trans trans;
	struct btree_iter iter;
	struct bkey_s_c k;
	u64 inum = 0;
	int ret = 0;

	bch2_trans_init(&trans, c, 0, 0);
retry:
	bch2_trans_begin(&trans);
	ret = __bch2_dirent_lookup_trans(&trans, &iter, dir_inum, hash_info,
					 name, &inum, 0);

	ret = __bch2_dirent_lookup_trans(&trans, &iter, dir_inum,
					 hash_info, name, 0);
	if (ret)
		goto out;

	k = bch2_btree_iter_peek_slot(&iter);
	ret = bkey_err(k);
	if (ret)
		goto out;

	inum = le64_to_cpu(bkey_s_c_to_dirent(k).v->d_inum);
	bch2_trans_iter_exit(&trans, &iter);
out:
	BUG_ON(ret == -EINTR);
	if (ret == -EINTR)
		goto retry;
	bch2_trans_exit(&trans);
	return inum;
}
@@ -408,7 +477,7 @@ int bch2_readdir(struct bch_fs *c, u64 inum, struct dir_context *ctx)
		if (!dir_emit(ctx, dirent.v->d_name,
			      bch2_dirent_name_bytes(dirent),
			      le64_to_cpu(dirent.v->d_inum),
			      dirent.v->d_type))
			      vfs_d_type(dirent.v->d_type)))
			break;
		ctx->pos = dirent.k->p.offset + 1;
	}
+13 −1
Original line number Diff line number Diff line
@@ -37,6 +37,17 @@ int bch2_dirent_delete_at(struct btree_trans *,
			  const struct bch_hash_info *,
			  struct btree_iter *);

int __bch2_dirent_read_target(struct btree_trans *, struct bkey_s_c_dirent,
			      u32 *, u32 *, u64 *, bool);

int bch2_dirent_read_target(struct btree_trans *,
			    struct bkey_s_c_dirent, u64 *);

static inline unsigned vfs_d_type(unsigned type)
{
	return type == DT_SUBVOL ? DT_DIR : type;
}

enum bch_rename_mode {
	BCH_RENAME,
	BCH_RENAME_OVERWRITE,
@@ -52,7 +63,8 @@ int bch2_dirent_rename(struct btree_trans *,

int __bch2_dirent_lookup_trans(struct btree_trans *, struct btree_iter *, u64,
			   const struct bch_hash_info *,
			   const struct qstr *, unsigned);
			   const struct qstr *, u64 *,
			   unsigned);
u64 bch2_dirent_lookup(struct bch_fs *, u64, const struct bch_hash_info *,
		       const struct qstr *);

+1 −8
Original line number Diff line number Diff line
@@ -159,17 +159,10 @@ int bch2_unlink_trans(struct btree_trans *trans,
	dir_hash = bch2_hash_info_init(c, dir_u);

	ret = __bch2_dirent_lookup_trans(trans, &dirent_iter, dir_inum, &dir_hash,
					 name, BTREE_ITER_INTENT);
					 name, &inum, BTREE_ITER_INTENT);
	if (ret)
		goto err;

	k = bch2_btree_iter_peek_slot(&dirent_iter);
	ret = bkey_err(k);
	if (ret)
		goto err;

	inum = le64_to_cpu(bkey_s_c_to_dirent(k).v->d_inum);

	ret = bch2_inode_peek(trans, &inode_iter, inode_u, inum, BTREE_ITER_INTENT);
	if (ret)
		goto err;
+22 −1
Original line number Diff line number Diff line
@@ -723,6 +723,7 @@ static int check_dirent(struct btree_trans *trans, struct btree_iter *iter,
	struct bkey_s_c_dirent d;
	struct bch_inode_unpacked target;
	u32 target_snapshot;
	u32 target_subvol;
	bool have_target;
	bool backpointer_exists = true;
	u64 d_inum;
@@ -783,6 +784,10 @@ static int check_dirent(struct btree_trans *trans, struct btree_iter *iter,
	d = bkey_s_c_to_dirent(k);
	d_inum = le64_to_cpu(d.v->d_inum);

	ret = bch2_dirent_read_target(trans, d, &d_inum);
	if (ret && ret != -ENOENT)
		return ret;

	ret = __lookup_inode(trans, d_inum, &target, &target_snapshot);
	if (ret && ret != -ENOENT)
		return ret;
@@ -855,7 +860,23 @@ static int check_dirent(struct btree_trans *trans, struct btree_iter *iter,
		}
	}

	if (fsck_err_on(d.v->d_type != mode_to_type(target.bi_mode), c,
	target_subvol = d.v->d_type == DT_SUBVOL
		? le64_to_cpu(d.v->d_inum) : 0;

	if (fsck_err_on(target.bi_subvol != target_subvol, c,
			"subvol root %llu has wrong subvol field:\n"
			"got       %u\n"
			"should be %u",
			target.bi_inum,
			target.bi_subvol,
			target_subvol)) {
		target.bi_subvol = target_subvol;

		ret = write_inode(trans, &target, target_snapshot);
		return ret ?: -EINTR;
	}

	if (fsck_err_on(vfs_d_type(d.v->d_type) != mode_to_type(target.bi_mode), c,
			"incorrect d_type: should be %u:\n%s",
			mode_to_type(target.bi_mode),
			(bch2_bkey_val_to_text(&PBUF(buf), c,