]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
bcachefs: Fix livelock in journal_entry_open()
authorKent Overstreet <kent.overstreet@linux.dev>
Tue, 13 May 2025 16:55:44 +0000 (12:55 -0400)
committerKent Overstreet <kent.overstreet@linux.dev>
Wed, 14 May 2025 21:05:19 +0000 (17:05 -0400)
When the journal is low on space, we might do discards from
journal_res_get() -> journal_entry_open().

Make sure we set j->can_discard correctly, so that if we're low on space
but not because discards aren't keeping up we don't livelock.

Fixes: 8e4d28036c29 ("bcachefs: Don't aggressively discard the journal")
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
fs/bcachefs/journal_reclaim.c

index 976464d8a695ae62ebc6cd74d83d8950926ee463..cc00b0fc40d8e338934338803f81dc4098638f5b 100644 (file)
@@ -17,6 +17,8 @@
 #include <linux/kthread.h>
 #include <linux/sched/mm.h>
 
+static bool __should_discard_bucket(struct journal *, struct journal_device *);
+
 /* Free space calculations: */
 
 static unsigned journal_space_from(struct journal_device *ja,
@@ -203,8 +205,7 @@ void bch2_journal_space_available(struct journal *j)
                       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;
+               can_discard |= __should_discard_bucket(j, ja);
 
                max_entry_size = min_t(unsigned, max_entry_size, ca->mi.bucket_size);
                nr_online++;
@@ -264,13 +265,19 @@ out:
 
 /* Discards - last part of journal reclaim: */
 
-static bool should_discard_bucket(struct journal *j, struct journal_device *ja)
+static bool __should_discard_bucket(struct journal *j, struct journal_device *ja)
 {
-       spin_lock(&j->lock);
        unsigned min_free = max(4, ja->nr / 8);
 
-       bool ret = bch2_journal_dev_buckets_available(j, ja, journal_space_discarded) < min_free &&
+       return bch2_journal_dev_buckets_available(j, ja, journal_space_discarded) <
+               min_free &&
                ja->discard_idx != ja->dirty_idx_ondisk;
+}
+
+static bool should_discard_bucket(struct journal *j, struct journal_device *ja)
+{
+       spin_lock(&j->lock);
+       bool ret = __should_discard_bucket(j, ja);
        spin_unlock(&j->lock);
 
        return ret;