]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
bcachefs: bch2_dev_journal_bucket_delete()
authorKent Overstreet <kent.overstreet@linux.dev>
Wed, 28 May 2025 18:26:33 +0000 (14:26 -0400)
committerKent Overstreet <kent.overstreet@linux.dev>
Sun, 1 Jun 2025 02:03:17 +0000 (22:03 -0400)
Recover from "journal and btree in same bucket".

Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
fs/bcachefs/buckets.c
fs/bcachefs/journal.c
fs/bcachefs/journal.h
fs/bcachefs/str_hash.c

index 1adf6792ef97060013fc842358a838c12938a6a6..410e0116917fde4776b22aebf35c898c6d3f9f35 100644 (file)
@@ -221,6 +221,20 @@ static int bch2_check_fix_ptr(struct btree_trans *trans,
                         bch2_bkey_val_to_text(&buf, c, k), buf.buf))) {
                if (!p.ptr.cached &&
                    data_type == BCH_DATA_btree) {
+                       switch (g->data_type) {
+                       case BCH_DATA_sb:
+                               bch_err(c, "btree and superblock in the same bucket - cannot repair");
+                               ret = -BCH_ERR_fsck_repair_unimplemented;
+                               goto out;
+                       case BCH_DATA_journal:
+                               ret = bch2_dev_journal_bucket_delete(ca, PTR_BUCKET_NR(ca, &p.ptr));
+                               bch_err_msg(c, ret, "error deleting journal bucket %zu",
+                                           PTR_BUCKET_NR(ca, &p.ptr));
+                               if (ret)
+                                       goto out;
+                               break;
+                       }
+
                        g->data_type            = data_type;
                        g->stripe_sectors       = 0;
                        g->dirty_sectors        = 0;
index 09b70fd140a104eb46fc47131da43fa88c664eef..fd7f9ff33da08f5ca85a74d1de61baf74e005957 100644 (file)
@@ -1304,6 +1304,66 @@ int bch2_set_nr_journal_buckets(struct bch_fs *c, struct bch_dev *ca,
        return ret;
 }
 
+int bch2_dev_journal_bucket_delete(struct bch_dev *ca, u64 b)
+{
+       struct bch_fs *c = ca->fs;
+       struct journal *j = &c->journal;
+       struct journal_device *ja = &ca->journal;
+
+       guard(mutex)(&c->sb_lock);
+       unsigned pos;
+       for (pos = 0; pos < ja->nr; pos++)
+               if (ja->buckets[pos] == b)
+                       break;
+
+       if (pos == ja->nr) {
+               bch_err(ca, "journal bucket %llu not found when deleting", b);
+               return -EINVAL;
+       }
+
+       u64 *new_buckets = kcalloc(ja->nr, sizeof(u64), GFP_KERNEL);;
+       if (!new_buckets)
+               return -BCH_ERR_ENOMEM_set_nr_journal_buckets;
+
+       memcpy(new_buckets, ja->buckets, ja->nr * sizeof(u64));
+       memmove(&new_buckets[pos],
+               &new_buckets[pos + 1],
+               (ja->nr - 1 - pos) * sizeof(new_buckets[0]));
+
+       int ret = bch2_journal_buckets_to_sb(c, ca, ja->buckets, ja->nr - 1) ?:
+               bch2_write_super(c);
+       if (ret) {
+               kfree(new_buckets);
+               return ret;
+       }
+
+       scoped_guard(spinlock, &j->lock) {
+               if (pos < ja->discard_idx)
+                       --ja->discard_idx;
+               if (pos < ja->dirty_idx_ondisk)
+                       --ja->dirty_idx_ondisk;
+               if (pos < ja->dirty_idx)
+                       --ja->dirty_idx;
+               if (pos < ja->cur_idx)
+                       --ja->cur_idx;
+
+               ja->nr--;
+
+               memmove(&ja->buckets[pos],
+                       &ja->buckets[pos + 1],
+                       (ja->nr - pos) * sizeof(ja->buckets[0]));
+
+               memmove(&ja->bucket_seq[pos],
+                       &ja->bucket_seq[pos + 1],
+                       (ja->nr - pos) * sizeof(ja->bucket_seq[0]));
+
+               bch2_journal_space_available(j);
+       }
+
+       kfree(new_buckets);
+       return 0;
+}
+
 int bch2_dev_journal_alloc(struct bch_dev *ca, bool new_fs)
 {
        struct bch_fs *c = ca->fs;
index 8ff00a0ec778aa0d3518f9ece0e28f32836afe4f..83734fe4331feca9358089b8d709543bafef5ce2 100644 (file)
@@ -444,8 +444,9 @@ struct journal_buf *bch2_next_write_buffer_flush_journal_buf(struct journal *, u
 void __bch2_journal_debug_to_text(struct printbuf *, struct journal *);
 void bch2_journal_debug_to_text(struct printbuf *, struct journal *);
 
-int bch2_set_nr_journal_buckets(struct bch_fs *, struct bch_dev *,
-                               unsigned nr);
+int bch2_set_nr_journal_buckets(struct bch_fs *, struct bch_dev *, unsigned);
+int bch2_dev_journal_bucket_delete(struct bch_dev *, u64);
+
 int bch2_dev_journal_alloc(struct bch_dev *, bool);
 int bch2_fs_journal_alloc(struct bch_fs *);
 
index 0cbf5508a32c8b75729e29462b3aaef1f9ba806b..bfd4346a4d9316644b7c7865098526947bbad3d4 100644 (file)
@@ -239,7 +239,8 @@ int __bch2_str_hash_check_key(struct btree_trans *trans,
 
        for_each_btree_key_norestart(trans, iter, desc->btree_id,
                                     SPOS(hash_k.k->p.inode, hash, hash_k.k->p.snapshot),
-                                    BTREE_ITER_slots, k, ret) {
+                                    BTREE_ITER_slots|
+                                    BTREE_ITER_with_updates, k, ret) {
                if (bkey_eq(k.k->p, hash_k.k->p))
                        break;
 
@@ -286,10 +287,11 @@ bad_hash:
                        goto duplicate_entries;
 
                ret =   bch2_hash_delete_at(trans, *desc, hash_info, k_iter,
+                                           BTREE_ITER_with_updates|
                                            BTREE_UPDATE_internal_snapshot_node) ?:
                        bch2_fsck_update_backpointers(trans, s, *desc, hash_info, new) ?:
                        bch2_trans_commit(trans, NULL, NULL, BCH_TRANS_COMMIT_no_enospc) ?:
-                       -BCH_ERR_transaction_restart_nested;
+                       -BCH_ERR_transaction_restart_commit;
                goto out;
        }
 fsck_err:
@@ -323,6 +325,6 @@ duplicate_entries:
        }
 
        ret = bch2_trans_commit(trans, NULL, NULL, 0) ?:
-               -BCH_ERR_transaction_restart_nested;
+               -BCH_ERR_transaction_restart_commit;
        goto out;
 }