]> git.sesse.net Git - bcachefs-tools-debian/blobdiff - libbcachefs/btree_io.c
New upstream snapshot
[bcachefs-tools-debian] / libbcachefs / btree_io.c
index 682f599cbef588d6a912cceaf7627b73a12d48d1..ec1290fa9138191cf845502883aff65266147e07 100644 (file)
@@ -24,8 +24,7 @@
 
 static void verify_no_dups(struct btree *b,
                           struct bkey_packed *start,
-                          struct bkey_packed *end,
-                          bool extents)
+                          struct bkey_packed *end)
 {
 #ifdef CONFIG_BCACHEFS_DEBUG
        struct bkey_packed *k, *p;
@@ -33,16 +32,13 @@ static void verify_no_dups(struct btree *b,
        if (start == end)
                return;
 
-       for (p = start, k = bkey_next_skip_noops(start, end);
+       for (p = start, k = bkey_next(start);
             k != end;
-            p = k, k = bkey_next_skip_noops(k, end)) {
+            p = k, k = bkey_next(k)) {
                struct bkey l = bkey_unpack_key(b, p);
                struct bkey r = bkey_unpack_key(b, k);
 
-               BUG_ON(extents
-                      ? bkey_cmp(l.p, bkey_start_pos(&r)) > 0
-                      : bkey_cmp(l.p, bkey_start_pos(&r)) >= 0);
-               //BUG_ON(bkey_cmp_packed(&b->format, p, k) >= 0);
+               BUG_ON(bpos_cmp(l.p, bkey_start_pos(&r)) >= 0);
        }
 #endif
 }
@@ -51,9 +47,7 @@ static void set_needs_whiteout(struct bset *i, int v)
 {
        struct bkey_packed *k;
 
-       for (k = i->start;
-            k != vstruct_last(i);
-            k = bkey_next_skip_noops(k, vstruct_last(i)))
+       for (k = i->start; k != vstruct_last(i); k = bkey_next(k))
                k->needs_whiteout = v;
 }
 
@@ -102,14 +96,14 @@ static void sort_bkey_ptrs(const struct btree *bt,
                        break;
 
                for (b = a; c = 2 * b + 1, (d = c + 1) < n;)
-                       b = bkey_cmp_packed(bt,
+                       b = bch2_bkey_cmp_packed(bt,
                                            ptrs[c],
                                            ptrs[d]) >= 0 ? c : d;
                if (d == n)
                        b = c;
 
                while (b != a &&
-                      bkey_cmp_packed(bt,
+                      bch2_bkey_cmp_packed(bt,
                                       ptrs[a],
                                       ptrs[b]) >= 0)
                        b = (b - 1) / 2;
@@ -150,8 +144,7 @@ static void bch2_sort_whiteouts(struct bch_fs *c, struct btree *b)
        }
 
        verify_no_dups(b, new_whiteouts,
-                      (void *) ((u64 *) new_whiteouts + b->whiteout_u64s),
-                      btree_node_old_extent_overwrite(b));
+                      (void *) ((u64 *) new_whiteouts + b->whiteout_u64s));
 
        memcpy_u64s(unwritten_whiteouts_start(c, b),
                    new_whiteouts, b->whiteout_u64s);
@@ -176,144 +169,6 @@ static bool should_compact_bset(struct btree *b, struct bset_tree *t,
        }
 }
 
-static bool bch2_compact_extent_whiteouts(struct bch_fs *c,
-                                         struct btree *b,
-                                         enum compact_mode mode)
-{
-       const struct bkey_format *f = &b->format;
-       struct bset_tree *t;
-       struct bkey_packed *whiteouts = NULL;
-       struct bkey_packed *u_start, *u_pos;
-       struct sort_iter sort_iter;
-       unsigned bytes, whiteout_u64s = 0, u64s;
-       bool used_mempool, compacting = false;
-
-       BUG_ON(!btree_node_is_extents(b));
-
-       for_each_bset(b, t)
-               if (should_compact_bset(b, t, whiteout_u64s != 0, mode))
-                       whiteout_u64s += bset_dead_u64s(b, t);
-
-       if (!whiteout_u64s)
-               return false;
-
-       bch2_sort_whiteouts(c, b);
-
-       sort_iter_init(&sort_iter, b);
-
-       whiteout_u64s += b->whiteout_u64s;
-       bytes = whiteout_u64s * sizeof(u64);
-
-       whiteouts = btree_bounce_alloc(c, bytes, &used_mempool);
-       u_start = u_pos = whiteouts;
-
-       memcpy_u64s(u_pos, unwritten_whiteouts_start(c, b),
-                   b->whiteout_u64s);
-       u_pos = (void *) u_pos + b->whiteout_u64s * sizeof(u64);
-
-       sort_iter_add(&sort_iter, u_start, u_pos);
-
-       for_each_bset(b, t) {
-               struct bset *i = bset(b, t);
-               struct bkey_packed *k, *n, *out, *start, *end;
-               struct btree_node_entry *src = NULL, *dst = NULL;
-
-               if (t != b->set && !bset_written(b, i)) {
-                       src = container_of(i, struct btree_node_entry, keys);
-                       dst = max(write_block(b),
-                                 (void *) btree_bkey_last(b, t - 1));
-               }
-
-               if (src != dst)
-                       compacting = true;
-
-               if (!should_compact_bset(b, t, compacting, mode)) {
-                       if (src != dst) {
-                               memmove(dst, src, sizeof(*src) +
-                                       le16_to_cpu(src->keys.u64s) *
-                                       sizeof(u64));
-                               i = &dst->keys;
-                               set_btree_bset(b, t, i);
-                       }
-                       continue;
-               }
-
-               compacting = true;
-               u_start = u_pos;
-               start = i->start;
-               end = vstruct_last(i);
-
-               if (src != dst) {
-                       memmove(dst, src, sizeof(*src));
-                       i = &dst->keys;
-                       set_btree_bset(b, t, i);
-               }
-
-               out = i->start;
-
-               for (k = start; k != end; k = n) {
-                       n = bkey_next_skip_noops(k, end);
-
-                       if (bkey_deleted(k))
-                               continue;
-
-                       BUG_ON(bkey_whiteout(k) &&
-                              k->needs_whiteout &&
-                              bkey_written(b, k));
-
-                       if (bkey_whiteout(k) && !k->needs_whiteout)
-                               continue;
-
-                       if (bkey_whiteout(k)) {
-                               memcpy_u64s(u_pos, k, bkeyp_key_u64s(f, k));
-                               set_bkeyp_val_u64s(f, u_pos, 0);
-                               u_pos = bkey_next(u_pos);
-                       } else {
-                               bkey_copy(out, k);
-                               out = bkey_next(out);
-                       }
-               }
-
-               sort_iter_add(&sort_iter, u_start, u_pos);
-
-               i->u64s = cpu_to_le16((u64 *) out - i->_data);
-               set_btree_bset_end(b, t);
-               bch2_bset_set_no_aux_tree(b, t);
-       }
-
-       b->whiteout_u64s = (u64 *) u_pos - (u64 *) whiteouts;
-
-       BUG_ON((void *) unwritten_whiteouts_start(c, b) <
-              (void *) btree_bkey_last(b, bset_tree_last(b)));
-
-       u64s = bch2_sort_extent_whiteouts(unwritten_whiteouts_start(c, b),
-                                         &sort_iter);
-
-       BUG_ON(u64s > b->whiteout_u64s);
-       BUG_ON(u_pos != whiteouts && !u64s);
-
-       if (u64s != b->whiteout_u64s) {
-               void *src = unwritten_whiteouts_start(c, b);
-
-               b->whiteout_u64s = u64s;
-               memmove_u64s_up(unwritten_whiteouts_start(c, b), src, u64s);
-       }
-
-       verify_no_dups(b,
-                      unwritten_whiteouts_start(c, b),
-                      unwritten_whiteouts_end(c, b),
-                      true);
-
-       btree_bounce_free(c, bytes, used_mempool, whiteouts);
-
-       bch2_btree_build_aux_trees(b);
-
-       bch_btree_keys_u64s_remaining(c, b);
-       bch2_verify_btree_nr_keys(b);
-
-       return true;
-}
-
 static bool bch2_drop_whiteouts(struct btree *b, enum compact_mode mode)
 {
        struct bset_tree *t;
@@ -356,9 +211,9 @@ static bool bch2_drop_whiteouts(struct btree *b, enum compact_mode mode)
                out = i->start;
 
                for (k = start; k != end; k = n) {
-                       n = bkey_next_skip_noops(k, end);
+                       n = bkey_next(k);
 
-                       if (!bkey_whiteout(k)) {
+                       if (!bkey_deleted(k)) {
                                bkey_copy(out, k);
                                out = bkey_next(out);
                        } else {
@@ -382,9 +237,7 @@ static bool bch2_drop_whiteouts(struct btree *b, enum compact_mode mode)
 bool bch2_compact_whiteouts(struct bch_fs *c, struct btree *b,
                            enum compact_mode mode)
 {
-       return !btree_node_old_extent_overwrite(b)
-               ? bch2_drop_whiteouts(b, mode)
-               : bch2_compact_extent_whiteouts(c, b, mode);
+       return bch2_drop_whiteouts(b, mode);
 }
 
 static void btree_node_sort(struct bch_fs *c, struct btree *b,
@@ -422,14 +275,7 @@ static void btree_node_sort(struct bch_fs *c, struct btree *b,
 
        start_time = local_clock();
 
-       if (btree_node_old_extent_overwrite(b))
-               filter_whiteouts = bset_written(b, start_bset);
-
-       u64s = (btree_node_old_extent_overwrite(b)
-               ? bch2_sort_extents
-               : bch2_sort_keys)(out->keys.start,
-                                 &sort_iter,
-                                 filter_whiteouts);
+       u64s = bch2_sort_keys(out->keys.start, &sort_iter, filter_whiteouts);
 
        out->keys.u64s = cpu_to_le16(u64s);
 
@@ -597,18 +443,30 @@ void bch2_btree_init_next(struct bch_fs *c, struct btree *b,
                bch2_btree_iter_reinit_node(iter, b);
 }
 
-static void btree_err_msg(struct printbuf *out, struct bch_fs *c,
-                         struct btree *b, struct bset *i,
-                         unsigned offset, int write)
+static void btree_pos_to_text(struct printbuf *out, struct bch_fs *c,
+                         struct btree *b)
 {
-       pr_buf(out, "error validating btree node %sat btree %u level %u/%u\n"
-              "pos ",
-              write ? "before write " : "",
-              b->c.btree_id, b->c.level,
+       pr_buf(out, "%s level %u/%u\n  ",
+              bch2_btree_ids[b->c.btree_id],
+              b->c.level,
               c->btree_roots[b->c.btree_id].level);
        bch2_bkey_val_to_text(out, c, bkey_i_to_s_c(&b->key));
+}
 
-       pr_buf(out, " node offset %u", b->written);
+static void btree_err_msg(struct printbuf *out, struct bch_fs *c,
+                         struct bch_dev *ca,
+                         struct btree *b, struct bset *i,
+                         unsigned offset, int write)
+{
+       pr_buf(out, "error validating btree node ");
+       if (write)
+               pr_buf(out, "before write ");
+       if (ca)
+               pr_buf(out, "on %s ", ca->name);
+       pr_buf(out, "at btree ");
+       btree_pos_to_text(out, c, b);
+
+       pr_buf(out, "\n  node offset %u", b->written);
        if (i)
                pr_buf(out, " bset u64s %u", le16_to_cpu(i->u64s));
 }
@@ -624,25 +482,30 @@ enum btree_validate_ret {
        BTREE_RETRY_READ = 64,
 };
 
-#define btree_err(type, c, b, i, msg, ...)                             \
+#define btree_err(type, c, ca, b, i, msg, ...)                         \
 ({                                                                     \
        __label__ out;                                                  \
        char _buf[300];                                                 \
+       char *_buf2 = _buf;                                             \
        struct printbuf out = PBUF(_buf);                               \
                                                                        \
-       btree_err_msg(&out, c, b, i, b->written, write);                \
+       _buf2 = kmalloc(4096, GFP_ATOMIC);                              \
+       if (_buf2)                                                      \
+               out = _PBUF(_buf2, 4986);                               \
+                                                                       \
+       btree_err_msg(&out, c, ca, b, i, b->written, write);            \
        pr_buf(&out, ": " msg, ##__VA_ARGS__);                          \
                                                                        \
        if (type == BTREE_ERR_FIXABLE &&                                \
            write == READ &&                                            \
            !test_bit(BCH_FS_INITIAL_GC_DONE, &c->flags)) {             \
-               mustfix_fsck_err(c, "%s", _buf);                        \
+               mustfix_fsck_err(c, "%s", _buf2);                       \
                goto out;                                               \
        }                                                               \
                                                                        \
        switch (write) {                                                \
        case READ:                                                      \
-               bch_err(c, "%s", _buf);                                 \
+               bch_err(c, "%s", _buf2);                                        \
                                                                        \
                switch (type) {                                         \
                case BTREE_ERR_FIXABLE:                                 \
@@ -663,7 +526,7 @@ enum btree_validate_ret {
                }                                                       \
                break;                                                  \
        case WRITE:                                                     \
-               bch_err(c, "corrupt metadata before write: %s", _buf);  \
+               bch_err(c, "corrupt metadata before write: %s", _buf2); \
                                                                        \
                if (bch2_fs_inconsistent(c)) {                          \
                        ret = BCH_FSCK_ERRORS_NOT_FIXED;                \
@@ -672,34 +535,62 @@ enum btree_validate_ret {
                break;                                                  \
        }                                                               \
 out:                                                                   \
+       if (_buf2 != _buf)                                              \
+               kfree(_buf2);                                           \
        true;                                                           \
 })
 
 #define btree_err_on(cond, ...)        ((cond) ? btree_err(__VA_ARGS__) : false)
 
-static int validate_bset(struct bch_fs *c, struct btree *b,
-                        struct bset *i, unsigned sectors,
-                        int write, bool have_retry)
+static int validate_bset(struct bch_fs *c, struct bch_dev *ca,
+                        struct btree *b, struct bset *i,
+                        unsigned sectors, int write, bool have_retry)
 {
        unsigned version = le16_to_cpu(i->version);
        const char *err;
+       char buf1[100];
+       char buf2[100];
        int ret = 0;
 
        btree_err_on((version != BCH_BSET_VERSION_OLD &&
                      version < bcachefs_metadata_version_min) ||
                     version >= bcachefs_metadata_version_max,
-                    BTREE_ERR_FATAL, c, b, i,
+                    BTREE_ERR_FATAL, c, ca, b, i,
                     "unsupported bset version");
 
+       if (btree_err_on(version < c->sb.version_min,
+                        BTREE_ERR_FIXABLE, c, NULL, b, i,
+                        "bset version %u older than superblock version_min %u",
+                        version, c->sb.version_min)) {
+               mutex_lock(&c->sb_lock);
+               c->disk_sb.sb->version_min = cpu_to_le16(version);
+               bch2_write_super(c);
+               mutex_unlock(&c->sb_lock);
+       }
+
+       if (btree_err_on(version > c->sb.version,
+                        BTREE_ERR_FIXABLE, c, NULL, b, i,
+                        "bset version %u newer than superblock version %u",
+                        version, c->sb.version)) {
+               mutex_lock(&c->sb_lock);
+               c->disk_sb.sb->version = cpu_to_le16(version);
+               bch2_write_super(c);
+               mutex_unlock(&c->sb_lock);
+       }
+
+       btree_err_on(BSET_SEPARATE_WHITEOUTS(i),
+                    BTREE_ERR_FATAL, c, ca, b, i,
+                    "BSET_SEPARATE_WHITEOUTS no longer supported");
+
        if (btree_err_on(b->written + sectors > c->opts.btree_node_size,
-                        BTREE_ERR_FIXABLE, c, b, i,
+                        BTREE_ERR_FIXABLE, c, ca, b, i,
                         "bset past end of btree node")) {
                i->u64s = 0;
                return 0;
        }
 
        btree_err_on(b->written && !i->u64s,
-                    BTREE_ERR_FIXABLE, c, b, i,
+                    BTREE_ERR_FIXABLE, c, ca, b, i,
                     "empty bset");
 
        if (!b->written) {
@@ -713,24 +604,18 @@ static int validate_bset(struct bch_fs *c, struct btree *b,
 
                        /* XXX endianness */
                        btree_err_on(bp->seq != bn->keys.seq,
-                                    BTREE_ERR_MUST_RETRY, c, b, NULL,
+                                    BTREE_ERR_MUST_RETRY, c, ca, b, NULL,
                                     "incorrect sequence number (wrong btree node)");
                }
 
                btree_err_on(BTREE_NODE_ID(bn) != b->c.btree_id,
-                            BTREE_ERR_MUST_RETRY, c, b, i,
+                            BTREE_ERR_MUST_RETRY, c, ca, b, i,
                             "incorrect btree id");
 
                btree_err_on(BTREE_NODE_LEVEL(bn) != b->c.level,
-                            BTREE_ERR_MUST_RETRY, c, b, i,
+                            BTREE_ERR_MUST_RETRY, c, ca, b, i,
                             "incorrect level");
 
-               if (BSET_BIG_ENDIAN(i) != CPU_BIG_ENDIAN) {
-                       u64 *p = (u64 *) &bn->ptr;
-
-                       *p = swab64(*p);
-               }
-
                if (!write)
                        compat_btree_node(b->c.level, b->c.btree_id, version,
                                          BSET_BIG_ENDIAN(i), write, bn);
@@ -739,42 +624,30 @@ static int validate_bset(struct bch_fs *c, struct btree *b,
                        struct bch_btree_ptr_v2 *bp =
                                &bkey_i_to_btree_ptr_v2(&b->key)->v;
 
-                       btree_err_on(bkey_cmp(b->data->min_key, bp->min_key),
-                                    BTREE_ERR_MUST_RETRY, c, b, NULL,
-                                    "incorrect min_key: got %llu:%llu should be %llu:%llu",
-                                    b->data->min_key.inode,
-                                    b->data->min_key.offset,
-                                    bp->min_key.inode,
-                                    bp->min_key.offset);
+                       if (BTREE_PTR_RANGE_UPDATED(bp)) {
+                               b->data->min_key = bp->min_key;
+                               b->data->max_key = b->key.k.p;
+                       }
+
+                       btree_err_on(bpos_cmp(b->data->min_key, bp->min_key),
+                                    BTREE_ERR_MUST_RETRY, c, ca, b, NULL,
+                                    "incorrect min_key: got %s should be %s",
+                                    (bch2_bpos_to_text(&PBUF(buf1), bn->min_key), buf1),
+                                    (bch2_bpos_to_text(&PBUF(buf2), bp->min_key), buf2));
                }
 
-               btree_err_on(bkey_cmp(bn->max_key, b->key.k.p),
-                            BTREE_ERR_MUST_RETRY, c, b, i,
-                            "incorrect max key %llu:%llu",
-                            bn->max_key.inode,
-                            bn->max_key.offset);
+               btree_err_on(bpos_cmp(bn->max_key, b->key.k.p),
+                            BTREE_ERR_MUST_RETRY, c, ca, b, i,
+                            "incorrect max key %s",
+                            (bch2_bpos_to_text(&PBUF(buf1), bn->max_key), buf1));
 
                if (write)
                        compat_btree_node(b->c.level, b->c.btree_id, version,
                                          BSET_BIG_ENDIAN(i), write, bn);
 
-               /* XXX: ideally we would be validating min_key too */
-#if 0
-               /*
-                * not correct anymore, due to btree node write error
-                * handling
-                *
-                * need to add bn->seq to btree keys and verify
-                * against that
-                */
-               btree_err_on(!extent_contains_ptr(bkey_i_to_s_c_extent(&b->key),
-                                                 bn->ptr),
-                            BTREE_ERR_FATAL, c, b, i,
-                            "incorrect backpointer");
-#endif
                err = bch2_bkey_format_validate(&bn->format);
                btree_err_on(err,
-                            BTREE_ERR_FATAL, c, b, i,
+                            BTREE_ERR_FATAL, c, ca, b, i,
                             "invalid bkey format: %s", err);
 
                compat_bformat(b->c.level, b->c.btree_id, version,
@@ -791,14 +664,8 @@ static int validate_bset_keys(struct bch_fs *c, struct btree *b,
 {
        unsigned version = le16_to_cpu(i->version);
        struct bkey_packed *k, *prev = NULL;
-       bool seen_non_whiteout = false;
        int ret = 0;
 
-       if (!BSET_SEPARATE_WHITEOUTS(i)) {
-               seen_non_whiteout = true;
-               *whiteout_u64s = 0;
-       }
-
        for (k = i->start;
             k != vstruct_last(i);) {
                struct bkey_s u;
@@ -806,14 +673,14 @@ static int validate_bset_keys(struct bch_fs *c, struct btree *b,
                const char *invalid;
 
                if (btree_err_on(bkey_next(k) > vstruct_last(i),
-                                BTREE_ERR_FIXABLE, c, b, i,
+                                BTREE_ERR_FIXABLE, c, NULL, b, i,
                                 "key extends past end of bset")) {
                        i->u64s = cpu_to_le16((u64 *) k - i->_data);
                        break;
                }
 
                if (btree_err_on(k->format > KEY_FORMAT_CURRENT,
-                                BTREE_ERR_FIXABLE, c, b, i,
+                                BTREE_ERR_FIXABLE, c, NULL, b, i,
                                 "invalid bkey format %u", k->format)) {
                        i->u64s = cpu_to_le16(le16_to_cpu(i->u64s) - k->u64s);
                        memmove_u64s_down(k, bkey_next(k),
@@ -836,8 +703,8 @@ static int validate_bset_keys(struct bch_fs *c, struct btree *b,
                        char buf[160];
 
                        bch2_bkey_val_to_text(&PBUF(buf), c, u.s_c);
-                       btree_err(BTREE_ERR_FIXABLE, c, b, i,
-                                 "invalid bkey:\n%s\n%s", invalid, buf);
+                       btree_err(BTREE_ERR_FIXABLE, c, NULL, b, i,
+                                 "invalid bkey: %s\n%s", invalid, buf);
 
                        i->u64s = cpu_to_le16(le16_to_cpu(i->u64s) - k->u64s);
                        memmove_u64s_down(k, bkey_next(k),
@@ -850,18 +717,7 @@ static int validate_bset_keys(struct bch_fs *c, struct btree *b,
                                    BSET_BIG_ENDIAN(i), write,
                                    &b->format, k);
 
-               /*
-                * with the separate whiteouts thing (used for extents), the
-                * second set of keys actually can have whiteouts too, so we
-                * can't solely go off bkey_whiteout()...
-                */
-
-               if (!seen_non_whiteout &&
-                   (!bkey_whiteout(k) ||
-                    (prev && bkey_iter_cmp(b, prev, k) > 0))) {
-                       *whiteout_u64s = k->_data - i->_data;
-                       seen_non_whiteout = true;
-               } else if (prev && bkey_iter_cmp(b, prev, k) > 0) {
+               if (prev && bkey_iter_cmp(b, prev, k) > 0) {
                        char buf1[80];
                        char buf2[80];
                        struct bkey up = bkey_unpack_key(b, prev);
@@ -870,20 +726,26 @@ static int validate_bset_keys(struct bch_fs *c, struct btree *b,
                        bch2_bkey_to_text(&PBUF(buf2), u.k);
 
                        bch2_dump_bset(c, b, i, 0);
-                       btree_err(BTREE_ERR_FATAL, c, b, i,
-                                 "keys out of order: %s > %s",
-                                 buf1, buf2);
-                       /* XXX: repair this */
+
+                       if (btree_err(BTREE_ERR_FIXABLE, c, NULL, b, i,
+                                     "keys out of order: %s > %s",
+                                     buf1, buf2)) {
+                               i->u64s = cpu_to_le16(le16_to_cpu(i->u64s) - k->u64s);
+                               memmove_u64s_down(k, bkey_next(k),
+                                                 (u64 *) vstruct_end(i) - (u64 *) k);
+                               continue;
+                       }
                }
 
                prev = k;
-               k = bkey_next_skip_noops(k, vstruct_last(i));
+               k = bkey_next(k);
        }
 fsck_err:
        return ret;
 }
 
-int bch2_btree_node_read_done(struct bch_fs *c, struct btree *b, bool have_retry)
+int bch2_btree_node_read_done(struct bch_fs *c, struct bch_dev *ca,
+                             struct btree *b, bool have_retry)
 {
        struct btree_node_entry *bne;
        struct sort_iter *iter;
@@ -895,20 +757,22 @@ int bch2_btree_node_read_done(struct bch_fs *c, struct btree *b, bool have_retry
        unsigned u64s;
        int ret, retry_read = 0, write = READ;
 
+       b->version_ondisk = U16_MAX;
+
        iter = mempool_alloc(&c->fill_iter, GFP_NOIO);
        sort_iter_init(iter, b);
        iter->size = (btree_blocks(c) + 1) * 2;
 
        if (bch2_meta_read_fault("btree"))
-               btree_err(BTREE_ERR_MUST_RETRY, c, b, NULL,
+               btree_err(BTREE_ERR_MUST_RETRY, c, ca, b, NULL,
                          "dynamic fault");
 
        btree_err_on(le64_to_cpu(b->data->magic) != bset_magic(c),
-                    BTREE_ERR_MUST_RETRY, c, b, NULL,
+                    BTREE_ERR_MUST_RETRY, c, ca, b, NULL,
                     "bad magic");
 
        btree_err_on(!b->data->keys.seq,
-                    BTREE_ERR_MUST_RETRY, c, b, NULL,
+                    BTREE_ERR_MUST_RETRY, c, ca, b, NULL,
                     "bad btree header");
 
        if (b->key.k.type == KEY_TYPE_btree_ptr_v2) {
@@ -916,7 +780,7 @@ int bch2_btree_node_read_done(struct bch_fs *c, struct btree *b, bool have_retry
                        &bkey_i_to_btree_ptr_v2(&b->key)->v;
 
                btree_err_on(b->data->keys.seq != bp->seq,
-                            BTREE_ERR_MUST_RETRY, c, b, NULL,
+                            BTREE_ERR_MUST_RETRY, c, ca, b, NULL,
                             "got wrong btree node (seq %llx want %llx)",
                             b->data->keys.seq, bp->seq);
        }
@@ -931,7 +795,7 @@ int bch2_btree_node_read_done(struct bch_fs *c, struct btree *b, bool have_retry
                        i = &b->data->keys;
 
                        btree_err_on(!bch2_checksum_type_valid(c, BSET_CSUM_TYPE(i)),
-                                    BTREE_ERR_WANT_RETRY, c, b, i,
+                                    BTREE_ERR_WANT_RETRY, c, ca, b, i,
                                     "unknown checksum type %llu",
                                     BSET_CSUM_TYPE(i));
 
@@ -939,16 +803,15 @@ int bch2_btree_node_read_done(struct bch_fs *c, struct btree *b, bool have_retry
                        csum = csum_vstruct(c, BSET_CSUM_TYPE(i), nonce, b->data);
 
                        btree_err_on(bch2_crc_cmp(csum, b->data->csum),
-                                    BTREE_ERR_WANT_RETRY, c, b, i,
+                                    BTREE_ERR_WANT_RETRY, c, ca, b, i,
                                     "invalid checksum");
 
                        bset_encrypt(c, i, b->written << 9);
 
-                       if (btree_node_is_extents(b) &&
-                           !BTREE_NODE_NEW_EXTENT_OVERWRITE(b->data)) {
-                               set_btree_node_old_extent_overwrite(b);
-                               set_btree_node_need_rewrite(b);
-                       }
+                       btree_err_on(btree_node_is_extents(b) &&
+                                    !BTREE_NODE_NEW_EXTENT_OVERWRITE(b->data),
+                                    BTREE_ERR_FATAL, c, NULL, b, NULL,
+                                    "btree node does not have NEW_EXTENT_OVERWRITE set");
 
                        sectors = vstruct_sectors(b->data, c->block_bits);
                } else {
@@ -959,7 +822,7 @@ int bch2_btree_node_read_done(struct bch_fs *c, struct btree *b, bool have_retry
                                break;
 
                        btree_err_on(!bch2_checksum_type_valid(c, BSET_CSUM_TYPE(i)),
-                                    BTREE_ERR_WANT_RETRY, c, b, i,
+                                    BTREE_ERR_WANT_RETRY, c, ca, b, i,
                                     "unknown checksum type %llu",
                                     BSET_CSUM_TYPE(i));
 
@@ -967,7 +830,7 @@ int bch2_btree_node_read_done(struct bch_fs *c, struct btree *b, bool have_retry
                        csum = csum_vstruct(c, BSET_CSUM_TYPE(i), nonce, bne);
 
                        btree_err_on(bch2_crc_cmp(csum, bne->csum),
-                                    BTREE_ERR_WANT_RETRY, c, b, i,
+                                    BTREE_ERR_WANT_RETRY, c, ca, b, i,
                                     "invalid checksum");
 
                        bset_encrypt(c, i, b->written << 9);
@@ -975,7 +838,10 @@ int bch2_btree_node_read_done(struct bch_fs *c, struct btree *b, bool have_retry
                        sectors = vstruct_sectors(bne, c->block_bits);
                }
 
-               ret = validate_bset(c, b, i, sectors,
+               b->version_ondisk = min(b->version_ondisk,
+                                       le16_to_cpu(i->version));
+
+               ret = validate_bset(c, ca, b, i, sectors,
                                    READ, have_retry);
                if (ret)
                        goto fsck_err;
@@ -997,7 +863,7 @@ int bch2_btree_node_read_done(struct bch_fs *c, struct btree *b, bool have_retry
                                        true);
 
                btree_err_on(blacklisted && first,
-                            BTREE_ERR_FIXABLE, c, b, i,
+                            BTREE_ERR_FIXABLE, c, ca, b, i,
                             "first btree node bset has blacklisted journal seq");
                if (blacklisted && !first)
                        continue;
@@ -1014,7 +880,7 @@ int bch2_btree_node_read_done(struct bch_fs *c, struct btree *b, bool have_retry
             bset_byte_offset(b, bne) < btree_bytes(c);
             bne = (void *) bne + block_bytes(c))
                btree_err_on(bne->keys.seq == b->data->keys.seq,
-                            BTREE_ERR_WANT_RETRY, c, b, NULL,
+                            BTREE_ERR_WANT_RETRY, c, ca, b, NULL,
                             "found bset signature after last bset");
 
        sorted = btree_bounce_alloc(c, btree_bytes(c), &used_mempool);
@@ -1022,9 +888,7 @@ int bch2_btree_node_read_done(struct bch_fs *c, struct btree *b, bool have_retry
 
        set_btree_bset(b, b->set, &b->data->keys);
 
-       b->nr = (btree_node_old_extent_overwrite(b)
-                ? bch2_extent_sort_fix_overlapping
-                : bch2_key_sort_fix_overlapping)(c, &sorted->keys, iter);
+       b->nr = bch2_key_sort_fix_overlapping(c, &sorted->keys, iter);
 
        u64s = le16_to_cpu(sorted->keys.u64s);
        *sorted = *b->data;
@@ -1044,12 +908,12 @@ int bch2_btree_node_read_done(struct bch_fs *c, struct btree *b, bool have_retry
                const char *invalid = bch2_bkey_val_invalid(c, u.s_c);
 
                if (invalid ||
-                   (inject_invalid_keys(c) &&
+                   (bch2_inject_invalid_keys &&
                     !bversion_cmp(u.k->version, MAX_VERSION))) {
                        char buf[160];
 
                        bch2_bkey_val_to_text(&PBUF(buf), c, u.s_c);
-                       btree_err(BTREE_ERR_FIXABLE, c, b, i,
+                       btree_err(BTREE_ERR_FIXABLE, c, NULL, b, i,
                                  "invalid bkey %s: %s", buf, invalid);
 
                        btree_keys_account_key_drop(&b->nr, 0, k);
@@ -1067,7 +931,7 @@ int bch2_btree_node_read_done(struct bch_fs *c, struct btree *b, bool have_retry
                        bp.v->mem_ptr = 0;
                }
 
-               k = bkey_next_skip_noops(k, vstruct_last(i));
+               k = bkey_next(k);
        }
 
        bch2_bset_build_aux_tree(b, b->set, false);
@@ -1079,7 +943,7 @@ int bch2_btree_node_read_done(struct bch_fs *c, struct btree *b, bool have_retry
        bkey_for_each_ptr(bch2_bkey_ptrs(bkey_i_to_s(&b->key)), ptr) {
                struct bch_dev *ca = bch_dev_bkey_exists(c, ptr->dev);
 
-               if (ca->mi.state != BCH_MEMBER_STATE_RW)
+               if (ca->mi.state != BCH_MEMBER_STATE_rw)
                        set_btree_node_need_rewrite(b);
        }
 out:
@@ -1104,6 +968,8 @@ static void btree_node_read_work(struct work_struct *work)
        struct btree *b         = rb->bio.bi_private;
        struct bio *bio         = &rb->bio;
        struct bch_io_failures failed = { .nr = 0 };
+       char buf[200];
+       struct printbuf out;
        bool can_retry;
 
        goto start;
@@ -1123,8 +989,10 @@ static void btree_node_read_work(struct work_struct *work)
                        bio->bi_status = BLK_STS_REMOVED;
                }
 start:
-               bch2_dev_io_err_on(bio->bi_status, ca, "btree read: %s",
-                                  bch2_blk_status_to_str(bio->bi_status));
+               out = PBUF(buf);
+               btree_pos_to_text(&out, c, b);
+               bch2_dev_io_err_on(bio->bi_status, ca, "btree read error %s for %s",
+                                  bch2_blk_status_to_str(bio->bi_status), buf);
                if (rb->have_ioref)
                        percpu_ref_put(&ca->io_ref);
                rb->have_ioref = false;
@@ -1136,7 +1004,7 @@ start:
                                &failed, &rb->pick) > 0;
 
                if (!bio->bi_status &&
-                   !bch2_btree_node_read_done(c, b, can_retry))
+                   !bch2_btree_node_read_done(c, ca, b, can_retry))
                        break;
 
                if (!can_retry) {
@@ -1302,12 +1170,13 @@ static void bch2_btree_node_write_error(struct bch_fs *c,
                                        struct btree_write_bio *wbio)
 {
        struct btree *b         = wbio->wbio.bio.bi_private;
-       __BKEY_PADDED(k, BKEY_BTREE_PTR_VAL_U64s_MAX) tmp;
+       struct bkey_buf k;
        struct bch_extent_ptr *ptr;
        struct btree_trans trans;
        struct btree_iter *iter;
        int ret;
 
+       bch2_bkey_buf_init(&k);
        bch2_trans_init(&trans, c, 0, 0);
 
        iter = bch2_trans_get_node_iter(&trans, b->c.btree_id, b->key.k.p,
@@ -1326,21 +1195,23 @@ retry:
 
        BUG_ON(!btree_node_hashed(b));
 
-       bkey_copy(&tmp.k, &b->key);
+       bch2_bkey_buf_copy(&k, c, &b->key);
 
-       bch2_bkey_drop_ptrs(bkey_i_to_s(&tmp.k), ptr,
+       bch2_bkey_drop_ptrs(bkey_i_to_s(k.k), ptr,
                bch2_dev_list_has_dev(wbio->wbio.failed, ptr->dev));
 
-       if (!bch2_bkey_nr_ptrs(bkey_i_to_s_c(&tmp.k)))
+       if (!bch2_bkey_nr_ptrs(bkey_i_to_s_c(k.k)))
                goto err;
 
-       ret = bch2_btree_node_update_key(c, iter, b, &tmp.k);
+       ret = bch2_btree_node_update_key(c, iter, b, k.k);
        if (ret == -EINTR)
                goto retry;
        if (ret)
                goto err;
 out:
+       bch2_trans_iter_put(&trans, iter);
        bch2_trans_exit(&trans);
+       bch2_bkey_buf_exit(&k, c);
        bio_put(&wbio->wbio.bio);
        btree_node_write_done(c, b);
        return;
@@ -1408,7 +1279,7 @@ static void btree_node_write_endio(struct bio *bio)
        if (wbio->have_ioref)
                bch2_latency_acct(ca, wbio->submit_time, WRITE);
 
-       if (bch2_dev_io_err_on(bio->bi_status, ca, "btree write: %s",
+       if (bch2_dev_io_err_on(bio->bi_status, ca, "btree write error: %s",
                               bch2_blk_status_to_str(bio->bi_status)) ||
            bch2_meta_write_fault("btree")) {
                spin_lock_irqsave(&c->btree_write_error_lock, flags);
@@ -1437,13 +1308,15 @@ static int validate_bset_for_write(struct bch_fs *c, struct btree *b,
        unsigned whiteout_u64s = 0;
        int ret;
 
-       if (bch2_bkey_invalid(c, bkey_i_to_s_c(&b->key), BKEY_TYPE_BTREE))
+       if (bch2_bkey_invalid(c, bkey_i_to_s_c(&b->key), BKEY_TYPE_btree))
                return -1;
 
-       ret = validate_bset(c, b, i, sectors, WRITE, false) ?:
-               validate_bset_keys(c, b, i, &whiteout_u64s, WRITE, false);
-       if (ret)
+       ret = validate_bset_keys(c, b, i, &whiteout_u64s, WRITE, false) ?:
+               validate_bset(c, NULL, b, i, sectors, WRITE, false);
+       if (ret) {
                bch2_inconsistent_error(c);
+               dump_stack();
+       }
 
        return ret;
 }
@@ -1456,7 +1329,7 @@ void __bch2_btree_node_write(struct bch_fs *c, struct btree *b,
        struct bset *i;
        struct btree_node *bn = NULL;
        struct btree_node_entry *bne = NULL;
-       BKEY_PADDED(key) k;
+       struct bkey_buf k;
        struct bch_extent_ptr *ptr;
        struct sort_iter sort_iter;
        struct nonce nonce;
@@ -1467,6 +1340,8 @@ void __bch2_btree_node_write(struct bch_fs *c, struct btree *b,
        bool validate_before_checksum = false;
        void *data;
 
+       bch2_bkey_buf_init(&k);
+
        if (test_bit(BCH_FS_HOLD_BTREE_WRITES, &c->flags))
                return;
 
@@ -1486,6 +1361,9 @@ void __bch2_btree_node_write(struct bch_fs *c, struct btree *b,
                if (!btree_node_may_write(b))
                        return;
 
+               if (old & (1 << BTREE_NODE_never_write))
+                       return;
+
                if (old & (1 << BTREE_NODE_write_in_flight)) {
                        btree_node_wait_on_io(b);
                        continue;
@@ -1498,6 +1376,8 @@ void __bch2_btree_node_write(struct bch_fs *c, struct btree *b,
                new ^=  (1 << BTREE_NODE_write_idx);
        } while (cmpxchg_acquire(&b->flags, old, new) != old);
 
+       atomic_dec(&c->btree_cache.dirty);
+
        BUG_ON(btree_node_fake(b));
        BUG_ON((b->will_make_reachable != 0) != !b->written);
 
@@ -1530,6 +1410,11 @@ void __bch2_btree_node_write(struct bch_fs *c, struct btree *b,
                seq = max(seq, le64_to_cpu(i->journal_seq));
        }
 
+       BUG_ON(b->written && !seq);
+
+       /* bch2_varint_decode may read up to 7 bytes past the end of the buffer: */
+       bytes += 8;
+
        data = btree_bounce_alloc(c, bytes, &used_mempool);
 
        if (!b->written) {
@@ -1545,24 +1430,14 @@ void __bch2_btree_node_write(struct bch_fs *c, struct btree *b,
        i->journal_seq  = cpu_to_le64(seq);
        i->u64s         = 0;
 
-       if (!btree_node_old_extent_overwrite(b)) {
-               sort_iter_add(&sort_iter,
-                             unwritten_whiteouts_start(c, b),
-                             unwritten_whiteouts_end(c, b));
-               SET_BSET_SEPARATE_WHITEOUTS(i, false);
-       } else {
-               memcpy_u64s(i->start,
-                           unwritten_whiteouts_start(c, b),
-                           b->whiteout_u64s);
-               i->u64s = cpu_to_le16(b->whiteout_u64s);
-               SET_BSET_SEPARATE_WHITEOUTS(i, true);
-       }
+       sort_iter_add(&sort_iter,
+                     unwritten_whiteouts_start(c, b),
+                     unwritten_whiteouts_end(c, b));
+       SET_BSET_SEPARATE_WHITEOUTS(i, false);
 
        b->whiteout_u64s = 0;
 
-       u64s = btree_node_old_extent_overwrite(b)
-               ? bch2_sort_extents(vstruct_last(i), &sort_iter, false)
-               : bch2_sort_keys(i->start, &sort_iter, false);
+       u64s = bch2_sort_keys(i->start, &sort_iter, false);
        le16_add_cpu(&i->u64s, u64s);
 
        set_needs_whiteout(i, false);
@@ -1590,7 +1465,7 @@ void __bch2_btree_node_write(struct bch_fs *c, struct btree *b,
                validate_before_checksum = true;
 
        /* validate_bset will be modifying: */
-       if (le16_to_cpu(i->version) < bcachefs_metadata_version_max)
+       if (le16_to_cpu(i->version) < bcachefs_metadata_version_current)
                validate_before_checksum = true;
 
        /* if we're going to be encrypting, check metadata validity first: */
@@ -1665,15 +1540,19 @@ void __bch2_btree_node_write(struct bch_fs *c, struct btree *b,
         * just make all btree node writes FUA to keep things sane.
         */
 
-       bkey_copy(&k.key, &b->key);
+       bch2_bkey_buf_copy(&k, c, &b->key);
 
-       bkey_for_each_ptr(bch2_bkey_ptrs(bkey_i_to_s(&k.key)), ptr)
+       bkey_for_each_ptr(bch2_bkey_ptrs(bkey_i_to_s(k.k)), ptr)
                ptr->offset += b->written;
 
        b->written += sectors_to_write;
 
+       atomic64_inc(&c->btree_writes_nr);
+       atomic64_add(sectors_to_write, &c->btree_writes_sectors);
+
        /* XXX: submitting IO with btree locks held: */
-       bch2_submit_wbio_replicas(&wbio->wbio, c, BCH_DATA_btree, &k.key);
+       bch2_submit_wbio_replicas(&wbio->wbio, c, BCH_DATA_btree, k.k);
+       bch2_bkey_buf_exit(&k, c);
        return;
 err:
        set_btree_node_noevict(b);
@@ -1793,23 +1672,6 @@ void bch2_btree_flush_all_writes(struct bch_fs *c)
        __bch2_btree_flush_all(c, BTREE_NODE_write_in_flight);
 }
 
-void bch2_btree_verify_flushed(struct bch_fs *c)
-{
-       struct bucket_table *tbl;
-       struct rhash_head *pos;
-       struct btree *b;
-       unsigned i;
-
-       rcu_read_lock();
-       for_each_cached_btree(b, c, tbl, i, pos) {
-               unsigned long flags = READ_ONCE(b->flags);
-
-               BUG_ON((flags & (1 << BTREE_NODE_dirty)) ||
-                      (flags & (1 << BTREE_NODE_write_in_flight)));
-       }
-       rcu_read_unlock();
-}
-
 void bch2_dirty_btree_nodes_to_text(struct printbuf *out, struct bch_fs *c)
 {
        struct bucket_table *tbl;