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