bcachefs: Count iterators for reflink_p overwrites correctly
authorKent Overstreet <kent.overstreet@gmail.com>
Sun, 22 Sep 2019 21:48:25 +0000 (17:48 -0400)
committerKent Overstreet <kent.overstreet@linux.dev>
Sun, 22 Oct 2023 21:08:27 +0000 (17:08 -0400)
In order to avoid trying to allocate too many btree iterators,
bch2_extent_atomic_end() needs to count how many iterators are going to
be needed for insertions and overwrites - but we weren't counting the
iterators for deleting a reflink_v when the refcount goes to 0.

Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
fs/bcachefs/extents.c

index 859b1e8206bdbd8fc95f054c4a25fe0d62e1a256..35abcde4bca2c93c1c57418d41452682d047f35e 100644 (file)
@@ -935,12 +935,13 @@ static unsigned bch2_bkey_nr_alloc_ptrs(struct bkey_s_c k)
        return ret;
 }
 
-static int __bch2_extent_atomic_end(struct btree_trans *trans,
-                                   struct bkey_s_c k,
-                                   unsigned offset,
-                                   struct bpos *end,
-                                   unsigned *nr_iters,
-                                   unsigned max_iters)
+static int count_iters_for_insert(struct btree_trans *trans,
+                                 struct bkey_s_c k,
+                                 unsigned offset,
+                                 struct bpos *end,
+                                 unsigned *nr_iters,
+                                 unsigned max_iters,
+                                 bool overwrite)
 {
        int ret = 0;
 
@@ -970,6 +971,20 @@ static int __bch2_extent_atomic_end(struct btree_trans *trans,
                                break;
 
                        *nr_iters += 1;
+
+                       if (overwrite &&
+                           k.k->type == KEY_TYPE_reflink_v) {
+                               struct bkey_s_c_reflink_v r = bkey_s_c_to_reflink_v(k);
+
+                               if (le64_to_cpu(r.v->refcount) == 1)
+                                       *nr_iters += bch2_bkey_nr_alloc_ptrs(k);
+                       }
+
+                       /*
+                        * if we're going to be deleting an entry from
+                        * the reflink btree, need more iters...
+                        */
+
                        if (*nr_iters >= max_iters) {
                                struct bpos pos = bkey_start_pos(k.k);
                                pos.offset += r_k.k->p.offset - idx;
@@ -1004,8 +1019,8 @@ int bch2_extent_atomic_end(struct btree_iter *iter,
 
        *end = bpos_min(insert->k.p, b->key.k.p);
 
-       ret = __bch2_extent_atomic_end(trans, bkey_i_to_s_c(insert),
-                                      0, end, &nr_iters, 10);
+       ret = count_iters_for_insert(trans, bkey_i_to_s_c(insert),
+                                    0, end, &nr_iters, 10, false);
        if (ret)
                return ret;
 
@@ -1024,8 +1039,8 @@ int bch2_extent_atomic_end(struct btree_iter *iter,
                        offset = bkey_start_offset(&insert->k) -
                                bkey_start_offset(k.k);
 
-               ret = __bch2_extent_atomic_end(trans, k, offset,
-                                              end, &nr_iters, 20);
+               ret = count_iters_for_insert(trans, k, offset,
+                                            end, &nr_iters, 20, true);
                if (ret)
                        return ret;