aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/dir-test.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/btrfs/dir-test.c')
-rw-r--r--fs/btrfs/dir-test.c404
1 files changed, 404 insertions, 0 deletions
diff --git a/fs/btrfs/dir-test.c b/fs/btrfs/dir-test.c
new file mode 100644
index 000000000000..b482b8f49f8a
--- /dev/null
+++ b/fs/btrfs/dir-test.c
@@ -0,0 +1,404 @@
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
12int keep_running = 1;
13struct btrfs_super_block super;
14static u64 dir_oid = 44556;
15static u64 file_oid = 33778;
16
17static 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
24again:
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
41static 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;
62error:
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 }
93fatal_release:
94 btrfs_release_path(root, &path);
95fatal:
96 printf("failed to insert %lu ret %d\n", oid, ret);
97 return -1;
98}
99
100static 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
120static 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;
146out_release:
147 btrfs_release_path(root, &path);
148out:
149 printf("failed to delete %lu %d\n", oid, ret);
150 return -1;
151}
152
153static 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
174static 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
195static 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;
252error:
253 fprintf(stderr, "failed to delete from the radix %lu\n", found);
254 return -1;
255}
256
257static 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 }
281out:
282 return ret;
283}
284
285static 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
304int (*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
308void sigstopper(int ignored)
309{
310 keep_running = 0;
311 fprintf(stderr, "caught exit signal, stopping\n");
312}
313
314int 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}
323int 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 }
400out:
401 close_ctree(root, &super);
402 return err;
403}
404