diff --git a/bd/lfs3_emubd.c b/bd/lfs3_emubd.c index 8a097827..b627c163 100644 --- a/bd/lfs3_emubd.c +++ b/bd/lfs3_emubd.c @@ -1,6 +1,10 @@ /* - * Emulating block device, wraps filebd and rambd while providing a bunch - * of hooks for testing littlefs in various conditions. + * emubd - High-level emulating block device with many bells and + * whistles for testing powerloss, wear, etc. + * + * Note emubd always backs the block device in RAM. Consider using + * kiwibd if you need a block device larger than the available RAM on + * the system. * * Copyright (c) 2022, The littlefs authors. * Copyright (c) 2017, Arm Limited. All rights reserved. @@ -1030,7 +1034,7 @@ int lfs3_emubd_sync(const struct lfs3_cfg *cfg) { } -/// Additional extended API for driving test features /// +/// Additional emubd features for testing /// void lfs3_emubd_seed(const struct lfs3_cfg *cfg, uint32_t seed) { LFS3_EMUBD_TRACE("lfs3_emubd_seed(%p, 0x%08"PRIx32")", diff --git a/bd/lfs3_emubd.h b/bd/lfs3_emubd.h index e3050deb..f9783948 100644 --- a/bd/lfs3_emubd.h +++ b/bd/lfs3_emubd.h @@ -1,6 +1,10 @@ /* - * Emulating block device, wraps filebd and rambd while providing a bunch - * of hooks for testing littlefs in various conditions. + * emubd - High-level emulating block device with many bells and + * whistles for testing powerloss, wear, etc. + * + * Note emubd always backs the block device in RAM. Consider using + * kiwibd if you need a block device larger than the available RAM on + * the system. * * Copyright (c) 2022, The littlefs authors. * Copyright (c) 2017, Arm Limited. All rights reserved. @@ -11,8 +15,6 @@ #include "lfs3.h" #include "lfs3_util.h" -#include "bd/lfs3_rambd.h" -#include "bd/lfs3_filebd.h" // Block device specific tracing @@ -99,7 +101,8 @@ struct lfs3_emubd_cfg { 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. + // the current state of the block device, but does not eliminate the RAM + // requirement. const char *disk_path; // Artificial delay in nanoseconds, there is no purpose for this other @@ -157,8 +160,11 @@ typedef struct lfs3_emubd { // Create an emulating block device using the geometry in lfs3_cfg // -// Note that filebd is used if a path is provided, if path is NULL -// emubd will use rambd which can be much faster. +// If disk_path is provided, emubd will mirror the block device in the +// file. Note this is a write-only mirror intended for introspection, +// and does not eliminate the RAM requirement. +// +// TODO wait, why do we have both disk_path and path here? int lfs3_emubd_create(const struct lfs3_cfg *cfg, const char *path); int lfs3_emubd_createcfg(const struct lfs3_cfg *cfg, const char *path, const struct lfs3_emubd_cfg *bdcfg); @@ -186,7 +192,7 @@ int lfs3_emubd_erase(const struct lfs3_cfg *cfg, lfs3_block_t block); int lfs3_emubd_sync(const struct lfs3_cfg *cfg); -/// Additional extended API for driving test features /// +/// Additional emubd features for testing /// // Set the current prng state void lfs3_emubd_seed(const struct lfs3_cfg *cfg, uint32_t seed); diff --git a/bd/lfs3_kiwibd.c b/bd/lfs3_kiwibd.c new file mode 100644 index 00000000..e2b84b95 --- /dev/null +++ b/bd/lfs3_kiwibd.c @@ -0,0 +1,559 @@ +/* + * kiwibd - A lightweight variant of emubd, useful for emulating large + * disks backed by a file or in RAM. + * + * Unlike emubd, file-backed disks are _not_ mirrored in RAM. kiwibd has + * fewer features than emubd, prioritizing speed for benchmarking. + * + * + */ + +#ifndef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE 199309L +#endif + +#include "bd/lfs3_kiwibd.h" + +#include +#include +#include +#include +#include + + + +// low-level flash memory emulation + +// read data +static inline void lfs3_kiwibd_memread(const struct lfs3_cfg *cfg, + void *restrict dst, const void *restrict src, size_t size) { + (void)cfg; + memcpy(dst, src, size); +} + +static inline void lfs3_kiwibd_memprog(const struct lfs3_cfg *cfg, + void *restrict dst, const void *restrict src, size_t size) { + lfs3_kiwibd_t *bd = cfg->context; + // emulating nor-masking? + if (bd->cfg->erase_value == -2) { + uint8_t *dst_ = dst; + const uint8_t *src_ = src; + for (size_t i = 0; i < size; i++) { + dst_[i] &= src_[i]; + } + } else { + memcpy(dst, src, size); + } +} + +static inline void lfs3_kiwibd_memerase(const struct lfs3_cfg *cfg, + void *restrict dst, size_t size) { + lfs3_kiwibd_t *bd = cfg->context; + // emulating erase value? + if (bd->cfg->erase_value != -1) { + memset(dst, + (bd->cfg->erase_value >= 0) + ? bd->cfg->erase_value + : 0xff, + size); + } +} + +// this is slightly different from lfs3_kiwibd_memerase in that we use +// lfs3_kiwibd_memzero when we need to unconditionally zero memory +static inline void lfs3_kiwibd_memzero(const struct lfs3_cfg *cfg, + void *restrict dst, size_t size) { + lfs3_kiwibd_t *bd = cfg->context; + memset(dst, + (bd->cfg->erase_value == -1) ? 0 + : (bd->cfg->erase_value >= 0) ? bd->cfg->erase_value + : (bd->cfg->erase_value == -2) ? 0xff + : 0, + size); +} + + + +// kiwibd create/destroy + +int lfs3_kiwibd_createcfg(const struct lfs3_cfg *cfg, const char *path, + const struct lfs3_kiwibd_cfg *bdcfg) { + LFS3_KIWIBD_TRACE("lfs3_kiwibd_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", " + ".disk_path=\"%s\", " + ".buffer=%p, " + ".read_sleep=%"PRIu64", " + ".prog_sleep=%"PRIu64", " + ".erase_sleep=%"PRIu64"})", + (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, + bdcfg->disk_path, + bdcfg->buffer, + bdcfg->read_sleep, + bdcfg->prog_sleep, + bdcfg->erase_sleep); + lfs3_kiwibd_t *bd = cfg->context; + bd->cfg = bdcfg; + + // setup some initial state + bd->readed = 0; + bd->proged = 0; + bd->erased = 0; + if (bd->cfg->disk_path) { + bd->u.disk.fd = -1; + bd->u.disk.scratch = NULL; + } else { + bd->u.mem = NULL; + } + int err; + + // if we have a disk_path, try to open the backing file + if (bd->cfg->disk_path) { + bd->u.disk.fd = open(bd->cfg->disk_path, + O_RDWR | O_CREAT, 0666); + if (bd->u.disk.fd < 0) { + err = -errno; + goto failed; + } + + // allocate a scratch buffer to help with zeroing/masking/etc + bd->u.disk.scratch = malloc(cfg->block_size); + if (!bd->u.disk.scratch) { + err = LFS3_ERR_NOMEM; + goto failed; + } + + // zero for reproducibility + lfs3_kiwibd_memzero(cfg, bd->u.disk.scratch, cfg->block_size); + for (lfs3_block_t i = 0; i < cfg->block_count; i++) { + ssize_t res = write(bd->u.disk.fd, + bd->u.disk.scratch, + cfg->block_size); + if (res < 0) { + err = -errno; + goto failed; + } + } + + // otherwise, try to malloc a big memory array + } else { + bd->u.mem = malloc((size_t)cfg->block_size * cfg->block_count); + if (!bd->u.mem) { + err = LFS3_ERR_NOMEM; + goto failed; + } + + // zero for reproducibility + lfs3_kiwibd_memzero(cfg, bd->u.mem, + (size_t)cfg->block_size * cfg->block_count); + } + + LFS3_KIWIBD_TRACE("lfs3_kiwibd_createcfg -> %d", 0); + return 0; + +failed:; + LFS3_KIWIBD_TRACE("lfs3_kiwibd_createcfg -> %d", err); + // clean up memory + if (bd->cfg->disk_path) { + if (bd->u.disk.fd != -1) { + close(bd->u.disk.fd); + } + free(bd->u.disk.scratch); + } else { + free(bd->u.mem); + } + return err; +} + +int lfs3_kiwibd_create(const struct lfs3_cfg *cfg, const char *path) { + LFS3_KIWIBD_TRACE("lfs3_kiwibd_create(" + "%p {" + ".context=%p, " + ".read=%p, " + ".prog=%p, " + ".erase=%p, " + ".sync=%p, " + ".read_size=%"PRIu32", " + ".prog_size=%"PRIu32", " + ".block_size=%"PRIu32", " + ".block_count=%"PRIu32"}, " + "\"%s\")", + (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); + static const struct lfs3_kiwibd_cfg defaults = {.erase_value=-1}; + int err = lfs3_kiwibd_createcfg(cfg, path, &defaults); + LFS3_KIWIBD_TRACE("lfs3_kiwibd_create -> %d", err); + return err; +} + +int lfs3_kiwibd_destroy(const struct lfs3_cfg *cfg) { + LFS3_KIWIBD_TRACE("lfs3_kiwibd_destroy(%p)", (void*)cfg); + lfs3_kiwibd_t *bd = cfg->context; + + // clean up memory + if (bd->cfg->disk_path) { + close(bd->u.disk.fd); + free(bd->u.disk.scratch); + } else { + free(bd->u.mem); + } + + LFS3_KIWIBD_TRACE("lfs3_kiwibd_destroy -> %d", 0); + return 0; +} + + +// block device API + +int lfs3_kiwibd_read(const struct lfs3_cfg *cfg, lfs3_block_t block, + lfs3_off_t off, void *buffer, lfs3_size_t size) { + LFS3_KIWIBD_TRACE("lfs3_kiwibd_read(%p, " + "0x%"PRIx32", %"PRIu32", %p, %"PRIu32")", + (void*)cfg, block, off, buffer, size); + lfs3_kiwibd_t *bd = cfg->context; + + // check if read is valid + LFS3_ASSERT(block < cfg->block_count); + LFS3_ASSERT(off % cfg->read_size == 0); + LFS3_ASSERT(size % cfg->read_size == 0); + LFS3_ASSERT(off+size <= cfg->block_size); + + // read in file? + if (bd->cfg->disk_path) { + lfs3_kiwibd_memerase(cfg, + bd->u.disk.scratch, + cfg->block_size); + + off_t res = lseek(bd->u.disk.fd, + (off_t)block*cfg->block_size + (off_t)off, + SEEK_SET); + if (res < 0) { + int err = -errno; + LFS3_KIWIBD_TRACE("lfs3_kiwibd_read -> %d", err); + return err; + } + + ssize_t res_ = read(bd->u.disk.fd, buffer, size); + if (res_ < 0) { + int err = -errno; + LFS3_KIWIBD_TRACE("lfs3_kiwibd_read -> %d", err); + return err; + } + + // read in RAM? + } else { + lfs3_kiwibd_memread(cfg, + buffer, + &bd->u.mem[(size_t)block*cfg->block_size + (size_t)off], + size); + } + + // track reads + bd->readed += size; + if (bd->cfg->read_sleep) { + int err = nanosleep(&(struct timespec){ + .tv_sec=bd->cfg->read_sleep/1000000000, + .tv_nsec=bd->cfg->read_sleep%1000000000}, + NULL); + if (err) { + err = -errno; + LFS3_KIWIBD_TRACE("lfs3_kiwibd_read -> %d", err); + return err; + } + } + + LFS3_KIWIBD_TRACE("lfs3_kiwibd_read -> %d", 0); + return 0; +} + +int lfs3_kiwibd_prog(const struct lfs3_cfg *cfg, lfs3_block_t block, + lfs3_off_t off, const void *buffer, lfs3_size_t size) { + LFS3_KIWIBD_TRACE("lfs3_kiwibd_prog(%p, " + "0x%"PRIx32", %"PRIu32", %p, %"PRIu32")", + (void*)cfg, block, off, buffer, size); + lfs3_kiwibd_t *bd = cfg->context; + + // check if write is valid + LFS3_ASSERT(block < cfg->block_count); + LFS3_ASSERT(off % cfg->prog_size == 0); + LFS3_ASSERT(size % cfg->prog_size == 0); + LFS3_ASSERT(off+size <= cfg->block_size); + + // prog in file? + if (bd->cfg->disk_path) { + // were we erased properly? + if (bd->cfg->erase_value >= 0) { + off_t res = lseek(bd->u.disk.fd, + (off_t)block*cfg->block_size + (off_t)off, + SEEK_SET); + if (res < 0) { + int err = -errno; + LFS3_KIWIBD_TRACE("lfs3_kiwibd_prog -> %d", err); + return err; + } + + ssize_t res_ = read(bd->u.disk.fd, bd->u.disk.scratch, size); + if (res_ < 0) { + int err = -errno; + LFS3_KIWIBD_TRACE("lfs3_kiwibd_prog -> %d", err); + return err; + } + + for (lfs3_off_t i = 0; i < size; i++) { + LFS3_ASSERT(bd->u.disk.scratch[i] == bd->cfg->erase_value); + } + } + + // masking progs? + if (bd->cfg->erase_value == -2) { + off_t res = lseek(bd->u.disk.fd, + (off_t)block*cfg->block_size + (off_t)off, + SEEK_SET); + if (res < 0) { + int err = -errno; + LFS3_KIWIBD_TRACE("lfs3_kiwibd_prog -> %d", err); + return err; + } + + ssize_t res_ = read(bd->u.disk.fd, bd->u.disk.scratch, size); + if (res_ < 0) { + int err = -errno; + LFS3_KIWIBD_TRACE("lfs3_kiwibd_prog -> %d", err); + return err; + } + + lfs3_kiwibd_memprog(cfg, bd->u.disk.scratch, buffer, size); + + res = lseek(bd->u.disk.fd, + (off_t)block*cfg->block_size + (off_t)off, + SEEK_SET); + if (res < 0) { + int err = -errno; + LFS3_KIWIBD_TRACE("lfs3_kiwibd_prog -> %d", err); + return err; + } + + res_ = write(bd->u.disk.fd, bd->u.disk.scratch, size); + if (res_ < 0) { + int err = -errno; + LFS3_KIWIBD_TRACE("lfs3_kiwibd_prog -> %d", err); + return err; + } + + // normal progs? + } else { + off_t res = lseek(bd->u.disk.fd, + (off_t)block*cfg->block_size + (off_t)off, + SEEK_SET); + if (res < 0) { + int err = -errno; + LFS3_KIWIBD_TRACE("lfs3_kiwibd_prog -> %d", err); + return err; + } + + ssize_t res_ = write(bd->u.disk.fd, buffer, size); + if (res_ < 0) { + int err = -errno; + LFS3_KIWIBD_TRACE("lfs3_kiwibd_prog -> %d", err); + return err; + } + } + + // prog in RAM? + } else { + // were we erased properly? + if (bd->cfg->erase_value >= 0) { + for (lfs3_off_t i = 0; i < size; i++) { + LFS3_ASSERT( + bd->u.mem[(size_t)block*cfg->block_size + (size_t)off] + == bd->cfg->erase_value); + } + } + + lfs3_kiwibd_memprog(cfg, + &bd->u.mem[(size_t)block*cfg->block_size + (size_t)off], + buffer, + size); + } + + // 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; + LFS3_KIWIBD_TRACE("lfs3_kiwibd_prog -> %d", err); + return err; + } + } + + LFS3_KIWIBD_TRACE("lfs3_kiwibd_prog -> %d", 0); + return 0; +} + +int lfs3_kiwibd_erase(const struct lfs3_cfg *cfg, lfs3_block_t block) { + LFS3_KIWIBD_TRACE("lfs3_kiwibd_erase(%p, 0x%"PRIx32" (%"PRIu32"))", + (void*)cfg, block, cfg->block_size); + lfs3_kiwibd_t *bd = cfg->context; + + // check if erase is valid + LFS3_ASSERT(block < cfg->block_count); + + // emulate an erase value? + if (bd->cfg->erase_value != -1) { + // erase in file? + if (bd->cfg->disk_path) { + off_t res = lseek(bd->u.disk.fd, + (off_t)block*cfg->block_size, + SEEK_SET); + if (res < 0) { + int err = -errno; + LFS3_KIWIBD_TRACE("lfs3_kiwibd_erase -> %d", err); + return err; + } + + lfs3_kiwibd_memerase(cfg, + bd->u.disk.scratch, + cfg->block_size); + + ssize_t res_ = write(bd->u.disk.fd, + bd->u.disk.scratch, + cfg->block_size); + if (res_ < 0) { + int err = -errno; + LFS3_KIWIBD_TRACE("lfs3_kiwibd_erase -> %d", err); + return err; + } + + // erase in RAM? + } else { + lfs3_kiwibd_memerase(cfg, + &bd->u.mem[(size_t)block*cfg->block_size], + cfg->block_size); + } + } + +erased:; + // track erases + bd->erased += cfg->block_size; + if (bd->cfg->erase_sleep) { + int err = nanosleep(&(struct timespec){ + .tv_sec=bd->cfg->erase_sleep/1000000000, + .tv_nsec=bd->cfg->erase_sleep%1000000000}, + NULL); + if (err) { + err = -errno; + LFS3_KIWIBD_TRACE("lfs3_kiwibd_erase -> %d", err); + return err; + } + } + + LFS3_KIWIBD_TRACE("lfs3_kiwibd_erase -> %d", 0); + return 0; +} + +int lfs3_kiwibd_sync(const struct lfs3_cfg *cfg) { + LFS3_KIWIBD_TRACE("lfs3_kiwibd_sync(%p)", (void*)cfg); + + // in theory we could actually sync here, but if our goal is + // performance, why bother? + // + // filebd may be a better block device is your goal is actual + // storage + + // sync is a noop + (void)cfg; + + LFS3_KIWIBD_TRACE("lfs3_kiwibd_sync -> %d", 0); + return 0; +} + + +/// Additional kiwibd features /// + +lfs3_kiwibd_sio_t lfs3_kiwibd_readed(const struct lfs3_cfg *cfg) { + LFS3_KIWIBD_TRACE("lfs3_kiwibd_readed(%p)", (void*)cfg); + lfs3_kiwibd_t *bd = cfg->context; + LFS3_KIWIBD_TRACE("lfs3_kiwibd_readed -> %"PRIu64, bd->readed); + return bd->readed; +} + +lfs3_kiwibd_sio_t lfs3_kiwibd_proged(const struct lfs3_cfg *cfg) { + LFS3_KIWIBD_TRACE("lfs3_kiwibd_proged(%p)", (void*)cfg); + lfs3_kiwibd_t *bd = cfg->context; + LFS3_KIWIBD_TRACE("lfs3_kiwibd_proged -> %"PRIu64, bd->proged); + return bd->proged; +} + +lfs3_kiwibd_sio_t lfs3_kiwibd_erased(const struct lfs3_cfg *cfg) { + LFS3_KIWIBD_TRACE("lfs3_kiwibd_erased(%p)", (void*)cfg); + lfs3_kiwibd_t *bd = cfg->context; + LFS3_KIWIBD_TRACE("lfs3_kiwibd_erased -> %"PRIu64, bd->erased); + return bd->erased; +} + +int lfs3_kiwibd_setreaded(const struct lfs3_cfg *cfg, + lfs3_kiwibd_io_t readed) { + LFS3_KIWIBD_TRACE("lfs3_kiwibd_setreaded(%p, %"PRIu64")", + (void*)cfg, readed); + lfs3_kiwibd_t *bd = cfg->context; + bd->readed = readed; + LFS3_KIWIBD_TRACE("lfs3_kiwibd_setreaded -> %d", 0); + return 0; +} + +int lfs3_kiwibd_setproged(const struct lfs3_cfg *cfg, + lfs3_kiwibd_io_t proged) { + LFS3_KIWIBD_TRACE("lfs3_kiwibd_setproged(%p, %"PRIu64")", + (void*)cfg, proged); + lfs3_kiwibd_t *bd = cfg->context; + bd->proged = proged; + LFS3_KIWIBD_TRACE("lfs3_kiwibd_setproged -> %d", 0); + return 0; +} + +int lfs3_kiwibd_seterased(const struct lfs3_cfg *cfg, + lfs3_kiwibd_io_t erased) { + LFS3_KIWIBD_TRACE("lfs3_kiwibd_seterased(%p, %"PRIu64")", + (void*)cfg, erased); + lfs3_kiwibd_t *bd = cfg->context; + bd->erased = erased; + LFS3_KIWIBD_TRACE("lfs3_kiwibd_seterased -> %d", 0); + return 0; +} + diff --git a/bd/lfs3_kiwibd.h b/bd/lfs3_kiwibd.h new file mode 100644 index 00000000..2e182fa9 --- /dev/null +++ b/bd/lfs3_kiwibd.h @@ -0,0 +1,143 @@ +/* + * kiwibd - A lightweight variant of emubd, useful for emulating large + * disks backed by a file or in RAM. + * + * Unlike emubd, file-backed disks are _not_ mirrored in RAM. kiwibd has + * fewer features than emubd, prioritizing speed for benchmarking. + * + * + */ +#ifndef LFS3_KIWIBD_H +#define LFS3_KIWIBD_H + +#include "lfs3.h" +#include "lfs3_util.h" + + +// Block device specific tracing +#ifndef LFS3_KIWIBD_TRACE +#ifdef LFS3_KIWIBD_YES_TRACE +#define LFS3_KIWIBD_TRACE(...) LFS3_TRACE(__VA_ARGS__) +#else +#define LFS3_KIWIBD_TRACE(...) +#endif +#endif + +// Type for measuring read/program/erase operations +typedef uint64_t lfs3_kiwibd_io_t; +typedef int64_t lfs3_kiwibd_sio_t; + +// Type for delays in nanoseconds +typedef uint64_t lfs3_kiwibd_sleep_t; +typedef int64_t lfs3_kiwibd_ssleep_t; + +// kiwibd config, this is required for testing +struct lfs3_kiwibd_cfg { + // 8-bit erase value to use for simulating erases. -1 simulates a noop + // erase, which is faster than simulating a fixed erase value. -2 emulates + // nor-masking, which is useful for testing other filesystems (littlefs + // does _not_ rely on this!). + int32_t erase_value; + + // Path to file to back the block device. If provided kiwibd uses this + // instead of RAM, allowing emulation of block devices > available RAM. + const char *disk_path; + + // Optional statically allocated buffer for the block device. Ignored + // if disk_path is provided. + void *buffer; + + // Artificial delay in nanoseconds, there is no purpose for this other + // than slowing down the simulation. + lfs3_kiwibd_sleep_t read_sleep; + + // Artificial delay in nanoseconds, there is no purpose for this other + // than slowing down the simulation. + lfs3_kiwibd_sleep_t prog_sleep; + + // Artificial delay in nanoseconds, there is no purpose for this other + // than slowing down the simulation. + lfs3_kiwibd_sleep_t erase_sleep; +}; + +// kiwibd state +typedef struct lfs3_kiwibd { + // backing disk + union { + struct { + int fd; + uint8_t *scratch; + } disk; + uint8_t *mem; + } u; + + // amount read/progged/erased + lfs3_kiwibd_io_t readed; + lfs3_kiwibd_io_t proged; + lfs3_kiwibd_io_t erased; + + const struct lfs3_kiwibd_cfg *cfg; +} lfs3_kiwibd_t; + + +/// Block device API /// + +// Create a kiwibd using the geometry in lfs3_cfg +// +// If disk_path is provided, it will be used to back the kiwibd, +// otherwise kiwibd will try to use RAM. +// +// TODO wait, why do we have both disk_path and path here? +int lfs3_kiwibd_create(const struct lfs3_cfg *cfg, const char *path); +int lfs3_kiwibd_createcfg(const struct lfs3_cfg *cfg, const char *path, + const struct lfs3_kiwibd_cfg *bdcfg); + +// Clean up memory associated with block device +int lfs3_kiwibd_destroy(const struct lfs3_cfg *cfg); + +// Read a block +int lfs3_kiwibd_read(const struct lfs3_cfg *cfg, lfs3_block_t block, + lfs3_off_t off, void *buffer, lfs3_size_t size); + +// Program a block +// +// The block must have previously been erased. +int lfs3_kiwibd_prog(const struct lfs3_cfg *cfg, lfs3_block_t block, + lfs3_off_t off, const void *buffer, lfs3_size_t size); + +// Erase a block +// +// A block must be erased before being programmed. The +// state of an erased block is undefined. +int lfs3_kiwibd_erase(const struct lfs3_cfg *cfg, lfs3_block_t block); + +// Sync the block device +int lfs3_kiwibd_sync(const struct lfs3_cfg *cfg); + + +/// Additional kiwibd features /// + +// Get total amount of bytes read +lfs3_kiwibd_sio_t lfs3_kiwibd_readed(const struct lfs3_cfg *cfg); + +// Get total amount of bytes programmed +lfs3_kiwibd_sio_t lfs3_kiwibd_proged(const struct lfs3_cfg *cfg); + +// Get total amount of bytes erased +lfs3_kiwibd_sio_t lfs3_kiwibd_erased(const struct lfs3_cfg *cfg); + +// Manually set amount of bytes read +int lfs3_kiwibd_setreaded(const struct lfs3_cfg *cfg, + lfs3_kiwibd_io_t readed); + +// Manually set amount of bytes programmed +int lfs3_kiwibd_setproged(const struct lfs3_cfg *cfg, + lfs3_kiwibd_io_t proged); + +// Manually set amount of bytes erased +int lfs3_kiwibd_seterased(const struct lfs3_cfg *cfg, + lfs3_kiwibd_io_t erased); + + +#endif + diff --git a/bd/lfs3_rambd.c b/bd/lfs3_rambd.c index 43016c97..2df32ebf 100644 --- a/bd/lfs3_rambd.c +++ b/bd/lfs3_rambd.c @@ -24,17 +24,17 @@ int lfs3_rambd_createcfg(const struct lfs3_cfg *cfg, // allocate buffer? if (bd->cfg->buffer) { - bd->buffer = bd->cfg->buffer; + bd->mem = bd->cfg->buffer; } else { - bd->buffer = lfs3_malloc(cfg->block_size * cfg->block_count); - if (!bd->buffer) { + bd->mem = lfs3_malloc(cfg->block_size * cfg->block_count); + if (!bd->mem) { LFS3_RAMBD_TRACE("lfs3_rambd_createcfg -> %d", LFS3_ERR_NOMEM); return LFS3_ERR_NOMEM; } } // zero for reproducibility - memset(bd->buffer, 0, cfg->block_size * cfg->block_count); + memset(bd->mem, 0, cfg->block_size * cfg->block_count); LFS3_RAMBD_TRACE("lfs3_rambd_createcfg -> %d", 0); return 0; @@ -60,7 +60,7 @@ int lfs3_rambd_destroy(const struct lfs3_cfg *cfg) { // clean up memory lfs3_rambd_t *bd = cfg->context; if (!bd->cfg->buffer) { - lfs3_free(bd->buffer); + lfs3_free(bd->mem); } LFS3_RAMBD_TRACE("lfs3_rambd_destroy -> %d", 0); return 0; @@ -80,7 +80,7 @@ int lfs3_rambd_read(const struct lfs3_cfg *cfg, lfs3_block_t block, LFS3_ASSERT(off+size <= cfg->block_size); // read data - memcpy(buffer, &bd->buffer[block*cfg->block_size + off], size); + memcpy(buffer, &bd->mem[block*cfg->block_size + off], size); LFS3_RAMBD_TRACE("lfs3_rambd_read -> %d", 0); return 0; @@ -100,7 +100,7 @@ int lfs3_rambd_prog(const struct lfs3_cfg *cfg, lfs3_block_t block, LFS3_ASSERT(off+size <= cfg->block_size); // program data - memcpy(&bd->buffer[block*cfg->block_size + off], buffer, size); + memcpy(&bd->mem[block*cfg->block_size + off], buffer, size); LFS3_RAMBD_TRACE("lfs3_rambd_prog -> %d", 0); return 0; diff --git a/bd/lfs3_rambd.h b/bd/lfs3_rambd.h index 26b1ddc3..fbd0acba 100644 --- a/bd/lfs3_rambd.h +++ b/bd/lfs3_rambd.h @@ -29,7 +29,7 @@ struct lfs3_rambd_cfg { // rambd state typedef struct lfs3_rambd { - uint8_t *buffer; + uint8_t *mem; const struct lfs3_rambd_cfg *cfg; } lfs3_rambd_t;