bcachefs: Refactor whiteouts compaction
authorKent Overstreet <kent.overstreet@gmail.com>
Fri, 13 Dec 2019 18:08:37 +0000 (13:08 -0500)
committerKent Overstreet <kent.overstreet@linux.dev>
Sun, 22 Oct 2023 21:08:32 +0000 (17:08 -0400)
The whiteout compaction path - as opposed to just dropping whiteouts -
is now only needed for extents, and soon will only be needed for extent
btree nodes in the old format.

Signed-off-by: Kent Overstreet <kent.overstreet@gmail.com>
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
fs/bcachefs/bkey_sort.c
fs/bcachefs/bkey_sort.h
fs/bcachefs/btree_io.c
fs/bcachefs/btree_io.h
fs/bcachefs/btree_types.h

index 2e205db5433d7bfd95ef9d7c81d4668bbbb00e2b..4f614cde3267145e0404917edcb4ef68f49b7e88 100644 (file)
@@ -530,28 +530,6 @@ unsigned bch2_sort_extents(struct bkey_packed *dst,
        return (u64 *) out - (u64 *) dst;
 }
 
-static inline int sort_key_whiteouts_cmp(struct btree *b,
-                                        struct bkey_packed *l,
-                                        struct bkey_packed *r)
-{
-       return bkey_cmp_packed(b, l, r);
-}
-
-unsigned bch2_sort_key_whiteouts(struct bkey_packed *dst,
-                                struct sort_iter *iter)
-{
-       struct bkey_packed *in, *out = dst;
-
-       sort_iter_sort(iter, sort_key_whiteouts_cmp);
-
-       while ((in = sort_iter_next(iter, sort_key_whiteouts_cmp))) {
-               bkey_copy(out, in);
-               out = bkey_next(out);
-       }
-
-       return (u64 *) out - (u64 *) dst;
-}
-
 static inline int sort_extent_whiteouts_cmp(struct btree *b,
                                            struct bkey_packed *l,
                                            struct bkey_packed *r)
index 397009181eaee233d0cf820d9cd2a775d87e76da..47a808670341dce48bae4d60ec5f60cb856496b9 100644 (file)
@@ -61,8 +61,6 @@ unsigned bch2_sort_keys(struct bkey_packed *,
 unsigned bch2_sort_extents(struct bkey_packed *,
                           struct sort_iter *, bool);
 
-unsigned bch2_sort_key_whiteouts(struct bkey_packed *,
-                                struct sort_iter *);
 unsigned bch2_sort_extent_whiteouts(struct bkey_packed *,
                                    struct sort_iter *);
 
index 9acf59c0710dd11464261661333017d9fe3ac6bf..6a658f2c63283810e40d2e453ec48f9c15da5cf9 100644 (file)
@@ -154,27 +154,26 @@ static void bch2_sort_whiteouts(struct bch_fs *c, struct btree *b)
        btree_bounce_free(c, order, used_mempool1, new_whiteouts);
 }
 
