History

bcachefs: Check for unlinked inodes with dirents

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.

Kent Overstreet committed 2 years ago

Commit c7da5ee1 parent 1c6051b2 files · +41 −15Browse files

Unified · Split

2 files
  1. fs/bcachefs/fsck.c +39 −14
  2. fs/bcachefs/sb-errors_format.h +2 −1
fs/bcachefs/fsck.c+39−14
@@ -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 }
1237err:1249err:
1238fsck_err:1250fsck_err:
1239 bch_err_fn(c, ret);1251 bch_err_fn(c, ret);
1252err_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);
fs/bcachefs/sb-errors_format.h+2−1
@@ -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
301enum bch_sb_error_id {302enum bch_sb_error_id {
302#define x(t, n, ...) BCH_FSCK_ERR_##t = n,303#define x(t, n, ...) BCH_FSCK_ERR_##t = n,