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:
authorChristopher Haster <geky@geky.net>2023-05-01 07:26:04 +0300
committerGitHub <noreply@github.com>2023-05-01 07:26:04 +0300
commit405f33214aefb718e16a115c990541f219eb63b6 (patch)
treedc1570c26643bcc7f9fbd21f479df39cf6b29c5b
parent3dca02911ffa9d66e16c4386de7d5cd414dd29a9 (diff)
parent259535ee73a792556bb16eebfbd076f467c5bdfa (diff)
Merge pull request #812 from littlefs-project/mkconsistent
Add lfs_fs_mkconsistent
-rw-r--r--lfs.c46
-rw-r--r--lfs.h12
-rw-r--r--tests/test_orphans.toml77
3 files changed, 135 insertions, 0 deletions
diff --git a/lfs.c b/lfs.c
index 0fd4a77..d2f3b5e 100644
--- a/lfs.c
+++ b/lfs.c
@@ -4887,6 +4887,36 @@ static int lfs_fs_forceconsistency(lfs_t *lfs) {
}
#endif
+#ifndef LFS_READONLY
+int lfs_fs_rawmkconsistent(lfs_t *lfs) {
+ // lfs_fs_forceconsistency does most of the work here
+ int err = lfs_fs_forceconsistency(lfs);
+ if (err) {
+ return err;
+ }
+
+ // do we have any pending gstate?
+ lfs_gstate_t delta = {0};
+ lfs_gstate_xor(&delta, &lfs->gdisk);
+ lfs_gstate_xor(&delta, &lfs->gstate);
+ if (!lfs_gstate_iszero(&delta)) {
+ // lfs_dir_commit will implicitly write out any pending gstate
+ lfs_mdir_t root;
+ err = lfs_dir_fetch(lfs, &root, lfs->root);
+ if (err) {
+ return err;
+ }
+
+ err = lfs_dir_commit(lfs, &root, NULL, 0);
+ if (err) {
+ return err;
+ }
+ }
+
+ return 0;
+}
+#endif
+
static int lfs_fs_size_count(void *p, lfs_block_t block) {
(void)block;
lfs_size_t *size = p;
@@ -6052,6 +6082,22 @@ int lfs_fs_traverse(lfs_t *lfs, int (*cb)(void *, lfs_block_t), void *data) {
return err;
}
+#ifndef LFS_READONLY
+int lfs_fs_mkconsistent(lfs_t *lfs) {
+ int err = LFS_LOCK(lfs->cfg);
+ if (err) {
+ return err;
+ }
+ LFS_TRACE("lfs_fs_mkconsistent(%p)", (void*)lfs);
+
+ err = lfs_fs_rawmkconsistent(lfs);
+
+ LFS_TRACE("lfs_fs_mkconsistent -> %d", err);
+ LFS_UNLOCK(lfs->cfg);
+ return err;
+}
+#endif
+
#ifdef LFS_MIGRATE
int lfs_migrate(lfs_t *lfs, const struct lfs_config *cfg) {
int err = LFS_LOCK(cfg);
diff --git a/lfs.h b/lfs.h
index f539f6a..eb5c355 100644
--- a/lfs.h
+++ b/lfs.h
@@ -677,6 +677,18 @@ lfs_ssize_t lfs_fs_size(lfs_t *lfs);
int lfs_fs_traverse(lfs_t *lfs, int (*cb)(void*, lfs_block_t), void *data);
#ifndef LFS_READONLY
+// Attempt to make the filesystem consistent and ready for writing
+//
+// Calling this function is not required, consistency will be implicitly
+// enforced on the first operation that writes to the filesystem, but this
+// function allows the work to be performed earlier and without other
+// filesystem changes.
+//
+// Returns a negative error code on failure.
+int lfs_fs_mkconsistent(lfs_t *lfs);
+#endif
+
+#ifndef LFS_READONLY
#ifdef LFS_MIGRATE
// Attempts to migrate a previous version of littlefs
//
diff --git a/tests/test_orphans.toml b/tests/test_orphans.toml
index 1cce2fb..2c8405a 100644
--- a/tests/test_orphans.toml
+++ b/tests/test_orphans.toml
@@ -126,6 +126,83 @@ code = '''
lfs_unmount(&lfs) => 0;
'''
+# test that we can persist gstate with lfs_fs_mkconsistent
+[cases.test_orphans_mkconsistent_no_orphans]
+in = 'lfs.c'
+code = '''
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
+
+ lfs_mount(&lfs, cfg) => 0;
+ // mark the filesystem as having orphans
+ lfs_fs_preporphans(&lfs, +1) => 0;
+ lfs_mdir_t mdir;
+ lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
+ lfs_dir_commit(&lfs, &mdir, NULL, 0) => 0;
+
+ // we should have orphans at this state
+ assert(lfs_gstate_hasorphans(&lfs.gstate));
+ lfs_unmount(&lfs) => 0;
+
+ // mount
+ lfs_mount(&lfs, cfg) => 0;
+ // we should detect orphans
+ assert(lfs_gstate_hasorphans(&lfs.gstate));
+ // force consistency
+ lfs_fs_mkconsistent(&lfs) => 0;
+ // we should no longer have orphans
+ assert(!lfs_gstate_hasorphans(&lfs.gstate));
+
+ // remount
+ lfs_unmount(&lfs) => 0;
+ lfs_mount(&lfs, cfg) => 0;
+ // we should still have no orphans
+ assert(!lfs_gstate_hasorphans(&lfs.gstate));
+ lfs_unmount(&lfs) => 0;
+'''
+
+[cases.test_orphans_mkconsistent_one_orphan]
+in = 'lfs.c'
+code = '''
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
+
+ lfs_mount(&lfs, cfg) => 0;
+ // create an orphan
+ lfs_mdir_t orphan;
+ lfs_alloc_ack(&lfs);
+ lfs_dir_alloc(&lfs, &orphan) => 0;
+ lfs_dir_commit(&lfs, &orphan, NULL, 0) => 0;
+
+ // append our orphan and mark the filesystem as having orphans
+ lfs_fs_preporphans(&lfs, +1) => 0;
+ lfs_mdir_t mdir;
+ lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
+ lfs_pair_tole32(orphan.pair);
+ lfs_dir_commit(&lfs, &mdir, LFS_MKATTRS(
+ {LFS_MKTAG(LFS_TYPE_SOFTTAIL, 0x3ff, 8), orphan.pair})) => 0;
+
+ // we should have orphans at this state
+ assert(lfs_gstate_hasorphans(&lfs.gstate));
+ lfs_unmount(&lfs) => 0;
+
+ // mount
+ lfs_mount(&lfs, cfg) => 0;
+ // we should detect orphans
+ assert(lfs_gstate_hasorphans(&lfs.gstate));
+ // force consistency
+ lfs_fs_mkconsistent(&lfs) => 0;
+ // we should no longer have orphans
+ assert(!lfs_gstate_hasorphans(&lfs.gstate));
+
+ // remount
+ lfs_unmount(&lfs) => 0;
+ lfs_mount(&lfs, cfg) => 0;
+ // we should still have no orphans
+ assert(!lfs_gstate_hasorphans(&lfs.gstate));
+ lfs_unmount(&lfs) => 0;
+'''
+
# reentrant testing for orphans, basically just spam mkdir/remove
[cases.test_orphans_reentrant]
reentrant = true