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