]> git.sesse.net Git - bcachefs-tools-debian/blobdiff - libbcachefs/btree_write_buffer.c
Update bcachefs sources to eb83f1f842bb mean and variance: Promote to lib/math
[bcachefs-tools-debian] / libbcachefs / btree_write_buffer.c
index a6bf6ed37ced60cfee4bb61c15c47c06d5ace9c7..6ab26576252c17edc603ad42438e7a9ebd9b4181 100644 (file)
@@ -33,17 +33,32 @@ static int btree_write_buffered_journal_cmp(const void *_l, const void *_r)
        return  cmp_int(l->journal_seq, r->journal_seq);
 }
 
-static int bch2_btree_write_buffer_flush_one(struct btree_trans *trans,
-                                            struct btree_iter *iter,
-                                            struct btree_write_buffered_key *wb,
-                                            unsigned commit_flags,
-                                            bool *write_locked,
-                                            size_t *fast)
+static noinline int wb_flush_one_slowpath(struct btree_trans *trans,
+                                         struct btree_iter *iter,
+                                         struct btree_write_buffered_key *wb)
+{
+       bch2_btree_node_unlock_write(trans, iter->path, iter->path->l[0].b);
+
+       trans->journal_res.seq = wb->journal_seq;
+
+       return bch2_trans_update(trans, iter, &wb->k,
+                                BTREE_UPDATE_INTERNAL_SNAPSHOT_NODE) ?:
+               bch2_trans_commit(trans, NULL, NULL,
+                                 BCH_TRANS_COMMIT_no_enospc|
+                                 BCH_TRANS_COMMIT_no_check_rw|
+                                 BCH_TRANS_COMMIT_no_journal_res|
+                                 BCH_TRANS_COMMIT_journal_reclaim);
+}
+
+static inline int wb_flush_one(struct btree_trans *trans, struct btree_iter *iter,
+                              struct btree_write_buffered_key *wb,
+                              bool *write_locked, size_t *fast)
 {
        struct bch_fs *c = trans->c;
        struct btree_path *path;
        int ret;
 
+       EBUG_ON(!wb->journal_seq);
        ret = bch2_btree_iter_traverse(iter);
        if (ret)
                return ret;
@@ -66,26 +81,14 @@ static int bch2_btree_write_buffer_flush_one(struct btree_trans *trans,
                *write_locked = true;
        }
 
-       if (!bch2_btree_node_insert_fits(c, path->l[0].b, wb->k.k.u64s)) {
-               bch2_btree_node_unlock_write(trans, path, path->l[0].b);
+       if (unlikely(!bch2_btree_node_insert_fits(c, path->l[0].b, wb->k.k.u64s))) {
                *write_locked = false;
-               goto trans_commit;
+               return wb_flush_one_slowpath(trans, iter, wb);
        }
 
        bch2_btree_insert_key_leaf(trans, path, &wb->k, wb->journal_seq);
        (*fast)++;
        return 0;
-trans_commit:
-       trans->journal_res.seq = wb->journal_seq;
-
-       return  bch2_trans_update(trans, iter, &wb->k,
-                                 BTREE_UPDATE_INTERNAL_SNAPSHOT_NODE) ?:
-               bch2_trans_commit(trans, NULL, NULL,
-                                 commit_flags|
-                                 BCH_TRANS_COMMIT_no_check_rw|
-                                 BCH_TRANS_COMMIT_no_enospc|
-                                 BCH_TRANS_COMMIT_no_journal_res|
-                                 BCH_TRANS_COMMIT_journal_reclaim);
 }
 
 static union btree_write_buffer_state btree_write_buffer_switch(struct btree_write_buffer *wb)
@@ -137,8 +140,7 @@ btree_write_buffered_insert(struct btree_trans *trans,
        return ret;
 }
 
-int __bch2_btree_write_buffer_flush(struct btree_trans *trans, unsigned commit_flags,
-                                   bool locked)
+int bch2_btree_write_buffer_flush_locked(struct btree_trans *trans)
 {
        struct bch_fs *c = trans->c;
        struct journal *j = &c->journal;
@@ -153,9 +155,6 @@ int __bch2_btree_write_buffer_flush(struct btree_trans *trans, unsigned commit_f
 
        memset(&pin, 0, sizeof(pin));
 
-       if (!locked && !mutex_trylock(&wb->flush_lock))
-               return 0;
-
        bch2_journal_pin_copy(j, &pin, &wb->journal_pin,
                              bch2_btree_write_buffer_journal_flush);
        bch2_journal_pin_drop(j, &wb->journal_pin);
@@ -164,9 +163,6 @@ int __bch2_btree_write_buffer_flush(struct btree_trans *trans, unsigned commit_f
        keys = wb->keys[s.idx];
        nr = s.nr;
 
-       if (race_fault())
-               goto slowpath;
-
        /*
         * We first sort so that we can detect and skip redundant updates, and
         * then we attempt to flush in sorted btree order, as this is most
@@ -210,81 +206,111 @@ int __bch2_btree_write_buffer_flush(struct btree_trans *trans, unsigned commit_f
                iter.path->preserve = false;
 
                do {
-                       ret = bch2_btree_write_buffer_flush_one(trans, &iter, i,
-                                               commit_flags, &write_locked, &fast);
+                       if (race_fault()) {
+                               ret = -BCH_ERR_journal_reclaim_would_deadlock;
+                               break;
+                       }
+
+                       ret = wb_flush_one(trans, &iter, i, &write_locked, &fast);
                        if (!write_locked)
                                bch2_trans_begin(trans);
                } while (bch2_err_matches(ret, BCH_ERR_transaction_restart));
 
-               if (ret == -BCH_ERR_journal_reclaim_would_deadlock) {
+               if (!ret) {
+                       i->journal_seq = 0;
+               } else if (ret == -BCH_ERR_journal_reclaim_would_deadlock) {
                        slowpath++;
-                       continue;
-               }
-               if (ret)
+                       ret = 0;
+               } else
                        break;
-
-               i->journal_seq = 0;
        }
 
        if (write_locked)
                bch2_btree_node_unlock_write(trans, iter.path, iter.path->l[0].b);
        bch2_trans_iter_exit(trans, &iter);
 
-       trace_write_buffer_flush(trans, nr, skipped, fast, wb->size);
-
-       if (slowpath)
-               goto slowpath;
-
+       if (ret)
+               goto err;
+
+       if (slowpath) {
+               /*
+                * Flush in the order they were present in the journal, so that
+                * we can release journal pins:
+                * The fastpath zapped the seq of keys that were successfully flushed so
+                * we can skip those here.
+                */
+               trace_and_count(c, write_buffer_flush_slowpath, trans, slowpath, nr);
+
+               sort(keys, nr, sizeof(keys[0]),
+                    btree_write_buffered_journal_cmp,
+                    NULL);
+
+               for (i = keys; i < keys + nr; i++) {
+                       if (!i->journal_seq)
+                               continue;
+
+                       bch2_journal_pin_update(j, i->journal_seq, &pin,
+                                     bch2_btree_write_buffer_journal_flush);
+
+                       ret = commit_do(trans, NULL, NULL,
+                                       BCH_WATERMARK_reclaim|
+                                       BCH_TRANS_COMMIT_no_check_rw|
+                                       BCH_TRANS_COMMIT_no_enospc|
+                                       BCH_TRANS_COMMIT_no_journal_res|
+                                       BCH_TRANS_COMMIT_journal_reclaim,
+                                       btree_write_buffered_insert(trans, i));
+                       if (ret)
+                               goto err;
+               }
+       }
+err:
        bch2_fs_fatal_err_on(ret, c, "%s: insert error %s", __func__, bch2_err_str(ret));
-out:
+       trace_write_buffer_flush(trans, nr, skipped, fast, wb->size);
        bch2_journal_pin_drop(j, &pin);
-       mutex_unlock(&wb->flush_lock);
        return ret;
-slowpath:
-       trace_write_buffer_flush_slowpath(trans, i - keys, nr);
+}
 
-       /*
-        * Now sort the rest by journal seq and bump the journal pin as we go.
-        * The slowpath zapped the seq of keys that were successfully flushed so
-        * we can skip those here.
-        */
-       sort(keys, nr, sizeof(keys[0]),
-            btree_write_buffered_journal_cmp,
-            NULL);
+int bch2_btree_write_buffer_flush_sync(struct btree_trans *trans)
+{
+       struct bch_fs *c = trans->c;
 
-       commit_flags &= ~BCH_WATERMARK_MASK;
-       commit_flags |= BCH_WATERMARK_reclaim;
+       if (!bch2_write_ref_tryget(c, BCH_WRITE_REF_btree_write_buffer))
+               return -BCH_ERR_erofs_no_writes;
 
-       for (i = keys; i < keys + nr; i++) {
-               if (!i->journal_seq)
-                       continue;
+       trace_and_count(c, write_buffer_flush_sync, trans, _RET_IP_);
 
-               bch2_journal_pin_update(j, i->journal_seq, &pin,
-                             bch2_btree_write_buffer_journal_flush);
+       bch2_trans_unlock(trans);
+       mutex_lock(&c->btree_write_buffer.flush_lock);
+       int ret = bch2_btree_write_buffer_flush_locked(trans);
+       mutex_unlock(&c->btree_write_buffer.flush_lock);
+       bch2_write_ref_put(c, BCH_WRITE_REF_btree_write_buffer);
+       return ret;
+}
 
-               ret = commit_do(trans, NULL, NULL,
-                               commit_flags|
-                               BCH_TRANS_COMMIT_no_enospc|
-                               BCH_TRANS_COMMIT_no_journal_res|
-                               BCH_TRANS_COMMIT_journal_reclaim,
-                               btree_write_buffered_insert(trans, i));
-               if (bch2_fs_fatal_err_on(ret, c, "%s: insert error %s", __func__, bch2_err_str(ret)))
-                       break;
+int bch2_btree_write_buffer_flush_nocheck_rw(struct btree_trans *trans)
+{
+       struct bch_fs *c = trans->c;
+       struct btree_write_buffer *wb = &c->btree_write_buffer;
+       int ret = 0;
+
+       if (mutex_trylock(&wb->flush_lock)) {
+               ret = bch2_btree_write_buffer_flush_locked(trans);
+               mutex_unlock(&wb->flush_lock);
        }
 
-       goto out;
+       return ret;
 }
 
-int bch2_btree_write_buffer_flush_sync(struct btree_trans *trans)
+int bch2_btree_write_buffer_tryflush(struct btree_trans *trans)
 {
-       bch2_trans_unlock(trans);
-       mutex_lock(&trans->c->btree_write_buffer.flush_lock);
-       return __bch2_btree_write_buffer_flush(trans, 0, true);
-}
+       struct bch_fs *c = trans->c;
 
-int bch2_btree_write_buffer_flush(struct btree_trans *trans)
-{
-       return __bch2_btree_write_buffer_flush(trans, 0, false);
+       if (!bch2_write_ref_tryget(c, BCH_WRITE_REF_btree_write_buffer))
+               return -BCH_ERR_erofs_no_writes;
+
+       int ret = bch2_btree_write_buffer_flush_nocheck_rw(trans);
+       bch2_write_ref_put(c, BCH_WRITE_REF_btree_write_buffer);
+       return ret;
 }
 
 static int bch2_btree_write_buffer_journal_flush(struct journal *j,
@@ -294,9 +320,10 @@ static int bch2_btree_write_buffer_journal_flush(struct journal *j,
        struct btree_write_buffer *wb = &c->btree_write_buffer;
 
        mutex_lock(&wb->flush_lock);
+       int ret = bch2_trans_run(c, bch2_btree_write_buffer_flush_locked(trans));
+       mutex_unlock(&wb->flush_lock);
 
-       return bch2_trans_run(c,
-                       __bch2_btree_write_buffer_flush(trans, BCH_TRANS_COMMIT_no_check_rw, true));
+       return ret;
 }
 
 static inline u64 btree_write_buffer_ref(int idx)