Commit 1d4f6404de26df49eb8452f8fdf7672b59f407fc

Authored by Chris Mason
Committed by David Woodhouse
1 parent 24af03ea5e

Btrfs: directory testing code and dir item fixes

Signed-off-by: Chris Mason <chris.mason@oracle.com>

Showing 5 changed files with 477 additions and 74 deletions Side-by-side Diff

1   -
2 1 CC=gcc
3 2 CFLAGS = -g -Wall
4 3 headers = radix-tree.h ctree.h disk-io.h kerncompat.h print-tree.h list.h
... ... @@ -15,7 +14,7 @@
15 14 $(check) $<
16 15 $(CC) $(CFLAGS) -c $<
17 16  
18   -all: tester debug-tree quick-test
  17 +all: tester debug-tree quick-test dir-test
19 18  
20 19 debug-tree: $(objects) debug-tree.o
21 20 gcc $(CFLAGS) -o debug-tree $(objects) debug-tree.o
... ... @@ -23,6 +22,8 @@
23 22 tester: $(objects) random-test.o
24 23 gcc $(CFLAGS) -o tester $(objects) random-test.o
25 24  
  25 +dir-test: $(objects) dir-test.o
  26 + gcc $(CFLAGS) -o dir-test $(objects) dir-test.o
26 27 quick-test: $(objects) quick-test.o
27 28 gcc $(CFLAGS) -o quick-test $(objects) quick-test.o
28 29  
... ... @@ -180,37 +180,6 @@
180 180 #define BTRFS_EXTENT_ITEM_KEY 4
181 181 #define BTRFS_STRING_ITEM_KEY 5
182 182  
183   -static inline u64 btrfs_dir_objectid(struct btrfs_dir_item *d)
184   -{
185   - return le64_to_cpu(d->objectid);
186   -}
187   -
188   -static inline void btrfs_set_dir_objectid(struct btrfs_dir_item *d, u64 val)
189   -{
190   - d->objectid = cpu_to_le64(val);
191   -}
192   -
193   -static inline u16 btrfs_dir_flags(struct btrfs_dir_item *d)
194   -{
195   - return le16_to_cpu(d->flags);
196   -}
197   -
198   -static inline void btrfs_set_dir_flags(struct btrfs_dir_item *d, u16 val)
199   -{
200   - d->flags = cpu_to_le16(val);
201   -}
202   -
203   -static inline u8 btrfs_dir_type(struct btrfs_dir_item *d)
204   -{
205   - return d->type;
206   -}
207   -
208   -static inline void btrfs_set_dir_type(struct btrfs_dir_item *d, u8 val)
209   -{
210   - d->type = val;
211   -}
212   -
213   -
214 183 static inline u64 btrfs_extent_owner(struct btrfs_extent_item *ei)
215 184 {
216 185 return le64_to_cpu(ei->owner);
... ... @@ -267,6 +236,41 @@
267 236 item->size = cpu_to_le16(val);
268 237 }
269 238  
  239 +static inline u64 btrfs_dir_objectid(struct btrfs_dir_item *d)
  240 +{
  241 + return le64_to_cpu(d->objectid);
  242 +}
  243 +
  244 +static inline void btrfs_set_dir_objectid(struct btrfs_dir_item *d, u64 val)
  245 +{
  246 + d->objectid = cpu_to_le64(val);
  247 +}
  248 +
  249 +static inline u16 btrfs_dir_flags(struct btrfs_dir_item *d)
  250 +{
  251 + return le16_to_cpu(d->flags);
  252 +}
  253 +
  254 +static inline void btrfs_set_dir_flags(struct btrfs_dir_item *d, u16 val)
  255 +{
  256 + d->flags = cpu_to_le16(val);
  257 +}
  258 +
  259 +static inline u8 btrfs_dir_type(struct btrfs_dir_item *d)
  260 +{
  261 + return d->type;
  262 +}
  263 +
  264 +static inline void btrfs_set_dir_type(struct btrfs_dir_item *d, u8 val)
  265 +{
  266 + d->type = val;
  267 +}
  268 +
  269 +static inline u32 btrfs_dir_name_len(struct btrfs_item *i)
  270 +{
  271 + return btrfs_item_size(i) - sizeof(struct btrfs_dir_item);
  272 +}
  273 +
