Compare commits

...

26 Commits

Author SHA1 Message Date
Christopher Haster
a70870c628 Renamed internal functions _raw* -> _*_
So instead of lfs_file_rawopencfg, it's now lfs_file_opencfg_.

The "raw" prefix is annoying, doesn't really add meaning ("internal"
would have been better), and gets in the way of finding the relevant
function implementations.

I have been using _s as suffixes for unimportant name collisions in
other codebases, and it seems to work well at reducing wasted brain
cycles naming things. Adopting it here avoids the need for "raw"
prefixes.

It's quite a bit like the use of prime symbols to resolve name
collisions in math, e.g. x' = x + 1. Which is even supported in Haskell
and is quite nice there.

And the main benefit: Now if you search for the public API name, you get
the internal function first, which is probably what you care about.

Here is the exact script:

  sed -i 's/_raw\([a-z0-9_]*\)\>/_\1_/g' $(git ls-tree -r HEAD --name-only | grep '.*\.c')
2024-01-19 13:20:56 -06:00
Christopher Haster
ceb17a0f4a Merge pull request #917 from tomscii/fix_return_value_of_lfs_rename
Fix return value of lfs_rename()
2024-01-19 13:19:21 -06:00
Christopher Haster
a8a0905777 Merge pull request #916 from littlefs-project/ci-ubuntu-latest
Change CI to just run on ubuntu-latest
2024-01-19 13:19:07 -06:00
Christopher Haster
13d78616fe Merge pull request #914 from littlefs-project/inline-max
Add inline_max, to optionally limit the size of inlined files
2024-01-19 13:18:54 -06:00
Christopher Haster
8b8fd14187 Added inline_max, to optionally limit the size of inlined files
Inlined files live in metadata and decrease storage requirements, but
may be limited to improve metadata-related performance. This is
especially important given the current plague of metadata performance.

Though decreasing inline_max may make metadata more dense and increase
block usage, so it's important to benchmark if optimizing for speed.

The underlying limits of inlined files haven't changed:
1. Inlined files need to fit in RAM, so <= cache_size
2. Inlined files need to fit in a single attr, so <= attr_max
3. Inlined files need to fit in 1/8 of a block to avoid metadata
   overflow issues, this is after limiting by metadata_max,
   so <= min(metadata_max, block_size)/8

By default, the largest possible inline_max is used. This preserves
backwards compatibility and is probably a good default for most use
cases.

This does have the awkward effect of requiring inline_max=-1 to
indicate disabled inlined files, but I don't think there's a good
way around this.
2024-01-19 13:00:27 -06:00
Christopher Haster
09972a1710 Merge pull request #913 from littlefs-project/gc-compactions
Extend lfs_fs_gc to compact metadata, compact_thresh
2024-01-19 12:51:11 -06:00
Christopher Haster
ed7bd05435 Merge pull request #912 from littlefs-project/relaxed-lookahead
Relaxed lookahead alignment, other internal block alloc readability improvements
2024-01-19 12:27:14 -06:00
Christopher Haster
b5cd957f42 Extended lfs_fs_gc to compact metadata, compact_thresh
This extends lfs_fs_gc to now handle three things:

1. Calls mkconsistent if not already consistent
2. Compacts metadata > compact_thresh
3. Populates the block allocator

Which should be all of the janitorial work that can be done without
additional on-disk data structures.

Normally, metadata compaction occurs when an mdir is full, and results in
mdirs that are at most block_size/2.

Now, if you call lfs_fs_gc, littlefs will eagerly compact any mdirs that
exceed the compact_thresh configuration option. Because the resulting
mdirs are at most block_size/2, it only makes sense for compact_thresh to
be >= block_size/2 and <= block_size.

Additionally, there are some special values:

- compact_thresh=0  => defaults to ~88% block_size, may change
- compact_thresh=-1 => disables metadata compaction during lfs_fs_gc

Note that compact_thresh only affects lfs_fs_gc. Normal compactions
still only occur when full.
2024-01-19 12:25:45 -06:00
Christopher Haster
1195d606ae Merge pull request #909 from littlefs-project/easy-util-defines
Add some easier util overrides: LFS_MALLOC/FREE/CRC
2024-01-19 12:24:16 -06:00
Christopher Haster
1711bdef76 Merge pull request #886 from BrianPugh/macro-sanity-check
Add value-range checks for user-definable macros at compile-time
2024-01-19 12:23:36 -06:00
Christopher Haster
f522ed907a Added tests over rename type errors 2024-01-17 00:10:30 -06:00
Tom Szilagyi
4f32738cd6 Fix return value of lfs_rename()
When lfs_rename() is called trying to rename (move) a file to an
existing directory, LFS_ERR_ISDIR is (correctly) returned. However, in
the opposite case, if one tries to rename (move) a directory to a path
currently occupied by a regular file, LFS_ERR_NOTDIR should be
returned (since the error is that the destination is NOT a directory),
but in reality, LFS_ERR_ISDIR is returned in this case as well.

