From cec572daccafa1e912cbed363df6f84687778c6f Mon Sep 17 00:00:00 2001 From: Nicholas D Steeves Date: Sat, 23 Apr 2016 00:41:30 +0100 Subject: btrfs-progs (4.4.1-1.1) unstable; urgency=medium * Non-maintainer upload. * New upstream release. * Rename package to btrfs-progs (Closes: #780081) * Update standards version to 3.9.7 (no changes needed). * debian/control: Add "Breaks" per Gianfranco Costamagna's suggestion * Change lintian override to reflect package rename * Switch from using postinst and postrm to using triggers per Christian Seiler's recommendation. # imported from the archive --- random-test.c | 433 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 433 insertions(+) create mode 100644 random-test.c (limited to 'random-test.c') diff --git a/random-test.c b/random-test.c new file mode 100644 index 00000000..b7c6cdb3 --- /dev/null +++ b/random-test.c @@ -0,0 +1,433 @@ +/* + * Copyright (C) 2007 Oracle. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License v2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 021110-1307, USA. + */ + +#include +#include +#include +#include "kerncompat.h" +#include "radix-tree.h" +#include "ctree.h" +#include "disk-io.h" +#include "print-tree.h" +#include "transaction.h" + +int keep_running = 1; +struct btrfs_super_block super; + +static int setup_key(struct radix_tree_root *root, struct btrfs_key *key, + int exists) +{ + int num = rand(); + unsigned long res[2]; + int ret; + + key->flags = 0; + btrfs_set_key_type(key, BTRFS_STRING_ITEM_KEY); + key->offset = 0; +again: + ret = radix_tree_gang_lookup(root, (void **)res, num, 2); + if (exists) { + if (ret == 0) + return -EEXIST; + num = res[0]; + } else if (ret != 0 && num == res[0]) { + num++; + if (ret > 1 && num == res[1]) { + num++; + goto again; + } + } + key->objectid = num; + return 0; +} + +static int ins_one(struct btrfs_trans_handle *trans, struct btrfs_root *root, + struct radix_tree_root *radix) +{ + struct btrfs_path path; + struct btrfs_key key; + int ret; + char buf[128]; + unsigned long oid; + btrfs_init_path(&path); + ret = setup_key(radix, &key, 0); + sprintf(buf, "str-%llu\n", (unsigned long long)key.objectid); + ret = btrfs_insert_item(trans, root, &key, buf, strlen(buf)); + if (ret) + goto error; + oid = (unsigned long)key.objectid; + radix_tree_preload(GFP_KERNEL); + ret = radix_tree_insert(radix, oid, (void *)oid); + radix_tree_preload_end(); + if (ret) + goto error; + return ret; +error: + printf("failed to insert %llu\n", (unsigned long long)key.objectid); + return ret; +} + +static int insert_dup(struct btrfs_trans_handle *trans, struct btrfs_root + *root, struct radix_tree_root *radix) +{ + struct btrfs_path path; + struct btrfs_key key; + int ret; + char buf[128]; + btrfs_init_path(&path); + ret = setup_key(radix, &key, 1); + if (ret < 0) + return 0; + sprintf(buf, "str-%llu\n", (unsigned long long)key.objectid); + ret = btrfs_insert_item(trans, root, &key, buf, strlen(buf)); + if (ret != -EEXIST) { + printf("insert on %llu gave us %d\n", + (unsigned long long)key.objectid, ret); + return ret; + } + return 0; +} + +static int del_one(struct btrfs_trans_handle *trans, struct btrfs_root *root, + struct radix_tree_root *radix) +{ + struct btrfs_path path; + struct btrfs_key key; + int ret; + unsigned long *ptr; + btrfs_init_path(&path); + ret = setup_key(radix, &key, 1); + if (ret < 0) + return 0; + ret = btrfs_search_slot(trans, root, &key, &path, -1, 1); + if (ret) + goto error; + ret = btrfs_del_item(trans, root, &path); + btrfs_release_path(&path); + if (ret != 0) + goto error; + ptr = radix_tree_delete(radix, key.objectid); + if (!ptr) + goto error; + return 0; +error: + printf("failed to delete %llu\n", (unsigned long long)key.objectid); + return ret; +} + +static int lookup_item(struct btrfs_trans_handle *trans, struct btrfs_root + *root, struct radix_tree_root *radix) +{ + struct btrfs_path path; + struct btrfs_key key; + int ret; + btrfs_init_path(&path); + ret = setup_key(radix, &key, 1); + if (ret < 0) + return 0; + ret = btrfs_search_slot(trans, root, &key, &path, 0, 1); + btrfs_release_path(&path); + if (ret) + goto error; + return 0; +error: + printf("unable to find key %llu\n", (unsigned long long)key.objectid); + return ret; +} + +static int lookup_enoent(struct btrfs_trans_handle *trans, struct btrfs_root + *root, struct radix_tree_root *radix) +{ + struct btrfs_path path; + struct btrfs_key key; + int ret; + btrfs_init_path(&path); + ret = setup_key(radix, &key, 0); + if (ret < 0) + return ret; + ret = btrfs_search_slot(trans, root, &key, &path, 0, 0); + btrfs_release_path(&path); + if (ret <= 0) + goto error; + return 0; +error: + printf("able to find key that should not exist %llu\n", + (unsigned long long)key.objectid); + return -EEXIST; +} + +static int empty_tree(struct btrfs_trans_handle *trans, struct btrfs_root + *root, struct radix_tree_root *radix, int nr) +{ + struct btrfs_path path; + struct btrfs_key key; + unsigned long found = 0; + int ret; + int slot; + int *ptr; + int count = 0; + + key.offset = 0; + key.flags = 0; + btrfs_set_key_type(&key, BTRFS_STRING_ITEM_KEY); + key.objectid = (unsigned long)-1; + while(nr-- >= 0) { + btrfs_init_path(&path); + ret = btrfs_search_slot(trans, root, &key, &path, -1, 1); + if (ret < 0) { + btrfs_release_path(&path); + return ret; + } + if (ret != 0) { + if (path.slots[0] == 0) { + btrfs_release_path(&path); + break; + } + path.slots[0] -= 1; + } + slot = path.slots[0]; + found = btrfs_disk_key_objectid( + &path.nodes[0]->leaf.items[slot].key); + ret = btrfs_del_item(trans, root, &path); + count++; + if (ret) { + fprintf(stderr, + "failed to remove %lu from tree\n", + found); + return ret; + } + btrfs_release_path(&path); + ptr = radix_tree_delete(radix, found); + if (!ptr) + goto error; + if (!keep_running) + break; + } + return 0; +error: + fprintf(stderr, "failed to delete from the radix %lu\n", found); + return -ENOENT; +} + +static int fill_tree(struct btrfs_trans_handle *trans, struct btrfs_root *root, + struct radix_tree_root *radix, int count) +{ + int i; + int ret = 0; + for (i = 0; i < count; i++) { + ret = ins_one(trans, root, radix); + if (ret) { + fprintf(stderr, "fill failed\n"); + goto out; + } + if (i % 1000 == 0) { + ret = btrfs_commit_transaction(trans, root, &super); + if (ret) { + fprintf(stderr, "fill commit failed\n"); + return ret; + } + } + if (i && i % 10000 == 0) { + printf("bigfill %d\n", i); + } + if (!keep_running) + break; + } +out: + return ret; +} + +static int bulk_op(struct btrfs_trans_handle *trans, struct btrfs_root *root, + struct radix_tree_root *radix) +{ + int ret; + int nr = rand() % 5000; + static int run_nr = 0; + + /* do the bulk op much less frequently */ + if (run_nr++ % 100) + return 0; + ret = empty_tree(trans, root, radix, nr); + if (ret) + return ret; + ret = fill_tree(trans, root, radix, nr); + if (ret) + return ret; + return 0; +} + + +int (*ops[])(struct btrfs_trans_handle *, + struct btrfs_root *root, struct radix_tree_root *radix) = + { ins_one, insert_dup, del_one, lookup_item, + lookup_enoent, bulk_op }; + +static int fill_radix(struct btrfs_root *root, struct radix_tree_root *radix) +{ + struct btrfs_path path; + struct btrfs_key key; + unsigned long found = 0; + int ret; + int slot; + int i; + + key.offset = 0; + key.flags = 0; + btrfs_set_key_type(&key, BTRFS_STRING_ITEM_KEY); + key.objectid = (unsigned long)-1; + while(1) { + btrfs_init_path(&path); + ret = btrfs_search_slot(NULL, root, &key, &path, 0, 0); + if (ret < 0) { + btrfs_release_path(&path); + return ret; + } + slot = path.slots[0]; + if (ret != 0) { + if (slot == 0) { + btrfs_release_path(&path); + break; + } + slot -= 1; + } + for (i = slot; i >= 0; i--) { + found = btrfs_disk_key_objectid(&path.nodes[0]-> + leaf.items[i].key); + radix_tree_preload(GFP_KERNEL); + ret = radix_tree_insert(radix, found, (void *)found); + if (ret) { + fprintf(stderr, + "failed to insert %lu into radix\n", + found); + exit(1); + } + + radix_tree_preload_end(); + } + btrfs_release_path(&path); + key.objectid = found - 1; + if (key.objectid > found) + break; + } + return 0; +} +void sigstopper(int ignored) +{ + keep_running = 0; + fprintf(stderr, "caught exit signal, stopping\n"); +} + +int print_usage(void) +{ + printf("usage: tester [-ih] [-c count] [-f count]\n"); + printf("\t -c count -- iteration count after filling\n"); + printf("\t -f count -- run this many random inserts before starting\n"); + printf("\t -i -- only do initial fill\n"); + printf("\t -h -- this help text\n"); + exit(1); +} +int main(int ac, char **av) +{ + RADIX_TREE(radix, GFP_KERNEL); + struct btrfs_root *root; + int i; + int ret; + int count; + int op; + int iterations = 20000; + int init_fill_count = 800000; + int err = 0; + int initial_only = 0; + struct btrfs_trans_handle *trans; + radix_tree_init(); + root = open_ctree("dbfile", &super); + if (!root) { + fprintf(stderr, "Open ctree failed\n"); + exit(1); + } + fill_radix(root, &radix); + + signal(SIGTERM, sigstopper); + signal(SIGINT, sigstopper); + + for (i = 1 ; i < ac ; i++) { + if (strcmp(av[i], "-i") == 0) { + initial_only = 1; + } else if (strcmp(av[i], "-c") == 0) { + iterations = atoi(av[i+1]); + i++; + } else if (strcmp(av[i], "-f") == 0) { + init_fill_count = atoi(av[i+1]); + i++; + } else { + print_usage(); + } + } + printf("initial fill\n"); + trans = btrfs_start_transaction(root, 1); + ret = fill_tree(trans, root, &radix, init_fill_count); + printf("starting run\n"); + if (ret) { + err = ret; + goto out; + } + if (initial_only == 1) { + goto out; + } + for (i = 0; i < iterations; i++) { + op = rand() % ARRAY_SIZE(ops); + count = rand() % 128; + if (i % 2000 == 0) { + printf("%d\n", i); + fflush(stdout); + } + if (i && i % 5000 == 0) { + printf("open & close, root level %d nritems %d\n", + btrfs_header_level(&root->node->node.header), + btrfs_header_nritems(&root->node->node.header)); + close_ctree(root, &super); + root = open_ctree("dbfile", &super); + if (!root) { + fprintf(stderr, "Open ctree failed\n"); + goto out; + } + } + while(count--) { + ret = ops[op](trans, root, &radix); + if (ret) { + fprintf(stderr, "op %d failed %d:%d\n", + op, i, iterations); + btrfs_print_tree(root, root->node, 1); + fprintf(stderr, "op %d failed %d:%d\n", + op, i, iterations); + err = ret; + goto out; + } + if (ops[op] == bulk_op) + break; + if (keep_running == 0) { + err = 0; + goto out; + } + } + } +out: + close_ctree(root, &super); + return !!err; +} + -- cgit v1.2.3