forked from Imagelibrary/littlefs
The main benefit is small test ids everywhere, though this is with the downside of needing longer names to properly prefix and avoid collisions. But this fits into the rest of the scripts with globally unique names a bit better. This is a C project after all. The other small benefit is test generators may have an easier time since per-case symbols can expect to be unique.
718 lines
22 KiB
TOML
718 lines
22 KiB
TOML
# allocator tests
|
|
# note for these to work there are a number constraints on the device geometry
|
|
if = 'BLOCK_CYCLES == -1'
|
|
|
|
# parallel allocation test
|
|
[cases.test_alloc_parallel]
|
|
defines.FILES = 3
|
|
defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-6)) / FILES)'
|
|
code = '''
|
|
const char *names[] = {"bacon", "eggs", "pancakes"};
|
|
lfs_file_t files[FILES];
|
|
|
|
lfs_t lfs;
|
|
lfs_format(&lfs, cfg) => 0;
|
|
lfs_mount(&lfs, cfg) => 0;
|
|
lfs_mkdir(&lfs, "breakfast") => 0;
|
|
lfs_unmount(&lfs) => 0;
|
|
|
|
lfs_mount(&lfs, cfg) => 0;
|
|
for (int n = 0; n < FILES; n++) {
|
|
char path[1024];
|
|
sprintf(path, "breakfast/%s", names[n]);
|
|
lfs_file_open(&lfs, &files[n], path,
|
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0;
|
|
}
|
|
for (int n = 0; n < FILES; n++) {
|
|
size_t size = strlen(names[n]);
|
|
for (lfs_size_t i = 0; i < SIZE; i += size) {
|
|
lfs_file_write(&lfs, &files[n], names[n], size) => size;
|
|
}
|
|
}
|
|
for (int n = 0; n < FILES; n++) {
|
|
lfs_file_close(&lfs, &files[n]) => 0;
|
|
}
|
|
lfs_unmount(&lfs) => 0;
|
|
|
|
lfs_mount(&lfs, cfg) => 0;
|
|
for (int n = 0; n < FILES; n++) {
|
|
char path[1024];
|
|
sprintf(path, "breakfast/%s", names[n]);
|
|
lfs_file_t file;
|
|
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
|
|
size_t size = strlen(names[n]);
|
|
for (lfs_size_t i = 0; i < SIZE; i += size) {
|
|
uint8_t buffer[1024];
|
|
lfs_file_read(&lfs, &file, buffer, size) => size;
|
|
assert(memcmp(buffer, names[n], size) == 0);
|
|
}
|
|
lfs_file_close(&lfs, &file) => 0;
|
|
}
|
|
lfs_unmount(&lfs) => 0;
|
|
'''
|
|
|
|
# serial allocation test
|
|
[cases.test_alloc_serial]
|
|
defines.FILES = 3
|
|
defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-6)) / FILES)'
|
|
code = '''
|
|
const char *names[] = {"bacon", "eggs", "pancakes"};
|
|
|
|
lfs_t lfs;
|
|
lfs_format(&lfs, cfg) => 0;
|
|
lfs_mount(&lfs, cfg) => 0;
|
|
lfs_mkdir(&lfs, "breakfast") => 0;
|
|
lfs_unmount(&lfs) => 0;
|
|
|
|
for (int n = 0; n < FILES; n++) {
|
|
lfs_mount(&lfs, cfg) => 0;
|
|
char path[1024];
|
|
sprintf(path, "breakfast/%s", names[n]);
|
|
lfs_file_t file;
|
|
lfs_file_open(&lfs, &file, path,
|
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0;
|
|
size_t size = strlen(names[n]);
|
|
uint8_t buffer[1024];
|
|
memcpy(buffer, names[n], size);
|
|
for (int i = 0; i < SIZE; i += size) {
|
|
lfs_file_write(&lfs, &file, buffer, size) => size;
|
|
}
|
|
lfs_file_close(&lfs, &file) => 0;
|
|
lfs_unmount(&lfs) => 0;
|
|
}
|
|
|
|
lfs_mount(&lfs, cfg) => 0;
|
|
for (int n = 0; n < FILES; n++) {
|
|
char path[1024];
|
|
sprintf(path, "breakfast/%s", names[n]);
|
|
lfs_file_t file;
|
|
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
|
|
size_t size = strlen(names[n]);
|
|
for (int i = 0; i < SIZE; i += size) {
|
|
uint8_t buffer[1024];
|
|
lfs_file_read(&lfs, &file, buffer, size) => size;
|
|
assert(memcmp(buffer, names[n], size) == 0);
|
|
}
|
|
lfs_file_close(&lfs, &file) => 0;
|
|
}
|
|
lfs_unmount(&lfs) => 0;
|
|
'''
|
|
|
|
# parallel allocation reuse test
|
|
[cases.test_alloc_parallel_reuse]
|
|
defines.FILES = 3
|
|
defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-6)) / FILES)'
|
|
defines.CYCLES = [1, 10]
|
|
code = '''
|
|
const char *names[] = {"bacon", "eggs", "pancakes"};
|
|
lfs_file_t files[FILES];
|
|
|
|
lfs_t lfs;
|
|
lfs_format(&lfs, cfg) => 0;
|
|
|
|
for (int c = 0; c < CYCLES; c++) {
|
|
lfs_mount(&lfs, cfg) => 0;
|
|
lfs_mkdir(&lfs, "breakfast") => 0;
|
|
lfs_unmount(&lfs) => 0;
|
|
|
|
lfs_mount(&lfs, cfg) => 0;
|
|
for (int n = 0; n < FILES; n++) {
|
|
char path[1024];
|
|
sprintf(path, "breakfast/%s", names[n]);
|
|
lfs_file_open(&lfs, &files[n], path,
|
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0;
|
|
}
|
|
for (int n = 0; n < FILES; n++) {
|
|
size_t size = strlen(names[n]);
|
|
for (int i = 0; i < SIZE; i += size) {
|
|
lfs_file_write(&lfs, &files[n], names[n], size) => size;
|
|
}
|
|
}
|
|
for (int n = 0; n < FILES; n++) {
|
|
lfs_file_close(&lfs, &files[n]) => 0;
|
|
}
|
|
lfs_unmount(&lfs) => 0;
|
|
|
|
lfs_mount(&lfs, cfg) => 0;
|
|
for (int n = 0; n < FILES; n++) {
|
|
char path[1024];
|
|
sprintf(path, "breakfast/%s", names[n]);
|
|
lfs_file_t file;
|
|
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
|
|
size_t size = strlen(names[n]);
|
|
for (int i = 0; i < SIZE; i += size) {
|
|
uint8_t buffer[1024];
|
|
lfs_file_read(&lfs, &file, buffer, size) => size;
|
|
assert(memcmp(buffer, names[n], size) == 0);
|
|
}
|
|
lfs_file_close(&lfs, &file) => 0;
|
|
}
|
|
lfs_unmount(&lfs) => 0;
|
|
|
|
lfs_mount(&lfs, cfg) => 0;
|
|
for (int n = 0; n < FILES; n++) {
|
|
char path[1024];
|
|
sprintf(path, "breakfast/%s", names[n]);
|
|
lfs_remove(&lfs, path) => 0;
|
|
}
|
|
lfs_remove(&lfs, "breakfast") => 0;
|
|
lfs_unmount(&lfs) => 0;
|
|
}
|
|
'''
|
|
|
|
# serial allocation reuse test
|
|
[cases.test_alloc_serial_reuse]
|
|
defines.FILES = 3
|
|
defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-6)) / FILES)'
|
|
defines.CYCLES = [1, 10]
|
|
code = '''
|
|
const char *names[] = {"bacon", "eggs", "pancakes"};
|
|
|
|
lfs_t lfs;
|
|
lfs_format(&lfs, cfg) => 0;
|
|
|
|
for (int c = 0; c < CYCLES; c++) {
|
|
lfs_mount(&lfs, cfg) => 0;
|
|
lfs_mkdir(&lfs, "breakfast") => 0;
|
|
lfs_unmount(&lfs) => 0;
|
|
|
|
for (int n = 0; n < FILES; n++) {
|
|
lfs_mount(&lfs, cfg) => 0;
|
|
char path[1024];
|
|
sprintf(path, "breakfast/%s", names[n]);
|
|
lfs_file_t file;
|
|
lfs_file_open(&lfs, &file, path,
|
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0;
|
|
size_t size = strlen(names[n]);
|
|
uint8_t buffer[1024];
|
|
memcpy(buffer, names[n], size);
|
|
for (int i = 0; i < SIZE; i += size) {
|
|
lfs_file_write(&lfs, &file, buffer, size) => size;
|
|
}
|
|
lfs_file_close(&lfs, &file) => 0;
|
|
lfs_unmount(&lfs) => 0;
|
|
}
|
|
|
|
lfs_mount(&lfs, cfg) => 0;
|
|
for (int n = 0; n < FILES; n++) {
|
|
char path[1024];
|
|
sprintf(path, "breakfast/%s", names[n]);
|
|
lfs_file_t file;
|
|
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
|
|
size_t size = strlen(names[n]);
|
|
for (int i = 0; i < SIZE; i += size) {
|
|
uint8_t buffer[1024];
|
|
lfs_file_read(&lfs, &file, buffer, size) => size;
|
|
assert(memcmp(buffer, names[n], size) == 0);
|
|
}
|
|
lfs_file_close(&lfs, &file) => 0;
|
|
}
|
|
lfs_unmount(&lfs) => 0;
|
|
|
|
lfs_mount(&lfs, cfg) => 0;
|
|
for (int n = 0; n < FILES; n++) {
|
|
char path[1024];
|
|
sprintf(path, "breakfast/%s", names[n]);
|
|
lfs_remove(&lfs, path) => 0;
|
|
}
|
|
lfs_remove(&lfs, "breakfast") => 0;
|
|
lfs_unmount(&lfs) => 0;
|
|
}
|
|
'''
|
|
|
|
# exhaustion test
|
|
[cases.test_alloc_exhaustion]
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfs_format(&lfs, cfg) => 0;
|
|
lfs_mount(&lfs, cfg) => 0;
|
|
lfs_file_t file;
|
|
lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT);
|
|
size_t size = strlen("exhaustion");
|
|
uint8_t buffer[1024];
|
|
memcpy(buffer, "exhaustion", size);
|
|
lfs_file_write(&lfs, &file, buffer, size) => size;
|
|
lfs_file_sync(&lfs, &file) => 0;
|
|
|
|
size = strlen("blahblahblahblah");
|
|
memcpy(buffer, "blahblahblahblah", size);
|
|
lfs_ssize_t res;
|
|
while (true) {
|
|
res = lfs_file_write(&lfs, &file, buffer, size);
|
|
if (res < 0) {
|
|
break;
|
|
}
|
|
|
|
res => size;
|
|
}
|
|
res => LFS_ERR_NOSPC;
|
|
|
|
lfs_file_close(&lfs, &file) => 0;
|
|
lfs_unmount(&lfs) => 0;
|
|
|
|
lfs_mount(&lfs, cfg) => 0;
|
|
lfs_file_open(&lfs, &file, "exhaustion", LFS_O_RDONLY);
|
|
size = strlen("exhaustion");
|
|
lfs_file_size(&lfs, &file) => size;
|
|
lfs_file_read(&lfs, &file, buffer, size) => size;
|
|
memcmp(buffer, "exhaustion", size) => 0;
|
|
lfs_file_close(&lfs, &file) => 0;
|
|
lfs_unmount(&lfs) => 0;
|
|
'''
|
|
|
|
# exhaustion wraparound test
|
|
[cases.test_alloc_exhaustion_wraparound]
|
|
defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-4)) / 3)'
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfs_format(&lfs, cfg) => 0;
|
|
lfs_mount(&lfs, cfg) => 0;
|
|
|
|
lfs_file_t file;
|
|
lfs_file_open(&lfs, &file, "padding", LFS_O_WRONLY | LFS_O_CREAT);
|
|
size_t size = strlen("buffering");
|
|
uint8_t buffer[1024];
|
|
memcpy(buffer, "buffering", size);
|
|
for (int i = 0; i < SIZE; i += size) {
|
|
lfs_file_write(&lfs, &file, buffer, size) => size;
|
|
}
|
|
lfs_file_close(&lfs, &file) => 0;
|
|
lfs_remove(&lfs, "padding") => 0;
|
|
|
|
lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT);
|
|
size = strlen("exhaustion");
|
|
memcpy(buffer, "exhaustion", size);
|
|
lfs_file_write(&lfs, &file, buffer, size) => size;
|
|
lfs_file_sync(&lfs, &file) => 0;
|
|
|
|
size = strlen("blahblahblahblah");
|
|
memcpy(buffer, "blahblahblahblah", size);
|
|
lfs_ssize_t res;
|
|
while (true) {
|
|
res = lfs_file_write(&lfs, &file, buffer, size);
|
|
if (res < 0) {
|
|
break;
|
|
}
|
|
|
|
res => size;
|
|
}
|
|
res => LFS_ERR_NOSPC;
|
|
|
|
lfs_file_close(&lfs, &file) => 0;
|
|
lfs_unmount(&lfs) => 0;
|
|
|
|
lfs_mount(&lfs, cfg) => 0;
|
|
lfs_file_open(&lfs, &file, "exhaustion", LFS_O_RDONLY);
|
|
size = strlen("exhaustion");
|
|
lfs_file_size(&lfs, &file) => size;
|
|
lfs_file_read(&lfs, &file, buffer, size) => size;
|
|
memcmp(buffer, "exhaustion", size) => 0;
|
|
lfs_file_close(&lfs, &file) => 0;
|
|
lfs_remove(&lfs, "exhaustion") => 0;
|
|
lfs_unmount(&lfs) => 0;
|
|
'''
|
|
|
|
# dir exhaustion test
|
|
[cases.test_alloc_dir_exhaustion]
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfs_format(&lfs, cfg) => 0;
|
|
lfs_mount(&lfs, cfg) => 0;
|
|
|
|
// find out max file size
|
|
lfs_mkdir(&lfs, "exhaustiondir") => 0;
|
|
size_t size = strlen("blahblahblahblah");
|
|
uint8_t buffer[1024];
|
|
memcpy(buffer, "blahblahblahblah", size);
|
|
lfs_file_t file;
|
|
lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT);
|
|
int count = 0;
|
|
int err;
|
|
while (true) {
|
|
err = lfs_file_write(&lfs, &file, buffer, size);
|
|
if (err < 0) {
|
|
break;
|
|
}
|
|
|
|
count += 1;
|
|
}
|
|
err => LFS_ERR_NOSPC;
|
|
lfs_file_close(&lfs, &file) => 0;
|
|
|
|
lfs_remove(&lfs, "exhaustion") => 0;
|
|
lfs_remove(&lfs, "exhaustiondir") => 0;
|
|
|
|
// see if dir fits with max file size
|
|
lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT);
|
|
for (int i = 0; i < count; i++) {
|
|
lfs_file_write(&lfs, &file, buffer, size) => size;
|
|
}
|
|
lfs_file_close(&lfs, &file) => 0;
|
|
|
|
lfs_mkdir(&lfs, "exhaustiondir") => 0;
|
|
lfs_remove(&lfs, "exhaustiondir") => 0;
|
|
lfs_remove(&lfs, "exhaustion") => 0;
|
|
|
|
// see if dir fits with > max file size
|
|
lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT);
|
|
for (int i = 0; i < count+1; i++) {
|
|
lfs_file_write(&lfs, &file, buffer, size) => size;
|
|
}
|
|
lfs_file_close(&lfs, &file) => 0;
|
|
|
|
lfs_mkdir(&lfs, "exhaustiondir") => LFS_ERR_NOSPC;
|
|
|
|
lfs_remove(&lfs, "exhaustion") => 0;
|
|
lfs_unmount(&lfs) => 0;
|
|
'''
|
|
|
|
# what if we have a bad block during an allocation scan?
|
|
[cases.test_alloc_bad_blocks]
|
|
in = "lfs.c"
|
|
defines.ERASE_CYCLES = 0xffffffff
|
|
defines.BADBLOCK_BEHAVIOR = 'LFS_TESTBD_BADBLOCK_READERROR'
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfs_format(&lfs, cfg) => 0;
|
|
lfs_mount(&lfs, cfg) => 0;
|
|
// first fill to exhaustion to find available space
|
|
lfs_file_t file;
|
|
lfs_file_open(&lfs, &file, "pacman", LFS_O_WRONLY | LFS_O_CREAT) => 0;
|
|
uint8_t buffer[1024];
|
|
strcpy((char*)buffer, "waka");
|
|
size_t 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*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.
|
|
|
|
# chained dir exhaustion test
|
|
[cases.test_alloc_chained_dir_exhaustion]
|
|
if = 'BLOCK_SIZE == 512'
|
|
defines.BLOCK_COUNT = 1024
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfs_format(&lfs, cfg) => 0;
|
|
lfs_mount(&lfs, cfg) => 0;
|
|
|
|
// find out max file size
|
|
lfs_mkdir(&lfs, "exhaustiondir") => 0;
|
|
for (int i = 0; i < 10; i++) {
|
|
char path[1024];
|
|
sprintf(path, "dirwithanexhaustivelylongnameforpadding%d", i);
|
|
lfs_mkdir(&lfs, path) => 0;
|
|
}
|
|
size_t size = strlen("blahblahblahblah");
|
|
uint8_t buffer[1024];
|
|
memcpy(buffer, "blahblahblahblah", size);
|
|
lfs_file_t file;
|
|
lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT);
|
|
int count = 0;
|
|
int err;
|
|
while (true) {
|
|
err = lfs_file_write(&lfs, &file, buffer, size);
|
|
if (err < 0) {
|
|
break;
|
|
}
|
|
|
|
count += 1;
|
|
}
|
|
err => LFS_ERR_NOSPC;
|
|
lfs_file_close(&lfs, &file) => 0;
|
|
|
|
lfs_remove(&lfs, "exhaustion") => 0;
|
|
lfs_remove(&lfs, "exhaustiondir") => 0;
|
|
for (int i = 0; i < 10; i++) {
|
|
char path[1024];
|
|
sprintf(path, "dirwithanexhaustivelylongnameforpadding%d", i);
|
|
lfs_remove(&lfs, path) => 0;
|
|
}
|
|
|
|
// see that chained dir fails
|
|
lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT);
|
|
for (int i = 0; i < count+1; i++) {
|
|
lfs_file_write(&lfs, &file, buffer, size) => size;
|
|
}
|
|
lfs_file_sync(&lfs, &file) => 0;
|
|
|
|
for (int i = 0; i < 10; i++) {
|
|
char path[1024];
|
|
sprintf(path, "dirwithanexhaustivelylongnameforpadding%d", i);
|
|
lfs_mkdir(&lfs, path) => 0;
|
|
}
|
|
|
|
lfs_mkdir(&lfs, "exhaustiondir") => LFS_ERR_NOSPC;
|
|
|
|
// shorten file to try a second chained dir
|
|
while (true) {
|
|
err = lfs_mkdir(&lfs, "exhaustiondir");
|
|
if (err != LFS_ERR_NOSPC) {
|
|
break;
|
|
}
|
|
|
|
lfs_ssize_t filesize = lfs_file_size(&lfs, &file);
|
|
filesize > 0 => true;
|
|
|
|
lfs_file_truncate(&lfs, &file, filesize - size) => 0;
|
|
lfs_file_sync(&lfs, &file) => 0;
|
|
}
|
|
err => 0;
|
|
|
|
lfs_mkdir(&lfs, "exhaustiondir2") => LFS_ERR_NOSPC;
|
|
|
|
lfs_file_close(&lfs, &file) => 0;
|
|
lfs_unmount(&lfs) => 0;
|
|
'''
|
|
|
|
# split dir test
|
|
[cases.test_alloc_split_dir]
|
|
if = 'BLOCK_SIZE == 512'
|
|
defines.BLOCK_COUNT = 1024
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfs_format(&lfs, cfg) => 0;
|
|
lfs_mount(&lfs, cfg) => 0;
|
|
|
|
// create one block hole for half a directory
|
|
lfs_file_t file;
|
|
lfs_file_open(&lfs, &file, "bump", LFS_O_WRONLY | LFS_O_CREAT) => 0;
|
|
for (lfs_size_t i = 0; i < cfg->block_size; i += 2) {
|
|
uint8_t buffer[1024];
|
|
memcpy(&buffer[i], "hi", 2);
|
|
}
|
|
uint8_t buffer[1024];
|
|
lfs_file_write(&lfs, &file, buffer, cfg->block_size) => cfg->block_size;
|
|
lfs_file_close(&lfs, &file) => 0;
|
|
|
|
lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT);
|
|
size_t size = strlen("blahblahblahblah");
|
|
memcpy(buffer, "blahblahblahblah", size);
|
|
for (lfs_size_t i = 0;
|
|
i < (cfg->block_count-4)*(cfg->block_size-8);
|
|
i += size) {
|
|
lfs_file_write(&lfs, &file, buffer, size) => size;
|
|
}
|
|
lfs_file_close(&lfs, &file) => 0;
|
|
|
|
// remount to force reset of lookahead
|
|
lfs_unmount(&lfs) => 0;
|
|
lfs_mount(&lfs, cfg) => 0;
|
|
|
|
// open hole
|
|
lfs_remove(&lfs, "bump") => 0;
|
|
|
|
lfs_mkdir(&lfs, "splitdir") => 0;
|
|
lfs_file_open(&lfs, &file, "splitdir/bump",
|
|
LFS_O_WRONLY | LFS_O_CREAT) => 0;
|
|
for (lfs_size_t i = 0; i < cfg->block_size; i += 2) {
|
|
memcpy(&buffer[i], "hi", 2);
|
|
}
|
|
lfs_file_write(&lfs, &file, buffer, 2*cfg->block_size) => LFS_ERR_NOSPC;
|
|
lfs_file_close(&lfs, &file) => 0;
|
|
|
|
lfs_unmount(&lfs) => 0;
|
|
'''
|
|
|
|
# outdated lookahead test
|
|
[cases.test_alloc_outdated_lookahead]
|
|
if = 'BLOCK_SIZE == 512'
|
|
defines.BLOCK_COUNT = 1024
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfs_format(&lfs, cfg) => 0;
|
|
lfs_mount(&lfs, cfg) => 0;
|
|
|
|
// fill completely with two files
|
|
lfs_file_t file;
|
|
lfs_file_open(&lfs, &file, "exhaustion1",
|
|
LFS_O_WRONLY | LFS_O_CREAT) => 0;
|
|
size_t size = strlen("blahblahblahblah");
|
|
uint8_t buffer[1024];
|
|
memcpy(buffer, "blahblahblahblah", size);
|
|
for (lfs_size_t i = 0;
|
|
i < ((cfg->block_count-2)/2)*(cfg->block_size-8);
|
|
i += size) {
|
|
lfs_file_write(&lfs, &file, buffer, size) => size;
|
|
}
|
|
lfs_file_close(&lfs, &file) => 0;
|
|
|
|
lfs_file_open(&lfs, &file, "exhaustion2",
|
|
LFS_O_WRONLY | LFS_O_CREAT) => 0;
|
|
size = strlen("blahblahblahblah");
|
|
memcpy(buffer, "blahblahblahblah", size);
|
|
for (lfs_size_t i = 0;
|
|
i < ((cfg->block_count-2+1)/2)*(cfg->block_size-8);
|
|
i += size) {
|
|
lfs_file_write(&lfs, &file, buffer, size) => size;
|
|
}
|
|
lfs_file_close(&lfs, &file) => 0;
|
|
|
|
// remount to force reset of lookahead
|
|
lfs_unmount(&lfs) => 0;
|
|
lfs_mount(&lfs, cfg) => 0;
|
|
|
|
// rewrite one file
|
|
lfs_file_open(&lfs, &file, "exhaustion1",
|
|
LFS_O_WRONLY | LFS_O_TRUNC) => 0;
|
|
lfs_file_sync(&lfs, &file) => 0;
|
|
size = strlen("blahblahblahblah");
|
|
memcpy(buffer, "blahblahblahblah", size);
|
|
for (lfs_size_t i = 0;
|
|
i < ((cfg->block_count-2)/2)*(cfg->block_size-8);
|
|
i += size) {
|
|
lfs_file_write(&lfs, &file, buffer, size) => size;
|
|
}
|
|
lfs_file_close(&lfs, &file) => 0;
|
|
|
|
// rewrite second file, this requires lookahead does not
|
|
// use old population
|
|
lfs_file_open(&lfs, &file, "exhaustion2",
|
|
LFS_O_WRONLY | LFS_O_TRUNC) => 0;
|
|
lfs_file_sync(&lfs, &file) => 0;
|
|
size = strlen("blahblahblahblah");
|
|
memcpy(buffer, "blahblahblahblah", size);
|
|
for (lfs_size_t i = 0;
|
|
i < ((cfg->block_count-2+1)/2)*(cfg->block_size-8);
|
|
i += size) {
|
|
lfs_file_write(&lfs, &file, buffer, size) => size;
|
|
}
|
|
lfs_file_close(&lfs, &file) => 0;
|
|
|
|
lfs_unmount(&lfs) => 0;
|
|
'''
|
|
|
|
# outdated lookahead and split dir test
|
|
[cases.test_alloc_outdated_lookahead_split_dir]
|
|
if = 'BLOCK_SIZE == 512'
|
|
defines.BLOCK_COUNT = 1024
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfs_format(&lfs, cfg) => 0;
|
|
lfs_mount(&lfs, cfg) => 0;
|
|
|
|
// fill completely with two files
|
|
lfs_file_t file;
|
|
lfs_file_open(&lfs, &file, "exhaustion1",
|
|
LFS_O_WRONLY | LFS_O_CREAT) => 0;
|
|
size_t size = strlen("blahblahblahblah");
|
|
uint8_t buffer[1024];
|
|
memcpy(buffer, "blahblahblahblah", size);
|
|
for (lfs_size_t i = 0;
|
|
i < ((cfg->block_count-2)/2)*(cfg->block_size-8);
|
|
i += size) {
|
|
lfs_file_write(&lfs, &file, buffer, size) => size;
|
|
}
|
|
lfs_file_close(&lfs, &file) => 0;
|
|
|
|
lfs_file_open(&lfs, &file, "exhaustion2",
|
|
LFS_O_WRONLY | LFS_O_CREAT) => 0;
|
|
size = strlen("blahblahblahblah");
|
|
memcpy(buffer, "blahblahblahblah", size);
|
|
for (lfs_size_t i = 0;
|
|
i < ((cfg->block_count-2+1)/2)*(cfg->block_size-8);
|
|
i += size) {
|
|
lfs_file_write(&lfs, &file, buffer, size) => size;
|
|
}
|
|
lfs_file_close(&lfs, &file) => 0;
|
|
|
|
// remount to force reset of lookahead
|
|
lfs_unmount(&lfs) => 0;
|
|
lfs_mount(&lfs, cfg) => 0;
|
|
|
|
// rewrite one file with a hole of one block
|
|
lfs_file_open(&lfs, &file, "exhaustion1",
|
|
LFS_O_WRONLY | LFS_O_TRUNC) => 0;
|
|
lfs_file_sync(&lfs, &file) => 0;
|
|
size = strlen("blahblahblahblah");
|
|
memcpy(buffer, "blahblahblahblah", size);
|
|
for (lfs_size_t i = 0;
|
|
i < ((cfg->block_count-2)/2 - 1)*(cfg->block_size-8);
|
|
i += size) {
|
|
lfs_file_write(&lfs, &file, buffer, size) => size;
|
|
}
|
|
lfs_file_close(&lfs, &file) => 0;
|
|
|
|
// try to allocate a directory, should fail!
|
|
lfs_mkdir(&lfs, "split") => LFS_ERR_NOSPC;
|
|
|
|
// file should not fail
|
|
lfs_file_open(&lfs, &file, "notasplit",
|
|
LFS_O_WRONLY | LFS_O_CREAT) => 0;
|
|
lfs_file_write(&lfs, &file, "hi", 2) => 2;
|
|
lfs_file_close(&lfs, &file) => 0;
|
|
|
|
lfs_unmount(&lfs) => 0;
|
|
'''
|