Commit 6fed42bb authored by Kent Overstreet's avatar Kent Overstreet Committed by Kent Overstreet
Browse files

bcachefs: Plumb through subvolume id



To implement snapshots, we need every filesystem btree operation (every
btree operation without a subvolume) to start by looking up the
subvolume and getting the current snapshot ID, with
bch2_subvolume_get_snapshot() - then, that snapshot ID is used for doing
btree lookups in BTREE_ITER_FILTER_SNAPSHOTS mode.

This patch adds those bch2_subvolume_get_snapshot() calls, and also
switches to passing around a subvol_inum instead of just an inode
number.

Signed-off-by: default avatarKent Overstreet <kent.overstreet@gmail.com>
parent c075ff70
Loading
Loading
Loading
Loading
+11 −14
Original line number Diff line number Diff line
@@ -230,7 +230,7 @@ struct posix_acl *bch2_get_acl(struct mnt_idmap *idmap,
	bch2_trans_begin(&trans);

	ret = bch2_hash_lookup(&trans, &iter, bch2_xattr_hash_desc,
			&hash, inode->v.i_ino,
			&hash, inode_inum(inode),
			&X_SEARCH(acl_to_xattr_type(type), "", 0),
			0);
	if (ret) {
@@ -260,11 +260,11 @@ struct posix_acl *bch2_get_acl(struct mnt_idmap *idmap,
	return acl;
}

int bch2_set_acl_trans(struct btree_trans *trans,
int bch2_set_acl_trans(struct btree_trans *trans, subvol_inum inum,
		       struct bch_inode_unpacked *inode_u,
		       const struct bch_hash_info *hash_info,
		       struct posix_acl *acl, int type)
{
	struct bch_hash_info hash_info = bch2_hash_info_init(trans->c, inode_u);
	int ret;

	if (type == ACL_TYPE_DEFAULT &&
@@ -277,14 +277,14 @@ int bch2_set_acl_trans(struct btree_trans *trans,
		if (IS_ERR(xattr))
			return PTR_ERR(xattr);

		ret = bch2_hash_set(trans, bch2_xattr_hash_desc, hash_info,
				    inode_u->bi_inum, &xattr->k_i, 0);
		ret = bch2_hash_set(trans, bch2_xattr_hash_desc, &hash_info,
				    inum, &xattr->k_i, 0);
	} else {
		struct xattr_search_key search =
			X_SEARCH(acl_to_xattr_type(type), "", 0);

		ret = bch2_hash_delete(trans, bch2_xattr_hash_desc, hash_info,
				       inode_u->bi_inum, &search);
		ret = bch2_hash_delete(trans, bch2_xattr_hash_desc, &hash_info,
				       inum, &search);
	}

	return ret == -ENOENT ? 0 : ret;
@@ -299,7 +299,6 @@ int bch2_set_acl(struct mnt_idmap *idmap,
	struct btree_trans trans;
	struct btree_iter inode_iter = { NULL };
	struct bch_inode_unpacked inode_u;
	struct bch_hash_info hash_info;
	struct posix_acl *acl;
	umode_t mode;
	int ret;
@@ -310,7 +309,7 @@ int bch2_set_acl(struct mnt_idmap *idmap,
	bch2_trans_begin(&trans);
	acl = _acl;

	ret = bch2_inode_peek(&trans, &inode_iter, &inode_u, inode->v.i_ino,
	ret = bch2_inode_peek(&trans, &inode_iter, &inode_u, inode_inum(inode),
			      BTREE_ITER_INTENT);
	if (ret)
		goto btree_err;
@@ -323,9 +322,7 @@ int bch2_set_acl(struct mnt_idmap *idmap,
			goto btree_err;
	}

	hash_info = bch2_hash_info_init(c, &inode_u);

	ret = bch2_set_acl_trans(&trans, &inode_u, &hash_info, acl, type);
	ret = bch2_set_acl_trans(&trans, inode_inum(inode), &inode_u, acl, type);
	if (ret)
		goto btree_err;

@@ -354,7 +351,7 @@ int bch2_set_acl(struct mnt_idmap *idmap,
	return ret;
}

int bch2_acl_chmod(struct btree_trans *trans,
int bch2_acl_chmod(struct btree_trans *trans, subvol_inum inum,
		   struct bch_inode_unpacked *inode,
		   umode_t mode,
		   struct posix_acl **new_acl)
@@ -368,7 +365,7 @@ int bch2_acl_chmod(struct btree_trans *trans,
	int ret;

	ret = bch2_hash_lookup(trans, &iter, bch2_xattr_hash_desc,
			&hash_info, inode->bi_inum,
			       &hash_info, inum,
			&X_SEARCH(KEY_TYPE_XATTR_INDEX_POSIX_ACL_ACCESS, "", 0),
			BTREE_ITER_INTENT);
	if (ret)
+5 −6
Original line number Diff line number Diff line
@@ -28,25 +28,24 @@ typedef struct {

struct posix_acl *bch2_get_acl(struct mnt_idmap *, struct dentry *, int);

int bch2_set_acl_trans(struct btree_trans *,
int bch2_set_acl_trans(struct btree_trans *, subvol_inum,
		       struct bch_inode_unpacked *,
		       const struct bch_hash_info *,
		       struct posix_acl *, int);
int bch2_set_acl(struct mnt_idmap *, struct dentry *, struct posix_acl *, int);
int bch2_acl_chmod(struct btree_trans *, struct bch_inode_unpacked *,
int bch2_acl_chmod(struct btree_trans *, subvol_inum,
		   struct bch_inode_unpacked *,
		   umode_t, struct posix_acl **);

#else

static inline int bch2_set_acl_trans(struct btree_trans *trans,
static inline int bch2_set_acl_trans(struct btree_trans *trans, subvol_inum inum,
				     struct bch_inode_unpacked *inode_u,
				     const struct bch_hash_info *hash_info,
				     struct posix_acl *acl, int type)
{
	return 0;
}

static inline int bch2_acl_chmod(struct btree_trans *trans,
static inline int bch2_acl_chmod(struct btree_trans *trans, subvol_inum inum,
				 struct bch_inode_unpacked *inode,
				 umode_t mode,
				 struct posix_acl **new_acl)
+72 −35
Original line number Diff line number Diff line
@@ -8,6 +8,7 @@
#include "fs.h"
#include "keylist.h"
#include "str_hash.h"
#include "subvolume.h"

#include <linux/dcache.h>

@@ -150,8 +151,8 @@ static struct bkey_i_dirent *dirent_create_key(struct btree_trans *trans,
	return dirent;
}

int bch2_dirent_create(struct btree_trans *trans,
		       u64 dir_inum, const struct bch_hash_info *hash_info,
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,
		       u64 *dir_offset, int flags)
{
@@ -164,7 +165,7 @@ int bch2_dirent_create(struct btree_trans *trans,
		return ret;

	ret = bch2_hash_set(trans, bch2_dirent_hash_desc, hash_info,
			    dir_inum, &dirent->k_i, flags);
			    dir, &dirent->k_i, flags);
	*dir_offset = dirent->k.p.offset;

	return ret;
@@ -223,20 +224,25 @@ int __bch2_dirent_read_target(struct btree_trans *trans,
	return ret;
}

int bch2_dirent_read_target(struct btree_trans *trans,
			    struct bkey_s_c_dirent d, u64 *target)
static int bch2_dirent_read_target(struct btree_trans *trans, subvol_inum dir,
				   struct bkey_s_c_dirent d, subvol_inum *target)
{
	u32 subvol, snapshot;
	u32 snapshot;
	int ret = 0;

	return __bch2_dirent_read_target(trans, d, &subvol,
					 &snapshot, target, false);
	ret = __bch2_dirent_read_target(trans, d, &target->subvol, &snapshot,
					&target->inum, false);
	if (!target->subvol)
		target->subvol = dir.subvol;

	return ret;
}

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,
		       const struct qstr *src_name, u64 *src_inum, u64 *src_offset,
		       const struct qstr *dst_name, u64 *dst_inum, u64 *dst_offset,
		subvol_inum src_dir, struct bch_hash_info *src_hash,
		subvol_inum dst_dir, struct bch_hash_info *dst_hash,
		const struct qstr *src_name, subvol_inum *src_inum, u64 *src_offset,
		const struct qstr *dst_name, subvol_inum *dst_inum, u64 *dst_offset,
		enum bch_rename_mode mode)
{
	struct btree_iter src_iter = { NULL };
@@ -244,10 +250,14 @@ int bch2_dirent_rename(struct btree_trans *trans,
	struct bkey_s_c old_src, old_dst;
	struct bkey_i_dirent *new_src = NULL, *new_dst = NULL;
	struct bpos dst_pos =
		POS(dst_dir, bch2_dirent_hash(dst_hash, dst_name));
		POS(dst_dir.inum, bch2_dirent_hash(dst_hash, dst_name));
	int ret = 0;

	*src_inum = *dst_inum = 0;
	if (src_dir.subvol != dst_dir.subvol)
		return -EXDEV;

	memset(src_inum, 0, sizeof(*src_inum));
	memset(dst_inum, 0, sizeof(*dst_inum));

	/*
	 * Lookup dst:
@@ -270,8 +280,12 @@ int bch2_dirent_rename(struct btree_trans *trans,
	if (ret)
		goto out;

	if (mode != BCH_RENAME)
		*dst_inum = le64_to_cpu(bkey_s_c_to_dirent(old_dst).v->d_inum);
	if (mode != BCH_RENAME) {
		ret = bch2_dirent_read_target(trans, dst_dir,
				bkey_s_c_to_dirent(old_dst), dst_inum);
		if (ret)
			goto out;
	}
	if (mode != BCH_RENAME_EXCHANGE)
		*src_offset = dst_iter.pos.offset;

@@ -287,7 +301,10 @@ int bch2_dirent_rename(struct btree_trans *trans,
	if (ret)
		goto out;

	*src_inum = le64_to_cpu(bkey_s_c_to_dirent(old_src).v->d_inum);
	ret = bch2_dirent_read_target(trans, src_dir,
			bkey_s_c_to_dirent(old_src), src_inum);
	if (ret)
		goto out;

	/* Create new dst key: */
	new_dst = dirent_create_key(trans, 0, dst_name, 0);
@@ -376,17 +393,22 @@ int bch2_dirent_delete_at(struct btree_trans *trans,

int __bch2_dirent_lookup_trans(struct btree_trans *trans,
			       struct btree_iter *iter,
			       u64 dir_inum,
			       subvol_inum dir,
			       const struct bch_hash_info *hash_info,
			       const struct qstr *name, u64 *inum,
			       const struct qstr *name, subvol_inum *inum,
			       unsigned flags)
{
	struct bkey_s_c k;
	struct bkey_s_c_dirent d;
	u32 snapshot;
	int ret;

	ret = bch2_subvolume_get_snapshot(trans, dir.subvol, &snapshot);
	if (ret)
		return ret;

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

@@ -399,44 +421,49 @@ int __bch2_dirent_lookup_trans(struct btree_trans *trans,

	d = bkey_s_c_to_dirent(k);

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

	return ret;
}

u64 bch2_dirent_lookup(struct bch_fs *c, u64 dir_inum,
u64 bch2_dirent_lookup(struct bch_fs *c, subvol_inum dir,
		       const struct bch_hash_info *hash_info,
		       const struct qstr *name)
		       const struct qstr *name, subvol_inum *inum)
{
	struct btree_trans trans;
	struct btree_iter iter;
	u64 inum = 0;
	int ret = 0;
	int ret;

	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, hash_info,
					  name, inum, 0);

	bch2_trans_iter_exit(&trans, &iter);
	if (ret == -EINTR)
		goto retry;
	bch2_trans_exit(&trans);
	return inum;
	return ret;
}

int bch2_empty_dir_trans(struct btree_trans *trans, u64 dir_inum)
int bch2_empty_dir_trans(struct btree_trans *trans, subvol_inum dir)
{
	struct btree_iter iter;
	struct bkey_s_c k;
	u32 snapshot;
	int ret;

	ret = bch2_subvolume_get_snapshot(trans, dir.subvol, &snapshot);
	if (ret)
		return ret;

	for_each_btree_key(trans, iter, BTREE_ID_dirents,
			   POS(dir_inum, 0), 0, k, ret) {
		if (k.k->p.inode > dir_inum)
			   SPOS(dir.inum, 0, snapshot), 0, k, ret) {
		if (k.k->p.inode > dir.inum)
			break;

		if (k.k->type == KEY_TYPE_dirent) {
@@ -449,19 +476,26 @@ int bch2_empty_dir_trans(struct btree_trans *trans, u64 dir_inum)
	return ret;
}

int bch2_readdir(struct bch_fs *c, u64 inum, struct dir_context *ctx)
int bch2_readdir(struct bch_fs *c, subvol_inum inum, struct dir_context *ctx)
{
	struct btree_trans trans;
	struct btree_iter iter;
	struct bkey_s_c k;
	struct bkey_s_c_dirent dirent;
	u32 snapshot;
	int ret;

	bch2_trans_init(&trans, c, 0, 0);
retry:
	bch2_trans_begin(&trans);

	ret = bch2_subvolume_get_snapshot(&trans, inum.subvol, &snapshot);
	if (ret)
		goto err;

	for_each_btree_key(&trans, iter, BTREE_ID_dirents,
			   POS(inum, ctx->pos), 0, k, ret) {
		if (k.k->p.inode > inum)
			   SPOS(inum.inum, ctx->pos, snapshot), 0, k, ret) {
		if (k.k->p.inode > inum.inum)
			break;

		if (k.k->type != KEY_TYPE_dirent)
@@ -482,6 +516,9 @@ int bch2_readdir(struct bch_fs *c, u64 inum, struct dir_context *ctx)
		ctx->pos = dirent.k->p.offset + 1;
	}
	bch2_trans_iter_exit(&trans, &iter);
err:
	if (ret == -EINTR)
		goto retry;

	ret = bch2_trans_exit(&trans) ?: ret;

+13 −16
Original line number Diff line number Diff line
@@ -29,7 +29,7 @@ static inline unsigned dirent_val_u64s(unsigned len)
			    sizeof(u64));
}

int bch2_dirent_create(struct btree_trans *, u64,
int bch2_dirent_create(struct btree_trans *, subvol_inum,
		       const struct bch_hash_info *, u8,
		       const struct qstr *, u64, u64 *, int);

@@ -40,9 +40,6 @@ int bch2_dirent_delete_at(struct btree_trans *,
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;
@@ -55,20 +52,20 @@ enum bch_rename_mode {
};

int bch2_dirent_rename(struct btree_trans *,
		       u64, struct bch_hash_info *,
		       u64, struct bch_hash_info *,
		       const struct qstr *, u64 *, u64 *,
		       const struct qstr *, u64 *, u64 *,
		       subvol_inum, struct bch_hash_info *,
		       subvol_inum, struct bch_hash_info *,
		       const struct qstr *, subvol_inum *, u64 *,
		       const struct qstr *, subvol_inum *, u64 *,
		       enum bch_rename_mode);

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

int bch2_empty_dir_trans(struct btree_trans *, u64);
int bch2_readdir(struct bch_fs *, u64, struct dir_context *);
int bch2_empty_dir_trans(struct btree_trans *, subvol_inum);
int bch2_readdir(struct bch_fs *, subvol_inum, struct dir_context *);

#endif /* _BCACHEFS_DIRENT_H */
+0 −32
Original line number Diff line number Diff line
@@ -611,38 +611,6 @@ bool bch2_bkey_is_incompressible(struct bkey_s_c k)
	return false;
}

bool bch2_check_range_allocated(struct bch_fs *c, struct bpos pos, u64 size,
				unsigned nr_replicas, bool compressed)
{
	struct btree_trans trans;
	struct btree_iter iter;
	struct bpos end = pos;
	struct bkey_s_c k;
	bool ret = true;
	int err;

	end.offset += size;

	bch2_trans_init(&trans, c, 0, 0);

	for_each_btree_key(&trans, iter, BTREE_ID_extents, pos,
			   BTREE_ITER_SLOTS, k, err) {
		if (bkey_cmp(bkey_start_pos(k.k), end) >= 0)
			break;

		if (nr_replicas > bch2_bkey_replicas(c, k) ||
		    (!compressed && bch2_bkey_sectors_compressed(k))) {
			ret = false;
			break;
		}
	}
	bch2_trans_iter_exit(&trans, &iter);

	bch2_trans_exit(&trans);

	return ret;
}

unsigned bch2_bkey_replicas(struct bch_fs *c, struct bkey_s_c k)
{
	struct bkey_ptrs_c ptrs = bch2_bkey_ptrs_c(k);
Loading