Commit fd65378d authored by Kent Overstreet's avatar Kent Overstreet

bcachefs: Don't delete unlinked inodes before logged op resume

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: default avatarKent Overstreet <kent.overstreet@linux.dev>
parent 8d65b15f
...@@ -1049,6 +1049,17 @@ static int check_inode(struct btree_trans *trans, ...@@ -1049,6 +1049,17 @@ static int check_inode(struct btree_trans *trans,
} }
if (u.bi_flags & BCH_INODE_unlinked) { if (u.bi_flags & BCH_INODE_unlinked) {
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); ret = check_inode_deleted_list(trans, k.k->p);
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -1057,19 +1068,21 @@ static int check_inode(struct btree_trans *trans, ...@@ -1057,19 +1068,21 @@ static int check_inode(struct btree_trans *trans,
trans, unlinked_inode_not_on_deleted_list, trans, unlinked_inode_not_on_deleted_list,
"inode %llu:%u unlinked, but not on deleted list", "inode %llu:%u unlinked, but not on deleted list",
u.bi_inum, k.k->p.snapshot); u.bi_inum, k.k->p.snapshot);
ret = 0;
}
if (u.bi_flags & BCH_INODE_unlinked && ret = bch2_btree_bit_mod_buffered(trans, BTREE_ID_deleted_inodes, k.k->p, 1);
!bch2_inode_is_open(c, k.k->p) && if (ret)
(!c->sb.clean || goto err;
fsck_err(trans, inode_unlinked_but_clean, } else {
"filesystem marked clean, but inode %llu unlinked", if (fsck_err_on(bch2_inode_is_open(c, k.k->p),
u.bi_inum))) { 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); ret = bch2_inode_rm_snapshot(trans, u.bi_inum, iter->pos.snapshot);
bch_err_msg(c, ret, "in fsck deleting inode"); bch_err_msg(c, ret, "in fsck deleting inode");
return ret; return ret;
} }
}
}
if (u.bi_flags & BCH_INODE_i_size_dirty && if (u.bi_flags & BCH_INODE_i_size_dirty &&
(!c->sb.clean || (!c->sb.clean ||
......
...@@ -50,7 +50,7 @@ ...@@ -50,7 +50,7 @@
x(check_directory_structure, 30, PASS_ONLINE|PASS_FSCK) \ x(check_directory_structure, 30, PASS_ONLINE|PASS_FSCK) \
x(check_nlinks, 31, PASS_FSCK) \ x(check_nlinks, 31, PASS_FSCK) \
x(resume_logged_ops, 23, PASS_ALWAYS) \ 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(fix_reflink_p, 33, 0) \
x(set_fs_needs_rebalance, 34, 0) \ x(set_fs_needs_rebalance, 34, 0) \
......
...@@ -210,6 +210,7 @@ enum bch_fsck_flags { ...@@ -210,6 +210,7 @@ enum bch_fsck_flags {
x(inode_snapshot_mismatch, 196, 0) \ x(inode_snapshot_mismatch, 196, 0) \
x(inode_unlinked_but_clean, 197, 0) \ x(inode_unlinked_but_clean, 197, 0) \
x(inode_unlinked_but_nlink_nonzero, 198, 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_checksum_type_invalid, 199, 0) \
x(inode_compression_type_invalid, 200, 0) \ x(inode_compression_type_invalid, 200, 0) \
x(inode_subvol_root_but_not_dir, 201, 0) \ x(inode_subvol_root_but_not_dir, 201, 0) \
...@@ -292,7 +293,7 @@ enum bch_fsck_flags { ...@@ -292,7 +293,7 @@ enum bch_fsck_flags {
x(accounting_key_replicas_nr_devs_0, 278, FSCK_AUTOFIX) \ x(accounting_key_replicas_nr_devs_0, 278, FSCK_AUTOFIX) \
x(accounting_key_replicas_nr_required_bad, 279, FSCK_AUTOFIX) \ x(accounting_key_replicas_nr_required_bad, 279, FSCK_AUTOFIX) \
x(accounting_key_replicas_devs_unsorted, 280, FSCK_AUTOFIX) \ x(accounting_key_replicas_devs_unsorted, 280, FSCK_AUTOFIX) \
x(MAX, 281, 0) x(MAX, 282, 0)
enum bch_sb_error_id { enum bch_sb_error_id {
#define x(t, n, ...) BCH_FSCK_ERR_##t = n, #define x(t, n, ...) BCH_FSCK_ERR_##t = n,
......
...@@ -1190,7 +1190,8 @@ static void bch2_sb_ext_to_text(struct printbuf *out, struct bch_sb *sb, ...@@ -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); le_bitvector_to_cpu(errors_silent, (void *) e->errors_silent, sizeof(e->errors_silent) * 8);
prt_printf(out, "Errors to silently fix:\t"); 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); prt_newline(out);
kfree(errors_silent); kfree(errors_silent);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment