Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow block_size/block_count to be optional, add erase_count, lfs_fs_stat, and lfs_fs_grow #753

Draft
wants to merge 9 commits into
base: test-and-bench-runners
Choose a base branch
from
107 changes: 46 additions & 61 deletions bd/lfs_emubd.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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_);
Expand All @@ -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;
}
Expand All @@ -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;
Expand All @@ -94,35 +94,35 @@ 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);
lfs_emubd_t *bd = cfg->context;
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;
Expand All @@ -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;
Expand All @@ -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);
Expand All @@ -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);
Expand Down Expand Up @@ -237,10 +220,12 @@ 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(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);
if (block >= bd->cfg->erase_count) {
return LFS_ERR_INVAL;
}
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];
Expand Down Expand Up @@ -287,10 +272,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(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]);
Expand Down Expand Up @@ -327,7 +312,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;
Expand Down Expand Up @@ -372,11 +357,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(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]);
Expand Down Expand Up @@ -405,12 +390,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;
Expand All @@ -420,7 +405,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);
Expand All @@ -430,7 +415,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,
Expand Down Expand Up @@ -573,7 +558,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;
Expand All @@ -594,7 +579,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]);
Expand Down Expand Up @@ -634,13 +619,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]);
}

Expand Down
18 changes: 13 additions & 5 deletions bd/lfs_emubd.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down
Loading