diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/bcachefs/btree_update_interior.c | 15 | ||||
-rw-r--r-- | fs/bcachefs/journal.c | 10 | ||||
-rw-r--r-- | fs/bcachefs/journal.h | 20 |
3 files changed, 30 insertions, 15 deletions
diff --git a/fs/bcachefs/btree_update_interior.c b/fs/bcachefs/btree_update_interior.c index 8f4087db7b67..bb921852a093 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 48607e01bd22..767cb6f809e7 100644 --- a/fs/bcachefs/journal.c +++ b/fs/bcachefs/journal.c @@ -427,9 +427,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); @@ -439,13 +440,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 2c55f74522e2..f14dfa59e702 100644 --- a/fs/bcachefs/journal.h +++ b/fs/bcachefs/journal.h @@ -301,6 +301,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, @@ -408,11 +409,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; @@ -423,7 +425,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); @@ -440,13 +450,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: */ |