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,
bch2_trans_begin(&trans);
ret = bch2_hash_lookup(&trans, &iter, bch2_xattr_hash_desc,
&hash, inode->v.i_ino,
&hash, inode_inum(inode),
&X_SEARCH(acl_to_xattr_type(type), "", 0),
0);
if (ret) {
......@@ -260,11 +260,11 @@ struct posix_acl *bch2_get_acl(struct mnt_idmap *idmap,
return acl;
}
int bch2_set_acl_trans(struct btree_trans *trans,
int bch2_set_acl_trans(struct btree_trans *trans, subvol_inum inum,
struct bch_inode_unpacked *inode_u,
const struct bch_hash_info *hash_info,
struct posix_acl *acl, int type)
{
struct bch_hash_info hash_info = bch2_hash_info_init(trans->c, inode_u);
int ret;
if (type == ACL_TYPE_DEFAULT &&
......@@ -277,14 +277,14 @@ int bch2_set_acl_trans(struct btree_trans *trans,
if (IS_ERR(xattr))
return PTR_ERR(xattr);
ret = bch2_hash_set(trans, bch2_xattr_hash_desc, hash_info,
inode_u->bi_inum, &xattr->k_i, 0);
ret = bch2_hash_set(trans, bch2_xattr_hash_desc, &hash_info,
inum, &xattr->k_i, 0);
} else {
struct xattr_search_key search =
X_SEARCH(acl_to_xattr_type(type), "", 0);
ret = bch2_hash_delete(trans, bch2_xattr_hash_desc, hash_info,
inode_u->bi_inum, &search);
ret = bch2_hash_delete(trans, bch2_xattr_hash_desc, &hash_info,
inum, &search);
}
return ret == -ENOENT ? 0 : ret;
......@@ -299,7 +299,6 @@ int bch2_set_acl(struct mnt_idmap *idmap,
struct btree_trans trans;
struct btree_iter inode_iter = { NULL };
struct bch_inode_unpacked inode_u;
struct bch_hash_info hash_info;
struct posix_acl *acl;
umode_t mode;
int ret;
......@@ -310,7 +309,7 @@ int bch2_set_acl(struct mnt_idmap *idmap,
bch2_trans_begin(&trans);
acl = _acl;
ret = bch2_inode_peek(&trans, &inode_iter, &inode_u, inode->v.i_ino,
ret = bch2_inode_peek(&trans, &inode_iter, &inode_u, inode_inum(inode),
BTREE_ITER_INTENT);
if (ret)
goto btree_err;
......@@ -323,9 +322,7 @@ int bch2_set_acl(struct mnt_idmap *idmap,
goto btree_err;
}
hash_info = bch2_hash_info_init(c, &inode_u);
ret = bch2_set_acl_trans(&trans, &inode_u, &hash_info, acl, type);
ret = bch2_set_acl_trans(&trans, inode_inum(inode), &inode_u, acl, type);
if (ret)
goto btree_err;
......@@ -354,7 +351,7 @@ int bch2_set_acl(struct mnt_idmap *idmap,
return ret;
}
int bch2_acl_chmod(struct btree_trans *trans,
int bch2_acl_chmod(struct btree_trans *trans, subvol_inum inum,
struct bch_inode_unpacked *inode,
umode_t mode,
struct posix_acl **new_acl)
......@@ -368,7 +365,7 @@ int bch2_acl_chmod(struct btree_trans *trans,
int ret;
ret = bch2_hash_lookup(trans, &iter, bch2_xattr_hash_desc,
&hash_info, inode->bi_inum,
&hash_info, inum,
&X_SEARCH(KEY_TYPE_XATTR_INDEX_POSIX_ACL_ACCESS, "", 0),
BTREE_ITER_INTENT);
if (ret)
......
......@@ -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 @@ int __bch2_dirent_read_target(struct btree_trans *trans,
return ret;
}
int bch2_dirent_read_target(struct btree_trans *trans,
struct bkey_s_c_dirent d, u64 *target)
static int bch2_dirent_read_target(struct btree_trans *trans, subvol_inum dir,
struct bkey_s_c_dirent d, subvol_inum *target)
{
u32 subvol, snapshot;
u32 snapshot;
int ret = 0;
return __bch2_dirent_read_target(trans, d, &subvol,
&snapshot, target, false);
ret = __bch2_dirent_read_target(trans, d, &target->subvol, &snapshot,
&target->inum, false);
if (!target->subvol)
target->subvol = dir.subvol;
return ret;
}
int bch2_dirent_rename(struct btree_trans *trans,
u64 src_dir, struct bch_hash_info *src_hash,
u64 dst_dir, struct bch_hash_info *dst_hash,
const struct qstr *src_name, u64 *src_inum, u64 *src_offset,
const struct qstr *dst_name, u64 *dst_inum, u64 *dst_offset,
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);
......
This diff is collapsed.
......@@ -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 @@ int bch2_fsync(struct file *file, loff_t start, loff_t end, int datasync)
/* 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 @@ __bch2_create(struct mnt_idmap *idmap,
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 @@ __bch2_create(struct mnt_idmap *idmap,
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 @@ int bch2_setattr_nonsize(struct mnt_idmap *idmap,
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 @@ int bch2_setattr_nonsize(struct mnt_idmap *idmap,
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 @@ static int bch2_fiemap(struct inode *vinode, struct fiemap_extent_info *info,
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 @@ 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),
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 @@ int bch2_inode_create(struct btree_trans *trans,
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 @@ int bch2_inode_rm(struct bch_fs *c, u64 inode_nr, bool cached)
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 @@ int bch2_inode_rm(struct bch_fs *c, u64 inode_nr, bool cached)
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);
......
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