270 274 static inline void btrfs_disk_key_to_cpu(struct btrfs_key *cpu,
271 275 struct btrfs_disk_key *disk)
272 276 {
... ... @@ -506,5 +510,11 @@
506 510 struct btrfs_root_item *item);
507 511 int btrfs_find_last_root(struct btrfs_root *root, u64 objectid,
508 512 struct btrfs_root_item *item, struct btrfs_key *key);
  513 +int btrfs_insert_dir_item(struct btrfs_root *root, char *name, int name_len,
  514 + u64 dir, u64 objectid, u8 type);
  515 +int btrfs_lookup_dir_item(struct btrfs_root *root, struct btrfs_path *path,
  516 + u64 dir, char *name, int name_len, int mod);
  517 +int btrfs_match_dir_item_name(struct btrfs_root *root, struct btrfs_path *path,
  518 + char *name, int name_len);
509 519 #endif
... ... @@ -18,6 +18,7 @@
18 18  
19 19 key.objectid = dir;
20 20 key.flags = 0;
  21 + btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY);
21 22 ret = btrfs_name_hash(name, name_len, &key.offset);
22 23 BUG_ON(ret);
23 24 btrfs_init_path(&path);
24 25  
25 26  
26 27  
27 28  
28 29  
29 30  
30 31  
31 32  
32 33  
33 34  
34 35  
35 36  
... ... @@ -38,66 +39,41 @@
38 39 return ret;
39 40 }
40 41  
41   -int btrfs_del_dir_item(struct btrfs_root *root, u64 dir, char *name,
42   - int name_len)
  42 +int btrfs_lookup_dir_item(struct btrfs_root *root, struct btrfs_path *path,
  43 + u64 dir, char *name, int name_len, int mod)
43 44 {
44   - int ret = 0;
45   - struct btrfs_path path;
  45 + int ret;
46 46 struct btrfs_key key;
  47 + int ins_len = mod < 0 ? -1 : 0;
  48 + int cow = mod != 0;
47 49  
48 50 key.objectid = dir;
49 51 key.flags = 0;
  52 + btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY);
50 53 ret = btrfs_name_hash(name, name_len, &key.offset);
51 54 BUG_ON(ret);
52   - btrfs_init_path(&path);
53   - ret = btrfs_search_slot(root, &key, &path, 0, 1);
54   - if (ret)
55   - goto out;
56   - ret = btrfs_del_item(root, &path);
57   -out:
58   - btrfs_release_path(root, &path);
  55 + ret = btrfs_search_slot(root, &key, path, ins_len, cow);
59 56 return ret;
60 57 }
61 58  
62   -int btrfs_lookup_dir_item(struct btrfs_root *root, u64 dir, char *name,
63   - int name_len, u64 *objectid)
  59 +int btrfs_match_dir_item_name(struct btrfs_root *root, struct btrfs_path *path,
  60 + char *name, int name_len)
