diff --git a/tests/test_alloc.toml b/tests/test_alloc.toml index c05f001..fa92da5 100644 --- a/tests/test_alloc.toml +++ b/tests/test_alloc.toml @@ -323,6 +323,90 @@ code = ''' lfs_unmount(&lfs) => 0; ''' +[[case]] # what if we have a bad block during an allocation scan? +in = "lfs.c" +define.LFS_ERASE_CYCLES = 0xffffffff +define.LFS_BADBLOCK_BEHAVIOR = 'LFS_TESTBD_BADBLOCK_READERROR' +code = ''' + lfs_format(&lfs, &cfg) => 0; + lfs_mount(&lfs, &cfg) => 0; + // first fill to exhaustion to find available space + lfs_file_open(&lfs, &file, "pacman", LFS_O_WRONLY | LFS_O_CREAT) => 0; + strcpy((char*)buffer, "waka"); + size = strlen("waka"); + lfs_size_t filesize = 0; + while (true) { + lfs_ssize_t res = lfs_file_write(&lfs, &file, buffer, size); + assert(res == (lfs_ssize_t)size || res == LFS_ERR_NOSPC); + if (res == LFS_ERR_NOSPC) { + break; + } + filesize += size; + } + lfs_file_close(&lfs, &file) => 0; + // now fill all but a couple of blocks of the filesystem with data + filesize -= 3*LFS_BLOCK_SIZE; + lfs_file_open(&lfs, &file, "pacman", LFS_O_WRONLY | LFS_O_CREAT) => 0; + strcpy((char*)buffer, "waka"); + size = strlen("waka"); + for (lfs_size_t i = 0; i < filesize/size; i++) { + lfs_file_write(&lfs, &file, buffer, size) => size; + } + lfs_file_close(&lfs, &file) => 0; + // also save head of file so we can error during lookahead scan + lfs_block_t fileblock = file.ctz.head; + lfs_unmount(&lfs) => 0; + + // remount to force an alloc scan + lfs_mount(&lfs, &cfg) => 0; + + // but mark the head of our file as a "bad block", this is force our + // scan to bail early + lfs_testbd_setwear(&cfg, fileblock, 0xffffffff) => 0; + lfs_file_open(&lfs, &file, "ghost", LFS_O_WRONLY | LFS_O_CREAT) => 0; + strcpy((char*)buffer, "chomp"); + size = strlen("chomp"); + while (true) { + lfs_ssize_t res = lfs_file_write(&lfs, &file, buffer, size); + assert(res == (lfs_ssize_t)size || res == LFS_ERR_CORRUPT); + if (res == LFS_ERR_CORRUPT) { + break; + } + } + lfs_file_close(&lfs, &file) => 0; + + // now reverse the "bad block" and try to write the file again until we + // run out of space + lfs_testbd_setwear(&cfg, fileblock, 0) => 0; + lfs_file_open(&lfs, &file, "ghost", LFS_O_WRONLY | LFS_O_CREAT) => 0; + strcpy((char*)buffer, "chomp"); + size = strlen("chomp"); + while (true) { + lfs_ssize_t res = lfs_file_write(&lfs, &file, buffer, size); + assert(res == (lfs_ssize_t)size || res == LFS_ERR_NOSPC); + if (res == LFS_ERR_NOSPC) { + break; + } + } + lfs_file_close(&lfs, &file) => 0; + + lfs_unmount(&lfs) => 0; + + // check that the disk isn't hurt + lfs_mount(&lfs, &cfg) => 0; + lfs_file_open(&lfs, &file, "pacman", LFS_O_RDONLY) => 0; + strcpy((char*)buffer, "waka"); + size = strlen("waka"); + for (lfs_size_t i = 0; i < filesize/size; i++) { + uint8_t rbuffer[4]; + lfs_file_read(&lfs, &file, rbuffer, size) => size; + assert(memcmp(rbuffer, buffer, size) == 0); + } + lfs_file_close(&lfs, &file) => 0; + lfs_unmount(&lfs) => 0; +''' + + # Below, I don't like these tests. They're fragile and depend _heavily_ # on the geometry of the block device. But they are valuable. Eventually they # should be removed and replaced with generalized tests.