link count works differently in bcachefs - it's only nonzero for files with multiple hardlinks, which means we can also avoid checking it except for files that are known to have hardlinks. That means we need a few different checks instead; in particular, we don't want fsck to delet a file that has a dirent pointing to it.
Unified · Split
| @@ -1029,6 +1029,7 @@ static int check_inode(struct btree_trans *trans, · 1028 unmodified lines | |||
| 1029 | bool full) | 1029 | bool full) |
| 1030 | { | 1030 | { |
| 1031 | struct bch_fs *c = trans->c; | 1031 | struct bch_fs *c = trans->c; |
| 1032 | struct printbuf buf = PRINTBUF; | ||
| 1032 | struct bch_inode_unpacked u; | 1033 | struct bch_inode_unpacked u; |
| 1033 | bool do_update = false; | 1034 | bool do_update = false; |
| 1034 | int ret; | 1035 | int ret; |
| @@ -1062,7 +1063,24 @@ static int check_inode(struct btree_trans *trans, · 27 unmodified lines | |||
| 1062 | trans, inode_snapshot_mismatch, | 1063 | trans, inode_snapshot_mismatch, |
| 1063 | "inodes in different snapshots don't match")) { | 1064 | "inodes in different snapshots don't match")) { |
| 1064 | bch_err(c, "repair not implemented yet"); | 1065 | bch_err(c, "repair not implemented yet"); |
| 1065 | return -BCH_ERR_fsck_repair_unimplemented; | 1066 | ret = -BCH_ERR_fsck_repair_unimplemented; |
| 1067 | goto err_noprint; | ||
| 1068 | } | ||
| 1069 | |||
| 1070 | if (u.bi_dir || u.bi_dir_offset) { | ||
| 1071 | ret = check_inode_dirent_inode(trans, &u, &do_update); | ||
| 1072 | if (ret) | ||
| 1073 | goto err; | ||
| 1074 | } | ||
| 1075 | |||
| 1076 | if (fsck_err_on(u.bi_dir && (u.bi_flags & BCH_INODE_unlinked), | ||
| 1077 | trans, inode_unlinked_but_has_dirent, | ||
| 1078 | "inode unlinked but has dirent\n%s", | ||
| 1079 | (printbuf_reset(&buf), | ||
| 1080 | bch2_inode_unpacked_to_text(&buf, &u), | ||
| 1081 | buf.buf))) { | ||
| 1082 | u.bi_flags &= ~BCH_INODE_unlinked; | ||
| 1083 | do_update = true; | ||
| 1066 | } | 1084 | } |
| 1067 | 1085 | ||
| 1068 | if ((u.bi_flags & (BCH_INODE_i_size_dirty|BCH_INODE_unlinked)) && | 1086 | if ((u.bi_flags & (BCH_INODE_i_size_dirty|BCH_INODE_unlinked)) && |
| @@ -1079,11 +1097,11 @@ static int check_inode(struct btree_trans *trans, · 10 unmodified lines | |||
| 1079 | 1097 | ||
| 1080 | bch_err_msg(c, ret, "in fsck updating inode"); | 1098 | bch_err_msg(c, ret, "in fsck updating inode"); |
| 1081 | if (ret) | 1099 | if (ret) |
| 1082 | return ret; | 1100 | goto err_noprint; |
| 1083 | 1101 | ||
| 1084 | if (!bpos_eq(new_min_pos, POS_MIN)) | 1102 | if (!bpos_eq(new_min_pos, POS_MIN)) |
| 1085 | bch2_btree_iter_set_pos(iter, bpos_predecessor(new_min_pos)); | 1103 | bch2_btree_iter_set_pos(iter, bpos_predecessor(new_min_pos)); |
| 1086 | return 0; | 1104 | goto err_noprint; |
| 1087 | } | 1105 | } |
| 1088 | 1106 | ||
| 1089 | if (u.bi_flags & BCH_INODE_unlinked) { | 1107 | if (u.bi_flags & BCH_INODE_unlinked) { |
| @@ -1100,7 +1118,7 @@ static int check_inode(struct btree_trans *trans, · 10 unmodified lines | |||
| 1100 | */ | 1118 | */ |
| 1101 | ret = check_inode_deleted_list(trans, k.k->p); | 1119 | ret = check_inode_deleted_list(trans, k.k->p); |
| 1102 | if (ret < 0) | 1120 | if (ret < 0) |
| 1103 | return ret; | 1121 | goto err_noprint; |
| 1104 | 1122 | ||
| 1105 | fsck_err_on(!ret, | 1123 | fsck_err_on(!ret, |
| 1106 | trans, unlinked_inode_not_on_deleted_list, | 1124 | trans, unlinked_inode_not_on_deleted_list, |
| @@ -1117,7 +1135,7 @@ static int check_inode(struct btree_trans *trans, · 10 unmodified lines | |||
| 1117 | u.bi_inum, u.bi_snapshot)) { | 1135 | u.bi_inum, u.bi_snapshot)) { |
| 1118 | ret = bch2_inode_rm_snapshot(trans, u.bi_inum, iter->pos.snapshot); | 1136 | ret = bch2_inode_rm_snapshot(trans, u.bi_inum, iter->pos.snapshot); |
| 1119 | bch_err_msg(c, ret, "in fsck deleting inode"); | 1137 | bch_err_msg(c, ret, "in fsck deleting inode"); |
| 1120 | return ret; | 1138 | goto err_noprint; |
| 1121 | } | 1139 | } |
| 1122 | } | 1140 | } |
| 1123 | } | 1141 | } |
| @@ -1182,12 +1200,6 @@ static int check_inode(struct btree_trans *trans, · 58 unmodified lines | |||
| 1182 | do_update = true; | 1200 | do_update = true; |
| 1183 | } | 1201 | } |
| 1184 | 1202 | ||
| 1185 | if (u.bi_dir || u.bi_dir_offset) { | ||
| 1186 | ret = check_inode_dirent_inode(trans, &u, &do_update); | ||
| 1187 | if (ret) | ||
| 1188 | goto err; | ||
| 1189 | } | ||
| 1190 | |||
| 1191 | if (fsck_err_on(u.bi_parent_subvol && | 1203 | if (fsck_err_on(u.bi_parent_subvol && |
| 1192 | (u.bi_subvol == 0 || | 1204 | (u.bi_subvol == 0 || |
| 1193 | u.bi_subvol == BCACHEFS_ROOT_SUBVOL), | 1205 | u.bi_subvol == BCACHEFS_ROOT_SUBVOL), |
| @@ -1232,11 +1244,13 @@ do_update: · 38 unmodified lines | |||
| 1232 | ret = __bch2_fsck_write_inode(trans, &u, iter->pos.snapshot); | 1244 | ret = __bch2_fsck_write_inode(trans, &u, iter->pos.snapshot); |
| 1233 | bch_err_msg(c, ret, "in fsck updating inode"); | 1245 | bch_err_msg(c, ret, "in fsck updating inode"); |
| 1234 | if (ret) | 1246 | if (ret) |
| 1235 | return ret; | 1247 | goto err_noprint; |
| 1236 | } | 1248 | } |
| 1237 | err: | 1249 | err: |
| 1238 | fsck_err: | 1250 | fsck_err: |
| 1239 | bch_err_fn(c, ret); | 1251 | bch_err_fn(c, ret); |
| 1252 | err_noprint: | ||
| 1253 | printbuf_exit(&buf); | ||
| 1240 | return ret; | 1254 | return ret; |
| 1241 | } | 1255 | } |
| 1242 | 1256 | ||
| @@ -1831,11 +1845,22 @@ static int check_dirent_inode_dirent(struct btree_trans *trans, · 588 unmodified lines | |||
| 1831 | fsck_err_on(S_ISDIR(target->bi_mode), | 1845 | fsck_err_on(S_ISDIR(target->bi_mode), |
| 1832 | trans, inode_dir_missing_backpointer, | 1846 | trans, inode_dir_missing_backpointer, |
| 1833 | "directory with missing backpointer\n%s", | 1847 | "directory with missing backpointer\n%s", |
| 1834 | (bch2_bkey_val_to_text(&buf, c, d.s_c), | 1848 | (printbuf_reset(&buf), |
| 1835 | prt_printf(&buf, "\n "), | 1849 | bch2_bkey_val_to_text(&buf, c, d.s_c), |
| 1850 | prt_printf(&buf, "\n"), | ||
| 1836 | bch2_inode_unpacked_to_text(&buf, target), | 1851 | bch2_inode_unpacked_to_text(&buf, target), |
| 1837 | buf.buf)); | 1852 | buf.buf)); |
| 1838 | 1853 | ||
| 1854 | fsck_err_on(target->bi_flags & BCH_INODE_unlinked, | ||
| 1855 | trans, inode_unlinked_but_has_dirent, | ||
| 1856 | "inode unlinked but has dirent\n%s", | ||
| 1857 | (printbuf_reset(&buf), | ||
| 1858 | bch2_bkey_val_to_text(&buf, c, d.s_c), | ||
| 1859 | prt_printf(&buf, "\n"), | ||
| 1860 | bch2_inode_unpacked_to_text(&buf, target), | ||
| 1861 | buf.buf)); | ||
| 1862 | |||
| 1863 | target->bi_flags &= ~BCH_INODE_unlinked; | ||
| 1839 | target->bi_dir = d.k->p.inode; | 1864 | target->bi_dir = d.k->p.inode; |
| 1840 | target->bi_dir_offset = d.k->p.offset; | 1865 | target->bi_dir_offset = d.k->p.offset; |
| 1841 | return __bch2_fsck_write_inode(trans, target, target_snapshot); | 1866 | return __bch2_fsck_write_inode(trans, target, target_snapshot); |
| @@ -211,6 +211,7 @@ enum bch_fsck_flags { · 210 unmodified lines | |||
| 211 | x(inode_unlinked_but_clean, 197, 0) \ | 211 | x(inode_unlinked_but_clean, 197, 0) \ |
| 212 | x(inode_unlinked_but_nlink_nonzero, 198, 0) \ | 212 | x(inode_unlinked_but_nlink_nonzero, 198, 0) \ |
| 213 | x(inode_unlinked_and_not_open, 281, 0) \ | 213 | x(inode_unlinked_and_not_open, 281, 0) \ |
| 214 | x(inode_unlinked_but_has_dirent, 285, 0) \ | ||
| 214 | x(inode_checksum_type_invalid, 199, 0) \ | 215 | x(inode_checksum_type_invalid, 199, 0) \ |
| 215 | x(inode_compression_type_invalid, 200, 0) \ | 216 | x(inode_compression_type_invalid, 200, 0) \ |
| 216 | x(inode_subvol_root_but_not_dir, 201, 0) \ | 217 | x(inode_subvol_root_but_not_dir, 201, 0) \ |
| @@ -296,7 +297,7 @@ enum bch_fsck_flags { · 79 unmodified lines | |||
| 296 | x(accounting_key_replicas_devs_unsorted, 280, FSCK_AUTOFIX) \ | 297 | x(accounting_key_replicas_devs_unsorted, 280, FSCK_AUTOFIX) \ |
| 297 | x(accounting_key_version_0, 282, FSCK_AUTOFIX) \ | 298 | x(accounting_key_version_0, 282, FSCK_AUTOFIX) \ |
| 298 | x(logged_op_but_clean, 283, FSCK_AUTOFIX) \ | 299 | x(logged_op_but_clean, 283, FSCK_AUTOFIX) \ |
| 299 | x(MAX, 285, 0) | 300 | x(MAX, 286, 0) |
| 300 | 301 | ||
| 301 | enum bch_sb_error_id { | 302 | enum bch_sb_error_id { |
| 302 | #define x(t, n, ...) BCH_FSCK_ERR_##t = n, | 303 | #define x(t, n, ...) BCH_FSCK_ERR_##t = n, |