bcachefs: bch2_bkey_get_empty_slot()
authorKent Overstreet <kent.overstreet@linux.dev>
Fri, 28 Apr 2023 03:20:18 +0000 (23:20 -0400)
committerKent Overstreet <kent.overstreet@linux.dev>
Sun, 22 Oct 2023 21:10:01 +0000 (17:10 -0400)
Add a new helper for allocating a new slot in a btree.

Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
fs/bcachefs/btree_update.h
fs/bcachefs/btree_update_leaf.c
fs/bcachefs/errcode.h
fs/bcachefs/subvolume.c

index 34ca2c43a8cac2e107a6b13aa417898505f88ab6..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 *,
index 0952885f3caab05459136bbd5e118a1e73f78c7c..33693467810b20a9fc4fcbaf54ee595a51b95eca 100644 (file)
@@ -1735,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 4304e25a6b24097edb1dc619f31a6f1e62568a3d..c73a5e78e26038d5982220dddf7d79c9fb60da1c 100644 (file)
@@ -92,6 +92,7 @@
        x(ENOSPC,                       ENOSPC_sb_replicas)                     \
        x(ENOSPC,                       ENOSPC_sb_members)                      \
        x(ENOSPC,                       ENOSPC_sb_crypt)                        \
+       x(ENOSPC,                       ENOSPC_btree_slot)                      \
        x(0,                            open_buckets_empty)                     \
        x(0,                            freelist_empty)                         \
        x(BCH_ERR_freelist_empty,       no_buckets_found)                       \
index cac295afc75fcb1c387d27aea8588d435cd0f6cd..8d87f90a0ac699f9650ad6fd34345c06395b6d33 100644 (file)
@@ -909,32 +909,19 @@ int bch2_subvolume_create(struct btree_trans *trans, u64 inode,
                          u32 *new_snapshotid,
                          bool ro)
 {
-       struct bch_fs *c = trans->c;
        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;