forked from Imagelibrary/littlefs
Merge pull request #812 from littlefs-project/mkconsistent
Add lfs_fs_mkconsistent
This commit is contained in:
46
lfs.c
46
lfs.c
@@ -4887,6 +4887,36 @@ static int lfs_fs_forceconsistency(lfs_t *lfs) {
|
|||||||
}
|
}
|
||||||
#endif
|
#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) {
|
static int lfs_fs_size_count(void *p, lfs_block_t block) {
|
||||||
(void)block;
|
(void)block;
|
||||||
lfs_size_t *size = p;
|
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;
|
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
|
#ifdef LFS_MIGRATE
|
||||||
int lfs_migrate(lfs_t *lfs, const struct lfs_config *cfg) {
|
int lfs_migrate(lfs_t *lfs, const struct lfs_config *cfg) {
|
||||||
int err = LFS_LOCK(cfg);
|
int err = LFS_LOCK(cfg);
|
||||||
|
|||||||
12
lfs.h
12
lfs.h
@@ -676,6 +676,18 @@ lfs_ssize_t lfs_fs_size(lfs_t *lfs);
|
|||||||
// Returns a negative error code on failure.
|
// Returns a negative error code on failure.
|
||||||
int lfs_fs_traverse(lfs_t *lfs, int (*cb)(void*, lfs_block_t), void *data);
|
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
|
#ifndef LFS_READONLY
|
||||||
#ifdef LFS_MIGRATE
|
#ifdef LFS_MIGRATE
|
||||||
// Attempts to migrate a previous version of littlefs
|
// Attempts to migrate a previous version of littlefs
|
||||||
|
|||||||
@@ -126,6 +126,83 @@ code = '''
|
|||||||
lfs_unmount(&lfs) => 0;
|
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
|
# reentrant testing for orphans, basically just spam mkdir/remove
|
||||||
[cases.test_orphans_reentrant]
|
[cases.test_orphans_reentrant]
|
||||||
reentrant = true
|
reentrant = true
|
||||||
|
|||||||
Reference in New Issue
Block a user