diff options
Diffstat (limited to 'fs/btrfs/dir-test.c')
-rw-r--r-- | fs/btrfs/dir-test.c | 494 |
1 files changed, 0 insertions, 494 deletions
diff --git a/fs/btrfs/dir-test.c b/fs/btrfs/dir-test.c deleted file mode 100644 index b673982a1f3c..000000000000 --- a/fs/btrfs/dir-test.c +++ /dev/null | |||
@@ -1,494 +0,0 @@ | |||
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 | #include "transaction.h" | ||
12 | |||
13 | int keep_running = 1; | ||
14 | struct btrfs_super_block super; | ||
15 | static u64 dir_oid = 44556; | ||
16 | static u64 file_oid = 33778; | ||
17 | |||
18 | static int find_num(struct radix_tree_root *root, unsigned long *num_ret, | ||
19 | int exists) | ||
20 | { | ||
21 | unsigned long num = rand(); | ||
22 | unsigned long res[2]; | ||
23 | int ret; | ||
24 | |||
25 | again: | ||
26 | ret = radix_tree_gang_lookup(root, (void **)res, num, 2); | ||
27 | if (exists) { | ||
28 | if (ret == 0) | ||
29 | return -1; | ||
30 | num = res[0]; | ||
31 | } else if (ret != 0 && num == res[0]) { | ||
32 | num++; | ||
33 | if (ret > 1 && num == res[1]) { | ||
34 | num++; | ||
35 | goto again; | ||
36 | } | ||
37 | } | ||
38 | *num_ret = num; | ||
39 | return 0; | ||
40 | } | ||
41 | |||
42 | static void initial_inode_init(struct btrfs_root *root, | ||
43 | struct btrfs_inode_item *inode_item) | ||
44 | { | ||
45 | memset(inode_item, 0, sizeof(*inode_item)); | ||
46 | btrfs_set_inode_generation(inode_item, root->fs_info->generation); | ||
47 | } | ||
48 | |||
49 | static int ins_one(struct btrfs_trans_handle *trans, struct btrfs_root *root, | ||
50 | struct radix_tree_root *radix) | ||
51 | { | ||
52 | int ret; | ||
53 | char buf[128]; | ||
54 | unsigned long oid; | ||
55 | u64 objectid; | ||
56 | struct btrfs_path path; | ||
57 | struct btrfs_key inode_map; | ||
58 | struct btrfs_inode_item inode_item; | ||
59 | |||
60 | find_num(radix, &oid, 0); | ||
61 | sprintf(buf, "str-%lu", oid); | ||
62 | |||
63 | ret = btrfs_find_free_objectid(trans, root, dir_oid + 1, &objectid); | ||
64 | if (ret) | ||
65 | goto error; | ||
66 | |||
67 | inode_map.objectid = objectid; | ||
68 | inode_map.flags = 0; | ||
69 | inode_map.offset = 0; | ||
70 | |||
71 | ret = btrfs_insert_inode_map(trans, root, objectid, &inode_map); | ||
72 | if (ret) | ||
73 | goto error; | ||
74 | |||
75 | initial_inode_init(root, &inode_item); | ||
76 | ret = btrfs_insert_inode(trans, root, objectid, &inode_item); | ||
77 | if (ret) | ||
78 | goto error; | ||
79 | ret = btrfs_insert_dir_item(trans, root, buf, strlen(buf), dir_oid, | ||
80 | objectid, 1); | ||
81 | if (ret) | ||
82 | goto error; | ||
83 | |||
84 | radix_tree_preload(GFP_KERNEL); | ||
85 | ret = radix_tree_insert(radix, oid, (void *)oid); | ||
86 | radix_tree_preload_end(); | ||
87 | if (ret) | ||
88 | goto error; | ||
89 | return ret; | ||
90 | error: | ||
91 | if (ret != -EEXIST) | ||
92 | goto fatal; | ||
93 | |||
94 | /* | ||
95 | * if we got an EEXIST, it may be due to hash collision, double | ||
96 | * check | ||
97 | */ | ||
98 | btrfs_init_path(&path); | ||
99 | ret = btrfs_lookup_dir_item(trans, root, &path, dir_oid, buf, | ||
100 | strlen(buf), 0); | ||
101 | if (ret) | ||
102 | goto fatal_release; | ||
103 | if (!btrfs_match_dir_item_name(root, &path, buf, strlen(buf))) { | ||
104 | struct btrfs_dir_item *di; | ||
105 | char *found; | ||
106 | u32 found_len; | ||
107 | u64 myhash; | ||
108 | u64 foundhash; | ||
109 | |||
110 | di = btrfs_item_ptr(&path.nodes[0]->leaf, path.slots[0], | ||
111 | struct btrfs_dir_item); | ||
112 | found = (char *)(di + 1); | ||
113 | found_len = btrfs_dir_name_len(di); | ||
114 | btrfs_name_hash(buf, strlen(buf), &myhash); | ||
115 | btrfs_name_hash(found, found_len, &foundhash); | ||
116 | if (myhash != foundhash) | ||
117 | goto fatal_release; | ||
118 | btrfs_release_path(root, &path); | ||
119 | return 0; | ||
120 | } | ||
121 | fatal_release: | ||
122 | btrfs_release_path(root, &path); | ||
123 | fatal: | ||
124 | printf("failed to insert %lu ret %d\n", oid, ret); | ||
125 | return -1; | ||
126 | } | ||
127 | |||
128 | static int insert_dup(struct btrfs_trans_handle *trans, struct btrfs_root | ||
129 | *root, struct radix_tree_root *radix) | ||
130 | { | ||
131 | int ret; | ||
132 | char buf[128]; | ||
133 | unsigned long oid; | ||
134 | |||
135 | ret = find_num(radix, &oid, 1); | ||
136 | if (ret < 0) | ||
137 | return 0; | ||
138 | sprintf(buf, "str-%lu", oid); | ||
139 | |||
140 | ret = btrfs_insert_dir_item(trans, root, buf, strlen(buf), dir_oid, | ||
141 | file_oid, 1); | ||
142 | if (ret != -EEXIST) { | ||
143 | printf("insert on %s gave us %d\n", buf, ret); | ||
144 | return 1; | ||
145 | } | ||
146 | return 0; | ||
147 | } | ||
148 | |||
149 | static int del_dir_item(struct btrfs_trans_handle *trans, | ||
150 | struct btrfs_root *root, | ||
151 | struct radix_tree_root *radix, | ||
152 | unsigned long radix_index, | ||
153 | struct btrfs_path *path) | ||
154 | { | ||
155 | int ret; | ||
156 | unsigned long *ptr; | ||
157 | u64 file_objectid; | ||
158 | struct btrfs_dir_item *di; | ||
159 | |||
160 | /* find the inode number of the file */ | ||
161 | di = btrfs_item_ptr(&path->nodes[0]->leaf, path->slots[0], | ||
162 | struct btrfs_dir_item); | ||
163 | file_objectid = btrfs_dir_objectid(di); | ||
164 | |||
165 | /* delete the directory item */ | ||
166 | ret = btrfs_del_item(trans, root, path); | ||
167 | if (ret) | ||
168 | goto out_release; | ||
169 | btrfs_release_path(root, path); | ||
170 | |||
171 | /* delete the inode */ | ||
172 | btrfs_init_path(path); | ||
173 | ret = btrfs_lookup_inode(trans, root, path, file_objectid, -1); | ||
174 | if (ret) | ||
175 | goto out_release; | ||
176 | ret = btrfs_del_item(trans, root, path); | ||
177 | if (ret) | ||
178 | goto out_release; | ||
179 | btrfs_release_path(root, path); | ||
180 | |||
181 | /* delete the inode mapping */ | ||
182 | btrfs_init_path(path); | ||
183 | ret = btrfs_lookup_inode_map(trans, root, path, file_objectid, -1); | ||
184 | if (ret) | ||
185 | goto out_release; | ||
186 | ret = btrfs_del_item(trans, root->fs_info->inode_root, path); | ||
187 | if (ret) | ||
188 | goto out_release; | ||
189 | |||
190 | if (root->fs_info->last_inode_alloc > file_objectid) | ||
191 | root->fs_info->last_inode_alloc = file_objectid; | ||
192 | btrfs_release_path(root, path); | ||
193 | ptr = radix_tree_delete(radix, radix_index); | ||
194 | if (!ptr) { | ||
195 | ret = -5555; | ||
196 | goto out; | ||
197 | } | ||
198 | return 0; | ||
199 | out_release: | ||
200 | btrfs_release_path(root, path); | ||
201 | out: | ||
202 | printf("failed to delete %lu %d\n", radix_index, ret); | ||
203 | return -1; | ||
204 | } | ||
205 | |||
206 | static int del_one(struct btrfs_trans_handle *trans, struct btrfs_root *root, | ||
207 | struct radix_tree_root *radix) | ||
208 | { | ||
209 | int ret; | ||
210 | char buf[128]; | ||
211 | unsigned long oid; | ||
212 | struct btrfs_path path; | ||
213 | |||
214 | ret = find_num(radix, &oid, 1); | ||
215 | if (ret < 0) | ||
216 | return 0; | ||
217 | sprintf(buf, "str-%lu", oid); | ||
218 | btrfs_init_path(&path); | ||
219 | ret = btrfs_lookup_dir_item(trans, root, &path, dir_oid, buf, | ||
220 | strlen(buf), -1); | ||
221 | if (ret) | ||
222 | goto out_release; | ||
223 | |||
224 | ret = del_dir_item(trans, root, radix, oid, &path); | ||
225 | if (ret) | ||
226 | goto out_release; | ||
227 | return ret; | ||
228 | out_release: | ||
229 | btrfs_release_path(root, &path); | ||
230 | printf("failed to delete %lu %d\n", oid, ret); | ||
231 | return -1; | ||
232 | } | ||
233 | |||
234 | static int lookup_item(struct btrfs_trans_handle *trans, struct btrfs_root | ||
235 | *root, struct radix_tree_root *radix) | ||
236 | { | ||
237 | struct btrfs_path path; | ||
238 | char buf[128]; | ||
239 | int ret; | ||
240 | unsigned long oid; | ||
241 | u64 objectid; | ||
242 | struct btrfs_dir_item *di; | ||
243 | |||
244 | ret = find_num(radix, &oid, 1); | ||
245 | if (ret < 0) | ||
246 | return 0; | ||
247 | sprintf(buf, "str-%lu", oid); | ||
248 | btrfs_init_path(&path); | ||
249 | ret = btrfs_lookup_dir_item(trans, root, &path, dir_oid, buf, | ||
250 | strlen(buf), 0); | ||
251 | if (!ret) { | ||
252 | di = btrfs_item_ptr(&path.nodes[0]->leaf, path.slots[0], | ||
253 | struct btrfs_dir_item); | ||
254 | objectid = btrfs_dir_objectid(di); | ||
255 | btrfs_release_path(root, &path); | ||
256 | btrfs_init_path(&path); | ||
257 | ret = btrfs_lookup_inode_map(trans, root, &path, objectid, 0); | ||
258 | } | ||
259 | btrfs_release_path(root, &path); | ||
260 | if (ret) { | ||
261 | printf("unable to find key %lu\n", oid); | ||
262 | return -1; | ||
263 | } | ||
264 | return 0; | ||
265 | } | ||
266 | |||
267 | static int lookup_enoent(struct btrfs_trans_handle *trans, struct btrfs_root | ||
268 | *root, struct radix_tree_root *radix) | ||
269 | { | ||
270 | struct btrfs_path path; | ||
271 | char buf[128]; | ||
272 | int ret; | ||
273 | unsigned long oid; | ||
274 | |||
275 | ret = find_num(radix, &oid, 0); | ||
276 | if (ret < 0) | ||
277 | return 0; | ||
278 | sprintf(buf, "str-%lu", oid); | ||
279 | btrfs_init_path(&path); | ||
280 | ret = btrfs_lookup_dir_item(trans, root, &path, dir_oid, buf, | ||
281 | strlen(buf), 0); | ||
282 | btrfs_release_path(root, &path); | ||
283 | if (!ret) { | ||
284 | printf("able to find key that should not exist %lu\n", oid); | ||
285 | return -1; | ||
286 | } | ||
287 | return 0; | ||
288 | } | ||
289 | |||
290 | static int empty_tree(struct btrfs_trans_handle *trans, struct btrfs_root | ||
291 | *root, struct radix_tree_root *radix, int nr) | ||
292 | { | ||
293 | struct btrfs_path path; | ||
294 | struct btrfs_key key; | ||
295 | unsigned long found = 0; | ||
296 | u32 found_len; | ||
297 | int ret; | ||
298 | int slot; | ||
299 | int count = 0; | ||
300 | char buf[128]; | ||
301 | struct btrfs_dir_item *di; | ||
302 | |||
303 | key.offset = (u64)-1; | ||
304 | key.flags = 0; | ||
305 | btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY); | ||
306 | key.objectid = dir_oid; | ||
307 | while(nr-- >= 0) { | ||
308 | btrfs_init_path(&path); | ||
309 | ret = btrfs_search_slot(trans, root, &key, &path, -1, 1); | ||
310 | if (ret < 0) { | ||
311 | btrfs_release_path(root, &path); | ||
312 | return ret; | ||
313 | } | ||
314 | if (ret != 0) { | ||
315 | if (path.slots[0] == 0) { | ||
316 | btrfs_release_path(root, &path); | ||
317 | break; | ||
318 | } | ||
319 | path.slots[0] -= 1; | ||
320 | } | ||
321 | slot = path.slots[0]; | ||
322 | di = btrfs_item_ptr(&path.nodes[0]->leaf, slot, | ||
323 | struct btrfs_dir_item); | ||
324 | found_len = btrfs_dir_name_len(di); | ||
325 | memcpy(buf, (char *)(di + 1), found_len); | ||
326 | BUG_ON(found_len > 128); | ||
327 | buf[found_len] = '\0'; | ||
328 | found = atoi(buf + 4); | ||
329 | ret = del_dir_item(trans, root, radix, found, &path); | ||
330 | count++; | ||
331 | if (ret) { | ||
332 | fprintf(stderr, | ||
333 | "failed to remove %lu from tree\n", | ||
334 | found); | ||
335 | return -1; | ||
336 | } | ||
337 | if (!keep_running) | ||
338 | break; | ||
339 | } | ||
340 | return 0; | ||
341 | fprintf(stderr, "failed to delete from the radix %lu\n", found); | ||
342 | return -1; | ||
343 | } | ||
344 | |||
345 | static int fill_tree(struct btrfs_trans_handle *trans, struct btrfs_root *root, | ||
346 | struct radix_tree_root *radix, int count) | ||
347 | { | ||
348 | int i; | ||
349 | int ret = 0; | ||
350 | for (i = 0; i < count; i++) { | ||
351 | ret = ins_one(trans, root, radix); | ||
352 | if (ret) { | ||
353 | fprintf(stderr, "fill failed\n"); | ||
354 | goto out; | ||
355 | } | ||
356 | if (i % 1000 == 0) { | ||
357 | ret = btrfs_commit_transaction(trans, root, &super); | ||
358 | if (ret) { | ||
359 | fprintf(stderr, "fill commit failed\n"); | ||
360 | return ret; | ||
361 | } | ||
362 | } | ||
363 | if (i && i % 10000 == 0) { | ||
364 | printf("bigfill %d\n", i); | ||
365 | } | ||
366 | if (!keep_running) | ||
367 | break; | ||
368 | } | ||
369 | out: | ||
370 | return ret; | ||
371 | } | ||
372 | |||
373 | static int bulk_op(struct btrfs_trans_handle *trans, struct btrfs_root *root, | ||
374 | struct radix_tree_root *radix) | ||
375 | { | ||
376 | int ret; | ||
377 | int nr = rand() % 5000; | ||
378 | static int run_nr = 0; | ||
379 | |||
380 | /* do the bulk op much less frequently */ | ||
381 | if (run_nr++ % 100) | ||
382 | return 0; | ||
383 | ret = empty_tree(trans, root, radix, nr); | ||
384 | if (ret) | ||
385 | return ret; | ||
386 | ret = fill_tree(trans, root, radix, nr); | ||
387 | if (ret) | ||
388 | return ret; | ||
389 | return 0; | ||
390 | } | ||
391 | |||
392 | |||
393 | int (*ops[])(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct | ||
394 | radix_tree_root *radix) = | ||
395 | { ins_one, insert_dup, del_one, lookup_item, | ||
396 | lookup_enoent, bulk_op }; | ||
397 | |||
398 | void sigstopper(int ignored) | ||
399 | { | ||
400 | keep_running = 0; | ||
401 | fprintf(stderr, "caught exit signal, stopping\n"); | ||
402 | } | ||
403 | |||
404 | int print_usage(void) | ||
405 | { | ||
406 | printf("usage: tester [-ih] [-c count] [-f count]\n"); | ||
407 | printf("\t -c count -- iteration count after filling\n"); | ||
408 | printf("\t -f count -- run this many random inserts before starting\n"); | ||
409 | printf("\t -i -- only do initial fill\n"); | ||
410 | printf("\t -h -- this help text\n"); | ||
411 | exit(1); | ||
412 | } | ||
413 | int main(int ac, char **av) | ||
414 | { | ||
415 | RADIX_TREE(radix, GFP_KERNEL); | ||
416 | struct btrfs_root *root; | ||
417 | int i; | ||
418 | int ret; | ||
419 | int count; | ||
420 | int op; | ||
421 | int iterations = 20000; | ||
422 | int init_fill_count = 800000; | ||
423 | int err = 0; | ||
424 | int initial_only = 0; | ||
425 | struct btrfs_trans_handle *trans; | ||
426 | radix_tree_init(); | ||
427 | |||
428 | root = open_ctree("dbfile", &super); | ||
429 | trans = btrfs_start_transaction(root, 1); | ||
430 | |||
431 | signal(SIGTERM, sigstopper); | ||
432 | signal(SIGINT, sigstopper); | ||
433 | |||
434 | for (i = 1 ; i < ac ; i++) { | ||
435 | if (strcmp(av[i], "-i") == 0) { | ||
436 | initial_only = 1; | ||
437 | } else if (strcmp(av[i], "-c") == 0) { | ||
438 | iterations = atoi(av[i+1]); | ||
439 | i++; | ||
440 | } else if (strcmp(av[i], "-f") == 0) { | ||
441 | init_fill_count = atoi(av[i+1]); | ||
442 | i++; | ||
443 | } else { | ||
444 | print_usage(); | ||
445 | } | ||
446 | } | ||
447 | printf("initial fill\n"); | ||
448 | ret = fill_tree(trans, root, &radix, init_fill_count); | ||
449 | printf("starting run\n"); | ||
450 | if (ret) { | ||
451 | err = ret; | ||
452 | goto out; | ||
453 | } | ||
454 | if (initial_only == 1) { | ||
455 | goto out; | ||
456 | } | ||
457 | for (i = 0; i < iterations; i++) { | ||
458 | op = rand() % ARRAY_SIZE(ops); | ||
459 | count = rand() % 128; | ||
460 | if (i % 2000 == 0) { | ||
461 | printf("%d\n", i); | ||
462 | fflush(stdout); | ||
463 | } | ||
464 | if (i && i % 5000 == 0) { | ||
465 | printf("open & close, root level %d nritems %d\n", | ||
466 | btrfs_header_level(&root->node->node.header), | ||
467 | btrfs_header_nritems(&root->node->node.header)); | ||
468 | close_ctree(root, &super); | ||
469 | root = open_ctree("dbfile", &super); | ||
470 | } | ||
471 | while(count--) { | ||
472 | ret = ops[op](trans, root, &radix); | ||
473 | if (ret) { | ||
474 | fprintf(stderr, "op %d failed %d:%d\n", | ||
475 | op, i, iterations); | ||
476 | btrfs_print_tree(root, root->node); | ||
477 | fprintf(stderr, "op %d failed %d:%d\n", | ||
478 | op, i, iterations); | ||
479 | err = ret; | ||
480 | goto out; | ||
481 | } | ||
482 | if (ops[op] == bulk_op) | ||
483 | break; | ||
484 | if (keep_running == 0) { | ||
485 | err = 0; | ||
486 | goto out; | ||
487 | } | ||
488 | } | ||
489 | } | ||
490 | out: | ||
491 | close_ctree(root, &super); | ||
492 | return err; | ||
493 | } | ||
494 | |||