This commit fixes the code so that in the latter case, LFS_ERR_NOTDIR
is returned.
2024-01-17 00:06:52 -06:00
Christopher Haster
6691718b18 Restricted LFS_FILE_MAX to signed 32-bits, <2^31, <=2147483647
I think realistically no one is using this. It's already only partially
supported and untested.

Worst case, if someone does depend on this we can always revert.
2024-01-16 23:40:30 -06:00
Christopher Haster
1fefcbbcba Rearranged compile-time constant checks to live near lfs_init
lfs_init handles the checks/asserts of most configuration, moving these
checks near lfs_init attempts to keep all of these checks nearby each
other.

Also updated the comments to avoid somtimes-ambiguous range notation.

And removed negative bounds checks. Negative bounds should be obviously
incorrect, and 0 is _technically_ not illegal for any define (though
admittedly unlikely to be correct).
2024-01-16 23:39:51 -06:00
Christopher Haster
897b571318 Changed CI to just run on ubuntu-latest
If we already have to bump this version as GitHub phases out older
Ubuntu runners (which is reasonable), I don't really see the value of
pinning a specific version. We might as well just respond to any
broken dependencies caused by GitHub's implicit updates as they
happen...

It's not like CI is truly continuous.
2023-12-21 00:33:44 -06:00
Christopher Haster
3513ff1afc Merge pull request #911 from littlefs-project/fix-release-structs
Fix struct sizes missing from generated release notes
2023-12-21 00:08:16 -06:00
Christopher Haster
8a22bd6e67 Merge pull request #910 from littlefs-project/fix-superblock-expansion-thresh
Increase threshold for superblock expansion from ~50% -> ~88% full
2023-12-21 00:07:55 -06:00
Christopher Haster
9b82db72d8 Merge pull request #898 from zchen24/patch-1
Update DESIGN.md minor typo
2023-12-21 00:06:29 -06:00
Zihan Chen
99b84ee3db Update DESIGN.md, fix minor typo 2023-12-20 23:42:26 -06:00
Christopher Haster
e91a29d2b5 Fixed struct sizes missing from generated release notes
This script was missed during a struct -> structs naming change
2023-12-19 22:00:18 -06:00
Christopher Haster
b9b95ab4bc Increase threshold for superblock expansion from ~50% -> ~88% full
Superblock expansion is an irreversible operation. In an effort to
prevent superblock expansion from claiming valuable scratch space
(important for small, <~8 block filesystems), littlefs prevents
superblock expansion when the disk is "mostly full".

In true computer-scientist fashion, this "mostly full" threshold was
set to ~50%.

As pointed out by gbolgradov and rojer, >~50% utilization is not
uncommon, and it can lead to a situation where superblock expansion does
not occur in a relatively healthy filesystem, causing focused wear at
the root.

To remedy this, the threshold is now increased to ~88% (7/8) full.

This may change in the future and should probably be eventually user
configurable.

Found by gbolgradov and rojer
2023-12-19 16:51:17 -06:00
Christopher Haster
9a620c730c Added LFS_CRC, easier override for lfs_crc
Now you can override littlefs's CRC implementation with some simple
defines:

  -DLFS_CRC=lfs_crc

The motivation for this is the same for LFS_MALLOC/LFS_FREE. I think
these are the main "system-level" utils that users want to override.

Don't override with this something that's not CRC32! Your filesystem
will no longer be compatible with other tools! This is only intended for
provided hardware acceleration!
2023-12-19 14:12:10 -06:00
Christopher Haster
a0c6c54345 Added LFS_MALLOC/FREE, easier overrides for lfs_malloc/free
Now you can override littlefs's malloc with some simple defines:

  -DLFS_MALLOC=my_malloc
  -DLFS_FREE=my_free

This is probably what most users expected when wanting to override
malloc/free in littlefs, but it hasn't been available, since instead
littlefs provides a file-level override of builtin utils.

