test_exhaustion.toml 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. [[case]] # test running a filesystem to exhaustion
  2. define.LFS_ERASE_CYCLES = 10
  3. define.LFS_BLOCK_COUNT = 256 # small bd so test runs faster
  4. define.LFS_BLOCK_CYCLES = 'LFS_ERASE_CYCLES / 2'
  5. define.LFS_BADBLOCK_BEHAVIOR = [
  6. 'LFS_TESTBD_BADBLOCK_PROGERROR',
  7. 'LFS_TESTBD_BADBLOCK_ERASEERROR',
  8. 'LFS_TESTBD_BADBLOCK_READERROR',
  9. 'LFS_TESTBD_BADBLOCK_PROGNOOP',
  10. 'LFS_TESTBD_BADBLOCK_ERASENOOP',
  11. ]
  12. define.FILES = 10
  13. code = '''
  14. lfs_format(&lfs, &cfg) => 0;
  15. lfs_mount(&lfs, &cfg) => 0;
  16. lfs_mkdir(&lfs, "roadrunner") => 0;
  17. lfs_unmount(&lfs) => 0;
  18. uint32_t cycle = 0;
  19. while (true) {
  20. lfs_mount(&lfs, &cfg) => 0;
  21. for (uint32_t i = 0; i < FILES; i++) {
  22. // chose name, roughly random seed, and random 2^n size
  23. sprintf(path, "roadrunner/test%d", i);
  24. srand(cycle * i);
  25. size = 1 << ((rand() % 10)+2);
  26. lfs_file_open(&lfs, &file, path,
  27. LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
  28. for (lfs_size_t j = 0; j < size; j++) {
  29. char c = 'a' + (rand() % 26);
  30. lfs_ssize_t res = lfs_file_write(&lfs, &file, &c, 1);
  31. assert(res == 1 || res == LFS_ERR_NOSPC);
  32. if (res == LFS_ERR_NOSPC) {
  33. goto exhausted;
  34. }
  35. }
  36. err = lfs_file_close(&lfs, &file);
  37. assert(err == 0 || err == LFS_ERR_NOSPC);
  38. if (err == LFS_ERR_NOSPC) {
  39. goto exhausted;
  40. }
  41. }
  42. for (uint32_t i = 0; i < FILES; i++) {
  43. // check for errors
  44. sprintf(path, "roadrunner/test%d", i);
  45. srand(cycle * i);
  46. size = 1 << ((rand() % 10)+2);
  47. lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
  48. for (lfs_size_t j = 0; j < size; j++) {
  49. char c = 'a' + (rand() % 26);
  50. char r;
  51. lfs_file_read(&lfs, &file, &r, 1) => 1;
  52. assert(r == c);
  53. }
  54. lfs_file_close(&lfs, &file) => 0;
  55. }
  56. lfs_unmount(&lfs) => 0;
  57. cycle += 1;
  58. }
  59. exhausted:
  60. // should still be readable
  61. lfs_mount(&lfs, &cfg) => 0;
  62. for (uint32_t i = 0; i < FILES; i++) {
  63. // check for errors
  64. sprintf(path, "roadrunner/test%d", i);
  65. lfs_stat(&lfs, path, &info) => 0;
  66. }
  67. lfs_unmount(&lfs) => 0;
  68. LFS_WARN("completed %d cycles", cycle);
  69. '''
  70. [[case]] # test running a filesystem to exhaustion
  71. # which also requires expanding superblocks
  72. define.LFS_ERASE_CYCLES = 10
  73. define.LFS_BLOCK_COUNT = 256 # small bd so test runs faster
  74. define.LFS_BLOCK_CYCLES = 'LFS_ERASE_CYCLES / 2'
  75. define.LFS_BADBLOCK_BEHAVIOR = [
  76. 'LFS_TESTBD_BADBLOCK_PROGERROR',
  77. 'LFS_TESTBD_BADBLOCK_ERASEERROR',
  78. 'LFS_TESTBD_BADBLOCK_READERROR',
  79. 'LFS_TESTBD_BADBLOCK_PROGNOOP',
  80. 'LFS_TESTBD_BADBLOCK_ERASENOOP',
  81. ]
  82. define.FILES = 10
  83. code = '''
  84. lfs_format(&lfs, &cfg) => 0;
  85. uint32_t cycle = 0;
  86. while (true) {
  87. lfs_mount(&lfs, &cfg) => 0;
  88. for (uint32_t i = 0; i < FILES; i++) {
  89. // chose name, roughly random seed, and random 2^n size
  90. sprintf(path, "test%d", i);
  91. srand(cycle * i);
  92. size = 1 << ((rand() % 10)+2);
  93. lfs_file_open(&lfs, &file, path,
  94. LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
  95. for (lfs_size_t j = 0; j < size; j++) {
  96. char c = 'a' + (rand() % 26);
  97. lfs_ssize_t res = lfs_file_write(&lfs, &file, &c, 1);
  98. assert(res == 1 || res == LFS_ERR_NOSPC);
  99. if (res == LFS_ERR_NOSPC) {
  100. goto exhausted;
  101. }
  102. }
  103. err = lfs_file_close(&lfs, &file);
  104. assert(err == 0 || err == LFS_ERR_NOSPC);
  105. if (err == LFS_ERR_NOSPC) {
  106. goto exhausted;
  107. }
  108. }
  109. for (uint32_t i = 0; i < FILES; i++) {
  110. // check for errors
  111. sprintf(path, "test%d", i);
  112. srand(cycle * i);
  113. size = 1 << ((rand() % 10)+2);
  114. lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
  115. for (lfs_size_t j = 0; j < size; j++) {
  116. char c = 'a' + (rand() % 26);
  117. char r;
  118. lfs_file_read(&lfs, &file, &r, 1) => 1;
  119. assert(r == c);
  120. }
  121. lfs_file_close(&lfs, &file) => 0;
  122. }
  123. lfs_unmount(&lfs) => 0;
  124. cycle += 1;
  125. }
  126. exhausted:
  127. // should still be readable
  128. lfs_mount(&lfs, &cfg) => 0;
  129. for (uint32_t i = 0; i < FILES; i++) {
  130. // check for errors
  131. sprintf(path, "test%d", i);
  132. lfs_stat(&lfs, path, &info) => 0;
  133. }
  134. lfs_unmount(&lfs) => 0;
  135. LFS_WARN("completed %d cycles", cycle);
  136. '''
  137. # These are a sort of high-level litmus test for wear-leveling. One definition
  138. # of wear-leveling is that increasing a block device's space translates directly
  139. # into increasing the block devices lifetime. This is something we can actually
  140. # check for.
  141. [[case]] # wear-level test running a filesystem to exhaustion
  142. define.LFS_ERASE_CYCLES = 20
  143. define.LFS_BLOCK_COUNT = 256 # small bd so test runs faster
  144. define.LFS_BLOCK_CYCLES = 'LFS_ERASE_CYCLES / 2'
  145. define.FILES = 10
  146. code = '''
  147. uint32_t run_cycles[2];
  148. const uint32_t run_block_count[2] = {LFS_BLOCK_COUNT/2, LFS_BLOCK_COUNT};
  149. for (int run = 0; run < 2; run++) {
  150. for (lfs_block_t b = 0; b < LFS_BLOCK_COUNT; b++) {
  151. lfs_testbd_setwear(&cfg, b,
  152. (b < run_block_count[run]) ? 0 : LFS_ERASE_CYCLES) => 0;
  153. }
  154. lfs_format(&lfs, &cfg) => 0;
  155. lfs_mount(&lfs, &cfg) => 0;
  156. lfs_mkdir(&lfs, "roadrunner") => 0;
  157. lfs_unmount(&lfs) => 0;
  158. uint32_t cycle = 0;
  159. while (true) {
  160. lfs_mount(&lfs, &cfg) => 0;
  161. for (uint32_t i = 0; i < FILES; i++) {
  162. // chose name, roughly random seed, and random 2^n size
  163. sprintf(path, "roadrunner/test%d", i);
  164. srand(cycle * i);
  165. size = 1 << ((rand() % 10)+2);
  166. lfs_file_open(&lfs, &file, path,
  167. LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
  168. for (lfs_size_t j = 0; j < size; j++) {
  169. char c = 'a' + (rand() % 26);
  170. lfs_ssize_t res = lfs_file_write(&lfs, &file, &c, 1);
  171. assert(res == 1 || res == LFS_ERR_NOSPC);
  172. if (res == LFS_ERR_NOSPC) {
  173. goto exhausted;
  174. }
  175. }
  176. err = lfs_file_close(&lfs, &file);
  177. assert(err == 0 || err == LFS_ERR_NOSPC);
  178. if (err == LFS_ERR_NOSPC) {
  179. goto exhausted;
  180. }
  181. }
  182. for (uint32_t i = 0; i < FILES; i++) {
  183. // check for errors
  184. sprintf(path, "roadrunner/test%d", i);
  185. srand(cycle * i);
  186. size = 1 << ((rand() % 10)+2);
  187. lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
  188. for (lfs_size_t j = 0; j < size; j++) {
  189. char c = 'a' + (rand() % 26);
  190. char r;
  191. lfs_file_read(&lfs, &file, &r, 1) => 1;
  192. assert(r == c);
  193. }
  194. lfs_file_close(&lfs, &file) => 0;
  195. }
  196. lfs_unmount(&lfs) => 0;
  197. cycle += 1;
  198. }
  199. exhausted:
  200. // should still be readable
  201. lfs_mount(&lfs, &cfg) => 0;
  202. for (uint32_t i = 0; i < FILES; i++) {
  203. // check for errors
  204. sprintf(path, "roadrunner/test%d", i);
  205. lfs_stat(&lfs, path, &info) => 0;
  206. }
  207. lfs_unmount(&lfs) => 0;
  208. run_cycles[run] = cycle;
  209. LFS_WARN("completed %d blocks %d cycles",
  210. run_block_count[run], run_cycles[run]);
  211. }
  212. // check we increased the lifetime by 2x with ~10% error
  213. LFS_ASSERT(run_cycles[1]*110/100 > 2*run_cycles[0]);
  214. '''
  215. [[case]] # wear-level test + expanding superblock
  216. define.LFS_ERASE_CYCLES = 20
  217. define.LFS_BLOCK_COUNT = 256 # small bd so test runs faster
  218. define.LFS_BLOCK_CYCLES = 'LFS_ERASE_CYCLES / 2'
  219. define.FILES = 10
  220. code = '''
  221. uint32_t run_cycles[2];
  222. const uint32_t run_block_count[2] = {LFS_BLOCK_COUNT/2, LFS_BLOCK_COUNT};
  223. for (int run = 0; run < 2; run++) {
  224. for (lfs_block_t b = 0; b < LFS_BLOCK_COUNT; b++) {
  225. lfs_testbd_setwear(&cfg, b,
  226. (b < run_block_count[run]) ? 0 : LFS_ERASE_CYCLES) => 0;
  227. }
  228. lfs_format(&lfs, &cfg) => 0;
  229. uint32_t cycle = 0;
  230. while (true) {
  231. lfs_mount(&lfs, &cfg) => 0;
  232. for (uint32_t i = 0; i < FILES; i++) {
  233. // chose name, roughly random seed, and random 2^n size
  234. sprintf(path, "test%d", i);
  235. srand(cycle * i);
  236. size = 1 << ((rand() % 10)+2);
  237. lfs_file_open(&lfs, &file, path,
  238. LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
  239. for (lfs_size_t j = 0; j < size; j++) {
  240. char c = 'a' + (rand() % 26);
  241. lfs_ssize_t res = lfs_file_write(&lfs, &file, &c, 1);
  242. assert(res == 1 || res == LFS_ERR_NOSPC);
  243. if (res == LFS_ERR_NOSPC) {
  244. goto exhausted;
  245. }
  246. }
  247. err = lfs_file_close(&lfs, &file);
  248. assert(err == 0 || err == LFS_ERR_NOSPC);
  249. if (err == LFS_ERR_NOSPC) {
  250. goto exhausted;
  251. }
  252. }
  253. for (uint32_t i = 0; i < FILES; i++) {
  254. // check for errors
  255. sprintf(path, "test%d", i);
  256. srand(cycle * i);
  257. size = 1 << ((rand() % 10)+2);
  258. lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
  259. for (lfs_size_t j = 0; j < size; j++) {
  260. char c = 'a' + (rand() % 26);
  261. char r;
  262. lfs_file_read(&lfs, &file, &r, 1) => 1;
  263. assert(r == c);
  264. }
  265. lfs_file_close(&lfs, &file) => 0;
  266. }
  267. lfs_unmount(&lfs) => 0;
  268. cycle += 1;
  269. }
  270. exhausted:
  271. // should still be readable
  272. lfs_mount(&lfs, &cfg) => 0;
  273. for (uint32_t i = 0; i < FILES; i++) {
  274. // check for errors
  275. sprintf(path, "test%d", i);
  276. lfs_stat(&lfs, path, &info) => 0;
  277. }
  278. lfs_unmount(&lfs) => 0;
  279. run_cycles[run] = cycle;
  280. LFS_WARN("completed %d blocks %d cycles",
  281. run_block_count[run], run_cycles[run]);
  282. }
  283. // check we increased the lifetime by 2x with ~10% error
  284. LFS_ASSERT(run_cycles[1]*110/100 > 2*run_cycles[0]);
  285. '''