1 // SPDX-License-Identifier: GPL-2.0
4 #include "btree_cache.h"
5 #include "btree_update.h"
11 static int bch2_dirent_has_target(struct btree_trans
*trans
, struct bkey_s_c_dirent d
)
13 if (d
.v
->d_type
== DT_SUBVOL
) {
14 struct bch_subvolume subvol
;
15 int ret
= bch2_subvolume_get(trans
, le32_to_cpu(d
.v
->d_child_subvol
),
17 if (ret
&& !bch2_err_matches(ret
, ENOENT
))
21 struct btree_iter iter
;
22 struct bkey_s_c k
= bch2_bkey_get_iter(trans
, &iter
, BTREE_ID_inodes
,
23 SPOS(0, le64_to_cpu(d
.v
->d_inum
), d
.k
->p
.snapshot
), 0);
24 int ret
= bkey_err(k
);
28 ret
= bkey_is_inode(k
.k
);
29 bch2_trans_iter_exit(trans
, &iter
);
34 static noinline
int fsck_rename_dirent(struct btree_trans
*trans
,
35 struct snapshots_seen
*s
,
36 const struct bch_hash_desc desc
,
37 struct bch_hash_info
*hash_info
,
38 struct bkey_s_c_dirent old
)
40 struct qstr old_name
= bch2_dirent_get_name(old
);
41 struct bkey_i_dirent
*new = bch2_trans_kmalloc(trans
, bkey_bytes(old
.k
) + 32);
42 int ret
= PTR_ERR_OR_ZERO(new);
46 bkey_dirent_init(&new->k_i
);
47 dirent_copy_target(new, old
);
50 for (unsigned i
= 0; i
< 1000; i
++) {
51 unsigned len
= sprintf(new->v
.d_name
, "%.*s.fsck_renamed-%u",
52 old_name
.len
, old_name
.name
, i
);
53 unsigned u64s
= BKEY_U64s
+ dirent_val_u64s(len
);
60 ret
= bch2_hash_set_in_snapshot(trans
, bch2_dirent_hash_desc
, hash_info
,
61 (subvol_inum
) { 0, old
.k
->p
.inode
},
62 old
.k
->p
.snapshot
, &new->k_i
,
63 BTREE_UPDATE_internal_snapshot_node
);
64 if (!bch2_err_matches(ret
, EEXIST
))
71 return bch2_fsck_update_backpointers(trans
, s
, desc
, hash_info
, &new->k_i
);
74 static noinline
int hash_pick_winner(struct btree_trans
*trans
,
75 const struct bch_hash_desc desc
,
76 struct bch_hash_info
*hash_info
,
80 if (bkey_val_bytes(k1
.k
) == bkey_val_bytes(k2
.k
) &&
81 !memcmp(k1
.v
, k2
.v
, bkey_val_bytes(k1
.k
)))
84 switch (desc
.btree_id
) {
85 case BTREE_ID_dirents
: {
86 int ret
= bch2_dirent_has_target(trans
, bkey_s_c_to_dirent(k1
));
92 ret
= bch2_dirent_has_target(trans
, bkey_s_c_to_dirent(k2
));
104 static int repair_inode_hash_info(struct btree_trans
*trans
,
105 struct bch_inode_unpacked
*snapshot_root
)
107 struct btree_iter iter
;
111 for_each_btree_key_reverse_norestart(trans
, iter
, BTREE_ID_inodes
,
112 SPOS(0, snapshot_root
->bi_inum
, snapshot_root
->bi_snapshot
- 1),
113 BTREE_ITER_all_snapshots
, k
, ret
) {
114 if (k
.k
->p
.offset
!= snapshot_root
->bi_inum
)
116 if (!bkey_is_inode(k
.k
))
119 struct bch_inode_unpacked inode
;
120 ret
= bch2_inode_unpack(k
, &inode
);
124 if (fsck_err_on(inode
.bi_hash_seed
!= snapshot_root
->bi_hash_seed
||
125 INODE_STR_HASH(&inode
) != INODE_STR_HASH(snapshot_root
),
126 trans
, inode_snapshot_mismatch
,
127 "inode hash info in different snapshots don't match")) {
128 inode
.bi_hash_seed
= snapshot_root
->bi_hash_seed
;
129 SET_INODE_STR_HASH(&inode
, INODE_STR_HASH(snapshot_root
));
130 ret
= __bch2_fsck_write_inode(trans
, &inode
) ?:
131 bch2_trans_commit(trans
, NULL
, NULL
, BCH_TRANS_COMMIT_no_enospc
) ?:
132 -BCH_ERR_transaction_restart_nested
;
137 bch2_trans_iter_exit(trans
, &iter
);
142 * All versions of the same inode in different snapshots must have the same hash
143 * seed/type: verify that the hash info we're using matches the root
145 static noinline
int check_inode_hash_info_matches_root(struct btree_trans
*trans
, u64 inum
,
146 struct bch_hash_info
*hash_info
)
148 struct bch_fs
*c
= trans
->c
;
149 struct btree_iter iter
;
153 for_each_btree_key_reverse_norestart(trans
, iter
, BTREE_ID_inodes
, SPOS(0, inum
, U32_MAX
),
154 BTREE_ITER_all_snapshots
, k
, ret
) {
155 if (k
.k
->p
.offset
!= inum
)
157 if (bkey_is_inode(k
.k
))
160 bch_err(c
, "%s(): inum %llu not found", __func__
, inum
);
161 ret
= -BCH_ERR_fsck_repair_unimplemented
;
164 struct bch_inode_unpacked inode
;
165 ret
= bch2_inode_unpack(k
, &inode
);
169 struct bch_hash_info hash2
= bch2_hash_info_init(c
, &inode
);
170 if (hash_info
->type
!= hash2
.type
||
171 memcmp(&hash_info
->siphash_key
, &hash2
.siphash_key
, sizeof(hash2
.siphash_key
))) {
172 ret
= repair_inode_hash_info(trans
, &inode
);
174 bch_err(c
, "inode hash info mismatch with root, but mismatch not found\n"
178 hash_info
->siphash_key
.k0
,
179 hash_info
->siphash_key
.k1
,
181 hash2
.siphash_key
.k0
,
182 hash2
.siphash_key
.k1
);
183 ret
= -BCH_ERR_fsck_repair_unimplemented
;
187 bch2_trans_iter_exit(trans
, &iter
);
191 int __bch2_str_hash_check_key(struct btree_trans
*trans
,
192 struct snapshots_seen
*s
,
193 const struct bch_hash_desc
*desc
,
194 struct bch_hash_info
*hash_info
,
195 struct btree_iter
*k_iter
, struct bkey_s_c hash_k
)
197 struct bch_fs
*c
= trans
->c
;
198 struct btree_iter iter
= { NULL
};
199 struct printbuf buf
= PRINTBUF
;
203 u64 hash
= desc
->hash_bkey(hash_info
, hash_k
);
204 if (hash_k
.k
->p
.offset
< hash
)
207 for_each_btree_key_norestart(trans
, iter
, desc
->btree_id
,
208 SPOS(hash_k
.k
->p
.inode
, hash
, hash_k
.k
->p
.snapshot
),
209 BTREE_ITER_slots
, k
, ret
) {
210 if (bkey_eq(k
.k
->p
, hash_k
.k
->p
))
213 if (k
.k
->type
== desc
->key_type
&&
214 !desc
->cmp_bkey(k
, hash_k
))
215 goto duplicate_entries
;
217 if (bkey_deleted(k
.k
)) {
218 bch2_trans_iter_exit(trans
, &iter
);
223 bch2_trans_iter_exit(trans
, &iter
);
228 * Before doing any repair, check hash_info itself:
230 ret
= check_inode_hash_info_matches_root(trans
, hash_k
.k
->p
.inode
, hash_info
);
234 if (fsck_err(trans
, hash_table_key_wrong_offset
,
235 "hash table key at wrong offset: btree %s inode %llu offset %llu, hashed to %llu\n %s",
236 bch2_btree_id_str(desc
->btree_id
), hash_k
.k
->p
.inode
, hash_k
.k
->p
.offset
, hash
,
237 (printbuf_reset(&buf
),
238 bch2_bkey_val_to_text(&buf
, c
, hash_k
), buf
.buf
))) {
239 struct bkey_i
*new = bch2_bkey_make_mut_noupdate(trans
, hash_k
);
243 k
= bch2_hash_set_or_get_in_snapshot(trans
, &iter
, *desc
, hash_info
,
244 (subvol_inum
) { 0, hash_k
.k
->p
.inode
},
245 hash_k
.k
->p
.snapshot
, new,
246 STR_HASH_must_create
|
247 BTREE_ITER_with_updates
|
248 BTREE_UPDATE_internal_snapshot_node
);
253 goto duplicate_entries
;
255 ret
= bch2_hash_delete_at(trans
, *desc
, hash_info
, k_iter
,
256 BTREE_UPDATE_internal_snapshot_node
) ?:
257 bch2_fsck_update_backpointers(trans
, s
, *desc
, hash_info
, new) ?:
258 bch2_trans_commit(trans
, NULL
, NULL
, BCH_TRANS_COMMIT_no_enospc
) ?:
259 -BCH_ERR_transaction_restart_nested
;
265 ret
= hash_pick_winner(trans
, *desc
, hash_info
, hash_k
, k
);
269 if (!fsck_err(trans
, hash_table_key_duplicate
,
270 "duplicate hash table keys%s:\n%s",
271 ret
!= 2 ? "" : ", both point to valid inodes",
272 (printbuf_reset(&buf
),
273 bch2_bkey_val_to_text(&buf
, c
, hash_k
),
275 bch2_bkey_val_to_text(&buf
, c
, k
),
281 ret
= bch2_hash_delete_at(trans
, *desc
, hash_info
, k_iter
, 0);
284 ret
= bch2_hash_delete_at(trans
, *desc
, hash_info
, &iter
, 0);
287 ret
= fsck_rename_dirent(trans
, s
, *desc
, hash_info
, bkey_s_c_to_dirent(hash_k
)) ?:
288 bch2_hash_delete_at(trans
, *desc
, hash_info
, k_iter
, 0);
292 ret
= bch2_trans_commit(trans
, NULL
, NULL
, 0) ?:
293 -BCH_ERR_transaction_restart_nested
;