Commit b7ba66c8 authored by Kent Overstreet's avatar Kent Overstreet Committed by Kent Overstreet

bcachefs: Inline more of bch2_trans_commit hot path

The main optimization here is that if we let
bch2_replicas_delta_list_apply() fail, we can completely skip calling
bch2_bkey_replicas_marked_locked().

And assorted other small optimizations.
Signed-off-by: default avatarKent Overstreet <kent.overstreet@linux.dev>
parent ff929515
...@@ -64,21 +64,9 @@ static inline int btree_iter_pos_cmp(struct btree_iter *iter, ...@@ -64,21 +64,9 @@ static inline int btree_iter_pos_cmp(struct btree_iter *iter,
/* Btree node locking: */ /* Btree node locking: */
/*
* Updates the saved lock sequence number, so that bch2_btree_node_relock() will
* succeed:
*/
void bch2_btree_node_unlock_write(struct btree *b, struct btree_iter *iter) void bch2_btree_node_unlock_write(struct btree *b, struct btree_iter *iter)
{ {
struct btree_iter *linked; bch2_btree_node_unlock_write_inlined(b, iter);
EBUG_ON(iter->l[b->c.level].b != b);
EBUG_ON(iter->l[b->c.level].lock_seq + 1 != b->c.lock.state.seq);
trans_for_each_iter_with_node(iter->trans, b, linked)
linked->l[b->c.level].lock_seq += 2;
six_unlock_write(&b->c.lock);
} }
void __bch2_btree_node_lock_write(struct btree *b, struct btree_iter *iter) void __bch2_btree_node_lock_write(struct btree *b, struct btree_iter *iter)
......
...@@ -202,6 +202,24 @@ static inline bool bch2_btree_node_relock(struct btree_iter *iter, ...@@ -202,6 +202,24 @@ static inline bool bch2_btree_node_relock(struct btree_iter *iter,
__bch2_btree_node_relock(iter, level); __bch2_btree_node_relock(iter, level);
} }
/*
* Updates the saved lock sequence number, so that bch2_btree_node_relock() will
* succeed:
*/
static inline void
bch2_btree_node_unlock_write_inlined(struct btree *b, struct btree_iter *iter)
{
struct btree_iter *linked;
EBUG_ON(iter->l[b->c.level].b != b);
EBUG_ON(iter->l[b->c.level].lock_seq + 1 != b->c.lock.state.seq);
trans_for_each_iter_with_node(iter->trans, b, linked)
linked->l[b->c.level].lock_seq += 2;
six_unlock_write(&b->c.lock);
}
void bch2_btree_node_unlock_write(struct btree *, struct btree_iter *); void bch2_btree_node_unlock_write(struct btree *, struct btree_iter *);
void __bch2_btree_node_lock_write(struct btree *, struct btree_iter *); void __bch2_btree_node_lock_write(struct btree *, struct btree_iter *);
......
...@@ -284,17 +284,17 @@ static inline unsigned btree_write_set_buffer(struct btree *b) ...@@ -284,17 +284,17 @@ static inline unsigned btree_write_set_buffer(struct btree *b)
static inline struct btree_node_entry *want_new_bset(struct bch_fs *c, static inline struct btree_node_entry *want_new_bset(struct bch_fs *c,
struct btree *b) struct btree *b)
{ {
struct bset *i = btree_bset_last(b); struct bset_tree *t = bset_tree_last(b);
struct btree_node_entry *bne = max(write_block(b), struct btree_node_entry *bne = max(write_block(b),
(void *) btree_bkey_last(b, bset_tree_last(b))); (void *) btree_bkey_last(b, bset_tree_last(b)));
ssize_t remaining_space = ssize_t remaining_space =
__bch_btree_u64s_remaining(c, b, &bne->keys.start[0]); __bch_btree_u64s_remaining(c, b, &bne->keys.start[0]);
if (unlikely(bset_written(b, i))) { if (unlikely(bset_written(b, bset(b, t)))) {
if (remaining_space > (ssize_t) (block_bytes(c) >> 3)) if (remaining_space > (ssize_t) (block_bytes(c) >> 3))
return bne; return bne;
} else { } else {
if (unlikely(vstruct_bytes(i) > btree_write_set_buffer(b)) && if (unlikely(bset_u64s(t) * sizeof(u64) > btree_write_set_buffer(b)) &&
remaining_space > (ssize_t) (btree_write_set_buffer(b) >> 3)) remaining_space > (ssize_t) (btree_write_set_buffer(b) >> 3))
return bne; return bne;
} }
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include "replicas.h" #include "replicas.h"
#include "trace.h" #include "trace.h"
#include <linux/prefetch.h>
#include <linux/sort.h> #include <linux/sort.h>
static inline bool same_leaf_as_prev(struct btree_trans *trans, static inline bool same_leaf_as_prev(struct btree_trans *trans,
...@@ -50,23 +51,6 @@ inline void bch2_btree_node_lock_for_insert(struct bch_fs *c, struct btree *b, ...@@ -50,23 +51,6 @@ inline void bch2_btree_node_lock_for_insert(struct bch_fs *c, struct btree *b,
bch2_btree_init_next(c, b, iter); bch2_btree_init_next(c, b, iter);
} }
static void btree_trans_lock_write(struct btree_trans *trans, bool lock)
{
struct bch_fs *c = trans->c;
struct btree_insert_entry *i;
unsigned iter;
trans_for_each_update_sorted(trans, i, iter) {
if (same_leaf_as_prev(trans, iter))
continue;
if (lock)
bch2_btree_node_lock_for_insert(c, i->iter->l[0].b, i->iter);
else
bch2_btree_node_unlock_write(i->iter->l[0].b, i->iter);
}
}
static inline void btree_trans_sort_updates(struct btree_trans *trans) static inline void btree_trans_sort_updates(struct btree_trans *trans)
{ {
struct btree_insert_entry *l, *r; struct btree_insert_entry *l, *r;
...@@ -377,29 +361,6 @@ btree_key_can_insert(struct btree_trans *trans, ...@@ -377,29 +361,6 @@ btree_key_can_insert(struct btree_trans *trans,
return BTREE_INSERT_OK; return BTREE_INSERT_OK;
} }
static int btree_trans_check_can_insert(struct btree_trans *trans,
struct btree_insert_entry **stopped_at)
{
struct btree_insert_entry *i;
unsigned iter, u64s = 0;
int ret;
trans_for_each_update_sorted(trans, i, iter) {
/* Multiple inserts might go to same leaf: */
if (!same_leaf_as_prev(trans, iter))
u64s = 0;
u64s += i->k->k.u64s;
ret = btree_key_can_insert(trans, i, &u64s);
if (ret) {
*stopped_at = i;
return ret;
}
}
return 0;
}
static inline void do_btree_insert_one(struct btree_trans *trans, static inline void do_btree_insert_one(struct btree_trans *trans,
struct btree_insert_entry *insert) struct btree_insert_entry *insert)
{ {
...@@ -450,6 +411,8 @@ bch2_trans_commit_write_locked(struct btree_trans *trans, ...@@ -450,6 +411,8 @@ bch2_trans_commit_write_locked(struct btree_trans *trans,
unsigned mark_flags = trans->flags & BTREE_INSERT_BUCKET_INVALIDATE unsigned mark_flags = trans->flags & BTREE_INSERT_BUCKET_INVALIDATE
? BCH_BUCKET_MARK_BUCKET_INVALIDATE ? BCH_BUCKET_MARK_BUCKET_INVALIDATE
: 0; : 0;
unsigned iter, u64s = 0;
bool marking = false;
int ret; int ret;
if (race_fault()) { if (race_fault()) {
...@@ -462,25 +425,28 @@ bch2_trans_commit_write_locked(struct btree_trans *trans, ...@@ -462,25 +425,28 @@ bch2_trans_commit_write_locked(struct btree_trans *trans,
* held, otherwise another thread could write the node changing the * held, otherwise another thread could write the node changing the
* amount of space available: * amount of space available:
*/ */
ret = btree_trans_check_can_insert(trans, stopped_at);
if (ret)
return ret;
trans_for_each_update(trans, i) { prefetch(&trans->c->journal.flags);
if (!btree_node_type_needs_gc(i->iter->btree_id))
continue;
if (!fs_usage) { trans_for_each_update_sorted(trans, i, iter) {
percpu_down_read(&c->mark_lock); /* Multiple inserts might go to same leaf: */
fs_usage = bch2_fs_usage_scratch_get(c); if (!same_leaf_as_prev(trans, iter))
} u64s = 0;
/* Must be called under mark_lock: */ u64s += i->k->k.u64s;
if (!bch2_bkey_replicas_marked_locked(c, ret = btree_key_can_insert(trans, i, &u64s);
bkey_i_to_s_c(i->k), true)) { if (ret) {
ret = BTREE_INSERT_NEED_MARK_REPLICAS; *stopped_at = i;
goto err; return ret;
} }
if (btree_node_type_needs_gc(i->iter->btree_id))
marking = true;
}
if (marking) {
percpu_down_read(&c->mark_lock);
fs_usage = bch2_fs_usage_scratch_get(c);
} }
/* /*
...@@ -508,16 +474,20 @@ bch2_trans_commit_write_locked(struct btree_trans *trans, ...@@ -508,16 +474,20 @@ bch2_trans_commit_write_locked(struct btree_trans *trans,
i->k->k.version = MAX_VERSION; i->k->k.version = MAX_VERSION;
} }
/* Must be called under mark_lock: */
if (marking && trans->fs_usage_deltas &&
bch2_replicas_delta_list_apply(c, &fs_usage->u,
trans->fs_usage_deltas)) {
ret = BTREE_INSERT_NEED_MARK_REPLICAS;
goto err;
}
trans_for_each_update(trans, i) trans_for_each_update(trans, i)
if (likely(!(trans->flags & BTREE_INSERT_NOMARK)) && if (likely(!(trans->flags & BTREE_INSERT_NOMARK)) &&
update_has_nontrans_triggers(i)) update_has_nontrans_triggers(i))
bch2_mark_update(trans, i, &fs_usage->u, mark_flags); bch2_mark_update(trans, i, &fs_usage->u, mark_flags);
if (fs_usage && trans->fs_usage_deltas) if (marking)
bch2_replicas_delta_list_apply(c, &fs_usage->u,
trans->fs_usage_deltas);
if (fs_usage)
bch2_trans_fs_usage_apply(trans, fs_usage); bch2_trans_fs_usage_apply(trans, fs_usage);
if (unlikely(c->gc_pos.phase)) if (unlikely(c->gc_pos.phase))
...@@ -526,7 +496,7 @@ bch2_trans_commit_write_locked(struct btree_trans *trans, ...@@ -526,7 +496,7 @@ bch2_trans_commit_write_locked(struct btree_trans *trans,
trans_for_each_update(trans, i) trans_for_each_update(trans, i)
do_btree_insert_one(trans, i); do_btree_insert_one(trans, i);
err: err:
if (fs_usage) { if (marking) {
bch2_fs_usage_scratch_put(c, fs_usage); bch2_fs_usage_scratch_put(c, fs_usage);
percpu_up_read(&c->mark_lock); percpu_up_read(&c->mark_lock);
} }
...@@ -609,9 +579,17 @@ static inline int do_bch2_trans_commit(struct btree_trans *trans, ...@@ -609,9 +579,17 @@ static inline int do_bch2_trans_commit(struct btree_trans *trans,
*/ */
btree_trans_sort_updates(trans); btree_trans_sort_updates(trans);
btree_trans_lock_write(trans, true); trans_for_each_update_sorted(trans, i, idx)
if (!same_leaf_as_prev(trans, idx))
bch2_btree_node_lock_for_insert(trans->c,
i->iter->l[0].b, i->iter);
ret = bch2_trans_commit_write_locked(trans, stopped_at); ret = bch2_trans_commit_write_locked(trans, stopped_at);
btree_trans_lock_write(trans, false);
trans_for_each_update_sorted(trans, i, idx)
if (!same_leaf_as_prev(trans, idx))
bch2_btree_node_unlock_write_inlined(i->iter->l[0].b,
i->iter);
/* /*
* Drop journal reservation after dropping write locks, since dropping * Drop journal reservation after dropping write locks, since dropping
......
...@@ -498,14 +498,18 @@ void bch2_dev_usage_from_buckets(struct bch_fs *c) ...@@ -498,14 +498,18 @@ void bch2_dev_usage_from_buckets(struct bch_fs *c)
} }
} }
static inline void update_replicas(struct bch_fs *c, static inline int update_replicas(struct bch_fs *c,
struct bch_fs_usage *fs_usage, struct bch_fs_usage *fs_usage,
struct bch_replicas_entry *r, struct bch_replicas_entry *r,
s64 sectors) s64 sectors)
{ {
int idx = bch2_replicas_entry_idx(c, r); int idx = bch2_replicas_entry_idx(c, r);
BUG_ON(idx < 0); if (idx < 0)
return -1;
if (!fs_usage)
return 0;
switch (r->data_type) { switch (r->data_type) {
case BCH_DATA_BTREE: case BCH_DATA_BTREE:
...@@ -519,6 +523,7 @@ static inline void update_replicas(struct bch_fs *c, ...@@ -519,6 +523,7 @@ static inline void update_replicas(struct bch_fs *c,
break; break;
} }
fs_usage->replicas[idx] += sectors; fs_usage->replicas[idx] += sectors;
return 0;
} }
static inline void update_cached_sectors(struct bch_fs *c, static inline void update_cached_sectors(struct bch_fs *c,
...@@ -579,14 +584,29 @@ static inline void update_cached_sectors_list(struct btree_trans *trans, ...@@ -579,14 +584,29 @@ static inline void update_cached_sectors_list(struct btree_trans *trans,
update_replicas_list(trans, &r.e, sectors); update_replicas_list(trans, &r.e, sectors);
} }
void bch2_replicas_delta_list_apply(struct bch_fs *c, static inline struct replicas_delta *
struct bch_fs_usage *fs_usage, replicas_delta_next(struct replicas_delta *d)
struct replicas_delta_list *r) {
return (void *) d + replicas_entry_bytes(&d->r) + 8;
}
int bch2_replicas_delta_list_apply(struct bch_fs *c,
struct bch_fs_usage *fs_usage,
struct replicas_delta_list *r)
{ {
struct replicas_delta *d = r->d; struct replicas_delta *d = r->d;
struct replicas_delta *top = (void *) r->d + r->used; struct replicas_delta *top = (void *) r->d + r->used;
unsigned i; unsigned i;
for (d = r->d; d != top; d = replicas_delta_next(d))
if (update_replicas(c, fs_usage, &d->r, d->delta)) {
top = d;
goto unwind;
}
if (!fs_usage)
return 0;
fs_usage->nr_inodes += r->nr_inodes; fs_usage->nr_inodes += r->nr_inodes;
for (i = 0; i < BCH_REPLICAS_MAX; i++) { for (i = 0; i < BCH_REPLICAS_MAX; i++) {
...@@ -594,13 +614,11 @@ void bch2_replicas_delta_list_apply(struct bch_fs *c, ...@@ -594,13 +614,11 @@ void bch2_replicas_delta_list_apply(struct bch_fs *c,
fs_usage->persistent_reserved[i] += r->persistent_reserved[i]; fs_usage->persistent_reserved[i] += r->persistent_reserved[i];
} }
while (d != top) { return 0;
BUG_ON((void *) d > (void *) top); unwind:
for (d = r->d; d != top; d = replicas_delta_next(d))
update_replicas(c, fs_usage, &d->r, d->delta); update_replicas(c, fs_usage, &d->r, -d->delta);
return -1;
d = (void *) d + replicas_entry_bytes(&d->r) + 8;
}
} }
#define do_mark_fn(fn, c, pos, flags, ...) \ #define do_mark_fn(fn, c, pos, flags, ...) \
......
...@@ -279,9 +279,9 @@ int bch2_mark_overwrite(struct btree_trans *, struct btree_iter *, ...@@ -279,9 +279,9 @@ int bch2_mark_overwrite(struct btree_trans *, struct btree_iter *,
int bch2_mark_update(struct btree_trans *, struct btree_insert_entry *, int bch2_mark_update(struct btree_trans *, struct btree_insert_entry *,
struct bch_fs_usage *, unsigned); struct bch_fs_usage *, unsigned);
void bch2_replicas_delta_list_apply(struct bch_fs *, int bch2_replicas_delta_list_apply(struct bch_fs *,
struct bch_fs_usage *, struct bch_fs_usage *,
struct replicas_delta_list *); struct replicas_delta_list *);
int bch2_trans_mark_key(struct btree_trans *, struct bkey_s_c, int bch2_trans_mark_key(struct btree_trans *, struct bkey_s_c,
unsigned, s64, unsigned); unsigned, s64, unsigned);
int bch2_trans_mark_update(struct btree_trans *, int bch2_trans_mark_update(struct btree_trans *,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment