diff options
author | Kent Overstreet <kent.overstreet@gmail.com> | 2019-02-19 17:56:21 -0500 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@gmail.com> | 2019-03-04 02:37:52 -0500 |
commit | fc9061b8b4653a320bc6ad0271a95ab8d0fe2fea (patch) | |
tree | fd1303a11d24ca1471bad043f752abb03d66cfe6 | |
parent | 70cd1dabd8efa0e8a05c83c43ddc9033db1bc54a (diff) |
bcachefs: Use journal preres for deferred btree updates
-rw-r--r-- | fs/bcachefs/btree_types.h | 3 | ||||
-rw-r--r-- | fs/bcachefs/btree_update.h | 4 | ||||
-rw-r--r-- | fs/bcachefs/btree_update_leaf.c | 84 |
3 files changed, 76 insertions, 15 deletions
diff --git a/fs/bcachefs/btree_types.h b/fs/bcachefs/btree_types.h index b38722da18eb..15a4d382c210 100644 --- a/fs/bcachefs/btree_types.h +++ b/fs/bcachefs/btree_types.h @@ -245,10 +245,11 @@ struct btree_iter { #define BTREE_ITER_MAX 8 struct deferred_update { + struct journal_preres res; struct journal_entry_pin journal; spinlock_t lock; - unsigned gen; + unsigned dirty:1; u8 allocated_u64s; enum btree_id btree_id; diff --git a/fs/bcachefs/btree_update.h b/fs/bcachefs/btree_update.h index faacde9ae4bb..7545f4f153d5 100644 --- a/fs/bcachefs/btree_update.h +++ b/fs/bcachefs/btree_update.h @@ -26,6 +26,7 @@ struct btree_insert { struct bch_fs *c; struct disk_reservation *disk_res; struct journal_res journal_res; + struct journal_preres journal_preres; u64 *journal_seq; unsigned flags; bool did_work; @@ -81,6 +82,7 @@ enum { __BTREE_INSERT_USE_RESERVE, __BTREE_INSERT_USE_ALLOC_RESERVE, __BTREE_INSERT_JOURNAL_REPLAY, + __BTREE_INSERT_JOURNAL_RESERVED, __BTREE_INSERT_NOMARK, __BTREE_INSERT_NOWAIT, __BTREE_INSERT_GC_LOCK_HELD, @@ -111,6 +113,8 @@ enum { /* Insert is for journal replay - don't get journal reservations: */ #define BTREE_INSERT_JOURNAL_REPLAY (1 << __BTREE_INSERT_JOURNAL_REPLAY) +#define BTREE_INSERT_JOURNAL_RESERVED (1 << __BTREE_INSERT_JOURNAL_RESERVED) + /* Don't call bch2_mark_key: */ #define BTREE_INSERT_NOMARK (1 << __BTREE_INSERT_NOMARK) diff --git a/fs/bcachefs/btree_update_leaf.c b/fs/bcachefs/btree_update_leaf.c index da8c69871c76..4a4904e743c3 100644 --- a/fs/bcachefs/btree_update_leaf.c +++ b/fs/bcachefs/btree_update_leaf.c @@ -17,6 +17,9 @@ #include <linux/sort.h> #include <trace/events/bcachefs.h> +static bool btree_trans_relock(struct btree_insert *); +static void btree_trans_unlock(struct btree_insert *); + /* Inserting into a given leaf node (last stage of insert): */ /* Handle overwrites and do insert, for non extents: */ @@ -239,15 +242,15 @@ btree_insert_key_leaf(struct btree_insert *trans, /* Deferred btree updates: */ static void deferred_update_flush(struct journal *j, - struct journal_entry_pin *pin, - u64 seq) + struct journal_entry_pin *pin, + u64 seq) { struct bch_fs *c = container_of(j, struct bch_fs, journal); struct deferred_update *d = container_of(pin, struct deferred_update, journal); + struct journal_preres res = { 0 }; u64 tmp[32]; struct bkey_i *k = (void *) tmp; - unsigned gen; int ret; if (d->allocated_u64s > ARRAY_SIZE(tmp)) { @@ -257,26 +260,32 @@ static void deferred_update_flush(struct journal *j, } spin_lock(&d->lock); - gen = d->gen; + if (d->dirty) { + BUG_ON(jset_u64s(d->k.k.u64s) > d->res.u64s); + + swap(res, d->res); - if (journal_pin_active(&d->journal)) { BUG_ON(d->k.k.u64s > d->allocated_u64s); - bkey_copy(k, &d->k); + bkey_copy(k, &d->k); + d->dirty = false; spin_unlock(&d->lock); ret = bch2_btree_insert(c, d->btree_id, k, NULL, NULL, - BTREE_INSERT_NOFAIL); + BTREE_INSERT_NOFAIL| + BTREE_INSERT_USE_RESERVE| + BTREE_INSERT_JOURNAL_RESERVED); bch2_fs_fatal_err_on(ret && !bch2_journal_error(j), - c, "error flushing deferred btree update: %i", ret); + c, "error flushing deferred btree update: %i", ret); spin_lock(&d->lock); } - if (gen == d->gen) + if (!d->dirty) bch2_journal_pin_drop(j, &d->journal); spin_unlock(&d->lock); + bch2_journal_preres_put(j, &res); if (k != (void *) tmp) kfree(k); } @@ -288,6 +297,7 @@ btree_insert_key_deferred(struct btree_insert *trans, struct bch_fs *c = trans->c; struct journal *j = &c->journal; struct deferred_update *d = insert->d; + int difference; BUG_ON(trans->flags & BTREE_INSERT_JOURNAL_REPLAY); BUG_ON(insert->k->u64s > d->allocated_u64s); @@ -295,12 +305,21 @@ btree_insert_key_deferred(struct btree_insert *trans, __btree_journal_key(trans, d->btree_id, insert->k); spin_lock(&d->lock); - d->gen++; + BUG_ON(jset_u64s(insert->k->u64s) > + trans->journal_preres.u64s); + + difference = jset_u64s(insert->k->u64s) - d->res.u64s; + if (difference > 0) { + trans->journal_preres.u64s -= difference; + d->res.u64s += difference; + } + bkey_copy(&d->k, insert->k); - spin_unlock(&d->lock); + d->dirty = true; bch2_journal_pin_update(j, trans->journal_res.seq, &d->journal, deferred_update_flush); + spin_unlock(&d->lock); return BTREE_INSERT_OK; } @@ -519,13 +538,16 @@ retry: } if (likely(!(trans->flags & BTREE_INSERT_JOURNAL_REPLAY))) { + unsigned flags = (trans->flags & BTREE_INSERT_JOURNAL_RESERVED) + ? JOURNAL_RES_GET_RESERVED : 0; + u64s = 0; trans_for_each_entry(trans, i) u64s += jset_u64s(i->k->k.u64s); ret = bch2_journal_res_get(&c->journal, &trans->journal_res, u64s, - JOURNAL_RES_GET_NONBLOCK); + flags|JOURNAL_RES_GET_NONBLOCK); if (likely(!ret)) goto got_journal_res; if (ret != -EAGAIN) @@ -536,7 +558,7 @@ retry: ret = bch2_journal_res_get(&c->journal, &trans->journal_res, u64s, - JOURNAL_RES_GET_CHECK); + flags|JOURNAL_RES_GET_CHECK); if (ret) return ret; @@ -586,6 +608,10 @@ got_journal_res: } } out: + BUG_ON(ret && + (trans->flags & BTREE_INSERT_JOURNAL_RESERVED) && + trans->journal_res.ref); + multi_unlock_write(trans); bch2_journal_res_put(&c->journal, &trans->journal_res); @@ -627,7 +653,7 @@ int __bch2_btree_insert_at(struct btree_insert *trans) struct bch_fs *c = trans->c; struct btree_insert_entry *i; struct btree_iter *linked; - unsigned flags; + unsigned flags, u64s = 0; int ret; BUG_ON(!trans->nr); @@ -638,11 +664,39 @@ int __bch2_btree_insert_at(struct btree_insert *trans) if (trans->flags & BTREE_INSERT_GC_LOCK_HELD) lockdep_assert_held(&c->gc_lock); + memset(&trans->journal_preres, 0, sizeof(trans->journal_preres)); + bubble_sort(trans->entries, trans->nr, btree_trans_cmp); trans_for_each_entry(trans, i) btree_insert_entry_checks(c, i); + trans_for_each_entry(trans, i) + if (i->deferred) + u64s += jset_u64s(i->k->k.u64s); + + if (u64s) { + ret = bch2_journal_preres_get(&c->journal, + &trans->journal_preres, u64s, + JOURNAL_RES_GET_NONBLOCK); + if (!ret) + goto got_journal_preres; + if (ret != -EAGAIN) + return ret; + + btree_trans_unlock(trans); + ret = bch2_journal_preres_get(&c->journal, + &trans->journal_preres, u64s, 0); + if (ret) + return ret; + + if (!btree_trans_relock(trans)) { + trans_restart(" (iter relock after journal preres get blocked)"); + bch2_journal_preres_put(&c->journal, &trans->journal_preres); + return -EINTR; + } + } +got_journal_preres: if (unlikely(!(trans->flags & BTREE_INSERT_NOCHECK_RW) && !percpu_ref_tryget(&c->writes))) return -EROFS; @@ -674,6 +728,8 @@ retry: trans_for_each_iter(trans, i) bch2_btree_iter_downgrade(i->iter); out: + bch2_journal_preres_put(&c->journal, &trans->journal_preres); + if (unlikely(!(trans->flags & BTREE_INSERT_NOCHECK_RW))) percpu_ref_put(&c->writes); |