btrfs-progs: replace leafsize with nodesize
[platform/upstream/btrfs-progs.git] / btrfs-corrupt-block.c
1 /*
2  * Copyright (C) 2009 Oracle.  All rights reserved.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public
6  * License v2 as published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public
14  * License along with this program; if not, write to the
15  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16  * Boston, MA 021110-1307, USA.
17  */
18
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <fcntl.h>
22 #include <unistd.h>
23 #include <getopt.h>
24 #include <limits.h>
25
26 #include "kerncompat.h"
27 #include "ctree.h"
28 #include "volumes.h"
29 #include "disk-io.h"
30 #include "print-tree.h"
31 #include "transaction.h"
32 #include "list.h"
33 #include "utils.h"
34
35 #define FIELD_BUF_LEN 80
36
37 static struct extent_buffer *debug_corrupt_block(struct btrfs_root *root,
38                 u64 bytenr, u32 blocksize, u64 copy)
39 {
40         int ret;
41         struct extent_buffer *eb;
42         u64 length;
43         struct btrfs_multi_bio *multi = NULL;
44         struct btrfs_device *device;
45         int num_copies;
46         int mirror_num = 1;
47
48         eb = btrfs_find_create_tree_block(root->fs_info, bytenr, blocksize);
49         if (!eb)
50                 return NULL;
51
52         length = blocksize;
53         while (1) {
54                 ret = btrfs_map_block(&root->fs_info->mapping_tree, READ,
55                                       eb->start, &length, &multi,
56                                       mirror_num, NULL);
57                 BUG_ON(ret);
58                 device = multi->stripes[0].dev;
59                 eb->fd = device->fd;
60                 device->total_ios++;
61                 eb->dev_bytenr = multi->stripes[0].physical;
62
63                 fprintf(stdout,
64                         "mirror %d logical %llu physical %llu device %s\n",
65                         mirror_num, (unsigned long long)bytenr,
66                         (unsigned long long)eb->dev_bytenr, device->name);
67                 kfree(multi);
68
69                 if (!copy || mirror_num == copy) {
70                         ret = read_extent_from_disk(eb, 0, eb->len);
71                         printf("corrupting %llu copy %d\n", eb->start,
72                                mirror_num);
73                         memset(eb->data, 0, eb->len);
74                         write_extent_to_disk(eb);
75                         fsync(eb->fd);
76                 }
77
78                 num_copies = btrfs_num_copies(&root->fs_info->mapping_tree,
79                                               eb->start, eb->len);
80                 if (num_copies == 1)
81                         break;
82
83                 mirror_num++;
84                 if (mirror_num > num_copies)
85                         break;
86         }
87         return eb;
88 }
89
90 static void print_usage(int ret)
91 {
92         fprintf(stderr, "usage: btrfs-corrupt-block [options] device\n");
93         fprintf(stderr, "\t-l Logical extent to be corrupted\n");
94         fprintf(stderr, "\t-c Copy of the extent to be corrupted"
95                 " (usually 1 or 2, default: 0)\n");
96         fprintf(stderr, "\t-b Number of bytes to be corrupted\n");
97         fprintf(stderr, "\t-e Extent to be corrupted\n");
98         fprintf(stderr, "\t-E The whole extent tree to be corrupted\n");
99         fprintf(stderr, "\t-u Given chunk item to be corrupted\n");
100         fprintf(stderr, "\t-U The whole chunk tree to be corrupted\n");
101         fprintf(stderr, "\t-i The inode item to corrupt (must also specify "
102                 "the field to corrupt)\n");
103         fprintf(stderr, "\t-x The file extent item to corrupt (must also "
104                 "specify -i for the inode and -f for the field to corrupt)\n");
105         fprintf(stderr, "\t-m The metadata block to corrupt (must also "
106                 "specify -f for the field to corrupt)\n");
107         fprintf(stderr, "\t-K The key to corrupt in the format "
108                 "<num>,<num>,<num> (must also specify -f for the field)\n");
109         fprintf(stderr, "\t-f The field in the item to corrupt\n");
110         fprintf(stderr, "\t-I An item to corrupt (must also specify the field "
111                 "to corrupt and a root+key for the item)\n");
112         fprintf(stderr, "\t-D Corrupt a dir item, must specify key and field\n");
113         fprintf(stderr, "\t-d Delete this item (must specify -K)\n");
114         fprintf(stderr, "\t-r Operate on this root (only works with -d)\n");
115         fprintf(stderr, "\t-C Delete a csum for the specified bytenr.  When "
116                 "used with -b it'll delete that many bytes, otherwise it's "
117                 "just sectorsize\n");
118         exit(ret);
119 }
120
121 static void corrupt_keys(struct btrfs_trans_handle *trans,
122                          struct btrfs_root *root,
123                          struct extent_buffer *eb)
124 {
125         int slot;
126         int bad_slot;
127         int nr;
128         struct btrfs_disk_key bad_key;;
129
130         nr = btrfs_header_nritems(eb);
131         if (nr == 0)
132                 return;
133
134         slot = rand() % nr;
135         bad_slot = rand() % nr;
136
137         if (bad_slot == slot)
138                 return;
139
140         fprintf(stderr,
141                 "corrupting keys in block %llu slot %d swapping with %d\n",
142                 (unsigned long long)eb->start, slot, bad_slot);
143
144         if (btrfs_header_level(eb) == 0) {
145                 btrfs_item_key(eb, &bad_key, bad_slot);
146                 btrfs_set_item_key(eb, &bad_key, slot);
147         } else {
148                 btrfs_node_key(eb, &bad_key, bad_slot);
149                 btrfs_set_node_key(eb, &bad_key, slot);
150         }
151         btrfs_mark_buffer_dirty(eb);
152         if (!trans) {
153                 u16 csum_size =
154                         btrfs_super_csum_size(root->fs_info->super_copy);
155                 csum_tree_block_size(eb, csum_size, 0);
156                 write_extent_to_disk(eb);
157         }
158 }
159
160
161 static int corrupt_keys_in_block(struct btrfs_root *root, u64 bytenr)
162 {
163         struct extent_buffer *eb;
164
165         eb = read_tree_block(root, bytenr, root->nodesize, 0);
166         if (!extent_buffer_uptodate(eb))
167                 return -EIO;;
168
169         corrupt_keys(NULL, root, eb);
170         free_extent_buffer(eb);
171         return 0;
172 }
173
174 static int corrupt_extent(struct btrfs_trans_handle *trans,
175                           struct btrfs_root *root, u64 bytenr, u64 copy)
176 {
177         struct btrfs_key key;
178         struct extent_buffer *leaf;
179         u32 item_size;
180         unsigned long ptr;
181         struct btrfs_path *path;
182         int ret;
183         int slot;
184         int should_del = rand() % 3;
185
186         path = btrfs_alloc_path();
187         if (!path)
188                 return -ENOMEM;
189
190         key.objectid = bytenr;
191         key.type = (u8)-1;
192         key.offset = (u64)-1;
193
194         while(1) {
195                 ret = btrfs_search_slot(trans, root->fs_info->extent_root,
196                                         &key, path, -1, 1);
197                 if (ret < 0)
198                         break;
199
200                 if (ret > 0) {
201                         if (path->slots[0] == 0)
202                                 break;
203                         path->slots[0]--;
204                         ret = 0;
205                 }
206                 leaf = path->nodes[0];
207                 slot = path->slots[0];
208                 btrfs_item_key_to_cpu(leaf, &key, slot);
209                 if (key.objectid != bytenr)
210                         break;
211
212                 if (key.type != BTRFS_EXTENT_ITEM_KEY &&
213                     key.type != BTRFS_TREE_BLOCK_REF_KEY &&
214                     key.type != BTRFS_EXTENT_DATA_REF_KEY &&
215                     key.type != BTRFS_EXTENT_REF_V0_KEY &&
216                     key.type != BTRFS_SHARED_BLOCK_REF_KEY &&
217                     key.type != BTRFS_SHARED_DATA_REF_KEY)
218                         goto next;
219
220                 if (should_del) {
221                         fprintf(stderr,
222                                 "deleting extent record: key %llu %u %llu\n",
223                                 key.objectid, key.type, key.offset);
224
225                         if (key.type == BTRFS_EXTENT_ITEM_KEY) {
226                                 /* make sure this extent doesn't get
227                                  * reused for other purposes */
228                                 btrfs_pin_extent(root->fs_info,
229                                                  key.objectid, key.offset);
230                         }
231
232                         btrfs_del_item(trans, root, path);
233                 } else {
234                         fprintf(stderr,
235                                 "corrupting extent record: key %llu %u %llu\n",
236                                 key.objectid, key.type, key.offset);
237                         ptr = btrfs_item_ptr_offset(leaf, slot);
238                         item_size = btrfs_item_size_nr(leaf, slot);
239                         memset_extent_buffer(leaf, 0, ptr, item_size);
240                         btrfs_mark_buffer_dirty(leaf);
241                 }
242 next:
243                 btrfs_release_path(path);
244
245                 if (key.offset > 0)
246                         key.offset--;
247                 if (key.offset == 0)
248                         break;
249         }
250
251         btrfs_free_path(path);
252         return 0;
253 }
254
255 static void btrfs_corrupt_extent_leaf(struct btrfs_trans_handle *trans,
256                                       struct btrfs_root *root,
257                                       struct extent_buffer *eb)
258 {
259         u32 nr = btrfs_header_nritems(eb);
260         u32 victim = rand() % nr;
261         u64 objectid;
262         struct btrfs_key key;
263
264         btrfs_item_key_to_cpu(eb, &key, victim);
265         objectid = key.objectid;
266         corrupt_extent(trans, root, objectid, 1);
267 }
268
269 static void btrfs_corrupt_extent_tree(struct btrfs_trans_handle *trans,
270                                       struct btrfs_root *root,
271                                       struct extent_buffer *eb)
272 {
273         int i;
274
275         if (!eb)
276                 return;
277
278         if (btrfs_is_leaf(eb)) {
279                 btrfs_corrupt_extent_leaf(trans, root, eb);
280                 return;
281         }
282
283         if (btrfs_header_level(eb) == 1 && eb != root->node) {
284                 if (rand() % 5)
285                         return;
286         }
287
288         for (i = 0; i < btrfs_header_nritems(eb); i++) {
289                 struct extent_buffer *next;
290
291                 next = read_tree_block(root, btrfs_node_blockptr(eb, i),
292                                        root->nodesize,
293                                        btrfs_node_ptr_generation(eb, i));
294                 if (!extent_buffer_uptodate(next))
295                         continue;
296                 btrfs_corrupt_extent_tree(trans, root, next);
297                 free_extent_buffer(next);
298         }
299 }
300
301 enum btrfs_inode_field {
302         BTRFS_INODE_FIELD_ISIZE,
303         BTRFS_INODE_FIELD_NBYTES,
304         BTRFS_INODE_FIELD_BAD,
305 };
306
307 enum btrfs_file_extent_field {
308         BTRFS_FILE_EXTENT_DISK_BYTENR,
309         BTRFS_FILE_EXTENT_BAD,
310 };
311
312 enum btrfs_dir_item_field {
313         BTRFS_DIR_ITEM_NAME,
314         BTRFS_DIR_ITEM_LOCATION_OBJECTID,
315         BTRFS_DIR_ITEM_BAD,
316 };
317
318 enum btrfs_metadata_block_field {
319         BTRFS_METADATA_BLOCK_GENERATION,
320         BTRFS_METADATA_BLOCK_SHIFT_ITEMS,
321         BTRFS_METADATA_BLOCK_BAD,
322 };
323
324 enum btrfs_item_field {
325         BTRFS_ITEM_OFFSET,
326         BTRFS_ITEM_BAD,
327 };
328
329 enum btrfs_key_field {
330         BTRFS_KEY_OBJECTID,
331         BTRFS_KEY_TYPE,
332         BTRFS_KEY_OFFSET,
333         BTRFS_KEY_BAD,
334 };
335
336 static enum btrfs_inode_field convert_inode_field(char *field)
337 {
338         if (!strncmp(field, "isize", FIELD_BUF_LEN))
339                 return BTRFS_INODE_FIELD_ISIZE;
340         if (!strncmp(field, "nbytes", FIELD_BUF_LEN))
341                 return BTRFS_INODE_FIELD_NBYTES;
342         return BTRFS_INODE_FIELD_BAD;
343 }
344
345 static enum btrfs_file_extent_field convert_file_extent_field(char *field)
346 {
347         if (!strncmp(field, "disk_bytenr", FIELD_BUF_LEN))
348                 return BTRFS_FILE_EXTENT_DISK_BYTENR;
349         return BTRFS_FILE_EXTENT_BAD;
350 }
351
352 static enum btrfs_metadata_block_field
353 convert_metadata_block_field(char *field)
354 {
355         if (!strncmp(field, "generation", FIELD_BUF_LEN))
356                 return BTRFS_METADATA_BLOCK_GENERATION;
357         if (!strncmp(field, "shift_items", FIELD_BUF_LEN))
358                 return BTRFS_METADATA_BLOCK_SHIFT_ITEMS;
359         return BTRFS_METADATA_BLOCK_BAD;
360 }
361
362 static enum btrfs_key_field convert_key_field(char *field)
363 {
364         if (!strncmp(field, "objectid", FIELD_BUF_LEN))
365                 return BTRFS_KEY_OBJECTID;
366         if (!strncmp(field, "type", FIELD_BUF_LEN))
367                 return BTRFS_KEY_TYPE;
368         if (!strncmp(field, "offset", FIELD_BUF_LEN))
369                 return BTRFS_KEY_OFFSET;
370         return BTRFS_KEY_BAD;
371 }
372
373 static enum btrfs_item_field convert_item_field(char *field)
374 {
375         if (!strncmp(field, "offset", FIELD_BUF_LEN))
376                 return BTRFS_ITEM_OFFSET;
377         return BTRFS_ITEM_BAD;
378 }
379
380 static enum btrfs_dir_item_field convert_dir_item_field(char *field)
381 {
382         if (!strncmp(field, "name", FIELD_BUF_LEN))
383                 return BTRFS_DIR_ITEM_NAME;
384         if (!strncmp(field, "location_objectid", FIELD_BUF_LEN))
385                 return BTRFS_DIR_ITEM_LOCATION_OBJECTID;
386         return BTRFS_DIR_ITEM_BAD;
387 }
388
389 static u64 generate_u64(u64 orig)
390 {
391         u64 ret;
392         do {
393                 ret = rand();
394         } while (ret == orig);
395         return ret;
396 }
397
398 static u32 generate_u32(u32 orig)
399 {
400         u32 ret;
401         do {
402                 ret = rand();
403         } while (ret == orig);
404         return ret;
405 }
406
407 static u8 generate_u8(u8 orig)
408 {
409         u8 ret;
410         do {
411                 ret = rand();
412         } while (ret == orig);
413         return ret;
414 }
415
416 static int corrupt_key(struct btrfs_root *root, struct btrfs_key *key,
417                        char *field)
418 {
419         enum btrfs_key_field corrupt_field = convert_key_field(field);
420         struct btrfs_path *path;
421         struct btrfs_trans_handle *trans;
422         int ret;
423
424         root = root->fs_info->fs_root;
425         if (corrupt_field == BTRFS_KEY_BAD) {
426                 fprintf(stderr, "Invalid field %s\n", field);
427                 return -EINVAL;
428         }
429
430         path = btrfs_alloc_path();
431         if (!path)
432                 return -ENOMEM;
433
434         trans = btrfs_start_transaction(root, 1);
435         if (IS_ERR(trans)) {
436                 btrfs_free_path(path);
437                 return PTR_ERR(trans);
438         }
439
440         ret = btrfs_search_slot(trans, root, key, path, 0, 1);
441         if (ret < 0)
442                 goto out;
443         if (ret > 0) {
444                 fprintf(stderr, "Couldn't find the key to corrupt\n");
445                 ret = -ENOENT;
446                 goto out;
447         }
448
449         switch (corrupt_field) {
450         case BTRFS_KEY_OBJECTID:
451                 key->objectid = generate_u64(key->objectid);
452                 break;
453         case BTRFS_KEY_TYPE:
454                 key->type = generate_u8(key->type);
455                 break;
456         case BTRFS_KEY_OFFSET:
457                 key->offset = generate_u64(key->objectid);
458                 break;
459         default:
460                 fprintf(stderr, "Invalid field %s, %d\n", field,
461                         corrupt_field);
462                 ret = -EINVAL;
463                 goto out;
464         }
465
466         btrfs_set_item_key_unsafe(root, path, key);
467 out:
468         btrfs_free_path(path);
469         btrfs_commit_transaction(trans, root);
470         return ret;
471 }
472
473 static int corrupt_dir_item(struct btrfs_root *root, struct btrfs_key *key,
474                             char *field)
475 {
476         struct btrfs_trans_handle *trans;
477         struct btrfs_dir_item *di;
478         struct btrfs_path *path;
479         char name[PATH_MAX];
480         struct btrfs_key location;
481         struct btrfs_disk_key disk_key;
482         unsigned long name_ptr;
483         enum btrfs_dir_item_field corrupt_field =
484                 convert_dir_item_field(field);
485         u64 bogus;
486         u16 name_len;
487         int ret;
488
489         if (corrupt_field == BTRFS_DIR_ITEM_BAD) {
490                 fprintf(stderr, "Invalid field %s\n", field);
491                 return -EINVAL;
492         }
493
494         path = btrfs_alloc_path();
495         if (!path)
496                 return -ENOMEM;
497
498         trans = btrfs_start_transaction(root, 1);
499         if (IS_ERR(trans)) {
500                 btrfs_free_path(path);
501                 return PTR_ERR(trans);
502         }
503
504         ret = btrfs_search_slot(trans, root, key, path, 0, 1);
505         if (ret) {
506                 if (ret > 0)
507                         ret = -ENOENT;
508                 fprintf(stderr, "Error searching for dir item %d\n", ret);
509                 goto out;
510         }
511
512         di = btrfs_item_ptr(path->nodes[0], path->slots[0],
513                             struct btrfs_dir_item);
514
515         switch (corrupt_field) {
516         case BTRFS_DIR_ITEM_NAME:
517                 name_len = btrfs_dir_name_len(path->nodes[0], di);
518                 name_ptr = (unsigned long)(di + 1);
519                 read_extent_buffer(path->nodes[0], name, name_ptr, name_len);
520                 name[0]++;
521                 write_extent_buffer(path->nodes[0], name, name_ptr, name_len);
522                 btrfs_mark_buffer_dirty(path->nodes[0]);
523                 goto out;
524         case BTRFS_DIR_ITEM_LOCATION_OBJECTID:
525                 btrfs_dir_item_key_to_cpu(path->nodes[0], di, &location);
526                 bogus = generate_u64(location.objectid);
527                 location.objectid = bogus;
528                 btrfs_cpu_key_to_disk(&disk_key, &location);
529                 btrfs_set_dir_item_key(path->nodes[0], di, &disk_key);
530                 btrfs_mark_buffer_dirty(path->nodes[0]);
531                 goto out;
532         default:
533                 ret = -EINVAL;
534                 goto out;
535         }
536 out:
537         btrfs_commit_transaction(trans, root);
538         btrfs_free_path(path);
539         return ret;
540 }
541
542 static int corrupt_inode(struct btrfs_trans_handle *trans,
543                          struct btrfs_root *root, u64 inode, char *field)
544 {
545         struct btrfs_inode_item *ei;
546         struct btrfs_path *path;
547         struct btrfs_key key;
548         enum btrfs_inode_field corrupt_field = convert_inode_field(field);
549         u64 bogus;
550         u64 orig;
551         int ret;
552
553         if (corrupt_field == BTRFS_INODE_FIELD_BAD) {
554                 fprintf(stderr, "Invalid field %s\n", field);
555                 return -EINVAL;
556         }
557
558         key.objectid = inode;
559         key.type = BTRFS_INODE_ITEM_KEY;
560         key.offset = (u64)-1;
561
562         path = btrfs_alloc_path();
563         if (!path)
564                 return -ENOMEM;
565
566         ret = btrfs_search_slot(trans, root, &key, path, 0, 1);
567         if (ret < 0)
568                 goto out;
569         if (ret) {
570                 if (!path->slots[0]) {
571                         fprintf(stderr, "Couldn't find inode %Lu\n", inode);
572                         ret = -ENOENT;
573                         goto out;
574                 }
575                 path->slots[0]--;
576                 ret = 0;
577         }
578
579         btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
580         if (key.objectid != inode) {
581                 fprintf(stderr, "Couldn't find inode %Lu\n", inode);
582                 ret = -ENOENT;
583                 goto out;
584         }
585
586         ei = btrfs_item_ptr(path->nodes[0], path->slots[0],
587                             struct btrfs_inode_item);
588         switch (corrupt_field) {
589         case BTRFS_INODE_FIELD_ISIZE:
590                 orig = btrfs_inode_size(path->nodes[0], ei);
591                 bogus = generate_u64(orig);
592                 btrfs_set_inode_size(path->nodes[0], ei, bogus);
593                 break;
594         case BTRFS_INODE_FIELD_NBYTES:
595                 orig = btrfs_inode_nbytes(path->nodes[0], ei);
596                 bogus = generate_u64(orig);
597                 btrfs_set_inode_nbytes(path->nodes[0], ei, bogus);
598                 break;
599         default:
600                 ret = -EINVAL;
601                 break;
602         }
603         btrfs_mark_buffer_dirty(path->nodes[0]);
604 out:
605         btrfs_free_path(path);
606         return ret;
607 }
608
609 static int corrupt_file_extent(struct btrfs_trans_handle *trans,
610                                struct btrfs_root *root, u64 inode, u64 extent,
611                                char *field)
612 {
613         struct btrfs_file_extent_item *fi;
614         struct btrfs_path *path;
615         struct btrfs_key key;
616         enum btrfs_file_extent_field corrupt_field;
617         u64 bogus;
618         u64 orig;
619         int ret = 0;
620
621         corrupt_field = convert_file_extent_field(field);
622         if (corrupt_field == BTRFS_FILE_EXTENT_BAD) {
623                 fprintf(stderr, "Invalid field %s\n", field);
624                 return -EINVAL;
625         }
626
627         key.objectid = inode;
628         key.type = BTRFS_EXTENT_DATA_KEY;
629         key.offset = extent;
630
631         path = btrfs_alloc_path();
632         if (!path)
633                 return -ENOMEM;
634
635         ret = btrfs_search_slot(trans, root, &key, path, 0, 1);
636         if (ret < 0)
637                 goto out;
638         if (ret) {
639                 fprintf(stderr, "Couldn't find extent %llu for inode %llu\n",
640                         extent, inode);
641                 ret = -ENOENT;
642                 goto out;
643         }
644
645         fi = btrfs_item_ptr(path->nodes[0], path->slots[0],
646                             struct btrfs_file_extent_item);
647         switch (corrupt_field) {
648         case BTRFS_FILE_EXTENT_DISK_BYTENR:
649                 orig = btrfs_file_extent_disk_bytenr(path->nodes[0], fi);
650                 bogus = generate_u64(orig);
651                 btrfs_set_file_extent_disk_bytenr(path->nodes[0], fi, bogus);
652                 break;
653         default:
654                 ret = -EINVAL;
655                 break;
656         }
657         btrfs_mark_buffer_dirty(path->nodes[0]);
658 out:
659         btrfs_free_path(path);
660         return ret;
661 }
662
663 static void shift_items(struct btrfs_root *root, struct extent_buffer *eb)
664 {
665         int nritems = btrfs_header_nritems(eb);
666         int shift_space = btrfs_leaf_free_space(root, eb) / 2;
667         int slot = nritems / 2;
668         int i = 0;
669         unsigned int data_end = btrfs_item_offset_nr(eb, nritems - 1);
670
671         /* Shift the item data up to and including slot back by shift space */
672         memmove_extent_buffer(eb, btrfs_leaf_data(eb) + data_end - shift_space,
673                               btrfs_leaf_data(eb) + data_end,
674                               btrfs_item_offset_nr(eb, slot - 1) - data_end);
675
676         /* Now update the item pointers. */
677         for (i = nritems - 1; i >= slot; i--) {
678                 u32 offset = btrfs_item_offset_nr(eb, i);
679                 offset -= shift_space;
680                 btrfs_set_item_offset(eb, btrfs_item_nr(i), offset);
681         }
682 }
683
684 static int corrupt_metadata_block(struct btrfs_root *root, u64 block,
685                                   char *field)
686 {
687         struct btrfs_trans_handle *trans;
688         struct btrfs_path *path;
689         struct extent_buffer *eb;
690         struct btrfs_key key, root_key;
691         enum btrfs_metadata_block_field corrupt_field;
692         u64 root_objectid;
693         u64 orig, bogus;
694         u8 level;
695         int ret;
696
697         corrupt_field = convert_metadata_block_field(field);
698         if (corrupt_field == BTRFS_METADATA_BLOCK_BAD) {
699                 fprintf(stderr, "Invalid field %s\n", field);
700                 return -EINVAL;
701         }
702
703         eb = read_tree_block(root, block, root->nodesize, 0);
704         if (!extent_buffer_uptodate(eb)) {
705                 fprintf(stderr, "Couldn't read in tree block %s\n", field);
706                 return -EINVAL;
707         }
708         root_objectid = btrfs_header_owner(eb);
709         level = btrfs_header_level(eb);
710         if (level)
711                 btrfs_node_key_to_cpu(eb, &key, 0);
712         else
713                 btrfs_item_key_to_cpu(eb, &key, 0);
714         free_extent_buffer(eb);
715
716         root_key.objectid = root_objectid;
717         root_key.type = BTRFS_ROOT_ITEM_KEY;
718         root_key.offset = (u64)-1;
719
720         root = btrfs_read_fs_root(root->fs_info, &root_key);
721         if (IS_ERR(root)) {
722                 fprintf(stderr, "Couldn't finde owner root %llu\n",
723                         key.objectid);
724                 return PTR_ERR(root);
725         }
726
727         path = btrfs_alloc_path();
728         if (!path)
729                 return -ENOMEM;
730
731         trans = btrfs_start_transaction(root, 1);
732         if (IS_ERR(trans)) {
733                 btrfs_free_path(path);
734                 fprintf(stderr, "Couldn't start transaction %ld\n",
735                         PTR_ERR(trans));
736                 return PTR_ERR(trans);
737         }
738
739         path->lowest_level = level;
740         ret = btrfs_search_slot(trans, root, &key, path, 0, 1);
741         if (ret < 0) {
742                 fprintf(stderr, "Error searching to node %d\n", ret);
743                 goto out;
744         }
745         eb = path->nodes[level];
746
747         ret = 0;
748         switch (corrupt_field) {
749         case BTRFS_METADATA_BLOCK_GENERATION:
750                 orig = btrfs_header_generation(eb);
751                 bogus = generate_u64(orig);
752                 btrfs_set_header_generation(eb, bogus);
753                 break;
754         case BTRFS_METADATA_BLOCK_SHIFT_ITEMS:
755                 shift_items(root, path->nodes[level]);
756                 break;
757         default:
758                 ret = -EINVAL;
759                 break;
760         }
761         btrfs_mark_buffer_dirty(path->nodes[level]);
762 out:
763         btrfs_commit_transaction(trans, root);
764         btrfs_free_path(path);
765         return ret;
766 }
767
768 static int corrupt_btrfs_item(struct btrfs_root *root, struct btrfs_key *key,
769                               char *field)
770 {
771         struct btrfs_trans_handle *trans;
772         struct btrfs_path *path;
773         enum btrfs_item_field corrupt_field;
774         u32 orig, bogus;
775         int ret;
776
777         corrupt_field = convert_item_field(field);
778         if (corrupt_field == BTRFS_ITEM_BAD) {
779                 fprintf(stderr, "Invalid field %s\n", field);
780                 return -EINVAL;
781         }
782
783         path = btrfs_alloc_path();
784         if (!path)
785                 return -ENOMEM;
786
787         trans = btrfs_start_transaction(root, 1);
788         if (IS_ERR(trans)) {
789                 btrfs_free_path(path);
790                 fprintf(stderr, "Couldn't start transaction %ld\n",
791                         PTR_ERR(trans));
792                 return PTR_ERR(trans);
793         }
794
795         ret = btrfs_search_slot(trans, root, key, path, 0, 1);
796         if (ret != 0) {
797                 fprintf(stderr, "Error searching to node %d\n", ret);
798                 goto out;
799         }
800
801         ret = 0;
802         switch (corrupt_field) {
803         case BTRFS_ITEM_OFFSET:
804                 orig = btrfs_item_offset_nr(path->nodes[0], path->slots[0]);
805                 bogus = generate_u32(orig);
806                 btrfs_set_item_offset(path->nodes[0],
807                                       btrfs_item_nr(path->slots[0]), bogus);
808                 break;
809         default:
810                 ret = -EINVAL;
811                 break;
812         }
813         btrfs_mark_buffer_dirty(path->nodes[0]);
814 out:
815         btrfs_commit_transaction(trans, root);
816         btrfs_free_path(path);
817         return ret;
818 }
819
820 static int delete_item(struct btrfs_root *root, struct btrfs_key *key)
821 {
822         struct btrfs_trans_handle *trans;
823         struct btrfs_path *path;
824         int ret;
825
826         path = btrfs_alloc_path();
827         if (!path)
828                 return -ENOMEM;
829
830         trans = btrfs_start_transaction(root, 1);
831         if (IS_ERR(trans)) {
832                 btrfs_free_path(path);
833                 fprintf(stderr, "Couldn't start transaction %ld\n",
834                         PTR_ERR(trans));
835                 return PTR_ERR(trans);
836         }
837
838         ret = btrfs_search_slot(trans, root, key, path, -1, 1);
839         if (ret) {
840                 if (ret > 0)
841                         ret = -ENOENT;
842                 fprintf(stderr, "Error searching to node %d\n", ret);
843                 goto out;
844         }
845         ret = btrfs_del_item(trans, root, path);
846         btrfs_mark_buffer_dirty(path->nodes[0]);
847 out:
848         btrfs_commit_transaction(trans, root);
849         btrfs_free_path(path);
850         return ret;
851 }
852
853 static int delete_csum(struct btrfs_root *root, u64 bytenr, u64 bytes)
854 {
855         struct btrfs_trans_handle *trans;
856         int ret;
857
858         root = root->fs_info->csum_root;
859         trans = btrfs_start_transaction(root, 1);
860         if (IS_ERR(trans)) {
861                 fprintf(stderr, "Couldn't start transaction %ld\n",
862                         PTR_ERR(trans));
863                 return PTR_ERR(trans);
864         }
865
866         ret = btrfs_del_csums(trans, root, bytenr, bytes);
867         if (ret)
868                 fprintf(stderr, "Error deleting csums %d\n", ret);
869         btrfs_commit_transaction(trans, root);
870         return ret;
871 }
872
873 /* corrupt item using NO cow.
874  * Because chunk recover will recover based on whole partition scaning,
875  * If using COW, chunk recover will use the old item to recover,
876  * which is still OK but we want to check the ability to rebuild chunk
877  * not only restore the old ones */
878 static int corrupt_item_nocow(struct btrfs_trans_handle *trans,
879                        struct btrfs_root *root, struct btrfs_path *path,
880                        int del)
881 {
882         int ret = 0;
883         struct btrfs_key key;
884         struct extent_buffer *leaf;
885         unsigned long ptr;
886         int slot;
887         u32 item_size;
888
889         leaf = path->nodes[0];
890         slot = path->slots[0];
891         /* Not deleting the first item of a leaf to keep leaf structure */
892         if (slot == 0)
893                 del = 0;
894         /* Only accept valid eb */
895         BUG_ON(!leaf->data || slot >= btrfs_header_nritems(leaf));
896         btrfs_item_key_to_cpu(leaf, &key, slot);
897         if (del) {
898                 fprintf(stdout, "Deleting key and data [%llu, %u, %llu].\n",
899                         key.objectid, key.type, key.offset);
900                 btrfs_del_item(trans, root, path);
901         } else {
902                 fprintf(stdout, "Corrupting key and data [%llu, %u, %llu].\n",
903                         key.objectid, key.type, key.offset);
904                 ptr = btrfs_item_ptr_offset(leaf, slot);
905                 item_size = btrfs_item_size_nr(leaf, slot);
906                 memset_extent_buffer(leaf, 0, ptr, item_size);
907                 btrfs_mark_buffer_dirty(leaf);
908         }
909         return ret;
910 }
911 static int corrupt_chunk_tree(struct btrfs_trans_handle *trans,
912                        struct btrfs_root *root)
913 {
914         int ret;
915         int del;
916         int slot;
917         struct btrfs_path *path;
918         struct btrfs_key key;
919         struct btrfs_key found_key;
920         struct extent_buffer *leaf;
921
922         path = btrfs_alloc_path();
923         if (!path)
924                 return -ENOMEM;
925
926         key.objectid = (u64)-1;
927         key.offset = (u64)-1;
928         key.type = (u8)-1;
929
930         /* Here, cow and ins_len must equals 0 for the following reasons:
931          * 1) chunk recover is based on disk scanning, so COW should be
932          *    disabled in case the original chunk being scanned and
933          *    recovered using the old chunk.
934          * 2) if cow = 0, ins_len must also be set to 0, or BUG_ON will be
935          *    triggered.
936          */
937         ret = btrfs_search_slot(trans, root, &key, path, 0, 0);
938         BUG_ON(ret == 0);
939         if (ret < 0) {
940                 fprintf(stderr, "Error searching tree\n");
941                 goto free_out;
942         }
943         /* corrupt/del dev_item first */
944         while (!btrfs_previous_item(root, path, 0, BTRFS_DEV_ITEM_KEY)) {
945                 slot = path->slots[0];
946                 leaf = path->nodes[0];
947                 del = rand() % 3;
948                 /* Never delete the first item to keep the leaf structure */
949                 if (path->slots[0] == 0)
950                         del = 0;
951                 ret = corrupt_item_nocow(trans, root, path, del);
952                 if (ret)
953                         goto free_out;
954         }
955         btrfs_release_path(path);
956
957         /* Here, cow and ins_len must equals 0 for the following reasons:
958          * 1) chunk recover is based on disk scanning, so COW should be
959          *    disabled in case the original chunk being scanned and
960          *    recovered using the old chunk.
961          * 2) if cow = 0, ins_len must also be set to 0, or BUG_ON will be
962          *    triggered.
963          */
964         ret = btrfs_search_slot(trans, root, &key, path, 0, 0);
965         BUG_ON(ret == 0);
966         if (ret < 0) {
967                 fprintf(stderr, "Error searching tree\n");
968                 goto free_out;
969         }
970         /* corrupt/del chunk then*/
971         while (!btrfs_previous_item(root, path, 0, BTRFS_CHUNK_ITEM_KEY)) {
972                 slot = path->slots[0];
973                 leaf = path->nodes[0];
974                 del = rand() % 3;
975                 btrfs_item_key_to_cpu(leaf, &found_key, slot);
976                 ret = corrupt_item_nocow(trans, root, path, del);
977                 if (ret)
978                         goto free_out;
979         }
980 free_out:
981         btrfs_free_path(path);
982         return ret;
983 }
984 static int find_chunk_offset(struct btrfs_root *root,
985                       struct btrfs_path *path, u64 offset)
986 {
987         struct btrfs_key key;
988         int ret;
989
990         key.objectid = BTRFS_FIRST_CHUNK_TREE_OBJECTID;
991         key.type = BTRFS_CHUNK_ITEM_KEY;
992         key.offset = offset;
993
994         /* Here, cow and ins_len must equals 0 for following reasons:
995          * 1) chunk recover is based on disk scanning, so COW should
996          *    be disabled in case the original chunk being scanned
997          *    and recovered using the old chunk.
998          * 2) if cow = 0, ins_len must also be set to 0, or BUG_ON
999          *    will be triggered.
1000          */
1001         ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
1002         if (ret > 0) {
1003                 fprintf(stderr, "Can't find chunk with given offset %llu\n",
1004                         offset);
1005                 goto out;
1006         }
1007         if (ret < 0) {
1008                 fprintf(stderr, "Error searching chunk\n");
1009                 goto out;
1010         }
1011 out:
1012         return ret;
1013
1014 }
1015 int main(int argc, char **argv)
1016 {
1017         struct cache_tree root_cache;
1018         struct btrfs_key key;
1019         struct btrfs_root *root;
1020         struct extent_buffer *eb;
1021         char *dev;
1022         /* chunk offset can be 0,so change to (u64)-1 */
1023         u64 logical = (u64)-1;
1024         int ret = 0;
1025         u64 copy = 0;
1026         u64 bytes = 4096;
1027         int extent_rec = 0;
1028         int extent_tree = 0;
1029         int corrupt_block_keys = 0;
1030         int chunk_rec = 0;
1031         int chunk_tree = 0;
1032         int corrupt_item = 0;
1033         int corrupt_di = 0;
1034         int delete = 0;
1035         u64 metadata_block = 0;
1036         u64 inode = 0;
1037         u64 file_extent = (u64)-1;
1038         u64 root_objectid = 0;
1039         u64 csum_bytenr = 0;
1040         char field[FIELD_BUF_LEN];
1041
1042         field[0] = '\0';
1043         srand(128);
1044         memset(&key, 0, sizeof(key));
1045
1046         while(1) {
1047                 int c;
1048                 static const struct option long_options[] = {
1049                         /* { "byte-count", 1, NULL, 'b' }, */
1050                         { "logical", required_argument, NULL, 'l' },
1051                         { "copy", required_argument, NULL, 'c' },
1052                         { "bytes", required_argument, NULL, 'b' },
1053                         { "extent-record", no_argument, NULL, 'e' },
1054                         { "extent-tree", no_argument, NULL, 'E' },
1055                         { "keys", no_argument, NULL, 'k' },
1056                         { "chunk-record", no_argument, NULL, 'u' },
1057                         { "chunk-tree", no_argument, NULL, 'U' },
1058                         { "inode", required_argument, NULL, 'i'},
1059                         { "file-extent", required_argument, NULL, 'x'},
1060                         { "metadata-block", required_argument, NULL, 'm'},
1061                         { "field", required_argument, NULL, 'f'},
1062                         { "key", required_argument, NULL, 'K'},
1063                         { "item", no_argument, NULL, 'I'},
1064                         { "dir-item", no_argument, NULL, 'D'},
1065                         { "delete", no_argument, NULL, 'd'},
1066                         { "root", no_argument, NULL, 'r'},
1067                         { "csum", required_argument, NULL, 'C'},
1068                         { "help", no_argument, NULL, GETOPT_VAL_HELP},
1069                         { NULL, 0, NULL, 0 }
1070                 };
1071
1072                 c = getopt_long(argc, argv, "l:c:b:eEkuUi:f:x:m:K:IDdr:C:",
1073                                 long_options, NULL);
1074                 if (c < 0)
1075                         break;
1076                 switch(c) {
1077                         case 'l':
1078                                 logical = arg_strtou64(optarg);
1079                                 break;
1080                         case 'c':
1081                                 copy = arg_strtou64(optarg);
1082                                 break;
1083                         case 'b':
1084                                 bytes = arg_strtou64(optarg);
1085                                 break;
1086                         case 'e':
1087                                 extent_rec = 1;
1088                                 break;
1089                         case 'E':
1090                                 extent_tree = 1;
1091                                 break;
1092                         case 'k':
1093                                 corrupt_block_keys = 1;
1094                                 break;
1095                         case 'u':
1096                                 chunk_rec = 1;
1097                                 break;
1098                         case 'U':
1099                                 chunk_tree = 1;
1100                                 break;
1101                         case 'i':
1102                                 inode = arg_strtou64(optarg);
1103                                 break;
1104                         case 'f':
1105                                 strncpy(field, optarg, FIELD_BUF_LEN);
1106                                 break;
1107                         case 'x':
1108                                 file_extent = arg_strtou64(optarg);
1109                                 break;
1110                         case 'm':
1111                                 metadata_block = arg_strtou64(optarg);
1112                                 break;
1113                         case 'K':
1114                                 ret = sscanf(optarg, "%llu,%u,%llu",
1115                                              &key.objectid,
1116                                              (unsigned int *)&key.type,
1117                                              &key.offset);
1118                                 if (ret != 3) {
1119                                         fprintf(stderr, "error reading key "
1120                                                 "%d\n", errno);
1121                                         print_usage(1);
1122                                 }
1123                                 break;
1124                         case 'D':
1125                                 corrupt_di = 1;
1126                                 break;
1127                         case 'I':
1128                                 corrupt_item = 1;
1129                                 break;
1130                         case 'd':
1131                                 delete = 1;
1132                                 break;
1133                         case 'r':
1134                                 root_objectid = arg_strtou64(optarg);
1135                                 break;
1136                         case 'C':
1137                                 csum_bytenr = arg_strtou64(optarg);
1138                                 break;
1139                         case GETOPT_VAL_HELP:
1140                         default:
1141                                 print_usage(c != GETOPT_VAL_HELP);
1142                 }
1143         }
1144         set_argv0(argv);
1145         if (check_argc_min(argc - optind, 1))
1146                 print_usage(1);
1147         dev = argv[optind];
1148
1149         radix_tree_init();
1150         cache_tree_init(&root_cache);
1151
1152         root = open_ctree(dev, 0, OPEN_CTREE_WRITES);
1153         if (!root) {
1154                 fprintf(stderr, "Open ctree failed\n");
1155                 exit(1);
1156         }
1157         if (extent_rec) {
1158                 struct btrfs_trans_handle *trans;
1159
1160                 if (logical == (u64)-1)
1161                         print_usage(1);
1162                 trans = btrfs_start_transaction(root, 1);
1163                 ret = corrupt_extent (trans, root, logical, 0);
1164                 btrfs_commit_transaction(trans, root);
1165                 goto out_close;
1166         }
1167         if (extent_tree) {
1168                 struct btrfs_trans_handle *trans;
1169                 trans = btrfs_start_transaction(root, 1);
1170                 btrfs_corrupt_extent_tree(trans, root->fs_info->extent_root,
1171                                           root->fs_info->extent_root->node);
1172                 btrfs_commit_transaction(trans, root);
1173                 goto out_close;
1174         }
1175         if (chunk_rec) {
1176                 struct btrfs_trans_handle *trans;
1177                 struct btrfs_path *path;
1178                 int del;
1179
1180                 if (logical == (u64)-1)
1181                         print_usage(1);
1182                 del = rand() % 3;
1183                 path = btrfs_alloc_path();
1184                 if (!path) {
1185                         fprintf(stderr, "path allocation failed\n");
1186                         goto out_close;
1187                 }
1188
1189                 if (find_chunk_offset(root->fs_info->chunk_root, path,
1190                                       logical) != 0) {
1191                         btrfs_free_path(path);
1192                         goto out_close;
1193                 }
1194                 trans = btrfs_start_transaction(root, 1);
1195                 ret = corrupt_item_nocow(trans, root->fs_info->chunk_root,
1196                                          path, del);
1197                 if (ret < 0)
1198                         fprintf(stderr, "Failed to corrupt chunk record\n");
1199                 btrfs_commit_transaction(trans, root);
1200                 goto out_close;
1201         }
1202         if (chunk_tree) {
1203                 struct btrfs_trans_handle *trans;
1204                 trans = btrfs_start_transaction(root, 1);
1205                 ret = corrupt_chunk_tree(trans, root->fs_info->chunk_root);
1206                 if (ret < 0)
1207                         fprintf(stderr, "Failed to corrupt chunk tree\n");
1208                 btrfs_commit_transaction(trans, root);
1209                 goto out_close;
1210         }
1211         if (inode) {
1212                 struct btrfs_trans_handle *trans;
1213
1214                 if (*field == 0)
1215                         print_usage(1);
1216
1217                 trans = btrfs_start_transaction(root, 1);
1218                 if (file_extent == (u64)-1) {
1219                         printf("corrupting inode\n");
1220                         ret = corrupt_inode(trans, root, inode, field);
1221                 } else {
1222                         printf("corrupting file extent\n");
1223                         ret = corrupt_file_extent(trans, root, inode,
1224                                                   file_extent, field);
1225                 }
1226                 btrfs_commit_transaction(trans, root);
1227                 goto out_close;
1228         }
1229         if (metadata_block) {
1230                 if (*field == 0)
1231                         print_usage(1);
1232                 ret = corrupt_metadata_block(root, metadata_block, field);
1233                 goto out_close;
1234         }
1235         if (corrupt_di) {
1236                 if (!key.objectid || *field == 0)
1237                         print_usage(1);
1238                 ret = corrupt_dir_item(root, &key, field);
1239                 goto out_close;
1240         }
1241         if (csum_bytenr) {
1242                 ret = delete_csum(root, csum_bytenr, bytes);
1243                 goto out_close;
1244         }
1245         if (corrupt_item) {
1246                 if (!key.objectid)
1247                         print_usage(1);
1248                 ret = corrupt_btrfs_item(root, &key, field);
1249         }
1250         if (delete) {
1251                 struct btrfs_root *target = root;
1252
1253                 if (!key.objectid)
1254                         print_usage(1);
1255                 if (root_objectid) {
1256                         struct btrfs_key root_key;
1257
1258                         root_key.objectid = root_objectid;
1259                         root_key.type = BTRFS_ROOT_ITEM_KEY;
1260                         root_key.offset = (u64)-1;
1261
1262                         target = btrfs_read_fs_root(root->fs_info, &root_key);
1263                         if (IS_ERR(target)) {
1264                                 fprintf(stderr, "Couldn't find root %llu\n",
1265                                         (unsigned long long)root_objectid);
1266                                 print_usage(1);
1267                         }
1268                 }
1269                 ret = delete_item(target, &key);
1270                 goto out_close;
1271         }
1272         if (key.objectid || key.offset || key.type) {
1273                 if (*field == 0)
1274                         print_usage(1);
1275                 ret = corrupt_key(root, &key, field);
1276                 goto out_close;
1277         }
1278         /*
1279          * If we made it here and we have extent set then we didn't specify
1280          * inode and we're screwed.
1281          */
1282         if (file_extent != (u64)-1)
1283                 print_usage(1);
1284
1285         if (logical == (u64)-1)
1286                 print_usage(1);
1287
1288         if (bytes == 0)
1289                 bytes = root->sectorsize;
1290
1291         bytes = (bytes + root->sectorsize - 1) / root->sectorsize;
1292         bytes *= root->sectorsize;
1293
1294         while (bytes > 0) {
1295                 if (corrupt_block_keys) {
1296                         corrupt_keys_in_block(root, logical);
1297                 } else {
1298                         eb = debug_corrupt_block(root, logical,
1299                                                  root->sectorsize, copy);
1300                         free_extent_buffer(eb);
1301                 }
1302                 logical += root->sectorsize;
1303                 bytes -= root->sectorsize;
1304         }
1305         return ret;
1306 out_close:
1307         close_ctree(root);
1308         return ret;
1309 }