extent-map-tests.c 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  1. /*
  2. * Copyright (C) 2017 Oracle. All rights reserved.
  3. *
  4. * This program is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU General Public
  6. * License v2 as published by the Free Software Foundation.
  7. *
  8. * This program is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. * General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU General Public
  14. * License along with this program; if not, write to the
  15. * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  16. * Boston, MA 021110-1307, USA.
  17. */
  18. #include <linux/types.h>
  19. #include "btrfs-tests.h"
  20. #include "../ctree.h"
  21. static void free_extent_map_tree(struct extent_map_tree *em_tree)
  22. {
  23. struct extent_map *em;
  24. struct rb_node *node;
  25. while (!RB_EMPTY_ROOT(&em_tree->map)) {
  26. node = rb_first(&em_tree->map);
  27. em = rb_entry(node, struct extent_map, rb_node);
  28. remove_extent_mapping(em_tree, em);
  29. #ifdef CONFIG_BTRFS_DEBUG
  30. if (refcount_read(&em->refs) != 1) {
  31. test_msg(
  32. "em leak: em (start 0x%llx len 0x%llx block_start 0x%llx block_len 0x%llx) refs %d\n",
  33. em->start, em->len, em->block_start,
  34. em->block_len, refcount_read(&em->refs));
  35. refcount_set(&em->refs, 1);
  36. }
  37. #endif
  38. free_extent_map(em);
  39. }
  40. }
  41. /*
  42. * Test scenario:
  43. *
  44. * Suppose that no extent map has been loaded into memory yet, there is a file
  45. * extent [0, 16K), followed by another file extent [16K, 20K), two dio reads
  46. * are entering btrfs_get_extent() concurrently, t1 is reading [8K, 16K), t2 is
  47. * reading [0, 8K)
  48. *
  49. * t1 t2
  50. * btrfs_get_extent() btrfs_get_extent()
  51. * -> lookup_extent_mapping() ->lookup_extent_mapping()
  52. * -> add_extent_mapping(0, 16K)
  53. * -> return em
  54. * ->add_extent_mapping(0, 16K)
  55. * -> #handle -EEXIST
  56. */
  57. static void test_case_1(struct extent_map_tree *em_tree)
  58. {
  59. struct extent_map *em;
  60. u64 start = 0;
  61. u64 len = SZ_8K;
  62. int ret;
  63. em = alloc_extent_map();
  64. if (!em)
  65. /* Skip the test on error. */
  66. return;
  67. /* Add [0, 16K) */
  68. em->start = 0;
  69. em->len = SZ_16K;
  70. em->block_start = 0;
  71. em->block_len = SZ_16K;
  72. ret = add_extent_mapping(em_tree, em, 0);
  73. ASSERT(ret == 0);
  74. free_extent_map(em);
  75. /* Add [16K, 20K) following [0, 16K) */
  76. em = alloc_extent_map();
  77. if (!em)
  78. goto out;
  79. em->start = SZ_16K;
  80. em->len = SZ_4K;
  81. em->block_start = SZ_32K; /* avoid merging */
  82. em->block_len = SZ_4K;
  83. ret = add_extent_mapping(em_tree, em, 0);
  84. ASSERT(ret == 0);
  85. free_extent_map(em);
  86. em = alloc_extent_map();
  87. if (!em)
  88. goto out;
  89. /* Add [0, 8K), should return [0, 16K) instead. */
  90. em->start = start;
  91. em->len = len;
  92. em->block_start = start;
  93. em->block_len = len;
  94. ret = btrfs_add_extent_mapping(em_tree, &em, em->start, em->len);
  95. if (ret)
  96. test_msg("case1 [%llu %llu]: ret %d\n", start, start + len, ret);
  97. if (em &&
  98. (em->start != 0 || extent_map_end(em) != SZ_16K ||
  99. em->block_start != 0 || em->block_len != SZ_16K))
  100. test_msg(
  101. "case1 [%llu %llu]: ret %d return a wrong em (start %llu len %llu block_start %llu block_len %llu\n",
  102. start, start + len, ret, em->start, em->len,
  103. em->block_start, em->block_len);
  104. free_extent_map(em);
  105. out:
  106. /* free memory */
  107. free_extent_map_tree(em_tree);
  108. }
  109. /*
  110. * Test scenario:
  111. *
  112. * Reading the inline ending up with EEXIST, ie. read an inline
  113. * extent and discard page cache and read it again.
  114. */
  115. static void test_case_2(struct extent_map_tree *em_tree)
  116. {
  117. struct extent_map *em;
  118. int ret;
  119. em = alloc_extent_map();
  120. if (!em)
  121. /* Skip the test on error. */
  122. return;
  123. /* Add [0, 1K) */
  124. em->start = 0;
  125. em->len = SZ_1K;
  126. em->block_start = EXTENT_MAP_INLINE;
  127. em->block_len = (u64)-1;
  128. ret = add_extent_mapping(em_tree, em, 0);
  129. ASSERT(ret == 0);
  130. free_extent_map(em);
  131. /* Add [4K, 4K) following [0, 1K) */
  132. em = alloc_extent_map();
  133. if (!em)
  134. goto out;
  135. em->start = SZ_4K;
  136. em->len = SZ_4K;
  137. em->block_start = SZ_4K;
  138. em->block_len = SZ_4K;
  139. ret = add_extent_mapping(em_tree, em, 0);
  140. ASSERT(ret == 0);
  141. free_extent_map(em);
  142. em = alloc_extent_map();
  143. if (!em)
  144. goto out;
  145. /* Add [0, 1K) */
  146. em->start = 0;
  147. em->len = SZ_1K;
  148. em->block_start = EXTENT_MAP_INLINE;
  149. em->block_len = (u64)-1;
  150. ret = btrfs_add_extent_mapping(em_tree, &em, em->start, em->len);
  151. if (ret)
  152. test_msg("case2 [0 1K]: ret %d\n", ret);
  153. if (em &&
  154. (em->start != 0 || extent_map_end(em) != SZ_1K ||
  155. em->block_start != EXTENT_MAP_INLINE || em->block_len != (u64)-1))
  156. test_msg(
  157. "case2 [0 1K]: ret %d return a wrong em (start %llu len %llu block_start %llu block_len %llu\n",
  158. ret, em->start, em->len, em->block_start,
  159. em->block_len);
  160. free_extent_map(em);
  161. out:
  162. /* free memory */
  163. free_extent_map_tree(em_tree);
  164. }
  165. static void __test_case_3(struct extent_map_tree *em_tree, u64 start)
  166. {
  167. struct extent_map *em;
  168. u64 len = SZ_4K;
  169. int ret;
  170. em = alloc_extent_map();
  171. if (!em)
  172. /* Skip this test on error. */
  173. return;
  174. /* Add [4K, 8K) */
  175. em->start = SZ_4K;
  176. em->len = SZ_4K;
  177. em->block_start = SZ_4K;
  178. em->block_len = SZ_4K;
  179. ret = add_extent_mapping(em_tree, em, 0);
  180. ASSERT(ret == 0);
  181. free_extent_map(em);
  182. em = alloc_extent_map();
  183. if (!em)
  184. goto out;
  185. /* Add [0, 16K) */
  186. em->start = 0;
  187. em->len = SZ_16K;
  188. em->block_start = 0;
  189. em->block_len = SZ_16K;
  190. ret = btrfs_add_extent_mapping(em_tree, &em, start, len);
  191. if (ret)
  192. test_msg("case3 [0x%llx 0x%llx): ret %d\n",
  193. start, start + len, ret);
  194. /*
  195. * Since bytes within em are contiguous, em->block_start is identical to
  196. * em->start.
  197. */
  198. if (em &&
  199. (start < em->start || start + len > extent_map_end(em) ||
  200. em->start != em->block_start || em->len != em->block_len))
  201. test_msg(
  202. "case3 [0x%llx 0x%llx): ret %d em (start 0x%llx len 0x%llx block_start 0x%llx block_len 0x%llx)\n",
  203. start, start + len, ret, em->start, em->len,
  204. em->block_start, em->block_len);
  205. free_extent_map(em);
  206. out:
  207. /* free memory */
  208. free_extent_map_tree(em_tree);
  209. }
  210. /*
  211. * Test scenario:
  212. *
  213. * Suppose that no extent map has been loaded into memory yet.
  214. * There is a file extent [0, 16K), two jobs are running concurrently
  215. * against it, t1 is buffered writing to [4K, 8K) and t2 is doing dio
  216. * read from [0, 4K) or [8K, 12K) or [12K, 16K).
  217. *
  218. * t1 goes ahead of t2 and adds em [4K, 8K) into tree.
  219. *
  220. * t1 t2
  221. * cow_file_range() btrfs_get_extent()
  222. * -> lookup_extent_mapping()
  223. * -> add_extent_mapping()
  224. * -> add_extent_mapping()
  225. */
  226. static void test_case_3(struct extent_map_tree *em_tree)
  227. {
  228. __test_case_3(em_tree, 0);
  229. __test_case_3(em_tree, SZ_8K);
  230. __test_case_3(em_tree, (12 * 1024ULL));
  231. }
  232. static void __test_case_4(struct extent_map_tree *em_tree, u64 start)
  233. {
  234. struct extent_map *em;
  235. u64 len = SZ_4K;
  236. int ret;
  237. em = alloc_extent_map();
  238. if (!em)
  239. /* Skip this test on error. */
  240. return;
  241. /* Add [0K, 8K) */
  242. em->start = 0;
  243. em->len = SZ_8K;
  244. em->block_start = 0;
  245. em->block_len = SZ_8K;
  246. ret = add_extent_mapping(em_tree, em, 0);
  247. ASSERT(ret == 0);
  248. free_extent_map(em);
  249. em = alloc_extent_map();
  250. if (!em)
  251. goto out;
  252. /* Add [8K, 24K) */
  253. em->start = SZ_8K;
  254. em->len = 24 * 1024ULL;
  255. em->block_start = SZ_16K; /* avoid merging */
  256. em->block_len = 24 * 1024ULL;
  257. ret = add_extent_mapping(em_tree, em, 0);
  258. ASSERT(ret == 0);
  259. free_extent_map(em);
  260. em = alloc_extent_map();
  261. if (!em)
  262. goto out;
  263. /* Add [0K, 32K) */
  264. em->start = 0;
  265. em->len = SZ_32K;
  266. em->block_start = 0;
  267. em->block_len = SZ_32K;
  268. ret = btrfs_add_extent_mapping(em_tree, &em, start, len);
  269. if (ret)
  270. test_msg("case4 [0x%llx 0x%llx): ret %d\n",
  271. start, len, ret);
  272. if (em &&
  273. (start < em->start || start + len > extent_map_end(em)))
  274. test_msg(
  275. "case4 [0x%llx 0x%llx): ret %d, added wrong em (start 0x%llx len 0x%llx block_start 0x%llx block_len 0x%llx)\n",
  276. start, len, ret, em->start, em->len, em->block_start,
  277. em->block_len);
  278. free_extent_map(em);
  279. out:
  280. /* free memory */
  281. free_extent_map_tree(em_tree);
  282. }
  283. /*
  284. * Test scenario:
  285. *
  286. * Suppose that no extent map has been loaded into memory yet.
  287. * There is a file extent [0, 32K), two jobs are running concurrently
  288. * against it, t1 is doing dio write to [8K, 32K) and t2 is doing dio
  289. * read from [0, 4K) or [4K, 8K).
  290. *
  291. * t1 goes ahead of t2 and splits em [0, 32K) to em [0K, 8K) and [8K 32K).
  292. *
  293. * t1 t2
  294. * btrfs_get_blocks_direct() btrfs_get_blocks_direct()
  295. * -> btrfs_get_extent() -> btrfs_get_extent()
  296. * -> lookup_extent_mapping()
  297. * -> add_extent_mapping() -> lookup_extent_mapping()
  298. * # load [0, 32K)
  299. * -> btrfs_new_extent_direct()
  300. * -> btrfs_drop_extent_cache()
  301. * # split [0, 32K)
  302. * -> add_extent_mapping()
  303. * # add [8K, 32K)
  304. * -> add_extent_mapping()
  305. * # handle -EEXIST when adding
  306. * # [0, 32K)
  307. */
  308. static void test_case_4(struct extent_map_tree *em_tree)
  309. {
  310. __test_case_4(em_tree, 0);
  311. __test_case_4(em_tree, SZ_4K);
  312. }
  313. int btrfs_test_extent_map(void)
  314. {
  315. struct extent_map_tree *em_tree;
  316. test_msg("Running extent_map tests\n");
  317. em_tree = kzalloc(sizeof(*em_tree), GFP_KERNEL);
  318. if (!em_tree)
  319. /* Skip the test on error. */
  320. return 0;
  321. extent_map_tree_init(em_tree);
  322. test_case_1(em_tree);
  323. test_case_2(em_tree);
  324. test_case_3(em_tree);
  325. test_case_4(em_tree);
  326. kfree(em_tree);
  327. return 0;
  328. }