8
8
#include "btree_update.h"
9
9
#include "btree_update_interior.h"
10
10
#include "btree_write_buffer.h"
11
+ #include "checksum.h"
11
12
#include "error.h"
12
13
13
14
#include <linux/mm.h>
@@ -418,28 +419,113 @@ struct extents_to_bp_state {
418
419
struct bkey_buf last_flushed ;
419
420
};
420
421
422
+ static int drop_dev_and_update (struct btree_trans * trans , enum btree_id btree ,
423
+ struct bkey_s_c extent , unsigned dev )
424
+ {
425
+ struct bkey_i * n = bch2_bkey_make_mut_noupdate (trans , extent );
426
+ int ret = PTR_ERR_OR_ZERO (n );
427
+ if (ret )
428
+ return ret ;
429
+
430
+ bch2_bkey_drop_device (bkey_i_to_s (n ), dev );
431
+ return bch2_btree_insert_trans (trans , btree , n , 0 );
432
+ }
433
+
434
+ static int check_extent_checksum (struct btree_trans * trans ,
435
+ enum btree_id btree , struct bkey_s_c extent ,
436
+ enum btree_id o_btree , struct bkey_s_c extent2 , unsigned dev )
437
+ {
438
+ struct bch_fs * c = trans -> c ;
439
+ struct bkey_ptrs_c ptrs = bch2_bkey_ptrs_c (extent );
440
+ const union bch_extent_entry * entry ;
441
+ struct extent_ptr_decoded p ;
442
+ struct printbuf buf = PRINTBUF ;
443
+ void * data_buf = NULL ;
444
+ struct bio * bio = NULL ;
445
+ size_t bytes ;
446
+ int ret = 0 ;
447
+
448
+ if (bkey_is_btree_ptr (extent .k ))
449
+ return false;
450
+
451
+ bkey_for_each_ptr_decode (extent .k , ptrs , p , entry )
452
+ if (p .ptr .dev == dev )
453
+ goto found ;
454
+ BUG ();
455
+ found :
456
+ if (!p .crc .csum_type )
457
+ return false;
458
+
459
+ bytes = p .crc .compressed_size << 9 ;
460
+
461
+ struct bch_dev * ca = bch_dev_bkey_exists (c , dev );
462
+ if (!bch2_dev_get_ioref (ca , READ ))
463
+ return false;
464
+
465
+ data_buf = kvmalloc (bytes , GFP_KERNEL );
466
+ if (!data_buf ) {
467
+ ret = - ENOMEM ;
468
+ goto err ;
469
+ }
470
+
471
+ bio = bio_alloc (ca -> disk_sb .bdev , 1 , REQ_OP_READ , GFP_KERNEL );
472
+ bio -> bi_iter .bi_sector = p .ptr .offset ;
473
+ bch2_bio_map (bio , data_buf , bytes );
474
+ ret = submit_bio_wait (bio );
475
+ if (ret )
476
+ goto err ;
477
+
478
+ prt_str (& buf , "extents pointing to same space, but first extent checksum bad:" );
479
+ prt_printf (& buf , "\n %s " , bch2_btree_id_str (btree ));
480
+ bch2_bkey_val_to_text (& buf , c , extent );
481
+ prt_printf (& buf , "\n %s " , bch2_btree_id_str (o_btree ));
482
+ bch2_bkey_val_to_text (& buf , c , extent2 );
483
+
484
+ struct nonce nonce = extent_nonce (extent .k -> version , p .crc );
485
+ struct bch_csum csum = bch2_checksum (c , p .crc .csum_type , nonce , data_buf , bytes );
486
+ if (fsck_err_on (bch2_crc_cmp (csum , p .crc .csum ),
487
+ c , dup_backpointer_to_bad_csum_extent ,
488
+ "%s" , buf .buf ))
489
+ ret = drop_dev_and_update (trans , btree , extent , dev ) ?: 1 ;
490
+ fsck_err :
491
+ err :
492
+ if (bio )
493
+ bio_put (bio );
494
+ kvfree (data_buf );
495
+ percpu_ref_put (& ca -> io_ref );
496
+ printbuf_exit (& buf );
497
+ return ret ;
498
+ }
499
+
421
500
static int check_bp_exists (struct btree_trans * trans ,
422
501
struct extents_to_bp_state * s ,
423
502
struct bpos bucket ,
424
503
struct bch_backpointer bp ,
425
504
struct bkey_s_c orig_k )
426
505
{
427
506
struct bch_fs * c = trans -> c ;
428
- struct btree_iter bp_iter = { NULL };
507
+ struct btree_iter bp_iter = {};
508
+ struct btree_iter other_extent_iter = {};
429
509
struct printbuf buf = PRINTBUF ;
430
510
struct bkey_s_c bp_k ;
431
511
struct bkey_buf tmp ;
432
512
int ret ;
433
513
434
514
bch2_bkey_buf_init (& tmp );
435
515
516
+ if (!bch2_dev_bucket_exists (c , bucket )) {
517
+ prt_str (& buf , "extent for nonexistent device:bucket " );
518
+ bch2_bpos_to_text (& buf , bucket );
519
+ prt_str (& buf , "\n " );
520
+ bch2_bkey_val_to_text (& buf , c , orig_k );
521
+ bch_err (c , "%s" , buf .buf );
522
+ return - BCH_ERR_fsck_repair_unimplemented ;
523
+ }
524
+
436
525
if (bpos_lt (bucket , s -> bucket_start ) ||
437
526
bpos_gt (bucket , s -> bucket_end ))
438
527
return 0 ;
439
528
440
- if (!bch2_dev_bucket_exists (c , bucket ))
441
- goto missing ;
442
-
443
529
bp_k = bch2_bkey_get_iter (trans , & bp_iter , BTREE_ID_backpointers ,
444
530
bucket_pos_to_bp (c , bucket , bp .bucket_offset ),
445
531
0 );
@@ -465,21 +551,94 @@ static int check_bp_exists(struct btree_trans *trans,
465
551
ret = - BCH_ERR_transaction_restart_write_buffer_flush ;
466
552
goto out ;
467
553
}
468
- goto missing ;
554
+
555
+ goto check_existing_bp ;
469
556
}
470
557
out :
471
558
err :
472
559
fsck_err :
560
+ bch2_trans_iter_exit (trans , & other_extent_iter );
473
561
bch2_trans_iter_exit (trans , & bp_iter );
474
562
bch2_bkey_buf_exit (& tmp , c );
475
563
printbuf_exit (& buf );
476
564
return ret ;
565
+ check_existing_bp :
566
+ /* Do we have a backpointer for a different extent? */
567
+ if (bp_k .k -> type != KEY_TYPE_backpointer )
568
+ goto missing ;
569
+
570
+ struct bch_backpointer other_bp = * bkey_s_c_to_backpointer (bp_k ).v ;
571
+
572
+ struct bkey_s_c other_extent =
573
+ bch2_backpointer_get_key (trans , & other_extent_iter , bp_k .k -> p , other_bp , 0 );
574
+ ret = bkey_err (other_extent );
575
+ if (ret == - BCH_ERR_backpointer_to_overwritten_btree_node )
576
+ ret = 0 ;
577
+ if (ret )
578
+ goto err ;
579
+
580
+ if (!other_extent .k )
581
+ goto missing ;
582
+
583
+ if (bch2_extents_match (orig_k , other_extent )) {
584
+ printbuf_reset (& buf );
585
+ prt_printf (& buf , "duplicate versions of same extent, deleting smaller\n " );
586
+ bch2_bkey_val_to_text (& buf , c , orig_k );
587
+ prt_str (& buf , "\n " );
588
+ bch2_bkey_val_to_text (& buf , c , other_extent );
589
+ bch_err (c , "%s" , buf .buf );
590
+
591
+ if (other_extent .k -> size <= orig_k .k -> size ) {
592
+ ret = drop_dev_and_update (trans , other_bp .btree_id , other_extent , bucket .inode );
593
+ if (ret )
594
+ goto err ;
595
+ goto out ;
596
+ } else {
597
+ ret = drop_dev_and_update (trans , bp .btree_id , orig_k , bucket .inode );
598
+ if (ret )
599
+ goto err ;
600
+ goto missing ;
601
+ }
602
+ }
603
+
604
+ ret = check_extent_checksum (trans , other_bp .btree_id , other_extent , bp .btree_id , orig_k , bucket .inode );
605
+ if (ret < 0 )
606
+ goto err ;
607
+ if (ret ) {
608
+ ret = 0 ;
609
+ goto missing ;
610
+ }
611
+
612
+ ret = check_extent_checksum (trans , bp .btree_id , orig_k , other_bp .btree_id , other_extent , bucket .inode );
613
+ if (ret < 0 )
614
+ goto err ;
615
+ if (ret ) {
616
+ ret = 0 ;
617
+ goto out ;
618
+ }
619
+
620
+ printbuf_reset (& buf );
621
+ prt_printf (& buf , "duplicate extents pointing to same space on dev %llu\n " , bucket .inode );
622
+ bch2_bkey_val_to_text (& buf , c , orig_k );
623
+ prt_str (& buf , "\n " );
624
+ bch2_bkey_val_to_text (& buf , c , other_extent );
625
+ bch_err (c , "%s" , buf .buf );
626
+ ret = - BCH_ERR_fsck_repair_unimplemented ;
627
+ goto err ;
477
628
missing :
629
+ printbuf_reset (& buf );
478
630
prt_printf (& buf , "missing backpointer for btree=%s l=%u " ,
479
631
bch2_btree_id_str (bp .btree_id ), bp .level );
480
632
bch2_bkey_val_to_text (& buf , c , orig_k );
481
- prt_printf (& buf , "\nbp pos " );
482
- bch2_bpos_to_text (& buf , bp_iter .pos );
633
+ prt_printf (& buf , "\n got: " );
634
+ bch2_bkey_val_to_text (& buf , c , bp_k );
635
+
636
+ struct bkey_i_backpointer n_bp_k ;
637
+ bkey_backpointer_init (& n_bp_k .k_i );
638
+ n_bp_k .k .p = bucket_pos_to_bp (trans -> c , bucket , bp .bucket_offset );
639
+ n_bp_k .v = bp ;
640
+ prt_printf (& buf , "\n want: " );
641
+ bch2_bkey_val_to_text (& buf , c , bkey_i_to_s_c (& n_bp_k .k_i ));
483
642
484
643
if (fsck_err (c , ptr_to_missing_backpointer , "%s" , buf .buf ))
485
644
ret = bch2_bucket_backpointer_mod (trans , bucket , bp , orig_k , true);
0 commit comments