Compare commits

..

1 Commits

Author SHA1 Message Date
Christopher Haster
52df70c669 Fixed name ordering when names only differ in length
Wild this hasn't been caught until now.

Because the exact ordering of the comparison in lfs_bd_cmp is a bit
ambiguous, lfs_dir_find_match returned the wrong result when filenames
were equal, and only differed in length.

For example:

  - cmp("a", "aa") should be LFS_CMP_LT
  - cmp("aaa", "aa") should be LFS_CMP_GT

We're quite lucky that none of the littlefs internals currently depend
on the sorted order, otherwise we'd probably be stuck with this weird
ordering for backwards compatibility reasons...

Fixed, and added some test cases over directory ordering to prevent
regression in the future.

Found by andriyndev
2024-01-17 14:38:04 -06:00
24 changed files with 392 additions and 692 deletions

View File

@@ -10,7 +10,7 @@ defaults:
jobs: jobs:
post-release: post-release:
runs-on: ubuntu-latest runs-on: ubuntu-22.04
steps: steps:
# trigger post-release in dependency repo, this indirection allows the # trigger post-release in dependency repo, this indirection allows the
# dependency repo to be updated often without affecting this repo. At # dependency repo to be updated often without affecting this repo. At

View File

@@ -11,7 +11,7 @@ defaults:
jobs: jobs:
release: release:
runs-on: ubuntu-latest runs-on: ubuntu-22.04
# need to manually check for a couple things # need to manually check for a couple things
# - tests passed? # - tests passed?

View File

@@ -11,7 +11,7 @@ defaults:
jobs: jobs:
# forward custom statuses # forward custom statuses
status: status:
runs-on: ubuntu-latest runs-on: ubuntu-22.04
steps: steps:
- uses: dawidd6/action-download-artifact@v2 - uses: dawidd6/action-download-artifact@v2
continue-on-error: true continue-on-error: true
@@ -60,7 +60,7 @@ jobs:
# forward custom pr-comments # forward custom pr-comments
comment: comment:
runs-on: ubuntu-latest runs-on: ubuntu-22.04
# only run on success (we don't want garbage comments!) # only run on success (we don't want garbage comments!)
if: ${{github.event.workflow_run.conclusion == 'success'}} if: ${{github.event.workflow_run.conclusion == 'success'}}

View File

@@ -14,7 +14,7 @@ env:
jobs: jobs:
# run tests # run tests
test: test:
runs-on: ubuntu-latest runs-on: ubuntu-22.04
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
@@ -329,7 +329,7 @@ jobs:
# #
# this grows exponentially, so it doesn't turn out to be that many # this grows exponentially, so it doesn't turn out to be that many
test-pls: test-pls:
runs-on: ubuntu-latest runs-on: ubuntu-22.04
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
@@ -359,7 +359,7 @@ jobs:
# run with LFS_NO_INTRINSICS to make sure that works # run with LFS_NO_INTRINSICS to make sure that works
test-no-intrinsics: test-no-intrinsics:
runs-on: ubuntu-latest runs-on: ubuntu-22.04
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: install - name: install
@@ -376,7 +376,7 @@ jobs:
# run LFS_MULTIVERSION tests # run LFS_MULTIVERSION tests
test-multiversion: test-multiversion:
runs-on: ubuntu-latest runs-on: ubuntu-22.04
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: install - name: install
@@ -393,7 +393,7 @@ jobs:
# run tests on the older version lfs2.0 # run tests on the older version lfs2.0
test-lfs2_0: test-lfs2_0:
runs-on: ubuntu-latest runs-on: ubuntu-22.04
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: install - name: install
@@ -412,7 +412,7 @@ jobs:
# run under Valgrind to check for memory errors # run under Valgrind to check for memory errors
test-valgrind: test-valgrind:
runs-on: ubuntu-latest runs-on: ubuntu-22.04
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: install - name: install
@@ -434,7 +434,7 @@ jobs:
# 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
test-clang: test-clang:
runs-on: ubuntu-latest runs-on: ubuntu-22.04
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: install - name: install
@@ -457,7 +457,7 @@ jobs:
# #
# note there's no real benefit to running these on multiple archs # note there's no real benefit to running these on multiple archs
bench: bench:
runs-on: ubuntu-latest runs-on: ubuntu-22.04
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: install - name: install
@@ -533,7 +533,7 @@ jobs:
# run compatibility tests using the current master as the previous version # run compatibility tests using the current master as the previous version
test-compat: test-compat:
runs-on: ubuntu-latest runs-on: ubuntu-22.04
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
if: ${{github.event_name == 'pull_request'}} if: ${{github.event_name == 'pull_request'}}
@@ -569,7 +569,7 @@ jobs:
# self-host with littlefs-fuse for a fuzz-like test # self-host with littlefs-fuse for a fuzz-like test
fuse: fuse:
runs-on: ubuntu-latest runs-on: ubuntu-22.04
if: ${{!endsWith(github.ref, '-prefix')}} if: ${{!endsWith(github.ref, '-prefix')}}
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
@@ -619,7 +619,7 @@ jobs:
# test migration using littlefs-fuse # test migration using littlefs-fuse
migrate: migrate:
runs-on: ubuntu-latest runs-on: ubuntu-22.04
if: ${{!endsWith(github.ref, '-prefix')}} if: ${{!endsWith(github.ref, '-prefix')}}
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
@@ -691,7 +691,7 @@ jobs:
# status related tasks that run after tests # status related tasks that run after tests
status: status:
runs-on: ubuntu-latest runs-on: ubuntu-22.04
needs: [test, bench] needs: [test, bench]
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2

View File

