Btrfs: add a name_len to dir items, reorder key
[linux-2.6-block.git] / fs / btrfs / dir-test.c
CommitLineData
1d4f6404
CM
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);
a8a2ee0c 84 found_len = btrfs_dir_name_len(di);
1d4f6404
CM
85 btrfs_name_hash(buf, strlen(buf), &myhash);
86 btrfs_name_hash(found, found_len, &foundhash);
87 if (myhash != foundhash)
88 goto fatal_release;
89 btrfs_release_path(root, &path);
90 return 0;
91 }
92fatal_release:
93 btrfs_release_path(root, &path);
94fatal:
95 printf("failed to insert %lu ret %d\n", oid, ret);
96 return -1;
97}
98
99static int insert_dup(struct btrfs_root *root, struct radix_tree_root *radix)
100{
101 int ret;
102 char buf[128];
103 unsigned long oid;
104
105 ret = find_num(radix, &oid, 1);
106 if (ret < 0)
107 return 0;
108 sprintf(buf, "str-%lu", oid);
109
110 ret = btrfs_insert_dir_item(root, buf, strlen(buf), dir_oid, file_oid,
111 1);
112 if (ret != -EEXIST) {
113 printf("insert on %s gave us %d\n", buf, ret);
114 return 1;
115 }
116 return 0;
117}
118
119static int del_one(struct btrfs_root *root, struct radix_tree_root *radix)
120{
121 int ret;
122 char buf[128];
123 unsigned long oid;
124 struct btrfs_path path;
125 unsigned long *ptr;
126
127 ret = find_num(radix, &oid, 1);
128 if (ret < 0)
129 return 0;
130 sprintf(buf, "str-%lu", oid);
131 btrfs_init_path(&path);
132 ret = btrfs_lookup_dir_item(root, &path, dir_oid, buf, strlen(buf), -1);
133 if (ret)
134 goto out_release;
135 ret = btrfs_del_item(root, &path);
136 if (ret)
137 goto out_release;
138 btrfs_release_path(root, &path);
139 ptr = radix_tree_delete(radix, oid);
140 if (!ptr) {
141 ret = -5555;
142 goto out;
143 }
144 return 0;
145out_release:
146 btrfs_release_path(root, &path);
147out:
148 printf("failed to delete %lu %d\n", oid, ret);
149 return -1;
150}
151
152static int lookup_item(struct btrfs_root *root, struct radix_tree_root *radix)
153{
154 struct btrfs_path path;
155 char buf[128];
156 int ret;
157 unsigned long oid;
158
159 ret = find_num(radix, &oid, 1);
160 if (ret < 0)
161 return 0;
162 sprintf(buf, "str-%lu", oid);
163 btrfs_init_path(&path);
164 ret = btrfs_lookup_dir_item(root, &path, dir_oid, buf, strlen(buf), 0);
165 btrfs_release_path(root, &path);
166 if (ret) {
167 printf("unable to find key %lu\n", oid);
168 return -1;
169 }
170 return 0;
171}
172
173static int lookup_enoent(struct btrfs_root *root, struct radix_tree_root *radix)
174{
175 struct btrfs_path path;
176 char buf[128];
177 int ret;
178 unsigned long oid;
179
180 ret = find_num(radix, &oid, 0);
181 if (ret < 0)
182 return 0;
183 sprintf(buf, "str-%lu", oid);
184 btrfs_init_path(&path);
185 ret = btrfs_lookup_dir_item(root, &path, dir_oid, buf, strlen(buf), 0);
186 btrfs_release_path(root, &path);
187 if (!ret) {
188 printf("able to find key that should not exist %lu\n", oid);
189 return -1;
190 }
191 return 0;
192}
193
194static int empty_tree(struct btrfs_root *root, struct radix_tree_root *radix,
195 int nr)
196{
197 struct btrfs_path path;
198 struct btrfs_key key;
199 unsigned long found = 0;
200 u32 found_len;
201 int ret;
202 int slot;
203 int *ptr;
204 int count = 0;
205 char buf[128];
206 struct btrfs_dir_item *di;
207
208 key.offset = (u64)-1;
209 key.flags = 0;
210 btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY);
211 key.objectid = dir_oid;
212 while(nr-- >= 0) {
213 btrfs_init_path(&path);
214 ret = btrfs_search_slot(root, &key, &path, -1, 1);
215 if (ret < 0) {
216 btrfs_release_path(root, &path);
217 return ret;
218 }
219 if (ret != 0) {
220 if (path.slots[0] == 0) {
221 btrfs_release_path(root, &path);
222 break;
223 }
224 path.slots[0] -= 1;
225 }
226 slot = path.slots[0];
227 di = btrfs_item_ptr(&path.nodes[0]->leaf, slot,
228 struct btrfs_dir_item);
a8a2ee0c 229 found_len = btrfs_dir_name_len(di);
1d4f6404
CM
230 memcpy(buf, (char *)(di + 1), found_len);
231 BUG_ON(found_len > 128);
232 buf[found_len] = '\0';
233 found = atoi(buf + 4);
234 ret = btrfs_del_item(root, &path);
235 count++;
236 if (ret) {
237 fprintf(stderr,
238 "failed to remove %lu from tree\n",
239 found);
240 return -1;
241 }
242 btrfs_release_path(root, &path);
243 ptr = radix_tree_delete(radix, found);
244 if (!ptr)
245 goto error;
246 if (!keep_running)
247 break;
248 }
249 return 0;
250error:
251 fprintf(stderr, "failed to delete from the radix %lu\n", found);
252 return -1;
253}
254
255static int fill_tree(struct btrfs_root *root, struct radix_tree_root *radix,
256 int count)
257{
258 int i;
259 int ret = 0;
260 for (i = 0; i < count; i++) {
261 ret = ins_one(root, radix);
262 if (ret) {
263 fprintf(stderr, "fill failed\n");
264 goto out;
265 }
266 if (i % 1000 == 0) {
267 ret = btrfs_commit_transaction(root, &super);
268 if (ret) {
269 fprintf(stderr, "fill commit failed\n");
270 return ret;
271 }
272 }
273 if (i && i % 10000 == 0) {
274 printf("bigfill %d\n", i);
275 }
276 if (!keep_running)
277 break;
278 }
279out:
280 return ret;
281}
282
283static int bulk_op(struct btrfs_root *root, struct radix_tree_root *radix)
284{
285 int ret;
286 int nr = rand() % 5000;
287 static int run_nr = 0;
288
289 /* do the bulk op much less frequently */
290 if (run_nr++ % 100)
291 return 0;
292 ret = empty_tree(root, radix, nr);
293 if (ret)
294 return ret;
295 ret = fill_tree(root, radix, nr);
296 if (ret)
297 return ret;
298 return 0;
299}
300
301
302int (*ops[])(struct btrfs_root *root, struct radix_tree_root *radix) =
303 { ins_one, insert_dup, del_one, lookup_item,
304 lookup_enoent, bulk_op };
305
306void sigstopper(int ignored)
307{
308 keep_running = 0;
309 fprintf(stderr, "caught exit signal, stopping\n");
310}
311
312int print_usage(void)
313{
314 printf("usage: tester [-ih] [-c count] [-f count]\n");
315 printf("\t -c count -- iteration count after filling\n");
316 printf("\t -f count -- run this many random inserts before starting\n");
317 printf("\t -i -- only do initial fill\n");
318 printf("\t -h -- this help text\n");
319 exit(1);
320}
321int main(int ac, char **av)
322{
323 RADIX_TREE(radix, GFP_KERNEL);
324 struct btrfs_root *root;
325 int i;
326 int ret;
327 int count;
328 int op;
329 int iterations = 20000;
330 int init_fill_count = 800000;
331 int err = 0;
332 int initial_only = 0;
333 radix_tree_init();
334
335 printf("removing old tree\n");
336 unlink("dbfile");
337 root = open_ctree("dbfile", &super);
338
339 signal(SIGTERM, sigstopper);
340 signal(SIGINT, sigstopper);
341
342 for (i = 1 ; i < ac ; i++) {
343 if (strcmp(av[i], "-i") == 0) {
344 initial_only = 1;
345 } else if (strcmp(av[i], "-c") == 0) {
346 iterations = atoi(av[i+1]);
347 i++;
348 } else if (strcmp(av[i], "-f") == 0) {
349 init_fill_count = atoi(av[i+1]);
350 i++;
351 } else {
352 print_usage();
353 }
354 }
355 printf("initial fill\n");
356 ret = fill_tree(root, &radix, init_fill_count);
357 printf("starting run\n");
358 if (ret) {
359 err = ret;
360 goto out;
361 }
362 if (initial_only == 1) {
363 goto out;
364 }
365 for (i = 0; i < iterations; i++) {
366 op = rand() % ARRAY_SIZE(ops);
367 count = rand() % 128;
368 if (i % 2000 == 0) {
369 printf("%d\n", i);
370 fflush(stdout);
371 }
372 if (i && i % 5000 == 0) {
373 printf("open & close, root level %d nritems %d\n",
374 btrfs_header_level(&root->node->node.header),
375 btrfs_header_nritems(&root->node->node.header));
376 close_ctree(root, &super);
377 root = open_ctree("dbfile", &super);
378 }
379 while(count--) {
380 ret = ops[op](root, &radix);
381 if (ret) {
382 fprintf(stderr, "op %d failed %d:%d\n",
383 op, i, iterations);
384 btrfs_print_tree(root, root->node);
385 fprintf(stderr, "op %d failed %d:%d\n",
386 op, i, iterations);
387 err = ret;
388 goto out;
389 }
390 if (ops[op] == bulk_op)
391 break;
392 if (keep_running == 0) {
393 err = 0;
394 goto out;
395 }
396 }
397 }
398out:
399 close_ctree(root, &super);
400 return err;
401}
402