-static unsigned should_compact_bset(struct btree *b, struct bset_tree *t,
-                                   bool compacting,
-                                   enum compact_mode mode)
+static bool should_compact_bset(struct btree *b, struct bset_tree *t,
+                               bool compacting, enum compact_mode mode)
 {
-       unsigned bset_u64s = le16_to_cpu(bset(b, t)->u64s);
-       unsigned dead_u64s = bset_u64s - b->nr.bset_u64s[t - b->set];
+       if (!bset_dead_u64s(b, t))
+               return false;
 
-       if (mode == COMPACT_LAZY) {
-               if (should_compact_bset_lazy(b, t) ||
-                   (compacting && !bset_written(b, bset(b, t))))
-                       return dead_u64s;
-       } else {
-               if (bset_written(b, bset(b, t)))
-                       return dead_u64s;
+       switch (mode) {
+       case COMPACT_LAZY:
+               return should_compact_bset_lazy(b, t) ||
+                       (compacting && !bset_written(b, bset(b, t)));
+       case COMPACT_ALL:
+               return true;
+       default:
+               BUG();
        }
-
-       return 0;
 }
 
-bool __bch2_compact_whiteouts(struct bch_fs *c, struct btree *b,
-                            enum compact_mode mode)
+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;
@@ -184,9 +183,11 @@ bool __bch2_compact_whiteouts(struct bch_fs *c, struct btree *b,
        unsigned order, whiteout_u64s = 0, u64s;
        bool used_mempool, compacting = false;
 
+       BUG_ON(!btree_node_is_extents(b));
+
        for_each_bset(b, t)
-               whiteout_u64s += should_compact_bset(b, t,
-                                       whiteout_u64s != 0, mode);
+               if (should_compact_bset(b, t, whiteout_u64s != 0, mode))
+                       whiteout_u64s += bset_dead_u64s(b, t);
 
        if (!whiteout_u64s)
                return false;
@@ -215,9 +216,12 @@ bool __bch2_compact_whiteouts(struct bch_fs *c, struct btree *b,
                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));
+                                 (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) +
@@ -245,7 +249,7 @@ bool __bch2_compact_whiteouts(struct bch_fs *c, struct btree *b,
                for (k = start; k != end; k = n) {
                        n = bkey_next_skip_noops(k, end);
 
-                       if (bkey_deleted(k) && btree_node_is_extents(b))
+                       if (bkey_deleted(k))
                                continue;
 
                        BUG_ON(bkey_whiteout(k) &&
@@ -259,7 +263,7 @@ bool __bch2_compact_whiteouts(struct bch_fs *c, struct btree *b,
                                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 if (mode != COMPACT_WRITTEN_NO_WRITE_LOCK) {
+                       } else {
                                bkey_copy(out, k);
                                out = bkey_next(out);
                        }
@@ -267,11 +271,9 @@ bool __bch2_compact_whiteouts(struct bch_fs *c, struct btree *b,
 
                sort_iter_add(&sort_iter, u_start, u_pos);
 
-               if (mode != COMPACT_WRITTEN_NO_WRITE_LOCK) {
-                       i->u64s = cpu_to_le16((u64 *) out - i->_data);
-                       set_btree_bset_end(b, t);
-                       bch2_bset_set_no_aux_tree(b, t);
-               }
+               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;
@@ -279,13 +281,10 @@ bool __bch2_compact_whiteouts(struct bch_fs *c, struct btree *b,
        BUG_ON((void *) unwritten_whiteouts_start(c, b) <
               (void *) btree_bkey_last(b, bset_tree_last(b)));
 
-       u64s = (btree_node_is_extents(b)
-               ? bch2_sort_extent_whiteouts
-               : bch2_sort_key_whiteouts)(unwritten_whiteouts_start(c, b),
-                                          &sort_iter);
+       u64s = bch2_sort_extent_whiteouts(unwritten_whiteouts_start(c, b),
+                                         &sort_iter);
 
        BUG_ON(u64s > b->whiteout_u64s);
-       BUG_ON(u64s != b->whiteout_u64s && !btree_node_is_extents(b));
        BUG_ON(u_pos != whiteouts && !u64s);
 
        if (u64s != b->whiteout_u64s) {
@@ -301,8 +300,7 @@ bool __bch2_compact_whiteouts(struct bch_fs *c, struct btree *b,
 
        btree_bounce_free(c, order, used_mempool, whiteouts);
 
-       if (mode != COMPACT_WRITTEN_NO_WRITE_LOCK)
-               bch2_btree_build_aux_trees(b);
+       bch2_btree_build_aux_trees(b);
 
        bch_btree_keys_u64s_remaining(c, b);
        bch2_verify_btree_nr_keys(b);
@@ -310,7 +308,7 @@ bool __bch2_compact_whiteouts(struct bch_fs *c, struct btree *b,
        return true;
 }
 
-static bool bch2_drop_whiteouts(struct btree *b)
+static bool bch2_drop_whiteouts(struct btree *b, enum compact_mode mode)
 {
        struct bset_tree *t;
        bool ret = false;
@@ -318,21 +316,34 @@ static bool bch2_drop_whiteouts(struct btree *b)
        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)
+                       ret = true;
 
-               if (!should_compact_bset(b, t, true, COMPACT_WRITTEN))
+               if (!should_compact_bset(b, t, ret, 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;
+               }
 
                start   = btree_bkey_first(b, t);
                end     = btree_bkey_last(b, t);
 
-               if (!bset_written(b, i) &&
-                   t != b->set) {
-                       struct bset *dst =
-                              max_t(struct bset *, write_block(b),
-                                    (void *) btree_bkey_last(b, t -1));
-
-                       memmove(dst, i, sizeof(struct bset));
-                       i = dst;
+               if (src != dst) {
+                       memmove(dst, src, sizeof(*src));
+                       i = &dst->keys;
                        set_btree_bset(b, t, i);
                }
 
@@ -344,19 +355,32 @@ static bool bch2_drop_whiteouts(struct btree *b)
                        if (!bkey_whiteout(k)) {
                                bkey_copy(out, k);
                                out = bkey_next(out);
+                       } else {
+                               BUG_ON(k->needs_whiteout);
                        }
                }
 
                i->u64s = cpu_to_le16((u64 *) out - i->_data);
+               set_btree_bset_end(b, t);
                bch2_bset_set_no_aux_tree(b, t);
                ret = true;
        }
 
        bch2_verify_btree_nr_keys(b);
 
+       bch2_btree_build_aux_trees(b);
+
        return ret;
 }
 
+bool bch2_compact_whiteouts(struct bch_fs *c, struct btree *b,
+                           enum compact_mode mode)
+{
+       return !btree_node_is_extents(b)
+               ? bch2_drop_whiteouts(b, mode)
+               : bch2_compact_extent_whiteouts(c, b, mode);
+}
+
 static void btree_node_sort(struct bch_fs *c, struct btree *b,
                            struct btree_iter *iter,
                            unsigned start_idx,
@@ -1631,7 +1655,7 @@ bool bch2_btree_post_write_cleanup(struct bch_fs *c, struct btree *b)
                btree_node_sort(c, b, NULL, 0, b->nsets, true);
                invalidated_iter = true;
        } else {
-               invalidated_iter = bch2_drop_whiteouts(b);
+               invalidated_iter = bch2_drop_whiteouts(b, COMPACT_ALL);
        }
 
        for_each_bset(b, t)
index 69516ec34b899bd8b24a00cc33256e1c04cf16ab..43fa8a6dbee57ca9800f138c6d1ebfcf87579a16 100644 (file)
@@ -54,16 +54,17 @@ static inline bool btree_node_may_write(struct btree *b)
 
 enum compact_mode {
        COMPACT_LAZY,
-       COMPACT_WRITTEN,
-       COMPACT_WRITTEN_NO_WRITE_LOCK,
+       COMPACT_ALL,
 };
 
-bool __bch2_compact_whiteouts(struct bch_fs *, struct btree *, enum compact_mode);
+bool bch2_compact_whiteouts(struct bch_fs *, struct btree *,
+                           enum compact_mode);
 
-static inline unsigned should_compact_bset_lazy(struct btree *b, struct bset_tree *t)
+static inline bool should_compact_bset_lazy(struct btree *b,
+                                           struct bset_tree *t)
 {
        unsigned total_u64s = bset_u64s(t);
-       unsigned dead_u64s = total_u64s - b->nr.bset_u64s[t - b->set];
+       unsigned dead_u64s = bset_dead_u64s(b, t);
 
        return dead_u64s > 64 && dead_u64s * 3 > total_u64s;
 }
@@ -74,7 +75,7 @@ static inline bool bch2_maybe_compact_whiteouts(struct bch_fs *c, struct btree *
 
        for_each_bset(b, t)
                if (should_compact_bset_lazy(b, t))
-                       return __bch2_compact_whiteouts(c, b, COMPACT_LAZY);
+                       return bch2_compact_whiteouts(c, b, COMPACT_LAZY);
 
        return false;
 }
index e370474fd8c293e5bfa514f74d8ccd633dc079b0..5f0b55c98f861aceeb7cc8db38ed3e75ef5c6535 100644 (file)
@@ -423,6 +423,11 @@ static inline unsigned bset_u64s(struct bset_tree *t)
                sizeof(struct bset) / sizeof(u64);
 }
 
+static inline unsigned bset_dead_u64s(struct btree *b, struct bset_tree *t)
+{
+       return bset_u64s(t) - b->nr.bset_u64s[t - b->set];
+}
+
 static inline unsigned bset_byte_offset(struct btree *b, void *i)
 {
        return i - (void *) b->data;