]> git.sesse.net Git - bcachefs-tools-debian/commitdiff
Update bcachefs sources to 6a20aede29 bcachefs: Fix quotas + snapshots
authorKent Overstreet <kent.overstreet@linux.dev>
Wed, 26 Apr 2023 20:34:57 +0000 (16:34 -0400)
committerKent Overstreet <kent.overstreet@linux.dev>
Tue, 2 May 2023 04:41:47 +0000 (00:41 -0400)
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
77 files changed:
.bcachefs_revision
Makefile
Makefile.compiler
include/linux/kernel.h
include/linux/poison.h
include/linux/types.h
include/linux/uuid.h
include/linux/xattr.h
libbcachefs/acl.c
libbcachefs/acl.h
libbcachefs/alloc_background.c
libbcachefs/alloc_background.h
libbcachefs/alloc_foreground.c
libbcachefs/backpointers.c
libbcachefs/backpointers.h
libbcachefs/bcachefs.h
libbcachefs/bcachefs_format.h
libbcachefs/bkey.h
libbcachefs/bkey_methods.c
libbcachefs/bkey_methods.h
libbcachefs/bset.c
libbcachefs/btree_cache.c
libbcachefs/btree_gc.c
libbcachefs/btree_io.c
libbcachefs/btree_iter.c
libbcachefs/btree_iter.h
libbcachefs/btree_key_cache.c
libbcachefs/btree_types.h
libbcachefs/btree_update.h
libbcachefs/btree_update_interior.c
libbcachefs/btree_update_leaf.c
libbcachefs/buckets.c
libbcachefs/data_update.c
libbcachefs/dirent.c
libbcachefs/dirent.h
libbcachefs/ec.c
libbcachefs/ec.h
libbcachefs/errcode.h
libbcachefs/extents.c
libbcachefs/extents.h
libbcachefs/fs-io.c
libbcachefs/fs-io.h
libbcachefs/fs-ioctl.c
libbcachefs/fs.c
libbcachefs/fs.h
libbcachefs/fsck.c
libbcachefs/inode.c
libbcachefs/inode.h
libbcachefs/io.c
libbcachefs/io.h
libbcachefs/io_types.h
libbcachefs/journal.c
libbcachefs/journal_io.c
libbcachefs/journal_reclaim.c
libbcachefs/lru.c
libbcachefs/lru.h
libbcachefs/migrate.c
libbcachefs/move.c
libbcachefs/movinggc.c
libbcachefs/quota.c
libbcachefs/quota.h
libbcachefs/rebalance.c
libbcachefs/recovery.c
libbcachefs/reflink.c
libbcachefs/reflink.h
libbcachefs/subvolume.c
libbcachefs/subvolume.h
libbcachefs/subvolume_types.h
libbcachefs/super-io.c
libbcachefs/super.c
libbcachefs/trace.c
libbcachefs/trace.h [moved from include/trace/events/bcachefs.h with 98% similarity]
libbcachefs/util.c
libbcachefs/util.h
libbcachefs/xattr.c
libbcachefs/xattr.h
rust-src/bch_bindgen/src/bkey.rs

index bed19acbd199bc75748396511916f3997653c2aa..e5747fce31c81b1b0de1ae11b230919ce9668abd 100644 (file)
@@ -1 +1 @@
-fd6fb298aa869dc009e525baa9be67ad52588361
+6a20aede294f72f3920146a352aa102a9fd3d0aa
index 31fb9ac07eaf605aaed6373233d5f83e9d952dcc..3fc52cfcdbe9fa0c560dea6749472c199fc7e045 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -184,8 +184,6 @@ update-bcachefs-sources:
        test -d libbcachefs || mkdir libbcachefs
        cp $(LINUX_DIR)/fs/bcachefs/*.[ch] libbcachefs/
        git add libbcachefs/*.[ch]
-       cp $(LINUX_DIR)/include/trace/events/bcachefs.h include/trace/events/
-       git add include/trace/events/bcachefs.h
        cp $(LINUX_DIR)/include/linux/closure.h include/linux/
        git add include/linux/closure.h
        cp $(LINUX_DIR)/lib/closure.c linux/
index 3d8adfd34af1baf9e9155af660cdafa708000612..7aa1fbc4aafef69327bf3b0ca51a80c1d46492a0 100644 (file)
@@ -29,16 +29,16 @@ try-run = $(shell set -e;           \
        fi)
 
 # as-option
-# Usage: cflags-y += $(call as-option,-Wa$(comma)-isa=foo,)
+# Usage: aflags-y += $(call as-option,-Wa$(comma)-isa=foo,)
 
 as-option = $(call try-run,\
-       $(CC) $(KBUILD_CFLAGS) $(1) -c -x assembler /dev/null -o "$$TMP",$(1),$(2))
+       $(CC) -Werror $(KBUILD_AFLAGS) $(1) -c -x assembler-with-cpp /dev/null -o "$$TMP",$(1),$(2))
 
 # as-instr
-# Usage: cflags-y += $(call as-instr,instr,option1,option2)
+# Usage: aflags-y += $(call as-instr,instr,option1,option2)
 
 as-instr = $(call try-run,\
-       printf "%b\n" "$(1)" | $(CC) $(KBUILD_AFLAGS) -c -x assembler -o "$$TMP" -,$(2),$(3))
+       printf "%b\n" "$(1)" | $(CC) -Werror $(KBUILD_AFLAGS) -c -x assembler-with-cpp -o "$$TMP" -,$(2),$(3))
 
 # __cc-option
 # Usage: MY_CFLAGS += $(call __cc-option,$(CC),$(MY_CFLAGS),-march=winchip-c6,-march=i586)
index a55b8a9b5d17f05ccbffce08f02628fba9c296ab..01466c408cdb8282fc137a602f34426ac6c6e3ed 100644 (file)
        (type *)((char *)__mptr - offsetof(type, member)); })
 #endif
 
+#define __struct_group(TAG, NAME, ATTRS, MEMBERS...) \
+       union { \
+               struct { MEMBERS } ATTRS; \
+               struct TAG { MEMBERS } ATTRS NAME; \
+       }
+#define struct_group(NAME, MEMBERS...) \
+       __struct_group(/* no tag */, NAME, /* no attrs */, MEMBERS)
+
 #define max(x, y) ({                           \
        typeof(x) _max1 = (x);                  \
        typeof(y) _max2 = (y);                  \
index 2d3249eb0e62d4b29f03e6e03a21934f555278aa..851a855d386884177eb50db59a67821168c2258d 100644 (file)
 /********** net/core/page_pool.c **********/
 #define PP_SIGNATURE           (0x40 + POISON_POINTER_DELTA)
 
+/********** net/core/skbuff.c **********/
+#define SKB_LIST_POISON_NEXT   ((void *)(0x800 + POISON_POINTER_DELTA))
+
 /********** kernel/bpf/ **********/
 #define BPF_PTR_POISON ((void *)(0xeB9FUL + POISON_POINTER_DELTA))
 
+/********** VFS **********/
+#define VFS_PTR_POISON ((void *)(0xF5 + POISON_POINTER_DELTA))
+
 #endif
index fc05e23afe379218b123b9e28102db8b7f7ce4b7..ce454e2661e9f70a1a5e53135f762751d454ab71 100644 (file)
@@ -82,5 +82,6 @@ typedef int (*cmp_func_t)(const void *a, const void *b);
 typedef unsigned int __bitwise slab_flags_t;
 typedef u64 phys_addr_t;
 struct vm_struct;
+struct mnt_idmap;
 
 #endif /* _TOOLS_LINUX_TYPES_H_ */
index c8eeb708e34f9f31c5440e07689bd002170e70ad..4674746fd98d55f2d3cb7b2559b838e97159f7ac 100644 (file)
@@ -41,9 +41,4 @@ typedef struct {
    ((c) >> 8) & 0xff, (c) & 0xff,                                      \
    (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) }})
 
-static inline int uuid_le_cmp(const uuid_le u1, const uuid_le u2)
-{
-       return memcmp(&u1, &u2, sizeof(uuid_le));
-}
-
 #endif
index 222c72fecb227087b57d3b7ad3e603e6f2c3c17c..dcdff6e8e18ca037726655b1a964f16b962e4cc2 100644 (file)
@@ -42,7 +42,7 @@ struct xattr_handler {
                   struct inode *inode, const char *name, void *buffer,
                   size_t size);
        int (*set)(const struct xattr_handler *,
-                  struct user_namespace *mnt_userns, struct dentry *dentry,
+                  struct mnt_idmap *idmap, struct dentry *dentry,
                   struct inode *inode, const char *name, const void *buffer,
                   size_t size, int flags);
 };
index 5cb06ac589602da4abf45fa5506788290607bf16..2bf58aa89f71603d5e8e257b4fab0693f50adaf6 100644 (file)
@@ -212,7 +212,7 @@ bch2_acl_to_xattr(struct btree_trans *trans,
        return xattr;
 }
 
