diff options
author | Kent Overstreet <kent.overstreet@gmail.com> | 2019-03-04 00:50:40 +0300 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@linux.dev> | 2023-10-23 00:08:17 +0300 |
commit | 03d5eaed8624fdc7918478bffd05d67e773ac7d0 (patch) | |
tree | e068c3ddb51b84a40bf0055472eef920e24e2dda /fs/bcachefs/journal_reclaim.c | |
parent | 2384db8f32a2df9e71cd3003d213b48f64cbde1e (diff) | |
download | linux-03d5eaed8624fdc7918478bffd05d67e773ac7d0.tar.xz |
bcachefs: bch2_journal_space_available improvements
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
Diffstat (limited to 'fs/bcachefs/journal_reclaim.c')
-rw-r--r-- | fs/bcachefs/journal_reclaim.c | 145 |
1 files changed, 92 insertions, 53 deletions
diff --git a/fs/bcachefs/journal_reclaim.c b/fs/bcachefs/journal_reclaim.c index ac9e6cb3d4ee..0884fc823cdf 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,62 +49,31 @@ 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; unsigned buckets_this_device, sectors_this_device; 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) |