mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-09 14:43:16 +00:00
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>
This commit is contained in:
parent
c075ff700f
commit
6fed42bb77
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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:
|
||||
|
@ -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 *,
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user