bcachefs: bch2_journal_space_available improvements
authorKent Overstreet <kent.overstreet@gmail.com>
Sun, 3 Mar 2019 21:50:40 +0000 (16:50 -0500)
committerKent Overstreet <kent.overstreet@linux.dev>
Sun, 22 Oct 2023 21:08:17 +0000 (17:08 -0400)
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
fs/bcachefs/journal.c
fs/bcachefs/journal_io.c
fs/bcachefs/journal_reclaim.c
fs/bcachefs/journal_reclaim.h

index 80d7980cf5aa5dc53387e592fd9b7ba8f546f88e..5caa01881d0043656e2ad6e77349526c95b13cce 100644 (file)
@@ -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],
index b6a51dff09784f683000d45395ae6a2975d7fe77..07cfbb975c37f66acb3e458fa3961c95c9197cb4 100644 (file)
@@ -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;
                }
index ac9e6cb3d4eef7674caa72d54010342225df767c..0884fc823cdf27aaf193e448472f15e32949195f 100644 (file)
@@ -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)
index 183419ea3e2529b61db6254758c0f3fb12792d20..71545ad3bd58c62d5a17c42a9013fc7c9cd60838 100644 (file)
@@ -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)