Added lfs_fs_stat for access to filesystem status/configuration

Currently this includes:

- minor_version - on-disk minor version
- block_usage - estimated number of in-use blocks
- name_max - configurable name limit
- file_max - configurable file limit
- attr_max - configurable attr limit

These are currently the only configuration operations that need to be
written to disk. Other configuration is either needed to mount, such as
block_size, or does not change the on-disk representation, such as
read/prog_size.

This also includes the current block usage, which is common in other
filesystems, though a more expensive to find in littlefs. I figure it's
not unreasonable to make lfs_fs_stat no worse than block allocation,
hopefully this isn't a mistake. It may be worth caching the current
usage after the most recent lookahead scan.

More configuration may be added to this struct in the future.
This commit is contained in:
Christopher Haster
2023-06-06 12:20:47 -05:00
parent 66f07563c3
commit 87bbf1d374
4 changed files with 237 additions and 20 deletions
+104 -18
View File
@@ -25,11 +25,16 @@ code = '''
#define LFSP_VERSION LFS_VERSION
#define LFSP_VERSION_MAJOR LFS_VERSION_MAJOR
#define LFSP_VERSION_MINOR LFS_VERSION_MINOR
#define LFSP_DISK_VERSION LFS_DISK_VERSION
#define LFSP_DISK_VERSION_MAJOR LFS_DISK_VERSION_MAJOR
#define LFSP_DISK_VERSION_MINOR LFS_DISK_VERSION_MINOR
#define lfsp_t lfs_t
#define lfsp_config lfs_config
#define lfsp_format lfs_format
#define lfsp_mount lfs_mount
#define lfsp_unmount lfs_unmount
#define lfsp_fsinfo lfs_fsinfo
#define lfsp_fs_stat lfs_fs_stat
#define lfsp_dir_t lfs_dir_t
#define lfsp_info lfs_info
#define LFSP_TYPE_REG LFS_TYPE_REG
@@ -74,6 +79,12 @@ code = '''
// now test the new mount
lfs_t lfs;
lfs_mount(&lfs, cfg) => 0;
// we should be able to read the version using lfs_fs_stat
struct lfs_fsinfo fsinfo;
lfs_fs_stat(&lfs, &fsinfo) => 0;
assert(fsinfo.minor_version == LFSP_DISK_VERSION_MINOR);
lfs_unmount(&lfs) => 0;
'''
@@ -102,6 +113,11 @@ code = '''
lfs_t lfs;
lfs_mount(&lfs, cfg) => 0;
// we should be able to read the version using lfs_fs_stat
struct lfs_fsinfo fsinfo;
lfs_fs_stat(&lfs, &fsinfo) => 0;
assert(fsinfo.minor_version == LFSP_DISK_VERSION_MINOR);
// can we list the directories?
lfs_dir_t dir;
lfs_dir_open(&lfs, &dir, "/") => 0;
@@ -166,6 +182,11 @@ code = '''
lfs_t lfs;
lfs_mount(&lfs, cfg) => 0;
// we should be able to read the version using lfs_fs_stat
struct lfs_fsinfo fsinfo;
lfs_fs_stat(&lfs, &fsinfo) => 0;
assert(fsinfo.minor_version == LFSP_DISK_VERSION_MINOR);
// can we list the files?
lfs_dir_t dir;
lfs_dir_open(&lfs, &dir, "/") => 0;
@@ -251,6 +272,11 @@ code = '''
lfs_t lfs;
lfs_mount(&lfs, cfg) => 0;
// we should be able to read the version using lfs_fs_stat
struct lfs_fsinfo fsinfo;
lfs_fs_stat(&lfs, &fsinfo) => 0;
assert(fsinfo.minor_version == LFSP_DISK_VERSION_MINOR);
// can we list the directories?
lfs_dir_t dir;
lfs_dir_open(&lfs, &dir, "/") => 0;
@@ -343,6 +369,11 @@ code = '''
lfs_t lfs;
lfs_mount(&lfs, cfg) => 0;
// we should be able to read the version using lfs_fs_stat
struct lfs_fsinfo fsinfo;
lfs_fs_stat(&lfs, &fsinfo) => 0;
assert(fsinfo.minor_version == LFSP_DISK_VERSION_MINOR);
// write another COUNT/2 dirs
for (lfs_size_t i = COUNT/2; i < COUNT; i++) {
char name[8];
@@ -420,6 +451,11 @@ code = '''
lfs_t lfs;
lfs_mount(&lfs, cfg) => 0;
// we should be able to read the version using lfs_fs_stat
struct lfs_fsinfo fsinfo;
lfs_fs_stat(&lfs, &fsinfo) => 0;
assert(fsinfo.minor_version == LFSP_DISK_VERSION_MINOR);
// write half COUNT files
prng = 42;
for (lfs_size_t i = 0; i < COUNT; i++) {
@@ -537,6 +573,11 @@ code = '''
lfs_t lfs;
lfs_mount(&lfs, cfg) => 0;
// we should be able to read the version using lfs_fs_stat
struct lfs_fsinfo fsinfo;
lfs_fs_stat(&lfs, &fsinfo) => 0;
assert(fsinfo.minor_version == LFSP_DISK_VERSION_MINOR);
// write half COUNT files
prng = 42;
for (lfs_size_t i = 0; i < COUNT; i++) {
@@ -651,6 +692,12 @@ code = '''
memcpy(&cfgp, cfg, sizeof(cfgp));
lfsp_t lfsp;
lfsp_mount(&lfsp, &cfgp) => 0;
// we should be able to read the version using lfs_fs_stat
struct lfsp_fsinfo fsinfo;
lfsp_fs_stat(&lfsp, &fsinfo) => 0;
assert(fsinfo.minor_version == LFS_DISK_VERSION_MINOR);
lfsp_unmount(&lfsp) => 0;
'''
@@ -679,6 +726,11 @@ code = '''
lfsp_t lfsp;
lfsp_mount(&lfsp, &cfgp) => 0;
// we should be able to read the version using lfs_fs_stat
struct lfs_fsinfo fsinfo;
lfs_fs_stat(&lfs, &fsinfo) => 0;
assert(fsinfo.minor_version == LFS_DISK_VERSION_MINOR);
// can we list the directories?
lfsp_dir_t dir;
lfsp_dir_open(&lfsp, &dir, "/") => 0;
@@ -743,6 +795,11 @@ code = '''
lfsp_t lfsp;
lfsp_mount(&lfsp, &cfgp) => 0;
// we should be able to read the version using lfs_fs_stat
struct lfsp_fsinfo fsinfo;
lfsp_fs_stat(&lfsp, &fsinfo) => 0;
assert(fsinfo.minor_version == LFS_DISK_VERSION_MINOR);
// can we list the files?
lfsp_dir_t dir;
lfsp_dir_open(&lfsp, &dir, "/") => 0;
@@ -828,6 +885,11 @@ code = '''
lfsp_t lfsp;
lfsp_mount(&lfsp, &cfgp) => 0;
// we should be able to read the version using lfs_fs_stat
struct lfsp_fsinfo fsinfo;
lfsp_fs_stat(&lfsp, &fsinfo) => 0;
assert(fsinfo.minor_version == LFS_DISK_VERSION_MINOR);
// can we list the directories?
lfsp_dir_t dir;
lfsp_dir_open(&lfsp, &dir, "/") => 0;
@@ -920,6 +982,11 @@ code = '''
lfsp_t lfsp;
lfsp_mount(&lfsp, &cfgp) => 0;
// we should be able to read the version using lfs_fs_stat
struct lfsp_fsinfo fsinfo;
lfsp_fs_stat(&lfsp, &fsinfo) => 0;
assert(fsinfo.minor_version == LFS_DISK_VERSION_MINOR);
// write another COUNT/2 dirs
for (lfs_size_t i = COUNT/2; i < COUNT; i++) {
char name[8];
@@ -997,6 +1064,11 @@ code = '''
lfsp_t lfsp;
lfsp_mount(&lfsp, &cfgp) => 0;
// we should be able to read the version using lfs_fs_stat
struct lfsp_fsinfo fsinfo;
lfsp_fs_stat(&lfsp, &fsinfo) => 0;
assert(fsinfo.minor_version == LFS_DISK_VERSION_MINOR);
// write half COUNT files
prng = 42;
for (lfs_size_t i = 0; i < COUNT; i++) {
@@ -1114,6 +1186,11 @@ code = '''
lfsp_t lfsp;
lfsp_mount(&lfsp, &cfgp) => 0;
// we should be able to read the version using lfs_fs_stat
struct lfsp_fsinfo fsinfo;
lfsp_fs_stat(&lfsp, &fsinfo) => 0;
assert(fsinfo.minor_version == LFS_DISK_VERSION_MINOR);
// write half COUNT files
prng = 42;
for (lfs_size_t i = 0; i < COUNT; i++) {
@@ -1316,45 +1393,54 @@ code = '''
// mount should still work
lfs_mount(&lfs, cfg) => 0;
struct lfs_fsinfo fsinfo;
lfs_fs_stat(&lfs, &fsinfo) => 0;
assert(fsinfo.minor_version == LFS_DISK_VERSION_MINOR-1);
lfs_file_open(&lfs, &file, "test", LFS_O_RDONLY) => 0;
uint8_t buffer[8];
lfs_file_read(&lfs, &file, buffer, 8) => 8;
assert(memcmp(buffer, "testtest", 8) == 0);
lfs_file_close(&lfs, &file) => 0;
// minor version should be unchanged
lfs_fs_stat(&lfs, &fsinfo) => 0;
assert(fsinfo.minor_version == LFS_DISK_VERSION_MINOR-1);
lfs_unmount(&lfs) => 0;
// if we write, we need to bump the minor version
lfs_mount(&lfs, cfg) => 0;
lfs_fs_stat(&lfs, &fsinfo) => 0;
assert(fsinfo.minor_version == LFS_DISK_VERSION_MINOR-1);
lfs_file_open(&lfs, &file, "test", LFS_O_WRONLY | LFS_O_TRUNC) => 0;
lfs_file_write(&lfs, &file, "teeeeest", 8) => 8;
lfs_file_close(&lfs, &file) => 0;
// minor version should have changed
lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
lfs_dir_get(&lfs, &mdir, LFS_MKTAG(0x7ff, 0x3ff, 0),
LFS_MKTAG(LFS_TYPE_INLINESTRUCT, 0, sizeof(superblock)),
&superblock)
=> LFS_MKTAG(LFS_TYPE_INLINESTRUCT, 0, sizeof(superblock));
lfs_superblock_fromle32(&superblock);
assert((superblock.version >> 16) & 0xffff == LFS_DISK_VERSION_MAJOR);
assert((superblock.version >> 0) & 0xffff == LFS_DISK_VERSION_MINOR);
// minor version should be changed
lfs_fs_stat(&lfs, &fsinfo) => 0;
assert(fsinfo.minor_version == LFS_DISK_VERSION_MINOR);
lfs_unmount(&lfs) => 0;
// and of course mount should still work
lfs_mount(&lfs, cfg) => 0;
// minor version should have changed
lfs_fs_stat(&lfs, &fsinfo) => 0;
assert(fsinfo.minor_version == LFS_DISK_VERSION_MINOR);
lfs_file_open(&lfs, &file, "test", LFS_O_RDONLY) => 0;
lfs_file_read(&lfs, &file, buffer, 8) => 8;
assert(memcmp(buffer, "teeeeest", 8) == 0);
lfs_file_close(&lfs, &file) => 0;
// minor version should have changed
lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
lfs_dir_get(&lfs, &mdir, LFS_MKTAG(0x7ff, 0x3ff, 0),
LFS_MKTAG(LFS_TYPE_INLINESTRUCT, 0, sizeof(superblock)),
&superblock)
=> LFS_MKTAG(LFS_TYPE_INLINESTRUCT, 0, sizeof(superblock));
lfs_superblock_fromle32(&superblock);
assert((superblock.version >> 16) & 0xffff == LFS_DISK_VERSION_MAJOR);
assert((superblock.version >> 0) & 0xffff == LFS_DISK_VERSION_MINOR);
// yep, still changed
lfs_fs_stat(&lfs, &fsinfo) => 0;
assert(fsinfo.minor_version == LFS_DISK_VERSION_MINOR);
lfs_unmount(&lfs) => 0;
'''
+48
View File
@@ -34,6 +34,54 @@ code = '''
lfs_mount(&lfs, cfg) => LFS_ERR_CORRUPT;
'''
# test we can read superblock info through lfs_fs_stat
[cases.test_superblocks_stat]
code = '''
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
// test we can mount and read fsinfo
lfs_mount(&lfs, cfg) => 0;
struct lfs_fsinfo fsinfo;
lfs_fs_stat(&lfs, &fsinfo) => 0;
assert(fsinfo.minor_version == LFS_DISK_VERSION_MINOR);
assert(fsinfo.block_usage > 0 && fsinfo.block_usage < BLOCK_COUNT);
assert(fsinfo.name_max == LFS_NAME_MAX);
assert(fsinfo.file_max == LFS_FILE_MAX);
assert(fsinfo.attr_max == LFS_ATTR_MAX);
lfs_unmount(&lfs) => 0;
'''
[cases.test_superblocks_stat_tweaked]
defines.TWEAKED_NAME_MAX = 63
defines.TWEAKED_FILE_MAX = '(1 << 16)-1'
defines.TWEAKED_ATTR_MAX = 512
code = '''
// create filesystem with tweaked params
struct lfs_config tweaked_cfg = *cfg;
tweaked_cfg.name_max = TWEAKED_NAME_MAX;
tweaked_cfg.file_max = TWEAKED_FILE_MAX;
tweaked_cfg.attr_max = TWEAKED_ATTR_MAX;
lfs_t lfs;
lfs_format(&lfs, &tweaked_cfg) => 0;
// test we can mount and read these params with the original config
lfs_mount(&lfs, cfg) => 0;
struct lfs_fsinfo fsinfo;
lfs_fs_stat(&lfs, &fsinfo) => 0;
assert(fsinfo.minor_version == LFS_DISK_VERSION_MINOR);
assert(fsinfo.block_usage > 0 && fsinfo.block_usage < BLOCK_COUNT);
assert(fsinfo.name_max == TWEAKED_NAME_MAX);
assert(fsinfo.file_max == TWEAKED_FILE_MAX);
assert(fsinfo.attr_max == TWEAKED_ATTR_MAX);
lfs_unmount(&lfs) => 0;
'''
# expanding superblock
[cases.test_superblocks_expand]
defines.BLOCK_CYCLES = [32, 33, 1]