mirror of
https://github.com/littlefs-project/littlefs.git
synced 2025-10-29 11:38:32 +00:00
The intention is to help interop with older minor versions of littlefs. Unfortunately, since lfs2.0 drivers cannot mount lfs2.1 images, there are situations where it would be useful to write to write strictly lfs2.0 compatible images. The solution here adds a "disk_version" configuration option which determines the behavior of lfs2.1 dependent features. Normally you would expect this to only change write behavior. But since the main change in lfs2.1 increased validation of erased data, we also need to skip this extra validation (fcrc) or see terrible slowdowns when writing.
186 lines
5.7 KiB
C
186 lines
5.7 KiB
C
# There are already a number of tests that test general operations under
|
|
# power-loss (see the reentrant attribute). These tests are for explicitly
|
|
# testing specific corner cases.
|
|
|
|
# only a revision count
|
|
[cases.test_powerloss_only_rev]
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfs_format(&lfs, cfg) => 0;
|
|
|
|
lfs_mount(&lfs, cfg) => 0;
|
|
lfs_mkdir(&lfs, "notebook") => 0;
|
|
lfs_file_t file;
|
|
lfs_file_open(&lfs, &file, "notebook/paper",
|
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0;
|
|
char buffer[256];
|
|
strcpy(buffer, "hello");
|
|
lfs_size_t size = strlen("hello");
|
|
for (int i = 0; i < 5; i++) {
|
|
lfs_file_write(&lfs, &file, buffer, size) => size;
|
|
lfs_file_sync(&lfs, &file) => 0;
|
|
}
|
|
lfs_file_close(&lfs, &file) => 0;
|
|
|
|
char rbuffer[256];
|
|
lfs_file_open(&lfs, &file, "notebook/paper", LFS_O_RDONLY) => 0;
|
|
for (int i = 0; i < 5; i++) {
|
|
lfs_file_read(&lfs, &file, rbuffer, size) => size;
|
|
assert(memcmp(rbuffer, buffer, size) == 0);
|
|
}
|
|
lfs_file_close(&lfs, &file) => 0;
|
|
lfs_unmount(&lfs) => 0;
|
|
|
|
// get pair/rev count
|
|
lfs_mount(&lfs, cfg) => 0;
|
|
lfs_dir_t dir;
|
|
lfs_dir_open(&lfs, &dir, "notebook") => 0;
|
|
lfs_block_t pair[2] = {dir.m.pair[0], dir.m.pair[1]};
|
|
uint32_t rev = dir.m.rev;
|
|
lfs_dir_close(&lfs, &dir) => 0;
|
|
lfs_unmount(&lfs) => 0;
|
|
|
|
// write just the revision count
|
|
uint8_t bbuffer[BLOCK_SIZE];
|
|
cfg->read(cfg, pair[1], 0, bbuffer, BLOCK_SIZE) => 0;
|
|
|
|
memcpy(bbuffer, &(uint32_t){lfs_tole32(rev+1)}, sizeof(uint32_t));
|
|
|
|
cfg->erase(cfg, pair[1]) => 0;
|
|
cfg->prog(cfg, pair[1], 0, bbuffer, BLOCK_SIZE) => 0;
|
|
|
|
lfs_mount(&lfs, cfg) => 0;
|
|
|
|
// can read?
|
|
lfs_file_open(&lfs, &file, "notebook/paper", LFS_O_RDONLY) => 0;
|
|
for (int i = 0; i < 5; i++) {
|
|
lfs_file_read(&lfs, &file, rbuffer, size) => size;
|
|
assert(memcmp(rbuffer, buffer, size) == 0);
|
|
}
|
|
lfs_file_close(&lfs, &file) => 0;
|
|
|
|
// can write?
|
|
lfs_file_open(&lfs, &file, "notebook/paper",
|
|
LFS_O_WRONLY | LFS_O_APPEND) => 0;
|
|
strcpy(buffer, "goodbye");
|
|
size = strlen("goodbye");
|
|
for (int i = 0; i < 5; i++) {
|
|
lfs_file_write(&lfs, &file, buffer, size) => size;
|
|
lfs_file_sync(&lfs, &file) => 0;
|
|
}
|
|
lfs_file_close(&lfs, &file) => 0;
|
|
|
|
lfs_file_open(&lfs, &file, "notebook/paper", LFS_O_RDONLY) => 0;
|
|
strcpy(buffer, "hello");
|
|
size = strlen("hello");
|
|
for (int i = 0; i < 5; i++) {
|
|
lfs_file_read(&lfs, &file, rbuffer, size) => size;
|
|
assert(memcmp(rbuffer, buffer, size) == 0);
|
|
}
|
|
strcpy(buffer, "goodbye");
|
|
size = strlen("goodbye");
|
|
for (int i = 0; i < 5; i++) {
|
|
lfs_file_read(&lfs, &file, rbuffer, size) => size;
|
|
assert(memcmp(rbuffer, buffer, size) == 0);
|
|
}
|
|
lfs_file_close(&lfs, &file) => 0;
|
|
|
|
lfs_unmount(&lfs) => 0;
|
|
'''
|
|
|
|
# partial prog, may not be byte in order!
|
|
[cases.test_powerloss_partial_prog]
|
|
if = '''
|
|
PROG_SIZE < BLOCK_SIZE
|
|
&& (DISK_VERSION == 0 || DISK_VERSION >= 0x00020001)
|
|
'''
|
|
defines.BYTE_OFF = ["0", "PROG_SIZE-1", "PROG_SIZE/2"]
|
|
defines.BYTE_VALUE = [0x33, 0xcc]
|
|
in = "lfs.c"
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfs_format(&lfs, cfg) => 0;
|
|
|
|
lfs_mount(&lfs, cfg) => 0;
|
|
lfs_mkdir(&lfs, "notebook") => 0;
|
|
lfs_file_t file;
|
|
lfs_file_open(&lfs, &file, "notebook/paper",
|
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0;
|
|
char buffer[256];
|
|
strcpy(buffer, "hello");
|
|
lfs_size_t size = strlen("hello");
|
|
for (int i = 0; i < 5; i++) {
|
|
lfs_file_write(&lfs, &file, buffer, size) => size;
|
|
lfs_file_sync(&lfs, &file) => 0;
|
|
}
|
|
lfs_file_close(&lfs, &file) => 0;
|
|
|
|
char rbuffer[256];
|
|
lfs_file_open(&lfs, &file, "notebook/paper", LFS_O_RDONLY) => 0;
|
|
for (int i = 0; i < 5; i++) {
|
|
lfs_file_read(&lfs, &file, rbuffer, size) => size;
|
|
assert(memcmp(rbuffer, buffer, size) == 0);
|
|
}
|
|
lfs_file_close(&lfs, &file) => 0;
|
|
lfs_unmount(&lfs) => 0;
|
|
|
|
// imitate a partial prog, value should not matter, if littlefs
|
|
// doesn't notice the partial prog testbd will assert
|
|
|
|
// get offset to next prog
|
|
lfs_mount(&lfs, cfg) => 0;
|
|
lfs_dir_t dir;
|
|
lfs_dir_open(&lfs, &dir, "notebook") => 0;
|
|
lfs_block_t block = dir.m.pair[0];
|
|
lfs_off_t off = dir.m.off;
|
|
lfs_dir_close(&lfs, &dir) => 0;
|
|
lfs_unmount(&lfs) => 0;
|
|
|
|
// tweak byte
|
|
uint8_t bbuffer[BLOCK_SIZE];
|
|
cfg->read(cfg, block, 0, bbuffer, BLOCK_SIZE) => 0;
|
|
|
|
bbuffer[off + BYTE_OFF] = BYTE_VALUE;
|
|
|
|
cfg->erase(cfg, block) => 0;
|
|
cfg->prog(cfg, block, 0, bbuffer, BLOCK_SIZE) => 0;
|
|
|
|
lfs_mount(&lfs, cfg) => 0;
|
|
|
|
// can read?
|
|
lfs_file_open(&lfs, &file, "notebook/paper", LFS_O_RDONLY) => 0;
|
|
for (int i = 0; i < 5; i++) {
|
|
lfs_file_read(&lfs, &file, rbuffer, size) => size;
|
|
assert(memcmp(rbuffer, buffer, size) == 0);
|
|
}
|
|
lfs_file_close(&lfs, &file) => 0;
|
|
|
|
// can write?
|
|
lfs_file_open(&lfs, &file, "notebook/paper",
|
|
LFS_O_WRONLY | LFS_O_APPEND) => 0;
|
|
strcpy(buffer, "goodbye");
|
|
size = strlen("goodbye");
|
|
for (int i = 0; i < 5; i++) {
|
|
lfs_file_write(&lfs, &file, buffer, size) => size;
|
|
lfs_file_sync(&lfs, &file) => 0;
|
|
}
|
|
lfs_file_close(&lfs, &file) => 0;
|
|
|
|
lfs_file_open(&lfs, &file, "notebook/paper", LFS_O_RDONLY) => 0;
|
|
strcpy(buffer, "hello");
|
|
size = strlen("hello");
|
|
for (int i = 0; i < 5; i++) {
|
|
lfs_file_read(&lfs, &file, rbuffer, size) => size;
|
|
assert(memcmp(rbuffer, buffer, size) == 0);
|
|
}
|
|
strcpy(buffer, "goodbye");
|
|
size = strlen("goodbye");
|
|
for (int i = 0; i < 5; i++) {
|
|
lfs_file_read(&lfs, &file, rbuffer, size) => size;
|
|
assert(memcmp(rbuffer, buffer, size) == 0);
|
|
}
|
|
lfs_file_close(&lfs, &file) => 0;
|
|
|
|
lfs_unmount(&lfs) => 0;
|
|
'''
|