diff --git a/bd/lfs_emubd.c b/bd/lfs_emubd.c index f14fb5a4..458ac17a 100644 --- a/bd/lfs_emubd.c +++ b/bd/lfs_emubd.c @@ -47,51 +47,66 @@ 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_block_t *block_ = *block; - if (block_ && block_->rc == 1) { + lfs_emubd_block_t *block) { + if (block && block->rc == 1) { // rc == 1? can modify - return block_; + return block; - } else if (block_) { + } else if (block) { // rc > 1? need to create a copy - lfs_emubd_block_t *nblock = malloc( + lfs_emubd_block_t *block_ = malloc( sizeof(lfs_emubd_block_t) + cfg->block_size); - if (!nblock) { + if (!block_) { return NULL; } - memcpy(nblock, block_, + memcpy(block_, block, sizeof(lfs_emubd_block_t) + cfg->block_size); - nblock->rc = 1; + block_->rc = 1; - lfs_emubd_decblock(block_); - *block = nblock; - return nblock; + lfs_emubd_decblock(block); + return block_; } else { // no block? need to allocate - lfs_emubd_block_t *nblock = malloc( + lfs_emubd_block_t *block_ = malloc( sizeof(lfs_emubd_block_t) + cfg->block_size); - if (!nblock) { + if (!block_) { return NULL; } - nblock->rc = 1; - nblock->wear = 0; + block_->rc = 1; + block_->wear = 0; // zero for consistency lfs_emubd_t *bd = cfg->context; - memset(nblock->data, + memset(block_->data, (bd->cfg->erase_value != -1) ? bd->cfg->erase_value : 0, cfg->block_size); - *block = nblock; - return nblock; + return block_; } } +// prng used for some emulation things +static uint32_t lfs_emubd_prng(uint32_t *state) { + // A simple xorshift32 generator, easily reproducible. Keep in mind + // determinism is much more important than actual randomness here. + uint32_t x = *state; + // must be non-zero, use uintmax here so that seed=0 is different + // from seed=1 and seed=range(0,n) makes a bit more sense + if (x == 0) { + x = -1; + } + x ^= x << 13; + x ^= x >> 17; + x ^= x << 5; + *state = x; + return x; +} + + // emubd create/destroy int lfs_emubd_createcfg(const struct lfs_config *cfg, const char *path, @@ -104,7 +119,7 @@ int lfs_emubd_createcfg(const struct lfs_config *cfg, const char *path, "%p {.erase_value=%"PRId32", .erase_cycles=%"PRIu32", " ".badblock_behavior=%"PRIu8", .power_cycles=%"PRIu32", " ".powerloss_behavior=%"PRIu8", .powerloss_cb=%p, " - ".powerloss_data=%p})", + ".powerloss_data=%p, seed=%"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, @@ -112,7 +127,7 @@ int lfs_emubd_createcfg(const struct lfs_config *cfg, const char *path, path, (void*)bdcfg, 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->powerloss_data, bdcfg->seed); lfs_emubd_t *bd = cfg->context; bd->cfg = bdcfg; @@ -121,6 +136,7 @@ int lfs_emubd_createcfg(const struct lfs_config *cfg, const char *path, bd->readed = 0; bd->proged = 0; bd->erased = 0; + bd->prng = bd->cfg->seed; bd->power_cycles = bd->cfg->power_cycles; bd->ooo_before = NULL; bd->ooo_after = NULL; @@ -342,78 +358,100 @@ int lfs_emubd_prog(const struct lfs_config *cfg, lfs_block_t block, LFS_ASSERT(size % cfg->prog_size == 0); LFS_ASSERT(off+size <= cfg->block_size); - // get the block - lfs_emubd_block_t *b = lfs_emubd_mutblock(cfg, &bd->blocks[block]); - if (!b) { - LFS_EMUBD_TRACE("lfs_emubd_prog -> %d", LFS_ERR_NOMEM); - return LFS_ERR_NOMEM; - } - - // block bad? - if (bd->cfg->erase_cycles && b->wear >= bd->cfg->erase_cycles) { - if (bd->cfg->badblock_behavior == - LFS_EMUBD_BADBLOCK_PROGERROR) { - LFS_EMUBD_TRACE("lfs_emubd_prog -> %d", LFS_ERR_CORRUPT); - return LFS_ERR_CORRUPT; - } else if (bd->cfg->badblock_behavior == - LFS_EMUBD_BADBLOCK_PROGNOOP || - bd->cfg->badblock_behavior == - LFS_EMUBD_BADBLOCK_ERASENOOP) { - LFS_EMUBD_TRACE("lfs_emubd_prog -> %d", 0); - return 0; - } - } - // were we erased properly? - if (bd->cfg->erase_value != -1) { + LFS_ASSERT(bd->blocks[block]); + if (bd->cfg->erase_value != -1 + && !(bd->cfg->erase_cycles + && bd->blocks[block]->wear >= bd->cfg->erase_cycles)) { for (lfs_off_t i = 0; i < size; i++) { - LFS_ASSERT(b->data[off+i] == bd->cfg->erase_value); + LFS_ASSERT(bd->blocks[block]->data[off+i] == bd->cfg->erase_value); } } - // prog data - memcpy(&b->data[off], buffer, size); - - // mirror to disk file? - if (bd->disk) { - off_t res1 = lseek(bd->disk->fd, - (off_t)block*cfg->block_size + (off_t)off, - SEEK_SET); - if (res1 < 0) { - int err = -errno; - LFS_EMUBD_TRACE("lfs_emubd_prog -> %d", err); - return err; - } - - ssize_t res2 = write(bd->disk->fd, buffer, size); - if (res2 < 0) { - int err = -errno; - LFS_EMUBD_TRACE("lfs_emubd_prog -> %d", err); - return err; - } - } - - // track progs - bd->proged += size; - if (bd->cfg->prog_sleep) { - int err = nanosleep(&(struct timespec){ - .tv_sec=bd->cfg->prog_sleep/1000000000, - .tv_nsec=bd->cfg->prog_sleep%1000000000}, - NULL); - if (err) { - err = -errno; - LFS_EMUBD_TRACE("lfs_emubd_prog -> %d", err); - return err; - } - } - - // lose power? + // losing power? if (bd->power_cycles > 0) { bd->power_cycles -= 1; if (bd->power_cycles == 0) { - // if we're emulating out-of-order writes, revert everything - // unsynced except for our current block - if (bd->cfg->powerloss_behavior == LFS_EMUBD_POWERLOSS_OOO) { + // if emulating some bits, choose a random bit to flip + if (bd->cfg->powerloss_behavior + == LFS_EMUBD_POWERLOSS_SOMEBITS) { + // mutate the block + lfs_emubd_block_t *b = lfs_emubd_mutblock(cfg, + bd->blocks[block]); + if (!b) { + LFS_EMUBD_TRACE("lfs_emubd_prog -> %d", LFS_ERR_NOMEM); + return LFS_ERR_NOMEM; + } + bd->blocks[block] = b; + + // flip bit + lfs_size_t bit = lfs_emubd_prng(&bd->prng) + % (cfg->prog_size*8); + b->data[off + (bit/8)] ^= (1 << (bit%8)); + + // mirror to disk file? + if (bd->disk) { + off_t res1 = lseek(bd->disk->fd, + (off_t)block*cfg->block_size + (off_t)off, + SEEK_SET); + if (res1 < 0) { + int err = -errno; + LFS_EMUBD_TRACE("lfs_emubd_prog -> %d", err); + return err; + } + + ssize_t res2 = write(bd->disk->fd, &b->data[off], size); + if (res2 < 0) { + int err = -errno; + LFS_EMUBD_TRACE("lfs_emubd_prog -> %d", err); + return err; + } + } + + // if emulating most bits, prog data and choose a random bit + // to flip + } else if (bd->cfg->powerloss_behavior + == LFS_EMUBD_POWERLOSS_MOSTBITS) { + // mutate the block + lfs_emubd_block_t *b = lfs_emubd_mutblock(cfg, + bd->blocks[block]); + if (!b) { + LFS_EMUBD_TRACE("lfs_emubd_prog -> %d", LFS_ERR_NOMEM); + return LFS_ERR_NOMEM; + } + bd->blocks[block] = b; + + // prog data + memcpy(&b->data[off], buffer, size); + + // flip bit + lfs_size_t bit = lfs_emubd_prng(&bd->prng) + % (cfg->prog_size*8); + b->data[off + (bit/8)] ^= (1 << (bit%8)); + + // mirror to disk file? + if (bd->disk) { + off_t res1 = lseek(bd->disk->fd, + (off_t)block*cfg->block_size + (off_t)off, + SEEK_SET); + if (res1 < 0) { + int err = -errno; + LFS_EMUBD_TRACE("lfs_emubd_prog -> %d", err); + return err; + } + + ssize_t res2 = write(bd->disk->fd, &b->data[off], size); + if (res2 < 0) { + int err = -errno; + LFS_EMUBD_TRACE("lfs_emubd_prog -> %d", err); + return err; + } + } + + // if emulating out-of-order writes, revert everything unsynced + // except for our current block + } else if (bd->cfg->powerloss_behavior + == LFS_EMUBD_POWERLOSS_OOO) { for (lfs_block_t i = 0; i < cfg->block_count; i++) { lfs_emubd_decblock(bd->ooo_after[i]); bd->ooo_after[i] = lfs_emubd_incblock(bd->blocks[i]); @@ -486,6 +524,65 @@ int lfs_emubd_prog(const struct lfs_config *cfg, lfs_block_t block, } } + // mutate the block + lfs_emubd_block_t *b = lfs_emubd_mutblock(cfg, bd->blocks[block]); + if (!b) { + LFS_EMUBD_TRACE("lfs_emubd_prog -> %d", LFS_ERR_NOMEM); + return LFS_ERR_NOMEM; + } + bd->blocks[block] = b; + + // block bad? + if (bd->cfg->erase_cycles && b->wear >= bd->cfg->erase_cycles) { + if (bd->cfg->badblock_behavior == + LFS_EMUBD_BADBLOCK_PROGERROR) { + LFS_EMUBD_TRACE("lfs_emubd_prog -> %d", LFS_ERR_CORRUPT); + return LFS_ERR_CORRUPT; + } else if (bd->cfg->badblock_behavior == + LFS_EMUBD_BADBLOCK_PROGNOOP || + bd->cfg->badblock_behavior == + LFS_EMUBD_BADBLOCK_ERASENOOP) { + LFS_EMUBD_TRACE("lfs_emubd_prog -> %d", 0); + return 0; + } + } + + // prog data + memcpy(&b->data[off], buffer, size); + + // mirror to disk file? + if (bd->disk) { + off_t res1 = lseek(bd->disk->fd, + (off_t)block*cfg->block_size + (off_t)off, + SEEK_SET); + if (res1 < 0) { + int err = -errno; + LFS_EMUBD_TRACE("lfs_emubd_prog -> %d", err); + return err; + } + + ssize_t res2 = write(bd->disk->fd, &b->data[off], size); + if (res2 < 0) { + int err = -errno; + LFS_EMUBD_TRACE("lfs_emubd_prog -> %d", err); + return err; + } + } + + // track progs + bd->proged += size; + if (bd->cfg->prog_sleep) { + int err = nanosleep(&(struct timespec){ + .tv_sec=bd->cfg->prog_sleep/1000000000, + .tv_nsec=bd->cfg->prog_sleep%1000000000}, + NULL); + if (err) { + err = -errno; + LFS_EMUBD_TRACE("lfs_emubd_prog -> %d", err); + return err; + } + } + LFS_EMUBD_TRACE("lfs_emubd_prog -> %d", 0); return 0; } @@ -498,16 +595,174 @@ int lfs_emubd_erase(const struct lfs_config *cfg, lfs_block_t block) { // check if erase is valid LFS_ASSERT(block < cfg->block_count); - // get the block - lfs_emubd_block_t *b = lfs_emubd_mutblock(cfg, &bd->blocks[block]); + // losing power? + if (bd->power_cycles > 0) { + bd->power_cycles -= 1; + if (bd->power_cycles == 0) { + // if emulating some bits, choose a random bit to flip + if (bd->cfg->powerloss_behavior + == LFS_EMUBD_POWERLOSS_SOMEBITS) { + // mutate the block + lfs_emubd_block_t *b = lfs_emubd_mutblock(cfg, + bd->blocks[block]); + if (!b) { + LFS_EMUBD_TRACE("lfs_emubd_erase -> %d", LFS_ERR_NOMEM); + return LFS_ERR_NOMEM; + } + bd->blocks[block] = b; + + // flip bit + lfs_size_t bit = lfs_emubd_prng(&bd->prng) + % (cfg->block_size*8); + b->data[(bit/8)] ^= (1 << (bit%8)); + + // mirror to disk file? + if (bd->disk) { + off_t res1 = lseek(bd->disk->fd, + (off_t)block*cfg->block_size, + SEEK_SET); + if (res1 < 0) { + int err = -errno; + LFS_EMUBD_TRACE("lfs_emubd_erase -> %d", err); + return err; + } + + ssize_t res2 = write(bd->disk->fd, + b->data, cfg->block_size); + if (res2 < 0) { + int err = -errno; + LFS_EMUBD_TRACE("lfs_emubd_erase -> %d", err); + return err; + } + } + + // if emulating most bits, erase data and choose a random bit + // to flip + } else if (bd->cfg->powerloss_behavior + == LFS_EMUBD_POWERLOSS_MOSTBITS) { + // mutate the block + lfs_emubd_block_t *b = lfs_emubd_mutblock(cfg, + bd->blocks[block]); + if (!b) { + LFS_EMUBD_TRACE("lfs_emubd_erase -> %d", LFS_ERR_NOMEM); + return LFS_ERR_NOMEM; + } + bd->blocks[block] = b; + + // emulate an erase value? + if (bd->cfg->erase_value != -1) { + memset(b->data, bd->cfg->erase_value, cfg->block_size); + } + + // flip bit + lfs_size_t bit = lfs_emubd_prng(&bd->prng) + % (cfg->block_size*8); + b->data[(bit/8)] ^= (1 << (bit%8)); + + // mirror to disk file? + if (bd->disk) { + off_t res1 = lseek(bd->disk->fd, + (off_t)block*cfg->block_size, + SEEK_SET); + if (res1 < 0) { + int err = -errno; + LFS_EMUBD_TRACE("lfs_emubd_erase -> %d", err); + return err; + } + + ssize_t res2 = write(bd->disk->fd, + b->data, cfg->block_size); + if (res2 < 0) { + int err = -errno; + LFS_EMUBD_TRACE("lfs_emubd_erase -> %d", err); + return err; + } + } + + // if emulating out-of-order writes, revert everything unsynced + // except for our current block + } else if (bd->cfg->powerloss_behavior + == LFS_EMUBD_POWERLOSS_OOO) { + for (lfs_block_t i = 0; i < cfg->block_count; i++) { + if (i != block && bd->blocks[i] != bd->ooo_before[i]) { + lfs_emubd_decblock(bd->blocks[i]); + bd->blocks[i] = lfs_emubd_incblock(bd->ooo_before[i]); + + // mirror to disk file? + if (bd->disk) { + off_t res1 = lseek(bd->disk->fd, + (off_t)i*cfg->block_size, + SEEK_SET); + if (res1 < 0) { + int err = -errno; + LFS_EMUBD_TRACE("lfs_emubd_erase -> %d", err); + return err; + } + + ssize_t res2 = write(bd->disk->fd, + (bd->blocks[i]) + ? bd->blocks[i]->data + : bd->disk->scratch, + cfg->block_size); + if (res2 < 0) { + int err = -errno; + LFS_EMUBD_TRACE("lfs_emubd_erase -> %d", err); + return err; + } + } + } + } + } + + // powerloss! + bd->cfg->powerloss_cb(bd->cfg->powerloss_data); + + // oh, continuing? undo out-of-order write emulation + if (bd->cfg->powerloss_behavior == LFS_EMUBD_POWERLOSS_OOO) { + for (lfs_block_t i = 0; i < cfg->block_count; i++) { + if (bd->blocks[i] != bd->ooo_after[i]) { + lfs_emubd_decblock(bd->blocks[i]); + bd->blocks[i] = lfs_emubd_incblock(bd->ooo_after[i]); + + // mirror to disk file? + if (bd->disk) { + off_t res1 = lseek(bd->disk->fd, + (off_t)i*cfg->block_size, + SEEK_SET); + if (res1 < 0) { + int err = -errno; + LFS_EMUBD_TRACE("lfs_emubd_erase -> %d", err); + return err; + } + + ssize_t res2 = write(bd->disk->fd, + (bd->blocks[i]) + ? bd->blocks[i]->data + : bd->disk->scratch, + cfg->block_size); + if (res2 < 0) { + int err = -errno; + LFS_EMUBD_TRACE("lfs_emubd_erase -> %d", err); + return err; + } + } + } + } + } + } + } + + // mutate the block + lfs_emubd_block_t *b = lfs_emubd_mutblock(cfg, bd->blocks[block]); if (!b) { LFS_EMUBD_TRACE("lfs_emubd_erase -> %d", LFS_ERR_NOMEM); return LFS_ERR_NOMEM; } + bd->blocks[block] = b; // block bad? if (bd->cfg->erase_cycles) { - if (b->wear >= bd->cfg->erase_cycles) { + if (b && b->wear >= bd->cfg->erase_cycles) { if (bd->cfg->badblock_behavior == LFS_EMUBD_BADBLOCK_ERASEERROR) { LFS_EMUBD_TRACE("lfs_emubd_erase -> %d", LFS_ERR_CORRUPT); @@ -561,85 +816,6 @@ int lfs_emubd_erase(const struct lfs_config *cfg, lfs_block_t block) { } } - // lose power? - if (bd->power_cycles > 0) { - bd->power_cycles -= 1; - if (bd->power_cycles == 0) { - // if we're emulating out-of-order writes, revert everything - // unsynced except for our current block - if (bd->cfg->powerloss_behavior == LFS_EMUBD_POWERLOSS_OOO) { - for (lfs_block_t i = 0; i < cfg->block_count; i++) { - lfs_emubd_decblock(bd->ooo_after[i]); - bd->ooo_after[i] = lfs_emubd_incblock(bd->blocks[i]); - - if (i != block && bd->blocks[i] != bd->ooo_before[i]) { - lfs_emubd_decblock(bd->blocks[i]); - bd->blocks[i] = lfs_emubd_incblock(bd->ooo_before[i]); - - // mirror to disk file? - if (bd->disk) { - off_t res1 = lseek(bd->disk->fd, - (off_t)i*cfg->block_size, - SEEK_SET); - if (res1 < 0) { - int err = -errno; - LFS_EMUBD_TRACE("lfs_emubd_erase -> %d", err); - return err; - } - - ssize_t res2 = write(bd->disk->fd, - (bd->blocks[i]) - ? bd->blocks[i]->data - : bd->disk->scratch, - cfg->block_size); - if (res2 < 0) { - int err = -errno; - LFS_EMUBD_TRACE("lfs_emubd_erase -> %d", err); - return err; - } - } - } - } - } - - // powerloss! - bd->cfg->powerloss_cb(bd->cfg->powerloss_data); - - // oh, continuing? undo out-of-order write emulation - if (bd->cfg->powerloss_behavior == LFS_EMUBD_POWERLOSS_OOO) { - for (lfs_block_t i = 0; i < cfg->block_count; i++) { - if (bd->blocks[i] != bd->ooo_after[i]) { - lfs_emubd_decblock(bd->blocks[i]); - bd->blocks[i] = lfs_emubd_incblock(bd->ooo_after[i]); - - // mirror to disk file? - if (bd->disk) { - off_t res1 = lseek(bd->disk->fd, - (off_t)i*cfg->block_size, - SEEK_SET); - if (res1 < 0) { - int err = -errno; - LFS_EMUBD_TRACE("lfs_emubd_erase -> %d", err); - return err; - } - - ssize_t res2 = write(bd->disk->fd, - (bd->blocks[i]) - ? bd->blocks[i]->data - : bd->disk->scratch, - cfg->block_size); - if (res2 < 0) { - int err = -errno; - LFS_EMUBD_TRACE("lfs_emubd_erase -> %d", err); - return err; - } - } - } - } - } - } - } - LFS_EMUBD_TRACE("lfs_emubd_erase -> %d", 0); return 0; } @@ -792,12 +968,15 @@ int lfs_emubd_setwear(const struct lfs_config *cfg, // check if block is valid LFS_ASSERT(block < cfg->block_count); - // set the wear - lfs_emubd_block_t *b = lfs_emubd_mutblock(cfg, &bd->blocks[block]); + // mutate the block + lfs_emubd_block_t *b = lfs_emubd_mutblock(cfg, bd->blocks[block]); if (!b) { LFS_EMUBD_TRACE("lfs_emubd_setwear -> %d", LFS_ERR_NOMEM); return LFS_ERR_NOMEM; } + bd->blocks[block] = b; + + // set the wear b->wear = wear; LFS_EMUBD_TRACE("lfs_emubd_setwear -> %d", 0); @@ -866,6 +1045,7 @@ int lfs_emubd_copy(const struct lfs_config *cfg, lfs_emubd_t *copy) { copy->readed = bd->readed; copy->proged = bd->proged; copy->erased = bd->erased; + copy->prng = bd->prng; copy->power_cycles = bd->power_cycles; copy->disk = bd->disk; if (copy->disk) { diff --git a/bd/lfs_emubd.h b/bd/lfs_emubd.h index 06b892c2..dfffe08a 100644 --- a/bd/lfs_emubd.h +++ b/bd/lfs_emubd.h @@ -46,8 +46,10 @@ typedef enum lfs_emubd_badblock_behavior { // Mode determining how power-loss behaves during testing. For now this // only supports a noop behavior, leaving the data on-disk untouched. typedef enum lfs_emubd_powerloss_behavior { - LFS_EMUBD_POWERLOSS_NOOP = 0, // Progs are atomic - LFS_EMUBD_POWERLOSS_OOO = 1, // Blocks are written out-of-order + LFS_EMUBD_POWERLOSS_NOOP = 0, // Progs are atomic + LFS_EMUBD_POWERLOSS_SOMEBITS = 1, // One bit is progged + LFS_EMUBD_POWERLOSS_MOSTBITS = 2, // All-but-one bit is progged + LFS_EMUBD_POWERLOSS_OOO = 3, // Blocks are written out-of-order } lfs_emubd_powerloss_behavior_t; // Type for measuring read/program/erase operations @@ -94,6 +96,10 @@ struct lfs_emubd_config { // Data for power-loss callback void *powerloss_data; + // Seed for prng, which may be used for emulating failed progs. This does + // not affect normal operation. + uint32_t seed; + // Path to file to use as a mirror of the disk. This provides a way to view // the current state of the block device. const char *disk_path; @@ -135,6 +141,7 @@ typedef struct lfs_emubd { lfs_emubd_io_t readed; lfs_emubd_io_t proged; lfs_emubd_io_t erased; + uint32_t prng; lfs_emubd_powercycles_t power_cycles; lfs_emubd_block_t **ooo_before; lfs_emubd_block_t **ooo_after; diff --git a/runners/bench_runner.h b/runners/bench_runner.h index 2c1f1036..5c7a30ac 100644 --- a/runners/bench_runner.h +++ b/runners/bench_runner.h @@ -128,7 +128,8 @@ void bench_permutation(size_t i, uint32_t *buffer, size_t size); BENCH_DEFINE(ERASE_VALUE, 0xff ) \ BENCH_DEFINE(ERASE_CYCLES, 0 ) \ BENCH_DEFINE(BADBLOCK_BEHAVIOR, LFS_EMUBD_BADBLOCK_PROGERROR ) \ - BENCH_DEFINE(POWERLOSS_BEHAVIOR, LFS_EMUBD_POWERLOSS_NOOP ) + BENCH_DEFINE(POWERLOSS_BEHAVIOR, LFS_EMUBD_POWERLOSS_NOOP ) \ + BENCH_DEFINE(EMUBD_SEED, 0 ) // declare defines as global intmax_ts #define BENCH_DEFINE(k, v) \ @@ -158,7 +159,8 @@ void bench_permutation(size_t i, uint32_t *buffer, size_t size); .erase_value = ERASE_VALUE, \ .erase_cycles = ERASE_CYCLES, \ .badblock_behavior = BADBLOCK_BEHAVIOR, \ - .powerloss_behavior = POWERLOSS_BEHAVIOR, + .powerloss_behavior = POWERLOSS_BEHAVIOR, \ + .seed = EMUBD_SEED, #endif diff --git a/runners/test_runner.h b/runners/test_runner.h index 77246c80..b24abdd3 100644 --- a/runners/test_runner.h +++ b/runners/test_runner.h @@ -113,7 +113,8 @@ void test_permutation(size_t i, uint32_t *buffer, size_t size); TEST_DEFINE(ERASE_VALUE, 0xff ) \ TEST_DEFINE(ERASE_CYCLES, 0 ) \ TEST_DEFINE(BADBLOCK_BEHAVIOR, LFS_EMUBD_BADBLOCK_PROGERROR ) \ - TEST_DEFINE(POWERLOSS_BEHAVIOR, LFS_EMUBD_POWERLOSS_NOOP ) + TEST_DEFINE(POWERLOSS_BEHAVIOR, LFS_EMUBD_POWERLOSS_NOOP ) \ + TEST_DEFINE(EMUBD_SEED, 0 ) // declare defines as global intmax_ts #define TEST_DEFINE(k, v) \ @@ -143,7 +144,8 @@ void test_permutation(size_t i, uint32_t *buffer, size_t size); .erase_value = ERASE_VALUE, \ .erase_cycles = ERASE_CYCLES, \ .badblock_behavior = BADBLOCK_BEHAVIOR, \ - .powerloss_behavior = POWERLOSS_BEHAVIOR, + .powerloss_behavior = POWERLOSS_BEHAVIOR, \ + .seed = EMUBD_SEED, #endif diff --git a/tests/test_powerloss.toml b/tests/test_powerloss.toml index b788a62b..dd1a8d2a 100644 --- a/tests/test_powerloss.toml +++ b/tests/test_powerloss.toml @@ -19,6 +19,8 @@ after = [ [cases.test_powerloss_dir_many] defines.POWERLOSS_BEHAVIOR = [ 'LFS_EMUBD_POWERLOSS_NOOP', + 'LFS_EMUBD_POWERLOSS_SOMEBITS', + 'LFS_EMUBD_POWERLOSS_MOSTBITS', 'LFS_EMUBD_POWERLOSS_OOO', ] defines.N = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512] @@ -111,6 +113,8 @@ code = ''' [cases.test_powerloss_file_many] defines.POWERLOSS_BEHAVIOR = [ 'LFS_EMUBD_POWERLOSS_NOOP', + 'LFS_EMUBD_POWERLOSS_SOMEBITS', + 'LFS_EMUBD_POWERLOSS_MOSTBITS', 'LFS_EMUBD_POWERLOSS_OOO', ] # inlining has a tendency to hide sync issues, so try without @@ -205,6 +209,8 @@ code = ''' [cases.test_powerloss_file_pl_fuzz] defines.POWERLOSS_BEHAVIOR = [ 'LFS_EMUBD_POWERLOSS_NOOP', + 'LFS_EMUBD_POWERLOSS_SOMEBITS', + 'LFS_EMUBD_POWERLOSS_MOSTBITS', 'LFS_EMUBD_POWERLOSS_OOO', ] # inlining has a tendency to hide sync issues, so try without @@ -429,6 +435,8 @@ code = ''' [cases.test_powerloss_filedir_pl_fuzz] defines.POWERLOSS_BEHAVIOR = [ 'LFS_EMUBD_POWERLOSS_NOOP', + 'LFS_EMUBD_POWERLOSS_SOMEBITS', + 'LFS_EMUBD_POWERLOSS_MOSTBITS', 'LFS_EMUBD_POWERLOSS_OOO', ] # inlining has a tendency to hide sync issues, so try without diff --git a/tests/test_rbyd.toml b/tests/test_rbyd.toml index d526a3c0..51c3cd11 100644 --- a/tests/test_rbyd.toml +++ b/tests/test_rbyd.toml @@ -16865,6 +16865,7 @@ code = ''' // create a null tag hole rbyd = init_rbyd; + lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0; lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS( LFSR_ATTR( LFSR_TAG_UATTR(0), 0, @@ -16913,6 +16914,7 @@ code = ''' // create a null tag hole rbyd = init_rbyd; + lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0; lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS( LFSR_ATTR( LFSR_TAG_UATTR(0), 0, @@ -16971,6 +16973,7 @@ code = ''' // create a null tag hole rbyd = init_rbyd; + lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0; lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS( LFSR_ATTR( LFSR_TAG_UATTR(0), 0, @@ -17028,6 +17031,7 @@ code = ''' // create a null tag hole rbyd = init_rbyd; + lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0; lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS( LFSR_ATTR( LFSR_TAG_UATTR(0), 0, @@ -17095,6 +17099,7 @@ code = ''' // create a null tag hole rbyd = init_rbyd; + lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0; lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_ATTRS( LFSR_ATTR( LFSR_TAG_UATTR(0), 0,