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