Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/littlefs-project/littlefs.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrian Pugh <bnp117@gmail.com>2023-08-17 07:46:04 +0300
committerBrian Pugh <bnp117@gmail.com>2023-08-17 08:23:34 +0300
commit73285278b98e0b15a608325b3f7e4c5b8e0c6b75 (patch)
tree8b73f14a47a61dc51418748e258214ff88d3a267
parent611c9b20db2b99faee261daa7cc9bbe175d3eaca (diff)
refactor lfs_scan_for_state_updates and lfs_scan_for_superblock out of lfs_format
-rw-r--r--lfs.c312
1 files changed, 181 insertions, 131 deletions
diff --git a/lfs.c b/lfs.c
index 38b825d..90e1365 100644
--- a/lfs.c
+++ b/lfs.c
@@ -4237,6 +4237,175 @@ static int lfs_deinit(lfs_t *lfs) {
return 0;
}
+static int lfs_scan_for_superblock(lfs_t *lfs, lfs_superblock_t *superblock){
+ // scan directory blocks for superblock and any global updates
+ lfs_mdir_t dir = {.tail = {0, 1}};
+ lfs_block_t tortoise[2] = {LFS_BLOCK_NULL, LFS_BLOCK_NULL};
+ lfs_size_t tortoise_i = 1;
+ lfs_size_t tortoise_period = 1;
+ while (!lfs_pair_isnull(dir.tail)) {
+ // detect cycles with Brent's algorithm
+ if (lfs_pair_issync(dir.tail, tortoise)) {
+ LFS_WARN("Cycle detected in tail list");
+ return LFS_ERR_CORRUPT;
+ }
+ if (tortoise_i == tortoise_period) {
+ tortoise[0] = dir.tail[0];
+ tortoise[1] = dir.tail[1];
+ tortoise_i = 0;
+ tortoise_period *= 2;
+ }
+ tortoise_i += 1;
+
+ // fetch next block in tail list
+ lfs_stag_t tag = lfs_dir_fetchmatch(lfs, &dir, dir.tail,
+ LFS_MKTAG(0x7ff, 0x3ff, 0),
+ LFS_MKTAG(LFS_TYPE_SUPERBLOCK, 0, 8),
+ NULL,
+ lfs_dir_find_match, &(struct lfs_dir_find_match){
+ lfs, "littlefs", 8});
+ if (tag < 0) {
+ return tag;
+ }
+
+ // has superblock?
+ if (tag && !lfs_tag_isdelete(tag)) {
+ // update root
+ lfs->root[0] = dir.pair[0];
+ lfs->root[1] = dir.pair[1];
+
+ // grab superblock
+ tag = lfs_dir_get(lfs, &dir, LFS_MKTAG(0x7ff, 0x3ff, 0),
+ LFS_MKTAG(LFS_TYPE_INLINESTRUCT, 0, sizeof(*superblock)),
+ superblock);
+ if (tag < 0) {
+ return tag;
+ }
+ lfs_superblock_fromle32(superblock);
+ }
+ }
+
+ return LFS_ERR_OK;
+}
+
+static int lfs_scan_for_state_updates(lfs_t *lfs){
+ int err;
+ // scan directory blocks for superblock and any global updates
+ lfs_mdir_t dir = {.tail = {0, 1}};
+ lfs_block_t tortoise[2] = {LFS_BLOCK_NULL, LFS_BLOCK_NULL};
+ lfs_size_t tortoise_i = 1;
+ lfs_size_t tortoise_period = 1;
+ while (!lfs_pair_isnull(dir.tail)) {
+ // detect cycles with Brent's algorithm
+ if (lfs_pair_issync(dir.tail, tortoise)) {
+ LFS_WARN("Cycle detected in tail list");
+ return LFS_ERR_CORRUPT;
+ }
+ if (tortoise_i == tortoise_period) {
+ tortoise[0] = dir.tail[0];
+ tortoise[1] = dir.tail[1];
+ tortoise_i = 0;
+ tortoise_period *= 2;
+ }
+ tortoise_i += 1;
+
+ // fetch next block in tail list
+ lfs_stag_t tag = lfs_dir_fetchmatch(lfs, &dir, dir.tail,
+ LFS_MKTAG(0x7ff, 0x3ff, 0),
+ LFS_MKTAG(LFS_TYPE_SUPERBLOCK, 0, 8),
+ NULL,
+ lfs_dir_find_match, &(struct lfs_dir_find_match){
+ lfs, "littlefs", 8});
+ if (tag < 0) {
+ return tag;
+ }
+
+ // has gstate?
+ err = lfs_dir_getgstate(lfs, &dir, &lfs->gstate);
+ if (err) {
+ return err;
+ }
+ }
+
+ return LFS_ERR_OK;
+}
+
+static int lfs_validate_superblock(lfs_t *lfs, lfs_superblock_t *superblock){
+ // check version
+ uint16_t major_version = (0xffff & (superblock->version >> 16));
+ uint16_t minor_version = (0xffff & (superblock->version >> 0));
+ if (major_version != lfs_fs_disk_version_major(lfs)
+ || minor_version > lfs_fs_disk_version_minor(lfs)) {
+ LFS_ERROR("Invalid version "
+ "v%"PRIu16".%"PRIu16" != v%"PRIu16".%"PRIu16,
+ major_version,
+ minor_version,
+ lfs_fs_disk_version_major(lfs),
+ lfs_fs_disk_version_minor(lfs));
+ return LFS_ERR_INVAL;
+ }
+
+ // found older minor version? set an in-device only bit in the
+ // gstate so we know we need to rewrite the superblock before
+ // the first write
+ if (minor_version < lfs_fs_disk_version_minor(lfs)) {
+ LFS_DEBUG("Found older minor version "
+ "v%"PRIu16".%"PRIu16" < v%"PRIu16".%"PRIu16,
+ major_version,
+ minor_version,
+ lfs_fs_disk_version_major(lfs),
+ lfs_fs_disk_version_minor(lfs));
+ // note this bit is reserved on disk, so fetching more gstate
+ // will not interfere here
+ lfs_fs_prepsuperblock(lfs, true);
+ }
+
+ // check superblock configuration
+ if (superblock->name_max) {
+ if (superblock->name_max > lfs->name_max) {
+ LFS_ERROR("Unsupported name_max (%"PRIu32" > %"PRIu32")",
+ superblock->name_max, lfs->name_max);
+ return LFS_ERR_INVAL;
+ }
+ lfs->name_max = superblock->name_max;
+ }
+
+ if (superblock->file_max) {
+ if (superblock->file_max > lfs->file_max) {
+ LFS_ERROR("Unsupported file_max (%"PRIu32" > %"PRIu32")",
+ superblock->file_max, lfs->file_max);
+ return LFS_ERR_INVAL;
+ }
+ lfs->file_max = superblock->file_max;
+ }
+
+ if (superblock->attr_max) {
+ if (superblock->attr_max > lfs->attr_max) {
+ LFS_ERROR("Unsupported attr_max (%"PRIu32" > %"PRIu32")",
+ superblock->attr_max, lfs->attr_max);
+ return LFS_ERR_INVAL;
+ }
+ lfs->attr_max = superblock->attr_max;
+ }
+
+ if (superblock->block_count != lfs->cfg->block_count) {
+ LFS_ERROR("Invalid block count (%"PRIu32" != %"PRIu32")",
+ superblock->block_count, lfs->cfg->block_count);
+ return LFS_ERR_INVAL;
+ }
+
+ if (superblock->block_size != lfs->cfg->block_size) {
+ LFS_ERROR("Invalid block size (%"PRIu32" != %"PRIu32")",
+ superblock->block_size, lfs->cfg->block_size);
+ return LFS_ERR_INVAL;
+ }
+
+ return LFS_ERR_OK;
+}
+
+
+
+
#ifndef LFS_READONLY
static int lfs_rawformat(lfs_t *lfs, const struct lfs_config *cfg) {
int err = 0;
@@ -4309,139 +4478,20 @@ static int lfs_rawmount(lfs_t *lfs, const struct lfs_config *cfg) {
return err;
}
- // scan directory blocks for superblock and any global updates
- lfs_mdir_t dir = {.tail = {0, 1}};
- lfs_block_t tortoise[2] = {LFS_BLOCK_NULL, LFS_BLOCK_NULL};
- lfs_size_t tortoise_i = 1;
- lfs_size_t tortoise_period = 1;
- while (!lfs_pair_isnull(dir.tail)) {
- // detect cycles with Brent's algorithm
- if (lfs_pair_issync(dir.tail, tortoise)) {
- LFS_WARN("Cycle detected in tail list");
- err = LFS_ERR_CORRUPT;
- goto cleanup;
- }
- if (tortoise_i == tortoise_period) {
- tortoise[0] = dir.tail[0];
- tortoise[1] = dir.tail[1];
- tortoise_i = 0;
- tortoise_period *= 2;
- }
- tortoise_i += 1;
-
- // fetch next block in tail list
- lfs_stag_t tag = lfs_dir_fetchmatch(lfs, &dir, dir.tail,
- LFS_MKTAG(0x7ff, 0x3ff, 0),
- LFS_MKTAG(LFS_TYPE_SUPERBLOCK, 0, 8),
- NULL,
- lfs_dir_find_match, &(struct lfs_dir_find_match){
- lfs, "littlefs", 8});
- if (tag < 0) {
- err = tag;
- goto cleanup;
- }
-
- // has superblock?
- if (tag && !lfs_tag_isdelete(tag)) {
- // update root
- lfs->root[0] = dir.pair[0];
- lfs->root[1] = dir.pair[1];
-
- // grab superblock
- lfs_superblock_t superblock;
- tag = lfs_dir_get(lfs, &dir, LFS_MKTAG(0x7ff, 0x3ff, 0),
- LFS_MKTAG(LFS_TYPE_INLINESTRUCT, 0, sizeof(superblock)),
- &superblock);
- if (tag < 0) {
- err = tag;
- goto cleanup;
- }
- lfs_superblock_fromle32(&superblock);
-
- // check version
- uint16_t major_version = (0xffff & (superblock.version >> 16));
- uint16_t minor_version = (0xffff & (superblock.version >> 0));
- if (major_version != lfs_fs_disk_version_major(lfs)
- || minor_version > lfs_fs_disk_version_minor(lfs)) {
- LFS_ERROR("Invalid version "
- "v%"PRIu16".%"PRIu16" != v%"PRIu16".%"PRIu16,
- major_version,
- minor_version,
- lfs_fs_disk_version_major(lfs),
- lfs_fs_disk_version_minor(lfs));
- err = LFS_ERR_INVAL;
- goto cleanup;
- }
-
- // found older minor version? set an in-device only bit in the
- // gstate so we know we need to rewrite the superblock before
- // the first write
- if (minor_version < lfs_fs_disk_version_minor(lfs)) {
- LFS_DEBUG("Found older minor version "
- "v%"PRIu16".%"PRIu16" < v%"PRIu16".%"PRIu16,
- major_version,
- minor_version,
- lfs_fs_disk_version_major(lfs),
- lfs_fs_disk_version_minor(lfs));
- // note this bit is reserved on disk, so fetching more gstate
- // will not interfere here
- lfs_fs_prepsuperblock(lfs, true);
- }
-
- // check superblock configuration
- 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.file_max) {
- if (superblock.file_max > lfs->file_max) {
- LFS_ERROR("Unsupported file_max (%"PRIu32" > %"PRIu32")",
- superblock.file_max, lfs->file_max);
- err = LFS_ERR_INVAL;
- goto cleanup;
- }
-
- lfs->file_max = superblock.file_max;
- }
-
- 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.block_count != lfs->cfg->block_count) {
- LFS_ERROR("Invalid block count (%"PRIu32" != %"PRIu32")",
- superblock.block_count, lfs->cfg->block_count);
- err = LFS_ERR_INVAL;
- goto cleanup;
- }
+ lfs_superblock_t superblock;
+ err = lfs_scan_for_superblock(lfs, &superblock);
+ if(err) {
+ goto cleanup;
+ }
- if (superblock.block_size != lfs->cfg->block_size) {
- LFS_ERROR("Invalid block size (%"PRIu32" != %"PRIu32")",
- superblock.block_size, lfs->cfg->block_size);
- err = LFS_ERR_INVAL;
- goto cleanup;
- }
- }
+ err = lfs_validate_superblock(lfs, &superblock);
+ if(err){
+ return err;
+ }
- // has gstate?
- err = lfs_dir_getgstate(lfs, &dir, &lfs->gstate);
- if (err) {
- goto cleanup;
- }
+ err = lfs_scan_for_state_updates(lfs);
+ if(err) {
+ goto cleanup;
}
// found superblock?