Compare commits

...

6 Commits

Author SHA1 Message Date
Christopher Haster
5f885f0af1 Adopted per-member static configurations
Instead of 1. defining LFS_STATICCFG and 2. defining all LFS_READ_SIZE,
LFS_PROG_SIZE, etc. Configuration can now be made static by defining
LFS_READ_SIZE, LFS_PROG_SIZE, etc. Thanks to a really large ifdef, if
all configurations are provided, LFS_STATICCFG will be defined and the
RAM cost fully removed.

Additionally, we can remove the ROM cost of each struct cfg member,
allowing code savings when config is only partially defined, which is
perhaps more common.

This moves all of the configuration logic in lfs.h, which has the nice
side effect of keeping all of the decision making in the same location.

The only catch is that we need to differentiate between the cfg->*_max
and *_MAX limits. To do this I've renamed the configuration *_max to
*_limit. Note that these two are slightly different, with *_max
indicating the maximum supported by the current driver, and *_limit
the maximum supported by the specific instance of littlefs. However if
you do define a *_LIMIT, I've added an override for the relevant *_MAX,
since I can't think of a time where you _wouldn't_ want to do that.

---

This also required some tweaks in scripts/test.py in order to populate
the lfs_cfg struct correctly. This happens since the test defines
overlap littlefs's configuration defines. This does change what is being
tested a bit, but hopefully that's not a real issue.

Suggested by tim-nordell-nimbelink
2020-12-14 23:50:39 -06:00
Christopher Haster
fe42d102a5 Added make build as an alias for make all 2020-11-28 20:11:36 -06:00
Christopher Haster
499083765c Renamed cache_size -> buffer_size
This makes littlefs's usage of the term "cache" an entirely internal
concept and hopefully avoids some confusion about the usefulness of
throwing RAM > block_size at these buffers.

The term cache isn't entirely inaccurate, these buffers do act as
single-line caches, however more often the term cache is used to
describe multi-line caches. Maybe this will be added in littlefs's
future, but the code-size cost makes this change not worth the overhead
at the moment.
2020-11-28 20:11:36 -06:00
Christopher Haster
aa46bb68ca Made it easier to debug generated test files
Added internal lineno tracking of generated test files so that test.py
can reset the generated #line directives after a test case. This helps
debug issues with the generated glue code itself, which would previously
end up with invalid/unhelpful lineno information in error messages.

Also changed suffix from .c.t to .tc
2020-11-28 20:11:36 -06:00
Christopher Haster
190eb833a2 Changed bd callbacks to use "bd_" prefix
This makes the block-device related operations more clearly block-device
related operations, and helps avoid possible conflicts with user
provided `lfs_bd_read/prog/erase` functions in the LFS_STATICCFG mode.
2020-11-28 20:11:36 -06:00
Christopher Haster
30ed816feb Standardized on externally provided config structs in the block devices
I have another branch where I tried exploring inlined config structs
backed by RAM, but this did not work out due to additional RAM and ROM costs.

Changing the bds to follow this was surprisingly annoying, as they had a
lot of shared geometry that was previously in a single shared config
object, and the way that testbd contains either of rambd and filebd made
configuring all three of these a bit complicated.

Ended up settling on a lfs_testbd_cfg that contains optional pointers to
lfs_rambd_cfg and lfs_filebd_cfg. These can be NULL, but only if that
bd goes unused.
2020-11-28 20:11:36 -06:00
15 changed files with 605 additions and 489 deletions

View File

@@ -50,7 +50,7 @@ _: &test-no-intrinsics
_: &test-no-inline
- make test TFLAGS+="-nrk -DLFS_INLINE_MAX=0"
_: &test-byte-writes
- make test TFLAGS+="-nrk -DLFS_READ_SIZE=1 -DLFS_CACHE_SIZE=1"
- make test TFLAGS+="-nrk -DLFS_READ_SIZE=1 -DLFS_BUFFER_SIZE=1"
_: &test-block-cycles
- make test TFLAGS+="-nrk -DLFS_BLOCK_CYCLES=1"
_: &test-odd-block-count
@@ -214,14 +214,20 @@ jobs:
- NAME=littlefs-minimal
- CC="arm-linux-gnueabi-gcc --static -mthumb"
- CFLAGS="-Werror
-DLFS_STATICCFG -DLFS_FILE_STATICCFG
-DLFS_BD_READ
-DLFS_BD_PROG
-DLFS_BD_ERASE
-DLFS_BD_SYNC
-DLFS_READ_SIZE=16
-DLFS_PROG_SIZE=16
-DLFS_BLOCK_SIZE=512
-DLFS_BLOCK_COUNT=1024
-DLFS_BLOCK_CYCLES=-1
-DLFS_CACHE_SIZE=64
-DLFS_BLOCK_CYCLES=1024
-DLFS_BUFFER_SIZE=64
-DLFS_LOOKAHEAD_SIZE=16
-DLFS_NAME_LIMIT=0
-DLFS_FILE_LIMIT=0
-DLFS_ATTR_LIMIT=0
-DLFS_NO_ASSERT -DLFS_NO_DEBUG -DLFS_NO_WARN -DLFS_NO_ERROR"
if: branch !~ -prefix$
install:

View File

@@ -32,7 +32,7 @@ override TFLAGS += -v
endif
all: $(TARGET)
all build: $(TARGET)
asm: $(ASM)

View File

