summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@gmail.com>2021-04-04 04:31:02 +0300
committerKent Overstreet <kent.overstreet@linux.dev>2023-10-23 00:08:59 +0300
commit671cc8a51b019b49a8538aceaaa5e770c1694c1b (patch)
tree712f2a3ec1ecb449caa883416e04fb1dfd8cd03d
parent08e337618f67abb9be1ff4b022a14e8721c5def2 (diff)
downloadlinux-671cc8a51b019b49a8538aceaaa5e770c1694c1b.tar.xz
bcachefs: Eliminate memory barrier from fast path of journal_preres_put()
Signed-off-by: Kent Overstreet <kent.overstreet@gmail.com> Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
-rw-r--r--fs/bcachefs/journal.c2
-rw-r--r--fs/bcachefs/journal.h39
-rw-r--r--fs/bcachefs/journal_types.h5
3 files changed, 26 insertions, 20 deletions
diff --git a/fs/bcachefs/journal.c b/fs/bcachefs/journal.c
index bce056cb6841..35a48629b63b 100644
--- a/fs/bcachefs/journal.c
+++ b/fs/bcachefs/journal.c
@@ -520,7 +520,7 @@ static bool journal_preres_available(struct journal *j,
unsigned new_u64s,
unsigned flags)
{
- bool ret = bch2_journal_preres_get_fast(j, res, new_u64s, flags);
+ bool ret = bch2_journal_preres_get_fast(j, res, new_u64s, flags, true);
if (!ret && mutex_trylock(&j->reclaim_lock)) {
bch2_journal_reclaim(j);
diff --git a/fs/bcachefs/journal.h b/fs/bcachefs/journal.h
index a0d19fad3bdd..cc497125889f 100644
--- a/fs/bcachefs/journal.h
+++ b/fs/bcachefs/journal.h
@@ -411,7 +411,12 @@ static inline void bch2_journal_preres_put(struct journal *j,
s.v = atomic64_sub_return(s.v, &j->prereserved.counter);
res->u64s = 0;
- closure_wake_up(&j->preres_wait);
+
+ if (unlikely(s.waiting)) {
+ clear_bit(ilog2((((union journal_preres_state) { .waiting = 1 }).v)),
+ (unsigned long *) &j->prereserved.v);
+ closure_wake_up(&j->preres_wait);
+ }
if (s.reserved <= s.remaining &&
!test_bit(JOURNAL_MAY_GET_UNRESERVED, &j->flags)) {
@@ -427,32 +432,32 @@ int __bch2_journal_preres_get(struct journal *,
static inline int bch2_journal_preres_get_fast(struct journal *j,
struct journal_preres *res,
unsigned new_u64s,
- unsigned flags)
+ unsigned flags,
+ bool set_waiting)
{
int d = new_u64s - res->u64s;
union journal_preres_state old, new;
u64 v = atomic64_read(&j->prereserved.counter);
+ int ret;
do {
old.v = new.v = v;
-
- new.reserved += d;
-
- /*
- * 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_RESERVED) &&
- new.reserved > new.remaining)
+ ret = 0;
+
+ if ((flags & JOURNAL_RES_GET_RESERVED) ||
+ new.reserved + d < new.remaining) {
+ new.reserved += d;
+ ret = 1;
+ } else if (set_waiting && !new.waiting)
+ new.waiting = true;
+ else
return 0;
} while ((v = atomic64_cmpxchg(&j->prereserved.counter,
old.v, new.v)) != old.v);
- res->u64s += d;
- return 1;
+ if (ret)
+ res->u64s += d;
+ return ret;
}
static inline int bch2_journal_preres_get(struct journal *j,
@@ -463,7 +468,7 @@ 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, flags))
+ if (bch2_journal_preres_get_fast(j, res, new_u64s, flags, false))
return 0;
if (flags & JOURNAL_RES_GET_NONBLOCK)
diff --git a/fs/bcachefs/journal_types.h b/fs/bcachefs/journal_types.h
index ec3c604cdf22..97d764370b89 100644
--- a/fs/bcachefs/journal_types.h
+++ b/fs/bcachefs/journal_types.h
@@ -105,8 +105,9 @@ union journal_preres_state {
};
struct {
- u32 reserved;
- u32 remaining;
+ u64 waiting:1,
+ reserved:31,
+ remaining:32;
};
};