aboutsummaryrefslogtreecommitdiff
path: root/fs/bcachefs
diff options
context:
space:
mode:
authorGravatar Kent Overstreet <kent.overstreet@gmail.com> 2021-03-16 00:28:17 -0400
committerGravatar Kent Overstreet <kent.overstreet@linux.dev> 2023-10-22 17:09:12 -0400
commit6fed42bb7750e217b0d1169ccfccc7639a3e1d3f (patch)
tree88e8f85e58cd7c68b86c6e804c99a2aebcbb74d0 /fs/bcachefs
parentbcachefs: BTREE_ITER_FILTER_SNAPSHOTS (diff)
downloadlinux-6fed42bb7750e217b0d1169ccfccc7639a3e1d3f.tar.gz
linux-6fed42bb7750e217b0d1169ccfccc7639a3e1d3f.tar.bz2
linux-6fed42bb7750e217b0d1169ccfccc7639a3e1d3f.zip
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: Kent Overstreet <kent.overstreet@gmail.com>
Diffstat (limited to 'fs/bcachefs')
-rw-r--r--fs/bcachefs/acl.c25
-rw-r--r--fs/bcachefs/acl.h11
-rw-r--r--fs/bcachefs/dirent.c107
-rw-r--r--fs/bcachefs/dirent.h29
-rw-r--r--fs/bcachefs/extents.c32
-rw-r--r--fs/bcachefs/extents.h1
-rw-r--r--fs/bcachefs/fs-common.c127
-rw-r--r--fs/bcachefs/fs-common.h21
-rw-r--r--fs/bcachefs/fs-io.c117
-rw-r--r--fs/bcachefs/fs-ioctl.c8
-rw-r--r--fs/bcachefs/fs.c77
-rw-r--r--fs/bcachefs/fs.h4
-rw-r--r--fs/bcachefs/fsck.c5
-rw-r--r--fs/bcachefs/inode.c109
-rw-r--r--fs/bcachefs/inode.h7
-rw-r--r--fs/bcachefs/io.c5
-rw-r--r--fs/bcachefs/move.c3
-rw-r--r--fs/bcachefs/recovery.c5
-rw-r--r--fs/bcachefs/reflink.c18
-rw-r--r--fs/bcachefs/reflink.h4
-rw-r--r--fs/bcachefs/str_hash.h41
-rw-r--r--fs/bcachefs/xattr.c23
-rw-r--r--fs/bcachefs/xattr.h3
23 files changed, 526 insertions, 256 deletions
diff --git a/fs/bcachefs/acl.c b/fs/bcachefs/acl.c
index 93b78e4e6e0d..2afa15b26700 100644
--- a/fs/bcachefs/acl.c
+++ b/fs/bcachefs/acl.c
@@ -230,7 +230,7 @@ retry:
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 @@ out:
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 @@ retry:
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 @@ retry:
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 @@ err:
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)
diff --git a/fs/bcachefs/acl.h b/fs/bcachefs/acl.h
index f11eb9d4592c..bb21d8d696a2 100644
--- a/fs/bcachefs/acl.h
+++ b/fs/bcachefs/acl.h
@@ -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)
diff --git a/fs/bcachefs/dirent.c b/fs/bcachefs/dirent.c
index f3aef0686928..f290580594ce 100644
--- a/fs/bcachefs/dirent.c
+++ b/fs/bcachefs/dirent.c
@@ -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,31 +224,40 @@ err:
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,
- enum bch_rename_mode mode)
+ 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 };
struct btree_iter dst_iter = { NULL };
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;
diff --git a/fs/bcachefs/dirent.h b/fs/bcachefs/dirent.h
index 3cd05a2454e1..88b784a99cb5 100644
--- a/fs/bcachefs/dirent.h
+++ b/fs/bcachefs/dirent.h
@@ -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,
- 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 *);
+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 *, 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 */
diff --git a/fs/bcachefs/extents.c b/fs/bcachefs/extents.c
index 0190605711e5..966d6ef41793 100644
--- a/fs/bcachefs/extents.c
+++ b/fs/bcachefs/extents.c
@@ -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);
diff --git a/fs/bcachefs/extents.h b/fs/bcachefs/extents.h
index 43cef0a3bdf3..afd3067bb64e 100644
--- a/fs/bcachefs/extents.h
+++ b/fs/bcachefs/extents.h
@@ -567,7 +567,6 @@ unsigned bch2_bkey_nr_ptrs_allocated(struct bkey_s_c);
unsigned bch2_bkey_nr_ptrs_fully_allocated(struct bkey_s_c);
bool bch2_bkey_is_incompressible(struct bkey_s_c);
unsigned bch2_bkey_sectors_compressed(struct bkey_s_c);
-bool bch2_check_range_allocated(struct bch_fs *, struct bpos, u64, unsigned, bool);
unsigned bch2_bkey_replicas(struct bch_fs *, struct bkey_s_c);
unsigned bch2_bkey_durability(struct bch_fs *, struct bkey_s_c);
diff --git a/fs/bcachefs/fs-common.c b/fs/bcachefs/fs-common.c
index 96b09b005d0b..02bf32cc7659 100644
--- a/fs/bcachefs/fs-common.c
+++ b/fs/bcachefs/fs-common.c
@@ -6,28 +6,38 @@
#include "dirent.h"
#include "fs-common.h"
#include "inode.h"
+#include "subvolume.h"
#include "xattr.h"
#include <linux/posix_acl.h>
-int bch2_create_trans(struct btree_trans *trans, u64 dir_inum,
+int bch2_create_trans(struct btree_trans *trans,
+ subvol_inum dir,
struct bch_inode_unpacked *dir_u,
struct bch_inode_unpacked *new_inode,
const struct qstr *name,
uid_t uid, gid_t gid, umode_t mode, dev_t rdev,
struct posix_acl *default_acl,
- struct posix_acl *acl)
+ struct posix_acl *acl,
+ unsigned flags)
{
struct bch_fs *c = trans->c;
struct btree_iter dir_iter = { NULL };
struct btree_iter inode_iter = { NULL };
- struct bch_hash_info hash = bch2_hash_info_init(c, new_inode);
+ subvol_inum new_inum = dir;
u64 now = bch2_current_time(c);
u64 cpu = raw_smp_processor_id();
u64 dir_offset = 0;
+ u64 dir_target;
+ u32 snapshot;
+ unsigned dir_type;
int ret;
- ret = bch2_inode_peek(trans, &dir_iter, dir_u, dir_inum, BTREE_ITER_INTENT);
+ ret = bch2_subvolume_get_snapshot(trans, dir.subvol, &snapshot);
+ if (ret)
+ goto err;
+
+ ret = bch2_inode_peek(trans, &dir_iter, dir_u, dir, BTREE_ITER_INTENT);
if (ret)
goto err;
@@ -36,19 +46,23 @@ int bch2_create_trans(struct btree_trans *trans, u64 dir_inum,
if (!name)
new_inode->bi_flags |= BCH_INODE_UNLINKED;
- ret = bch2_inode_create(trans, &inode_iter, new_inode, U32_MAX, cpu);
+ ret = bch2_inode_create(trans, &inode_iter, new_inode, snapshot, cpu);
if (ret)
goto err;
+ new_inum.inum = new_inode->bi_inum;
+ dir_target = new_inode->bi_inum;
+ dir_type = mode_to_type(new_inode->bi_mode);
+
if (default_acl) {
- ret = bch2_set_acl_trans(trans, new_inode, &hash,
+ ret = bch2_set_acl_trans(trans, new_inum, new_inode,
default_acl, ACL_TYPE_DEFAULT);
if (ret)
goto err;
}
if (acl) {
- ret = bch2_set_acl_trans(trans, new_inode, &hash,
+ ret = bch2_set_acl_trans(trans, new_inum, new_inode,
acl, ACL_TYPE_ACCESS);
if (ret)
goto err;
@@ -56,18 +70,19 @@ int bch2_create_trans(struct btree_trans *trans, u64 dir_inum,
if (name) {
struct bch_hash_info dir_hash = bch2_hash_info_init(c, dir_u);
- dir_u->bi_mtime = dir_u->bi_ctime = now;
if (S_ISDIR(new_inode->bi_mode))
dir_u->bi_nlink++;
+ dir_u->bi_mtime = dir_u->bi_ctime = now;
ret = bch2_inode_write(trans, &dir_iter, dir_u);
if (ret)
goto err;
- ret = bch2_dirent_create(trans, dir_inum, &dir_hash,
- mode_to_type(new_inode->bi_mode),
- name, new_inode->bi_inum,
+ ret = bch2_dirent_create(trans, dir, &dir_hash,
+ dir_type,
+ name,
+ dir_target,
&dir_offset,
BCH_HASH_SET_MUST_CREATE);
if (ret)
@@ -79,9 +94,8 @@ int bch2_create_trans(struct btree_trans *trans, u64 dir_inum,
new_inode->bi_dir_offset = dir_offset;
}
- /* XXX use bch2_btree_iter_set_snapshot() */
- inode_iter.snapshot = U32_MAX;
- bch2_btree_iter_set_pos(&inode_iter, SPOS(0, new_inode->bi_inum, U32_MAX));
+ inode_iter.flags &= ~BTREE_ITER_ALL_SNAPSHOTS;
+ bch2_btree_iter_set_snapshot(&inode_iter, snapshot);
ret = bch2_btree_iter_traverse(&inode_iter) ?:
bch2_inode_write(trans, &inode_iter, new_inode);
@@ -91,9 +105,10 @@ err:
return ret;
}
-int bch2_link_trans(struct btree_trans *trans, u64 dir_inum,
- u64 inum, struct bch_inode_unpacked *dir_u,
- struct bch_inode_unpacked *inode_u, const struct qstr *name)
+int bch2_link_trans(struct btree_trans *trans,
+ subvol_inum dir, struct bch_inode_unpacked *dir_u,
+ subvol_inum inum, struct bch_inode_unpacked *inode_u,
+ const struct qstr *name)
{
struct bch_fs *c = trans->c;
struct btree_iter dir_iter = { NULL };
@@ -103,6 +118,9 @@ int bch2_link_trans(struct btree_trans *trans, u64 dir_inum,
u64 dir_offset = 0;
int ret;
+ if (dir.subvol != inum.subvol)
+ return -EXDEV;
+
ret = bch2_inode_peek(trans, &inode_iter, inode_u, inum, BTREE_ITER_INTENT);
if (ret)
goto err;
@@ -110,7 +128,7 @@ int bch2_link_trans(struct btree_trans *trans, u64 dir_inum,
inode_u->bi_ctime = now;
bch2_inode_nlink_inc(inode_u);
- ret = bch2_inode_peek(trans, &dir_iter, dir_u, dir_inum, BTREE_ITER_INTENT);
+ ret = bch2_inode_peek(trans, &dir_iter, dir_u, dir, BTREE_ITER_INTENT);
if (ret)
goto err;
@@ -118,15 +136,15 @@ int bch2_link_trans(struct btree_trans *trans, u64 dir_inum,
dir_hash = bch2_hash_info_init(c, dir_u);
- ret = bch2_dirent_create(trans, dir_inum, &dir_hash,
+ ret = bch2_dirent_create(trans, dir, &dir_hash,
mode_to_type(inode_u->bi_mode),
- name, inum, &dir_offset,
+ name, inum.inum, &dir_offset,
BCH_HASH_SET_MUST_CREATE);
if (ret)
goto err;
if (c->sb.version >= bcachefs_metadata_version_inode_backpointers) {
- inode_u->bi_dir = dir_inum;
+ inode_u->bi_dir = dir.inum;
inode_u->bi_dir_offset = dir_offset;
}
@@ -139,7 +157,8 @@ err:
}
int bch2_unlink_trans(struct btree_trans *trans,
- u64 dir_inum, struct bch_inode_unpacked *dir_u,
+ subvol_inum dir,
+ struct bch_inode_unpacked *dir_u,
struct bch_inode_unpacked *inode_u,
const struct qstr *name)
{
@@ -148,39 +167,49 @@ int bch2_unlink_trans(struct btree_trans *trans,
struct btree_iter dirent_iter = { NULL };
struct btree_iter inode_iter = { NULL };
struct bch_hash_info dir_hash;
- u64 inum, now = bch2_current_time(c);
- struct bkey_s_c k;
+ subvol_inum inum;
+ u64 now = bch2_current_time(c);
int ret;
- ret = bch2_inode_peek(trans, &dir_iter, dir_u, dir_inum, BTREE_ITER_INTENT);
+ ret = bch2_inode_peek(trans, &dir_iter, dir_u, dir, BTREE_ITER_INTENT);
if (ret)
goto err;
dir_hash = bch2_hash_info_init(c, dir_u);
- ret = __bch2_dirent_lookup_trans(trans, &dirent_iter, dir_inum, &dir_hash,
+ ret = __bch2_dirent_lookup_trans(trans, &dirent_iter, dir, &dir_hash,
name, &inum, BTREE_ITER_INTENT);
if (ret)
goto err;
- ret = bch2_inode_peek(trans, &inode_iter, inode_u, inum, BTREE_ITER_INTENT);
+ ret = bch2_inode_peek(trans, &inode_iter, inode_u, inum,
+ BTREE_ITER_INTENT);
if (ret)
goto err;
- if (inode_u->bi_dir == k.k->p.inode &&
- inode_u->bi_dir_offset == k.k->p.offset) {
+ if (inode_u->bi_dir == dirent_iter.pos.inode &&
+ inode_u->bi_dir_offset == dirent_iter.pos.offset) {
inode_u->bi_dir = 0;
inode_u->bi_dir_offset = 0;
}
+ if (S_ISDIR(inode_u->bi_mode)) {
+ ret = bch2_empty_dir_trans(trans, inum);
+ if (ret)
+ goto err;
+ }
+
+ if (dir.subvol != inum.subvol) {
+ ret = bch2_subvolume_delete(trans, inum.subvol, false);
+ if (ret)
+ goto err;
+ }
+
dir_u->bi_mtime = dir_u->bi_ctime = inode_u->bi_ctime = now;
dir_u->bi_nlink -= S_ISDIR(inode_u->bi_mode);
bch2_inode_nlink_dec(inode_u);
- ret = (S_ISDIR(inode_u->bi_mode)
- ? bch2_empty_dir_trans(trans, inum)
- : 0) ?:
- bch2_dirent_delete_at(trans, &dir_hash, &dirent_iter) ?:
+ ret = bch2_dirent_delete_at(trans, &dir_hash, &dirent_iter) ?:
bch2_inode_write(trans, &dir_iter, dir_u) ?:
bch2_inode_write(trans, &inode_iter, inode_u);
err:
@@ -215,8 +244,8 @@ bool bch2_reinherit_attrs(struct bch_inode_unpacked *dst_u,
}
int bch2_rename_trans(struct btree_trans *trans,
- u64 src_dir, struct bch_inode_unpacked *src_dir_u,
- u64 dst_dir, struct bch_inode_unpacked *dst_dir_u,
+ subvol_inum src_dir, struct bch_inode_unpacked *src_dir_u,
+ subvol_inum dst_dir, struct bch_inode_unpacked *dst_dir_u,
struct bch_inode_unpacked *src_inode_u,
struct bch_inode_unpacked *dst_inode_u,
const struct qstr *src_name,
@@ -229,7 +258,8 @@ int bch2_rename_trans(struct btree_trans *trans,
struct btree_iter src_inode_iter = { NULL };
struct btree_iter dst_inode_iter = { NULL };
struct bch_hash_info src_hash, dst_hash;
- u64 src_inode, src_offset, dst_inode, dst_offset;
+ subvol_inum src_inum, dst_inum;
+ u64 src_offset, dst_offset;
u64 now = bch2_current_time(c);
int ret;
@@ -240,7 +270,8 @@ int bch2_rename_trans(struct btree_trans *trans,
src_hash = bch2_hash_info_init(c, src_dir_u);
- if (dst_dir != src_dir) {
+ if (dst_dir.inum != src_dir.inum ||
+ dst_dir.subvol != src_dir.subvol) {
ret = bch2_inode_peek(trans, &dst_dir_iter, dst_dir_u, dst_dir,
BTREE_ITER_INTENT);
if (ret)
@@ -255,19 +286,19 @@ int bch2_rename_trans(struct btree_trans *trans,
ret = bch2_dirent_rename(trans,
src_dir, &src_hash,
dst_dir, &dst_hash,
- src_name, &src_inode, &src_offset,
- dst_name, &dst_inode, &dst_offset,
+ src_name, &src_inum, &src_offset,
+ dst_name, &dst_inum, &dst_offset,
mode);
if (ret)
goto err;
- ret = bch2_inode_peek(trans, &src_inode_iter, src_inode_u, src_inode,
+ ret = bch2_inode_peek(trans, &src_inode_iter, src_inode_u, src_inum,
BTREE_ITER_INTENT);
if (ret)
goto err;
- if (dst_inode) {
- ret = bch2_inode_peek(trans, &dst_inode_iter, dst_inode_u, dst_inode,
+ if (dst_inum.inum) {
+ ret = bch2_inode_peek(trans, &dst_inode_iter, dst_inode_u, dst_inum,
BTREE_ITER_INTENT);
if (ret)
goto err;
@@ -298,7 +329,7 @@ int bch2_rename_trans(struct btree_trans *trans,
}
if (S_ISDIR(dst_inode_u->bi_mode) &&
- bch2_empty_dir_trans(trans, dst_inode)) {
+ bch2_empty_dir_trans(trans, dst_inum)) {
ret = -ENOTEMPTY;
goto err;
}
@@ -322,7 +353,7 @@ int bch2_rename_trans(struct btree_trans *trans,
dst_dir_u->bi_nlink++;
}
- if (dst_inode && S_ISDIR(dst_inode_u->bi_mode)) {
+ if (dst_inum.inum && S_ISDIR(dst_inode_u->bi_mode)) {
dst_dir_u->bi_nlink--;
src_dir_u->bi_nlink += mode == BCH_RENAME_EXCHANGE;
}
@@ -333,22 +364,22 @@ int bch2_rename_trans(struct btree_trans *trans,
src_dir_u->bi_mtime = now;
src_dir_u->bi_ctime = now;
- if (src_dir != dst_dir) {
+ if (src_dir.inum != dst_dir.inum) {
dst_dir_u->bi_mtime = now;
dst_dir_u->bi_ctime = now;
}
src_inode_u->bi_ctime = now;
- if (dst_inode)
+ if (dst_inum.inum)
dst_inode_u->bi_ctime = now;
ret = bch2_inode_write(trans, &src_dir_iter, src_dir_u) ?:
- (src_dir != dst_dir
+ (src_dir.inum != dst_dir.inum
? bch2_inode_write(trans, &dst_dir_iter, dst_dir_u)
: 0 ) ?:
bch2_inode_write(trans, &src_inode_iter, src_inode_u) ?:
- (dst_inode
+ (dst_inum.inum
? bch2_inode_write(trans, &dst_inode_iter, dst_inode_u)
: 0 );
err:
diff --git a/fs/bcachefs/fs-common.h b/fs/bcachefs/fs-common.h
index 2273b7961c9b..1bb2ac4dc13a 100644
--- a/fs/bcachefs/fs-common.h
+++ b/fs/bcachefs/fs-common.h
@@ -4,27 +4,30 @@
struct posix_acl;
-int bch2_create_trans(struct btree_trans *, u64,
+#define BCH_CREATE_TMPFILE (1U << 0)
+
+int bch2_create_trans(struct btree_trans *, subvol_inum,
struct bch_inode_unpacked *,
struct bch_inode_unpacked *,
const struct qstr *,
uid_t, gid_t, umode_t, dev_t,
struct posix_acl *,
- struct posix_acl *);
+ struct posix_acl *,
+ unsigned);
-int bch2_link_trans(struct btree_trans *, u64,
- u64, struct bch_inode_unpacked *,
- struct bch_inode_unpacked *,
+int bch2_link_trans(struct btree_trans *,
+ subvol_inum, struct bch_inode_unpacked *,
+ subvol_inum, struct bch_inode_unpacked *,
const struct qstr *);
-int bch2_unlink_trans(struct btree_trans *,
- u64, struct bch_inode_unpacked *,
+int bch2_unlink_trans(struct btree_trans *, subvol_inum,
+ struct bch_inode_unpacked *,
struct bch_inode_unpacked *,
const struct qstr *);
int bch2_rename_trans(struct btree_trans *,
- u64, struct bch_inode_unpacked *,
- u64, struct bch_inode_unpacked *,
+ subvol_inum, struct bch_inode_unpacked *,
+ subvol_inum, struct bch_inode_unpacked *,
struct bch_inode_unpacked *,
struct bch_inode_unpacked *,
const struct qstr *,
diff --git a/fs/bcachefs/fs-io.c b/fs/bcachefs/fs-io.c
index 909db2f104cd..7a0772195182 100644
--- a/fs/bcachefs/fs-io.c
+++ b/fs/bcachefs/fs-io.c
@@ -1790,6 +1790,49 @@ ssize_t bch2_read_iter(struct kiocb *iocb, struct iov_iter *iter)
/* O_DIRECT writes */
+static bool bch2_check_range_allocated(struct bch_fs *c, subvol_inum inum,
+ u64 offset, u64 size,
+ unsigned nr_replicas, bool compressed)
+{
+ struct btree_trans trans;
+ struct btree_iter iter;
+ struct bkey_s_c k;
+ u64 end = offset + size;
+ u32 snapshot;
+ bool ret = true;
+ int err;
+
+ bch2_trans_init(&trans, c, 0, 0);
+retry:
+ bch2_trans_begin(&trans);
+
+ err = bch2_subvolume_get_snapshot(&trans, inum.subvol, &snapshot);
+ if (err)
+ goto err;
+
+ for_each_btree_key(&trans, iter, BTREE_ID_extents,
+ SPOS(inum.inum, offset, snapshot),
+ BTREE_ITER_SLOTS, k, err) {
+ if (bkey_cmp(bkey_start_pos(k.k), POS(inum.inum, end)) >= 0)
+ break;
+
+ if (nr_replicas > bch2_bkey_replicas(c, k) ||
+ (!compressed && bch2_bkey_sectors_compressed(k))) {
+ ret = false;
+ break;
+ }
+ }
+
+ offset = iter.pos.offset;
+ bch2_trans_iter_exit(&trans, &iter);
+err:
+ if (err == -EINTR)
+ goto retry;
+ bch2_trans_exit(&trans);
+
+ return err ? false : ret;
+}
+
/*
* We're going to return -EIOCBQUEUED, but we haven't finished consuming the
* iov_iter yet, so we need to stash a copy of the iovec: it might be on the
@@ -1911,8 +1954,8 @@ static long bch2_dio_write_loop(struct dio_write *dio)
ret = bch2_disk_reservation_get(c, &dio->op.res, bio_sectors(bio),
dio->op.opts.data_replicas, 0);
if (unlikely(ret) &&
- !bch2_check_range_allocated(c, dio->op.pos,
- bio_sectors(bio),
+ !bch2_check_range_allocated(c, inode_inum(inode),
+ dio->op.pos.offset, bio_sectors(bio),
dio->op.opts.data_replicas,
dio->op.opts.compression != 0))
goto err;
@@ -2141,9 +2184,9 @@ out:
/* truncate: */
-static inline int range_has_data(struct bch_fs *c,
- struct bpos start,
- struct bpos end)
+static inline int range_has_data(struct bch_fs *c, u32 subvol,
+ struct bpos start,
+ struct bpos end)
{
struct btree_trans trans;
struct btree_iter iter;
@@ -2151,6 +2194,12 @@ static inline int range_has_data(struct bch_fs *c,
int ret = 0;
bch2_trans_init(&trans, c, 0, 0);
+retry:
+ bch2_trans_begin(&trans);
+
+ ret = bch2_subvolume_get_snapshot(&trans, subvol, &start.snapshot);
+ if (ret)
+ goto err;
for_each_btree_key(&trans, iter, BTREE_ID_extents, start, 0, k, ret) {
if (bkey_cmp(bkey_start_pos(k.k), end) >= 0)
@@ -2161,7 +2210,11 @@ static inline int range_has_data(struct bch_fs *c,
break;
}
}
+ start = iter.pos;
bch2_trans_iter_exit(&trans, &iter);
+err:
+ if (ret == -EINTR)
+ goto retry;
return bch2_trans_exit(&trans) ?: ret;
}
@@ -2193,7 +2246,7 @@ static int __bch2_truncate_page(struct bch_inode_info *inode,
* XXX: we're doing two index lookups when we end up reading the
* page
*/
- ret = range_has_data(c,
+ ret = range_has_data(c, inode->ei_subvol,
POS(inode->v.i_ino, index << PAGE_SECTOR_SHIFT),
POS(inode->v.i_ino, (index + 1) << PAGE_SECTOR_SHIFT));
if (ret <= 0)
@@ -2327,7 +2380,7 @@ int bch2_truncate(struct mnt_idmap *idmap,
inode_dio_wait(&inode->v);
bch2_pagecache_block_get(&inode->ei_pagecache_lock);
- ret = bch2_inode_find_by_inum(c, inode->v.i_ino, &inode_u);
+ ret = bch2_inode_find_by_inum(c, inode_inum(inode), &inode_u);
if (ret)
goto err;
@@ -2551,6 +2604,18 @@ static long bchfs_fcollapse_finsert(struct bch_inode_info *inode,
struct bpos move_pos = POS(inode->v.i_ino, offset >> 9);
struct bpos atomic_end;
unsigned trigger_flags = 0;
+ u32 snapshot;
+
+ bch2_trans_begin(&trans);
+
+ ret = bch2_subvolume_get_snapshot(&trans,
+ inode->ei_subvol, &snapshot);
+ if (ret)
+ continue;
+
+ bch2_btree_iter_set_snapshot(&src, snapshot);
+ bch2_btree_iter_set_snapshot(&dst, snapshot);
+ bch2_btree_iter_set_snapshot(&del, snapshot);
bch2_trans_begin(&trans);
@@ -2671,9 +2736,17 @@ static int __bchfs_fallocate(struct bch_inode_info *inode, int mode,
struct bkey_i_reservation reservation;
struct bkey_s_c k;
unsigned sectors;
+ u32 snapshot;
bch2_trans_begin(&trans);
+ ret = bch2_subvolume_get_snapshot(&trans,
+ inode->ei_subvol, &snapshot);
+ if (ret)
+ goto bkey_err;
+
+ bch2_btree_iter_set_snapshot(&iter, snapshot);
+
k = bch2_btree_iter_peek_slot(&iter);
if ((ret = bkey_err(k)))
goto bkey_err;
@@ -2918,8 +2991,8 @@ loff_t bch2_remap_file_range(struct file *file_src, loff_t pos_src,
mark_range_unallocated(src, pos_src, pos_src + aligned_len);
ret = bch2_remap_range(c,
- POS(dst->v.i_ino, pos_dst >> 9),
- POS(src->v.i_ino, pos_src >> 9),
+ inode_inum(dst), pos_dst >> 9,
+ inode_inum(src), pos_src >> 9,
aligned_len >> 9,
&dst->ei_journal_seq,
pos_dst + len, &i_sectors_delta);
@@ -3012,7 +3085,9 @@ static loff_t bch2_seek_data(struct file *file, u64 offset)
struct btree_trans trans;
struct btree_iter iter;
struct bkey_s_c k;
+ subvol_inum inum = inode_inum(inode);
u64 isize, next_data = MAX_LFS_FILESIZE;
+ u32 snapshot;
int ret;
isize = i_size_read(&inode->v);
@@ -3020,9 +3095,15 @@ static loff_t bch2_seek_data(struct file *file, u64 offset)
return -ENXIO;
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_extents,
- POS(inode->v.i_ino, offset >> 9), 0, k, ret) {
+ SPOS(inode->v.i_ino, offset >> 9, snapshot), 0, k, ret) {
if (k.k->p.inode != inode->v.i_ino) {
break;
} else if (bkey_extent_is_data(k.k)) {
@@ -3032,6 +3113,9 @@ static loff_t bch2_seek_data(struct file *file, u64 offset)
break;
}
bch2_trans_iter_exit(&trans, &iter);
+err:
+ if (ret == -EINTR)
+ goto retry;
ret = bch2_trans_exit(&trans) ?: ret;
if (ret)
@@ -3108,7 +3192,9 @@ static loff_t bch2_seek_hole(struct file *file, u64 offset)
struct btree_trans trans;
struct btree_iter iter;
struct bkey_s_c k;
+ subvol_inum inum = inode_inum(inode);
u64 isize, next_hole = MAX_LFS_FILESIZE;
+ u32 snapshot;
int ret;
isize = i_size_read(&inode->v);
@@ -3116,9 +3202,15 @@ static loff_t bch2_seek_hole(struct file *file, u64 offset)
return -ENXIO;
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_extents,
- POS(inode->v.i_ino, offset >> 9),
+ SPOS(inode->v.i_ino, offset >> 9, snapshot),
BTREE_ITER_SLOTS, k, ret) {
if (k.k->p.inode != inode->v.i_ino) {
next_hole = bch2_seek_pagecache_hole(&inode->v,
@@ -3136,6 +3228,9 @@ static loff_t bch2_seek_hole(struct file *file, u64 offset)
}
}
bch2_trans_iter_exit(&trans, &iter);
+err:
+ if (ret == -EINTR)
+ goto retry;
ret = bch2_trans_exit(&trans) ?: ret;
if (ret)
diff --git a/fs/bcachefs/fs-ioctl.c b/fs/bcachefs/fs-ioctl.c
index ff6b1739342d..91f52ab9b4e2 100644
--- a/fs/bcachefs/fs-ioctl.c
+++ b/fs/bcachefs/fs-ioctl.c
@@ -192,7 +192,7 @@ static int bch2_ioc_reinherit_attrs(struct bch_fs *c,
char *kname = NULL;
struct qstr qstr;
int ret = 0;
- subvol_inum inum = { .subvol = 1 };
+ subvol_inum inum;
kname = kmalloc(BCH_NAME_MAX + 1, GFP_KERNEL);
if (!kname)
@@ -205,10 +205,8 @@ static int bch2_ioc_reinherit_attrs(struct bch_fs *c,
qstr.len = ret;
qstr.name = kname;
- ret = -ENOENT;
- inum.inum = bch2_dirent_lookup(c, src->v.i_ino, &hash,
- &qstr);
- if (!inum.inum)
+ ret = bch2_dirent_lookup(c, inode_inum(src), &hash, &qstr, &inum);
+ if (ret)
goto err1;
vinode = bch2_vfs_inode_get(c, inum);
diff --git a/fs/bcachefs/fs.c b/fs/bcachefs/fs.c
index 7a994f3f9d20..0d47d9d5737b 100644
--- a/fs/bcachefs/fs.c
+++ b/fs/bcachefs/fs.c
@@ -150,7 +150,7 @@ int __must_check bch2_write_inode(struct bch_fs *c,
retry:
bch2_trans_begin(&trans);
- ret = bch2_inode_peek(&trans, &iter, &inode_u, inode->v.i_ino,
+ ret = bch2_inode_peek(&trans, &iter, &inode_u, inode_inum(inode),
BTREE_ITER_INTENT) ?:
(set ? set(inode, &inode_u, p) : 0) ?:
bch2_inode_write(&trans, &iter, &inode_u) ?:
@@ -256,7 +256,7 @@ struct inode *bch2_vfs_inode_get(struct bch_fs *c, subvol_inum inum)
if (!(inode->v.i_state & I_NEW))
return &inode->v;
- ret = bch2_inode_find_by_inum(c, inum.inum, &inode_u);
+ ret = bch2_inode_find_by_inum(c, inum, &inode_u);
if (ret) {
iget_failed(&inode->v);
return ERR_PTR(ret);
@@ -271,10 +271,10 @@ struct inode *bch2_vfs_inode_get(struct bch_fs *c, subvol_inum inum)
return &inode->v;
}
-static struct bch_inode_info *
+struct bch_inode_info *
__bch2_create(struct mnt_idmap *idmap,
struct bch_inode_info *dir, struct dentry *dentry,
- umode_t mode, dev_t rdev, bool tmpfile)
+ umode_t mode, dev_t rdev, unsigned flags)
{
struct bch_fs *c = dir->v.i_sb->s_fs_info;
struct btree_trans trans;
@@ -303,20 +303,23 @@ __bch2_create(struct mnt_idmap *idmap,
bch2_inode_init_early(c, &inode_u);
- if (!tmpfile)
+ if (!(flags & BCH_CREATE_TMPFILE))
mutex_lock(&dir->ei_update_lock);
bch2_trans_init(&trans, c, 8,
- 2048 + (!tmpfile ? dentry->d_name.len : 0));
+ 2048 + (!(flags & BCH_CREATE_TMPFILE)
+ ? dentry->d_name.len : 0));
retry:
bch2_trans_begin(&trans);
- ret = bch2_create_trans(&trans, dir->v.i_ino, &dir_u, &inode_u,
- !tmpfile ? &dentry->d_name : NULL,
+ ret = bch2_create_trans(&trans,
+ inode_inum(dir), &dir_u, &inode_u,
+ !(flags & BCH_CREATE_TMPFILE)
+ ? &dentry->d_name : NULL,
from_kuid(i_user_ns(&dir->v), current_fsuid()),
from_kgid(i_user_ns(&dir->v), current_fsgid()),
mode, rdev,
- default_acl, acl) ?:
+ default_acl, acl, flags) ?:
bch2_quota_acct(c, bch_qid(&inode_u), Q_INO, 1,
KEY_TYPE_QUOTA_PREALLOC);
if (unlikely(ret))
@@ -332,7 +335,7 @@ err_before_quota:
goto err_trans;
}
- if (!tmpfile) {
+ if (!(flags & BCH_CREATE_TMPFILE)) {
bch2_inode_update_after_write(c, dir, &dir_u,
ATTR_MTIME|ATTR_CTIME);
journal_seq_copy(c, dir, journal_seq);
@@ -387,7 +390,7 @@ err:
posix_acl_release(acl);
return inode;
err_trans:
- if (!tmpfile)
+ if (!(flags & BCH_CREATE_TMPFILE))
mutex_unlock(&dir->ei_update_lock);
bch2_trans_exit(&trans);
@@ -407,11 +410,12 @@ static struct dentry *bch2_lookup(struct inode *vdir, struct dentry *dentry,
struct bch_hash_info hash = bch2_hash_info_init(c, &dir->ei_inode);
struct inode *vinode = NULL;
subvol_inum inum = { .subvol = 1 };
+ int ret;
- inum.inum = bch2_dirent_lookup(c, dir->v.i_ino, &hash,
- &dentry->d_name);
+ ret = bch2_dirent_lookup(c, inode_inum(dir), &hash,
+ &dentry->d_name, &inum);
- if (inum.inum)
+ if (!ret)
vinode = bch2_vfs_inode_get(c, inum);
return d_splice_alias(vinode, dentry);
@@ -422,7 +426,7 @@ static int bch2_mknod(struct mnt_idmap *idmap,
umode_t mode, dev_t rdev)
{
struct bch_inode_info *inode =
- __bch2_create(idmap, to_bch_ei(vdir), dentry, mode, rdev, false);
+ __bch2_create(idmap, to_bch_ei(vdir), dentry, mode, rdev, 0);
if (IS_ERR(inode))
return PTR_ERR(inode);
@@ -452,8 +456,8 @@ static int __bch2_link(struct bch_fs *c,
ret = __bch2_trans_do(&trans, NULL, &inode->ei_journal_seq, 0,
bch2_link_trans(&trans,
- dir->v.i_ino,
- inode->v.i_ino, &dir_u, &inode_u,
+ inode_inum(dir), &dir_u,
+ inode_inum(inode), &inode_u,
&dentry->d_name));
if (likely(!ret)) {
@@ -504,7 +508,7 @@ static int bch2_unlink(struct inode *vdir, struct dentry *dentry)
ret = __bch2_trans_do(&trans, NULL, &dir->ei_journal_seq,
BTREE_INSERT_NOFAIL,
bch2_unlink_trans(&trans,
- dir->v.i_ino, &dir_u,
+ inode_inum(dir), &dir_u,
&inode_u, &dentry->d_name));
if (likely(!ret)) {
@@ -531,7 +535,8 @@ static int bch2_symlink(struct mnt_idmap *idmap,
struct bch_inode_info *dir = to_bch_ei(vdir), *inode;
int ret;
- inode = __bch2_create(idmap, dir, dentry, S_IFLNK|S_IRWXUGO, 0, true);
+ inode = __bch2_create(idmap, dir, dentry, S_IFLNK|S_IRWXUGO, 0,
+ BCH_CREATE_TMPFILE);
if (unlikely(IS_ERR(inode)))
return PTR_ERR(inode);
@@ -624,8 +629,8 @@ static int bch2_rename2(struct mnt_idmap *idmap,
ret = __bch2_trans_do(&trans, NULL, &journal_seq, 0,
bch2_rename_trans(&trans,
- src_dir->v.i_ino, &src_dir_u,
- dst_dir->v.i_ino, &dst_dir_u,
+ inode_inum(src_dir), &src_dir_u,
+ inode_inum(dst_dir), &dst_dir_u,
&src_inode_u,
&dst_inode_u,
&src_dentry->d_name,
@@ -748,7 +753,7 @@ retry:
kfree(acl);
acl = NULL;
- 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;
@@ -756,7 +761,8 @@ retry:
bch2_setattr_copy(idmap, inode, &inode_u, attr);
if (attr->ia_valid & ATTR_MODE) {
- ret = bch2_acl_chmod(&trans, &inode_u, inode_u.bi_mode, &acl);
+ ret = bch2_acl_chmod(&trans, inode_inum(inode), &inode_u,
+ inode_u.bi_mode, &acl);
if (ret)
goto btree_err;
}
@@ -848,7 +854,8 @@ static int bch2_tmpfile(struct mnt_idmap *idmap,
{
struct bch_inode_info *inode =
__bch2_create(idmap, to_bch_ei(vdir),
- file->f_path.dentry, mode, 0, true);
+ file->f_path.dentry, mode, 0,
+ BCH_CREATE_TMPFILE);
if (IS_ERR(inode))
return PTR_ERR(inode);
@@ -923,6 +930,7 @@ static int bch2_fiemap(struct inode *vinode, struct fiemap_extent_info *info,
struct bpos end = POS(ei->v.i_ino, (start + len) >> 9);
unsigned offset_into_extent, sectors;
bool have_extent = false;
+ u32 snapshot;
int ret = 0;
ret = fiemap_prep(&ei->v, info, start, &len, FIEMAP_FLAG_SYNC);
@@ -932,15 +940,21 @@ static int bch2_fiemap(struct inode *vinode, struct fiemap_extent_info *info,
if (start + len < start)
return -EINVAL;
+ start >>= 9;
+
bch2_bkey_buf_init(&cur);
bch2_bkey_buf_init(&prev);
bch2_trans_init(&trans, c, 0, 0);
-
- bch2_trans_iter_init(&trans, &iter, BTREE_ID_extents,
- POS(ei->v.i_ino, start >> 9), 0);
retry:
bch2_trans_begin(&trans);
+ ret = bch2_subvolume_get_snapshot(&trans, ei->ei_subvol, &snapshot);
+ if (ret)
+ goto err;
+
+ bch2_trans_iter_init(&trans, &iter, BTREE_ID_extents,
+ SPOS(ei->v.i_ino, start, snapshot), 0);
+
while ((k = bch2_btree_iter_peek(&iter)).k &&
!(ret = bkey_err(k)) &&
bkey_cmp(iter.pos, end) < 0) {
@@ -989,7 +1003,9 @@ retry:
bch2_btree_iter_set_pos(&iter,
POS(iter.pos.inode, iter.pos.offset + sectors));
}
-
+ start = iter.pos.offset;
+ bch2_trans_iter_exit(&trans, &iter);
+err:
if (ret == -EINTR)
goto retry;
@@ -997,7 +1013,6 @@ retry:
ret = bch2_fill_extent(c, info, bkey_i_to_s_c(prev.k),
FIEMAP_EXTENT_LAST);
- bch2_trans_iter_exit(&trans, &iter);
ret = bch2_trans_exit(&trans) ?: ret;
bch2_bkey_buf_exit(&cur, c);
bch2_bkey_buf_exit(&prev, c);
@@ -1034,7 +1049,7 @@ static int bch2_vfs_readdir(struct file *file, struct dir_context *ctx)
if (!dir_emit_dots(file, ctx))
return 0;
- return bch2_readdir(c, inode->v.i_ino, ctx);
+ return bch2_readdir(c, inode_inum(inode), ctx);
}
static const struct file_operations bch_file_operations = {
@@ -1290,7 +1305,7 @@ static void bch2_evict_inode(struct inode *vinode)
KEY_TYPE_QUOTA_WARN);
bch2_quota_acct(c, inode->ei_qid, Q_INO, -1,
KEY_TYPE_QUOTA_WARN);
- bch2_inode_rm(c, inode->v.i_ino, true);
+ bch2_inode_rm(c, inode_inum(inode), true);
}
}
diff --git a/fs/bcachefs/fs.h b/fs/bcachefs/fs.h
index 6dae425bf616..aa755987b36c 100644
--- a/fs/bcachefs/fs.h
+++ b/fs/bcachefs/fs.h
@@ -144,6 +144,10 @@ struct bch_inode_unpacked;
#ifndef NO_BCACHEFS_FS
+struct bch_inode_info *
+__bch2_create(struct mnt_idmap *, struct bch_inode_info *,
+ struct dentry *, umode_t, dev_t, unsigned);
+
int bch2_fs_quota_transfer(struct bch_fs *,
struct bch_inode_info *,
struct bch_qid,
diff --git a/fs/bcachefs/fsck.c b/fs/bcachefs/fsck.c
index e4ca05aae76c..40b107715cdd 100644
--- a/fs/bcachefs/fsck.c
+++ b/fs/bcachefs/fsck.c
@@ -858,7 +858,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);
+ ret = __bch2_dirent_read_target(&trans, d,
+ &target_subvol,
+ &target_snapshot,
+ &target_inum);
if (ret && ret != -ENOENT)
return ret;
diff --git a/fs/bcachefs/inode.c b/fs/bcachefs/inode.c
index 3b19dc6b9ddc..7fccf842a46b 100644
--- a/fs/bcachefs/inode.c
+++ b/fs/bcachefs/inode.c
@@ -6,6 +6,7 @@
#include "btree_update.h"
#include "error.h"
#include "extents.h"
+#include "extent_update.h"
#include "inode.h"
#include "str_hash.h"
#include "subvolume.h"
@@ -296,15 +297,21 @@ int bch2_inode_unpack(struct bkey_s_c_inode inode,
int bch2_inode_peek(struct btree_trans *trans,
struct btree_iter *iter,
struct bch_inode_unpacked *inode,
- u64 inum, unsigned flags)
+ subvol_inum inum, unsigned flags)
{
struct bkey_s_c k;
+ u32 snapshot;
int ret;
if (trans->c->opts.inodes_use_key_cache)
flags |= BTREE_ITER_CACHED;
- bch2_trans_iter_init(trans, iter, BTREE_ID_inodes, POS(0, inum), flags);
+ ret = bch2_subvolume_get_snapshot(trans, inum.subvol, &snapshot);
+ if (ret)
+ return ret;
+
+ bch2_trans_iter_init(trans, iter, BTREE_ID_inodes,
+ SPOS(0, inum.inum, snapshot), flags);
k = bch2_btree_iter_peek_slot(iter);
ret = bkey_err(k);
if (ret)
@@ -486,6 +493,9 @@ static inline u32 bkey_generation(struct bkey_s_c k)
}
}
+/*
+ * This just finds an empty slot:
+ */
int bch2_inode_create(struct btree_trans *trans,
struct btree_iter *iter,
struct bch_inode_unpacked *inode_u,
@@ -585,16 +595,74 @@ found_slot:
return 0;
}
-int bch2_inode_rm(struct bch_fs *c, u64 inode_nr, bool cached)
+static int bch2_inode_delete_keys(struct btree_trans *trans,
+ subvol_inum inum, enum btree_id id)
+{
+ u64 offset = 0;
+ int ret = 0;
+
+ while (!ret || ret == -EINTR) {
+ struct btree_iter iter;
+ struct bkey_s_c k;
+ struct bkey_i delete;
+ u32 snapshot;
+
+ bch2_trans_begin(trans);
+
+ ret = bch2_subvolume_get_snapshot(trans, inum.subvol, &snapshot);
+ if (ret)
+ continue;
+
+ bch2_trans_iter_init(trans, &iter, id,
+ SPOS(inum.inum, offset, snapshot),
+ BTREE_ITER_INTENT);
+ k = bch2_btree_iter_peek(&iter);
+
+ if (!k.k || iter.pos.inode != inum.inum) {
+ bch2_trans_iter_exit(trans, &iter);
+ break;
+ }
+
+ ret = bkey_err(k);
+ if (ret)
+ goto err;
+
+ bkey_init(&delete.k);
+ delete.k.p = iter.pos;
+
+ if (btree_node_type_is_extents(iter.btree_id)) {
+ unsigned max_sectors =
+ min_t(u64, U64_MAX - iter.pos.offset,
+ KEY_SIZE_MAX & (~0 << trans->c->block_bits));
+
+ /* create the biggest key we can */
+ bch2_key_resize(&delete.k, max_sectors);
+
+ ret = bch2_extent_trim_atomic(trans, &iter, &delete);
+ if (ret)
+ goto err;
+ }
+
+ ret = bch2_trans_update(trans, &iter, &delete, 0) ?:
+ bch2_trans_commit(trans, NULL, NULL,
+ BTREE_INSERT_NOFAIL);
+err:
+ offset = iter.pos.offset;
+ bch2_trans_iter_exit(trans, &iter);
+ }
+
+ return ret;
+}
+
+int bch2_inode_rm(struct bch_fs *c, subvol_inum inum, bool cached)
{
struct btree_trans trans;
struct btree_iter iter = { NULL };
struct bkey_i_inode_generation delete;
- struct bpos start = POS(inode_nr, 0);
- struct bpos end = POS(inode_nr + 1, 0);
struct bch_inode_unpacked inode_u;
struct bkey_s_c k;
unsigned iter_flags = BTREE_ITER_INTENT;
+ u32 snapshot;
int ret;
if (cached && c->opts.inodes_use_key_cache)
@@ -610,19 +678,20 @@ int bch2_inode_rm(struct bch_fs *c, u64 inode_nr, bool cached)
* XXX: the dirent could ideally would delete whiteouts when they're no
* longer needed
*/
- ret = bch2_btree_delete_range_trans(&trans, BTREE_ID_extents,
- start, end, NULL) ?:
- bch2_btree_delete_range_trans(&trans, BTREE_ID_xattrs,
- start, end, NULL) ?:
- bch2_btree_delete_range_trans(&trans, BTREE_ID_dirents,
- start, end, NULL);
+ ret = bch2_inode_delete_keys(&trans, inum, BTREE_ID_extents) ?:
+ bch2_inode_delete_keys(&trans, inum, BTREE_ID_xattrs) ?:
+ bch2_inode_delete_keys(&trans, inum, BTREE_ID_dirents);
if (ret)
goto err;
retry:
bch2_trans_begin(&trans);
+ ret = bch2_subvolume_get_snapshot(&trans, inum.subvol, &snapshot);
+ if (ret)
+ goto err;
+
bch2_trans_iter_init(&trans, &iter, BTREE_ID_inodes,
- POS(0, inode_nr), iter_flags);
+ SPOS(0, inum.inum, snapshot), iter_flags);
k = bch2_btree_iter_peek_slot(&iter);
ret = bkey_err(k);
@@ -632,7 +701,7 @@ retry:
if (k.k->type != KEY_TYPE_inode) {
bch2_fs_inconsistent(trans.c,
"inode %llu not found when deleting",
- inode_nr);
+ inum.inum);
ret = -EIO;
goto err;
}
@@ -662,20 +731,22 @@ err:
return ret;
}
-static int bch2_inode_find_by_inum_trans(struct btree_trans *trans, u64 inode_nr,
+static int bch2_inode_find_by_inum_trans(struct btree_trans *trans,
+ subvol_inum inum,
struct bch_inode_unpacked *inode)
{
- struct btree_iter iter = { NULL };
+ struct btree_iter iter;
int ret;
- ret = bch2_inode_peek(trans, &iter, inode, inode_nr, 0);
- bch2_trans_iter_exit(trans, &iter);
+ ret = bch2_inode_peek(trans, &iter, inode, inum, 0);
+ if (!ret)
+ bch2_trans_iter_exit(trans, &iter);
return ret;
}
-int bch2_inode_find_by_inum(struct bch_fs *c, u64 inode_nr,
+int bch2_inode_find_by_inum(struct bch_fs *c, subvol_inum inum,
struct bch_inode_unpacked *inode)
{
return bch2_trans_do(c, NULL, NULL, 0,
- bch2_inode_find_by_inum_trans(&trans, inode_nr, inode));
+ bch2_inode_find_by_inum_trans(&trans, inum, inode));
}
diff --git a/fs/bcachefs/inode.h b/fs/bcachefs/inode.h
index 25bef104ebcc..9e84cddcc6cb 100644
--- a/fs/bcachefs/inode.h
+++ b/fs/bcachefs/inode.h
@@ -58,7 +58,7 @@ int bch2_inode_unpack(struct bkey_s_c_inode, struct bch_inode_unpacked *);
void bch2_inode_unpacked_to_text(struct printbuf *, struct bch_inode_unpacked *);
int bch2_inode_peek(struct btree_trans *, struct btree_iter *,
- struct bch_inode_unpacked *, u64, unsigned);
+ struct bch_inode_unpacked *, subvol_inum, unsigned);
int bch2_inode_write(struct btree_trans *, struct btree_iter *,
struct bch_inode_unpacked *);
@@ -74,9 +74,10 @@ void bch2_inode_init(struct bch_fs *, struct bch_inode_unpacked *,
int bch2_inode_create(struct btree_trans *, struct btree_iter *,
struct bch_inode_unpacked *, u32, u64);
-int bch2_inode_rm(struct bch_fs *, u64, bool);
+int bch2_inode_rm(struct bch_fs *, subvol_inum, bool);
-int bch2_inode_find_by_inum(struct bch_fs *, u64, struct bch_inode_unpacked *);
+int bch2_inode_find_by_inum(struct bch_fs *, subvol_inum,
+ struct bch_inode_unpacked *);
static inline struct bch_io_opts bch2_inode_opts_get(struct bch_inode_unpacked *inode)
{
diff --git a/fs/bcachefs/io.c b/fs/bcachefs/io.c
index f95ceb820faa..0f5e0099b848 100644
--- a/fs/bcachefs/io.c
+++ b/fs/bcachefs/io.c
@@ -325,7 +325,10 @@ int bch2_extent_update(struct btree_trans *trans,
struct bch_inode_unpacked inode_u;
ret = bch2_inode_peek(trans, &inode_iter, &inode_u,
- k->k.p.inode, BTREE_ITER_INTENT);
+ (subvol_inum) {
+ .subvol = BCACHEFS_ROOT_SUBVOL,
+ .inum = k->k.p.inode,
+ }, BTREE_ITER_INTENT);
if (ret)
return ret;
diff --git a/fs/bcachefs/move.c b/fs/bcachefs/move.c
index eb2b91f7e682..9dc6684139de 100644
--- a/fs/bcachefs/move.c
+++ b/fs/bcachefs/move.c
@@ -581,7 +581,8 @@ static int __bch2_move_data(struct bch_fs *c,
stats->pos = start;
bch2_trans_iter_init(&trans, &iter, btree_id, start,
- BTREE_ITER_PREFETCH);
+ BTREE_ITER_PREFETCH|
+ BTREE_ITER_ALL_SNAPSHOTS);
if (rate)
bch2_ratelimit_reset(rate);
diff --git a/fs/bcachefs/recovery.c b/fs/bcachefs/recovery.c
index 2aab57cf09e1..47c8fecc6839 100644
--- a/fs/bcachefs/recovery.c
+++ b/fs/bcachefs/recovery.c
@@ -1480,11 +1480,12 @@ int bch2_fs_initialize(struct bch_fs *c)
err = "error creating lost+found";
ret = bch2_trans_do(c, NULL, NULL, 0,
- bch2_create_trans(&trans, BCACHEFS_ROOT_INO,
+ bch2_create_trans(&trans,
+ BCACHEFS_ROOT_SUBVOL_INUM,
&root_inode, &lostfound_inode,
&lostfound,
0, 0, S_IFDIR|0700, 0,
- NULL, NULL));
+ NULL, NULL, 0));
if (ret) {
bch_err(c, "error creating lost+found");
goto err;
diff --git a/fs/bcachefs/reflink.c b/fs/bcachefs/reflink.c
index 576cfbccf5b5..be4b47bc7438 100644
--- a/fs/bcachefs/reflink.c
+++ b/fs/bcachefs/reflink.c
@@ -7,6 +7,7 @@
#include "inode.h"
#include "io.h"
#include "reflink.h"
+#include "subvolume.h"
#include <linux/sched/signal.h>
@@ -197,7 +198,8 @@ static struct bkey_s_c get_next_src(struct btree_iter *iter, struct bpos end)
}
s64 bch2_remap_range(struct bch_fs *c,
- struct bpos dst_start, struct bpos src_start,
+ subvol_inum dst_inum, u64 dst_offset,
+ subvol_inum src_inum, u64 src_offset,
u64 remap_sectors, u64 *journal_seq,
u64 new_i_size, s64 *i_sectors_delta)
{
@@ -205,6 +207,8 @@ s64 bch2_remap_range(struct bch_fs *c,
struct btree_iter dst_iter, src_iter;
struct bkey_s_c src_k;
struct bkey_buf new_dst, new_src;
+ struct bpos dst_start = POS(dst_inum.inum, dst_offset);
+ struct bpos src_start = POS(src_inum.inum, src_offset);
struct bpos dst_end = dst_start, src_end = src_start;
struct bpos src_want;
u64 dst_done;
@@ -238,6 +242,16 @@ s64 bch2_remap_range(struct bch_fs *c,
break;
}
+ ret = bch2_subvolume_get_snapshot(&trans, src_inum.subvol,
+ &src_iter.snapshot);
+ if (ret)
+ continue;
+
+ ret = bch2_subvolume_get_snapshot(&trans, dst_inum.subvol,
+ &dst_iter.snapshot);
+ if (ret)
+ continue;
+
dst_done = dst_iter.pos.offset - dst_start.offset;
src_want = POS(src_start.inode, src_start.offset + dst_done);
bch2_btree_iter_set_pos(&src_iter, src_want);
@@ -311,7 +325,7 @@ s64 bch2_remap_range(struct bch_fs *c,
bch2_trans_begin(&trans);
ret2 = bch2_inode_peek(&trans, &inode_iter, &inode_u,
- dst_start.inode, BTREE_ITER_INTENT);
+ dst_inum, BTREE_ITER_INTENT);
if (!ret2 &&
inode_u.bi_size < new_i_size) {
diff --git a/fs/bcachefs/reflink.h b/fs/bcachefs/reflink.h
index 68c5cb5a2780..4c1b82860b0b 100644
--- a/fs/bcachefs/reflink.h
+++ b/fs/bcachefs/reflink.h
@@ -57,7 +57,7 @@ static inline __le64 *bkey_refcount(struct bkey_i *k)
}
}
-s64 bch2_remap_range(struct bch_fs *, struct bpos, struct bpos,
- u64, u64 *, u64, s64 *);
+s64 bch2_remap_range(struct bch_fs *, subvol_inum, u64,
+ subvol_inum, u64, u64, u64 *, u64, s64 *);
#endif /* _BCACHEFS_REFLINK_H */
diff --git a/fs/bcachefs/str_hash.h b/fs/bcachefs/str_hash.h
index c6a132b3c5bb..6418089531ad 100644
--- a/fs/bcachefs/str_hash.h
+++ b/fs/bcachefs/str_hash.h
@@ -8,6 +8,7 @@
#include "error.h"
#include "inode.h"
#include "siphash.h"
+#include "subvolume.h"
#include "super.h"
#include <linux/crc32c.h>
@@ -144,16 +145,21 @@ bch2_hash_lookup(struct btree_trans *trans,
struct btree_iter *iter,
const struct bch_hash_desc desc,
const struct bch_hash_info *info,
- u64 inode, const void *key,
+ subvol_inum inum, const void *key,
unsigned flags)
{
struct bkey_s_c k;
+ u32 snapshot;
int ret;
+ ret = bch2_subvolume_get_snapshot(trans, inum.subvol, &snapshot);
+ if (ret)
+ return ret;
+
for_each_btree_key(trans, *iter, desc.btree_id,
- POS(inode, desc.hash_key(info, key)),
+ SPOS(inum.inum, desc.hash_key(info, key), snapshot),
BTREE_ITER_SLOTS|flags, k, ret) {
- if (iter->pos.inode != inode)
+ if (iter->pos.inode != inum.inum)
break;
if (k.k->type == desc.key_type) {
@@ -176,15 +182,20 @@ bch2_hash_hole(struct btree_trans *trans,
struct btree_iter *iter,
const struct bch_hash_desc desc,
const struct bch_hash_info *info,
- u64 inode, const void *key)
+ subvol_inum inum, const void *key)
{
struct bkey_s_c k;
+ u32 snapshot;
int ret;
+ ret = bch2_subvolume_get_snapshot(trans, inum.subvol, &snapshot);
+ if (ret)
+ return ret;
+
for_each_btree_key(trans, *iter, desc.btree_id,
- POS(inode, desc.hash_key(info, key)),
+ SPOS(inum.inum, desc.hash_key(info, key), snapshot),
BTREE_ITER_SLOTS|BTREE_ITER_INTENT, k, ret) {
- if (iter->pos.inode != inode)
+ if (iter->pos.inode != inum.inum)
break;
if (k.k->type != desc.key_type)
@@ -229,17 +240,25 @@ static __always_inline
int bch2_hash_set(struct btree_trans *trans,
const struct bch_hash_desc desc,
const struct bch_hash_info *info,
- u64 inode, struct bkey_i *insert, int flags)
+ subvol_inum inum,
+ struct bkey_i *insert, int flags)
{
struct btree_iter iter, slot = { NULL };
struct bkey_s_c k;
bool found = false;
+ u32 snapshot;
int ret;
+ ret = bch2_subvolume_get_snapshot(trans, inum.subvol, &snapshot);
+ if (ret)
+ return ret;
+
for_each_btree_key(trans, iter, desc.btree_id,
- POS(inode, desc.hash_bkey(info, bkey_i_to_s_c(insert))),
+ SPOS(inum.inum,
+ desc.hash_bkey(info, bkey_i_to_s_c(insert)),
+ snapshot),
BTREE_ITER_SLOTS|BTREE_ITER_INTENT, k, ret) {
- if (iter.pos.inode != inode)
+ if (iter.pos.inode != inum.inum)
break;
if (k.k->type == desc.key_type) {
@@ -313,12 +332,12 @@ static __always_inline
int bch2_hash_delete(struct btree_trans *trans,
const struct bch_hash_desc desc,
const struct bch_hash_info *info,
- u64 inode, const void *key)
+ subvol_inum inum, const void *key)
{
struct btree_iter iter;
int ret;
- ret = bch2_hash_lookup(trans, &iter, desc, info, inode, key,
+ ret = bch2_hash_lookup(trans, &iter, desc, info, inum, key,
BTREE_ITER_INTENT);
if (ret)
return ret;
diff --git a/fs/bcachefs/xattr.c b/fs/bcachefs/xattr.c
index babbfaadeb3f..ff81a25698ff 100644
--- a/fs/bcachefs/xattr.c
+++ b/fs/bcachefs/xattr.c
@@ -128,7 +128,7 @@ static int bch2_xattr_get_trans(struct btree_trans *trans, struct bch_inode_info
int ret;
ret = bch2_hash_lookup(trans, &iter, bch2_xattr_hash_desc, &hash,
- inode->v.i_ino,
+ inode_inum(inode),
&X_SEARCH(type, name, strlen(name)),
0);
if (ret)
@@ -160,7 +160,7 @@ int bch2_xattr_get(struct bch_fs *c, struct bch_inode_info *inode,
bch2_xattr_get_trans(&trans, inode, name, buffer, size, type));
}
-int bch2_xattr_set(struct btree_trans *trans, u64 inum,
+int bch2_xattr_set(struct btree_trans *trans, subvol_inum inum,
const struct bch_hash_info *hash_info,
const char *name, const void *value, size_t size,
int type, int flags)
@@ -282,13 +282,21 @@ ssize_t bch2_xattr_list(struct dentry *dentry, char *buffer, size_t buffer_size)
struct btree_iter iter;
struct bkey_s_c k;
struct xattr_buf buf = { .buf = buffer, .len = buffer_size };
- u64 inum = dentry->d_inode->i_ino;
+ u64 offset = 0, inum = inode->ei_inode.bi_inum;
+ u32 snapshot;
int ret;
bch2_trans_init(&trans, c, 0, 0);
+retry:
+ bch2_trans_begin(&trans);
+ iter = (struct btree_iter) { NULL };
+
+ ret = bch2_subvolume_get_snapshot(&trans, inode->ei_subvol, &snapshot);
+ if (ret)
+ goto err;
for_each_btree_key(&trans, iter, BTREE_ID_xattrs,
- POS(inum, 0), 0, k, ret) {
+ SPOS(inum, offset, snapshot), 0, k, ret) {
BUG_ON(k.k->p.inode < inum);
if (k.k->p.inode > inum)
@@ -301,7 +309,12 @@ ssize_t bch2_xattr_list(struct dentry *dentry, char *buffer, size_t buffer_size)
if (ret)
break;
}
+
+ offset = iter.pos.offset;
bch2_trans_iter_exit(&trans, &iter);
+err:
+ if (ret == -EINTR)
+ goto retry;
ret = bch2_trans_exit(&trans) ?: ret;
@@ -340,7 +353,7 @@ static int bch2_xattr_set_handler(const struct xattr_handler *handler,
struct bch_hash_info hash = bch2_hash_info_init(c, &inode->ei_inode);
return bch2_trans_do(c, NULL, &inode->ei_journal_seq, 0,
- bch2_xattr_set(&trans, inode->v.i_ino, &hash,
+ bch2_xattr_set(&trans, inode_inum(inode), &hash,
name, value, size,
handler->flags, flags));
}
diff --git a/fs/bcachefs/xattr.h b/fs/bcachefs/xattr.h
index 4151065ab853..f4f896545e1c 100644
--- a/fs/bcachefs/xattr.h
+++ b/fs/bcachefs/xattr.h
@@ -39,7 +39,8 @@ struct bch_inode_info;
int bch2_xattr_get(struct bch_fs *, struct bch_inode_info *,
const char *, void *, size_t, int);
-int bch2_xattr_set(struct btree_trans *, u64, const struct bch_hash_info *,
+int bch2_xattr_set(struct btree_trans *, subvol_inum,
+ const struct bch_hash_info *,
const char *, const void *, size_t, int, int);
ssize_t bch2_xattr_list(struct dentry *, char *, size_t);