bcachefs: Seralize btree_update operations at btree_update_nodes_written()
authorKent Overstreet <kent.overstreet@gmail.com>
Sat, 8 Feb 2020 21:39:37 +0000 (16:39 -0500)
committerKent Overstreet <kent.overstreet@linux.dev>
Sun, 22 Oct 2023 21:08:35 +0000 (17:08 -0400)
Prep work for journalling updates to interior nodes - enforcing ordering
will greatly simplify those changes.

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

index 0d4a8b75ff42beb2e650e332da25cdf2ba0affcd..32cdf87ee55d50c45bca29bda78886d51dc6437c 100644 (file)
@@ -610,6 +610,7 @@ struct bch_fs {
 
        mempool_t               btree_interior_update_pool;
        struct list_head        btree_interior_update_list;
+       struct list_head        btree_interior_updates_unwritten;
        struct mutex            btree_interior_update_lock;
        struct closure_waitlist btree_interior_update_wait;
 
index 3d8b6218c983df9a528e75380b9df75a45fcd5e7..677cb76731c1d5d2ec94c59da0895f3e30bf5272 100644 (file)
@@ -666,9 +666,15 @@ static void btree_update_nodes_written(struct closure *cl)
         * to child nodes that weren't written yet: now, the child nodes have
         * been written so we can write out the update to the interior node.
         */
-retry:
        mutex_lock(&c->btree_interior_update_lock);
        as->nodes_written = true;
+retry:
+       as = list_first_entry_or_null(&c->btree_interior_updates_unwritten,
+                                     struct btree_update, unwritten_list);
+       if (!as || !as->nodes_written) {
+               mutex_unlock(&c->btree_interior_update_lock);
+               return;
+       }
 
        switch (as->mode) {
        case BTREE_INTERIOR_NO_UPDATE:
@@ -681,11 +687,12 @@ retry:
                        mutex_unlock(&c->btree_interior_update_lock);
                        btree_node_lock_type(c, b, SIX_LOCK_read);
                        six_unlock_read(&b->c.lock);
+                       mutex_lock(&c->btree_interior_update_lock);
                        goto retry;
                }
 
                BUG_ON(!btree_node_dirty(b));
-               closure_wait(&btree_current_write(b)->wait, cl);
+               closure_wait(&btree_current_write(b)->wait, &as->cl);
 
                list_del(&as->write_blocked_list);
 
@@ -694,6 +701,8 @@ retry:
                 * nodes to be writeable:
                 */
                closure_wake_up(&c->btree_interior_update_wait);
+
+               list_del(&as->unwritten_list);
                mutex_unlock(&c->btree_interior_update_lock);
 
                /*
@@ -702,6 +711,7 @@ retry:
                 */
                bch2_btree_node_write_cond(c, b, true);
                six_unlock_read(&b->c.lock);
+               continue_at(&as->cl, btree_update_nodes_reachable, system_wq);
                break;
 
        case BTREE_INTERIOR_UPDATING_AS:
@@ -716,8 +726,12 @@ retry:
                /*
                 * and then we have to wait on that btree_update to finish:
                 */
-               closure_wait(&as->parent_as->wait, cl);
+               closure_wait(&as->parent_as->wait, &as->cl);
+
+               list_del(&as->unwritten_list);
                mutex_unlock(&c->btree_interior_update_lock);
+
+               continue_at(&as->cl, btree_update_nodes_reachable, system_wq);
                break;
 
        case BTREE_INTERIOR_UPDATING_ROOT:
@@ -728,6 +742,7 @@ retry:
                        mutex_unlock(&c->btree_interior_update_lock);
                        btree_node_lock_type(c, b, SIX_LOCK_read);
                        six_unlock_read(&b->c.lock);
+                       mutex_lock(&c->btree_interior_update_lock);
                        goto retry;
                }
 
@@ -744,6 +759,8 @@ retry:
                 * can reuse the old nodes it'll have to do a journal commit:
                 */
                six_unlock_read(&b->c.lock);
+
+               list_del(&as->unwritten_list);
                mutex_unlock(&c->btree_interior_update_lock);
 
                /*
@@ -762,11 +779,12 @@ retry:
 
                as->journal_seq = bch2_journal_last_unwritten_seq(&c->journal);
 
-               btree_update_wait_on_journal(cl);
-               return;
+               btree_update_wait_on_journal(&as->cl);
+               break;
        }
 
-       continue_at(cl, btree_update_nodes_reachable, system_wq);
+       mutex_lock(&c->btree_interior_update_lock);
+       goto retry;
 }
 
 /*
@@ -778,6 +796,7 @@ static void btree_update_updated_node(struct btree_update *as, struct btree *b)
        struct bch_fs *c = as->c;
 
        mutex_lock(&c->btree_interior_update_lock);
+       list_add_tail(&as->unwritten_list, &c->btree_interior_updates_unwritten);
 
        BUG_ON(as->mode != BTREE_INTERIOR_NO_UPDATE);
        BUG_ON(!btree_node_dirty(b));
@@ -858,6 +877,7 @@ static void btree_update_updated_root(struct btree_update *as)
        struct btree_root *r = &c->btree_roots[as->btree_id];
 
        mutex_lock(&c->btree_interior_update_lock);
+       list_add_tail(&as->unwritten_list, &c->btree_interior_updates_unwritten);
 
        BUG_ON(as->mode != BTREE_INTERIOR_NO_UPDATE);
 
index 8f9d4a0b68eaa35dd9858a354c471a55dd0e12dc..e3204f32cc687ae3ad3b94c452eda35c2dbb99e3 100644 (file)
@@ -55,6 +55,7 @@ struct btree_update {
        struct bch_fs                   *c;
 
        struct list_head                list;
+       struct list_head                unwritten_list;
 
        /* What kind of update are we doing? */
        enum {
index 586636a4c204034f62aa15ff2c05685555ba56d0..2ba04b08529d5e45c62404fee8f41c377867714f 100644 (file)
@@ -642,6 +642,7 @@ static struct bch_fs *bch2_fs_alloc(struct bch_sb *sb, struct bch_opts opts)
        INIT_LIST_HEAD(&c->list);
 
        INIT_LIST_HEAD(&c->btree_interior_update_list);
+       INIT_LIST_HEAD(&c->btree_interior_updates_unwritten);
        mutex_init(&c->btree_reserve_cache_lock);
        mutex_init(&c->btree_interior_update_lock);