@@ -9670,6 +9670,266 @@ static int zero_log_tree(struct btrfs_root *root)
96709670 return ret ;
96719671}
96729672
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+
96739933static void free_roots_info_cache (void )
96749934{
96759935 if (!roots_info_cache )
@@ -10468,9 +10728,21 @@ static int cmd_check(const struct cmd_struct *cmd, int argc, char **argv)
1046810728 goto close_out ;
1046910729 }
1047010730
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+
1047110743 if (!init_extent_tree ) {
1047210744 if (!g_task_ctx .progress_enabled ) {
10473- fprintf (stderr , "[1/7 ] checking root items\n" );
10745+ fprintf (stderr , "[2/8 ] checking root items\n" );
1047410746 } else {
1047510747 g_task_ctx .tp = TASK_ROOT_ITEMS ;
1047610748 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)
1050510777 }
1050610778 }
1050710779 } else {
10508- fprintf (stderr , "[1/7 ] checking root items... skipped\n" );
10780+ fprintf (stderr , "[2/8 ] checking root items... skipped\n" );
1050910781 }
1051010782
1051110783 if (!g_task_ctx .progress_enabled ) {
10512- fprintf (stderr , "[2/7 ] checking extents\n" );
10784+ fprintf (stderr , "[3/8 ] checking extents\n" );
1051310785 } else {
1051410786 g_task_ctx .tp = TASK_EXTENTS ;
1051510787 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)
1052710799
1052810800 if (!g_task_ctx .progress_enabled ) {
1052910801 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" );
1053110803 else
10532- fprintf (stderr , "[3/7 ] checking free space cache\n" );
10804+ fprintf (stderr , "[4/8 ] checking free space cache\n" );
1053310805 } else {
1053410806 g_task_ctx .tp = TASK_FREE_SPACE ;
1053510807 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)
1054710819 */
1054810820 no_holes = btrfs_fs_incompat (gfs_info , NO_HOLES );
1054910821 if (!g_task_ctx .progress_enabled ) {
10550- fprintf (stderr , "[4/7 ] checking fs roots\n" );
10822+ fprintf (stderr , "[5/8 ] checking fs roots\n" );
1055110823 } else {
1055210824 g_task_ctx .tp = TASK_FS_ROOTS ;
1055310825 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)
1056310835
1056410836 if (!g_task_ctx .progress_enabled ) {
1056510837 if (check_data_csum )
10566- fprintf (stderr , "[5/7 ] checking csums against data\n" );
10838+ fprintf (stderr , "[6/8 ] checking csums against data\n" );
1056710839 else
1056810840 fprintf (stderr ,
10569- "[5/7 ] checking only csums items (without verifying data)\n" );
10841+ "[6/8 ] checking only csums items (without verifying data)\n" );
1057010842 } else {
1057110843 g_task_ctx .tp = TASK_CSUMS ;
1057210844 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)
1058510857 /* For low memory mode, check_fs_roots_v2 handles root refs */
1058610858 if (check_mode != CHECK_MODE_LOWMEM ) {
1058710859 if (!g_task_ctx .progress_enabled ) {
10588- fprintf (stderr , "[6/7 ] checking root refs\n" );
10860+ fprintf (stderr , "[7/8 ] checking root refs\n" );
1058910861 } else {
1059010862 g_task_ctx .tp = TASK_ROOT_REFS ;
1059110863 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)
1060010872 }
1060110873 } else {
1060210874 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" );
1060410876 }
1060510877
1060610878 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)
1063210904
1063310905 if (gfs_info -> quota_enabled ) {
1063410906 if (!g_task_ctx .progress_enabled ) {
10635- fprintf (stderr , "[7/7 ] checking quota groups\n" );
10907+ fprintf (stderr , "[8/8 ] checking quota groups\n" );
1063610908 } else {
1063710909 g_task_ctx .tp = TASK_QGROUPS ;
1063810910 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)
1065510927 ret = 0 ;
1065610928 } else {
1065710929 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" );
1065910931 }
1066010932
1066110933 if (!list_empty (& gfs_info -> recow_ebs )) {
0 commit comments