dir-test.c 9.0 KB

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