@@ -258,9 +258,6 @@ License Identifiers that are here available: http://spdx.org/licenses/
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.
- [nim-littlefs] - A Nim wrapper and API for littlefs. Includes a fuse
implementation based on [littlefs-fuse]
[BSD-3-Clause]: https://spdx.org/licenses/BSD-3-Clause.html [BSD-3-Clause]: https://spdx.org/licenses/BSD-3-Clause.html
[littlefs-disk-img-viewer]: https://github.com/tniessen/littlefs-disk-img-viewer [littlefs-disk-img-viewer]: https://github.com/tniessen/littlefs-disk-img-viewer
[littlefs-fuse]: https://github.com/geky/littlefs-fuse [littlefs-fuse]: https://github.com/geky/littlefs-fuse
@@ -277,4 +274,3 @@ License Identifiers that are here available: http://spdx.org/licenses/
[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
[nim-littlefs]: https://github.com/Graveflo/nim-littlefs

View File

@@ -129,8 +129,6 @@ int lfs_emubd_create(const struct lfs_config *cfg,
bd->proged = 0; bd->proged = 0;
bd->erased = 0; bd->erased = 0;
bd->power_cycles = bd->cfg->power_cycles; bd->power_cycles = bd->cfg->power_cycles;
bd->ooo_block = -1;
bd->ooo_data = NULL;
bd->disk = NULL; bd->disk = NULL;
if (bd->cfg->disk_path) { if (bd->cfg->disk_path) {
@@ -197,7 +195,6 @@ int lfs_emubd_destroy(const struct lfs_config *cfg) {
free(bd->blocks); free(bd->blocks);
// clean up other resources // clean up other resources
lfs_emubd_decblock(bd->ooo_data);
if (bd->disk) { if (bd->disk) {
bd->disk->rc -= 1; bd->disk->rc -= 1;
if (bd->disk->rc == 0) { if (bd->disk->rc == 0) {
@@ -212,75 +209,6 @@ int lfs_emubd_destroy(const struct lfs_config *cfg) {
} }
// powerloss hook
static int lfs_emubd_powerloss(const struct lfs_config *cfg) {
lfs_emubd_t *bd = cfg->context;
// emulate out-of-order writes?
lfs_emubd_block_t *ooo_data = NULL;
if (bd->cfg->powerloss_behavior == LFS_EMUBD_POWERLOSS_OOO
&& bd->ooo_block != -1) {
// since writes between syncs are allowed to be out-of-order, it
// shouldn't hurt to restore the first write on powerloss, right?
ooo_data = bd->blocks[bd->ooo_block];
bd->blocks[bd->ooo_block] = lfs_emubd_incblock(bd->ooo_data);
// mirror to disk file?
if (bd->disk
&& (bd->blocks[bd->ooo_block]
|| bd->cfg->erase_value != -1)) {
off_t res1 = lseek(bd->disk->fd,
(off_t)bd->ooo_block*bd->cfg->erase_size,
SEEK_SET);
if (res1 < 0) {
return -errno;
}
ssize_t res2 = write(bd->disk->fd,
(bd->blocks[bd->ooo_block])
? bd->blocks[bd->ooo_block]->data
: bd->disk->scratch,
bd->cfg->erase_size);
if (res2 < 0) {
return -errno;
}
}
}
// simulate power loss
bd->cfg->powerloss_cb(bd->cfg->powerloss_data);
// if we continue, undo out-of-order write emulation
if (bd->cfg->powerloss_behavior == LFS_EMUBD_POWERLOSS_OOO
&& bd->ooo_block != -1) {
lfs_emubd_decblock(bd->blocks[bd->ooo_block]);
bd->blocks[bd->ooo_block] = ooo_data;
// mirror to disk file?
if (bd->disk
&& (bd->blocks[bd->ooo_block]
|| bd->cfg->erase_value != -1)) {
off_t res1 = lseek(bd->disk->fd,
(off_t)bd->ooo_block*bd->cfg->erase_size,
SEEK_SET);
if (res1 < 0) {
return -errno;
}
ssize_t res2 = write(bd->disk->fd,
(bd->blocks[bd->ooo_block])
? bd->blocks[bd->ooo_block]->data
: bd->disk->scratch,
bd->cfg->erase_size);
if (res2 < 0) {
return -errno;
}
}
}
return 0;
}
// block device API // block device API
@@ -416,11 +344,8 @@ int lfs_emubd_prog(const struct lfs_config *cfg, lfs_block_t block,
if (bd->power_cycles > 0) { if (bd->power_cycles > 0) {
bd->power_cycles -= 1; bd->power_cycles -= 1;
if (bd->power_cycles == 0) { if (bd->power_cycles == 0) {
int err = lfs_emubd_powerloss(cfg); // simulate power loss
if (err) { bd->cfg->powerloss_cb(bd->cfg->powerloss_data);
LFS_EMUBD_TRACE("lfs_emubd_prog -> %d", err);
return err;
}
} }
} }
@@ -436,17 +361,10 @@ int lfs_emubd_erase(const struct lfs_config *cfg, lfs_block_t block) {
// check if erase is valid // check if erase is valid
LFS_ASSERT(block < bd->cfg->erase_count); LFS_ASSERT(block < bd->cfg->erase_count);
// emulate out-of-order writes? save first write
if (bd->cfg->powerloss_behavior == LFS_EMUBD_POWERLOSS_OOO
&& bd->ooo_block == -1) {
bd->ooo_block = block;
bd->ooo_data = lfs_emubd_incblock(bd->blocks[block]);
}
// get the block // get the block
lfs_emubd_block_t *b = lfs_emubd_mutblock(cfg, &bd->blocks[block]); lfs_emubd_block_t *b = lfs_emubd_mutblock(cfg, &bd->blocks[block]);
if (!b) { if (!b) {
LFS_EMUBD_TRACE("lfs_emubd_erase -> %d", LFS_ERR_NOMEM); LFS_EMUBD_TRACE("lfs_emubd_prog -> %d", LFS_ERR_NOMEM);
return LFS_ERR_NOMEM; return LFS_ERR_NOMEM;
} }
@@ -512,11 +430,8 @@ int lfs_emubd_erase(const struct lfs_config *cfg, lfs_block_t block) {
if (bd->power_cycles > 0) { if (bd->power_cycles > 0) {
bd->power_cycles -= 1; bd->power_cycles -= 1;
if (bd->power_cycles == 0) { if (bd->power_cycles == 0) {
int err = lfs_emubd_powerloss(cfg); // simulate power loss
if (err) { bd->cfg->powerloss_cb(bd->cfg->powerloss_data);
LFS_EMUBD_TRACE("lfs_emubd_erase -> %d", err);
return err;
}
} }
} }
@@ -526,24 +441,17 @@ int lfs_emubd_erase(const struct lfs_config *cfg, lfs_block_t block) {
int lfs_emubd_sync(const struct lfs_config *cfg) { int lfs_emubd_sync(const struct lfs_config *cfg) {
LFS_EMUBD_TRACE("lfs_emubd_sync(%p)", (void*)cfg); LFS_EMUBD_TRACE("lfs_emubd_sync(%p)", (void*)cfg);
lfs_emubd_t *bd = cfg->context;
// emulate out-of-order writes? reset first write, writes // do nothing
// cannot be out-of-order across sync (void)cfg;
if (bd->cfg->powerloss_behavior == LFS_EMUBD_POWERLOSS_OOO) {
lfs_emubd_decblock(bd->ooo_data);
bd->ooo_block = -1;
bd->ooo_data = NULL;
}
LFS_EMUBD_TRACE("lfs_emubd_sync -> %d", 0); LFS_EMUBD_TRACE("lfs_emubd_sync -> %d", 0);
return 0; return 0;
} }
/// Additional extended API for driving test features /// /// Additional extended API for driving test features ///
static int lfs_emubd_crc_(const struct lfs_config *cfg, static int lfs_emubd_rawcrc(const struct lfs_config *cfg,
lfs_block_t block, uint32_t *crc) { lfs_block_t block, uint32_t *crc) {
lfs_emubd_t *bd = cfg->context; lfs_emubd_t *bd = cfg->context;
@@ -572,7 +480,7 @@ int lfs_emubd_crc(const struct lfs_config *cfg,
lfs_block_t block, uint32_t *crc) { lfs_block_t block, uint32_t *crc) {
LFS_EMUBD_TRACE("lfs_emubd_crc(%p, %"PRIu32", %p)", LFS_EMUBD_TRACE("lfs_emubd_crc(%p, %"PRIu32", %p)",
(void*)cfg, block, crc); (void*)cfg, block, crc);
int err = lfs_emubd_crc_(cfg, block, crc); int err = lfs_emubd_rawcrc(cfg, block, crc);
LFS_EMUBD_TRACE("lfs_emubd_crc -> %d", err); LFS_EMUBD_TRACE("lfs_emubd_crc -> %d", err);
return err; return err;
} }
@@ -583,7 +491,7 @@ int lfs_emubd_bdcrc(const struct lfs_config *cfg, uint32_t *crc) {
uint32_t crc_ = 0xffffffff; uint32_t crc_ = 0xffffffff;
for (lfs_block_t i = 0; i < cfg->block_count; i++) { for (lfs_block_t i = 0; i < cfg->block_count; i++) {
uint32_t i_crc; uint32_t i_crc;
int err = lfs_emubd_crc_(cfg, i, &i_crc); int err = lfs_emubd_rawcrc(cfg, i, &i_crc);
if (err) { if (err) {
LFS_EMUBD_TRACE("lfs_emubd_bdcrc -> %d", err); LFS_EMUBD_TRACE("lfs_emubd_bdcrc -> %d", err);
return err; return err;
@@ -725,8 +633,6 @@ int lfs_emubd_copy(const struct lfs_config *cfg, lfs_emubd_t *copy) {
copy->proged = bd->proged; copy->proged = bd->proged;
copy->erased = bd->erased; copy->erased = bd->erased;
copy->power_cycles = bd->power_cycles; copy->power_cycles = bd->power_cycles;
copy->ooo_block = bd->ooo_block;
copy->ooo_data = lfs_emubd_incblock(bd->ooo_data);
copy->disk = bd->disk; copy->disk = bd->disk;
if (copy->disk) { if (copy->disk) {
copy->disk->rc += 1; copy->disk->rc += 1;

View File

@@ -36,18 +36,17 @@ extern "C"
// Not that read-noop is not allowed. Read _must_ return a consistent (but // Not that read-noop is not allowed. Read _must_ return a consistent (but
// may be arbitrary) value on every read. // may be arbitrary) value on every read.
typedef enum lfs_emubd_badblock_behavior { typedef enum lfs_emubd_badblock_behavior {
LFS_EMUBD_BADBLOCK_PROGERROR = 0, // Error on prog LFS_EMUBD_BADBLOCK_PROGERROR,
LFS_EMUBD_BADBLOCK_ERASEERROR = 1, // Error on erase LFS_EMUBD_BADBLOCK_ERASEERROR,
LFS_EMUBD_BADBLOCK_READERROR = 2, // Error on read LFS_EMUBD_BADBLOCK_READERROR,
LFS_EMUBD_BADBLOCK_PROGNOOP = 3, // Prog does nothing silently LFS_EMUBD_BADBLOCK_PROGNOOP,
LFS_EMUBD_BADBLOCK_ERASENOOP = 4, // Erase does nothing silently LFS_EMUBD_BADBLOCK_ERASENOOP,
} lfs_emubd_badblock_behavior_t; } lfs_emubd_badblock_behavior_t;
// Mode determining how power-loss behaves during testing. For now this // Mode determining how power-loss behaves during testing. For now this
// only supports a noop behavior, leaving the data on-disk untouched. // only supports a noop behavior, leaving the data on-disk untouched.
typedef enum lfs_emubd_powerloss_behavior { typedef enum lfs_emubd_powerloss_behavior {
LFS_EMUBD_POWERLOSS_NOOP = 0, // Progs are atomic LFS_EMUBD_POWERLOSS_NOOP,
LFS_EMUBD_POWERLOSS_OOO = 1, // Blocks are written out-of-order
} lfs_emubd_powerloss_behavior_t; } lfs_emubd_powerloss_behavior_t;
// Type for measuring read/program/erase operations // Type for measuring read/program/erase operations
@@ -153,8 +152,6 @@ typedef struct lfs_emubd {
lfs_emubd_io_t proged; lfs_emubd_io_t proged;
lfs_emubd_io_t erased; lfs_emubd_io_t erased;
lfs_emubd_powercycles_t power_cycles; lfs_emubd_powercycles_t power_cycles;
lfs_ssize_t ooo_block;
lfs_emubd_block_t *ooo_data;
lfs_emubd_disk_t *disk; lfs_emubd_disk_t *disk;
const struct lfs_emubd_config *cfg; const struct lfs_emubd_config *cfg;

498
lfs.c

File diff suppressed because it is too large Load Diff

94
lfs.h
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 LFS_VERSION 0x00020009 #define LFS_VERSION 0x00020008
#define LFS_VERSION_MAJOR (0xffff & (LFS_VERSION >> 16)) #define LFS_VERSION_MAJOR (0xffff & (LFS_VERSION >> 16))
#define LFS_VERSION_MINOR (0xffff & (LFS_VERSION >> 0)) #define LFS_VERSION_MINOR (0xffff & (LFS_VERSION >> 0))
@@ -52,15 +52,16 @@ typedef uint32_t lfs_block_t;
#endif #endif
// Maximum size of a file in bytes, may be redefined to limit to support other // Maximum size of a file in bytes, may be redefined to limit to support other
// drivers. Limited on disk to <= 2147483647. Stored in superblock and must be // drivers. Limited on disk to <= 4294967296. However, above 2147483647 the
// respected by other littlefs drivers. // functions lfs_file_seek, lfs_file_size, and lfs_file_tell will return
// incorrect values due to using signed integers. Stored in superblock and
// must be respected by other littlefs drivers.
#ifndef LFS_FILE_MAX #ifndef LFS_FILE_MAX
#define LFS_FILE_MAX 2147483647 #define LFS_FILE_MAX 2147483647
#endif #endif
// Maximum size of custom attributes in bytes, may be redefined, but there is // Maximum size of custom attributes in bytes, may be redefined, but there is
// no real benefit to using a smaller LFS_ATTR_MAX. Limited to <= 1022. Stored // no real benefit to using a smaller LFS_ATTR_MAX. Limited to <= 1022.
// in superblock and must be respected by other littlefs drivers.
#ifndef LFS_ATTR_MAX #ifndef LFS_ATTR_MAX
#define LFS_ATTR_MAX 1022 #define LFS_ATTR_MAX 1022
#endif #endif
@@ -204,8 +205,7 @@ struct lfs_config {
// program sizes. // program sizes.
lfs_size_t block_size; lfs_size_t block_size;
// Number of erasable blocks on the device. Defaults to block_count stored // Number of erasable blocks on the device.
// on disk when zero.
lfs_size_t block_count; lfs_size_t block_count;
// Number of erase cycles before littlefs evicts metadata logs and moves // Number of erase cycles before littlefs evicts metadata logs and moves
@@ -226,20 +226,9 @@ struct lfs_config {
// Size of the lookahead buffer in bytes. A larger lookahead buffer // Size of the lookahead buffer in bytes. A larger lookahead buffer
// increases the number of blocks found during an allocation pass. The // increases the number of blocks found during an allocation pass. The
// lookahead buffer is stored as a compact bitmap, so each byte of RAM // lookahead buffer is stored as a compact bitmap, so each byte of RAM
// can track 8 blocks. // can track 8 blocks. Must be a multiple of 8.
lfs_size_t lookahead_size; lfs_size_t lookahead_size;
// Threshold for metadata compaction during lfs_fs_gc in bytes. Metadata
// pairs that exceed this threshold will be compacted during lfs_fs_gc.
// Defaults to ~88% block_size when zero, though the default may change
// in the future.
//
// Note this only affects lfs_fs_gc. Normal compactions still only occur
// when full.
//
// Set to -1 to disable metadata compaction during lfs_fs_gc.
lfs_size_t compact_thresh;
// Optional statically allocated read buffer. Must be cache_size. // Optional statically allocated read buffer. Must be cache_size.
// By default lfs_malloc is used to allocate this buffer. // By default lfs_malloc is used to allocate this buffer.
void *read_buffer; void *read_buffer;
@@ -248,24 +237,25 @@ struct lfs_config {
// By default lfs_malloc is used to allocate this buffer. // By default lfs_malloc is used to allocate this buffer.
void *prog_buffer; void *prog_buffer;
// Optional statically allocated lookahead buffer. Must be lookahead_size. // Optional statically allocated lookahead buffer. Must be lookahead_size
// By default lfs_malloc is used to allocate this buffer. // and aligned to a 32-bit boundary. By default lfs_malloc is used to
// allocate this buffer.
void *lookahead_buffer; void *lookahead_buffer;
// Optional upper limit on length of file names in bytes. No downside for // Optional upper limit on length of file names in bytes. No downside for
// larger names except the size of the info struct which is controlled by // larger names except the size of the info struct which is controlled by
// the LFS_NAME_MAX define. Defaults to LFS_NAME_MAX or name_max stored on // the LFS_NAME_MAX define. Defaults to LFS_NAME_MAX when zero. Stored in
// disk when zero. // superblock and must be respected by other littlefs drivers.
lfs_size_t name_max; lfs_size_t name_max;
// Optional upper limit on files in bytes. No downside for larger files // Optional upper limit on files in bytes. No downside for larger files
// but must be <= LFS_FILE_MAX. Defaults to LFS_FILE_MAX or file_max stored // but must be <= LFS_FILE_MAX. Defaults to LFS_FILE_MAX when zero. Stored
// on disk when zero. // in superblock and must be respected by other littlefs drivers.
lfs_size_t file_max; lfs_size_t file_max;
// Optional upper limit on custom attributes in bytes. No downside for // Optional upper limit on custom attributes in bytes. No downside for
// larger attributes size but must be <= LFS_ATTR_MAX. Defaults to // larger attributes size but must be <= LFS_ATTR_MAX. Defaults to
// LFS_ATTR_MAX or attr_max stored on disk when zero. // LFS_ATTR_MAX when zero.
lfs_size_t attr_max; lfs_size_t attr_max;
// Optional upper limit on total space given to metadata pairs in bytes. On // Optional upper limit on total space given to metadata pairs in bytes. On
@@ -274,15 +264,6 @@ struct lfs_config {
// Defaults to block_size when zero. // Defaults to block_size when zero.
lfs_size_t metadata_max; lfs_size_t metadata_max;
// Optional upper limit on inlined files in bytes. Inlined files live in
// metadata and decrease storage requirements, but may be limited to
// improve metadata-related performance. Must be <= cache_size, <=
// attr_max, and <= block_size/8. Defaults to the largest possible
// inline_max when zero.
//
// Set to -1 to disable inlined files.
lfs_size_t inline_max;
#ifdef LFS_MULTIVERSION #ifdef LFS_MULTIVERSION
// On-disk version to use when writing in the form of 16-bit major version // 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 // + 16-bit minor version. This limiting metadata to what is supported by
@@ -449,20 +430,19 @@ typedef struct lfs {
lfs_gstate_t gdisk; lfs_gstate_t gdisk;
lfs_gstate_t gdelta; lfs_gstate_t gdelta;
struct lfs_lookahead { struct lfs_free {
lfs_block_t start; lfs_block_t off;
lfs_block_t size; lfs_block_t size;
lfs_block_t next; lfs_block_t i;
lfs_block_t ckpoint; lfs_block_t ack;
uint8_t *buffer; uint32_t *buffer;
} lookahead; } free;
const struct lfs_config *cfg; const struct lfs_config *cfg;
lfs_size_t block_count; lfs_size_t block_count;
lfs_size_t name_max; lfs_size_t name_max;
lfs_size_t file_max; lfs_size_t file_max;
lfs_size_t attr_max; lfs_size_t attr_max;
lfs_size_t inline_max;
#ifdef LFS_MIGRATE #ifdef LFS_MIGRATE
struct lfs1 *lfs1; struct lfs1 *lfs1;
@@ -732,6 +712,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);
// Attempt to proactively find free blocks
//
// Calling this function is not required, but may allowing the offloading of
// the expensive block allocation scan to a less time-critical code path.
//
// Note: littlefs currently does not persist any found free blocks to disk.
// This may change in the future.
//
// Returns a negative error code on failure. Finding no free blocks is
// not an error.
int lfs_fs_gc(lfs_t *lfs);
#ifndef LFS_READONLY #ifndef LFS_READONLY
// Attempt to make the filesystem consistent and ready for writing // Attempt to make the filesystem consistent and ready for writing
// //
@@ -744,24 +736,6 @@ int lfs_fs_traverse(lfs_t *lfs, int (*cb)(void*, lfs_block_t), void *data);
int lfs_fs_mkconsistent(lfs_t *lfs); int lfs_fs_mkconsistent(lfs_t *lfs);
#endif #endif
#ifndef LFS_READONLY
// Attempt any janitorial work
//
// This currently:
// 1. Calls mkconsistent if not already consistent
// 2. Compacts metadata > compact_thresh
// 3. Populates the block allocator
//
// Though additional janitorial work may be added in the future.
//
// Calling this function is not required, but may allow the offloading of
// expensive janitorial work to a less time-critical code path.
//
// Returns a negative error code on failure. Accomplishing nothing is not
// an error.
int lfs_fs_gc(lfs_t *lfs);
#endif
#ifndef LFS_READONLY #ifndef LFS_READONLY
// Grows the filesystem to a new size, updating the superblock with the new // Grows the filesystem to a new size, updating the superblock with the new
// block count. // block count.

View File

@@ -11,8 +11,6 @@
#ifndef LFS_CONFIG #ifndef LFS_CONFIG
// If user provides their own CRC impl we don't need this
#ifndef LFS_CRC
// Software CRC implementation with small lookup table // Software CRC implementation with small lookup table
uint32_t lfs_crc(uint32_t crc, const void *buffer, size_t size) { uint32_t lfs_crc(uint32_t crc, const void *buffer, size_t size) {
static const uint32_t rtable[16] = { static const uint32_t rtable[16] = {
@@ -31,7 +29,6 @@ uint32_t lfs_crc(uint32_t crc, const void *buffer, size_t size) {
return crc; return crc;
} }
#endif
#endif #endif

View File

@@ -212,22 +212,12 @@ static inline uint32_t lfs_tobe32(uint32_t a) {
} }
// Calculate CRC-32 with polynomial = 0x04c11db7 // Calculate CRC-32 with polynomial = 0x04c11db7
#ifdef LFS_CRC
uint32_t lfs_crc(uint32_t crc, const void *buffer, size_t size) {
return LFS_CRC(crc, buffer, size)
}
#else
uint32_t lfs_crc(uint32_t crc, const void *buffer, size_t size); uint32_t lfs_crc(uint32_t crc, const void *buffer, size_t size);
#endif
// Allocate memory, only used if buffers are not provided to littlefs // Allocate memory, only used if buffers are not provided to littlefs
// // Note, memory must be 64-bit aligned
// littlefs current has no alignment requirements, as it only allocates
// byte-level buffers.
static inline void *lfs_malloc(size_t size) { static inline void *lfs_malloc(size_t size) {
#if defined(LFS_MALLOC) #ifndef LFS_NO_MALLOC
return LFS_MALLOC(size);
#elif !defined(LFS_NO_MALLOC)
return malloc(size); return malloc(size);
#else #else
(void)size; (void)size;
@@ -237,9 +227,7 @@ static inline void *lfs_malloc(size_t size) {
// Deallocate memory, only used if buffers are not provided to littlefs // Deallocate memory, only used if buffers are not provided to littlefs
static inline void lfs_free(void *p) { static inline void lfs_free(void *p) {
#if defined(LFS_FREE) #ifndef LFS_NO_MALLOC
LFS_FREE(p);
#elif !defined(LFS_NO_MALLOC)
free(p); free(p);
#else #else
(void)p; (void)p;

View File

@@ -1321,8 +1321,6 @@ void perm_run(
.block_cycles = BLOCK_CYCLES, .block_cycles = BLOCK_CYCLES,
.cache_size = CACHE_SIZE, .cache_size = CACHE_SIZE,
.lookahead_size = LOOKAHEAD_SIZE, .lookahead_size = LOOKAHEAD_SIZE,
.compact_thresh = COMPACT_THRESH,
.inline_max = INLINE_MAX,
}; };
struct lfs_emubd_config bdcfg = { struct lfs_emubd_config bdcfg = {

View File

@@ -95,13 +95,11 @@ intmax_t bench_define(size_t define);
#define BLOCK_COUNT_i 5 #define BLOCK_COUNT_i 5
#define CACHE_SIZE_i 6 #define CACHE_SIZE_i 6
#define LOOKAHEAD_SIZE_i 7 #define LOOKAHEAD_SIZE_i 7
#define COMPACT_THRESH_i 8 #define BLOCK_CYCLES_i 8
#define INLINE_MAX_i 9 #define ERASE_VALUE_i 9
#define BLOCK_CYCLES_i 10 #define ERASE_CYCLES_i 10
#define ERASE_VALUE_i 11 #define BADBLOCK_BEHAVIOR_i 11
#define ERASE_CYCLES_i 12 #define POWERLOSS_BEHAVIOR_i 12
#define BADBLOCK_BEHAVIOR_i 13
#define POWERLOSS_BEHAVIOR_i 14
#define READ_SIZE bench_define(READ_SIZE_i) #define READ_SIZE bench_define(READ_SIZE_i)
#define PROG_SIZE bench_define(PROG_SIZE_i) #define PROG_SIZE bench_define(PROG_SIZE_i)
@@ -111,8 +109,6 @@ intmax_t bench_define(size_t define);
#define BLOCK_COUNT bench_define(BLOCK_COUNT_i) #define BLOCK_COUNT bench_define(BLOCK_COUNT_i)
#define CACHE_SIZE bench_define(CACHE_SIZE_i) #define CACHE_SIZE bench_define(CACHE_SIZE_i)
#define LOOKAHEAD_SIZE bench_define(LOOKAHEAD_SIZE_i) #define LOOKAHEAD_SIZE bench_define(LOOKAHEAD_SIZE_i)
#define COMPACT_THRESH bench_define(COMPACT_THRESH_i)
#define INLINE_MAX bench_define(INLINE_MAX_i)
#define BLOCK_CYCLES bench_define(BLOCK_CYCLES_i) #define BLOCK_CYCLES bench_define(BLOCK_CYCLES_i)
#define ERASE_VALUE bench_define(ERASE_VALUE_i) #define ERASE_VALUE bench_define(ERASE_VALUE_i)
#define ERASE_CYCLES bench_define(ERASE_CYCLES_i) #define ERASE_CYCLES bench_define(ERASE_CYCLES_i)
@@ -128,8 +124,6 @@ intmax_t bench_define(size_t define);
BENCH_DEF(BLOCK_COUNT, ERASE_COUNT/lfs_max(BLOCK_SIZE/ERASE_SIZE,1))\ BENCH_DEF(BLOCK_COUNT, ERASE_COUNT/lfs_max(BLOCK_SIZE/ERASE_SIZE,1))\
BENCH_DEF(CACHE_SIZE, lfs_max(64,lfs_max(READ_SIZE,PROG_SIZE))) \ BENCH_DEF(CACHE_SIZE, lfs_max(64,lfs_max(READ_SIZE,PROG_SIZE))) \
BENCH_DEF(LOOKAHEAD_SIZE, 16) \ BENCH_DEF(LOOKAHEAD_SIZE, 16) \
BENCH_DEF(COMPACT_THRESH, 0) \
BENCH_DEF(INLINE_MAX, 0) \
BENCH_DEF(BLOCK_CYCLES, -1) \ BENCH_DEF(BLOCK_CYCLES, -1) \
BENCH_DEF(ERASE_VALUE, 0xff) \ BENCH_DEF(ERASE_VALUE, 0xff) \
BENCH_DEF(ERASE_CYCLES, 0) \ BENCH_DEF(ERASE_CYCLES, 0) \
@@ -137,7 +131,7 @@ intmax_t bench_define(size_t define);
BENCH_DEF(POWERLOSS_BEHAVIOR, LFS_EMUBD_POWERLOSS_NOOP) BENCH_DEF(POWERLOSS_BEHAVIOR, LFS_EMUBD_POWERLOSS_NOOP)
#define BENCH_GEOMETRY_DEFINE_COUNT 4 #define BENCH_GEOMETRY_DEFINE_COUNT 4
#define BENCH_IMPLICIT_DEFINE_COUNT 15 #define BENCH_IMPLICIT_DEFINE_COUNT 13
#endif #endif

View File

@@ -1346,8 +1346,6 @@ 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,
.compact_thresh = COMPACT_THRESH,
.inline_max = INLINE_MAX,
#ifdef LFS_MULTIVERSION #ifdef LFS_MULTIVERSION
.disk_version = DISK_VERSION, .disk_version = DISK_VERSION,
#endif #endif
@@ -1424,8 +1422,6 @@ 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,
.compact_thresh = COMPACT_THRESH,
.inline_max = INLINE_MAX,
#ifdef LFS_MULTIVERSION #ifdef LFS_MULTIVERSION
.disk_version = DISK_VERSION, .disk_version = DISK_VERSION,
#endif #endif
@@ -1519,8 +1515,6 @@ 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,
.compact_thresh = COMPACT_THRESH,
.inline_max = INLINE_MAX,
#ifdef LFS_MULTIVERSION #ifdef LFS_MULTIVERSION
.disk_version = DISK_VERSION, .disk_version = DISK_VERSION,
#endif #endif
@@ -1612,8 +1606,6 @@ 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,
.compact_thresh = COMPACT_THRESH,
.inline_max = INLINE_MAX,
#ifdef LFS_MULTIVERSION #ifdef LFS_MULTIVERSION
.disk_version = DISK_VERSION, .disk_version = DISK_VERSION,
#endif #endif
@@ -1803,8 +1795,6 @@ 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,
.compact_thresh = COMPACT_THRESH,
.inline_max = INLINE_MAX,
#ifdef LFS_MULTIVERSION #ifdef LFS_MULTIVERSION
.disk_version = DISK_VERSION, .disk_version = DISK_VERSION,
#endif #endif

View File

@@ -88,14 +88,12 @@ intmax_t test_define(size_t define);
#define BLOCK_COUNT_i 5 #define BLOCK_COUNT_i 5
#define CACHE_SIZE_i 6 #define CACHE_SIZE_i 6
#define LOOKAHEAD_SIZE_i 7 #define LOOKAHEAD_SIZE_i 7
#define COMPACT_THRESH_i 8 #define BLOCK_CYCLES_i 8
#define INLINE_MAX_i 9 #define ERASE_VALUE_i 9
#define BLOCK_CYCLES_i 10 #define ERASE_CYCLES_i 10
#define ERASE_VALUE_i 11 #define BADBLOCK_BEHAVIOR_i 11
#define ERASE_CYCLES_i 12 #define POWERLOSS_BEHAVIOR_i 12
#define BADBLOCK_BEHAVIOR_i 13 #define DISK_VERSION_i 13
#define POWERLOSS_BEHAVIOR_i 14
#define DISK_VERSION_i 15
#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)
@@ -105,8 +103,6 @@ intmax_t test_define(size_t define);
#define BLOCK_COUNT TEST_DEFINE(BLOCK_COUNT_i) #define BLOCK_COUNT TEST_DEFINE(BLOCK_COUNT_i)
#define CACHE_SIZE TEST_DEFINE(CACHE_SIZE_i) #define CACHE_SIZE TEST_DEFINE(CACHE_SIZE_i)
#define LOOKAHEAD_SIZE TEST_DEFINE(LOOKAHEAD_SIZE_i) #define LOOKAHEAD_SIZE TEST_DEFINE(LOOKAHEAD_SIZE_i)
#define COMPACT_THRESH TEST_DEFINE(COMPACT_THRESH_i)
#define INLINE_MAX TEST_DEFINE(INLINE_MAX_i)
#define BLOCK_CYCLES TEST_DEFINE(BLOCK_CYCLES_i) #define BLOCK_CYCLES TEST_DEFINE(BLOCK_CYCLES_i)
#define ERASE_VALUE TEST_DEFINE(ERASE_VALUE_i) #define ERASE_VALUE TEST_DEFINE(ERASE_VALUE_i)
#define ERASE_CYCLES TEST_DEFINE(ERASE_CYCLES_i) #define ERASE_CYCLES TEST_DEFINE(ERASE_CYCLES_i)
@@ -123,8 +119,6 @@ intmax_t test_define(size_t define);
TEST_DEF(BLOCK_COUNT, ERASE_COUNT/lfs_max(BLOCK_SIZE/ERASE_SIZE,1)) \ TEST_DEF(BLOCK_COUNT, ERASE_COUNT/lfs_max(BLOCK_SIZE/ERASE_SIZE,1)) \
TEST_DEF(CACHE_SIZE, lfs_max(64,lfs_max(READ_SIZE,PROG_SIZE))) \ TEST_DEF(CACHE_SIZE, lfs_max(64,lfs_max(READ_SIZE,PROG_SIZE))) \
TEST_DEF(LOOKAHEAD_SIZE, 16) \ TEST_DEF(LOOKAHEAD_SIZE, 16) \
TEST_DEF(COMPACT_THRESH, 0) \
TEST_DEF(INLINE_MAX, 0) \
TEST_DEF(BLOCK_CYCLES, -1) \ TEST_DEF(BLOCK_CYCLES, -1) \
TEST_DEF(ERASE_VALUE, 0xff) \ TEST_DEF(ERASE_VALUE, 0xff) \
TEST_DEF(ERASE_CYCLES, 0) \ TEST_DEF(ERASE_CYCLES, 0) \
@@ -133,7 +127,7 @@ intmax_t test_define(size_t define);
TEST_DEF(DISK_VERSION, 0) TEST_DEF(DISK_VERSION, 0)
#define TEST_GEOMETRY_DEFINE_COUNT 4 #define TEST_GEOMETRY_DEFINE_COUNT 4
#define TEST_IMPLICIT_DEFINE_COUNT 16 #define TEST_IMPLICIT_DEFINE_COUNT 14
#endif #endif

View File

@@ -7,23 +7,17 @@ if = 'BLOCK_CYCLES == -1'
defines.FILES = 3 defines.FILES = 3
defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-6)) / FILES)' defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-6)) / FILES)'
defines.GC = [false, true] defines.GC = [false, true]
defines.COMPACT_THRESH = ['-1', '0', 'BLOCK_SIZE/2']
defines.INFER_BC = [false, true]
code = ''' code = '''
const char *names[] = {"bacon", "eggs", "pancakes"}; const char *names[] = {"bacon", "eggs", "pancakes"};
lfs_file_t files[FILES]; lfs_file_t files[FILES];
lfs_t lfs; lfs_t lfs;
lfs_format(&lfs, cfg) => 0; lfs_format(&lfs, cfg) => 0;
struct lfs_config cfg_ = *cfg; lfs_mount(&lfs, cfg) => 0;
if (INFER_BC) {
cfg_.block_count = 0;
}
lfs_mount(&lfs, &cfg_) => 0;
lfs_mkdir(&lfs, "breakfast") => 0; lfs_mkdir(&lfs, "breakfast") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg_) => 0; lfs_mount(&lfs, cfg) => 0;
for (int n = 0; n < FILES; n++) { for (int n = 0; n < FILES; n++) {
char path[1024]; char path[1024];
sprintf(path, "breakfast/%s", names[n]); sprintf(path, "breakfast/%s", names[n]);
@@ -44,7 +38,7 @@ code = '''
} }
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg_) => 0; lfs_mount(&lfs, cfg) => 0;
for (int n = 0; n < FILES; n++) { for (int n = 0; n < FILES; n++) {
char path[1024]; char path[1024];
sprintf(path, "breakfast/%s", names[n]); sprintf(path, "breakfast/%s", names[n]);
@@ -66,23 +60,17 @@ code = '''
defines.FILES = 3 defines.FILES = 3
defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-6)) / FILES)' defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-6)) / FILES)'
defines.GC = [false, true] defines.GC = [false, true]
defines.COMPACT_THRESH = ['-1', '0', 'BLOCK_SIZE/2']
defines.INFER_BC = [false, true]
code = ''' code = '''
const char *names[] = {"bacon", "eggs", "pancakes"}; const char *names[] = {"bacon", "eggs", "pancakes"};
lfs_t lfs; lfs_t lfs;
lfs_format(&lfs, cfg) => 0; lfs_format(&lfs, cfg) => 0;
struct lfs_config cfg_ = *cfg; lfs_mount(&lfs, cfg) => 0;
if (INFER_BC) {
cfg_.block_count = 0;
}
lfs_mount(&lfs, &cfg_) => 0;
lfs_mkdir(&lfs, "breakfast") => 0; lfs_mkdir(&lfs, "breakfast") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
for (int n = 0; n < FILES; n++) { for (int n = 0; n < FILES; n++) {
lfs_mount(&lfs, &cfg_) => 0; lfs_mount(&lfs, cfg) => 0;
char path[1024]; char path[1024];
sprintf(path, "breakfast/%s", names[n]); sprintf(path, "breakfast/%s", names[n]);
lfs_file_t file; lfs_file_t file;
@@ -101,7 +89,7 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
} }
lfs_mount(&lfs, &cfg_) => 0; lfs_mount(&lfs, cfg) => 0;
for (int n = 0; n < FILES; n++) { for (int n = 0; n < FILES; n++) {
char path[1024]; char path[1024];
sprintf(path, "breakfast/%s", names[n]); sprintf(path, "breakfast/%s", names[n]);
@@ -123,24 +111,19 @@ code = '''
defines.FILES = 3 defines.FILES = 3
defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-6)) / FILES)' defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-6)) / FILES)'
defines.CYCLES = [1, 10] defines.CYCLES = [1, 10]
defines.INFER_BC = [false, true]
code = ''' code = '''
const char *names[] = {"bacon", "eggs", "pancakes"}; const char *names[] = {"bacon", "eggs", "pancakes"};
lfs_file_t files[FILES]; lfs_file_t files[FILES];
lfs_t lfs; lfs_t lfs;
lfs_format(&lfs, cfg) => 0; lfs_format(&lfs, cfg) => 0;
struct lfs_config cfg_ = *cfg;
if (INFER_BC) {
cfg_.block_count = 0;
}
for (int c = 0; c < CYCLES; c++) { for (int c = 0; c < CYCLES; c++) {
lfs_mount(&lfs, &cfg_) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "breakfast") => 0; lfs_mkdir(&lfs, "breakfast") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg_) => 0; lfs_mount(&lfs, cfg) => 0;
for (int n = 0; n < FILES; n++) { for (int n = 0; n < FILES; n++) {
char path[1024]; char path[1024];
sprintf(path, "breakfast/%s", names[n]); sprintf(path, "breakfast/%s", names[n]);
@@ -158,7 +141,7 @@ code = '''
} }
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg_) => 0; lfs_mount(&lfs, cfg) => 0;
for (int n = 0; n < FILES; n++) { for (int n = 0; n < FILES; n++) {
char path[1024]; char path[1024];
sprintf(path, "breakfast/%s", names[n]); sprintf(path, "breakfast/%s", names[n]);
@@ -174,7 +157,7 @@ code = '''
} }
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg_) => 0; lfs_mount(&lfs, cfg) => 0;
for (int n = 0; n < FILES; n++) { for (int n = 0; n < FILES; n++) {
char path[1024]; char path[1024];
sprintf(path, "breakfast/%s", names[n]); sprintf(path, "breakfast/%s", names[n]);
@@ -190,24 +173,19 @@ code = '''
defines.FILES = 3 defines.FILES = 3
defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-6)) / FILES)' defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-6)) / FILES)'
defines.CYCLES = [1, 10] defines.CYCLES = [1, 10]
defines.INFER_BC = [false, true]
code = ''' code = '''
const char *names[] = {"bacon", "eggs", "pancakes"}; const char *names[] = {"bacon", "eggs", "pancakes"};
lfs_t lfs; lfs_t lfs;
lfs_format(&lfs, cfg) => 0; lfs_format(&lfs, cfg) => 0;
struct lfs_config cfg_ = *cfg;
if (INFER_BC) {
cfg_.block_count = 0;
}
for (int c = 0; c < CYCLES; c++) { for (int c = 0; c < CYCLES; c++) {
lfs_mount(&lfs, &cfg_) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "breakfast") => 0; lfs_mkdir(&lfs, "breakfast") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
for (int n = 0; n < FILES; n++) { for (int n = 0; n < FILES; n++) {
lfs_mount(&lfs, &cfg_) => 0; lfs_mount(&lfs, cfg) => 0;
char path[1024]; char path[1024];
sprintf(path, "breakfast/%s", names[n]); sprintf(path, "breakfast/%s", names[n]);
lfs_file_t file; lfs_file_t file;
@@ -252,15 +230,10 @@ code = '''
# exhaustion test # exhaustion test
[cases.test_alloc_exhaustion] [cases.test_alloc_exhaustion]
defines.INFER_BC = [false, true]
code = ''' code = '''
lfs_t lfs; lfs_t lfs;
lfs_format(&lfs, cfg) => 0; lfs_format(&lfs, cfg) => 0;
struct lfs_config cfg_ = *cfg; lfs_mount(&lfs, cfg) => 0;
if (INFER_BC) {
cfg_.block_count = 0;
}
lfs_mount(&lfs, &cfg_) => 0;
lfs_file_t file; lfs_file_t file;
lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT); lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT);
size_t size = strlen("exhaustion"); size_t size = strlen("exhaustion");
@@ -288,7 +261,7 @@ code = '''
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg_) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_file_open(&lfs, &file, "exhaustion", LFS_O_RDONLY); lfs_file_open(&lfs, &file, "exhaustion", LFS_O_RDONLY);
size = strlen("exhaustion"); size = strlen("exhaustion");
lfs_file_size(&lfs, &file) => size; lfs_file_size(&lfs, &file) => size;
@@ -301,15 +274,10 @@ code = '''
# exhaustion wraparound test # exhaustion wraparound test
[cases.test_alloc_exhaustion_wraparound] [cases.test_alloc_exhaustion_wraparound]
defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-4)) / 3)' defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-4)) / 3)'
defines.INFER_BC = [false, true]
code = ''' code = '''
lfs_t lfs; lfs_t lfs;
lfs_format(&lfs, cfg) => 0; lfs_format(&lfs, cfg) => 0;
struct lfs_config cfg_ = *cfg; lfs_mount(&lfs, cfg) => 0;
if (INFER_BC) {
cfg_.block_count = 0;
}
lfs_mount(&lfs, &cfg_) => 0;
lfs_file_t file; lfs_file_t file;
lfs_file_open(&lfs, &file, "padding", LFS_O_WRONLY | LFS_O_CREAT); lfs_file_open(&lfs, &file, "padding", LFS_O_WRONLY | LFS_O_CREAT);
@@ -347,7 +315,7 @@ code = '''
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg_) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_file_open(&lfs, &file, "exhaustion", LFS_O_RDONLY); lfs_file_open(&lfs, &file, "exhaustion", LFS_O_RDONLY);
size = strlen("exhaustion"); size = strlen("exhaustion");
lfs_file_size(&lfs, &file) => size; lfs_file_size(&lfs, &file) => size;
@@ -360,15 +328,10 @@ code = '''
# dir exhaustion test # dir exhaustion test
[cases.test_alloc_dir_exhaustion] [cases.test_alloc_dir_exhaustion]
defines.INFER_BC = [false, true]
code = ''' code = '''
lfs_t lfs; lfs_t lfs;
lfs_format(&lfs, cfg) => 0; lfs_format(&lfs, cfg) => 0;
struct lfs_config cfg_ = *cfg; lfs_mount(&lfs, cfg) => 0;
if (INFER_BC) {
cfg_.block_count = 0;
}
lfs_mount(&lfs, &cfg_) => 0;
// find out max file size // find out max file size
lfs_mkdir(&lfs, "exhaustiondir") => 0; lfs_mkdir(&lfs, "exhaustiondir") => 0;

View File

@@ -181,10 +181,6 @@ code = '''
defines.N = [5, 11] defines.N = [5, 11]
if = 'BLOCK_COUNT >= 4*N' if = 'BLOCK_COUNT >= 4*N'
reentrant = true reentrant = true
defines.POWERLOSS_BEHAVIOR = [
'LFS_EMUBD_POWERLOSS_NOOP',
'LFS_EMUBD_POWERLOSS_OOO',
]
code = ''' code = '''
lfs_t lfs; lfs_t lfs;
int err = lfs_mount(&lfs, cfg); int err = lfs_mount(&lfs, cfg);
@@ -443,10 +439,6 @@ code = '''
defines.N = [5, 25] defines.N = [5, 25]
if = 'N < BLOCK_COUNT/2' if = 'N < BLOCK_COUNT/2'
reentrant = true reentrant = true
defines.POWERLOSS_BEHAVIOR = [
'LFS_EMUBD_POWERLOSS_NOOP',
'LFS_EMUBD_POWERLOSS_OOO',
]
code = ''' code = '''
lfs_t lfs; lfs_t lfs;
int err = lfs_mount(&lfs, cfg); int err = lfs_mount(&lfs, cfg);
@@ -725,6 +717,105 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
# littlefs should keep directories in lexicographic order
[cases.test_dirs_ordering]
# ORDER=0 => inorder
# ORDER=1 => reversed
# ORDER=2 => random
defines.ORDER = [0, 1, 2]
code = '''
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
if (ORDER == 0) {
lfs_mkdir(&lfs, "a") => 0;
lfs_mkdir(&lfs, "b") => 0;
lfs_mkdir(&lfs, "c") => 0;
} else if (ORDER == 1) {
lfs_mkdir(&lfs, "c") => 0;
lfs_mkdir(&lfs, "b") => 0;
lfs_mkdir(&lfs, "a") => 0;
} else if (ORDER == 2) {
// "random"
lfs_mkdir(&lfs, "a") => 0;
lfs_mkdir(&lfs, "c") => 0;
lfs_mkdir(&lfs, "b") => 0;
}
// check the order
lfs_dir_t dir;
lfs_dir_open(&lfs, &dir, "/") => 0;
struct lfs_info info;
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR);
assert(strcmp(info.name, ".") == 0);
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR);
assert(strcmp(info.name, "..") == 0);
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR);
assert(strcmp(info.name, "a") == 0);
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR);
assert(strcmp(info.name, "b") == 0);
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR);
assert(strcmp(info.name, "c") == 0);
lfs_dir_read(&lfs, &dir, &info) => 0;
lfs_dir_close(&lfs, &dir) => 0;
lfs_unmount(&lfs) => 0;
'''
[cases.test_dirs_ordering_length]
# ORDER=0 => inorder
# ORDER=1 => reversed
# ORDER=2 => random
defines.ORDER = [0, 1, 2]
code = '''
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
if (ORDER == 0) {
lfs_mkdir(&lfs, "a") => 0;
lfs_mkdir(&lfs, "aa") => 0;
lfs_mkdir(&lfs, "aaa") => 0;
} else if (ORDER == 1) {
lfs_mkdir(&lfs, "aaa") => 0;
lfs_mkdir(&lfs, "aa") => 0;
lfs_mkdir(&lfs, "a") => 0;
} else if (ORDER == 2) {
// "random"
lfs_mkdir(&lfs, "a") => 0;
lfs_mkdir(&lfs, "aaa") => 0;
lfs_mkdir(&lfs, "aa") => 0;
}
// check the order
lfs_dir_t dir;
lfs_dir_open(&lfs, &dir, "/") => 0;
struct lfs_info info;
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR);
assert(strcmp(info.name, ".") == 0);
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR);
assert(strcmp(info.name, "..") == 0);
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR);
assert(strcmp(info.name, "a") == 0);
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR);
assert(strcmp(info.name, "aa") == 0);
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR);
assert(strcmp(info.name, "aaa") == 0);
lfs_dir_read(&lfs, &dir, &info) => 0;
lfs_dir_close(&lfs, &dir) => 0;
lfs_unmount(&lfs) => 0;
'''
[cases.test_dirs_other_errors] [cases.test_dirs_other_errors]
code = ''' code = '''
lfs_t lfs; lfs_t lfs;
@@ -755,11 +846,6 @@ code = '''
lfs_file_open(&lfs, &file, "potato", lfs_file_open(&lfs, &file, "potato",
LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR;
lfs_file_open(&lfs, &file, "tacoto", LFS_O_WRONLY | LFS_O_CREAT) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs_rename(&lfs, "tacoto", "potato") => LFS_ERR_ISDIR;
lfs_rename(&lfs, "potato", "tacoto") => LFS_ERR_NOTDIR;
lfs_mkdir(&lfs, "/") => LFS_ERR_EXIST; lfs_mkdir(&lfs, "/") => LFS_ERR_EXIST;
lfs_file_open(&lfs, &file, "/", lfs_file_open(&lfs, &file, "/",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST;
@@ -783,10 +869,6 @@ code = '''
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
assert(strcmp(info.name, "potato") == 0); assert(strcmp(info.name, "potato") == 0);
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_REG);
assert(strcmp(info.name, "tacoto") == 0);
assert(info.size == 0);
lfs_dir_read(&lfs, &dir, &info) => 0; lfs_dir_read(&lfs, &dir, &info) => 0;
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir) => 0;
@@ -807,10 +889,6 @@ code = '''
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
assert(strcmp(info.name, "potato") == 0); assert(strcmp(info.name, "potato") == 0);
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_REG);
assert(strcmp(info.name, "tacoto") == 0);
assert(info.size == 0);
lfs_dir_read(&lfs, &dir, &info) => 0; lfs_dir_read(&lfs, &dir, &info) => 0;
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;

View File

@@ -1,6 +1,5 @@
[cases.test_files_simple] [cases.test_files_simple]
defines.INLINE_MAX = [0, -1, 8]
code = ''' code = '''
lfs_t lfs; lfs_t lfs;
lfs_format(&lfs, cfg) => 0; lfs_format(&lfs, cfg) => 0;
@@ -26,7 +25,6 @@ code = '''
[cases.test_files_large] [cases.test_files_large]
defines.SIZE = [32, 8192, 262144, 0, 7, 8193] defines.SIZE = [32, 8192, 262144, 0, 7, 8193]
defines.CHUNKSIZE = [31, 16, 33, 1, 1023] defines.CHUNKSIZE = [31, 16, 33, 1, 1023]
defines.INLINE_MAX = [0, -1, 8]
code = ''' code = '''
lfs_t lfs; lfs_t lfs;
lfs_format(&lfs, cfg) => 0; lfs_format(&lfs, cfg) => 0;
@@ -69,7 +67,6 @@ code = '''
defines.SIZE1 = [32, 8192, 131072, 0, 7, 8193] defines.SIZE1 = [32, 8192, 131072, 0, 7, 8193]
defines.SIZE2 = [32, 8192, 131072, 0, 7, 8193] defines.SIZE2 = [32, 8192, 131072, 0, 7, 8193]
defines.CHUNKSIZE = [31, 16, 1] defines.CHUNKSIZE = [31, 16, 1]
defines.INLINE_MAX = [0, -1, 8]
code = ''' code = '''
lfs_t lfs; lfs_t lfs;
lfs_format(&lfs, cfg) => 0; lfs_format(&lfs, cfg) => 0;
@@ -155,7 +152,6 @@ code = '''
defines.SIZE1 = [32, 8192, 131072, 0, 7, 8193] defines.SIZE1 = [32, 8192, 131072, 0, 7, 8193]
defines.SIZE2 = [32, 8192, 131072, 0, 7, 8193] defines.SIZE2 = [32, 8192, 131072, 0, 7, 8193]
defines.CHUNKSIZE = [31, 16, 1] defines.CHUNKSIZE = [31, 16, 1]
defines.INLINE_MAX = [0, -1, 8]
code = ''' code = '''
lfs_t lfs; lfs_t lfs;
lfs_format(&lfs, cfg) => 0; lfs_format(&lfs, cfg) => 0;
@@ -236,7 +232,6 @@ code = '''
defines.SIZE1 = [32, 8192, 131072, 0, 7, 8193] defines.SIZE1 = [32, 8192, 131072, 0, 7, 8193]
defines.SIZE2 = [32, 8192, 131072, 0, 7, 8193] defines.SIZE2 = [32, 8192, 131072, 0, 7, 8193]
defines.CHUNKSIZE = [31, 16, 1] defines.CHUNKSIZE = [31, 16, 1]
defines.INLINE_MAX = [0, -1, 8]
code = ''' code = '''
lfs_t lfs; lfs_t lfs;
lfs_format(&lfs, cfg) => 0; lfs_format(&lfs, cfg) => 0;
@@ -308,12 +303,7 @@ code = '''
[cases.test_files_reentrant_write] [cases.test_files_reentrant_write]
defines.SIZE = [32, 0, 7, 2049] defines.SIZE = [32, 0, 7, 2049]
defines.CHUNKSIZE = [31, 16, 65] defines.CHUNKSIZE = [31, 16, 65]
defines.INLINE_MAX = [0, -1, 8]
reentrant = true reentrant = true
defines.POWERLOSS_BEHAVIOR = [
'LFS_EMUBD_POWERLOSS_NOOP',
'LFS_EMUBD_POWERLOSS_OOO',
]
code = ''' code = '''
lfs_t lfs; lfs_t lfs;
int err = lfs_mount(&lfs, cfg); int err = lfs_mount(&lfs, cfg);
@@ -364,20 +354,11 @@ code = '''
[cases.test_files_reentrant_write_sync] [cases.test_files_reentrant_write_sync]
defines = [ defines = [
# append (O(n)) # append (O(n))
{MODE='LFS_O_APPEND', {MODE='LFS_O_APPEND', SIZE=[32, 0, 7, 2049], CHUNKSIZE=[31, 16, 65]},
SIZE=[32, 0, 7, 2049],
CHUNKSIZE=[31, 16, 65],
INLINE_MAX=[0, -1, 8]},
# truncate (O(n^2)) # truncate (O(n^2))
{MODE='LFS_O_TRUNC', {MODE='LFS_O_TRUNC', SIZE=[32, 0, 7, 200], CHUNKSIZE=[31, 16, 65]},
SIZE=[32, 0, 7, 200],
CHUNKSIZE=[31, 16, 65],
INLINE_MAX=[0, -1, 8]},
# rewrite (O(n^2)) # rewrite (O(n^2))
{MODE=0, {MODE=0, SIZE=[32, 0, 7, 200], CHUNKSIZE=[31, 16, 65]},
SIZE=[32, 0, 7, 200],
CHUNKSIZE=[31, 16, 65],
INLINE_MAX=[0, -1, 8]},
] ]
reentrant = true reentrant = true
code = ''' code = '''
@@ -504,10 +485,6 @@ code = '''
[cases.test_files_many_power_loss] [cases.test_files_many_power_loss]
defines.N = 300 defines.N = 300
reentrant = true reentrant = true
defines.POWERLOSS_BEHAVIOR = [
'LFS_EMUBD_POWERLOSS_NOOP',
'LFS_EMUBD_POWERLOSS_OOO',
]
code = ''' code = '''
lfs_t lfs; lfs_t lfs;
int err = lfs_mount(&lfs, cfg); int err = lfs_mount(&lfs, cfg);

View File

@@ -195,10 +195,6 @@ code = '''
defines.SIZE = [10, 100] defines.SIZE = [10, 100]
defines.FILES = [4, 10, 26] defines.FILES = [4, 10, 26]
reentrant = true reentrant = true
defines.POWERLOSS_BEHAVIOR = [
'LFS_EMUBD_POWERLOSS_NOOP',
'LFS_EMUBD_POWERLOSS_OOO',
]
code = ''' code = '''
lfs_t lfs; lfs_t lfs;
lfs_file_t files[FILES]; lfs_file_t files[FILES];

View File

@@ -357,10 +357,6 @@ code = '''
[cases.test_move_reentrant_file] [cases.test_move_reentrant_file]
reentrant = true reentrant = true
defines.POWERLOSS_BEHAVIOR = [
'LFS_EMUBD_POWERLOSS_NOOP',
'LFS_EMUBD_POWERLOSS_OOO',
]
code = ''' code = '''
lfs_t lfs; lfs_t lfs;
int err = lfs_mount(&lfs, cfg); int err = lfs_mount(&lfs, cfg);
@@ -843,10 +839,6 @@ code = '''
[cases.test_reentrant_dir] [cases.test_reentrant_dir]
reentrant = true reentrant = true
defines.POWERLOSS_BEHAVIOR = [
'LFS_EMUBD_POWERLOSS_NOOP',
'LFS_EMUBD_POWERLOSS_OOO',
]
code = ''' code = '''
lfs_t lfs; lfs_t lfs;
int err = lfs_mount(&lfs, cfg); int err = lfs_mount(&lfs, cfg);

View File

@@ -98,7 +98,7 @@ code = '''
lfs_mount(&lfs, cfg) => 0; lfs_mount(&lfs, cfg) => 0;
// create an orphan // create an orphan
lfs_mdir_t orphan; lfs_mdir_t orphan;
lfs_alloc_ckpoint(&lfs); lfs_alloc_ack(&lfs);
lfs_dir_alloc(&lfs, &orphan) => 0; lfs_dir_alloc(&lfs, &orphan) => 0;
lfs_dir_commit(&lfs, &orphan, NULL, 0) => 0; lfs_dir_commit(&lfs, &orphan, NULL, 0) => 0;
@@ -170,7 +170,7 @@ code = '''
lfs_mount(&lfs, cfg) => 0; lfs_mount(&lfs, cfg) => 0;
// create an orphan // create an orphan
lfs_mdir_t orphan; lfs_mdir_t orphan;
lfs_alloc_ckpoint(&lfs); lfs_alloc_ack(&lfs);
lfs_dir_alloc(&lfs, &orphan) => 0; lfs_dir_alloc(&lfs, &orphan) => 0;
lfs_dir_commit(&lfs, &orphan, NULL, 0) => 0; lfs_dir_commit(&lfs, &orphan, NULL, 0) => 0;

View File

@@ -329,10 +329,6 @@ code = '''
# must be power-of-2 for quadratic probing to be exhaustive # must be power-of-2 for quadratic probing to be exhaustive
defines.COUNT = [4, 64, 128] defines.COUNT = [4, 64, 128]
reentrant = true reentrant = true
defines.POWERLOSS_BEHAVIOR = [
'LFS_EMUBD_POWERLOSS_NOOP',
'LFS_EMUBD_POWERLOSS_OOO',
]
code = ''' code = '''
lfs_t lfs; lfs_t lfs;
int err = lfs_mount(&lfs, cfg); int err = lfs_mount(&lfs, cfg);

View File

@@ -32,10 +32,6 @@ code = '''
# reentrant format # reentrant format
[cases.test_superblocks_reentrant_format] [cases.test_superblocks_reentrant_format]
reentrant = true reentrant = true
defines.POWERLOSS_BEHAVIOR = [
'LFS_EMUBD_POWERLOSS_NOOP',
'LFS_EMUBD_POWERLOSS_OOO',
]
code = ''' code = '''
lfs_t lfs; lfs_t lfs;
int err = lfs_mount(&lfs, cfg); int err = lfs_mount(&lfs, cfg);
@@ -178,10 +174,6 @@ code = '''
defines.BLOCK_CYCLES = [2, 1] defines.BLOCK_CYCLES = [2, 1]
defines.N = 24 defines.N = 24
reentrant = true reentrant = true
defines.POWERLOSS_BEHAVIOR = [
'LFS_EMUBD_POWERLOSS_NOOP',
'LFS_EMUBD_POWERLOSS_OOO',
]
code = ''' code = '''
lfs_t lfs; lfs_t lfs;
int err = lfs_mount(&lfs, cfg); int err = lfs_mount(&lfs, cfg);

View File

@@ -231,10 +231,6 @@ defines.SMALLSIZE = [4, 512]
defines.MEDIUMSIZE = [0, 3, 4, 5, 31, 32, 33, 511, 512, 513, 1023, 1024, 1025] defines.MEDIUMSIZE = [0, 3, 4, 5, 31, 32, 33, 511, 512, 513, 1023, 1024, 1025]
defines.LARGESIZE = 2048 defines.LARGESIZE = 2048
reentrant = true reentrant = true
defines.POWERLOSS_BEHAVIOR = [
'LFS_EMUBD_POWERLOSS_NOOP',
'LFS_EMUBD_POWERLOSS_OOO',
]
code = ''' code = '''
lfs_t lfs; lfs_t lfs;
int err = lfs_mount(&lfs, cfg); int err = lfs_mount(&lfs, cfg);