Loading fs/bcachefs/fsck.c +111 −92 Original line number Diff line number Diff line Loading @@ -455,21 +455,14 @@ static int reconstruct_subvol(struct btree_trans *trans, u32 snapshotid, u32 sub return 0; } static int reconstruct_inode(struct btree_trans *trans, u32 snapshot, u64 inum, u64 size, unsigned mode) static int reconstruct_inode(struct btree_trans *trans, enum btree_id btree, u32 snapshot, u64 inum) { struct bch_fs *c = trans->c; struct bch_inode_unpacked new_inode; bch2_inode_init_early(c, &new_inode); bch2_inode_init_late(&new_inode, bch2_current_time(c), 0, 0, mode|0755, 0, NULL); new_inode.bi_size = size; new_inode.bi_inum = inum; unsigned i_mode = S_IFREG; u64 i_size = 0; return __bch2_fsck_write_inode(trans, &new_inode, snapshot); } static int reconstruct_reg_inode(struct btree_trans *trans, u32 snapshot, u64 inum) { switch (btree) { case BTREE_ID_extents: { struct btree_iter iter = {}; bch2_trans_iter_init(trans, &iter, BTREE_ID_extents, SPOS(inum, U64_MAX, snapshot), 0); Loading @@ -479,7 +472,25 @@ static int reconstruct_reg_inode(struct btree_trans *trans, u32 snapshot, u64 in if (ret) return ret; return reconstruct_inode(trans, snapshot, inum, k.k->p.offset << 9, S_IFREG); i_size = k.k->p.offset << 9; break; } case BTREE_ID_dirents: i_mode = S_IFDIR; break; case BTREE_ID_xattrs: break; default: BUG(); } struct bch_inode_unpacked new_inode; bch2_inode_init_early(c, &new_inode); bch2_inode_init_late(&new_inode, bch2_current_time(c), 0, 0, i_mode|0600, 0, NULL); new_inode.bi_size = i_size; new_inode.bi_inum = inum; return __bch2_fsck_write_inode(trans, &new_inode, snapshot); } struct snapshots_seen { Loading Loading @@ -1170,6 +1181,70 @@ int bch2_check_inodes(struct bch_fs *c) return ret; } static inline bool btree_matches_i_mode(enum btree_id btree, unsigned mode) { switch (btree) { case BTREE_ID_extents: return S_ISREG(mode) || S_ISLNK(mode); case BTREE_ID_dirents: return S_ISDIR(mode); case BTREE_ID_xattrs: return true; default: BUG(); } } static int check_key_has_inode(struct btree_trans *trans, struct btree_iter *iter, struct inode_walker *inode, struct inode_walker_entry *i, struct bkey_s_c k) { struct bch_fs *c = trans->c; struct printbuf buf = PRINTBUF; int ret = PTR_ERR_OR_ZERO(i); if (ret) return ret; if (k.k->type == KEY_TYPE_whiteout) goto out; if (!i && (c->sb.btrees_lost_data & BIT_ULL(BTREE_ID_inodes))) { ret = reconstruct_inode(trans, iter->btree_id, k.k->p.snapshot, k.k->p.inode) ?: bch2_trans_commit(trans, NULL, NULL, BCH_TRANS_COMMIT_no_enospc); if (ret) goto err; inode->last_pos.inode--; ret = -BCH_ERR_transaction_restart_nested; goto err; } if (fsck_err_on(!i, c, key_in_missing_inode, "key in missing inode:\n %s", (printbuf_reset(&buf), bch2_bkey_val_to_text(&buf, c, k), buf.buf))) goto delete; if (fsck_err_on(i && !btree_matches_i_mode(iter->btree_id, i->inode.bi_mode), c, key_in_wrong_inode_type, "key for wrong inode mode %o:\n %s", i->inode.bi_mode, (printbuf_reset(&buf), bch2_bkey_val_to_text(&buf, c, k), buf.buf))) goto delete; out: err: fsck_err: printbuf_exit(&buf); bch_err_fn(c, ret); return ret; delete: ret = bch2_btree_delete_at(trans, iter, BTREE_UPDATE_internal_snapshot_node); goto out; } static int check_i_sectors_notnested(struct btree_trans *trans, struct inode_walker *w) { struct bch_fs *c = trans->c; Loading Loading @@ -1476,43 +1551,20 @@ static int check_extent(struct btree_trans *trans, struct btree_iter *iter, goto err; } i = walk_inode(trans, inode, k); ret = PTR_ERR_OR_ZERO(i); if (ret) goto err; ret = snapshots_seen_update(c, s, iter->btree_id, k.k->p); if (ret) goto err; if (k.k->type != KEY_TYPE_whiteout) { if (!i && (c->sb.btrees_lost_data & BIT_ULL(BTREE_ID_inodes))) { ret = reconstruct_reg_inode(trans, k.k->p.snapshot, k.k->p.inode) ?: bch2_trans_commit(trans, NULL, NULL, BCH_TRANS_COMMIT_no_enospc); i = walk_inode(trans, inode, k); ret = PTR_ERR_OR_ZERO(i); if (ret) goto err; inode->last_pos.inode--; ret = -BCH_ERR_transaction_restart_nested; ret = check_key_has_inode(trans, iter, inode, i, k); if (ret) goto err; } if (fsck_err_on(!i, c, extent_in_missing_inode, "extent in missing inode:\n %s", (printbuf_reset(&buf), bch2_bkey_val_to_text(&buf, c, k), buf.buf))) goto delete; if (fsck_err_on(i && !S_ISREG(i->inode.bi_mode) && !S_ISLNK(i->inode.bi_mode), c, extent_in_non_reg_inode, "extent in non regular inode mode %o:\n %s", i->inode.bi_mode, (printbuf_reset(&buf), bch2_bkey_val_to_text(&buf, c, k), buf.buf))) goto delete; if (k.k->type != KEY_TYPE_whiteout) { ret = check_overlapping_extents(trans, s, extent_ends, k, iter, &inode->recalculate_sums); if (ret) Loading @@ -1525,7 +1577,7 @@ static int check_extent(struct btree_trans *trans, struct btree_iter *iter, * didn't have one, iterate over all inodes: */ if (!i) i = inode->inodes.data + inode->inodes.nr - 1; i = &darray_last(inode->inodes); for (; inode->inodes.data && i >= inode->inodes.data; Loading Loading @@ -1574,9 +1626,6 @@ static int check_extent(struct btree_trans *trans, struct btree_iter *iter, printbuf_exit(&buf); bch_err_fn(c, ret); return ret; delete: ret = bch2_btree_delete_at(trans, iter, BTREE_UPDATE_internal_snapshot_node); goto out; } /* Loading Loading @@ -2009,49 +2058,21 @@ static int check_dirent(struct btree_trans *trans, struct btree_iter *iter, goto err; } BUG_ON(!btree_iter_path(trans, iter)->should_be_locked); i = walk_inode(trans, dir, k); ret = PTR_ERR_OR_ZERO(i); if (ret < 0) goto err; if (dir->first_this_inode && dir->inodes.nr) *hash_info = bch2_hash_info_init(c, &dir->inodes.data[0].inode); dir->first_this_inode = false; if (!i && (c->sb.btrees_lost_data & BIT_ULL(BTREE_ID_inodes))) { ret = reconstruct_inode(trans, k.k->p.snapshot, k.k->p.inode, 0, S_IFDIR) ?: bch2_trans_commit(trans, NULL, NULL, BCH_TRANS_COMMIT_no_enospc); ret = check_key_has_inode(trans, iter, dir, i, k); if (ret) goto err; dir->last_pos.inode--; ret = -BCH_ERR_transaction_restart_nested; goto err; } if (fsck_err_on(!i, c, dirent_in_missing_dir_inode, "dirent in nonexisting directory:\n%s", (printbuf_reset(&buf), bch2_bkey_val_to_text(&buf, c, k), buf.buf))) { ret = bch2_btree_delete_at(trans, iter, BTREE_UPDATE_internal_snapshot_node); goto out; } if (!i) goto out; if (fsck_err_on(!S_ISDIR(i->inode.bi_mode), c, dirent_in_non_dir_inode, "dirent in non directory inode type %s:\n%s", bch2_d_type_str(inode_d_type(&i->inode)), (printbuf_reset(&buf), bch2_bkey_val_to_text(&buf, c, k), buf.buf))) { ret = bch2_btree_delete_at(trans, iter, 0); goto out; } if (dir->first_this_inode) *hash_info = bch2_hash_info_init(c, &i->inode); dir->first_this_inode = false; ret = hash_check_key(trans, bch2_dirent_hash_desc, hash_info, iter, k); if (ret < 0) Loading Loading @@ -2156,20 +2177,18 @@ static int check_xattr(struct btree_trans *trans, struct btree_iter *iter, if (ret) return ret; if (inode->first_this_inode && inode->inodes.nr) *hash_info = bch2_hash_info_init(c, &inode->inodes.data[0].inode); inode->first_this_inode = false; if (fsck_err_on(!i, c, xattr_in_missing_inode, "xattr for missing inode %llu", k.k->p.inode)) return bch2_btree_delete_at(trans, iter, 0); ret = check_key_has_inode(trans, iter, inode, i, k); if (ret) return ret; if (!i) return 0; if (inode->first_this_inode) *hash_info = bch2_hash_info_init(c, &i->inode); inode->first_this_inode = false; ret = hash_check_key(trans, bch2_xattr_hash_desc, hash_info, iter, k); fsck_err: bch_err_fn(c, ret); return ret; } Loading fs/bcachefs/sb-errors_format.h +2 −2 Original line number Diff line number Diff line Loading @@ -227,8 +227,8 @@ enum bch_fsck_flags { x(deleted_inode_is_dir, 213, 0) \ x(deleted_inode_not_unlinked, 214, 0) \ x(extent_overlapping, 215, 0) \ x(extent_in_missing_inode, 216, 0) \ x(extent_in_non_reg_inode, 217, 0) \ x(key_in_missing_inode, 216, 0) \ x(key_in_wrong_inode_type, 217, 0) \ x(extent_past_end_of_inode, 218, 0) \ x(dirent_empty_name, 219, 0) \ x(dirent_val_too_big, 220, 0) \ Loading Loading
fs/bcachefs/fsck.c +111 −92 Original line number Diff line number Diff line Loading @@ -455,21 +455,14 @@ static int reconstruct_subvol(struct btree_trans *trans, u32 snapshotid, u32 sub return 0; } static int reconstruct_inode(struct btree_trans *trans, u32 snapshot, u64 inum, u64 size, unsigned mode) static int reconstruct_inode(struct btree_trans *trans, enum btree_id btree, u32 snapshot, u64 inum) { struct bch_fs *c = trans->c; struct bch_inode_unpacked new_inode; bch2_inode_init_early(c, &new_inode); bch2_inode_init_late(&new_inode, bch2_current_time(c), 0, 0, mode|0755, 0, NULL); new_inode.bi_size = size; new_inode.bi_inum = inum; unsigned i_mode = S_IFREG; u64 i_size = 0; return __bch2_fsck_write_inode(trans, &new_inode, snapshot); } static int reconstruct_reg_inode(struct btree_trans *trans, u32 snapshot, u64 inum) { switch (btree) { case BTREE_ID_extents: { struct btree_iter iter = {}; bch2_trans_iter_init(trans, &iter, BTREE_ID_extents, SPOS(inum, U64_MAX, snapshot), 0); Loading @@ -479,7 +472,25 @@ static int reconstruct_reg_inode(struct btree_trans *trans, u32 snapshot, u64 in if (ret) return ret; return reconstruct_inode(trans, snapshot, inum, k.k->p.offset << 9, S_IFREG); i_size = k.k->p.offset << 9; break; } case BTREE_ID_dirents: i_mode = S_IFDIR; break; case BTREE_ID_xattrs: break; default: BUG(); } struct bch_inode_unpacked new_inode; bch2_inode_init_early(c, &new_inode); bch2_inode_init_late(&new_inode, bch2_current_time(c), 0, 0, i_mode|0600, 0, NULL); new_inode.bi_size = i_size; new_inode.bi_inum = inum; return __bch2_fsck_write_inode(trans, &new_inode, snapshot); } struct snapshots_seen { Loading Loading @@ -1170,6 +1181,70 @@ int bch2_check_inodes(struct bch_fs *c) return ret; } static inline bool btree_matches_i_mode(enum btree_id btree, unsigned mode) { switch (btree) { case BTREE_ID_extents: return S_ISREG(mode) || S_ISLNK(mode); case BTREE_ID_dirents: return S_ISDIR(mode); case BTREE_ID_xattrs: return true; default: BUG(); } } static int check_key_has_inode(struct btree_trans *trans, struct btree_iter *iter, struct inode_walker *inode, struct inode_walker_entry *i, struct bkey_s_c k) { struct bch_fs *c = trans->c; struct printbuf buf = PRINTBUF; int ret = PTR_ERR_OR_ZERO(i); if (ret) return ret; if (k.k->type == KEY_TYPE_whiteout) goto out; if (!i && (c->sb.btrees_lost_data & BIT_ULL(BTREE_ID_inodes))) { ret = reconstruct_inode(trans, iter->btree_id, k.k->p.snapshot, k.k->p.inode) ?: bch2_trans_commit(trans, NULL, NULL, BCH_TRANS_COMMIT_no_enospc); if (ret) goto err; inode->last_pos.inode--; ret = -BCH_ERR_transaction_restart_nested; goto err; } if (fsck_err_on(!i, c, key_in_missing_inode, "key in missing inode:\n %s", (printbuf_reset(&buf), bch2_bkey_val_to_text(&buf, c, k), buf.buf))) goto delete; if (fsck_err_on(i && !btree_matches_i_mode(iter->btree_id, i->inode.bi_mode), c, key_in_wrong_inode_type, "key for wrong inode mode %o:\n %s", i->inode.bi_mode, (printbuf_reset(&buf), bch2_bkey_val_to_text(&buf, c, k), buf.buf))) goto delete; out: err: fsck_err: printbuf_exit(&buf); bch_err_fn(c, ret); return ret; delete: ret = bch2_btree_delete_at(trans, iter, BTREE_UPDATE_internal_snapshot_node); goto out; } static int check_i_sectors_notnested(struct btree_trans *trans, struct inode_walker *w) { struct bch_fs *c = trans->c; Loading Loading @@ -1476,43 +1551,20 @@ static int check_extent(struct btree_trans *trans, struct btree_iter *iter, goto err; } i = walk_inode(trans, inode, k); ret = PTR_ERR_OR_ZERO(i); if (ret) goto err; ret = snapshots_seen_update(c, s, iter->btree_id, k.k->p); if (ret) goto err; if (k.k->type != KEY_TYPE_whiteout) { if (!i && (c->sb.btrees_lost_data & BIT_ULL(BTREE_ID_inodes))) { ret = reconstruct_reg_inode(trans, k.k->p.snapshot, k.k->p.inode) ?: bch2_trans_commit(trans, NULL, NULL, BCH_TRANS_COMMIT_no_enospc); i = walk_inode(trans, inode, k); ret = PTR_ERR_OR_ZERO(i); if (ret) goto err; inode->last_pos.inode--; ret = -BCH_ERR_transaction_restart_nested; ret = check_key_has_inode(trans, iter, inode, i, k); if (ret) goto err; } if (fsck_err_on(!i, c, extent_in_missing_inode, "extent in missing inode:\n %s", (printbuf_reset(&buf), bch2_bkey_val_to_text(&buf, c, k), buf.buf))) goto delete; if (fsck_err_on(i && !S_ISREG(i->inode.bi_mode) && !S_ISLNK(i->inode.bi_mode), c, extent_in_non_reg_inode, "extent in non regular inode mode %o:\n %s", i->inode.bi_mode, (printbuf_reset(&buf), bch2_bkey_val_to_text(&buf, c, k), buf.buf))) goto delete; if (k.k->type != KEY_TYPE_whiteout) { ret = check_overlapping_extents(trans, s, extent_ends, k, iter, &inode->recalculate_sums); if (ret) Loading @@ -1525,7 +1577,7 @@ static int check_extent(struct btree_trans *trans, struct btree_iter *iter, * didn't have one, iterate over all inodes: */ if (!i) i = inode->inodes.data + inode->inodes.nr - 1; i = &darray_last(inode->inodes); for (; inode->inodes.data && i >= inode->inodes.data; Loading Loading @@ -1574,9 +1626,6 @@ static int check_extent(struct btree_trans *trans, struct btree_iter *iter, printbuf_exit(&buf); bch_err_fn(c, ret); return ret; delete: ret = bch2_btree_delete_at(trans, iter, BTREE_UPDATE_internal_snapshot_node); goto out; } /* Loading Loading @@ -2009,49 +2058,21 @@ static int check_dirent(struct btree_trans *trans, struct btree_iter *iter, goto err; } BUG_ON(!btree_iter_path(trans, iter)->should_be_locked); i = walk_inode(trans, dir, k); ret = PTR_ERR_OR_ZERO(i); if (ret < 0) goto err; if (dir->first_this_inode && dir->inodes.nr) *hash_info = bch2_hash_info_init(c, &dir->inodes.data[0].inode); dir->first_this_inode = false; if (!i && (c->sb.btrees_lost_data & BIT_ULL(BTREE_ID_inodes))) { ret = reconstruct_inode(trans, k.k->p.snapshot, k.k->p.inode, 0, S_IFDIR) ?: bch2_trans_commit(trans, NULL, NULL, BCH_TRANS_COMMIT_no_enospc); ret = check_key_has_inode(trans, iter, dir, i, k); if (ret) goto err; dir->last_pos.inode--; ret = -BCH_ERR_transaction_restart_nested; goto err; } if (fsck_err_on(!i, c, dirent_in_missing_dir_inode, "dirent in nonexisting directory:\n%s", (printbuf_reset(&buf), bch2_bkey_val_to_text(&buf, c, k), buf.buf))) { ret = bch2_btree_delete_at(trans, iter, BTREE_UPDATE_internal_snapshot_node); goto out; } if (!i) goto out; if (fsck_err_on(!S_ISDIR(i->inode.bi_mode), c, dirent_in_non_dir_inode, "dirent in non directory inode type %s:\n%s", bch2_d_type_str(inode_d_type(&i->inode)), (printbuf_reset(&buf), bch2_bkey_val_to_text(&buf, c, k), buf.buf))) { ret = bch2_btree_delete_at(trans, iter, 0); goto out; } if (dir->first_this_inode) *hash_info = bch2_hash_info_init(c, &i->inode); dir->first_this_inode = false; ret = hash_check_key(trans, bch2_dirent_hash_desc, hash_info, iter, k); if (ret < 0) Loading Loading @@ -2156,20 +2177,18 @@ static int check_xattr(struct btree_trans *trans, struct btree_iter *iter, if (ret) return ret; if (inode->first_this_inode && inode->inodes.nr) *hash_info = bch2_hash_info_init(c, &inode->inodes.data[0].inode); inode->first_this_inode = false; if (fsck_err_on(!i, c, xattr_in_missing_inode, "xattr for missing inode %llu", k.k->p.inode)) return bch2_btree_delete_at(trans, iter, 0); ret = check_key_has_inode(trans, iter, inode, i, k); if (ret) return ret; if (!i) return 0; if (inode->first_this_inode) *hash_info = bch2_hash_info_init(c, &i->inode); inode->first_this_inode = false; ret = hash_check_key(trans, bch2_xattr_hash_desc, hash_info, iter, k); fsck_err: bch_err_fn(c, ret); return ret; } Loading
fs/bcachefs/sb-errors_format.h +2 −2 Original line number Diff line number Diff line Loading @@ -227,8 +227,8 @@ enum bch_fsck_flags { x(deleted_inode_is_dir, 213, 0) \ x(deleted_inode_not_unlinked, 214, 0) \ x(extent_overlapping, 215, 0) \ x(extent_in_missing_inode, 216, 0) \ x(extent_in_non_reg_inode, 217, 0) \ x(key_in_missing_inode, 216, 0) \ x(key_in_wrong_inode_type, 217, 0) \ x(extent_past_end_of_inode, 218, 0) \ x(dirent_empty_name, 219, 0) \ x(dirent_val_too_big, 220, 0) \ Loading