diff --git a/bd/lfs_filebd.c b/bd/lfs_filebd.c index 98e5abc8..3040735b 100644 --- a/bd/lfs_filebd.c +++ b/bd/lfs_filebd.c @@ -15,39 +15,6 @@ #include #endif -int lfs_filebd_createcfg(const struct lfs_config *cfg, const char *path, - const struct lfs_filebd_config *bdcfg) { - LFS_FILEBD_TRACE("lfs_filebd_createcfg(%p {.context=%p, " - ".read=%p, .prog=%p, .erase=%p, .sync=%p, " - ".read_size=%"PRIu32", .prog_size=%"PRIu32", " - ".block_size=%"PRIu32", .block_count=%"PRIu32"}, " - "\"%s\", " - "%p {.erase_value=%"PRId32"})", - (void*)cfg, cfg->context, - (void*)(uintptr_t)cfg->read, (void*)(uintptr_t)cfg->prog, - (void*)(uintptr_t)cfg->erase, (void*)(uintptr_t)cfg->sync, - cfg->read_size, cfg->prog_size, cfg->block_size, cfg->block_count, - path, (void*)bdcfg, bdcfg->erase_value); - lfs_filebd_t *bd = cfg->context; - bd->cfg = bdcfg; - - // open file - #ifdef _WIN32 - bd->fd = open(path, O_RDWR | O_CREAT | O_BINARY, 0666); - #else - bd->fd = open(path, O_RDWR | O_CREAT, 0666); - #endif - - if (bd->fd < 0) { - int err = -errno; - LFS_FILEBD_TRACE("lfs_filebd_createcfg -> %d", err); - return err; - } - - LFS_FILEBD_TRACE("lfs_filebd_createcfg -> %d", 0); - return 0; -} - int lfs_filebd_create(const struct lfs_config *cfg, const char *path) { LFS_FILEBD_TRACE("lfs_filebd_create(%p {.context=%p, " ".read=%p, .prog=%p, .erase=%p, .sync=%p, " @@ -58,11 +25,24 @@ int lfs_filebd_create(const struct lfs_config *cfg, const char *path) { (void*)(uintptr_t)cfg->read, (void*)(uintptr_t)cfg->prog, (void*)(uintptr_t)cfg->erase, (void*)(uintptr_t)cfg->sync, cfg->read_size, cfg->prog_size, cfg->block_size, cfg->block_count, - path); - static const struct lfs_filebd_config defaults = {.erase_value=-1}; - int err = lfs_filebd_createcfg(cfg, path, &defaults); - LFS_FILEBD_TRACE("lfs_filebd_create -> %d", err); - return err; + path, (void*)bdcfg, bdcfg->erase_value); + lfs_filebd_t *bd = cfg->context; + + // open file + #ifdef _WIN32 + bd->fd = open(path, O_RDWR | O_CREAT | O_BINARY, 0666); + #else + bd->fd = open(path, O_RDWR | O_CREAT, 0666); + #endif + + if (bd->fd < 0) { + int err = -errno; + LFS_FILEBD_TRACE("lfs_filebd_create -> %d", err); + return err; + } + + LFS_FILEBD_TRACE("lfs_filebd_create -> %d", 0); + return 0; } int lfs_filebd_destroy(const struct lfs_config *cfg) { @@ -86,14 +66,13 @@ int lfs_filebd_read(const struct lfs_config *cfg, lfs_block_t block, lfs_filebd_t *bd = cfg->context; // check if read is valid + LFS_ASSERT(block < cfg->block_count); LFS_ASSERT(off % cfg->read_size == 0); LFS_ASSERT(size % cfg->read_size == 0); - LFS_ASSERT(block < cfg->block_count); + LFS_ASSERT(off+size <= cfg->block_size); // zero for reproducibility (in case file is truncated) - if (bd->cfg->erase_value != -1) { - memset(buffer, bd->cfg->erase_value, size); - } + memset(buffer, 0, size); // read off_t res1 = lseek(bd->fd, @@ -122,32 +101,10 @@ int lfs_filebd_prog(const struct lfs_config *cfg, lfs_block_t block, lfs_filebd_t *bd = cfg->context; // check if write is valid + LFS_ASSERT(block < cfg->block_count); LFS_ASSERT(off % cfg->prog_size == 0); LFS_ASSERT(size % cfg->prog_size == 0); - LFS_ASSERT(block < cfg->block_count); - - // check that data was erased? only needed for testing - if (bd->cfg->erase_value != -1) { - off_t res1 = lseek(bd->fd, - (off_t)block*cfg->block_size + (off_t)off, SEEK_SET); - if (res1 < 0) { - int err = -errno; - LFS_FILEBD_TRACE("lfs_filebd_prog -> %d", err); - return err; - } - - for (lfs_off_t i = 0; i < size; i++) { - uint8_t c; - ssize_t res2 = read(bd->fd, &c, 1); - if (res2 < 0) { - int err = -errno; - LFS_FILEBD_TRACE("lfs_filebd_prog -> %d", err); - return err; - } - - LFS_ASSERT(c == bd->cfg->erase_value); - } - } + LFS_ASSERT(off+size <= cfg->block_size); // program data off_t res1 = lseek(bd->fd, @@ -171,29 +128,12 @@ int lfs_filebd_prog(const struct lfs_config *cfg, lfs_block_t block, int lfs_filebd_erase(const struct lfs_config *cfg, lfs_block_t block) { LFS_FILEBD_TRACE("lfs_filebd_erase(%p, 0x%"PRIx32")", (void*)cfg, block); - lfs_filebd_t *bd = cfg->context; // check if erase is valid LFS_ASSERT(block < cfg->block_count); - // erase, only needed for testing - if (bd->cfg->erase_value != -1) { - off_t res1 = lseek(bd->fd, (off_t)block*cfg->block_size, SEEK_SET); - if (res1 < 0) { - int err = -errno; - LFS_FILEBD_TRACE("lfs_filebd_erase -> %d", err); - return err; - } - - for (lfs_off_t i = 0; i < cfg->block_size; i++) { - ssize_t res2 = write(bd->fd, &(uint8_t){bd->cfg->erase_value}, 1); - if (res2 < 0) { - int err = -errno; - LFS_FILEBD_TRACE("lfs_filebd_erase -> %d", err); - return err; - } - } - } + // erase is a noop + (void)block; LFS_FILEBD_TRACE("lfs_filebd_erase -> %d", 0); return 0; @@ -201,6 +141,7 @@ int lfs_filebd_erase(const struct lfs_config *cfg, lfs_block_t block) { int lfs_filebd_sync(const struct lfs_config *cfg) { LFS_FILEBD_TRACE("lfs_filebd_sync(%p)", (void*)cfg); + // file sync lfs_filebd_t *bd = cfg->context; #ifdef _WIN32 diff --git a/bd/lfs_filebd.h b/bd/lfs_filebd.h index 0ed1909a..0f24996a 100644 --- a/bd/lfs_filebd.h +++ b/bd/lfs_filebd.h @@ -26,25 +26,14 @@ extern "C" #endif #endif -// filebd config (optional) -struct lfs_filebd_config { - // 8-bit erase value to use for simulating erases. -1 does not simulate - // erases, which can speed up testing by avoiding all the extra block-device - // operations to store the erase value. - int32_t erase_value; -}; - // filebd state typedef struct lfs_filebd { int fd; - const struct lfs_filebd_config *cfg; } lfs_filebd_t; // Create a file block device using the geometry in lfs_config int lfs_filebd_create(const struct lfs_config *cfg, const char *path); -int lfs_filebd_createcfg(const struct lfs_config *cfg, const char *path, - const struct lfs_filebd_config *bdcfg); // Clean up memory associated with block device int lfs_filebd_destroy(const struct lfs_config *cfg); diff --git a/bd/lfs_rambd.c b/bd/lfs_rambd.c index 39bb8150..cbdd7d0f 100644 --- a/bd/lfs_rambd.c +++ b/bd/lfs_rambd.c @@ -13,12 +13,12 @@ int lfs_rambd_createcfg(const struct lfs_config *cfg, ".read=%p, .prog=%p, .erase=%p, .sync=%p, " ".read_size=%"PRIu32", .prog_size=%"PRIu32", " ".block_size=%"PRIu32", .block_count=%"PRIu32"}, " - "%p {.erase_value=%"PRId32", .buffer=%p})", + "%p {.buffer=%p})", (void*)cfg, cfg->context, (void*)(uintptr_t)cfg->read, (void*)(uintptr_t)cfg->prog, (void*)(uintptr_t)cfg->erase, (void*)(uintptr_t)cfg->sync, cfg->read_size, cfg->prog_size, cfg->block_size, cfg->block_count, - (void*)bdcfg, bdcfg->erase_value, bdcfg->buffer); + (void*)bdcfg, bdcfg->buffer); lfs_rambd_t *bd = cfg->context; bd->cfg = bdcfg; @@ -33,13 +33,8 @@ int lfs_rambd_createcfg(const struct lfs_config *cfg, } } - // zero for reproducibility? - if (bd->cfg->erase_value != -1) { - memset(bd->buffer, bd->cfg->erase_value, - cfg->block_size * cfg->block_count); - } else { - memset(bd->buffer, 0, cfg->block_size * cfg->block_count); - } + // zero for reproducibility + memset(bd->buffer, 0, cfg->block_size * cfg->block_count); LFS_RAMBD_TRACE("lfs_rambd_createcfg -> %d", 0); return 0; @@ -54,7 +49,7 @@ int lfs_rambd_create(const struct lfs_config *cfg) { (void*)(uintptr_t)cfg->read, (void*)(uintptr_t)cfg->prog, (void*)(uintptr_t)cfg->erase, (void*)(uintptr_t)cfg->sync, cfg->read_size, cfg->prog_size, cfg->block_size, cfg->block_count); - static const struct lfs_rambd_config defaults = {.erase_value=-1}; + static const struct lfs_rambd_config defaults = {0}; int err = lfs_rambd_createcfg(cfg, &defaults); LFS_RAMBD_TRACE("lfs_rambd_create -> %d", err); return err; @@ -79,9 +74,10 @@ int lfs_rambd_read(const struct lfs_config *cfg, lfs_block_t block, lfs_rambd_t *bd = cfg->context; // check if read is valid + LFS_ASSERT(block < cfg->block_count); LFS_ASSERT(off % cfg->read_size == 0); LFS_ASSERT(size % cfg->read_size == 0); - LFS_ASSERT(block < cfg->block_count); + LFS_ASSERT(off+size <= cfg->block_size); // read data memcpy(buffer, &bd->buffer[block*cfg->block_size + off], size); @@ -98,17 +94,10 @@ int lfs_rambd_prog(const struct lfs_config *cfg, lfs_block_t block, lfs_rambd_t *bd = cfg->context; // check if write is valid + LFS_ASSERT(block < cfg->block_count); LFS_ASSERT(off % cfg->prog_size == 0); LFS_ASSERT(size % cfg->prog_size == 0); - LFS_ASSERT(block < cfg->block_count); - - // check that data was erased? only needed for testing - if (bd->cfg->erase_value != -1) { - for (lfs_off_t i = 0; i < size; i++) { - LFS_ASSERT(bd->buffer[block*cfg->block_size + off + i] == - bd->cfg->erase_value); - } - } + LFS_ASSERT(off+size <= cfg->block_size); // program data memcpy(&bd->buffer[block*cfg->block_size + off], buffer, size); @@ -119,16 +108,12 @@ int lfs_rambd_prog(const struct lfs_config *cfg, lfs_block_t block, int lfs_rambd_erase(const struct lfs_config *cfg, lfs_block_t block) { LFS_RAMBD_TRACE("lfs_rambd_erase(%p, 0x%"PRIx32")", (void*)cfg, block); - lfs_rambd_t *bd = cfg->context; // check if erase is valid LFS_ASSERT(block < cfg->block_count); - // erase, only needed for testing - if (bd->cfg->erase_value != -1) { - memset(&bd->buffer[block*cfg->block_size], - bd->cfg->erase_value, cfg->block_size); - } + // erase is a noop + (void)block; LFS_RAMBD_TRACE("lfs_rambd_erase -> %d", 0); return 0; @@ -136,8 +121,10 @@ int lfs_rambd_erase(const struct lfs_config *cfg, lfs_block_t block) { int lfs_rambd_sync(const struct lfs_config *cfg) { LFS_RAMBD_TRACE("lfs_rambd_sync(%p)", (void*)cfg); - // sync does nothing because we aren't backed by anything real + + // sync is a noop (void)cfg; + LFS_RAMBD_TRACE("lfs_rambd_sync -> %d", 0); return 0; } diff --git a/bd/lfs_rambd.h b/bd/lfs_rambd.h index b7629a9b..34246802 100644 --- a/bd/lfs_rambd.h +++ b/bd/lfs_rambd.h @@ -28,10 +28,6 @@ extern "C" // rambd config (optional) struct lfs_rambd_config { - // 8-bit erase value to simulate erasing with. -1 indicates no erase - // occurs, which is still a valid block device - int32_t erase_value; - // Optional statically allocated buffer for the block device. void *buffer; }; diff --git a/bd/lfs_testbd.c b/bd/lfs_testbd.c index 1f0877d4..e9a96a96 100644 --- a/bd/lfs_testbd.c +++ b/bd/lfs_testbd.c @@ -35,6 +35,20 @@ int lfs_testbd_createcfg(const struct lfs_config *cfg, const char *path, bd->persist = path; bd->power_cycles = bd->cfg->power_cycles; + // create scratch block if we need it (for emulating erase values) + if (bd->cfg->erase_value != -1) { + if (bd->cfg->scratch_buffer) { + bd->scratch = bd->cfg->scratch_buffer; + } else { + bd->scratch = lfs_malloc(cfg->block_size); + if (!bd->scratch) { + LFS_TESTBD_TRACE("lfs_testbd_createcfg -> %d", LFS_ERR_NOMEM); + return LFS_ERR_NOMEM; + } + } + } + + // create map of wear if (bd->cfg->erase_cycles) { if (bd->cfg->wear_buffer) { bd->wear = bd->cfg->wear_buffer; @@ -51,15 +65,11 @@ int lfs_testbd_createcfg(const struct lfs_config *cfg, const char *path, // create underlying block device if (bd->persist) { - bd->u.file.cfg = (struct lfs_filebd_config){ - .erase_value = bd->cfg->erase_value, - }; - int err = lfs_filebd_createcfg(cfg, path, &bd->u.file.cfg); + int err = lfs_filebd_create(cfg, path); LFS_TESTBD_TRACE("lfs_testbd_createcfg -> %d", err); return err; } else { bd->u.ram.cfg = (struct lfs_rambd_config){ - .erase_value = bd->cfg->erase_value, .buffer = bd->cfg->buffer, }; int err = lfs_rambd_createcfg(cfg, &bd->u.ram.cfg); @@ -88,6 +98,10 @@ int lfs_testbd_create(const struct lfs_config *cfg, const char *path) { int lfs_testbd_destroy(const struct lfs_config *cfg) { LFS_TESTBD_TRACE("lfs_testbd_destroy(%p)", (void*)cfg); lfs_testbd_t *bd = cfg->context; + + if (bd->cfg->erase_value != -1 && !bd->cfg->scratch_buffer) { + lfs_free(bd->scratch); + } if (bd->cfg->erase_cycles && !bd->cfg->wear_buffer) { lfs_free(bd->wear); } @@ -152,9 +166,10 @@ int lfs_testbd_read(const struct lfs_config *cfg, lfs_block_t block, lfs_testbd_t *bd = cfg->context; // check if read is valid + LFS_ASSERT(block < cfg->block_count); LFS_ASSERT(off % cfg->read_size == 0); LFS_ASSERT(size % cfg->read_size == 0); - LFS_ASSERT(block < cfg->block_count); + LFS_ASSERT(off+size <= cfg->block_size); // block bad? if (bd->cfg->erase_cycles && bd->wear[block] >= bd->cfg->erase_cycles && @@ -177,9 +192,10 @@ int lfs_testbd_prog(const struct lfs_config *cfg, lfs_block_t block, lfs_testbd_t *bd = cfg->context; // check if write is valid + LFS_ASSERT(block < cfg->block_count); LFS_ASSERT(off % cfg->prog_size == 0); LFS_ASSERT(size % cfg->prog_size == 0); - LFS_ASSERT(block < cfg->block_count); + LFS_ASSERT(off+size <= cfg->block_size); // block bad? if (bd->cfg->erase_cycles && bd->wear[block] >= bd->cfg->erase_cycles) { @@ -196,11 +212,41 @@ int lfs_testbd_prog(const struct lfs_config *cfg, lfs_block_t block, } } - // prog - int err = lfs_testbd_rawprog(cfg, block, off, buffer, size); - if (err) { - LFS_TESTBD_TRACE("lfs_testbd_prog -> %d", err); - return err; + // emulate an erase value? + if (bd->cfg->erase_value != -1) { + int err = lfs_testbd_rawread(cfg, block, 0, + bd->scratch, cfg->block_size); + if (err) { + LFS_TESTBD_TRACE("lfs_testbd_prog -> %d", err); + return err; + } + + // assert that program block was erased + for (lfs_off_t i = 0; i < size; i++) { + LFS_ASSERT(bd->scratch[off+i] == bd->cfg->erase_value); + } + + memcpy(&bd->scratch[off], buffer, size); + + err = lfs_testbd_rawerase(cfg, block); + if (err) { + LFS_TESTBD_TRACE("lfs_testbd_prog -> %d", err); + return err; + } + + err = lfs_testbd_rawprog(cfg, block, 0, + bd->scratch, cfg->block_size); + if (err) { + LFS_TESTBD_TRACE("lfs_testbd_prog -> %d", err); + return err; + } + } else { + // prog + int err = lfs_testbd_rawprog(cfg, block, off, buffer, size); + if (err) { + LFS_TESTBD_TRACE("lfs_testbd_prog -> %d", err); + return err; + } } // lose power? @@ -243,11 +289,29 @@ int lfs_testbd_erase(const struct lfs_config *cfg, lfs_block_t block) { } } - // erase - int err = lfs_testbd_rawerase(cfg, block); - if (err) { - LFS_TESTBD_TRACE("lfs_testbd_erase -> %d", err); - return err; + // emulate an erase value? + if (bd->cfg->erase_value != -1) { + memset(bd->scratch, bd->cfg->erase_value, cfg->block_size); + + int err = lfs_testbd_rawerase(cfg, block); + if (err) { + LFS_TESTBD_TRACE("lfs_testbd_erase -> %d", err); + return err; + } + + err = lfs_testbd_rawprog(cfg, block, 0, + bd->scratch, cfg->block_size); + if (err) { + LFS_TESTBD_TRACE("lfs_testbd_erase -> %d", err); + return err; + } + } else { + // erase + int err = lfs_testbd_rawerase(cfg, block); + if (err) { + LFS_TESTBD_TRACE("lfs_testbd_erase -> %d", err); + return err; + } } // lose power? diff --git a/bd/lfs_testbd.h b/bd/lfs_testbd.h index 06794e72..3eafb8f4 100644 --- a/bd/lfs_testbd.h +++ b/bd/lfs_testbd.h @@ -50,7 +50,7 @@ typedef int32_t lfs_testbd_swear_t; // testbd config, this is required for testing struct lfs_testbd_config { // 8-bit erase value to use for simulating erases. -1 does not simulate - // erases, which can speed up testing by avoiding all the extra block-device + // erases, which can speed up testing by avoiding the extra block-device // operations to store the erase value. int32_t erase_value; @@ -68,8 +68,11 @@ struct lfs_testbd_config { // Optional buffer for RAM block device. void *buffer; - // Optional buffer for wear + // Optional buffer for wear. void *wear_buffer; + + // Optional buffer for scratch memory, needed when erase_value != -1. + void *scratch_buffer; }; // testbd state @@ -77,7 +80,6 @@ typedef struct lfs_testbd { union { struct { lfs_filebd_t bd; - struct lfs_filebd_config cfg; } file; struct { lfs_rambd_t bd; @@ -88,6 +90,7 @@ typedef struct lfs_testbd { bool persist; uint32_t power_cycles; lfs_testbd_wear_t *wear; + uint8_t *scratch; const struct lfs_testbd_config *cfg; } lfs_testbd_t;