Btrfs progs v4.17.1
[btrfs-progs-unstable/devel.git] / btrfs-corrupt-block.c
blob3add8e63b7bb656e4a3168194f7ede3656ff669f
1 /*
2 * Copyright (C) 2009 Oracle. All rights reserved.
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.
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.
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.
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <fcntl.h>
22 #include <unistd.h>
23 #include <getopt.h>
24 #include <limits.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 "utils.h"
34 #include "help.h"
36 #define FIELD_BUF_LEN 80
38 static int debug_corrupt_block(struct extent_buffer *eb,
39 struct btrfs_root *root, u64 bytenr, u32 blocksize, u64 copy)
41 int ret;
42 u64 length;
43 struct btrfs_multi_bio *multi = NULL;
44 struct btrfs_device *device;
45 int num_copies;
46 int mirror_num = 1;
48 length = blocksize;
49 while (1) {
50 ret = btrfs_map_block(root->fs_info, READ, eb->start, &length,
51 &multi, mirror_num, NULL);
52 if (ret) {
53 error("cannot map block %llu length %llu mirror %d: %d",
54 (unsigned long long)eb->start,
55 (unsigned long long)length,
56 mirror_num, ret);
57 return ret;
59 device = multi->stripes[0].dev;
60 eb->fd = device->fd;
61 device->total_ios++;
62 eb->dev_bytenr = multi->stripes[0].physical;
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 free(multi);
70 if (!copy || mirror_num == copy) {
71 ret = read_extent_from_disk(eb, 0, eb->len);
72 if (ret < 0) {
73 error("cannot read eb bytenr %llu: %s",
74 (unsigned long long)eb->dev_bytenr,
75 strerror(-ret));
76 return ret;
78 printf("corrupting %llu copy %d\n", eb->start,
79 mirror_num);
80 memset(eb->data, 0, eb->len);
81 ret = write_extent_to_disk(eb);
82 if (ret < 0) {
83 error("cannot write eb bytenr %llu: %s",
84 (unsigned long long)eb->dev_bytenr,
85 strerror(-ret));
86 return ret;
88 fsync(eb->fd);
91 num_copies = btrfs_num_copies(root->fs_info, eb->start,
92 eb->len);
93 if (num_copies == 1)
94 break;
96 mirror_num++;
97 if (mirror_num > num_copies)
98 break;
101 return 0;
104 static void print_usage(int ret)
106 printf("usage: btrfs-corrupt-block [options] device\n");
107 printf("\t-l Logical extent to be corrupted\n");
108 printf("\t-c Copy of the extent to be corrupted (usually 1 or 2, default: 0)\n");
109 printf("\t-b Number of bytes to be corrupted\n");
110 printf("\t-e Extent to be corrupted\n");
111 printf("\t-E The whole extent tree to be corrupted\n");
112 printf("\t-u Given chunk item to be corrupted\n");
113 printf("\t-U The whole chunk tree to be corrupted\n");
114 printf("\t-i The inode item to corrupt (must also specify the field to corrupt)\n");
115 printf("\t-x The file extent item to corrupt (must also specify -i for the inode and -f for the field to corrupt)\n");
116 printf("\t-m The metadata block to corrupt (must also specify -f for the field to corrupt)\n");
117 printf("\t-K <u64,u8,u64> Corrupt the given key (must also specify -f for the field and optionally -r for the root)\n");
118 printf("\t-f The field in the item to corrupt\n");
119 printf("\t-I <u64,u8,u64> Corrupt an item corresponding to the passed key triplet (must also specify the field to corrupt and root for the item)\n");
120 printf("\t-D <u64,u8,u64> Corrupt a dir item corresponding to the passed key triplet, must also specify a field\n");
121 printf("\t-d <u64,u8,u64> Delete item corresponding to passed key triplet\n");
122 printf("\t-r Operate on this root (only works with -d)\n");
123 printf("\t-C Delete a csum for the specified bytenr. When used with -b it'll delete that many bytes, otherwise it's just sectorsize\n");
124 exit(ret);
127 static void corrupt_keys(struct btrfs_trans_handle *trans,
128 struct btrfs_fs_info *fs_info,
129 struct extent_buffer *eb)
131 int slot;
132 int bad_slot;
133 int nr;
134 struct btrfs_disk_key bad_key;;
136 nr = btrfs_header_nritems(eb);
137 if (nr == 0)
138 return;
140 slot = rand_range(nr);
141 bad_slot = rand_range(nr);
143 if (bad_slot == slot)
144 return;
146 fprintf(stderr,
147 "corrupting keys in block %llu slot %d swapping with %d\n",
148 (unsigned long long)eb->start, slot, bad_slot);
150 if (btrfs_header_level(eb) == 0) {
151 btrfs_item_key(eb, &bad_key, bad_slot);
152 btrfs_set_item_key(eb, &bad_key, slot);
153 } else {
154 btrfs_node_key(eb, &bad_key, bad_slot);
155 btrfs_set_node_key(eb, &bad_key, slot);
157 btrfs_mark_buffer_dirty(eb);
158 if (!trans) {
159 u16 csum_size =
160 btrfs_super_csum_size(fs_info->super_copy);
161 csum_tree_block_size(eb, csum_size, 0);
162 write_extent_to_disk(eb);
167 static int corrupt_keys_in_block(struct btrfs_fs_info *fs_info, u64 bytenr)
169 struct extent_buffer *eb;
171 eb = read_tree_block(fs_info, bytenr, 0);
172 if (!extent_buffer_uptodate(eb))
173 return -EIO;;
175 corrupt_keys(NULL, fs_info, eb);
176 free_extent_buffer(eb);
177 return 0;
180 static int corrupt_extent(struct btrfs_trans_handle *trans,
181 struct btrfs_root *root, u64 bytenr)
183 struct btrfs_key key;
184 struct extent_buffer *leaf;
185 u32 item_size;
186 unsigned long ptr;
187 struct btrfs_path *path;
188 int ret;
189 int slot;
190 int should_del = rand_range(3);
192 path = btrfs_alloc_path();
193 if (!path)
194 return -ENOMEM;
196 key.objectid = bytenr;
197 key.type = (u8)-1;
198 key.offset = (u64)-1;
200 while(1) {
201 ret = btrfs_search_slot(trans, root->fs_info->extent_root,
202 &key, path, -1, 1);
203 if (ret < 0)
204 break;
206 if (ret > 0) {
207 if (path->slots[0] == 0)
208 break;
209 path->slots[0]--;
210 ret = 0;
212 leaf = path->nodes[0];
213 slot = path->slots[0];
214 btrfs_item_key_to_cpu(leaf, &key, slot);
215 if (key.objectid != bytenr)
216 break;
218 if (key.type != BTRFS_EXTENT_ITEM_KEY &&
219 key.type != BTRFS_METADATA_ITEM_KEY &&
220 key.type != BTRFS_TREE_BLOCK_REF_KEY &&
221 key.type != BTRFS_EXTENT_DATA_REF_KEY &&
222 key.type != BTRFS_EXTENT_REF_V0_KEY &&
223 key.type != BTRFS_SHARED_BLOCK_REF_KEY &&
224 key.type != BTRFS_SHARED_DATA_REF_KEY)
225 goto next;
227 if (should_del) {
228 fprintf(stderr,
229 "deleting extent record: key %llu %u %llu\n",
230 key.objectid, key.type, key.offset);
232 if (key.type == BTRFS_EXTENT_ITEM_KEY) {
233 /* make sure this extent doesn't get
234 * reused for other purposes */
235 btrfs_pin_extent(root->fs_info,
236 key.objectid, key.offset);
239 btrfs_del_item(trans, root, path);
240 } else {
241 fprintf(stderr,
242 "corrupting extent record: key %llu %u %llu\n",
243 key.objectid, key.type, key.offset);
244 ptr = btrfs_item_ptr_offset(leaf, slot);
245 item_size = btrfs_item_size_nr(leaf, slot);
246 memset_extent_buffer(leaf, 0, ptr, item_size);
247 btrfs_mark_buffer_dirty(leaf);
249 next:
250 btrfs_release_path(path);
252 if (key.offset > 0)
253 key.offset--;
254 if (key.offset == 0)
255 break;
258 btrfs_free_path(path);
259 return 0;
262 static void btrfs_corrupt_extent_leaf(struct btrfs_trans_handle *trans,
263 struct btrfs_root *root,
264 struct extent_buffer *eb)
266 u32 nr = btrfs_header_nritems(eb);
267 u32 victim = rand_range(nr);
268 u64 objectid;
269 struct btrfs_key key;
271 btrfs_item_key_to_cpu(eb, &key, victim);
272 objectid = key.objectid;
273 corrupt_extent(trans, root, objectid);
276 static void btrfs_corrupt_extent_tree(struct btrfs_trans_handle *trans,
277 struct btrfs_root *root,
278 struct extent_buffer *eb)
280 struct btrfs_fs_info *fs_info = root->fs_info;
281 int i;
283 if (!eb)
284 return;
286 if (btrfs_is_leaf(eb)) {
287 btrfs_corrupt_extent_leaf(trans, root, eb);
288 return;
291 if (btrfs_header_level(eb) == 1 && eb != root->node) {
292 if (rand_range(5))
293 return;
296 for (i = 0; i < btrfs_header_nritems(eb); i++) {
297 struct extent_buffer *next;
299 next = read_tree_block(fs_info, btrfs_node_blockptr(eb, i),
300 btrfs_node_ptr_generation(eb, i));
301 if (!extent_buffer_uptodate(next))
302 continue;
303 btrfs_corrupt_extent_tree(trans, root, next);
304 free_extent_buffer(next);
308 enum btrfs_inode_field {
309 BTRFS_INODE_FIELD_ISIZE,
310 BTRFS_INODE_FIELD_NBYTES,
311 BTRFS_INODE_FIELD_NLINK,
312 BTRFS_INODE_FIELD_GENERATION,
313 BTRFS_INODE_FIELD_TRANSID,
314 BTRFS_INODE_FIELD_BLOCK_GROUP,
315 BTRFS_INODE_FIELD_MODE,
316 BTRFS_INODE_FIELD_UID,
317 BTRFS_INODE_FIELD_GID,
318 BTRFS_INODE_FIELD_BAD,
321 enum btrfs_file_extent_field {
322 BTRFS_FILE_EXTENT_DISK_BYTENR,
323 BTRFS_FILE_EXTENT_BAD,
326 enum btrfs_dir_item_field {
327 BTRFS_DIR_ITEM_NAME,
328 BTRFS_DIR_ITEM_LOCATION_OBJECTID,
329 BTRFS_DIR_ITEM_BAD,
332 enum btrfs_metadata_block_field {
333 BTRFS_METADATA_BLOCK_GENERATION,
334 BTRFS_METADATA_BLOCK_SHIFT_ITEMS,
335 BTRFS_METADATA_BLOCK_BAD,
338 enum btrfs_item_field {
339 BTRFS_ITEM_OFFSET,
340 BTRFS_ITEM_BAD,
343 enum btrfs_key_field {
344 BTRFS_KEY_OBJECTID,
345 BTRFS_KEY_TYPE,
346 BTRFS_KEY_OFFSET,
347 BTRFS_KEY_BAD,
350 static enum btrfs_inode_field convert_inode_field(char *field)
352 if (!strncmp(field, "isize", FIELD_BUF_LEN))
353 return BTRFS_INODE_FIELD_ISIZE;
354 if (!strncmp(field, "nbytes", FIELD_BUF_LEN))
355 return BTRFS_INODE_FIELD_NBYTES;
356 if (!strncmp(field, "nlink", FIELD_BUF_LEN))
357 return BTRFS_INODE_FIELD_NLINK;
358 if (!strncmp(field, "generation", FIELD_BUF_LEN))
359 return BTRFS_INODE_FIELD_GENERATION;
360 if (!strncmp(field, "transid", FIELD_BUF_LEN))
361 return BTRFS_INODE_FIELD_TRANSID;
362 if (!strncmp(field, "block_group", FIELD_BUF_LEN))
363 return BTRFS_INODE_FIELD_BLOCK_GROUP;
364 if (!strncmp(field, "mode", FIELD_BUF_LEN))
365 return BTRFS_INODE_FIELD_MODE;
366 if (!strncmp(field, "uid", FIELD_BUF_LEN))
367 return BTRFS_INODE_FIELD_UID;
368 if (!strncmp(field, "gid", FIELD_BUF_LEN))
369 return BTRFS_INODE_FIELD_GID;
370 return BTRFS_INODE_FIELD_BAD;
373 static enum btrfs_file_extent_field convert_file_extent_field(char *field)
375 if (!strncmp(field, "disk_bytenr", FIELD_BUF_LEN))
376 return BTRFS_FILE_EXTENT_DISK_BYTENR;
377 return BTRFS_FILE_EXTENT_BAD;
380 static enum btrfs_metadata_block_field
381 convert_metadata_block_field(char *field)
383 if (!strncmp(field, "generation", FIELD_BUF_LEN))
384 return BTRFS_METADATA_BLOCK_GENERATION;
385 if (!strncmp(field, "shift_items", FIELD_BUF_LEN))
386 return BTRFS_METADATA_BLOCK_SHIFT_ITEMS;
387 return BTRFS_METADATA_BLOCK_BAD;
390 static enum btrfs_key_field convert_key_field(char *field)
392 if (!strncmp(field, "objectid", FIELD_BUF_LEN))
393 return BTRFS_KEY_OBJECTID;
394 if (!strncmp(field, "type", FIELD_BUF_LEN))
395 return BTRFS_KEY_TYPE;
396 if (!strncmp(field, "offset", FIELD_BUF_LEN))
397 return BTRFS_KEY_OFFSET;
398 return BTRFS_KEY_BAD;
401 static enum btrfs_item_field convert_item_field(char *field)
403 if (!strncmp(field, "offset", FIELD_BUF_LEN))
404 return BTRFS_ITEM_OFFSET;
405 return BTRFS_ITEM_BAD;
408 static enum btrfs_dir_item_field convert_dir_item_field(char *field)
410 if (!strncmp(field, "name", FIELD_BUF_LEN))
411 return BTRFS_DIR_ITEM_NAME;
412 if (!strncmp(field, "location_objectid", FIELD_BUF_LEN))
413 return BTRFS_DIR_ITEM_LOCATION_OBJECTID;
414 return BTRFS_DIR_ITEM_BAD;
417 static u64 generate_u64(u64 orig)
419 u64 ret;
420 do {
421 ret = rand_u64();
422 } while (ret == orig);
423 return ret;
426 static u32 generate_u32(u32 orig)
428 u32 ret;
429 do {
430 ret = rand_u32();
431 } while (ret == orig);
432 return ret;
435 static u8 generate_u8(u8 orig)
437 u8 ret;
438 do {
439 ret = rand_u8();
440 } while (ret == orig);
441 return ret;
444 static int corrupt_key(struct btrfs_root *root, struct btrfs_key *key,
445 char *field)
447 enum btrfs_key_field corrupt_field = convert_key_field(field);
448 struct btrfs_path *path;
449 struct btrfs_trans_handle *trans;
450 int ret;
452 if (corrupt_field == BTRFS_KEY_BAD) {
453 fprintf(stderr, "Invalid field %s\n", field);
454 return -EINVAL;
457 path = btrfs_alloc_path();
458 if (!path)
459 return -ENOMEM;
461 trans = btrfs_start_transaction(root, 1);
462 if (IS_ERR(trans)) {
463 btrfs_free_path(path);
464 return PTR_ERR(trans);
467 ret = btrfs_search_slot(trans, root, key, path, 0, 1);
468 if (ret < 0)
469 goto out;
470 if (ret > 0) {
471 fprintf(stderr, "Couldn't find the key to corrupt\n");
472 ret = -ENOENT;
473 goto out;
476 switch (corrupt_field) {
477 case BTRFS_KEY_OBJECTID:
478 key->objectid = generate_u64(key->objectid);
479 break;
480 case BTRFS_KEY_TYPE:
481 key->type = generate_u8(key->type);
482 break;
483 case BTRFS_KEY_OFFSET:
484 key->offset = generate_u64(key->objectid);
485 break;
486 default:
487 fprintf(stderr, "Invalid field %s, %d\n", field,
488 corrupt_field);
489 ret = -EINVAL;
490 goto out;
493 btrfs_set_item_key_unsafe(root, path, key);
494 out:
495 btrfs_free_path(path);
496 btrfs_commit_transaction(trans, root);
497 return ret;
500 static int corrupt_dir_item(struct btrfs_root *root, struct btrfs_key *key,
501 char *field)
503 struct btrfs_trans_handle *trans;
504 struct btrfs_dir_item *di;
505 struct btrfs_path *path;
506 char name[PATH_MAX];
507 struct btrfs_key location;
508 struct btrfs_disk_key disk_key;
509 unsigned long name_ptr;
510 enum btrfs_dir_item_field corrupt_field =
511 convert_dir_item_field(field);
512 u64 bogus;
513 u16 name_len;
514 int ret;
516 if (corrupt_field == BTRFS_DIR_ITEM_BAD) {
517 fprintf(stderr, "Invalid field %s\n", field);
518 return -EINVAL;
521 path = btrfs_alloc_path();
522 if (!path)
523 return -ENOMEM;
525 trans = btrfs_start_transaction(root, 1);
526 if (IS_ERR(trans)) {
527 btrfs_free_path(path);
528 return PTR_ERR(trans);
531 ret = btrfs_search_slot(trans, root, key, path, 0, 1);
532 if (ret) {
533 if (ret > 0)
534 ret = -ENOENT;
535 fprintf(stderr, "Error searching for dir item %d\n", ret);
536 goto out;
539 di = btrfs_item_ptr(path->nodes[0], path->slots[0],
540 struct btrfs_dir_item);
542 switch (corrupt_field) {
543 case BTRFS_DIR_ITEM_NAME:
544 name_len = btrfs_dir_name_len(path->nodes[0], di);
545 name_ptr = (unsigned long)(di + 1);
546 read_extent_buffer(path->nodes[0], name, name_ptr, name_len);
547 name[0]++;
548 write_extent_buffer(path->nodes[0], name, name_ptr, name_len);
549 btrfs_mark_buffer_dirty(path->nodes[0]);
550 goto out;
551 case BTRFS_DIR_ITEM_LOCATION_OBJECTID:
552 btrfs_dir_item_key_to_cpu(path->nodes[0], di, &location);
553 bogus = generate_u64(location.objectid);
554 location.objectid = bogus;
555 btrfs_cpu_key_to_disk(&disk_key, &location);
556 btrfs_set_dir_item_key(path->nodes[0], di, &disk_key);
557 btrfs_mark_buffer_dirty(path->nodes[0]);
558 goto out;
559 default:
560 ret = -EINVAL;
561 goto out;
563 out:
564 btrfs_commit_transaction(trans, root);
565 btrfs_free_path(path);
566 return ret;
569 static int corrupt_inode(struct btrfs_trans_handle *trans,
570 struct btrfs_root *root, u64 inode, char *field)
572 struct btrfs_inode_item *ei;
573 struct btrfs_path *path;
574 struct btrfs_key key;
575 enum btrfs_inode_field corrupt_field = convert_inode_field(field);
576 u64 bogus;
577 u64 orig;
578 int ret;
580 if (corrupt_field == BTRFS_INODE_FIELD_BAD) {
581 fprintf(stderr, "Invalid field %s\n", field);
582 return -EINVAL;
585 key.objectid = inode;
586 key.type = BTRFS_INODE_ITEM_KEY;
587 key.offset = (u64)-1;
589 path = btrfs_alloc_path();
590 if (!path)
591 return -ENOMEM;
593 ret = btrfs_search_slot(trans, root, &key, path, 0, 1);
594 if (ret < 0)
595 goto out;
596 if (ret) {
597 if (!path->slots[0]) {
598 fprintf(stderr, "Couldn't find inode %Lu\n", inode);
599 ret = -ENOENT;
600 goto out;
602 path->slots[0]--;
603 ret = 0;
606 btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
607 if (key.objectid != inode) {
608 fprintf(stderr, "Couldn't find inode %Lu\n", inode);
609 ret = -ENOENT;
610 goto out;
613 ei = btrfs_item_ptr(path->nodes[0], path->slots[0],
614 struct btrfs_inode_item);
615 switch (corrupt_field) {
616 case BTRFS_INODE_FIELD_ISIZE:
617 orig = btrfs_inode_size(path->nodes[0], ei);
618 bogus = generate_u64(orig);
619 btrfs_set_inode_size(path->nodes[0], ei, bogus);
620 break;
621 case BTRFS_INODE_FIELD_NBYTES:
622 orig = btrfs_inode_nbytes(path->nodes[0], ei);
623 bogus = generate_u64(orig);
624 btrfs_set_inode_nbytes(path->nodes[0], ei, bogus);
625 break;
626 case BTRFS_INODE_FIELD_NLINK:
627 orig = btrfs_inode_nlink(path->nodes[0], ei);
628 bogus = generate_u32(orig);
629 btrfs_set_inode_nlink(path->nodes[0], ei, bogus);
630 break;
631 case BTRFS_INODE_FIELD_GENERATION:
632 orig = btrfs_inode_generation(path->nodes[0], ei);
633 bogus = generate_u64(orig);
634 btrfs_set_inode_generation(path->nodes[0], ei, bogus);
635 break;
636 case BTRFS_INODE_FIELD_TRANSID:
637 orig = btrfs_inode_transid(path->nodes[0], ei);
638 bogus = generate_u64(orig);
639 btrfs_set_inode_transid(path->nodes[0], ei, bogus);
640 break;
641 case BTRFS_INODE_FIELD_BLOCK_GROUP:
642 orig = btrfs_inode_block_group(path->nodes[0], ei);
643 bogus = generate_u64(orig);
644 btrfs_set_inode_block_group(path->nodes[0], ei, bogus);
645 break;
646 case BTRFS_INODE_FIELD_MODE:
647 orig = btrfs_inode_mode(path->nodes[0], ei);
648 bogus = generate_u32(orig);
649 btrfs_set_inode_mode(path->nodes[0], ei, bogus);
650 break;
651 case BTRFS_INODE_FIELD_UID:
652 orig = btrfs_inode_uid(path->nodes[0], ei);
653 bogus = generate_u32(orig);
654 btrfs_set_inode_uid(path->nodes[0], ei, bogus);
655 break;
656 case BTRFS_INODE_FIELD_GID:
657 orig = btrfs_inode_gid(path->nodes[0], ei);
658 bogus = generate_u32(orig);
659 btrfs_set_inode_gid(path->nodes[0], ei, bogus);
660 break;
661 default:
662 ret = -EINVAL;
663 break;
665 btrfs_mark_buffer_dirty(path->nodes[0]);
666 out:
667 btrfs_free_path(path);
668 return ret;
671 static int corrupt_file_extent(struct btrfs_trans_handle *trans,
672 struct btrfs_root *root, u64 inode, u64 extent,
673 char *field)
675 struct btrfs_file_extent_item *fi;
676 struct btrfs_path *path;
677 struct btrfs_key key;
678 enum btrfs_file_extent_field corrupt_field;
679 u64 bogus;
680 u64 orig;
681 int ret = 0;
683 corrupt_field = convert_file_extent_field(field);
684 if (corrupt_field == BTRFS_FILE_EXTENT_BAD) {
685 fprintf(stderr, "Invalid field %s\n", field);
686 return -EINVAL;
689 key.objectid = inode;
690 key.type = BTRFS_EXTENT_DATA_KEY;
691 key.offset = extent;
693 path = btrfs_alloc_path();
694 if (!path)
695 return -ENOMEM;
697 ret = btrfs_search_slot(trans, root, &key, path, 0, 1);
698 if (ret < 0)
699 goto out;
700 if (ret) {
701 fprintf(stderr, "Couldn't find extent %llu for inode %llu\n",
702 extent, inode);
703 ret = -ENOENT;
704 goto out;
707 fi = btrfs_item_ptr(path->nodes[0], path->slots[0],
708 struct btrfs_file_extent_item);
709 switch (corrupt_field) {
710 case BTRFS_FILE_EXTENT_DISK_BYTENR:
711 orig = btrfs_file_extent_disk_bytenr(path->nodes[0], fi);
712 bogus = generate_u64(orig);
713 btrfs_set_file_extent_disk_bytenr(path->nodes[0], fi, bogus);
714 break;
715 default:
716 ret = -EINVAL;
717 break;
719 btrfs_mark_buffer_dirty(path->nodes[0]);
720 out:
721 btrfs_free_path(path);
722 return ret;
725 static void shift_items(struct btrfs_root *root, struct extent_buffer *eb)
727 int nritems = btrfs_header_nritems(eb);
728 int shift_space = btrfs_leaf_free_space(eb) / 2;
729 int slot = nritems / 2;
730 int i = 0;
731 unsigned int data_end = btrfs_item_offset_nr(eb, nritems - 1);
733 /* Shift the item data up to and including slot back by shift space */
734 memmove_extent_buffer(eb, btrfs_leaf_data(eb) + data_end - shift_space,
735 btrfs_leaf_data(eb) + data_end,
736 btrfs_item_offset_nr(eb, slot - 1) - data_end);
738 /* Now update the item pointers. */
739 for (i = nritems - 1; i >= slot; i--) {
740 u32 offset = btrfs_item_offset_nr(eb, i);
741 offset -= shift_space;
742 btrfs_set_item_offset(eb, btrfs_item_nr(i), offset);
746 static int corrupt_metadata_block(struct btrfs_fs_info *fs_info, u64 block,
747 char *field)
749 struct btrfs_trans_handle *trans;
750 struct btrfs_root *root;
751 struct btrfs_path *path;
752 struct extent_buffer *eb;
753 struct btrfs_key key, root_key;
754 enum btrfs_metadata_block_field corrupt_field;
755 u64 root_objectid;
756 u64 orig, bogus;
757 u8 level;
758 int ret;
760 corrupt_field = convert_metadata_block_field(field);
761 if (corrupt_field == BTRFS_METADATA_BLOCK_BAD) {
762 fprintf(stderr, "Invalid field %s\n", field);
763 return -EINVAL;
766 eb = read_tree_block(fs_info, block, 0);
767 if (!extent_buffer_uptodate(eb)) {
768 fprintf(stderr, "Couldn't read in tree block %s\n", field);
769 return -EINVAL;
771 root_objectid = btrfs_header_owner(eb);
772 level = btrfs_header_level(eb);
773 if (level)
774 btrfs_node_key_to_cpu(eb, &key, 0);
775 else
776 btrfs_item_key_to_cpu(eb, &key, 0);
777 free_extent_buffer(eb);
779 root_key.objectid = root_objectid;
780 root_key.type = BTRFS_ROOT_ITEM_KEY;
781 root_key.offset = (u64)-1;
783 root = btrfs_read_fs_root(fs_info, &root_key);
784 if (IS_ERR(root)) {
785 fprintf(stderr, "Couldn't find owner root %llu\n",
786 key.objectid);
787 return PTR_ERR(root);
790 path = btrfs_alloc_path();
791 if (!path)
792 return -ENOMEM;
794 trans = btrfs_start_transaction(root, 1);
795 if (IS_ERR(trans)) {
796 btrfs_free_path(path);
797 fprintf(stderr, "Couldn't start transaction %ld\n",
798 PTR_ERR(trans));
799 return PTR_ERR(trans);
802 path->lowest_level = level;
803 ret = btrfs_search_slot(trans, root, &key, path, 0, 1);
804 if (ret < 0) {
805 fprintf(stderr, "Error searching to node %d\n", ret);
806 goto out;
808 eb = path->nodes[level];
810 ret = 0;
811 switch (corrupt_field) {
812 case BTRFS_METADATA_BLOCK_GENERATION:
813 orig = btrfs_header_generation(eb);
814 bogus = generate_u64(orig);
815 btrfs_set_header_generation(eb, bogus);
816 break;
817 case BTRFS_METADATA_BLOCK_SHIFT_ITEMS:
818 shift_items(root, path->nodes[level]);
819 break;
820 default:
821 ret = -EINVAL;
822 break;
824 btrfs_mark_buffer_dirty(path->nodes[level]);
825 out:
826 btrfs_commit_transaction(trans, root);
827 btrfs_free_path(path);
828 return ret;
831 static int corrupt_btrfs_item(struct btrfs_root *root, struct btrfs_key *key,
832 char *field)
834 struct btrfs_trans_handle *trans;
835 struct btrfs_path *path;
836 enum btrfs_item_field corrupt_field;
837 u32 orig, bogus;
838 int ret;
840 corrupt_field = convert_item_field(field);
841 if (corrupt_field == BTRFS_ITEM_BAD) {
842 fprintf(stderr, "Invalid field %s\n", field);
843 return -EINVAL;
846 path = btrfs_alloc_path();
847 if (!path)
848 return -ENOMEM;
850 trans = btrfs_start_transaction(root, 1);
851 if (IS_ERR(trans)) {
852 btrfs_free_path(path);
853 fprintf(stderr, "Couldn't start transaction %ld\n",
854 PTR_ERR(trans));
855 return PTR_ERR(trans);
858 ret = btrfs_search_slot(trans, root, key, path, 0, 1);
859 if (ret != 0) {
860 fprintf(stderr, "Error searching to node %d\n", ret);
861 goto out;
864 ret = 0;
865 switch (corrupt_field) {
866 case BTRFS_ITEM_OFFSET:
867 orig = btrfs_item_offset_nr(path->nodes[0], path->slots[0]);
868 bogus = generate_u32(orig);
869 btrfs_set_item_offset(path->nodes[0],
870 btrfs_item_nr(path->slots[0]), bogus);
871 break;
872 default:
873 ret = -EINVAL;
874 break;
876 btrfs_mark_buffer_dirty(path->nodes[0]);
877 out:
878 btrfs_commit_transaction(trans, root);
879 btrfs_free_path(path);
880 return ret;
883 static int delete_item(struct btrfs_root *root, struct btrfs_key *key)
885 struct btrfs_trans_handle *trans;
886 struct btrfs_path *path;
887 int ret;
889 path = btrfs_alloc_path();
890 if (!path)
891 return -ENOMEM;
893 trans = btrfs_start_transaction(root, 1);
894 if (IS_ERR(trans)) {
895 btrfs_free_path(path);
896 fprintf(stderr, "Couldn't start transaction %ld\n",
897 PTR_ERR(trans));
898 return PTR_ERR(trans);
901 ret = btrfs_search_slot(trans, root, key, path, -1, 1);
902 if (ret) {
903 if (ret > 0)
904 ret = -ENOENT;
905 fprintf(stderr, "Error searching to node %d\n", ret);
906 goto out;
908 ret = btrfs_del_item(trans, root, path);
909 btrfs_mark_buffer_dirty(path->nodes[0]);
910 out:
911 btrfs_commit_transaction(trans, root);
912 btrfs_free_path(path);
913 return ret;
916 static int delete_csum(struct btrfs_root *root, u64 bytenr, u64 bytes)
918 struct btrfs_trans_handle *trans;
919 int ret;
921 root = root->fs_info->csum_root;
922 trans = btrfs_start_transaction(root, 1);
923 if (IS_ERR(trans)) {
924 fprintf(stderr, "Couldn't start transaction %ld\n",
925 PTR_ERR(trans));
926 return PTR_ERR(trans);
929 ret = btrfs_del_csums(trans, bytenr, bytes);
930 if (ret)
931 fprintf(stderr, "Error deleting csums %d\n", ret);
932 btrfs_commit_transaction(trans, root);
933 return ret;
936 /* corrupt item using NO cow.
937 * Because chunk recover will recover based on whole partition scanning,
938 * If using COW, chunk recover will use the old item to recover,
939 * which is still OK but we want to check the ability to rebuild chunk
940 * not only restore the old ones */
941 static int corrupt_item_nocow(struct btrfs_trans_handle *trans,
942 struct btrfs_root *root, struct btrfs_path *path,
943 int del)
945 int ret = 0;
946 struct btrfs_key key;
947 struct extent_buffer *leaf;
948 unsigned long ptr;
949 int slot;
950 u32 item_size;
952 leaf = path->nodes[0];
953 slot = path->slots[0];
954 /* Not deleting the first item of a leaf to keep leaf structure */
955 if (slot == 0)
956 del = 0;
957 /* Only accept valid eb */
958 if (slot >= btrfs_header_nritems(leaf)) {
959 error("invalid eb: no data or slot out of range: %d >= %d",
960 slot, btrfs_header_nritems(leaf));
961 return -EINVAL;
963 btrfs_item_key_to_cpu(leaf, &key, slot);
964 if (del) {
965 fprintf(stdout, "Deleting key and data [%llu, %u, %llu].\n",
966 key.objectid, key.type, key.offset);
967 btrfs_del_item(trans, root, path);
968 } else {
969 fprintf(stdout, "Corrupting key and data [%llu, %u, %llu].\n",
970 key.objectid, key.type, key.offset);
971 ptr = btrfs_item_ptr_offset(leaf, slot);
972 item_size = btrfs_item_size_nr(leaf, slot);
973 memset_extent_buffer(leaf, 0, ptr, item_size);
974 btrfs_mark_buffer_dirty(leaf);
976 return ret;
978 static int corrupt_chunk_tree(struct btrfs_trans_handle *trans,
979 struct btrfs_root *root)
981 int ret;
982 int del;
983 int slot;
984 struct btrfs_path *path;
985 struct btrfs_key key;
986 struct btrfs_key found_key;
987 struct extent_buffer *leaf;
989 path = btrfs_alloc_path();
990 if (!path)
991 return -ENOMEM;
993 key.objectid = (u64)-1;
994 key.offset = (u64)-1;
995 key.type = (u8)-1;
997 /* Here, cow and ins_len must equals 0 for the following reasons:
998 * 1) chunk recover is based on disk scanning, so COW should be
999 * disabled in case the original chunk being scanned and
1000 * recovered using the old chunk.
1001 * 2) if cow = 0, ins_len must also be set to 0, or BUG_ON will be
1002 * triggered.
1004 ret = btrfs_search_slot(trans, root, &key, path, 0, 0);
1005 BUG_ON(ret == 0);
1006 if (ret < 0) {
1007 fprintf(stderr, "Error searching tree\n");
1008 goto free_out;
1010 /* corrupt/del dev_item first */
1011 while (!btrfs_previous_item(root, path, 0, BTRFS_DEV_ITEM_KEY)) {
1012 slot = path->slots[0];
1013 leaf = path->nodes[0];
1014 del = rand_range(3);
1015 /* Never delete the first item to keep the leaf structure */
1016 if (path->slots[0] == 0)
1017 del = 0;
1018 ret = corrupt_item_nocow(trans, root, path, del);
1019 if (ret)
1020 goto free_out;
1022 btrfs_release_path(path);
1024 /* Here, cow and ins_len must equals 0 for the following reasons:
1025 * 1) chunk recover is based on disk scanning, so COW should be
1026 * disabled in case the original chunk being scanned and
1027 * recovered using the old chunk.
1028 * 2) if cow = 0, ins_len must also be set to 0, or BUG_ON will be
1029 * triggered.
1031 ret = btrfs_search_slot(trans, root, &key, path, 0, 0);
1032 BUG_ON(ret == 0);
1033 if (ret < 0) {
1034 fprintf(stderr, "Error searching tree\n");
1035 goto free_out;
1037 /* corrupt/del chunk then*/
1038 while (!btrfs_previous_item(root, path, 0, BTRFS_CHUNK_ITEM_KEY)) {
1039 slot = path->slots[0];
1040 leaf = path->nodes[0];
1041 del = rand_range(3);
1042 btrfs_item_key_to_cpu(leaf, &found_key, slot);
1043 ret = corrupt_item_nocow(trans, root, path, del);
1044 if (ret)
1045 goto free_out;
1047 free_out:
1048 btrfs_free_path(path);
1049 return ret;
1051 static int find_chunk_offset(struct btrfs_root *root,
1052 struct btrfs_path *path, u64 offset)
1054 struct btrfs_key key;
1055 int ret;
1057 key.objectid = BTRFS_FIRST_CHUNK_TREE_OBJECTID;
1058 key.type = BTRFS_CHUNK_ITEM_KEY;
1059 key.offset = offset;
1061 /* Here, cow and ins_len must equals 0 for following reasons:
1062 * 1) chunk recover is based on disk scanning, so COW should
1063 * be disabled in case the original chunk being scanned
1064 * and recovered using the old chunk.
1065 * 2) if cow = 0, ins_len must also be set to 0, or BUG_ON
1066 * will be triggered.
1068 ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
1069 if (ret > 0) {
1070 fprintf(stderr, "Can't find chunk with given offset %llu\n",
1071 offset);
1072 goto out;
1074 if (ret < 0) {
1075 fprintf(stderr, "Error searching chunk\n");
1076 goto out;
1078 out:
1079 return ret;
1083 static void parse_key(u64 *objectid, u8 *type, u64 *offset)
1086 int ret = sscanf(optarg, "%llu,%hhu,%llu", objectid, type, offset);
1087 if (ret != 3) {
1088 fprintf(stderr, "error parsing key '%s': %d\n", optarg, errno);
1089 print_usage(1);
1093 static struct btrfs_root *open_root(struct btrfs_fs_info *fs_info,
1094 u64 root_objectid)
1097 struct btrfs_key root_key;
1098 struct btrfs_root *root;
1100 root_key.objectid = root_objectid;
1101 root_key.type = BTRFS_ROOT_ITEM_KEY;
1102 root_key.offset = (u64)-1;
1104 root = btrfs_read_fs_root(fs_info, &root_key);
1105 if (IS_ERR(root)) {
1106 fprintf(stderr, "couldn't find root %llu\n", root_objectid);
1107 print_usage(1);
1110 return root;
1112 int main(int argc, char **argv)
1114 struct cache_tree root_cache;
1115 struct btrfs_key key;
1116 struct btrfs_root *root, *target_root;
1117 char *dev;
1118 /* chunk offset can be 0,so change to (u64)-1 */
1119 u64 logical = (u64)-1;
1120 int ret = 0;
1121 u64 copy = 0;
1122 u64 bytes = 4096;
1123 int extent_rec = 0;
1124 int extent_tree = 0;
1125 int corrupt_block_keys = 0;
1126 int chunk_rec = 0;
1127 int chunk_tree = 0;
1128 int corrupt_item = 0;
1129 int corrupt_di = 0;
1130 int delete = 0;
1131 int should_corrupt_key = 0;
1132 u64 metadata_block = 0;
1133 u64 inode = 0;
1134 u64 file_extent = (u64)-1;
1135 u64 root_objectid = 0;
1136 u64 csum_bytenr = 0;
1137 char field[FIELD_BUF_LEN];
1139 field[0] = '\0';
1140 memset(&key, 0, sizeof(key));
1142 while(1) {
1143 int c;
1144 static const struct option long_options[] = {
1145 /* { "byte-count", 1, NULL, 'b' }, */
1146 { "logical", required_argument, NULL, 'l' },
1147 { "copy", required_argument, NULL, 'c' },
1148 { "bytes", required_argument, NULL, 'b' },
1149 { "extent-record", no_argument, NULL, 'e' },
1150 { "extent-tree", no_argument, NULL, 'E' },
1151 { "keys", no_argument, NULL, 'k' },
1152 { "chunk-record", no_argument, NULL, 'u' },
1153 { "chunk-tree", no_argument, NULL, 'U' },
1154 { "inode", required_argument, NULL, 'i'},
1155 { "file-extent", required_argument, NULL, 'x'},
1156 { "metadata-block", required_argument, NULL, 'm'},
1157 { "field", required_argument, NULL, 'f'},
1158 { "key", required_argument, NULL, 'K'},
1159 { "item", no_argument, NULL, 'I'},
1160 { "dir-item", no_argument, NULL, 'D'},
1161 { "delete", no_argument, NULL, 'd'},
1162 { "root", no_argument, NULL, 'r'},
1163 { "csum", required_argument, NULL, 'C'},
1164 { "help", no_argument, NULL, GETOPT_VAL_HELP},
1165 { NULL, 0, NULL, 0 }
1168 c = getopt_long(argc, argv, "l:c:b:eEkuUi:f:x:m:K:I:D:d:r:C:",
1169 long_options, NULL);
1170 if (c < 0)
1171 break;
1172 switch(c) {
1173 case 'l':
1174 logical = arg_strtou64(optarg);
1175 break;
1176 case 'c':
1177 copy = arg_strtou64(optarg);
1178 break;
1179 case 'b':
1180 bytes = arg_strtou64(optarg);
1181 break;
1182 case 'e':
1183 extent_rec = 1;
1184 break;
1185 case 'E':
1186 extent_tree = 1;
1187 break;
1188 case 'k':
1189 corrupt_block_keys = 1;
1190 break;
1191 case 'u':
1192 chunk_rec = 1;
1193 break;
1194 case 'U':
1195 chunk_tree = 1;
1196 break;
1197 case 'i':
1198 inode = arg_strtou64(optarg);
1199 break;
1200 case 'f':
1201 strncpy(field, optarg, FIELD_BUF_LEN);
1202 break;
1203 case 'x':
1204 file_extent = arg_strtou64(optarg);
1205 break;
1206 case 'm':
1207 metadata_block = arg_strtou64(optarg);
1208 break;
1209 case 'K':
1210 should_corrupt_key = 1;
1211 parse_key(&key.objectid, &key.type, &key.offset);
1212 break;
1213 case 'D':
1214 corrupt_di = 1;
1215 parse_key(&key.objectid, &key.type, &key.offset);
1216 break;
1217 case 'I':
1218 corrupt_item = 1;
1219 parse_key(&key.objectid, &key.type, &key.offset);
1220 break;
1221 case 'd':
1222 delete = 1;
1223 parse_key(&key.objectid, &key.type, &key.offset);
1224 break;
1225 case 'r':
1226 root_objectid = arg_strtou64(optarg);
1227 break;
1228 case 'C':
1229 csum_bytenr = arg_strtou64(optarg);
1230 break;
1231 case GETOPT_VAL_HELP:
1232 default:
1233 print_usage(c != GETOPT_VAL_HELP);
1236 set_argv0(argv);
1237 if (check_argc_min(argc - optind, 1))
1238 print_usage(1);
1239 dev = argv[optind];
1241 radix_tree_init();
1242 cache_tree_init(&root_cache);
1244 root = open_ctree(dev, 0, OPEN_CTREE_WRITES);
1245 if (!root) {
1246 fprintf(stderr, "Open ctree failed\n");
1247 exit(1);
1249 target_root = root;
1250 if (root_objectid)
1251 target_root = open_root(root->fs_info, root_objectid);
1253 if (extent_rec) {
1254 struct btrfs_trans_handle *trans;
1256 if (logical == (u64)-1)
1257 print_usage(1);
1258 trans = btrfs_start_transaction(root, 1);
1259 BUG_ON(IS_ERR(trans));
1260 ret = corrupt_extent(trans, root, logical);
1261 btrfs_commit_transaction(trans, root);
1262 goto out_close;
1264 if (extent_tree) {
1265 struct btrfs_trans_handle *trans;
1267 trans = btrfs_start_transaction(root, 1);
1268 BUG_ON(IS_ERR(trans));
1269 btrfs_corrupt_extent_tree(trans, root->fs_info->extent_root,
1270 root->fs_info->extent_root->node);
1271 btrfs_commit_transaction(trans, root);
1272 goto out_close;
1274 if (chunk_rec) {
1275 struct btrfs_trans_handle *trans;
1276 struct btrfs_path *path;
1277 int del;
1279 if (logical == (u64)-1)
1280 print_usage(1);
1281 del = rand_range(3);
1282 path = btrfs_alloc_path();
1283 if (!path) {
1284 fprintf(stderr, "path allocation failed\n");
1285 goto out_close;
1288 if (find_chunk_offset(root->fs_info->chunk_root, path,
1289 logical) != 0) {
1290 btrfs_free_path(path);
1291 goto out_close;
1293 trans = btrfs_start_transaction(root, 1);
1294 BUG_ON(IS_ERR(trans));
1295 ret = corrupt_item_nocow(trans, root->fs_info->chunk_root,
1296 path, del);
1297 if (ret < 0)
1298 fprintf(stderr, "Failed to corrupt chunk record\n");
1299 btrfs_commit_transaction(trans, root);
1300 goto out_close;
1302 if (chunk_tree) {
1303 struct btrfs_trans_handle *trans;
1305 trans = btrfs_start_transaction(root, 1);
1306 BUG_ON(IS_ERR(trans));
1307 ret = corrupt_chunk_tree(trans, root->fs_info->chunk_root);
1308 if (ret < 0)
1309 fprintf(stderr, "Failed to corrupt chunk tree\n");
1310 btrfs_commit_transaction(trans, root);
1311 goto out_close;
1313 if (inode) {
1314 struct btrfs_trans_handle *trans;
1316 if (*field == 0)
1317 print_usage(1);
1319 trans = btrfs_start_transaction(root, 1);
1320 BUG_ON(IS_ERR(trans));
1321 if (file_extent == (u64)-1) {
1322 printf("corrupting inode\n");
1323 ret = corrupt_inode(trans, root, inode, field);
1324 } else {
1325 printf("corrupting file extent\n");
1326 ret = corrupt_file_extent(trans, root, inode,
1327 file_extent, field);
1329 btrfs_commit_transaction(trans, root);
1330 goto out_close;
1332 if (metadata_block) {
1333 if (*field == 0)
1334 print_usage(1);
1335 ret = corrupt_metadata_block(root->fs_info, metadata_block,
1336 field);
1337 goto out_close;
1339 if (corrupt_di) {
1340 if (!key.objectid || *field == 0)
1341 print_usage(1);
1342 ret = corrupt_dir_item(target_root, &key, field);
1343 goto out_close;
1345 if (csum_bytenr) {
1346 ret = delete_csum(root, csum_bytenr, bytes);
1347 goto out_close;
1349 if (corrupt_item) {
1350 if (!key.objectid)
1351 print_usage(1);
1352 if (!root_objectid)
1353 print_usage(1);
1355 ret = corrupt_btrfs_item(target_root, &key, field);
1356 goto out_close;
1358 if (delete) {
1359 if (!key.objectid)
1360 print_usage(1);
1362 ret = delete_item(target_root, &key);
1363 goto out_close;
1365 if (should_corrupt_key) {
1366 if (*field == 0)
1367 print_usage(1);
1369 ret = corrupt_key(target_root, &key, field);
1370 goto out_close;
1373 * If we made it here and we have extent set then we didn't specify
1374 * inode and we're screwed.
1376 if (file_extent != (u64)-1)
1377 print_usage(1);
1379 if (logical == (u64)-1)
1380 print_usage(1);
1382 if (bytes == 0)
1383 bytes = root->fs_info->sectorsize;
1385 bytes = round_up(bytes, root->fs_info->sectorsize);
1387 while (bytes > 0) {
1388 if (corrupt_block_keys) {
1389 corrupt_keys_in_block(root->fs_info, logical);
1390 } else {
1391 struct extent_buffer *eb;
1393 eb = btrfs_find_create_tree_block(root->fs_info,
1394 logical);
1395 if (!eb) {
1396 error(
1397 "not enough memory to allocate extent buffer for bytenr %llu",
1398 (unsigned long long)logical);
1399 ret = 1;
1400 goto out_close;
1403 debug_corrupt_block(eb, root, logical,
1404 root->fs_info->sectorsize, copy);
1405 free_extent_buffer(eb);
1407 logical += root->fs_info->sectorsize;
1408 bytes -= root->fs_info->sectorsize;
1410 return ret;
1411 out_close:
1412 close_ctree(root);
1413 return ret;