From 03d5eaed8624fdc7918478bffd05d67e773ac7d0 Mon Sep 17 00:00:00 2001 From: Kent Overstreet Date: Sun, 3 Mar 2019 16:50:40 -0500 Subject: [PATCH] bcachefs: bch2_journal_space_available improvements Signed-off-by: Kent Overstreet --- fs/bcachefs/journal.c | 2 +- fs/bcachefs/journal_io.c | 3 +- fs/bcachefs/journal_reclaim.c | 145 +++++++++++++++++++++------------- fs/bcachefs/journal_reclaim.h | 9 ++- 4 files changed, 103 insertions(+), 56 deletions(-) diff --git a/fs/bcachefs/journal.c b/fs/bcachefs/journal.c index 80d7980cf5aa5..5caa01881d004 100644 --- a/fs/bcachefs/journal.c +++ b/fs/bcachefs/journal.c @@ -1160,7 +1160,7 @@ ssize_t bch2_journal_print_debug(struct journal *j, char *buf) "\tdirty_idx\t\t%u (seq %llu)\n" "\tcur_idx\t\t%u (seq %llu)\n", iter, ja->nr, - bch2_journal_dev_buckets_available(j, ja), + bch2_journal_dev_buckets_available(j, ja, journal_space_discarded), ja->sectors_free, ja->discard_idx, ja->dirty_idx_ondisk, ja->bucket_seq[ja->dirty_idx_ondisk], diff --git a/fs/bcachefs/journal_io.c b/fs/bcachefs/journal_io.c index b6a51dff09784..07cfbb975c37f 100644 --- a/fs/bcachefs/journal_io.c +++ b/fs/bcachefs/journal_io.c @@ -970,7 +970,8 @@ static int journal_write_alloc(struct journal *j, struct journal_buf *w, if (sectors > ja->sectors_free && sectors <= ca->mi.bucket_size && - bch2_journal_dev_buckets_available(j, ja)) { + bch2_journal_dev_buckets_available(j, ja, + journal_space_discarded)) { ja->cur_idx = (ja->cur_idx + 1) % ja->nr; ja->sectors_free = ca->mi.bucket_size; } diff --git a/fs/bcachefs/journal_reclaim.c b/fs/bcachefs/journal_reclaim.c index ac9e6cb3d4eef..0884fc823cdf2 100644 --- a/fs/bcachefs/journal_reclaim.c +++ b/fs/bcachefs/journal_reclaim.c @@ -9,12 +9,28 @@ /* Free space calculations: */ +static unsigned journal_space_from(struct journal_device *ja, + enum journal_space_from from) +{ + switch (from) { + case journal_space_discarded: + return ja->discard_idx; + case journal_space_clean_ondisk: + return ja->dirty_idx_ondisk; + case journal_space_clean: + return ja->dirty_idx; + default: + BUG(); + } +} + unsigned bch2_journal_dev_buckets_available(struct journal *j, - struct journal_device *ja) + struct journal_device *ja, + enum journal_space_from from) { struct bch_fs *c = container_of(j, struct bch_fs, journal); - unsigned next = (ja->cur_idx + 1) % ja->nr; - unsigned available = (ja->discard_idx + ja->nr - next) % ja->nr; + unsigned available = (journal_space_from(ja, from) - + ja->cur_idx - 1 + ja->nr) % ja->nr; /* * Allocator startup needs some journal space before we can do journal @@ -33,53 +49,22 @@ unsigned bch2_journal_dev_buckets_available(struct journal *j, return available; } -void bch2_journal_space_available(struct journal *j) +static struct journal_space { + unsigned next_entry; + unsigned remaining; +} __journal_space_available(struct journal *j, unsigned nr_devs_want, + enum journal_space_from from) { struct bch_fs *c = container_of(j, struct bch_fs, journal); struct bch_dev *ca; unsigned sectors_next_entry = UINT_MAX; unsigned sectors_total = UINT_MAX; - unsigned max_entry_size = min(j->buf[0].buf_size >> 9, - j->buf[1].buf_size >> 9); - unsigned i, nr_online = 0, nr_devs = 0; + unsigned i, nr_devs = 0; unsigned unwritten_sectors = j->reservations.prev_buf_unwritten ? journal_prev_buf(j)->sectors : 0; - bool can_discard = false; - int ret = 0; - - lockdep_assert_held(&j->lock); rcu_read_lock(); - for_each_member_device_rcu(ca, c, i, - &c->rw_devs[BCH_DATA_JOURNAL]) { - struct journal_device *ja = &ca->journal; - - if (!ja->nr) - continue; - - while (ja->dirty_idx != ja->cur_idx && - ja->bucket_seq[ja->dirty_idx] < journal_last_seq(j)) - ja->dirty_idx = (ja->dirty_idx + 1) % ja->nr; - - while (ja->dirty_idx_ondisk != ja->dirty_idx && - ja->bucket_seq[ja->dirty_idx_ondisk] < j->last_seq_ondisk) - ja->dirty_idx_ondisk = (ja->dirty_idx_ondisk + 1) % ja->nr; - - if (ja->discard_idx != ja->dirty_idx_ondisk) - can_discard = true; - - nr_online++; - } - - j->can_discard = can_discard; - - if (nr_online < c->opts.metadata_replicas_required) { - ret = -EROFS; - sectors_next_entry = 0; - goto out; - } - for_each_member_device_rcu(ca, c, i, &c->rw_devs[BCH_DATA_JOURNAL]) { struct journal_device *ja = &ca->journal; @@ -88,7 +73,7 @@ void bch2_journal_space_available(struct journal *j) if (!ja->nr) continue; - buckets_this_device = bch2_journal_dev_buckets_available(j, ja); + buckets_this_device = bch2_journal_dev_buckets_available(j, ja, from); sectors_this_device = ja->sectors_free; /* @@ -121,24 +106,78 @@ void bch2_journal_space_available(struct journal *j) buckets_this_device * ca->mi.bucket_size + sectors_this_device); - max_entry_size = min_t(unsigned, max_entry_size, - ca->mi.bucket_size); - nr_devs++; } + rcu_read_unlock(); - if (!sectors_next_entry || - nr_devs < min_t(unsigned, nr_online, c->opts.metadata_replicas)) { - ret = -ENOSPC; - sectors_next_entry = 0; - } else if (!fifo_free(&j->pin)) { - ret = -ENOSPC; - sectors_next_entry = 0; + if (nr_devs < nr_devs_want) + return (struct journal_space) { 0, 0 }; + + return (struct journal_space) { + .next_entry = sectors_next_entry, + .remaining = max_t(int, 0, sectors_total - sectors_next_entry), + }; +} + +void bch2_journal_space_available(struct journal *j) +{ + struct bch_fs *c = container_of(j, struct bch_fs, journal); + struct bch_dev *ca; + struct journal_space discarded, clean_ondisk, clean; + unsigned max_entry_size = min(j->buf[0].buf_size >> 9, + j->buf[1].buf_size >> 9); + unsigned i, nr_online = 0, nr_devs_want; + bool can_discard = false; + int ret = 0; + + lockdep_assert_held(&j->lock); + + rcu_read_lock(); + for_each_member_device_rcu(ca, c, i, + &c->rw_devs[BCH_DATA_JOURNAL]) { + struct journal_device *ja = &ca->journal; + + if (!ja->nr) + continue; + + while (ja->dirty_idx != ja->cur_idx && + ja->bucket_seq[ja->dirty_idx] < journal_last_seq(j)) + ja->dirty_idx = (ja->dirty_idx + 1) % ja->nr; + + while (ja->dirty_idx_ondisk != ja->dirty_idx && + ja->bucket_seq[ja->dirty_idx_ondisk] < j->last_seq_ondisk) + ja->dirty_idx_ondisk = (ja->dirty_idx_ondisk + 1) % ja->nr; + + if (ja->discard_idx != ja->dirty_idx_ondisk) + can_discard = true; + + max_entry_size = min_t(unsigned, max_entry_size, ca->mi.bucket_size); + nr_online++; } -out: rcu_read_unlock(); - j->cur_entry_sectors = sectors_next_entry; + j->can_discard = can_discard; + + if (nr_online < c->opts.metadata_replicas_required) { + ret = -EROFS; + goto out; + } + + if (!fifo_free(&j->pin)) { + ret = -ENOSPC; + goto out; + } + + nr_devs_want = min_t(unsigned, nr_online, c->opts.metadata_replicas); + + discarded = __journal_space_available(j, nr_devs_want, journal_space_discarded); + clean_ondisk = __journal_space_available(j, nr_devs_want, journal_space_clean_ondisk); + clean = __journal_space_available(j, nr_devs_want, journal_space_clean); + + if (!discarded.next_entry) + ret = -ENOSPC; +out: + j->cur_entry_sectors = !ret ? discarded.next_entry : 0; j->cur_entry_error = ret; if (!ret) diff --git a/fs/bcachefs/journal_reclaim.h b/fs/bcachefs/journal_reclaim.h index 183419ea3e252..71545ad3bd58c 100644 --- a/fs/bcachefs/journal_reclaim.h +++ b/fs/bcachefs/journal_reclaim.h @@ -4,8 +4,15 @@ #define JOURNAL_PIN (32 * 1024) +enum journal_space_from { + journal_space_discarded, + journal_space_clean_ondisk, + journal_space_clean, +}; + unsigned bch2_journal_dev_buckets_available(struct journal *, - struct journal_device *); + struct journal_device *, + enum journal_space_from); void bch2_journal_space_available(struct journal *); static inline bool journal_pin_active(struct journal_entry_pin *pin) -- 2.30.2