test_alloc.toml 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737
  1. # allocator tests
  2. # note for these to work there are a number constraints on the device geometry
  3. if = 'BLOCK_CYCLES == -1'
  4. # parallel allocation test
  5. [cases.test_alloc_parallel]
  6. defines.FILES = 3
  7. defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-6)) / FILES)'
  8. defines.GC = [false, true]
  9. defines.COMPACT_THRESH = ['-1', '0', 'BLOCK_SIZE/2']
  10. code = '''
  11. const char *names[] = {"bacon", "eggs", "pancakes"};
  12. lfs_file_t files[FILES];
  13. lfs_t lfs;
  14. lfs_format(&lfs, cfg) => 0;
  15. lfs_mount(&lfs, cfg) => 0;
  16. lfs_mkdir(&lfs, "breakfast") => 0;
  17. lfs_unmount(&lfs) => 0;
  18. lfs_mount(&lfs, cfg) => 0;
  19. for (int n = 0; n < FILES; n++) {
  20. char path[1024];
  21. sprintf(path, "breakfast/%s", names[n]);
  22. lfs_file_open(&lfs, &files[n], path,
  23. LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0;
  24. }
  25. for (int n = 0; n < FILES; n++) {
  26. if (GC) {
  27. lfs_fs_gc(&lfs) => 0;
  28. }
  29. size_t size = strlen(names[n]);
  30. for (lfs_size_t i = 0; i < SIZE; i += size) {
  31. lfs_file_write(&lfs, &files[n], names[n], size) => size;
  32. }
  33. }
  34. for (int n = 0; n < FILES; n++) {
  35. lfs_file_close(&lfs, &files[n]) => 0;
  36. }
  37. lfs_unmount(&lfs) => 0;
  38. lfs_mount(&lfs, cfg) => 0;
  39. for (int n = 0; n < FILES; n++) {
  40. char path[1024];
  41. sprintf(path, "breakfast/%s", names[n]);
  42. lfs_file_t file;
  43. lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
  44. size_t size = strlen(names[n]);
  45. for (lfs_size_t i = 0; i < SIZE; i += size) {
  46. uint8_t buffer[1024];
  47. lfs_file_read(&lfs, &file, buffer, size) => size;
  48. assert(memcmp(buffer, names[n], size) == 0);
  49. }
  50. lfs_file_close(&lfs, &file) => 0;
  51. }
  52. lfs_unmount(&lfs) => 0;
  53. '''
  54. # serial allocation test
  55. [cases.test_alloc_serial]
  56. defines.FILES = 3
  57. defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-6)) / FILES)'
  58. defines.GC = [false, true]
  59. defines.COMPACT_THRESH = ['-1', '0', 'BLOCK_SIZE/2']
  60. code = '''
  61. const char *names[] = {"bacon", "eggs", "pancakes"};
  62. lfs_t lfs;
  63. lfs_format(&lfs, cfg) => 0;
  64. lfs_mount(&lfs, cfg) => 0;
  65. lfs_mkdir(&lfs, "breakfast") => 0;
  66. lfs_unmount(&lfs) => 0;
  67. for (int n = 0; n < FILES; n++) {
  68. lfs_mount(&lfs, cfg) => 0;
  69. char path[1024];
  70. sprintf(path, "breakfast/%s", names[n]);
  71. lfs_file_t file;
  72. lfs_file_open(&lfs, &file, path,
  73. LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0;
  74. size_t size = strlen(names[n]);
  75. uint8_t buffer[1024];
  76. memcpy(buffer, names[n], size);
  77. for (int i = 0; i < SIZE; i += size) {
  78. if (GC) {
  79. lfs_fs_gc(&lfs) => 0;
  80. }
  81. lfs_file_write(&lfs, &file, buffer, size) => size;
  82. }
  83. lfs_file_close(&lfs, &file) => 0;
  84. lfs_unmount(&lfs) => 0;
  85. }
  86. lfs_mount(&lfs, cfg) => 0;
  87. for (int n = 0; n < FILES; n++) {
  88. char path[1024];
  89. sprintf(path, "breakfast/%s", names[n]);
  90. lfs_file_t file;
  91. lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
  92. size_t size = strlen(names[n]);
  93. for (int i = 0; i < SIZE; i += size) {
  94. uint8_t buffer[1024];
  95. lfs_file_read(&lfs, &file, buffer, size) => size;
  96. assert(memcmp(buffer, names[n], size) == 0);
  97. }
  98. lfs_file_close(&lfs, &file) => 0;
  99. }
  100. lfs_unmount(&lfs) => 0;
  101. '''
  102. # parallel allocation reuse test
  103. [cases.test_alloc_parallel_reuse]
  104. defines.FILES = 3
  105. defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-6)) / FILES)'
  106. defines.CYCLES = [1, 10]
  107. code = '''
  108. const char *names[] = {"bacon", "eggs", "pancakes"};
  109. lfs_file_t files[FILES];
  110. lfs_t lfs;
  111. lfs_format(&lfs, cfg) => 0;
  112. for (int c = 0; c < CYCLES; c++) {
  113. lfs_mount(&lfs, cfg) => 0;
  114. lfs_mkdir(&lfs, "breakfast") => 0;
  115. lfs_unmount(&lfs) => 0;
  116. lfs_mount(&lfs, cfg) => 0;
  117. for (int n = 0; n < FILES; n++) {
  118. char path[1024];
  119. sprintf(path, "breakfast/%s", names[n]);
  120. lfs_file_open(&lfs, &files[n], path,
  121. LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0;
  122. }
  123. for (int n = 0; n < FILES; n++) {
  124. size_t size = strlen(names[n]);
  125. for (int i = 0; i < SIZE; i += size) {
  126. lfs_file_write(&lfs, &files[n], names[n], size) => size;
  127. }
  128. }
  129. for (int n = 0; n < FILES; n++) {
  130. lfs_file_close(&lfs, &files[n]) => 0;
  131. }
  132. lfs_unmount(&lfs) => 0;
  133. lfs_mount(&lfs, cfg) => 0;
  134. for (int n = 0; n < FILES; n++) {
  135. char path[1024];
  136. sprintf(path, "breakfast/%s", names[n]);
  137. lfs_file_t file;
  138. lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
  139. size_t size = strlen(names[n]);
  140. for (int i = 0; i < SIZE; i += size) {
  141. uint8_t buffer[1024];
  142. lfs_file_read(&lfs, &file, buffer, size) => size;
  143. assert(memcmp(buffer, names[n], size) == 0);
  144. }
  145. lfs_file_close(&lfs, &file) => 0;
  146. }
  147. lfs_unmount(&lfs) => 0;
  148. lfs_mount(&lfs, cfg) => 0;
  149. for (int n = 0; n < FILES; n++) {
  150. char path[1024];
  151. sprintf(path, "breakfast/%s", names[n]);
  152. lfs_remove(&lfs, path) => 0;
  153. }
  154. lfs_remove(&lfs, "breakfast") => 0;
  155. lfs_unmount(&lfs) => 0;
  156. }
  157. '''
  158. # serial allocation reuse test
  159. [cases.test_alloc_serial_reuse]
  160. defines.FILES = 3
  161. defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-6)) / FILES)'
  162. defines.CYCLES = [1, 10]
  163. code = '''
  164. const char *names[] = {"bacon", "eggs", "pancakes"};
  165. lfs_t lfs;
  166. lfs_format(&lfs, cfg) => 0;
  167. for (int c = 0; c < CYCLES; c++) {
  168. lfs_mount(&lfs, cfg) => 0;
  169. lfs_mkdir(&lfs, "breakfast") => 0;
  170. lfs_unmount(&lfs) => 0;
  171. for (int n = 0; n < FILES; n++) {
  172. lfs_mount(&lfs, cfg) => 0;
  173. char path[1024];
  174. sprintf(path, "breakfast/%s", names[n]);
  175. lfs_file_t file;
  176. lfs_file_open(&lfs, &file, path,
  177. LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0;
  178. size_t size = strlen(names[n]);
  179. uint8_t buffer[1024];
  180. memcpy(buffer, names[n], size);
  181. for (int i = 0; i < SIZE; i += size) {
  182. lfs_file_write(&lfs, &file, buffer, size) => size;
  183. }
  184. lfs_file_close(&lfs, &file) => 0;
  185. lfs_unmount(&lfs) => 0;
  186. }
  187. lfs_mount(&lfs, cfg) => 0;
  188. for (int n = 0; n < FILES; n++) {
  189. char path[1024];
  190. sprintf(path, "breakfast/%s", names[n]);
  191. lfs_file_t file;
  192. lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
  193. size_t size = strlen(names[n]);
  194. for (int i = 0; i < SIZE; i += size) {
  195. uint8_t buffer[1024];
  196. lfs_file_read(&lfs, &file, buffer, size) => size;
  197. assert(memcmp(buffer, names[n], size) == 0);
  198. }
  199. lfs_file_close(&lfs, &file) => 0;
  200. }
  201. lfs_unmount(&lfs) => 0;
  202. lfs_mount(&lfs, cfg) => 0;
  203. for (int n = 0; n < FILES; n++) {
  204. char path[1024];
  205. sprintf(path, "breakfast/%s", names[n]);
  206. lfs_remove(&lfs, path) => 0;
  207. }
  208. lfs_remove(&lfs, "breakfast") => 0;
  209. lfs_unmount(&lfs) => 0;
  210. }
  211. '''
  212. # exhaustion test
  213. [cases.test_alloc_exhaustion]
  214. code = '''
  215. lfs_t lfs;
  216. lfs_format(&lfs, cfg) => 0;
  217. lfs_mount(&lfs, cfg) => 0;
  218. lfs_file_t file;
  219. lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT);
  220. size_t size = strlen("exhaustion");
  221. uint8_t buffer[1024];
  222. memcpy(buffer, "exhaustion", size);
  223. lfs_file_write(&lfs, &file, buffer, size) => size;
  224. lfs_file_sync(&lfs, &file) => 0;
  225. size = strlen("blahblahblahblah");
  226. memcpy(buffer, "blahblahblahblah", size);
  227. lfs_ssize_t res;
  228. while (true) {
  229. res = lfs_file_write(&lfs, &file, buffer, size);
  230. if (res < 0) {
  231. break;
  232. }
  233. res => size;
  234. }
  235. res => LFS_ERR_NOSPC;
  236. // note that lfs_fs_gc should not error here
  237. lfs_fs_gc(&lfs) => 0;
  238. lfs_file_close(&lfs, &file) => 0;
  239. lfs_unmount(&lfs) => 0;
  240. lfs_mount(&lfs, cfg) => 0;
  241. lfs_file_open(&lfs, &file, "exhaustion", LFS_O_RDONLY);
  242. size = strlen("exhaustion");
  243. lfs_file_size(&lfs, &file) => size;
  244. lfs_file_read(&lfs, &file, buffer, size) => size;
  245. memcmp(buffer, "exhaustion", size) => 0;
  246. lfs_file_close(&lfs, &file) => 0;
  247. lfs_unmount(&lfs) => 0;
  248. '''
  249. # exhaustion wraparound test
  250. [cases.test_alloc_exhaustion_wraparound]
  251. defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-4)) / 3)'
  252. code = '''
  253. lfs_t lfs;
  254. lfs_format(&lfs, cfg) => 0;
  255. lfs_mount(&lfs, cfg) => 0;
  256. lfs_file_t file;
  257. lfs_file_open(&lfs, &file, "padding", LFS_O_WRONLY | LFS_O_CREAT);
  258. size_t size = strlen("buffering");
  259. uint8_t buffer[1024];
  260. memcpy(buffer, "buffering", size);
  261. for (int i = 0; i < SIZE; i += size) {
  262. lfs_file_write(&lfs, &file, buffer, size) => size;
  263. }
  264. lfs_file_close(&lfs, &file) => 0;
  265. lfs_remove(&lfs, "padding") => 0;
  266. lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT);
  267. size = strlen("exhaustion");
  268. memcpy(buffer, "exhaustion", size);
  269. lfs_file_write(&lfs, &file, buffer, size) => size;
  270. lfs_file_sync(&lfs, &file) => 0;
  271. size = strlen("blahblahblahblah");
  272. memcpy(buffer, "blahblahblahblah", size);
  273. lfs_ssize_t res;
  274. while (true) {
  275. res = lfs_file_write(&lfs, &file, buffer, size);
  276. if (res < 0) {
  277. break;
  278. }
  279. res => size;
  280. }
  281. res => LFS_ERR_NOSPC;
  282. // note that lfs_fs_gc should not error here
  283. lfs_fs_gc(&lfs) => 0;
  284. lfs_file_close(&lfs, &file) => 0;
  285. lfs_unmount(&lfs) => 0;
  286. lfs_mount(&lfs, cfg) => 0;
  287. lfs_file_open(&lfs, &file, "exhaustion", LFS_O_RDONLY);
  288. size = strlen("exhaustion");
  289. lfs_file_size(&lfs, &file) => size;
  290. lfs_file_read(&lfs, &file, buffer, size) => size;
  291. memcmp(buffer, "exhaustion", size) => 0;
  292. lfs_file_close(&lfs, &file) => 0;
  293. lfs_remove(&lfs, "exhaustion") => 0;
  294. lfs_unmount(&lfs) => 0;
  295. '''
  296. # dir exhaustion test
  297. [cases.test_alloc_dir_exhaustion]
  298. code = '''
  299. lfs_t lfs;
  300. lfs_format(&lfs, cfg) => 0;
  301. lfs_mount(&lfs, cfg) => 0;
  302. // find out max file size
  303. lfs_mkdir(&lfs, "exhaustiondir") => 0;
  304. size_t size = strlen("blahblahblahblah");
  305. uint8_t buffer[1024];
  306. memcpy(buffer, "blahblahblahblah", size);
  307. lfs_file_t file;
  308. lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT);
  309. int count = 0;
  310. int err;
  311. while (true) {
  312. err = lfs_file_write(&lfs, &file, buffer, size);
  313. if (err < 0) {
  314. break;
  315. }
  316. count += 1;
  317. }
  318. err => LFS_ERR_NOSPC;
  319. // note that lfs_fs_gc should not error here
  320. lfs_fs_gc(&lfs) => 0;
  321. lfs_file_close(&lfs, &file) => 0;
  322. lfs_remove(&lfs, "exhaustion") => 0;
  323. lfs_remove(&lfs, "exhaustiondir") => 0;
  324. // see if dir fits with max file size
  325. lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT);
  326. for (int i = 0; i < count; i++) {
  327. lfs_file_write(&lfs, &file, buffer, size) => size;
  328. }
  329. lfs_file_close(&lfs, &file) => 0;
  330. lfs_mkdir(&lfs, "exhaustiondir") => 0;
  331. lfs_remove(&lfs, "exhaustiondir") => 0;
  332. lfs_remove(&lfs, "exhaustion") => 0;
  333. // see if dir fits with > max file size
  334. lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT);
  335. for (int i = 0; i < count+1; i++) {
  336. lfs_file_write(&lfs, &file, buffer, size) => size;
  337. }
  338. lfs_file_close(&lfs, &file) => 0;
  339. lfs_mkdir(&lfs, "exhaustiondir") => LFS_ERR_NOSPC;
  340. lfs_remove(&lfs, "exhaustion") => 0;
  341. lfs_unmount(&lfs) => 0;
  342. '''
  343. # what if we have a bad block during an allocation scan?
  344. [cases.test_alloc_bad_blocks]
  345. in = "lfs.c"
  346. defines.ERASE_CYCLES = 0xffffffff
  347. defines.BADBLOCK_BEHAVIOR = 'LFS_EMUBD_BADBLOCK_READERROR'
  348. code = '''
  349. lfs_t lfs;
  350. lfs_format(&lfs, cfg) => 0;
  351. lfs_mount(&lfs, cfg) => 0;
  352. // first fill to exhaustion to find available space
  353. lfs_file_t file;
  354. lfs_file_open(&lfs, &file, "pacman", LFS_O_WRONLY | LFS_O_CREAT) => 0;
  355. uint8_t buffer[1024];
  356. strcpy((char*)buffer, "waka");
  357. size_t size = strlen("waka");
  358. lfs_size_t filesize = 0;
  359. while (true) {
  360. lfs_ssize_t res = lfs_file_write(&lfs, &file, buffer, size);
  361. assert(res == (lfs_ssize_t)size || res == LFS_ERR_NOSPC);
  362. if (res == LFS_ERR_NOSPC) {
  363. break;
  364. }
  365. filesize += size;
  366. }
  367. lfs_file_close(&lfs, &file) => 0;
  368. // now fill all but a couple of blocks of the filesystem with data
  369. filesize -= 3*BLOCK_SIZE;
  370. lfs_file_open(&lfs, &file, "pacman", LFS_O_WRONLY | LFS_O_CREAT) => 0;
  371. strcpy((char*)buffer, "waka");
  372. size = strlen("waka");
  373. for (lfs_size_t i = 0; i < filesize/size; i++) {
  374. lfs_file_write(&lfs, &file, buffer, size) => size;
  375. }
  376. lfs_file_close(&lfs, &file) => 0;
  377. // also save head of file so we can error during lookahead scan
  378. lfs_block_t fileblock = file.ctz.head;
  379. lfs_unmount(&lfs) => 0;
  380. // remount to force an alloc scan
  381. lfs_mount(&lfs, cfg) => 0;
  382. // but mark the head of our file as a "bad block", this is force our
  383. // scan to bail early
  384. lfs_emubd_setwear(cfg, fileblock, 0xffffffff) => 0;
  385. lfs_file_open(&lfs, &file, "ghost", LFS_O_WRONLY | LFS_O_CREAT) => 0;
  386. strcpy((char*)buffer, "chomp");
  387. size = strlen("chomp");
  388. while (true) {
  389. lfs_ssize_t res = lfs_file_write(&lfs, &file, buffer, size);
  390. assert(res == (lfs_ssize_t)size || res == LFS_ERR_CORRUPT);
  391. if (res == LFS_ERR_CORRUPT) {
  392. break;
  393. }
  394. }
  395. lfs_file_close(&lfs, &file) => 0;
  396. // now reverse the "bad block" and try to write the file again until we
  397. // run out of space
  398. lfs_emubd_setwear(cfg, fileblock, 0) => 0;
  399. lfs_file_open(&lfs, &file, "ghost", LFS_O_WRONLY | LFS_O_CREAT) => 0;
  400. strcpy((char*)buffer, "chomp");
  401. size = strlen("chomp");
  402. while (true) {
  403. lfs_ssize_t res = lfs_file_write(&lfs, &file, buffer, size);
  404. assert(res == (lfs_ssize_t)size || res == LFS_ERR_NOSPC);
  405. if (res == LFS_ERR_NOSPC) {
  406. break;
  407. }
  408. }
  409. // note that lfs_fs_gc should not error here
  410. lfs_fs_gc(&lfs) => 0;
  411. lfs_file_close(&lfs, &file) => 0;
  412. lfs_unmount(&lfs) => 0;
  413. // check that the disk isn't hurt
  414. lfs_mount(&lfs, cfg) => 0;
  415. lfs_file_open(&lfs, &file, "pacman", LFS_O_RDONLY) => 0;
  416. strcpy((char*)buffer, "waka");
  417. size = strlen("waka");
  418. for (lfs_size_t i = 0; i < filesize/size; i++) {
  419. uint8_t rbuffer[4];
  420. lfs_file_read(&lfs, &file, rbuffer, size) => size;
  421. assert(memcmp(rbuffer, buffer, size) == 0);
  422. }
  423. lfs_file_close(&lfs, &file) => 0;
  424. lfs_unmount(&lfs) => 0;
  425. '''
  426. # Below, I don't like these tests. They're fragile and depend _heavily_
  427. # on the geometry of the block device. But they are valuable. Eventually they
  428. # should be removed and replaced with generalized tests.
  429. # chained dir exhaustion test
  430. [cases.test_alloc_chained_dir_exhaustion]
  431. if = 'ERASE_SIZE == 512'
  432. defines.ERASE_COUNT = 1024
  433. code = '''
  434. lfs_t lfs;
  435. lfs_format(&lfs, cfg) => 0;
  436. lfs_mount(&lfs, cfg) => 0;
  437. // find out max file size
  438. lfs_mkdir(&lfs, "exhaustiondir") => 0;
  439. for (int i = 0; i < 10; i++) {
  440. char path[1024];
  441. sprintf(path, "dirwithanexhaustivelylongnameforpadding%d", i);
  442. lfs_mkdir(&lfs, path) => 0;
  443. }
  444. size_t size = strlen("blahblahblahblah");
  445. uint8_t buffer[1024];
  446. memcpy(buffer, "blahblahblahblah", size);
  447. lfs_file_t file;
  448. lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT);
  449. int count = 0;
  450. int err;
  451. while (true) {
  452. err = lfs_file_write(&lfs, &file, buffer, size);
  453. if (err < 0) {
  454. break;
  455. }
  456. count += 1;
  457. }
  458. err => LFS_ERR_NOSPC;
  459. lfs_file_close(&lfs, &file) => 0;
  460. lfs_remove(&lfs, "exhaustion") => 0;
  461. lfs_remove(&lfs, "exhaustiondir") => 0;
  462. for (int i = 0; i < 10; i++) {
  463. char path[1024];
  464. sprintf(path, "dirwithanexhaustivelylongnameforpadding%d", i);
  465. lfs_remove(&lfs, path) => 0;
  466. }
  467. // see that chained dir fails
  468. lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT);
  469. for (int i = 0; i < count+1; i++) {
  470. lfs_file_write(&lfs, &file, buffer, size) => size;
  471. }
  472. lfs_file_sync(&lfs, &file) => 0;
  473. for (int i = 0; i < 10; i++) {
  474. char path[1024];
  475. sprintf(path, "dirwithanexhaustivelylongnameforpadding%d", i);
  476. lfs_mkdir(&lfs, path) => 0;
  477. }
  478. lfs_mkdir(&lfs, "exhaustiondir") => LFS_ERR_NOSPC;
  479. // shorten file to try a second chained dir
  480. while (true) {
  481. err = lfs_mkdir(&lfs, "exhaustiondir");
  482. if (err != LFS_ERR_NOSPC) {
  483. break;
  484. }
  485. lfs_ssize_t filesize = lfs_file_size(&lfs, &file);
  486. filesize > 0 => true;
  487. lfs_file_truncate(&lfs, &file, filesize - size) => 0;
  488. lfs_file_sync(&lfs, &file) => 0;
  489. }
  490. err => 0;
  491. lfs_mkdir(&lfs, "exhaustiondir2") => LFS_ERR_NOSPC;
  492. lfs_file_close(&lfs, &file) => 0;
  493. lfs_unmount(&lfs) => 0;
  494. '''
  495. # split dir test
  496. [cases.test_alloc_split_dir]
  497. if = 'ERASE_SIZE == 512'
  498. defines.ERASE_COUNT = 1024
  499. code = '''
  500. lfs_t lfs;
  501. lfs_format(&lfs, cfg) => 0;
  502. lfs_mount(&lfs, cfg) => 0;
  503. // create one block hole for half a directory
  504. lfs_file_t file;
  505. lfs_file_open(&lfs, &file, "bump", LFS_O_WRONLY | LFS_O_CREAT) => 0;
  506. for (lfs_size_t i = 0; i < cfg->block_size; i += 2) {
  507. uint8_t buffer[1024];
  508. memcpy(&buffer[i], "hi", 2);
  509. }
  510. uint8_t buffer[1024];
  511. lfs_file_write(&lfs, &file, buffer, cfg->block_size) => cfg->block_size;
  512. lfs_file_close(&lfs, &file) => 0;
  513. lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT);
  514. size_t size = strlen("blahblahblahblah");
  515. memcpy(buffer, "blahblahblahblah", size);
  516. for (lfs_size_t i = 0;
  517. i < (cfg->block_count-4)*(cfg->block_size-8);
  518. i += size) {
  519. lfs_file_write(&lfs, &file, buffer, size) => size;
  520. }
  521. lfs_file_close(&lfs, &file) => 0;
  522. // remount to force reset of lookahead
  523. lfs_unmount(&lfs) => 0;
  524. lfs_mount(&lfs, cfg) => 0;
  525. // open hole
  526. lfs_remove(&lfs, "bump") => 0;
  527. lfs_mkdir(&lfs, "splitdir") => 0;
  528. lfs_file_open(&lfs, &file, "splitdir/bump",
  529. LFS_O_WRONLY | LFS_O_CREAT) => 0;
  530. for (lfs_size_t i = 0; i < cfg->block_size; i += 2) {
  531. memcpy(&buffer[i], "hi", 2);
  532. }
  533. lfs_file_write(&lfs, &file, buffer, 2*cfg->block_size) => LFS_ERR_NOSPC;
  534. lfs_file_close(&lfs, &file) => 0;
  535. lfs_unmount(&lfs) => 0;
  536. '''
  537. # outdated lookahead test
  538. [cases.test_alloc_outdated_lookahead]
  539. if = 'ERASE_SIZE == 512'
  540. defines.ERASE_COUNT = 1024
  541. code = '''
  542. lfs_t lfs;
  543. lfs_format(&lfs, cfg) => 0;
  544. lfs_mount(&lfs, cfg) => 0;
  545. // fill completely with two files
  546. lfs_file_t file;
  547. lfs_file_open(&lfs, &file, "exhaustion1",
  548. LFS_O_WRONLY | LFS_O_CREAT) => 0;
  549. size_t size = strlen("blahblahblahblah");
  550. uint8_t buffer[1024];
  551. memcpy(buffer, "blahblahblahblah", size);
  552. for (lfs_size_t i = 0;
  553. i < ((cfg->block_count-2)/2)*(cfg->block_size-8);
  554. i += size) {
  555. lfs_file_write(&lfs, &file, buffer, size) => size;
  556. }
  557. lfs_file_close(&lfs, &file) => 0;
  558. lfs_file_open(&lfs, &file, "exhaustion2",
  559. LFS_O_WRONLY | LFS_O_CREAT) => 0;
  560. size = strlen("blahblahblahblah");
  561. memcpy(buffer, "blahblahblahblah", size);
  562. for (lfs_size_t i = 0;
  563. i < ((cfg->block_count-2+1)/2)*(cfg->block_size-8);
  564. i += size) {
  565. lfs_file_write(&lfs, &file, buffer, size) => size;
  566. }
  567. lfs_file_close(&lfs, &file) => 0;
  568. // remount to force reset of lookahead
  569. lfs_unmount(&lfs) => 0;
  570. lfs_mount(&lfs, cfg) => 0;
  571. // rewrite one file
  572. lfs_file_open(&lfs, &file, "exhaustion1",
  573. LFS_O_WRONLY | LFS_O_TRUNC) => 0;
  574. lfs_file_sync(&lfs, &file) => 0;
  575. size = strlen("blahblahblahblah");
  576. memcpy(buffer, "blahblahblahblah", size);
  577. for (lfs_size_t i = 0;
  578. i < ((cfg->block_count-2)/2)*(cfg->block_size-8);
  579. i += size) {
  580. lfs_file_write(&lfs, &file, buffer, size) => size;
  581. }
  582. lfs_file_close(&lfs, &file) => 0;
  583. // rewrite second file, this requires lookahead does not
  584. // use old population
  585. lfs_file_open(&lfs, &file, "exhaustion2",
  586. LFS_O_WRONLY | LFS_O_TRUNC) => 0;
  587. lfs_file_sync(&lfs, &file) => 0;
  588. size = strlen("blahblahblahblah");
  589. memcpy(buffer, "blahblahblahblah", size);
  590. for (lfs_size_t i = 0;
  591. i < ((cfg->block_count-2+1)/2)*(cfg->block_size-8);
  592. i += size) {
  593. lfs_file_write(&lfs, &file, buffer, size) => size;
  594. }
  595. lfs_file_close(&lfs, &file) => 0;
  596. lfs_unmount(&lfs) => 0;
  597. '''
  598. # outdated lookahead and split dir test
  599. [cases.test_alloc_outdated_lookahead_split_dir]
  600. if = 'ERASE_SIZE == 512'
  601. defines.ERASE_COUNT = 1024
  602. code = '''
  603. lfs_t lfs;
  604. lfs_format(&lfs, cfg) => 0;
  605. lfs_mount(&lfs, cfg) => 0;
  606. // fill completely with two files
  607. lfs_file_t file;
  608. lfs_file_open(&lfs, &file, "exhaustion1",
  609. LFS_O_WRONLY | LFS_O_CREAT) => 0;
  610. size_t size = strlen("blahblahblahblah");
  611. uint8_t buffer[1024];
  612. memcpy(buffer, "blahblahblahblah", size);
  613. for (lfs_size_t i = 0;
  614. i < ((cfg->block_count-2)/2)*(cfg->block_size-8);
  615. i += size) {
  616. lfs_file_write(&lfs, &file, buffer, size) => size;
  617. }
  618. lfs_file_close(&lfs, &file) => 0;
  619. lfs_file_open(&lfs, &file, "exhaustion2",
  620. LFS_O_WRONLY | LFS_O_CREAT) => 0;
  621. size = strlen("blahblahblahblah");
  622. memcpy(buffer, "blahblahblahblah", size);
  623. for (lfs_size_t i = 0;
  624. i < ((cfg->block_count-2+1)/2)*(cfg->block_size-8);
  625. i += size) {
  626. lfs_file_write(&lfs, &file, buffer, size) => size;
  627. }
  628. lfs_file_close(&lfs, &file) => 0;
  629. // remount to force reset of lookahead
  630. lfs_unmount(&lfs) => 0;
  631. lfs_mount(&lfs, cfg) => 0;
  632. // rewrite one file with a hole of one block
  633. lfs_file_open(&lfs, &file, "exhaustion1",
  634. LFS_O_WRONLY | LFS_O_TRUNC) => 0;
  635. lfs_file_sync(&lfs, &file) => 0;
  636. size = strlen("blahblahblahblah");
  637. memcpy(buffer, "blahblahblahblah", size);
  638. for (lfs_size_t i = 0;
  639. i < ((cfg->block_count-2)/2 - 1)*(cfg->block_size-8);
  640. i += size) {
  641. lfs_file_write(&lfs, &file, buffer, size) => size;
  642. }
  643. lfs_file_close(&lfs, &file) => 0;
  644. // try to allocate a directory, should fail!
  645. lfs_mkdir(&lfs, "split") => LFS_ERR_NOSPC;
  646. // file should not fail
  647. lfs_file_open(&lfs, &file, "notasplit",
  648. LFS_O_WRONLY | LFS_O_CREAT) => 0;
  649. lfs_file_write(&lfs, &file, "hi", 2) => 2;
  650. lfs_file_close(&lfs, &file) => 0;
  651. lfs_unmount(&lfs) => 0;
  652. '''