-struct posix_acl *bch2_get_acl(struct user_namespace *mnt_userns,
+struct posix_acl *bch2_get_acl(struct mnt_idmap *idmap,
                               struct dentry *dentry, int type)
 {
        struct bch_inode_info *inode = to_bch_ei(dentry->d_inode);
@@ -290,7 +290,7 @@ int bch2_set_acl_trans(struct btree_trans *trans, subvol_inum inum,
        return ret == -ENOENT ? 0 : ret;
 }
 
-int bch2_set_acl(struct user_namespace *mnt_userns,
+int bch2_set_acl(struct mnt_idmap *idmap,
                 struct dentry *dentry,
                 struct posix_acl *_acl, int type)
 {
@@ -317,7 +317,7 @@ retry:
        mode = inode_u.bi_mode;
 
        if (type == ACL_TYPE_ACCESS) {
-               ret = posix_acl_update_mode(mnt_userns, &inode->v, &mode, &acl);
+               ret = posix_acl_update_mode(idmap, &inode->v, &mode, &acl);
                if (ret)
                        goto btree_err;
        }
index ac206f6584e9856828f061d3bbe6343251f1c901..bb21d8d696a2fc3806d9ee1e353999ccd424d99b 100644 (file)
@@ -26,12 +26,12 @@ typedef struct {
        __le32          a_version;
 } bch_acl_header;
 
-struct posix_acl *bch2_get_acl(struct user_namespace *, struct dentry *, int);
+struct posix_acl *bch2_get_acl(struct mnt_idmap *, struct dentry *, int);
 
 int bch2_set_acl_trans(struct btree_trans *, subvol_inum,
                       struct bch_inode_unpacked *,
                       struct posix_acl *, int);
-int bch2_set_acl(struct user_namespace *, struct dentry *, struct posix_acl *, int);
+int bch2_set_acl(struct mnt_idmap *, struct dentry *, struct posix_acl *, int);
 int bch2_acl_chmod(struct btree_trans *, subvol_inum,
                   struct bch_inode_unpacked *,
                   umode_t, struct posix_acl **);
index 816208703f4742c1420d6ad2bdf1105cd959e5c5..dcdef3bcd4c49159fb1962601acb1e5bb9d495c4 100644 (file)
@@ -18,6 +18,7 @@
 #include "error.h"
 #include "lru.h"
 #include "recovery.h"
+#include "trace.h"
 #include "varint.h"
 
 #include <linux/kthread.h>
@@ -27,7 +28,6 @@
 #include <linux/rcupdate.h>
 #include <linux/sched/task.h>
 #include <linux/sort.h>
-#include <trace/events/bcachefs.h>
 
 /* Persistent alloc info: */
 
@@ -511,18 +511,8 @@ static inline struct bkey_i_alloc_v4 *bch2_alloc_to_v4_mut_inlined(struct btree_
 
        if (likely(k.k->type == KEY_TYPE_alloc_v4) &&
            ((a = bkey_s_c_to_alloc_v4(k), true) &&
-            BCH_ALLOC_V4_BACKPOINTERS_START(a.v) == BCH_ALLOC_V4_U64s &&
-            BCH_ALLOC_V4_NR_BACKPOINTERS(a.v) == 0)) {
-               /*
-                * Reserve space for one more backpointer here:
-                * Not sketchy at doing it this way, nope...
-                */
-               struct bkey_i_alloc_v4 *ret =
-                       bch2_trans_kmalloc_nomemzero(trans, bkey_bytes(k.k) + sizeof(struct bch_backpointer));
-               if (!IS_ERR(ret))
-                       bkey_reassemble(&ret->k_i, k);
-               return ret;
-       }
+            BCH_ALLOC_V4_NR_BACKPOINTERS(a.v) == 0))
+               return bch2_bkey_make_mut_noupdate_typed(trans, k, alloc_v4);
 
        return __bch2_alloc_to_v4_mut(trans, k);
 }
@@ -540,14 +530,13 @@ bch2_trans_start_alloc_update(struct btree_trans *trans, struct btree_iter *iter
        struct bkey_i_alloc_v4 *a;
        int ret;
 
-       bch2_trans_iter_init(trans, iter, BTREE_ID_alloc, pos,
+       k = bch2_bkey_get_iter(trans, iter, BTREE_ID_alloc, pos,
                             BTREE_ITER_WITH_UPDATES|
                             BTREE_ITER_CACHED|
                             BTREE_ITER_INTENT);
-       k = bch2_btree_iter_peek_slot(iter);
        ret = bkey_err(k);
        if (unlikely(ret))
-               goto err;
+               return ERR_PTR(ret);
 
        a = bch2_alloc_to_v4_mut_inlined(trans, k);
        ret = PTR_ERR_OR_ZERO(a);
@@ -789,13 +778,12 @@ static int bch2_bucket_do_index(struct btree_trans *trans,
                return 0;
        }
 
-       bch2_trans_iter_init(trans, &iter, btree,
+       old = bch2_bkey_get_iter(trans, &iter, btree,
                             bkey_start_pos(&k->k),
                             BTREE_ITER_INTENT);
-       old = bch2_btree_iter_peek_slot(&iter);
        ret = bkey_err(old);
        if (ret)
-               goto err;
+               return ret;
 
        if (ca->mi.freespace_initialized &&
            test_bit(BCH_FS_CHECK_ALLOC_DONE, &c->flags) &&
@@ -833,13 +821,12 @@ static noinline int bch2_bucket_gen_update(struct btree_trans *trans,
        if (ret)
                return ret;
 
-       bch2_trans_iter_init(trans, &iter, BTREE_ID_bucket_gens, pos,
-                            BTREE_ITER_INTENT|
-                            BTREE_ITER_WITH_UPDATES);
-       k = bch2_btree_iter_peek_slot(&iter);
+       k = bch2_bkey_get_iter(trans, &iter, BTREE_ID_bucket_gens, pos,
+                              BTREE_ITER_INTENT|
+                              BTREE_ITER_WITH_UPDATES);
        ret = bkey_err(k);
        if (ret)
-               goto err;
+               return ret;
 
        if (k.k->type != KEY_TYPE_bucket_gens) {
                bkey_bucket_gens_init(&g->k_i);
@@ -851,7 +838,6 @@ static noinline int bch2_bucket_gen_update(struct btree_trans *trans,
        g->v.gens[offset] = gen;
 
        ret = bch2_trans_update(trans, &iter, &g->k_i, 0);
-err:
        bch2_trans_iter_exit(trans, &iter);
        return ret;
 }
@@ -1312,18 +1298,16 @@ static int bch2_check_discard_freespace_key(struct btree_trans *trans,
        pos.offset &= ~(~0ULL << 56);
        genbits = iter->pos.offset & (~0ULL << 56);
 
-       bch2_trans_iter_init(trans, &alloc_iter, BTREE_ID_alloc, pos, 0);
+       alloc_k = bch2_bkey_get_iter(trans, &alloc_iter, BTREE_ID_alloc, pos, 0);
+       ret = bkey_err(alloc_k);
+       if (ret)
+               return ret;
 
        if (fsck_err_on(!bch2_dev_bucket_exists(c, pos), c,
                        "entry in %s btree for nonexistant dev:bucket %llu:%llu",
                        bch2_btree_ids[iter->btree_id], pos.inode, pos.offset))
                goto delete;
 
-       alloc_k = bch2_btree_iter_peek_slot(&alloc_iter);
-       ret = bkey_err(alloc_k);
-       if (ret)
-               goto err;
-
        a = bch2_alloc_to_v4(alloc_k, &a_convert);
 
        if (fsck_err_on(a->data_type != state ||
@@ -1336,7 +1320,6 @@ static int bch2_check_discard_freespace_key(struct btree_trans *trans,
                        genbits >> 56, alloc_freespace_genbits(*a) >> 56))
                goto delete;
 out:
-err:
 fsck_err:
        bch2_trans_iter_exit(trans, &alloc_iter);
        printbuf_exit(&buf);
@@ -1525,7 +1508,7 @@ static int bch2_check_alloc_to_lru_ref(struct btree_trans *trans,
        struct btree_iter lru_iter;
        struct bch_alloc_v4 a_convert;
        const struct bch_alloc_v4 *a;
-       struct bkey_s_c alloc_k, k;
+       struct bkey_s_c alloc_k, lru_k;
        struct printbuf buf = PRINTBUF;
        int ret;
 
@@ -1542,21 +1525,20 @@ static int bch2_check_alloc_to_lru_ref(struct btree_trans *trans,
        if (a->data_type != BCH_DATA_cached)
                return 0;
 
-       bch2_trans_iter_init(trans, &lru_iter, BTREE_ID_lru,
+       lru_k = bch2_bkey_get_iter(trans, &lru_iter, BTREE_ID_lru,
                             lru_pos(alloc_k.k->p.inode,
                                     bucket_to_u64(alloc_k.k->p),
                                     a->io_time[READ]), 0);
-       k = bch2_btree_iter_peek_slot(&lru_iter);
-       ret = bkey_err(k);
+       ret = bkey_err(lru_k);
        if (ret)
-               goto err;
+               return ret;
 
        if (fsck_err_on(!a->io_time[READ], c,
                        "cached bucket with read_time 0\n"
                        "  %s",
                (printbuf_reset(&buf),
                 bch2_bkey_val_to_text(&buf, c, alloc_k), buf.buf)) ||
-           fsck_err_on(k.k->type != KEY_TYPE_set, c,
+           fsck_err_on(lru_k.k->type != KEY_TYPE_set, c,
                        "missing lru entry\n"
                        "  %s",
                        (printbuf_reset(&buf),
@@ -1645,10 +1627,9 @@ static int bch2_discard_one_bucket(struct btree_trans *trans,
                goto out;
        }
 
-       bch2_trans_iter_init(trans, &iter, BTREE_ID_alloc,
-                            need_discard_iter->pos,
-                            BTREE_ITER_CACHED);
-       k = bch2_btree_iter_peek_slot(&iter);
+       k = bch2_bkey_get_iter(trans, &iter, BTREE_ID_alloc,
+                              need_discard_iter->pos,
+                              BTREE_ITER_CACHED);
        ret = bkey_err(k);
        if (ret)
                goto out;
index 324798396fc6b667f608e035a78033e2c035f456..fc4420f4bc21fc7a430f7a8225f091abf5dafbb1 100644 (file)
@@ -159,6 +159,7 @@ void bch2_alloc_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
        .val_to_text    = bch2_alloc_to_text,           \
        .trans_trigger  = bch2_trans_mark_alloc,        \
        .atomic_trigger = bch2_mark_alloc,              \
+       .min_val_size   = 8,                            \
 })
 
 #define bch2_bkey_ops_alloc_v2 ((struct bkey_ops) {    \
@@ -166,6 +167,7 @@ void bch2_alloc_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
        .val_to_text    = bch2_alloc_to_text,           \
        .trans_trigger  = bch2_trans_mark_alloc,        \
        .atomic_trigger = bch2_mark_alloc,              \
+       .min_val_size   = 8,                            \
 })
 
 #define bch2_bkey_ops_alloc_v3 ((struct bkey_ops) {    \
@@ -173,6 +175,7 @@ void bch2_alloc_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
        .val_to_text    = bch2_alloc_to_text,           \
        .trans_trigger  = bch2_trans_mark_alloc,        \
        .atomic_trigger = bch2_mark_alloc,              \
+       .min_val_size   = 16,                           \
 })
 
 #define bch2_bkey_ops_alloc_v4 ((struct bkey_ops) {    \
@@ -181,6 +184,7 @@ void bch2_alloc_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
        .swab           = bch2_alloc_v4_swab,           \
        .trans_trigger  = bch2_trans_mark_alloc,        \
        .atomic_trigger = bch2_mark_alloc,              \
+       .min_val_size   = 56,                           \
 })
 
 int bch2_bucket_gens_invalid(const struct bch_fs *, struct bkey_s_c, unsigned, struct printbuf *);
index 350635f3b118b31c1d203e909b7616b9789babc3..ec77601ebd0cb704683514ac42b0339ae0fc1eb2 100644 (file)
 #include "journal.h"
 #include "movinggc.h"
 #include "nocow_locking.h"
+#include "trace.h"
 
 #include <linux/math64.h>
 #include <linux/rculist.h>
 #include <linux/rcupdate.h>
-#include <trace/events/bcachefs.h>
 
 const char * const bch2_alloc_reserves[] = {
 #define x(t) #t,
@@ -303,8 +303,9 @@ static struct open_bucket *try_alloc_bucket(struct btree_trans *trans, struct bc
                goto err;
        }
 
-       bch2_trans_iter_init(trans, &iter, BTREE_ID_alloc, POS(ca->dev_idx, b), BTREE_ITER_CACHED);
-       k = bch2_btree_iter_peek_slot(&iter);
+       k = bch2_bkey_get_iter(trans, &iter,
+                              BTREE_ID_alloc, POS(ca->dev_idx, b),
+                              BTREE_ITER_CACHED);
        ret = bkey_err(k);
        if (ret) {
                ob = ERR_PTR(ret);
index a3a1ed6e596819bbdb530ee70d14a8a2e781fc74..e9ae623cf4a8145fd8dc148565f21235976866ec 100644 (file)
@@ -43,11 +43,6 @@ int bch2_backpointer_invalid(const struct bch_fs *c, struct bkey_s_c k,
        struct bkey_s_c_backpointer bp = bkey_s_c_to_backpointer(k);
        struct bpos bucket = bp_pos_to_bucket(c, bp.k->p);
 
-       if (bkey_val_bytes(bp.k) < sizeof(*bp.v)) {
-               prt_str(err, "incorrect value size");
-               return -BCH_ERR_invalid_bkey;
-       }
-
        if (!bpos_eq(bp.k->p, bucket_pos_to_bp(c, bucket, bp.v->bucket_offset))) {
                prt_str(err, "backpointer at wrong pos");
                return -BCH_ERR_invalid_bkey;
@@ -163,12 +158,11 @@ int bch2_bucket_backpointer_mod_nowritebuffer(struct btree_trans *trans,
                set_bkey_val_u64s(&bp_k->k, 0);
        }
 
-       bch2_trans_iter_init(trans, &bp_iter, BTREE_ID_backpointers,
-                            bp_k->k.p,
-                            BTREE_ITER_INTENT|
-                            BTREE_ITER_SLOTS|
-                            BTREE_ITER_WITH_UPDATES);
-       k = bch2_btree_iter_peek_slot(&bp_iter);
+       k = bch2_bkey_get_iter(trans, &bp_iter, BTREE_ID_backpointers,
+                              bp_k->k.p,
+                              BTREE_ITER_INTENT|
+                              BTREE_ITER_SLOTS|
+                              BTREE_ITER_WITH_UPDATES);
        ret = bkey_err(k);
        if (ret)
                goto err;
@@ -207,9 +201,8 @@ int bch2_get_next_backpointer(struct btree_trans *trans,
                goto done;
 
        if (gen >= 0) {
-               bch2_trans_iter_init(trans, &alloc_iter, BTREE_ID_alloc,
-                                    bucket, BTREE_ITER_CACHED|iter_flags);
-               k = bch2_btree_iter_peek_slot(&alloc_iter);
+               k = bch2_bkey_get_iter(trans, &alloc_iter, BTREE_ID_alloc,
+                                      bucket, BTREE_ITER_CACHED|iter_flags);
                ret = bkey_err(k);
                if (ret)
                        goto out;
@@ -386,10 +379,8 @@ static int bch2_check_btree_backpointer(struct btree_trans *trans, struct btree_
 
        ca = bch_dev_bkey_exists(c, k.k->p.inode);
 
-       bch2_trans_iter_init(trans, &alloc_iter, BTREE_ID_alloc,
-                            bp_pos_to_bucket(c, k.k->p), 0);
-
-       alloc_k = bch2_btree_iter_peek_slot(&alloc_iter);
+       alloc_k = bch2_bkey_get_iter(trans, &alloc_iter, BTREE_ID_alloc,
+                                    bp_pos_to_bucket(c, k.k->p), 0);
        ret = bkey_err(alloc_k);
        if (ret)
                goto out;
@@ -447,10 +438,9 @@ static int check_bp_exists(struct btree_trans *trans,
        if (!bch2_dev_bucket_exists(c, bucket))
                goto missing;
 
-       bch2_trans_iter_init(trans, &bp_iter, BTREE_ID_backpointers,
-                            bucket_pos_to_bp(c, bucket, bp.bucket_offset),
-                            0);
-       bp_k = bch2_btree_iter_peek_slot(&bp_iter);
+       bp_k = bch2_bkey_get_iter(trans, &bp_iter, BTREE_ID_backpointers,
+                                 bucket_pos_to_bp(c, bucket, bp.bucket_offset),
+                                 0);
        ret = bkey_err(bp_k);
        if (ret)
                goto err;
index 9c03709ade50420ee7e694ca8b04ed90871599c7..3994bc83d69df31e90df8fd7c48677e217be42d7 100644 (file)
@@ -17,6 +17,7 @@ void bch2_backpointer_swab(struct bkey_s);
        .key_invalid    = bch2_backpointer_invalid,     \
        .val_to_text    = bch2_backpointer_k_to_text,   \
        .swab           = bch2_backpointer_swab,        \
+       .min_val_size   = 32,                           \
 })
 
 #define MAX_EXTENT_COMPRESS_RATIO_SHIFT                10
index 1e7c810d3569203b3471cf6509a826f15422f08e..e8ec7b847aeab762b03f89d34338936d402735b4 100644 (file)
@@ -445,6 +445,7 @@ enum gc_phase {
        GC_PHASE_BTREE_need_discard,
        GC_PHASE_BTREE_backpointers,
        GC_PHASE_BTREE_bucket_gens,
+       GC_PHASE_BTREE_snapshot_trees,
 
        GC_PHASE_PENDING_DELETE,
 };
index 7d1c0b1e3c54939d7f5fba2eb734e2059b3c176b..4d142b2e3bf6691dc136b10d22ed1f61f7b47f51 100644 (file)
@@ -250,6 +250,11 @@ struct bkey_packed {
        __u8            pad[sizeof(struct bkey) - 3];
 } __packed __aligned(8);
 
+typedef struct {
+       __le64                  lo;
+       __le64                  hi;
+} bch_le128;
+
 #define BKEY_U64s                      (sizeof(struct bkey) / sizeof(__u64))
 #define BKEY_U64s_MAX                  U8_MAX
 #define BKEY_VAL_U64s_MAX              (BKEY_U64s_MAX - BKEY_U64s)
@@ -360,7 +365,8 @@ static inline void bkey_init(struct bkey *k)
        x(alloc_v4,             27)                     \
        x(backpointer,          28)                     \
        x(inode_v3,             29)                     \
-       x(bucket_gens,          30)
+       x(bucket_gens,          30)                     \
+       x(snapshot_tree,        31)
 
 enum bch_bkey_type {
 #define x(name, nr) KEY_TYPE_##name    = nr,
@@ -1101,6 +1107,9 @@ struct bch_subvolume {
        __le32                  flags;
        __le32                  snapshot;
        __le64                  inode;
+       __le32                  parent;
+       __le32                  pad;
+       bch_le128               otime;
 };
 
 LE32_BITMASK(BCH_SUBVOLUME_RO,         struct bch_subvolume, flags,  0,  1)
@@ -1119,7 +1128,7 @@ struct bch_snapshot {
        __le32                  parent;
        __le32                  children[2];
        __le32                  subvol;
-       __le32                  pad;
+       __le32                  tree;
 };
 
 LE32_BITMASK(BCH_SNAPSHOT_DELETED,     struct bch_snapshot, flags,  0,  1)
@@ -1127,6 +1136,19 @@ LE32_BITMASK(BCH_SNAPSHOT_DELETED,       struct bch_snapshot, flags,  0,  1)
 /* True if a subvolume points to this snapshot node: */
 LE32_BITMASK(BCH_SNAPSHOT_SUBVOL,      struct bch_snapshot, flags,  1,  2)
 
+/*
+ * Snapshot trees:
+ *
+ * The snapshot_trees btree gives us persistent indentifier for each tree of
+ * bch_snapshot nodes, and allow us to record and easily find the root/master
+ * subvolume that other snapshots were created from:
+ */
+struct bch_snapshot_tree {
+       struct bch_val          v;
+       __le32                  master_subvol;
+       __le32                  root_snapshot;
+};
+
 /* LRU btree: */
 
 struct bch_lru {
@@ -1555,7 +1577,8 @@ struct bch_sb_field_journal_seq_blacklist {
        x(bucket_gens,                  25)             \
        x(lru_v2,                       26)             \
        x(fragmentation_lru,            27)             \
-       x(no_bps_in_alloc_keys,         28)
+       x(no_bps_in_alloc_keys,         28)             \
+       x(snapshot_trees,               29)
 
 enum bcachefs_metadata_version {
        bcachefs_metadata_version_min = 9,
@@ -1565,6 +1588,8 @@ enum bcachefs_metadata_version {
        bcachefs_metadata_version_max
 };
 
+static const unsigned bcachefs_metadata_required_upgrade_below = bcachefs_metadata_version_snapshot_trees;
+
 #define bcachefs_metadata_version_current      (bcachefs_metadata_version_max - 1)
 
 #define BCH_SB_SECTOR                  8
@@ -2091,7 +2116,8 @@ LE32_BITMASK(JSET_NO_FLUSH,       struct jset, flags, 5, 6);
        x(freespace,            11)             \
        x(need_discard,         12)             \
        x(backpointers,         13)             \
-       x(bucket_gens,          14)
+       x(bucket_gens,          14)             \
+       x(snapshot_trees,       15)
 
 enum btree_id {
 #define x(kwd, val) BTREE_ID_##kwd = val,
index 2650bd639b55998c9b6a31f6ce2312520d687a22..727bed99554bde5336665569ecde728388f6b199 100644 (file)
@@ -611,20 +611,20 @@ struct bkey_s_##name {                                                    \
                                                                        \
 static inline struct bkey_i_##name *bkey_i_to_##name(struct bkey_i *k) \
 {                                                                      \
-       EBUG_ON(k->k.type != KEY_TYPE_##name);                          \
+       EBUG_ON(!IS_ERR_OR_NULL(k) && k->k.type != KEY_TYPE_##name);    \
        return container_of(&k->k, struct bkey_i_##name, k);            \
 }                                                                      \
                                                                        \
 static inline const struct bkey_i_##name *                             \
 bkey_i_to_##name##_c(const struct bkey_i *k)                           \
 {                                                                      \
-       EBUG_ON(k->k.type != KEY_TYPE_##name);                          \
+       EBUG_ON(!IS_ERR_OR_NULL(k) && k->k.type != KEY_TYPE_##name);    \
        return container_of(&k->k, struct bkey_i_##name, k);            \
 }                                                                      \
                                                                        \
 static inline struct bkey_s_##name bkey_s_to_##name(struct bkey_s k)   \
 {                                                                      \
-       EBUG_ON(k.k->type != KEY_TYPE_##name);                          \
+       EBUG_ON(!IS_ERR_OR_NULL(k.k) && k.k->type != KEY_TYPE_##name);  \
        return (struct bkey_s_##name) {                                 \
                .k = k.k,                                               \
                .v = container_of(k.v, struct bch_##name, v),           \
@@ -633,7 +633,7 @@ static inline struct bkey_s_##name bkey_s_to_##name(struct bkey_s k)        \
                                                                        \
 static inline struct bkey_s_c_##name bkey_s_c_to_##name(struct bkey_s_c k)\
 {                                                                      \
-       EBUG_ON(k.k->type != KEY_TYPE_##name);                          \
+       EBUG_ON(!IS_ERR_OR_NULL(k.k) && k.k->type != KEY_TYPE_##name);  \
        return (struct bkey_s_c_##name) {                               \
                .k = k.k,                                               \
                .v = container_of(k.v, struct bch_##name, v),           \
@@ -659,7 +659,7 @@ name##_i_to_s_c(const struct bkey_i_##name *k)                              \
                                                                        \
 static inline struct bkey_s_##name bkey_i_to_s_##name(struct bkey_i *k)        \
 {                                                                      \
-       EBUG_ON(k->k.type != KEY_TYPE_##name);                          \
+       EBUG_ON(!IS_ERR_OR_NULL(k) && k->k.type != KEY_TYPE_##name);    \
        return (struct bkey_s_##name) {                                 \
                .k = &k->k,                                             \
                .v = container_of(&k->v, struct bch_##name, v),         \
@@ -669,7 +669,7 @@ static inline struct bkey_s_##name bkey_i_to_s_##name(struct bkey_i *k)     \
 static inline struct bkey_s_c_##name                                   \
 bkey_i_to_s_c_##name(const struct bkey_i *k)                           \
 {                                                                      \
-       EBUG_ON(k->k.type != KEY_TYPE_##name);                          \
+       EBUG_ON(!IS_ERR_OR_NULL(k) && k->k.type != KEY_TYPE_##name);    \
        return (struct bkey_s_c_##name) {                               \
                .k = &k->k,                                             \
                .v = container_of(&k->v, struct bch_##name, v),         \
index 72d95831d65df7a752dfc5a2ca0e084c9d2d141b..79f3fbe925d5290235e15c6e4a44d270ba4c277b 100644 (file)
@@ -56,17 +56,12 @@ static int empty_val_key_invalid(const struct bch_fs *c, struct bkey_s_c k,
 static int key_type_cookie_invalid(const struct bch_fs *c, struct bkey_s_c k,
                                   unsigned flags, struct printbuf *err)
 {
-       if (bkey_val_bytes(k.k) != sizeof(struct bch_cookie)) {
-               prt_printf(err, "incorrect value size (%zu != %zu)",
-                      bkey_val_bytes(k.k), sizeof(struct bch_cookie));
-               return -BCH_ERR_invalid_bkey;
-       }
-
        return 0;
 }
 
 #define bch2_bkey_ops_cookie ((struct bkey_ops) {      \
-       .key_invalid = key_type_cookie_invalid,         \
+       .key_invalid    = key_type_cookie_invalid,      \
+       .min_val_size   = 8,                            \
 })
 
 #define bch2_bkey_ops_hash_whiteout ((struct bkey_ops) {\
@@ -126,12 +121,22 @@ const struct bkey_ops bch2_bkey_ops[] = {
 int bch2_bkey_val_invalid(struct bch_fs *c, struct bkey_s_c k,
                          unsigned flags, struct printbuf *err)
 {
+       const struct bkey_ops *ops;
+
        if (k.k->type >= KEY_TYPE_MAX) {
                prt_printf(err, "invalid type (%u >= %u)", k.k->type, KEY_TYPE_MAX);
                return -BCH_ERR_invalid_bkey;
        }
 
-       return bch2_bkey_ops[k.k->type].key_invalid(c, k, flags, err);
+       ops = &bch2_bkey_ops[k.k->type];
+
+       if (bkey_val_bytes(k.k) < ops->min_val_size) {
+               prt_printf(err, "bad val size (%zu < %u)",
+                          bkey_val_bytes(k.k), ops->min_val_size);
+               return -BCH_ERR_invalid_bkey;
+       }
+
+       return ops->key_invalid(c, k, flags, err);
 }
 
 static unsigned bch2_key_types_allowed[] = {
@@ -199,6 +204,9 @@ static unsigned bch2_key_types_allowed[] = {
        [BKEY_TYPE_bucket_gens] =
                (1U << KEY_TYPE_deleted)|
                (1U << KEY_TYPE_bucket_gens),
+       [BKEY_TYPE_snapshot_trees] =
+               (1U << KEY_TYPE_deleted)|
+               (1U << KEY_TYPE_snapshot_tree),
        [BKEY_TYPE_btree] =
                (1U << KEY_TYPE_deleted)|
                (1U << KEY_TYPE_btree_ptr)|
index 6ae517884a37e8755517f33452299fc39452a2f5..a65756e306b05eb16569896e3b4bc9b54f0696c8 100644 (file)
@@ -34,6 +34,9 @@ struct bkey_ops {
        void            (*compat)(enum btree_id id, unsigned version,
                                  unsigned big_endian, int write,
                                  struct bkey_s);
+
+       /* Size of value type when first created: */
+       unsigned        min_val_size;
 };
 
 extern const struct bkey_ops bch2_bkey_ops[];
@@ -80,10 +83,9 @@ static inline int bch2_mark_key(struct btree_trans *trans,
 }
 
 enum btree_update_flags {
-       __BTREE_UPDATE_INTERNAL_SNAPSHOT_NODE,
+       __BTREE_UPDATE_INTERNAL_SNAPSHOT_NODE = __BTREE_ITER_FLAGS_END,
        __BTREE_UPDATE_NOJOURNAL,
        __BTREE_UPDATE_KEY_CACHE_RECLAIM,
-       __BTREE_UPDATE_NO_KEY_CACHE_COHERENCY,
 
        __BTREE_TRIGGER_NORUN,          /* Don't run triggers at all */
 
@@ -98,8 +100,6 @@ enum btree_update_flags {
 #define BTREE_UPDATE_INTERNAL_SNAPSHOT_NODE (1U << __BTREE_UPDATE_INTERNAL_SNAPSHOT_NODE)
 #define BTREE_UPDATE_NOJOURNAL         (1U << __BTREE_UPDATE_NOJOURNAL)
 #define BTREE_UPDATE_KEY_CACHE_RECLAIM (1U << __BTREE_UPDATE_KEY_CACHE_RECLAIM)
-#define BTREE_UPDATE_NO_KEY_CACHE_COHERENCY    \
-       (1U << __BTREE_UPDATE_NO_KEY_CACHE_COHERENCY)
 
 #define BTREE_TRIGGER_NORUN            (1U << __BTREE_TRIGGER_NORUN)
 
index 0216ad96777a370808d328634a2fe65cc44b54b4..a4c06e856c2e67c0cb1202443712fba11d735a07 100644 (file)
@@ -10,6 +10,7 @@
 #include "btree_cache.h"
 #include "bset.h"
 #include "eytzinger.h"
+#include "trace.h"
 #include "util.h"
 
 #include <asm/unaligned.h>
 #include <linux/random.h>
 #include <linux/prefetch.h>
 
-/* hack.. */
-#include "alloc_types.h"
-#include <trace/events/bcachefs.h>
-
 static inline void __bch2_btree_node_iter_advance(struct btree_node_iter *,
                                                  struct btree *);
 
index c53597a29e2e0bdcdc42421771beda976dfba056..73d326880cbb1168986f011d22a64b4fea9c8167 100644 (file)
@@ -9,11 +9,11 @@
 #include "debug.h"
 #include "errcode.h"
 #include "error.h"
+#include "trace.h"
 
 #include <linux/prefetch.h>
 #include <linux/sched/mm.h>
 #include <linux/seq_buf.h>
-#include <trace/events/bcachefs.h>
 
 #define BTREE_CACHE_NOT_FREED_INCREMENT(counter) \
 do {                                            \
index fb4226aa0255b680a467e8e7330500d186dce59e..02154c38ec14960b60a32f2681b3c65dec524901 100644 (file)
@@ -27,6 +27,7 @@
 #include "reflink.h"
 #include "replicas.h"
 #include "super-io.h"
+#include "trace.h"
 
 #include <linux/slab.h>
 #include <linux/bitops.h>
@@ -35,7 +36,6 @@
 #include <linux/preempt.h>
 #include <linux/rcupdate.h>
 #include <linux/sched/task.h>
-#include <trace/events/bcachefs.h>
 
 #define DROP_THIS_NODE         10
 #define DROP_PREV_NODE         11
@@ -1594,7 +1594,7 @@ static int bch2_gc_write_reflink_key(struct btree_trans *trans,
                        "  should be %u",
                        (bch2_bkey_val_to_text(&buf, c, k), buf.buf),
                        r->refcount)) {
-               struct bkey_i *new = bch2_bkey_make_mut(trans, k);
+               struct bkey_i *new = bch2_bkey_make_mut(trans, iter, k, 0);
 
                ret = PTR_ERR_OR_ZERO(new);
                if (ret)
@@ -1604,8 +1604,6 @@ static int bch2_gc_write_reflink_key(struct btree_trans *trans,
                        new->k.type = KEY_TYPE_deleted;
                else
                        *bkey_refcount(new) = cpu_to_le64(r->refcount);
-
-               ret = bch2_trans_update(trans, iter, new, 0);
        }
 fsck_err:
        printbuf_exit(&buf);
@@ -1802,9 +1800,10 @@ again:
 
        bch2_mark_superblocks(c);
 
-       if (BCH_SB_HAS_TOPOLOGY_ERRORS(c->disk_sb.sb) &&
-           !test_bit(BCH_FS_INITIAL_GC_DONE, &c->flags) &&
-           c->opts.fix_errors != FSCK_OPT_NO) {
+       if (IS_ENABLED(CONFIG_BCACHEFS_DEBUG) ||
+           (BCH_SB_HAS_TOPOLOGY_ERRORS(c->disk_sb.sb) &&
+            !test_bit(BCH_FS_INITIAL_GC_DONE, &c->flags) &&
+            c->opts.fix_errors != FSCK_OPT_NO)) {
                bch_info(c, "Starting topology repair pass");
                ret = bch2_repair_topology(c);
                if (ret)
@@ -1920,13 +1919,13 @@ static int gc_btree_gens_key(struct btree_trans *trans,
        percpu_up_read(&c->mark_lock);
        return 0;
 update:
-       u = bch2_bkey_make_mut(trans, k);
+       u = bch2_bkey_make_mut(trans, iter, k, 0);
        ret = PTR_ERR_OR_ZERO(u);
        if (ret)
                return ret;
 
        bch2_extent_normalize(c, bkey_i_to_s(u));
-       return bch2_trans_update(trans, iter, u, 0);
+       return 0;
 }
 
 static int bch2_alloc_write_oldest_gen(struct btree_trans *trans, struct btree_iter *iter,
index 945d1b9e1c1d5ebd877fcf8b5b5605439d3cc129..decbbaace1eef03e98a143325a296fceafdd30a8 100644 (file)
@@ -18,9 +18,9 @@
 #include "journal_reclaim.h"
 #include "journal_seq_blacklist.h"
 #include "super-io.h"
+#include "trace.h"
 
 #include <linux/sched/mm.h>
-#include <trace/events/bcachefs.h>
 
 void bch2_btree_node_io_unlock(struct btree *b)
 {
@@ -105,8 +105,8 @@ static void btree_bounce_free(struct bch_fs *c, size_t size,
                vpfree(p, size);
 }
 
-static void *_btree_bounce_alloc(struct bch_fs *c, size_t size,
-                                bool *used_mempool)
+static void *btree_bounce_alloc(struct bch_fs *c, size_t size,
+                               bool *used_mempool)
 {
        unsigned flags = memalloc_nofs_save();
        void *p;
@@ -114,7 +114,7 @@ static void *_btree_bounce_alloc(struct bch_fs *c, size_t size,
        BUG_ON(size > btree_bytes(c));
 
        *used_mempool = false;
-       p = _vpmalloc(size, __GFP_NOWARN|GFP_NOWAIT);
+       p = vpmalloc(size, __GFP_NOWARN|GFP_NOWAIT);
        if (!p) {
                *used_mempool = true;
                p = mempool_alloc(&c->btree_bounce_pool, GFP_NOIO);
@@ -122,8 +122,6 @@ static void *_btree_bounce_alloc(struct bch_fs *c, size_t size,
        memalloc_nofs_restore(flags);
        return p;
 }
-#define btree_bounce_alloc(_c, _size, _used_mempool)           \
-       alloc_hooks(_btree_bounce_alloc(_c, _size, _used_mempool), void *, NULL)
 
 static void sort_bkey_ptrs(const struct btree *bt,
                           struct bkey_packed **ptrs, unsigned nr)
index f524e4b394c3feff8db5c5fe623dd3ae24ae333a..365794dc4dcd66c4b18a1519987e01ed6628d25d 100644 (file)
 #include "recovery.h"
 #include "replicas.h"
 #include "subvolume.h"
+#include "trace.h"
 
 #include <linux/random.h>
 #include <linux/prefetch.h>
-#include <trace/events/bcachefs.h>
 
 static inline void btree_path_list_remove(struct btree_trans *, struct btree_path *);
 static inline void btree_path_list_add(struct btree_trans *, struct btree_path *,
index 6b7cef145cedd72185381592ca90b22a7b33e23d..02dd81a1d70416baa5593f75301a2f96d99fad61 100644 (file)
@@ -4,8 +4,14 @@
 
 #include "bset.h"
 #include "btree_types.h"
+#include "trace.h"
 
-#include <trace/events/bcachefs.h>
+static inline int __bkey_err(const struct bkey *k)
+{
+       return PTR_ERR_OR_ZERO(k);
+}
+
+#define bkey_err(_k)   __bkey_err((_k).k)
 
 static inline void __btree_path_get(struct btree_path *path, bool intent)
 {
@@ -477,48 +483,61 @@ static inline void *bch2_trans_kmalloc_nomemzero(struct btree_trans *trans, size
        }
 }
 
-static inline struct bkey_i *bch2_bkey_make_mut(struct btree_trans *trans, struct bkey_s_c k)
+static inline struct bkey_s_c __bch2_bkey_get_iter(struct btree_trans *trans,
+                               struct btree_iter *iter,
+                               unsigned btree_id, struct bpos pos,
+                               unsigned flags, unsigned type)
 {
-       struct bkey_i *mut = bch2_trans_kmalloc_nomemzero(trans, bkey_bytes(k.k));
+       struct bkey_s_c k;
 
-       if (!IS_ERR(mut))
-               bkey_reassemble(mut, k);
-       return mut;
+       bch2_trans_iter_init(trans, iter, btree_id, pos, flags);
+       k = bch2_btree_iter_peek_slot(iter);
+
+       if (!bkey_err(k) && type && k.k->type != type)
+               k = bkey_s_c_err(-ENOENT);
+       if (unlikely(bkey_err(k)))
+               bch2_trans_iter_exit(trans, iter);
+       return k;
 }
 
-static inline struct bkey_i *bch2_bkey_get_mut(struct btree_trans *trans,
-                                              struct btree_iter *iter)
+static inline struct bkey_s_c bch2_bkey_get_iter(struct btree_trans *trans,
+                               struct btree_iter *iter,
+                               unsigned btree_id, struct bpos pos,
+                               unsigned flags)
 {
-       struct bkey_s_c k = bch2_btree_iter_peek_slot(iter);
-
-       return unlikely(IS_ERR(k.k))
-               ? ERR_CAST(k.k)
-               : bch2_bkey_make_mut(trans, k);
+       return __bch2_bkey_get_iter(trans, iter, btree_id, pos, flags, 0);
 }
 
-#define bch2_bkey_get_mut_typed(_trans, _iter, _type)                  \
-({                                                                     \
-       struct bkey_i *_k = bch2_bkey_get_mut(_trans, _iter);           \
-       struct bkey_i_##_type *_ret;                                    \
-                                                                       \
-       if (IS_ERR(_k))                                                 \
-               _ret = ERR_CAST(_k);                                    \
-       else if (unlikely(_k->k.type != KEY_TYPE_##_type))              \
-               _ret = ERR_PTR(-ENOENT);                                \
-       else                                                            \
-               _ret = bkey_i_to_##_type(_k);                           \
-       _ret;                                                           \
-})
+#define bch2_bkey_get_iter_typed(_trans, _iter, _btree_id, _pos, _flags, _type)\
+       bkey_s_c_to_##_type(__bch2_bkey_get_iter(_trans, _iter,                 \
+                                      _btree_id, _pos, _flags, KEY_TYPE_##_type))
 
-#define bch2_bkey_alloc(_trans, _iter, _type)                          \
-({                                                                     \
-       struct bkey_i_##_type *_k = bch2_trans_kmalloc_nomemzero(_trans, sizeof(*_k));\
-       if (!IS_ERR(_k)) {                                              \
-               bkey_##_type##_init(&_k->k_i);                          \
-               _k->k.p = (_iter)->pos;                                 \
-       }                                                               \
-       _k;                                                             \
-})
+static inline int __bch2_bkey_get_val_typed(struct btree_trans *trans,
+                               unsigned btree_id, struct bpos pos,
+                               unsigned flags, unsigned type,
+                               unsigned val_size, void *val)
+{
+       struct btree_iter iter;
+       struct bkey_s_c k;
+       int ret;
+
+       k = __bch2_bkey_get_iter(trans, &iter, btree_id, pos, flags, type);
+       ret = bkey_err(k);
+       if (!ret) {
+               unsigned b = min_t(unsigned, bkey_val_bytes(k.k), val_size);
+
+               memcpy(val, k.v, b);
+               if (unlikely(b < sizeof(*val)))
+                       memset((void *) val + b, 0, sizeof(*val) - b);
+               bch2_trans_iter_exit(trans, &iter);
+       }
+
+       return ret;
+}
+
+#define bch2_bkey_get_val_typed(_trans, _btree_id, _pos, _flags, _type, _val)\
+       __bch2_bkey_get_val_typed(_trans, _btree_id, _pos, _flags,      \
+                                 KEY_TYPE_##_type, sizeof(*_val), _val)
 
 u32 bch2_trans_begin(struct btree_trans *);
 
@@ -540,11 +559,6 @@ u32 bch2_trans_begin(struct btree_trans *);
        __for_each_btree_node(_trans, _iter, _btree_id, _start,         \
                              0, 0, _flags, _b, _ret)
 
-static inline int bkey_err(struct bkey_s_c k)
-{
-       return PTR_ERR_OR_ZERO(k.k);
-}
-
 static inline struct bkey_s_c bch2_btree_iter_peek_prev_type(struct btree_iter *iter,
                                                             unsigned flags)
 {
index 33269afe9cf22c39ee6cf8a16194fdc2765f76a0..3b333e3bc2436c8188556121b98308400e5f97f9 100644 (file)
 #include "error.h"
 #include "journal.h"
 #include "journal_reclaim.h"
+#include "trace.h"
 
 #include <linux/sched/mm.h>
 #include <linux/seq_buf.h>
-#include <trace/events/bcachefs.h>
 
 static inline bool btree_uses_pcpu_readers(enum btree_id id)
 {
@@ -387,10 +387,9 @@ static int btree_key_cache_fill(struct btree_trans *trans,
        struct bkey_i *new_k = NULL;
        int ret;
 
-       bch2_trans_iter_init(trans, &iter, ck->key.btree_id, ck->key.pos,
-                            BTREE_ITER_KEY_CACHE_FILL|
-                            BTREE_ITER_CACHED_NOFILL);
-       k = bch2_btree_iter_peek_slot(&iter);
+       k = bch2_bkey_get_iter(trans, &iter, ck->key.btree_id, ck->key.pos,
+                              BTREE_ITER_KEY_CACHE_FILL|
+                              BTREE_ITER_CACHED_NOFILL);
        ret = bkey_err(k);
        if (ret)
                goto err;
index 6250f34fe561e58d5c9b258e4cc11cedd065c522..d4ff72128ad3d2a3e06a8a2e3daf2868c8836943 100644 (file)
@@ -221,6 +221,7 @@ static const u16 BTREE_ITER_FILTER_SNAPSHOTS        = 1 << 12;
 static const u16 BTREE_ITER_NOPRESERVE         = 1 << 13;
 static const u16 BTREE_ITER_CACHED_NOFILL      = 1 << 14;
 static const u16 BTREE_ITER_KEY_CACHE_FILL     = 1 << 15;
+#define __BTREE_ITER_FLAGS_END                        16
 
 enum btree_path_uptodate {
        BTREE_ITER_UPTODATE             = 0,
index 4adb6f646655b2c95b00104e741f18cdaacb63b2..1ac3a81e0af6fba206cc796449c34d81c445753a 100644 (file)
@@ -86,6 +86,9 @@ int bch2_btree_node_update_key_get_iter(struct btree_trans *,
 int bch2_trans_update_extent(struct btree_trans *, struct btree_iter *,
                             struct bkey_i *, enum btree_update_flags);
 
+int bch2_bkey_get_empty_slot(struct btree_trans *, struct btree_iter *,
+                            enum btree_id, struct bpos);
+
 int __must_check bch2_trans_update(struct btree_trans *, struct btree_iter *,
                                   struct bkey_i *, enum btree_update_flags);
 int __must_check bch2_trans_update_buffered(struct btree_trans *,
@@ -183,4 +186,150 @@ static inline void bch2_trans_reset_updates(struct btree_trans *trans)
        }
 }
 
+static inline struct bkey_i *__bch2_bkey_make_mut_noupdate(struct btree_trans *trans, struct bkey_s_c k,
+                                                 unsigned type, unsigned min_bytes)
+{
+       unsigned bytes = max_t(unsigned, min_bytes, bkey_bytes(k.k));
+       struct bkey_i *mut;
+
+       if (type && k.k->type != type)
+               return ERR_PTR(-ENOENT);
+
+       mut = bch2_trans_kmalloc_nomemzero(trans, bytes);
+       if (!IS_ERR(mut)) {
+               bkey_reassemble(mut, k);
+
+               if (unlikely(bytes > bkey_bytes(k.k))) {
+                       memset((void *) mut + bkey_bytes(k.k), 0,
+                              bytes - bkey_bytes(k.k));
+                       mut->k.u64s = DIV_ROUND_UP(bytes, sizeof(u64));
+               }
+       }
+       return mut;
+}
+
+static inline struct bkey_i *bch2_bkey_make_mut_noupdate(struct btree_trans *trans, struct bkey_s_c k)
+{
+       return __bch2_bkey_make_mut_noupdate(trans, k, 0, 0);
+}
+
+#define bch2_bkey_make_mut_noupdate_typed(_trans, _k, _type)           \
+       bkey_i_to_##_type(__bch2_bkey_make_mut_noupdate(_trans, _k,     \
+                               KEY_TYPE_##_type, sizeof(struct bkey_i_##_type)))
+
+static inline struct bkey_i *__bch2_bkey_make_mut(struct btree_trans *trans, struct btree_iter *iter,
+                                       struct bkey_s_c k, unsigned flags,
+                                       unsigned type, unsigned min_bytes)
+{
+       struct bkey_i *mut = __bch2_bkey_make_mut_noupdate(trans, k, type, min_bytes);
+       int ret;
+
+       if (IS_ERR(mut))
+               return mut;
+
+       ret = bch2_trans_update(trans, iter, mut, flags);
+       if (ret)
+               return ERR_PTR(ret);
+       return mut;
+}
+
+static inline struct bkey_i *bch2_bkey_make_mut(struct btree_trans *trans, struct btree_iter *iter,
+                                               struct bkey_s_c k, unsigned flags)
+{
+       return __bch2_bkey_make_mut(trans, iter, k, flags, 0, 0);
+}
+
+#define bch2_bkey_make_mut_typed(_trans, _iter, _k, _flags, _type)     \
+       bkey_i_to_##_type(__bch2_bkey_make_mut(_trans, _iter, _k, _flags,\
+                               KEY_TYPE_##_type, sizeof(struct bkey_i_##_type)))
+
+static inline struct bkey_i *__bch2_bkey_get_mut_noupdate(struct btree_trans *trans,
+                                        struct btree_iter *iter,
+                                        unsigned btree_id, struct bpos pos,
+                                        unsigned flags, unsigned type, unsigned min_bytes)
+{
+       struct bkey_s_c k = __bch2_bkey_get_iter(trans, iter,
+                               btree_id, pos, flags|BTREE_ITER_INTENT, type);
+       struct bkey_i *ret = unlikely(IS_ERR(k.k))
+               ? ERR_CAST(k.k)
+               : __bch2_bkey_make_mut_noupdate(trans, k, 0, min_bytes);
+       if (unlikely(IS_ERR(ret)))
+               bch2_trans_iter_exit(trans, iter);
+       return ret;
+}
+
+static inline struct bkey_i *bch2_bkey_get_mut_noupdate(struct btree_trans *trans,
+                                              struct btree_iter *iter,
+                                              unsigned btree_id, struct bpos pos,
+                                              unsigned flags)
+{
+       return __bch2_bkey_get_mut_noupdate(trans, iter, btree_id, pos, flags, 0, 0);
+}
+
+static inline struct bkey_i *__bch2_bkey_get_mut(struct btree_trans *trans,
+                                        struct btree_iter *iter,
+                                        unsigned btree_id, struct bpos pos,
+                                        unsigned flags, unsigned type, unsigned min_bytes)
+{
+       struct bkey_i *mut = __bch2_bkey_get_mut_noupdate(trans, iter,
+                               btree_id, pos, flags|BTREE_ITER_INTENT, type, min_bytes);
+       int ret;
+
+       if (IS_ERR(mut))
+               return mut;
+
+       ret = bch2_trans_update(trans, iter, mut, flags);
+       if (ret) {
+               bch2_trans_iter_exit(trans, iter);
+               return ERR_PTR(ret);
+       }
+
+       return mut;
+}
+
+static inline struct bkey_i *bch2_bkey_get_mut_minsize(struct btree_trans *trans,
+                                                      struct btree_iter *iter,
+                                                      unsigned btree_id, struct bpos pos,
+                                                      unsigned flags, unsigned min_bytes)
+{
+       return __bch2_bkey_get_mut(trans, iter, btree_id, pos, flags, 0, min_bytes);
+}
+
+static inline struct bkey_i *bch2_bkey_get_mut(struct btree_trans *trans,
+                                              struct btree_iter *iter,
+                                              unsigned btree_id, struct bpos pos,
+                                              unsigned flags)
+{
+       return __bch2_bkey_get_mut(trans, iter, btree_id, pos, flags, 0, 0);
+}
+
+#define bch2_bkey_get_mut_typed(_trans, _iter, _btree_id, _pos, _flags, _type)\
+       bkey_i_to_##_type(__bch2_bkey_get_mut(_trans, _iter,            \
+                       _btree_id, _pos, _flags,                        \
+                       KEY_TYPE_##_type, sizeof(struct bkey_i_##_type)))
+
+static inline struct bkey_i *__bch2_bkey_alloc(struct btree_trans *trans, struct btree_iter *iter,
+                                              unsigned flags, unsigned type, unsigned val_size)
+{
+       struct bkey_i *k = bch2_trans_kmalloc(trans, sizeof(*k) + val_size);
+       int ret;
+
+       if (IS_ERR(k))
+               return k;
+
+       bkey_init(&k->k);
+       k->k.p = iter->pos;
+       k->k.type = type;
+       set_bkey_val_bytes(&k->k, val_size);
+
+       ret = bch2_trans_update(trans, iter, k, flags);
+       if (unlikely(ret))
+               return ERR_PTR(ret);
+       return k;
+}
+
+#define bch2_bkey_alloc(_trans, _iter, _flags, _type)                  \
+       bkey_i_to_##_type(__bch2_bkey_alloc(_trans, _iter, _flags,      \
+                               KEY_TYPE_##_type, sizeof(struct bch_##_type)))
+
 #endif /* _BCACHEFS_BTREE_UPDATE_H */
index e42e852199f585e639447ad9fff395063d4afd5d..6ba0954e648e6ac9161f84fbdc3aa654c780d349 100644 (file)
@@ -20,9 +20,9 @@
 #include "recovery.h"
 #include "replicas.h"
 #include "super-io.h"
+#include "trace.h"
 
 #include <linux/random.h>
-#include <trace/events/bcachefs.h>
 
 static int bch2_btree_insert_node(struct btree_update *, struct btree_trans *,
                                  struct btree_path *, struct btree *,
index c17d048b1c267c146dba61a78a4d2814572bb035..33693467810b20a9fc4fcbaf54ee595a51b95eca 100644 (file)
 #include "recovery.h"
 #include "subvolume.h"
 #include "replicas.h"
+#include "trace.h"
 
 #include <linux/prefetch.h>
 #include <linux/sort.h>
-#include <trace/events/bcachefs.h>
 
 /*
  * bch2_btree_path_peek_slot() for a cached iterator might return a key in a
@@ -1268,7 +1268,7 @@ static noinline int extent_front_merge(struct btree_trans *trans,
        struct bkey_i *update;
        int ret;
 
-       update = bch2_bkey_make_mut(trans, k);
+       update = bch2_bkey_make_mut_noupdate(trans, k);
        ret = PTR_ERR_OR_ZERO(update);
        if (ret)
                return ret;
@@ -1390,7 +1390,7 @@ int bch2_trans_update_extent(struct btree_trans *trans,
                        trans->extra_journal_res += compressed_sectors;
 
                if (front_split) {
-                       update = bch2_bkey_make_mut(trans, k);
+                       update = bch2_bkey_make_mut_noupdate(trans, k);
                        if ((ret = PTR_ERR_OR_ZERO(update)))
                                goto err;
 
@@ -1404,7 +1404,7 @@ int bch2_trans_update_extent(struct btree_trans *trans,
 
                if (k.k->p.snapshot != insert->k.p.snapshot &&
                    (front_split || back_split)) {
-                       update = bch2_bkey_make_mut(trans, k);
+                       update = bch2_bkey_make_mut_noupdate(trans, k);
                        if ((ret = PTR_ERR_OR_ZERO(update)))
                                goto err;
 
@@ -1443,7 +1443,7 @@ int bch2_trans_update_extent(struct btree_trans *trans,
                }
 
                if (back_split) {
-                       update = bch2_bkey_make_mut(trans, k);
+                       update = bch2_bkey_make_mut_noupdate(trans, k);
                        if ((ret = PTR_ERR_OR_ZERO(update)))
                                goto err;
 
@@ -1501,21 +1501,31 @@ static noinline int flush_new_cached_update(struct btree_trans *trans,
                                            unsigned long ip)
 {
        struct btree_path *btree_path;
+       struct bkey k;
        int ret;
 
-       i->key_cache_already_flushed = true;
-       i->flags |= BTREE_TRIGGER_NORUN;
-
        btree_path = bch2_path_get(trans, path->btree_id, path->pos, 1, 0,
                                   BTREE_ITER_INTENT, _THIS_IP_);
-
        ret = bch2_btree_path_traverse(trans, btree_path, 0);
        if (ret)
-               goto err;
+               goto out;
+
+       /*
+        * The old key in the insert entry might actually refer to an existing
+        * key in the btree that has been deleted from cache and not yet
+        * flushed. Check for this and skip the flush so we don't run triggers
+        * against a stale key.
+        */
+       bch2_btree_path_peek_slot_exact(btree_path, &k);
+       if (!bkey_deleted(&k))
+               goto out;
+
+       i->key_cache_already_flushed = true;
+       i->flags |= BTREE_TRIGGER_NORUN;
 
        btree_path_set_should_be_locked(btree_path);
        ret = bch2_trans_update_by_path_trace(trans, btree_path, i->k, flags, ip);
-err:
+out:
        bch2_path_put(trans, btree_path, true);
        return ret;
 }
@@ -1596,9 +1606,7 @@ bch2_trans_update_by_path_trace(struct btree_trans *trans, struct btree_path *pa
         * the key cache - but the key has to exist in the btree for that to
         * work:
         */
-       if (path->cached &&
-           bkey_deleted(&i->old_k) &&
-           !(flags & BTREE_UPDATE_NO_KEY_CACHE_COHERENCY))
+       if (path->cached && bkey_deleted(&i->old_k))
                return flush_new_cached_update(trans, path, i, flags, ip);
 
        return 0;
@@ -1727,6 +1735,37 @@ int __must_check bch2_trans_update_buffered(struct btree_trans *trans,
        return 0;
 }
 
+int bch2_bkey_get_empty_slot(struct btree_trans *trans, struct btree_iter *iter,
+                            enum btree_id btree, struct bpos end)
+{
+       struct bkey_s_c k;
+       int ret = 0;
+
+       bch2_trans_iter_init(trans, iter, btree, POS_MAX, BTREE_ITER_INTENT);
+       k = bch2_btree_iter_prev(iter);
+       ret = bkey_err(k);
+       if (ret)
+               goto err;
+
+       bch2_btree_iter_advance(iter);
+       k = bch2_btree_iter_peek_slot(iter);
+       ret = bkey_err(k);
+       if (ret)
+               goto err;
+
+       BUG_ON(k.k->type != KEY_TYPE_deleted);
+
+       if (bkey_gt(k.k->p, end)) {
+               ret = -BCH_ERR_ENOSPC_btree_slot;
+               goto err;
+       }
+
+       return 0;
+err:
+       bch2_trans_iter_exit(trans, iter);
+       return ret;
+}
+
 void bch2_trans_commit_hook(struct btree_trans *trans,
                            struct btree_trans_commit_hook *h)
 {
index 0362e10eb6aeb87ebc3d45a8507cd84ca6c3daae..bce42eef6f576001341fe94283a05ea46652a1d9 100644 (file)
@@ -21,9 +21,9 @@
 #include "reflink.h"
 #include "replicas.h"
 #include "subvolume.h"
+#include "trace.h"
 
 #include <linux/preempt.h>
-#include <trace/events/bcachefs.h>
 
 static inline void fs_usage_data_type_to_base(struct bch_fs_usage *fs_usage,
                                              enum bch_data_type data_type,
@@ -1448,10 +1448,9 @@ static int bch2_trans_mark_stripe_ptr(struct btree_trans *trans,
        struct bch_replicas_padded r;
        int ret = 0;
 
-       bch2_trans_iter_init(trans, &iter, BTREE_ID_stripes, POS(0, p.ec.idx),
-                            BTREE_ITER_INTENT|
-                            BTREE_ITER_WITH_UPDATES);
-       s = bch2_bkey_get_mut_typed(trans, &iter, stripe);
+       s = bch2_bkey_get_mut_typed(trans, &iter,
+                       BTREE_ID_stripes, POS(0, p.ec.idx),
+                       BTREE_ITER_WITH_UPDATES, stripe);
        ret = PTR_ERR_OR_ZERO(s);
        if (unlikely(ret)) {
                bch2_trans_inconsistent_on(ret == -ENOENT, trans,
@@ -1472,10 +1471,6 @@ static int bch2_trans_mark_stripe_ptr(struct btree_trans *trans,
                stripe_blockcount_get(&s->v, p.ec.block) +
                sectors);
 
-       ret = bch2_trans_update(trans, &iter, &s->k_i, 0);
-       if (ret)
-               goto err;
-
        bch2_bkey_to_replicas(&r.e, bkey_i_to_s_c(&s->k_i));
        r.e.data_type = data_type;
        update_replicas_list(trans, &r.e, sectors);
@@ -1750,10 +1745,9 @@ static int __bch2_trans_mark_reflink_p(struct btree_trans *trans,
        struct printbuf buf = PRINTBUF;
        int ret;
 
-       bch2_trans_iter_init(trans, &iter, BTREE_ID_reflink, POS(0, *idx),
-                            BTREE_ITER_INTENT|
-                            BTREE_ITER_WITH_UPDATES);
-       k = bch2_bkey_get_mut(trans, &iter);
+       k = bch2_bkey_get_mut_noupdate(trans, &iter,
+                       BTREE_ID_reflink, POS(0, *idx),
+                       BTREE_ITER_WITH_UPDATES);
        ret = PTR_ERR_OR_ZERO(k);
        if (ret)
                goto err;
index 0e29ff56966ab5a61dc84be67078fa199dc33117..c709538ce9c2e432e6606eecd52d541067d763c0 100644 (file)
@@ -14,8 +14,7 @@
 #include "move.h"
 #include "nocow_locking.h"
 #include "subvolume.h"
-
-#include <trace/events/bcachefs.h>
+#include "trace.h"
 
 static int insert_snapshot_whiteouts(struct btree_trans *trans,
                                     enum btree_id id,
@@ -58,10 +57,9 @@ static int insert_snapshot_whiteouts(struct btree_trans *trans,
 
                        whiteout_pos.snapshot = k.k->p.snapshot;
 
-                       bch2_trans_iter_init(trans, &iter2, id, whiteout_pos,
-                                            BTREE_ITER_NOT_EXTENTS|
-                                            BTREE_ITER_INTENT);
-                       k2 = bch2_btree_iter_peek_slot(&iter2);
+                       k2 = bch2_bkey_get_iter(trans, &iter2, id, whiteout_pos,
+                                               BTREE_ITER_NOT_EXTENTS|
+                                               BTREE_ITER_INTENT);
                        ret = bkey_err(k2);
 
                        if (!ret && k2.k->type == KEY_TYPE_deleted) {
index 4c85d3399fb4cf4b93f5467ec50c8d409c05b25d..1544fc56974f213d51c978756033482bd205c512 100644 (file)
@@ -89,12 +89,6 @@ int bch2_dirent_invalid(const struct bch_fs *c, struct bkey_s_c k,
        struct bkey_s_c_dirent d = bkey_s_c_to_dirent(k);
        unsigned len;
 
-       if (bkey_val_bytes(k.k) < sizeof(struct bch_dirent)) {
-               prt_printf(err, "incorrect value size (%zu < %zu)",
-                      bkey_val_bytes(k.k), sizeof(*d.v));
-               return -BCH_ERR_invalid_bkey;
-       }
-
        len = bch2_dirent_name_bytes(d);
        if (!len) {
                prt_printf(err, "empty name");
index ad131e8edc29649da8a544f71d95740a13bfa480..bf9ea2e35faeb9a87c42be340e1d17e4fbb6e136 100644 (file)
@@ -12,6 +12,7 @@ void bch2_dirent_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
 #define bch2_bkey_ops_dirent ((struct bkey_ops) {      \
        .key_invalid    = bch2_dirent_invalid,          \
        .val_to_text    = bch2_dirent_to_text,          \
+       .min_val_size   = 16,                           \
 })
 
 struct qstr;
index 1855d08efd4be2b190398a57250b091ec3afa8a5..439fa540323f472f63ebc854a52bdc07ff3b850b 100644 (file)
@@ -119,12 +119,6 @@ int bch2_stripe_invalid(const struct bch_fs *c, struct bkey_s_c k,
                return -BCH_ERR_invalid_bkey;
        }
 
-       if (bkey_val_bytes(k.k) < sizeof(*s)) {
-               prt_printf(err, "incorrect value size (%zu < %zu)",
-                      bkey_val_bytes(k.k), sizeof(*s));
-               return -BCH_ERR_invalid_bkey;
-       }
-
        if (bkey_val_u64s(k.k) < stripe_val_u64s(s)) {
                prt_printf(err, "incorrect value size (%zu < %u)",
                       bkey_val_u64s(k.k), stripe_val_u64s(s));
@@ -458,9 +452,8 @@ static int get_stripe_key_trans(struct btree_trans *trans, u64 idx,
        struct bkey_s_c k;
        int ret;
 
-       bch2_trans_iter_init(trans, &iter, BTREE_ID_stripes,
-                            POS(0, idx), BTREE_ITER_SLOTS);
-       k = bch2_btree_iter_peek_slot(&iter);
+       k = bch2_bkey_get_iter(trans, &iter, BTREE_ID_stripes,
+                              POS(0, idx), BTREE_ITER_SLOTS);
        ret = bkey_err(k);
        if (ret)
                goto err;
@@ -761,9 +754,8 @@ static int ec_stripe_delete(struct btree_trans *trans, u64 idx)
        struct bkey_s_c_stripe s;
        int ret;
 
-       bch2_trans_iter_init(trans, &iter, BTREE_ID_stripes, POS(0, idx),
-                            BTREE_ITER_INTENT);
-       k = bch2_btree_iter_peek_slot(&iter);
+       k = bch2_bkey_get_iter(trans, &iter, BTREE_ID_stripes, POS(0, idx),
+                              BTREE_ITER_INTENT);
        ret = bkey_err(k);
        if (ret)
                goto err;
@@ -841,9 +833,8 @@ static int ec_stripe_key_update(struct btree_trans *trans,
        struct bkey_s_c k;
        int ret;
 
-       bch2_trans_iter_init(trans, &iter, BTREE_ID_stripes,
-                            new->k.p, BTREE_ITER_INTENT);
-       k = bch2_btree_iter_peek_slot(&iter);
+       k = bch2_bkey_get_iter(trans, &iter, BTREE_ID_stripes,
+                              new->k.p, BTREE_ITER_INTENT);
        ret = bkey_err(k);
        if (ret)
                goto err;
index 7c08a49d741956534a229e92e2d787ceacb3b407..3995b707642702f782732480858c7c941ea56d00 100644 (file)
@@ -17,6 +17,7 @@ void bch2_stripe_to_text(struct printbuf *, struct bch_fs *,
        .swab           = bch2_ptr_swab,                \
        .trans_trigger  = bch2_trans_mark_stripe,       \
        .atomic_trigger = bch2_mark_stripe,             \
+       .min_val_size   = 8,                            \
 })
 
 static inline unsigned stripe_csums_per_device(const struct bch_stripe *s)
index 4304e25a6b24097edb1dc619f31a6f1e62568a3d..c8ac08e5548bcd798c7f0de98e4a3b787a5a10b6 100644 (file)
@@ -92,6 +92,8 @@
        x(ENOSPC,                       ENOSPC_sb_replicas)                     \
        x(ENOSPC,                       ENOSPC_sb_members)                      \
        x(ENOSPC,                       ENOSPC_sb_crypt)                        \
+       x(ENOSPC,                       ENOSPC_btree_slot)                      \
+       x(ENOSPC,                       ENOSPC_snapshot_tree)                   \
        x(0,                            open_buckets_empty)                     \
        x(0,                            freelist_empty)                         \
        x(BCH_ERR_freelist_empty,       no_buckets_found)                       \
index b35b584176ee494f41087e95a6b7f29f8fc63c94..e2b126ad2babdf5a3b8fdb8730cffd6453e12d25 100644 (file)
 #include "replicas.h"
 #include "super.h"
 #include "super-io.h"
+#include "trace.h"
 #include "util.h"
 
-#include <trace/events/bcachefs.h>
-
 static unsigned bch2_crc_field_size_max[] = {
        [BCH_EXTENT_ENTRY_crc32] = CRC32_SIZE_MAX,
        [BCH_EXTENT_ENTRY_crc64] = CRC64_SIZE_MAX,
@@ -184,27 +183,12 @@ void bch2_btree_ptr_to_text(struct printbuf *out, struct bch_fs *c,
 int bch2_btree_ptr_v2_invalid(const struct bch_fs *c, struct bkey_s_c k,
                              unsigned flags, struct printbuf *err)
 {
-       struct bkey_s_c_btree_ptr_v2 bp = bkey_s_c_to_btree_ptr_v2(k);
-
-       if (bkey_val_bytes(k.k) <= sizeof(*bp.v)) {
-               prt_printf(err, "value too small (%zu <= %zu)",
-                      bkey_val_bytes(k.k), sizeof(*bp.v));
-               return -BCH_ERR_invalid_bkey;
-       }
-
        if (bkey_val_u64s(k.k) > BKEY_BTREE_PTR_VAL_U64s_MAX) {
                prt_printf(err, "value too big (%zu > %zu)",
                       bkey_val_u64s(k.k), BKEY_BTREE_PTR_VAL_U64s_MAX);
                return -BCH_ERR_invalid_bkey;
        }
 
-       if (c->sb.version < bcachefs_metadata_version_snapshot &&
-           bp.v->min_key.snapshot) {
-               prt_printf(err, "invalid min_key.snapshot (%u != 0)",
-                      bp.v->min_key.snapshot);
-               return -BCH_ERR_invalid_bkey;
-       }
-
        return bch2_bkey_ptrs_invalid(c, k, flags, err);
 }
 
@@ -391,12 +375,6 @@ int bch2_reservation_invalid(const struct bch_fs *c, struct bkey_s_c k,
 {
        struct bkey_s_c_reservation r = bkey_s_c_to_reservation(k);
 
-       if (bkey_val_bytes(k.k) != sizeof(struct bch_reservation)) {
-               prt_printf(err, "incorrect value size (%zu != %zu)",
-                      bkey_val_bytes(k.k), sizeof(*r.v));
-               return -BCH_ERR_invalid_bkey;
-       }
-
        if (!r.v->nr_replicas || r.v->nr_replicas > BCH_REPLICAS_MAX) {
                prt_printf(err, "invalid nr_replicas (%u)",
                       r.v->nr_replicas);
index 9b026ae95932f382d5b6c7aacd34b38d628c059f..31c8140950e0073d615c52bb39a4146e7815c2e4 100644 (file)
@@ -407,6 +407,7 @@ void bch2_btree_ptr_v2_compat(enum btree_id, unsigned, unsigned,
        .compat         = bch2_btree_ptr_v2_compat,             \
        .trans_trigger  = bch2_trans_mark_extent,               \
        .atomic_trigger = bch2_mark_extent,                     \
+       .min_val_size   = 40,                                   \
 })
 
 /* KEY_TYPE_extent: */
@@ -436,6 +437,7 @@ bool bch2_reservation_merge(struct bch_fs *, struct bkey_s, struct bkey_s_c);
        .key_merge      = bch2_reservation_merge,               \
        .trans_trigger  = bch2_trans_mark_reservation,          \
        .atomic_trigger = bch2_mark_reservation,                \
+       .min_val_size   = 8,                                    \
 })
 
 /* Extent checksum entries: */
index 43c39c62740307d5b2987fe5efe5f87e9af661f6..3e104bf090559485888926494063b63830742fae 100644 (file)
@@ -19,6 +19,7 @@
 #include "keylist.h"
 #include "quota.h"
 #include "reflink.h"
+#include "trace.h"
 
 #include <linux/aio.h>
 #include <linux/backing-dev.h>
@@ -32,7 +33,6 @@
 #include <linux/uio.h>
 #include <linux/writeback.h>
 
-#include <trace/events/bcachefs.h>
 #include <trace/events/writeback.h>
 
 /*
@@ -290,6 +290,9 @@ static int bch2_quota_reservation_add(struct bch_fs *c,
 {
        int ret;
 
+       if (test_bit(EI_INODE_SNAPSHOT, &inode->ei_flags))
+               return 0;
+
        mutex_lock(&inode->ei_quota_lock);
        ret = bch2_quota_acct(c, inode->ei_qid, Q_SPC, sectors,
                              check_enospc ? KEY_TYPE_QUOTA_PREALLOC : KEY_TYPE_QUOTA_NOCHECK);
@@ -371,7 +374,9 @@ static void __i_sectors_acct(struct bch_fs *c, struct bch_inode_info *inode,
        inode->v.i_blocks += sectors;
 
 #ifdef CONFIG_BCACHEFS_QUOTA
-       if (quota_res && sectors > 0) {
+       if (quota_res &&
+           !test_bit(EI_INODE_SNAPSHOT, &inode->ei_flags) &&
+           sectors > 0) {
                BUG_ON(sectors > quota_res->sectors);
                BUG_ON(sectors > inode->ei_quota_reserved);
 
@@ -1512,11 +1517,10 @@ static void bch2_writepage_io_alloc(struct bch_fs *c,
        op->wbio.bio.bi_opf     = wbc_to_write_flags(wbc);
 }
 
-static int __bch2_writepage(struct page *_page,
+static int __bch2_writepage(struct folio *folio,
                            struct writeback_control *wbc,
                            void *data)
 {
-       struct folio *folio = page_folio(_page);
        struct bch_inode_info *inode = to_bch_ei(folio->mapping->host);
        struct bch_fs *c = inode->v.i_sb->s_fs_info;
        struct bch_writepage_state *w = data;
@@ -2912,7 +2916,7 @@ static int bch2_truncate_folios(struct bch_inode_info *inode,
        return ret;
 }
 
-static int bch2_extend(struct user_namespace *mnt_userns,
+static int bch2_extend(struct mnt_idmap *idmap,
                       struct bch_inode_info *inode,
                       struct bch_inode_unpacked *inode_u,
                       struct iattr *iattr)
@@ -2931,7 +2935,7 @@ static int bch2_extend(struct user_namespace *mnt_userns,
 
        truncate_setsize(&inode->v, iattr->ia_size);
 
-       return bch2_setattr_nonsize(mnt_userns, inode, iattr);
+       return bch2_setattr_nonsize(idmap, inode, iattr);
 }
 
 static int bch2_truncate_finish_fn(struct bch_inode_info *inode,
@@ -2952,7 +2956,7 @@ static int bch2_truncate_start_fn(struct bch_inode_info *inode,
        return 0;
 }
 
-int bch2_truncate(struct user_namespace *mnt_userns,
+int bch2_truncate(struct mnt_idmap *idmap,
                  struct bch_inode_info *inode, struct iattr *iattr)
 {
        struct bch_fs *c = inode->v.i_sb->s_fs_info;
@@ -2997,7 +3001,7 @@ int bch2_truncate(struct user_namespace *mnt_userns,
                  (u64) inode->v.i_size, inode_u.bi_size);
 
        if (iattr->ia_size > inode->v.i_size) {
-               ret = bch2_extend(mnt_userns, inode, &inode_u, iattr);
+               ret = bch2_extend(idmap, inode, &inode_u, iattr);
                goto err;
        }
 
@@ -3055,7 +3059,7 @@ int bch2_truncate(struct user_namespace *mnt_userns,
        ret = bch2_write_inode(c, inode, bch2_truncate_finish_fn, NULL, 0);
        mutex_unlock(&inode->ei_update_lock);
 
-       ret = bch2_setattr_nonsize(mnt_userns, inode, iattr);
+       ret = bch2_setattr_nonsize(idmap, inode, iattr);
 err:
        bch2_pagecache_block_put(inode);
        return bch2_err_class(ret);
index a8835298613a95954e4311b2ecec4088d7d47e91..af905331542dd99191b43866ee423991764a8e66 100644 (file)
@@ -30,7 +30,7 @@ ssize_t bch2_write_iter(struct kiocb *, struct iov_iter *);
 
 int bch2_fsync(struct file *, loff_t, loff_t, int);
 
-int bch2_truncate(struct user_namespace *,
+int bch2_truncate(struct mnt_idmap *,
                  struct bch_inode_info *, struct iattr *);
 long bch2_fallocate_dispatch(struct file *, int, loff_t, loff_t);
 
index 571b4dca4d39a46a6cff4a8dafe992cf0750061f..269af9393824c14348a2c62b5544e8abb70b2b3c 100644 (file)
@@ -93,7 +93,7 @@ static int bch2_ioc_setflags(struct bch_fs *c,
                return ret;
 
        inode_lock(&inode->v);
-       if (!inode_owner_or_capable(file_mnt_user_ns(file), &inode->v)) {
+       if (!inode_owner_or_capable(file_mnt_idmap(file), &inode->v)) {
                ret = -EACCES;
                goto setflags_out;
        }
@@ -172,7 +172,7 @@ static int bch2_ioc_fssetxattr(struct bch_fs *c,
                return ret;
 
        inode_lock(&inode->v);
-       if (!inode_owner_or_capable(file_mnt_user_ns(file), &inode->v)) {
+       if (!inode_owner_or_capable(file_mnt_idmap(file), &inode->v)) {
                ret = -EACCES;
                goto err;
        }
@@ -393,7 +393,7 @@ retry:
                goto err3;
        }
 
-       error = inode_permission(file_mnt_user_ns(filp),
+       error = inode_permission(file_mnt_idmap(filp),
                                 dir, MAY_WRITE | MAY_EXEC);
        if (error)
                goto err3;
@@ -409,7 +409,7 @@ retry:
            !arg.src_ptr)
                snapshot_src.subvol = to_bch_ei(dir)->ei_inode.bi_subvol;
 
-       inode = __bch2_create(file_mnt_user_ns(filp), to_bch_ei(dir),
+       inode = __bch2_create(file_mnt_idmap(filp), to_bch_ei(dir),
                              dst_dentry, arg.mode|S_IFDIR,
                              0, snapshot_src, create_flags);
        error = PTR_ERR_OR_ZERO(inode);
index 6dbbc6ff4cb8a5e51959621bc3cefe5c5cfd3b3c..56091ce8407fee7a9fbb3fccf486ceff4fcffdbe 100644 (file)
@@ -216,7 +216,7 @@ struct inode *bch2_vfs_inode_get(struct bch_fs *c, subvol_inum inum)
 }
 
 struct bch_inode_info *
-__bch2_create(struct user_namespace *mnt_userns,
+__bch2_create(struct mnt_idmap *idmap,
              struct bch_inode_info *dir, struct dentry *dentry,
              umode_t mode, dev_t rdev, subvol_inum snapshot_src,
              unsigned flags)
@@ -262,8 +262,8 @@ retry:
                                  inode_inum(dir), &dir_u, &inode_u,
                                  !(flags & BCH_CREATE_TMPFILE)
                                  ? &dentry->d_name : NULL,
-                                 from_kuid(mnt_userns, current_fsuid()),
-                                 from_kgid(mnt_userns, current_fsgid()),
+                                 from_kuid(i_user_ns(&dir->v), current_fsuid()),
+                                 from_kgid(i_user_ns(&dir->v), current_fsgid()),
                                  mode, rdev,
                                  default_acl, acl, snapshot_src, flags) ?:
                bch2_quota_acct(c, bch_qid(&inode_u), Q_INO, 1,
@@ -370,12 +370,12 @@ static struct dentry *bch2_lookup(struct inode *vdir, struct dentry *dentry,
        return d_splice_alias(vinode, dentry);
 }
 
-static int bch2_mknod(struct user_namespace *mnt_userns,
+static int bch2_mknod(struct mnt_idmap *idmap,
                      struct inode *vdir, struct dentry *dentry,
                      umode_t mode, dev_t rdev)
 {
        struct bch_inode_info *inode =
-               __bch2_create(mnt_userns, to_bch_ei(vdir), dentry, mode, rdev,
+               __bch2_create(idmap, to_bch_ei(vdir), dentry, mode, rdev,
                              (subvol_inum) { 0 }, 0);
 
        if (IS_ERR(inode))
@@ -385,11 +385,11 @@ static int bch2_mknod(struct user_namespace *mnt_userns,
        return 0;
 }
 
-static int bch2_create(struct user_namespace *mnt_userns,
+static int bch2_create(struct mnt_idmap *idmap,
                       struct inode *vdir, struct dentry *dentry,
                       umode_t mode, bool excl)
 {
-       return bch2_mknod(mnt_userns, vdir, dentry, mode|S_IFREG, 0);
+       return bch2_mknod(idmap, vdir, dentry, mode|S_IFREG, 0);
 }
 
 static int __bch2_link(struct bch_fs *c,
@@ -486,7 +486,7 @@ static int bch2_unlink(struct inode *vdir, struct dentry *dentry)
        return __bch2_unlink(vdir, dentry, false);
 }
 
-static int bch2_symlink(struct user_namespace *mnt_userns,
+static int bch2_symlink(struct mnt_idmap *idmap,
                        struct inode *vdir, struct dentry *dentry,
                        const char *symname)
 {
@@ -494,7 +494,7 @@ static int bch2_symlink(struct user_namespace *mnt_userns,
        struct bch_inode_info *dir = to_bch_ei(vdir), *inode;
        int ret;
 
-       inode = __bch2_create(mnt_userns, dir, dentry, S_IFLNK|S_IRWXUGO, 0,
+       inode = __bch2_create(idmap, dir, dentry, S_IFLNK|S_IRWXUGO, 0,
                              (subvol_inum) { 0 }, BCH_CREATE_TMPFILE);
        if (IS_ERR(inode))
                return bch2_err_class(PTR_ERR(inode));
@@ -521,13 +521,13 @@ err:
        return ret;
 }
 
-static int bch2_mkdir(struct user_namespace *mnt_userns,
+static int bch2_mkdir(struct mnt_idmap *idmap,
                      struct inode *vdir, struct dentry *dentry, umode_t mode)
 {
-       return bch2_mknod(mnt_userns, vdir, dentry, mode|S_IFDIR, 0);
+       return bch2_mknod(idmap, vdir, dentry, mode|S_IFDIR, 0);
 }
 
-static int bch2_rename2(struct user_namespace *mnt_userns,
+static int bch2_rename2(struct mnt_idmap *idmap,
                        struct inode *src_vdir, struct dentry *src_dentry,
                        struct inode *dst_vdir, struct dentry *dst_dentry,
                        unsigned flags)
@@ -634,7 +634,7 @@ err:
        return ret;
 }
 
-static void bch2_setattr_copy(struct user_namespace *mnt_userns,
+static void bch2_setattr_copy(struct mnt_idmap *idmap,
                              struct bch_inode_info *inode,
                              struct bch_inode_unpacked *bi,
                              struct iattr *attr)
@@ -643,9 +643,9 @@ static void bch2_setattr_copy(struct user_namespace *mnt_userns,
        unsigned int ia_valid = attr->ia_valid;
 
        if (ia_valid & ATTR_UID)
-               bi->bi_uid = from_kuid(mnt_userns, attr->ia_uid);
+               bi->bi_uid = from_kuid(i_user_ns(&inode->v), attr->ia_uid);
        if (ia_valid & ATTR_GID)
-               bi->bi_gid = from_kgid(mnt_userns, attr->ia_gid);
+               bi->bi_gid = from_kgid(i_user_ns(&inode->v), attr->ia_gid);
 
        if (ia_valid & ATTR_SIZE)
                bi->bi_size = attr->ia_size;
@@ -664,13 +664,13 @@ static void bch2_setattr_copy(struct user_namespace *mnt_userns,
                        : inode->v.i_gid;
 
                if (!in_group_p(gid) &&
-                   !capable_wrt_inode_uidgid(mnt_userns, &inode->v, CAP_FSETID))
+                   !capable_wrt_inode_uidgid(idmap, &inode->v, CAP_FSETID))
                        mode &= ~S_ISGID;
                bi->bi_mode = mode;
        }
 }
 
-int bch2_setattr_nonsize(struct user_namespace *mnt_userns,
+int bch2_setattr_nonsize(struct mnt_idmap *idmap,
                         struct bch_inode_info *inode,
                         struct iattr *attr)
 {
@@ -687,10 +687,10 @@ int bch2_setattr_nonsize(struct user_namespace *mnt_userns,
        qid = inode->ei_qid;
 
        if (attr->ia_valid & ATTR_UID)
-               qid.q[QTYP_USR] = from_kuid(mnt_userns, attr->ia_uid);
+               qid.q[QTYP_USR] = from_kuid(i_user_ns(&inode->v), attr->ia_uid);
 
        if (attr->ia_valid & ATTR_GID)
-               qid.q[QTYP_GRP] = from_kgid(mnt_userns, attr->ia_gid);
+               qid.q[QTYP_GRP] = from_kgid(i_user_ns(&inode->v), attr->ia_gid);
 
        ret = bch2_fs_quota_transfer(c, inode, qid, ~0,
                                     KEY_TYPE_QUOTA_PREALLOC);
@@ -708,7 +708,7 @@ retry:
        if (ret)
                goto btree_err;
 
-       bch2_setattr_copy(mnt_userns, inode, &inode_u, attr);
+       bch2_setattr_copy(idmap, inode, &inode_u, attr);
 
        if (attr->ia_valid & ATTR_MODE) {
                ret = bch2_acl_chmod(&trans, inode_inum(inode), &inode_u,
@@ -740,7 +740,7 @@ err:
        return bch2_err_class(ret);
 }
 
-static int bch2_getattr(struct user_namespace *mnt_userns,
+static int bch2_getattr(struct mnt_idmap *idmap,
                        const struct path *path, struct kstat *stat,
                        u32 request_mask, unsigned query_flags)
 {
@@ -781,7 +781,7 @@ static int bch2_getattr(struct user_namespace *mnt_userns,
        return 0;
 }
 
-static int bch2_setattr(struct user_namespace *mnt_userns,
+static int bch2_setattr(struct mnt_idmap *idmap,
                        struct dentry *dentry, struct iattr *iattr)
 {
        struct bch_inode_info *inode = to_bch_ei(dentry->d_inode);
@@ -789,20 +789,20 @@ static int bch2_setattr(struct user_namespace *mnt_userns,
 
        lockdep_assert_held(&inode->v.i_rwsem);
 
-       ret = setattr_prepare(mnt_userns, dentry, iattr);
+       ret = setattr_prepare(idmap, dentry, iattr);
        if (ret)
                return ret;
 
        return iattr->ia_valid & ATTR_SIZE
-               ? bch2_truncate(mnt_userns, inode, iattr)
-               : bch2_setattr_nonsize(mnt_userns, inode, iattr);
+               ? bch2_truncate(idmap, inode, iattr)
+               : bch2_setattr_nonsize(idmap, inode, iattr);
 }
 
-static int bch2_tmpfile(struct user_namespace *mnt_userns,
+static int bch2_tmpfile(struct mnt_idmap *idmap,
                        struct inode *vdir, struct file *file, umode_t mode)
 {
        struct bch_inode_info *inode =
-               __bch2_create(mnt_userns, to_bch_ei(vdir),
+               __bch2_create(idmap, to_bch_ei(vdir),
                              file->f_path.dentry, mode, 0,
                              (subvol_inum) { 0 }, BCH_CREATE_TMPFILE);
 
index cf0413534182a92d1ecdde48e94f58d06172fa57..2e63cb6603bd7f1da9eee3eb1c368fb7770fdc5b 100644 (file)
@@ -149,7 +149,7 @@ struct bch_inode_unpacked;
 #ifndef NO_BCACHEFS_FS
 
 struct bch_inode_info *
-__bch2_create(struct user_namespace *, struct bch_inode_info *,
+__bch2_create(struct mnt_idmap *, struct bch_inode_info *,
              struct dentry *, umode_t, dev_t, subvol_inum, unsigned);
 
 int bch2_fs_quota_transfer(struct bch_fs *,
@@ -184,7 +184,7 @@ void bch2_inode_update_after_write(struct btree_trans *,
 int __must_check bch2_write_inode(struct bch_fs *, struct bch_inode_info *,
                                  inode_set_fn, void *, unsigned);
 
-int bch2_setattr_nonsize(struct user_namespace *,
+int bch2_setattr_nonsize(struct mnt_idmap *,
                         struct bch_inode_info *,
                         struct iattr *);
 int __bch2_unlink(struct inode *, struct dentry *, bool);
index 4e71005777348667bd2875031b07f279e3a618eb..eb3609aa45933afcca1d37b3e3554b15540ba99e 100644 (file)
@@ -72,26 +72,14 @@ static s64 bch2_count_subdirs(struct btree_trans *trans, u64 inum,
 static int __snapshot_lookup_subvol(struct btree_trans *trans, u32 snapshot,
                                    u32 *subvol)
 {
-       struct btree_iter iter;
-       struct bkey_s_c k;
-       int ret;
-
-       bch2_trans_iter_init(trans, &iter, BTREE_ID_snapshots,
-                            POS(0, snapshot), 0);
-       k = bch2_btree_iter_peek_slot(&iter);
-       ret = bkey_err(k);
-       if (ret)
-               goto err;
-
-       if (k.k->type != KEY_TYPE_snapshot) {
+       struct bch_snapshot s;
+       int ret = bch2_bkey_get_val_typed(trans, BTREE_ID_snapshots,
+                                         POS(0, snapshot), 0,
+                                         snapshot, &s);
+       if (!ret)
+               *subvol = le32_to_cpu(s.subvol);
+       else if (ret == -ENOENT)
                bch_err(trans->c, "snapshot %u not fonud", snapshot);
-               ret = -ENOENT;
-               goto err;
-       }
-
-       *subvol = le32_to_cpu(bkey_s_c_to_snapshot(k).v->subvol);
-err:
-       bch2_trans_iter_exit(trans, &iter);
        return ret;
 
 }
@@ -152,9 +140,8 @@ static int __lookup_inode(struct btree_trans *trans, u64 inode_nr,
        struct bkey_s_c k;
        int ret;
 
-       bch2_trans_iter_init(trans, &iter, BTREE_ID_inodes,
-                            SPOS(0, inode_nr, *snapshot), 0);
-       k = bch2_btree_iter_peek_slot(&iter);
+       k = bch2_bkey_get_iter(trans, &iter, BTREE_ID_inodes,
+                              SPOS(0, inode_nr, *snapshot), 0);
        ret = bkey_err(k);
        if (ret)
                goto err;
@@ -259,10 +246,8 @@ static int fsck_inode_rm(struct btree_trans *trans, u64 inum, u32 snapshot)
 retry:
        bch2_trans_begin(trans);
 
-       bch2_trans_iter_init(trans, &iter, BTREE_ID_inodes,
-                            SPOS(0, inum, snapshot), BTREE_ITER_INTENT);
-       k = bch2_btree_iter_peek_slot(&iter);
-
+       k = bch2_bkey_get_iter(trans, &iter, BTREE_ID_inodes,
+                              SPOS(0, inum, snapshot), BTREE_ITER_INTENT);
        ret = bkey_err(k);
        if (ret)
                goto err;
@@ -453,22 +438,14 @@ static int remove_backpointer(struct btree_trans *trans,
                              struct bch_inode_unpacked *inode)
 {
        struct btree_iter iter;
-       struct bkey_s_c k;
+       struct bkey_s_c_dirent d;
        int ret;
 
-       bch2_trans_iter_init(trans, &iter, BTREE_ID_dirents,
-                            POS(inode->bi_dir, inode->bi_dir_offset), 0);
-       k = bch2_btree_iter_peek_slot(&iter);
-       ret = bkey_err(k);
-       if (ret)
-               goto out;
-       if (k.k->type != KEY_TYPE_dirent) {
-               ret = -ENOENT;
-               goto out;
-       }
-
-       ret = __remove_dirent(trans, k.k->p);
-out:
+       d = bch2_bkey_get_iter_typed(trans, &iter, BTREE_ID_dirents,
+                                    POS(inode->bi_dir, inode->bi_dir_offset), 0,
+                                    dirent);
+       ret =   bkey_err(d) ?:
+               __remove_dirent(trans, d.k->p);
        bch2_trans_iter_exit(trans, &iter);
        return ret;
 }
@@ -788,7 +765,7 @@ static int hash_redo_key(struct btree_trans *trans,
        if (IS_ERR(delete))
                return PTR_ERR(delete);
 
-       tmp = bch2_bkey_make_mut(trans, k);
+       tmp = bch2_bkey_make_mut_noupdate(trans, k);
        if (IS_ERR(tmp))
                return PTR_ERR(tmp);
 
@@ -1081,20 +1058,7 @@ static struct bkey_s_c_dirent dirent_get_by_pos(struct btree_trans *trans,
                                                struct btree_iter *iter,
                                                struct bpos pos)
 {
-       struct bkey_s_c k;
-       int ret;
-
-       bch2_trans_iter_init(trans, iter, BTREE_ID_dirents, pos, 0);
-       k = bch2_btree_iter_peek_slot(iter);
-       ret = bkey_err(k);
-       if (!ret && k.k->type != KEY_TYPE_dirent)
-               ret = -ENOENT;
-       if (ret) {
-               bch2_trans_iter_exit(trans, iter);
-               return (struct bkey_s_c_dirent) { .k = ERR_PTR(ret) };
-       }
-
-       return bkey_s_c_to_dirent(k);
+       return bch2_bkey_get_iter_typed(trans, iter, BTREE_ID_dirents, pos, 0, dirent);
 }
 
 static bool inode_points_to_dirent(struct bch_inode_unpacked *inode,
@@ -1122,7 +1086,7 @@ static int inode_backpointer_exists(struct btree_trans *trans,
 
        d = dirent_get_by_pos(trans, &iter,
                        SPOS(inode->bi_dir, inode->bi_dir_offset, snapshot));
-       ret = bkey_err(d.s_c);
+       ret = bkey_err(d);
        if (ret)
                return ret == -ENOENT ? 0 : ret;
 
@@ -2463,7 +2427,8 @@ int bch2_fsck_full(struct bch_fs *c)
 {
        int ret;
 again:
-       ret =   bch2_fs_check_snapshots(c) ?:
+       ret =   bch2_fs_check_snapshot_trees(c);
+               bch2_fs_check_snapshots(c) ?:
                bch2_fs_check_subvols(c) ?:
                bch2_delete_dead_snapshots(c) ?:
                check_inodes(c, true) ?:
index 7ccbc00b7156ed9f7ad9e2f16326555b475a5760..ddcd7b125f3223014721b79ec4b32dafee642893 100644 (file)
@@ -329,13 +329,12 @@ int bch2_inode_peek(struct btree_trans *trans,
        if (ret)
                return ret;
 
-       bch2_trans_iter_init(trans, iter, BTREE_ID_inodes,
-                            SPOS(0, inum.inum, snapshot),
-                            flags|BTREE_ITER_CACHED);
-       k = bch2_btree_iter_peek_slot(iter);
+       k = bch2_bkey_get_iter(trans, iter, BTREE_ID_inodes,
+                              SPOS(0, inum.inum, snapshot),
+                              flags|BTREE_ITER_CACHED);
        ret = bkey_err(k);
        if (ret)
-               goto err;
+               return ret;
 
        ret = bkey_is_inode(k.k) ? 0 : -ENOENT;
        if (ret)
@@ -437,12 +436,6 @@ int bch2_inode_invalid(const struct bch_fs *c, struct bkey_s_c k,
 {
        struct bkey_s_c_inode inode = bkey_s_c_to_inode(k);
 
-       if (bkey_val_bytes(k.k) < sizeof(*inode.v)) {
-               prt_printf(err, "incorrect value size (%zu < %zu)",
-                      bkey_val_bytes(k.k), sizeof(*inode.v));
-               return -BCH_ERR_invalid_bkey;
-       }
-
        if (INODE_STR_HASH(inode.v) >= BCH_STR_HASH_NR) {
                prt_printf(err, "invalid str hash type (%llu >= %u)",
                       INODE_STR_HASH(inode.v), BCH_STR_HASH_NR);
@@ -457,12 +450,6 @@ int bch2_inode_v2_invalid(const struct bch_fs *c, struct bkey_s_c k,
 {
        struct bkey_s_c_inode_v2 inode = bkey_s_c_to_inode_v2(k);
 
-       if (bkey_val_bytes(k.k) < sizeof(*inode.v)) {
-               prt_printf(err, "incorrect value size (%zu < %zu)",
-                      bkey_val_bytes(k.k), sizeof(*inode.v));
-               return -BCH_ERR_invalid_bkey;
-       }
-
        if (INODEv2_STR_HASH(inode.v) >= BCH_STR_HASH_NR) {
                prt_printf(err, "invalid str hash type (%llu >= %u)",
                       INODEv2_STR_HASH(inode.v), BCH_STR_HASH_NR);
@@ -477,12 +464,6 @@ int bch2_inode_v3_invalid(const struct bch_fs *c, struct bkey_s_c k,
 {
        struct bkey_s_c_inode_v3 inode = bkey_s_c_to_inode_v3(k);
 
-       if (bkey_val_bytes(k.k) < sizeof(*inode.v)) {
-               prt_printf(err, "incorrect value size (%zu < %zu)",
-                      bkey_val_bytes(k.k), sizeof(*inode.v));
-               return -BCH_ERR_invalid_bkey;
-       }
-
        if (INODEv3_FIELDS_START(inode.v) < INODEv3_FIELDS_START_INITIAL ||
            INODEv3_FIELDS_START(inode.v) > bkey_val_u64s(inode.k)) {
                prt_printf(err, "invalid fields_start (got %llu, min %u max %zu)",
@@ -543,12 +524,6 @@ int bch2_inode_generation_invalid(const struct bch_fs *c, struct bkey_s_c k,
                return -BCH_ERR_invalid_bkey;
        }
 
-       if (bkey_val_bytes(k.k) != sizeof(struct bch_inode_generation)) {
-               prt_printf(err, "incorrect value size (%zu != %zu)",
-                      bkey_val_bytes(k.k), sizeof(struct bch_inode_generation));
-               return -BCH_ERR_invalid_bkey;
-       }
-
        return 0;
 }
 
@@ -784,11 +759,9 @@ retry:
        if (ret)
                goto err;
 
-       bch2_trans_iter_init(&trans, &iter, BTREE_ID_inodes,
-                            SPOS(0, inum.inum, snapshot),
-                            BTREE_ITER_INTENT|BTREE_ITER_CACHED);
-       k = bch2_btree_iter_peek_slot(&iter);
-
+       k = bch2_bkey_get_iter(&trans, &iter, BTREE_ID_inodes,
+                              SPOS(0, inum.inum, snapshot),
+                              BTREE_ITER_INTENT|BTREE_ITER_CACHED);
        ret = bkey_err(k);
        if (ret)
                goto err;
index f5066afb4886c5e67a3fd426020f74596e3b257f..0c3022d3f995f00ef0bfe99de85a6f50877e9032 100644 (file)
@@ -17,6 +17,7 @@ void bch2_inode_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
        .val_to_text    = bch2_inode_to_text,           \
        .trans_trigger  = bch2_trans_mark_inode,        \
        .atomic_trigger = bch2_mark_inode,              \
+       .min_val_size   = 16,                           \
 })
 
 #define bch2_bkey_ops_inode_v2 ((struct bkey_ops) {    \
@@ -24,6 +25,7 @@ void bch2_inode_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
        .val_to_text    = bch2_inode_to_text,           \
        .trans_trigger  = bch2_trans_mark_inode,        \
        .atomic_trigger = bch2_mark_inode,              \
+       .min_val_size   = 32,                           \
 })
 
 #define bch2_bkey_ops_inode_v3 ((struct bkey_ops) {    \
@@ -31,6 +33,7 @@ void bch2_inode_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
        .val_to_text    = bch2_inode_to_text,           \
        .trans_trigger  = bch2_trans_mark_inode,        \
        .atomic_trigger = bch2_mark_inode,              \
+       .min_val_size   = 48,                           \
 })
 
 static inline bool bkey_is_inode(const struct bkey *k)
@@ -47,6 +50,7 @@ void bch2_inode_generation_to_text(struct printbuf *, struct bch_fs *, struct bk
 #define bch2_bkey_ops_inode_generation ((struct bkey_ops) {    \
        .key_invalid    = bch2_inode_generation_invalid,        \
        .val_to_text    = bch2_inode_generation_to_text,        \
+       .min_val_size   = 8,                                    \
 })
 
 #if 0
index c0371e23a4bc0f1cd9abc445a572b4e98a1cca94..5a04ee514f4a95d1f82636d6a75d02d8be509886 100644 (file)
 #include "subvolume.h"
 #include "super.h"
 #include "super-io.h"
+#include "trace.h"
 
 #include <linux/blkdev.h>
 #include <linux/prefetch.h>
 #include <linux/random.h>
 #include <linux/sched/mm.h>
 
-#include <trace/events/bcachefs.h>
-
 const char *bch2_blk_status_to_str(blk_status_t status)
 {
        if (status == BLK_STS_REMOVED)
@@ -258,15 +257,14 @@ static inline int bch2_extent_update_i_size_sectors(struct btree_trans *trans,
        unsigned inode_update_flags = BTREE_UPDATE_NOJOURNAL;
        int ret;
 
-       bch2_trans_iter_init(trans, &iter, BTREE_ID_inodes,
-                            SPOS(0,
-                                 extent_iter->pos.inode,
-                                 extent_iter->snapshot),
-                            BTREE_ITER_INTENT|BTREE_ITER_CACHED);
-       k = bch2_bkey_get_mut(trans, &iter);
+       k = bch2_bkey_get_mut_noupdate(trans, &iter, BTREE_ID_inodes,
+                             SPOS(0,
+                                  extent_iter->pos.inode,
+                                  extent_iter->snapshot),
+                             BTREE_ITER_CACHED);
        ret = PTR_ERR_OR_ZERO(k);
        if (unlikely(ret))
-               goto err;
+               return ret;
 
        if (unlikely(k->k.type != KEY_TYPE_inode_v3)) {
                k = bch2_inode_to_v3(trans, k);
@@ -1395,7 +1393,7 @@ static int bch2_nocow_write_convert_one_unwritten(struct btree_trans *trans,
                return 0;
        }
 
-       new = bch2_bkey_make_mut(trans, k);
+       new = bch2_bkey_make_mut_noupdate(trans, k);
        ret = PTR_ERR_OR_ZERO(new);
        if (ret)
                return ret;
@@ -2313,9 +2311,8 @@ static int __bch2_rbio_narrow_crcs(struct btree_trans *trans,
        if (crc_is_compressed(rbio->pick.crc))
                return 0;
 
-       bch2_trans_iter_init(trans, &iter, rbio->data_btree, rbio->data_pos,
-                            BTREE_ITER_SLOTS|BTREE_ITER_INTENT);
-       k = bch2_btree_iter_peek_slot(&iter);
+       k = bch2_bkey_get_iter(trans, &iter, rbio->data_btree, rbio->data_pos,
+                              BTREE_ITER_SLOTS|BTREE_ITER_INTENT);
        if ((ret = bkey_err(k)))
                goto out;
 
@@ -2551,10 +2548,8 @@ int __bch2_read_indirect_extent(struct btree_trans *trans,
        reflink_offset = le64_to_cpu(bkey_i_to_reflink_p(orig_k->k)->v.idx) +
                *offset_into_extent;
 
-       bch2_trans_iter_init(trans, &iter, BTREE_ID_reflink,
-                            POS(0, reflink_offset),
-                            BTREE_ITER_SLOTS);
-       k = bch2_btree_iter_peek_slot(&iter);
+       k = bch2_bkey_get_iter(trans, &iter, BTREE_ID_reflink,
+                              POS(0, reflink_offset), 0);
        ret = bkey_err(k);
        if (ret)
                goto err;
index 90948bb0aabd62b8be5e69ce7d2add70f0d56ec1..87d80fb28c05135a1a065d5c286bc13a3463efc2 100644 (file)
@@ -113,7 +113,7 @@ static inline struct bch_write_bio *wbio_init(struct bio *bio)
 {
        struct bch_write_bio *wbio = to_wbio(bio);
 
-       memset(wbio, 0, offsetof(struct bch_write_bio, bio));
+       memset(&wbio->wbio, 0, sizeof(wbio->wbio));
        return wbio;
 }
 
index 3b2ed0fa583a05b50fb92ad9adff7f37a10d7ce0..4149291c0df6f153f8f7a147eed75487767efd18 100644 (file)
@@ -83,6 +83,7 @@ struct bch_read_bio {
 };
 
 struct bch_write_bio {
+       struct_group(wbio,
        struct bch_fs           *c;
        struct bch_write_bio    *parent;
 
@@ -99,6 +100,7 @@ struct bch_write_bio {
                                nocow:1,
                                used_mempool:1,
                                first_btree_write:1;
+       );
 
        struct bio              bio;
 };
index 3f0e6d71aa3299c2b08a510517009f5afc828c56..433c97844f36f7058f5501600e6651f256706add 100644 (file)
@@ -17,8 +17,7 @@
 #include "journal_reclaim.h"
 #include "journal_sb.h"
 #include "journal_seq_blacklist.h"
-
-#include <trace/events/bcachefs.h>
+#include "trace.h"
 
 #define x(n)   #n,
 static const char * const bch2_journal_watermarks[] = {
index 45b1b839783de66f712aaac1b337cf522e365d84..38458ab0013d049d6b7cc3c6db990be1a09e2c95 100644 (file)
@@ -14,8 +14,7 @@
 #include "journal_reclaim.h"
 #include "journal_seq_blacklist.h"
 #include "replicas.h"
-
-#include <trace/events/bcachefs.h>
+#include "trace.h"
 
 static struct nonce journal_nonce(const struct jset *jset)
 {
index 37c6846a30aa4eecf6f13d017834d0549640826b..29d843e6d6d437c501693b9c5c65ea848ca74cff 100644 (file)
 #include "journal_reclaim.h"
 #include "replicas.h"
 #include "super.h"
+#include "trace.h"
 
 #include <linux/kthread.h>
 #include <linux/sched/mm.h>
-#include <trace/events/bcachefs.h>
 
 /* Free space calculations: */
 
index c2dece27da2d3c856a46af66ae3c0579584d0011..4f23e88f6ae18df71a3adfef24b5535a493b4092 100644 (file)
 int bch2_lru_invalid(const struct bch_fs *c, struct bkey_s_c k,
                     unsigned flags, struct printbuf *err)
 {
-       const struct bch_lru *lru = bkey_s_c_to_lru(k).v;
-
-       if (bkey_val_bytes(k.k) < sizeof(*lru)) {
-               prt_printf(err, "incorrect value size (%zu < %zu)",
-                      bkey_val_bytes(k.k), sizeof(*lru));
-               return -BCH_ERR_invalid_bkey;
-       }
-
        if (!lru_pos_time(k.k->p)) {
                prt_printf(err, "lru entry at time=0");
                return -BCH_ERR_invalid_bkey;
@@ -122,8 +114,7 @@ static int bch2_check_lru_key(struct btree_trans *trans,
                        alloc_pos.inode, alloc_pos.offset))
                return bch2_btree_delete_at(trans, lru_iter, 0);
 
-       bch2_trans_iter_init(trans, &iter, BTREE_ID_alloc, alloc_pos, 0);
-       k = bch2_btree_iter_peek_slot(&iter);
+       k = bch2_bkey_get_iter(trans, &iter, BTREE_ID_alloc, alloc_pos, 0);
        ret = bkey_err(k);
        if (ret)
                goto err;
index 78a6076999ed11383a029e007440c7c61d0f22b5..adb98429248ef3ceee4b34f34d05417fbe3a1ce8 100644 (file)
@@ -51,6 +51,7 @@ void bch2_lru_pos_to_text(struct printbuf *, struct bpos);
 #define bch2_bkey_ops_lru ((struct bkey_ops) { \
        .key_invalid    = bch2_lru_invalid,     \
        .val_to_text    = bch2_lru_to_text,     \
+       .min_val_size   = 8,                    \
 })
 
 int bch2_lru_del(struct btree_trans *, u16, u64, u64);
index d93db07f0c8781d9ad35afeeeebb10938e94428d..0898fa49b3cd360b04e5a1ee552c954221c23e3a 100644 (file)
@@ -49,7 +49,7 @@ static int bch2_dev_usrdata_drop_key(struct btree_trans *trans,
        if (!bch2_bkey_has_device_c(k, dev_idx))
                return 0;
 
-       n = bch2_bkey_make_mut(trans, k);
+       n = bch2_bkey_make_mut(trans, iter, k, BTREE_UPDATE_INTERNAL_SNAPSHOT_NODE);
        ret = PTR_ERR_OR_ZERO(n);
        if (ret)
                return ret;
@@ -73,8 +73,7 @@ static int bch2_dev_usrdata_drop_key(struct btree_trans *trans,
         */
        if (bkey_deleted(&n->k))
                n->k.size = 0;
-
-       return bch2_trans_update(trans, iter, n, BTREE_UPDATE_INTERNAL_SNAPSHOT_NODE);
+       return 0;
 }
 
 static int bch2_dev_usrdata_drop(struct bch_fs *c, unsigned dev_idx, int flags)
index 200aa5dc0cf9d3959812586533ad95e53e5915c4..7e22176a5c7e5b4351b5b18227e70f1122979355 100644 (file)
 #include "inode.h"
 #include "io.h"
 #include "journal_reclaim.h"
+#include "keylist.h"
 #include "move.h"
 #include "replicas.h"
 #include "super-io.h"
-#include "keylist.h"
+#include "trace.h"
 
 #include <linux/ioprio.h>
 #include <linux/kthread.h>
 
-#include <trace/events/bcachefs.h>
-
 static void trace_move_extent2(struct bch_fs *c, struct bkey_s_c k)
 {
        if (trace_move_extent_enabled()) {
@@ -252,7 +251,7 @@ static int bch2_extent_drop_ptrs(struct btree_trans *trans,
        struct bkey_i *n;
        int ret;
 
-       n = bch2_bkey_make_mut(trans, k);
+       n = bch2_bkey_make_mut_noupdate(trans, k);
        ret = PTR_ERR_OR_ZERO(n);
        if (ret)
                return ret;
@@ -676,7 +675,7 @@ int __bch2_evacuate_bucket(struct btree_trans *trans,
        struct bpos bp_pos = POS_MIN;
        int ret = 0;
 
-       trace_bucket_evacuate(c, bucket);
+       trace_bucket_evacuate(c, &bucket);
 
        bch2_bkey_buf_init(&sk);
 
index c0fc669cdb0fc1ed471d93867fdb195598c54886..0d96346d5040a76a073880d4f274f6e691d9c2c8 100644 (file)
@@ -24,8 +24,8 @@
 #include "move.h"
 #include "movinggc.h"
 #include "super-io.h"
+#include "trace.h"
 
-#include <trace/events/bcachefs.h>
 #include <linux/bsearch.h>
 #include <linux/freezer.h>
 #include <linux/kthread.h>
@@ -91,12 +91,9 @@ static int bch2_bucket_is_movable(struct btree_trans *trans,
                                b->k.bucket.offset))
                return 0;
 
-       bch2_trans_iter_init(trans, &iter, BTREE_ID_alloc,
-                            b->k.bucket, BTREE_ITER_CACHED);
-       k = bch2_btree_iter_peek_slot(&iter);
+       k = bch2_bkey_get_iter(trans, &iter, BTREE_ID_alloc,
+                              b->k.bucket, BTREE_ITER_CACHED);
        ret = bkey_err(k);
-       bch2_trans_iter_exit(trans, &iter);
-
        if (ret)
                return ret;
 
@@ -108,14 +105,7 @@ static int bch2_bucket_is_movable(struct btree_trans *trans,
                a->fragmentation_lru &&
                a->fragmentation_lru <= time;
 
-       if (!ret) {
-               struct printbuf buf = PRINTBUF;
-
-               bch2_bkey_val_to_text(&buf, trans->c, k);
-               pr_debug("%s", buf.buf);
-               printbuf_exit(&buf);
-       }
-
+       bch2_trans_iter_exit(trans, &iter);
        return ret;
 }
 
@@ -205,6 +195,7 @@ static int bch2_copygc_get_buckets(struct btree_trans *trans,
        return ret < 0 ? ret : 0;
 }
 
+noinline
 static int bch2_copygc(struct btree_trans *trans,
                       struct moving_context *ctxt,
                       struct buckets_in_flight *buckets_in_flight)
index 331f22835d1859574cd073784242d557e130d7cd..cc0db72ce1df8163aa01f3f317051e9248eccaab 100644 (file)
@@ -67,12 +67,6 @@ int bch2_quota_invalid(const struct bch_fs *c, struct bkey_s_c k,
                return -BCH_ERR_invalid_bkey;
        }
 
-       if (bkey_val_bytes(k.k) != sizeof(struct bch_quota)) {
-               prt_printf(err, "incorrect value size (%zu != %zu)",
-                      bkey_val_bytes(k.k), sizeof(struct bch_quota));
-               return -BCH_ERR_invalid_bkey;
-       }
-
        return 0;
 }
 
@@ -562,23 +556,22 @@ static int bch2_fs_quota_read_inode(struct btree_trans *trans,
 {
        struct bch_fs *c = trans->c;
        struct bch_inode_unpacked u;
-       struct bch_subvolume subvolume;
+       struct bch_snapshot_tree s_t;
        int ret;
 
-       ret = bch2_snapshot_get_subvol(trans, k.k->p.snapshot, &subvolume);
+       ret = bch2_snapshot_tree_lookup(trans,
+                       snapshot_t(c, k.k->p.snapshot)->tree, &s_t);
        if (ret)
                return ret;
 
-       /*
-        * We don't do quota accounting in snapshots:
-        */
-       if (BCH_SUBVOLUME_SNAP(&subvolume))
+       if (!s_t.master_subvol)
                goto advance;
 
-       if (!bkey_is_inode(k.k))
-               goto advance;
-
-       ret = bch2_inode_unpack(k, &u);
+       ret = bch2_inode_find_by_inum_trans(trans,
+                               (subvol_inum) {
+                                       le32_to_cpu(s_t.master_subvol),
+                                       k.k->p.offset,
+                               }, &u);
        if (ret)
                return ret;
 
@@ -587,7 +580,7 @@ static int bch2_fs_quota_read_inode(struct btree_trans *trans,
        bch2_quota_acct(c, bch_qid(&u), Q_INO, 1,
                        KEY_TYPE_QUOTA_NOCHECK);
 advance:
-       bch2_btree_iter_set_pos(iter, POS(iter->pos.inode, iter->pos.offset + 1));
+       bch2_btree_iter_set_pos(iter, bpos_nosnap_successor(iter->pos));
        return 0;
 }
 
@@ -907,10 +900,8 @@ static int bch2_set_quota_trans(struct btree_trans *trans,
        struct bkey_s_c k;
        int ret;
 
-       bch2_trans_iter_init(trans, &iter, BTREE_ID_quotas, new_quota->k.p,
-                            BTREE_ITER_SLOTS|BTREE_ITER_INTENT);
-       k = bch2_btree_iter_peek_slot(&iter);
-
+       k = bch2_bkey_get_iter(trans, &iter, BTREE_ID_quotas, new_quota->k.p,
+                              BTREE_ITER_SLOTS|BTREE_ITER_INTENT);
        ret = bkey_err(k);
        if (unlikely(ret))
                return ret;
index 146264fd16ce0bf24a5dafe285b4921b0355d79f..b0f7d4ee775e17ae15e0177652c49d8006086558 100644 (file)
@@ -13,6 +13,7 @@ void bch2_quota_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
 #define bch2_bkey_ops_quota ((struct bkey_ops) {       \
        .key_invalid    = bch2_quota_invalid,           \
        .val_to_text    = bch2_quota_to_text,           \
+       .min_val_size   = 32,                           \
 })
 
 static inline struct bch_qid bch_qid(struct bch_inode_unpacked *u)
index 4df981bd96df18966481ab05f76c68f2b18eea1c..66c40999163d64bcc6fdf8491398da02cac1ab0e 100644 (file)
 #include "move.h"
 #include "rebalance.h"
 #include "super-io.h"
+#include "trace.h"
 
 #include <linux/freezer.h>
 #include <linux/kthread.h>
 #include <linux/sched/cputime.h>
-#include <trace/events/bcachefs.h>
 
 /*
  * Check if an extent should be moved:
index 91a66b5916eb7ed0d2629c0ee64424678ae7ec3b..af76c029fb6a530cfb5589dd1a7dfc1213a9c382 100644 (file)
@@ -1025,16 +1025,25 @@ fsck_err:
 
 static int bch2_fs_initialize_subvolumes(struct bch_fs *c)
 {
-       struct bkey_i_snapshot  root_snapshot;
-       struct bkey_i_subvolume root_volume;
+       struct bkey_i_snapshot_tree     root_tree;
+       struct bkey_i_snapshot          root_snapshot;
+       struct bkey_i_subvolume         root_volume;
        int ret;
 
+       bkey_snapshot_tree_init(&root_tree.k_i);
+       root_tree.k.p.offset            = 1;
+       root_tree.v.master_subvol       = cpu_to_le32(1);
+       root_tree.v.root_snapshot       = cpu_to_le32(U32_MAX);
+       ret = bch2_btree_insert(c, BTREE_ID_snapshot_trees,
+                               &root_tree.k_i,
+                               NULL, NULL, 0);
+
        bkey_snapshot_init(&root_snapshot.k_i);
        root_snapshot.k.p.offset = U32_MAX;
        root_snapshot.v.flags   = 0;
        root_snapshot.v.parent  = 0;
        root_snapshot.v.subvol  = BCACHEFS_ROOT_SUBVOL;
-       root_snapshot.v.pad     = 0;
+       root_snapshot.v.tree    = cpu_to_le32(1);
        SET_BCH_SNAPSHOT_SUBVOL(&root_snapshot.v, true);
 
        ret = bch2_btree_insert(c, BTREE_ID_snapshots,
@@ -1065,12 +1074,11 @@ static int bch2_fs_upgrade_for_subvolumes(struct btree_trans *trans)
        struct bch_inode_unpacked inode;
        int ret;
 
-       bch2_trans_iter_init(trans, &iter, BTREE_ID_inodes,
-                            SPOS(0, BCACHEFS_ROOT_INO, U32_MAX), 0);
-       k = bch2_btree_iter_peek_slot(&iter);
+       k = bch2_bkey_get_iter(trans, &iter, BTREE_ID_inodes,
+                              SPOS(0, BCACHEFS_ROOT_INO, U32_MAX), 0);
        ret = bkey_err(k);
        if (ret)
-               goto err;
+               return ret;
 
        if (!bkey_is_inode(k.k)) {
                bch_err(trans->c, "root inode not found");
@@ -1136,8 +1144,12 @@ int bch2_fs_recovery(struct bch_fs *c)
        }
 
        if (!c->opts.nochanges) {
-               if (c->sb.version < bcachefs_metadata_version_no_bps_in_alloc_keys) {
-                       bch_info(c, "version prior to no_bps_in_alloc_keys, upgrade and fsck required");
+               if (c->sb.version < bcachefs_metadata_required_upgrade_below) {
+                       bch_info(c, "version %s (%u) prior to %s (%u), upgrade and fsck required",
+                                bch2_metadata_versions[c->sb.version],
+                                c->sb.version,
+                                bch2_metadata_versions[bcachefs_metadata_required_upgrade_below],
+                                bcachefs_metadata_required_upgrade_below);
                        c->opts.version_upgrade = true;
                        c->opts.fsck            = true;
                        c->opts.fix_errors      = FSCK_OPT_YES;
index d8426e754cdf0cd9cef8ed9c71a26c367294987b..9430899a5a31633ddb56cb2fde5dae3f4869b29a 100644 (file)
@@ -30,12 +30,6 @@ int bch2_reflink_p_invalid(const struct bch_fs *c, struct bkey_s_c k,
 {
        struct bkey_s_c_reflink_p p = bkey_s_c_to_reflink_p(k);
 
-       if (bkey_val_bytes(p.k) != sizeof(*p.v)) {
-               prt_printf(err, "incorrect value size (%zu != %zu)",
-                      bkey_val_bytes(p.k), sizeof(*p.v));
-               return -EINVAL;
-       }
-
        if (c->sb.version >= bcachefs_metadata_version_reflink_p_fix &&
            le64_to_cpu(p.v->idx) < le32_to_cpu(p.v->front_pad)) {
                prt_printf(err, "idx < front_pad (%llu < %u)",
@@ -80,14 +74,6 @@ bool bch2_reflink_p_merge(struct bch_fs *c, struct bkey_s _l, struct bkey_s_c _r
 int bch2_reflink_v_invalid(const struct bch_fs *c, struct bkey_s_c k,
                           unsigned flags, struct printbuf *err)
 {
-       struct bkey_s_c_reflink_v r = bkey_s_c_to_reflink_v(k);
-
-       if (bkey_val_bytes(r.k) < sizeof(*r.v)) {
-               prt_printf(err, "incorrect value size (%zu < %zu)",
-                      bkey_val_bytes(r.k), sizeof(*r.v));
-               return -BCH_ERR_invalid_bkey;
-       }
-
        return bch2_bkey_ptrs_invalid(c, k, flags, err);
 }
 
@@ -133,12 +119,6 @@ int bch2_trans_mark_reflink_v(struct btree_trans *trans,
 int bch2_indirect_inline_data_invalid(const struct bch_fs *c, struct bkey_s_c k,
                                      unsigned flags, struct printbuf *err)
 {
-       if (bkey_val_bytes(k.k) < sizeof(struct bch_indirect_inline_data)) {
-               prt_printf(err, "incorrect value size (%zu < %zu)",
-                      bkey_val_bytes(k.k), sizeof(struct bch_indirect_inline_data));
-               return -BCH_ERR_invalid_bkey;
-       }
-
        return 0;
 }
 
index 2391037c2ece6ca5ad2ec1ac4c3f69bf7f352037..ba400188f5befeea949f69a95cefc5c876309e44 100644 (file)
@@ -14,6 +14,7 @@ bool bch2_reflink_p_merge(struct bch_fs *, struct bkey_s, struct bkey_s_c);
        .key_merge      = bch2_reflink_p_merge,                 \
        .trans_trigger  = bch2_trans_mark_reflink_p,            \
        .atomic_trigger = bch2_mark_reflink_p,                  \
+       .min_val_size   = 16,                                   \
 })
 
 int bch2_reflink_v_invalid(const struct bch_fs *, struct bkey_s_c,
@@ -29,6 +30,7 @@ int bch2_trans_mark_reflink_v(struct btree_trans *, enum btree_id, unsigned,
        .swab           = bch2_ptr_swab,                        \
        .trans_trigger  = bch2_trans_mark_reflink_v,            \
        .atomic_trigger = bch2_mark_extent,                     \
+       .min_val_size   = 8,                                    \
 })
 
 int bch2_indirect_inline_data_invalid(const struct bch_fs *, struct bkey_s_c,
@@ -44,6 +46,7 @@ int bch2_trans_mark_indirect_inline_data(struct btree_trans *,
        .key_invalid    = bch2_indirect_inline_data_invalid,    \
        .val_to_text    = bch2_indirect_inline_data_to_text,    \
        .trans_trigger  = bch2_trans_mark_indirect_inline_data, \
+       .min_val_size   = 8,                                    \
 })
 
 static inline const __le64 *bkey_refcount_c(struct bkey_s_c k)
index 6407d19edc0e5cc87be979376a906858d0137ae3..68121df2db669ddef47c34ce2aac0196ac7fdda3 100644 (file)
@@ -8,8 +8,75 @@
 #include "fs.h"
 #include "subvolume.h"
 
+static int bch2_subvolume_delete(struct btree_trans *, u32);
+
 /* Snapshot tree: */
 
+void bch2_snapshot_tree_to_text(struct printbuf *out, struct bch_fs *c,
+                               struct bkey_s_c k)
+{
+       struct bkey_s_c_snapshot_tree t = bkey_s_c_to_snapshot_tree(k);
+
+       prt_printf(out, "subvol %u root snapshot %u",
+                  le32_to_cpu(t.v->master_subvol),
+                  le32_to_cpu(t.v->root_snapshot));
+}
+
+int bch2_snapshot_tree_invalid(const struct bch_fs *c, struct bkey_s_c k,
+                              unsigned flags, struct printbuf *err)
+{
+       if (bkey_gt(k.k->p, POS(0, U32_MAX)) ||
+           bkey_lt(k.k->p, POS(0, 1))) {
+               prt_printf(err, "bad pos");
+               return -BCH_ERR_invalid_bkey;
+       }
+
+       return 0;
+}
+
+int bch2_snapshot_tree_lookup(struct btree_trans *trans, u32 id,
+                             struct bch_snapshot_tree *s)
+{
+       return bch2_bkey_get_val_typed(trans, BTREE_ID_snapshot_trees, POS(0, id),
+                                      BTREE_ITER_WITH_UPDATES, snapshot_tree, s);
+}
+
+static struct bkey_i_snapshot_tree *
+__snapshot_tree_create(struct btree_trans *trans)
+{
+       struct btree_iter iter;
+       int ret = bch2_bkey_get_empty_slot(trans, &iter,
+                       BTREE_ID_snapshot_trees, POS(0, U32_MAX));
+       struct bkey_i_snapshot_tree *s_t;
+
+       if (ret == -BCH_ERR_ENOSPC_btree_slot)
+               ret = -BCH_ERR_ENOSPC_snapshot_tree;
+       if (ret)
+               return ERR_PTR(ret);
+
+       s_t = bch2_bkey_alloc(trans, &iter, 0, snapshot_tree);
+       ret = PTR_ERR_OR_ZERO(s_t);
+       bch2_trans_iter_exit(trans, &iter);
+       return ret ? ERR_PTR(ret) : s_t;
+}
+
+static int snapshot_tree_create(struct btree_trans *trans,
+                               u32 root_id, u32 subvol_id, u32 *tree_id)
+{
+       struct bkey_i_snapshot_tree *n_tree =
+               __snapshot_tree_create(trans);
+
+       if (IS_ERR(n_tree))
+               return PTR_ERR(n_tree);
+
+       n_tree->v.master_subvol = cpu_to_le32(subvol_id);
+       n_tree->v.root_snapshot = cpu_to_le32(root_id);
+       *tree_id = n_tree->k.p.offset;
+       return 0;
+}
+
+/* Snapshot nodes: */
+
 void bch2_snapshot_to_text(struct printbuf *out, struct bch_fs *c,
                           struct bkey_s_c k)
 {
@@ -36,12 +103,6 @@ int bch2_snapshot_invalid(const struct bch_fs *c, struct bkey_s_c k,
                return -BCH_ERR_invalid_bkey;
        }
 
-       if (bkey_val_bytes(k.k) != sizeof(struct bch_snapshot)) {
-               prt_printf(err, "bad val size (%zu != %zu)",
-                      bkey_val_bytes(k.k), sizeof(struct bch_snapshot));
-               return -BCH_ERR_invalid_bkey;
-       }
-
        s = bkey_s_c_to_snapshot(k);
 
        id = le32_to_cpu(s.v->parent);
@@ -96,11 +157,13 @@ int bch2_mark_snapshot(struct btree_trans *trans,
                t->children[0]  = le32_to_cpu(s.v->children[0]);
                t->children[1]  = le32_to_cpu(s.v->children[1]);
                t->subvol       = BCH_SNAPSHOT_SUBVOL(s.v) ? le32_to_cpu(s.v->subvol) : 0;
+               t->tree         = le32_to_cpu(s.v->tree);
        } else {
                t->parent       = 0;
                t->children[0]  = 0;
                t->children[1]  = 0;
                t->subvol       = 0;
+               t->tree         = 0;
        }
 
        return 0;
@@ -109,20 +172,8 @@ int bch2_mark_snapshot(struct btree_trans *trans,
 static int snapshot_lookup(struct btree_trans *trans, u32 id,
                           struct bch_snapshot *s)
 {
-       struct btree_iter iter;
-       struct bkey_s_c k;
-       int ret;
-
-       bch2_trans_iter_init(trans, &iter, BTREE_ID_snapshots, POS(0, id),
-                            BTREE_ITER_WITH_UPDATES);
-       k = bch2_btree_iter_peek_slot(&iter);
-       ret = bkey_err(k) ?: k.k->type == KEY_TYPE_snapshot ? 0 : -ENOENT;
-
-       if (!ret)
-               *s = *bkey_s_c_to_snapshot(k).v;
-
-       bch2_trans_iter_exit(trans, &iter);
-       return ret;
+       return bch2_bkey_get_val_typed(trans, BTREE_ID_snapshots, POS(0, id),
+                                      BTREE_ITER_WITH_UPDATES, snapshot, s);
 }
 
 static int snapshot_live(struct btree_trans *trans, u32 id)
@@ -175,6 +226,266 @@ static int bch2_snapshot_set_equiv(struct btree_trans *trans, struct bkey_s_c k)
 }
 
 /* fsck: */
+
+static u32 bch2_snapshot_child(struct bch_fs *c, u32 id, unsigned child)
+{
+       return snapshot_t(c, id)->children[child];
+}
+
+static u32 bch2_snapshot_left_child(struct bch_fs *c, u32 id)
+{
+       return bch2_snapshot_child(c, id, 0);
+}
+
+static u32 bch2_snapshot_right_child(struct bch_fs *c, u32 id)
+{
+       return bch2_snapshot_child(c, id, 1);
+}
+
+static u32 bch2_snapshot_tree_next(struct bch_fs *c, u32 id)
+{
+       u32 n, parent;
+
+       n = bch2_snapshot_left_child(c, id);
+       if (n)
+               return n;
+
+       while ((parent = bch2_snapshot_parent(c, id))) {
+               n = bch2_snapshot_right_child(c, parent);
+               if (n && n != id)
+                       return n;
+               id = parent;
+       }
+
+       return 0;
+}
+
+static u32 bch2_snapshot_tree_oldest_subvol(struct bch_fs *c, u32 snapshot_root)
+{
+       u32 id = snapshot_root;
+       u32 subvol = 0, s;
+
+       while (id) {
+               s = snapshot_t(c, id)->subvol;
+
+               if (s && (!subvol || s < subvol))
+                       subvol = s;
+
+               id = bch2_snapshot_tree_next(c, id);
+       }
+
+       return subvol;
+}
+
+static int bch2_snapshot_tree_master_subvol(struct btree_trans *trans,
+                                           u32 snapshot_root, u32 *subvol_id)
+{
+       struct bch_fs *c = trans->c;
+       struct btree_iter iter;
+       struct bkey_s_c k;
+       struct bkey_s_c_subvolume s;
+       int ret;
+
+       for_each_btree_key_norestart(trans, iter, BTREE_ID_subvolumes, POS_MIN,
+                                    0, k, ret) {
+               if (k.k->type != KEY_TYPE_subvolume)
+                       continue;
+
+               s = bkey_s_c_to_subvolume(k);
+               if (!bch2_snapshot_is_ancestor(c, le32_to_cpu(s.v->snapshot), snapshot_root))
+                       continue;
+               if (!BCH_SUBVOLUME_SNAP(s.v)) {
+                       *subvol_id = s.k->p.offset;
+                       goto found;
+               }
+       }
+       ret = ret ?: -ENOENT;
+found:
+       bch2_trans_iter_exit(trans, &iter);
+
+       if (ret == -ENOENT) {
+               struct bkey_i_subvolume *s;
+
+               *subvol_id = bch2_snapshot_tree_oldest_subvol(c, snapshot_root);
+
+               s = bch2_bkey_get_mut_typed(trans, &iter,
+                                           BTREE_ID_subvolumes, POS(0, *subvol_id),
+                                           0, subvolume);
+               ret = PTR_ERR_OR_ZERO(s);
+               if (ret)
+                       return ret;
+
+               SET_BCH_SUBVOLUME_SNAP(&s->v, false);
+       }
+
+       return ret;
+}
+
+static int check_snapshot_tree(struct btree_trans *trans,
+                              struct btree_iter *iter,
+                              struct bkey_s_c k)
+{
+       struct bch_fs *c = trans->c;
+       struct bkey_s_c_snapshot_tree st;
+       struct bch_snapshot s;
+       struct bch_subvolume subvol;
+       struct printbuf buf = PRINTBUF;
+       u32 root_id;
+       int ret;
+
+       if (k.k->type != KEY_TYPE_snapshot_tree)
+               return 0;
+
+       st = bkey_s_c_to_snapshot_tree(k);
+       root_id = le32_to_cpu(st.v->root_snapshot);
+
+       ret = snapshot_lookup(trans, root_id, &s);
+       if (ret && !bch2_err_matches(ret, ENOENT))
+               goto err;
+
+       if (fsck_err_on(ret ||
+                       root_id != bch2_snapshot_root(c, root_id) ||
+                       st.k->p.offset != le32_to_cpu(s.tree),
+                       c,
+                       "snapshot tree points to missing/incorrect snapshot:\n  %s",
+                       (bch2_bkey_val_to_text(&buf, c, st.s_c), buf.buf))) {
+               ret = bch2_btree_delete_at(trans, iter, 0);
+               goto err;
+       }
+
+       ret = bch2_subvolume_get(trans, le32_to_cpu(st.v->master_subvol),
+                                false, 0, &subvol);
+       if (ret && !bch2_err_matches(ret, ENOENT))
+               goto err;
+
+       if (fsck_err_on(ret ||
+                       !bch2_snapshot_is_ancestor(c,
+                                                  le32_to_cpu(subvol.snapshot),
+                                                  root_id) ||
+                       !BCH_SUBVOLUME_SNAP(&subvol), c,
+                       "snapshot tree points to missing/incorrect subvolume:\n  %s",
+                       (printbuf_reset(&buf),
+                        bch2_bkey_val_to_text(&buf, c, st.s_c), buf.buf))) {
+               struct bkey_i_snapshot_tree *u;
+               u32 subvol_id;
+
+               ret = bch2_snapshot_tree_master_subvol(trans, root_id, &subvol_id);
+               if (ret)
+                       goto err;
+
+               u = bch2_bkey_make_mut_typed(trans, iter, k, 0, snapshot_tree);
+               ret = PTR_ERR_OR_ZERO(u);
+               if (ret)
+                       goto err;
+
+               u->v.master_subvol = cpu_to_le32(subvol_id);
+               st = snapshot_tree_i_to_s_c(u);
+       }
+err:
+fsck_err:
+       printbuf_exit(&buf);
+       return ret;
+}
+
+/*
+ * For each snapshot_tree, make sure it points to the root of a snapshot tree
+ * and that snapshot entry points back to it, or delete it.
+ *
+ * And, make sure it points to a subvolume within that snapshot tree, or correct
+ * it to point to the oldest subvolume within that snapshot tree.
+ */
+int bch2_fs_check_snapshot_trees(struct bch_fs *c)
+{
+       struct btree_iter iter;
+       struct bkey_s_c k;
+       int ret;
+
+       ret = bch2_trans_run(c,
+               for_each_btree_key_commit(&trans, iter,
+                       BTREE_ID_snapshot_trees, POS_MIN,
+                       BTREE_ITER_PREFETCH, k,
+                       NULL, NULL, BTREE_INSERT_LAZY_RW|BTREE_INSERT_NOFAIL,
+               check_snapshot_tree(&trans, &iter, k)));
+
+       if (ret)
+               bch_err(c, "error %i checking snapshot trees", ret);
+       return ret;
+}
+
+/*
+ * Look up snapshot tree for @tree_id and find root,
+ * make sure @snap_id is a descendent:
+ */
+static int snapshot_tree_ptr_good(struct btree_trans *trans,
+                                 u32 snap_id, u32 tree_id)
+{
+       struct bch_snapshot_tree s_t;
+       int ret = bch2_snapshot_tree_lookup(trans, tree_id, &s_t);
+
+       if (ret)
+               return ret;
+
+       return bch2_snapshot_is_ancestor(trans->c, snap_id, le32_to_cpu(s_t.root_snapshot));
+}
+
+/*
+ * snapshot_tree pointer was incorrect: look up root snapshot node, make sure
+ * its snapshot_tree pointer is correct (allocate new one if necessary), then
+ * update this node's pointer to root node's pointer:
+ */
+static int snapshot_tree_ptr_repair(struct btree_trans *trans,
+                                   struct btree_iter *iter,
+                                   struct bkey_s_c_snapshot *s)
+{
+       struct bch_fs *c = trans->c;
+       struct btree_iter root_iter;
+       struct bch_snapshot_tree s_t;
+       struct bkey_s_c_snapshot root;
+       struct bkey_i_snapshot *u;
+       u32 root_id = bch2_snapshot_root(c, s->k->p.offset), tree_id;
+       int ret;
+
+       root = bch2_bkey_get_iter_typed(trans, &root_iter,
+                              BTREE_ID_snapshots, POS(0, root_id),
+                              BTREE_ITER_WITH_UPDATES, snapshot);
+       ret = bkey_err(root);
+       if (ret)
+               goto err;
+
+       tree_id = le32_to_cpu(root.v->tree);
+
+       ret = bch2_snapshot_tree_lookup(trans, tree_id, &s_t);
+       if (ret)
+               return ret;
+
+       if (le32_to_cpu(s_t.root_snapshot) != root_id) {
+               u = bch2_bkey_make_mut_typed(trans, &root_iter, root.s_c, 0, snapshot);
+               ret =   PTR_ERR_OR_ZERO(u) ?:
+                       snapshot_tree_create(trans, root_id,
+                               bch2_snapshot_tree_oldest_subvol(c, root_id),
+                               &tree_id);
+               if (ret)
+                       goto err;
+
+               u->v.tree = cpu_to_le32(tree_id);
+               if (s->k->p.snapshot == root_id)
+                       *s = snapshot_i_to_s_c(u);
+       }
+
+       if (s->k->p.snapshot != root_id) {
+               u = bch2_bkey_make_mut_typed(trans, iter, s->s_c, 0, snapshot);
+               ret = PTR_ERR_OR_ZERO(u);
+               if (ret)
+                       goto err;
+
+               u->v.tree = cpu_to_le32(tree_id);
+               *s = snapshot_i_to_s_c(u);
+       }
+err:
+       bch2_trans_iter_exit(trans, &root_iter);
+       return ret;
+}
+
 static int check_snapshot(struct btree_trans *trans,
                          struct btree_iter *iter,
                          struct bkey_s_c k)
@@ -260,9 +571,22 @@ static int check_snapshot(struct btree_trans *trans,
                        ret = bch2_trans_update(trans, iter, &u->k_i, 0);
                        if (ret)
                                goto err;
+
+                       s = snapshot_i_to_s_c(u);
                }
        }
 
+       ret = snapshot_tree_ptr_good(trans, s.k->p.offset, le32_to_cpu(s.v->tree));
+       if (ret < 0)
+               goto err;
+
+       if (fsck_err_on(!ret, c, "snapshot points to missing/incorrect tree:\n  %s",
+                       (bch2_bkey_val_to_text(&buf, c, s.s_c), buf.buf))) {
+               ret = snapshot_tree_ptr_repair(trans, iter, &s);
+               if (ret)
+                       goto err;
+       }
+
        if (BCH_SNAPSHOT_DELETED(s.v))
                set_bit(BCH_FS_HAVE_DELETED_SNAPSHOTS, &c->flags);
 err:
@@ -273,23 +597,19 @@ fsck_err:
 
 int bch2_fs_check_snapshots(struct bch_fs *c)
 {
-       struct btree_trans trans;
        struct btree_iter iter;
        struct bkey_s_c k;
        int ret;
 
-       bch2_trans_init(&trans, c, 0, 0);
-
-       ret = for_each_btree_key_commit(&trans, iter,
+       ret = bch2_trans_run(c,
+               for_each_btree_key_commit(&trans, iter,
                        BTREE_ID_snapshots, POS_MIN,
                        BTREE_ITER_PREFETCH, k,
                        NULL, NULL, BTREE_INSERT_LAZY_RW|BTREE_INSERT_NOFAIL,
-               check_snapshot(&trans, &iter, k));
+               check_snapshot(&trans, &iter, k)));
 
        if (ret)
                bch_err(c, "error %i checking snapshots", ret);
-
-       bch2_trans_exit(&trans);
        return ret;
 }
 
@@ -297,10 +617,11 @@ static int check_subvol(struct btree_trans *trans,
                        struct btree_iter *iter,
                        struct bkey_s_c k)
 {
+       struct bch_fs *c = trans->c;
        struct bkey_s_c_subvolume subvol;
        struct bch_snapshot snapshot;
        unsigned snapid;
-       int ret;
+       int ret = 0;
 
        if (k.k->type != KEY_TYPE_subvolume)
                return 0;
@@ -310,21 +631,44 @@ static int check_subvol(struct btree_trans *trans,
        ret = snapshot_lookup(trans, snapid, &snapshot);
 
        if (ret == -ENOENT)
-               bch_err(trans->c, "subvolume %llu points to nonexistent snapshot %u",
+               bch_err(c, "subvolume %llu points to nonexistent snapshot %u",
                        k.k->p.offset, snapid);
        if (ret)
                return ret;
 
        if (BCH_SUBVOLUME_UNLINKED(subvol.v)) {
+               bch2_fs_lazy_rw(c);
+
                ret = bch2_subvolume_delete(trans, iter->pos.offset);
-               if (ret && !bch2_err_matches(ret, BCH_ERR_transaction_restart))
-                       bch_err(trans->c, "error deleting subvolume %llu: %s",
+               if (ret)
+                       bch_err(c, "error deleting subvolume %llu: %s",
                                iter->pos.offset, bch2_err_str(ret));
+               return ret ?: -BCH_ERR_transaction_restart_nested;
+       }
+
+       if (!BCH_SUBVOLUME_SNAP(subvol.v)) {
+               u32 snapshot_root = bch2_snapshot_root(c, le32_to_cpu(subvol.v->snapshot));
+               struct bch_snapshot_tree st;
+
+               ret = bch2_snapshot_tree_lookup(trans, snapshot_root, &st);
                if (ret)
                        return ret;
+
+               if (fsck_err_on(le32_to_cpu(st.master_subvol) != subvol.k->p.offset, c,
+                               "subvolume %llu is not set as snapshot but is not master subvolume",
+                               k.k->p.offset)) {
+                       struct bkey_i_subvolume *s =
+                               bch2_bkey_make_mut_typed(trans, iter, subvol.s_c, 0, subvolume);
+                       ret = PTR_ERR_OR_ZERO(s);
+                       if (ret)
+                               return ret;
+
+                       SET_BCH_SUBVOLUME_SNAP(&s->v, true);
+               }
        }
 
-       return 0;
+fsck_err:
+       return ret;
 }
 
 int bch2_fs_check_subvols(struct bch_fs *c)
@@ -381,13 +725,13 @@ static int bch2_snapshot_node_set_deleted(struct btree_trans *trans, u32 id)
        struct bkey_i_snapshot *s;
        int ret = 0;
 
-       bch2_trans_iter_init(trans, &iter, BTREE_ID_snapshots, POS(0, id),
-                            BTREE_ITER_INTENT);
-       s = bch2_bkey_get_mut_typed(trans, &iter, snapshot);
+       s = bch2_bkey_get_mut_typed(trans, &iter,
+                                   BTREE_ID_snapshots, POS(0, id),
+                                   0, snapshot);
        ret = PTR_ERR_OR_ZERO(s);
        if (unlikely(ret)) {
                bch2_fs_inconsistent_on(ret == -ENOENT, trans->c, "missing snapshot %u", id);
-               goto err;
+               return ret;
        }
 
        /* already deleted? */
@@ -397,10 +741,6 @@ static int bch2_snapshot_node_set_deleted(struct btree_trans *trans, u32 id)
        SET_BCH_SNAPSHOT_DELETED(&s->v, true);
        SET_BCH_SNAPSHOT_SUBVOL(&s->v, false);
        s->v.subvol = 0;
-
-       ret = bch2_trans_update(trans, &iter, &s->k_i, 0);
-       if (ret)
-               goto err;
 err:
        bch2_trans_iter_exit(trans, &iter);
        return ret;
@@ -408,27 +748,21 @@ err:
 
 static int bch2_snapshot_node_delete(struct btree_trans *trans, u32 id)
 {
+       struct bch_fs *c = trans->c;
        struct btree_iter iter, p_iter = (struct btree_iter) { NULL };
-       struct bkey_s_c k;
+       struct btree_iter tree_iter = (struct btree_iter) { NULL };
        struct bkey_s_c_snapshot s;
        u32 parent_id;
        unsigned i;
        int ret = 0;
 
-       bch2_trans_iter_init(trans, &iter, BTREE_ID_snapshots, POS(0, id),
-                            BTREE_ITER_INTENT);
-       k = bch2_btree_iter_peek_slot(&iter);
-       ret = bkey_err(k);
-       if (ret)
-               goto err;
+       s = bch2_bkey_get_iter_typed(trans, &iter, BTREE_ID_snapshots, POS(0, id),
+                                    BTREE_ITER_INTENT, snapshot);
+       ret = bkey_err(s);
+       bch2_fs_inconsistent_on(ret == -ENOENT, c, "missing snapshot %u", id);
 
-       if (k.k->type != KEY_TYPE_snapshot) {
-               bch2_fs_inconsistent(trans->c, "missing snapshot %u", id);
-               ret = -ENOENT;
+       if (ret)
                goto err;
-       }
-
-       s = bkey_s_c_to_snapshot(k);
 
        BUG_ON(!BCH_SNAPSHOT_DELETED(s.v));
        parent_id = le32_to_cpu(s.v->parent);
@@ -436,13 +770,12 @@ static int bch2_snapshot_node_delete(struct btree_trans *trans, u32 id)
        if (parent_id) {
                struct bkey_i_snapshot *parent;
 
-               bch2_trans_iter_init(trans, &p_iter, BTREE_ID_snapshots,
-                                    POS(0, parent_id),
-                                    BTREE_ITER_INTENT);
-               parent = bch2_bkey_get_mut_typed(trans, &p_iter, snapshot);
+               parent = bch2_bkey_get_mut_typed(trans, &p_iter,
+                                    BTREE_ID_snapshots, POS(0, parent_id),
+                                    0, snapshot);
                ret = PTR_ERR_OR_ZERO(parent);
                if (unlikely(ret)) {
-                       bch2_fs_inconsistent_on(ret == -ENOENT, trans->c, "missing snapshot %u", parent_id);
+                       bch2_fs_inconsistent_on(ret == -ENOENT, c, "missing snapshot %u", parent_id);
                        goto err;
                }
 
@@ -451,7 +784,7 @@ static int bch2_snapshot_node_delete(struct btree_trans *trans, u32 id)
                                break;
 
                if (i == 2)
-                       bch_err(trans->c, "snapshot %u missing child pointer to %u",
+                       bch_err(c, "snapshot %u missing child pointer to %u",
                                parent_id, id);
                else
                        parent->v.children[i] = 0;
@@ -460,29 +793,49 @@ static int bch2_snapshot_node_delete(struct btree_trans *trans, u32 id)
                    le32_to_cpu(parent->v.children[1]))
                        swap(parent->v.children[0],
                             parent->v.children[1]);
+       } else {
+               /*
+                * We're deleting the root of a snapshot tree: update the
+                * snapshot_tree entry to point to the new root, or delete it if
+                * this is the last snapshot ID in this tree:
+                */
+               struct bkey_i_snapshot_tree *s_t;
+
+               BUG_ON(s.v->children[1]);
 
-               ret = bch2_trans_update(trans, &p_iter, &parent->k_i, 0);
+               s_t = bch2_bkey_get_mut_typed(trans, &tree_iter,
+                               BTREE_ID_snapshot_trees, POS(0, le32_to_cpu(s.v->tree)),
+                               0, snapshot_tree);
+               ret = PTR_ERR_OR_ZERO(s_t);
                if (ret)
                        goto err;
+
+               if (s.v->children[0]) {
+                       s_t->v.root_snapshot = cpu_to_le32(s.v->children[0]);
+               } else {
+                       s_t->k.type = KEY_TYPE_deleted;
+                       set_bkey_val_u64s(&s_t->k, 0);
+               }
        }
 
        ret = bch2_btree_delete_at(trans, &iter, 0);
 err:
+       bch2_trans_iter_exit(trans, &tree_iter);
        bch2_trans_iter_exit(trans, &p_iter);
        bch2_trans_iter_exit(trans, &iter);
        return ret;
 }
 
-int bch2_snapshot_node_create(struct btree_trans *trans, u32 parent,
-                             u32 *new_snapids,
-                             u32 *snapshot_subvols,
-                             unsigned nr_snapids)
+static int create_snapids(struct btree_trans *trans, u32 parent, u32 tree,
+                         u32 *new_snapids,
+                         u32 *snapshot_subvols,
+                         unsigned nr_snapids)
 {
        struct btree_iter iter;
        struct bkey_i_snapshot *n;
        struct bkey_s_c k;
        unsigned i;
-       int ret = 0;
+       int ret;
 
        bch2_trans_iter_init(trans, &iter, BTREE_ID_snapshots,
                             POS_MIN, BTREE_ITER_INTENT);
@@ -502,7 +855,7 @@ int bch2_snapshot_node_create(struct btree_trans *trans, u32 parent,
                        goto err;
                }
 
-               n = bch2_bkey_alloc(trans, &iter, snapshot);
+               n = bch2_bkey_alloc(trans, &iter, 0, snapshot);
                ret = PTR_ERR_OR_ZERO(n);
                if (ret)
                        goto err;
@@ -510,47 +863,102 @@ int bch2_snapshot_node_create(struct btree_trans *trans, u32 parent,
                n->v.flags      = 0;
                n->v.parent     = cpu_to_le32(parent);
                n->v.subvol     = cpu_to_le32(snapshot_subvols[i]);
-               n->v.pad        = 0;
+               n->v.tree       = cpu_to_le32(tree);
                SET_BCH_SNAPSHOT_SUBVOL(&n->v, true);
 
-               ret   = bch2_trans_update(trans, &iter, &n->k_i, 0) ?:
-                       bch2_mark_snapshot(trans, BTREE_ID_snapshots, 0,
-                                          bkey_s_c_null, bkey_i_to_s_c(&n->k_i), 0);
+               ret = bch2_mark_snapshot(trans, BTREE_ID_snapshots, 0,
+                                        bkey_s_c_null, bkey_i_to_s_c(&n->k_i), 0);
                if (ret)
                        goto err;
 
                new_snapids[i]  = iter.pos.offset;
        }
+err:
+       bch2_trans_iter_exit(trans, &iter);
+       return ret;
+}
 
-       if (parent) {
-               bch2_btree_iter_set_pos(&iter, POS(0, parent));
-               n = bch2_bkey_get_mut_typed(trans, &iter, snapshot);
-               ret = PTR_ERR_OR_ZERO(n);
-               if (unlikely(ret)) {
-                       if (ret == -ENOENT)
-                               bch_err(trans->c, "snapshot %u not found", parent);
-                       goto err;
-               }
+/*
+ * Create new snapshot IDs as children of an existing snapshot ID:
+ */
+static int bch2_snapshot_node_create_children(struct btree_trans *trans, u32 parent,
+                             u32 *new_snapids,
+                             u32 *snapshot_subvols,
+                             unsigned nr_snapids)
+{
+       struct btree_iter iter;
+       struct bkey_i_snapshot *n_parent;
+       int ret = 0;
 
-               if (n->v.children[0] || n->v.children[1]) {
-                       bch_err(trans->c, "Trying to add child snapshot nodes to parent that already has children");
-                       ret = -EINVAL;
-                       goto err;
-               }
+       n_parent = bch2_bkey_get_mut_typed(trans, &iter,
+                       BTREE_ID_snapshots, POS(0, parent),
+                       0, snapshot);
+       ret = PTR_ERR_OR_ZERO(n_parent);
+       if (unlikely(ret)) {
+               if (ret == -ENOENT)
+                       bch_err(trans->c, "snapshot %u not found", parent);
+               return ret;
+       }
 
-               n->v.children[0] = cpu_to_le32(new_snapids[0]);
-               n->v.children[1] = cpu_to_le32(new_snapids[1]);
-               n->v.subvol = 0;
-               SET_BCH_SNAPSHOT_SUBVOL(&n->v, false);
-               ret   = bch2_trans_update(trans, &iter, &n->k_i, 0);
-               if (ret)
-                       goto err;
+       if (n_parent->v.children[0] || n_parent->v.children[1]) {
+               bch_err(trans->c, "Trying to add child snapshot nodes to parent that already has children");
+               ret = -EINVAL;
+               goto err;
        }
+
+       ret = create_snapids(trans, parent, le32_to_cpu(n_parent->v.tree),
+                            new_snapids, snapshot_subvols, nr_snapids);
+       if (ret)
+               goto err;
+
+       n_parent->v.children[0] = cpu_to_le32(new_snapids[0]);
+       n_parent->v.children[1] = cpu_to_le32(new_snapids[1]);
+       n_parent->v.subvol = 0;
+       SET_BCH_SNAPSHOT_SUBVOL(&n_parent->v, false);
 err:
        bch2_trans_iter_exit(trans, &iter);
        return ret;
 }
 
+/*
+ * Create a snapshot node that is the root of a new tree:
+ */
+static int bch2_snapshot_node_create_tree(struct btree_trans *trans,
+                             u32 *new_snapids,
+                             u32 *snapshot_subvols,
+                             unsigned nr_snapids)
+{
+       struct bkey_i_snapshot_tree *n_tree;
+       int ret;
+
+       n_tree = __snapshot_tree_create(trans);
+       ret =   PTR_ERR_OR_ZERO(n_tree) ?:
+               create_snapids(trans, 0, n_tree->k.p.offset,
+                            new_snapids, snapshot_subvols, nr_snapids);
+       if (ret)
+               return ret;
+
+       n_tree->v.master_subvol = cpu_to_le32(snapshot_subvols[0]);
+       n_tree->v.root_snapshot = cpu_to_le32(new_snapids[0]);
+       return 0;
+}
+
+int bch2_snapshot_node_create(struct btree_trans *trans, u32 parent,
+                             u32 *new_snapids,
+                             u32 *snapshot_subvols,
+                             unsigned nr_snapids)
+{
+       BUG_ON((parent == 0) != (nr_snapids == 1));
+       BUG_ON((parent != 0) != (nr_snapids == 2));
+
+       return parent
+               ? bch2_snapshot_node_create_children(trans, parent,
+                               new_snapids, snapshot_subvols, nr_snapids)
+               : bch2_snapshot_node_create_tree(trans,
+                               new_snapids, snapshot_subvols, nr_snapids);
+
+}
+
 static int snapshot_delete_key(struct btree_trans *trans,
                               struct btree_iter *iter,
                               struct bkey_s_c k,
@@ -743,12 +1151,6 @@ int bch2_subvolume_invalid(const struct bch_fs *c, struct bkey_s_c k,
                return -BCH_ERR_invalid_bkey;
        }
 
-       if (bkey_val_bytes(k.k) != sizeof(struct bch_subvolume)) {
-               prt_printf(err, "incorrect value size (%zu != %zu)",
-                      bkey_val_bytes(k.k), sizeof(struct bch_subvolume));
-               return -BCH_ERR_invalid_bkey;
-       }
-
        return 0;
 }
 
@@ -758,8 +1160,11 @@ void bch2_subvolume_to_text(struct printbuf *out, struct bch_fs *c,
        struct bkey_s_c_subvolume s = bkey_s_c_to_subvolume(k);
 
        prt_printf(out, "root %llu snapshot id %u",
-              le64_to_cpu(s.v->inode),
-              le32_to_cpu(s.v->snapshot));
+                  le64_to_cpu(s.v->inode),
+                  le32_to_cpu(s.v->snapshot));
+
+       if (bkey_val_bytes(s.k) > offsetof(struct bch_subvolume, parent))
+               prt_printf(out, " parent %u", le32_to_cpu(s.v->parent));
 }
 
 static __always_inline int
@@ -768,21 +1173,10 @@ bch2_subvolume_get_inlined(struct btree_trans *trans, unsigned subvol,
                           int iter_flags,
                           struct bch_subvolume *s)
 {
-       struct btree_iter iter;
-       struct bkey_s_c k;
-       int ret;
-
-       bch2_trans_iter_init(trans, &iter, BTREE_ID_subvolumes, POS(0, subvol),
-                            iter_flags);
-       k = bch2_btree_iter_peek_slot(&iter);
-       ret = bkey_err(k) ?: k.k->type == KEY_TYPE_subvolume ? 0 : -ENOENT;
-
-       if (ret == -ENOENT && inconsistent_if_not_found)
-               bch2_fs_inconsistent(trans->c, "missing subvolume %u", subvol);
-       if (!ret)
-               *s = *bkey_s_c_to_subvolume(k).v;
-
-       bch2_trans_iter_exit(trans, &iter);
+       int ret = bch2_bkey_get_val_typed(trans, BTREE_ID_subvolumes, POS(0, subvol),
+                                         iter_flags, subvolume, s);
+       bch2_fs_inconsistent_on(ret == -ENOENT && inconsistent_if_not_found,
+                               trans->c, "missing subvolume %u", subvol);
        return ret;
 }
 
@@ -806,47 +1200,87 @@ int bch2_snapshot_get_subvol(struct btree_trans *trans, u32 snapshot,
 int bch2_subvolume_get_snapshot(struct btree_trans *trans, u32 subvol,
                                u32 *snapid)
 {
-       struct bch_subvolume s;
+       struct btree_iter iter;
+       struct bkey_s_c k;
        int ret;
 
-       ret = bch2_subvolume_get_inlined(trans, subvol, true,
-                                        BTREE_ITER_CACHED|
-                                        BTREE_ITER_WITH_UPDATES,
-                                        &s);
-       if (!ret)
-               *snapid = le32_to_cpu(s.snapshot);
+       k = bch2_bkey_get_iter(trans, &iter, BTREE_ID_subvolumes, POS(0, subvol),
+                              BTREE_ITER_CACHED|
+                              BTREE_ITER_WITH_UPDATES);
+       ret = bkey_err(k) ?: k.k->type == KEY_TYPE_subvolume ? 0 : -ENOENT;
+
+       if (likely(!ret))
+               *snapid = le32_to_cpu(bkey_s_c_to_subvolume(k).v->snapshot);
+       else if (ret == -ENOENT)
+               bch2_fs_inconsistent(trans->c, "missing subvolume %u", subvol);
+       bch2_trans_iter_exit(trans, &iter);
        return ret;
 }
 
+static int bch2_subvolume_reparent(struct btree_trans *trans,
+                                  struct btree_iter *iter,
+                                  struct bkey_s_c k,
+                                  u32 old_parent, u32 new_parent)
+{
+       struct bkey_i_subvolume *s;
+       int ret;
+
+       if (k.k->type != KEY_TYPE_subvolume)
+               return 0;
+
+       if (bkey_val_bytes(k.k) > offsetof(struct bch_subvolume, parent) &&
+           le32_to_cpu(bkey_s_c_to_subvolume(k).v->parent) != old_parent)
+               return 0;
+
+       s = bch2_bkey_make_mut_typed(trans, iter, k, 0, subvolume);
+       ret = PTR_ERR_OR_ZERO(s);
+       if (ret)
+               return ret;
+
+       s->v.parent = cpu_to_le32(new_parent);
+       return 0;
+}
+
+/*
+ * Scan for subvolumes with parent @subvolid_to_delete, reparent:
+ */
+static int bch2_subvolumes_reparent(struct btree_trans *trans, u32 subvolid_to_delete)
+{
+       struct btree_iter iter;
+       struct bkey_s_c k;
+       struct bch_subvolume s;
+
+       return lockrestart_do(trans,
+                       bch2_subvolume_get(trans, subvolid_to_delete, true,
+                                  BTREE_ITER_CACHED, &s)) ?:
+               for_each_btree_key_commit(trans, iter,
+                               BTREE_ID_subvolumes, POS_MIN, BTREE_ITER_PREFETCH, k,
+                               NULL, NULL, BTREE_INSERT_NOFAIL,
+                       bch2_subvolume_reparent(trans, &iter, k,
+                                       subvolid_to_delete, le32_to_cpu(s.parent)));
+}
+
 /*
  * Delete subvolume, mark snapshot ID as deleted, queue up snapshot
  * deletion/cleanup:
  */
-int bch2_subvolume_delete(struct btree_trans *trans, u32 subvolid)
+static int __bch2_subvolume_delete(struct btree_trans *trans, u32 subvolid)
 {
        struct btree_iter iter;
-       struct bkey_s_c k;
        struct bkey_s_c_subvolume subvol;
        struct btree_trans_commit_hook *h;
        u32 snapid;
        int ret = 0;
 
-       bch2_trans_iter_init(trans, &iter, BTREE_ID_subvolumes,
-                            POS(0, subvolid),
-                            BTREE_ITER_CACHED|
-                            BTREE_ITER_INTENT);
-       k = bch2_btree_iter_peek_slot(&iter);
-       ret = bkey_err(k);
+       subvol = bch2_bkey_get_iter_typed(trans, &iter,
+                               BTREE_ID_subvolumes, POS(0, subvolid),
+                               BTREE_ITER_CACHED|BTREE_ITER_INTENT,
+                               subvolume);
+       ret = bkey_err(subvol);
+       bch2_fs_inconsistent_on(ret == -ENOENT, trans->c, "missing subvolume %u", subvolid);
        if (ret)
-               goto err;
-
-       if (k.k->type != KEY_TYPE_subvolume) {
-               bch2_fs_inconsistent(trans->c, "missing subvolume %u", subvolid);
-               ret = -EIO;
-               goto err;
-       }
+               return ret;
 
-       subvol = bkey_s_c_to_subvolume(k);
        snapid = le32_to_cpu(subvol.v->snapshot);
 
        ret = bch2_btree_delete_at(trans, &iter, 0);
@@ -869,6 +1303,13 @@ err:
        return ret;
 }
 
+static int bch2_subvolume_delete(struct btree_trans *trans, u32 subvolid)
+{
+       return bch2_subvolumes_reparent(trans, subvolid) ?:
+               commit_do(trans, NULL, NULL, BTREE_INSERT_NOFAIL,
+                         __bch2_subvolume_delete(trans, subvolid));
+}
+
 void bch2_subvolume_wait_for_pagecache_and_delete(struct work_struct *work)
 {
        struct bch_fs *c = container_of(work, struct bch_fs,
@@ -889,8 +1330,7 @@ void bch2_subvolume_wait_for_pagecache_and_delete(struct work_struct *work)
                bch2_evict_subvolume_inodes(c, &s);
 
                for (id = s.data; id < s.data + s.nr; id++) {
-                       ret = bch2_trans_do(c, NULL, NULL, BTREE_INSERT_NOFAIL,
-                                     bch2_subvolume_delete(&trans, *id));
+                       ret = bch2_trans_run(c, bch2_subvolume_delete(&trans, *id));
                        if (ret) {
                                bch_err(c, "error deleting subvolume %u: %s", *id, bch2_err_str(ret));
                                break;
@@ -938,32 +1378,25 @@ int bch2_subvolume_unlink(struct btree_trans *trans, u32 subvolid)
        struct subvolume_unlink_hook *h;
        int ret = 0;
 
-       bch2_trans_iter_init(trans, &iter, BTREE_ID_subvolumes,
-                            POS(0, subvolid),
-                            BTREE_ITER_CACHED|
-                            BTREE_ITER_INTENT);
-       n = bch2_bkey_get_mut_typed(trans, &iter, subvolume);
-       ret = PTR_ERR_OR_ZERO(n);
-       if (unlikely(ret)) {
-               bch2_fs_inconsistent_on(ret == -ENOENT, trans->c, "missing subvolume %u", subvolid);
-               goto err;
-       }
-
-       SET_BCH_SUBVOLUME_UNLINKED(&n->v, true);
-
-       ret = bch2_trans_update(trans, &iter, &n->k_i, 0);
-       if (ret)
-               goto err;
-
        h = bch2_trans_kmalloc(trans, sizeof(*h));
        ret = PTR_ERR_OR_ZERO(h);
        if (ret)
-               goto err;
+               return ret;
 
        h->h.fn         = bch2_subvolume_wait_for_pagecache_and_delete_hook;
        h->subvol       = subvolid;
        bch2_trans_commit_hook(trans, &h->h);
-err:
+
+       n = bch2_bkey_get_mut_typed(trans, &iter,
+                       BTREE_ID_subvolumes, POS(0, subvolid),
+                       BTREE_ITER_CACHED, subvolume);
+       ret = PTR_ERR_OR_ZERO(n);
+       if (unlikely(ret)) {
+               bch2_fs_inconsistent_on(ret == -ENOENT, trans->c, "missing subvolume %u", subvolid);
+               return ret;
+       }
+
+       SET_BCH_SUBVOLUME_UNLINKED(&n->v, true);
        bch2_trans_iter_exit(trans, &iter);
        return ret;
 }
@@ -978,42 +1411,28 @@ int bch2_subvolume_create(struct btree_trans *trans, u64 inode,
        struct btree_iter dst_iter, src_iter = (struct btree_iter) { NULL };
        struct bkey_i_subvolume *new_subvol = NULL;
        struct bkey_i_subvolume *src_subvol = NULL;
-       struct bkey_s_c k;
        u32 parent = 0, new_nodes[2], snapshot_subvols[2];
        int ret = 0;
 
-       for_each_btree_key(trans, dst_iter, BTREE_ID_subvolumes, SUBVOL_POS_MIN,
-                          BTREE_ITER_SLOTS|BTREE_ITER_INTENT, k, ret) {
-               if (bkey_gt(k.k->p, SUBVOL_POS_MAX))
-                       break;
-
-               /*
-                * bch2_subvolume_delete() doesn't flush the btree key cache -
-                * ideally it would but that's tricky
-                */
-               if (bkey_deleted(k.k) &&
-                   !bch2_btree_key_cache_find(c, BTREE_ID_subvolumes, dst_iter.pos))
-                       goto found_slot;
-       }
-
-       if (!ret)
+       ret = bch2_bkey_get_empty_slot(trans, &dst_iter,
+                               BTREE_ID_subvolumes, POS(0, U32_MAX));
+       if (ret == -BCH_ERR_ENOSPC_btree_slot)
                ret = -BCH_ERR_ENOSPC_subvolume_create;
-       goto err;
-found_slot:
+       if (ret)
+               return ret;
+
        snapshot_subvols[0] = dst_iter.pos.offset;
        snapshot_subvols[1] = src_subvolid;
 
        if (src_subvolid) {
                /* Creating a snapshot: */
 
-               bch2_trans_iter_init(trans, &src_iter, BTREE_ID_subvolumes,
-                                    POS(0, src_subvolid),
-                                    BTREE_ITER_CACHED|
-                                    BTREE_ITER_INTENT);
-               src_subvol = bch2_bkey_get_mut_typed(trans, &src_iter, subvolume);
+               src_subvol = bch2_bkey_get_mut_typed(trans, &src_iter,
+                               BTREE_ID_subvolumes, POS(0, src_subvolid),
+                               BTREE_ITER_CACHED, subvolume);
                ret = PTR_ERR_OR_ZERO(src_subvol);
                if (unlikely(ret)) {
-                       bch2_fs_inconsistent_on(ret == -ENOENT, trans->c,
+                       bch2_fs_inconsistent_on(ret == -ENOENT, c,
                                                "subvolume %u not found", src_subvolid);
                        goto err;
                }
@@ -1034,7 +1453,7 @@ found_slot:
                        goto err;
        }
 
-       new_subvol = bch2_bkey_alloc(trans, &dst_iter, subvolume);
+       new_subvol = bch2_bkey_alloc(trans, &dst_iter, 0, subvolume);
        ret = PTR_ERR_OR_ZERO(new_subvol);
        if (ret)
                goto err;
@@ -1042,11 +1461,12 @@ found_slot:
        new_subvol->v.flags     = 0;
        new_subvol->v.snapshot  = cpu_to_le32(new_nodes[0]);
        new_subvol->v.inode     = cpu_to_le64(inode);
+       new_subvol->v.parent    = cpu_to_le32(src_subvolid);
+       new_subvol->v.otime.lo  = cpu_to_le64(bch2_current_time(c));
+       new_subvol->v.otime.hi  = 0;
+
        SET_BCH_SUBVOLUME_RO(&new_subvol->v, ro);
        SET_BCH_SUBVOLUME_SNAP(&new_subvol->v, src_subvolid != 0);
-       ret = bch2_trans_update(trans, &dst_iter, &new_subvol->k_i, 0);
-       if (ret)
-               goto err;
 
        *new_subvolid   = new_subvol->k.p.offset;
        *new_snapshotid = new_nodes[0];
index df6657952e2f66922577319b1d0a80f64a9d7e61..1a39f713db87c8731778d297f045a946c6835904 100644 (file)
@@ -5,6 +5,18 @@
 #include "darray.h"
 #include "subvolume_types.h"
 
+void bch2_snapshot_tree_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
+int bch2_snapshot_tree_invalid(const struct bch_fs *, struct bkey_s_c,
+                              unsigned, struct printbuf *);
+
+#define bch2_bkey_ops_snapshot_tree ((struct bkey_ops) {       \
+       .key_invalid    = bch2_snapshot_tree_invalid,           \
+       .val_to_text    = bch2_snapshot_tree_to_text,           \
+       .min_val_size   = 8,                                    \
+})
+
+int bch2_snapshot_tree_lookup(struct btree_trans *, u32, struct bch_snapshot_tree *);
+
 void bch2_snapshot_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
 int bch2_snapshot_invalid(const struct bch_fs *, struct bkey_s_c,
                          unsigned, struct printbuf *);
@@ -15,6 +27,7 @@ int bch2_mark_snapshot(struct btree_trans *, enum btree_id, unsigned,
        .key_invalid    = bch2_snapshot_invalid,                \
        .val_to_text    = bch2_snapshot_to_text,                \
        .atomic_trigger = bch2_mark_snapshot,                   \
+       .min_val_size   = 24,                                   \
 })
 
 static inline struct snapshot_t *snapshot_t(struct bch_fs *c, u32 id)
@@ -27,6 +40,15 @@ static inline u32 bch2_snapshot_parent(struct bch_fs *c, u32 id)
        return snapshot_t(c, id)->parent;
 }
 
+static inline u32 bch2_snapshot_root(struct bch_fs *c, u32 id)
+{
+       u32 parent;
+
+       while ((parent = bch2_snapshot_parent(c, id)))
+               id = parent;
+       return id;
+}
+
 static inline u32 bch2_snapshot_equiv(struct bch_fs *c, u32 id)
 {
        return snapshot_t(c, id)->equiv;
@@ -106,6 +128,7 @@ static inline int snapshot_list_add(struct bch_fs *c, snapshot_id_list *s, u32 i
        return ret;
 }
 
+int bch2_fs_check_snapshot_trees(struct bch_fs *);
 int bch2_fs_check_snapshots(struct bch_fs *);
 int bch2_fs_check_subvols(struct bch_fs *);
 
@@ -119,6 +142,7 @@ void bch2_subvolume_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c)
 #define bch2_bkey_ops_subvolume ((struct bkey_ops) {           \
        .key_invalid    = bch2_subvolume_invalid,               \
        .val_to_text    = bch2_subvolume_to_text,               \
+       .min_val_size   = 16,                                   \
 })
 
 int bch2_subvolume_get(struct btree_trans *, unsigned,
@@ -134,7 +158,6 @@ int bch2_snapshot_node_create(struct btree_trans *, u32,
 int bch2_delete_dead_snapshots(struct bch_fs *);
 void bch2_delete_dead_snapshots_async(struct bch_fs *);
 
-int bch2_subvolume_delete(struct btree_trans *, u32);
 int bch2_subvolume_unlink(struct btree_trans *, u32);
 int bch2_subvolume_create(struct btree_trans *, u64, u32,
                          u32 *, u32 *, bool);
index aa49c45a35ab2d2ee853b3119f349bb189919a39..c6c1cbad97816c6cf0b8974b5e53d64cc2468c8f 100644 (file)
@@ -10,6 +10,7 @@ struct snapshot_t {
        u32                     parent;
        u32                     children[2];
        u32                     subvol; /* Nonzero only if a subvolume points to this node: */
+       u32                     tree;
        u32                     equiv;
 };
 
index 519df09917e3cbaed9472647968f1c4a556695f9..5a15d649d3575d35d7f7a9ec9d1fac08774adb46 100644 (file)
 #include "quota.h"
 #include "super-io.h"
 #include "super.h"
+#include "trace.h"
 #include "vstructs.h"
 #include "counters.h"
 
 #include <linux/backing-dev.h>
 #include <linux/sort.h>
 
-#include <trace/events/bcachefs.h>
-
 const char * const bch2_sb_fields[] = {
 #define x(name, nr)    #name,
        BCH_SB_FIELDS()
index 066a72a2f57261ff5f003c2b0929708f6c1ea1cb..696ea13861016b63d0dc8db30e4cd0471d5fd9cb 100644 (file)
@@ -22,6 +22,7 @@
 #include "checksum.h"
 #include "clock.h"
 #include "compress.h"
+#include "counters.h"
 #include "debug.h"
 #include "disk_groups.h"
 #include "ec.h"
@@ -47,7 +48,7 @@
 #include "super.h"
 #include "super-io.h"
 #include "sysfs.h"
-#include "counters.h"
+#include "trace.h"
 
 #include <linux/backing-dev.h>
 #include <linux/blkdev.h>
@@ -60,8 +61,6 @@
 #include <linux/sysfs.h>
 #include <crypto/hash.h>
 
-#include <trace/events/bcachefs.h>
-
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Kent Overstreet <kent.overstreet@gmail.com>");
 
index 6813147d73d36f52177b30d9d1943ca22b5eae37..d294b3d71b367cc14886857b6612efac8167ad2e 100644 (file)
@@ -13,4 +13,4 @@
 #include <linux/six.h>
 
 #define CREATE_TRACE_POINTS
-#include <trace/events/bcachefs.h>
+#include "trace.h"
similarity index 98%
rename from include/trace/events/bcachefs.h
rename to libbcachefs/trace.h
index e8cfae6bdbb4ac9750d729d1d7a6951117b3433b..8027c2a14199bc02db05fc73cd8b379b6cf2d330 100644 (file)
@@ -2,8 +2,8 @@
 #undef TRACE_SYSTEM
 #define TRACE_SYSTEM bcachefs
 
-#if !defined(_TRACE_BCACHE_H) || defined(TRACE_HEADER_MULTI_READ)
-#define _TRACE_BCACHE_H
+#if !defined(_TRACE_BCACHEFS_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_BCACHEFS_H
 
 #include <linux/tracepoint.h>
 
@@ -663,7 +663,7 @@ TRACE_EVENT(bucket_invalidate,
 /* Moving IO */
 
 TRACE_EVENT(bucket_evacuate,
-       TP_PROTO(struct bch_fs *c, struct bpos bucket),
+       TP_PROTO(struct bch_fs *c, struct bpos *bucket),
        TP_ARGS(c, bucket),
 
        TP_STRUCT__entry(
@@ -674,8 +674,8 @@ TRACE_EVENT(bucket_evacuate,
 
        TP_fast_assign(
                __entry->dev            = c->dev;
-               __entry->dev_idx        = bucket.inode;
-               __entry->bucket         = bucket.offset;
+               __entry->dev_idx        = bucket->inode;
+               __entry->bucket         = bucket->offset;
        ),
 
        TP_printk("%d:%d %u:%llu",
@@ -1250,7 +1250,13 @@ TRACE_EVENT(write_buffer_flush_slowpath,
        TP_printk("%zu/%zu", __entry->nr, __entry->size)
 );
 
-#endif /* _TRACE_BCACHE_H */
+#endif /* _TRACE_BCACHEFS_H */
 
 /* This part must be outside protection */
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH ../../fs/bcachefs
+
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE trace
+
 #include <trace/define_trace.h>
index c50473d4925d9dd436b409fe2d8fc3a76f9dc4dd..dfc55fe4c7d17e1f57de2f823ad1b6dc0104e7d0 100644 (file)
@@ -761,10 +761,10 @@ void bch2_bio_map(struct bio *bio, void *base, size_t size)
        }
 }
 
-int _bch2_bio_alloc_pages(struct bio *bio, size_t size, gfp_t gfp_mask)
+int bch2_bio_alloc_pages(struct bio *bio, size_t size, gfp_t gfp_mask)
 {
        while (size) {
-               struct page *page = _alloc_pages(gfp_mask, 0);
+               struct page *page = alloc_pages(gfp_mask, 0);
                unsigned len = min_t(size_t, PAGE_SIZE, size);
 
                if (!page)
index ecfe54012e3d0306b04e0c7c7e5ffa790b0a4742..9eb86c58e5509d5d69efb52ef0f62562bea75026 100644 (file)
@@ -60,14 +60,12 @@ static inline void vpfree(void *p, size_t size)
                free_pages((unsigned long) p, get_order(size));
 }
 
-static inline void *_vpmalloc(size_t size, gfp_t gfp_mask)
+static inline void *vpmalloc(size_t size, gfp_t gfp_mask)
 {
-       return (void *) _get_free_pages(gfp_mask|__GFP_NOWARN,
+       return (void *) __get_free_pages(gfp_mask|__GFP_NOWARN,
                                         get_order(size)) ?:
                __vmalloc(size, gfp_mask);
 }
-#define vpmalloc(_size, _gfp)                  \
-       alloc_hooks(_vpmalloc(_size, _gfp), void *, NULL)
 
 static inline void kvpfree(void *p, size_t size)
 {
@@ -77,14 +75,12 @@ static inline void kvpfree(void *p, size_t size)
                vpfree(p, size);
 }
 
-static inline void *_kvpmalloc(size_t size, gfp_t gfp_mask)
+static inline void *kvpmalloc(size_t size, gfp_t gfp_mask)
 {
        return size < PAGE_SIZE
-               ? _kmalloc(size, gfp_mask)
-               : _vpmalloc(size, gfp_mask);
+               ? kmalloc(size, gfp_mask)
+               : vpmalloc(size, gfp_mask);
 }
-#define kvpmalloc(_size, _gfp)                 \
-       alloc_hooks(_kvpmalloc(_size, _gfp), void *, NULL)
 
 int mempool_init_kvpmalloc_pool(mempool_t *, int, size_t);
 
@@ -534,9 +530,7 @@ static inline unsigned fract_exp_two(unsigned x, unsigned fract_bits)
 }
 
 void bch2_bio_map(struct bio *bio, void *base, size_t);
-int _bch2_bio_alloc_pages(struct bio *, size_t, gfp_t);
-#define bch2_bio_alloc_pages(_bio, _size, _gfp)                                \
-       alloc_hooks(_bch2_bio_alloc_pages(_bio, _size, _gfp), int, -ENOMEM)
+int bch2_bio_alloc_pages(struct bio *, size_t, gfp_t);
 
 static inline sector_t bdev_sectors(struct block_device *bdev)
 {
@@ -843,4 +837,11 @@ static inline int u8_cmp(u8 l, u8 r)
        return cmp_int(l, r);
 }
 
+#include <linux/uuid.h>
+
+static inline int uuid_le_cmp(const uuid_le u1, const uuid_le u2)
+{
+       return memcmp(&u1, &u2, sizeof(uuid_le));
+}
+
 #endif /* _BCACHEFS_UTIL_H */
index 9f77bb2ecf5fe741aae306f3dee90efc94dc17b1..4fc6e065d4212c31962d502dd41e95a0b603e631 100644 (file)
@@ -75,12 +75,6 @@ int bch2_xattr_invalid(const struct bch_fs *c, struct bkey_s_c k,
        const struct xattr_handler *handler;
        struct bkey_s_c_xattr xattr = bkey_s_c_to_xattr(k);
 
-       if (bkey_val_bytes(k.k) < sizeof(struct bch_xattr)) {
-               prt_printf(err, "incorrect value size (%zu < %zu)",
-                      bkey_val_bytes(k.k), sizeof(*xattr.v));
-               return -BCH_ERR_invalid_bkey;
-       }
-
        if (bkey_val_u64s(k.k) <
            xattr_val_u64s(xattr.v->x_name_len,
                           le16_to_cpu(xattr.v->x_val_len))) {
@@ -378,7 +372,7 @@ static int bch2_xattr_get_handler(const struct xattr_handler *handler,
 }
 
 static int bch2_xattr_set_handler(const struct xattr_handler *handler,
-                                 struct user_namespace *mnt_userns,
+                                 struct mnt_idmap *idmap,
                                  struct dentry *dentry, struct inode *vinode,
                                  const char *name, const void *value,
                                  size_t size, int flags)
@@ -517,7 +511,7 @@ static int inode_opt_set_fn(struct bch_inode_info *inode,
 }
 
 static int bch2_xattr_bcachefs_set(const struct xattr_handler *handler,
-                                  struct user_namespace *mnt_userns,
+                                  struct mnt_idmap *idmap,
                                   struct dentry *dentry, struct inode *vinode,
                                   const char *name, const void *value,
                                   size_t size, int flags)
index 1a4cff3a9d962aaa994a0ce554a3c2fdb4e4fab0..b3e16729bcbba472f15302a3c3bb0b560330c8ce 100644 (file)
@@ -12,6 +12,7 @@ void bch2_xattr_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
 #define bch2_bkey_ops_xattr ((struct bkey_ops) {       \
        .key_invalid    = bch2_xattr_invalid,           \
        .val_to_text    = bch2_xattr_to_text,           \
+       .min_val_size   = 8,                            \
 })
 
 static inline unsigned xattr_val_u64s(unsigned name_len, unsigned val_len)
index 36106b5e2e4d4a93ad28fbb66bb2efec550b0d03..64697ea65863c8f8d804b4c5dfbc6c2c1f49850a 100644 (file)
@@ -46,6 +46,7 @@ pub enum BkeyValC<'a> {
     backpointer(&'a c::bch_backpointer),
     inode_v3(&'a c::bch_inode_v3),
     bucket_gens(&'a c::bch_bucket_gens),
+    snapshot_tree(&'a c::bch_snapshot_tree),
 }
 
 impl<'a, 'b> BkeySC<'a> {
@@ -94,6 +95,7 @@ impl<'a, 'b> BkeySC<'a> {
             KEY_TYPE_backpointer            => backpointer(unsafe { transmute(self.v) }),
             KEY_TYPE_inode_v3               => inode_v3(unsafe { transmute(self.v) }),
             KEY_TYPE_bucket_gens            => bucket_gens(unsafe { transmute(self.v) }),
+            KEY_TYPE_snapshot_tree          => snapshot_tree(unsafe { transmute(self.v) }),
             KEY_TYPE_MAX                    => unreachable!(),
         }
     }