@@ -109,6 +109,8 @@ static void print_usage(void)
109109 "<num>,<num>,<num> (must also specify -f for the field)\n" );
110110 fprintf (stderr , "\t-f The field in the item to corrupt\n" );
111111 fprintf (stderr , "\t-d Delete this item (must specify -K)\n" );
112+ fprintf (stderr , "\t-I An item to corrupt (must also specify the field "
113+ "to corrupt and a root+key for the item)\n" );
112114 exit (1 );
113115}
114116
@@ -308,6 +310,11 @@ enum btrfs_metadata_block_field {
308310 BTRFS_METADATA_BLOCK_BAD ,
309311};
310312
313+ enum btrfs_item_field {
314+ BTRFS_ITEM_OFFSET ,
315+ BTRFS_ITEM_BAD ,
316+ };
317+
311318enum btrfs_key_field {
312319 BTRFS_KEY_OBJECTID ,
313320 BTRFS_KEY_TYPE ,
@@ -350,6 +357,13 @@ static enum btrfs_key_field convert_key_field(char *field)
350357 return BTRFS_KEY_BAD ;
351358}
352359
360+ static enum btrfs_item_field convert_item_field (char * field )
361+ {
362+ if (!strncmp (field , "offset" , FIELD_BUF_LEN ))
363+ return BTRFS_ITEM_OFFSET ;
364+ return BTRFS_ITEM_BAD ;
365+ }
366+
353367static u64 generate_u64 (u64 orig )
354368{
355369 u64 ret ;
@@ -359,6 +373,15 @@ static u64 generate_u64(u64 orig)
359373 return ret ;
360374}
361375
376+ static u32 generate_u32 (u32 orig )
377+ {
378+ u32 ret ;
379+ do {
380+ ret = rand ();
381+ } while (ret == orig );
382+ return ret ;
383+ }
384+
362385static u8 generate_u8 (u8 orig )
363386{
364387 u8 ret ;
@@ -680,6 +703,58 @@ static int delete_item(struct btrfs_root *root, struct btrfs_key *key)
680703 return ret ;
681704}
682705
706+ static int corrupt_btrfs_item (struct btrfs_root * root , struct btrfs_key * key ,
707+ char * field )
708+ {
709+ struct btrfs_trans_handle * trans ;
710+ struct btrfs_path * path ;
711+ enum btrfs_item_field corrupt_field ;
712+ u32 orig , bogus ;
713+ int ret ;
714+
715+ corrupt_field = convert_item_field (field );
716+ if (corrupt_field == BTRFS_ITEM_BAD ) {
717+ fprintf (stderr , "Invalid field %s\n" , field );
718+ return - EINVAL ;
719+ }
720+
721+ path = btrfs_alloc_path ();
722+ if (!path )
723+ return - ENOMEM ;
724+
725+ trans = btrfs_start_transaction (root , 1 );
726+ if (IS_ERR (trans )) {
727+ btrfs_free_path (path );
728+ fprintf (stderr , "Couldn't start transaction %ld\n" ,
729+ PTR_ERR (trans ));
730+ return PTR_ERR (trans );
731+ }
732+
733+ ret = btrfs_search_slot (trans , root , key , path , 0 , 1 );
734+ if (ret != 0 ) {
735+ fprintf (stderr , "Error searching to node %d\n" , ret );
736+ goto out ;
737+ }
738+
739+ ret = 0 ;
740+ switch (corrupt_field ) {
741+ case BTRFS_ITEM_OFFSET :
742+ orig = btrfs_item_offset_nr (path -> nodes [0 ], path -> slots [0 ]);
743+ bogus = generate_u32 (orig );
744+ btrfs_set_item_offset (path -> nodes [0 ],
745+ btrfs_item_nr (path -> slots [0 ]), bogus );
746+ break ;
747+ default :
748+ ret = - EINVAL ;
749+ break ;
750+ }
751+ btrfs_mark_buffer_dirty (path -> nodes [0 ]);
752+ out :
753+ btrfs_commit_transaction (trans , root );
754+ btrfs_free_path (path );
755+ return ret ;
756+ }
757+
683758static struct option long_options [] = {
684759 /* { "byte-count", 1, NULL, 'b' }, */
685760 { "logical" , 1 , NULL , 'l' },
@@ -696,6 +771,7 @@ static struct option long_options[] = {
696771 { "field" , 1 , NULL , 'f' },
697772 { "key" , 1 , NULL , 'K' },
698773 { "delete" , 0 , NULL , 'd' },
774+ { "item" , 0 , NULL , 'I' },
699775 { 0 , 0 , 0 , 0 }
700776};
701777
@@ -860,6 +936,7 @@ int main(int ac, char **av)
860936 int chunk_rec = 0 ;
861937 int chunk_tree = 0 ;
862938 int delete = 0 ;
939+ int corrupt_item = 0 ;
863940 u64 metadata_block = 0 ;
864941 u64 inode = 0 ;
865942 u64 file_extent = (u64 )- 1 ;
@@ -871,8 +948,8 @@ int main(int ac, char **av)
871948
872949 while (1 ) {
873950 int c ;
874- c = getopt_long (ac , av , "l:c:b:eEkuUi:f:x:m:K:d" , long_options ,
875- & option_index );
951+ c = getopt_long (ac , av , "l:c:b:eEkuUi:f:x:m:K:dI" ,
952+ long_options , & option_index );
876953 if (c < 0 )
877954 break ;
878955 switch (c ) {
@@ -925,6 +1002,9 @@ int main(int ac, char **av)
9251002 case 'd' :
9261003 delete = 1 ;
9271004 break ;
1005+ case 'I' :
1006+ corrupt_item = 1 ;
1007+ break ;
9281008 default :
9291009 print_usage ();
9301010 }
@@ -1027,6 +1107,12 @@ int main(int ac, char **av)
10271107 ret = delete_item (root , & key );
10281108 goto out_close ;
10291109 }
1110+ if (corrupt_item ) {
1111+ if (!key .objectid )
1112+ print_usage ();
1113+ ret = corrupt_btrfs_item (root , & key , field );
1114+ goto out_close ;
1115+ }
10301116 if (key .objectid || key .offset || key .type ) {
10311117 if (!strlen (field ))
10321118 print_usage ();
0 commit comments