test_alloc.toml 24 KB

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