Generated v2 prefixes
This commit is contained in:
+101
-7
@@ -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
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user