extents-test.c 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Written by Ojaswin Mujoo <ojaswin@linux.ibm.com> (IBM)
  4. *
  5. * These Kunit tests are designed to test the functionality of
  6. * extent split and conversion in ext4.
  7. *
  8. * Currently, ext4 can split extents in 2 ways:
  9. * 1. By splitting the extents in the extent tree and optionally converting them
  10. * to written or unwritten based on flags passed.
  11. * 2. In case 1 encounters an error, ext4 instead zerooes out the unwritten
  12. * areas of the extent and marks the complete extent written.
  13. *
  14. * The primary function that handles this is ext4_split_convert_extents().
  15. *
  16. * We test both of the methods of split. The behavior we try to enforce is:
  17. * 1. When passing EXT4_GET_BLOCKS_CONVERT flag to ext4_split_convert_extents(),
  18. * the split extent should be converted to initialized.
  19. * 2. When passing EXT4_GET_BLOCKS_CONVERT_UNWRITTEN flag to
  20. * ext4_split_convert_extents(), the split extent should be converted to
  21. * uninitialized.
  22. * 3. In case we use the zeroout method, then we should correctly write zeroes
  23. * to the unwritten areas of the extent and we should not corrupt/leak any
  24. * data.
  25. *
  26. * Enforcing 1 and 2 is straight forward, we just setup a minimal inode with
  27. * extent tree, call ext4_split_convert_extents() and check the final state of
  28. * the extent tree.
  29. *
  30. * For zeroout testing, we maintain a separate buffer which represents the disk
  31. * data corresponding to the extents. We then override ext4's zeroout functions
  32. * to instead write zeroes to our buffer. Then, we override
  33. * ext4_ext_insert_extent() to return -ENOSPC, which triggers the zeroout.
  34. * Finally, we check the state of the extent tree and zeroout buffer to confirm
  35. * everything went well.
  36. */
  37. #include <kunit/test.h>
  38. #include <kunit/static_stub.h>
  39. #include <linux/gfp_types.h>
  40. #include <linux/stddef.h>
  41. #include "ext4.h"
  42. #include "ext4_extents.h"
  43. #define EXT_DATA_PBLK 100
  44. #define EXT_DATA_LBLK 10
  45. #define EXT_DATA_LEN 3
  46. struct kunit_ctx {
  47. /*
  48. * Ext4 inode which has only 1 unwrit extent
  49. */
  50. struct ext4_inode_info *k_ei;
  51. /*
  52. * Represents the underlying data area (used for zeroout testing)
  53. */
  54. char *k_data;
  55. } k_ctx;
  56. /*
  57. * describes the state of an expected extent in extent tree.
  58. */
  59. struct kunit_ext_state {
  60. ext4_lblk_t ex_lblk;
  61. ext4_lblk_t ex_len;
  62. bool is_unwrit;
  63. };
  64. /*
  65. * describes the state of the data area of a writ extent. Used for testing
  66. * correctness of zeroout.
  67. */
  68. struct kunit_ext_data_state {
  69. char exp_char;
  70. ext4_lblk_t off_blk;
  71. ext4_lblk_t len_blk;
  72. };
  73. enum kunit_test_types {
  74. TEST_SPLIT_CONVERT,
  75. TEST_CREATE_BLOCKS,
  76. };
  77. struct kunit_ext_test_param {
  78. /* description of test */
  79. char *desc;
  80. /* determines which function will be tested */
  81. int type;
  82. /* is extent unwrit at beginning of test */
  83. bool is_unwrit_at_start;
  84. /* flags to pass while splitting */
  85. int split_flags;
  86. /* map describing range to split */
  87. struct ext4_map_blocks split_map;
  88. /* disable zeroout */
  89. bool disable_zeroout;
  90. /* no of extents expected after split */
  91. int nr_exp_ext;
  92. /*
  93. * expected state of extents after split. We will never split into more
  94. * than 3 extents
  95. */
  96. struct kunit_ext_state exp_ext_state[3];
  97. /* Below fields used for zeroout tests */
  98. bool is_zeroout_test;
  99. /*
  100. * no of expected data segments (zeroout tests). Example, if we expect
  101. * data to be 4kb 0s, followed by 8kb non-zero, then nr_exp_data_segs==2
  102. */
  103. int nr_exp_data_segs;
  104. /*
  105. * expected state of data area after zeroout.
  106. */
  107. struct kunit_ext_data_state exp_data_state[3];
  108. };
  109. static void ext_kill_sb(struct super_block *sb)
  110. {
  111. generic_shutdown_super(sb);
  112. }
  113. static int ext_set(struct super_block *sb, void *data)
  114. {
  115. return 0;
  116. }
  117. static struct file_system_type ext_fs_type = {
  118. .name = "extents test",
  119. .kill_sb = ext_kill_sb,
  120. };
  121. static void extents_kunit_exit(struct kunit *test)
  122. {
  123. struct super_block *sb = k_ctx.k_ei->vfs_inode.i_sb;
  124. struct ext4_sb_info *sbi = sb->s_fs_info;
  125. ext4_es_unregister_shrinker(sbi);
  126. kfree(sbi);
  127. kfree(k_ctx.k_ei);
  128. kfree(k_ctx.k_data);
  129. }
  130. static int __ext4_ext_dirty_stub(const char *where, unsigned int line,
  131. handle_t *handle, struct inode *inode,
  132. struct ext4_ext_path *path)
  133. {
  134. return 0;
  135. }
  136. static struct ext4_ext_path *
  137. ext4_ext_insert_extent_stub(handle_t *handle, struct inode *inode,
  138. struct ext4_ext_path *path,
  139. struct ext4_extent *newext, int gb_flags)
  140. {
  141. return ERR_PTR(-ENOSPC);
  142. }
  143. /*
  144. * We will zeroout the equivalent range in the data area
  145. */
  146. static int ext4_ext_zeroout_stub(struct inode *inode, struct ext4_extent *ex)
  147. {
  148. ext4_lblk_t ee_block, off_blk;
  149. loff_t ee_len;
  150. loff_t off_bytes;
  151. struct kunit *test = kunit_get_current_test();
  152. ee_block = le32_to_cpu(ex->ee_block);
  153. ee_len = ext4_ext_get_actual_len(ex);
  154. KUNIT_EXPECT_EQ_MSG(test, 1, ee_block >= EXT_DATA_LBLK, "ee_block=%d",
  155. ee_block);
  156. KUNIT_EXPECT_EQ(test, 1,
  157. ee_block + ee_len <= EXT_DATA_LBLK + EXT_DATA_LEN);
  158. off_blk = ee_block - EXT_DATA_LBLK;
  159. off_bytes = off_blk << inode->i_sb->s_blocksize_bits;
  160. memset(k_ctx.k_data + off_bytes, 0,
  161. ee_len << inode->i_sb->s_blocksize_bits);
  162. return 0;
  163. }
  164. static int ext4_issue_zeroout_stub(struct inode *inode, ext4_lblk_t lblk,
  165. ext4_fsblk_t pblk, ext4_lblk_t len)
  166. {
  167. ext4_lblk_t off_blk;
  168. loff_t off_bytes;
  169. struct kunit *test = kunit_get_current_test();
  170. kunit_log(KERN_ALERT, test,
  171. "%s: lblk=%u pblk=%llu len=%u", __func__, lblk, pblk, len);
  172. KUNIT_EXPECT_EQ(test, 1, lblk >= EXT_DATA_LBLK);
  173. KUNIT_EXPECT_EQ(test, 1, lblk + len <= EXT_DATA_LBLK + EXT_DATA_LEN);
  174. KUNIT_EXPECT_EQ(test, 1, lblk - EXT_DATA_LBLK == pblk - EXT_DATA_PBLK);
  175. off_blk = lblk - EXT_DATA_LBLK;
  176. off_bytes = off_blk << inode->i_sb->s_blocksize_bits;
  177. memset(k_ctx.k_data + off_bytes, 0,
  178. len << inode->i_sb->s_blocksize_bits);
  179. return 0;
  180. }
  181. static int extents_kunit_init(struct kunit *test)
  182. {
  183. struct ext4_extent_header *eh = NULL;
  184. struct ext4_inode_info *ei;
  185. struct inode *inode;
  186. struct super_block *sb;
  187. struct ext4_sb_info *sbi = NULL;
  188. struct kunit_ext_test_param *param =
  189. (struct kunit_ext_test_param *)(test->param_value);
  190. int err;
  191. sb = sget(&ext_fs_type, NULL, ext_set, 0, NULL);
  192. if (IS_ERR(sb))
  193. return PTR_ERR(sb);
  194. sb->s_blocksize = 4096;
  195. sb->s_blocksize_bits = 12;
  196. sbi = kzalloc_obj(struct ext4_sb_info);
  197. if (sbi == NULL)
  198. return -ENOMEM;
  199. sbi->s_sb = sb;
  200. sb->s_fs_info = sbi;
  201. if (!param || !param->disable_zeroout)
  202. sbi->s_extent_max_zeroout_kb = 32;
  203. /* setup the mock inode */
  204. k_ctx.k_ei = kzalloc_obj(struct ext4_inode_info);
  205. if (k_ctx.k_ei == NULL)
  206. return -ENOMEM;
  207. ei = k_ctx.k_ei;
  208. inode = &ei->vfs_inode;
  209. err = ext4_es_register_shrinker(sbi);
  210. if (err)
  211. return err;
  212. ext4_es_init_tree(&ei->i_es_tree);
  213. rwlock_init(&ei->i_es_lock);
  214. INIT_LIST_HEAD(&ei->i_es_list);
  215. ei->i_es_all_nr = 0;
  216. ei->i_es_shk_nr = 0;
  217. ei->i_es_shrink_lblk = 0;
  218. ei->i_disksize = (EXT_DATA_LBLK + EXT_DATA_LEN + 10)
  219. << sb->s_blocksize_bits;
  220. ei->i_flags = 0;
  221. ext4_set_inode_flag(inode, EXT4_INODE_EXTENTS);
  222. inode->i_sb = sb;
  223. k_ctx.k_data = kzalloc(EXT_DATA_LEN * 4096, GFP_KERNEL);
  224. if (k_ctx.k_data == NULL)
  225. return -ENOMEM;
  226. /*
  227. * set the data area to a junk value
  228. */
  229. memset(k_ctx.k_data, 'X', EXT_DATA_LEN * 4096);
  230. /* create a tree with depth 0 */
  231. eh = (struct ext4_extent_header *)k_ctx.k_ei->i_data;
  232. /* Fill extent header */
  233. eh = ext_inode_hdr(&k_ctx.k_ei->vfs_inode);
  234. eh->eh_depth = 0;
  235. eh->eh_entries = cpu_to_le16(1);
  236. eh->eh_magic = EXT4_EXT_MAGIC;
  237. eh->eh_max = cpu_to_le16(ext4_ext_space_root_idx_test(
  238. &k_ctx.k_ei->vfs_inode, 0));
  239. eh->eh_generation = 0;
  240. /*
  241. * add 1 extent in leaf node covering:
  242. * - lblks: [EXT_DATA_LBLK, EXT_DATA_LBLK * + EXT_DATA_LEN)
  243. * - pblks: [EXT_DATA_PBLK, EXT_DATA_PBLK + EXT_DATA_LEN)
  244. */
  245. EXT_FIRST_EXTENT(eh)->ee_block = cpu_to_le32(EXT_DATA_LBLK);
  246. EXT_FIRST_EXTENT(eh)->ee_len = cpu_to_le16(EXT_DATA_LEN);
  247. ext4_ext_store_pblock(EXT_FIRST_EXTENT(eh), EXT_DATA_PBLK);
  248. if (!param || param->is_unwrit_at_start)
  249. ext4_ext_mark_unwritten(EXT_FIRST_EXTENT(eh));
  250. ext4_es_insert_extent(inode, EXT_DATA_LBLK, EXT_DATA_LEN, EXT_DATA_PBLK,
  251. ext4_ext_is_unwritten(EXT_FIRST_EXTENT(eh)) ?
  252. EXTENT_STATUS_UNWRITTEN :
  253. EXTENT_STATUS_WRITTEN,
  254. 0);
  255. /* Add stubs */
  256. kunit_activate_static_stub(test, __ext4_ext_dirty,
  257. __ext4_ext_dirty_stub);
  258. kunit_activate_static_stub(test, ext4_ext_zeroout, ext4_ext_zeroout_stub);
  259. kunit_activate_static_stub(test, ext4_issue_zeroout,
  260. ext4_issue_zeroout_stub);
  261. return 0;
  262. }
  263. /*
  264. * Return 1 if all bytes in the buf equal to c, else return the offset of first mismatch
  265. */
  266. static int check_buffer(char *buf, int c, int size)
  267. {
  268. void *ret = NULL;
  269. ret = memchr_inv(buf, c, size);
  270. if (ret == NULL)
  271. return 0;
  272. kunit_log(KERN_ALERT, kunit_get_current_test(),
  273. "# %s: wrong char found at offset %u (expected:%d got:%d)", __func__,
  274. (u32)((char *)ret - buf), c, *((char *)ret));
  275. return 1;
  276. }
  277. /*
  278. * Simulate a map block call by first calling ext4_map_query_blocks() to
  279. * correctly populate map flags and pblk and then call the
  280. * ext4_map_create_blocks() to do actual split and conversion. This is easier
  281. * than calling ext4_map_blocks() because that needs mocking a lot of unrelated
  282. * functions.
  283. */
  284. static void ext4_map_create_blocks_helper(struct kunit *test,
  285. struct inode *inode,
  286. struct ext4_map_blocks *map,
  287. int flags)
  288. {
  289. int retval = 0;
  290. retval = ext4_map_query_blocks(NULL, inode, map, flags);
  291. if (retval < 0) {
  292. KUNIT_FAIL(test,
  293. "ext4_map_query_blocks() failed. Cannot proceed\n");
  294. return;
  295. }
  296. ext4_map_create_blocks(NULL, inode, map, flags);
  297. }
  298. static void test_split_convert(struct kunit *test)
  299. {
  300. struct ext4_ext_path *path;
  301. struct inode *inode = &k_ctx.k_ei->vfs_inode;
  302. struct ext4_extent *ex;
  303. struct ext4_map_blocks map;
  304. const struct kunit_ext_test_param *param =
  305. (const struct kunit_ext_test_param *)(test->param_value);
  306. int blkbits = inode->i_sb->s_blocksize_bits;
  307. if (param->is_zeroout_test)
  308. /*
  309. * Force zeroout by making ext4_ext_insert_extent return ENOSPC
  310. */
  311. kunit_activate_static_stub(test, ext4_ext_insert_extent,
  312. ext4_ext_insert_extent_stub);
  313. path = ext4_find_extent(inode, EXT_DATA_LBLK, NULL, EXT4_EX_NOCACHE);
  314. ex = path->p_ext;
  315. KUNIT_EXPECT_EQ(test, EXT_DATA_LBLK, le32_to_cpu(ex->ee_block));
  316. KUNIT_EXPECT_EQ(test, EXT_DATA_LEN, ext4_ext_get_actual_len(ex));
  317. KUNIT_EXPECT_EQ(test, param->is_unwrit_at_start,
  318. ext4_ext_is_unwritten(ex));
  319. if (param->is_zeroout_test)
  320. KUNIT_EXPECT_EQ(test, 0,
  321. check_buffer(k_ctx.k_data, 'X',
  322. EXT_DATA_LEN << blkbits));
  323. map.m_lblk = param->split_map.m_lblk;
  324. map.m_len = param->split_map.m_len;
  325. switch (param->type) {
  326. case TEST_SPLIT_CONVERT:
  327. path = ext4_split_convert_extents_test(NULL, inode, &map,
  328. path, param->split_flags, NULL);
  329. break;
  330. case TEST_CREATE_BLOCKS:
  331. ext4_map_create_blocks_helper(test, inode, &map, param->split_flags);
  332. break;
  333. default:
  334. KUNIT_FAIL(test, "param->type %d not support.", param->type);
  335. }
  336. path = ext4_find_extent(inode, EXT_DATA_LBLK, NULL, EXT4_EX_NOCACHE);
  337. ex = path->p_ext;
  338. for (int i = 0; i < param->nr_exp_ext; i++) {
  339. struct kunit_ext_state exp_ext = param->exp_ext_state[i];
  340. bool es_check_needed = param->type != TEST_SPLIT_CONVERT;
  341. struct extent_status es;
  342. int contains_ex, ex_end, es_end, es_pblk;
  343. KUNIT_EXPECT_EQ(test, exp_ext.ex_lblk,
  344. le32_to_cpu(ex->ee_block));
  345. KUNIT_EXPECT_EQ(test, exp_ext.ex_len,
  346. ext4_ext_get_actual_len(ex));
  347. KUNIT_EXPECT_EQ(test, exp_ext.is_unwrit,
  348. ext4_ext_is_unwritten(ex));
  349. /*
  350. * Confirm extent cache is in sync. Note that es cache can be
  351. * merged even when on-disk extents are not so take that into
  352. * account.
  353. *
  354. * Also, ext4_split_convert_extents() forces EXT4_EX_NOCACHE hence
  355. * es status are ignored for that case.
  356. */
  357. if (es_check_needed) {
  358. ext4_es_lookup_extent(inode, le32_to_cpu(ex->ee_block),
  359. NULL, &es, NULL);
  360. ex_end = exp_ext.ex_lblk + exp_ext.ex_len;
  361. es_end = es.es_lblk + es.es_len;
  362. contains_ex = es.es_lblk <= exp_ext.ex_lblk &&
  363. es_end >= ex_end;
  364. es_pblk = ext4_es_pblock(&es) +
  365. (exp_ext.ex_lblk - es.es_lblk);
  366. KUNIT_EXPECT_EQ(test, contains_ex, 1);
  367. KUNIT_EXPECT_EQ(test, ext4_ext_pblock(ex), es_pblk);
  368. KUNIT_EXPECT_EQ(test, 1,
  369. (exp_ext.is_unwrit &&
  370. ext4_es_is_unwritten(&es)) ||
  371. (!exp_ext.is_unwrit &&
  372. ext4_es_is_written(&es)));
  373. }
  374. /* Only printed on failure */
  375. kunit_log(KERN_INFO, test,
  376. "# [extent %d] exp: lblk:%d len:%d unwrit:%d \n", i,
  377. exp_ext.ex_lblk, exp_ext.ex_len, exp_ext.is_unwrit);
  378. kunit_log(KERN_INFO, test,
  379. "# [extent %d] got: lblk:%d len:%d unwrit:%d\n", i,
  380. le32_to_cpu(ex->ee_block),
  381. ext4_ext_get_actual_len(ex),
  382. ext4_ext_is_unwritten(ex));
  383. if (es_check_needed)
  384. kunit_log(
  385. KERN_INFO, test,
  386. "# [extent %d] es: lblk:%d len:%d pblk:%lld type:0x%x\n",
  387. i, es.es_lblk, es.es_len, ext4_es_pblock(&es),
  388. ext4_es_type(&es));
  389. kunit_log(KERN_INFO, test, "------------------\n");
  390. ex = ex + 1;
  391. }
  392. if (!param->is_zeroout_test)
  393. return;
  394. /*
  395. * Check that then data area has been zeroed out correctly
  396. */
  397. for (int i = 0; i < param->nr_exp_data_segs; i++) {
  398. loff_t off, len;
  399. struct kunit_ext_data_state exp_data_seg = param->exp_data_state[i];
  400. off = exp_data_seg.off_blk << blkbits;
  401. len = exp_data_seg.len_blk << blkbits;
  402. KUNIT_EXPECT_EQ_MSG(test, 0,
  403. check_buffer(k_ctx.k_data + off,
  404. exp_data_seg.exp_char, len),
  405. "# corruption in byte range [%lld, %lld)",
  406. off, len);
  407. }
  408. return;
  409. }
  410. static const struct kunit_ext_test_param test_split_convert_params[] = {
  411. /* unwrit to writ splits */
  412. { .desc = "split unwrit extent to 2 extents and convert 1st half writ",
  413. .type = TEST_SPLIT_CONVERT,
  414. .is_unwrit_at_start = 1,
  415. .split_flags = EXT4_GET_BLOCKS_CONVERT,
  416. .split_map = { .m_lblk = EXT_DATA_LBLK, .m_len = 1 },
  417. .nr_exp_ext = 2,
  418. .exp_ext_state = { { .ex_lblk = EXT_DATA_LBLK,
  419. .ex_len = 1,
  420. .is_unwrit = 0 },
  421. { .ex_lblk = EXT_DATA_LBLK + 1,
  422. .ex_len = EXT_DATA_LEN - 1,
  423. .is_unwrit = 1 } },
  424. .is_zeroout_test = 0 },
  425. { .desc = "split unwrit extent to 2 extents and convert 2nd half writ",
  426. .type = TEST_SPLIT_CONVERT,
  427. .is_unwrit_at_start = 1,
  428. .split_flags = EXT4_GET_BLOCKS_CONVERT,
  429. .split_map = { .m_lblk = EXT_DATA_LBLK + 1, .m_len = EXT_DATA_LEN - 1 },
  430. .nr_exp_ext = 2,
  431. .exp_ext_state = { { .ex_lblk = EXT_DATA_LBLK,
  432. .ex_len = 1,
  433. .is_unwrit = 1 },
  434. { .ex_lblk = EXT_DATA_LBLK + 1,
  435. .ex_len = EXT_DATA_LEN - 1,
  436. .is_unwrit = 0 } },
  437. .is_zeroout_test = 0 },
  438. { .desc = "split unwrit extent to 3 extents and convert 2nd half to writ",
  439. .type = TEST_SPLIT_CONVERT,
  440. .is_unwrit_at_start = 1,
  441. .split_flags = EXT4_GET_BLOCKS_CONVERT,
  442. .split_map = { .m_lblk = EXT_DATA_LBLK + 1, .m_len = EXT_DATA_LEN - 2 },
  443. .nr_exp_ext = 3,
  444. .exp_ext_state = { { .ex_lblk = EXT_DATA_LBLK,
  445. .ex_len = 1,
  446. .is_unwrit = 1 },
  447. { .ex_lblk = EXT_DATA_LBLK + 1,
  448. .ex_len = EXT_DATA_LEN - 2,
  449. .is_unwrit = 0 },
  450. { .ex_lblk = EXT_DATA_LBLK + 1 + (EXT_DATA_LEN - 2),
  451. .ex_len = 1,
  452. .is_unwrit = 1 } },
  453. .is_zeroout_test = 0 },
  454. /* writ to unwrit splits */
  455. { .desc = "split writ extent to 2 extents and convert 1st half unwrit",
  456. .type = TEST_SPLIT_CONVERT,
  457. .is_unwrit_at_start = 0,
  458. .split_flags = EXT4_GET_BLOCKS_CONVERT_UNWRITTEN,
  459. .split_map = { .m_lblk = EXT_DATA_LBLK, .m_len = 1 },
  460. .nr_exp_ext = 2,
  461. .exp_ext_state = { { .ex_lblk = EXT_DATA_LBLK,
  462. .ex_len = 1,
  463. .is_unwrit = 1 },
  464. { .ex_lblk = EXT_DATA_LBLK + 1,
  465. .ex_len = EXT_DATA_LEN - 1,
  466. .is_unwrit = 0 } },
  467. .is_zeroout_test = 0 },
  468. { .desc = "split writ extent to 2 extents and convert 2nd half unwrit",
  469. .type = TEST_SPLIT_CONVERT,
  470. .is_unwrit_at_start = 0,
  471. .split_flags = EXT4_GET_BLOCKS_CONVERT_UNWRITTEN,
  472. .split_map = { .m_lblk = EXT_DATA_LBLK + 1, .m_len = EXT_DATA_LEN - 1 },
  473. .nr_exp_ext = 2,
  474. .exp_ext_state = { { .ex_lblk = EXT_DATA_LBLK,
  475. .ex_len = 1,
  476. .is_unwrit = 0 },
  477. { .ex_lblk = EXT_DATA_LBLK + 1,
  478. .ex_len = EXT_DATA_LEN - 1,
  479. .is_unwrit = 1 } },
  480. .is_zeroout_test = 0 },
  481. { .desc = "split writ extent to 3 extents and convert 2nd half to unwrit",
  482. .type = TEST_SPLIT_CONVERT,
  483. .is_unwrit_at_start = 0,
  484. .split_flags = EXT4_GET_BLOCKS_CONVERT_UNWRITTEN,
  485. .split_map = { .m_lblk = EXT_DATA_LBLK + 1, .m_len = EXT_DATA_LEN - 2 },
  486. .nr_exp_ext = 3,
  487. .exp_ext_state = { { .ex_lblk = EXT_DATA_LBLK,
  488. .ex_len = 1,
  489. .is_unwrit = 0 },
  490. { .ex_lblk = EXT_DATA_LBLK + 1,
  491. .ex_len = EXT_DATA_LEN - 2,
  492. .is_unwrit = 1 },
  493. { .ex_lblk = EXT_DATA_LBLK + 1 + (EXT_DATA_LEN - 2),
  494. .ex_len = 1,
  495. .is_unwrit = 0 } },
  496. .is_zeroout_test = 0 },
  497. /*
  498. * ***** zeroout tests *****
  499. */
  500. /* unwrit to writ splits */
  501. { .desc = "split unwrit extent to 2 extents and convert 1st half writ (zeroout)",
  502. .type = TEST_SPLIT_CONVERT,
  503. .is_unwrit_at_start = 1,
  504. .split_flags = EXT4_GET_BLOCKS_CONVERT,
  505. .split_map = { .m_lblk = EXT_DATA_LBLK, .m_len = 1 },
  506. .nr_exp_ext = 1,
  507. .exp_ext_state = { { .ex_lblk = EXT_DATA_LBLK,
  508. .ex_len = EXT_DATA_LEN,
  509. .is_unwrit = 0 } },
  510. .is_zeroout_test = 1,
  511. .nr_exp_data_segs = 2,
  512. .exp_data_state = { { .exp_char = 'X', .off_blk = 0, .len_blk = 1 },
  513. { .exp_char = 0,
  514. .off_blk = 1,
  515. .len_blk = EXT_DATA_LEN - 1 } } },
  516. { .desc = "split unwrit extent to 2 extents and convert 2nd half writ (zeroout)",
  517. .type = TEST_SPLIT_CONVERT,
  518. .is_unwrit_at_start = 1,
  519. .split_flags = EXT4_GET_BLOCKS_CONVERT,
  520. .split_map = { .m_lblk = EXT_DATA_LBLK + 1, .m_len = EXT_DATA_LEN - 1 },
  521. .nr_exp_ext = 1,
  522. .exp_ext_state = { { .ex_lblk = EXT_DATA_LBLK,
  523. .ex_len = EXT_DATA_LEN,
  524. .is_unwrit = 0 } },
  525. .is_zeroout_test = 1,
  526. .nr_exp_data_segs = 2,
  527. .exp_data_state = { { .exp_char = 0, .off_blk = 0, .len_blk = 1 },
  528. { .exp_char = 'X',
  529. .off_blk = 1,
  530. .len_blk = EXT_DATA_LEN - 1 } } },
  531. { .desc = "split unwrit extent to 3 extents and convert 2nd half writ (zeroout)",
  532. .type = TEST_SPLIT_CONVERT,
  533. .is_unwrit_at_start = 1,
  534. .split_flags = EXT4_GET_BLOCKS_CONVERT,
  535. .split_map = { .m_lblk = EXT_DATA_LBLK + 1, .m_len = EXT_DATA_LEN - 2 },
  536. .nr_exp_ext = 1,
  537. .exp_ext_state = { { .ex_lblk = EXT_DATA_LBLK,
  538. .ex_len = EXT_DATA_LEN,
  539. .is_unwrit = 0 } },
  540. .is_zeroout_test = 1,
  541. .nr_exp_data_segs = 3,
  542. .exp_data_state = { { .exp_char = 0, .off_blk = 0, .len_blk = 1 },
  543. { .exp_char = 'X', .off_blk = 1, .len_blk = EXT_DATA_LEN - 2 },
  544. { .exp_char = 0, .off_blk = EXT_DATA_LEN - 1, .len_blk = 1 } } },
  545. /* writ to unwrit splits */
  546. { .desc = "split writ extent to 2 extents and convert 1st half unwrit (zeroout)",
  547. .type = TEST_SPLIT_CONVERT,
  548. .is_unwrit_at_start = 0,
  549. .split_flags = EXT4_GET_BLOCKS_CONVERT_UNWRITTEN,
  550. .split_map = { .m_lblk = EXT_DATA_LBLK, .m_len = 1 },
  551. .nr_exp_ext = 1,
  552. .exp_ext_state = { { .ex_lblk = EXT_DATA_LBLK,
  553. .ex_len = EXT_DATA_LEN,
  554. .is_unwrit = 0 } },
  555. .is_zeroout_test = 1,
  556. .nr_exp_data_segs = 2,
  557. .exp_data_state = { { .exp_char = 0, .off_blk = 0, .len_blk = 1 },
  558. { .exp_char = 'X',
  559. .off_blk = 1,
  560. .len_blk = EXT_DATA_LEN - 1 } } },
  561. { .desc = "split writ extent to 2 extents and convert 2nd half unwrit (zeroout)",
  562. .type = TEST_SPLIT_CONVERT,
  563. .is_unwrit_at_start = 0,
  564. .split_flags = EXT4_GET_BLOCKS_CONVERT_UNWRITTEN,
  565. .split_map = { .m_lblk = EXT_DATA_LBLK + 1, .m_len = EXT_DATA_LEN - 1 },
  566. .nr_exp_ext = 1,
  567. .exp_ext_state = { { .ex_lblk = EXT_DATA_LBLK,
  568. .ex_len = EXT_DATA_LEN,
  569. .is_unwrit = 0 } },
  570. .is_zeroout_test = 1,
  571. .nr_exp_data_segs = 2,
  572. .exp_data_state = { { .exp_char = 'X', .off_blk = 0, .len_blk = 1 },
  573. { .exp_char = 0,
  574. .off_blk = 1,
  575. .len_blk = EXT_DATA_LEN - 1 } } },
  576. { .desc = "split writ extent to 3 extents and convert 2nd half unwrit (zeroout)",
  577. .type = TEST_SPLIT_CONVERT,
  578. .is_unwrit_at_start = 0,
  579. .split_flags = EXT4_GET_BLOCKS_CONVERT_UNWRITTEN,
  580. .split_map = { .m_lblk = EXT_DATA_LBLK + 1, .m_len = EXT_DATA_LEN - 2 },
  581. .nr_exp_ext = 1,
  582. .exp_ext_state = { { .ex_lblk = EXT_DATA_LBLK,
  583. .ex_len = EXT_DATA_LEN,
  584. .is_unwrit = 0 } },
  585. .is_zeroout_test = 1,
  586. .nr_exp_data_segs = 3,
  587. .exp_data_state = { { .exp_char = 'X', .off_blk = 0, .len_blk = 1 },
  588. { .exp_char = 0,
  589. .off_blk = 1,
  590. .len_blk = EXT_DATA_LEN - 2 },
  591. { .exp_char = 'X',
  592. .off_blk = EXT_DATA_LEN - 1,
  593. .len_blk = 1 } } },
  594. };
  595. /* Tests to trigger ext4_ext_map_blocks() -> convert_initialized_extent() */
  596. static const struct kunit_ext_test_param test_convert_initialized_params[] = {
  597. /* writ to unwrit splits */
  598. { .desc = "split writ extent to 2 extents and convert 1st half unwrit",
  599. .type = TEST_CREATE_BLOCKS,
  600. .split_flags = EXT4_GET_BLOCKS_CONVERT_UNWRITTEN,
  601. .is_unwrit_at_start = 0,
  602. .split_map = { .m_lblk = EXT_DATA_LBLK, .m_len = 1 },
  603. .nr_exp_ext = 2,
  604. .exp_ext_state = { { .ex_lblk = EXT_DATA_LBLK,
  605. .ex_len = 1,
  606. .is_unwrit = 1 },
  607. { .ex_lblk = EXT_DATA_LBLK + 1,
  608. .ex_len = EXT_DATA_LEN - 1,
  609. .is_unwrit = 0 } },
  610. .is_zeroout_test = 0 },
  611. { .desc = "split writ extent to 2 extents and convert 2nd half unwrit",
  612. .type = TEST_CREATE_BLOCKS,
  613. .split_flags = EXT4_GET_BLOCKS_CONVERT_UNWRITTEN,
  614. .is_unwrit_at_start = 0,
  615. .split_map = { .m_lblk = EXT_DATA_LBLK + 1, .m_len = EXT_DATA_LEN - 1 },
  616. .nr_exp_ext = 2,
  617. .exp_ext_state = { { .ex_lblk = EXT_DATA_LBLK,
  618. .ex_len = 1,
  619. .is_unwrit = 0 },
  620. { .ex_lblk = EXT_DATA_LBLK + 1,
  621. .ex_len = EXT_DATA_LEN - 1,
  622. .is_unwrit = 1 } },
  623. .is_zeroout_test = 0 },
  624. { .desc = "split writ extent to 3 extents and convert 2nd half to unwrit",
  625. .type = TEST_CREATE_BLOCKS,
  626. .split_flags = EXT4_GET_BLOCKS_CONVERT_UNWRITTEN,
  627. .is_unwrit_at_start = 0,
  628. .split_map = { .m_lblk = EXT_DATA_LBLK + 1, .m_len = EXT_DATA_LEN - 2 },
  629. .nr_exp_ext = 3,
  630. .exp_ext_state = { { .ex_lblk = EXT_DATA_LBLK,
  631. .ex_len = 1,
  632. .is_unwrit = 0 },
  633. { .ex_lblk = EXT_DATA_LBLK + 1,
  634. .ex_len = EXT_DATA_LEN - 2,
  635. .is_unwrit = 1 },
  636. { .ex_lblk = EXT_DATA_LBLK + 1 + (EXT_DATA_LEN - 2),
  637. .ex_len = 1,
  638. .is_unwrit = 0 } },
  639. .is_zeroout_test = 0 },
  640. /* writ to unwrit splits (zeroout) */
  641. { .desc = "split writ extent to 2 extents and convert 1st half unwrit (zeroout)",
  642. .type = TEST_CREATE_BLOCKS,
  643. .is_unwrit_at_start = 0,
  644. .split_flags = EXT4_GET_BLOCKS_CONVERT_UNWRITTEN,
  645. .split_map = { .m_lblk = EXT_DATA_LBLK, .m_len = 1 },
  646. .nr_exp_ext = 1,
  647. .exp_ext_state = { { .ex_lblk = EXT_DATA_LBLK,
  648. .ex_len = EXT_DATA_LEN,
  649. .is_unwrit = 0 } },
  650. .is_zeroout_test = 1,
  651. .nr_exp_data_segs = 2,
  652. .exp_data_state = { { .exp_char = 0, .off_blk = 0, .len_blk = 1 },
  653. { .exp_char = 'X',
  654. .off_blk = 1,
  655. .len_blk = EXT_DATA_LEN - 1 } } },
  656. { .desc = "split writ extent to 2 extents and convert 2nd half unwrit (zeroout)",
  657. .type = TEST_CREATE_BLOCKS,
  658. .is_unwrit_at_start = 0,
  659. .split_flags = EXT4_GET_BLOCKS_CONVERT_UNWRITTEN,
  660. .split_map = { .m_lblk = EXT_DATA_LBLK + 1, .m_len = EXT_DATA_LEN - 1 },
  661. .nr_exp_ext = 1,
  662. .exp_ext_state = { { .ex_lblk = EXT_DATA_LBLK,
  663. .ex_len = EXT_DATA_LEN,
  664. .is_unwrit = 0 } },
  665. .is_zeroout_test = 1,
  666. .nr_exp_data_segs = 2,
  667. .exp_data_state = { { .exp_char = 'X', .off_blk = 0, .len_blk = 1 },
  668. { .exp_char = 0,
  669. .off_blk = 1,
  670. .len_blk = EXT_DATA_LEN - 1 } } },
  671. { .desc = "split writ extent to 3 extents and convert 2nd half unwrit (zeroout)",
  672. .type = TEST_CREATE_BLOCKS,
  673. .is_unwrit_at_start = 0,
  674. .split_flags = EXT4_GET_BLOCKS_CONVERT_UNWRITTEN,
  675. .split_map = { .m_lblk = EXT_DATA_LBLK + 1, .m_len = EXT_DATA_LEN - 2 },
  676. .nr_exp_ext = 1,
  677. .exp_ext_state = { { .ex_lblk = EXT_DATA_LBLK,
  678. .ex_len = EXT_DATA_LEN,
  679. .is_unwrit = 0 } },
  680. .is_zeroout_test = 1,
  681. .nr_exp_data_segs = 3,
  682. .exp_data_state = { { .exp_char = 'X', .off_blk = 0, .len_blk = 1 },
  683. { .exp_char = 0,
  684. .off_blk = 1,
  685. .len_blk = EXT_DATA_LEN - 2 },
  686. { .exp_char = 'X',
  687. .off_blk = EXT_DATA_LEN - 1,
  688. .len_blk = 1 } } },
  689. };
  690. /* Tests to trigger ext4_ext_map_blocks() -> ext4_ext_handle_unwritten_exntents() */
  691. static const struct kunit_ext_test_param test_handle_unwritten_params[] = {
  692. /* unwrit to writ splits via endio path */
  693. { .desc = "split unwrit extent to 2 extents and convert 1st half writ (endio)",
  694. .type = TEST_CREATE_BLOCKS,
  695. .is_unwrit_at_start = 1,
  696. .split_flags = EXT4_GET_BLOCKS_CONVERT,
  697. .split_map = { .m_lblk = EXT_DATA_LBLK, .m_len = 1 },
  698. .nr_exp_ext = 2,
  699. .exp_ext_state = { { .ex_lblk = EXT_DATA_LBLK,
  700. .ex_len = 1,
  701. .is_unwrit = 0 },
  702. { .ex_lblk = EXT_DATA_LBLK + 1,
  703. .ex_len = EXT_DATA_LEN - 1,
  704. .is_unwrit = 1 } },
  705. .is_zeroout_test = 0 },
  706. { .desc = "split unwrit extent to 2 extents and convert 2nd half writ (endio)",
  707. .type = TEST_CREATE_BLOCKS,
  708. .is_unwrit_at_start = 1,
  709. .split_flags = EXT4_GET_BLOCKS_CONVERT,
  710. .split_map = { .m_lblk = EXT_DATA_LBLK + 1, .m_len = EXT_DATA_LEN - 1 },
  711. .nr_exp_ext = 2,
  712. .exp_ext_state = { { .ex_lblk = EXT_DATA_LBLK,
  713. .ex_len = 1,
  714. .is_unwrit = 1 },
  715. { .ex_lblk = EXT_DATA_LBLK + 1,
  716. .ex_len = EXT_DATA_LEN - 1,
  717. .is_unwrit = 0 } },
  718. .is_zeroout_test = 0 },
  719. { .desc = "split unwrit extent to 3 extents and convert 2nd half to writ (endio)",
  720. .type = TEST_CREATE_BLOCKS,
  721. .is_unwrit_at_start = 1,
  722. .split_flags = EXT4_GET_BLOCKS_CONVERT,
  723. .split_map = { .m_lblk = EXT_DATA_LBLK + 1, .m_len = EXT_DATA_LEN - 2 },
  724. .nr_exp_ext = 3,
  725. .exp_ext_state = { { .ex_lblk = EXT_DATA_LBLK,
  726. .ex_len = 1,
  727. .is_unwrit = 1 },
  728. { .ex_lblk = EXT_DATA_LBLK + 1,
  729. .ex_len = EXT_DATA_LEN - 2,
  730. .is_unwrit = 0 },
  731. { .ex_lblk = EXT_DATA_LBLK + 1 + (EXT_DATA_LEN - 2),
  732. .ex_len = 1,
  733. .is_unwrit = 1 } },
  734. .is_zeroout_test = 0 },
  735. /* unwrit to writ splits via non-endio path */
  736. { .desc = "split unwrit extent to 2 extents and convert 1st half writ (non endio)",
  737. .type = TEST_CREATE_BLOCKS,
  738. .is_unwrit_at_start = 1,
  739. .split_flags = EXT4_GET_BLOCKS_CREATE,
  740. .split_map = { .m_lblk = EXT_DATA_LBLK, .m_len = 1 },
  741. .nr_exp_ext = 2,
  742. .disable_zeroout = true,
  743. .exp_ext_state = { { .ex_lblk = EXT_DATA_LBLK,
  744. .ex_len = 1,
  745. .is_unwrit = 0 },
  746. { .ex_lblk = EXT_DATA_LBLK + 1,
  747. .ex_len = EXT_DATA_LEN - 1,
  748. .is_unwrit = 1 } },
  749. .is_zeroout_test = 0 },
  750. { .desc = "split unwrit extent to 2 extents and convert 2nd half writ (non endio)",
  751. .type = TEST_CREATE_BLOCKS,
  752. .is_unwrit_at_start = 1,
  753. .split_flags = EXT4_GET_BLOCKS_CREATE,
  754. .split_map = { .m_lblk = EXT_DATA_LBLK + 1, .m_len = EXT_DATA_LEN - 1 },
  755. .nr_exp_ext = 2,
  756. .disable_zeroout = true,
  757. .exp_ext_state = { { .ex_lblk = EXT_DATA_LBLK,
  758. .ex_len = 1,
  759. .is_unwrit = 1 },
  760. { .ex_lblk = EXT_DATA_LBLK + 1,
  761. .ex_len = EXT_DATA_LEN - 1,
  762. .is_unwrit = 0 } },
  763. .is_zeroout_test = 0 },
  764. { .desc = "split unwrit extent to 3 extents and convert 2nd half to writ (non endio)",
  765. .type = TEST_CREATE_BLOCKS,
  766. .is_unwrit_at_start = 1,
  767. .split_flags = EXT4_GET_BLOCKS_CREATE,
  768. .split_map = { .m_lblk = EXT_DATA_LBLK + 1, .m_len = EXT_DATA_LEN - 2 },
  769. .nr_exp_ext = 3,
  770. .disable_zeroout = true,
  771. .exp_ext_state = { { .ex_lblk = EXT_DATA_LBLK,
  772. .ex_len = 1,
  773. .is_unwrit = 1 },
  774. { .ex_lblk = EXT_DATA_LBLK + 1,
  775. .ex_len = EXT_DATA_LEN - 2,
  776. .is_unwrit = 0 },
  777. { .ex_lblk = EXT_DATA_LBLK + 1 + (EXT_DATA_LEN - 2),
  778. .ex_len = 1,
  779. .is_unwrit = 1 } },
  780. .is_zeroout_test = 0 },
  781. /*
  782. * ***** zeroout tests *****
  783. */
  784. /* unwrit to writ splits (endio)*/
  785. { .desc = "split unwrit extent to 2 extents and convert 1st half writ (endio, zeroout)",
  786. .type = TEST_CREATE_BLOCKS,
  787. .is_unwrit_at_start = 1,
  788. .split_flags = EXT4_GET_BLOCKS_CONVERT,
  789. .split_map = { .m_lblk = EXT_DATA_LBLK, .m_len = 1 },
  790. .nr_exp_ext = 1,
  791. .exp_ext_state = { { .ex_lblk = EXT_DATA_LBLK,
  792. .ex_len = EXT_DATA_LEN,
  793. .is_unwrit = 0 } },
  794. .is_zeroout_test = 1,
  795. .nr_exp_data_segs = 2,
  796. .exp_data_state = { { .exp_char = 'X', .off_blk = 0, .len_blk = 1 },
  797. { .exp_char = 0,
  798. .off_blk = 1,
  799. .len_blk = EXT_DATA_LEN - 1 } } },
  800. { .desc = "split unwrit extent to 2 extents and convert 2nd half writ (endio, zeroout)",
  801. .type = TEST_CREATE_BLOCKS,
  802. .is_unwrit_at_start = 1,
  803. .split_flags = EXT4_GET_BLOCKS_CONVERT,
  804. .split_map = { .m_lblk = EXT_DATA_LBLK + 1, .m_len = EXT_DATA_LEN - 1 },
  805. .nr_exp_ext = 1,
  806. .exp_ext_state = { { .ex_lblk = EXT_DATA_LBLK,
  807. .ex_len = EXT_DATA_LEN,
  808. .is_unwrit = 0 } },
  809. .is_zeroout_test = 1,
  810. .nr_exp_data_segs = 2,
  811. .exp_data_state = { { .exp_char = 0, .off_blk = 0, .len_blk = 1 },
  812. { .exp_char = 'X',
  813. .off_blk = 1,
  814. .len_blk = EXT_DATA_LEN - 1 } } },
  815. { .desc = "split unwrit extent to 3 extents and convert 2nd half writ (endio, zeroout)",
  816. .type = TEST_CREATE_BLOCKS,
  817. .is_unwrit_at_start = 1,
  818. .split_flags = EXT4_GET_BLOCKS_CONVERT,
  819. .split_map = { .m_lblk = EXT_DATA_LBLK + 1, .m_len = EXT_DATA_LEN - 2 },
  820. .nr_exp_ext = 1,
  821. .exp_ext_state = { { .ex_lblk = EXT_DATA_LBLK,
  822. .ex_len = EXT_DATA_LEN,
  823. .is_unwrit = 0 } },
  824. .is_zeroout_test = 1,
  825. .nr_exp_data_segs = 3,
  826. .exp_data_state = { { .exp_char = 0, .off_blk = 0, .len_blk = 1 },
  827. { .exp_char = 'X',
  828. .off_blk = 1,
  829. .len_blk = EXT_DATA_LEN - 2 },
  830. { .exp_char = 0,
  831. .off_blk = EXT_DATA_LEN - 1,
  832. .len_blk = 1 } } },
  833. /* unwrit to writ splits (non-endio)*/
  834. { .desc = "split unwrit extent to 2 extents and convert 1st half writ (non-endio, zeroout)",
  835. .type = TEST_CREATE_BLOCKS,
  836. .is_unwrit_at_start = 1,
  837. .split_flags = EXT4_GET_BLOCKS_CREATE,
  838. .split_map = { .m_lblk = EXT_DATA_LBLK, .m_len = 1 },
  839. .nr_exp_ext = 1,
  840. .exp_ext_state = { { .ex_lblk = EXT_DATA_LBLK,
  841. .ex_len = EXT_DATA_LEN,
  842. .is_unwrit = 0 } },
  843. .is_zeroout_test = 1,
  844. .nr_exp_data_segs = 2,
  845. .exp_data_state = { { .exp_char = 'X', .off_blk = 0, .len_blk = 1 },
  846. { .exp_char = 0,
  847. .off_blk = 1,
  848. .len_blk = EXT_DATA_LEN - 1 } } },
  849. { .desc = "split unwrit extent to 2 extents and convert 2nd half writ (non-endio, zeroout)",
  850. .type = TEST_CREATE_BLOCKS,
  851. .is_unwrit_at_start = 1,
  852. .split_flags = EXT4_GET_BLOCKS_CREATE,
  853. .split_map = { .m_lblk = EXT_DATA_LBLK + 1, .m_len = EXT_DATA_LEN - 1 },
  854. .nr_exp_ext = 1,
  855. .exp_ext_state = { { .ex_lblk = EXT_DATA_LBLK,
  856. .ex_len = EXT_DATA_LEN,
  857. .is_unwrit = 0 } },
  858. .is_zeroout_test = 1,
  859. .nr_exp_data_segs = 2,
  860. .exp_data_state = { { .exp_char = 0, .off_blk = 0, .len_blk = 1 },
  861. { .exp_char = 'X',
  862. .off_blk = 1,
  863. .len_blk = EXT_DATA_LEN - 1 } } },
  864. { .desc = "split unwrit extent to 3 extents and convert 2nd half writ (non-endio, zeroout)",
  865. .type = TEST_CREATE_BLOCKS,
  866. .is_unwrit_at_start = 1,
  867. .split_flags = EXT4_GET_BLOCKS_CREATE,
  868. .split_map = { .m_lblk = EXT_DATA_LBLK + 1, .m_len = EXT_DATA_LEN - 2 },
  869. .nr_exp_ext = 1,
  870. .exp_ext_state = { { .ex_lblk = EXT_DATA_LBLK,
  871. .ex_len = EXT_DATA_LEN,
  872. .is_unwrit = 0 } },
  873. .is_zeroout_test = 1,
  874. .nr_exp_data_segs = 3,
  875. .exp_data_state = { { .exp_char = 0, .off_blk = 0, .len_blk = 1 },
  876. { .exp_char = 'X',
  877. .off_blk = 1,
  878. .len_blk = EXT_DATA_LEN - 2 },
  879. { .exp_char = 0,
  880. .off_blk = EXT_DATA_LEN - 1,
  881. .len_blk = 1 } } },
  882. };
  883. static void ext_get_desc(struct kunit *test, const void *p, char *desc)
  884. {
  885. struct kunit_ext_test_param *param = (struct kunit_ext_test_param *)p;
  886. snprintf(desc, KUNIT_PARAM_DESC_SIZE, "%s %s\n", param->desc,
  887. (param->type & TEST_CREATE_BLOCKS) ? "(highlevel)" : "");
  888. }
  889. static int test_split_convert_param_init(struct kunit *test)
  890. {
  891. size_t arr_size = ARRAY_SIZE(test_split_convert_params);
  892. kunit_register_params_array(test, test_split_convert_params, arr_size,
  893. ext_get_desc);
  894. return 0;
  895. }
  896. static int test_convert_initialized_param_init(struct kunit *test)
  897. {
  898. size_t arr_size = ARRAY_SIZE(test_convert_initialized_params);
  899. kunit_register_params_array(test, test_convert_initialized_params,
  900. arr_size, ext_get_desc);
  901. return 0;
  902. }
  903. static int test_handle_unwritten_init(struct kunit *test)
  904. {
  905. size_t arr_size = ARRAY_SIZE(test_handle_unwritten_params);
  906. kunit_register_params_array(test, test_handle_unwritten_params,
  907. arr_size, ext_get_desc);
  908. return 0;
  909. }
  910. /*
  911. * Note that we use KUNIT_CASE_PARAM_WITH_INIT() instead of the more compact
  912. * KUNIT_ARRAY_PARAM() because the later currently has a limitation causing the
  913. * output parsing to be prone to error. For more context:
  914. *
  915. * https://lore.kernel.org/linux-kselftest/aULJpTvJDw9ctUDe@li-dc0c254c-257c-11b2-a85c-98b6c1322444.ibm.com/
  916. */
  917. static struct kunit_case extents_test_cases[] = {
  918. KUNIT_CASE_PARAM_WITH_INIT(test_split_convert, kunit_array_gen_params,
  919. test_split_convert_param_init, NULL),
  920. KUNIT_CASE_PARAM_WITH_INIT(test_split_convert, kunit_array_gen_params,
  921. test_convert_initialized_param_init, NULL),
  922. KUNIT_CASE_PARAM_WITH_INIT(test_split_convert, kunit_array_gen_params,
  923. test_handle_unwritten_init, NULL),
  924. {}
  925. };
  926. static struct kunit_suite extents_test_suite = {
  927. .name = "ext4_extents_test",
  928. .init = extents_kunit_init,
  929. .exit = extents_kunit_exit,
  930. .test_cases = extents_test_cases,
  931. };
  932. kunit_test_suites(&extents_test_suite);
  933. MODULE_LICENSE("GPL");