@@ -31,12 +31,12 @@ static int bch2_dirent_has_target(struct btree_trans *trans, struct bkey_s_c_dir
31
31
}
32
32
}
33
33
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 ,
39
- bool * updated_before_k_pos )
34
+ static int bch2_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 ,
39
+ bool * updated_before_k_pos )
40
40
{
41
41
struct qstr old_name = bch2_dirent_get_name (old );
42
42
struct bkey_i_dirent * new = bch2_trans_kmalloc (trans , BKEY_U64s_MAX * sizeof (u64 ));
@@ -233,54 +233,20 @@ static noinline int check_inode_hash_info_matches_root(struct btree_trans *trans
233
233
return ret ;
234
234
}
235
235
236
- int __bch2_str_hash_check_key (struct btree_trans * trans ,
237
- struct snapshots_seen * s ,
238
- const struct bch_hash_desc * desc ,
239
- struct bch_hash_info * hash_info ,
240
- struct btree_iter * k_iter , struct bkey_s_c hash_k ,
241
- bool * updated_before_k_pos )
236
+ /* Put a str_hash key in its proper location, checking for duplicates */
237
+ int bch2_str_hash_repair_key (struct btree_trans * trans ,
238
+ struct snapshots_seen * s ,
239
+ const struct bch_hash_desc * desc ,
240
+ struct bch_hash_info * hash_info ,
241
+ struct btree_iter * k_iter , struct bkey_s_c k ,
242
+ struct btree_iter * dup_iter , struct bkey_s_c dup_k ,
243
+ bool * updated_before_k_pos )
242
244
{
243
245
struct bch_fs * c = trans -> c ;
244
- struct btree_iter iter = {};
245
246
struct printbuf buf = PRINTBUF ;
246
- struct bkey_s_c k ;
247
247
bool free_snapshots_seen = false;
248
248
int ret = 0 ;
249
249
250
- u64 hash = desc -> hash_bkey (hash_info , hash_k );
251
- if (hash_k .k -> p .offset < hash )
252
- goto bad_hash ;
253
-
254
- for_each_btree_key_norestart (trans , iter , desc -> btree_id ,
255
- SPOS (hash_k .k -> p .inode , hash , hash_k .k -> p .snapshot ),
256
- BTREE_ITER_slots |
257
- BTREE_ITER_with_updates , k , ret ) {
258
- if (bkey_eq (k .k -> p , hash_k .k -> p ))
259
- break ;
260
-
261
- if (k .k -> type == desc -> key_type &&
262
- !desc -> cmp_bkey (k , hash_k ))
263
- goto duplicate_entries ;
264
-
265
- if (bkey_deleted (k .k )) {
266
- bch2_trans_iter_exit (trans , & iter );
267
- goto bad_hash ;
268
- }
269
- }
270
- out :
271
- bch2_trans_iter_exit (trans , & iter );
272
- printbuf_exit (& buf );
273
- if (free_snapshots_seen )
274
- darray_exit (& s -> ids );
275
- return ret ;
276
- bad_hash :
277
- /*
278
- * Before doing any repair, check hash_info itself:
279
- */
280
- ret = check_inode_hash_info_matches_root (trans , hash_k .k -> p .inode , hash_info );
281
- if (ret )
282
- goto out ;
283
-
284
250
if (!s ) {
285
251
s = bch2_trans_kmalloc (trans , sizeof (* s ));
286
252
ret = PTR_ERR_OR_ZERO (s );
@@ -297,25 +263,22 @@ int __bch2_str_hash_check_key(struct btree_trans *trans,
297
263
free_snapshots_seen = true;
298
264
}
299
265
300
- if (fsck_err (trans , hash_table_key_wrong_offset ,
301
- "hash table key at wrong offset: btree %s inode %llu offset %llu, hashed to %llu\n%s" ,
302
- bch2_btree_id_str (desc -> btree_id ), hash_k .k -> p .inode , hash_k .k -> p .offset , hash ,
303
- (printbuf_reset (& buf ),
304
- bch2_bkey_val_to_text (& buf , c , hash_k ), buf .buf ))) {
305
- struct bkey_i * new = bch2_bkey_make_mut_noupdate (trans , hash_k );
306
- if (IS_ERR (new ))
307
- return PTR_ERR (new );
308
-
309
- k = bch2_hash_set_or_get_in_snapshot (trans , & iter , * desc , hash_info ,
310
- (subvol_inum ) { 0 , hash_k .k -> p .inode },
311
- hash_k .k -> p .snapshot , new ,
266
+ if (!dup_k .k ) {
267
+ struct bkey_i * new = bch2_bkey_make_mut_noupdate (trans , k );
268
+ ret = PTR_ERR_OR_ZERO (new );
269
+ if (ret )
270
+ goto out ;
271
+
272
+ dup_k = bch2_hash_set_or_get_in_snapshot (trans , dup_iter , * desc , hash_info ,
273
+ (subvol_inum ) { 0 , new -> k .p .inode },
274
+ new -> k .p .snapshot , new ,
312
275
STR_HASH_must_create |
313
276
BTREE_ITER_with_updates |
314
277
BTREE_UPDATE_internal_snapshot_node );
315
- ret = bkey_err (k );
278
+ ret = bkey_err (dup_k );
316
279
if (ret )
317
280
goto out ;
318
- if (k .k )
281
+ if (dup_k .k )
319
282
goto duplicate_entries ;
320
283
321
284
if (bpos_lt (new -> k .p , k .k -> p ))
@@ -329,40 +292,108 @@ int __bch2_str_hash_check_key(struct btree_trans *trans,
329
292
bch2_fsck_update_backpointers (trans , s , * desc , hash_info , new ) ?:
330
293
bch2_trans_commit (trans , NULL , NULL , BCH_TRANS_COMMIT_no_enospc ) ?:
331
294
- BCH_ERR_transaction_restart_commit ;
332
- goto out ;
295
+ } else {
296
+ duplicate_entries :
297
+ ret = hash_pick_winner (trans , * desc , hash_info , k , dup_k );
298
+ if (ret < 0 )
299
+ goto out ;
300
+
301
+ if (!fsck_err (trans , hash_table_key_duplicate ,
302
+ "duplicate hash table keys%s:\n%s" ,
303
+ ret != 2 ? "" : ", both point to valid inodes" ,
304
+ (printbuf_reset (& buf ),
305
+ bch2_bkey_val_to_text (& buf , c , k ),
306
+ prt_newline (& buf ),
307
+ bch2_bkey_val_to_text (& buf , c , dup_k ),
308
+ buf .buf )))
309
+ goto out ;
310
+
311
+ switch (ret ) {
312
+ case 0 :
313
+ ret = bch2_hash_delete_at (trans , * desc , hash_info , k_iter , 0 );
314
+ break ;
315
+ case 1 :
316
+ ret = bch2_hash_delete_at (trans , * desc , hash_info , dup_iter , 0 );
317
+ break ;
318
+ case 2 :
319
+ ret = bch2_fsck_rename_dirent (trans , s , * desc , hash_info ,
320
+ bkey_s_c_to_dirent (k ),
321
+ updated_before_k_pos ) ?:
322
+ bch2_hash_delete_at (trans , * desc , hash_info , k_iter ,
323
+ BTREE_ITER_with_updates );
324
+ goto out ;
325
+ }
326
+
327
+ ret = bch2_trans_commit (trans , NULL , NULL , 0 ) ?:
328
+ - BCH_ERR_transaction_restart_commit ;
333
329
}
330
+ out :
334
331
fsck_err :
335
- goto out ;
336
- duplicate_entries :
337
- ret = hash_pick_winner (trans , * desc , hash_info , hash_k , k );
338
- if (ret < 0 )
339
- goto out ;
332
+ bch2_trans_iter_exit (trans , dup_iter );
333
+ printbuf_exit (& buf );
334
+ if (free_snapshots_seen )
335
+ darray_exit (& s -> ids );
336
+ return ret ;
337
+ }
340
338
341
- if (!fsck_err (trans , hash_table_key_duplicate ,
342
- "duplicate hash table keys%s:\n%s" ,
343
- ret != 2 ? "" : ", both point to valid inodes" ,
344
- (printbuf_reset (& buf ),
345
- bch2_bkey_val_to_text (& buf , c , hash_k ),
346
- prt_newline (& buf ),
347
- bch2_bkey_val_to_text (& buf , c , k ),
348
- buf .buf )))
349
- goto out ;
339
+ int __bch2_str_hash_check_key (struct btree_trans * trans ,
340
+ struct snapshots_seen * s ,
341
+ const struct bch_hash_desc * desc ,
342
+ struct bch_hash_info * hash_info ,
343
+ struct btree_iter * k_iter , struct bkey_s_c hash_k ,
344
+ bool * updated_before_k_pos )
345
+ {
346
+ struct bch_fs * c = trans -> c ;
347
+ struct btree_iter iter = {};
348
+ struct printbuf buf = PRINTBUF ;
349
+ struct bkey_s_c k ;
350
+ int ret = 0 ;
350
351
351
- switch (ret ) {
352
- case 0 :
353
- ret = bch2_hash_delete_at (trans , * desc , hash_info , k_iter , 0 );
354
- break ;
355
- case 1 :
356
- ret = bch2_hash_delete_at (trans , * desc , hash_info , & iter , 0 );
357
- break ;
358
- case 2 :
359
- ret = fsck_rename_dirent (trans , s , * desc , hash_info , bkey_s_c_to_dirent (hash_k ),
360
- updated_before_k_pos ) ?:
361
- bch2_hash_delete_at (trans , * desc , hash_info , k_iter , 0 );
362
- goto out ;
352
+ u64 hash = desc -> hash_bkey (hash_info , hash_k );
353
+ if (hash_k .k -> p .offset < hash )
354
+ goto bad_hash ;
355
+
356
+ for_each_btree_key_norestart (trans , iter , desc -> btree_id ,
357
+ SPOS (hash_k .k -> p .inode , hash , hash_k .k -> p .snapshot ),
358
+ BTREE_ITER_slots |
359
+ BTREE_ITER_with_updates , k , ret ) {
360
+ if (bkey_eq (k .k -> p , hash_k .k -> p ))
361
+ break ;
362
+
363
+ if (k .k -> type == desc -> key_type &&
364
+ !desc -> cmp_bkey (k , hash_k )) {
365
+ ret = check_inode_hash_info_matches_root (trans , hash_k .k -> p .inode ,
366
+ hash_info ) ?:
367
+ bch2_str_hash_repair_key (trans , s , desc , hash_info ,
368
+ k_iter , hash_k ,
369
+ & iter , k , updated_before_k_pos );
370
+ break ;
371
+ }
372
+
373
+ if (bkey_deleted (k .k ))
374
+ goto bad_hash ;
363
375
}
376
+ bch2_trans_iter_exit (trans , & iter );
377
+ out :
378
+ fsck_err :
379
+ printbuf_exit (& buf );
380
+ return ret ;
381
+ bad_hash :
382
+ bch2_trans_iter_exit (trans , & iter );
383
+ /*
384
+ * Before doing any repair, check hash_info itself:
385
+ */
386
+ ret = check_inode_hash_info_matches_root (trans , hash_k .k -> p .inode , hash_info );
387
+ if (ret )
388
+ goto out ;
364
389
365
- ret = bch2_trans_commit (trans , NULL , NULL , 0 ) ?:
366
- - BCH_ERR_transaction_restart_commit ;
390
+ if (fsck_err (trans , hash_table_key_wrong_offset ,
391
+ "hash table key at wrong offset: should be at %llu\n%s" ,
392
+ hash ,
393
+ (bch2_bkey_val_to_text (& buf , c , hash_k ), buf .buf )))
394
+ ret = bch2_str_hash_repair_key (trans , s , desc , hash_info ,
395
+ k_iter , hash_k ,
396
+ & iter , bkey_s_c_null ,
397
+ updated_before_k_pos );
367
398
goto out ;
368
399
}
0 commit comments