The thinking was that there's just too many builtins that could be
overriden, lfs_max/min/alignup/npw2/etc/etc/etc, so allowing users to
just override the util file provides the best flexibility without a ton
of ifdefs.

But it's become clear this is awkward for users that just want to
replace malloc.

Maybe the original goal was too optimistic, maybe there's a better way
to structure this file, or maybe the best API is just a bunch of ifdefs,
I have no idea! This will hopefully continue to evolve.
2023-12-19 13:57:17 -06:00
Zihan Chen
10bcff1af8 Update DESIGN.md minor typo 2023-11-26 11:10:24 -08:00
Brian Pugh
c531a5e88f Replace erroneous LFS_FILE_MAX upper bound 4294967296 to 4294967295 2023-10-30 11:18:20 -07:00
Brian Pugh
8f9427dd53 Add value-range checks for user-definable macros 2023-10-29 13:50:38 -07:00
17 changed files with 378 additions and 190 deletions

View File

@@ -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

View File

@@ -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?
@@ -112,7 +112,7 @@ jobs:
table[$i,$j]=$c_camel
((j+=1))
for s in code stack struct
for s in code stack structs
do
f=sizes/thumb${c:+-$c}.$s.csv
[ -e $f ] && table[$i,$j]=$( \

View File

@@ -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'}}

View File

@@ -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

View File

@@ -59,7 +59,7 @@ This leaves us with three major requirements for an embedded filesystem.
RAM to temporarily store filesystem metadata.
For ROM, this means we need to keep our design simple and reuse code paths
were possible. For RAM we have a stronger requirement, all RAM usage is
where possible. For RAM we have a stronger requirement, all RAM usage is
bounded. This means RAM usage does not grow as the filesystem changes in
size or number of files. This creates a unique challenge as even presumably
simple operations, such as traversing the filesystem, become surprisingly
@@ -626,7 +626,7 @@ log&#8322;_n_ pointers that skip to different preceding elements of the
skip-list.
The name comes from heavy use of the [CTZ instruction][wikipedia-ctz], which
lets us calculate the power-of-two factors efficiently. For a give block _n_,
lets us calculate the power-of-two factors efficiently. For a given block _n_,
that block contains ctz(_n_)+1 pointers.
```

View File

@@ -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;

364
lfs.c
View File

@@ -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,38 +574,25 @@ 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 ///
#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->lookahead.start)
+ lfs->block_count) % lfs->block_count;
if (off < lfs->lookahead.size) {
lfs->lookahead.buffer[off / 8] |= 1U << (off % 8);
}
return 0;
}
#endif
// allocations should call this when all allocated blocks are committed to
// the filesystem
@@ -624,7 +611,21 @@ static void lfs_alloc_drop(lfs_t *lfs) {
}
#ifndef LFS_READONLY
static int lfs_fs_rawgc(lfs_t *lfs) {
static int lfs_alloc_lookahead(void *p, lfs_block_t block) {
lfs_t *lfs = (lfs_t*)p;
lfs_block_t off = ((block - lfs->lookahead.start)
+ lfs->block_count) % lfs->block_count;
if (off < lfs->lookahead.size) {
lfs->lookahead.buffer[off / 8] |= 1U << (off % 8);
}
return 0;
}
#endif
#ifndef LFS_READONLY
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
@@ -638,7 +639,7 @@ static int lfs_fs_rawgc(lfs_t *lfs) {
// find mask of free blocks from tree
memset(lfs->lookahead.buffer, 0, lfs->cfg->lookahead_size);
int err = lfs_fs_rawtraverse(lfs, lfs_alloc_lookahead, lfs, true);
int err = lfs_fs_traverse_(lfs, lfs_alloc_lookahead, lfs, true);
if (err) {
lfs_alloc_drop(lfs);
return err;
@@ -693,7 +694,7 @@ static int lfs_alloc(lfs_t *lfs, lfs_block_t *block) {
// No blocks in our lookahead buffer, we need to scan the filesystem for
// unused blocks in the next lookahead window.
int err = lfs_fs_rawgc(lfs);
int err = lfs_alloc_scan(lfs);
if(err) {
return err;
}
@@ -2165,14 +2166,16 @@ 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;
}
// do we have extra space? littlefs can't reclaim this space
// by itself, so expand cautiously
if ((lfs_size_t)size < lfs->block_count/2) {
// littlefs cannot reclaim expanded superblocks, so expand cautiously
//
// if our filesystem is more than ~88% full, don't expand, this is
// somewhat arbitrary
if (lfs->block_count - size > lfs->block_count/8) {
LFS_DEBUG("Expanding superblock at rev %"PRIu32, dir->rev);
int err = lfs_dir_split(lfs, dir, attrs, attrcount,
source, begin, end);
@@ -2583,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) {
@@ -2679,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;
@@ -2723,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 '..'
@@ -2775,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;
}
@@ -2812,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) {
@@ -3023,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
@@ -3185,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
@@ -3383,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;
@@ -3496,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);
@@ -3521,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) {
@@ -3603,7 +3602,7 @@ relocate:
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);
@@ -3647,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;
@@ -3660,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 {
@@ -3711,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) {
@@ -3719,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;
}
@@ -3772,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;
}
@@ -3787,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;
}
@@ -3796,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;
}
@@ -3810,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
@@ -3824,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) {
@@ -3835,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) {
@@ -3914,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) {
@@ -3957,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;
@@ -4049,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);
@@ -4107,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;
@@ -4118,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
@@ -4172,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) {
@@ -4233,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;
@@ -4272,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);
@@ -4339,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;
@@ -4456,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
@@ -4502,17 +4547,17 @@ static int lfs_rawmount(lfs_t *lfs, const struct lfs_config *cfg) {
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)) {
@@ -4552,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
@@ -5017,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) {
@@ -5053,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;
}
@@ -5063,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);
@@ -5523,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.
@@ -5790,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);
@@ -5820,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);
@@ -5834,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);
@@ -5849,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);
@@ -5865,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);
@@ -5880,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);
@@ -5896,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);
@@ -5913,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);
@@ -5929,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);
@@ -5947,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);
@@ -5968,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);
@@ -5983,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);
@@ -5999,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);
@@ -6017,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);
@@ -6035,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);
@@ -6053,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);
@@ -6070,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);
@@ -6086,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);
@@ -6100,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);
@@ -6115,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);
@@ -6130,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);
@@ -6146,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);
@@ -6160,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);
@@ -6175,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);
@@ -6190,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);
@@ -6204,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);
@@ -6218,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);
@@ -6232,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);
@@ -6246,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);
@@ -6261,29 +6357,13 @@ 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);
return err;
}
#ifndef LFS_READONLY
int lfs_fs_gc(lfs_t *lfs) {
int err = LFS_LOCK(lfs->cfg);
if (err) {
return err;
}
LFS_TRACE("lfs_fs_gc(%p)", (void*)lfs);
err = lfs_fs_rawgc(lfs);
LFS_TRACE("lfs_fs_gc -> %d", err);
LFS_UNLOCK(lfs->cfg);
return err;
}
#endif
#ifndef LFS_READONLY
int lfs_fs_mkconsistent(lfs_t *lfs) {
int err = LFS_LOCK(lfs->cfg);
@@ -6292,7 +6372,7 @@ int lfs_fs_mkconsistent(lfs_t *lfs) {
}
LFS_TRACE("lfs_fs_mkconsistent(%p)", (void*)lfs);
err = lfs_fs_rawmkconsistent(lfs);
err = lfs_fs_mkconsistent_(lfs);
LFS_TRACE("lfs_fs_mkconsistent -> %d", err);
LFS_UNLOCK(lfs->cfg);
@@ -6300,6 +6380,22 @@ int lfs_fs_mkconsistent(lfs_t *lfs) {
}
#endif
#ifndef LFS_READONLY
int lfs_fs_gc(lfs_t *lfs) {
int err = LFS_LOCK(lfs->cfg);
if (err) {
return err;
}
LFS_TRACE("lfs_fs_gc(%p)", (void*)lfs);
err = lfs_fs_gc_(lfs);
LFS_TRACE("lfs_fs_gc -> %d", err);
LFS_UNLOCK(lfs->cfg);
return err;
}
#endif
#ifndef LFS_READONLY
int lfs_fs_grow(lfs_t *lfs, lfs_size_t block_count) {
int err = LFS_LOCK(lfs->cfg);
@@ -6308,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);
@@ -6339,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);

57
lfs.h
View File

@@ -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
@@ -229,6 +227,17 @@ struct lfs_config {
// 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;
@@ -263,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
@@ -442,6 +460,7 @@ typedef struct lfs {
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;
@@ -711,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
//
@@ -735,6 +742,24 @@ int lfs_fs_gc(lfs_t *lfs);
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.

View File

@@ -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

View File

@@ -212,14 +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
//
// 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;
@@ -229,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;

View File

@@ -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 = {

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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"};

View File

@@ -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;

View File

@@ -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 = '''