]> git.sesse.net Git - bcachefs-tools-debian/blobdiff - libbcachefs/btree_update_interior.c
Update bcachefs sources to 3e0c5b0722 fixup! bcachefs: Btree write buffer
[bcachefs-tools-debian] / libbcachefs / btree_update_interior.c
index a40a0f5ca4bdb5d632eb1841fc3d17016042f685..172fd3b6cfc258eabd1d3bcf9c454fb0f361590f 100644 (file)
@@ -1997,6 +1997,7 @@ err:
 struct async_btree_rewrite {
        struct bch_fs           *c;
        struct work_struct      work;
+       struct list_head        list;
        enum btree_id           btree_id;
        unsigned                level;
        struct bpos             pos;
@@ -2056,15 +2057,10 @@ void async_btree_node_rewrite_work(struct work_struct *work)
 void bch2_btree_node_rewrite_async(struct bch_fs *c, struct btree *b)
 {
        struct async_btree_rewrite *a;
-
-       if (!bch2_write_ref_tryget(c, BCH_WRITE_REF_node_rewrite)) {
-               bch_err(c, "%s: error getting c->writes ref", __func__);
-               return;
-       }
+       int ret;
 
        a = kmalloc(sizeof(*a), GFP_NOFS);
        if (!a) {
-               bch2_write_ref_put(c, BCH_WRITE_REF_node_rewrite);
                bch_err(c, "%s: error allocating memory", __func__);
                return;
        }
@@ -2074,11 +2070,63 @@ void bch2_btree_node_rewrite_async(struct bch_fs *c, struct btree *b)
        a->level        = b->c.level;
        a->pos          = b->key.k.p;
        a->seq          = b->data->keys.seq;
-
        INIT_WORK(&a->work, async_btree_node_rewrite_work);
+
+       if (unlikely(!test_bit(BCH_FS_MAY_GO_RW, &c->flags))) {
+               mutex_lock(&c->pending_node_rewrites_lock);
+               list_add(&a->list, &c->pending_node_rewrites);
+               mutex_unlock(&c->pending_node_rewrites_lock);
+               return;
+       }
+
+       if (!bch2_write_ref_tryget(c, BCH_WRITE_REF_node_rewrite)) {
+               if (test_bit(BCH_FS_STARTED, &c->flags)) {
+                       bch_err(c, "%s: error getting c->writes ref", __func__);
+                       kfree(a);
+                       return;
+               }
+
+               ret = bch2_fs_read_write_early(c);
+               if (ret) {
+                       bch_err(c, "%s: error going read-write: %s",
+                               __func__, bch2_err_str(ret));
+                       kfree(a);
+                       return;
+               }
+
+               bch2_write_ref_get(c, BCH_WRITE_REF_node_rewrite);
+       }
+
        queue_work(c->btree_interior_update_worker, &a->work);
 }
 
+void bch2_do_pending_node_rewrites(struct bch_fs *c)
+{
+       struct async_btree_rewrite *a, *n;
+
+       mutex_lock(&c->pending_node_rewrites_lock);
+       list_for_each_entry_safe(a, n, &c->pending_node_rewrites, list) {
+               list_del(&a->list);
+
+               bch2_write_ref_get(c, BCH_WRITE_REF_node_rewrite);
+               queue_work(c->btree_interior_update_worker, &a->work);
+       }
+       mutex_unlock(&c->pending_node_rewrites_lock);
+}
+
+void bch2_free_pending_node_rewrites(struct bch_fs *c)
+{
+       struct async_btree_rewrite *a, *n;
+
+       mutex_lock(&c->pending_node_rewrites_lock);
+       list_for_each_entry_safe(a, n, &c->pending_node_rewrites, list) {
+               list_del(&a->list);
+
+               kfree(a);
+       }
+       mutex_unlock(&c->pending_node_rewrites_lock);
+}
+
 static int __bch2_btree_node_update_key(struct btree_trans *trans,
                                        struct btree_iter *iter,
                                        struct btree *b, struct btree *new_hash,
@@ -2416,6 +2464,9 @@ int bch2_fs_btree_interior_update_init(struct bch_fs *c)
        mutex_init(&c->btree_interior_update_lock);
        INIT_WORK(&c->btree_interior_update_work, btree_interior_update_work);
 
+       INIT_LIST_HEAD(&c->pending_node_rewrites);
+       mutex_init(&c->pending_node_rewrites_lock);
+
        c->btree_interior_update_worker =
                alloc_workqueue("btree_update", WQ_UNBOUND|WQ_MEM_RECLAIM, 1);
        if (!c->btree_interior_update_worker)