Combined superblock scan and fetch of xored-globals during mount

Conceptually these are two separate operations. However, they are both
only needed during mount, both require iteration over the linked-list of
metadata-pairs, and both are independent from each other.

Combining these into one gives us a nice code savings.

Additionally, this greatly simplifies the lookup of the root directory.
Initially we used a flag to indicate which superblock was root, since we
didn't want to fetch more pairs than we needed to. But since we're going
to fetch all metadata-pairs anyways, we can just use the last superblock
we find as the indicator of our root directory.
This commit is contained in:
Christopher Haster 2018-09-12 01:50:21 -05:00
parent 7bacf9b1e0
commit cf87ba5375
3 changed files with 80 additions and 86 deletions

157
lfs.c
View File

@ -3116,7 +3116,7 @@ int lfs_format(lfs_t *lfs, const struct lfs_config *cfg) {
lfs_superblock_tole32(&superblock);
err = lfs_dir_commit(lfs, &root,
LFS_MKATTR(LFS_TYPE_ROOT, 0, &superblock, sizeof(superblock),
LFS_MKATTR(LFS_TYPE_SUPERBLOCK, 0, &superblock, sizeof(superblock),
NULL));
if (err) {
goto cleanup;
@ -3139,97 +3139,94 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) {
return err;
}
// find root/superblock
lfs_mdir_t root;
lfs_superblock_t superblock;
lfs_stag_t tag = lfs_dir_findmatch(lfs,
&root, (const lfs_block_t[2]){0, 1}, false, 0x7fc00000,
LFS_MKTAG(LFS_TYPE_ROOT, 0, 8),
lfs_dir_find_match, &(struct lfs_dir_find_match){
lfs, "littlefs", 8});
if (tag < 0) {
err = tag;
goto cleanup;
}
lfs_stag_t res = lfs_dir_get(lfs, &root, 0x7f800000,
LFS_MKTAG(LFS_TYPE_SUPERBLOCK, 0, sizeof(superblock)),
&superblock);
if (res < 0) {
err = res;
goto cleanup;
}
lfs_superblock_fromle32(&superblock);
lfs->root[0] = root.pair[0];
lfs->root[1] = root.pair[1];
// check version
uint16_t major_version = (0xffff & (superblock.version >> 16));
uint16_t minor_version = (0xffff & (superblock.version >> 0));
if ((major_version != LFS_DISK_VERSION_MAJOR ||
minor_version > LFS_DISK_VERSION_MINOR)) {
LFS_ERROR("Invalid version %"PRIu32".%"PRIu32,
major_version, minor_version);
err = LFS_ERR_INVAL;
goto cleanup;
}
// check superblock configuration
if (superblock.attr_max) {
if (superblock.attr_max > lfs->attr_max) {
LFS_ERROR("Unsupported attr_max (%"PRIu32" > %"PRIu32")",
superblock.attr_max, lfs->attr_max);
err = LFS_ERR_INVAL;
goto cleanup;
}
lfs->attr_max = superblock.attr_max;
}
if (superblock.name_max) {
if (superblock.name_max > lfs->name_max) {
LFS_ERROR("Unsupported name_max (%"PRIu32" > %"PRIu32")",
superblock.name_max, lfs->name_max);
err = LFS_ERR_INVAL;
goto cleanup;
}
lfs->name_max = superblock.name_max;
}
if (superblock.inline_max) {
if (superblock.inline_max > lfs->inline_max) {
LFS_ERROR("Unsupported inline_max (%"PRIu32" > %"PRIu32")",
superblock.inline_max, lfs->inline_max);
err = LFS_ERR_INVAL;
goto cleanup;
}
lfs->inline_max = superblock.inline_max;
}
// scan for any global updates
// scan directory blocks for superblock and any global updates
lfs_mdir_t dir = {.tail = {0, 1}};
while (!lfs_pair_isnull(dir.tail)) {
res = lfs_dir_fetchmatch(lfs, &dir, dir.tail, 0x7c000000,
LFS_MKTAG(LFS_TYPE_GLOBALS, 0, 10), NULL, NULL);
// fetch next block in tail list
lfs_stag_t res = lfs_dir_fetchmatch(lfs, &dir, dir.tail, 0x7fc00000,
LFS_MKTAG(LFS_TYPE_SUPERBLOCK, 0, 8),
lfs_dir_find_match, &(struct lfs_dir_find_match){
lfs, "littlefs", 8});
if (res < 0) {
err = LFS_ERR_INVAL;
err = res;
goto cleanup;
}
// has superblock?
if (res) {
lfs_global_t locals;
res = lfs_dir_get(lfs, &dir, 0x7c000000,
LFS_MKTAG(LFS_TYPE_GLOBALS, 0, 10), &locals);
// update root
lfs->root[0] = dir.pair[0];
lfs->root[1] = dir.pair[1];
// grab superblock
lfs_superblock_t superblock;
res = lfs_dir_get(lfs, &dir, 0x7f800000,
LFS_MKTAG(LFS_TYPE_SUPERBLOCK, 0, sizeof(superblock)),
&superblock);
if (res < 0) {
err = res;
goto cleanup;
}
locals.l.deorphaned = (lfs_tag_type(res) & 1);
lfs_superblock_fromle32(&superblock);
// xor together indirect deletes
// check version
uint16_t major_version = (0xffff & (superblock.version >> 16));
uint16_t minor_version = (0xffff & (superblock.version >> 0));
if ((major_version != LFS_DISK_VERSION_MAJOR ||
minor_version > LFS_DISK_VERSION_MINOR)) {
LFS_ERROR("Invalid version %"PRIu32".%"PRIu32,
major_version, minor_version);
err = LFS_ERR_INVAL;
goto cleanup;
}
// check superblock configuration
if (superblock.attr_max) {
if (superblock.attr_max > lfs->attr_max) {
LFS_ERROR("Unsupported attr_max (%"PRIu32" > %"PRIu32")",
superblock.attr_max, lfs->attr_max);
err = LFS_ERR_INVAL;
goto cleanup;
}
lfs->attr_max = superblock.attr_max;
}
if (superblock.name_max) {
if (superblock.name_max > lfs->name_max) {
LFS_ERROR("Unsupported name_max (%"PRIu32" > %"PRIu32")",
superblock.name_max, lfs->name_max);
err = LFS_ERR_INVAL;
goto cleanup;
}
lfs->name_max = superblock.name_max;
}
if (superblock.inline_max) {
if (superblock.inline_max > lfs->inline_max) {
LFS_ERROR("Unsupported inline_max (%"PRIu32" > %"PRIu32")",
superblock.inline_max, lfs->inline_max);
err = LFS_ERR_INVAL;
goto cleanup;
}
lfs->inline_max = superblock.inline_max;
}
}
// has globals?
lfs_global_t locals;
res = lfs_dir_get(lfs, &dir, 0x7c000000,
LFS_MKTAG(LFS_TYPE_GLOBALS, 0, 10), &locals);
if (res < 0 && res != LFS_ERR_NOENT) {
err = res;
goto cleanup;
}
if (res != LFS_ERR_NOENT) {
locals.l.deorphaned = (lfs_tag_type(res) & 1);
// xor together to find resulting globals
lfs_global_xor(&lfs->locals, &locals);
}
}

8
lfs.h
View File

@ -94,27 +94,25 @@ enum lfs_type {
// internally used types
LFS_TYPE_USER = 0x100,
LFS_TYPE_SUPERBLOCK = 0x001,
LFS_TYPE_ROOT = 0x000,
LFS_TYPE_NAME = 0x000,
LFS_TYPE_DELETE = 0x020,
LFS_TYPE_STRUCT = 0x040,
LFS_TYPE_GLOBALS = 0x0e0,
LFS_TYPE_TAIL = 0x080,
LFS_TYPE_SOFTTAIL = 0x080,
LFS_TYPE_HARDTAIL = 0x081,
LFS_TYPE_CRC = 0x0a0,
LFS_TYPE_SUPERBLOCK = 0x001,
LFS_TYPE_GLOBALS = 0x0e0,
LFS_TYPE_DIRSTRUCT = 0x040,
LFS_TYPE_INLINESTRUCT = 0x041,
LFS_TYPE_CTZSTRUCT = 0x042,
// internal chip sources
LFS_FROM_REGION = 0x000,
LFS_FROM_MEM = 0x000,
LFS_FROM_DISK = 0x200,
LFS_FROM_MOVE = 0x0c1,
LFS_FROM_USERATTRS = 0x0c2,
LFS_FROM_SUPERBLOCK = 0x0c3,
};
// File open flags

View File

@ -7,7 +7,6 @@ TYPES = {
(0x1ff, 0x002): 'reg',
(0x1ff, 0x003): 'dir',
(0x1ff, 0x001): 'superblock',
(0x1ff, 0x000): 'root',
(0x1ff, 0x020): 'delete',
(0x1f0, 0x0e0): 'globals',
(0x1ff, 0x080): 'tail soft',