mirror of
https://github.com/eledio-devices/thirdparty-littlefs.git
synced 2025-11-01 08:48:31 +01:00
Compare commits
6 Commits
config-imp
...
config-imp
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5f885f0af1 | ||
|
|
fe42d102a5 | ||
|
|
499083765c | ||
|
|
aa46bb68ca | ||
|
|
190eb833a2 | ||
|
|
30ed816feb |
14
.travis.yml
14
.travis.yml
@@ -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:
|
||||
|
||||
2
Makefile
2
Makefile
@@ -32,7 +32,7 @@ override TFLAGS += -v
|
||||
endif
|
||||
|
||||
|
||||
all: $(TARGET)
|
||||
all build: $(TARGET)
|
||||
|
||||
asm: $(ASM)
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
|
||||
271
lfs.h
271
lfs.h
@@ -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
|
||||
@@ -384,7 +512,7 @@ typedef struct lfs_file {
|
||||
lfs_cache_t cache;
|
||||
|
||||
#ifndef LFS_FILE_STATICCFG
|
||||
struct lfs_file_cfg cfg;
|
||||
const struct lfs_file_cfg *cfg;
|
||||
#endif
|
||||
} lfs_file_t;
|
||||
|
||||
@@ -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 {
|
||||
@@ -429,8 +557,11 @@ typedef struct lfs {
|
||||
} free;
|
||||
|
||||
#ifndef LFS_STATICCFG
|
||||
struct lfs_cfg cfg;
|
||||
const struct lfs_cfg *cfg;
|
||||
#endif
|
||||
lfs_size_t name_limit;
|
||||
lfs_size_t file_limit;
|
||||
lfs_size_t attr_limit;
|
||||
|
||||
#ifdef LFS_MIGRATE
|
||||
struct lfs1 *lfs1;
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -12,7 +12,8 @@ code = '''
|
||||
lfs_formatcfg(&lfs, &cfg) => 0;
|
||||
|
||||
// change tail-pointer to invalid pointers
|
||||
lfs_initcommon(&lfs, &cfg) => 0;
|
||||
lfs.cfg = &cfg;
|
||||
lfs_initcommon(&lfs) => 0;
|
||||
lfs_mdir_t mdir;
|
||||
lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
|
||||
lfs_dir_commit(&lfs, &mdir, LFS_MKATTRS(
|
||||
@@ -38,7 +39,8 @@ code = '''
|
||||
lfs_unmount(&lfs) => 0;
|
||||
|
||||
// change the dir pointer to be invalid
|
||||
lfs_initcommon(&lfs, &cfg) => 0;
|
||||
lfs.cfg = &cfg;
|
||||
lfs_initcommon(&lfs) => 0;
|
||||
lfs_mdir_t mdir;
|
||||
lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
|
||||
// make sure id 1 == our directory
|
||||
@@ -86,7 +88,8 @@ code = '''
|
||||
lfs_unmount(&lfs) => 0;
|
||||
|
||||
// change the file pointer to be invalid
|
||||
lfs_initcommon(&lfs, &cfg) => 0;
|
||||
lfs.cfg = &cfg;
|
||||
lfs_initcommon(&lfs) => 0;
|
||||
lfs_mdir_t mdir;
|
||||
lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
|
||||
// make sure id 1 == our file
|
||||
@@ -137,7 +140,8 @@ code = '''
|
||||
lfs_file_close(&lfs, &file) => 0;
|
||||
lfs_unmount(&lfs) => 0;
|
||||
// change pointer in CTZ skip-list to be invalid
|
||||
lfs_initcommon(&lfs, &cfg) => 0;
|
||||
lfs.cfg = &cfg;
|
||||
lfs_initcommon(&lfs) => 0;
|
||||
lfs_mdir_t mdir;
|
||||
lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
|
||||
// make sure id 1 == our file and get our CTZ structure
|
||||
@@ -190,7 +194,8 @@ code = '''
|
||||
lfs_formatcfg(&lfs, &cfg) => 0;
|
||||
|
||||
// create an invalid gstate
|
||||
lfs_initcommon(&lfs, &cfg) => 0;
|
||||
lfs.cfg = &cfg;
|
||||
lfs_initcommon(&lfs) => 0;
|
||||
lfs_mdir_t mdir;
|
||||
lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
|
||||
lfs_fs_prepmove(&lfs, 1, (lfs_block_t [2]){
|
||||
@@ -216,7 +221,8 @@ code = '''
|
||||
lfs_formatcfg(&lfs, &cfg) => 0;
|
||||
|
||||
// change tail-pointer to point to ourself
|
||||
lfs_initcommon(&lfs, &cfg) => 0;
|
||||
lfs.cfg = &cfg;
|
||||
lfs_initcommon(&lfs) => 0;
|
||||
lfs_mdir_t mdir;
|
||||
lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
|
||||
lfs_dir_commit(&lfs, &mdir, LFS_MKATTRS(
|
||||
@@ -238,7 +244,8 @@ code = '''
|
||||
lfs_unmount(&lfs) => 0;
|
||||
|
||||
// find child
|
||||
lfs_initcommon(&lfs, &cfg) => 0;
|
||||
lfs.cfg = &cfg;
|
||||
lfs_initcommon(&lfs) => 0;
|
||||
lfs_mdir_t mdir;
|
||||
lfs_block_t pair[2];
|
||||
lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
|
||||
@@ -268,7 +275,8 @@ code = '''
|
||||
lfs_unmount(&lfs) => 0;
|
||||
|
||||
// find child
|
||||
lfs_initcommon(&lfs, &cfg) => 0;
|
||||
lfs.cfg = &cfg;
|
||||
lfs_initcommon(&lfs) => 0;
|
||||
lfs_mdir_t mdir;
|
||||
lfs_block_t pair[2];
|
||||
lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
|
||||
|
||||
@@ -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},
|
||||
|
||||
@@ -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},
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user