@@ -9670,6 +9670,266 @@ static int zero_log_tree(struct btrfs_root *root)
9670
9670
return ret ;
9671
9671
}
9672
9672
9673
+ static int check_log_csum (struct btrfs_root * root , u64 addr , u64 length )
9674
+ {
9675
+ struct btrfs_path path = { 0 };
9676
+ struct btrfs_key key ;
9677
+ struct extent_buffer * leaf ;
9678
+ u16 csum_size = gfs_info -> csum_size ;
9679
+ u16 num_entries ;
9680
+ u64 data_len ;
9681
+ int ret ;
9682
+
9683
+ key .objectid = BTRFS_EXTENT_CSUM_OBJECTID ;
9684
+ key .type = BTRFS_EXTENT_CSUM_KEY ;
9685
+ key .offset = addr ;
9686
+
9687
+ ret = btrfs_search_slot (NULL , root , & key , & path , 0 , 0 );
9688
+ if (ret < 0 )
9689
+ return ret ;
9690
+
9691
+ if (ret > 0 && path .slots [0 ])
9692
+ path .slots [0 ]-- ;
9693
+
9694
+ ret = 0 ;
9695
+
9696
+ while (1 ) {
9697
+ leaf = path .nodes [0 ];
9698
+ if (path .slots [0 ] >= btrfs_header_nritems (leaf )) {
9699
+ ret = btrfs_next_leaf (root , & path );
9700
+ if (ret ) {
9701
+ if (ret > 0 )
9702
+ ret = 0 ;
9703
+
9704
+ break ;
9705
+ }
9706
+ leaf = path .nodes [0 ];
9707
+ }
9708
+
9709
+ btrfs_item_key_to_cpu (leaf , & key , path .slots [0 ]);
9710
+
9711
+ if (key .objectid > BTRFS_EXTENT_CSUM_OBJECTID )
9712
+ break ;
9713
+
9714
+ if (key .objectid != BTRFS_EXTENT_CSUM_OBJECTID ||
9715
+ key .type != BTRFS_EXTENT_CSUM_KEY )
9716
+ goto next ;
9717
+
9718
+ if (key .offset >= addr + length )
9719
+ break ;
9720
+
9721
+ num_entries = btrfs_item_size (leaf , path .slots [0 ]) / csum_size ;
9722
+ data_len = num_entries * gfs_info -> sectorsize ;
9723
+
9724
+ if (addr >= key .offset && addr <= key .offset + data_len ) {
9725
+ u64 end = min (addr + length , key .offset + data_len );
9726
+
9727
+ length = addr + length - end ;
9728
+ addr = end ;
9729
+
9730
+ if (length == 0 )
9731
+ break ;
9732
+ }
9733
+
9734
+ next :
9735
+ path .slots [0 ]++ ;
9736
+ }
9737
+
9738
+ btrfs_release_path (& path );
9739
+
9740
+ if (ret >= 0 )
9741
+ ret = length == 0 ? 0 : 1 ;
9742
+
9743
+ return ret ;
9744
+ }
9745
+
9746
+ static int check_log_root (struct btrfs_root * root , struct cache_tree * root_cache )
9747
+ {
9748
+ struct btrfs_path path = { 0 };
9749
+ struct btrfs_key key ;
9750
+ struct extent_buffer * leaf ;
9751
+ int ret , err = 0 ;
9752
+ u64 last_csum_inode = 0 ;
9753
+
9754
+ key .objectid = BTRFS_FIRST_FREE_OBJECTID ;
9755
+ key .type = BTRFS_INODE_ITEM_KEY ;
9756
+ key .offset = 0 ;
9757
+ ret = btrfs_search_slot (NULL , root , & key , & path , 0 , 0 );
9758
+ if (ret < 0 )
9759
+ return 1 ;
9760
+
9761
+ while (1 ) {
9762
+ leaf = path .nodes [0 ];
9763
+ if (path .slots [0 ] >= btrfs_header_nritems (leaf )) {
9764
+ ret = btrfs_next_leaf (root , & path );
9765
+ if (ret ) {
9766
+ if (ret < 0 )
9767
+ err = 1 ;
9768
+
9769
+ break ;
9770
+ }
9771
+ leaf = path .nodes [0 ];
9772
+ }
9773
+ btrfs_item_key_to_cpu (leaf , & key , path .slots [0 ]);
9774
+
9775
+ if (key .objectid == BTRFS_EXTENT_CSUM_OBJECTID )
9776
+ break ;
9777
+
9778
+ if (key .type == BTRFS_INODE_ITEM_KEY ) {
9779
+ struct btrfs_inode_item * item ;
9780
+
9781
+ item = btrfs_item_ptr (leaf , path .slots [0 ],
9782
+ struct btrfs_inode_item );
9783
+
9784
+ if (!(btrfs_inode_flags (leaf , item ) & BTRFS_INODE_NODATASUM ))
9785
+ last_csum_inode = key .objectid ;
9786
+ } else if (key .type == BTRFS_EXTENT_DATA_KEY &&
9787
+ key .objectid == last_csum_inode ) {
9788
+ struct btrfs_file_extent_item * fi ;
9789
+ u64 addr , length ;
9790
+
9791
+ fi = btrfs_item_ptr (leaf , path .slots [0 ],
9792
+ struct btrfs_file_extent_item );
9793
+
9794
+ if (btrfs_file_extent_type (leaf , fi ) != BTRFS_FILE_EXTENT_REG )
9795
+ goto next ;
9796
+
9797
+ addr = btrfs_file_extent_disk_bytenr (leaf , fi ) +
9798
+ btrfs_file_extent_offset (leaf , fi );
9799
+ length = btrfs_file_extent_num_bytes (leaf , fi );
9800
+
9801
+ ret = check_log_csum (root , addr , length );
9802
+ if (ret < 0 ) {
9803
+ err = 1 ;
9804
+ break ;
9805
+ }
9806
+
9807
+ if (ret ) {
9808
+ error ("csum missing in log (root %llu, inode %llu, "
9809
+ "offset %llu, address 0x%llx, length %llu)" ,
9810
+ root -> objectid , last_csum_inode , key .offset ,
9811
+ addr , length );
9812
+ err = 1 ;
9813
+ }
9814
+ }
9815
+
9816
+ next :
9817
+ path .slots [0 ]++ ;
9818
+ }
9819
+
9820
+ btrfs_release_path (& path );
9821
+
9822
+ return err ;
9823
+ }
9824
+
9825
+ static int load_log_root (u64 root_id , struct btrfs_path * path ,
9826
+ struct btrfs_root * tmp_root )
9827
+ {
9828
+ struct extent_buffer * l ;
9829
+ struct btrfs_tree_parent_check check = { 0 };
9830
+ int ret ;
9831
+
9832
+ btrfs_setup_root (tmp_root , gfs_info , root_id );
9833
+
9834
+ l = path -> nodes [0 ];
9835
+ read_extent_buffer (l , & tmp_root -> root_item ,
9836
+ btrfs_item_ptr_offset (l , path -> slots [0 ]),
9837
+ sizeof (tmp_root -> root_item ));
9838
+
9839
+ tmp_root -> root_key .objectid = root_id ;
9840
+ tmp_root -> root_key .type = BTRFS_ROOT_ITEM_KEY ;
9841
+ tmp_root -> root_key .offset = 0 ;
9842
+
9843
+ check .owner_root = btrfs_root_id (tmp_root );
9844
+ check .transid = btrfs_root_generation (& tmp_root -> root_item );
9845
+ check .level = btrfs_root_level (& tmp_root -> root_item );
9846
+
9847
+ tmp_root -> node = read_tree_block (gfs_info ,
9848
+ btrfs_root_bytenr (& tmp_root -> root_item ),
9849
+ & check );
9850
+ if (IS_ERR (tmp_root -> node )) {
9851
+ ret = PTR_ERR (tmp_root -> node );
9852
+ tmp_root -> node = NULL ;
9853
+ return ret ;
9854
+ }
9855
+
9856
+ if (btrfs_header_level (tmp_root -> node ) != btrfs_root_level (& tmp_root -> root_item )) {
9857
+ error ("root [%llu %llu] level %d does not match %d" ,
9858
+ tmp_root -> root_key .objectid ,
9859
+ tmp_root -> root_key .offset ,
9860
+ btrfs_header_level (tmp_root -> node ),
9861
+ btrfs_root_level (& tmp_root -> root_item ));
9862
+ return - EIO ;
9863
+ }
9864
+
9865
+ return 0 ;
9866
+ }
9867
+
9868
+ static int check_log (struct cache_tree * root_cache )
9869
+ {
9870
+ struct btrfs_path path = { 0 };
9871
+ struct btrfs_key key ;
9872
+ struct extent_buffer * leaf ;
9873
+ struct btrfs_root * log_root = gfs_info -> log_root_tree ;
9874
+ int ret ;
9875
+ int err = 0 ;
9876
+
9877
+ key .objectid = BTRFS_TREE_LOG_OBJECTID ;
9878
+ key .type = BTRFS_ROOT_ITEM_KEY ;
9879
+ key .offset = 0 ;
9880
+ ret = btrfs_search_slot (NULL , log_root , & key , & path , 0 , 0 );
9881
+ if (ret < 0 ) {
9882
+ err = 1 ;
9883
+ goto out ;
9884
+ }
9885
+
9886
+ while (1 ) {
9887
+ leaf = path .nodes [0 ];
9888
+ if (path .slots [0 ] >= btrfs_header_nritems (leaf )) {
9889
+ ret = btrfs_next_leaf (log_root , & path );
9890
+ if (ret ) {
9891
+ if (ret < 0 )
9892
+ err = 1 ;
9893
+ break ;
9894
+ }
9895
+ leaf = path .nodes [0 ];
9896
+ }
9897
+ btrfs_item_key_to_cpu (leaf , & key , path .slots [0 ]);
9898
+
9899
+ if (key .objectid > BTRFS_TREE_LOG_OBJECTID ||
9900
+ key .type > BTRFS_ROOT_ITEM_KEY )
9901
+ break ;
9902
+
9903
+ if (key .objectid == BTRFS_TREE_LOG_OBJECTID &&
9904
+ key .type == BTRFS_ROOT_ITEM_KEY &&
9905
+ fs_root_objectid (key .offset )) {
9906
+ struct btrfs_root tmp_root ;
9907
+
9908
+ memset (& tmp_root , 0 , sizeof (tmp_root ));
9909
+
9910
+ ret = load_log_root (key .offset , & path , & tmp_root );
9911
+ if (ret ) {
9912
+ err = 1 ;
9913
+ goto next ;
9914
+ }
9915
+
9916
+ ret = check_log_root (& tmp_root , root_cache );
9917
+ if (ret )
9918
+ err = 1 ;
9919
+
9920
+ next :
9921
+ if (tmp_root .node )
9922
+ free_extent_buffer (tmp_root .node );
9923
+ }
9924
+
9925
+ path .slots [0 ]++ ;
9926
+ }
9927
+ out :
9928
+ btrfs_release_path (& path );
9929
+
9930
+ return err ;
9931
+ }
9932
+
9673
9933
static void free_roots_info_cache (void )
9674
9934
{
9675
9935
if (!roots_info_cache )
@@ -10468,9 +10728,21 @@ static int cmd_check(const struct cmd_struct *cmd, int argc, char **argv)
10468
10728
goto close_out ;
10469
10729
}
10470
10730
10731
+ if (gfs_info -> log_root_tree ) {
10732
+ fprintf (stderr , "[1/8] checking log\n" );
10733
+ ret = check_log (& root_cache );
10734
+
10735
+ if (ret )
10736
+ error ("errors found in log" );
10737
+ err |= !!ret ;
10738
+ } else {
10739
+ fprintf (stderr ,
10740
+ "[1/8] checking log skipped (none written)\n" );
10741
+ }
10742
+
10471
10743
if (!init_extent_tree ) {
10472
10744
if (!g_task_ctx .progress_enabled ) {
10473
- fprintf (stderr , "[1/7 ] checking root items\n" );
10745
+ fprintf (stderr , "[2/8 ] checking root items\n" );
10474
10746
} else {
10475
10747
g_task_ctx .tp = TASK_ROOT_ITEMS ;
10476
10748
task_start (g_task_ctx .info , & g_task_ctx .start_time ,
@@ -10505,11 +10777,11 @@ static int cmd_check(const struct cmd_struct *cmd, int argc, char **argv)
10505
10777
}
10506
10778
}
10507
10779
} else {
10508
- fprintf (stderr , "[1/7 ] checking root items... skipped\n" );
10780
+ fprintf (stderr , "[2/8 ] checking root items... skipped\n" );
10509
10781
}
10510
10782
10511
10783
if (!g_task_ctx .progress_enabled ) {
10512
- fprintf (stderr , "[2/7 ] checking extents\n" );
10784
+ fprintf (stderr , "[3/8 ] checking extents\n" );
10513
10785
} else {
10514
10786
g_task_ctx .tp = TASK_EXTENTS ;
10515
10787
task_start (g_task_ctx .info , & g_task_ctx .start_time , & g_task_ctx .item_count );
@@ -10527,9 +10799,9 @@ static int cmd_check(const struct cmd_struct *cmd, int argc, char **argv)
10527
10799
10528
10800
if (!g_task_ctx .progress_enabled ) {
10529
10801
if (is_free_space_tree )
10530
- fprintf (stderr , "[3/7 ] checking free space tree\n" );
10802
+ fprintf (stderr , "[4/8 ] checking free space tree\n" );
10531
10803
else
10532
- fprintf (stderr , "[3/7 ] checking free space cache\n" );
10804
+ fprintf (stderr , "[4/8 ] checking free space cache\n" );
10533
10805
} else {
10534
10806
g_task_ctx .tp = TASK_FREE_SPACE ;
10535
10807
task_start (g_task_ctx .info , & g_task_ctx .start_time , & g_task_ctx .item_count );
@@ -10547,7 +10819,7 @@ static int cmd_check(const struct cmd_struct *cmd, int argc, char **argv)
10547
10819
*/
10548
10820
no_holes = btrfs_fs_incompat (gfs_info , NO_HOLES );
10549
10821
if (!g_task_ctx .progress_enabled ) {
10550
- fprintf (stderr , "[4/7 ] checking fs roots\n" );
10822
+ fprintf (stderr , "[5/8 ] checking fs roots\n" );
10551
10823
} else {
10552
10824
g_task_ctx .tp = TASK_FS_ROOTS ;
10553
10825
task_start (g_task_ctx .info , & g_task_ctx .start_time , & g_task_ctx .item_count );
@@ -10563,10 +10835,10 @@ static int cmd_check(const struct cmd_struct *cmd, int argc, char **argv)
10563
10835
10564
10836
if (!g_task_ctx .progress_enabled ) {
10565
10837
if (check_data_csum )
10566
- fprintf (stderr , "[5/7 ] checking csums against data\n" );
10838
+ fprintf (stderr , "[6/8 ] checking csums against data\n" );
10567
10839
else
10568
10840
fprintf (stderr ,
10569
- "[5/7 ] checking only csums items (without verifying data)\n" );
10841
+ "[6/8 ] checking only csums items (without verifying data)\n" );
10570
10842
} else {
10571
10843
g_task_ctx .tp = TASK_CSUMS ;
10572
10844
task_start (g_task_ctx .info , & g_task_ctx .start_time , & g_task_ctx .item_count );
@@ -10585,7 +10857,7 @@ static int cmd_check(const struct cmd_struct *cmd, int argc, char **argv)
10585
10857
/* For low memory mode, check_fs_roots_v2 handles root refs */
10586
10858
if (check_mode != CHECK_MODE_LOWMEM ) {
10587
10859
if (!g_task_ctx .progress_enabled ) {
10588
- fprintf (stderr , "[6/7 ] checking root refs\n" );
10860
+ fprintf (stderr , "[7/8 ] checking root refs\n" );
10589
10861
} else {
10590
10862
g_task_ctx .tp = TASK_ROOT_REFS ;
10591
10863
task_start (g_task_ctx .info , & g_task_ctx .start_time , & g_task_ctx .item_count );
@@ -10600,7 +10872,7 @@ static int cmd_check(const struct cmd_struct *cmd, int argc, char **argv)
10600
10872
}
10601
10873
} else {
10602
10874
fprintf (stderr ,
10603
- "[6/7 ] checking root refs done with fs roots in lowmem mode, skipping\n" );
10875
+ "[7/8 ] checking root refs done with fs roots in lowmem mode, skipping\n" );
10604
10876
}
10605
10877
10606
10878
while (opt_check_repair && !list_empty (& gfs_info -> recow_ebs )) {
@@ -10632,7 +10904,7 @@ static int cmd_check(const struct cmd_struct *cmd, int argc, char **argv)
10632
10904
10633
10905
if (gfs_info -> quota_enabled ) {
10634
10906
if (!g_task_ctx .progress_enabled ) {
10635
- fprintf (stderr , "[7/7 ] checking quota groups\n" );
10907
+ fprintf (stderr , "[8/8 ] checking quota groups\n" );
10636
10908
} else {
10637
10909
g_task_ctx .tp = TASK_QGROUPS ;
10638
10910
task_start (g_task_ctx .info , & g_task_ctx .start_time , & g_task_ctx .item_count );
@@ -10655,7 +10927,7 @@ static int cmd_check(const struct cmd_struct *cmd, int argc, char **argv)
10655
10927
ret = 0 ;
10656
10928
} else {
10657
10929
fprintf (stderr ,
10658
- "[7/7 ] checking quota groups skipped (not enabled on this FS)\n" );
10930
+ "[8/8 ] checking quota groups skipped (not enabled on this FS)\n" );
10659
10931
}
10660
10932
10661
10933
if (!list_empty (& gfs_info -> recow_ebs )) {
0 commit comments