]> git.proxmox.com Git - mirror_ubuntu-kernels.git/commitdiff
bcachefs: Fix degraded mode fsck
authorKent Overstreet <kent.overstreet@linux.dev>
Sun, 10 Mar 2024 18:54:09 +0000 (14:54 -0400)
committerKent Overstreet <kent.overstreet@linux.dev>
Sun, 10 Mar 2024 19:18:45 +0000 (15:18 -0400)
We don't know where the superblock and journal lives on offline devices;
that means if a device is offline fsck can't check those buckets.

Previously, fsck would incorrectly clear bucket data types for those
buckets on offline devices; now we just use the previous state.

Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
fs/bcachefs/btree_gc.c

index 1102995643b137c3a8a9fe5f12f0cce95edfafeb..829da0f92f0de1a379f02593cdb756a7bc0f8ed2 100644 (file)
@@ -1365,11 +1365,10 @@ static int bch2_alloc_write_key(struct btree_trans *trans,
 {
        struct bch_fs *c = trans->c;
        struct bch_dev *ca = bch_dev_bkey_exists(c, iter->pos.inode);
-       struct bucket gc, *b;
+       struct bucket old_gc, gc, *b;
        struct bkey_i_alloc_v4 *a;
        struct bch_alloc_v4 old_convert, new;
        const struct bch_alloc_v4 *old;
-       enum bch_data_type type;
        int ret;
 
        old = bch2_alloc_to_v4(k, &old_convert);
@@ -1377,30 +1376,31 @@ static int bch2_alloc_write_key(struct btree_trans *trans,
 
        percpu_down_read(&c->mark_lock);
        b = gc_bucket(ca, iter->pos.offset);
+       old_gc = *b;
+
+       if ((old->data_type == BCH_DATA_sb ||
+            old->data_type == BCH_DATA_journal) &&
+           !bch2_dev_is_online(ca)) {
+               b->data_type = old->data_type;
+               b->dirty_sectors = old->dirty_sectors;
+       }
 
        /*
         * b->data_type doesn't yet include need_discard & need_gc_gen states -
         * fix that here:
         */
-       type = __alloc_data_type(b->dirty_sectors,
-                                b->cached_sectors,
-                                b->stripe,
-                                *old,
-                                b->data_type);
-       if (b->data_type != type) {
-               struct bch_dev_usage *u;
-
-               preempt_disable();
-               u = this_cpu_ptr(ca->usage_gc);
-               u->d[b->data_type].buckets--;
-               b->data_type = type;
-               u->d[b->data_type].buckets++;
-               preempt_enable();
-       }
-
+       b->data_type = __alloc_data_type(b->dirty_sectors,
+                                        b->cached_sectors,
+                                        b->stripe,
+                                        *old,
+                                        b->data_type);
        gc = *b;
        percpu_up_read(&c->mark_lock);
 
+       if (gc.data_type != old_gc.data_type ||
+           gc.dirty_sectors != old_gc.dirty_sectors)
+               bch2_dev_usage_update_m(c, ca, &old_gc, &gc);
+
        if (metadata_only &&
            gc.data_type != BCH_DATA_sb &&
            gc.data_type != BCH_DATA_journal &&