test_superblocks.toml 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660
  1. # simple formatting test
  2. [cases.test_superblocks_format]
  3. code = '''
  4. lfs_t lfs;
  5. lfs_format(&lfs, cfg) => 0;
  6. '''
  7. # mount/unmount
  8. [cases.test_superblocks_mount]
  9. code = '''
  10. lfs_t lfs;
  11. lfs_format(&lfs, cfg) => 0;
  12. lfs_mount(&lfs, cfg) => 0;
  13. lfs_unmount(&lfs) => 0;
  14. '''
  15. # make sure the magic string "littlefs" is always at offset=8
  16. [cases.test_superblocks_magic]
  17. code = '''
  18. lfs_t lfs;
  19. lfs_format(&lfs, cfg) => 0;
  20. // check our magic string
  21. //
  22. // note if we lose power we may not have the magic string in both blocks!
  23. // but we don't lose power in this test so we can assert the magic string
  24. // is present in both
  25. uint8_t magic[lfs_max(16, READ_SIZE)];
  26. cfg->read(cfg, 0, 0, magic, lfs_max(16, READ_SIZE)) => 0;
  27. assert(memcmp(&magic[8], "littlefs", 8) == 0);
  28. cfg->read(cfg, 1, 0, magic, lfs_max(16, READ_SIZE)) => 0;
  29. assert(memcmp(&magic[8], "littlefs", 8) == 0);
  30. '''
  31. # mount/unmount from interpretting a previous superblock block_count
  32. [cases.test_superblocks_mount_unknown_block_count]
  33. code = '''
  34. lfs_t lfs;
  35. lfs_format(&lfs, cfg) => 0;
  36. memset(&lfs, 0, sizeof(lfs));
  37. struct lfs_config tweaked_cfg = *cfg;
  38. tweaked_cfg.block_count = 0;
  39. lfs_mount(&lfs, &tweaked_cfg) => 0;
  40. assert(lfs.block_count == cfg->block_count);
  41. lfs_unmount(&lfs) => 0;
  42. '''
  43. # reentrant format
  44. [cases.test_superblocks_reentrant_format]
  45. reentrant = true
  46. defines.POWERLOSS_BEHAVIOR = [
  47. 'LFS_EMUBD_POWERLOSS_NOOP',
  48. 'LFS_EMUBD_POWERLOSS_OOO',
  49. ]
  50. code = '''
  51. lfs_t lfs;
  52. int err = lfs_mount(&lfs, cfg);
  53. if (err) {
  54. lfs_format(&lfs, cfg) => 0;
  55. lfs_mount(&lfs, cfg) => 0;
  56. }
  57. lfs_unmount(&lfs) => 0;
  58. '''
  59. # invalid mount
  60. [cases.test_superblocks_invalid_mount]
  61. code = '''
  62. lfs_t lfs;
  63. lfs_mount(&lfs, cfg) => LFS_ERR_CORRUPT;
  64. '''
  65. # test we can read superblock info through lfs_fs_stat
  66. [cases.test_superblocks_stat]
  67. if = 'DISK_VERSION == 0'
  68. code = '''
  69. lfs_t lfs;
  70. lfs_format(&lfs, cfg) => 0;
  71. // test we can mount and read fsinfo
  72. lfs_mount(&lfs, cfg) => 0;
  73. struct lfs_fsinfo fsinfo;
  74. lfs_fs_stat(&lfs, &fsinfo) => 0;
  75. assert(fsinfo.disk_version == LFS_DISK_VERSION);
  76. assert(fsinfo.name_max == LFS_NAME_MAX);
  77. assert(fsinfo.file_max == LFS_FILE_MAX);
  78. assert(fsinfo.attr_max == LFS_ATTR_MAX);
  79. lfs_unmount(&lfs) => 0;
  80. '''
  81. [cases.test_superblocks_stat_tweaked]
  82. if = 'DISK_VERSION == 0'
  83. defines.TWEAKED_NAME_MAX = 63
  84. defines.TWEAKED_FILE_MAX = '(1 << 16)-1'
  85. defines.TWEAKED_ATTR_MAX = 512
  86. code = '''
  87. // create filesystem with tweaked params
  88. struct lfs_config tweaked_cfg = *cfg;
  89. tweaked_cfg.name_max = TWEAKED_NAME_MAX;
  90. tweaked_cfg.file_max = TWEAKED_FILE_MAX;
  91. tweaked_cfg.attr_max = TWEAKED_ATTR_MAX;
  92. lfs_t lfs;
  93. lfs_format(&lfs, &tweaked_cfg) => 0;
  94. // test we can mount and read these params with the original config
  95. lfs_mount(&lfs, cfg) => 0;
  96. struct lfs_fsinfo fsinfo;
  97. lfs_fs_stat(&lfs, &fsinfo) => 0;
  98. assert(fsinfo.disk_version == LFS_DISK_VERSION);
  99. assert(fsinfo.name_max == TWEAKED_NAME_MAX);
  100. assert(fsinfo.file_max == TWEAKED_FILE_MAX);
  101. assert(fsinfo.attr_max == TWEAKED_ATTR_MAX);
  102. lfs_unmount(&lfs) => 0;
  103. '''
  104. # expanding superblock
  105. [cases.test_superblocks_expand]
  106. defines.BLOCK_CYCLES = [32, 33, 1]
  107. defines.N = [10, 100, 1000]
  108. code = '''
  109. lfs_t lfs;
  110. lfs_format(&lfs, cfg) => 0;
  111. lfs_mount(&lfs, cfg) => 0;
  112. for (int i = 0; i < N; i++) {
  113. lfs_file_t file;
  114. lfs_file_open(&lfs, &file, "dummy",
  115. LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
  116. lfs_file_close(&lfs, &file) => 0;
  117. struct lfs_info info;
  118. lfs_stat(&lfs, "dummy", &info) => 0;
  119. assert(strcmp(info.name, "dummy") == 0);
  120. assert(info.type == LFS_TYPE_REG);
  121. lfs_remove(&lfs, "dummy") => 0;
  122. }
  123. lfs_unmount(&lfs) => 0;
  124. // one last check after power-cycle
  125. lfs_mount(&lfs, cfg) => 0;
  126. lfs_file_t file;
  127. lfs_file_open(&lfs, &file, "dummy",
  128. LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
  129. lfs_file_close(&lfs, &file) => 0;
  130. struct lfs_info info;
  131. lfs_stat(&lfs, "dummy", &info) => 0;
  132. assert(strcmp(info.name, "dummy") == 0);
  133. assert(info.type == LFS_TYPE_REG);
  134. lfs_unmount(&lfs) => 0;
  135. '''
  136. # make sure the magic string "littlefs" is always at offset=8
  137. [cases.test_superblocks_magic_expand]
  138. defines.BLOCK_CYCLES = [32, 33, 1]
  139. defines.N = [10, 100, 1000]
  140. code = '''
  141. lfs_t lfs;
  142. lfs_format(&lfs, cfg) => 0;
  143. lfs_mount(&lfs, cfg) => 0;
  144. for (int i = 0; i < N; i++) {
  145. lfs_file_t file;
  146. lfs_file_open(&lfs, &file, "dummy",
  147. LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
  148. lfs_file_close(&lfs, &file) => 0;
  149. struct lfs_info info;
  150. lfs_stat(&lfs, "dummy", &info) => 0;
  151. assert(strcmp(info.name, "dummy") == 0);
  152. assert(info.type == LFS_TYPE_REG);
  153. lfs_remove(&lfs, "dummy") => 0;
  154. }
  155. lfs_unmount(&lfs) => 0;
  156. // check our magic string
  157. //
  158. // note if we lose power we may not have the magic string in both blocks!
  159. // but we don't lose power in this test so we can assert the magic string
  160. // is present in both
  161. uint8_t magic[lfs_max(16, READ_SIZE)];
  162. cfg->read(cfg, 0, 0, magic, lfs_max(16, READ_SIZE)) => 0;
  163. assert(memcmp(&magic[8], "littlefs", 8) == 0);
  164. cfg->read(cfg, 1, 0, magic, lfs_max(16, READ_SIZE)) => 0;
  165. assert(memcmp(&magic[8], "littlefs", 8) == 0);
  166. '''
  167. # expanding superblock with power cycle
  168. [cases.test_superblocks_expand_power_cycle]
  169. defines.BLOCK_CYCLES = [32, 33, 1]
  170. defines.N = [10, 100, 1000]
  171. code = '''
  172. lfs_t lfs;
  173. lfs_format(&lfs, cfg) => 0;
  174. for (int i = 0; i < N; i++) {
  175. lfs_mount(&lfs, cfg) => 0;
  176. // remove lingering dummy?
  177. struct lfs_info info;
  178. int err = lfs_stat(&lfs, "dummy", &info);
  179. assert(err == 0 || (err == LFS_ERR_NOENT && i == 0));
  180. if (!err) {
  181. assert(strcmp(info.name, "dummy") == 0);
  182. assert(info.type == LFS_TYPE_REG);
  183. lfs_remove(&lfs, "dummy") => 0;
  184. }
  185. lfs_file_t file;
  186. lfs_file_open(&lfs, &file, "dummy",
  187. LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
  188. lfs_file_close(&lfs, &file) => 0;
  189. lfs_stat(&lfs, "dummy", &info) => 0;
  190. assert(strcmp(info.name, "dummy") == 0);
  191. assert(info.type == LFS_TYPE_REG);
  192. lfs_unmount(&lfs) => 0;
  193. }
  194. // one last check after power-cycle
  195. lfs_mount(&lfs, cfg) => 0;
  196. struct lfs_info info;
  197. lfs_stat(&lfs, "dummy", &info) => 0;
  198. assert(strcmp(info.name, "dummy") == 0);
  199. assert(info.type == LFS_TYPE_REG);
  200. lfs_unmount(&lfs) => 0;
  201. '''
  202. # reentrant expanding superblock
  203. [cases.test_superblocks_reentrant_expand]
  204. defines.BLOCK_CYCLES = [2, 1]
  205. defines.N = 24
  206. reentrant = true
  207. defines.POWERLOSS_BEHAVIOR = [
  208. 'LFS_EMUBD_POWERLOSS_NOOP',
  209. 'LFS_EMUBD_POWERLOSS_OOO',
  210. ]
  211. code = '''
  212. lfs_t lfs;
  213. int err = lfs_mount(&lfs, cfg);
  214. if (err) {
  215. lfs_format(&lfs, cfg) => 0;
  216. lfs_mount(&lfs, cfg) => 0;
  217. }
  218. for (int i = 0; i < N; i++) {
  219. // remove lingering dummy?
  220. struct lfs_info info;
  221. err = lfs_stat(&lfs, "dummy", &info);
  222. assert(err == 0 || (err == LFS_ERR_NOENT && i == 0));
  223. if (!err) {
  224. assert(strcmp(info.name, "dummy") == 0);
  225. assert(info.type == LFS_TYPE_REG);
  226. lfs_remove(&lfs, "dummy") => 0;
  227. }
  228. lfs_file_t file;
  229. lfs_file_open(&lfs, &file, "dummy",
  230. LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
  231. lfs_file_close(&lfs, &file) => 0;
  232. lfs_stat(&lfs, "dummy", &info) => 0;
  233. assert(strcmp(info.name, "dummy") == 0);
  234. assert(info.type == LFS_TYPE_REG);
  235. }
  236. lfs_unmount(&lfs) => 0;
  237. // one last check after power-cycle
  238. lfs_mount(&lfs, cfg) => 0;
  239. struct lfs_info info;
  240. lfs_stat(&lfs, "dummy", &info) => 0;
  241. assert(strcmp(info.name, "dummy") == 0);
  242. assert(info.type == LFS_TYPE_REG);
  243. lfs_unmount(&lfs) => 0;
  244. '''
  245. # mount with unknown block_count
  246. [cases.test_superblocks_unknown_blocks]
  247. code = '''
  248. lfs_t lfs;
  249. lfs_format(&lfs, cfg) => 0;
  250. // known block_size/block_count
  251. cfg->block_size = BLOCK_SIZE;
  252. cfg->block_count = BLOCK_COUNT;
  253. lfs_mount(&lfs, cfg) => 0;
  254. struct lfs_fsinfo fsinfo;
  255. lfs_fs_stat(&lfs, &fsinfo) => 0;
  256. assert(fsinfo.block_size == BLOCK_SIZE);
  257. assert(fsinfo.block_count == BLOCK_COUNT);
  258. lfs_unmount(&lfs) => 0;
  259. // unknown block_count
  260. cfg->block_size = BLOCK_SIZE;
  261. cfg->block_count = 0;
  262. lfs_mount(&lfs, cfg) => 0;
  263. lfs_fs_stat(&lfs, &fsinfo) => 0;
  264. assert(fsinfo.block_size == BLOCK_SIZE);
  265. assert(fsinfo.block_count == BLOCK_COUNT);
  266. lfs_unmount(&lfs) => 0;
  267. // do some work
  268. lfs_mount(&lfs, cfg) => 0;
  269. lfs_fs_stat(&lfs, &fsinfo) => 0;
  270. assert(fsinfo.block_size == BLOCK_SIZE);
  271. assert(fsinfo.block_count == BLOCK_COUNT);
  272. lfs_file_t file;
  273. lfs_file_open(&lfs, &file, "test",
  274. LFS_O_CREAT | LFS_O_EXCL | LFS_O_WRONLY) => 0;
  275. lfs_file_write(&lfs, &file, "hello!", 6) => 6;
  276. lfs_file_close(&lfs, &file) => 0;
  277. lfs_unmount(&lfs) => 0;
  278. lfs_mount(&lfs, cfg) => 0;
  279. lfs_fs_stat(&lfs, &fsinfo) => 0;
  280. assert(fsinfo.block_size == BLOCK_SIZE);
  281. assert(fsinfo.block_count == BLOCK_COUNT);
  282. lfs_file_open(&lfs, &file, "test", LFS_O_RDONLY) => 0;
  283. uint8_t buffer[256];
  284. lfs_file_read(&lfs, &file, buffer, sizeof(buffer)) => 6;
  285. lfs_file_close(&lfs, &file) => 0;
  286. assert(memcmp(buffer, "hello!", 6) == 0);
  287. lfs_unmount(&lfs) => 0;
  288. '''
  289. # mount with blocks fewer than the erase_count
  290. [cases.test_superblocks_fewer_blocks]
  291. defines.BLOCK_COUNT = ['ERASE_COUNT/2', 'ERASE_COUNT/4', '2']
  292. code = '''
  293. lfs_t lfs;
  294. lfs_format(&lfs, cfg) => 0;
  295. // known block_size/block_count
  296. cfg->block_size = BLOCK_SIZE;
  297. cfg->block_count = BLOCK_COUNT;
  298. lfs_mount(&lfs, cfg) => 0;
  299. struct lfs_fsinfo fsinfo;
  300. lfs_fs_stat(&lfs, &fsinfo) => 0;
  301. assert(fsinfo.block_size == BLOCK_SIZE);
  302. assert(fsinfo.block_count == BLOCK_COUNT);
  303. lfs_unmount(&lfs) => 0;
  304. // incorrect block_count
  305. cfg->block_size = BLOCK_SIZE;
  306. cfg->block_count = ERASE_COUNT;
  307. lfs_mount(&lfs, cfg) => LFS_ERR_INVAL;
  308. // unknown block_count
  309. cfg->block_size = BLOCK_SIZE;
  310. cfg->block_count = 0;
  311. lfs_mount(&lfs, cfg) => 0;
  312. lfs_fs_stat(&lfs, &fsinfo) => 0;
  313. assert(fsinfo.block_size == BLOCK_SIZE);
  314. assert(fsinfo.block_count == BLOCK_COUNT);
  315. lfs_unmount(&lfs) => 0;
  316. // do some work
  317. lfs_mount(&lfs, cfg) => 0;
  318. lfs_fs_stat(&lfs, &fsinfo) => 0;
  319. assert(fsinfo.block_size == BLOCK_SIZE);
  320. assert(fsinfo.block_count == BLOCK_COUNT);
  321. lfs_file_t file;
  322. lfs_file_open(&lfs, &file, "test",
  323. LFS_O_CREAT | LFS_O_EXCL | LFS_O_WRONLY) => 0;
  324. lfs_file_write(&lfs, &file, "hello!", 6) => 6;
  325. lfs_file_close(&lfs, &file) => 0;
  326. lfs_unmount(&lfs) => 0;
  327. lfs_mount(&lfs, cfg) => 0;
  328. lfs_fs_stat(&lfs, &fsinfo) => 0;
  329. assert(fsinfo.block_size == BLOCK_SIZE);
  330. assert(fsinfo.block_count == BLOCK_COUNT);
  331. lfs_file_open(&lfs, &file, "test", LFS_O_RDONLY) => 0;
  332. uint8_t buffer[256];
  333. lfs_file_read(&lfs, &file, buffer, sizeof(buffer)) => 6;
  334. lfs_file_close(&lfs, &file) => 0;
  335. assert(memcmp(buffer, "hello!", 6) == 0);
  336. lfs_unmount(&lfs) => 0;
  337. '''
  338. # mount with more blocks than the erase_count
  339. [cases.test_superblocks_more_blocks]
  340. defines.FORMAT_BLOCK_COUNT = '2*ERASE_COUNT'
  341. in = 'lfs.c'
  342. code = '''
  343. lfs_t lfs;
  344. lfs_init(&lfs, cfg) => 0;
  345. lfs.block_count = BLOCK_COUNT;
  346. lfs_mdir_t root = {
  347. .pair = {0, 0}, // make sure this goes into block 0
  348. .rev = 0,
  349. .off = sizeof(uint32_t),
  350. .etag = 0xffffffff,
  351. .count = 0,
  352. .tail = {LFS_BLOCK_NULL, LFS_BLOCK_NULL},
  353. .erased = false,
  354. .split = false,
  355. };
  356. lfs_superblock_t superblock = {
  357. .version = LFS_DISK_VERSION,
  358. .block_size = BLOCK_SIZE,
  359. .block_count = FORMAT_BLOCK_COUNT,
  360. .name_max = LFS_NAME_MAX,
  361. .file_max = LFS_FILE_MAX,
  362. .attr_max = LFS_ATTR_MAX,
  363. };
  364. lfs_superblock_tole32(&superblock);
  365. lfs_dir_commit(&lfs, &root, LFS_MKATTRS(
  366. {LFS_MKTAG(LFS_TYPE_CREATE, 0, 0), NULL},
  367. {LFS_MKTAG(LFS_TYPE_SUPERBLOCK, 0, 8), "littlefs"},
  368. {LFS_MKTAG(LFS_TYPE_INLINESTRUCT, 0, sizeof(superblock)),
  369. &superblock})) => 0;
  370. lfs_deinit(&lfs) => 0;
  371. // known block_size/block_count
  372. cfg->block_size = BLOCK_SIZE;
  373. cfg->block_count = BLOCK_COUNT;
  374. lfs_mount(&lfs, cfg) => LFS_ERR_INVAL;
  375. '''
  376. # mount and grow the filesystem
  377. [cases.test_superblocks_grow]
  378. defines.BLOCK_COUNT = ['ERASE_COUNT/2', 'ERASE_COUNT/4', '2']
  379. defines.BLOCK_COUNT_2 = 'ERASE_COUNT'
  380. defines.KNOWN_BLOCK_COUNT = [true, false]
  381. code = '''
  382. lfs_t lfs;
  383. lfs_format(&lfs, cfg) => 0;
  384. if (KNOWN_BLOCK_COUNT) {
  385. cfg->block_count = BLOCK_COUNT;
  386. } else {
  387. cfg->block_count = 0;
  388. }
  389. // mount with block_size < erase_size
  390. lfs_mount(&lfs, cfg) => 0;
  391. struct lfs_fsinfo fsinfo;
  392. lfs_fs_stat(&lfs, &fsinfo) => 0;
  393. assert(fsinfo.block_size == BLOCK_SIZE);
  394. assert(fsinfo.block_count == BLOCK_COUNT);
  395. lfs_unmount(&lfs) => 0;
  396. // same size is a noop
  397. lfs_mount(&lfs, cfg) => 0;
  398. lfs_fs_grow(&lfs, BLOCK_COUNT) => 0;
  399. lfs_fs_stat(&lfs, &fsinfo) => 0;
  400. assert(fsinfo.block_size == BLOCK_SIZE);
  401. assert(fsinfo.block_count == BLOCK_COUNT);
  402. lfs_unmount(&lfs) => 0;
  403. lfs_mount(&lfs, cfg) => 0;
  404. lfs_fs_stat(&lfs, &fsinfo) => 0;
  405. assert(fsinfo.block_size == BLOCK_SIZE);
  406. assert(fsinfo.block_count == BLOCK_COUNT);
  407. lfs_unmount(&lfs) => 0;
  408. // grow to new size
  409. lfs_mount(&lfs, cfg) => 0;
  410. lfs_fs_grow(&lfs, BLOCK_COUNT_2) => 0;
  411. lfs_fs_stat(&lfs, &fsinfo) => 0;
  412. assert(fsinfo.block_size == BLOCK_SIZE);
  413. assert(fsinfo.block_count == BLOCK_COUNT_2);
  414. lfs_unmount(&lfs) => 0;
  415. if (KNOWN_BLOCK_COUNT) {
  416. cfg->block_count = BLOCK_COUNT_2;
  417. } else {
  418. cfg->block_count = 0;
  419. }
  420. lfs_mount(&lfs, cfg) => 0;
  421. lfs_fs_stat(&lfs, &fsinfo) => 0;
  422. assert(fsinfo.block_size == BLOCK_SIZE);
  423. assert(fsinfo.block_count == BLOCK_COUNT_2);
  424. lfs_unmount(&lfs) => 0;
  425. // mounting with the previous size should fail
  426. cfg->block_count = BLOCK_COUNT;
  427. lfs_mount(&lfs, cfg) => LFS_ERR_INVAL;
  428. if (KNOWN_BLOCK_COUNT) {
  429. cfg->block_count = BLOCK_COUNT_2;
  430. } else {
  431. cfg->block_count = 0;
  432. }
  433. // same size is a noop
  434. lfs_mount(&lfs, cfg) => 0;
  435. lfs_fs_grow(&lfs, BLOCK_COUNT_2) => 0;
  436. lfs_fs_stat(&lfs, &fsinfo) => 0;
  437. assert(fsinfo.block_size == BLOCK_SIZE);
  438. assert(fsinfo.block_count == BLOCK_COUNT_2);
  439. lfs_unmount(&lfs) => 0;
  440. lfs_mount(&lfs, cfg) => 0;
  441. lfs_fs_stat(&lfs, &fsinfo) => 0;
  442. assert(fsinfo.block_size == BLOCK_SIZE);
  443. assert(fsinfo.block_count == BLOCK_COUNT_2);
  444. lfs_unmount(&lfs) => 0;
  445. // do some work
  446. lfs_mount(&lfs, cfg) => 0;
  447. lfs_fs_stat(&lfs, &fsinfo) => 0;
  448. assert(fsinfo.block_size == BLOCK_SIZE);
  449. assert(fsinfo.block_count == BLOCK_COUNT_2);
  450. lfs_file_t file;
  451. lfs_file_open(&lfs, &file, "test",
  452. LFS_O_CREAT | LFS_O_EXCL | LFS_O_WRONLY) => 0;
  453. lfs_file_write(&lfs, &file, "hello!", 6) => 6;
  454. lfs_file_close(&lfs, &file) => 0;
  455. lfs_unmount(&lfs) => 0;
  456. lfs_mount(&lfs, cfg) => 0;
  457. lfs_fs_stat(&lfs, &fsinfo) => 0;
  458. assert(fsinfo.block_size == BLOCK_SIZE);
  459. assert(fsinfo.block_count == BLOCK_COUNT_2);
  460. lfs_file_open(&lfs, &file, "test", LFS_O_RDONLY) => 0;
  461. uint8_t buffer[256];
  462. lfs_file_read(&lfs, &file, buffer, sizeof(buffer)) => 6;
  463. lfs_file_close(&lfs, &file) => 0;
  464. assert(memcmp(buffer, "hello!", 6) == 0);
  465. lfs_unmount(&lfs) => 0;
  466. '''
  467. # mount and grow the filesystem
  468. [cases.test_superblocks_shrink]
  469. defines.BLOCK_COUNT = 'ERASE_COUNT'
  470. defines.BLOCK_COUNT_2 = ['ERASE_COUNT/2', 'ERASE_COUNT/4', '2']
  471. defines.KNOWN_BLOCK_COUNT = [true, false]
  472. code = '''
  473. #ifdef LFS_SHRINKNONRELOCATING
  474. lfs_t lfs;
  475. lfs_format(&lfs, cfg) => 0;
  476. if (KNOWN_BLOCK_COUNT) {
  477. cfg->block_count = BLOCK_COUNT;
  478. } else {
  479. cfg->block_count = 0;
  480. }
  481. // mount with block_size < erase_size
  482. lfs_mount(&lfs, cfg) => 0;
  483. struct lfs_fsinfo fsinfo;
  484. lfs_fs_stat(&lfs, &fsinfo) => 0;
  485. assert(fsinfo.block_size == BLOCK_SIZE);
  486. assert(fsinfo.block_count == BLOCK_COUNT);
  487. lfs_unmount(&lfs) => 0;
  488. // same size is a noop
  489. lfs_mount(&lfs, cfg) => 0;
  490. lfs_fs_grow(&lfs, BLOCK_COUNT) => 0;
  491. lfs_fs_stat(&lfs, &fsinfo) => 0;
  492. assert(fsinfo.block_size == BLOCK_SIZE);
  493. assert(fsinfo.block_count == BLOCK_COUNT);
  494. lfs_unmount(&lfs) => 0;
  495. lfs_mount(&lfs, cfg) => 0;
  496. lfs_fs_stat(&lfs, &fsinfo) => 0;
  497. assert(fsinfo.block_size == BLOCK_SIZE);
  498. assert(fsinfo.block_count == BLOCK_COUNT);
  499. lfs_unmount(&lfs) => 0;
  500. // grow to new size
  501. lfs_mount(&lfs, cfg) => 0;
  502. lfs_fs_grow(&lfs, BLOCK_COUNT_2) => 0;
  503. lfs_fs_stat(&lfs, &fsinfo) => 0;
  504. assert(fsinfo.block_size == BLOCK_SIZE);
  505. assert(fsinfo.block_count == BLOCK_COUNT_2);
  506. lfs_unmount(&lfs) => 0;
  507. if (KNOWN_BLOCK_COUNT) {
  508. cfg->block_count = BLOCK_COUNT_2;
  509. } else {
  510. cfg->block_count = 0;
  511. }
  512. lfs_mount(&lfs, cfg) => 0;
  513. lfs_fs_stat(&lfs, &fsinfo) => 0;
  514. assert(fsinfo.block_size == BLOCK_SIZE);
  515. assert(fsinfo.block_count == BLOCK_COUNT_2);
  516. lfs_unmount(&lfs) => 0;
  517. // mounting with the previous size should fail
  518. cfg->block_count = BLOCK_COUNT;
  519. lfs_mount(&lfs, cfg) => LFS_ERR_INVAL;
  520. if (KNOWN_BLOCK_COUNT) {
  521. cfg->block_count = BLOCK_COUNT_2;
  522. } else {
  523. cfg->block_count = 0;
  524. }
  525. // same size is a noop
  526. lfs_mount(&lfs, cfg) => 0;
  527. lfs_fs_grow(&lfs, BLOCK_COUNT_2) => 0;
  528. lfs_fs_stat(&lfs, &fsinfo) => 0;
  529. assert(fsinfo.block_size == BLOCK_SIZE);
  530. assert(fsinfo.block_count == BLOCK_COUNT_2);
  531. lfs_unmount(&lfs) => 0;
  532. lfs_mount(&lfs, cfg) => 0;
  533. lfs_fs_stat(&lfs, &fsinfo) => 0;
  534. assert(fsinfo.block_size == BLOCK_SIZE);
  535. assert(fsinfo.block_count == BLOCK_COUNT_2);
  536. lfs_unmount(&lfs) => 0;
  537. // do some work
  538. lfs_mount(&lfs, cfg) => 0;
  539. lfs_fs_stat(&lfs, &fsinfo) => 0;
  540. assert(fsinfo.block_size == BLOCK_SIZE);
  541. assert(fsinfo.block_count == BLOCK_COUNT_2);
  542. lfs_file_t file;
  543. lfs_file_open(&lfs, &file, "test",
  544. LFS_O_CREAT | LFS_O_EXCL | LFS_O_WRONLY) => 0;
  545. lfs_file_write(&lfs, &file, "hello!", 6) => 6;
  546. lfs_file_close(&lfs, &file) => 0;
  547. lfs_unmount(&lfs) => 0;
  548. lfs_mount(&lfs, cfg) => 0;
  549. lfs_fs_stat(&lfs, &fsinfo) => 0;
  550. assert(fsinfo.block_size == BLOCK_SIZE);
  551. assert(fsinfo.block_count == BLOCK_COUNT_2);
  552. lfs_file_open(&lfs, &file, "test", LFS_O_RDONLY) => 0;
  553. uint8_t buffer[256];
  554. lfs_file_read(&lfs, &file, buffer, sizeof(buffer)) => 6;
  555. lfs_file_close(&lfs, &file) => 0;
  556. assert(memcmp(buffer, "hello!", 6) == 0);
  557. lfs_unmount(&lfs) => 0;
  558. #endif
  559. '''
  560. # test that metadata_max does not cause problems for superblock compaction
  561. [cases.test_superblocks_metadata_max]
  562. defines.METADATA_MAX = [
  563. 'lfs_max(512, PROG_SIZE)',
  564. 'lfs_max(BLOCK_SIZE/2, PROG_SIZE)',
  565. 'BLOCK_SIZE'
  566. ]
  567. defines.N = [10, 100, 1000]
  568. code = '''
  569. lfs_t lfs;
  570. lfs_format(&lfs, cfg) => 0;
  571. lfs_mount(&lfs, cfg) => 0;
  572. for (int i = 0; i < N; i++) {
  573. lfs_file_t file;
  574. char name[256];
  575. sprintf(name, "hello%03x", i);
  576. lfs_file_open(&lfs, &file, name,
  577. LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
  578. lfs_file_close(&lfs, &file) => 0;
  579. struct lfs_info info;
  580. lfs_stat(&lfs, name, &info) => 0;
  581. assert(strcmp(info.name, name) == 0);
  582. assert(info.type == LFS_TYPE_REG);
  583. }
  584. lfs_unmount(&lfs) => 0;
  585. '''