summaryrefslogtreecommitdiff
path: root/fs/bcachefs/journal_sb.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/bcachefs/journal_sb.c')
-rw-r--r--fs/bcachefs/journal_sb.c45
1 files changed, 41 insertions, 4 deletions
diff --git a/fs/bcachefs/journal_sb.c b/fs/bcachefs/journal_sb.c
index 0cb9b93f13e7..dc0ecedb3a8f 100644
--- a/fs/bcachefs/journal_sb.c
+++ b/fs/bcachefs/journal_sb.c
@@ -30,7 +30,7 @@ static int bch2_sb_journal_validate(struct bch_sb *sb, struct bch_sb_field *f,
if (!nr)
return 0;
- b = kmalloc_array(nr, sizeof(u64), GFP_KERNEL);
+ b = kvmalloc_array(nr, sizeof(u64), GFP_KERNEL);
if (!b)
return -BCH_ERR_ENOMEM_sb_journal_validate;
@@ -64,7 +64,7 @@ static int bch2_sb_journal_validate(struct bch_sb *sb, struct bch_sb_field *f,
ret = 0;
err:
- kfree(b);
+ kvfree(b);
return ret;
}
@@ -113,7 +113,7 @@ static int bch2_sb_journal_v2_validate(struct bch_sb *sb, struct bch_sb_field *f
if (!nr)
return 0;
- b = kmalloc_array(nr, sizeof(*b), GFP_KERNEL);
+ b = kvmalloc_array(nr, sizeof(*b), GFP_KERNEL);
if (!b)
return -BCH_ERR_ENOMEM_sb_journal_v2_validate;
@@ -165,7 +165,7 @@ static int bch2_sb_journal_v2_validate(struct bch_sb *sb, struct bch_sb_field *f
ret = 0;
err:
- kfree(b);
+ kvfree(b);
return ret;
}
@@ -230,3 +230,40 @@ int bch2_journal_buckets_to_sb(struct bch_fs *c, struct bch_dev *ca,
BUG_ON(dst + 1 != nr_compacted);
return 0;
}
+
+static inline bool journal_v2_unsorted(struct bch_sb_field_journal_v2 *j)
+{
+ unsigned nr = bch2_sb_field_journal_v2_nr_entries(j);
+ for (unsigned i = 0; i + 1 < nr; i++)
+ if (le64_to_cpu(j->d[i].start) > le64_to_cpu(j->d[i + 1].start))
+ return true;
+ return false;
+}
+
+int bch2_sb_journal_sort(struct bch_fs *c)
+{
+ BUG_ON(!c->sb.clean);
+ BUG_ON(test_bit(BCH_FS_rw, &c->flags));
+
+ guard(mutex)(&c->sb_lock);
+ bool write_sb = false;
+
+ for_each_online_member(c, ca, BCH_DEV_READ_REF_sb_journal_sort) {
+ struct bch_sb_field_journal_v2 *j = bch2_sb_field_get(ca->disk_sb.sb, journal_v2);
+ if (!j)
+ continue;
+
+ if ((j && journal_v2_unsorted(j)) ||
+ bch2_sb_field_get(ca->disk_sb.sb, journal)) {
+ struct journal_device *ja = &ca->journal;
+
+ sort(ja->buckets, ja->nr, sizeof(ja->buckets[0]), u64_cmp, NULL);
+ bch2_journal_buckets_to_sb(c, ca, ja->buckets, ja->nr);
+ write_sb = true;
+ }
+ }
+
+ return write_sb
+ ? bch2_write_super(c)
+ : 0;
+}