Adopted erase_size/erase_count config in test block-devices/runners
In separating the configuration of littlefs from the physical geometry of the underlying device, we can no longer rely solely on lfs_config to contain all of the information necessary for the simulated block devices we use for testing. This adds a new lfs_*bd_config struct for each of the block devices, and new erase_size/erase_count fields. The erase_* name was chosen since these reflect the (simulated) physical erase size and count of erase-sized blocks, unlike the block_* variants which represent logical block sizes used for littlefs's bookkeeping. It may be worth adopting erase_size/erase_count in littlefs's config at some point in the future, but at the moment doesn't seem necessary. Changing the lfs_bd_config structs to be required is probably a good idea anyways, as it moves us more towards separating the bds from littlefs. Though we can't quite get rid of the lfs_config parameter because of the block-device API in lfs_config. Eventually it would be nice to get rid of it, but that would require API breakage.
This commit is contained in:
+44
-61
@@ -48,6 +48,7 @@ static void lfs_emubd_decblock(lfs_emubd_block_t *block) {
|
||||
static lfs_emubd_block_t *lfs_emubd_mutblock(
|
||||
const struct lfs_config *cfg,
|
||||
lfs_emubd_block_t **block) {
|
||||
lfs_emubd_t *bd = cfg->context;
|
||||
lfs_emubd_block_t *block_ = *block;
|
||||
if (block_ && block_->rc == 1) {
|
||||
// rc == 1? can modify
|
||||
@@ -56,13 +57,13 @@ static lfs_emubd_block_t *lfs_emubd_mutblock(
|
||||
} else if (block_) {
|
||||
// rc > 1? need to create a copy
|
||||
lfs_emubd_block_t *nblock = malloc(
|
||||
sizeof(lfs_emubd_block_t) + cfg->block_size);
|
||||
sizeof(lfs_emubd_block_t) + bd->cfg->erase_size);
|
||||
if (!nblock) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(nblock, block_,
|
||||
sizeof(lfs_emubd_block_t) + cfg->block_size);
|
||||
sizeof(lfs_emubd_block_t) + bd->cfg->erase_size);
|
||||
nblock->rc = 1;
|
||||
|
||||
lfs_emubd_decblock(block_);
|
||||
@@ -72,7 +73,7 @@ static lfs_emubd_block_t *lfs_emubd_mutblock(
|
||||
} else {
|
||||
// no block? need to allocate
|
||||
lfs_emubd_block_t *nblock = malloc(
|
||||
sizeof(lfs_emubd_block_t) + cfg->block_size);
|
||||
sizeof(lfs_emubd_block_t) + bd->cfg->erase_size);
|
||||
if (!nblock) {
|
||||
return NULL;
|
||||
}
|
||||
@@ -81,10 +82,9 @@ static lfs_emubd_block_t *lfs_emubd_mutblock(
|
||||
nblock->wear = 0;
|
||||
|
||||
// zero for consistency
|
||||
lfs_emubd_t *bd = cfg->context;
|
||||
memset(nblock->data,
|
||||
(bd->cfg->erase_value != -1) ? bd->cfg->erase_value : 0,
|
||||
cfg->block_size);
|
||||
bd->cfg->erase_size);
|
||||
|
||||
*block = nblock;
|
||||
return nblock;
|
||||
@@ -94,22 +94,22 @@ static lfs_emubd_block_t *lfs_emubd_mutblock(
|
||||
|
||||
// emubd create/destroy
|
||||
|
||||
int lfs_emubd_createcfg(const struct lfs_config *cfg, const char *path,
|
||||
int lfs_emubd_create(const struct lfs_config *cfg,
|
||||
const struct lfs_emubd_config *bdcfg) {
|
||||
LFS_EMUBD_TRACE("lfs_emubd_createcfg(%p {.context=%p, "
|
||||
".read=%p, .prog=%p, .erase=%p, .sync=%p, "
|
||||
".read_size=%"PRIu32", .prog_size=%"PRIu32", "
|
||||
".block_size=%"PRIu32", .block_count=%"PRIu32"}, "
|
||||
"\"%s\", "
|
||||
"%p {.erase_value=%"PRId32", .erase_cycles=%"PRIu32", "
|
||||
LFS_EMUBD_TRACE("lfs_emubd_create(%p {.context=%p, "
|
||||
".read=%p, .prog=%p, .erase=%p, .sync=%p}, "
|
||||
"%p {.read_size=%"PRIu32", .prog_size=%"PRIu32", "
|
||||
".erase_size=%"PRIu32", .erase_count=%"PRIu32", "
|
||||
".erase_value=%"PRId32", .erase_cycles=%"PRIu32", "
|
||||
".badblock_behavior=%"PRIu8", .power_cycles=%"PRIu32", "
|
||||
".powerloss_behavior=%"PRIu8", .powerloss_cb=%p, "
|
||||
".powerloss_data=%p, .track_branches=%d})",
|
||||
(void*)cfg, cfg->context,
|
||||
(void*)(uintptr_t)cfg->read, (void*)(uintptr_t)cfg->prog,
|
||||
(void*)(uintptr_t)cfg->erase, (void*)(uintptr_t)cfg->sync,
|
||||
cfg->read_size, cfg->prog_size, cfg->block_size, cfg->block_count,
|
||||
path, (void*)bdcfg, bdcfg->erase_value, bdcfg->erase_cycles,
|
||||
(void*)bdcfg,
|
||||
bdcfg->read_size, bdcfg->prog_size, bdcfg->erase_size,
|
||||
bdcfg->erase_count, bdcfg->erase_value, bdcfg->erase_cycles,
|
||||
bdcfg->badblock_behavior, bdcfg->power_cycles,
|
||||
bdcfg->powerloss_behavior, (void*)(uintptr_t)bdcfg->powerloss_cb,
|
||||
bdcfg->powerloss_data, bdcfg->track_branches);
|
||||
@@ -117,12 +117,12 @@ int lfs_emubd_createcfg(const struct lfs_config *cfg, const char *path,
|
||||
bd->cfg = bdcfg;
|
||||
|
||||
// allocate our block array, all blocks start as uninitialized
|
||||
bd->blocks = malloc(cfg->block_count * sizeof(lfs_emubd_block_t*));
|
||||
bd->blocks = malloc(bd->cfg->erase_count * sizeof(lfs_emubd_block_t*));
|
||||
if (!bd->blocks) {
|
||||
LFS_EMUBD_TRACE("lfs_emubd_createcfg -> %d", LFS_ERR_NOMEM);
|
||||
LFS_EMUBD_TRACE("lfs_emubd_create -> %d", LFS_ERR_NOMEM);
|
||||
return LFS_ERR_NOMEM;
|
||||
}
|
||||
memset(bd->blocks, 0, cfg->block_count * sizeof(lfs_emubd_block_t*));
|
||||
memset(bd->blocks, 0, bd->cfg->erase_count * sizeof(lfs_emubd_block_t*));
|
||||
|
||||
// setup testing things
|
||||
bd->readed = 0;
|
||||
@@ -134,7 +134,7 @@ int lfs_emubd_createcfg(const struct lfs_config *cfg, const char *path,
|
||||
if (bd->cfg->disk_path) {
|
||||
bd->disk = malloc(sizeof(lfs_emubd_disk_t));
|
||||
if (!bd->disk) {
|
||||
LFS_EMUBD_TRACE("lfs_emubd_createcfg -> %d", LFS_ERR_NOMEM);
|
||||
LFS_EMUBD_TRACE("lfs_emubd_create -> %d", LFS_ERR_NOMEM);
|
||||
return LFS_ERR_NOMEM;
|
||||
}
|
||||
bd->disk->rc = 1;
|
||||
@@ -156,21 +156,21 @@ int lfs_emubd_createcfg(const struct lfs_config *cfg, const char *path,
|
||||
// if we're emulating erase values, we can keep a block around in
|
||||
// memory of just the erase state to speed up emulated erases
|
||||
if (bd->cfg->erase_value != -1) {
|
||||
bd->disk->scratch = malloc(cfg->block_size);
|
||||
bd->disk->scratch = malloc(bd->cfg->erase_size);
|
||||
if (!bd->disk->scratch) {
|
||||
LFS_EMUBD_TRACE("lfs_emubd_createcfg -> %d", LFS_ERR_NOMEM);
|
||||
LFS_EMUBD_TRACE("lfs_emubd_create -> %d", LFS_ERR_NOMEM);
|
||||
return LFS_ERR_NOMEM;
|
||||
}
|
||||
memset(bd->disk->scratch,
|
||||
bd->cfg->erase_value,
|
||||
cfg->block_size);
|
||||
bd->cfg->erase_size);
|
||||
|
||||
// go ahead and erase all of the disk, otherwise the file will not
|
||||
// match our internal representation
|
||||
for (size_t i = 0; i < cfg->block_count; i++) {
|
||||
for (size_t i = 0; i < bd->cfg->erase_count; i++) {
|
||||
ssize_t res = write(bd->disk->fd,
|
||||
bd->disk->scratch,
|
||||
cfg->block_size);
|
||||
bd->cfg->erase_size);
|
||||
if (res < 0) {
|
||||
int err = -errno;
|
||||
LFS_EMUBD_TRACE("lfs_emubd_create -> %d", err);
|
||||
@@ -180,33 +180,16 @@ int lfs_emubd_createcfg(const struct lfs_config *cfg, const char *path,
|
||||
}
|
||||
}
|
||||
|
||||
LFS_EMUBD_TRACE("lfs_emubd_createcfg -> %d", 0);
|
||||
LFS_EMUBD_TRACE("lfs_emubd_create -> %d", 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lfs_emubd_create(const struct lfs_config *cfg, const char *path) {
|
||||
LFS_EMUBD_TRACE("lfs_emubd_create(%p {.context=%p, "
|
||||
".read=%p, .prog=%p, .erase=%p, .sync=%p, "
|
||||
".read_size=%"PRIu32", .prog_size=%"PRIu32", "
|
||||
".block_size=%"PRIu32", .block_count=%"PRIu32"}, "
|
||||
"\"%s\")",
|
||||
(void*)cfg, cfg->context,
|
||||
(void*)(uintptr_t)cfg->read, (void*)(uintptr_t)cfg->prog,
|
||||
(void*)(uintptr_t)cfg->erase, (void*)(uintptr_t)cfg->sync,
|
||||
cfg->read_size, cfg->prog_size, cfg->block_size, cfg->block_count,
|
||||
path);
|
||||
static const struct lfs_emubd_config defaults = {.erase_value=-1};
|
||||
int err = lfs_emubd_createcfg(cfg, path, &defaults);
|
||||
LFS_EMUBD_TRACE("lfs_emubd_create -> %d", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
int lfs_emubd_destroy(const struct lfs_config *cfg) {
|
||||
LFS_EMUBD_TRACE("lfs_emubd_destroy(%p)", (void*)cfg);
|
||||
lfs_emubd_t *bd = cfg->context;
|
||||
|
||||
// decrement reference counts
|
||||
for (lfs_block_t i = 0; i < cfg->block_count; i++) {
|
||||
for (lfs_block_t i = 0; i < bd->cfg->erase_count; i++) {
|
||||
lfs_emubd_decblock(bd->blocks[i]);
|
||||
}
|
||||
free(bd->blocks);
|
||||
@@ -237,10 +220,10 @@ int lfs_emubd_read(const struct lfs_config *cfg, lfs_block_t block,
|
||||
lfs_emubd_t *bd = cfg->context;
|
||||
|
||||
// check if read is valid
|
||||
LFS_ASSERT(!cfg->block_count || block < cfg->block_count);
|
||||
LFS_ASSERT(off % cfg->read_size == 0);
|
||||
LFS_ASSERT(size % cfg->read_size == 0);
|
||||
LFS_ASSERT(off+size <= cfg->block_size);
|
||||
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(off+size <= bd->cfg->erase_size);
|
||||
|
||||
// get the block
|
||||
const lfs_emubd_block_t *b = bd->blocks[block];
|
||||
@@ -287,10 +270,10 @@ int lfs_emubd_prog(const struct lfs_config *cfg, lfs_block_t block,
|
||||
lfs_emubd_t *bd = cfg->context;
|
||||
|
||||
// check if write is valid
|
||||
LFS_ASSERT(!cfg->block_count || block < cfg->block_count);
|
||||
LFS_ASSERT(off % cfg->prog_size == 0);
|
||||
LFS_ASSERT(size % cfg->prog_size == 0);
|
||||
LFS_ASSERT(off+size <= cfg->block_size);
|
||||
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(off+size <= bd->cfg->erase_size);
|
||||
|
||||
// get the block
|
||||
lfs_emubd_block_t *b = lfs_emubd_mutblock(cfg, &bd->blocks[block]);
|
||||
@@ -327,7 +310,7 @@ int lfs_emubd_prog(const struct lfs_config *cfg, lfs_block_t block,
|
||||
// mirror to disk file?
|
||||
if (bd->disk) {
|
||||
off_t res1 = lseek(bd->disk->fd,
|
||||
(off_t)block*cfg->block_size + (off_t)off,
|
||||
(off_t)block*bd->cfg->erase_size + (off_t)off,
|
||||
SEEK_SET);
|
||||
if (res1 < 0) {
|
||||
int err = -errno;
|
||||
@@ -372,11 +355,11 @@ int lfs_emubd_prog(const struct lfs_config *cfg, lfs_block_t block,
|
||||
|
||||
int lfs_emubd_erase(const struct lfs_config *cfg, lfs_block_t block) {
|
||||
LFS_EMUBD_TRACE("lfs_emubd_erase(%p, 0x%"PRIx32" (%"PRIu32"))",
|
||||
(void*)cfg, block, cfg->block_size);
|
||||
(void*)cfg, block, ((lfs_emubd_t*)cfg->context)->cfg->erase_size);
|
||||
lfs_emubd_t *bd = cfg->context;
|
||||
|
||||
// check if erase is valid
|
||||
LFS_ASSERT(!cfg->block_count || block < cfg->block_count);
|
||||
LFS_ASSERT(block < bd->cfg->erase_count);
|
||||
|
||||
// get the block
|
||||
lfs_emubd_block_t *b = lfs_emubd_mutblock(cfg, &bd->blocks[block]);
|
||||
@@ -405,12 +388,12 @@ int lfs_emubd_erase(const struct lfs_config *cfg, lfs_block_t block) {
|
||||
|
||||
// emulate an erase value?
|
||||
if (bd->cfg->erase_value != -1) {
|
||||
memset(b->data, bd->cfg->erase_value, cfg->block_size);
|
||||
memset(b->data, bd->cfg->erase_value, bd->cfg->erase_size);
|
||||
|
||||
// mirror to disk file?
|
||||
if (bd->disk) {
|
||||
off_t res1 = lseek(bd->disk->fd,
|
||||
(off_t)block*cfg->block_size,
|
||||
(off_t)block*bd->cfg->erase_size,
|
||||
SEEK_SET);
|
||||
if (res1 < 0) {
|
||||
int err = -errno;
|
||||
@@ -420,7 +403,7 @@ int lfs_emubd_erase(const struct lfs_config *cfg, lfs_block_t block) {
|
||||
|
||||
ssize_t res2 = write(bd->disk->fd,
|
||||
bd->disk->scratch,
|
||||
cfg->block_size);
|
||||
bd->cfg->erase_size);
|
||||
if (res2 < 0) {
|
||||
int err = -errno;
|
||||
LFS_EMUBD_TRACE("lfs_emubd_erase -> %d", err);
|
||||
@@ -430,7 +413,7 @@ int lfs_emubd_erase(const struct lfs_config *cfg, lfs_block_t block) {
|
||||
}
|
||||
|
||||
// track erases
|
||||
bd->erased += cfg->block_size;
|
||||
bd->erased += bd->cfg->erase_size;
|
||||
if (bd->cfg->erase_sleep) {
|
||||
int err = nanosleep(&(struct timespec){
|
||||
.tv_sec=bd->cfg->erase_sleep/1000000000,
|
||||
@@ -573,7 +556,7 @@ lfs_emubd_swear_t lfs_emubd_wear(const struct lfs_config *cfg,
|
||||
lfs_emubd_t *bd = cfg->context;
|
||||
|
||||
// check if block is valid
|
||||
LFS_ASSERT(block < cfg->block_count);
|
||||
LFS_ASSERT(block < bd->cfg->erase_count);
|
||||
|
||||
// get the wear
|
||||
lfs_emubd_wear_t wear;
|
||||
@@ -595,7 +578,7 @@ int lfs_emubd_setwear(const struct lfs_config *cfg,
|
||||
lfs_emubd_t *bd = cfg->context;
|
||||
|
||||
// check if block is valid
|
||||
LFS_ASSERT(block < cfg->block_count);
|
||||
LFS_ASSERT(block < bd->cfg->erase_count);
|
||||
|
||||
// set the wear
|
||||
lfs_emubd_block_t *b = lfs_emubd_mutblock(cfg, &bd->blocks[block]);
|
||||
@@ -635,13 +618,13 @@ int lfs_emubd_copy(const struct lfs_config *cfg, lfs_emubd_t *copy) {
|
||||
lfs_emubd_t *bd = cfg->context;
|
||||
|
||||
// lazily copy over our block array
|
||||
copy->blocks = malloc(cfg->block_count * sizeof(lfs_emubd_block_t*));
|
||||
copy->blocks = malloc(bd->cfg->erase_count * sizeof(lfs_emubd_block_t*));
|
||||
if (!copy->blocks) {
|
||||
LFS_EMUBD_TRACE("lfs_emubd_copy -> %d", LFS_ERR_NOMEM);
|
||||
return LFS_ERR_NOMEM;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < cfg->block_count; i++) {
|
||||
for (size_t i = 0; i < bd->cfg->erase_count; i++) {
|
||||
copy->blocks[i] = lfs_emubd_incblock(bd->blocks[i]);
|
||||
}
|
||||
|
||||
|
||||
+13
-5
@@ -67,6 +67,18 @@ typedef int64_t lfs_emubd_ssleep_t;
|
||||
|
||||
// emubd config, this is required for testing
|
||||
struct lfs_emubd_config {
|
||||
// Minimum size of a read operation in bytes.
|
||||
lfs_size_t read_size;
|
||||
|
||||
// Minimum size of a program operation in bytes.
|
||||
lfs_size_t prog_size;
|
||||
|
||||
// Size of an erase operation in bytes.
|
||||
lfs_size_t erase_size;
|
||||
|
||||
// Number of erase blocks on the device.
|
||||
lfs_size_t erase_count;
|
||||
|
||||
// 8-bit erase value to use for simulating erases. -1 does not simulate
|
||||
// erases, which can speed up testing by avoiding the extra block-device
|
||||
// operations to store the erase value.
|
||||
@@ -149,11 +161,7 @@ typedef struct lfs_emubd {
|
||||
/// Block device API ///
|
||||
|
||||
// Create an emulating block device using the geometry in lfs_config
|
||||
//
|
||||
// Note that filebd is used if a path is provided, if path is NULL
|
||||
// emubd will use rambd which can be much faster.
|
||||
int lfs_emubd_create(const struct lfs_config *cfg, const char *path);
|
||||
int lfs_emubd_createcfg(const struct lfs_config *cfg, const char *path,
|
||||
int lfs_emubd_create(const struct lfs_config *cfg,
|
||||
const struct lfs_emubd_config *bdcfg);
|
||||
|
||||
// Clean up memory associated with block device
|
||||
|
||||
+24
-19
@@ -15,18 +15,22 @@
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
int lfs_filebd_create(const struct lfs_config *cfg, const char *path) {
|
||||
int lfs_filebd_create(const struct lfs_config *cfg, const char *path,
|
||||
const struct lfs_filebd_config *bdcfg) {
|
||||
LFS_FILEBD_TRACE("lfs_filebd_create(%p {.context=%p, "
|
||||
".read=%p, .prog=%p, .erase=%p, .sync=%p, "
|
||||
".read_size=%"PRIu32", .prog_size=%"PRIu32", "
|
||||
".block_size=%"PRIu32", .block_count=%"PRIu32"}, "
|
||||
"\"%s\")",
|
||||
".read=%p, .prog=%p, .erase=%p, .sync=%p}, "
|
||||
"\"%s\", "
|
||||
"%p {.read_size=%"PRIu32", .prog_size=%"PRIu32", "
|
||||
".erase_size=%"PRIu32", .erase_count=%"PRIu32"})",
|
||||
(void*)cfg, cfg->context,
|
||||
(void*)(uintptr_t)cfg->read, (void*)(uintptr_t)cfg->prog,
|
||||
(void*)(uintptr_t)cfg->erase, (void*)(uintptr_t)cfg->sync,
|
||||
cfg->read_size, cfg->prog_size, cfg->block_size, cfg->block_count,
|
||||
path, (void*)bdcfg, bdcfg->erase_value);
|
||||
path,
|
||||
(void*)bdcfg,
|
||||
bdcfg->read_size, bdcfg->prog_size, bdcfg->erase_size,
|
||||
bdcfg->erase_count);
|
||||
lfs_filebd_t *bd = cfg->context;
|
||||
bd->cfg = bdcfg;
|
||||
|
||||
// open file
|
||||
#ifdef _WIN32
|
||||
@@ -66,17 +70,17 @@ int lfs_filebd_read(const struct lfs_config *cfg, lfs_block_t block,
|
||||
lfs_filebd_t *bd = cfg->context;
|
||||
|
||||
// check if read is valid
|
||||
LFS_ASSERT(block < cfg->block_count);
|
||||
LFS_ASSERT(off % cfg->read_size == 0);
|
||||
LFS_ASSERT(size % cfg->read_size == 0);
|
||||
LFS_ASSERT(off+size <= cfg->block_size);
|
||||
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(off+size <= bd->cfg->erase_size);
|
||||
|
||||
// zero for reproducibility (in case file is truncated)
|
||||
memset(buffer, 0, size);
|
||||
|
||||
// read
|
||||
off_t res1 = lseek(bd->fd,
|
||||
(off_t)block*cfg->block_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);
|
||||
@@ -102,14 +106,14 @@ int lfs_filebd_prog(const struct lfs_config *cfg, lfs_block_t block,
|
||||
lfs_filebd_t *bd = cfg->context;
|
||||
|
||||
// check if write is valid
|
||||
LFS_ASSERT(block < cfg->block_count);
|
||||
LFS_ASSERT(off % cfg->prog_size == 0);
|
||||
LFS_ASSERT(size % cfg->prog_size == 0);
|
||||
LFS_ASSERT(off+size <= cfg->block_size);
|
||||
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(off+size <= bd->cfg->erase_size);
|
||||
|
||||
// program data
|
||||
off_t res1 = lseek(bd->fd,
|
||||
(off_t)block*cfg->block_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);
|
||||
@@ -129,10 +133,11 @@ int lfs_filebd_prog(const struct lfs_config *cfg, lfs_block_t block,
|
||||
|
||||
int lfs_filebd_erase(const struct lfs_config *cfg, lfs_block_t block) {
|
||||
LFS_FILEBD_TRACE("lfs_filebd_erase(%p, 0x%"PRIx32" (%"PRIu32"))",
|
||||
(void*)cfg, block, cfg->block_size);
|
||||
(void*)cfg, block, ((lfs_file_t*)cfg->context)->cfg->erase_size);
|
||||
lfs_filebd_t *bd = cfg->context;
|
||||
|
||||
// check if erase is valid
|
||||
LFS_ASSERT(block < cfg->block_count);
|
||||
LFS_ASSERT(block < bd->cfg->erase_count);
|
||||
|
||||
// erase is a noop
|
||||
(void)block;
|
||||
|
||||
+19
-2
@@ -26,14 +26,31 @@ extern "C"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// filebd config
|
||||
struct lfs_filebd_config {
|
||||
// Minimum size of a read operation in bytes.
|
||||
lfs_size_t read_size;
|
||||
|
||||
// Minimum size of a program operation in bytes.
|
||||
lfs_size_t prog_size;
|
||||
|
||||
// Size of an erase operation in bytes.
|
||||
lfs_size_t erase_size;
|
||||
|
||||
// Number of erase blocks on the device.
|
||||
lfs_size_t erase_count;
|
||||
};
|
||||
|
||||
// filebd state
|
||||
typedef struct lfs_filebd {
|
||||
int fd;
|
||||
const struct lfs_filebd_config *cfg;
|
||||
} lfs_filebd_t;
|
||||
|
||||
|
||||
// Create a file block device using the geometry in lfs_config
|
||||
int lfs_filebd_create(const struct lfs_config *cfg, const char *path);
|
||||
// Create a file block device
|
||||
int lfs_filebd_create(const struct lfs_config *cfg, const char *path,
|
||||
const struct lfs_filebd_config *bdcfg);
|
||||
|
||||
// Clean up memory associated with block device
|
||||
int lfs_filebd_destroy(const struct lfs_config *cfg);
|
||||
|
||||
+26
-39
@@ -7,18 +7,19 @@
|
||||
*/
|
||||
#include "bd/lfs_rambd.h"
|
||||
|
||||
int lfs_rambd_createcfg(const struct lfs_config *cfg,
|
||||
int lfs_rambd_create(const struct lfs_config *cfg,
|
||||
const struct lfs_rambd_config *bdcfg) {
|
||||
LFS_RAMBD_TRACE("lfs_rambd_createcfg(%p {.context=%p, "
|
||||
".read=%p, .prog=%p, .erase=%p, .sync=%p, "
|
||||
".read_size=%"PRIu32", .prog_size=%"PRIu32", "
|
||||
".block_size=%"PRIu32", .block_count=%"PRIu32"}, "
|
||||
"%p {.buffer=%p})",
|
||||
LFS_RAMBD_TRACE("lfs_rambd_create(%p {.context=%p, "
|
||||
".read=%p, .prog=%p, .erase=%p, .sync=%p}, "
|
||||
"%p {.read_size=%"PRIu32", .prog_size=%"PRIu32", "
|
||||
".erase_size=%"PRIu32", .erase_count=%"PRIu32", "
|
||||
".buffer=%p})",
|
||||
(void*)cfg, cfg->context,
|
||||
(void*)(uintptr_t)cfg->read, (void*)(uintptr_t)cfg->prog,
|
||||
(void*)(uintptr_t)cfg->erase, (void*)(uintptr_t)cfg->sync,
|
||||
cfg->read_size, cfg->prog_size, cfg->block_size, cfg->block_count,
|
||||
(void*)bdcfg, bdcfg->buffer);
|
||||
(void*)bdcfg,
|
||||
bdcfg->read_size, bdcfg->prog_size, bdcfg->erase_size,
|
||||
bdcfg->erase_count, bdcfg->buffer);
|
||||
lfs_rambd_t *bd = cfg->context;
|
||||
bd->cfg = bdcfg;
|
||||
|
||||
@@ -26,35 +27,20 @@ int lfs_rambd_createcfg(const struct lfs_config *cfg,
|
||||
if (bd->cfg->buffer) {
|
||||
bd->buffer = bd->cfg->buffer;
|
||||
} else {
|
||||
bd->buffer = lfs_malloc(cfg->block_size * cfg->block_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);
|
||||
LFS_RAMBD_TRACE("lfs_rambd_create -> %d", LFS_ERR_NOMEM);
|
||||
return LFS_ERR_NOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
// zero for reproducibility
|
||||
memset(bd->buffer, 0, cfg->block_size * cfg->block_count);
|
||||
memset(bd->buffer, 0, bd->cfg->erase_size * bd->cfg->erase_count);
|
||||
|
||||
LFS_RAMBD_TRACE("lfs_rambd_createcfg -> %d", 0);
|
||||
LFS_RAMBD_TRACE("lfs_rambd_create -> %d", 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lfs_rambd_create(const struct lfs_config *cfg) {
|
||||
LFS_RAMBD_TRACE("lfs_rambd_create(%p {.context=%p, "
|
||||
".read=%p, .prog=%p, .erase=%p, .sync=%p, "
|
||||
".read_size=%"PRIu32", .prog_size=%"PRIu32", "
|
||||
".block_size=%"PRIu32", .block_count=%"PRIu32"})",
|
||||
(void*)cfg, cfg->context,
|
||||
(void*)(uintptr_t)cfg->read, (void*)(uintptr_t)cfg->prog,
|
||||
(void*)(uintptr_t)cfg->erase, (void*)(uintptr_t)cfg->sync,
|
||||
cfg->read_size, cfg->prog_size, cfg->block_size, cfg->block_count);
|
||||
static const struct lfs_rambd_config defaults = {0};
|
||||
int err = lfs_rambd_createcfg(cfg, &defaults);
|
||||
LFS_RAMBD_TRACE("lfs_rambd_create -> %d", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
int lfs_rambd_destroy(const struct lfs_config *cfg) {
|
||||
LFS_RAMBD_TRACE("lfs_rambd_destroy(%p)", (void*)cfg);
|
||||
// clean up memory
|
||||
@@ -74,13 +60,13 @@ int lfs_rambd_read(const struct lfs_config *cfg, lfs_block_t block,
|
||||
lfs_rambd_t *bd = cfg->context;
|
||||
|
||||
// check if read is valid
|
||||
LFS_ASSERT(block < cfg->block_count);
|
||||
LFS_ASSERT(off % cfg->read_size == 0);
|
||||
LFS_ASSERT(size % cfg->read_size == 0);
|
||||
LFS_ASSERT(off+size <= cfg->block_size);
|
||||
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(off+size <= bd->cfg->erase_size);
|
||||
|
||||
// read data
|
||||
memcpy(buffer, &bd->buffer[block*cfg->block_size + off], size);
|
||||
memcpy(buffer, &bd->buffer[block*bd->cfg->erase_size + off], size);
|
||||
|
||||
LFS_RAMBD_TRACE("lfs_rambd_read -> %d", 0);
|
||||
return 0;
|
||||
@@ -94,13 +80,13 @@ int lfs_rambd_prog(const struct lfs_config *cfg, lfs_block_t block,
|
||||
lfs_rambd_t *bd = cfg->context;
|
||||
|
||||
// check if write is valid
|
||||
LFS_ASSERT(block < cfg->block_count);
|
||||
LFS_ASSERT(off % cfg->prog_size == 0);
|
||||
LFS_ASSERT(size % cfg->prog_size == 0);
|
||||
LFS_ASSERT(off+size <= cfg->block_size);
|
||||
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(off+size <= bd->cfg->erase_size);
|
||||
|
||||
// program data
|
||||
memcpy(&bd->buffer[block*cfg->block_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;
|
||||
@@ -108,10 +94,11 @@ int lfs_rambd_prog(const struct lfs_config *cfg, lfs_block_t block,
|
||||
|
||||
int lfs_rambd_erase(const struct lfs_config *cfg, lfs_block_t block) {
|
||||
LFS_RAMBD_TRACE("lfs_rambd_erase(%p, 0x%"PRIx32" (%"PRIu32"))",
|
||||
(void*)cfg, block, cfg->block_size);
|
||||
(void*)cfg, block, ((lfs_rambd_t*)cfg->context)->cfg->erase_size);
|
||||
lfs_rambd_t *bd = cfg->context;
|
||||
|
||||
// check if erase is valid
|
||||
LFS_ASSERT(block < cfg->block_count);
|
||||
LFS_ASSERT(block < bd->cfg->erase_count);
|
||||
|
||||
// erase is a noop
|
||||
(void)block;
|
||||
|
||||
+15
-4
@@ -26,8 +26,20 @@ extern "C"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// rambd config (optional)
|
||||
// rambd config
|
||||
struct lfs_rambd_config {
|
||||
// Minimum size of a read operation in bytes.
|
||||
lfs_size_t read_size;
|
||||
|
||||
// Minimum size of a program operation in bytes.
|
||||
lfs_size_t prog_size;
|
||||
|
||||
// Size of an erase operation in bytes.
|
||||
lfs_size_t erase_size;
|
||||
|
||||
// Number of erase blocks on the device.
|
||||
lfs_size_t erase_count;
|
||||
|
||||
// Optional statically allocated buffer for the block device.
|
||||
void *buffer;
|
||||
};
|
||||
@@ -39,9 +51,8 @@ typedef struct lfs_rambd {
|
||||
} lfs_rambd_t;
|
||||
|
||||
|
||||
// Create a RAM block device using the geometry in lfs_config
|
||||
int lfs_rambd_create(const struct lfs_config *cfg);
|
||||
int lfs_rambd_createcfg(const struct lfs_config *cfg,
|
||||
// Create a RAM block device
|
||||
int lfs_rambd_create(const struct lfs_config *cfg,
|
||||
const struct lfs_rambd_config *bdcfg);
|
||||
|
||||
// Clean up memory associated with block device
|
||||
|
||||
Reference in New Issue
Block a user