diff --git a/bd/lfs_emubd.c b/bd/lfs_emubd.c index 2d2c168b..3f6183c9 100644 --- a/bd/lfs_emubd.c +++ b/bd/lfs_emubd.c @@ -217,15 +217,18 @@ static int lfs_emubd_powerloss(const struct lfs_config *cfg) { lfs_emubd_t *bd = cfg->context; // emulate out-of-order writes? + lfs_emubd_block_t *ooo_data = NULL; if (bd->cfg->powerloss_behavior == LFS_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? - lfs_emubd_decblock(bd->blocks[bd->ooo_block]); - bd->blocks[bd->ooo_block] = bd->ooo_data; + ooo_data = bd->blocks[bd->ooo_block]; + bd->blocks[bd->ooo_block] = lfs_emubd_incblock(bd->ooo_data); // mirror to disk file? - if (bd->disk && (bd->ooo_data || bd->cfg->erase_value != -1)) { + 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); @@ -234,22 +237,47 @@ static int lfs_emubd_powerloss(const struct lfs_config *cfg) { } ssize_t res2 = write(bd->disk->fd, - (bd->ooo_data) - ? bd->ooo_data->data + (bd->blocks[bd->ooo_block]) + ? bd->blocks[bd->ooo_block]->data : bd->disk->scratch, bd->cfg->erase_size); if (res2 < 0) { return -errno; } } - - bd->ooo_block = -1; - bd->ooo_data = NULL; } // 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 == LFS_EMUBD_POWERLOSS_OOO + && bd->ooo_block != -1) { + lfs_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; }