Generated v2 prefixes

This commit is contained in:
geky-bot
2024-03-08 23:23:45 +00:00
11 changed files with 174 additions and 17 deletions
+101 -7
View File
@@ -129,6 +129,8 @@ int lfs2_emubd_create(const struct lfs2_config *cfg,
bd->proged = 0;
bd->erased = 0;
bd->power_cycles = bd->cfg->power_cycles;
bd->ooo_block = -1;
bd->ooo_data = NULL;
bd->disk = NULL;
if (bd->cfg->disk_path) {
@@ -195,6 +197,7 @@ int lfs2_emubd_destroy(const struct lfs2_config *cfg) {
free(bd->blocks);
// clean up other resources
lfs2_emubd_decblock(bd->ooo_data);
if (bd->disk) {
bd->disk->rc -= 1;
if (bd->disk->rc == 0) {
@@ -209,6 +212,75 @@ int lfs2_emubd_destroy(const struct lfs2_config *cfg) {
}
// powerloss hook
static int lfs2_emubd_powerloss(const struct lfs2_config *cfg) {
lfs2_emubd_t *bd = cfg->context;
// emulate out-of-order writes?
lfs2_emubd_block_t *ooo_data = NULL;
if (bd->cfg->powerloss_behavior == LFS2_EMUBD_POWERLOSS_OOO
&& bd->ooo_block != -1) {
// since writes between syncs are allowed to be out-of-order, it
// shouldn't hurt to restore the first write on powerloss, right?
ooo_data = bd->blocks[bd->ooo_block];
bd->blocks[bd->ooo_block] = lfs2_emubd_incblock(bd->ooo_data);
// mirror to disk file?
if (bd->disk
&& (bd->blocks[bd->ooo_block]
|| bd->cfg->erase_value != -1)) {
off_t res1 = lseek(bd->disk->fd,
(off_t)bd->ooo_block*bd->cfg->erase_size,
SEEK_SET);
if (res1 < 0) {
return -errno;
}
ssize_t res2 = write(bd->disk->fd,
(bd->blocks[bd->ooo_block])
? bd->blocks[bd->ooo_block]->data
: bd->disk->scratch,
bd->cfg->erase_size);
if (res2 < 0) {
return -errno;
}
}
}
// simulate power loss
bd->cfg->powerloss_cb(bd->cfg->powerloss_data);
// if we continue, undo out-of-order write emulation
if (bd->cfg->powerloss_behavior == LFS2_EMUBD_POWERLOSS_OOO
&& bd->ooo_block != -1) {
lfs2_emubd_decblock(bd->blocks[bd->ooo_block]);
bd->blocks[bd->ooo_block] = ooo_data;
// mirror to disk file?
if (bd->disk
&& (bd->blocks[bd->ooo_block]
|| bd->cfg->erase_value != -1)) {
off_t res1 = lseek(bd->disk->fd,
(off_t)bd->ooo_block*bd->cfg->erase_size,
SEEK_SET);
if (res1 < 0) {
return -errno;
}
ssize_t res2 = write(bd->disk->fd,
(bd->blocks[bd->ooo_block])
? bd->blocks[bd->ooo_block]->data
: bd->disk->scratch,
bd->cfg->erase_size);
if (res2 < 0) {
return -errno;
}
}
}
return 0;
}
// block device API
@@ -344,8 +416,11 @@ int lfs2_emubd_prog(const struct lfs2_config *cfg, lfs2_block_t block,
if (bd->power_cycles > 0) {
bd->power_cycles -= 1;
if (bd->power_cycles == 0) {
// simulate power loss
bd->cfg->powerloss_cb(bd->cfg->powerloss_data);
int err = lfs2_emubd_powerloss(cfg);
if (err) {
LFS2_EMUBD_TRACE("lfs2_emubd_prog -> %d", err);
return err;
}
}
}
@@ -361,10 +436,17 @@ int lfs2_emubd_erase(const struct lfs2_config *cfg, lfs2_block_t block) {
// check if erase is valid
LFS2_ASSERT(block < bd->cfg->erase_count);
// emulate out-of-order writes? save first write
if (bd->cfg->powerloss_behavior == LFS2_EMUBD_POWERLOSS_OOO
&& bd->ooo_block == -1) {
bd->ooo_block = block;
bd->ooo_data = lfs2_emubd_incblock(bd->blocks[block]);
}
// get the block
lfs2_emubd_block_t *b = lfs2_emubd_mutblock(cfg, &bd->blocks[block]);
if (!b) {
LFS2_EMUBD_TRACE("lfs2_emubd_prog -> %d", LFS2_ERR_NOMEM);
LFS2_EMUBD_TRACE("lfs2_emubd_erase -> %d", LFS2_ERR_NOMEM);
return LFS2_ERR_NOMEM;
}
@@ -430,8 +512,11 @@ int lfs2_emubd_erase(const struct lfs2_config *cfg, lfs2_block_t block) {
if (bd->power_cycles > 0) {
bd->power_cycles -= 1;
if (bd->power_cycles == 0) {
// simulate power loss
bd->cfg->powerloss_cb(bd->cfg->powerloss_data);
int err = lfs2_emubd_powerloss(cfg);
if (err) {
LFS2_EMUBD_TRACE("lfs2_emubd_erase -> %d", err);
return err;
}
}
}
@@ -441,14 +526,21 @@ int lfs2_emubd_erase(const struct lfs2_config *cfg, lfs2_block_t block) {
int lfs2_emubd_sync(const struct lfs2_config *cfg) {
LFS2_EMUBD_TRACE("lfs2_emubd_sync(%p)", (void*)cfg);
lfs2_emubd_t *bd = cfg->context;
// do nothing
(void)cfg;
// emulate out-of-order writes? reset first write, writes
// cannot be out-of-order across sync
if (bd->cfg->powerloss_behavior == LFS2_EMUBD_POWERLOSS_OOO) {
lfs2_emubd_decblock(bd->ooo_data);
bd->ooo_block = -1;
bd->ooo_data = NULL;
}
LFS2_EMUBD_TRACE("lfs2_emubd_sync -> %d", 0);
return 0;
}
/// Additional extended API for driving test features ///
static int lfs2_emubd_crc_(const struct lfs2_config *cfg,
@@ -633,6 +725,8 @@ int lfs2_emubd_copy(const struct lfs2_config *cfg, lfs2_emubd_t *copy) {
copy->proged = bd->proged;
copy->erased = bd->erased;
copy->power_cycles = bd->power_cycles;
copy->ooo_block = bd->ooo_block;
copy->ooo_data = lfs2_emubd_incblock(bd->ooo_data);
copy->disk = bd->disk;
if (copy->disk) {
copy->disk->rc += 1;
+9 -6
View File
@@ -36,17 +36,18 @@ extern "C"
// Not that read-noop is not allowed. Read _must_ return a consistent (but
// may be arbitrary) value on every read.
typedef enum lfs2_emubd_badblock_behavior {
LFS2_EMUBD_BADBLOCK_PROGERROR,
LFS2_EMUBD_BADBLOCK_ERASEERROR,
LFS2_EMUBD_BADBLOCK_READERROR,
LFS2_EMUBD_BADBLOCK_PROGNOOP,
LFS2_EMUBD_BADBLOCK_ERASENOOP,
LFS2_EMUBD_BADBLOCK_PROGERROR = 0, // Error on prog
LFS2_EMUBD_BADBLOCK_ERASEERROR = 1, // Error on erase
LFS2_EMUBD_BADBLOCK_READERROR = 2, // Error on read
LFS2_EMUBD_BADBLOCK_PROGNOOP = 3, // Prog does nothing silently
LFS2_EMUBD_BADBLOCK_ERASENOOP = 4, // Erase does nothing silently
} lfs2_emubd_badblock_behavior_t;
// Mode determining how power-loss behaves during testing. For now this
// only supports a noop behavior, leaving the data on-disk untouched.
typedef enum lfs2_emubd_powerloss_behavior {
LFS2_EMUBD_POWERLOSS_NOOP,
LFS2_EMUBD_POWERLOSS_NOOP = 0, // Progs are atomic
LFS2_EMUBD_POWERLOSS_OOO = 1, // Blocks are written out-of-order
} lfs2_emubd_powerloss_behavior_t;
// Type for measuring read/program/erase operations
@@ -152,6 +153,8 @@ typedef struct lfs2_emubd {
lfs2_emubd_io_t proged;
lfs2_emubd_io_t erased;
lfs2_emubd_powercycles_t power_cycles;
lfs2_ssize_t ooo_block;
lfs2_emubd_block_t *ooo_data;
lfs2_emubd_disk_t *disk;
const struct lfs2_emubd_config *cfg;