]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
bcachefs: Don't delete unlinked inodes before logged op resume
authorKent Overstreet <kent.overstreet@linux.dev>
Thu, 26 Sep 2024 19:19:17 +0000 (15:19 -0400)
committerKent Overstreet <kent.overstreet@linux.dev>
Sat, 28 Sep 2024 01:46:35 +0000 (21:46 -0400)
Previously, check_inode() would delete unlinked inodes if they weren't
on the deleted list - this code dating from before there was a deleted
list.

But, if we crash during a logged op (truncate or finsert/fcollapse) of
an unlinked file, logged op resume will get confused if the inode has
already been deleted - instead, just add it to the deleted list if it
needs to be there; delete_dead_inodes runs after logged op resume.

Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
fs/bcachefs/fsck.c
fs/bcachefs/recovery_passes_types.h
fs/bcachefs/sb-errors_format.h
fs/bcachefs/super-io.c

index 8fe67abae36e3df1c17d6ecaba5f7e45789fdc13..10e2930b62da356c55f2c114871ea2376b35b17c 100644 (file)
@@ -1049,26 +1049,39 @@ static int check_inode(struct btree_trans *trans,
        }
 
        if (u.bi_flags & BCH_INODE_unlinked) {
-               ret = check_inode_deleted_list(trans, k.k->p);
-               if (ret < 0)
-                       return ret;
+               if (!test_bit(BCH_FS_started, &c->flags)) {
+                       /*
+                        * If we're not in online fsck, don't delete unlinked
+                        * inodes, just make sure they're on the deleted list.
+                        *
+                        * They might be referred to by a logged operation -
+                        * i.e. we might have crashed in the middle of a
+                        * truncate on an unlinked but open file - so we want to
+                        * let the delete_dead_inodes kill it after resuming
+                        * logged ops.
+                        */
+                       ret = check_inode_deleted_list(trans, k.k->p);
+                       if (ret < 0)
+                               return ret;
 
-               fsck_err_on(!ret,
-                           trans, unlinked_inode_not_on_deleted_list,
-                           "inode %llu:%u unlinked, but not on deleted list",
-                           u.bi_inum, k.k->p.snapshot);
-               ret = 0;
-       }
+                       fsck_err_on(!ret,
+                                   trans, unlinked_inode_not_on_deleted_list,
+                                   "inode %llu:%u unlinked, but not on deleted list",
+                                   u.bi_inum, k.k->p.snapshot);
 
-       if (u.bi_flags & BCH_INODE_unlinked &&
-           !bch2_inode_is_open(c, k.k->p) &&
-           (!c->sb.clean ||
-            fsck_err(trans, inode_unlinked_but_clean,
-                     "filesystem marked clean, but inode %llu unlinked",
-                     u.bi_inum))) {
-               ret = bch2_inode_rm_snapshot(trans, u.bi_inum, iter->pos.snapshot);
-               bch_err_msg(c, ret, "in fsck deleting inode");
-               return ret;
+                       ret = bch2_btree_bit_mod_buffered(trans, BTREE_ID_deleted_inodes, k.k->p, 1);
+                       if (ret)
+                               goto err;
+               } else {
+                       if (fsck_err_on(bch2_inode_is_open(c, k.k->p),
+                                       trans, inode_unlinked_and_not_open,
+                                     "inode %llu%u unlinked and not open",
+                                     u.bi_inum, u.bi_snapshot)) {
+                               ret = bch2_inode_rm_snapshot(trans, u.bi_inum, iter->pos.snapshot);
+                               bch_err_msg(c, ret, "in fsck deleting inode");
+                               return ret;
+                       }
+               }
        }
 
        if (u.bi_flags & BCH_INODE_i_size_dirty &&
index 8c7dee5983d272131bfec6c935ef92b9d71b1bcf..50406ce0e4ef12336a9ff65c8ecaa4e5871ccb9a 100644 (file)
@@ -50,7 +50,7 @@
        x(check_directory_structure,            30, PASS_ONLINE|PASS_FSCK)      \
        x(check_nlinks,                         31, PASS_FSCK)                  \
        x(resume_logged_ops,                    23, PASS_ALWAYS)                \
-       x(delete_dead_inodes,                   32, PASS_FSCK|PASS_UNCLEAN)     \
+       x(delete_dead_inodes,                   32, PASS_ALWAYS)                \
        x(fix_reflink_p,                        33, 0)                          \
        x(set_fs_needs_rebalance,               34, 0)                          \
 
index 49d8609c4a08a6f4b260d886ded407d29af9d2cc..3fca1d836318a246ca033c1893f13f97f7bccca3 100644 (file)
@@ -210,6 +210,7 @@ enum bch_fsck_flags {
        x(inode_snapshot_mismatch,                              196,    0)              \
        x(inode_unlinked_but_clean,                             197,    0)              \
        x(inode_unlinked_but_nlink_nonzero,                     198,    0)              \
+       x(inode_unlinked_and_not_open,                          281,    0)              \
        x(inode_checksum_type_invalid,                          199,    0)              \
        x(inode_compression_type_invalid,                       200,    0)              \
        x(inode_subvol_root_but_not_dir,                        201,    0)              \
@@ -292,7 +293,7 @@ enum bch_fsck_flags {
        x(accounting_key_replicas_nr_devs_0,                    278,    FSCK_AUTOFIX)   \
        x(accounting_key_replicas_nr_required_bad,              279,    FSCK_AUTOFIX)   \
        x(accounting_key_replicas_devs_unsorted,                280,    FSCK_AUTOFIX)   \
-       x(MAX,                                                  281,    0)
+       x(MAX,                                                  282,    0)
 
 enum bch_sb_error_id {
 #define x(t, n, ...) BCH_FSCK_ERR_##t = n,
index b2e914841b5f9656a24d05bd7cfed0f31304099d..ce7410d72089226e4421ca452a2c47d8f0e8c132 100644 (file)
@@ -1190,7 +1190,8 @@ static void bch2_sb_ext_to_text(struct printbuf *out, struct bch_sb *sb,
                le_bitvector_to_cpu(errors_silent, (void *) e->errors_silent, sizeof(e->errors_silent) * 8);
 
                prt_printf(out, "Errors to silently fix:\t");
-               prt_bitflags_vector(out, bch2_sb_error_strs, errors_silent, sizeof(e->errors_silent) * 8);
+               prt_bitflags_vector(out, bch2_sb_error_strs, errors_silent,
+                                   min(BCH_FSCK_ERR_MAX, sizeof(e->errors_silent) * 8));
                prt_newline(out);
 
                kfree(errors_silent);