Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/littlefs-project/littlefs.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/post-release.yml2
-rw-r--r--.github/workflows/release.yml2
-rw-r--r--.github/workflows/status.yml4
-rw-r--r--.github/workflows/test.yml24
-rw-r--r--bd/lfs_emubd.c6
-rw-r--r--lfs.c462
-rw-r--r--lfs.h78
-rw-r--r--lfs_util.c3
-rw-r--r--lfs_util.h18
-rw-r--r--runners/bench_runner.c2
-rw-r--r--runners/bench_runner.h18
-rw-r--r--runners/test_runner.c10
-rw-r--r--runners/test_runner.h20
-rw-r--r--tests/test_alloc.toml2
-rw-r--r--tests/test_dirs.toml13
-rw-r--r--tests/test_files.toml21
-rw-r--r--tests/test_orphans.toml4
17 files changed, 447 insertions, 242 deletions
diff --git a/.github/workflows/post-release.yml b/.github/workflows/post-release.yml
index 6524124..8104a94 100644
--- a/.github/workflows/post-release.yml
+++ b/.github/workflows/post-release.yml
@@ -10,7 +10,7 @@ defaults:
jobs:
post-release:
- runs-on: ubuntu-22.04
+ runs-on: ubuntu-latest
steps:
# trigger post-release in dependency repo, this indirection allows the
# dependency repo to be updated often without affecting this repo. At
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 5ccc9e0..055b54a 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -11,7 +11,7 @@ defaults:
jobs:
release:
- runs-on: ubuntu-22.04
+ runs-on: ubuntu-latest
# need to manually check for a couple things
# - tests passed?
diff --git a/.github/workflows/status.yml b/.github/workflows/status.yml
index 8bd3990..e6e983a 100644
--- a/.github/workflows/status.yml
+++ b/.github/workflows/status.yml
@@ -11,7 +11,7 @@ defaults:
jobs:
# forward custom statuses
status:
- runs-on: ubuntu-22.04
+ runs-on: ubuntu-latest
steps:
- uses: dawidd6/action-download-artifact@v2
continue-on-error: true
@@ -60,7 +60,7 @@ jobs:
# forward custom pr-comments
comment:
- runs-on: ubuntu-22.04
+ runs-on: ubuntu-latest
# only run on success (we don't want garbage comments!)
if: ${{github.event.workflow_run.conclusion == 'success'}}
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index ccb08fe..db3413b 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -14,7 +14,7 @@ env:
jobs:
# run tests
test:
- runs-on: ubuntu-22.04
+ runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
@@ -329,7 +329,7 @@ jobs:
#
# this grows exponentially, so it doesn't turn out to be that many
test-pls:
- runs-on: ubuntu-22.04
+ runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
@@ -359,7 +359,7 @@ jobs:
# run with LFS_NO_INTRINSICS to make sure that works
test-no-intrinsics:
- runs-on: ubuntu-22.04
+ runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: install
@@ -376,7 +376,7 @@ jobs:
# run LFS_MULTIVERSION tests
test-multiversion:
- runs-on: ubuntu-22.04
+ runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: install
@@ -393,7 +393,7 @@ jobs:
# run tests on the older version lfs2.0
test-lfs2_0:
- runs-on: ubuntu-22.04
+ runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: install
@@ -412,7 +412,7 @@ jobs:
# run under Valgrind to check for memory errors
test-valgrind:
- runs-on: ubuntu-22.04
+ runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: install
@@ -434,7 +434,7 @@ jobs:
# test that compilation is warning free under clang
# run with Clang, mostly to check for Clang-specific warnings
test-clang:
- runs-on: ubuntu-22.04
+ runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: install
@@ -457,7 +457,7 @@ jobs:
#
# note there's no real benefit to running these on multiple archs
bench:
- runs-on: ubuntu-22.04
+ runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: install
@@ -533,7 +533,7 @@ jobs:
# run compatibility tests using the current master as the previous version
test-compat:
- runs-on: ubuntu-22.04
+ runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
if: ${{github.event_name == 'pull_request'}}
@@ -569,7 +569,7 @@ jobs:
# self-host with littlefs-fuse for a fuzz-like test
fuse:
- runs-on: ubuntu-22.04
+ runs-on: ubuntu-latest
if: ${{!endsWith(github.ref, '-prefix')}}
steps:
- uses: actions/checkout@v2
@@ -619,7 +619,7 @@ jobs:
# test migration using littlefs-fuse
migrate:
- runs-on: ubuntu-22.04
+ runs-on: ubuntu-latest
if: ${{!endsWith(github.ref, '-prefix')}}
steps:
- uses: actions/checkout@v2
@@ -691,7 +691,7 @@ jobs:
# status related tasks that run after tests
status:
- runs-on: ubuntu-22.04
+ runs-on: ubuntu-latest
needs: [test, bench]
steps:
- uses: actions/checkout@v2
diff --git a/bd/lfs_emubd.c b/bd/lfs_emubd.c
index c27ae30..9d88d05 100644
--- a/bd/lfs_emubd.c
+++ b/bd/lfs_emubd.c
@@ -451,7 +451,7 @@ int lfs_emubd_sync(const struct lfs_config *cfg) {
/// Additional extended API for driving test features ///
-static int lfs_emubd_rawcrc(const struct lfs_config *cfg,
+static int lfs_emubd_crc_(const struct lfs_config *cfg,
lfs_block_t block, uint32_t *crc) {
lfs_emubd_t *bd = cfg->context;
@@ -480,7 +480,7 @@ int lfs_emubd_crc(const struct lfs_config *cfg,
lfs_block_t block, uint32_t *crc) {
LFS_EMUBD_TRACE("lfs_emubd_crc(%p, %"PRIu32", %p)",
(void*)cfg, block, crc);
- int err = lfs_emubd_rawcrc(cfg, block, crc);
+ int err = lfs_emubd_crc_(cfg, block, crc);
LFS_EMUBD_TRACE("lfs_emubd_crc -> %d", err);
return err;
}
@@ -491,7 +491,7 @@ int lfs_emubd_bdcrc(const struct lfs_config *cfg, uint32_t *crc) {
uint32_t crc_ = 0xffffffff;
for (lfs_block_t i = 0; i < cfg->block_count; i++) {
uint32_t i_crc;
- int err = lfs_emubd_rawcrc(cfg, i, &i_crc);
+ int err = lfs_emubd_crc_(cfg, i, &i_crc);
if (err) {
LFS_EMUBD_TRACE("lfs_emubd_bdcrc -> %d", err);
return err;
diff --git a/lfs.c b/lfs.c
index a152687..d5885ca 100644
--- a/lfs.c
+++ b/lfs.c
@@ -550,9 +550,9 @@ static int lfs_dir_compact(lfs_t *lfs,
lfs_mdir_t *source, uint16_t begin, uint16_t end);
static lfs_ssize_t lfs_file_flushedwrite(lfs_t *lfs, lfs_file_t *file,
const void *buffer, lfs_size_t size);
-static lfs_ssize_t lfs_file_rawwrite(lfs_t *lfs, lfs_file_t *file,
+static lfs_ssize_t lfs_file_write_(lfs_t *lfs, lfs_file_t *file,
const void *buffer, lfs_size_t size);
-static int lfs_file_rawsync(lfs_t *lfs, lfs_file_t *file);
+static int lfs_file_sync_(lfs_t *lfs, lfs_file_t *file);
static int lfs_file_outline(lfs_t *lfs, lfs_file_t *file);
static int lfs_file_flush(lfs_t *lfs, lfs_file_t *file);
@@ -574,65 +574,72 @@ static int lfs1_traverse(lfs_t *lfs,
int (*cb)(void*, lfs_block_t), void *data);
#endif
-static int lfs_dir_rawrewind(lfs_t *lfs, lfs_dir_t *dir);
+static int lfs_dir_rewind_(lfs_t *lfs, lfs_dir_t *dir);
static lfs_ssize_t lfs_file_flushedread(lfs_t *lfs, lfs_file_t *file,
void *buffer, lfs_size_t size);
-static lfs_ssize_t lfs_file_rawread(lfs_t *lfs, lfs_file_t *file,
+static lfs_ssize_t lfs_file_read_(lfs_t *lfs, lfs_file_t *file,
void *buffer, lfs_size_t size);
-static int lfs_file_rawclose(lfs_t *lfs, lfs_file_t *file);
-static lfs_soff_t lfs_file_rawsize(lfs_t *lfs, lfs_file_t *file);
+static int lfs_file_close_(lfs_t *lfs, lfs_file_t *file);
+static lfs_soff_t lfs_file_size_(lfs_t *lfs, lfs_file_t *file);
-static lfs_ssize_t lfs_fs_rawsize(lfs_t *lfs);
-static int lfs_fs_rawtraverse(lfs_t *lfs,
+static lfs_ssize_t lfs_fs_size_(lfs_t *lfs);
+static int lfs_fs_traverse_(lfs_t *lfs,
int (*cb)(void *data, lfs_block_t block), void *data,
bool includeorphans);
static int lfs_deinit(lfs_t *lfs);
-static int lfs_rawunmount(lfs_t *lfs);
+static int lfs_unmount_(lfs_t *lfs);
/// Block allocator ///
+
+// allocations should call this when all allocated blocks are committed to
+// the filesystem
+//
+// after a checkpoint, the block allocator may realloc any untracked blocks
+static void lfs_alloc_ckpoint(lfs_t *lfs) {
+ lfs->lookahead.ckpoint = lfs->block_count;
+}
+
+// drop the lookahead buffer, this is done during mounting and failed
+// traversals in order to avoid invalid lookahead state
+static void lfs_alloc_drop(lfs_t *lfs) {
+ lfs->lookahead.size = 0;
+ lfs->lookahead.next = 0;
+ lfs_alloc_ckpoint(lfs);
+}
+
#ifndef LFS_READONLY
static int lfs_alloc_lookahead(void *p, lfs_block_t block) {
lfs_t *lfs = (lfs_t*)p;
- lfs_block_t off = ((block - lfs->free.off)
+ lfs_block_t off = ((block - lfs->lookahead.start)
+ lfs->block_count) % lfs->block_count;
- if (off < lfs->free.size) {
- lfs->free.buffer[off / 32] |= 1U << (off % 32);
+ if (off < lfs->lookahead.size) {
+ lfs->lookahead.buffer[off / 8] |= 1U << (off % 8);
}
return 0;
}
#endif
-// indicate allocated blocks have been committed into the filesystem, this
-// is to prevent blocks from being garbage collected in the middle of a
-// commit operation
-static void lfs_alloc_ack(lfs_t *lfs) {
- lfs->free.ack = lfs->block_count;
-}
-
-// drop the lookahead buffer, this is done during mounting and failed
-// traversals in order to avoid invalid lookahead state
-static void lfs_alloc_drop(lfs_t *lfs) {
- lfs->free.size = 0;
- lfs->free.i = 0;
- lfs_alloc_ack(lfs);
-}
-
#ifndef LFS_READONLY
-static int lfs_fs_rawgc(lfs_t *lfs) {
- // Move free offset at the first unused block (lfs->free.i)
- // lfs->free.i is equal lfs->free.size when all blocks are used
- lfs->free.off = (lfs->free.off + lfs->free.i) % lfs->block_count;
- lfs->free.size = lfs_min(8*lfs->cfg->lookahead_size, lfs->free.ack);
- lfs->free.i = 0;
+static int lfs_alloc_scan(lfs_t *lfs) {
+ // move lookahead buffer to the first unused block
+ //
+ // note we limit the lookahead buffer to at most the amount of blocks
+ // checkpointed, this prevents the math in lfs_alloc from underflowing
+ lfs->lookahead.start = (lfs->lookahead.start + lfs->lookahead.next)
+ % lfs->block_count;
+ lfs->lookahead.next = 0;
+ lfs->lookahead.size = lfs_min(
+ 8*lfs->cfg->lookahead_size,
+ lfs->lookahead.ckpoint);
// find mask of free blocks from tree
- memset(lfs->free.buffer, 0, lfs->cfg->lookahead_size);
- int err = lfs_fs_rawtraverse(lfs, lfs_alloc_lookahead, lfs, true);
+ memset(lfs->lookahead.buffer, 0, lfs->cfg->lookahead_size);
+ int err = lfs_fs_traverse_(lfs, lfs_alloc_lookahead, lfs, true);
if (err) {
lfs_alloc_drop(lfs);
return err;
@@ -645,36 +652,49 @@ static int lfs_fs_rawgc(lfs_t *lfs) {
#ifndef LFS_READONLY
static int lfs_alloc(lfs_t *lfs, lfs_block_t *block) {
while (true) {
- while (lfs->free.i != lfs->free.size) {
- lfs_block_t off = lfs->free.i;
- lfs->free.i += 1;
- lfs->free.ack -= 1;
-
- if (!(lfs->free.buffer[off / 32] & (1U << (off % 32)))) {
+ // scan our lookahead buffer for free blocks
+ while (lfs->lookahead.next < lfs->lookahead.size) {
+ if (!(lfs->lookahead.buffer[lfs->lookahead.next / 8]
+ & (1U << (lfs->lookahead.next % 8)))) {
// found a free block
- *block = (lfs->free.off + off) % lfs->block_count;
-
- // eagerly find next off so an alloc ack can
- // discredit old lookahead blocks
- while (lfs->free.i != lfs->free.size &&
- (lfs->free.buffer[lfs->free.i / 32]
- & (1U << (lfs->free.i % 32)))) {
- lfs->free.i += 1;
- lfs->free.ack -= 1;
+ *block = (lfs->lookahead.start + lfs->lookahead.next)
+ % lfs->block_count;
+
+ // eagerly find next free block to maximize how many blocks
+ // lfs_alloc_ckpoint makes available for scanning
+ while (true) {
+ lfs->lookahead.next += 1;
+ lfs->lookahead.ckpoint -= 1;
+
+ if (lfs->lookahead.next >= lfs->lookahead.size
+ || !(lfs->lookahead.buffer[lfs->lookahead.next / 8]
+ & (1U << (lfs->lookahead.next % 8)))) {
+ return 0;
+ }
}
-
- return 0;
}
+
+ lfs->lookahead.next += 1;
+ lfs->lookahead.ckpoint -= 1;
}
- // check if we have looked at all blocks since last ack
- if (lfs->free.ack == 0) {
- LFS_ERROR("No more free space %"PRIu32,
- lfs->free.i + lfs->free.off);
+ // In order to keep our block allocator from spinning forever when our
+ // filesystem is full, we mark points where there are no in-flight
+ // allocations with a checkpoint before starting a set of allocations.
+ //
+ // If we've looked at all blocks since the last checkpoint, we report
+ // the filesystem as out of storage.
+ //
+ if (lfs->lookahead.ckpoint <= 0) {
+ LFS_ERROR("No more free space 0x%"PRIx32,
+ (lfs->lookahead.start + lfs->lookahead.next)
+ % lfs->cfg->block_count);
return LFS_ERR_NOSPC;
}
- int err = lfs_fs_rawgc(lfs);
+ // No blocks in our lookahead buffer, we need to scan the filesystem for
+ // unused blocks in the next lookahead window.
+ int err = lfs_alloc_scan(lfs);
if(err) {
return err;
}
@@ -2146,7 +2166,7 @@ static int lfs_dir_splittingcompact(lfs_t *lfs, lfs_mdir_t *dir,
&& lfs_pair_cmp(dir->pair, (const lfs_block_t[2]){0, 1}) == 0) {
// oh no! we're writing too much to the superblock,
// should we expand?
- lfs_ssize_t size = lfs_fs_rawsize(lfs);
+ lfs_ssize_t size = lfs_fs_size_(lfs);
if (size < 0) {
return size;
}
@@ -2566,7 +2586,7 @@ static int lfs_dir_commit(lfs_t *lfs, lfs_mdir_t *dir,
/// Top level directory operations ///
#ifndef LFS_READONLY
-static int lfs_rawmkdir(lfs_t *lfs, const char *path) {
+static int lfs_mkdir_(lfs_t *lfs, const char *path) {
// deorphan if we haven't yet, needed at most once after poweron
int err = lfs_fs_forceconsistency(lfs);
if (err) {
@@ -2588,7 +2608,7 @@ static int lfs_rawmkdir(lfs_t *lfs, const char *path) {
}
// build up new directory
- lfs_alloc_ack(lfs);
+ lfs_alloc_ckpoint(lfs);
lfs_mdir_t dir;
err = lfs_dir_alloc(lfs, &dir);
if (err) {
@@ -2662,7 +2682,7 @@ static int lfs_rawmkdir(lfs_t *lfs, const char *path) {
}
#endif
-static int lfs_dir_rawopen(lfs_t *lfs, lfs_dir_t *dir, const char *path) {
+static int lfs_dir_open_(lfs_t *lfs, lfs_dir_t *dir, const char *path) {
lfs_stag_t tag = lfs_dir_find(lfs, &dir->m, &path, NULL);
if (tag < 0) {
return tag;
@@ -2706,14 +2726,14 @@ static int lfs_dir_rawopen(lfs_t *lfs, lfs_dir_t *dir, const char *path) {
return 0;
}
-static int lfs_dir_rawclose(lfs_t *lfs, lfs_dir_t *dir) {
+static int lfs_dir_close_(lfs_t *lfs, lfs_dir_t *dir) {
// remove from list of mdirs
lfs_mlist_remove(lfs, (struct lfs_mlist *)dir);
return 0;
}
-static int lfs_dir_rawread(lfs_t *lfs, lfs_dir_t *dir, struct lfs_info *info) {
+static int lfs_dir_read_(lfs_t *lfs, lfs_dir_t *dir, struct lfs_info *info) {
memset(info, 0, sizeof(*info));
// special offset for '.' and '..'
@@ -2758,9 +2778,9 @@ static int lfs_dir_rawread(lfs_t *lfs, lfs_dir_t *dir, struct lfs_info *info) {
return true;
}
-static int lfs_dir_rawseek(lfs_t *lfs, lfs_dir_t *dir, lfs_off_t off) {
+static int lfs_dir_seek_(lfs_t *lfs, lfs_dir_t *dir, lfs_off_t off) {
// simply walk from head dir
- int err = lfs_dir_rawrewind(lfs, dir);
+ int err = lfs_dir_rewind_(lfs, dir);
if (err) {
return err;
}
@@ -2795,12 +2815,12 @@ static int lfs_dir_rawseek(lfs_t *lfs, lfs_dir_t *dir, lfs_off_t off) {
return 0;
}
-static lfs_soff_t lfs_dir_rawtell(lfs_t *lfs, lfs_dir_t *dir) {
+static lfs_soff_t lfs_dir_tell_(lfs_t *lfs, lfs_dir_t *dir) {
(void)lfs;
return dir->pos;
}
-static int lfs_dir_rawrewind(lfs_t *lfs, lfs_dir_t *dir) {
+static int lfs_dir_rewind_(lfs_t *lfs, lfs_dir_t *dir) {
// reload the head dir
int err = lfs_dir_fetch(lfs, &dir->m, dir->head);
if (err) {
@@ -3006,7 +3026,7 @@ static int lfs_ctz_traverse(lfs_t *lfs,
/// Top level file operations ///
-static int lfs_file_rawopencfg(lfs_t *lfs, lfs_file_t *file,
+static int lfs_file_opencfg_(lfs_t *lfs, lfs_file_t *file,
const char *path, int flags,
const struct lfs_file_config *cfg) {
#ifndef LFS_READONLY
@@ -3168,22 +3188,22 @@ cleanup:
#ifndef LFS_READONLY
file->flags |= LFS_F_ERRED;
#endif
- lfs_file_rawclose(lfs, file);
+ lfs_file_close_(lfs, file);
return err;
}
#ifndef LFS_NO_MALLOC
-static int lfs_file_rawopen(lfs_t *lfs, lfs_file_t *file,
+static int lfs_file_open_(lfs_t *lfs, lfs_file_t *file,
const char *path, int flags) {
static const struct lfs_file_config defaults = {0};
- int err = lfs_file_rawopencfg(lfs, file, path, flags, &defaults);
+ int err = lfs_file_opencfg_(lfs, file, path, flags, &defaults);
return err;
}
#endif
-static int lfs_file_rawclose(lfs_t *lfs, lfs_file_t *file) {
+static int lfs_file_close_(lfs_t *lfs, lfs_file_t *file) {
#ifndef LFS_READONLY
- int err = lfs_file_rawsync(lfs, file);
+ int err = lfs_file_sync_(lfs, file);
#else
int err = 0;
#endif
@@ -3274,7 +3294,7 @@ relocate:
#ifndef LFS_READONLY
static int lfs_file_outline(lfs_t *lfs, lfs_file_t *file) {
file->off = file->pos;
- lfs_alloc_ack(lfs);
+ lfs_alloc_ckpoint(lfs);
int err = lfs_file_relocate(lfs, file);
if (err) {
return err;
@@ -3366,7 +3386,7 @@ relocate:
}
#ifndef LFS_READONLY
-static int lfs_file_rawsync(lfs_t *lfs, lfs_file_t *file) {
+static int lfs_file_sync_(lfs_t *lfs, lfs_file_t *file) {
if (file->flags & LFS_F_ERRED) {
// it's not safe to do anything if our file errored
return 0;
@@ -3479,7 +3499,7 @@ static lfs_ssize_t lfs_file_flushedread(lfs_t *lfs, lfs_file_t *file,
return size;
}
-static lfs_ssize_t lfs_file_rawread(lfs_t *lfs, lfs_file_t *file,
+static lfs_ssize_t lfs_file_read_(lfs_t *lfs, lfs_file_t *file,
void *buffer, lfs_size_t size) {
LFS_ASSERT((file->flags & LFS_O_RDONLY) == LFS_O_RDONLY);
@@ -3504,11 +3524,7 @@ static lfs_ssize_t lfs_file_flushedwrite(lfs_t *lfs, lfs_file_t *file,
lfs_size_t nsize = size;
if ((file->flags & LFS_F_INLINE) &&
- lfs_max(file->pos+nsize, file->ctz.size) >
- lfs_min(0x3fe, lfs_min(
- lfs->cfg->cache_size,
- (lfs->cfg->metadata_max ?
- lfs->cfg->metadata_max : lfs->cfg->block_size) / 8))) {
+ lfs_max(file->pos+nsize, file->ctz.size) > lfs->inline_max) {
// inline file doesn't fit anymore
int err = lfs_file_outline(lfs, file);
if (err) {
@@ -3537,7 +3553,7 @@ static lfs_ssize_t lfs_file_flushedwrite(lfs_t *lfs, lfs_file_t *file,
}
// extend file with new blocks
- lfs_alloc_ack(lfs);
+ lfs_alloc_ckpoint(lfs);
int err = lfs_ctz_extend(lfs, &file->cache, &lfs->rcache,
file->block, file->pos,
&file->block, &file->off);
@@ -3580,13 +3596,13 @@ relocate:
data += diff;
nsize -= diff;
- lfs_alloc_ack(lfs);
+ lfs_alloc_ckpoint(lfs);
}
return size;
}
-static lfs_ssize_t lfs_file_rawwrite(lfs_t *lfs, lfs_file_t *file,
+static lfs_ssize_t lfs_file_write_(lfs_t *lfs, lfs_file_t *file,
const void *buffer, lfs_size_t size) {
LFS_ASSERT((file->flags & LFS_O_WRONLY) == LFS_O_WRONLY);
@@ -3630,7 +3646,7 @@ static lfs_ssize_t lfs_file_rawwrite(lfs_t *lfs, lfs_file_t *file,
}
#endif
-static lfs_soff_t lfs_file_rawseek(lfs_t *lfs, lfs_file_t *file,
+static lfs_soff_t lfs_file_seek_(lfs_t *lfs, lfs_file_t *file,
lfs_soff_t off, int whence) {
// find new pos
lfs_off_t npos = file->pos;
@@ -3643,7 +3659,7 @@ static lfs_soff_t lfs_file_rawseek(lfs_t *lfs, lfs_file_t *file,
npos = file->pos + off;
}
} else if (whence == LFS_SEEK_END) {
- lfs_soff_t res = lfs_file_rawsize(lfs, file) + off;
+ lfs_soff_t res = lfs_file_size_(lfs, file) + off;
if (res < 0) {
return LFS_ERR_INVAL;
} else {
@@ -3694,7 +3710,7 @@ static lfs_soff_t lfs_file_rawseek(lfs_t *lfs, lfs_file_t *file,
}
#ifndef LFS_READONLY
-static int lfs_file_rawtruncate(lfs_t *lfs, lfs_file_t *file, lfs_off_t size) {
+static int lfs_file_truncate_(lfs_t *lfs, lfs_file_t *file, lfs_off_t size) {
LFS_ASSERT((file->flags & LFS_O_WRONLY) == LFS_O_WRONLY);
if (size > LFS_FILE_MAX) {
@@ -3702,15 +3718,12 @@ static int lfs_file_rawtruncate(lfs_t *lfs, lfs_file_t *file, lfs_off_t size) {
}
lfs_off_t pos = file->pos;
- lfs_off_t oldsize = lfs_file_rawsize(lfs, file);
+ lfs_off_t oldsize = lfs_file_size_(lfs, file);
if (size < oldsize) {
// revert to inline file?
- if (size <= lfs_min(0x3fe, lfs_min(
- lfs->cfg->cache_size,
- (lfs->cfg->metadata_max ?
- lfs->cfg->metadata_max : lfs->cfg->block_size) / 8))) {
+ if (size <= lfs->inline_max) {
// flush+seek to head
- lfs_soff_t res = lfs_file_rawseek(lfs, file, 0, LFS_SEEK_SET);
+ lfs_soff_t res = lfs_file_seek_(lfs, file, 0, LFS_SEEK_SET);
if (res < 0) {
return (int)res;
}
@@ -3755,14 +3768,14 @@ static int lfs_file_rawtruncate(lfs_t *lfs, lfs_file_t *file, lfs_off_t size) {
}
} else if (size > oldsize) {
// flush+seek if not already at end
- lfs_soff_t res = lfs_file_rawseek(lfs, file, 0, LFS_SEEK_END);
+ lfs_soff_t res = lfs_file_seek_(lfs, file, 0, LFS_SEEK_END);
if (res < 0) {
return (int)res;
}
// fill with zeros
while (file->pos < size) {
- res = lfs_file_rawwrite(lfs, file, &(uint8_t){0}, 1);
+ res = lfs_file_write_(lfs, file, &(uint8_t){0}, 1);
if (res < 0) {
return (int)res;
}
@@ -3770,7 +3783,7 @@ static int lfs_file_rawtruncate(lfs_t *lfs, lfs_file_t *file, lfs_off_t size) {
}
// restore pos
- lfs_soff_t res = lfs_file_rawseek(lfs, file, pos, LFS_SEEK_SET);
+ lfs_soff_t res = lfs_file_seek_(lfs, file, pos, LFS_SEEK_SET);
if (res < 0) {
return (int)res;
}
@@ -3779,13 +3792,13 @@ static int lfs_file_rawtruncate(lfs_t *lfs, lfs_file_t *file, lfs_off_t size) {
}
#endif
-static lfs_soff_t lfs_file_rawtell(lfs_t *lfs, lfs_file_t *file) {
+static lfs_soff_t lfs_file_tell_(lfs_t *lfs, lfs_file_t *file) {
(void)lfs;
return file->pos;
}
-static int lfs_file_rawrewind(lfs_t *lfs, lfs_file_t *file) {
- lfs_soff_t res = lfs_file_rawseek(lfs, file, 0, LFS_SEEK_SET);
+static int lfs_file_rewind_(lfs_t *lfs, lfs_file_t *file) {
+ lfs_soff_t res = lfs_file_seek_(lfs, file, 0, LFS_SEEK_SET);
if (res < 0) {
return (int)res;
}
@@ -3793,7 +3806,7 @@ static int lfs_file_rawrewind(lfs_t *lfs, lfs_file_t *file) {
return 0;
}
-static lfs_soff_t lfs_file_rawsize(lfs_t *lfs, lfs_file_t *file) {
+static lfs_soff_t lfs_file_size_(lfs_t *lfs, lfs_file_t *file) {
(void)lfs;
#ifndef LFS_READONLY
@@ -3807,7 +3820,7 @@ static lfs_soff_t lfs_file_rawsize(lfs_t *lfs, lfs_file_t *file) {
/// General fs operations ///
-static int lfs_rawstat(lfs_t *lfs, const char *path, struct lfs_info *info) {
+static int lfs_stat_(lfs_t *lfs, const char *path, struct lfs_info *info) {
lfs_mdir_t cwd;
lfs_stag_t tag = lfs_dir_find(lfs, &cwd, &path, NULL);
if (tag < 0) {
@@ -3818,7 +3831,7 @@ static int lfs_rawstat(lfs_t *lfs, const char *path, struct lfs_info *info) {
}
#ifndef LFS_READONLY
-static int lfs_rawremove(lfs_t *lfs, const char *path) {
+static int lfs_remove_(lfs_t *lfs, const char *path) {
// deorphan if we haven't yet, needed at most once after poweron
int err = lfs_fs_forceconsistency(lfs);
if (err) {
@@ -3897,7 +3910,7 @@ static int lfs_rawremove(lfs_t *lfs, const char *path) {
#endif
#ifndef LFS_READONLY
-static int lfs_rawrename(lfs_t *lfs, const char *oldpath, const char *newpath) {
+static int lfs_rename_(lfs_t *lfs, const char *oldpath, const char *newpath) {
// deorphan if we haven't yet, needed at most once after poweron
int err = lfs_fs_forceconsistency(lfs);
if (err) {
@@ -3940,7 +3953,9 @@ static int lfs_rawrename(lfs_t *lfs, const char *oldpath, const char *newpath) {
newoldid += 1;
}
} else if (lfs_tag_type3(prevtag) != lfs_tag_type3(oldtag)) {
- return LFS_ERR_ISDIR;
+ return (lfs_tag_type3(prevtag) == LFS_TYPE_DIR)
+ ? LFS_ERR_ISDIR
+ : LFS_ERR_NOTDIR;
} else if (samepair && newid == newoldid) {
// we're renaming to ourselves??
return 0;
@@ -4032,7 +4047,7 @@ static int lfs_rawrename(lfs_t *lfs, const char *oldpath, const char *newpath) {
}
#endif
-static lfs_ssize_t lfs_rawgetattr(lfs_t *lfs, const char *path,
+static lfs_ssize_t lfs_getattr_(lfs_t *lfs, const char *path,
uint8_t type, void *buffer, lfs_size_t size) {
lfs_mdir_t cwd;
lfs_stag_t tag = lfs_dir_find(lfs, &cwd, &path, NULL);
@@ -4090,7 +4105,7 @@ static int lfs_commitattr(lfs_t *lfs, const char *path,
#endif
#ifndef LFS_READONLY
-static int lfs_rawsetattr(lfs_t *lfs, const char *path,
+static int lfs_setattr_(lfs_t *lfs, const char *path,
uint8_t type, const void *buffer, lfs_size_t size) {
if (size > lfs->attr_max) {
return LFS_ERR_NOSPC;
@@ -4101,13 +4116,28 @@ static int lfs_rawsetattr(lfs_t *lfs, const char *path,
#endif
#ifndef LFS_READONLY
-static int lfs_rawremoveattr(lfs_t *lfs, const char *path, uint8_t type) {
+static int lfs_removeattr_(lfs_t *lfs, const char *path, uint8_t type) {
return lfs_commitattr(lfs, path, type, NULL, 0x3ff);
}
#endif
/// Filesystem operations ///
+
+// compile time checks, see lfs.h for why these limits exist
+#if LFS_NAME_MAX > 1022
+#error "Invalid LFS_NAME_MAX, must be <= 1022"
+#endif
+
+#if LFS_FILE_MAX > 2147483647
+#error "Invalid LFS_FILE_MAX, must be <= 2147483647"
+#endif
+
+#if LFS_ATTR_MAX > 1022
+#error "Invalid LFS_ATTR_MAX, must be <= 1022"
+#endif
+
+// common filesystem initialization
static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) {
lfs->cfg = cfg;
lfs->block_count = cfg->block_count; // May be 0
@@ -4155,6 +4185,14 @@ static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) {
// wear-leveling.
LFS_ASSERT(lfs->cfg->block_cycles != 0);
+ // check that compact_thresh makes sense
+ //
+ // metadata can't be compacted below block_size/2, and metadata can't
+ // exceed a block_size
+ LFS_ASSERT(lfs->cfg->compact_thresh == 0
+ || lfs->cfg->compact_thresh >= lfs->cfg->block_size/2);
+ LFS_ASSERT(lfs->cfg->compact_thresh == (lfs_size_t)-1
+ || lfs->cfg->compact_thresh <= lfs->cfg->block_size);
// setup read cache
if (lfs->cfg->read_buffer) {
@@ -4182,15 +4220,14 @@ static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) {
lfs_cache_zero(lfs, &lfs->rcache);
lfs_cache_zero(lfs, &lfs->pcache);
- // setup lookahead, must be multiple of 64-bits, 32-bit aligned
+ // setup lookahead buffer, note mount finishes initializing this after
+ // we establish a decent pseudo-random seed
LFS_ASSERT(lfs->cfg->lookahead_size > 0);
- LFS_ASSERT(lfs->cfg->lookahead_size % 8 == 0 &&
- (uintptr_t)lfs->cfg->lookahead_buffer % 4 == 0);
if (lfs->cfg->lookahead_buffer) {
- lfs->free.buffer = lfs->cfg->lookahead_buffer;
+ lfs->lookahead.buffer = lfs->cfg->lookahead_buffer;
} else {
- lfs->free.buffer = lfs_malloc(lfs->cfg->lookahead_size);
- if (!lfs->free.buffer) {
+ lfs->lookahead.buffer = lfs_malloc(lfs->cfg->lookahead_size);
+ if (!lfs->lookahead.buffer) {
err = LFS_ERR_NOMEM;
goto cleanup;
}
@@ -4217,6 +4254,27 @@ static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) {
LFS_ASSERT(lfs->cfg->metadata_max <= lfs->cfg->block_size);
+ LFS_ASSERT(lfs->cfg->inline_max == (lfs_size_t)-1
+ || lfs->cfg->inline_max <= lfs->cfg->cache_size);
+ LFS_ASSERT(lfs->cfg->inline_max == (lfs_size_t)-1
+ || lfs->cfg->inline_max <= lfs->attr_max);
+ LFS_ASSERT(lfs->cfg->inline_max == (lfs_size_t)-1
+ || lfs->cfg->inline_max <= ((lfs->cfg->metadata_max)
+ ? lfs->cfg->metadata_max
+ : lfs->cfg->block_size)/8);
+ lfs->inline_max = lfs->cfg->inline_max;
+ if (lfs->inline_max == (lfs_size_t)-1) {
+ lfs->inline_max = 0;
+ } else if (lfs->inline_max == 0) {
+ lfs->inline_max = lfs_min(
+ lfs->cfg->cache_size,
+ lfs_min(
+ lfs->attr_max,
+ ((lfs->cfg->metadata_max)
+ ? lfs->cfg->metadata_max
+ : lfs->cfg->block_size)/8));
+ }
+
// setup default state
lfs->root[0] = LFS_BLOCK_NULL;
lfs->root[1] = LFS_BLOCK_NULL;
@@ -4247,7 +4305,7 @@ static int lfs_deinit(lfs_t *lfs) {
}
if (!lfs->cfg->lookahead_buffer) {
- lfs_free(lfs->free.buffer);
+ lfs_free(lfs->lookahead.buffer);
}
return 0;
@@ -4256,7 +4314,7 @@ static int lfs_deinit(lfs_t *lfs) {
#ifndef LFS_READONLY
-static int lfs_rawformat(lfs_t *lfs, const struct lfs_config *cfg) {
+static int lfs_format_(lfs_t *lfs, const struct lfs_config *cfg) {
int err = 0;
{
err = lfs_init(lfs, cfg);
@@ -4267,12 +4325,12 @@ static int lfs_rawformat(lfs_t *lfs, const struct lfs_config *cfg) {
LFS_ASSERT(cfg->block_count != 0);
// create free lookahead
- memset(lfs->free.buffer, 0, lfs->cfg->lookahead_size);
- lfs->free.off = 0;
- lfs->free.size = lfs_min(8*lfs->cfg->lookahead_size,
+ memset(lfs->lookahead.buffer, 0, lfs->cfg->lookahead_size);
+ lfs->lookahead.start = 0;
+ lfs->lookahead.size = lfs_min(8*lfs->cfg->lookahead_size,
lfs->block_count);
- lfs->free.i = 0;
- lfs_alloc_ack(lfs);
+ lfs->lookahead.next = 0;
+ lfs_alloc_ckpoint(lfs);
// create root dir
lfs_mdir_t root;
@@ -4323,7 +4381,7 @@ cleanup:
}
#endif
-static int lfs_rawmount(lfs_t *lfs, const struct lfs_config *cfg) {
+static int lfs_mount_(lfs_t *lfs, const struct lfs_config *cfg) {
int err = lfs_init(lfs, cfg);
if (err) {
return err;
@@ -4440,6 +4498,9 @@ static int lfs_rawmount(lfs_t *lfs, const struct lfs_config *cfg) {
}
lfs->attr_max = superblock.attr_max;
+
+ // we also need to update inline_max in case attr_max changed
+ lfs->inline_max = lfs_min(lfs->inline_max, lfs->attr_max);
}
// this is where we get the block_count from disk if block_count=0
@@ -4480,23 +4541,23 @@ static int lfs_rawmount(lfs_t *lfs, const struct lfs_config *cfg) {
// setup free lookahead, to distribute allocations uniformly across
// boots, we start the allocator at a random location
- lfs->free.off = lfs->seed % lfs->block_count;
+ lfs->lookahead.start = lfs->seed % lfs->block_count;
lfs_alloc_drop(lfs);
return 0;
cleanup:
- lfs_rawunmount(lfs);
+ lfs_unmount_(lfs);
return err;
}
-static int lfs_rawunmount(lfs_t *lfs) {
+static int lfs_unmount_(lfs_t *lfs) {
return lfs_deinit(lfs);
}
/// Filesystem filesystem operations ///
-static int lfs_fs_rawstat(lfs_t *lfs, struct lfs_fsinfo *fsinfo) {
+static int lfs_fs_stat_(lfs_t *lfs, struct lfs_fsinfo *fsinfo) {
// if the superblock is up-to-date, we must be on the most recent
// minor version of littlefs
if (!lfs_gstate_needssuperblock(&lfs->gstate)) {
@@ -4536,7 +4597,7 @@ static int lfs_fs_rawstat(lfs_t *lfs, struct lfs_fsinfo *fsinfo) {
return 0;
}
-int lfs_fs_rawtraverse(lfs_t *lfs,
+int lfs_fs_traverse_(lfs_t *lfs,
int (*cb)(void *data, lfs_block_t block), void *data,
bool includeorphans) {
// iterate over metadata pairs
@@ -5001,7 +5062,7 @@ static int lfs_fs_forceconsistency(lfs_t *lfs) {
#endif
#ifndef LFS_READONLY
-static int lfs_fs_rawmkconsistent(lfs_t *lfs) {
+static int lfs_fs_mkconsistent_(lfs_t *lfs) {
// lfs_fs_forceconsistency does most of the work here
int err = lfs_fs_forceconsistency(lfs);
if (err) {
@@ -5037,9 +5098,9 @@ static int lfs_fs_size_count(void *p, lfs_block_t block) {
return 0;
}
-static lfs_ssize_t lfs_fs_rawsize(lfs_t *lfs) {
+static lfs_ssize_t lfs_fs_size_(lfs_t *lfs) {
lfs_size_t size = 0;
- int err = lfs_fs_rawtraverse(lfs, lfs_fs_size_count, &size, false);
+ int err = lfs_fs_traverse_(lfs, lfs_fs_size_count, &size, false);
if (err) {
return err;
}
@@ -5047,8 +5108,59 @@ static lfs_ssize_t lfs_fs_rawsize(lfs_t *lfs) {
return size;
}
+// explicit garbage collection
#ifndef LFS_READONLY
-static int lfs_fs_rawgrow(lfs_t *lfs, lfs_size_t block_count) {
+static int lfs_fs_gc_(lfs_t *lfs) {
+ // force consistency, even if we're not necessarily going to write,
+ // because this function is supposed to take care of janitorial work
+ // isn't it?
+ int err = lfs_fs_forceconsistency(lfs);
+ if (err) {
+ return err;
+ }
+
+ // try to compact metadata pairs, note we can't really accomplish
+ // anything if compact_thresh doesn't at least leave a prog_size
+ // available
+ if (lfs->cfg->compact_thresh
+ < lfs->cfg->block_size - lfs->cfg->prog_size) {
+ // iterate over all mdirs
+ lfs_mdir_t mdir = {.tail = {0, 1}};
+ while (!lfs_pair_isnull(mdir.tail)) {
+ err = lfs_dir_fetch(lfs, &mdir, mdir.tail);
+ if (err) {
+ return err;
+ }
+
+ // not erased? exceeds our compaction threshold?
+ if (!mdir.erased || ((lfs->cfg->compact_thresh == 0)
+ ? mdir.off > lfs->cfg->block_size - lfs->cfg->block_size/8
+ : mdir.off > lfs->cfg->compact_thresh)) {
+ // the easiest way to trigger a compaction is to mark
+ // the mdir as unerased and add an empty commit
+ mdir.erased = false;
+ err = lfs_dir_commit(lfs, &mdir, NULL, 0);
+ if (err) {
+ return err;
+ }
+ }
+ }
+ }
+
+ // try to populate the lookahead buffer, unless it's already full
+ if (lfs->lookahead.size < 8*lfs->cfg->lookahead_size) {
+ err = lfs_alloc_scan(lfs);
+ if (err) {
+ return err;
+ }
+ }
+
+ return 0;
+}
+#endif
+
+#ifndef LFS_READONLY
+static int lfs_fs_grow_(lfs_t *lfs, lfs_size_t block_count) {
// shrinking is not supported
LFS_ASSERT(block_count >= lfs->block_count);
@@ -5453,10 +5565,10 @@ static int lfs1_mount(lfs_t *lfs, struct lfs1 *lfs1,
lfs->lfs1->root[1] = LFS_BLOCK_NULL;
// setup free lookahead
- lfs->free.off = 0;
- lfs->free.size = 0;
- lfs->free.i = 0;
- lfs_alloc_ack(lfs);
+ lfs->lookahead.start = 0;
+ lfs->lookahead.size = 0;
+ lfs->lookahead.next = 0;
+ lfs_alloc_ckpoint(lfs);
// load superblock
lfs1_dir_t dir;
@@ -5507,7 +5619,7 @@ static int lfs1_unmount(lfs_t *lfs) {
}
/// v1 migration ///
-static int lfs_rawmigrate(lfs_t *lfs, const struct lfs_config *cfg) {
+static int lfs_migrate_(lfs_t *lfs, const struct lfs_config *cfg) {
struct lfs1 lfs1;
// Indeterminate filesystem size not allowed for migration.
@@ -5774,7 +5886,7 @@ int lfs_format(lfs_t *lfs, const struct lfs_config *cfg) {
cfg->read_buffer, cfg->prog_buffer, cfg->lookahead_buffer,
cfg->name_max, cfg->file_max, cfg->attr_max);
- err = lfs_rawformat(lfs, cfg);
+ err = lfs_format_(lfs, cfg);
LFS_TRACE("lfs_format -> %d", err);
LFS_UNLOCK(cfg);
@@ -5804,7 +5916,7 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) {
cfg->read_buffer, cfg->prog_buffer, cfg->lookahead_buffer,
cfg->name_max, cfg->file_max, cfg->attr_max);
- err = lfs_rawmount(lfs, cfg);
+ err = lfs_mount_(lfs, cfg);
LFS_TRACE("lfs_mount -> %d", err);
LFS_UNLOCK(cfg);
@@ -5818,7 +5930,7 @@ int lfs_unmount(lfs_t *lfs) {
}
LFS_TRACE("lfs_unmount(%p)", (void*)lfs);
- err = lfs_rawunmount(lfs);
+ err = lfs_unmount_(lfs);
LFS_TRACE("lfs_unmount -> %d", err);
LFS_UNLOCK(lfs->cfg);
@@ -5833,7 +5945,7 @@ int lfs_remove(lfs_t *lfs, const char *path) {
}
LFS_TRACE("lfs_remove(%p, \"%s\")", (void*)lfs, path);
- err = lfs_rawremove(lfs, path);
+ err = lfs_remove_(lfs, path);
LFS_TRACE("lfs_remove -> %d", err);
LFS_UNLOCK(lfs->cfg);
@@ -5849,7 +5961,7 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) {
}
LFS_TRACE("lfs_rename(%p, \"%s\", \"%s\")", (void*)lfs, oldpath, newpath);
- err = lfs_rawrename(lfs, oldpath, newpath);
+ err = lfs_rename_(lfs, oldpath, newpath);
LFS_TRACE("lfs_rename -> %d", err);
LFS_UNLOCK(lfs->cfg);
@@ -5864,7 +5976,7 @@ int lfs_stat(lfs_t *lfs, const char *path, struct lfs_info *info) {
}
LFS_TRACE("lfs_stat(%p, \"%s\", %p)", (void*)lfs, path, (void*)info);
- err = lfs_rawstat(lfs, path, info);
+ err = lfs_stat_(lfs, path, info);
LFS_TRACE("lfs_stat -> %d", err);
LFS_UNLOCK(lfs->cfg);
@@ -5880,7 +5992,7 @@ lfs_ssize_t lfs_getattr(lfs_t *lfs, const char *path,
LFS_TRACE("lfs_getattr(%p, \"%s\", %"PRIu8", %p, %"PRIu32")",
(void*)lfs, path, type, buffer, size);
- lfs_ssize_t res = lfs_rawgetattr(lfs, path, type, buffer, size);
+ lfs_ssize_t res = lfs_getattr_(lfs, path, type, buffer, size);
LFS_TRACE("lfs_getattr -> %"PRId32, res);
LFS_UNLOCK(lfs->cfg);
@@ -5897,7 +6009,7 @@ int lfs_setattr(lfs_t *lfs, const char *path,
LFS_TRACE("lfs_setattr(%p, \"%s\", %"PRIu8", %p, %"PRIu32")",
(void*)lfs, path, type, buffer, size);
- err = lfs_rawsetattr(lfs, path, type, buffer, size);
+ err = lfs_setattr_(lfs, path, type, buffer, size);
LFS_TRACE("lfs_setattr -> %d", err);
LFS_UNLOCK(lfs->cfg);
@@ -5913,7 +6025,7 @@ int lfs_removeattr(lfs_t *lfs, const char *path, uint8_t type) {
}
LFS_TRACE("lfs_removeattr(%p, \"%s\", %"PRIu8")", (void*)lfs, path, type);
- err = lfs_rawremoveattr(lfs, path, type);
+ err = lfs_removeattr_(lfs, path, type);
LFS_TRACE("lfs_removeattr -> %d", err);
LFS_UNLOCK(lfs->cfg);
@@ -5931,7 +6043,7 @@ int lfs_file_open(lfs_t *lfs, lfs_file_t *file, const char *path, int flags) {
(void*)lfs, (void*)file, path, flags);
LFS_ASSERT(!lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file));
- err = lfs_file_rawopen(lfs, file, path, flags);
+ err = lfs_file_open_(lfs, file, path, flags);
LFS_TRACE("lfs_file_open -> %d", err);
LFS_UNLOCK(lfs->cfg);
@@ -5952,7 +6064,7 @@ int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file,
(void*)cfg, cfg->buffer, (void*)cfg->attrs, cfg->attr_count);
LFS_ASSERT(!lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file));
- err = lfs_file_rawopencfg(lfs, file, path, flags, cfg);
+ err = lfs_file_opencfg_(lfs, file, path, flags, cfg);
LFS_TRACE("lfs_file_opencfg -> %d", err);
LFS_UNLOCK(lfs->cfg);
@@ -5967,7 +6079,7 @@ int lfs_file_close(lfs_t *lfs, lfs_file_t *file) {
LFS_TRACE("lfs_file_close(%p, %p)", (void*)lfs, (void*)file);
LFS_ASSERT(lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file));
- err = lfs_file_rawclose(lfs, file);
+ err = lfs_file_close_(lfs, file);
LFS_TRACE("lfs_file_close -> %d", err);
LFS_UNLOCK(lfs->cfg);
@@ -5983,7 +6095,7 @@ int lfs_file_sync(lfs_t *lfs, lfs_file_t *file) {
LFS_TRACE("lfs_file_sync(%p, %p)", (void*)lfs, (void*)file);
LFS_ASSERT(lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file));
- err = lfs_file_rawsync(lfs, file);
+ err = lfs_file_sync_(lfs, file);
LFS_TRACE("lfs_file_sync -> %d", err);
LFS_UNLOCK(lfs->cfg);
@@ -6001,7 +6113,7 @@ lfs_ssize_t lfs_file_read(lfs_t *lfs, lfs_file_t *file,
(void*)lfs, (void*)file, buffer, size);
LFS_ASSERT(lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file));
- lfs_ssize_t res = lfs_file_rawread(lfs, file, buffer, size);
+ lfs_ssize_t res = lfs_file_read_(lfs, file, buffer, size);
LFS_TRACE("lfs_file_read -> %"PRId32, res);
LFS_UNLOCK(lfs->cfg);
@@ -6019,7 +6131,7 @@ lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file,
(void*)lfs, (void*)file, buffer, size);
LFS_ASSERT(lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file));
- lfs_ssize_t res = lfs_file_rawwrite(lfs, file, buffer, size);
+ lfs_ssize_t res = lfs_file_write_(lfs, file, buffer, size);
LFS_TRACE("lfs_file_write -> %"PRId32, res);
LFS_UNLOCK(lfs->cfg);
@@ -6037,7 +6149,7 @@ lfs_soff_t lfs_file_seek(lfs_t *lfs, lfs_file_t *file,
(void*)lfs, (void*)file, off, whence);
LFS_ASSERT(lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file));
- lfs_soff_t res = lfs_file_rawseek(lfs, file, off, whence);
+ lfs_soff_t res = lfs_file_seek_(lfs, file, off, whence);
LFS_TRACE("lfs_file_seek -> %"PRId32, res);
LFS_UNLOCK(lfs->cfg);
@@ -6054,7 +6166,7 @@ int lfs_file_truncate(lfs_t *lfs, lfs_file_t *file, lfs_off_t size) {
(void*)lfs, (void*)file, size);
LFS_ASSERT(lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file));
- err = lfs_file_rawtruncate(lfs, file, size);
+ err = lfs_file_truncate_(lfs, file, size);
LFS_TRACE("lfs_file_truncate -> %d", err);
LFS_UNLOCK(lfs->cfg);
@@ -6070,7 +6182,7 @@ lfs_soff_t lfs_file_tell(lfs_t *lfs, lfs_file_t *file) {
LFS_TRACE("lfs_file_tell(%p, %p)", (void*)lfs, (void*)file);
LFS_ASSERT(lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file));
- lfs_soff_t res = lfs_file_rawtell(lfs, file);
+ lfs_soff_t res = lfs_file_tell_(lfs, file);
LFS_TRACE("lfs_file_tell -> %"PRId32, res);
LFS_UNLOCK(lfs->cfg);
@@ -6084,7 +6196,7 @@ int lfs_file_rewind(lfs_t *lfs, lfs_file_t *file) {
}
LFS_TRACE("lfs_file_rewind(%p, %p)", (void*)lfs, (void*)file);
- err = lfs_file_rawrewind(lfs, file);
+ err = lfs_file_rewind_(lfs, file);
LFS_TRACE("lfs_file_rewind -> %d", err);
LFS_UNLOCK(lfs->cfg);
@@ -6099,7 +6211,7 @@ lfs_soff_t lfs_file_size(lfs_t *lfs, lfs_file_t *file) {
LFS_TRACE("lfs_file_size(%p, %p)", (void*)lfs, (void*)file);
LFS_ASSERT(lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file));
- lfs_soff_t res = lfs_file_rawsize(lfs, file);
+ lfs_soff_t res = lfs_file_size_(lfs, file);
LFS_TRACE("lfs_file_size -> %"PRId32, res);
LFS_UNLOCK(lfs->cfg);
@@ -6114,7 +6226,7 @@ int lfs_mkdir(lfs_t *lfs, const char *path) {
}
LFS_TRACE("lfs_mkdir(%p, \"%s\")", (void*)lfs, path);
- err = lfs_rawmkdir(lfs, path);
+ err = lfs_mkdir_(lfs, path);
LFS_TRACE("lfs_mkdir -> %d", err);
LFS_UNLOCK(lfs->cfg);
@@ -6130,7 +6242,7 @@ int lfs_dir_open(lfs_t *lfs, lfs_dir_t *dir, const char *path) {
LFS_TRACE("lfs_dir_open(%p, %p, \"%s\")", (void*)lfs, (void*)dir, path);
LFS_ASSERT(!lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)dir));
- err = lfs_dir_rawopen(lfs, dir, path);
+ err = lfs_dir_open_(lfs, dir, path);
LFS_TRACE("lfs_dir_open -> %d", err);
LFS_UNLOCK(lfs->cfg);
@@ -6144,7 +6256,7 @@ int lfs_dir_close(lfs_t *lfs, lfs_dir_t *dir) {
}
LFS_TRACE("lfs_dir_close(%p, %p)", (void*)lfs, (void*)dir);
- err = lfs_dir_rawclose(lfs, dir);
+ err = lfs_dir_close_(lfs, dir);
LFS_TRACE("lfs_dir_close -> %d", err);
LFS_UNLOCK(lfs->cfg);
@@ -6159,7 +6271,7 @@ int lfs_dir_read(lfs_t *lfs, lfs_dir_t *dir, struct lfs_info *info) {
LFS_TRACE("lfs_dir_read(%p, %p, %p)",
(void*)lfs, (void*)dir, (void*)info);
- err = lfs_dir_rawread(lfs, dir, info);
+ err = lfs_dir_read_(lfs, dir, info);
LFS_TRACE("lfs_dir_read -> %d", err);
LFS_UNLOCK(lfs->cfg);
@@ -6174,7 +6286,7 @@ int lfs_dir_seek(lfs_t *lfs, lfs_dir_t *dir, lfs_off_t off) {
LFS_TRACE("lfs_dir_seek(%p, %p, %"PRIu32")",
(void*)lfs, (void*)dir, off);
- err = lfs_dir_rawseek(lfs, dir, off);
+ err = lfs_dir_seek_(lfs, dir, off);
LFS_TRACE("lfs_dir_seek -> %d", err);
LFS_UNLOCK(lfs->cfg);
@@ -6188,7 +6300,7 @@ lfs_soff_t lfs_dir_tell(lfs_t *lfs, lfs_dir_t *dir) {
}
LFS_TRACE("lfs_dir_tell(%p, %p)", (void*)lfs, (void*)dir);
- lfs_soff_t res = lfs_dir_rawtell(lfs, dir);
+ lfs_soff_t res = lfs_dir_tell_(lfs, dir);
LFS_TRACE("lfs_dir_tell -> %"PRId32, res);
LFS_UNLOCK(lfs->cfg);
@@ -6202,7 +6314,7 @@ int lfs_dir_rewind(lfs_t *lfs, lfs_dir_t *dir) {
}
LFS_TRACE("lfs_dir_rewind(%p, %p)", (void*)lfs, (void*)dir);
- err = lfs_dir_rawrewind(lfs, dir);
+ err = lfs_dir_rewind_(lfs, dir);
LFS_TRACE("lfs_dir_rewind -> %d", err);
LFS_UNLOCK(lfs->cfg);
@@ -6216,7 +6328,7 @@ int lfs_fs_stat(lfs_t *lfs, struct lfs_fsinfo *fsinfo) {
}
LFS_TRACE("lfs_fs_stat(%p, %p)", (void*)lfs, (void*)fsinfo);
- err = lfs_fs_rawstat(lfs, fsinfo);
+ err = lfs_fs_stat_(lfs, fsinfo);
LFS_TRACE("lfs_fs_stat -> %d", err);
LFS_UNLOCK(lfs->cfg);
@@ -6230,7 +6342,7 @@ lfs_ssize_t lfs_fs_size(lfs_t *lfs) {
}
LFS_TRACE("lfs_fs_size(%p)", (void*)lfs);
- lfs_ssize_t res = lfs_fs_rawsize(lfs);
+ lfs_ssize_t res = lfs_fs_size_(lfs);
LFS_TRACE("lfs_fs_size -> %"PRId32, res);
LFS_UNLOCK(lfs->cfg);
@@ -6245,7 +6357,7 @@ int lfs_fs_traverse(lfs_t *lfs, int (*cb)(void *, lfs_block_t), void *data) {
LFS_TRACE("lfs_fs_traverse(%p, %p, %p)",
(void*)lfs, (void*)(uintptr_t)cb, data);
- err = lfs_fs_rawtraverse(lfs, cb, data, true);
+ err = lfs_fs_traverse_(lfs, cb, data, true);
LFS_TRACE("lfs_fs_traverse -> %d", err);
LFS_UNLOCK(lfs->cfg);
@@ -6253,32 +6365,32 @@ int lfs_fs_traverse(lfs_t *lfs, int (*cb)(void *, lfs_block_t), void *data) {
}
#ifndef LFS_READONLY
-int lfs_fs_gc(lfs_t *lfs) {
+int lfs_fs_mkconsistent(lfs_t *lfs) {
int err = LFS_LOCK(lfs->cfg);
if (err) {
return err;
}
- LFS_TRACE("lfs_fs_gc(%p)", (void*)lfs);
+ LFS_TRACE("lfs_fs_mkconsistent(%p)", (void*)lfs);
- err = lfs_fs_rawgc(lfs);
+ err = lfs_fs_mkconsistent_(lfs);
- LFS_TRACE("lfs_fs_gc -> %d", err);
+ LFS_TRACE("lfs_fs_mkconsistent -> %d", err);
LFS_UNLOCK(lfs->cfg);
return err;
}
#endif
#ifndef LFS_READONLY
-int lfs_fs_mkconsistent(lfs_t *lfs) {
+int lfs_fs_gc(lfs_t *lfs) {
int err = LFS_LOCK(lfs->cfg);
if (err) {
return err;
}
- LFS_TRACE("lfs_fs_mkconsistent(%p)", (void*)lfs);
+ LFS_TRACE("lfs_fs_gc(%p)", (void*)lfs);
- err = lfs_fs_rawmkconsistent(lfs);
+ err = lfs_fs_gc_(lfs);
- LFS_TRACE("lfs_fs_mkconsistent -> %d", err);
+ LFS_TRACE("lfs_fs_gc -> %d", err);
LFS_UNLOCK(lfs->cfg);
return err;
}
@@ -6292,7 +6404,7 @@ int lfs_fs_grow(lfs_t *lfs, lfs_size_t block_count) {
}
LFS_TRACE("lfs_fs_grow(%p, %"PRIu32")", (void*)lfs, block_count);
- err = lfs_fs_rawgrow(lfs, block_count);
+ err = lfs_fs_grow_(lfs, block_count);
LFS_TRACE("lfs_fs_grow -> %d", err);
LFS_UNLOCK(lfs->cfg);
@@ -6323,7 +6435,7 @@ int lfs_migrate(lfs_t *lfs, const struct lfs_config *cfg) {
cfg->read_buffer, cfg->prog_buffer, cfg->lookahead_buffer,
cfg->name_max, cfg->file_max, cfg->attr_max);
- err = lfs_rawmigrate(lfs, cfg);
+ err = lfs_migrate_(lfs, cfg);
LFS_TRACE("lfs_migrate -> %d", err);
LFS_UNLOCK(cfg);
diff --git a/lfs.h b/lfs.h
index 9eeab23..9914502 100644
--- a/lfs.h
+++ b/lfs.h
@@ -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 LFS_VERSION 0x00020008
+#define LFS_VERSION 0x00020009
#define LFS_VERSION_MAJOR (0xffff & (LFS_VERSION >> 16))
#define LFS_VERSION_MINOR (0xffff & (LFS_VERSION >> 0))
@@ -52,10 +52,8 @@ typedef uint32_t lfs_block_t;
#endif
// Maximum size of a file in bytes, may be redefined to limit to support other
-// drivers. Limited on disk to <= 4294967296. However, above 2147483647 the
-// 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.
+// drivers. Limited on disk to <= 2147483647. Stored in superblock and must be
+// respected by other littlefs drivers.
#ifndef LFS_FILE_MAX
#define LFS_FILE_MAX 2147483647
#endif
@@ -226,9 +224,20 @@ struct lfs_config {
// Size of the lookahead buffer in bytes. A larger lookahead buffer
// increases the number of blocks found during an allocation pass. The
// lookahead buffer is stored as a compact bitmap, so each byte of RAM
- // can track 8 blocks. Must be a multiple of 8.
+ // can track 8 blocks.
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.
// By default lfs_malloc is used to allocate this buffer.
void *read_buffer;
@@ -237,9 +246,8 @@ struct lfs_config {
// By default lfs_malloc is used to allocate this buffer.
void *prog_buffer;
- // Optional statically allocated lookahead buffer. Must be lookahead_size
- // and aligned to a 32-bit boundary. By default lfs_malloc is used to
- // allocate this buffer.
+ // Optional statically allocated lookahead buffer. Must be lookahead_size.
+ // By default lfs_malloc is used to allocate this buffer.
void *lookahead_buffer;
// Optional upper limit on length of file names in bytes. No downside for
@@ -264,6 +272,15 @@ struct lfs_config {
// Defaults to block_size when zero.
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
// 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
@@ -430,19 +447,20 @@ typedef struct lfs {
lfs_gstate_t gdisk;
lfs_gstate_t gdelta;
- struct lfs_free {
- lfs_block_t off;
+ struct lfs_lookahead {
+ lfs_block_t start;
lfs_block_t size;
- lfs_block_t i;
- lfs_block_t ack;
- uint32_t *buffer;
- } free;
+ lfs_block_t next;
+ lfs_block_t ckpoint;
+ uint8_t *buffer;
+ } lookahead;
const struct lfs_config *cfg;
lfs_size_t block_count;
lfs_size_t name_max;
lfs_size_t file_max;
lfs_size_t attr_max;
+ lfs_size_t inline_max;
#ifdef LFS_MIGRATE
struct lfs1 *lfs1;
@@ -712,18 +730,6 @@ lfs_ssize_t lfs_fs_size(lfs_t *lfs);
// Returns a negative error code on failure.
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
// Attempt to make the filesystem consistent and ready for writing
//
@@ -737,6 +743,24 @@ int lfs_fs_mkconsistent(lfs_t *lfs);
#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
// Grows the filesystem to a new size, updating the superblock with the new
// block count.
//
diff --git a/lfs_util.c b/lfs_util.c
index 9cdd1c6..dac72ab 100644
--- a/lfs_util.c
+++ b/lfs_util.c
@@ -11,6 +11,8 @@
#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
uint32_t lfs_crc(uint32_t crc, const void *buffer, size_t size) {
static const uint32_t rtable[16] = {
@@ -29,6 +31,7 @@ uint32_t lfs_crc(uint32_t crc, const void *buffer, size_t size) {
return crc;
}
+#endif
#endif
diff --git a/lfs_util.h b/lfs_util.h
index 13e9396..4e57700 100644
--- a/lfs_util.h
+++ b/lfs_util.h
@@ -212,12 +212,22 @@ static inline uint32_t lfs_tobe32(uint32_t a) {
}
// 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);
+#endif
// 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) {
-#ifndef LFS_NO_MALLOC
+#if defined(LFS_MALLOC)
+ return LFS_MALLOC(size);
+#elif !defined(LFS_NO_MALLOC)
return malloc(size);
#else
(void)size;
@@ -227,7 +237,9 @@ static inline void *lfs_malloc(size_t size) {
// Deallocate memory, only used if buffers are not provided to littlefs
static inline void lfs_free(void *p) {
-#ifndef LFS_NO_MALLOC
+#if defined(LFS_FREE)
+ LFS_FREE(p);
+#elif !defined(LFS_NO_MALLOC)
free(p);
#else
(void)p;
diff --git a/runners/bench_runner.c b/runners/bench_runner.c
index f4dce22..387889d 100644
--- a/runners/bench_runner.c
+++ b/runners/bench_runner.c
@@ -1321,6 +1321,8 @@ void perm_run(
.block_cycles = BLOCK_CYCLES,
.cache_size = CACHE_SIZE,
.lookahead_size = LOOKAHEAD_SIZE,
+ .compact_thresh = COMPACT_THRESH,
+ .inline_max = INLINE_MAX,
};
struct lfs_emubd_config bdcfg = {
diff --git a/runners/bench_runner.h b/runners/bench_runner.h
index b072970..174733c 100644
--- a/runners/bench_runner.h
+++ b/runners/bench_runner.h
@@ -95,11 +95,13 @@ intmax_t bench_define(size_t define);
#define BLOCK_COUNT_i 5
#define CACHE_SIZE_i 6
#define LOOKAHEAD_SIZE_i 7
-#define BLOCK_CYCLES_i 8
-#define ERASE_VALUE_i 9
-#define ERASE_CYCLES_i 10
-#define BADBLOCK_BEHAVIOR_i 11
-#define POWERLOSS_BEHAVIOR_i 12
+#define COMPACT_THRESH_i 8
+#define INLINE_MAX_i 9
+#define BLOCK_CYCLES_i 10
+#define ERASE_VALUE_i 11
+#define ERASE_CYCLES_i 12
+#define BADBLOCK_BEHAVIOR_i 13
+#define POWERLOSS_BEHAVIOR_i 14
#define READ_SIZE bench_define(READ_SIZE_i)
#define PROG_SIZE bench_define(PROG_SIZE_i)
@@ -109,6 +111,8 @@ intmax_t bench_define(size_t define);
#define BLOCK_COUNT bench_define(BLOCK_COUNT_i)
#define CACHE_SIZE bench_define(CACHE_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 ERASE_VALUE bench_define(ERASE_VALUE_i)
#define ERASE_CYCLES bench_define(ERASE_CYCLES_i)
@@ -124,6 +128,8 @@ intmax_t bench_define(size_t define);
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(LOOKAHEAD_SIZE, 16) \
+ BENCH_DEF(COMPACT_THRESH, 0) \
+ BENCH_DEF(INLINE_MAX, 0) \
BENCH_DEF(BLOCK_CYCLES, -1) \
BENCH_DEF(ERASE_VALUE, 0xff) \
BENCH_DEF(ERASE_CYCLES, 0) \
@@ -131,7 +137,7 @@ intmax_t bench_define(size_t define);
BENCH_DEF(POWERLOSS_BEHAVIOR, LFS_EMUBD_POWERLOSS_NOOP)
#define BENCH_GEOMETRY_DEFINE_COUNT 4
-#define BENCH_IMPLICIT_DEFINE_COUNT 13
+#define BENCH_IMPLICIT_DEFINE_COUNT 15
#endif
diff --git a/runners/test_runner.c b/runners/test_runner.c
index 13befdc..ff52673 100644
--- a/runners/test_runner.c
+++ b/runners/test_runner.c
@@ -1346,6 +1346,8 @@ static void run_powerloss_none(
.block_cycles = BLOCK_CYCLES,
.cache_size = CACHE_SIZE,
.lookahead_size = LOOKAHEAD_SIZE,
+ .compact_thresh = COMPACT_THRESH,
+ .inline_max = INLINE_MAX,
#ifdef LFS_MULTIVERSION
.disk_version = DISK_VERSION,
#endif
@@ -1422,6 +1424,8 @@ static void run_powerloss_linear(
.block_cycles = BLOCK_CYCLES,
.cache_size = CACHE_SIZE,
.lookahead_size = LOOKAHEAD_SIZE,
+ .compact_thresh = COMPACT_THRESH,
+ .inline_max = INLINE_MAX,
#ifdef LFS_MULTIVERSION
.disk_version = DISK_VERSION,
#endif
@@ -1515,6 +1519,8 @@ static void run_powerloss_log(
.block_cycles = BLOCK_CYCLES,
.cache_size = CACHE_SIZE,
.lookahead_size = LOOKAHEAD_SIZE,
+ .compact_thresh = COMPACT_THRESH,
+ .inline_max = INLINE_MAX,
#ifdef LFS_MULTIVERSION
.disk_version = DISK_VERSION,
#endif
@@ -1606,6 +1612,8 @@ static void run_powerloss_cycles(
.block_cycles = BLOCK_CYCLES,
.cache_size = CACHE_SIZE,
.lookahead_size = LOOKAHEAD_SIZE,
+ .compact_thresh = COMPACT_THRESH,
+ .inline_max = INLINE_MAX,
#ifdef LFS_MULTIVERSION
.disk_version = DISK_VERSION,
#endif
@@ -1795,6 +1803,8 @@ static void run_powerloss_exhaustive(
.block_cycles = BLOCK_CYCLES,
.cache_size = CACHE_SIZE,
.lookahead_size = LOOKAHEAD_SIZE,
+ .compact_thresh = COMPACT_THRESH,
+ .inline_max = INLINE_MAX,
#ifdef LFS_MULTIVERSION
.disk_version = DISK_VERSION,
#endif
diff --git a/runners/test_runner.h b/runners/test_runner.h
index 4be72e4..0f0e594 100644
--- a/runners/test_runner.h
+++ b/runners/test_runner.h
@@ -88,12 +88,14 @@ intmax_t test_define(size_t define);
#define BLOCK_COUNT_i 5
#define CACHE_SIZE_i 6
#define LOOKAHEAD_SIZE_i 7
-#define BLOCK_CYCLES_i 8
-#define ERASE_VALUE_i 9
-#define ERASE_CYCLES_i 10
-#define BADBLOCK_BEHAVIOR_i 11
-#define POWERLOSS_BEHAVIOR_i 12
-#define DISK_VERSION_i 13
+#define COMPACT_THRESH_i 8
+#define INLINE_MAX_i 9
+#define BLOCK_CYCLES_i 10
+#define ERASE_VALUE_i 11
+#define ERASE_CYCLES_i 12
+#define BADBLOCK_BEHAVIOR_i 13
+#define POWERLOSS_BEHAVIOR_i 14
+#define DISK_VERSION_i 15
#define READ_SIZE TEST_DEFINE(READ_SIZE_i)
#define PROG_SIZE TEST_DEFINE(PROG_SIZE_i)
@@ -103,6 +105,8 @@ intmax_t test_define(size_t define);
#define BLOCK_COUNT TEST_DEFINE(BLOCK_COUNT_i)
#define CACHE_SIZE TEST_DEFINE(CACHE_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 ERASE_VALUE TEST_DEFINE(ERASE_VALUE_i)
#define ERASE_CYCLES TEST_DEFINE(ERASE_CYCLES_i)
@@ -119,6 +123,8 @@ intmax_t test_define(size_t define);
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(LOOKAHEAD_SIZE, 16) \
+ TEST_DEF(COMPACT_THRESH, 0) \
+ TEST_DEF(INLINE_MAX, 0) \
TEST_DEF(BLOCK_CYCLES, -1) \
TEST_DEF(ERASE_VALUE, 0xff) \
TEST_DEF(ERASE_CYCLES, 0) \
@@ -127,7 +133,7 @@ intmax_t test_define(size_t define);
TEST_DEF(DISK_VERSION, 0)
#define TEST_GEOMETRY_DEFINE_COUNT 4
-#define TEST_IMPLICIT_DEFINE_COUNT 14
+#define TEST_IMPLICIT_DEFINE_COUNT 16
#endif
diff --git a/tests/test_alloc.toml b/tests/test_alloc.toml
index e6fba97..9e4daee 100644
--- a/tests/test_alloc.toml
+++ b/tests/test_alloc.toml
@@ -7,6 +7,7 @@ if = 'BLOCK_CYCLES == -1'
defines.FILES = 3
defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-6)) / FILES)'
defines.GC = [false, true]
+defines.COMPACT_THRESH = ['-1', '0', 'BLOCK_SIZE/2']
code = '''
const char *names[] = {"bacon", "eggs", "pancakes"};
lfs_file_t files[FILES];
@@ -60,6 +61,7 @@ code = '''
defines.FILES = 3
defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-6)) / FILES)'
defines.GC = [false, true]
+defines.COMPACT_THRESH = ['-1', '0', 'BLOCK_SIZE/2']
code = '''
const char *names[] = {"bacon", "eggs", "pancakes"};
diff --git a/tests/test_dirs.toml b/tests/test_dirs.toml
index 4262a1a..181dd6a 100644
--- a/tests/test_dirs.toml
+++ b/tests/test_dirs.toml
@@ -747,6 +747,11 @@ code = '''
lfs_file_open(&lfs, &file, "potato",
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_file_open(&lfs, &file, "/",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST;
@@ -770,6 +775,10 @@ code = '''
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR);
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_close(&lfs, &dir) => 0;
@@ -790,6 +799,10 @@ code = '''
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR);
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_close(&lfs, &dir) => 0;
lfs_unmount(&lfs) => 0;
diff --git a/tests/test_files.toml b/tests/test_files.toml
index afb0811..1c86cd8 100644
--- a/tests/test_files.toml
+++ b/tests/test_files.toml
@@ -1,5 +1,6 @@
[cases.test_files_simple]
+defines.INLINE_MAX = [0, -1, 8]
code = '''
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
@@ -25,6 +26,7 @@ code = '''
[cases.test_files_large]
defines.SIZE = [32, 8192, 262144, 0, 7, 8193]
defines.CHUNKSIZE = [31, 16, 33, 1, 1023]
+defines.INLINE_MAX = [0, -1, 8]
code = '''
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
@@ -67,6 +69,7 @@ code = '''
defines.SIZE1 = [32, 8192, 131072, 0, 7, 8193]
defines.SIZE2 = [32, 8192, 131072, 0, 7, 8193]
defines.CHUNKSIZE = [31, 16, 1]
+defines.INLINE_MAX = [0, -1, 8]
code = '''
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
@@ -152,6 +155,7 @@ code = '''
defines.SIZE1 = [32, 8192, 131072, 0, 7, 8193]
defines.SIZE2 = [32, 8192, 131072, 0, 7, 8193]
defines.CHUNKSIZE = [31, 16, 1]
+defines.INLINE_MAX = [0, -1, 8]
code = '''
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
@@ -232,6 +236,7 @@ code = '''
defines.SIZE1 = [32, 8192, 131072, 0, 7, 8193]
defines.SIZE2 = [32, 8192, 131072, 0, 7, 8193]
defines.CHUNKSIZE = [31, 16, 1]
+defines.INLINE_MAX = [0, -1, 8]
code = '''
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
@@ -303,6 +308,7 @@ code = '''
[cases.test_files_reentrant_write]
defines.SIZE = [32, 0, 7, 2049]
defines.CHUNKSIZE = [31, 16, 65]
+defines.INLINE_MAX = [0, -1, 8]
reentrant = true
code = '''
lfs_t lfs;
@@ -354,11 +360,20 @@ code = '''
[cases.test_files_reentrant_write_sync]
defines = [
# append (O(n))
- {MODE='LFS_O_APPEND', SIZE=[32, 0, 7, 2049], CHUNKSIZE=[31, 16, 65]},
+ {MODE='LFS_O_APPEND',
+ SIZE=[32, 0, 7, 2049],
+ CHUNKSIZE=[31, 16, 65],
+ INLINE_MAX=[0, -1, 8]},
# truncate (O(n^2))
- {MODE='LFS_O_TRUNC', SIZE=[32, 0, 7, 200], CHUNKSIZE=[31, 16, 65]},
+ {MODE='LFS_O_TRUNC',
+ SIZE=[32, 0, 7, 200],
+ CHUNKSIZE=[31, 16, 65],
+ INLINE_MAX=[0, -1, 8]},
# rewrite (O(n^2))
- {MODE=0, SIZE=[32, 0, 7, 200], CHUNKSIZE=[31, 16, 65]},
+ {MODE=0,
+ SIZE=[32, 0, 7, 200],
+ CHUNKSIZE=[31, 16, 65],
+ INLINE_MAX=[0, -1, 8]},
]
reentrant = true
code = '''
diff --git a/tests/test_orphans.toml b/tests/test_orphans.toml
index 2c8405a..d7040ed 100644
--- a/tests/test_orphans.toml
+++ b/tests/test_orphans.toml
@@ -98,7 +98,7 @@ code = '''
lfs_mount(&lfs, cfg) => 0;
// create an orphan
lfs_mdir_t orphan;
- lfs_alloc_ack(&lfs);
+ lfs_alloc_ckpoint(&lfs);
lfs_dir_alloc(&lfs, &orphan) => 0;
lfs_dir_commit(&lfs, &orphan, NULL, 0) => 0;
@@ -170,7 +170,7 @@ code = '''
lfs_mount(&lfs, cfg) => 0;
// create an orphan
lfs_mdir_t orphan;
- lfs_alloc_ack(&lfs);
+ lfs_alloc_ckpoint(&lfs);
lfs_dir_alloc(&lfs, &orphan) => 0;
lfs_dir_commit(&lfs, &orphan, NULL, 0) => 0;