64 61 {
65   - int ret = 0;
66   - struct btrfs_path path;
  62 + struct btrfs_item *item;
67 63 struct btrfs_dir_item *dir_item;
68 64 char *name_ptr;
69   - struct btrfs_key key;
70 65 u32 item_len;
71   - struct btrfs_item *item;
72   -
73   - key.objectid = dir;
74   - key.flags = 0;
75   - ret = btrfs_name_hash(name, name_len, &key.offset);
76   - BUG_ON(ret);
77   - btrfs_init_path(&path);
78   - ret = btrfs_search_slot(root, &key, &path, 0, 0);
79   - if (ret)
80   - goto out;
81   -
82   - dir_item = btrfs_item_ptr(&path.nodes[0]->leaf, path.slots[0],
83   - struct btrfs_dir_item);
84   -
85   - item = path.nodes[0]->leaf.items + path.slots[0];
  66 + item = path->nodes[0]->leaf.items + path->slots[0];
86 67 item_len = btrfs_item_size(item);
87 68 if (item_len != name_len + sizeof(struct btrfs_dir_item)) {
88   - BUG();
89   - ret = 1;
90   - goto out;
  69 + return 0;
91 70 }
  71 + dir_item = btrfs_item_ptr(&path->nodes[0]->leaf, path->slots[0],
  72 + struct btrfs_dir_item);
92 73 name_ptr = (char *)(dir_item + 1);
93 74 if (memcmp(name_ptr, name, name_len)) {
94   - BUG();
95   - ret = 1;
96   - goto out;
  75 + return 0;
97 76 }
98   - *objectid = btrfs_dir_objectid(dir_item);
99   -out:
100   - btrfs_release_path(root, &path);
101   - return ret;
  77 + return 1;
102 78 }
  1 +#include <stdio.h>
  2 +#include <stdlib.h>
  3 +#include <signal.h>
  4 +#include <unistd.h>
  5 +#include "kerncompat.h"
  6 +#include "radix-tree.h"
  7 +#include "ctree.h"
  8 +#include "disk-io.h"
  9 +#include "print-tree.h"
  10 +#include "hash.h"
  11 +
  12 +int keep_running = 1;
  13 +struct btrfs_super_block super;
  14 +static u64 dir_oid = 44556;
  15 +static u64 file_oid = 33778;
  16 +
  17 +static int find_num(struct radix_tree_root *root, unsigned long *num_ret,
  18 + int exists)
  19 +{
  20 + unsigned long num = rand();
  21 + unsigned long res[2];
  22 + int ret;
  23 +
  24 +again:
  25 + ret = radix_tree_gang_lookup(root, (void **)res, num, 2);
  26 + if (exists) {
  27 + if (ret == 0)
  28 + return -1;
  29 + num = res[0];
  30 + } else if (ret != 0 && num == res[0]) {
  31 + num++;
  32 + if (ret > 1 && num == res[1]) {
  33 + num++;
  34 + goto again;
  35 + }
  36 + }
  37 + *num_ret = num;
  38 + return 0;
  39 +}
  40 +
  41 +static int ins_one(struct btrfs_root *root, struct radix_tree_root *radix)
  42 +{
  43 + int ret;
  44 + char buf[128];
  45 + unsigned long oid;
  46 + struct btrfs_path path;
  47 +
  48 + find_num(radix, &oid, 0);
  49 + sprintf(buf, "str-%lu", oid);
  50 +
  51 + ret = btrfs_insert_dir_item(root, buf, strlen(buf), dir_oid, file_oid,
  52 + 1);
  53 + if (ret)
  54 + goto error;
  55 +
  56 + radix_tree_preload(GFP_KERNEL);
  57 + ret = radix_tree_insert(radix, oid, (void *)oid);
  58 + radix_tree_preload_end();
  59 + if (ret)
  60 + goto error;
  61 + return ret;
  62 +error:
  63 + if (ret != -EEXIST)
  64 + goto fatal;
  65 +
  66 + /*
  67 + * if we got an EEXIST, it may be due to hash collision, double
  68 + * check
  69 + */
  70 + btrfs_init_path(&path);
  71 + ret = btrfs_lookup_dir_item(root, &path, dir_oid, buf, strlen(buf), 0);
  72 + if (ret)
  73 + goto fatal_release;
  74 + if (!btrfs_match_dir_item_name(root, &path, buf, strlen(buf))) {
  75 + struct btrfs_dir_item *di;
  76 + char *found;
  77 + u32 found_len;
  78 + u64 myhash;
  79 + u64 foundhash;
  80 +
  81 + di = btrfs_item_ptr(&path.nodes[0]->leaf, path.slots[0],
  82 + struct btrfs_dir_item);
  83 + found = (char *)(di + 1);
  84 + found_len = btrfs_dir_name_len(path.nodes[0]->leaf.items +
  85 + path.slots[0]);
  86 + btrfs_name_hash(buf, strlen(buf), &myhash);
  87 + btrfs_name_hash(found, found_len, &foundhash);
  88 + if (myhash != foundhash)
  89 + goto fatal_release;
  90 + btrfs_release_path(root, &path);
  91 + return 0;
  92 + }
  93 +fatal_release:
  94 + btrfs_release_path(root, &path);
  95 +fatal:
  96 + printf("failed to insert %lu ret %d\n", oid, ret);
  97 + return -1;
  98 +}
  99 +
  100 +static int insert_dup(struct btrfs_root *root, struct radix_tree_root *radix)
  101 +{
  102 + int ret;
  103 + char buf[128];
  104 + unsigned long oid;
  105 +
  106 + ret = find_num(radix, &oid, 1);
  107 + if (ret < 0)
  108 + return 0;
  109 + sprintf(buf, "str-%lu", oid);
  110 +
  111 + ret = btrfs_insert_dir_item(root, buf, strlen(buf), dir_oid, file_oid,
  112 + 1);
  113 + if (ret != -EEXIST) {
  114 + printf("insert on %s gave us %d\n", buf, ret);
  115 + return 1;
  116 + }
  117 + return 0;
  118 +}
  119 +
  120 +static int del_one(struct btrfs_root *root, struct radix_tree_root *radix)
  121 +{
  122 + int ret;
  123 + char buf[128];
  124 + unsigned long oid;
  125 + struct btrfs_path path;
  126 + unsigned long *ptr;
  127 +
  128 + ret = find_num(radix, &oid, 1);
  129 + if (ret < 0)
  130 + return 0;
  131 + sprintf(buf, "str-%lu", oid);
  132 + btrfs_init_path(&path);
  133 + ret = btrfs_lookup_dir_item(root, &path, dir_oid, buf, strlen(buf), -1);
  134 + if (ret)
  135 + goto out_release;
  136 + ret = btrfs_del_item(root, &path);
  137 + if (ret)
  138 + goto out_release;
  139 + btrfs_release_path(root, &path);
  140 + ptr = radix_tree_delete(radix, oid);
  141 + if (!ptr) {
  142 + ret = -5555;
  143 + goto out;
  144 + }
  145 + return 0;
  146 +out_release:
  147 + btrfs_release_path(root, &path);
  148 +out:
  149 + printf("failed to delete %lu %d\n", oid, ret);
  150 + return -1;
  151 +}
  152 +
  153 +static int lookup_item(struct btrfs_root *root, struct radix_tree_root *radix)
  154 +{
  155 + struct btrfs_path path;
  156 + char buf[128];
  157 + int ret;
  158 + unsigned long oid;
  159 +
  160 + ret = find_num(radix, &oid, 1);
  161 + if (ret < 0)
  162 + return 0;
  163 + sprintf(buf, "str-%lu", oid);
  164 + btrfs_init_path(&path);
  165 + ret = btrfs_lookup_dir_item(root, &path, dir_oid, buf, strlen(buf), 0);
  166 + btrfs_release_path(root, &path);
  167 + if (ret) {
  168 + printf("unable to find key %lu\n", oid);
  169 + return -1;
  170 + }
  171 + return 0;
  172 +}
  173 +
  174 +static int lookup_enoent(struct btrfs_root *root, struct radix_tree_root *radix)
  175 +{
  176 + struct btrfs_path path;
  177 + char buf[128];
  178 + int ret;
  179 + unsigned long oid;
  180 +
  181 + ret = find_num(radix, &oid, 0);
  182 + if (ret < 0)
  183 + return 0;
  184 + sprintf(buf, "str-%lu", oid);
  185 + btrfs_init_path(&path);
  186 + ret = btrfs_lookup_dir_item(root, &path, dir_oid, buf, strlen(buf), 0);
  187 + btrfs_release_path(root, &path);
  188 + if (!ret) {
  189 + printf("able to find key that should not exist %lu\n", oid);
  190 + return -1;
  191 + }
  192 + return 0;
  193 +}
  194 +
  195 +static int empty_tree(struct btrfs_root *root, struct radix_tree_root *radix,
  196 + int nr)
  197 +{
  198 + struct btrfs_path path;
  199 + struct btrfs_key key;
  200 + unsigned long found = 0;
  201 + u32 found_len;
  202 + int ret;
  203 + int slot;
  204 + int *ptr;
  205 + int count = 0;
  206 + char buf[128];
  207 + struct btrfs_dir_item *di;
  208 +
  209 + key.offset = (u64)-1;
  210 + key.flags = 0;
  211 + btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY);
  212 + key.objectid = dir_oid;
  213 + while(nr-- >= 0) {
  214 + btrfs_init_path(&path);
  215 + ret = btrfs_search_slot(root, &key, &path, -1, 1);
  216 + if (ret < 0) {
  217 + btrfs_release_path(root, &path);
  218 + return ret;
  219 + }
  220 + if (ret != 0) {
  221 + if (path.slots[0] == 0) {
  222 + btrfs_release_path(root, &path);
  223 + break;
  224 + }
  225 + path.slots[0] -= 1;
  226 + }
  227 + slot = path.slots[0];
  228 + di = btrfs_item_ptr(&path.nodes[0]->leaf, slot,
  229 + struct btrfs_dir_item);
  230 + found_len = btrfs_dir_name_len(path.nodes[0]->leaf.items +
  231 + slot);
  232 + memcpy(buf, (char *)(di + 1), found_len);
  233 + BUG_ON(found_len > 128);
  234 + buf[found_len] = '\0';
  235 + found = atoi(buf + 4);
  236 + ret = btrfs_del_item(root, &path);
  237 + count++;
  238 + if (ret) {
  239 + fprintf(stderr,
  240 + "failed to remove %lu from tree\n",
  241 + found);
  242 + return -1;
  243 + }
  244 + btrfs_release_path(root, &path);
  245 + ptr = radix_tree_delete(radix, found);
  246 + if (!ptr)
  247 + goto error;
  248 + if (!keep_running)
  249 + break;
  250 + }
  251 + return 0;
  252 +error:
  253 + fprintf(stderr, "failed to delete from the radix %lu\n", found);
  254 + return -1;
  255 +}
  256 +
  257 +static int fill_tree(struct btrfs_root *root, struct radix_tree_root *radix,
  258 + int count)
  259 +{
  260 + int i;
  261 + int ret = 0;
  262 + for (i = 0; i < count; i++) {
  263 + ret = ins_one(root, radix);
  264 + if (ret) {
  265 + fprintf(stderr, "fill failed\n");
  266 + goto out;
  267 + }
  268 + if (i % 1000 == 0) {
  269 + ret = btrfs_commit_transaction(root, &super);
  270 + if (ret) {
  271 + fprintf(stderr, "fill commit failed\n");
  272 + return ret;
  273 + }
  274 + }
  275 + if (i && i % 10000 == 0) {
  276 + printf("bigfill %d\n", i);
  277 + }
  278 + if (!keep_running)
  279 + break;
  280 + }
  281 +out:
  282 + return ret;
  283 +}
  284 +
  285 +static int bulk_op(struct btrfs_root *root, struct radix_tree_root *radix)
  286 +{
  287 + int ret;
  288 + int nr = rand() % 5000;
  289 + static int run_nr = 0;
  290 +
  291 + /* do the bulk op much less frequently */
  292 + if (run_nr++ % 100)
  293 + return 0;
  294 + ret = empty_tree(root, radix, nr);
  295 + if (ret)
  296 + return ret;
  297 + ret = fill_tree(root, radix, nr);
  298 + if (ret)
  299 + return ret;
  300 + return 0;
  301 +}
  302 +
  303 +
  304 +int (*ops[])(struct btrfs_root *root, struct radix_tree_root *radix) =
  305 + { ins_one, insert_dup, del_one, lookup_item,
  306 + lookup_enoent, bulk_op };
  307 +
  308 +void sigstopper(int ignored)
  309 +{
  310 + keep_running = 0;
  311 + fprintf(stderr, "caught exit signal, stopping\n");
  312 +}
  313 +
  314 +int print_usage(void)
  315 +{
  316 + printf("usage: tester [-ih] [-c count] [-f count]\n");
  317 + printf("\t -c count -- iteration count after filling\n");
  318 + printf("\t -f count -- run this many random inserts before starting\n");
  319 + printf("\t -i -- only do initial fill\n");
  320 + printf("\t -h -- this help text\n");
  321 + exit(1);
  322 +}
  323 +int main(int ac, char **av)
  324 +{
  325 + RADIX_TREE(radix, GFP_KERNEL);
  326 + struct btrfs_root *root;
  327 + int i;
  328 + int ret;
  329 + int count;
  330 + int op;
  331 + int iterations = 20000;
  332 + int init_fill_count = 800000;
  333 + int err = 0;
  334 + int initial_only = 0;
  335 + radix_tree_init();
  336 +
  337 + printf("removing old tree\n");
  338 + unlink("dbfile");
  339 + root = open_ctree("dbfile", &super);
  340 +
  341 + signal(SIGTERM, sigstopper);
  342 + signal(SIGINT, sigstopper);
  343 +
  344 + for (i = 1 ; i < ac ; i++) {
  345 + if (strcmp(av[i], "-i") == 0) {
  346 + initial_only = 1;
  347 + } else if (strcmp(av[i], "-c") == 0) {
  348 + iterations = atoi(av[i+1]);
  349 + i++;
  350 + } else if (strcmp(av[i], "-f") == 0) {
  351 + init_fill_count = atoi(av[i+1]);
  352 + i++;
  353 + } else {
  354 + print_usage();
  355 + }
  356 + }
  357 + printf("initial fill\n");
  358 + ret = fill_tree(root, &radix, init_fill_count);
  359 + printf("starting run\n");
  360 + if (ret) {
  361 + err = ret;
  362 + goto out;
  363 + }
  364 + if (initial_only == 1) {
  365 + goto out;
  366 + }
  367 + for (i = 0; i < iterations; i++) {
  368 + op = rand() % ARRAY_SIZE(ops);
  369 + count = rand() % 128;
  370 + if (i % 2000 == 0) {
  371 + printf("%d\n", i);
  372 + fflush(stdout);
  373 + }
  374 + if (i && i % 5000 == 0) {
  375 + printf("open & close, root level %d nritems %d\n",
  376 + btrfs_header_level(&root->node->node.header),
  377 + btrfs_header_nritems(&root->node->node.header));
  378 + close_ctree(root, &super);
  379 + root = open_ctree("dbfile", &super);
  380 + }
  381 + while(count--) {
  382 + ret = ops[op](root, &radix);
  383 + if (ret) {
  384 + fprintf(stderr, "op %d failed %d:%d\n",
  385 + op, i, iterations);
  386 + btrfs_print_tree(root, root->node);
  387 + fprintf(stderr, "op %d failed %d:%d\n",
  388 + op, i, iterations);
  389 + err = ret;
  390 + goto out;
  391 + }
  392 + if (ops[op] == bulk_op)
  393 + break;
  394 + if (keep_running == 0) {
  395 + err = 0;
  396 + goto out;
  397 + }
  398 + }
  399 + }
  400 +out:
  401 + close_ctree(root, &super);
  402 + return err;
  403 +}
