bcachefs: Plumb through subvolume id
authorKent Overstreet <kent.overstreet@gmail.com>
Tue, 16 Mar 2021 04:28:17 +0000 (00:28 -0400)
committerKent Overstreet <kent.overstreet@linux.dev>
Sun, 22 Oct 2023 21:09:12 +0000 (17:09 -0400)
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>
23 files changed:
fs/bcachefs/acl.c
fs/bcachefs/acl.h
fs/bcachefs/dirent.c
fs/bcachefs/dirent.h
fs/bcachefs/extents.c
fs/bcachefs/extents.h
fs/bcachefs/fs-common.c
fs/bcachefs/fs-common.h
fs/bcachefs/fs-io.c
fs/bcachefs/fs-ioctl.c
fs/bcachefs/fs.c
fs/bcachefs/fs.h
fs/bcachefs/fsck.c
fs/bcachefs/inode.c
fs/bcachefs/inode.h
fs/bcachefs/io.c
fs/bcachefs/move.c
fs/bcachefs/recovery.c
fs/bcachefs/reflink.c
fs/bcachefs/reflink.h
fs/bcachefs/str_hash.h
fs/bcachefs/xattr.c
fs/bcachefs/xattr.h

index 93b78e4e6e0dc12933019e31aba78f68b5971b46..2afa15b267009cd28a012c4e15b7a586437bbfc9 100644 (file)
@@ -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)
index f11eb9d4592c470ad496d42136ba042786b66c59..bb21d8d696a2fc3806d9ee1e353999ccd424d99b 100644 (file)
@@ -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)
index f3aef06869283b430fefd241507cbffc6d1cba81..f290580594ce3b68ba3a03546681f3f3a915dc78 100644 (file)
@@ -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;
 
index 3cd05a2454e11e47febb75771115bc2e5dc0fe89..88b784a99cb5dc2f5f88ca4bd24eed3f2a017615 100644 (file)
@@ -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 */
index 0190605711e531dcbf2c706408cd9636e8a0a82c..966d6ef4179391fd907fcdf10992a76d1f2d2455 100644 (file)
@@ -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);
index 43cef0a3bdf3870f47afc849f5f54700e3664824..afd3067bb64eb83be7c16f954094f9c148c72be7 100644 (file)
@@ -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);
index 96b09b005d0bcc54720f887a5404e255b9409b82..02bf32cc7659a857084ff22c51ed91267f68bbde 100644 (file)
@@ -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:
index 2273b7961c9be6ab2d8960fda7f86068d4e44cad..1bb2ac4dc13af624927065d72e28c1e540fc2ed8 100644 (file)
@@ -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 *,
index 909db2f104cdc74dfd382e0fb8b84ce80a8e7dab..7a07721951827124d3a2e1455b0b80d7402c0746 100644 (file)
@@ -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)
index ff6b1739342df4a121b50c0e765822b0358d3ab3..91f52ab9b4e21af4eb7ea81c383b08e2569aa081 100644 (file)
@@ -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);
index 7a994f3f9d20978c757189bcd4f8b61bf99fc11c..0d47d9d5737b7de10f235f9d2a3021d5d324d255 100644 (file)
@@ -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);
        }
 }
 
index 6dae425bf616cb65ab5918b946c22521fb899a4d..aa755987b36c913ef1d221f30305bcd31193e147 100644 (file)
@@ -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,
index e4ca05aae76c9215600e7435ddcf0859b2213f3b..40b107715cddf4489cda45b09795e334e00a4a3f 100644 (file)
@@ -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;
 
index 3b19dc6b9ddc4a23334a22d99814c1ba75fa0a14..7fccf842a46bd147888ebaec19b86f46887cc118 100644 (file)
@@ -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));
 }
index 25bef104ebcc5a692a6dcc54c2b105697fadb294..9e84cddcc6cb707461b2810e510849ff0eabd343 100644 (file)
@@ -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)
 {
index f95ceb820faabf19ab7dcc688424d7cc62fadfca..0f5e0099b848f25f32c6184682bd86f14eb8853e 100644 (file)
@@ -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;
 
index eb2b91f7e68222205b6f28cfe7869df2282478e8..9dc6684139de584c734563de2493fbcbc324298b 100644 (file)
@@ -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);
index 2aab57cf09e1ba9af17950ff833ff4f4540fe429..47c8fecc683953cbdceedea1e211de1a45d382a6 100644 (file)
@@ -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;
index 576cfbccf5b537b2d000935d739476b278fe58b7..be4b47bc7438589b6e20099c744c4abc6f42fdaa 100644 (file)
@@ -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) {
index 68c5cb5a2780ddd1552d41d03229e145f1d14d3c..4c1b82860b0b9ca31aae88213d2dcb7916bfcfc1 100644 (file)
@@ -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 */
index c6a132b3c5bb2eb24cf112f11fd23d254e01b499..6418089531ad6d788a8f6de718ac40860eff777e 100644 (file)
@@ -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;
index babbfaadeb3f328d7dc7ae973c6365fb75e8af1d..ff81a25698ff0290c431aba50557e5d1e3dd6f67 100644 (file)
@@ -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));
 }
index 4151065ab853546c3f071a831cfba10d9af03010..f4f896545e1c29f0ff35018263bf6b227250567b 100644 (file)
@@ -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);