Skip to content

Commit 405f332

Browse files
authored
Merge pull request #812 from littlefs-project/mkconsistent
Add lfs_fs_mkconsistent
2 parents 3dca029 + 259535e commit 405f332

File tree

3 files changed

+135
-0
lines changed

3 files changed

+135
-0
lines changed

lfs.c

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4887,6 +4887,36 @@ static int lfs_fs_forceconsistency(lfs_t *lfs) {
48874887
}
48884888
#endif
48894889

4890+
#ifndef LFS_READONLY
4891+
int lfs_fs_rawmkconsistent(lfs_t *lfs) {
4892+
// lfs_fs_forceconsistency does most of the work here
4893+
int err = lfs_fs_forceconsistency(lfs);
4894+
if (err) {
4895+
return err;
4896+
}
4897+
4898+
// do we have any pending gstate?
4899+
lfs_gstate_t delta = {0};
4900+
lfs_gstate_xor(&delta, &lfs->gdisk);
4901+
lfs_gstate_xor(&delta, &lfs->gstate);
4902+
if (!lfs_gstate_iszero(&delta)) {
4903+
// lfs_dir_commit will implicitly write out any pending gstate
4904+
lfs_mdir_t root;
4905+
err = lfs_dir_fetch(lfs, &root, lfs->root);
4906+
if (err) {
4907+
return err;
4908+
}
4909+
4910+
err = lfs_dir_commit(lfs, &root, NULL, 0);
4911+
if (err) {
4912+
return err;
4913+
}
4914+
}
4915+
4916+
return 0;
4917+
}
4918+
#endif
4919+
48904920
static int lfs_fs_size_count(void *p, lfs_block_t block) {
48914921
(void)block;
48924922
lfs_size_t *size = p;
@@ -6052,6 +6082,22 @@ int lfs_fs_traverse(lfs_t *lfs, int (*cb)(void *, lfs_block_t), void *data) {
60526082
return err;
60536083
}
60546084

6085+
#ifndef LFS_READONLY
6086+
int lfs_fs_mkconsistent(lfs_t *lfs) {
6087+
int err = LFS_LOCK(lfs->cfg);
6088+
if (err) {
6089+
return err;
6090+
}
6091+
LFS_TRACE("lfs_fs_mkconsistent(%p)", (void*)lfs);
6092+
6093+
err = lfs_fs_rawmkconsistent(lfs);
6094+
6095+
LFS_TRACE("lfs_fs_mkconsistent -> %d", err);
6096+
LFS_UNLOCK(lfs->cfg);
6097+
return err;
6098+
}
6099+
#endif
6100+
60556101
#ifdef LFS_MIGRATE
60566102
int lfs_migrate(lfs_t *lfs, const struct lfs_config *cfg) {
60576103
int err = LFS_LOCK(cfg);

lfs.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -676,6 +676,18 @@ lfs_ssize_t lfs_fs_size(lfs_t *lfs);
676676
// Returns a negative error code on failure.
677677
int lfs_fs_traverse(lfs_t *lfs, int (*cb)(void*, lfs_block_t), void *data);
678678

679+
#ifndef LFS_READONLY
680+
// Attempt to make the filesystem consistent and ready for writing
681+
//
682+
// Calling this function is not required, consistency will be implicitly
683+
// enforced on the first operation that writes to the filesystem, but this
684+
// function allows the work to be performed earlier and without other
685+
// filesystem changes.
686+
//
687+
// Returns a negative error code on failure.
688+
int lfs_fs_mkconsistent(lfs_t *lfs);
689+
#endif
690+
679691
#ifndef LFS_READONLY
680692
#ifdef LFS_MIGRATE
681693
// Attempts to migrate a previous version of littlefs

tests/test_orphans.toml

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,83 @@ code = '''
126126
lfs_unmount(&lfs) => 0;
127127
'''
128128

129+
# test that we can persist gstate with lfs_fs_mkconsistent
130+
[cases.test_orphans_mkconsistent_no_orphans]
131+
in = 'lfs.c'
132+
code = '''
133+
lfs_t lfs;
134+
lfs_format(&lfs, cfg) => 0;
135+
136+
lfs_mount(&lfs, cfg) => 0;
137+
// mark the filesystem as having orphans
138+
lfs_fs_preporphans(&lfs, +1) => 0;
139+
lfs_mdir_t mdir;
140+
lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
141+
lfs_dir_commit(&lfs, &mdir, NULL, 0) => 0;
142+
143+
// we should have orphans at this state
144+
assert(lfs_gstate_hasorphans(&lfs.gstate));
145+
lfs_unmount(&lfs) => 0;
146+
147+
// mount
148+
lfs_mount(&lfs, cfg) => 0;
149+
// we should detect orphans
150+
assert(lfs_gstate_hasorphans(&lfs.gstate));
151+
// force consistency
152+
lfs_fs_mkconsistent(&lfs) => 0;
153+
// we should no longer have orphans
154+
assert(!lfs_gstate_hasorphans(&lfs.gstate));
155+
156+
// remount
157+
lfs_unmount(&lfs) => 0;
158+
lfs_mount(&lfs, cfg) => 0;
159+
// we should still have no orphans
160+
assert(!lfs_gstate_hasorphans(&lfs.gstate));
161+
lfs_unmount(&lfs) => 0;
162+
'''
163+
164+
[cases.test_orphans_mkconsistent_one_orphan]
165+
in = 'lfs.c'
166+
code = '''
167+
lfs_t lfs;
168+
lfs_format(&lfs, cfg) => 0;
169+
170+
lfs_mount(&lfs, cfg) => 0;
171+
// create an orphan
172+
lfs_mdir_t orphan;
173+
lfs_alloc_ack(&lfs);
174+
lfs_dir_alloc(&lfs, &orphan) => 0;
175+
lfs_dir_commit(&lfs, &orphan, NULL, 0) => 0;
176+
177+
// append our orphan and mark the filesystem as having orphans
178+
lfs_fs_preporphans(&lfs, +1) => 0;
179+
lfs_mdir_t mdir;
180+
lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
181+
lfs_pair_tole32(orphan.pair);
182+
lfs_dir_commit(&lfs, &mdir, LFS_MKATTRS(
183+
{LFS_MKTAG(LFS_TYPE_SOFTTAIL, 0x3ff, 8), orphan.pair})) => 0;
184+
185+
// we should have orphans at this state
186+
assert(lfs_gstate_hasorphans(&lfs.gstate));
187+
lfs_unmount(&lfs) => 0;
188+
189+
// mount
190+
lfs_mount(&lfs, cfg) => 0;
191+
// we should detect orphans
192+
assert(lfs_gstate_hasorphans(&lfs.gstate));
193+
// force consistency
194+
lfs_fs_mkconsistent(&lfs) => 0;
195+
// we should no longer have orphans
196+
assert(!lfs_gstate_hasorphans(&lfs.gstate));
197+
198+
// remount
199+
lfs_unmount(&lfs) => 0;
200+
lfs_mount(&lfs, cfg) => 0;
201+
// we should still have no orphans
202+
assert(!lfs_gstate_hasorphans(&lfs.gstate));
203+
lfs_unmount(&lfs) => 0;
204+
'''
205+
129206
# reentrant testing for orphans, basically just spam mkdir/remove
130207
[cases.test_orphans_reentrant]
131208
reentrant = true

0 commit comments

Comments
 (0)