X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=btrfs-corrupt-block.c;h=6eb04a7fb9a2109c4c687991d48529cb2a9c108f;hb=f802f572b1cb1d33bab9747e87e6506b284546cf;hp=64f515ecd1c5616c9e432bbd12d92750e6ee15ee;hpb=2b7cdab42529bc4ed4c36a3659504e50f0ef700c;p=platform%2Fupstream%2Fbtrfs-progs.git diff --git a/btrfs-corrupt-block.c b/btrfs-corrupt-block.c index 64f515e..6eb04a7 100644 --- a/btrfs-corrupt-block.c +++ b/btrfs-corrupt-block.c @@ -16,13 +16,12 @@ * Boston, MA 021110-1307, USA. */ -#define _XOPEN_SOURCE 500 -#define _GNU_SOURCE 1 #include #include #include #include #include + #include "kerncompat.h" #include "ctree.h" #include "volumes.h" @@ -30,7 +29,6 @@ #include "print-tree.h" #include "transaction.h" #include "list.h" -#include "version.h" #include "utils.h" #define FIELD_BUF_LEN 80 @@ -88,7 +86,7 @@ struct extent_buffer *debug_corrupt_block(struct btrfs_root *root, u64 bytenr, return eb; } -static void print_usage(void) +static void print_usage(int ret) { fprintf(stderr, "usage: btrfs-corrupt-block [options] device\n"); fprintf(stderr, "\t-l Logical extent to be corrupted\n"); @@ -112,7 +110,11 @@ static void print_usage(void) "to corrupt and a root+key for the item)\n"); fprintf(stderr, "\t-D Corrupt a dir item, must specify key and field\n"); fprintf(stderr, "\t-d Delete this item (must specify -K)\n"); - exit(1); + fprintf(stderr, "\t-r Operate on this root (only works with -d)\n"); + fprintf(stderr, "\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"); + exit(ret); } static void corrupt_keys(struct btrfs_trans_handle *trans, @@ -160,7 +162,7 @@ static int corrupt_keys_in_block(struct btrfs_root *root, u64 bytenr) struct extent_buffer *eb; eb = read_tree_block(root, bytenr, root->leafsize, 0); - if (!eb) + if (!extent_buffer_uptodate(eb)) return -EIO;; corrupt_keys(NULL, root, eb); @@ -288,7 +290,7 @@ static void btrfs_corrupt_extent_tree(struct btrfs_trans_handle *trans, next = read_tree_block(root, btrfs_node_blockptr(eb, i), root->leafsize, btrfs_node_ptr_generation(eb, i)); - if (!next) + if (!extent_buffer_uptodate(next)) continue; btrfs_corrupt_extent_tree(trans, root, next); free_extent_buffer(next); @@ -696,7 +698,7 @@ static int corrupt_metadata_block(struct btrfs_root *root, u64 block, } eb = read_tree_block(root, block, root->leafsize, 0); - if (!eb) { + if (!extent_buffer_uptodate(eb)) { fprintf(stderr, "Couldn't read in tree block %s\n", field); return -EINVAL; } @@ -845,6 +847,26 @@ out: return ret; } +static int delete_csum(struct btrfs_root *root, u64 bytenr, u64 bytes) +{ + struct btrfs_trans_handle *trans; + int ret; + + root = root->fs_info->csum_root; + trans = btrfs_start_transaction(root, 1); + if (IS_ERR(trans)) { + fprintf(stderr, "Couldn't start transaction %ld\n", + PTR_ERR(trans)); + return PTR_ERR(trans); + } + + ret = btrfs_del_csums(trans, root, bytenr, bytes); + if (ret) + fprintf(stderr, "Error deleting csums %d\n", ret); + btrfs_commit_transaction(trans, root); + return ret; +} + /* corrupt item using NO cow. * Because chunk recover will recover based on whole partition scaning, * If using COW, chunk recover will use the old item to recover, @@ -1010,6 +1032,8 @@ int main(int ac, char **av) u64 metadata_block = 0; u64 inode = 0; u64 file_extent = (u64)-1; + u64 root_objectid = 0; + u64 csum_bytenr = 0; char field[FIELD_BUF_LEN]; field[0] = '\0'; @@ -1018,30 +1042,32 @@ int main(int ac, char **av) while(1) { int c; - int option_index = 0; static const struct option long_options[] = { /* { "byte-count", 1, NULL, 'b' }, */ - { "logical", 1, NULL, 'l' }, - { "copy", 1, NULL, 'c' }, - { "bytes", 1, NULL, 'b' }, - { "extent-record", 0, NULL, 'e' }, - { "extent-tree", 0, NULL, 'E' }, - { "keys", 0, NULL, 'k' }, - { "chunk-record", 0, NULL, 'u' }, - { "chunk-tree", 0, NULL, 'U' }, - { "inode", 1, NULL, 'i'}, - { "file-extent", 1, NULL, 'x'}, - { "metadata-block", 1, NULL, 'm'}, - { "field", 1, NULL, 'f'}, - { "key", 1, NULL, 'K'}, - { "item", 0, NULL, 'I'}, - { "dir-item", 0, NULL, 'D'}, - { "delete", 0, NULL, 'd'}, - { 0, 0, 0, 0} + { "logical", required_argument, NULL, 'l' }, + { "copy", required_argument, NULL, 'c' }, + { "bytes", required_argument, NULL, 'b' }, + { "extent-record", no_argument, NULL, 'e' }, + { "extent-tree", no_argument, NULL, 'E' }, + { "keys", no_argument, NULL, 'k' }, + { "chunk-record", no_argument, NULL, 'u' }, + { "chunk-tree", no_argument, NULL, 'U' }, + { "inode", required_argument, NULL, 'i'}, + { "file-extent", required_argument, NULL, 'x'}, + { "metadata-block", required_argument, NULL, 'm'}, + { "field", required_argument, NULL, 'f'}, + { "key", required_argument, NULL, 'K'}, + { "item", no_argument, NULL, 'I'}, + { "dir-item", no_argument, NULL, 'D'}, + { "delete", no_argument, NULL, 'd'}, + { "root", no_argument, NULL, 'r'}, + { "csum", required_argument, NULL, 'C'}, + { "help", no_argument, NULL, GETOPT_VAL_HELP}, + { NULL, 0, NULL, 0 } }; - c = getopt_long(ac, av, "l:c:b:eEkuUi:f:x:m:K:IDd", long_options, - &option_index); + c = getopt_long(ac, av, "l:c:b:eEkuUi:f:x:m:K:IDdr:C:", + long_options, NULL); if (c < 0) break; switch(c) { @@ -1089,7 +1115,7 @@ int main(int ac, char **av) if (ret != 3) { fprintf(stderr, "error reading key " "%d\n", errno); - print_usage(); + print_usage(1); } break; case 'D': @@ -1101,14 +1127,21 @@ int main(int ac, char **av) case 'd': delete = 1; break; + case 'r': + root_objectid = arg_strtou64(optarg); + break; + case 'C': + csum_bytenr = arg_strtou64(optarg); + break; + case GETOPT_VAL_HELP: default: - print_usage(); + print_usage(c != GETOPT_VAL_HELP); } } set_argv0(av); ac = ac - optind; if (check_argc_min(ac, 1)) - print_usage(); + print_usage(1); dev = av[optind]; radix_tree_init(); @@ -1123,7 +1156,7 @@ int main(int ac, char **av) struct btrfs_trans_handle *trans; if (logical == (u64)-1) - print_usage(); + print_usage(1); trans = btrfs_start_transaction(root, 1); ret = corrupt_extent (trans, root, logical, 0); btrfs_commit_transaction(trans, root); @@ -1143,7 +1176,7 @@ int main(int ac, char **av) int del; if (logical == (u64)-1) - print_usage(); + print_usage(1); del = rand() % 3; path = btrfs_alloc_path(); if (!path) { @@ -1177,7 +1210,7 @@ int main(int ac, char **av) struct btrfs_trans_handle *trans; if (!strlen(field)) - print_usage(); + print_usage(1); trans = btrfs_start_transaction(root, 1); if (file_extent == (u64)-1) { @@ -1193,30 +1226,50 @@ int main(int ac, char **av) } if (metadata_block) { if (!strlen(field)) - print_usage(); + print_usage(1); ret = corrupt_metadata_block(root, metadata_block, field); goto out_close; } if (corrupt_di) { if (!key.objectid || !strlen(field)) - print_usage(); + print_usage(1); ret = corrupt_dir_item(root, &key, field); goto out_close; } + if (csum_bytenr) { + ret = delete_csum(root, csum_bytenr, bytes); + goto out_close; + } if (corrupt_item) { if (!key.objectid) - print_usage(); + print_usage(1); ret = corrupt_btrfs_item(root, &key, field); } if (delete) { + struct btrfs_root *target = root; + if (!key.objectid) - print_usage(); - ret = delete_item(root, &key); + print_usage(1); + if (root_objectid) { + struct btrfs_key root_key; + + root_key.objectid = root_objectid; + root_key.type = BTRFS_ROOT_ITEM_KEY; + root_key.offset = (u64)-1; + + target = btrfs_read_fs_root(root->fs_info, &root_key); + if (IS_ERR(target)) { + fprintf(stderr, "Couldn't find root %llu\n", + (unsigned long long)root_objectid); + print_usage(1); + } + } + ret = delete_item(target, &key); goto out_close; } if (key.objectid || key.offset || key.type) { if (!strlen(field)) - print_usage(); + print_usage(1); ret = corrupt_key(root, &key, field); goto out_close; } @@ -1225,10 +1278,10 @@ int main(int ac, char **av) * inode and we're screwed. */ if (file_extent != (u64)-1) - print_usage(); + print_usage(1); if (logical == (u64)-1) - print_usage(); + print_usage(1); if (bytes == 0) bytes = root->sectorsize;