@@ -19,9 +19,7 @@ int lfs_filebd_createcfg(lfs_filebd_t *bd, const char *path,
(void*)bd, path, (void*)cfg,
cfg->read_size, cfg->prog_size, cfg->erase_size, cfg->erase_count,
cfg->erase_value);
// copy over config
bd->cfg = *cfg;
bd->cfg = cfg;
// open file
bd->fd = open(path, O_RDWR | O_CREAT, 0666);
@@ -54,18 +52,18 @@ int lfs_filebd_read(lfs_filebd_t *bd, lfs_block_t block,
(void*)bd, block, off, buffer, size);
// check if read is valid
LFS_ASSERT(off % bd->cfg.read_size == 0);
LFS_ASSERT(size % bd->cfg.read_size == 0);
LFS_ASSERT(block < bd->cfg.erase_count);
LFS_ASSERT(off % bd->cfg->read_size == 0);
LFS_ASSERT(size % bd->cfg->read_size == 0);
LFS_ASSERT(block < bd->cfg->erase_count);
// zero for reproducability (in case file is truncated)
if (bd->cfg.erase_value != -1) {
memset(buffer, bd->cfg.erase_value, size);
if (bd->cfg->erase_value != -1) {
memset(buffer, bd->cfg->erase_value, size);
}
// read
off_t res1 = lseek(bd->fd,
(off_t)block*bd->cfg.erase_size + (off_t)off, SEEK_SET);
(off_t)block*bd->cfg->erase_size + (off_t)off, SEEK_SET);
if (res1 < 0) {
int err = -errno;
LFS_FILEBD_TRACE("lfs_filebd_read -> %d", err);
@@ -90,14 +88,14 @@ int lfs_filebd_prog(lfs_filebd_t *bd, lfs_block_t block,
(void*)bd, block, off, buffer, size);
// check if write is valid
LFS_ASSERT(off % bd->cfg.prog_size == 0);
LFS_ASSERT(size % bd->cfg.prog_size == 0);
LFS_ASSERT(block < bd->cfg.erase_count);
LFS_ASSERT(off % bd->cfg->prog_size == 0);
LFS_ASSERT(size % bd->cfg->prog_size == 0);
LFS_ASSERT(block < bd->cfg->erase_count);
// check that data was erased? only needed for testing
if (bd->cfg.erase_value != -1) {
if (bd->cfg->erase_value != -1) {
off_t res1 = lseek(bd->fd,
(off_t)block*bd->cfg.erase_size + (off_t)off, SEEK_SET);
(off_t)block*bd->cfg->erase_size + (off_t)off, SEEK_SET);
if (res1 < 0) {
int err = -errno;
LFS_FILEBD_TRACE("lfs_filebd_prog -> %d", err);
@@ -113,13 +111,13 @@ int lfs_filebd_prog(lfs_filebd_t *bd, lfs_block_t block,
return err;
}
LFS_ASSERT(c == bd->cfg.erase_value);
LFS_ASSERT(c == bd->cfg->erase_value);
}
}
// program data
off_t res1 = lseek(bd->fd,
(off_t)block*bd->cfg.erase_size + (off_t)off, SEEK_SET);
(off_t)block*bd->cfg->erase_size + (off_t)off, SEEK_SET);
if (res1 < 0) {
int err = -errno;
LFS_FILEBD_TRACE("lfs_filebd_prog -> %d", err);
@@ -141,19 +139,19 @@ int lfs_filebd_erase(lfs_filebd_t *bd, lfs_block_t block) {
LFS_FILEBD_TRACE("lfs_filebd_erase(%p, 0x%"PRIx32")", (void*)bd, block);
// check if erase is valid
LFS_ASSERT(block < bd->cfg.erase_count);
LFS_ASSERT(block < bd->cfg->erase_count);
// erase, only needed for testing
if (bd->cfg.erase_value != -1) {
off_t res1 = lseek(bd->fd, (off_t)block*bd->cfg.erase_size, SEEK_SET);
if (bd->cfg->erase_value != -1) {
off_t res1 = lseek(bd->fd, (off_t)block*bd->cfg->erase_size, SEEK_SET);
if (res1 < 0) {
int err = -errno;
LFS_FILEBD_TRACE("lfs_filebd_erase -> %d", err);
return err;
}
for (lfs_off_t i = 0; i < bd->cfg.erase_size; i++) {
ssize_t res2 = write(bd->fd, &(uint8_t){bd->cfg.erase_value}, 1);
for (lfs_off_t i = 0; i < bd->cfg->erase_size; i++) {
ssize_t res2 = write(bd->fd, &(uint8_t){bd->cfg->erase_value}, 1);
if (res2 < 0) {
int err = -errno;
LFS_FILEBD_TRACE("lfs_filebd_erase -> %d", err);

View File

@@ -46,7 +46,7 @@ struct lfs_filebd_cfg {
// filebd state
typedef struct lfs_filebd {
int fd;
struct lfs_filebd_cfg cfg;
const struct lfs_filebd_cfg *cfg;
} lfs_filebd_t;

View File

@@ -15,15 +15,13 @@ int lfs_rambd_createcfg(lfs_rambd_t *bd,
(void*)bd, (void*)cfg,
cfg->read_size, cfg->prog_size, cfg->erase_size, cfg->erase_count,
cfg->erase_value, cfg->buffer);
// copy over config
bd->cfg = *cfg;
bd->cfg = cfg;
// allocate buffer?
if (bd->cfg.buffer) {
bd->buffer = bd->cfg.buffer;
if (bd->cfg->buffer) {
bd->buffer = bd->cfg->buffer;
} else {
bd->buffer = lfs_malloc(bd->cfg.erase_size * bd->cfg.erase_count);
bd->buffer = lfs_malloc(bd->cfg->erase_size * bd->cfg->erase_count);
if (!bd->buffer) {
LFS_RAMBD_TRACE("lfs_rambd_createcfg -> %d", LFS_ERR_NOMEM);
return LFS_ERR_NOMEM;
@@ -31,9 +29,9 @@ int lfs_rambd_createcfg(lfs_rambd_t *bd,
}
// zero for reproducability?
if (bd->cfg.erase_value != -1) {
memset(bd->buffer, bd->cfg.erase_value,
bd->cfg.erase_size * bd->cfg.erase_count);
if (bd->cfg->erase_value != -1) {
memset(bd->buffer, bd->cfg->erase_value,
bd->cfg->erase_size * bd->cfg->erase_count);
}
LFS_RAMBD_TRACE("lfs_rambd_createcfg -> %d", 0);
@@ -43,7 +41,7 @@ int lfs_rambd_createcfg(lfs_rambd_t *bd,
int lfs_rambd_destroy(lfs_rambd_t *bd) {
LFS_RAMBD_TRACE("lfs_rambd_destroy(%p)", (void*)bd);
// clean up memory
if (!bd->cfg.buffer) {
if (!bd->cfg->buffer) {
lfs_free(bd->buffer);
}
LFS_RAMBD_TRACE("lfs_rambd_destroy -> %d", 0);
@@ -57,12 +55,12 @@ int lfs_rambd_read(lfs_rambd_t *bd, lfs_block_t block,
(void*)bd, block, off, buffer, size);
// check if read is valid
LFS_ASSERT(off % bd->cfg.read_size == 0);
LFS_ASSERT(size % bd->cfg.read_size == 0);
LFS_ASSERT(block < bd->cfg.erase_count);
LFS_ASSERT(off % bd->cfg->read_size == 0);
LFS_ASSERT(size % bd->cfg->read_size == 0);
LFS_ASSERT(block < bd->cfg->erase_count);
// read data
memcpy(buffer, &bd->buffer[block*bd->cfg.erase_size + off], size);
memcpy(buffer, &bd->buffer[block*bd->cfg->erase_size + off], size);
LFS_RAMBD_TRACE("lfs_rambd_read -> %d", 0);
return 0;
@@ -75,20 +73,20 @@ int lfs_rambd_prog(lfs_rambd_t *bd, lfs_block_t block,
(void*)bd, block, off, buffer, size);
// check if write is valid
LFS_ASSERT(off % bd->cfg.prog_size == 0);
LFS_ASSERT(size % bd->cfg.prog_size == 0);
LFS_ASSERT(block < bd->cfg.erase_count);
LFS_ASSERT(off % bd->cfg->prog_size == 0);
LFS_ASSERT(size % bd->cfg->prog_size == 0);
LFS_ASSERT(block < bd->cfg->erase_count);
// check that data was erased? only needed for testing
if (bd->cfg.erase_value != -1) {
if (bd->cfg->erase_value != -1) {
for (lfs_off_t i = 0; i < size; i++) {
LFS_ASSERT(bd->buffer[block*bd->cfg.erase_size + off + i] ==
bd->cfg.erase_value);
LFS_ASSERT(bd->buffer[block*bd->cfg->erase_size + off + i] ==
bd->cfg->erase_value);
}
}
// program data
memcpy(&bd->buffer[block*bd->cfg.erase_size + off], buffer, size);
memcpy(&bd->buffer[block*bd->cfg->erase_size + off], buffer, size);
LFS_RAMBD_TRACE("lfs_rambd_prog -> %d", 0);
return 0;
@@ -98,12 +96,12 @@ int lfs_rambd_erase(lfs_rambd_t *bd, lfs_block_t block) {
LFS_RAMBD_TRACE("lfs_rambd_erase(%p, 0x%"PRIx32")", (void*)bd, block);
// check if erase is valid
LFS_ASSERT(block < bd->cfg.erase_count);
LFS_ASSERT(block < bd->cfg->erase_count);
// erase, only needed for testing
if (bd->cfg.erase_value != -1) {
memset(&bd->buffer[block*bd->cfg.erase_size],
bd->cfg.erase_value, bd->cfg.erase_size);
if (bd->cfg->erase_value != -1) {
memset(&bd->buffer[block*bd->cfg->erase_size],
bd->cfg->erase_value, bd->cfg->erase_size);
}
LFS_RAMBD_TRACE("lfs_rambd_erase -> %d", 0);

View File

@@ -37,8 +37,9 @@ struct lfs_rambd_cfg {
// Number of erasable blocks on the device.
lfs_size_t erase_count;
// 8-bit erase value to simulate erasing with. -1 indicates no erase
// occurs, which is still a valid block device
// 8-bit erase value to use for simulating erases. -1 does not simulate
// erases, which can speed up testing by avoiding all the extra block-device
// operations to store the erase value.
int32_t erase_value;
// Optional statically allocated buffer for the block device.
@@ -48,7 +49,7 @@ struct lfs_rambd_cfg {
// rambd state
typedef struct lfs_rambd {
uint8_t *buffer;
struct lfs_rambd_cfg cfg;
const struct lfs_rambd_cfg *cfg;
} lfs_rambd_t;

View File

@@ -23,17 +23,15 @@ int lfs_testbd_createcfg(lfs_testbd_t *bd, const char *path,
cfg->erase_value, cfg->erase_cycles,
cfg->badblock_behavior, cfg->power_cycles,
cfg->buffer, cfg->wear_buffer);
// copy over config
bd->cfg = *cfg;
bd->cfg = cfg;
// setup testing things
bd->persist = path;
bd->power_cycles = bd->cfg.power_cycles;
bd->power_cycles = bd->cfg->power_cycles;
if (bd->cfg.erase_cycles) {
if (bd->cfg.wear_buffer) {
bd->wear = bd->cfg.wear_buffer;
if (bd->cfg->erase_cycles) {
if (bd->cfg->wear_buffer) {
bd->wear = bd->cfg->wear_buffer;
} else {
bd->wear = lfs_malloc(sizeof(lfs_testbd_wear_t)*cfg->erase_count);
if (!bd->wear) {
@@ -42,29 +40,18 @@ int lfs_testbd_createcfg(lfs_testbd_t *bd, const char *path,
}
}
memset(bd->wear, 0, sizeof(lfs_testbd_wear_t) * bd->cfg.erase_count);
memset(bd->wear, 0, sizeof(lfs_testbd_wear_t) * bd->cfg->erase_count);
}
// create underlying block device
if (bd->persist) {
int err = lfs_filebd_createcfg(&bd->impl.filebd, path,
&(struct lfs_filebd_cfg){
.read_size=bd->cfg.read_size,
.prog_size=bd->cfg.prog_size,
.erase_size=bd->cfg.erase_size,
.erase_count=bd->cfg.erase_count,
.erase_value=bd->cfg.erase_value});
bd->cfg->filebd_cfg);
LFS_TESTBD_TRACE("lfs_testbd_createcfg -> %d", err);
return err;
} else {
int err = lfs_rambd_createcfg(&bd->impl.rambd,
&(struct lfs_rambd_cfg){
.read_size=bd->cfg.read_size,
.prog_size=bd->cfg.prog_size,
.erase_size=bd->cfg.erase_size,
.erase_count=bd->cfg.erase_count,
.erase_value=bd->cfg.erase_value,
.buffer=bd->cfg.buffer});
bd->cfg->rambd_cfg);
LFS_TESTBD_TRACE("lfs_testbd_createcfg -> %d", err);
return err;
}
@@ -72,7 +59,7 @@ int lfs_testbd_createcfg(lfs_testbd_t *bd, const char *path,
int lfs_testbd_destroy(lfs_testbd_t *bd) {
LFS_TESTBD_TRACE("lfs_testbd_destroy(%p)", (void*)bd);
if (bd->cfg.erase_cycles && !bd->cfg.wear_buffer) {
if (bd->cfg->erase_cycles && !bd->cfg->wear_buffer) {
lfs_free(bd->wear);
}
@@ -131,13 +118,13 @@ int lfs_testbd_read(lfs_testbd_t *bd, lfs_block_t block,
(void*)bd, block, off, buffer, size);
// check if read is valid
LFS_ASSERT(off % bd->cfg.read_size == 0);
LFS_ASSERT(size % bd->cfg.read_size == 0);
LFS_ASSERT(block < bd->cfg.erase_count);
LFS_ASSERT(off % bd->cfg->read_size == 0);
LFS_ASSERT(size % bd->cfg->read_size == 0);
LFS_ASSERT(block < bd->cfg->erase_count);
// block bad?
if (bd->cfg.erase_cycles && bd->wear[block] >= bd->cfg.erase_cycles &&
bd->cfg.badblock_behavior == LFS_TESTBD_BADBLOCK_READERROR) {
if (bd->cfg->erase_cycles && bd->wear[block] >= bd->cfg->erase_cycles &&
bd->cfg->badblock_behavior == LFS_TESTBD_BADBLOCK_READERROR) {
LFS_TESTBD_TRACE("lfs_testbd_read -> %d", LFS_ERR_CORRUPT);
return LFS_ERR_CORRUPT;
}
@@ -155,19 +142,19 @@ int lfs_testbd_prog(lfs_testbd_t *bd, lfs_block_t block,
(void*)bd, block, off, buffer, size);
// check if write is valid
LFS_ASSERT(off % bd->cfg.prog_size == 0);
LFS_ASSERT(size % bd->cfg.prog_size == 0);
LFS_ASSERT(block < bd->cfg.erase_count);
LFS_ASSERT(off % bd->cfg->prog_size == 0);
LFS_ASSERT(size % bd->cfg->prog_size == 0);
LFS_ASSERT(block < bd->cfg->erase_count);
// block bad?
if (bd->cfg.erase_cycles && bd->wear[block] >= bd->cfg.erase_cycles) {
if (bd->cfg.badblock_behavior ==
if (bd->cfg->erase_cycles && bd->wear[block] >= bd->cfg->erase_cycles) {
if (bd->cfg->badblock_behavior ==
LFS_TESTBD_BADBLOCK_PROGERROR) {
LFS_TESTBD_TRACE("lfs_testbd_prog -> %d", LFS_ERR_CORRUPT);
return LFS_ERR_CORRUPT;
} else if (bd->cfg.badblock_behavior ==
} else if (bd->cfg->badblock_behavior ==
LFS_TESTBD_BADBLOCK_PROGNOOP ||
bd->cfg.badblock_behavior ==
bd->cfg->badblock_behavior ==
LFS_TESTBD_BADBLOCK_ERASENOOP) {
LFS_TESTBD_TRACE("lfs_testbd_prog -> %d", 0);
return 0;
@@ -200,16 +187,16 @@ int lfs_testbd_erase(lfs_testbd_t *bd, lfs_block_t block) {
LFS_TESTBD_TRACE("lfs_testbd_erase(%p, 0x%"PRIx32")", (void*)bd, block);
// check if erase is valid
LFS_ASSERT(block < bd->cfg.erase_count);
LFS_ASSERT(block < bd->cfg->erase_count);
// block bad?
if (bd->cfg.erase_cycles) {
if (bd->wear[block] >= bd->cfg.erase_cycles) {
if (bd->cfg.badblock_behavior ==
if (bd->cfg->erase_cycles) {
if (bd->wear[block] >= bd->cfg->erase_cycles) {
if (bd->cfg->badblock_behavior ==
LFS_TESTBD_BADBLOCK_ERASEERROR) {
LFS_TESTBD_TRACE("lfs_testbd_erase -> %d", LFS_ERR_CORRUPT);
return LFS_ERR_CORRUPT;
} else if (bd->cfg.badblock_behavior ==
} else if (bd->cfg->badblock_behavior ==
LFS_TESTBD_BADBLOCK_ERASENOOP) {
LFS_TESTBD_TRACE("lfs_testbd_erase -> %d", 0);
return 0;
@@ -256,8 +243,8 @@ lfs_testbd_swear_t lfs_testbd_getwear(lfs_testbd_t *bd,
LFS_TESTBD_TRACE("lfs_testbd_getwear(%p, %"PRIu32")", (void*)bd, block);
// check if block is valid
LFS_ASSERT(bd->cfg.erase_cycles);
LFS_ASSERT(block < bd->cfg.erase_count);
LFS_ASSERT(bd->cfg->erase_cycles);
LFS_ASSERT(block < bd->cfg->erase_count);
LFS_TESTBD_TRACE("lfs_testbd_getwear -> %"PRIu32, bd->wear[block]);
return bd->wear[block];
@@ -268,8 +255,8 @@ int lfs_testbd_setwear(lfs_testbd_t *bd,
LFS_TESTBD_TRACE("lfs_testbd_setwear(%p, %"PRIu32")", (void*)bd, block);
// check if block is valid
LFS_ASSERT(bd->cfg.erase_cycles);
LFS_ASSERT(block < bd->cfg.erase_count);
LFS_ASSERT(bd->cfg->erase_cycles);
LFS_ASSERT(block < bd->cfg->erase_count);
bd->wear[block] = wear;

View File

@@ -44,6 +44,11 @@ typedef int32_t lfs_testbd_swear_t;
// testbd config, this is required for testing
struct lfs_testbd_cfg {
// Block device specific configuration, see the related config structs.
// May be NULL if the underlying implementation goes unused.
const struct lfs_rambd_cfg *rambd_cfg;
const struct lfs_filebd_cfg *filebd_cfg;
// Minimum size of block read. All read operations must be a
// multiple of this value.
lfs_size_t read_size;
@@ -74,9 +79,6 @@ struct lfs_testbd_cfg {
// the program with exit. Simulates power-loss. 0 disables.
uint32_t power_cycles;
// Optional buffer for RAM block device.
void *buffer;
// Optional buffer for wear
void *wear_buffer;
};
@@ -92,7 +94,7 @@ typedef struct lfs_testbd {
uint32_t power_cycles;
lfs_testbd_wear_t *wear;
struct lfs_testbd_cfg cfg;
const struct lfs_testbd_cfg *cfg;
} lfs_testbd_t;

520
lfs.c

File diff suppressed because it is too large Load Diff

270
lfs.h
View File

@@ -46,8 +46,13 @@ typedef uint32_t lfs_block_t;
// info struct. Limited to <= 1022. Stored in superblock and must be
// respected by other littlefs drivers.
#ifndef LFS_NAME_MAX
#if defined(LFS_NAME_LIMIT) && \
LFS_NAME_LIMIT > 0 && LFS_NAME_MAX <= 1022
#define LFS_NAME_MAX LFS_NAME_LIMIT
#else
#define LFS_NAME_MAX 255
#endif
#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
@@ -55,14 +60,24 @@ typedef uint32_t lfs_block_t;
// incorrect values due to using signed integers. Stored in superblock and
// must be respected by other littlefs drivers.
#ifndef LFS_FILE_MAX
#if defined(LFS_FILE_LIMIT) && \
LFS_FILE_LIMIT > 0 && LFS_FILE_LIMIT <= 4294967296
#define LFS_FILE_MAX LFS_FILE_LIMIT
#else
#define LFS_FILE_MAX 2147483647
#endif
#endif
// Maximum size of custom attributes in bytes, may be redefined, but there is
// no real benefit to using a smaller LFS_ATTR_MAX. Limited to <= 1022.
#ifndef LFS_ATTR_MAX
#if defined(LFS_ATTR_LIMIT) && \
LFS_ATTR_LIMIT > 0 && LFS_ATTR_LIMIT <= 1022
#define LFS_ATTR_MAX LFS_FILE_LIMIT
#else
#define LFS_ATTR_MAX 1022
#endif
#endif
// File types
enum lfs_type {
@@ -125,50 +140,129 @@ enum lfs_whence_flags {
};
#if !defined(LFS_STATICCFG)
// Configuration provided during initialization of the littlefs
// If every config option is provided at compile time, littlefs switches
// to "LFS_STATICCFG" mode. The dynamic lfs_cfg struct is not included in
// the lfs_t struct, and *cfg functions are no longer available.
#if defined(LFS_BD_READ) && \
defined(LFS_BD_PROG) && \
defined(LFS_BD_ERASE) && \
defined(LFS_BD_SYNC) && \
defined(LFS_READ_SIZE) && \
defined(LFS_PROG_SIZE) && \
defined(LFS_BLOCK_SIZE) && \
defined(LFS_BLOCK_COUNT) && \
defined(LFS_BLOCK_CYCLES) && \
defined(LFS_BUFFER_SIZE) && \
defined(LFS_LOOKAHEAD_SIZE) && \
defined(LFS_READ_BUFFER) && \
defined(LFS_PROG_BUFFER) && \
defined(LFS_LOOKAHEAD_BUFFER) && \
defined(LFS_NAME_LIMIT) && \
defined(LFS_FILE_LIMIT) && \
defined(LFS_ATTR_LIMIT)
#define LFS_STATICCFG
#endif
// Dynamic config struct
#ifndef LFS_STATICCFG
struct lfs_cfg {
#endif
// Opaque user provided context that can be used to pass
// information to the block device operations
void *ctx;
#if !(defined(LFS_BD_READ) && \
defined(LFS_BD_PROG) && \
defined(LFS_BD_ERASE) && \
defined(LFS_BD_SYNC))
void *bd_ctx;
#endif
// Read a region in a block. Negative error codes are propogated
// to the user.
int (*read)(void *ctx, lfs_block_t block,
#ifndef LFS_BD_READ
int (*bd_read)(void *ctx, lfs_block_t block,
lfs_off_t off, void *buffer, lfs_size_t size);
#define LFS_CFG_BD_READ(cfg, block, off, buffer, size) \
(cfg)->bd_read((cfg)->bd_ctx, block, off, buffer, size)
#else
#define LFS_CFG_BD_READ(cfg, block, off, buffer, size) \
lfs_bd_read(block, off, buffer, size)
#endif
// Program a region in a block. The block must have previously
// been erased. Negative error codes are propogated to the user.
// May return LFS_ERR_CORRUPT if the block should be considered bad.
int (*prog)(void *ctx, lfs_block_t block,
#ifndef LFS_BD_PROG
int (*bd_prog)(void *ctx, lfs_block_t block,
lfs_off_t off, const void *buffer, lfs_size_t size);
#define LFS_CFG_BD_PROG(cfg, block, off, buffer, size) \
(cfg)->bd_prog((cfg)->bd_ctx, block, off, buffer, size)
#else
#define LFS_CFG_BD_PROG(cfg, block, off, buffer, size) \
lfs_bd_prog(block, off, buffer, size)
#endif
// Erase a block. A block must be erased before being programmed.
// The state of an erased block is undefined. Negative error codes
// are propogated to the user.
// May return LFS_ERR_CORRUPT if the block should be considered bad.
int (*erase)(void *ctx, lfs_block_t block);
#ifndef LFS_BD_ERASE
int (*bd_erase)(void *ctx, lfs_block_t block);
#define LFS_CFG_BD_ERASE(cfg, block) \
(cfg)->bd_erase((cfg)->bd_ctx, block)
#else
#define LFS_CFG_BD_ERASE(cfg, block) \
lfs_bd_erase(block)
#endif
// Sync the state of the underlying block device. Negative error codes
// are propogated to the user.
int (*sync)(void *ctx);
#ifndef LFS_BD_SYNC
int (*bd_sync)(void *ctx);
#define LFS_CFG_BD_SYNC(cfg) \
(cfg)->bd_sync((cfg)->bd_ctx)
#else
#define LFS_CFG_BD_SYNC(cfg) \
lfs_bd_sync()
#endif
// Minimum size of a block read. All read operations will be a
// multiple of this value.
#ifndef LFS_READ_SIZE
lfs_size_t read_size;
#define LFS_CFG_READ_SIZE(cfg) (cfg)->read_size
#else
#define LFS_CFG_READ_SIZE(cfg) LFS_READ_SIZE
#endif
// Minimum size of a block program. All program operations will be a
// multiple of this value.
#ifndef LFS_PROG_SIZE
lfs_size_t prog_size;
#define LFS_CFG_PROG_SIZE(cfg) (cfg)->prog_size
#else
#define LFS_CFG_PROG_SIZE(cfg) LFS_PROG_SIZE
#endif
// Size of an erasable block. This does not impact ram consumption and
// may be larger than the physical erase size. However, non-inlined files
// take up at minimum one block. Must be a multiple of the read
// and program sizes.
#ifndef LFS_BLOCK_SIZE
lfs_size_t block_size;
#define LFS_CFG_BLOCK_SIZE(cfg) (cfg)->block_size
#else
#define LFS_CFG_BLOCK_SIZE(cfg) LFS_BLOCK_SIZE
#endif
// Number of erasable blocks on the device.
#ifndef LFS_BLOCK_COUNT
lfs_size_t block_count;
#define LFS_CFG_BLOCK_COUNT(cfg) (cfg)->block_count
#else
#define LFS_CFG_BLOCK_COUNT(cfg) LFS_BLOCK_COUNT
#endif
// Number of erase cycles before littlefs evicts metadata logs and moves
// the metadata to another block. Suggested values are in the
@@ -176,104 +270,139 @@ struct lfs_cfg {
// of less consistent wear distribution.
//
// Set to -1 to disable block-level wear-leveling.
#ifndef LFS_BLOCK_CYCLES
int32_t block_cycles;
#define LFS_CFG_BLOCK_CYCLES(cfg) (cfg)->block_cycles
#else
#define LFS_CFG_BLOCK_CYCLES(cfg) LFS_BLOCK_CYCLES
#endif
// Size of block caches. Each cache buffers a portion of a block in RAM.
// The littlefs needs a read cache, a program cache, and one additional
// cache per file. Larger caches can improve performance by storing more
// Size of internal buffers used to cache slices of blocks in RAM.
// The littlefs needs a read buffer, a program buffer, and one additional
// buffer per file. Larger buffers can improve performance by storing more
// data and reducing the number of disk accesses. Must be a multiple of
// the read and program sizes, and a factor of the block size.
lfs_size_t cache_size;
#ifndef LFS_BUFFER_SIZE
lfs_size_t buffer_size;
#define LFS_CFG_BUFFER_SIZE(cfg) (cfg)->buffer_size
#else
#define LFS_CFG_BUFFER_SIZE(cfg) LFS_BUFFER_SIZE
#endif
// 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.
#ifndef LFS_LOOKAHEAD_SIZE
lfs_size_t lookahead_size;
#define LFS_CFG_LOOKAHEAD_SIZE(cfg) (cfg)->lookahead_size
#else
#define LFS_CFG_LOOKAHEAD_SIZE(cfg) LFS_LOOKAHEAD_SIZE
#endif
// Optional statically allocated read buffer. Must be cache_size.
// By default lfs_malloc is used to allocate this buffer.
#ifndef LFS_READ_BUFFER
void *read_buffer;
#define LFS_CFG_READ_BUFFER(cfg) (cfg)->read_buffer
#else
#define LFS_CFG_READ_BUFFER(cfg) LFS_READ_BUFFER
#endif
// Optional statically allocated program buffer. Must be cache_size.
// By default lfs_malloc is used to allocate this buffer.
#ifndef LFS_PROG_BUFFER
void *prog_buffer;
#define LFS_CFG_PROG_BUFFER(cfg) (cfg)->prog_buffer
#else
#define LFS_CFG_PROG_BUFFER(cfg) LFS_PROG_BUFFER
#endif
// 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.
#ifndef LFS_LOOKAHEAD_BUFFER
void *lookahead_buffer;
#define LFS_CFG_LOOKAHEAD_BUFFER(cfg) (cfg)->lookahead_buffer
#else
#define LFS_CFG_LOOKAHEAD_BUFFER(cfg) LFS_LOOKAHEAD_BUFFER
#endif
// Optional upper limit on length of file names in bytes. No downside for
// larger names except the size of the info struct which is controlled by
// the LFS_NAME_MAX define. Defaults to LFS_NAME_MAX when zero. Stored in
// superblock and must be respected by other littlefs drivers.
lfs_size_t name_max;
#ifndef LFS_NAME_LIMIT
lfs_size_t name_limit;
#define LFS_CFG_NAME_LIMIT(cfg) (cfg)->name_limit
#else
#define LFS_CFG_NAME_LIMIT(cfg) LFS_NAME_LIMIT
#endif
// Optional upper limit on files in bytes. No downside for larger files
// but must be <= LFS_FILE_MAX. Defaults to LFS_FILE_MAX when zero. Stored
// in superblock and must be respected by other littlefs drivers.
lfs_size_t file_max;
#ifndef LFS_FILE_LIMIT
lfs_size_t file_limit;
#define LFS_CFG_FILE_LIMIT(cfg) (cfg)->file_limit
#else
#define LFS_CFG_FILE_LIMIT(cfg) LFS_FILE_LIMIT
#endif
// Optional upper limit on custom attributes in bytes. No downside for
// larger attributes size but must be <= LFS_ATTR_MAX. Defaults to
// LFS_ATTR_MAX when zero.
lfs_size_t attr_max;
#ifndef LFS_ATTR_LIMIT
lfs_size_t attr_limit;
#define LFS_CFG_ATTR_LIMIT(cfg) (cfg)->attr_limit
#else
#define LFS_CFG_ATTR_LIMIT(cfg) LFS_ATTR_LIMIT
#endif
#ifndef LFS_STATICCFG
};
#else
// Static configuration if LFS_STATICCFG is defined, there are defaults
// for some of these, but some are required. For full documentation, see
// the lfs_cfg struct above.
#endif
// Block device operations
int lfs_read(lfs_block_t block,
// Configurable callbacks are a bit special, when LFS_BD_* is defined,
// LFS_CFG_* instead expands into a call to an extern lfs_bd_*, which
// must be defined by the user. This preserves type-safety of the
// callbacks.
#ifdef LFS_BD_READ
extern int lfs_bd_read(lfs_block_t block,
lfs_off_t off, void *buffer, lfs_size_t size);
int lfs_prog(lfs_block_t block,
#endif
#ifdef LFS_BD_PROG
extern int lfs_bd_prog(lfs_block_t block,
lfs_off_t off, const void *buffer, lfs_size_t size);
int lfs_erase(lfs_block_t block);
int lfs_sync(void);
// Required configuration
#ifndef LFS_READ_SIZE
#error "LFS_STATICCFG requires LFS_READ_SIZE"
#endif
#ifndef LFS_PROG_SIZE
#error "LFS_STATICCFG requires LFS_PROG_SIZE"
#ifdef LFS_BD_ERASE
extern int lfs_bd_erase(lfs_block_t block);
#endif
#ifndef LFS_BLOCK_SIZE
#error "LFS_STATICCFG requires LFS_BLOCK_SIZE"
#endif
#ifndef LFS_BLOCK_COUNT
#error "LFS_STATICCFG requires LFS_BLOCK_COUNT"
#endif
#ifndef LFS_BLOCK_CYCLES
#error "LFS_STATICCFG requires LFS_BLOCK_CYCLES"
#endif
#ifndef LFS_CACHE_SIZE
#error "LFS_STATICCFG requires LFS_CACHE_SIZE"
#endif
#ifndef LFS_LOOKAHEAD_SIZE
#error "LFS_STATICCFG requires LFS_LOOKAHEAD_SIZE"
#ifdef LFS_BD_SYNC
extern int lfs_bd_sync(void);
#endif
// Optional configuration
#ifndef LFS_READ_BUFFER
#define LFS_READ_BUFFER NULL
#endif
#ifndef LFS_PROG_BUFFER
#define LFS_PROG_BUFFER NULL
#endif
#ifndef LFS_LOOKAHEAD_BUFFER
#define LFS_LOOKAHEAD_BUFFER NULL
#endif
// If every config option is provided at compile time, littlefs switches
// to "LFS_FILE_STATICCFG" mode. The dynamic lfs_file_cfg struct is not
// included in the lfs_file_t struct, and *cfg functions are no longer
// available.
#if defined(LFS_FILE_BUFFER) && \
defined(LFS_FILE_ATTRS) && \
defined(LFS_FILE_ATTR_COUNT)
#define LFS_STATICCFG
#endif
#if !defined(LFS_FILE_STATICCFG)
#ifndef LFS_FILE_STATICCFG
// Optional configuration provided during lfs_file_opencfg
struct lfs_file_cfg {
#endif
// Optional statically allocated file buffer. Must be cache_size.
// By default lfs_malloc is used to allocate this buffer.
#ifndef LFS_FILE_BUFFER
void *buffer;
#define LFS_FILE_CFG_BUFFER(cfg) (cfg)->buffer
#else
#define LFS_FILE_CFG_BUFFER(cfg) LFS_FILE_BUFFER
#endif
// Optional list of custom attributes related to the file. If the file
// is opened with read access, these attributes will be read from disk
@@ -286,23 +415,22 @@ struct lfs_file_cfg {
// than the buffer, it will be padded with zeros. If the stored attribute
// is larger, then it will be silently truncated. If the attribute is not
// found, it will be created implicitly.
#ifndef LFS_FILE_ATTRS
struct lfs_attr *attrs;
#define LFS_FILE_CFG_ATTRS(cfg) (cfg)->attrs
#else
#define LFS_FILE_CFG_ATTRS(cfg) LFS_FILE_ATTRS
#endif
// Number of custom attributes in the list
#ifndef LFS_FILE_ATTR_COUNT
lfs_size_t attr_count;
#define LFS_FILE_CFG_ATTR_COUNT(cfg) (cfg)->attr_count
#else
#define LFS_FILE_CFG_ATTR_COUNT(cfg) LFS_FILE_ATTR_COUNT
#endif
#ifndef LFS_FILE_STATICCFG
};
#else
// Static configuration if LFS_FILE_STATICCFG is defined. For full
// documentation, see the lfs_file_cfg struct above.
#ifndef LFS_FILE_BUFFER
#define LFS_FILE_BUFFER NULL
#endif
#ifndef LFS_FILE_ATTRS
#define LFS_FILE_ATTRS ((struct lfs_attr*)NULL)
#endif
#ifndef LFS_FILE_ATTR_COUNT
#define LFS_FILE_ATTR_COUNT 0
#endif
#endif
// File info structure
@@ -392,9 +520,9 @@ typedef struct lfs_superblock {
uint32_t version;
lfs_size_t block_size;
lfs_size_t block_count;
lfs_size_t name_max;
lfs_size_t file_max;
lfs_size_t attr_max;
lfs_size_t name_limit;
lfs_size_t file_limit;
lfs_size_t attr_limit;
} lfs_superblock_t;
typedef struct lfs_gstate {
@@ -431,9 +559,9 @@ typedef struct lfs {
#ifndef LFS_STATICCFG
const struct lfs_cfg *cfg;
#endif
lfs_size_t name_max;
lfs_size_t file_max;
lfs_size_t attr_max;
lfs_size_t name_limit;
lfs_size_t file_limit;
lfs_size_t attr_limit;
#ifdef LFS_MIGRATE
struct lfs1 *lfs1;

View File

@@ -78,12 +78,23 @@ DEFINES = {
'LFS_BLOCK_SIZE': 512,
'LFS_BLOCK_COUNT': 1024,
'LFS_BLOCK_CYCLES': -1,
'LFS_CACHE_SIZE': '(64 % LFS_PROG_SIZE == 0 ? 64 : LFS_PROG_SIZE)',
'LFS_BUFFER_SIZE': '(64 % LFS_PROG_SIZE == 0 ? 64 : LFS_PROG_SIZE)',
'LFS_LOOKAHEAD_SIZE': 16,
'LFS_ERASE_VALUE': 0xff,
'LFS_ERASE_CYCLES': 0,
'LFS_BADBLOCK_BEHAVIOR': 'LFS_TESTBD_BADBLOCK_PROGERROR',
}
CFG = {
'read_size': 'LFS_READ_SIZE',
'prog_size': 'LFS_PROG_SIZE',
'read_size': 'LFS_READ_SIZE',
'prog_size': 'LFS_PROG_SIZE',
'block_size': 'LFS_BLOCK_SIZE',
'block_count': 'LFS_BLOCK_COUNT',
'block_cycles': 'LFS_BLOCK_CYCLES',
'buffer_size': 'LFS_BUFFER_SIZE',
'lookahead_size': 'LFS_LOOKAHEAD_SIZE',
}
PROLOGUE = """
// prologue
__attribute__((unused)) lfs_t lfs;
@@ -97,21 +108,29 @@ PROLOGUE = """
__attribute__((unused)) int err;
__attribute__((unused)) const struct lfs_cfg cfg = {
.ctx = &bd,
.read = lfs_testbd_readctx,
.prog = lfs_testbd_progctx,
.erase = lfs_testbd_erasectx,
.sync = lfs_testbd_syncctx,
.read_size = LFS_READ_SIZE,
.prog_size = LFS_PROG_SIZE,
.block_size = LFS_BLOCK_SIZE,
.block_count = LFS_BLOCK_COUNT,
.block_cycles = LFS_BLOCK_CYCLES,
.cache_size = LFS_CACHE_SIZE,
.lookahead_size = LFS_LOOKAHEAD_SIZE,
.bd_ctx = &bd,
.bd_read = lfs_testbd_readctx,
.bd_prog = lfs_testbd_progctx,
.bd_erase = lfs_testbd_erasectx,
.bd_sync = lfs_testbd_syncctx,
%(cfg)s
};
__attribute__((unused)) const struct lfs_testbd_cfg bdcfg = {
.rambd_cfg = &(const struct lfs_rambd_cfg){
.read_size = LFS_READ_SIZE,
.prog_size = LFS_PROG_SIZE,
.erase_size = LFS_BLOCK_SIZE,
.erase_count = LFS_BLOCK_COUNT,
.erase_value = LFS_ERASE_VALUE,
},
.filebd_cfg = &(const struct lfs_filebd_cfg){
.read_size = LFS_READ_SIZE,
.prog_size = LFS_PROG_SIZE,
.erase_size = LFS_BLOCK_SIZE,
.erase_count = LFS_BLOCK_COUNT,
.erase_value = LFS_ERASE_VALUE,
},
.read_size = LFS_READ_SIZE,
.prog_size = LFS_PROG_SIZE,
.erase_size = LFS_BLOCK_SIZE,
@@ -188,7 +207,11 @@ class TestCase:
for k in sorted(self.perms[0].defines)
if k not in self.defines)))
f.write(PROLOGUE)
f.write(PROLOGUE % dict(
cfg='\n'.join(
8*' '+'.%s = %s,\n' % (k, d)
for k, d in sorted(CFG.items())
if d not in self.suite.defines)))
f.write('\n')
f.write(4*' '+'// test case %d\n' % self.caseno)
f.write(4*' '+'#line %d "%s"\n' % (self.code_lineno, self.suite.path))
@@ -197,6 +220,7 @@ class TestCase:
f.write(self.code)
# epilogue
f.write(4*' '+'#line %d "%s"\n' % (f.lineno+1, f.path))
f.write(EPILOGUE)
f.write('}\n')
@@ -500,18 +524,32 @@ class TestSuite:
return self.perms
def build(self, **args):
# intercept writes to keep track of linenos
def lineno_open(path, flags):
f = open(path, flags)
f.path = path
f.lineno = 1
write = f.write
def lineno_write(s):
f.lineno += s.count('\n')
write(s)
f.write = lineno_write
return f
# build test files
tf = open(self.path + '.test.c.t', 'w')
tf = lineno_open(self.path + '.test.tc', 'w')
tf.write(BEFORE_TESTS)
if self.code is not None:
tf.write('#line %d "%s"\n' % (self.code_lineno, self.path))
tf.write(self.code)
tf.write('#line %d "%s"\n' % (tf.lineno+1, tf.path))
tfs = {None: tf}
for case in self.cases:
if case.in_ not in tfs:
tfs[case.in_] = open(self.path+'.'+
case.in_.replace('/', '.')+'.t', 'w')
tfs[case.in_] = lineno_open(self.path+'.'+
case.in_.replace('/', '.')[:-2]+'.tc', 'w')
tfs[case.in_].write('#line 1 "%s"\n' % case.in_)
with open(case.in_) as f:
for line in f:
@@ -562,12 +600,12 @@ class TestSuite:
mk.write('%s: %s | %s\n' % (
self.path+'.test.c',
self.path,
self.path+'.test.c.t'))
self.path+'.test.tc'))
else:
mk.write('%s: %s %s | %s\n' % (
self.path+'.'+path.replace('/', '.'),
self.path, path,
self.path+'.'+path.replace('/', '.')+'.t'))
self.path+'.'+path.replace('/', '.')[:-2]+'.tc'))
mk.write('\t./scripts/explode_asserts.py $| -o $@\n')
self.makefile = self.path + '.mk'

View File

@@ -492,17 +492,17 @@ code = '''
// create one block hole for half a directory
lfs_file_open(&lfs, &file, "bump", LFS_O_WRONLY | LFS_O_CREAT) => 0;
for (lfs_size_t i = 0; i < cfg.block_size; i += 2) {
for (lfs_size_t i = 0; i < LFS_BLOCK_SIZE; i += 2) {
memcpy(&buffer[i], "hi", 2);
}
lfs_file_write(&lfs, &file, buffer, cfg.block_size) => cfg.block_size;
lfs_file_write(&lfs, &file, buffer, LFS_BLOCK_SIZE) => LFS_BLOCK_SIZE;
lfs_file_close(&lfs, &file) => 0;
lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT);
size = strlen("blahblahblahblah");
memcpy(buffer, "blahblahblahblah", size);
for (lfs_size_t i = 0;
i < (cfg.block_count-4)*(cfg.block_size-8);
i < (LFS_BLOCK_COUNT-4)*(LFS_BLOCK_SIZE-8);
i += size) {
lfs_file_write(&lfs, &file, buffer, size) => size;
}
@@ -518,10 +518,10 @@ code = '''
lfs_mkdir(&lfs, "splitdir") => 0;
lfs_file_open(&lfs, &file, "splitdir/bump",
LFS_O_WRONLY | LFS_O_CREAT) => 0;
for (lfs_size_t i = 0; i < cfg.block_size; i += 2) {
for (lfs_size_t i = 0; i < LFS_BLOCK_SIZE; i += 2) {
memcpy(&buffer[i], "hi", 2);
}
lfs_file_write(&lfs, &file, buffer, 2*cfg.block_size) => LFS_ERR_NOSPC;
lfs_file_write(&lfs, &file, buffer, 2*LFS_BLOCK_SIZE) => LFS_ERR_NOSPC;
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
@@ -541,7 +541,7 @@ code = '''
size = strlen("blahblahblahblah");
memcpy(buffer, "blahblahblahblah", size);
for (lfs_size_t i = 0;
i < ((cfg.block_count-2)/2)*(cfg.block_size-8);
i < ((LFS_BLOCK_COUNT-2)/2)*(LFS_BLOCK_SIZE-8);
i += size) {
lfs_file_write(&lfs, &file, buffer, size) => size;
}
@@ -552,7 +552,7 @@ code = '''
size = strlen("blahblahblahblah");
memcpy(buffer, "blahblahblahblah", size);
for (lfs_size_t i = 0;
i < ((cfg.block_count-2+1)/2)*(cfg.block_size-8);
i < ((LFS_BLOCK_COUNT-2+1)/2)*(LFS_BLOCK_SIZE-8);
i += size) {
lfs_file_write(&lfs, &file, buffer, size) => size;
}
@@ -569,7 +569,7 @@ code = '''
size = strlen("blahblahblahblah");
memcpy(buffer, "blahblahblahblah", size);
for (lfs_size_t i = 0;
i < ((cfg.block_count-2)/2)*(cfg.block_size-8);
i < ((LFS_BLOCK_COUNT-2)/2)*(LFS_BLOCK_SIZE-8);
i += size) {
lfs_file_write(&lfs, &file, buffer, size) => size;
}
@@ -583,7 +583,7 @@ code = '''
size = strlen("blahblahblahblah");
memcpy(buffer, "blahblahblahblah", size);
for (lfs_size_t i = 0;
i < ((cfg.block_count-2+1)/2)*(cfg.block_size-8);
i < ((LFS_BLOCK_COUNT-2+1)/2)*(LFS_BLOCK_SIZE-8);
i += size) {
lfs_file_write(&lfs, &file, buffer, size) => size;
}
@@ -606,7 +606,7 @@ code = '''
size = strlen("blahblahblahblah");
memcpy(buffer, "blahblahblahblah", size);
for (lfs_size_t i = 0;
i < ((cfg.block_count-2)/2)*(cfg.block_size-8);
i < ((LFS_BLOCK_COUNT-2)/2)*(LFS_BLOCK_SIZE-8);
i += size) {
lfs_file_write(&lfs, &file, buffer, size) => size;
}
@@ -617,7 +617,7 @@ code = '''
size = strlen("blahblahblahblah");
memcpy(buffer, "blahblahblahblah", size);
for (lfs_size_t i = 0;
i < ((cfg.block_count-2+1)/2)*(cfg.block_size-8);
i < ((LFS_BLOCK_COUNT-2+1)/2)*(LFS_BLOCK_SIZE-8);
i += size) {
lfs_file_write(&lfs, &file, buffer, size) => size;
}
@@ -634,7 +634,7 @@ code = '''
size = strlen("blahblahblahblah");
memcpy(buffer, "blahblahblahblah", size);
for (lfs_size_t i = 0;
i < ((cfg.block_count-2)/2 - 1)*(cfg.block_size-8);
i < ((LFS_BLOCK_COUNT-2)/2 - 1)*(LFS_BLOCK_SIZE-8);
i += size) {
lfs_file_write(&lfs, &file, buffer, size) => size;
}

View File

@@ -59,7 +59,7 @@ code = '''
[[case]] # reentrant testing for orphans, basically just spam mkdir/remove
reentrant = true
# TODO fix this case, caused by non-DAG trees
if = '!(DEPTH == 3 && LFS_CACHE_SIZE != 64)'
if = '!(DEPTH == 3 && LFS_BUFFER_SIZE != 64)'
define = [
{FILES=6, DEPTH=1, CYCLES=20},
{FILES=26, DEPTH=1, CYCLES=20},

View File

@@ -148,7 +148,7 @@ code = '''
# almost every tree operation needs a relocation
reentrant = true
# TODO fix this case, caused by non-DAG trees
if = '!(DEPTH == 3 && LFS_CACHE_SIZE != 64)'
if = '!(DEPTH == 3 && LFS_BUFFER_SIZE != 64)'
define = [
{FILES=6, DEPTH=1, CYCLES=20, LFS_BLOCK_CYCLES=1},
{FILES=26, DEPTH=1, CYCLES=20, LFS_BLOCK_CYCLES=1},
@@ -210,7 +210,7 @@ code = '''
[[case]] # reentrant testing for relocations, but now with random renames!
reentrant = true
# TODO fix this case, caused by non-DAG trees
if = '!(DEPTH == 3 && LFS_CACHE_SIZE != 64)'
if = '!(DEPTH == 3 && LFS_BUFFER_SIZE != 64)'
define = [
{FILES=6, DEPTH=1, CYCLES=20, LFS_BLOCK_CYCLES=1},
{FILES=26, DEPTH=1, CYCLES=20, LFS_BLOCK_CYCLES=1},

View File

@@ -100,7 +100,7 @@ code = '''
lfs_file_open(&lfs, &file, "sequence",
LFS_O_RDWR | LFS_O_CREAT | LFS_O_TRUNC) => 0;
size = lfs_min(lfs.cfg->cache_size, sizeof(buffer)/2);
size = lfs_min(LFS_BUFFER_SIZE, sizeof(buffer)/2);
lfs_size_t qsize = size / 4;
uint8_t *wb = buffer;
uint8_t *rb = buffer + size;