88#include "btree_update.h"
99#include "btree_update_interior.h"
1010#include "btree_write_buffer.h"
11+ #include "checksum.h"
1112#include "error.h"
1213
1314#include <linux/mm.h>
@@ -418,28 +419,113 @@ struct extents_to_bp_state {
418419 struct bkey_buf last_flushed ;
419420};
420421
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+
421500static int check_bp_exists (struct btree_trans * trans ,
422501 struct extents_to_bp_state * s ,
423502 struct bpos bucket ,
424503 struct bch_backpointer bp ,
425504 struct bkey_s_c orig_k )
426505{
427506 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 = {};
429509 struct printbuf buf = PRINTBUF ;
430510 struct bkey_s_c bp_k ;
431511 struct bkey_buf tmp ;
432512 int ret ;
433513
434514 bch2_bkey_buf_init (& tmp );
435515
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+
436525 if (bpos_lt (bucket , s -> bucket_start ) ||
437526 bpos_gt (bucket , s -> bucket_end ))
438527 return 0 ;
439528
440- if (!bch2_dev_bucket_exists (c , bucket ))
441- goto missing ;
442-
443529 bp_k = bch2_bkey_get_iter (trans , & bp_iter , BTREE_ID_backpointers ,
444530 bucket_pos_to_bp (c , bucket , bp .bucket_offset ),
445531 0 );
@@ -465,21 +551,94 @@ static int check_bp_exists(struct btree_trans *trans,
465551 ret = - BCH_ERR_transaction_restart_write_buffer_flush ;
466552 goto out ;
467553 }
468- goto missing ;
554+
555+ goto check_existing_bp ;
469556 }
470557out :
471558err :
472559fsck_err :
560+ bch2_trans_iter_exit (trans , & other_extent_iter );
473561 bch2_trans_iter_exit (trans , & bp_iter );
474562 bch2_bkey_buf_exit (& tmp , c );
475563 printbuf_exit (& buf );
476564 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 ;
477628missing :
629+ printbuf_reset (& buf );
478630 prt_printf (& buf , "missing backpointer for btree=%s l=%u " ,
479631 bch2_btree_id_str (bp .btree_id ), bp .level );
480632 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 ));
483642
484643 if (fsck_err (c , ptr_to_missing_backpointer , "%s" , buf .buf ))
485644 ret = bch2_bucket_backpointer_mod (trans , bucket , bp , orig_k , true);
0 commit comments