Generated v2 prefixes

This commit is contained in:
geky-bot
2023-06-30 17:56:00 +00:00
10 changed files with 451 additions and 91 deletions
+1 -1
View File
@@ -102,7 +102,7 @@ jobs:
# sizes table # sizes table
i=0 i=0
j=0 j=0
for c in "" readonly threadsafe migrate error-asserts for c in "" readonly threadsafe multiversion migrate error-asserts
do do
# per-config results # per-config results
c_or_default=${c:-default} c_or_default=${c:-default}
+60 -2
View File
@@ -170,6 +170,27 @@ jobs:
cp lfs2.data.csv sizes/${{matrix.arch}}-threadsafe.data.csv cp lfs2.data.csv sizes/${{matrix.arch}}-threadsafe.data.csv
cp lfs2.stack.csv sizes/${{matrix.arch}}-threadsafe.stack.csv cp lfs2.stack.csv sizes/${{matrix.arch}}-threadsafe.stack.csv
cp lfs2.structs.csv sizes/${{matrix.arch}}-threadsafe.structs.csv cp lfs2.structs.csv sizes/${{matrix.arch}}-threadsafe.structs.csv
- name: sizes-multiversion
run: |
make clean
CFLAGS="$CFLAGS \
-DLFS2_NO_ASSERT \
-DLFS2_NO_DEBUG \
-DLFS2_NO_WARN \
-DLFS2_NO_ERROR \
-DLFS2_MULTIVERSION" \
make lfs2.code.csv lfs2.data.csv lfs2.stack.csv lfs2.structs.csv
./scripts/structs.py -u lfs2.structs.csv
./scripts/summary.py lfs2.code.csv lfs2.data.csv lfs2.stack.csv \
-bfunction \
-fcode=code_size \
-fdata=data_size \
-fstack=stack_limit --max=stack_limit
mkdir -p sizes
cp lfs2.code.csv sizes/${{matrix.arch}}-multiversion.code.csv
cp lfs2.data.csv sizes/${{matrix.arch}}-multiversion.data.csv
cp lfs2.stack.csv sizes/${{matrix.arch}}-multiversion.stack.csv
cp lfs2.structs.csv sizes/${{matrix.arch}}-multiversion.structs.csv
- name: sizes-migrate - name: sizes-migrate
run: | run: |
make clean make clean
@@ -353,6 +374,42 @@ jobs:
run: | run: |
CFLAGS="$CFLAGS -DLFS2_NO_INTRINSICS" make test CFLAGS="$CFLAGS -DLFS2_NO_INTRINSICS" make test
# run LFS2_MULTIVERSION tests
test-multiversion:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v2
- name: install
run: |
# need a few things
sudo apt-get update -qq
sudo apt-get install -qq gcc python3 python3-pip
pip3 install toml
gcc --version
python3 --version
- name: test-multiversion
run: |
CFLAGS="$CFLAGS -DLFS2_MULTIVERSION" make test
# run tests on the older version lfs22.0
test-lfs22_0:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v2
- name: install
run: |
# need a few things
sudo apt-get update -qq
sudo apt-get install -qq gcc python3 python3-pip
pip3 install toml
gcc --version
python3 --version
- name: test-lfs22_0
run: |
CFLAGS="$CFLAGS -DLFS2_MULTIVERSION" \
TESTFLAGS="$TESTFLAGS -DDISK_VERSION=0x00020000" \
make test
# run under Valgrind to check for memory errors # run under Valgrind to check for memory errors
test-valgrind: test-valgrind:
runs-on: ubuntu-22.04 runs-on: ubuntu-22.04
@@ -371,7 +428,8 @@ jobs:
# on one geometry # on one geometry
- name: test-valgrind - name: test-valgrind
run: | run: |
TESTFLAGS="$TESTFLAGS --valgrind -Gdefault -Pnone" make test TESTFLAGS="$TESTFLAGS --valgrind --context=1024 -Gdefault -Pnone" \
make test
# test that compilation is warning free under clang # test that compilation is warning free under clang
# run with Clang, mostly to check for Clang-specific warnings # run with Clang, mostly to check for Clang-specific warnings
@@ -684,7 +742,7 @@ jobs:
# sizes table # sizes table
i=0 i=0
j=0 j=0
for c in "" readonly threadsafe migrate error-asserts for c in "" readonly threadsafe multiversion migrate error-asserts
do do
# per-config results # per-config results
c_or_default=${c:-default} c_or_default=${c:-default}
+5
View File
@@ -250,6 +250,10 @@ License Identifiers that are here available: http://spdx.org/licenses/
MCUs. It offers static wear-leveling and power-resilience with only a fixed MCUs. It offers static wear-leveling and power-resilience with only a fixed
_O(|address|)_ pointer structure stored on each block and in RAM. _O(|address|)_ pointer structure stored on each block and in RAM.
- [ChaN's FatFs] - A lightweight reimplementation of the infamous FAT filesystem
for microcontroller-scale devices. Due to limitations of FAT it can't provide
power-loss resilience, but it does allow easy interop with PCs.
- [chamelon] - A pure-OCaml implementation of (most of) littlefs, designed for - [chamelon] - A pure-OCaml implementation of (most of) littlefs, designed for
use with the MirageOS library operating system project. It is interoperable use with the MirageOS library operating system project. It is interoperable
with the reference implementation, with some caveats. with the reference implementation, with some caveats.
@@ -266,6 +270,7 @@ License Identifiers that are here available: http://spdx.org/licenses/
[LittleFileSystem]: https://os.mbed.com/docs/mbed-os/latest/apis/littlefilesystem.html [LittleFileSystem]: https://os.mbed.com/docs/mbed-os/latest/apis/littlefilesystem.html
[SPIFFS]: https://github.com/pellepl/spiffs [SPIFFS]: https://github.com/pellepl/spiffs
[Dhara]: https://github.com/dlbeer/dhara [Dhara]: https://github.com/dlbeer/dhara
[ChaN's FatFs]: http://elm-chan.org/fsw/ff/00index_e.html
[littlefs-python]: https://pypi.org/project/littlefs-python/ [littlefs-python]: https://pypi.org/project/littlefs-python/
[littlefs2-rust]: https://crates.io/crates/littlefs2 [littlefs2-rust]: https://crates.io/crates/littlefs2
[chamelon]: https://github.com/yomimono/chamelon [chamelon]: https://github.com/yomimono/chamelon
+154 -48
View File
@@ -415,11 +415,11 @@ static inline uint8_t lfs2_gstate_getorphans(const lfs2_gstate_t *a) {
static inline bool lfs2_gstate_hasmove(const lfs2_gstate_t *a) { static inline bool lfs2_gstate_hasmove(const lfs2_gstate_t *a) {
return lfs2_tag_type1(a->tag); return lfs2_tag_type1(a->tag);
} }
#endif
static inline bool lfs2_gstate_needssuperblock(const lfs2_gstate_t *a) { static inline bool lfs2_gstate_needssuperblock(const lfs2_gstate_t *a) {
return lfs2_tag_size(a->tag) >> 9; return lfs2_tag_size(a->tag) >> 9;
} }
#endif
static inline bool lfs2_gstate_hasmovehere(const lfs2_gstate_t *a, static inline bool lfs2_gstate_hasmovehere(const lfs2_gstate_t *a,
const lfs2_block_t *pair) { const lfs2_block_t *pair) {
@@ -518,6 +518,28 @@ static void lfs2_mlist_append(lfs2_t *lfs2, struct lfs2_mlist *mlist) {
lfs2->mlist = mlist; lfs2->mlist = mlist;
} }
// some other filesystem operations
static uint32_t lfs2_fs_disk_version(lfs2_t *lfs2) {
(void)lfs2;
#ifdef LFS2_MULTIVERSION
if (lfs2->cfg->disk_version) {
return lfs2->cfg->disk_version;
} else
#endif
{
return LFS2_DISK_VERSION;
}
}
static uint16_t lfs2_fs_disk_version_major(lfs2_t *lfs2) {
return 0xffff & (lfs2_fs_disk_version(lfs2) >> 16);
}
static uint16_t lfs2_fs_disk_version_minor(lfs2_t *lfs2) {
return 0xffff & (lfs2_fs_disk_version(lfs2) >> 0);
}
/// Internal operations predeclared here /// /// Internal operations predeclared here ///
#ifndef LFS2_READONLY #ifndef LFS2_READONLY
@@ -535,7 +557,6 @@ static int lfs2_file_outline(lfs2_t *lfs2, lfs2_file_t *file);
static int lfs2_file_flush(lfs2_t *lfs2, lfs2_file_t *file); static int lfs2_file_flush(lfs2_t *lfs2, lfs2_file_t *file);
static int lfs2_fs_deorphan(lfs2_t *lfs2, bool powerloss); static int lfs2_fs_deorphan(lfs2_t *lfs2, bool powerloss);
static void lfs2_fs_prepsuperblock(lfs2_t *lfs2, bool needssuperblock);
static int lfs2_fs_preporphans(lfs2_t *lfs2, int8_t orphans); static int lfs2_fs_preporphans(lfs2_t *lfs2, int8_t orphans);
static void lfs2_fs_prepmove(lfs2_t *lfs2, static void lfs2_fs_prepmove(lfs2_t *lfs2,
uint16_t id, const lfs2_block_t pair[2]); uint16_t id, const lfs2_block_t pair[2]);
@@ -546,6 +567,8 @@ static lfs2_stag_t lfs2_fs_parent(lfs2_t *lfs2, const lfs2_block_t dir[2],
static int lfs2_fs_forceconsistency(lfs2_t *lfs2); static int lfs2_fs_forceconsistency(lfs2_t *lfs2);
#endif #endif
static void lfs2_fs_prepsuperblock(lfs2_t *lfs2, bool needssuperblock);
#ifdef LFS2_MIGRATE #ifdef LFS2_MIGRATE
static int lfs21_traverse(lfs2_t *lfs2, static int lfs21_traverse(lfs2_t *lfs2,
int (*cb)(void*, lfs2_block_t), void *data); int (*cb)(void*, lfs2_block_t), void *data);
@@ -1110,7 +1133,8 @@ static lfs2_stag_t lfs2_dir_fetchmatch(lfs2_t *lfs2,
// next commit not yet programmed? // next commit not yet programmed?
if (!lfs2_tag_isvalid(tag)) { if (!lfs2_tag_isvalid(tag)) {
maybeerased = true; // we only might be erased if the last tag was a crc
maybeerased = (lfs2_tag_type2(ptag) == LFS2_TYPE_CCRC);
break; break;
// out of range? // out of range?
} else if (off + lfs2_tag_dsize(tag) > lfs2->cfg->block_size) { } else if (off + lfs2_tag_dsize(tag) > lfs2->cfg->block_size) {
@@ -1155,14 +1179,11 @@ static lfs2_stag_t lfs2_dir_fetchmatch(lfs2_t *lfs2,
dir->tail[1] = temptail[1]; dir->tail[1] = temptail[1];
dir->split = tempsplit; dir->split = tempsplit;
// reset crc // reset crc, hasfcrc
crc = 0xffffffff; crc = 0xffffffff;
continue; continue;
} }
// fcrc is only valid when last tag was a crc
hasfcrc = false;
// crc the entry first, hopefully leaving it in the cache // crc the entry first, hopefully leaving it in the cache
err = lfs2_bd_crc(lfs2, err = lfs2_bd_crc(lfs2,
NULL, &lfs2->rcache, lfs2->cfg->block_size, NULL, &lfs2->rcache, lfs2->cfg->block_size,
@@ -1256,20 +1277,33 @@ static lfs2_stag_t lfs2_dir_fetchmatch(lfs2_t *lfs2,
// did we end on a valid commit? we may have an erased block // did we end on a valid commit? we may have an erased block
dir->erased = false; dir->erased = false;
if (maybeerased && hasfcrc && dir->off % lfs2->cfg->prog_size == 0) { if (maybeerased && dir->off % lfs2->cfg->prog_size == 0) {
// check for an fcrc matching the next prog's erased state, if #ifdef LFS2_MULTIVERSION
// this failed most likely a previous prog was interrupted, we // note versions < lfs22.1 did not have fcrc tags, if
// need a new erase // we're < lfs22.1 treat missing fcrc as erased data
uint32_t fcrc_ = 0xffffffff; //
int err = lfs2_bd_crc(lfs2, // we don't strictly need to do this, but otherwise writing
NULL, &lfs2->rcache, lfs2->cfg->block_size, // to lfs22.0 disks becomes very inefficient
dir->pair[0], dir->off, fcrc.size, &fcrc_); if (lfs2_fs_disk_version(lfs2) < 0x00020001) {
if (err && err != LFS2_ERR_CORRUPT) { dir->erased = true;
return err;
}
// found beginning of erased part? } else
dir->erased = (fcrc_ == fcrc.crc); #endif
if (hasfcrc) {
// check for an fcrc matching the next prog's erased state, if
// this failed most likely a previous prog was interrupted, we
// need a new erase
uint32_t fcrc_ = 0xffffffff;
int err = lfs2_bd_crc(lfs2,
NULL, &lfs2->rcache, lfs2->cfg->block_size,
dir->pair[0], dir->off, fcrc.size, &fcrc_);
if (err && err != LFS2_ERR_CORRUPT) {
return err;
}
// found beginning of erased part?
dir->erased = (fcrc_ == fcrc.crc);
}
} }
// synthetic move // synthetic move
@@ -1605,22 +1639,34 @@ static int lfs2_dir_commitcrc(lfs2_t *lfs2, struct lfs2_commit *commit) {
return err; return err;
} }
// find the expected fcrc, don't bother avoiding a reread #ifdef LFS2_MULTIVERSION
// of the eperturb, it should still be in our cache // unfortunately fcrcs break mdir fetching < lfs22.1, so only write
struct lfs2_fcrc fcrc = {.size=lfs2->cfg->prog_size, .crc=0xffffffff}; // these if we're a >= lfs22.1 filesystem
err = lfs2_bd_crc(lfs2, if (lfs2_fs_disk_version(lfs2) <= 0x00020000) {
NULL, &lfs2->rcache, lfs2->cfg->prog_size, // don't write fcrc
commit->block, noff, fcrc.size, &fcrc.crc); } else
if (err && err != LFS2_ERR_CORRUPT) { #endif
return err; {
} // find the expected fcrc, don't bother avoiding a reread
// of the eperturb, it should still be in our cache
struct lfs2_fcrc fcrc = {
.size = lfs2->cfg->prog_size,
.crc = 0xffffffff
};
err = lfs2_bd_crc(lfs2,
NULL, &lfs2->rcache, lfs2->cfg->prog_size,
commit->block, noff, fcrc.size, &fcrc.crc);
if (err && err != LFS2_ERR_CORRUPT) {
return err;
}
lfs2_fcrc_tole32(&fcrc); lfs2_fcrc_tole32(&fcrc);
err = lfs2_dir_commitattr(lfs2, commit, err = lfs2_dir_commitattr(lfs2, commit,
LFS2_MKTAG(LFS2_TYPE_FCRC, 0x3ff, sizeof(struct lfs2_fcrc)), LFS2_MKTAG(LFS2_TYPE_FCRC, 0x3ff, sizeof(struct lfs2_fcrc)),
&fcrc); &fcrc);
if (err) { if (err) {
return err; return err;
}
} }
} }
@@ -4051,6 +4097,15 @@ static int lfs2_init(lfs2_t *lfs2, const struct lfs2_config *cfg) {
lfs2->cfg = cfg; lfs2->cfg = cfg;
int err = 0; int err = 0;
#ifdef LFS2_MULTIVERSION
// this driver only supports minor version < current minor version
LFS2_ASSERT(!lfs2->cfg->disk_version || (
(0xffff & (lfs2->cfg->disk_version >> 16))
== LFS2_DISK_VERSION_MAJOR
&& (0xffff & (lfs2->cfg->disk_version >> 0))
<= LFS2_DISK_VERSION_MINOR));
#endif
// check that bool is a truthy-preserving type // check that bool is a truthy-preserving type
// //
// note the most common reason for this failure is a before-c99 compiler, // note the most common reason for this failure is a before-c99 compiler,
@@ -4208,7 +4263,7 @@ static int lfs2_rawformat(lfs2_t *lfs2, const struct lfs2_config *cfg) {
// write one superblock // write one superblock
lfs2_superblock_t superblock = { lfs2_superblock_t superblock = {
.version = LFS2_DISK_VERSION, .version = lfs2_fs_disk_version(lfs2),
.block_size = lfs2->cfg->block_size, .block_size = lfs2->cfg->block_size,
.block_count = lfs2->cfg->block_count, .block_count = lfs2->cfg->block_count,
.name_max = lfs2->name_max, .name_max = lfs2->name_max,
@@ -4306,12 +4361,14 @@ static int lfs2_rawmount(lfs2_t *lfs2, const struct lfs2_config *cfg) {
// check version // check version
uint16_t major_version = (0xffff & (superblock.version >> 16)); uint16_t major_version = (0xffff & (superblock.version >> 16));
uint16_t minor_version = (0xffff & (superblock.version >> 0)); uint16_t minor_version = (0xffff & (superblock.version >> 0));
if ((major_version != LFS2_DISK_VERSION_MAJOR || if (major_version != lfs2_fs_disk_version_major(lfs2)
minor_version > LFS2_DISK_VERSION_MINOR)) { || minor_version > lfs2_fs_disk_version_minor(lfs2)) {
LFS2_ERROR("Invalid version " LFS2_ERROR("Invalid version "
"v%"PRIu16".%"PRIu16" != v%"PRIu16".%"PRIu16, "v%"PRIu16".%"PRIu16" != v%"PRIu16".%"PRIu16,
major_version, minor_version, major_version,
LFS2_DISK_VERSION_MAJOR, LFS2_DISK_VERSION_MINOR); minor_version,
lfs2_fs_disk_version_major(lfs2),
lfs2_fs_disk_version_minor(lfs2));
err = LFS2_ERR_INVAL; err = LFS2_ERR_INVAL;
goto cleanup; goto cleanup;
} }
@@ -4319,16 +4376,16 @@ static int lfs2_rawmount(lfs2_t *lfs2, const struct lfs2_config *cfg) {
// found older minor version? set an in-device only bit in the // found older minor version? set an in-device only bit in the
// gstate so we know we need to rewrite the superblock before // gstate so we know we need to rewrite the superblock before
// the first write // the first write
if (minor_version < LFS2_DISK_VERSION_MINOR) { if (minor_version < lfs2_fs_disk_version_minor(lfs2)) {
LFS2_DEBUG("Found older minor version " LFS2_DEBUG("Found older minor version "
"v%"PRIu16".%"PRIu16" < v%"PRIu16".%"PRIu16, "v%"PRIu16".%"PRIu16" < v%"PRIu16".%"PRIu16,
major_version, minor_version, major_version,
LFS2_DISK_VERSION_MAJOR, LFS2_DISK_VERSION_MINOR); minor_version,
#ifndef LFS2_READONLY lfs2_fs_disk_version_major(lfs2),
lfs2_fs_disk_version_minor(lfs2));
// note this bit is reserved on disk, so fetching more gstate // note this bit is reserved on disk, so fetching more gstate
// will not interfere here // will not interfere here
lfs2_fs_prepsuperblock(lfs2, true); lfs2_fs_prepsuperblock(lfs2, true);
#endif
} }
// check superblock configuration // check superblock configuration
@@ -4421,6 +4478,42 @@ static int lfs2_rawunmount(lfs2_t *lfs2) {
/// Filesystem filesystem operations /// /// Filesystem filesystem operations ///
static int lfs2_fs_rawstat(lfs2_t *lfs2, struct lfs2_fsinfo *fsinfo) {
// if the superblock is up-to-date, we must be on the most recent
// minor version of littlefs
if (!lfs2_gstate_needssuperblock(&lfs2->gstate)) {
fsinfo->disk_version = lfs2_fs_disk_version(lfs2);
// otherwise we need to read the minor version on disk
} else {
// fetch the superblock
lfs2_mdir_t dir;
int err = lfs2_dir_fetch(lfs2, &dir, lfs2->root);
if (err) {
return err;
}
lfs2_superblock_t superblock;
lfs2_stag_t tag = lfs2_dir_get(lfs2, &dir, LFS2_MKTAG(0x7ff, 0x3ff, 0),
LFS2_MKTAG(LFS2_TYPE_INLINESTRUCT, 0, sizeof(superblock)),
&superblock);
if (tag < 0) {
return tag;
}
lfs2_superblock_fromle32(&superblock);
// read the on-disk version
fsinfo->disk_version = superblock.version;
}
// other on-disk configuration, we cache all of these for internal use
fsinfo->name_max = lfs2->name_max;
fsinfo->file_max = lfs2->file_max;
fsinfo->attr_max = lfs2->attr_max;
return 0;
}
int lfs2_fs_rawtraverse(lfs2_t *lfs2, int lfs2_fs_rawtraverse(lfs2_t *lfs2,
int (*cb)(void *data, lfs2_block_t block), void *data, int (*cb)(void *data, lfs2_block_t block), void *data,
bool includeorphans) { bool includeorphans) {
@@ -4631,12 +4724,10 @@ static lfs2_stag_t lfs2_fs_parent(lfs2_t *lfs2, const lfs2_block_t pair[2],
} }
#endif #endif
#ifndef LFS2_READONLY
static void lfs2_fs_prepsuperblock(lfs2_t *lfs2, bool needssuperblock) { static void lfs2_fs_prepsuperblock(lfs2_t *lfs2, bool needssuperblock) {
lfs2->gstate.tag = (lfs2->gstate.tag & ~LFS2_MKTAG(0, 0, 0x200)) lfs2->gstate.tag = (lfs2->gstate.tag & ~LFS2_MKTAG(0, 0, 0x200))
| (uint32_t)needssuperblock << 9; | (uint32_t)needssuperblock << 9;
} }
#endif
#ifndef LFS2_READONLY #ifndef LFS2_READONLY
static int lfs2_fs_preporphans(lfs2_t *lfs2, int8_t orphans) { static int lfs2_fs_preporphans(lfs2_t *lfs2, int8_t orphans) {
@@ -4678,7 +4769,7 @@ static int lfs2_fs_desuperblock(lfs2_t *lfs2) {
// write a new superblock // write a new superblock
lfs2_superblock_t superblock = { lfs2_superblock_t superblock = {
.version = LFS2_DISK_VERSION, .version = lfs2_fs_disk_version(lfs2),
.block_size = lfs2->cfg->block_size, .block_size = lfs2->cfg->block_size,
.block_count = lfs2->cfg->block_count, .block_count = lfs2->cfg->block_count,
.name_max = lfs2->name_max, .name_max = lfs2->name_max,
@@ -4934,6 +5025,7 @@ static lfs2_ssize_t lfs2_fs_rawsize(lfs2_t *lfs2) {
return size; return size;
} }
#ifdef LFS2_MIGRATE #ifdef LFS2_MIGRATE
////// Migration from littelfs v1 below this ////// ////// Migration from littelfs v1 below this //////
@@ -6053,6 +6145,20 @@ int lfs2_dir_rewind(lfs2_t *lfs2, lfs2_dir_t *dir) {
return err; return err;
} }
int lfs2_fs_stat(lfs2_t *lfs2, struct lfs2_fsinfo *fsinfo) {
int err = LFS2_LOCK(lfs2->cfg);
if (err) {
return err;
}
LFS2_TRACE("lfs2_fs_stat(%p, %p)", (void*)lfs2, (void*)fsinfo);
err = lfs2_fs_rawstat(lfs2, fsinfo);
LFS2_TRACE("lfs2_fs_stat -> %d", err);
LFS2_UNLOCK(lfs2->cfg);
return err;
}
lfs2_ssize_t lfs2_fs_size(lfs2_t *lfs2) { lfs2_ssize_t lfs2_fs_size(lfs2_t *lfs2) {
int err = LFS2_LOCK(lfs2->cfg); int err = LFS2_LOCK(lfs2->cfg);
if (err) { if (err) {
+30 -1
View File
@@ -21,7 +21,7 @@ extern "C"
// Software library version // Software library version
// Major (top-nibble), incremented on backwards incompatible changes // Major (top-nibble), incremented on backwards incompatible changes
// Minor (bottom-nibble), incremented on feature additions // Minor (bottom-nibble), incremented on feature additions
#define LFS2_VERSION 0x00020006 #define LFS2_VERSION 0x00020007
#define LFS2_VERSION_MAJOR (0xffff & (LFS2_VERSION >> 16)) #define LFS2_VERSION_MAJOR (0xffff & (LFS2_VERSION >> 16))
#define LFS2_VERSION_MINOR (0xffff & (LFS2_VERSION >> 0)) #define LFS2_VERSION_MINOR (0xffff & (LFS2_VERSION >> 0))
@@ -263,6 +263,14 @@ struct lfs2_config {
// can help bound the metadata compaction time. Must be <= block_size. // can help bound the metadata compaction time. Must be <= block_size.
// Defaults to block_size when zero. // Defaults to block_size when zero.
lfs2_size_t metadata_max; lfs2_size_t metadata_max;
#ifdef LFS2_MULTIVERSION
// On-disk version to use when writing in the form of 16-bit major version
// + 16-bit minor version. This limiting metadata to what is supported by
// older minor versions. Note that some features will be lost. Defaults to
// to the most recent minor version when zero.
uint32_t disk_version;
#endif
}; };
// File info structure // File info structure
@@ -280,6 +288,21 @@ struct lfs2_info {
char name[LFS2_NAME_MAX+1]; char name[LFS2_NAME_MAX+1];
}; };
// Filesystem info structure
struct lfs2_fsinfo {
// On-disk version.
uint32_t disk_version;
// Upper limit on the length of file names in bytes.
lfs2_size_t name_max;
// Upper limit on the size of files in bytes.
lfs2_size_t file_max;
// Upper limit on the size of custom attributes in bytes.
lfs2_size_t attr_max;
};
// Custom attribute structure, used to describe custom attributes // Custom attribute structure, used to describe custom attributes
// committed atomically during file writes. // committed atomically during file writes.
struct lfs2_attr { struct lfs2_attr {
@@ -659,6 +682,12 @@ int lfs2_dir_rewind(lfs2_t *lfs2, lfs2_dir_t *dir);
/// Filesystem-level filesystem operations /// Filesystem-level filesystem operations
// Find on-disk info about the filesystem
//
// Fills out the fsinfo structure based on the filesystem found on-disk.
// Returns a negative error code on failure.
int lfs2_fs_stat(lfs2_t *lfs2, struct lfs2_fsinfo *fsinfo);
// Finds the current size of the filesystem // Finds the current size of the filesystem
// //
// Note: Result is best effort. If files share COW structures, the returned // Note: Result is best effort. If files share COW structures, the returned
+15
View File
@@ -1346,6 +1346,9 @@ static void run_powerloss_none(
.block_cycles = BLOCK_CYCLES, .block_cycles = BLOCK_CYCLES,
.cache_size = CACHE_SIZE, .cache_size = CACHE_SIZE,
.lookahead_size = LOOKAHEAD_SIZE, .lookahead_size = LOOKAHEAD_SIZE,
#ifdef LFS2_MULTIVERSION
.disk_version = DISK_VERSION,
#endif
}; };
struct lfs2_emubd_config bdcfg = { struct lfs2_emubd_config bdcfg = {
@@ -1415,6 +1418,9 @@ static void run_powerloss_linear(
.block_cycles = BLOCK_CYCLES, .block_cycles = BLOCK_CYCLES,
.cache_size = CACHE_SIZE, .cache_size = CACHE_SIZE,
.lookahead_size = LOOKAHEAD_SIZE, .lookahead_size = LOOKAHEAD_SIZE,
#ifdef LFS2_MULTIVERSION
.disk_version = DISK_VERSION,
#endif
}; };
struct lfs2_emubd_config bdcfg = { struct lfs2_emubd_config bdcfg = {
@@ -1501,6 +1507,9 @@ static void run_powerloss_log(
.block_cycles = BLOCK_CYCLES, .block_cycles = BLOCK_CYCLES,
.cache_size = CACHE_SIZE, .cache_size = CACHE_SIZE,
.lookahead_size = LOOKAHEAD_SIZE, .lookahead_size = LOOKAHEAD_SIZE,
#ifdef LFS2_MULTIVERSION
.disk_version = DISK_VERSION,
#endif
}; };
struct lfs2_emubd_config bdcfg = { struct lfs2_emubd_config bdcfg = {
@@ -1585,6 +1594,9 @@ static void run_powerloss_cycles(
.block_cycles = BLOCK_CYCLES, .block_cycles = BLOCK_CYCLES,
.cache_size = CACHE_SIZE, .cache_size = CACHE_SIZE,
.lookahead_size = LOOKAHEAD_SIZE, .lookahead_size = LOOKAHEAD_SIZE,
#ifdef LFS2_MULTIVERSION
.disk_version = DISK_VERSION,
#endif
}; };
struct lfs2_emubd_config bdcfg = { struct lfs2_emubd_config bdcfg = {
@@ -1767,6 +1779,9 @@ static void run_powerloss_exhaustive(
.block_cycles = BLOCK_CYCLES, .block_cycles = BLOCK_CYCLES,
.cache_size = CACHE_SIZE, .cache_size = CACHE_SIZE,
.lookahead_size = LOOKAHEAD_SIZE, .lookahead_size = LOOKAHEAD_SIZE,
#ifdef LFS2_MULTIVERSION
.disk_version = DISK_VERSION,
#endif
}; };
struct lfs2_emubd_config bdcfg = { struct lfs2_emubd_config bdcfg = {
+5 -2
View File
@@ -91,6 +91,7 @@ intmax_t test_define(size_t define);
#define ERASE_CYCLES_i 8 #define ERASE_CYCLES_i 8
#define BADBLOCK_BEHAVIOR_i 9 #define BADBLOCK_BEHAVIOR_i 9
#define POWERLOSS_BEHAVIOR_i 10 #define POWERLOSS_BEHAVIOR_i 10
#define DISK_VERSION_i 11
#define READ_SIZE TEST_DEFINE(READ_SIZE_i) #define READ_SIZE TEST_DEFINE(READ_SIZE_i)
#define PROG_SIZE TEST_DEFINE(PROG_SIZE_i) #define PROG_SIZE TEST_DEFINE(PROG_SIZE_i)
@@ -103,6 +104,7 @@ intmax_t test_define(size_t define);
#define ERASE_CYCLES TEST_DEFINE(ERASE_CYCLES_i) #define ERASE_CYCLES TEST_DEFINE(ERASE_CYCLES_i)
#define BADBLOCK_BEHAVIOR TEST_DEFINE(BADBLOCK_BEHAVIOR_i) #define BADBLOCK_BEHAVIOR TEST_DEFINE(BADBLOCK_BEHAVIOR_i)
#define POWERLOSS_BEHAVIOR TEST_DEFINE(POWERLOSS_BEHAVIOR_i) #define POWERLOSS_BEHAVIOR TEST_DEFINE(POWERLOSS_BEHAVIOR_i)
#define DISK_VERSION TEST_DEFINE(DISK_VERSION_i)
#define TEST_IMPLICIT_DEFINES \ #define TEST_IMPLICIT_DEFINES \
TEST_DEF(READ_SIZE, PROG_SIZE) \ TEST_DEF(READ_SIZE, PROG_SIZE) \
@@ -115,9 +117,10 @@ intmax_t test_define(size_t define);
TEST_DEF(ERASE_VALUE, 0xff) \ TEST_DEF(ERASE_VALUE, 0xff) \
TEST_DEF(ERASE_CYCLES, 0) \ TEST_DEF(ERASE_CYCLES, 0) \
TEST_DEF(BADBLOCK_BEHAVIOR, LFS2_EMUBD_BADBLOCK_PROGERROR) \ TEST_DEF(BADBLOCK_BEHAVIOR, LFS2_EMUBD_BADBLOCK_PROGERROR) \
TEST_DEF(POWERLOSS_BEHAVIOR, LFS2_EMUBD_POWERLOSS_NOOP) TEST_DEF(POWERLOSS_BEHAVIOR, LFS2_EMUBD_POWERLOSS_NOOP) \
TEST_DEF(DISK_VERSION, 0)
#define TEST_IMPLICIT_DEFINE_COUNT 11 #define TEST_IMPLICIT_DEFINE_COUNT 12
#define TEST_GEOMETRY_DEFINE_COUNT 4 #define TEST_GEOMETRY_DEFINE_COUNT 4
+129 -36
View File
@@ -22,14 +22,16 @@ code = '''
#define STRINGIZE_(x) #x #define STRINGIZE_(x) #x
#include STRINGIZE(LFS2P) #include STRINGIZE(LFS2P)
#else #else
#define LFS2P_VERSION LFS2_VERSION #define LFS2P_DISK_VERSION LFS2_DISK_VERSION
#define LFS2P_VERSION_MAJOR LFS2_VERSION_MAJOR #define LFS2P_DISK_VERSION_MAJOR LFS2_DISK_VERSION_MAJOR
#define LFS2P_VERSION_MINOR LFS2_VERSION_MINOR #define LFS2P_DISK_VERSION_MINOR LFS2_DISK_VERSION_MINOR
#define lfs2p_t lfs2_t #define lfs2p_t lfs2_t
#define lfs2p_config lfs2_config #define lfs2p_config lfs2_config
#define lfs2p_format lfs2_format #define lfs2p_format lfs2_format
#define lfs2p_mount lfs2_mount #define lfs2p_mount lfs2_mount
#define lfs2p_unmount lfs2_unmount #define lfs2p_unmount lfs2_unmount
#define lfs2p_fsinfo lfs2_fsinfo
#define lfs2p_fs_stat lfs2_fs_stat
#define lfs2p_dir_t lfs2_dir_t #define lfs2p_dir_t lfs2_dir_t
#define lfs2p_info lfs2_info #define lfs2p_info lfs2_info
#define LFS2P_TYPE_REG LFS2_TYPE_REG #define LFS2P_TYPE_REG LFS2_TYPE_REG
@@ -58,7 +60,10 @@ code = '''
# test we can mount in a new version # test we can mount in a new version
[cases.test_compat_forward_mount] [cases.test_compat_forward_mount]
if = 'LFS2_VERSION_MAJOR == LFS2P_VERSION_MAJOR' if = '''
LFS2_DISK_VERSION_MAJOR == LFS2P_DISK_VERSION_MAJOR
&& DISK_VERSION == 0
'''
code = ''' code = '''
// create the previous version // create the previous version
struct lfs2p_config cfgp; struct lfs2p_config cfgp;
@@ -74,13 +79,22 @@ code = '''
// now test the new mount // now test the new mount
lfs2_t lfs2; lfs2_t lfs2;
lfs2_mount(&lfs2, cfg) => 0; lfs2_mount(&lfs2, cfg) => 0;
// we should be able to read the version using lfs2_fs_stat
struct lfs2_fsinfo fsinfo;
lfs2_fs_stat(&lfs2, &fsinfo) => 0;
assert(fsinfo.disk_version == LFS2P_DISK_VERSION);
lfs2_unmount(&lfs2) => 0; lfs2_unmount(&lfs2) => 0;
''' '''
# test we can read dirs in a new version # test we can read dirs in a new version
[cases.test_compat_forward_read_dirs] [cases.test_compat_forward_read_dirs]
defines.COUNT = 5 defines.COUNT = 5
if = 'LFS2_VERSION_MAJOR == LFS2P_VERSION_MAJOR' if = '''
LFS2_DISK_VERSION_MAJOR == LFS2P_DISK_VERSION_MAJOR
&& DISK_VERSION == 0
'''
code = ''' code = '''
// create the previous version // create the previous version
struct lfs2p_config cfgp; struct lfs2p_config cfgp;
@@ -102,6 +116,11 @@ code = '''
lfs2_t lfs2; lfs2_t lfs2;
lfs2_mount(&lfs2, cfg) => 0; lfs2_mount(&lfs2, cfg) => 0;
// we should be able to read the version using lfs2_fs_stat
struct lfs2_fsinfo fsinfo;
lfs2_fs_stat(&lfs2, &fsinfo) => 0;
assert(fsinfo.disk_version == LFS2P_DISK_VERSION);
// can we list the directories? // can we list the directories?
lfs2_dir_t dir; lfs2_dir_t dir;
lfs2_dir_open(&lfs2, &dir, "/") => 0; lfs2_dir_open(&lfs2, &dir, "/") => 0;
@@ -132,7 +151,10 @@ code = '''
defines.COUNT = 5 defines.COUNT = 5
defines.SIZE = [4, 32, 512, 8192] defines.SIZE = [4, 32, 512, 8192]
defines.CHUNK = 4 defines.CHUNK = 4
if = 'LFS2_VERSION_MAJOR == LFS2P_VERSION_MAJOR' if = '''
LFS2_DISK_VERSION_MAJOR == LFS2P_DISK_VERSION_MAJOR
&& DISK_VERSION == 0
'''
code = ''' code = '''
// create the previous version // create the previous version
struct lfs2p_config cfgp; struct lfs2p_config cfgp;
@@ -166,6 +188,11 @@ code = '''
lfs2_t lfs2; lfs2_t lfs2;
lfs2_mount(&lfs2, cfg) => 0; lfs2_mount(&lfs2, cfg) => 0;
// we should be able to read the version using lfs2_fs_stat
struct lfs2_fsinfo fsinfo;
lfs2_fs_stat(&lfs2, &fsinfo) => 0;
assert(fsinfo.disk_version == LFS2P_DISK_VERSION);
// can we list the files? // can we list the files?
lfs2_dir_t dir; lfs2_dir_t dir;
lfs2_dir_open(&lfs2, &dir, "/") => 0; lfs2_dir_open(&lfs2, &dir, "/") => 0;
@@ -214,7 +241,10 @@ code = '''
defines.COUNT = 5 defines.COUNT = 5
defines.SIZE = [4, 32, 512, 8192] defines.SIZE = [4, 32, 512, 8192]
defines.CHUNK = 4 defines.CHUNK = 4
if = 'LFS2_VERSION_MAJOR == LFS2P_VERSION_MAJOR' if = '''
LFS2_DISK_VERSION_MAJOR == LFS2P_DISK_VERSION_MAJOR
&& DISK_VERSION == 0
'''
code = ''' code = '''
// create the previous version // create the previous version
struct lfs2p_config cfgp; struct lfs2p_config cfgp;
@@ -251,6 +281,11 @@ code = '''
lfs2_t lfs2; lfs2_t lfs2;
lfs2_mount(&lfs2, cfg) => 0; lfs2_mount(&lfs2, cfg) => 0;
// we should be able to read the version using lfs2_fs_stat
struct lfs2_fsinfo fsinfo;
lfs2_fs_stat(&lfs2, &fsinfo) => 0;
assert(fsinfo.disk_version == LFS2P_DISK_VERSION);
// can we list the directories? // can we list the directories?
lfs2_dir_t dir; lfs2_dir_t dir;
lfs2_dir_open(&lfs2, &dir, "/") => 0; lfs2_dir_open(&lfs2, &dir, "/") => 0;
@@ -321,7 +356,10 @@ code = '''
# test we can write dirs in a new version # test we can write dirs in a new version
[cases.test_compat_forward_write_dirs] [cases.test_compat_forward_write_dirs]
defines.COUNT = 10 defines.COUNT = 10
if = 'LFS2_VERSION_MAJOR == LFS2P_VERSION_MAJOR' if = '''
LFS2_DISK_VERSION_MAJOR == LFS2P_DISK_VERSION_MAJOR
&& DISK_VERSION == 0
'''
code = ''' code = '''
// create the previous version // create the previous version
struct lfs2p_config cfgp; struct lfs2p_config cfgp;
@@ -343,6 +381,11 @@ code = '''
lfs2_t lfs2; lfs2_t lfs2;
lfs2_mount(&lfs2, cfg) => 0; lfs2_mount(&lfs2, cfg) => 0;
// we should be able to read the version using lfs2_fs_stat
struct lfs2_fsinfo fsinfo;
lfs2_fs_stat(&lfs2, &fsinfo) => 0;
assert(fsinfo.disk_version == LFS2P_DISK_VERSION);
// write another COUNT/2 dirs // write another COUNT/2 dirs
for (lfs2_size_t i = COUNT/2; i < COUNT; i++) { for (lfs2_size_t i = COUNT/2; i < COUNT; i++) {
char name[8]; char name[8];
@@ -380,7 +423,10 @@ code = '''
defines.COUNT = 5 defines.COUNT = 5
defines.SIZE = [4, 32, 512, 8192] defines.SIZE = [4, 32, 512, 8192]
defines.CHUNK = 2 defines.CHUNK = 2
if = 'LFS2_VERSION_MAJOR == LFS2P_VERSION_MAJOR' if = '''
LFS2_DISK_VERSION_MAJOR == LFS2P_DISK_VERSION_MAJOR
&& DISK_VERSION == 0
'''
code = ''' code = '''
// create the previous version // create the previous version
struct lfs2p_config cfgp; struct lfs2p_config cfgp;
@@ -420,6 +466,11 @@ code = '''
lfs2_t lfs2; lfs2_t lfs2;
lfs2_mount(&lfs2, cfg) => 0; lfs2_mount(&lfs2, cfg) => 0;
// we should be able to read the version using lfs2_fs_stat
struct lfs2_fsinfo fsinfo;
lfs2_fs_stat(&lfs2, &fsinfo) => 0;
assert(fsinfo.disk_version == LFS2P_DISK_VERSION);
// write half COUNT files // write half COUNT files
prng = 42; prng = 42;
for (lfs2_size_t i = 0; i < COUNT; i++) { for (lfs2_size_t i = 0; i < COUNT; i++) {
@@ -494,7 +545,10 @@ code = '''
defines.COUNT = 5 defines.COUNT = 5
defines.SIZE = [4, 32, 512, 8192] defines.SIZE = [4, 32, 512, 8192]
defines.CHUNK = 2 defines.CHUNK = 2
if = 'LFS2_VERSION_MAJOR == LFS2P_VERSION_MAJOR' if = '''
LFS2_DISK_VERSION_MAJOR == LFS2P_DISK_VERSION_MAJOR
&& DISK_VERSION == 0
'''
code = ''' code = '''
// create the previous version // create the previous version
struct lfs2p_config cfgp; struct lfs2p_config cfgp;
@@ -537,6 +591,11 @@ code = '''
lfs2_t lfs2; lfs2_t lfs2;
lfs2_mount(&lfs2, cfg) => 0; lfs2_mount(&lfs2, cfg) => 0;
// we should be able to read the version using lfs2_fs_stat
struct lfs2_fsinfo fsinfo;
lfs2_fs_stat(&lfs2, &fsinfo) => 0;
assert(fsinfo.disk_version == LFS2P_DISK_VERSION);
// write half COUNT files // write half COUNT files
prng = 42; prng = 42;
for (lfs2_size_t i = 0; i < COUNT; i++) { for (lfs2_size_t i = 0; i < COUNT; i++) {
@@ -636,7 +695,10 @@ code = '''
# test we can mount in an old version # test we can mount in an old version
[cases.test_compat_backward_mount] [cases.test_compat_backward_mount]
if = 'LFS2_VERSION == LFS2P_VERSION' if = '''
LFS2_DISK_VERSION == LFS2P_DISK_VERSION
&& DISK_VERSION == 0
'''
code = ''' code = '''
// create the new version // create the new version
lfs2_t lfs2; lfs2_t lfs2;
@@ -651,13 +713,17 @@ code = '''
memcpy(&cfgp, cfg, sizeof(cfgp)); memcpy(&cfgp, cfg, sizeof(cfgp));
lfs2p_t lfs2p; lfs2p_t lfs2p;
lfs2p_mount(&lfs2p, &cfgp) => 0; lfs2p_mount(&lfs2p, &cfgp) => 0;
lfs2p_unmount(&lfs2p) => 0; lfs2p_unmount(&lfs2p) => 0;
''' '''
# test we can read dirs in an old version # test we can read dirs in an old version
[cases.test_compat_backward_read_dirs] [cases.test_compat_backward_read_dirs]
defines.COUNT = 5 defines.COUNT = 5
if = 'LFS2_VERSION == LFS2P_VERSION' if = '''
LFS2_DISK_VERSION == LFS2P_DISK_VERSION
&& DISK_VERSION == 0
'''
code = ''' code = '''
// create the new version // create the new version
lfs2_t lfs2; lfs2_t lfs2;
@@ -709,7 +775,10 @@ code = '''
defines.COUNT = 5 defines.COUNT = 5
defines.SIZE = [4, 32, 512, 8192] defines.SIZE = [4, 32, 512, 8192]
defines.CHUNK = 4 defines.CHUNK = 4
if = 'LFS2_VERSION == LFS2P_VERSION' if = '''
LFS2_DISK_VERSION == LFS2P_DISK_VERSION
&& DISK_VERSION == 0
'''
code = ''' code = '''
// create the new version // create the new version
lfs2_t lfs2; lfs2_t lfs2;
@@ -791,7 +860,10 @@ code = '''
defines.COUNT = 5 defines.COUNT = 5
defines.SIZE = [4, 32, 512, 8192] defines.SIZE = [4, 32, 512, 8192]
defines.CHUNK = 4 defines.CHUNK = 4
if = 'LFS2_VERSION == LFS2P_VERSION' if = '''
LFS2_DISK_VERSION == LFS2P_DISK_VERSION
&& DISK_VERSION == 0
'''
code = ''' code = '''
// create the new version // create the new version
lfs2_t lfs2; lfs2_t lfs2;
@@ -898,7 +970,10 @@ code = '''
# test we can write dirs in an old version # test we can write dirs in an old version
[cases.test_compat_backward_write_dirs] [cases.test_compat_backward_write_dirs]
defines.COUNT = 10 defines.COUNT = 10
if = 'LFS2_VERSION == LFS2P_VERSION' if = '''
LFS2_DISK_VERSION == LFS2P_DISK_VERSION
&& DISK_VERSION == 0
'''
code = ''' code = '''
// create the new version // create the new version
lfs2_t lfs2; lfs2_t lfs2;
@@ -957,7 +1032,10 @@ code = '''
defines.COUNT = 5 defines.COUNT = 5
defines.SIZE = [4, 32, 512, 8192] defines.SIZE = [4, 32, 512, 8192]
defines.CHUNK = 2 defines.CHUNK = 2
if = 'LFS2_VERSION == LFS2P_VERSION' if = '''
LFS2_DISK_VERSION == LFS2P_DISK_VERSION
&& DISK_VERSION == 0
'''
code = ''' code = '''
// create the previous version // create the previous version
lfs2_t lfs2; lfs2_t lfs2;
@@ -1071,7 +1149,10 @@ code = '''
defines.COUNT = 5 defines.COUNT = 5
defines.SIZE = [4, 32, 512, 8192] defines.SIZE = [4, 32, 512, 8192]
defines.CHUNK = 2 defines.CHUNK = 2
if = 'LFS2_VERSION == LFS2P_VERSION' if = '''
LFS2_DISK_VERSION == LFS2P_DISK_VERSION
&& DISK_VERSION == 0
'''
code = ''' code = '''
// create the previous version // create the previous version
lfs2_t lfs2; lfs2_t lfs2;
@@ -1280,7 +1361,10 @@ code = '''
# test that we correctly bump the minor version # test that we correctly bump the minor version
[cases.test_compat_minor_bump] [cases.test_compat_minor_bump]
in = 'lfs2.c' in = 'lfs2.c'
if = 'LFS2_DISK_VERSION_MINOR > 0' if = '''
LFS2_DISK_VERSION_MINOR > 0
&& DISK_VERSION == 0
'''
code = ''' code = '''
// create a superblock // create a superblock
lfs2_t lfs2; lfs2_t lfs2;
@@ -1316,45 +1400,54 @@ code = '''
// mount should still work // mount should still work
lfs2_mount(&lfs2, cfg) => 0; lfs2_mount(&lfs2, cfg) => 0;
struct lfs2_fsinfo fsinfo;
lfs2_fs_stat(&lfs2, &fsinfo) => 0;
assert(fsinfo.disk_version == LFS2_DISK_VERSION-1);
lfs2_file_open(&lfs2, &file, "test", LFS2_O_RDONLY) => 0; lfs2_file_open(&lfs2, &file, "test", LFS2_O_RDONLY) => 0;
uint8_t buffer[8]; uint8_t buffer[8];
lfs2_file_read(&lfs2, &file, buffer, 8) => 8; lfs2_file_read(&lfs2, &file, buffer, 8) => 8;
assert(memcmp(buffer, "testtest", 8) == 0); assert(memcmp(buffer, "testtest", 8) == 0);
lfs2_file_close(&lfs2, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
// minor version should be unchanged
lfs2_fs_stat(&lfs2, &fsinfo) => 0;
assert(fsinfo.disk_version == LFS2_DISK_VERSION-1);
lfs2_unmount(&lfs2) => 0; lfs2_unmount(&lfs2) => 0;
// if we write, we need to bump the minor version // if we write, we need to bump the minor version
lfs2_mount(&lfs2, cfg) => 0; lfs2_mount(&lfs2, cfg) => 0;
lfs2_fs_stat(&lfs2, &fsinfo) => 0;
assert(fsinfo.disk_version == LFS2_DISK_VERSION-1);
lfs2_file_open(&lfs2, &file, "test", LFS2_O_WRONLY | LFS2_O_TRUNC) => 0; lfs2_file_open(&lfs2, &file, "test", LFS2_O_WRONLY | LFS2_O_TRUNC) => 0;
lfs2_file_write(&lfs2, &file, "teeeeest", 8) => 8; lfs2_file_write(&lfs2, &file, "teeeeest", 8) => 8;
lfs2_file_close(&lfs2, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
// minor version should have changed // minor version should be changed
lfs2_dir_fetch(&lfs2, &mdir, (lfs2_block_t[2]){0, 1}) => 0; lfs2_fs_stat(&lfs2, &fsinfo) => 0;
lfs2_dir_get(&lfs2, &mdir, LFS2_MKTAG(0x7ff, 0x3ff, 0), assert(fsinfo.disk_version == LFS2_DISK_VERSION);
LFS2_MKTAG(LFS2_TYPE_INLINESTRUCT, 0, sizeof(superblock)),
&superblock)
=> LFS2_MKTAG(LFS2_TYPE_INLINESTRUCT, 0, sizeof(superblock));
lfs2_superblock_fromle32(&superblock);
assert((superblock.version >> 16) & 0xffff == LFS2_DISK_VERSION_MAJOR);
assert((superblock.version >> 0) & 0xffff == LFS2_DISK_VERSION_MINOR);
lfs2_unmount(&lfs2) => 0; lfs2_unmount(&lfs2) => 0;
// and of course mount should still work // and of course mount should still work
lfs2_mount(&lfs2, cfg) => 0; lfs2_mount(&lfs2, cfg) => 0;
// minor version should have changed
lfs2_fs_stat(&lfs2, &fsinfo) => 0;
assert(fsinfo.disk_version == LFS2_DISK_VERSION);
lfs2_file_open(&lfs2, &file, "test", LFS2_O_RDONLY) => 0; lfs2_file_open(&lfs2, &file, "test", LFS2_O_RDONLY) => 0;
lfs2_file_read(&lfs2, &file, buffer, 8) => 8; lfs2_file_read(&lfs2, &file, buffer, 8) => 8;
assert(memcmp(buffer, "teeeeest", 8) == 0); assert(memcmp(buffer, "teeeeest", 8) == 0);
lfs2_file_close(&lfs2, &file) => 0; lfs2_file_close(&lfs2, &file) => 0;
// minor version should have changed // yep, still changed
lfs2_dir_fetch(&lfs2, &mdir, (lfs2_block_t[2]){0, 1}) => 0; lfs2_fs_stat(&lfs2, &fsinfo) => 0;
lfs2_dir_get(&lfs2, &mdir, LFS2_MKTAG(0x7ff, 0x3ff, 0), assert(fsinfo.disk_version == LFS2_DISK_VERSION);
LFS2_MKTAG(LFS2_TYPE_INLINESTRUCT, 0, sizeof(superblock)),
&superblock)
=> LFS2_MKTAG(LFS2_TYPE_INLINESTRUCT, 0, sizeof(superblock));
lfs2_superblock_fromle32(&superblock);
assert((superblock.version >> 16) & 0xffff == LFS2_DISK_VERSION_MAJOR);
assert((superblock.version >> 0) & 0xffff == LFS2_DISK_VERSION_MINOR);
lfs2_unmount(&lfs2) => 0; lfs2_unmount(&lfs2) => 0;
''' '''
+4 -1
View File
@@ -90,7 +90,10 @@ code = '''
# partial prog, may not be byte in order! # partial prog, may not be byte in order!
[cases.test_powerloss_partial_prog] [cases.test_powerloss_partial_prog]
if = "PROG_SIZE < BLOCK_SIZE" if = '''
PROG_SIZE < BLOCK_SIZE
&& (DISK_VERSION == 0 || DISK_VERSION >= 0x00020001)
'''
defines.BYTE_OFF = ["0", "PROG_SIZE-1", "PROG_SIZE/2"] defines.BYTE_OFF = ["0", "PROG_SIZE-1", "PROG_SIZE/2"]
defines.BYTE_VALUE = [0x33, 0xcc] defines.BYTE_VALUE = [0x33, 0xcc]
in = "lfs2.c" in = "lfs2.c"
+48
View File
@@ -34,6 +34,54 @@ code = '''
lfs2_mount(&lfs2, cfg) => LFS2_ERR_CORRUPT; lfs2_mount(&lfs2, cfg) => LFS2_ERR_CORRUPT;
''' '''
# test we can read superblock info through lfs2_fs_stat
[cases.test_superblocks_stat]
if = 'DISK_VERSION == 0'
code = '''
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
// test we can mount and read fsinfo
lfs2_mount(&lfs2, cfg) => 0;
struct lfs2_fsinfo fsinfo;
lfs2_fs_stat(&lfs2, &fsinfo) => 0;
assert(fsinfo.disk_version == LFS2_DISK_VERSION);
assert(fsinfo.name_max == LFS2_NAME_MAX);
assert(fsinfo.file_max == LFS2_FILE_MAX);
assert(fsinfo.attr_max == LFS2_ATTR_MAX);
lfs2_unmount(&lfs2) => 0;
'''
[cases.test_superblocks_stat_tweaked]
if = 'DISK_VERSION == 0'
defines.TWEAKED_NAME_MAX = 63
defines.TWEAKED_FILE_MAX = '(1 << 16)-1'
defines.TWEAKED_ATTR_MAX = 512
code = '''
// create filesystem with tweaked params
struct lfs2_config tweaked_cfg = *cfg;
tweaked_cfg.name_max = TWEAKED_NAME_MAX;
tweaked_cfg.file_max = TWEAKED_FILE_MAX;
tweaked_cfg.attr_max = TWEAKED_ATTR_MAX;
lfs2_t lfs2;
lfs2_format(&lfs2, &tweaked_cfg) => 0;
// test we can mount and read these params with the original config
lfs2_mount(&lfs2, cfg) => 0;
struct lfs2_fsinfo fsinfo;
lfs2_fs_stat(&lfs2, &fsinfo) => 0;
assert(fsinfo.disk_version == LFS2_DISK_VERSION);
assert(fsinfo.name_max == TWEAKED_NAME_MAX);
assert(fsinfo.file_max == TWEAKED_FILE_MAX);
assert(fsinfo.attr_max == TWEAKED_ATTR_MAX);
lfs2_unmount(&lfs2) => 0;
'''
# expanding superblock # expanding superblock
[cases.test_superblocks_expand] [cases.test_superblocks_expand]
defines.BLOCK_CYCLES = [32, 33, 1] defines.BLOCK_CYCLES = [32, 33, 1]