Readded support for mirror writes to a file in testbd

Before this was available implicitly by supporting both rambd and filebd
as backends, but now that testbd is a bit more complicated and no longer
maps directly to a block-device, this needs to be explicitly supported.
This commit is contained in:
Christopher Haster
2022-08-23 14:48:29 -05:00
parent 4689678208
commit 3f4f85986e
3 changed files with 95 additions and 50 deletions

View File

@@ -6,9 +6,17 @@
* Copyright (c) 2017, Arm Limited. All rights reserved. * Copyright (c) 2017, Arm Limited. All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause * SPDX-License-Identifier: BSD-3-Clause
*/ */
#include "bd/lfs_testbd.h" #include "bd/lfs_testbd.h"
#include <stdlib.h> #include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#ifdef _WIN32
#include <windows.h>
#endif
// access to lazily-allocated/copy-on-write blocks // access to lazily-allocated/copy-on-write blocks
@@ -116,10 +124,41 @@ int lfs_testbd_createcfg(const struct lfs_config *cfg, const char *path,
// setup testing things // setup testing things
bd->power_cycles = bd->cfg->power_cycles; bd->power_cycles = bd->cfg->power_cycles;
bd->disk_fd = -1;
bd->disk_scratch_block = NULL;
bd->branches = NULL; bd->branches = NULL;
bd->branch_capacity = 0; bd->branch_capacity = 0;
bd->branch_count = 0; bd->branch_count = 0;
if (bd->cfg->disk_path) {
#ifdef _WIN32
bd->disk_fd = open(bd->cfg->disk_path,
O_RDWR | O_CREAT | O_BINARY, 0666);
#else
bd->disk_fd = open(bd->cfg->disk_path,
O_RDWR | O_CREAT, 0666);
#endif
if (bd->disk_fd < 0) {
int err = -errno;
LFS_TESTBD_TRACE("lfs_testbd_create -> %d", err);
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_block = malloc(cfg->block_size);
if (!bd->disk_scratch_block) {
LFS_TESTBD_TRACE("lfs_testbd_createcfg -> %d", LFS_ERR_NOMEM);
return LFS_ERR_NOMEM;
}
memset(bd->disk_scratch_block,
bd->cfg->erase_value,
cfg->block_size);
}
}
LFS_TESTBD_TRACE("lfs_testbd_createcfg -> %d", 0); LFS_TESTBD_TRACE("lfs_testbd_createcfg -> %d", 0);
return 0; return 0;
} }
@@ -154,54 +193,17 @@ int lfs_testbd_destroy(const struct lfs_config *cfg) {
free(bd->blocks); free(bd->blocks);
free(bd->branches); free(bd->branches);
if (bd->disk_fd >= 0) {
close(bd->disk_fd);
free(bd->disk_scratch_block);
}
LFS_TESTBD_TRACE("lfs_testbd_destroy -> %d", 0); LFS_TESTBD_TRACE("lfs_testbd_destroy -> %d", 0);
return 0; return 0;
} }
///// Internal mapping to block devices ///
//static int lfs_testbd_rawread(const struct lfs_config *cfg, lfs_block_t block,
// lfs_off_t off, void *buffer, lfs_size_t size) {
// lfs_testbd_t *bd = cfg->context;
// if (bd->persist) {
// return lfs_filebd_read(cfg, block, off, buffer, size);
// } else {
// return lfs_rambd_read(cfg, block, off, buffer, size);
// }
//}
//
//static int lfs_testbd_rawprog(const struct lfs_config *cfg, lfs_block_t block,
// lfs_off_t off, const void *buffer, lfs_size_t size) {
// lfs_testbd_t *bd = cfg->context;
// if (bd->persist) {
// return lfs_filebd_prog(cfg, block, off, buffer, size);
// } else {
// return lfs_rambd_prog(cfg, block, off, buffer, size);
// }
//}
//
//static int lfs_testbd_rawerase(const struct lfs_config *cfg,
// lfs_block_t block) {
// lfs_testbd_t *bd = cfg->context;
// if (bd->persist) {
// return lfs_filebd_erase(cfg, block);
// } else {
// return lfs_rambd_erase(cfg, block);
// }
//}
//
//static int lfs_testbd_rawsync(const struct lfs_config *cfg) {
// lfs_testbd_t *bd = cfg->context;
// if (bd->persist) {
// return lfs_filebd_sync(cfg);
// } else {
// return lfs_rambd_sync(cfg);
// }
//}
// block device API // block device API
int lfs_testbd_read(const struct lfs_config *cfg, lfs_block_t block, int lfs_testbd_read(const struct lfs_config *cfg, lfs_block_t block,
@@ -285,6 +287,25 @@ int lfs_testbd_prog(const struct lfs_config *cfg, lfs_block_t block,
// prog data // prog data
memcpy(&b->data[off], buffer, size); memcpy(&b->data[off], buffer, size);
// mirror to disk file?
if (bd->disk_fd >= 0) {
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_TESTBD_TRACE("lfs_testbd_prog -> %d", err);
return err;
}
ssize_t res2 = write(bd->disk_fd, buffer, size);
if (res2 < 0) {
int err = -errno;
LFS_TESTBD_TRACE("lfs_testbd_prog -> %d", err);
return err;
}
}
// lose power? // lose power?
if (bd->power_cycles > 0) { if (bd->power_cycles > 0) {
bd->power_cycles -= 1; bd->power_cycles -= 1;
@@ -342,6 +363,27 @@ int lfs_testbd_erase(const struct lfs_config *cfg, lfs_block_t block) {
// emulate an erase value? // emulate an erase value?
if (bd->cfg->erase_value != -1) { if (bd->cfg->erase_value != -1) {
memset(b->data, bd->cfg->erase_value, cfg->block_size); memset(b->data, bd->cfg->erase_value, cfg->block_size);
// mirror to disk file?
if (bd->disk_fd >= 0) {
off_t res1 = lseek(bd->disk_fd,
(off_t)block*cfg->block_size,
SEEK_SET);
if (res1 < 0) {
int err = -errno;
LFS_TESTBD_TRACE("lfs_testbd_erase -> %d", err);
return err;
}
ssize_t res2 = write(bd->disk_fd,
bd->disk_scratch_block,
cfg->block_size);
if (res2 < 0) {
int err = -errno;
LFS_TESTBD_TRACE("lfs_testbd_erase -> %d", err);
return err;
}
}
} }
// lose power? // lose power?

View File

@@ -90,14 +90,9 @@ struct lfs_testbd_config {
// heavy memory usage! // heavy memory usage!
bool track_branches; bool track_branches;
// // Optional buffer for RAM block device. // Path to file to use as a mirror of the disk. This provides a way to view
// void *buffer; // the current state of the block device.
// const char *disk_path;
// // Optional buffer for wear.
// void *wear_buffer;
//
// // Optional buffer for scratch memory, needed when erase_value != -1.
// void *scratch_buffer;
}; };
// A reference counted block // A reference counted block
@@ -112,7 +107,11 @@ typedef struct lfs_testbd_block {
typedef struct lfs_testbd { typedef struct lfs_testbd {
// array of copy-on-write blocks // array of copy-on-write blocks
lfs_testbd_block_t **blocks; lfs_testbd_block_t **blocks;
// some other test state
uint32_t power_cycles; uint32_t power_cycles;
int disk_fd;
uint8_t *disk_scratch_block;
// array of tracked branches // array of tracked branches
struct lfs_testbd *branches; struct lfs_testbd *branches;

View File

@@ -610,6 +610,7 @@ static void run_powerloss_none(
.erase_value = ERASE_VALUE, .erase_value = ERASE_VALUE,
.erase_cycles = ERASE_CYCLES, .erase_cycles = ERASE_CYCLES,
.badblock_behavior = BADBLOCK_BEHAVIOR, .badblock_behavior = BADBLOCK_BEHAVIOR,
.disk_path = test_disk,
}; };
int err = lfs_testbd_createcfg(&cfg, test_disk, &bdcfg); int err = lfs_testbd_createcfg(&cfg, test_disk, &bdcfg);
@@ -672,6 +673,7 @@ static void run_powerloss_linear(
.erase_value = ERASE_VALUE, .erase_value = ERASE_VALUE,
.erase_cycles = ERASE_CYCLES, .erase_cycles = ERASE_CYCLES,
.badblock_behavior = BADBLOCK_BEHAVIOR, .badblock_behavior = BADBLOCK_BEHAVIOR,
.disk_path = test_disk,
.power_cycles = i, .power_cycles = i,
.powerloss_behavior = POWERLOSS_BEHAVIOR, .powerloss_behavior = POWERLOSS_BEHAVIOR,
.powerloss_cb = powerloss_longjmp, .powerloss_cb = powerloss_longjmp,
@@ -748,6 +750,7 @@ static void run_powerloss_exponential(
.erase_value = ERASE_VALUE, .erase_value = ERASE_VALUE,
.erase_cycles = ERASE_CYCLES, .erase_cycles = ERASE_CYCLES,
.badblock_behavior = BADBLOCK_BEHAVIOR, .badblock_behavior = BADBLOCK_BEHAVIOR,
.disk_path = test_disk,
.power_cycles = i, .power_cycles = i,
.powerloss_behavior = POWERLOSS_BEHAVIOR, .powerloss_behavior = POWERLOSS_BEHAVIOR,
.powerloss_cb = powerloss_longjmp, .powerloss_cb = powerloss_longjmp,
@@ -822,6 +825,7 @@ static void run_powerloss_cycles(
.erase_value = ERASE_VALUE, .erase_value = ERASE_VALUE,
.erase_cycles = ERASE_CYCLES, .erase_cycles = ERASE_CYCLES,
.badblock_behavior = BADBLOCK_BEHAVIOR, .badblock_behavior = BADBLOCK_BEHAVIOR,
.disk_path = test_disk,
.power_cycles = (i < cycle_count) ? cycles[i] : 0, .power_cycles = (i < cycle_count) ? cycles[i] : 0,
.powerloss_behavior = POWERLOSS_BEHAVIOR, .powerloss_behavior = POWERLOSS_BEHAVIOR,
.powerloss_cb = powerloss_longjmp, .powerloss_cb = powerloss_longjmp,