Generated v2 prefixes
This commit is contained in:
@@ -102,7 +102,7 @@ jobs:
|
||||
# sizes table
|
||||
i=0
|
||||
j=0
|
||||
for c in "" readonly threadsafe migrate error-asserts
|
||||
for c in "" readonly threadsafe multiversion migrate error-asserts
|
||||
do
|
||||
# per-config results
|
||||
c_or_default=${c:-default}
|
||||
|
||||
@@ -170,6 +170,27 @@ jobs:
|
||||
cp lfs2.data.csv sizes/${{matrix.arch}}-threadsafe.data.csv
|
||||
cp lfs2.stack.csv sizes/${{matrix.arch}}-threadsafe.stack.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
|
||||
run: |
|
||||
make clean
|
||||
@@ -353,6 +374,42 @@ jobs:
|
||||
run: |
|
||||
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
|
||||
test-valgrind:
|
||||
runs-on: ubuntu-22.04
|
||||
@@ -371,7 +428,8 @@ jobs:
|
||||
# on one geometry
|
||||
- name: test-valgrind
|
||||
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
|
||||
# run with Clang, mostly to check for Clang-specific warnings
|
||||
@@ -684,7 +742,7 @@ jobs:
|
||||
# sizes table
|
||||
i=0
|
||||
j=0
|
||||
for c in "" readonly threadsafe migrate error-asserts
|
||||
for c in "" readonly threadsafe multiversion migrate error-asserts
|
||||
do
|
||||
# per-config results
|
||||
c_or_default=${c:-default}
|
||||
|
||||
@@ -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
|
||||
_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
|
||||
use with the MirageOS library operating system project. It is interoperable
|
||||
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
|
||||
[SPIFFS]: https://github.com/pellepl/spiffs
|
||||
[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/
|
||||
[littlefs2-rust]: https://crates.io/crates/littlefs2
|
||||
[chamelon]: https://github.com/yomimono/chamelon
|
||||
|
||||
@@ -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) {
|
||||
return lfs2_tag_type1(a->tag);
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline bool lfs2_gstate_needssuperblock(const lfs2_gstate_t *a) {
|
||||
return lfs2_tag_size(a->tag) >> 9;
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline bool lfs2_gstate_hasmovehere(const lfs2_gstate_t *a,
|
||||
const lfs2_block_t *pair) {
|
||||
@@ -518,6 +518,28 @@ static void lfs2_mlist_append(lfs2_t *lfs2, struct 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 ///
|
||||
#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_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 void lfs2_fs_prepmove(lfs2_t *lfs2,
|
||||
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);
|
||||
#endif
|
||||
|
||||
static void lfs2_fs_prepsuperblock(lfs2_t *lfs2, bool needssuperblock);
|
||||
|
||||
#ifdef LFS2_MIGRATE
|
||||
static int lfs21_traverse(lfs2_t *lfs2,
|
||||
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?
|
||||
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;
|
||||
// out of range?
|
||||
} 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->split = tempsplit;
|
||||
|
||||
// reset crc
|
||||
// reset crc, hasfcrc
|
||||
crc = 0xffffffff;
|
||||
continue;
|
||||
}
|
||||
|
||||
// fcrc is only valid when last tag was a crc
|
||||
hasfcrc = false;
|
||||
|
||||
// crc the entry first, hopefully leaving it in the cache
|
||||
err = lfs2_bd_crc(lfs2,
|
||||
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
|
||||
dir->erased = false;
|
||||
if (maybeerased && hasfcrc && dir->off % lfs2->cfg->prog_size == 0) {
|
||||
// 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;
|
||||
}
|
||||
if (maybeerased && dir->off % lfs2->cfg->prog_size == 0) {
|
||||
#ifdef LFS2_MULTIVERSION
|
||||
// note versions < lfs22.1 did not have fcrc tags, if
|
||||
// we're < lfs22.1 treat missing fcrc as erased data
|
||||
//
|
||||
// we don't strictly need to do this, but otherwise writing
|
||||
// to lfs22.0 disks becomes very inefficient
|
||||
if (lfs2_fs_disk_version(lfs2) < 0x00020001) {
|
||||
dir->erased = true;
|
||||
|
||||
// found beginning of erased part?
|
||||
dir->erased = (fcrc_ == fcrc.crc);
|
||||
} else
|
||||
#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
|
||||
@@ -1605,22 +1639,34 @@ static int lfs2_dir_commitcrc(lfs2_t *lfs2, struct lfs2_commit *commit) {
|
||||
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;
|
||||
}
|
||||
#ifdef LFS2_MULTIVERSION
|
||||
// unfortunately fcrcs break mdir fetching < lfs22.1, so only write
|
||||
// these if we're a >= lfs22.1 filesystem
|
||||
if (lfs2_fs_disk_version(lfs2) <= 0x00020000) {
|
||||
// don't write fcrc
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
// 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);
|
||||
err = lfs2_dir_commitattr(lfs2, commit,
|
||||
LFS2_MKTAG(LFS2_TYPE_FCRC, 0x3ff, sizeof(struct lfs2_fcrc)),
|
||||
&fcrc);
|
||||
if (err) {
|
||||
return err;
|
||||
lfs2_fcrc_tole32(&fcrc);
|
||||
err = lfs2_dir_commitattr(lfs2, commit,
|
||||
LFS2_MKTAG(LFS2_TYPE_FCRC, 0x3ff, sizeof(struct lfs2_fcrc)),
|
||||
&fcrc);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4051,6 +4097,15 @@ static int lfs2_init(lfs2_t *lfs2, const struct lfs2_config *cfg) {
|
||||
lfs2->cfg = cfg;
|
||||
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
|
||||
//
|
||||
// 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
|
||||
lfs2_superblock_t superblock = {
|
||||
.version = LFS2_DISK_VERSION,
|
||||
.version = lfs2_fs_disk_version(lfs2),
|
||||
.block_size = lfs2->cfg->block_size,
|
||||
.block_count = lfs2->cfg->block_count,
|
||||
.name_max = lfs2->name_max,
|
||||
@@ -4306,12 +4361,14 @@ static int lfs2_rawmount(lfs2_t *lfs2, const struct lfs2_config *cfg) {
|
||||
// check version
|
||||
uint16_t major_version = (0xffff & (superblock.version >> 16));
|
||||
uint16_t minor_version = (0xffff & (superblock.version >> 0));
|
||||
if ((major_version != LFS2_DISK_VERSION_MAJOR ||
|
||||
minor_version > LFS2_DISK_VERSION_MINOR)) {
|
||||
if (major_version != lfs2_fs_disk_version_major(lfs2)
|
||||
|| minor_version > lfs2_fs_disk_version_minor(lfs2)) {
|
||||
LFS2_ERROR("Invalid version "
|
||||
"v%"PRIu16".%"PRIu16" != v%"PRIu16".%"PRIu16,
|
||||
major_version, minor_version,
|
||||
LFS2_DISK_VERSION_MAJOR, LFS2_DISK_VERSION_MINOR);
|
||||
major_version,
|
||||
minor_version,
|
||||
lfs2_fs_disk_version_major(lfs2),
|
||||
lfs2_fs_disk_version_minor(lfs2));
|
||||
err = LFS2_ERR_INVAL;
|
||||
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
|
||||
// gstate so we know we need to rewrite the superblock before
|
||||
// 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 "
|
||||
"v%"PRIu16".%"PRIu16" < v%"PRIu16".%"PRIu16,
|
||||
major_version, minor_version,
|
||||
LFS2_DISK_VERSION_MAJOR, LFS2_DISK_VERSION_MINOR);
|
||||
#ifndef LFS2_READONLY
|
||||
major_version,
|
||||
minor_version,
|
||||
lfs2_fs_disk_version_major(lfs2),
|
||||
lfs2_fs_disk_version_minor(lfs2));
|
||||
// note this bit is reserved on disk, so fetching more gstate
|
||||
// will not interfere here
|
||||
lfs2_fs_prepsuperblock(lfs2, true);
|
||||
#endif
|
||||
}
|
||||
|
||||
// check superblock configuration
|
||||
@@ -4421,6 +4478,42 @@ static int lfs2_rawunmount(lfs2_t *lfs2) {
|
||||
|
||||
|
||||
/// 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 (*cb)(void *data, lfs2_block_t block), void *data,
|
||||
bool includeorphans) {
|
||||
@@ -4631,12 +4724,10 @@ static lfs2_stag_t lfs2_fs_parent(lfs2_t *lfs2, const lfs2_block_t pair[2],
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef LFS2_READONLY
|
||||
static void lfs2_fs_prepsuperblock(lfs2_t *lfs2, bool needssuperblock) {
|
||||
lfs2->gstate.tag = (lfs2->gstate.tag & ~LFS2_MKTAG(0, 0, 0x200))
|
||||
| (uint32_t)needssuperblock << 9;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef LFS2_READONLY
|
||||
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
|
||||
lfs2_superblock_t superblock = {
|
||||
.version = LFS2_DISK_VERSION,
|
||||
.version = lfs2_fs_disk_version(lfs2),
|
||||
.block_size = lfs2->cfg->block_size,
|
||||
.block_count = lfs2->cfg->block_count,
|
||||
.name_max = lfs2->name_max,
|
||||
@@ -4934,6 +5025,7 @@ static lfs2_ssize_t lfs2_fs_rawsize(lfs2_t *lfs2) {
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
#ifdef LFS2_MIGRATE
|
||||
////// Migration from littelfs v1 below this //////
|
||||
|
||||
@@ -6053,6 +6145,20 @@ int lfs2_dir_rewind(lfs2_t *lfs2, lfs2_dir_t *dir) {
|
||||
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) {
|
||||
int err = LFS2_LOCK(lfs2->cfg);
|
||||
if (err) {
|
||||
|
||||
@@ -21,7 +21,7 @@ extern "C"
|
||||
// Software library version
|
||||
// Major (top-nibble), incremented on backwards incompatible changes
|
||||
// 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_MINOR (0xffff & (LFS2_VERSION >> 0))
|
||||
|
||||
@@ -263,6 +263,14 @@ struct lfs2_config {
|
||||
// can help bound the metadata compaction time. Must be <= block_size.
|
||||
// Defaults to block_size when zero.
|
||||
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
|
||||
@@ -280,6 +288,21 @@ struct lfs2_info {
|
||||
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
|
||||
// committed atomically during file writes.
|
||||
struct lfs2_attr {
|
||||
@@ -659,6 +682,12 @@ int lfs2_dir_rewind(lfs2_t *lfs2, lfs2_dir_t *dir);
|
||||
|
||||
/// 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
|
||||
//
|
||||
// Note: Result is best effort. If files share COW structures, the returned
|
||||
|
||||
@@ -1346,6 +1346,9 @@ static void run_powerloss_none(
|
||||
.block_cycles = BLOCK_CYCLES,
|
||||
.cache_size = CACHE_SIZE,
|
||||
.lookahead_size = LOOKAHEAD_SIZE,
|
||||
#ifdef LFS2_MULTIVERSION
|
||||
.disk_version = DISK_VERSION,
|
||||
#endif
|
||||
};
|
||||
|
||||
struct lfs2_emubd_config bdcfg = {
|
||||
@@ -1415,6 +1418,9 @@ static void run_powerloss_linear(
|
||||
.block_cycles = BLOCK_CYCLES,
|
||||
.cache_size = CACHE_SIZE,
|
||||
.lookahead_size = LOOKAHEAD_SIZE,
|
||||
#ifdef LFS2_MULTIVERSION
|
||||
.disk_version = DISK_VERSION,
|
||||
#endif
|
||||
};
|
||||
|
||||
struct lfs2_emubd_config bdcfg = {
|
||||
@@ -1501,6 +1507,9 @@ static void run_powerloss_log(
|
||||
.block_cycles = BLOCK_CYCLES,
|
||||
.cache_size = CACHE_SIZE,
|
||||
.lookahead_size = LOOKAHEAD_SIZE,
|
||||
#ifdef LFS2_MULTIVERSION
|
||||
.disk_version = DISK_VERSION,
|
||||
#endif
|
||||
};
|
||||
|
||||
struct lfs2_emubd_config bdcfg = {
|
||||
@@ -1585,6 +1594,9 @@ static void run_powerloss_cycles(
|
||||
.block_cycles = BLOCK_CYCLES,
|
||||
.cache_size = CACHE_SIZE,
|
||||
.lookahead_size = LOOKAHEAD_SIZE,
|
||||
#ifdef LFS2_MULTIVERSION
|
||||
.disk_version = DISK_VERSION,
|
||||
#endif
|
||||
};
|
||||
|
||||
struct lfs2_emubd_config bdcfg = {
|
||||
@@ -1767,6 +1779,9 @@ static void run_powerloss_exhaustive(
|
||||
.block_cycles = BLOCK_CYCLES,
|
||||
.cache_size = CACHE_SIZE,
|
||||
.lookahead_size = LOOKAHEAD_SIZE,
|
||||
#ifdef LFS2_MULTIVERSION
|
||||
.disk_version = DISK_VERSION,
|
||||
#endif
|
||||
};
|
||||
|
||||
struct lfs2_emubd_config bdcfg = {
|
||||
|
||||
@@ -91,6 +91,7 @@ intmax_t test_define(size_t define);
|
||||
#define ERASE_CYCLES_i 8
|
||||
#define BADBLOCK_BEHAVIOR_i 9
|
||||
#define POWERLOSS_BEHAVIOR_i 10
|
||||
#define DISK_VERSION_i 11
|
||||
|
||||
#define READ_SIZE TEST_DEFINE(READ_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 BADBLOCK_BEHAVIOR TEST_DEFINE(BADBLOCK_BEHAVIOR_i)
|
||||
#define POWERLOSS_BEHAVIOR TEST_DEFINE(POWERLOSS_BEHAVIOR_i)
|
||||
#define DISK_VERSION TEST_DEFINE(DISK_VERSION_i)
|
||||
|
||||
#define TEST_IMPLICIT_DEFINES \
|
||||
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_CYCLES, 0) \
|
||||
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
|
||||
|
||||
|
||||
|
||||
+129
-36
@@ -22,14 +22,16 @@ code = '''
|
||||
#define STRINGIZE_(x) #x
|
||||
#include STRINGIZE(LFS2P)
|
||||
#else
|
||||
#define LFS2P_VERSION LFS2_VERSION
|
||||
#define LFS2P_VERSION_MAJOR LFS2_VERSION_MAJOR
|
||||
#define LFS2P_VERSION_MINOR LFS2_VERSION_MINOR
|
||||
#define LFS2P_DISK_VERSION LFS2_DISK_VERSION
|
||||
#define LFS2P_DISK_VERSION_MAJOR LFS2_DISK_VERSION_MAJOR
|
||||
#define LFS2P_DISK_VERSION_MINOR LFS2_DISK_VERSION_MINOR
|
||||
#define lfs2p_t lfs2_t
|
||||
#define lfs2p_config lfs2_config
|
||||
#define lfs2p_format lfs2_format
|
||||
#define lfs2p_mount lfs2_mount
|
||||
#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_info lfs2_info
|
||||
#define LFS2P_TYPE_REG LFS2_TYPE_REG
|
||||
@@ -58,7 +60,10 @@ code = '''
|
||||
|
||||
# test we can mount in a new version
|
||||
[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 = '''
|
||||
// create the previous version
|
||||
struct lfs2p_config cfgp;
|
||||
@@ -74,13 +79,22 @@ code = '''
|
||||
// now test the new mount
|
||||
lfs2_t lfs2;
|
||||
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;
|
||||
'''
|
||||
|
||||
# test we can read dirs in a new version
|
||||
[cases.test_compat_forward_read_dirs]
|
||||
defines.COUNT = 5
|
||||
if = 'LFS2_VERSION_MAJOR == LFS2P_VERSION_MAJOR'
|
||||
if = '''
|
||||
LFS2_DISK_VERSION_MAJOR == LFS2P_DISK_VERSION_MAJOR
|
||||
&& DISK_VERSION == 0
|
||||
'''
|
||||
code = '''
|
||||
// create the previous version
|
||||
struct lfs2p_config cfgp;
|
||||
@@ -102,6 +116,11 @@ code = '''
|
||||
lfs2_t lfs2;
|
||||
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?
|
||||
lfs2_dir_t dir;
|
||||
lfs2_dir_open(&lfs2, &dir, "/") => 0;
|
||||
@@ -132,7 +151,10 @@ code = '''
|
||||
defines.COUNT = 5
|
||||
defines.SIZE = [4, 32, 512, 8192]
|
||||
defines.CHUNK = 4
|
||||
if = 'LFS2_VERSION_MAJOR == LFS2P_VERSION_MAJOR'
|
||||
if = '''
|
||||
LFS2_DISK_VERSION_MAJOR == LFS2P_DISK_VERSION_MAJOR
|
||||
&& DISK_VERSION == 0
|
||||
'''
|
||||
code = '''
|
||||
// create the previous version
|
||||
struct lfs2p_config cfgp;
|
||||
@@ -166,6 +188,11 @@ code = '''
|
||||
lfs2_t lfs2;
|
||||
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?
|
||||
lfs2_dir_t dir;
|
||||
lfs2_dir_open(&lfs2, &dir, "/") => 0;
|
||||
@@ -214,7 +241,10 @@ code = '''
|
||||
defines.COUNT = 5
|
||||
defines.SIZE = [4, 32, 512, 8192]
|
||||
defines.CHUNK = 4
|
||||
if = 'LFS2_VERSION_MAJOR == LFS2P_VERSION_MAJOR'
|
||||
if = '''
|
||||
LFS2_DISK_VERSION_MAJOR == LFS2P_DISK_VERSION_MAJOR
|
||||
&& DISK_VERSION == 0
|
||||
'''
|
||||
code = '''
|
||||
// create the previous version
|
||||
struct lfs2p_config cfgp;
|
||||
@@ -251,6 +281,11 @@ code = '''
|
||||
lfs2_t lfs2;
|
||||
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?
|
||||
lfs2_dir_t dir;
|
||||
lfs2_dir_open(&lfs2, &dir, "/") => 0;
|
||||
@@ -321,7 +356,10 @@ code = '''
|
||||
# test we can write dirs in a new version
|
||||
[cases.test_compat_forward_write_dirs]
|
||||
defines.COUNT = 10
|
||||
if = 'LFS2_VERSION_MAJOR == LFS2P_VERSION_MAJOR'
|
||||
if = '''
|
||||
LFS2_DISK_VERSION_MAJOR == LFS2P_DISK_VERSION_MAJOR
|
||||
&& DISK_VERSION == 0
|
||||
'''
|
||||
code = '''
|
||||
// create the previous version
|
||||
struct lfs2p_config cfgp;
|
||||
@@ -343,6 +381,11 @@ code = '''
|
||||
lfs2_t lfs2;
|
||||
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
|
||||
for (lfs2_size_t i = COUNT/2; i < COUNT; i++) {
|
||||
char name[8];
|
||||
@@ -380,7 +423,10 @@ code = '''
|
||||
defines.COUNT = 5
|
||||
defines.SIZE = [4, 32, 512, 8192]
|
||||
defines.CHUNK = 2
|
||||
if = 'LFS2_VERSION_MAJOR == LFS2P_VERSION_MAJOR'
|
||||
if = '''
|
||||
LFS2_DISK_VERSION_MAJOR == LFS2P_DISK_VERSION_MAJOR
|
||||
&& DISK_VERSION == 0
|
||||
'''
|
||||
code = '''
|
||||
// create the previous version
|
||||
struct lfs2p_config cfgp;
|
||||
@@ -420,6 +466,11 @@ code = '''
|
||||
lfs2_t lfs2;
|
||||
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
|
||||
prng = 42;
|
||||
for (lfs2_size_t i = 0; i < COUNT; i++) {
|
||||
@@ -494,7 +545,10 @@ code = '''
|
||||
defines.COUNT = 5
|
||||
defines.SIZE = [4, 32, 512, 8192]
|
||||
defines.CHUNK = 2
|
||||
if = 'LFS2_VERSION_MAJOR == LFS2P_VERSION_MAJOR'
|
||||
if = '''
|
||||
LFS2_DISK_VERSION_MAJOR == LFS2P_DISK_VERSION_MAJOR
|
||||
&& DISK_VERSION == 0
|
||||
'''
|
||||
code = '''
|
||||
// create the previous version
|
||||
struct lfs2p_config cfgp;
|
||||
@@ -537,6 +591,11 @@ code = '''
|
||||
lfs2_t lfs2;
|
||||
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
|
||||
prng = 42;
|
||||
for (lfs2_size_t i = 0; i < COUNT; i++) {
|
||||
@@ -636,7 +695,10 @@ code = '''
|
||||
|
||||
# test we can mount in an old version
|
||||
[cases.test_compat_backward_mount]
|
||||
if = 'LFS2_VERSION == LFS2P_VERSION'
|
||||
if = '''
|
||||
LFS2_DISK_VERSION == LFS2P_DISK_VERSION
|
||||
&& DISK_VERSION == 0
|
||||
'''
|
||||
code = '''
|
||||
// create the new version
|
||||
lfs2_t lfs2;
|
||||
@@ -651,13 +713,17 @@ code = '''
|
||||
memcpy(&cfgp, cfg, sizeof(cfgp));
|
||||
lfs2p_t lfs2p;
|
||||
lfs2p_mount(&lfs2p, &cfgp) => 0;
|
||||
|
||||
lfs2p_unmount(&lfs2p) => 0;
|
||||
'''
|
||||
|
||||
# test we can read dirs in an old version
|
||||
[cases.test_compat_backward_read_dirs]
|
||||
defines.COUNT = 5
|
||||
if = 'LFS2_VERSION == LFS2P_VERSION'
|
||||
if = '''
|
||||
LFS2_DISK_VERSION == LFS2P_DISK_VERSION
|
||||
&& DISK_VERSION == 0
|
||||
'''
|
||||
code = '''
|
||||
// create the new version
|
||||
lfs2_t lfs2;
|
||||
@@ -709,7 +775,10 @@ code = '''
|
||||
defines.COUNT = 5
|
||||
defines.SIZE = [4, 32, 512, 8192]
|
||||
defines.CHUNK = 4
|
||||
if = 'LFS2_VERSION == LFS2P_VERSION'
|
||||
if = '''
|
||||
LFS2_DISK_VERSION == LFS2P_DISK_VERSION
|
||||
&& DISK_VERSION == 0
|
||||
'''
|
||||
code = '''
|
||||
// create the new version
|
||||
lfs2_t lfs2;
|
||||
@@ -791,7 +860,10 @@ code = '''
|
||||
defines.COUNT = 5
|
||||
defines.SIZE = [4, 32, 512, 8192]
|
||||
defines.CHUNK = 4
|
||||
if = 'LFS2_VERSION == LFS2P_VERSION'
|
||||
if = '''
|
||||
LFS2_DISK_VERSION == LFS2P_DISK_VERSION
|
||||
&& DISK_VERSION == 0
|
||||
'''
|
||||
code = '''
|
||||
// create the new version
|
||||
lfs2_t lfs2;
|
||||
@@ -898,7 +970,10 @@ code = '''
|
||||
# test we can write dirs in an old version
|
||||
[cases.test_compat_backward_write_dirs]
|
||||
defines.COUNT = 10
|
||||
if = 'LFS2_VERSION == LFS2P_VERSION'
|
||||
if = '''
|
||||
LFS2_DISK_VERSION == LFS2P_DISK_VERSION
|
||||
&& DISK_VERSION == 0
|
||||
'''
|
||||
code = '''
|
||||
// create the new version
|
||||
lfs2_t lfs2;
|
||||
@@ -957,7 +1032,10 @@ code = '''
|
||||
defines.COUNT = 5
|
||||
defines.SIZE = [4, 32, 512, 8192]
|
||||
defines.CHUNK = 2
|
||||
if = 'LFS2_VERSION == LFS2P_VERSION'
|
||||
if = '''
|
||||
LFS2_DISK_VERSION == LFS2P_DISK_VERSION
|
||||
&& DISK_VERSION == 0
|
||||
'''
|
||||
code = '''
|
||||
// create the previous version
|
||||
lfs2_t lfs2;
|
||||
@@ -1071,7 +1149,10 @@ code = '''
|
||||
defines.COUNT = 5
|
||||
defines.SIZE = [4, 32, 512, 8192]
|
||||
defines.CHUNK = 2
|
||||
if = 'LFS2_VERSION == LFS2P_VERSION'
|
||||
if = '''
|
||||
LFS2_DISK_VERSION == LFS2P_DISK_VERSION
|
||||
&& DISK_VERSION == 0
|
||||
'''
|
||||
code = '''
|
||||
// create the previous version
|
||||
lfs2_t lfs2;
|
||||
@@ -1280,7 +1361,10 @@ code = '''
|
||||
# test that we correctly bump the minor version
|
||||
[cases.test_compat_minor_bump]
|
||||
in = 'lfs2.c'
|
||||
if = 'LFS2_DISK_VERSION_MINOR > 0'
|
||||
if = '''
|
||||
LFS2_DISK_VERSION_MINOR > 0
|
||||
&& DISK_VERSION == 0
|
||||
'''
|
||||
code = '''
|
||||
// create a superblock
|
||||
lfs2_t lfs2;
|
||||
@@ -1316,45 +1400,54 @@ code = '''
|
||||
|
||||
// mount should still work
|
||||
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;
|
||||
uint8_t buffer[8];
|
||||
lfs2_file_read(&lfs2, &file, buffer, 8) => 8;
|
||||
assert(memcmp(buffer, "testtest", 8) == 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;
|
||||
|
||||
// if we write, we need to bump the minor version
|
||||
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_write(&lfs2, &file, "teeeeest", 8) => 8;
|
||||
lfs2_file_close(&lfs2, &file) => 0;
|
||||
|
||||
// minor version should have changed
|
||||
lfs2_dir_fetch(&lfs2, &mdir, (lfs2_block_t[2]){0, 1}) => 0;
|
||||
lfs2_dir_get(&lfs2, &mdir, LFS2_MKTAG(0x7ff, 0x3ff, 0),
|
||||
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);
|
||||
// minor version should be changed
|
||||
lfs2_fs_stat(&lfs2, &fsinfo) => 0;
|
||||
assert(fsinfo.disk_version == LFS2_DISK_VERSION);
|
||||
|
||||
lfs2_unmount(&lfs2) => 0;
|
||||
|
||||
// and of course mount should still work
|
||||
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_read(&lfs2, &file, buffer, 8) => 8;
|
||||
assert(memcmp(buffer, "teeeeest", 8) == 0);
|
||||
lfs2_file_close(&lfs2, &file) => 0;
|
||||
|
||||
// minor version should have changed
|
||||
lfs2_dir_fetch(&lfs2, &mdir, (lfs2_block_t[2]){0, 1}) => 0;
|
||||
lfs2_dir_get(&lfs2, &mdir, LFS2_MKTAG(0x7ff, 0x3ff, 0),
|
||||
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);
|
||||
// yep, still changed
|
||||
lfs2_fs_stat(&lfs2, &fsinfo) => 0;
|
||||
assert(fsinfo.disk_version == LFS2_DISK_VERSION);
|
||||
|
||||
lfs2_unmount(&lfs2) => 0;
|
||||
'''
|
||||
|
||||
@@ -90,7 +90,10 @@ code = '''
|
||||
|
||||
# partial prog, may not be byte in order!
|
||||
[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_VALUE = [0x33, 0xcc]
|
||||
in = "lfs2.c"
|
||||
|
||||
@@ -34,6 +34,54 @@ code = '''
|
||||
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
|
||||
[cases.test_superblocks_expand]
|
||||
defines.BLOCK_CYCLES = [32, 33, 1]
|
||||
|
||||
Reference in New Issue
Block a user