bcachefs: Split extents if necessary in bch2_trans_update()
authorKent Overstreet <kent.overstreet@gmail.com>
Wed, 19 May 2021 03:17:03 +0000 (23:17 -0400)
committerKent Overstreet <kent.overstreet@linux.dev>
Sun, 22 Oct 2023 21:09:03 +0000 (17:09 -0400)
Currently, we handle multiple overlapping extents in the same
transaction commit by doing fixups in bch2_trans_update() - this patch
extents that to split updates when necessary. The next patch that
changes the reflink code to not fragment extents when making them
indirect will require this.

Signed-off-by: Kent Overstreet <kent.overstreet@gmail.com>
fs/bcachefs/btree_update_leaf.c
fs/bcachefs/io.c
fs/bcachefs/reflink.c

index fbe6a17ffd8a99c8df7665da29697f0a4f020614..cc844ca81bccbaf88ef11419cad41c1d7d6efd02 100644 (file)
@@ -1099,9 +1099,30 @@ int bch2_trans_update(struct btree_trans *trans, struct btree_iter *iter,
                if (i < trans->updates + trans->nr_updates &&
                    i->btree_id == n.btree_id &&
                    bkey_cmp(n.k->k.p, bkey_start_pos(&i->k->k)) > 0) {
-                       /* We don't handle splitting extents here: */
-                       BUG_ON(bkey_cmp(bkey_start_pos(&n.k->k),
-                                       bkey_start_pos(&i->k->k)) > 0);
+                       if (bkey_cmp(bkey_start_pos(&n.k->k),
+                                    bkey_start_pos(&i->k->k)) > 0) {
+                               struct btree_insert_entry split = *i;
+                               int ret;
+
+                               BUG_ON(trans->nr_updates + 1 >= BTREE_ITER_MAX);
+
+                               split.k = bch2_trans_kmalloc(trans, bkey_bytes(&i->k->k));
+                               ret = PTR_ERR_OR_ZERO(split.k);
+                               if (ret)
+                                       return ret;
+
+                               bkey_copy(split.k, i->k);
+                               bch2_cut_back(bkey_start_pos(&n.k->k), split.k);
+
+                               split.iter = bch2_trans_get_iter(trans, split.btree_id,
+                                                                bkey_start_pos(&split.k->k),
+                                                                BTREE_ITER_INTENT);
+                               split.iter->flags |= BTREE_ITER_KEEP_UNTIL_COMMIT;
+                               bch2_trans_iter_put(trans, split.iter);
+                               array_insert_item(trans->updates, trans->nr_updates,
+                                                 i - trans->updates, split);
+                               i++;
+                       }
 
                        /*
                         * When we have an extent that overwrites the start of another
index 9fc858a0a49623007c1b310bc7b8144142d30a3c..5a45e738bc8049104d1601ead9ceb44bdd53bd7b 100644 (file)
@@ -342,9 +342,8 @@ int bch2_extent_update(struct btree_trans *trans,
                bch2_trans_iter_put(trans, inode_iter);
        }
 
-       bch2_trans_update(trans, iter, k, 0);
-
-       ret = bch2_trans_commit(trans, disk_res, journal_seq,
+       ret =   bch2_trans_update(trans, iter, k, 0) ?:
+               bch2_trans_commit(trans, disk_res, journal_seq,
                                BTREE_INSERT_NOCHECK_RW|
                                BTREE_INSERT_NOFAIL);
        if (ret)
index 405a194d10e5db7e6b1d9446351013c5be3b1791..ec8532b39a49af5b762c3601eb68ee343cdbb0e0 100644 (file)
@@ -155,7 +155,9 @@ static int bch2_make_extent_indirect(struct btree_trans *trans,
        *refcount       = 0;
        memcpy(refcount + 1, &orig->v, bkey_val_bytes(&orig->k));
 
-       bch2_trans_update(trans, reflink_iter, r_v, 0);
+       ret = bch2_trans_update(trans, reflink_iter, r_v, 0);
+       if (ret)
+               goto err;
 
        r_p = bch2_trans_kmalloc(trans, sizeof(*r_p));
        if (IS_ERR(r_p)) {
@@ -168,7 +170,7 @@ static int bch2_make_extent_indirect(struct btree_trans *trans,
        set_bkey_val_bytes(&r_p->k, sizeof(r_p->v));
        r_p->v.idx = cpu_to_le64(bkey_start_offset(&r_v->k));
 
-       bch2_trans_update(trans, extent_iter, &r_p->k_i, 0);
+       ret = bch2_trans_update(trans, extent_iter, &r_p->k_i, 0);
 err:
        if (!IS_ERR(reflink_iter))
                c->reflink_hint = reflink_iter->pos.offset;