summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@gmail.com>2020-06-09 20:54:36 -0400
committerKent Overstreet <kent.overstreet@gmail.com>2020-06-09 21:32:47 -0400
commitbcd09245ba31309ca78fbaed81cf908ae66569f9 (patch)
tree97e71f047d349e8dbdfa2f638e9ac0e6d3ff23f5
parent4731055fa223be13e3a7c1160b88297100741641 (diff)
bcachefs: Always give out journal pre-res if we already have one
This is better than skipping the journal pre-reservation if we already have one - we should still acount for the journal reservation we're going to have to get. Signed-off-by: Kent Overstreet <kent.overstreet@gmail.com>
-rw-r--r--fs/bcachefs/btree_update_interior.c15
-rw-r--r--fs/bcachefs/journal.c10
-rw-r--r--fs/bcachefs/journal.h20
3 files changed, 30 insertions, 15 deletions
diff --git a/fs/bcachefs/btree_update_interior.c b/fs/bcachefs/btree_update_interior.c
index c18b21b50c9c..932e45548510 100644
--- a/fs/bcachefs/btree_update_interior.c
+++ b/fs/bcachefs/btree_update_interior.c
@@ -864,8 +864,11 @@ bch2_btree_update_start(struct btree_trans *trans, enum btree_id id,
{
struct bch_fs *c = trans->c;
struct btree_update *as;
- int ret, disk_res_flags = (flags & BTREE_INSERT_NOFAIL)
+ int disk_res_flags = (flags & BTREE_INSERT_NOFAIL)
? BCH_DISK_RESERVATION_NOFAIL : 0;
+ int journal_flags = (flags & BTREE_INSERT_JOURNAL_RESERVED)
+ ? JOURNAL_RES_GET_RECLAIM : 0;
+ int ret = 0;
/*
* This check isn't necessary for correctness - it's just to potentially
@@ -888,10 +891,9 @@ bch2_btree_update_start(struct btree_trans *trans, enum btree_id id,
bch2_keylist_init(&as->new_keys, as->_new_keys);
bch2_keylist_init(&as->parent_keys, as->inline_keys);
- if (!(flags & BTREE_INSERT_JOURNAL_RESERVED))
- ret = bch2_journal_preres_get(&c->journal, &as->journal_preres,
- BTREE_UPDATE_JOURNAL_RES,
- JOURNAL_RES_GET_NONBLOCK);
+ ret = bch2_journal_preres_get(&c->journal, &as->journal_preres,
+ BTREE_UPDATE_JOURNAL_RES,
+ journal_flags|JOURNAL_RES_GET_NONBLOCK);
if (ret == -EAGAIN) {
if (flags & BTREE_INSERT_NOUNLOCK)
return ERR_PTR(-EINTR);
@@ -899,7 +901,8 @@ bch2_btree_update_start(struct btree_trans *trans, enum btree_id id,
bch2_trans_unlock(trans);
ret = bch2_journal_preres_get(&c->journal, &as->journal_preres,
- BTREE_UPDATE_JOURNAL_RES, 0);
+ BTREE_UPDATE_JOURNAL_RES,
+ journal_flags);
if (ret)
return ERR_PTR(ret);
diff --git a/fs/bcachefs/journal.c b/fs/bcachefs/journal.c
index 17dc60d98dc3..ab4134305bba 100644
--- a/fs/bcachefs/journal.c
+++ b/fs/bcachefs/journal.c
@@ -428,9 +428,10 @@ int bch2_journal_res_get_slowpath(struct journal *j, struct journal_res *res,
static bool journal_preres_available(struct journal *j,
struct journal_preres *res,
- unsigned new_u64s)
+ unsigned new_u64s,
+ unsigned flags)
{
- bool ret = bch2_journal_preres_get_fast(j, res, new_u64s);
+ bool ret = bch2_journal_preres_get_fast(j, res, new_u64s, flags);
if (!ret)
bch2_journal_reclaim_work(&j->reclaim_work.work);
@@ -440,13 +441,14 @@ static bool journal_preres_available(struct journal *j,
int __bch2_journal_preres_get(struct journal *j,
struct journal_preres *res,
- unsigned new_u64s)
+ unsigned new_u64s,
+ unsigned flags)
{
int ret;
closure_wait_event(&j->preres_wait,
(ret = bch2_journal_error(j)) ||
- journal_preres_available(j, res, new_u64s));
+ journal_preres_available(j, res, new_u64s, flags));
return ret;
}
diff --git a/fs/bcachefs/journal.h b/fs/bcachefs/journal.h
index 997a28ae862e..30de6d96188e 100644
--- a/fs/bcachefs/journal.h
+++ b/fs/bcachefs/journal.h
@@ -299,6 +299,7 @@ int bch2_journal_res_get_slowpath(struct journal *, struct journal_res *,
#define JOURNAL_RES_GET_NONBLOCK (1 << 0)
#define JOURNAL_RES_GET_CHECK (1 << 1)
#define JOURNAL_RES_GET_RESERVED (1 << 2)
+#define JOURNAL_RES_GET_RECLAIM (1 << 3)
static inline int journal_res_get_fast(struct journal *j,
struct journal_res *res,
@@ -406,11 +407,12 @@ static inline void bch2_journal_preres_put(struct journal *j,
}
int __bch2_journal_preres_get(struct journal *,
- struct journal_preres *, unsigned);
+ struct journal_preres *, unsigned, unsigned);
static inline int bch2_journal_preres_get_fast(struct journal *j,
struct journal_preres *res,
- unsigned new_u64s)
+ unsigned new_u64s,
+ unsigned flags)
{
int d = new_u64s - res->u64s;
union journal_preres_state old, new;
@@ -421,7 +423,15 @@ static inline int bch2_journal_preres_get_fast(struct journal *j,
new.reserved += d;
- if (new.reserved > new.remaining)
+ /*
+ * If we're being called from the journal reclaim path, we have
+ * to unconditionally give out the pre-reservation, there's
+ * nothing else sensible we can do - otherwise we'd recurse back
+ * into the reclaim path and deadlock:
+ */
+
+ if (!(flags & JOURNAL_RES_GET_RECLAIM) &&
+ new.reserved > new.remaining)
return 0;
} while ((v = atomic64_cmpxchg(&j->prereserved.counter,
old.v, new.v)) != old.v);
@@ -438,13 +448,13 @@ static inline int bch2_journal_preres_get(struct journal *j,
if (new_u64s <= res->u64s)
return 0;
- if (bch2_journal_preres_get_fast(j, res, new_u64s))
+ if (bch2_journal_preres_get_fast(j, res, new_u64s, flags))
return 0;
if (flags & JOURNAL_RES_GET_NONBLOCK)
return -EAGAIN;
- return __bch2_journal_preres_get(j, res, new_u64s);
+ return __bch2_journal_preres_get(j, res, new_u64s, flags);
}
/* journal_entry_res: */