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