]> git.sesse.net Git - bcachefs-tools-debian/blobdiff - libbcachefs/journal_seq_blacklist.c
Update bcachefs sources to 0d63ed13ea3d closures: Fix race in closure_sync()
[bcachefs-tools-debian] / libbcachefs / journal_seq_blacklist.c
index d0f1bbf8f6a7984ff5f96d997235b49d484d2eee..f9d9aa95bf3a64640d3d1e6012fc319ca7aad05e 100644 (file)
@@ -58,14 +58,20 @@ blacklist_entry_try_merge(struct bch_fs *c,
                        &bl->start[i + 1],
                        sizeof(bl->start[0]) * (nr - i));
 
-               bl = bch2_sb_resize_journal_seq_blacklist(&c->disk_sb,
-                                                       sb_blacklist_u64s(nr));
+               bl = bch2_sb_field_resize(&c->disk_sb, journal_seq_blacklist,
+                                         sb_blacklist_u64s(nr));
                BUG_ON(!bl);
        }
 
        return bl;
 }
 
+static bool bl_entry_contig_or_overlaps(struct journal_seq_blacklist_entry *e,
+                                       u64 start, u64 end)
+{
+       return !(end < le64_to_cpu(e->start) || le64_to_cpu(e->end) < start);
+}
+
 int bch2_journal_seq_blacklist_add(struct bch_fs *c, u64 start, u64 end)
 {
        struct bch_sb_field_journal_seq_blacklist *bl;
@@ -73,52 +79,44 @@ int bch2_journal_seq_blacklist_add(struct bch_fs *c, u64 start, u64 end)
        int ret = 0;
 
        mutex_lock(&c->sb_lock);
-       bl = bch2_sb_get_journal_seq_blacklist(c->disk_sb.sb);
+       bl = bch2_sb_field_get(c->disk_sb.sb, journal_seq_blacklist);
        nr = blacklist_nr_entries(bl);
 
-       if (bl) {
-               for (i = 0; i < nr; i++) {
-                       struct journal_seq_blacklist_entry *e =
-                               bl->start + i;
-
-                       if (start == le64_to_cpu(e->start) &&
-                           end   == le64_to_cpu(e->end))
-                               goto out;
-
-                       if (start <= le64_to_cpu(e->start) &&
-                           end   >= le64_to_cpu(e->end)) {
-                               e->start = cpu_to_le64(start);
-                               e->end  = cpu_to_le64(end);
-
-                               if (i + 1 < nr)
-                                       bl = blacklist_entry_try_merge(c,
-                                                               bl, i);
-                               if (i)
-                                       bl = blacklist_entry_try_merge(c,
-                                                               bl, i - 1);
-                               goto out_write_sb;
-                       }
+       for (i = 0; i < nr; i++) {
+               struct journal_seq_blacklist_entry *e =
+                       bl->start + i;
+
+               if (bl_entry_contig_or_overlaps(e, start, end)) {
+                       e->start = cpu_to_le64(min(start, le64_to_cpu(e->start)));
+                       e->end  = cpu_to_le64(max(end, le64_to_cpu(e->end)));
+
+                       if (i + 1 < nr)
+                               bl = blacklist_entry_try_merge(c,
+                                                       bl, i);
+                       if (i)
+                               bl = blacklist_entry_try_merge(c,
+                                                       bl, i - 1);
+                       goto out_write_sb;
                }
        }
 
-       bl = bch2_sb_resize_journal_seq_blacklist(&c->disk_sb,
-                                       sb_blacklist_u64s(nr + 1));
+       bl = bch2_sb_field_resize(&c->disk_sb, journal_seq_blacklist,
+                                 sb_blacklist_u64s(nr + 1));
        if (!bl) {
-               ret = -ENOMEM;
+               ret = -BCH_ERR_ENOSPC_sb_journal_seq_blacklist;
                goto out;
        }
 
        bl->start[nr].start     = cpu_to_le64(start);
        bl->start[nr].end       = cpu_to_le64(end);
 out_write_sb:
-       c->disk_sb.sb->features[0] |=
-               1ULL << BCH_FEATURE_journal_seq_blacklist_v3;
+       c->disk_sb.sb->features[0] |= cpu_to_le64(1ULL << BCH_FEATURE_journal_seq_blacklist_v3);
 
        ret = bch2_write_super(c);
 out:
        mutex_unlock(&c->sb_lock);
 
-       return ret;
+       return ret ?: bch2_blacklist_table_initialize(c);
 }
 
 static int journal_seq_blacklist_table_cmp(const void *_l,
@@ -160,19 +158,17 @@ bool bch2_journal_seq_is_blacklisted(struct bch_fs *c, u64 seq,
 int bch2_blacklist_table_initialize(struct bch_fs *c)
 {
        struct bch_sb_field_journal_seq_blacklist *bl =
-               bch2_sb_get_journal_seq_blacklist(c->disk_sb.sb);
+               bch2_sb_field_get(c->disk_sb.sb, journal_seq_blacklist);
        struct journal_seq_blacklist_table *t;
        unsigned i, nr = blacklist_nr_entries(bl);
 
-       BUG_ON(c->journal_seq_blacklist_table);
-
        if (!bl)
                return 0;
 
        t = kzalloc(sizeof(*t) + sizeof(t->entries[0]) * nr,
                    GFP_KERNEL);
        if (!t)
-               return -ENOMEM;
+               return -BCH_ERR_ENOMEM_blacklist_table_init;
 
        t->nr = nr;
 
@@ -187,31 +183,39 @@ int bch2_blacklist_table_initialize(struct bch_fs *c)
                        journal_seq_blacklist_table_cmp,
                        NULL);
 
+       kfree(c->journal_seq_blacklist_table);
        c->journal_seq_blacklist_table = t;
        return 0;
 }
 
-static const char *
-bch2_sb_journal_seq_blacklist_validate(struct bch_sb *sb,
-                                      struct bch_sb_field *f)
+static int bch2_sb_journal_seq_blacklist_validate(struct bch_sb *sb,
+                                                 struct bch_sb_field *f,
+                                                 struct printbuf *err)
 {
        struct bch_sb_field_journal_seq_blacklist *bl =
                field_to_type(f, journal_seq_blacklist);
-       struct journal_seq_blacklist_entry *i;
-       unsigned nr = blacklist_nr_entries(bl);
+       unsigned i, nr = blacklist_nr_entries(bl);
 
-       for (i = bl->start; i < bl->start + nr; i++) {
-               if (le64_to_cpu(i->start) >=
-                   le64_to_cpu(i->end))
-                       return "entry start >= end";
-
-               if (i + 1 < bl->start + nr &&
-                   le64_to_cpu(i[0].end) >
-                   le64_to_cpu(i[1].start))
-                       return "entries out of order";
+       for (i = 0; i < nr; i++) {
+               struct journal_seq_blacklist_entry *e = bl->start + i;
+
+               if (le64_to_cpu(e->start) >=
+                   le64_to_cpu(e->end)) {
+                       prt_printf(err, "entry %u start >= end (%llu >= %llu)",
+                              i, le64_to_cpu(e->start), le64_to_cpu(e->end));
+                       return -BCH_ERR_invalid_sb_journal_seq_blacklist;
+               }
+
+               if (i + 1 < nr &&
+                   le64_to_cpu(e[0].end) >
+                   le64_to_cpu(e[1].start)) {
+                       prt_printf(err, "entry %u out of order with next entry (%llu > %llu)",
+                              i + 1, le64_to_cpu(e[0].end), le64_to_cpu(e[1].start));
+                       return -BCH_ERR_invalid_sb_journal_seq_blacklist;
+               }
        }
 
-       return NULL;
+       return 0;
 }
 
 static void bch2_sb_journal_seq_blacklist_to_text(struct printbuf *out,
@@ -225,12 +229,13 @@ static void bch2_sb_journal_seq_blacklist_to_text(struct printbuf *out,
 
        for (i = bl->start; i < bl->start + nr; i++) {
                if (i != bl->start)
-                       pr_buf(out, " ");
+                       prt_printf(out, " ");
 
-               pr_buf(out, "%llu-%llu",
+               prt_printf(out, "%llu-%llu",
                       le64_to_cpu(i->start),
                       le64_to_cpu(i->end));
        }
+       prt_newline(out);
 }
 
 const struct bch_sb_field_ops bch_sb_field_ops_journal_seq_blacklist = {
@@ -245,31 +250,38 @@ void bch2_blacklist_entries_gc(struct work_struct *work)
        struct journal_seq_blacklist_table *t;
        struct bch_sb_field_journal_seq_blacklist *bl;
        struct journal_seq_blacklist_entry *src, *dst;
-       struct btree_trans trans;
+       struct btree_trans *trans = bch2_trans_get(c);
        unsigned i, nr, new_nr;
        int ret;
 
-       bch2_trans_init(&trans, c, 0, 0);
-
        for (i = 0; i < BTREE_ID_NR; i++) {
-               struct btree_iter *iter;
+               struct btree_iter iter;
                struct btree *b;
 
-               for_each_btree_node(&trans, iter, i, POS_MIN,
-                                   BTREE_ITER_PREFETCH, b)
-                       if (test_bit(BCH_FS_STOPPING, &c->flags)) {
-                               bch2_trans_exit(&trans);
-                               return;
-                       }
-               bch2_trans_iter_free(&trans, iter);
+               bch2_trans_node_iter_init(trans, &iter, i, POS_MIN,
+                                         0, 0, BTREE_ITER_PREFETCH);
+retry:
+               bch2_trans_begin(trans);
+
+               b = bch2_btree_iter_peek_node(&iter);
+
+               while (!(ret = PTR_ERR_OR_ZERO(b)) &&
+                      b &&
+                      !test_bit(BCH_FS_STOPPING, &c->flags))
+                       b = bch2_btree_iter_next_node(&iter);
+
+               if (bch2_err_matches(ret, BCH_ERR_transaction_restart))
+                       goto retry;
+
+               bch2_trans_iter_exit(trans, &iter);
        }
 
-       ret = bch2_trans_exit(&trans);
+       bch2_trans_put(trans);
        if (ret)
                return;
 
        mutex_lock(&c->sb_lock);
-       bl = bch2_sb_get_journal_seq_blacklist(c->disk_sb.sb);
+       bl = bch2_sb_field_get(c->disk_sb.sb, journal_seq_blacklist);
        if (!bl)
                goto out;
 
@@ -294,13 +306,12 @@ void bch2_blacklist_entries_gc(struct work_struct *work)
        bch_info(c, "nr blacklist entries was %u, now %u", nr, new_nr);
 
        if (new_nr != nr) {
-               bl = bch2_sb_resize_journal_seq_blacklist(&c->disk_sb,
+               bl = bch2_sb_field_resize(&c->disk_sb, journal_seq_blacklist,
                                new_nr ? sb_blacklist_u64s(new_nr) : 0);
                BUG_ON(new_nr && !bl);
 
                if (!new_nr)
-                       c->disk_sb.sb->features[0] &=
-                               ~(1ULL << BCH_FEATURE_journal_seq_blacklist_v3);
+                       c->disk_sb.sb->features[0] &= cpu_to_le64(~(1ULL << BCH_FEATURE_journal_seq_blacklist_v3));
 
                bch2_write_super(c);
        }