fs/btrfs/print-tree.c
... ... @@ -12,7 +12,10 @@
12 12 struct btrfs_item *item;
13 13 struct btrfs_extent_item *ei;
14 14 struct btrfs_root_item *ri;
  15 + struct btrfs_dir_item *di;
15 16 u32 type;
  17 + u32 namelen;
  18 +
16 19 printf("leaf %Lu total ptrs %d free space %d\n",
17 20 btrfs_header_blocknr(&l->header), nr,
18 21 btrfs_leaf_free_space(root, l));
... ... @@ -31,6 +34,15 @@
31 34 case BTRFS_INODE_ITEM_KEY:
32 35 break;
33 36 case BTRFS_DIR_ITEM_KEY:
  37 + namelen = btrfs_item_size(l->items + i) - sizeof(*di);
  38 + di = btrfs_item_ptr(l, i, struct btrfs_dir_item);
  39 + printf("\t\tdir oid %Lu flags %u type %u\n",
  40 + btrfs_dir_objectid(di),
  41 + btrfs_dir_flags(di),
  42 + btrfs_dir_type(di));
  43 + printf("\t\tname %.*s\n",
  44 + namelen, (char *)(di + 1));
  45 +
34 46 break;
35 47 case BTRFS_ROOT_ITEM_KEY:
36 48 ri = btrfs_item_ptr(l, i, struct btrfs_root_item);