Fixed issue in emubd where noop erases start out-of-sync with disk

Because reproducibility is extremely important, emubd always zeros
blocks on the first erase, even when erase_value=-1.

Well, at least it should be. We were correctly zeroing the blocks in
RAM, but if erase_value=-1 we were leaving the disk unzeroed, causing
the disk to fall out of sync.

Fixed by zeroing disk in lfs_emubd_createcfg, even if erase_value=-1.

Also I went ahead and dropped the bd->disk->scratch block. We're already
allocating RAM-backed blocks on erase anyways, so keeping scratch around
doesn't really gain us anything anymore. Now there is just a temporary
allocation in lfs_emubd_createcfg to zero the disk efficiently during
initialization.
This commit is contained in:
Christopher Haster
2024-05-01 15:03:38 -05:00
parent b122a50b6c
commit 5fbf073bfb
2 changed files with 22 additions and 31 deletions
+20 -27
View File
@@ -138,7 +138,6 @@ int lfs_emubd_createcfg(const struct lfs_config *cfg, const char *path,
return LFS_ERR_NOMEM;
}
bd->disk->rc = 1;
bd->disk->scratch = NULL;
#ifdef _WIN32
bd->disk->fd = open(bd->cfg->disk_path,
@@ -153,31 +152,28 @@ int lfs_emubd_createcfg(const struct lfs_config *cfg, const char *path,
return err;
}
// 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);
if (!bd->disk->scratch) {
LFS_EMUBD_TRACE("lfs_emubd_createcfg -> %d", LFS_ERR_NOMEM);
return LFS_ERR_NOMEM;
}
memset(bd->disk->scratch,
bd->cfg->erase_value,
cfg->block_size);
// go ahead and erase all of the disk, otherwise the file will not
// match our internal representation
uint8_t *scratch = malloc(cfg->block_size);
if (!scratch) {
LFS_EMUBD_TRACE("lfs_emubd_createcfg -> %d", LFS_ERR_NOMEM);
return LFS_ERR_NOMEM;
}
memset(scratch,
(bd->cfg->erase_value != -1) ? bd->cfg->erase_value : 0,
cfg->block_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++) {
ssize_t res = write(bd->disk->fd,
bd->disk->scratch,
cfg->block_size);
if (res < 0) {
int err = -errno;
LFS_EMUBD_TRACE("lfs_emubd_create -> %d", err);
return err;
}
for (size_t i = 0; i < cfg->block_count; i++) {
ssize_t res = write(bd->disk->fd, scratch, cfg->block_size);
if (res < 0) {
int err = -errno;
free(scratch);
LFS_EMUBD_TRACE("lfs_emubd_create -> %d", err);
return err;
}
}
free(scratch);
}
LFS_EMUBD_TRACE("lfs_emubd_createcfg -> %d", 0);
@@ -216,7 +212,6 @@ int lfs_emubd_destroy(const struct lfs_config *cfg) {
bd->disk->rc -= 1;
if (bd->disk->rc == 0) {
close(bd->disk->fd);
free(bd->disk->scratch);
free(bd->disk);
}
}
@@ -418,9 +413,7 @@ int lfs_emubd_erase(const struct lfs_config *cfg, lfs_block_t block) {
return err;
}
ssize_t res2 = write(bd->disk->fd,
bd->disk->scratch,
cfg->block_size);
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);
+2 -4
View File
@@ -67,9 +67,8 @@ typedef int64_t lfs_emubd_ssleep_t;
// emubd config, this is required for testing
struct lfs_emubd_config {
// 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.
// 8-bit erase value to use for simulating erases. -1 simulates a noop
// erase, which is faster than simulating a fixed erase value.
int32_t erase_value;
// Number of erase cycles before a block becomes "bad". The exact behavior
@@ -127,7 +126,6 @@ typedef struct lfs_emubd_block {
typedef struct lfs_emubd_disk {
uint32_t rc;
int fd;
uint8_t *scratch;
} lfs_emubd_disk_t;
// emubd state