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

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
...@@ -230,7 +230,7 @@ struct posix_acl *bch2_get_acl(struct mnt_idmap *idmap, ...@@ -230,7 +230,7 @@ struct posix_acl *bch2_get_acl(struct mnt_idmap *idmap,
bch2_trans_begin(&trans); bch2_trans_begin(&trans);
ret = bch2_hash_lookup(&trans, &iter, bch2_xattr_hash_desc, 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), &X_SEARCH(acl_to_xattr_type(type), "", 0),
0); 0);
if (ret) { if (ret) {
...@@ -260,11 +260,11 @@ struct posix_acl *bch2_get_acl(struct mnt_idmap *idmap, ...@@ -260,11 +260,11 @@ struct posix_acl *bch2_get_acl(struct mnt_idmap *idmap,
return acl; 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, struct bch_inode_unpacked *inode_u,
const struct bch_hash_info *hash_info,
struct posix_acl *acl, int type) struct posix_acl *acl, int type)
{ {
struct bch_hash_info hash_info = bch2_hash_info_init(trans->c, inode_u);
int ret; int ret;
if (type == ACL_TYPE_DEFAULT && if (type == ACL_TYPE_DEFAULT &&
...@@ -277,14 +277,14 @@ int bch2_set_acl_trans(struct btree_trans *trans, ...@@ -277,14 +277,14 @@ int bch2_set_acl_trans(struct btree_trans *trans,
if (IS_ERR(xattr)) if (IS_ERR(xattr))
return PTR_ERR(xattr); return PTR_ERR(xattr);
ret = bch2_hash_set(trans, bch2_xattr_hash_desc, hash_info, ret = bch2_hash_set(trans, bch2_xattr_hash_desc, &hash_info,
inode_u->bi_inum, &xattr->k_i, 0); inum, &xattr->k_i, 0);
} else { } else {
struct xattr_search_key search = struct xattr_search_key search =
X_SEARCH(acl_to_xattr_type(type), "", 0); X_SEARCH(acl_to_xattr_type(type), "", 0);
ret = bch2_hash_delete(trans, bch2_xattr_hash_desc, hash_info, ret = bch2_hash_delete(trans, bch2_xattr_hash_desc, &hash_info,
inode_u->bi_inum, &search); inum, &search);
} }
return ret == -ENOENT ? 0 : ret; return ret == -ENOENT ? 0 : ret;
...@@ -299,7 +299,6 @@ int bch2_set_acl(struct mnt_idmap *idmap, ...@@ -299,7 +299,6 @@ int bch2_set_acl(struct mnt_idmap *idmap,
struct btree_trans trans; struct btree_trans trans;
struct btree_iter inode_iter = { NULL }; struct btree_iter inode_iter = { NULL };
struct bch_inode_unpacked inode_u; struct bch_inode_unpacked inode_u;
struct bch_hash_info hash_info;
struct posix_acl *acl; struct posix_acl *acl;
umode_t mode; umode_t mode;
int ret; int ret;
...@@ -310,7 +309,7 @@ int bch2_set_acl(struct mnt_idmap *idmap, ...@@ -310,7 +309,7 @@ int bch2_set_acl(struct mnt_idmap *idmap,
bch2_trans_begin(&trans); bch2_trans_begin(&trans);
acl = _acl; 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); BTREE_ITER_INTENT);
if (ret) if (ret)
goto btree_err; goto btree_err;
...@@ -323,9 +322,7 @@ int bch2_set_acl(struct mnt_idmap *idmap, ...@@ -323,9 +322,7 @@ int bch2_set_acl(struct mnt_idmap *idmap,
goto btree_err; goto btree_err;
} }
hash_info = bch2_hash_info_init(c, &inode_u); ret = bch2_set_acl_trans(&trans, inode_inum(inode), &inode_u, acl, type);
ret = bch2_set_acl_trans(&trans, &inode_u, &hash_info, acl, type);
if (ret) if (ret)
goto btree_err; goto btree_err;
...@@ -354,7 +351,7 @@ int bch2_set_acl(struct mnt_idmap *idmap, ...@@ -354,7 +351,7 @@ int bch2_set_acl(struct mnt_idmap *idmap,
return ret; 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, struct bch_inode_unpacked *inode,
umode_t mode, umode_t mode,
struct posix_acl **new_acl) struct posix_acl **new_acl)
...@@ -368,7 +365,7 @@ int bch2_acl_chmod(struct btree_trans *trans, ...@@ -368,7 +365,7 @@ int bch2_acl_chmod(struct btree_trans *trans,
int ret; int ret;
ret = bch2_hash_lookup(trans, &iter, bch2_xattr_hash_desc, 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), &X_SEARCH(KEY_TYPE_XATTR_INDEX_POSIX_ACL_ACCESS, "", 0),
BTREE_ITER_INTENT); BTREE_ITER_INTENT);
if (ret) if (ret)
......
...@@ -28,25 +28,24 @@ typedef struct { ...@@ -28,25 +28,24 @@ typedef struct {
struct posix_acl *bch2_get_acl(struct mnt_idmap *, struct dentry *, int); 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 *, struct bch_inode_unpacked *,
const struct bch_hash_info *,
struct posix_acl *, int); struct posix_acl *, int);
int bch2_set_acl(struct mnt_idmap *, struct dentry *, 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 **); umode_t, struct posix_acl **);
#else #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, struct bch_inode_unpacked *inode_u,
const struct bch_hash_info *hash_info,
struct posix_acl *acl, int type) struct posix_acl *acl, int type)
{ {
return 0; 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, struct bch_inode_unpacked *inode,
umode_t mode, umode_t mode,
struct posix_acl **new_acl) struct posix_acl **new_acl)
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "fs.h" #include "fs.h"
#include "keylist.h" #include "keylist.h"
#include "str_hash.h" #include "str_hash.h"
#include "subvolume.h"
#include <linux/dcache.h> #include <linux/dcache.h>
...@@ -150,8 +151,8 @@ static struct bkey_i_dirent *dirent_create_key(struct btree_trans *trans, ...@@ -150,8 +151,8 @@ static struct bkey_i_dirent *dirent_create_key(struct btree_trans *trans,
return dirent; return dirent;
} }
int bch2_dirent_create(struct btree_trans *trans, int bch2_dirent_create(struct btree_trans *trans, subvol_inum dir,
u64 dir_inum, const struct bch_hash_info *hash_info, const struct bch_hash_info *hash_info,
u8 type, const struct qstr *name, u64 dst_inum, u8 type, const struct qstr *name, u64 dst_inum,
u64 *dir_offset, int flags) u64 *dir_offset, int flags)
{ {
...@@ -164,7 +165,7 @@ int bch2_dirent_create(struct btree_trans *trans, ...@@ -164,7 +165,7 @@ int bch2_dirent_create(struct btree_trans *trans,
return ret; return ret;
ret = bch2_hash_set(trans, bch2_dirent_hash_desc, hash_info, 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; *dir_offset = dirent->k.p.offset;
return ret; return ret;
...@@ -223,31 +224,40 @@ int __bch2_dirent_read_target(struct btree_trans *trans, ...@@ -223,31 +224,40 @@ int __bch2_dirent_read_target(struct btree_trans *trans,
return ret; return ret;
} }
int bch2_dirent_read_target(struct btree_trans *trans, static int bch2_dirent_read_target(struct btree_trans *trans, subvol_inum dir,
struct bkey_s_c_dirent d, u64 *target) 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, ret = __bch2_dirent_read_target(trans, d, &target->subvol, &snapshot,
&snapshot, target, false); &target->inum, false);
if (!target->subvol)
target->subvol = dir.subvol;
return ret;
} }
int bch2_dirent_rename(struct btree_trans *trans, int bch2_dirent_rename(struct btree_trans *trans,
u64 src_dir, struct bch_hash_info *src_hash, subvol_inum src_dir, struct bch_hash_info *src_hash,
u64 dst_dir, struct bch_hash_info *dst_hash, subvol_inum dst_dir, struct bch_hash_info *dst_hash,
const struct qstr *src_name, u64 *src_inum, u64 *src_offset, const struct qstr *src_name, subvol_inum *src_inum, u64 *src_offset,
const struct qstr *dst_name, u64 *dst_inum, u64 *dst_offset, const struct qstr *dst_name, subvol_inum *dst_inum, u64 *dst_offset,
enum bch_rename_mode mode) enum bch_rename_mode mode)
{ {
struct btree_iter src_iter = { NULL }; struct btree_iter src_iter = { NULL };
struct btree_iter dst_iter = { NULL }; struct btree_iter dst_iter = { NULL };
struct bkey_s_c old_src, old_dst; struct bkey_s_c old_src, old_dst;
struct bkey_i_dirent *new_src = NULL, *new_dst = NULL; struct bkey_i_dirent *new_src = NULL, *new_dst = NULL;
struct bpos dst_pos = 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; 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: * Lookup dst:
...@@ -270,8 +280,12 @@ int bch2_dirent_rename(struct btree_trans *trans, ...@@ -270,8 +280,12 @@ int bch2_dirent_rename(struct btree_trans *trans,
if (ret) if (ret)
goto out; goto out;
if (mode != BCH_RENAME) if (mode != BCH_RENAME) {
*dst_inum = le64_to_cpu(bkey_s_c_to_dirent(old_dst).v->d_inum); 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) if (mode != BCH_RENAME_EXCHANGE)
*src_offset = dst_iter.pos.offset; *src_offset = dst_iter.pos.offset;
...@@ -287,7 +301,10 @@ int bch2_dirent_rename(struct btree_trans *trans, ...@@ -287,7 +301,10 @@ int bch2_dirent_rename(struct btree_trans *trans,
if (ret) if (ret)
goto out; 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: */ /* Create new dst key: */
new_dst = dirent_create_key(trans, 0, dst_name, 0); new_dst = dirent_create_key(trans, 0, dst_name, 0);
...@@ -376,17 +393,22 @@ int bch2_dirent_delete_at(struct btree_trans *trans, ...@@ -376,17 +393,22 @@ int bch2_dirent_delete_at(struct btree_trans *trans,
int __bch2_dirent_lookup_trans(struct btree_trans *trans, int __bch2_dirent_lookup_trans(struct btree_trans *trans,
struct btree_iter *iter, struct btree_iter *iter,
u64 dir_inum, subvol_inum dir,
const struct bch_hash_info *hash_info, const struct bch_hash_info *hash_info,
const struct qstr *name, u64 *inum, const struct qstr *name, subvol_inum *inum,
unsigned flags) unsigned flags)
{ {
struct bkey_s_c k; struct bkey_s_c k;
struct bkey_s_c_dirent d; struct bkey_s_c_dirent d;
u32 snapshot;
int ret; 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, ret = bch2_hash_lookup(trans, iter, bch2_dirent_hash_desc,
hash_info, dir_inum, name, flags); hash_info, dir, name, flags);
if (ret) if (ret)
return ret; return ret;
...@@ -399,44 +421,49 @@ int __bch2_dirent_lookup_trans(struct btree_trans *trans, ...@@ -399,44 +421,49 @@ int __bch2_dirent_lookup_trans(struct btree_trans *trans,
d = bkey_s_c_to_dirent(k); 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) if (ret)
bch2_trans_iter_exit(trans, iter); bch2_trans_iter_exit(trans, iter);
return ret; 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 bch_hash_info *hash_info,
const struct qstr *name) const struct qstr *name, subvol_inum *inum)
{ {
struct btree_trans trans; struct btree_trans trans;
struct btree_iter iter; struct btree_iter iter;
u64 inum = 0; int ret;
int ret = 0;
bch2_trans_init(&trans, c, 0, 0); bch2_trans_init(&trans, c, 0, 0);
retry: retry:
bch2_trans_begin(&trans); 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); bch2_trans_iter_exit(&trans, &iter);
if (ret == -EINTR) if (ret == -EINTR)
goto retry; goto retry;
bch2_trans_exit(&trans); 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 btree_iter iter;
struct bkey_s_c k; struct bkey_s_c k;
u32 snapshot;
int ret; int ret;
ret = bch2_subvolume_get_snapshot(trans, dir.subvol, &snapshot);
if (ret)
return ret;
for_each_btree_key(trans, iter, BTREE_ID_dirents, for_each_btree_key(trans, iter, BTREE_ID_dirents,
POS(dir_inum, 0), 0, k, ret) { SPOS(dir.inum, 0, snapshot), 0, k, ret) {
if (k.k->p.inode > dir_inum) if (k.k->p.inode > dir.inum)
break; break;
if (k.k->type == KEY_TYPE_dirent) { if (k.k->type == KEY_TYPE_dirent) {
...@@ -449,19 +476,26 @@ int bch2_empty_dir_trans(struct btree_trans *trans, u64 dir_inum) ...@@ -449,19 +476,26 @@ int bch2_empty_dir_trans(struct btree_trans *trans, u64 dir_inum)
return ret; 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_trans trans;
struct btree_iter iter; struct btree_iter iter;
struct bkey_s_c k; struct bkey_s_c k;
struct bkey_s_c_dirent dirent; struct bkey_s_c_dirent dirent;
u32 snapshot;
int ret; int ret;
bch2_trans_init(&trans, c, 0, 0); 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, for_each_btree_key(&trans, iter, BTREE_ID_dirents,
POS(inum, ctx->pos), 0, k, ret) { SPOS(inum.inum, ctx->pos, snapshot), 0, k, ret) {
if (k.k->p.inode > inum) if (k.k->p.inode > inum.inum)
break; break;
if (k.k->type != KEY_TYPE_dirent) if (k.k->type != KEY_TYPE_dirent)
...@@ -482,6 +516,9 @@ int bch2_readdir(struct bch_fs *c, u64 inum, struct dir_context *ctx) ...@@ -482,6 +516,9 @@ int bch2_readdir(struct bch_fs *c, u64 inum, struct dir_context *ctx)
ctx->pos = dirent.k->p.offset + 1; ctx->pos = dirent.k->p.offset + 1;
} }
bch2_trans_iter_exit(&trans, &iter); bch2_trans_iter_exit(&trans, &iter);
err:
if (ret == -EINTR)
goto retry;
ret = bch2_trans_exit(&trans) ?: ret; ret = bch2_trans_exit(&trans) ?: ret;
......
...@@ -29,7 +29,7 @@ static inline unsigned dirent_val_u64s(unsigned len) ...@@ -29,7 +29,7 @@ static inline unsigned dirent_val_u64s(unsigned len)
sizeof(u64)); 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 bch_hash_info *, u8,
const struct qstr *, u64, u64 *, int); const struct qstr *, u64, u64 *, int);
...@@ -40,9 +40,6 @@ int bch2_dirent_delete_at(struct btree_trans *, ...@@ -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, int __bch2_dirent_read_target(struct btree_trans *, struct bkey_s_c_dirent,
u32 *, u32 *, u64 *, bool); 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) static inline unsigned vfs_d_type(unsigned type)
{ {
return type == DT_SUBVOL ? DT_DIR : type; return type == DT_SUBVOL ? DT_DIR : type;
...@@ -55,20 +52,20 @@ enum bch_rename_mode { ...@@ -55,20 +52,20 @@ enum bch_rename_mode {
}; };
int bch2_dirent_rename(struct btree_trans *, int bch2_dirent_rename(struct btree_trans *,
u64, struct bch_hash_info *, subvol_inum, struct bch_hash_info *,
u64, struct bch_hash_info *, subvol_inum, struct bch_hash_info *,
const struct qstr *, u64 *, u64 *, const struct qstr *, subvol_inum *, u64 *,
const struct qstr *, u64 *, u64 *, const struct qstr *, subvol_inum *, u64 *,
enum bch_rename_mode); 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 *,
const struct bch_hash_info *, subvol_inum, const struct bch_hash_info *,
const struct qstr *, u64 *, const struct qstr *, subvol_inum *, unsigned);
unsigned); u64 bch2_dirent_lookup(struct bch_fs *, subvol_inum,
u64 bch2_dirent_lookup(struct bch_fs *, u64, const struct bch_hash_info *, const struct bch_hash_info *,
const struct qstr *); const struct qstr *, subvol_inum *);
int bch2_empty_dir_trans(struct btree_trans *, u64); int bch2_empty_dir_trans(struct btree_trans *, subvol_inum);
int bch2_readdir(struct bch_fs *, u64, struct dir_context *); int bch2_readdir(struct bch_fs *, subvol_inum, struct dir_context *);
#endif /* _BCACHEFS_DIRENT_H */ #endif /* _BCACHEFS_DIRENT_H */
...@@ -611,38 +611,6 @@ bool bch2_bkey_is_incompressible(struct bkey_s_c k) ...@@ -611,38 +611,6 @@ bool bch2_bkey_is_incompressible(struct bkey_s_c k)
return false; 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) unsigned bch2_bkey_replicas(struct bch_fs *c, struct bkey_s_c k)
{ {
struct bkey_ptrs_c ptrs = bch2_bkey_ptrs_c(k); struct bkey_ptrs_c ptrs = bch2_bkey_ptrs_c(k);
......
...@@ -567,7 +567,6 @@ unsigned bch2_bkey_nr_ptrs_allocated(struct bkey_s_c); ...@@ -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); unsigned bch2_bkey_nr_ptrs_fully_allocated(struct bkey_s_c);
bool bch2_bkey_is_incompressible(struct bkey_s_c); bool bch2_bkey_is_incompressible(struct bkey_s_c);
unsigned bch2_bkey_sectors_compressed(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_replicas(struct bch_fs *, struct bkey_s_c);
unsigned bch2_bkey_durability(struct bch_fs *, struct bkey_s_c); unsigned bch2_bkey_durability(struct bch_fs *, struct bkey_s_c);
......
This diff is collapsed.
...@@ -4,27 +4,30 @@ ...@@ -4,27 +4,30 @@
struct posix_acl; 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 *,
struct bch_inode_unpacked *, struct bch_inode_unpacked *,
const struct qstr *, const struct qstr *,
uid_t, gid_t, umode_t, dev_t, uid_t, gid_t, umode_t, dev_t,
struct posix_acl *, struct posix_acl *,
struct posix_acl *); struct posix_acl *,
unsigned);
int bch2_link_trans(struct btree_trans *, u64, int bch2_link_trans(struct btree_trans *,
u64, struct bch_inode_unpacked *, subvol_inum, struct bch_inode_unpacked *,
struct bch_inode_unpacked *, subvol_inum, struct bch_inode_unpacked *,
const struct qstr *); const struct qstr *);
int bch2_unlink_trans(struct btree_trans *, int bch2_unlink_trans(struct btree_trans *, subvol_inum,
u64, struct bch_inode_unpacked *, struct bch_inode_unpacked *,
struct bch_inode_unpacked *, struct bch_inode_unpacked *,
const struct qstr *); const struct qstr *);
int bch2_rename_trans(struct btree_trans *, int bch2_rename_trans(struct btree_trans *,
u64, struct bch_inode_unpacked *, subvol_inum, struct bch_inode_unpacked *,
u64, struct bch_inode_unpacked *, subvol_inum, struct bch_inode_unpacked *,
struct bch_inode_unpacked *, struct bch_inode_unpacked *,
struct bch_inode_unpacked *, struct bch_inode_unpacked *,
const struct qstr *, const struct qstr *,
......
...@@ -1790,6 +1790,49 @@ ssize_t bch2_read_iter(struct kiocb *iocb, struct iov_iter *iter) ...@@ -1790,6 +1790,49 @@ ssize_t bch2_read_iter(struct kiocb *iocb, struct iov_iter *iter)
/* O_DIRECT writes */ /* 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 * 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 * 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) ...@@ -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), ret = bch2_disk_reservation_get(c, &dio->op.res, bio_sectors(bio),
dio->op.opts.data_replicas, 0); dio->op.opts.data_replicas, 0);
if (unlikely(ret) && if (unlikely(ret) &&
!bch2_check_range_allocated(c, dio->op.pos, !bch2_check_range_allocated(c, inode_inum(inode),
bio_sectors(bio), dio->op.pos.offset, bio_sectors(bio),
dio->op.opts.data_replicas, dio->op.opts.data_replicas,
dio->op.opts.compression != 0)) dio->op.opts.compression != 0))
goto err; goto err;
...@@ -2141,9 +2184,9 @@ int bch2_fsync(struct file *file, loff_t start, loff_t end, int datasync) ...@@ -2141,9 +2184,9 @@ int bch2_fsync(struct file *file, loff_t start, loff_t end, int datasync)
/* truncate: */ /* truncate: */
static inline int range_has_data(struct bch_fs *c, static inline int range_has_data(struct bch_fs *c, u32 subvol,
struct bpos start, struct bpos start,
struct bpos end) struct bpos end)
{ {
struct btree_trans trans; struct btree_trans trans;
struct btree_iter iter; struct btree_iter iter;
...@@ -2151,6 +2194,12 @@ static inline int range_has_data(struct bch_fs *c, ...@@ -2151,6 +2194,12 @@ static inline int range_has_data(struct bch_fs *c,
int ret = 0; int ret = 0;
bch2_trans_init(&trans, c, 0, 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) { for_each_btree_key(&trans, iter, BTREE_ID_extents, start, 0, k, ret) {
if (bkey_cmp(bkey_start_pos(k.k), end) >= 0) if (bkey_cmp(bkey_start_pos(k.k), end) >= 0)
...@@ -2161,7 +2210,11 @@ static inline int range_has_data(struct bch_fs *c, ...@@ -2161,7 +2210,11 @@ static inline int range_has_data(struct bch_fs *c,
break; break;
} }
} }
start = iter.pos;
bch2_trans_iter_exit(&trans, &iter); bch2_trans_iter_exit(&trans, &iter);
err:
if (ret == -EINTR)
goto retry;
return bch2_trans_exit(&trans) ?: ret; return bch2_trans_exit(&trans) ?: ret;
} }
...@@ -2193,7 +2246,7 @@ static int __bch2_truncate_page(struct bch_inode_info *inode, ...@@ -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 * XXX: we're doing two index lookups when we end up reading the
* page * 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 << PAGE_SECTOR_SHIFT),
POS(inode->v.i_ino, (index + 1) << PAGE_SECTOR_SHIFT)); POS(inode->v.i_ino, (index + 1) << PAGE_SECTOR_SHIFT));
if (ret <= 0) if (ret <= 0)
...@@ -2327,7 +2380,7 @@ int bch2_truncate(struct mnt_idmap *idmap, ...@@ -2327,7 +2380,7 @@ int bch2_truncate(struct mnt_idmap *idmap,
inode_dio_wait(&inode->v); inode_dio_wait(&inode->v);
bch2_pagecache_block_get(&inode->ei_pagecache_lock); 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) if (ret)
goto err; goto err;
...@@ -2551,6 +2604,18 @@ static long bchfs_fcollapse_finsert(struct bch_inode_info *inode, ...@@ -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 move_pos = POS(inode->v.i_ino, offset >> 9);
struct bpos atomic_end; struct bpos atomic_end;
unsigned trigger_flags = 0; 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); bch2_trans_begin(&trans);
...@@ -2671,9 +2736,17 @@ static int __bchfs_fallocate(struct bch_inode_info *inode, int mode, ...@@ -2671,9 +2736,17 @@ static int __bchfs_fallocate(struct bch_inode_info *inode, int mode,
struct bkey_i_reservation reservation; struct bkey_i_reservation reservation;
struct bkey_s_c k; struct bkey_s_c k;
unsigned sectors; unsigned sectors;
u32 snapshot;
bch2_trans_begin(&trans); 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); k = bch2_btree_iter_peek_slot(&iter);
if ((ret = bkey_err(k))) if ((ret = bkey_err(k)))
goto bkey_err; goto bkey_err;
...@@ -2918,8 +2991,8 @@ loff_t bch2_remap_file_range(struct file *file_src, loff_t pos_src, ...@@ -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); mark_range_unallocated(src, pos_src, pos_src + aligned_len);
ret = bch2_remap_range(c, ret = bch2_remap_range(c,
POS(dst->v.i_ino, pos_dst >> 9), inode_inum(dst), pos_dst >> 9,
POS(src->v.i_ino, pos_src >> 9), inode_inum(src), pos_src >> 9,
aligned_len >> 9, aligned_len >> 9,
&dst->ei_journal_seq, &dst->ei_journal_seq,
pos_dst + len, &i_sectors_delta); pos_dst + len, &i_sectors_delta);
...@@ -3012,7 +3085,9 @@ static loff_t bch2_seek_data(struct file *file, u64 offset) ...@@ -3012,7 +3085,9 @@ static loff_t bch2_seek_data(struct file *file, u64 offset)
struct btree_trans trans; struct btree_trans trans;
struct btree_iter iter; struct btree_iter iter;
struct bkey_s_c k; struct bkey_s_c k;
subvol_inum inum = inode_inum(inode);
u64 isize, next_data = MAX_LFS_FILESIZE; u64 isize, next_data = MAX_LFS_FILESIZE;
u32 snapshot;
int ret; int ret;
isize = i_size_read(&inode->v); isize = i_size_read(&inode->v);
...@@ -3020,9 +3095,15 @@ static loff_t bch2_seek_data(struct file *file, u64 offset) ...@@ -3020,9 +3095,15 @@ static loff_t bch2_seek_data(struct file *file, u64 offset)
return -ENXIO; return -ENXIO;
bch2_trans_init(&trans, c, 0, 0); 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, 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) { if (k.k->p.inode != inode->v.i_ino) {
break; break;
} else if (bkey_extent_is_data(k.k)) { } else if (bkey_extent_is_data(k.k)) {
...@@ -3032,6 +3113,9 @@ static loff_t bch2_seek_data(struct file *file, u64 offset) ...@@ -3032,6 +3113,9 @@ static loff_t bch2_seek_data(struct file *file, u64 offset)
break; break;
} }
bch2_trans_iter_exit(&trans, &iter); bch2_trans_iter_exit(&trans, &iter);
err:
if (ret == -EINTR)
goto retry;
ret = bch2_trans_exit(&trans) ?: ret; ret = bch2_trans_exit(&trans) ?: ret;
if (ret) if (ret)
...@@ -3108,7 +3192,9 @@ static loff_t bch2_seek_hole(struct file *file, u64 offset) ...@@ -3108,7 +3192,9 @@ static loff_t bch2_seek_hole(struct file *file, u64 offset)
struct btree_trans trans; struct btree_trans trans;
struct btree_iter iter; struct btree_iter iter;
struct bkey_s_c k; struct bkey_s_c k;
subvol_inum inum = inode_inum(inode);
u64 isize, next_hole = MAX_LFS_FILESIZE; u64 isize, next_hole = MAX_LFS_FILESIZE;
u32 snapshot;
int ret; int ret;
isize = i_size_read(&inode->v); isize = i_size_read(&inode->v);
...@@ -3116,9 +3202,15 @@ static loff_t bch2_seek_hole(struct file *file, u64 offset) ...@@ -3116,9 +3202,15 @@ static loff_t bch2_seek_hole(struct file *file, u64 offset)
return -ENXIO; return -ENXIO;
bch2_trans_init(&trans, c, 0, 0); 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, 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) { BTREE_ITER_SLOTS, k, ret) {
if (k.k->p.inode != inode->v.i_ino) { if (k.k->p.inode != inode->v.i_ino) {
next_hole = bch2_seek_pagecache_hole(&inode->v, next_hole = bch2_seek_pagecache_hole(&inode->v,
...@@ -3136,6 +3228,9 @@ static loff_t bch2_seek_hole(struct file *file, u64 offset) ...@@ -3136,6 +3228,9 @@ static loff_t bch2_seek_hole(struct file *file, u64 offset)
} }
} }
bch2_trans_iter_exit(&trans, &iter); bch2_trans_iter_exit(&trans, &iter);
err:
if (ret == -EINTR)
goto retry;
ret = bch2_trans_exit(&trans) ?: ret; ret = bch2_trans_exit(&trans) ?: ret;
if (ret) if (ret)
......
...@@ -192,7 +192,7 @@ static int bch2_ioc_reinherit_attrs(struct bch_fs *c, ...@@ -192,7 +192,7 @@ static int bch2_ioc_reinherit_attrs(struct bch_fs *c,
char *kname = NULL; char *kname = NULL;
struct qstr qstr; struct qstr qstr;
int ret = 0; int ret = 0;
subvol_inum inum = { .subvol = 1 }; subvol_inum inum;
kname = kmalloc(BCH_NAME_MAX + 1, GFP_KERNEL); kname = kmalloc(BCH_NAME_MAX + 1, GFP_KERNEL);
if (!kname) if (!kname)
...@@ -205,10 +205,8 @@ static int bch2_ioc_reinherit_attrs(struct bch_fs *c, ...@@ -205,10 +205,8 @@ static int bch2_ioc_reinherit_attrs(struct bch_fs *c,
qstr.len = ret; qstr.len = ret;
qstr.name = kname; qstr.name = kname;
ret = -ENOENT; ret = bch2_dirent_lookup(c, inode_inum(src), &hash, &qstr, &inum);
inum.inum = bch2_dirent_lookup(c, src->v.i_ino, &hash, if (ret)
&qstr);
if (!inum.inum)
goto err1; goto err1;
vinode = bch2_vfs_inode_get(c, inum); vinode = bch2_vfs_inode_get(c, inum);
......
...@@ -150,7 +150,7 @@ int __must_check bch2_write_inode(struct bch_fs *c, ...@@ -150,7 +150,7 @@ int __must_check bch2_write_inode(struct bch_fs *c,
retry: retry:
bch2_trans_begin(&trans); 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) ?: BTREE_ITER_INTENT) ?:
(set ? set(inode, &inode_u, p) : 0) ?: (set ? set(inode, &inode_u, p) : 0) ?:
bch2_inode_write(&trans, &iter, &inode_u) ?: bch2_inode_write(&trans, &iter, &inode_u) ?:
...@@ -256,7 +256,7 @@ struct inode *bch2_vfs_inode_get(struct bch_fs *c, subvol_inum inum) ...@@ -256,7 +256,7 @@ struct inode *bch2_vfs_inode_get(struct bch_fs *c, subvol_inum inum)
if (!(inode->v.i_state & I_NEW)) if (!(inode->v.i_state & I_NEW))
return &inode->v; 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) { if (ret) {
iget_failed(&inode->v); iget_failed(&inode->v);
return ERR_PTR(ret); return ERR_PTR(ret);
...@@ -271,10 +271,10 @@ struct inode *bch2_vfs_inode_get(struct bch_fs *c, subvol_inum inum) ...@@ -271,10 +271,10 @@ struct inode *bch2_vfs_inode_get(struct bch_fs *c, subvol_inum inum)
return &inode->v; return &inode->v;
} }
static struct bch_inode_info * struct bch_inode_info *
__bch2_create(struct mnt_idmap *idmap, __bch2_create(struct mnt_idmap *idmap,
struct bch_inode_info *dir, struct dentry *dentry, 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 bch_fs *c = dir->v.i_sb->s_fs_info;
struct btree_trans trans; struct btree_trans trans;
...@@ -303,20 +303,23 @@ __bch2_create(struct mnt_idmap *idmap, ...@@ -303,20 +303,23 @@ __bch2_create(struct mnt_idmap *idmap,
bch2_inode_init_early(c, &inode_u); bch2_inode_init_early(c, &inode_u);
if (!tmpfile) if (!(flags & BCH_CREATE_TMPFILE))
mutex_lock(&dir->ei_update_lock); mutex_lock(&dir->ei_update_lock);
bch2_trans_init(&trans, c, 8, bch2_trans_init(&trans, c, 8,
2048 + (!tmpfile ? dentry->d_name.len : 0)); 2048 + (!(flags & BCH_CREATE_TMPFILE)
? dentry->d_name.len : 0));
retry: retry:
bch2_trans_begin(&trans); bch2_trans_begin(&trans);
ret = bch2_create_trans(&trans, dir->v.i_ino, &dir_u, &inode_u, ret = bch2_create_trans(&trans,
!tmpfile ? &dentry->d_name : NULL, 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_kuid(i_user_ns(&dir->v), current_fsuid()),
from_kgid(i_user_ns(&dir->v), current_fsgid()), from_kgid(i_user_ns(&dir->v), current_fsgid()),
mode, rdev, mode, rdev,
default_acl, acl) ?: default_acl, acl, flags) ?:
bch2_quota_acct(c, bch_qid(&inode_u), Q_INO, 1, bch2_quota_acct(c, bch_qid(&inode_u), Q_INO, 1,
KEY_TYPE_QUOTA_PREALLOC); KEY_TYPE_QUOTA_PREALLOC);
if (unlikely(ret)) if (unlikely(ret))
...@@ -332,7 +335,7 @@ __bch2_create(struct mnt_idmap *idmap, ...@@ -332,7 +335,7 @@ __bch2_create(struct mnt_idmap *idmap,
goto err_trans; goto err_trans;
} }
if (!tmpfile) { if (!(flags & BCH_CREATE_TMPFILE)) {
bch2_inode_update_after_write(c, dir, &dir_u, bch2_inode_update_after_write(c, dir, &dir_u,
ATTR_MTIME|ATTR_CTIME); ATTR_MTIME|ATTR_CTIME);
journal_seq_copy(c, dir, journal_seq); journal_seq_copy(c, dir, journal_seq);
...@@ -387,7 +390,7 @@ __bch2_create(struct mnt_idmap *idmap, ...@@ -387,7 +390,7 @@ __bch2_create(struct mnt_idmap *idmap,
posix_acl_release(acl); posix_acl_release(acl);
return inode; return inode;
err_trans: err_trans:
if (!tmpfile) if (!(flags & BCH_CREATE_TMPFILE))
mutex_unlock(&dir->ei_update_lock); mutex_unlock(&dir->ei_update_lock);
bch2_trans_exit(&trans); bch2_trans_exit(&trans);
...@@ -407,11 +410,12 @@ static struct dentry *bch2_lookup(struct inode *vdir, struct dentry *dentry, ...@@ -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 bch_hash_info hash = bch2_hash_info_init(c, &dir->ei_inode);
struct inode *vinode = NULL; struct inode *vinode = NULL;
subvol_inum inum = { .subvol = 1 }; subvol_inum inum = { .subvol = 1 };
int ret;
inum.inum = bch2_dirent_lookup(c, dir->v.i_ino, &hash, ret = bch2_dirent_lookup(c, inode_inum(dir), &hash,
&dentry->d_name); &dentry->d_name, &inum);
if (inum.inum) if (!ret)
vinode = bch2_vfs_inode_get(c, inum); vinode = bch2_vfs_inode_get(c, inum);
return d_splice_alias(vinode, dentry); return d_splice_alias(vinode, dentry);
...@@ -422,7 +426,7 @@ static int bch2_mknod(struct mnt_idmap *idmap, ...@@ -422,7 +426,7 @@ static int bch2_mknod(struct mnt_idmap *idmap,
umode_t mode, dev_t rdev) umode_t mode, dev_t rdev)
{ {
struct bch_inode_info *inode = 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)) if (IS_ERR(inode))
return PTR_ERR(inode); return PTR_ERR(inode);
...@@ -452,8 +456,8 @@ static int __bch2_link(struct bch_fs *c, ...@@ -452,8 +456,8 @@ static int __bch2_link(struct bch_fs *c,
ret = __bch2_trans_do(&trans, NULL, &inode->ei_journal_seq, 0, ret = __bch2_trans_do(&trans, NULL, &inode->ei_journal_seq, 0,
bch2_link_trans(&trans, bch2_link_trans(&trans,
dir->v.i_ino, inode_inum(dir), &dir_u,
inode->v.i_ino, &dir_u, &inode_u, inode_inum(inode), &inode_u,
&dentry->d_name)); &dentry->d_name));
if (likely(!ret)) { if (likely(!ret)) {
...@@ -504,7 +508,7 @@ static int bch2_unlink(struct inode *vdir, struct dentry *dentry) ...@@ -504,7 +508,7 @@ static int bch2_unlink(struct inode *vdir, struct dentry *dentry)
ret = __bch2_trans_do(&trans, NULL, &dir->ei_journal_seq, ret = __bch2_trans_do(&trans, NULL, &dir->ei_journal_seq,
BTREE_INSERT_NOFAIL, BTREE_INSERT_NOFAIL,
bch2_unlink_trans(&trans, bch2_unlink_trans(&trans,
dir->v.i_ino, &dir_u, inode_inum(dir), &dir_u,
&inode_u, &dentry->d_name)); &inode_u, &dentry->d_name));
if (likely(!ret)) { if (likely(!ret)) {
...@@ -531,7 +535,8 @@ static int bch2_symlink(struct mnt_idmap *idmap, ...@@ -531,7 +535,8 @@ static int bch2_symlink(struct mnt_idmap *idmap,
struct bch_inode_info *dir = to_bch_ei(vdir), *inode; struct bch_inode_info *dir = to_bch_ei(vdir), *inode;
int ret; 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))) if (unlikely(IS_ERR(inode)))
return PTR_ERR(inode); return PTR_ERR(inode);
...@@ -624,8 +629,8 @@ static int bch2_rename2(struct mnt_idmap *idmap, ...@@ -624,8 +629,8 @@ static int bch2_rename2(struct mnt_idmap *idmap,
ret = __bch2_trans_do(&trans, NULL, &journal_seq, 0, ret = __bch2_trans_do(&trans, NULL, &journal_seq, 0,
bch2_rename_trans(&trans, bch2_rename_trans(&trans,
src_dir->v.i_ino, &src_dir_u, inode_inum(src_dir), &src_dir_u,
dst_dir->v.i_ino, &dst_dir_u, inode_inum(dst_dir), &dst_dir_u,
&src_inode_u, &src_inode_u,
&dst_inode_u, &dst_inode_u,
&src_dentry->d_name, &src_dentry->d_name,
...@@ -748,7 +753,7 @@ int bch2_setattr_nonsize(struct mnt_idmap *idmap, ...@@ -748,7 +753,7 @@ int bch2_setattr_nonsize(struct mnt_idmap *idmap,
kfree(acl); kfree(acl);
acl = NULL; 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); BTREE_ITER_INTENT);
if (ret) if (ret)
goto btree_err; goto btree_err;
...@@ -756,7 +761,8 @@ int bch2_setattr_nonsize(struct mnt_idmap *idmap, ...@@ -756,7 +761,8 @@ int bch2_setattr_nonsize(struct mnt_idmap *idmap,
bch2_setattr_copy(idmap, inode, &inode_u, attr); bch2_setattr_copy(idmap, inode, &inode_u, attr);
if (attr->ia_valid & ATTR_MODE) { 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) if (ret)
goto btree_err; goto btree_err;
} }
...@@ -848,7 +854,8 @@ static int bch2_tmpfile(struct mnt_idmap *idmap, ...@@ -848,7 +854,8 @@ static int bch2_tmpfile(struct mnt_idmap *idmap,
{ {
struct bch_inode_info *inode = struct bch_inode_info *inode =
__bch2_create(idmap, to_bch_ei(vdir), __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)) if (IS_ERR(inode))
return PTR_ERR(inode); return PTR_ERR(inode);
...@@ -923,6 +930,7 @@ static int bch2_fiemap(struct inode *vinode, struct fiemap_extent_info *info, ...@@ -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); struct bpos end = POS(ei->v.i_ino, (start + len) >> 9);
unsigned offset_into_extent, sectors; unsigned offset_into_extent, sectors;
bool have_extent = false; bool have_extent = false;
u32 snapshot;
int ret = 0; int ret = 0;
ret = fiemap_prep(&ei->v, info, start, &len, FIEMAP_FLAG_SYNC); 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, ...@@ -932,15 +940,21 @@ static int bch2_fiemap(struct inode *vinode, struct fiemap_extent_info *info,
if (start + len < start) if (start + len < start)
return -EINVAL; return -EINVAL;
start >>= 9;
bch2_bkey_buf_init(&cur); bch2_bkey_buf_init(&cur);
bch2_bkey_buf_init(&prev); bch2_bkey_buf_init(&prev);
bch2_trans_init(&trans, c, 0, 0); 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: retry:
bch2_trans_begin(&trans); 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 && while ((k = bch2_btree_iter_peek(&iter)).k &&
!(ret = bkey_err(k)) && !(ret = bkey_err(k)) &&
bkey_cmp(iter.pos, end) < 0) { bkey_cmp(iter.pos, end) < 0) {
...@@ -989,7 +1003,9 @@ static int bch2_fiemap(struct inode *vinode, struct fiemap_extent_info *info, ...@@ -989,7 +1003,9 @@ static int bch2_fiemap(struct inode *vinode, struct fiemap_extent_info *info,
bch2_btree_iter_set_pos(&iter, bch2_btree_iter_set_pos(&iter,
POS(iter.pos.inode, iter.pos.offset + sectors)); POS(iter.pos.inode, iter.pos.offset + sectors));
} }
start = iter.pos.offset;
bch2_trans_iter_exit(&trans, &iter);
err:
if (ret == -EINTR) if (ret == -EINTR)
goto retry; goto retry;
...@@ -997,7 +1013,6 @@ static int bch2_fiemap(struct inode *vinode, struct fiemap_extent_info *info, ...@@ -997,7 +1013,6 @@ static int bch2_fiemap(struct inode *vinode, struct fiemap_extent_info *info,
ret = bch2_fill_extent(c, info, bkey_i_to_s_c(prev.k), ret = bch2_fill_extent(c, info, bkey_i_to_s_c(prev.k),
FIEMAP_EXTENT_LAST); FIEMAP_EXTENT_LAST);
bch2_trans_iter_exit(&trans, &iter);
ret = bch2_trans_exit(&trans) ?: ret; ret = bch2_trans_exit(&trans) ?: ret;
bch2_bkey_buf_exit(&cur, c); bch2_bkey_buf_exit(&cur, c);
bch2_bkey_buf_exit(&prev, c); bch2_bkey_buf_exit(&prev, c);
...@@ -1034,7 +1049,7 @@ static int bch2_vfs_readdir(struct file *file, struct dir_context *ctx) ...@@ -1034,7 +1049,7 @@ static int bch2_vfs_readdir(struct file *file, struct dir_context *ctx)
if (!dir_emit_dots(file, ctx)) if (!dir_emit_dots(file, ctx))
return 0; 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 = { static const struct file_operations bch_file_operations = {
...@@ -1290,7 +1305,7 @@ static void bch2_evict_inode(struct inode *vinode) ...@@ -1290,7 +1305,7 @@ static void bch2_evict_inode(struct inode *vinode)
KEY_TYPE_QUOTA_WARN); KEY_TYPE_QUOTA_WARN);
bch2_quota_acct(c, inode->ei_qid, Q_INO, -1, bch2_quota_acct(c, inode->ei_qid, Q_INO, -1,
KEY_TYPE_QUOTA_WARN); KEY_TYPE_QUOTA_WARN);
bch2_inode_rm(c, inode->v.i_ino, true); bch2_inode_rm(c, inode_inum(inode), true);
} }
} }
......
...@@ -144,6 +144,10 @@ struct bch_inode_unpacked; ...@@ -144,6 +144,10 @@ struct bch_inode_unpacked;
#ifndef NO_BCACHEFS_FS #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 *, int bch2_fs_quota_transfer(struct bch_fs *,
struct bch_inode_info *, struct bch_inode_info *,
struct bch_qid, struct bch_qid,
......
...@@ -858,7 +858,10 @@ static int check_dirent(struct btree_trans *trans, struct btree_iter *iter, ...@@ -858,7 +858,10 @@ static int check_dirent(struct btree_trans *trans, struct btree_iter *iter,
d = bkey_s_c_to_dirent(k); d = bkey_s_c_to_dirent(k);
d_inum = le64_to_cpu(d.v->d_inum); 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) if (ret && ret != -ENOENT)
return ret; return ret;
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include "btree_update.h" #include "btree_update.h"
#include "error.h" #include "error.h"
#include "extents.h" #include "extents.h"
#include "extent_update.h"
#include "inode.h" #include "inode.h"
#include "str_hash.h" #include "str_hash.h"
#include "subvolume.h" #include "subvolume.h"
...@@ -296,15 +297,21 @@ int bch2_inode_unpack(struct bkey_s_c_inode inode, ...@@ -296,15 +297,21 @@ int bch2_inode_unpack(struct bkey_s_c_inode inode,
int bch2_inode_peek(struct btree_trans *trans, int bch2_inode_peek(struct btree_trans *trans,
struct btree_iter *iter, struct btree_iter *iter,
struct bch_inode_unpacked *inode, struct bch_inode_unpacked *inode,
u64 inum, unsigned flags) subvol_inum inum, unsigned flags)
{ {
struct bkey_s_c k; struct bkey_s_c k;
u32 snapshot;
int ret; int ret;
if (trans->c->opts.inodes_use_key_cache) if (trans->c->opts.inodes_use_key_cache)
flags |= BTREE_ITER_CACHED; 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); k = bch2_btree_iter_peek_slot(iter);
ret = bkey_err(k); ret = bkey_err(k);
if (ret) if (ret)
...@@ -486,6 +493,9 @@ static inline u32 bkey_generation(struct bkey_s_c k) ...@@ -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, int bch2_inode_create(struct btree_trans *trans,
struct btree_iter *iter, struct btree_iter *iter,
struct bch_inode_unpacked *inode_u, struct bch_inode_unpacked *inode_u,
...@@ -585,16 +595,74 @@ int bch2_inode_create(struct btree_trans *trans, ...@@ -585,16 +595,74 @@ int bch2_inode_create(struct btree_trans *trans,
return 0; 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_trans trans;
struct btree_iter iter = { NULL }; struct btree_iter iter = { NULL };
struct bkey_i_inode_generation delete; 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 bch_inode_unpacked inode_u;
struct bkey_s_c k; struct bkey_s_c k;
unsigned iter_flags = BTREE_ITER_INTENT; unsigned iter_flags = BTREE_ITER_INTENT;
u32 snapshot;
int ret; int ret;
if (cached && c->opts.inodes_use_key_cache) 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) ...@@ -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 * XXX: the dirent could ideally would delete whiteouts when they're no
* longer needed * longer needed
*/ */
ret = bch2_btree_delete_range_trans(&trans, BTREE_ID_extents, ret = bch2_inode_delete_keys(&trans, inum, BTREE_ID_extents) ?:
start, end, NULL) ?: bch2_inode_delete_keys(&trans, inum, BTREE_ID_xattrs) ?:
bch2_btree_delete_range_trans(&trans, BTREE_ID_xattrs, bch2_inode_delete_keys(&trans, inum, BTREE_ID_dirents);
start, end, NULL) ?:
bch2_btree_delete_range_trans(&trans, BTREE_ID_dirents,
start, end, NULL);
if (ret) if (ret)
goto err; goto err;
retry: retry:
bch2_trans_begin(&trans); 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, 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); k = bch2_btree_iter_peek_slot(&iter);
ret = bkey_err(k); ret = bkey_err(k);
...@@ -632,7 +701,7 @@ int bch2_inode_rm(struct bch_fs *c, u64 inode_nr, bool cached) ...@@ -632,7 +701,7 @@ int bch2_inode_rm(struct bch_fs *c, u64 inode_nr, bool cached)
if (k.k->type != KEY_TYPE_inode) { if (k.k->type != KEY_TYPE_inode) {
bch2_fs_inconsistent(trans.c, bch2_fs_inconsistent(trans.c,
"inode %llu not found when deleting", "inode %llu not found when deleting",
inode_nr); inum.inum);
ret = -EIO; ret = -EIO;
goto err; goto err;
} }
...@@ -662,20 +731,22 @@ int bch2_inode_rm(struct bch_fs *c, u64 inode_nr, bool cached) ...@@ -662,20 +731,22 @@ int bch2_inode_rm(struct bch_fs *c, u64 inode_nr, bool cached)
return ret; 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 bch_inode_unpacked *inode)
{ {
struct btree_iter iter = { NULL }; struct btree_iter iter;
int ret; int ret;
ret = bch2_inode_peek(trans, &iter, inode, inode_nr, 0); ret = bch2_inode_peek(trans, &iter, inode, inum, 0);
bch2_trans_iter_exit(trans, &iter); if (!ret)
bch2_trans_iter_exit(trans, &iter);
return ret; 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) struct bch_inode_unpacked *inode)
{ {
return bch2_trans_do(c, NULL, NULL, 0, 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));
} }
...@@ -58,7 +58,7 @@ int bch2_inode_unpack(struct bkey_s_c_inode, struct bch_inode_unpacked *); ...@@ -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 *); void bch2_inode_unpacked_to_text(struct printbuf *, struct bch_inode_unpacked *);
int bch2_inode_peek(struct btree_trans *, struct btree_iter *, 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 *, int bch2_inode_write(struct btree_trans *, struct btree_iter *,
struct bch_inode_unpacked *); struct bch_inode_unpacked *);
...@@ -74,9 +74,10 @@ void bch2_inode_init(struct bch_fs *, 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 *, int bch2_inode_create(struct btree_trans *, struct btree_iter *,
struct bch_inode_unpacked *, u32, u64); 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) static inline struct bch_io_opts bch2_inode_opts_get(struct bch_inode_unpacked *inode)
{ {
......
...@@ -325,7 +325,10 @@ int bch2_extent_update(struct btree_trans *trans, ...@@ -325,7 +325,10 @@ int bch2_extent_update(struct btree_trans *trans,
struct bch_inode_unpacked inode_u; struct bch_inode_unpacked inode_u;
ret = bch2_inode_peek(trans, &inode_iter, &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) if (ret)
return ret; return ret;
......
...@@ -581,7 +581,8 @@ static int __bch2_move_data(struct bch_fs *c, ...@@ -581,7 +581,8 @@ static int __bch2_move_data(struct bch_fs *c,
stats->pos = start; stats->pos = start;
bch2_trans_iter_init(&trans, &iter, btree_id, start, bch2_trans_iter_init(&trans, &iter, btree_id, start,
BTREE_ITER_PREFETCH); BTREE_ITER_PREFETCH|
BTREE_ITER_ALL_SNAPSHOTS);
if (rate) if (rate)
bch2_ratelimit_reset(rate); bch2_ratelimit_reset(rate);
......
...@@ -1480,11 +1480,12 @@ int bch2_fs_initialize(struct bch_fs *c) ...@@ -1480,11 +1480,12 @@ int bch2_fs_initialize(struct bch_fs *c)
err = "error creating lost+found"; err = "error creating lost+found";
ret = bch2_trans_do(c, NULL, NULL, 0, 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, &root_inode, &lostfound_inode,
&lostfound, &lostfound,
0, 0, S_IFDIR|0700, 0, 0, 0, S_IFDIR|0700, 0,
NULL, NULL)); NULL, NULL, 0));
if (ret) { if (ret) {
bch_err(c, "error creating lost+found"); bch_err(c, "error creating lost+found");
goto err; goto err;
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include "inode.h" #include "inode.h"
#include "io.h" #include "io.h"
#include "reflink.h" #include "reflink.h"
#include "subvolume.h"
#include <linux/sched/signal.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) ...@@ -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, 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 remap_sectors, u64 *journal_seq,
u64 new_i_size, s64 *i_sectors_delta) u64 new_i_size, s64 *i_sectors_delta)
{ {
...@@ -205,6 +207,8 @@ s64 bch2_remap_range(struct bch_fs *c, ...@@ -205,6 +207,8 @@ s64 bch2_remap_range(struct bch_fs *c,
struct btree_iter dst_iter, src_iter; struct btree_iter dst_iter, src_iter;
struct bkey_s_c src_k; struct bkey_s_c src_k;
struct bkey_buf new_dst, new_src; 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 dst_end = dst_start, src_end = src_start;
struct bpos src_want; struct bpos src_want;
u64 dst_done; u64 dst_done;
...@@ -238,6 +242,16 @@ s64 bch2_remap_range(struct bch_fs *c, ...@@ -238,6 +242,16 @@ s64 bch2_remap_range(struct bch_fs *c,
break; 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; dst_done = dst_iter.pos.offset - dst_start.offset;
src_want = POS(src_start.inode, src_start.offset + dst_done); src_want = POS(src_start.inode, src_start.offset + dst_done);
bch2_btree_iter_set_pos(&src_iter, src_want); bch2_btree_iter_set_pos(&src_iter, src_want);
...@@ -311,7 +325,7 @@ s64 bch2_remap_range(struct bch_fs *c, ...@@ -311,7 +325,7 @@ s64 bch2_remap_range(struct bch_fs *c,
bch2_trans_begin(&trans); bch2_trans_begin(&trans);
ret2 = bch2_inode_peek(&trans, &inode_iter, &inode_u, ret2 = bch2_inode_peek(&trans, &inode_iter, &inode_u,
dst_start.inode, BTREE_ITER_INTENT); dst_inum, BTREE_ITER_INTENT);
if (!ret2 && if (!ret2 &&
inode_u.bi_size < new_i_size) { inode_u.bi_size < new_i_size) {
......
...@@ -57,7 +57,7 @@ static inline __le64 *bkey_refcount(struct bkey_i *k) ...@@ -57,7 +57,7 @@ static inline __le64 *bkey_refcount(struct bkey_i *k)
} }
} }
s64 bch2_remap_range(struct bch_fs *, struct bpos, struct bpos, s64 bch2_remap_range(struct bch_fs *, subvol_inum, u64,
u64, u64 *, u64, s64 *); subvol_inum, u64, u64, u64 *, u64, s64 *);
#endif /* _BCACHEFS_REFLINK_H */ #endif /* _BCACHEFS_REFLINK_H */
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "error.h" #include "error.h"
#include "inode.h" #include "inode.h"
#include "siphash.h" #include "siphash.h"
#include "subvolume.h"
#include "super.h" #include "super.h"
#include <linux/crc32c.h> #include <linux/crc32c.h>
...@@ -144,16 +145,21 @@ bch2_hash_lookup(struct btree_trans *trans, ...@@ -144,16 +145,21 @@ bch2_hash_lookup(struct btree_trans *trans,
struct btree_iter *iter, struct btree_iter *iter,
const struct bch_hash_desc desc, const struct bch_hash_desc desc,
const struct bch_hash_info *info, const struct bch_hash_info *info,
u64 inode, const void *key, subvol_inum inum, const void *key,
unsigned flags) unsigned flags)
{ {
struct bkey_s_c k; struct bkey_s_c k;
u32 snapshot;
int ret; int ret;
ret = bch2_subvolume_get_snapshot(trans, inum.subvol, &snapshot);
if (ret)
return ret;
for_each_btree_key(trans, *iter, desc.btree_id, 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) { BTREE_ITER_SLOTS|flags, k, ret) {
if (iter->pos.inode != inode) if (iter->pos.inode != inum.inum)
break; break;
if (k.k->type == desc.key_type) { if (k.k->type == desc.key_type) {
...@@ -176,15 +182,20 @@ bch2_hash_hole(struct btree_trans *trans, ...@@ -176,15 +182,20 @@ bch2_hash_hole(struct btree_trans *trans,
struct btree_iter *iter, struct btree_iter *iter,
const struct bch_hash_desc desc, const struct bch_hash_desc desc,
const struct bch_hash_info *info, const struct bch_hash_info *info,
u64 inode, const void *key) subvol_inum inum, const void *key)
{ {
struct bkey_s_c k; struct bkey_s_c k;
u32 snapshot;
int ret; int ret;
ret = bch2_subvolume_get_snapshot(trans, inum.subvol, &snapshot);
if (ret)
return ret;
for_each_btree_key(trans, *iter, desc.btree_id, 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) { BTREE_ITER_SLOTS|BTREE_ITER_INTENT, k, ret) {
if (iter->pos.inode != inode) if (iter->pos.inode != inum.inum)
break; break;
if (k.k->type != desc.key_type) if (k.k->type != desc.key_type)
...@@ -229,17 +240,25 @@ static __always_inline ...@@ -229,17 +240,25 @@ static __always_inline
int bch2_hash_set(struct btree_trans *trans, int bch2_hash_set(struct btree_trans *trans,
const struct bch_hash_desc desc, const struct bch_hash_desc desc,
const struct bch_hash_info *info, 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 btree_iter iter, slot = { NULL };
struct bkey_s_c k; struct bkey_s_c k;
bool found = false; bool found = false;
u32 snapshot;
int ret; int ret;
ret = bch2_subvolume_get_snapshot(trans, inum.subvol, &snapshot);
if (ret)
return ret;
for_each_btree_key(trans, iter, desc.btree_id, 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) { BTREE_ITER_SLOTS|BTREE_ITER_INTENT, k, ret) {
if (iter.pos.inode != inode) if (iter.pos.inode != inum.inum)
break; break;
if (k.k->type == desc.key_type) { if (k.k->type == desc.key_type) {
...@@ -313,12 +332,12 @@ static __always_inline ...@@ -313,12 +332,12 @@ static __always_inline
int bch2_hash_delete(struct btree_trans *trans, int bch2_hash_delete(struct btree_trans *trans,
const struct bch_hash_desc desc, const struct bch_hash_desc desc,
const struct bch_hash_info *info, const struct bch_hash_info *info,
u64 inode, const void *key) subvol_inum inum, const void *key)
{ {
struct btree_iter iter; struct btree_iter iter;
int ret; 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); BTREE_ITER_INTENT);
if (ret) if (ret)
return ret; return ret;
......
...@@ -128,7 +128,7 @@ static int bch2_xattr_get_trans(struct btree_trans *trans, struct bch_inode_info ...@@ -128,7 +128,7 @@ static int bch2_xattr_get_trans(struct btree_trans *trans, struct bch_inode_info
int ret; int ret;
ret = bch2_hash_lookup(trans, &iter, bch2_xattr_hash_desc, &hash, ret = bch2_hash_lookup(trans, &iter, bch2_xattr_hash_desc, &hash,
inode->v.i_ino, inode_inum(inode),
&X_SEARCH(type, name, strlen(name)), &X_SEARCH(type, name, strlen(name)),
0); 0);
if (ret) if (ret)
...@@ -160,7 +160,7 @@ int bch2_xattr_get(struct bch_fs *c, struct bch_inode_info *inode, ...@@ -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)); 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 struct bch_hash_info *hash_info,
const char *name, const void *value, size_t size, const char *name, const void *value, size_t size,
int type, int flags) int type, int flags)
...@@ -282,13 +282,21 @@ ssize_t bch2_xattr_list(struct dentry *dentry, char *buffer, size_t buffer_size) ...@@ -282,13 +282,21 @@ ssize_t bch2_xattr_list(struct dentry *dentry, char *buffer, size_t buffer_size)
struct btree_iter iter; struct btree_iter iter;
struct bkey_s_c k; struct bkey_s_c k;
struct xattr_buf buf = { .buf = buffer, .len = buffer_size }; 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; int ret;
bch2_trans_init(&trans, c, 0, 0); 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, 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); BUG_ON(k.k->p.inode < inum);
if (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) ...@@ -301,7 +309,12 @@ ssize_t bch2_xattr_list(struct dentry *dentry, char *buffer, size_t buffer_size)
if (ret) if (ret)
break; break;
} }
offset = iter.pos.offset;
bch2_trans_iter_exit(&trans, &iter); bch2_trans_iter_exit(&trans, &iter);
err:
if (ret == -EINTR)
goto retry;
ret = bch2_trans_exit(&trans) ?: ret; ret = bch2_trans_exit(&trans) ?: ret;
...@@ -340,7 +353,7 @@ static int bch2_xattr_set_handler(const struct xattr_handler *handler, ...@@ -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); struct bch_hash_info hash = bch2_hash_info_init(c, &inode->ei_inode);
return bch2_trans_do(c, NULL, &inode->ei_journal_seq, 0, 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, name, value, size,
handler->flags, flags)); handler->flags, flags));
} }
......
...@@ -39,7 +39,8 @@ struct bch_inode_info; ...@@ -39,7 +39,8 @@ struct bch_inode_info;
int bch2_xattr_get(struct bch_fs *, struct bch_inode_info *, int bch2_xattr_get(struct bch_fs *, struct bch_inode_info *,
const char *, void *, size_t, int); 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); const char *, const void *, size_t, int, int);
ssize_t bch2_xattr_list(struct dentry *, char *, size_t); ssize_t bch2_xattr_list(struct dentry *, char *, size_t);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment