Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
26bee8a
drop a few unsupported CFLAGS for clang
yamt Apr 7, 2025
0d861b7
adapt the linker sections usage to mach-o
yamt Apr 7, 2025
b823728
lfs_crc should be static if LFS_CRC is defined
DvdGiessen Apr 16, 2025
2105e50
Add support for shrinking a filesystem
sosthene-nitrokey Apr 16, 2025
0634d13
tests: Added non-reentrant variants of orphan/relocation tests
geky May 3, 2025
a3d6bec
Fixed a double deorphan caused by relocation mid dir remove
geky May 3, 2025
9b8f802
fixup! Add support for shrinking a filesystem
sosthene-nitrokey May 5, 2025
f4a1bb3
fix: added uint32_t cast to the bitshift places
selimkeles May 5, 2025
7782d3d
Mention that shrinking is unlikely to work
sosthene-nitrokey May 6, 2025
7d79423
Rename SHRINKIFCHEAP to SHRINKNONRELOCATING
sosthene-nitrokey May 7, 2025
edaaaf8
Apply review comments
sosthene-nitrokey May 7, 2025
bff4dfd
Added NO_GCC to allow users to explicitly disable GCC-specific flags
geky May 8, 2025
0115cf6
gha: Dropped explicit CFLAGS from clang testing in CI
geky May 8, 2025
b26bf34
Merge pull request #1095 from DvdGiessen/lfs_crc
geky May 13, 2025
c1bf7ce
Merge pull request #1100 from selimkeles/fix/bitshift_overflow
geky May 13, 2025
d73fb8e
Merge pull request #1099 from littlefs-project/fix-remove-double-deor…
geky May 13, 2025
6a43f3c
Merge pull request #1090 from yamt/clang
geky May 13, 2025
3149201
Merge pull request #1091 from yamt/mach-o
geky May 13, 2025
8c458fa
Merge pull request #1094 from sosthene-nitrokey/shrink-fs
geky May 13, 2025
ba250a3
use shutil.move instead of os.rename to move file
DvdGiessen May 13, 2025
523319b
Merge pull request #1104 from DvdGiessen/os-rename-between-filesystems
geky May 13, 2025
8434536
Bumped minor version to v2.11
geky May 13, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 19 additions & 8 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,22 @@ jobs:
run: |
CFLAGS="$CFLAGS -DLFS_NO_INTRINSICS" make test

test-shrink:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: install
run: |
# need a few things
sudo apt-get update -qq
sudo apt-get install -qq gcc python3 python3-pip
pip3 install toml
gcc --version
python3 --version
- name: test-no-intrinsics
run: |
CFLAGS="$CFLAGS -DLFS_SHRINKNONRELOCATING" make test

# run with all trace options enabled to at least make sure these
# all compile
test-yes-trace:
Expand Down Expand Up @@ -454,8 +470,7 @@ jobs:
TESTFLAGS="$TESTFLAGS --valgrind --context=1024 -Gdefault -Pnone" \
make test

# test that compilation is warning free under clang
# run with Clang, mostly to check for Clang-specific warnings
# compile/run with Clang, mostly to check for Clang-specific warnings
test-clang:
runs-on: ubuntu-latest
steps:
Expand All @@ -469,12 +484,8 @@ jobs:
python3 --version
- name: test-clang
run: |
# override CFLAGS since Clang does not support -fcallgraph-info
# and -ftrack-macro-expansions
make \
CC=clang \
CFLAGS="$CFLAGS -MMD -g3 -I. -std=c99 -Wall -Wextra -pedantic" \
test
CC=clang \
make test

# run benchmarks
#
Expand Down
11 changes: 10 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ VALGRIND ?= valgrind
GDB ?= gdb
PERF ?= perf

# guess clang or gcc (clang sometimes masquerades as gcc because of
# course it does)
ifneq ($(shell $(CC) --version | grep clang),)
NO_GCC = 1
endif

SRC ?= $(filter-out $(wildcard *.t.* *.b.*),$(wildcard *.c))
OBJ := $(SRC:%.c=$(BUILDDIR)/%.o)
DEP := $(SRC:%.c=$(BUILDDIR)/%.d)
Expand Down Expand Up @@ -59,12 +65,15 @@ BENCH_PERF := $(BENCH_RUNNER:%=%.perf)
BENCH_TRACE := $(BENCH_RUNNER:%=%.trace)
BENCH_CSV := $(BENCH_RUNNER:%=%.csv)

CFLAGS += -fcallgraph-info=su
CFLAGS += -g3
CFLAGS += -I.
CFLAGS += -std=c99 -Wall -Wextra -pedantic
CFLAGS += -Wmissing-prototypes
ifndef NO_GCC
CFLAGS += -fcallgraph-info=su
CFLAGS += -ftrack-macro-expansion=0
endif

ifdef DEBUG
CFLAGS += -O0
else
Expand Down
80 changes: 54 additions & 26 deletions lfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -3932,7 +3932,9 @@ static int lfs_remove_(lfs_t *lfs, const char *path) {
}

lfs->mlist = dir.next;
if (lfs_tag_type3(tag) == LFS_TYPE_DIR) {
if (lfs_gstate_hasorphans(&lfs->gstate)) {
LFS_ASSERT(lfs_tag_type3(tag) == LFS_TYPE_DIR);

// fix orphan
err = lfs_fs_preporphans(lfs, -1);
if (err) {
Expand Down Expand Up @@ -4076,8 +4078,10 @@ static int lfs_rename_(lfs_t *lfs, const char *oldpath, const char *newpath) {
}

lfs->mlist = prevdir.next;
if (prevtag != LFS_ERR_NOENT
&& lfs_tag_type3(prevtag) == LFS_TYPE_DIR) {
if (lfs_gstate_hasorphans(&lfs->gstate)) {
LFS_ASSERT(prevtag != LFS_ERR_NOENT
&& lfs_tag_type3(prevtag) == LFS_TYPE_DIR);

// fix orphan
err = lfs_fs_preporphans(lfs, -1);
if (err) {
Expand Down Expand Up @@ -5233,40 +5237,64 @@ static int lfs_fs_gc_(lfs_t *lfs) {
#endif

#ifndef LFS_READONLY
#ifdef LFS_SHRINKNONRELOCATING
static int lfs_shrink_checkblock(void *data, lfs_block_t block) {
lfs_size_t threshold = *((lfs_size_t*)data);
if (block >= threshold) {
return LFS_ERR_NOTEMPTY;
}
return 0;
}
#endif

static int lfs_fs_grow_(lfs_t *lfs, lfs_size_t block_count) {
// shrinking is not supported
LFS_ASSERT(block_count >= lfs->block_count);
int err;

if (block_count > lfs->block_count) {
lfs->block_count = block_count;
if (block_count == lfs->block_count) {
return 0;
}

// fetch the root
lfs_mdir_t root;
int err = lfs_dir_fetch(lfs, &root, lfs->root);

#ifndef LFS_SHRINKNONRELOCATING
// shrinking is not supported
LFS_ASSERT(block_count >= lfs->block_count);
#endif
#ifdef LFS_SHRINKNONRELOCATING
if (block_count < lfs->block_count) {
err = lfs_fs_traverse_(lfs, lfs_shrink_checkblock, &block_count, true);
if (err) {
return err;
}
}
#endif

// update the superblock
lfs_superblock_t superblock;
lfs_stag_t tag = lfs_dir_get(lfs, &root, LFS_MKTAG(0x7ff, 0x3ff, 0),
LFS_MKTAG(LFS_TYPE_INLINESTRUCT, 0, sizeof(superblock)),
&superblock);
if (tag < 0) {
return tag;
}
lfs_superblock_fromle32(&superblock);
lfs->block_count = block_count;

superblock.block_count = lfs->block_count;
// fetch the root
lfs_mdir_t root;
err = lfs_dir_fetch(lfs, &root, lfs->root);
if (err) {
return err;
}

lfs_superblock_tole32(&superblock);
err = lfs_dir_commit(lfs, &root, LFS_MKATTRS(
{tag, &superblock}));
if (err) {
return err;
}
// update the superblock
lfs_superblock_t superblock;
lfs_stag_t tag = lfs_dir_get(lfs, &root, LFS_MKTAG(0x7ff, 0x3ff, 0),
LFS_MKTAG(LFS_TYPE_INLINESTRUCT, 0, sizeof(superblock)),
&superblock);
if (tag < 0) {
return tag;
}
lfs_superblock_fromle32(&superblock);

superblock.block_count = lfs->block_count;

lfs_superblock_tole32(&superblock);
err = lfs_dir_commit(lfs, &root, LFS_MKATTRS(
{tag, &superblock}));
if (err) {
return err;
}
return 0;
}
#endif
Expand Down
8 changes: 6 additions & 2 deletions lfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 0x0002000a
#define LFS_VERSION 0x0002000b
#define LFS_VERSION_MAJOR (0xffff & (LFS_VERSION >> 16))
#define LFS_VERSION_MINOR (0xffff & (LFS_VERSION >> 0))

Expand Down Expand Up @@ -766,7 +766,11 @@ int lfs_fs_gc(lfs_t *lfs);
// Grows the filesystem to a new size, updating the superblock with the new
// block count.
//
// Note: This is irreversible.
// If LFS_SHRINKNONRELOCATING is defined, this function will also accept
// block_counts smaller than the current configuration, after checking
// that none of the blocks that are being removed are in use.
// Note that littlefs's pseudorandom block allocation means that
// this is very unlikely to work in the general case.
//
// Returns a negative error code on failure.
int lfs_fs_grow(lfs_t *lfs, lfs_size_t block_count);
Expand Down
20 changes: 10 additions & 10 deletions lfs_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -195,10 +195,10 @@ static inline uint32_t lfs_fromle32(uint32_t a) {
(defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))
return __builtin_bswap32(a);
#else
return (((uint8_t*)&a)[0] << 0) |
(((uint8_t*)&a)[1] << 8) |
(((uint8_t*)&a)[2] << 16) |
(((uint8_t*)&a)[3] << 24);
return ((uint32_t)((uint8_t*)&a)[0] << 0) |
((uint32_t)((uint8_t*)&a)[1] << 8) |
((uint32_t)((uint8_t*)&a)[2] << 16) |
((uint32_t)((uint8_t*)&a)[3] << 24);
#endif
}

Expand All @@ -218,10 +218,10 @@ static inline uint32_t lfs_frombe32(uint32_t a) {
(defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
return a;
#else
return (((uint8_t*)&a)[0] << 24) |
(((uint8_t*)&a)[1] << 16) |
(((uint8_t*)&a)[2] << 8) |
(((uint8_t*)&a)[3] << 0);
return ((uint32_t)((uint8_t*)&a)[0] << 24) |
((uint32_t)((uint8_t*)&a)[1] << 16) |
((uint32_t)((uint8_t*)&a)[2] << 8) |
((uint32_t)((uint8_t*)&a)[3] << 0);
#endif
}

Expand All @@ -231,8 +231,8 @@ 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)
static inline 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);
Expand Down
5 changes: 5 additions & 0 deletions runners/bench_runner.c
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,13 @@ typedef struct bench_id {


// bench suites are linked into a custom ld section
#if defined(__APPLE__)
extern struct bench_suite __start__bench_suites __asm("section$start$__DATA$_bench_suites");
extern struct bench_suite __stop__bench_suites __asm("section$end$__DATA$_bench_suites");
#else
extern struct bench_suite __start__bench_suites;
extern struct bench_suite __stop__bench_suites;
#endif

const struct bench_suite *bench_suites = &__start__bench_suites;
#define BENCH_SUITE_COUNT \
Expand Down
5 changes: 5 additions & 0 deletions runners/test_runner.c
Original file line number Diff line number Diff line change
Expand Up @@ -136,8 +136,13 @@ typedef struct test_id {


// test suites are linked into a custom ld section
#if defined(__APPLE__)
extern struct test_suite __start__test_suites __asm("section$start$__DATA$_test_suites");
extern struct test_suite __stop__test_suites __asm("section$end$__DATA$_test_suites");
#else
extern struct test_suite __start__test_suites;
extern struct test_suite __stop__test_suites;
#endif

const struct test_suite *test_suites = &__start__test_suites;
#define TEST_SUITE_COUNT \
Expand Down
5 changes: 4 additions & 1 deletion scripts/bench.py
Original file line number Diff line number Diff line change
Expand Up @@ -404,12 +404,15 @@ def write_case_functions(f, suite, case):
f.writeln()

# create suite struct
#
f.writeln('#if defined(__APPLE__)')
f.writeln('__attribute__((section("__DATA,_bench_suites")))')
f.writeln('#else')
# note we place this in the custom bench_suites section with
# minimum alignment, otherwise GCC ups the alignment to
# 32-bytes for some reason
f.writeln('__attribute__((section("_bench_suites"), '
'aligned(1)))')
f.writeln('#endif')
f.writeln('const struct bench_suite __bench__%s__suite = {'
% suite.name)
f.writeln(4*' '+'.name = "%s",' % suite.name)
Expand Down
2 changes: 1 addition & 1 deletion scripts/changeprefix.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ def changefile(from_prefix, to_prefix, from_path, to_path, *,
shutil.copystat(from_path, to_path)

if to_path_temp:
os.rename(to_path, from_path)
shutil.move(to_path, from_path)
elif from_path != '-':
os.remove(from_path)

Expand Down
5 changes: 4 additions & 1 deletion scripts/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -412,12 +412,15 @@ def write_case_functions(f, suite, case):
f.writeln()

# create suite struct
#
f.writeln('#if defined(__APPLE__)')
f.writeln('__attribute__((section("__DATA,_test_suites")))')
f.writeln('#else')
# note we place this in the custom test_suites section with
# minimum alignment, otherwise GCC ups the alignment to
# 32-bytes for some reason
f.writeln('__attribute__((section("_test_suites"), '
'aligned(1)))')
f.writeln('#endif')
f.writeln('const struct test_suite __test__%s__suite = {'
% suite.name)
f.writeln(4*' '+'.name = "%s",' % suite.name)
Expand Down
Loading
Loading