btrfs-progs: check path alloc in corrupt block
[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 #define _XOPEN_SOURCE 500
20 #define _GNU_SOURCE 1
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <fcntl.h>
24 #include <unistd.h>
25 #include <getopt.h>
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 "version.h"
34 #include "utils.h"
35
36 #define FIELD_BUF_LEN 80
37
38 struct extent_buffer *debug_corrupt_block(struct btrfs_root *root, u64 bytenr,
39                                      u32 blocksize, int copy)
40 {
41         int ret;
42         struct extent_buffer *eb;
43         u64 length;
44         struct btrfs_multi_bio *multi = NULL;
45         struct btrfs_device *device;
46         int num_copies;
47         int mirror_num = 1;
48
49         eb = btrfs_find_create_tree_block(root, bytenr, blocksize);
50         if (!eb)
51                 return NULL;
52
53         length = blocksize;
54         while (1) {
55                 ret = btrfs_map_block(&root->fs_info->mapping_tree, READ,
56                                       eb->start, &length, &multi,
57                                       mirror_num, NULL);
58                 BUG_ON(ret);
59                 device = multi->stripes[0].dev;
60                 eb->fd = device->fd;
61                 device->total_ios++;
62                 eb->dev_bytenr = multi->stripes[0].physical;
63
64                 fprintf(stdout,
65                         "mirror %d logical %llu physical %llu device %s\n",
66                         mirror_num, (unsigned long long)bytenr,
67                         (unsigned long long)eb->dev_bytenr, device->name);
68                 kfree(multi);
69
70                 if (!copy || mirror_num == copy) {
71                         ret = read_extent_from_disk(eb, 0, eb->len);
72                         printf("corrupting %llu copy %d\n", eb->start,
73                                mirror_num);
74                         memset(eb->data, 0, eb->len);
75                         write_extent_to_disk(eb);
76                         fsync(eb->fd);
77                 }
78
79                 num_copies = btrfs_num_copies(&root->fs_info->mapping_tree,
80                                               eb->start, eb->len);
81                 if (num_copies == 1)
82                         break;
83
84                 mirror_num++;
85                 if (mirror_num > num_copies)
86                         break;
87         }
88         return eb;
89 }
90
91 static void print_usage(void)
92 {
93         fprintf(stderr, "usage: btrfs-corrupt-block [options] device\n");
94         fprintf(stderr, "\t-l Logical extent to be corrupted\n");
95         fprintf(stderr, "\t-c Copy of the extent to be corrupted"
96                 " (usually 1 or 2, default: 0)\n");
97         fprintf(stderr, "\t-b Number of bytes to be corrupted\n");
98         fprintf(stderr, "\t-e Extent to be corrupted\n");
99         fprintf(stderr, "\t-E The whole extent tree to be corrupted\n");
100         fprintf(stderr, "\t-u Given chunk item to be corrupted\n");
101         fprintf(stderr, "\t-U The whole chunk tree to be corrupted\n");
102         fprintf(stderr, "\t-i The inode item to corrupt (must also specify "
103                 "the field to corrupt)\n");
104         fprintf(stderr, "\t-x The file extent item to corrupt (must also "
105                 "specify -i for the inode and -f for the field to corrupt)\n");
106         fprintf(stderr, "\t-m The metadata block to corrupt (must also "
107                 "specify -f for the field to corrupt)\n");
108         fprintf(stderr, "\t-f The field in the item to corrupt\n");
109         exit(1);
110 }
111
112 static void corrupt_keys(struct btrfs_trans_handle *trans,
113                          struct btrfs_root *root,
114                          struct extent_buffer *eb)
115 {
116         int slot;
117         int bad_slot;
118         int nr;
119         struct btrfs_disk_key bad_key;;
120
121         nr = btrfs_header_nritems(eb);
122         if (nr == 0)
123                 return;
124
125         slot = rand() % nr;
126         bad_slot = rand() % nr;
127
128         if (bad_slot == slot)
129                 return;
130
131         fprintf(stderr,
132                 "corrupting keys in block %llu slot %d swapping with %d\n",
133                 (unsigned long long)eb->start, slot, bad_slot);
134
135         if (btrfs_header_level(eb) == 0) {
136                 btrfs_item_key(eb, &bad_key, bad_slot);
137                 btrfs_set_item_key(eb, &bad_key, slot);
138         } else {
139                 btrfs_node_key(eb, &bad_key, bad_slot);
140                 btrfs_set_node_key(eb, &bad_key, slot);
141         }
142         btrfs_mark_buffer_dirty(eb);
143         if (!trans) {
144                 u16 csum_size =
145                         btrfs_super_csum_size(root->fs_info->super_copy);
146                 csum_tree_block_size(eb, csum_size, 0);
147                 write_extent_to_disk(eb);
148         }
149 }
150
151
152 static int corrupt_keys_in_block(struct btrfs_root *root, u64 bytenr)
153 {
154         struct extent_buffer *eb;
155
156         eb = read_tree_block(root, bytenr, root->leafsize, 0);
157         if (!eb)
158                 return -EIO;;
159
160         corrupt_keys(NULL, root, eb);
161         free_extent_buffer(eb);
162         return 0;
163 }
164
165 static int corrupt_extent(struct btrfs_trans_handle *trans,
166                           struct btrfs_root *root, u64 bytenr, int copy)
167 {
168         struct btrfs_key key;
169         struct extent_buffer *leaf;
170         u32 item_size;
171         unsigned long ptr;
172         struct btrfs_path *path;
173         int ret;
174         int slot;
175         int should_del = rand() % 3;
176
177         path = btrfs_alloc_path();
178         if (!path)
179                 return -ENOMEM;
180
181         key.objectid = bytenr;
182         key.type = (u8)-1;
183         key.offset = (u64)-1;
184
185         while(1) {
186                 ret = btrfs_search_slot(trans, root->fs_info->extent_root,
187                                         &key, path, -1, 1);
188                 if (ret < 0)
189                         break;
190
191                 if (ret > 0) {
192                         if (path->slots[0] == 0)
193                                 break;
194                         path->slots[0]--;
195                         ret = 0;
196                 }
197                 leaf = path->nodes[0];
198                 slot = path->slots[0];
199                 btrfs_item_key_to_cpu(leaf, &key, slot);
200                 if (key.objectid != bytenr)
201                         break;
202
203                 if (key.type != BTRFS_EXTENT_ITEM_KEY &&
204                     key.type != BTRFS_TREE_BLOCK_REF_KEY &&
205                     key.type != BTRFS_EXTENT_DATA_REF_KEY &&
206                     key.type != BTRFS_EXTENT_REF_V0_KEY &&
207                     key.type != BTRFS_SHARED_BLOCK_REF_KEY &&
208                     key.type != BTRFS_SHARED_DATA_REF_KEY)
209                         goto next;
210
211                 if (should_del) {
212                         fprintf(stderr,
213                                 "deleting extent record: key %llu %u %llu\n",
214                                 key.objectid, key.type, key.offset);
215
216                         if (key.type == BTRFS_EXTENT_ITEM_KEY) {
217                                 /* make sure this extent doesn't get
218                                  * reused for other purposes */
219                                 btrfs_pin_extent(root->fs_info,
220                                                  key.objectid, key.offset);
221                         }
222
223                         btrfs_del_item(trans, root, path);
224                 } else {
225                         fprintf(stderr,
226                                 "corrupting extent record: key %llu %u %llu\n",
227                                 key.objectid, key.type, key.offset);
228                         ptr = btrfs_item_ptr_offset(leaf, slot);
229                         item_size = btrfs_item_size_nr(leaf, slot);
230                         memset_extent_buffer(leaf, 0, ptr, item_size);
231                         btrfs_mark_buffer_dirty(leaf);
232                 }
233 next:
234                 btrfs_release_path(path);
235
236                 if (key.offset > 0)
237                         key.offset--;
238                 if (key.offset == 0)
239                         break;
240         }
241
242         btrfs_free_path(path);
243         return 0;
244 }
245
246 static void btrfs_corrupt_extent_leaf(struct btrfs_trans_handle *trans,
247                                       struct btrfs_root *root,
248                                       struct extent_buffer *eb)
249 {
250         u32 nr = btrfs_header_nritems(eb);
251         u32 victim = rand() % nr;
252         u64 objectid;
253         struct btrfs_key key;
254
255         btrfs_item_key_to_cpu(eb, &key, victim);
256         objectid = key.objectid;
257         corrupt_extent(trans, root, objectid, 1);
258 }
259
260 static void btrfs_corrupt_extent_tree(struct btrfs_trans_handle *trans,
261                                       struct btrfs_root *root,
262                                       struct extent_buffer *eb)
263 {
264         int i;
265         u32 nr;
266
267         if (!eb)
268                 return;
269
270         nr = btrfs_header_nritems(eb);
271         if (btrfs_is_leaf(eb)) {
272                 btrfs_corrupt_extent_leaf(trans, root, eb);
273                 return;
274         }
275
276         if (btrfs_header_level(eb) == 1 && eb != root->node) {
277                 if (rand() % 5)
278                         return;
279         }
280
281         for (i = 0; i < nr; i++) {
282                 struct extent_buffer *next;
283
284                 next = read_tree_block(root, btrfs_node_blockptr(eb, i),
285                                        root->leafsize,
286                                        btrfs_node_ptr_generation(eb, i));
287                 if (!next)
288                         continue;
289                 btrfs_corrupt_extent_tree(trans, root, next);
290                 free_extent_buffer(next);
291         }
292 }
293
294 enum btrfs_inode_field {
295         BTRFS_INODE_FIELD_ISIZE,
296         BTRFS_INODE_FIELD_BAD,
297 };
298
299 enum btrfs_file_extent_field {
300         BTRFS_FILE_EXTENT_DISK_BYTENR,
301         BTRFS_FILE_EXTENT_BAD,
302 };
303
304 enum btrfs_metadata_block_field {
305         BTRFS_METADATA_BLOCK_GENERATION,
306         BTRFS_METADATA_BLOCK_BAD,
307 };
308
309 static enum btrfs_inode_field convert_inode_field(char *field)
310 {
311         if (!strncmp(field, "isize", FIELD_BUF_LEN))
312                 return BTRFS_INODE_FIELD_ISIZE;
313         return BTRFS_INODE_FIELD_BAD;
314 }
315
316 static enum btrfs_file_extent_field convert_file_extent_field(char *field)
317 {
318         if (!strncmp(field, "disk_bytenr", FIELD_BUF_LEN))
319                 return BTRFS_FILE_EXTENT_DISK_BYTENR;
320         return BTRFS_FILE_EXTENT_BAD;
321 }
322
323 static enum btrfs_metadata_block_field
324 convert_metadata_block_field(char *field)
325 {
326         if (!strncmp(field, "generation", FIELD_BUF_LEN))
327                 return BTRFS_METADATA_BLOCK_GENERATION;
328         return BTRFS_METADATA_BLOCK_BAD;
329 }
330
331 static u64 generate_u64(u64 orig)
332 {
333         u64 ret;
334         do {
335                 ret = rand();
336         } while (ret == orig);
337         return ret;
338 }
339
340 static int corrupt_inode(struct btrfs_trans_handle *trans,
341                          struct btrfs_root *root, u64 inode, char *field)
342 {
343         struct btrfs_inode_item *ei;
344         struct btrfs_path *path;
345         struct btrfs_key key;
346         enum btrfs_inode_field corrupt_field = convert_inode_field(field);
347         u64 bogus;
348         u64 orig;
349         int ret;
350
351         if (corrupt_field == BTRFS_INODE_FIELD_BAD) {
352                 fprintf(stderr, "Invalid field %s\n", field);
353                 return -EINVAL;
354         }
355
356         key.objectid = inode;
357         key.type = BTRFS_INODE_ITEM_KEY;
358         key.offset = (u64)-1;
359
360         path = btrfs_alloc_path();
361         if (!path)
362                 return -ENOMEM;
363
364         ret = btrfs_search_slot(trans, root, &key, path, 0, 1);
365         if (ret < 0)
366                 goto out;
367         if (ret) {
368                 if (!path->slots[0]) {
369                         fprintf(stderr, "Couldn't find inode %Lu\n", inode);
370                         ret = -ENOENT;
371                         goto out;
372                 }
373                 path->slots[0]--;
374                 ret = 0;
375         }
376
377         btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
378         if (key.objectid != inode) {
379                 fprintf(stderr, "Couldn't find inode %Lu\n", inode);
380                 ret = -ENOENT;
381                 goto out;
382         }
383
384         ei = btrfs_item_ptr(path->nodes[0], path->slots[0],
385                             struct btrfs_inode_item);
386         switch (corrupt_field) {
387         case BTRFS_INODE_FIELD_ISIZE:
388                 orig = btrfs_inode_size(path->nodes[0], ei);
389                 bogus = generate_u64(orig);
390                 btrfs_set_inode_size(path->nodes[0], ei, bogus);
391                 break;
392         default:
393                 ret = -EINVAL;
394                 break;
395         }
396         btrfs_mark_buffer_dirty(path->nodes[0]);
397 out:
398         btrfs_free_path(path);
399         return ret;
400 }
401
402 static int corrupt_file_extent(struct btrfs_trans_handle *trans,
403                                struct btrfs_root *root, u64 inode, u64 extent,
404                                char *field)
405 {
406         struct btrfs_file_extent_item *fi;
407         struct btrfs_path *path;
408         struct btrfs_key key;
409         enum btrfs_file_extent_field corrupt_field;
410         u64 bogus;
411         u64 orig;
412         int ret = 0;
413
414         corrupt_field = convert_file_extent_field(field);
415         if (corrupt_field == BTRFS_FILE_EXTENT_BAD) {
416                 fprintf(stderr, "Invalid field %s\n", field);
417                 return -EINVAL;
418         }
419
420         key.objectid = inode;
421         key.type = BTRFS_EXTENT_DATA_KEY;
422         key.offset = extent;
423
424         path = btrfs_alloc_path();
425         if (!path)
426                 return -ENOMEM;
427
428         ret = btrfs_search_slot(trans, root, &key, path, 0, 1);
429         if (ret < 0)
430                 goto out;
431         if (ret) {
432                 fprintf(stderr, "Couldn't find extent %llu for inode %llu\n",
433                         extent, inode);
434                 ret = -ENOENT;
435                 goto out;
436         }
437
438         fi = btrfs_item_ptr(path->nodes[0], path->slots[0],
439                             struct btrfs_file_extent_item);
440         switch (corrupt_field) {
441         case BTRFS_FILE_EXTENT_DISK_BYTENR:
442                 orig = btrfs_file_extent_disk_bytenr(path->nodes[0], fi);
443                 bogus = generate_u64(orig);
444                 btrfs_set_file_extent_disk_bytenr(path->nodes[0], fi, bogus);
445                 break;
446         default:
447                 ret = -EINVAL;
448                 break;
449         }
450         btrfs_mark_buffer_dirty(path->nodes[0]);
451 out:
452         btrfs_free_path(path);
453         return ret;
454 }
455
456 static int corrupt_metadata_block(struct btrfs_root *root, u64 block,
457                                   char *field)
458 {
459         struct btrfs_trans_handle *trans;
460         struct btrfs_path *path;
461         struct extent_buffer *eb;
462         struct btrfs_key key, root_key;
463         enum btrfs_metadata_block_field corrupt_field;
464         u64 root_objectid;
465         u64 orig, bogus;
466         u8 level;
467         int ret;
468
469         corrupt_field = convert_metadata_block_field(field);
470         if (corrupt_field == BTRFS_METADATA_BLOCK_BAD) {
471                 fprintf(stderr, "Invalid field %s\n", field);
472                 return -EINVAL;
473         }
474
475         eb = read_tree_block(root, block, root->leafsize, 0);
476         if (!eb) {
477                 fprintf(stderr, "Couldn't read in tree block %s\n", field);
478                 return -EINVAL;
479         }
480         root_objectid = btrfs_header_owner(eb);
481         level = btrfs_header_level(eb);
482         if (level)
483                 btrfs_node_key_to_cpu(eb, &key, 0);
484         else
485                 btrfs_item_key_to_cpu(eb, &key, 0);
486         free_extent_buffer(eb);
487
488         root_key.objectid = root_objectid;
489         root_key.type = BTRFS_ROOT_ITEM_KEY;
490         root_key.offset = (u64)-1;
491
492         root = btrfs_read_fs_root(root->fs_info, &root_key);
493         if (IS_ERR(root)) {
494                 fprintf(stderr, "Couldn't finde owner root %llu\n",
495                         key.objectid);
496                 return PTR_ERR(root);
497         }
498
499         path = btrfs_alloc_path();
500         if (!path)
501                 return -ENOMEM;
502
503         trans = btrfs_start_transaction(root, 1);
504         if (IS_ERR(trans)) {
505                 btrfs_free_path(path);
506                 fprintf(stderr, "Couldn't start transaction %ld\n",
507                         PTR_ERR(trans));
508                 return PTR_ERR(trans);
509         }
510
511         path->lowest_level = level;
512         ret = btrfs_search_slot(trans, root, &key, path, 0, 1);
513         if (ret < 0) {
514                 fprintf(stderr, "Error searching to node %d\n", ret);
515                 goto out;
516         }
517         eb = path->nodes[level];
518
519         ret = 0;
520         switch (corrupt_field) {
521         case BTRFS_METADATA_BLOCK_GENERATION:
522                 orig = btrfs_header_generation(eb);
523                 bogus = generate_u64(orig);
524                 btrfs_set_header_generation(eb, bogus);
525                 break;
526         default:
527                 ret = -EINVAL;
528                 break;
529         }
530         btrfs_mark_buffer_dirty(path->nodes[level]);
531 out:
532         btrfs_commit_transaction(trans, root);
533         btrfs_free_path(path);
534         return ret;
535 }
536
537 static struct option long_options[] = {
538         /* { "byte-count", 1, NULL, 'b' }, */
539         { "logical", 1, NULL, 'l' },
540         { "copy", 1, NULL, 'c' },
541         { "bytes", 1, NULL, 'b' },
542         { "extent-record", 0, NULL, 'e' },
543         { "extent-tree", 0, NULL, 'E' },
544         { "keys", 0, NULL, 'k' },
545         { "chunk-record", 0, NULL, 'u' },
546         { "chunk-tree", 0, NULL, 'U' },
547         { "inode", 1, NULL, 'i'},
548         { "file-extent", 1, NULL, 'x'},
549         { "metadata-block", 1, NULL, 'm'},
550         { "field", 1, NULL, 'f'},
551         { 0, 0, 0, 0}
552 };
553
554 /* corrupt item using NO cow.
555  * Because chunk recover will recover based on whole partition scaning,
556  * If using COW, chunk recover will use the old item to recover,
557  * which is still OK but we want to check the ability to rebuild chunk
558  * not only restore the old ones */
559 int corrupt_item_nocow(struct btrfs_trans_handle *trans,
560                        struct btrfs_root *root, struct btrfs_path *path,
561                        int del)
562 {
563         int ret = 0;
564         struct btrfs_key key;
565         struct extent_buffer *leaf;
566         unsigned long ptr;
567         int slot;
568         u32 item_size;
569
570         leaf = path->nodes[0];
571         slot = path->slots[0];
572         /* Not deleting the first item of a leaf to keep leaf structure */
573         if (slot == 0)
574                 del = 0;
575         /* Only accept valid eb */
576         BUG_ON(!leaf->data || slot >= btrfs_header_nritems(leaf));
577         btrfs_item_key_to_cpu(leaf, &key, slot);
578         if (del) {
579                 fprintf(stdout, "Deleting key and data [%llu, %u, %llu].\n",
580                         key.objectid, key.type, key.offset);
581                 btrfs_del_item(trans, root, path);
582         } else {
583                 fprintf(stdout, "Corrupting key and data [%llu, %u, %llu].\n",
584                         key.objectid, key.type, key.offset);
585                 ptr = btrfs_item_ptr_offset(leaf, slot);
586                 item_size = btrfs_item_size_nr(leaf, slot);
587                 memset_extent_buffer(leaf, 0, ptr, item_size);
588                 btrfs_mark_buffer_dirty(leaf);
589         }
590         return ret;
591 }
592 int corrupt_chunk_tree(struct btrfs_trans_handle *trans,
593                        struct btrfs_root *root)
594 {
595         int ret;
596         int del;
597         int slot;
598         struct btrfs_path *path;
599         struct btrfs_key key;
600         struct btrfs_key found_key;
601         struct extent_buffer *leaf;
602
603         path = btrfs_alloc_path();
604         if (!path)
605                 return -ENOMEM;
606
607         key.objectid = (u64)-1;
608         key.offset = (u64)-1;
609         key.type = (u8)-1;
610
611         /* Here, cow and ins_len must equals 0 for the following reasons:
612          * 1) chunk recover is based on disk scanning, so COW should be
613          *    disabled in case the original chunk being scanned and
614          *    recovered using the old chunk.
615          * 2) if cow = 0, ins_len must also be set to 0, or BUG_ON will be
616          *    triggered.
617          */
618         ret = btrfs_search_slot(trans, root, &key, path, 0, 0);
619         BUG_ON(ret == 0);
620         if (ret < 0) {
621                 fprintf(stderr, "Error searching tree\n");
622                 goto free_out;
623         }
624         /* corrupt/del dev_item first */
625         while (!btrfs_previous_item(root, path, 0, BTRFS_DEV_ITEM_KEY)) {
626                 slot = path->slots[0];
627                 leaf = path->nodes[0];
628                 del = rand() % 3;
629                 /* Never delete the first item to keep the leaf structure */
630                 if (path->slots[0] == 0)
631                         del = 0;
632                 ret = corrupt_item_nocow(trans, root, path, del);
633                 if (ret)
634                         goto free_out;
635         }
636         btrfs_release_path(path);
637
638         /* Here, cow and ins_len must equals 0 for the following reasons:
639          * 1) chunk recover is based on disk scanning, so COW should be
640          *    disabled in case the original chunk being scanned and
641          *    recovered using the old chunk.
642          * 2) if cow = 0, ins_len must also be set to 0, or BUG_ON will be
643          *    triggered.
644          */
645         ret = btrfs_search_slot(trans, root, &key, path, 0, 0);
646         BUG_ON(ret == 0);
647         if (ret < 0) {
648                 fprintf(stderr, "Error searching tree\n");
649                 goto free_out;
650         }
651         /* corrupt/del chunk then*/
652         while (!btrfs_previous_item(root, path, 0, BTRFS_CHUNK_ITEM_KEY)) {
653                 slot = path->slots[0];
654                 leaf = path->nodes[0];
655                 del = rand() % 3;
656                 btrfs_item_key_to_cpu(leaf, &found_key, slot);
657                 ret = corrupt_item_nocow(trans, root, path, del);
658                 if (ret)
659                         goto free_out;
660         }
661 free_out:
662         btrfs_free_path(path);
663         return ret;
664 }
665 int find_chunk_offset(struct btrfs_root *root,
666                       struct btrfs_path *path, u64 offset)
667 {
668         struct btrfs_key key;
669         int ret;
670
671         key.objectid = BTRFS_FIRST_CHUNK_TREE_OBJECTID;
672         key.type = BTRFS_CHUNK_ITEM_KEY;
673         key.offset = offset;
674
675         /* Here, cow and ins_len must equals 0 for following reasons:
676          * 1) chunk recover is based on disk scanning, so COW should
677          *    be disabled in case the original chunk being scanned
678          *    and recovered using the old chunk.
679          * 2) if cow = 0, ins_len must also be set to 0, or BUG_ON
680          *    will be triggered.
681          */
682         ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
683         if (ret > 0) {
684                 fprintf(stderr, "Can't find chunk with given offset %llu\n",
685                         offset);
686                 goto out;
687         }
688         if (ret < 0) {
689                 fprintf(stderr, "Error searching chunk");
690                 goto out;
691         }
692 out:
693         return ret;
694
695 }
696 int main(int ac, char **av)
697 {
698         struct cache_tree root_cache;
699         struct btrfs_root *root;
700         struct extent_buffer *eb;
701         char *dev;
702         /* chunk offset can be 0,so change to (u64)-1 */
703         u64 logical = (u64)-1;
704         int ret = 0;
705         int option_index = 0;
706         int copy = 0;
707         u64 bytes = 4096;
708         int extent_rec = 0;
709         int extent_tree = 0;
710         int corrupt_block_keys = 0;
711         int chunk_rec = 0;
712         int chunk_tree = 0;
713         u64 metadata_block = 0;
714         u64 inode = 0;
715         u64 file_extent = (u64)-1;
716         char field[FIELD_BUF_LEN];
717
718         field[0] = '\0';
719         srand(128);
720
721         while(1) {
722                 int c;
723                 c = getopt_long(ac, av, "l:c:b:eEkuUi:f:x:m:", long_options,
724                                 &option_index);
725                 if (c < 0)
726                         break;
727                 switch(c) {
728                         case 'l':
729                                 logical = atoll(optarg);
730                                 break;
731                         case 'c':
732                                 copy = atoi(optarg);
733                                 if (copy <= 0) {
734                                         fprintf(stderr,
735                                                 "invalid copy number\n");
736                                         print_usage();
737                                 }
738                                 break;
739                         case 'b':
740                                 bytes = atoll(optarg);
741                                 if (bytes == 0) {
742                                         fprintf(stderr,
743                                                 "invalid byte count\n");
744                                         print_usage();
745                                 }
746                                 break;
747                         case 'e':
748                                 extent_rec = 1;
749                                 break;
750                         case 'E':
751                                 extent_tree = 1;
752                                 break;
753                         case 'k':
754                                 corrupt_block_keys = 1;
755                                 break;
756                         case 'u':
757                                 chunk_rec = 1;
758                                 break;
759                         case 'U':
760                                 chunk_tree = 1;
761                         case 'i':
762                                 inode = atoll(optarg);
763                                 if (inode == 0) {
764                                         fprintf(stderr,
765                                                 "invalid inode number\n");
766                                         print_usage();
767                                 }
768                                 break;
769                         case 'f':
770                                 strncpy(field, optarg, FIELD_BUF_LEN);
771                                 break;
772                         case 'x':
773                                 errno = 0;
774                                 file_extent = atoll(optarg);
775                                 if (errno) {
776                                         fprintf(stderr, "error converting "
777                                                 "%d\n", errno);
778                                         print_usage();
779                                 }
780                                 break;
781                         case 'm':
782                                 errno = 0;
783                                 metadata_block = atoll(optarg);
784                                 if (errno) {
785                                         fprintf(stderr, "error converting "
786                                                 "%d\n", errno);
787                                         print_usage();
788                                 }
789                                 break;
790                         default:
791                                 print_usage();
792                 }
793         }
794         ac = ac - optind;
795         if (ac == 0)
796                 print_usage();
797         dev = av[optind];
798
799         radix_tree_init();
800         cache_tree_init(&root_cache);
801
802         root = open_ctree(dev, 0, 1);
803         if (!root) {
804                 fprintf(stderr, "Open ctree failed\n");
805                 exit(1);
806         }
807         if (extent_rec) {
808                 struct btrfs_trans_handle *trans;
809
810                 if (logical == (u64)-1)
811                         print_usage();
812                 trans = btrfs_start_transaction(root, 1);
813                 ret = corrupt_extent (trans, root, logical, 0);
814                 btrfs_commit_transaction(trans, root);
815                 goto out_close;
816         }
817         if (extent_tree) {
818                 struct btrfs_trans_handle *trans;
819                 trans = btrfs_start_transaction(root, 1);
820                 btrfs_corrupt_extent_tree(trans, root->fs_info->extent_root,
821                                           root->fs_info->extent_root->node);
822                 btrfs_commit_transaction(trans, root);
823                 goto out_close;
824         }
825         if (chunk_rec) {
826                 struct btrfs_trans_handle *trans;
827                 struct btrfs_path *path;
828                 int del;
829
830                 if (logical == (u64)-1)
831                         print_usage();
832                 del = rand() % 3;
833                 path = btrfs_alloc_path();
834                 if (!path) {
835                         fprintf(stderr, "path allocation failed\n");
836                         goto out_close;
837                 }
838
839                 if (find_chunk_offset(root->fs_info->chunk_root, path,
840                                       logical) != 0) {
841                         btrfs_free_path(path);
842                         goto out_close;
843                 }
844                 trans = btrfs_start_transaction(root, 1);
845                 ret = corrupt_item_nocow(trans, root->fs_info->chunk_root,
846                                          path, del);
847                 if (ret < 0)
848                         fprintf(stderr, "Failed to corrupt chunk record\n");
849                 btrfs_commit_transaction(trans, root);
850                 goto out_close;
851         }
852         if (chunk_tree) {
853                 struct btrfs_trans_handle *trans;
854                 trans = btrfs_start_transaction(root, 1);
855                 ret = corrupt_chunk_tree(trans, root->fs_info->chunk_root);
856                 if (ret < 0)
857                         fprintf(stderr, "Failed to corrupt chunk tree\n");
858                 btrfs_commit_transaction(trans, root);
859                 goto out_close;
860         }
861         if (inode) {
862                 struct btrfs_trans_handle *trans;
863
864                 if (!strlen(field))
865                         print_usage();
866
867                 trans = btrfs_start_transaction(root, 1);
868                 if (file_extent == (u64)-1) {
869                         printf("corrupting inode\n");
870                         ret = corrupt_inode(trans, root, inode, field);
871                 } else {
872                         printf("corrupting file extent\n");
873                         ret = corrupt_file_extent(trans, root, inode,
874                                                   file_extent, field);
875                 }
876                 btrfs_commit_transaction(trans, root);
877                 goto out_close;
878         }
879         if (metadata_block) {
880                 if (!strlen(field))
881                         print_usage();
882                 ret = corrupt_metadata_block(root, metadata_block, field);
883                 goto out_close;
884         }
885         /*
886          * If we made it here and we have extent set then we didn't specify
887          * inode and we're screwed.
888          */
889         if (file_extent != (u64)-1)
890                 print_usage();
891
892         if (logical == (u64)-1)
893                 print_usage();
894
895         if (bytes == 0)
896                 bytes = root->sectorsize;
897
898         bytes = (bytes + root->sectorsize - 1) / root->sectorsize;
899         bytes *= root->sectorsize;
900
901         while (bytes > 0) {
902                 if (corrupt_block_keys) {
903                         corrupt_keys_in_block(root, logical);
904                 } else {
905                         eb = debug_corrupt_block(root, logical,
906                                                  root->sectorsize, copy);
907                         free_extent_buffer(eb);
908                 }
909                 logical += root->sectorsize;
910                 bytes -= root->sectorsize;
911         }
912         return ret;
913 out_close:
914         close_ctree(root);
915         return ret;
916 }