mirror of
				https://github.com/eledio-devices/thirdparty-littlefs.git
				synced 2025-10-31 16:14:16 +01:00 
			
		
		
		
	Changed callbacks to take user-provided context directly
This is a style change to make littlefs's callbacks consistent with most callback declarations found in C. That is, taking in a user-provided `void*`. Previously, these callbacks took a pointer to the config struct itself, which indirectly contained a user provided context, and this gets the job done, but taking in a callback with a `void*` is arguably more expected, has a better chance of integrating with C++/OS-specific code, and is more likely to be optimized out by a clever compiler. --- As a part of these changes, the geometry for the test bds needed to be moved into bd specific configuration objects. This is a good change as it also allows for testing situations where littlefs's geometry does not match the underlying bd.
This commit is contained in:
		
							
								
								
									
										107
									
								
								bd/lfs_filebd.c
									
									
									
									
									
								
							
							
						
						
									
										107
									
								
								bd/lfs_filebd.c
									
									
									
									
									
								
							| @@ -10,21 +10,18 @@ | |||||||
| #include <unistd.h> | #include <unistd.h> | ||||||
| #include <errno.h> | #include <errno.h> | ||||||
|  |  | ||||||
| int lfs_filebd_createcfg(const struct lfs_cfg *cfg, const char *path, | int lfs_filebd_createcfg(lfs_filebd_t *bd, const char *path, | ||||||
|         const struct lfs_filebd_cfg *bdcfg) { |         const struct lfs_filebd_cfg *cfg) { | ||||||
|     LFS_FILEBD_TRACE("lfs_filebd_createcfg(%p {.context=%p, " |     LFS_FILEBD_TRACE("lfs_filebd_createcfg(%p, \"%s\", %p {" | ||||||
|                 ".read=%p, .prog=%p, .erase=%p, .sync=%p, " |  | ||||||
|                 ".read_size=%"PRIu32", .prog_size=%"PRIu32", " |                 ".read_size=%"PRIu32", .prog_size=%"PRIu32", " | ||||||
|                 ".block_size=%"PRIu32", .block_count=%"PRIu32"}, " |                 ".erase_size=%"PRIu32", .erase_count=%"PRIu32", " | ||||||
|                 "\"%s\", " |                 ".erase_value=%"PRId32"})", | ||||||
|                 "%p {.erase_value=%"PRId32"})", |             (void*)bd, path, (void*)cfg, | ||||||
|             (void*)cfg, cfg->context, |             cfg->read_size, cfg->prog_size, cfg->erase_size, cfg->erase_count, | ||||||
|             (void*)(uintptr_t)cfg->read, (void*)(uintptr_t)cfg->prog, |             cfg->erase_value); | ||||||
|             (void*)(uintptr_t)cfg->erase, (void*)(uintptr_t)cfg->sync, |  | ||||||
|             cfg->read_size, cfg->prog_size, cfg->block_size, cfg->block_count, |     // copy over config | ||||||
|             path, (void*)bdcfg, bdcfg->erase_value); |     bd->cfg = *cfg; | ||||||
|     lfs_filebd_t *bd = cfg->context; |  | ||||||
|     bd->cfg = bdcfg; |  | ||||||
|  |  | ||||||
|     // open file |     // open file | ||||||
|     bd->fd = open(path, O_RDWR | O_CREAT, 0666); |     bd->fd = open(path, O_RDWR | O_CREAT, 0666); | ||||||
| @@ -38,26 +35,8 @@ int lfs_filebd_createcfg(const struct lfs_cfg *cfg, const char *path, | |||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| int lfs_filebd_create(const struct lfs_cfg *cfg, const char *path) { | int lfs_filebd_destroy(lfs_filebd_t *bd) { | ||||||
|     LFS_FILEBD_TRACE("lfs_filebd_create(%p {.context=%p, " |     LFS_FILEBD_TRACE("lfs_filebd_destroy(%p)", (void*)bd); | ||||||
|                 ".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 lfs_filebd_cfg defaults = {.erase_value=-1}; |  | ||||||
|     int err = lfs_filebd_createcfg(cfg, path, &defaults); |  | ||||||
|     LFS_FILEBD_TRACE("lfs_filebd_create -> %d", err); |  | ||||||
|     return err; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| int lfs_filebd_destroy(const struct lfs_cfg *cfg) { |  | ||||||
|     LFS_FILEBD_TRACE("lfs_filebd_destroy(%p)", (void*)cfg); |  | ||||||
|     lfs_filebd_t *bd = cfg->context; |  | ||||||
|     int err = close(bd->fd); |     int err = close(bd->fd); | ||||||
|     if (err < 0) { |     if (err < 0) { | ||||||
|         err = -errno; |         err = -errno; | ||||||
| @@ -68,26 +47,25 @@ int lfs_filebd_destroy(const struct lfs_cfg *cfg) { | |||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| int lfs_filebd_read(const struct lfs_cfg *cfg, lfs_block_t block, | int lfs_filebd_read(lfs_filebd_t *bd, lfs_block_t block, | ||||||
|         lfs_off_t off, void *buffer, lfs_size_t size) { |         lfs_off_t off, void *buffer, lfs_size_t size) { | ||||||
|     LFS_FILEBD_TRACE("lfs_filebd_read(%p, " |     LFS_FILEBD_TRACE("lfs_filebd_read(%p, " | ||||||
|                 "0x%"PRIx32", %"PRIu32", %p, %"PRIu32")", |                 "0x%"PRIx32", %"PRIu32", %p, %"PRIu32")", | ||||||
|             (void*)cfg, block, off, buffer, size); |             (void*)bd, block, off, buffer, size); | ||||||
|     lfs_filebd_t *bd = cfg->context; |  | ||||||
|  |  | ||||||
|     // check if read is valid |     // check if read is valid | ||||||
|     LFS_ASSERT(off  % cfg->read_size == 0); |     LFS_ASSERT(off  % bd->cfg.read_size == 0); | ||||||
|     LFS_ASSERT(size % cfg->read_size == 0); |     LFS_ASSERT(size % bd->cfg.read_size == 0); | ||||||
|     LFS_ASSERT(block < cfg->block_count); |     LFS_ASSERT(block < bd->cfg.erase_count); | ||||||
|  |  | ||||||
|     // zero for reproducability (in case file is truncated) |     // zero for reproducability (in case file is truncated) | ||||||
|     if (bd->cfg->erase_value != -1) { |     if (bd->cfg.erase_value != -1) { | ||||||
|         memset(buffer, bd->cfg->erase_value, size); |         memset(buffer, bd->cfg.erase_value, size); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // read |     // read | ||||||
|     off_t res1 = lseek(bd->fd, |     off_t res1 = lseek(bd->fd, | ||||||
|             (off_t)block*cfg->block_size + (off_t)off, SEEK_SET); |             (off_t)block*bd->cfg.erase_size + (off_t)off, SEEK_SET); | ||||||
|     if (res1 < 0) { |     if (res1 < 0) { | ||||||
|         int err = -errno; |         int err = -errno; | ||||||
|         LFS_FILEBD_TRACE("lfs_filebd_read -> %d", err); |         LFS_FILEBD_TRACE("lfs_filebd_read -> %d", err); | ||||||
| @@ -105,21 +83,21 @@ int lfs_filebd_read(const struct lfs_cfg *cfg, lfs_block_t block, | |||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| int lfs_filebd_prog(const struct lfs_cfg *cfg, lfs_block_t block, | int lfs_filebd_prog(lfs_filebd_t *bd, lfs_block_t block, | ||||||
|         lfs_off_t off, const void *buffer, lfs_size_t size) { |         lfs_off_t off, const void *buffer, lfs_size_t size) { | ||||||
|     LFS_FILEBD_TRACE("lfs_filebd_prog(%p, 0x%"PRIx32", %"PRIu32", %p, %"PRIu32")", |     LFS_FILEBD_TRACE("lfs_filebd_prog(%p, " | ||||||
|             (void*)cfg, block, off, buffer, size); |                 "0x%"PRIx32", %"PRIu32", %p, %"PRIu32")", | ||||||
|     lfs_filebd_t *bd = cfg->context; |             (void*)bd, block, off, buffer, size); | ||||||
|  |  | ||||||
|     // check if write is valid |     // check if write is valid | ||||||
|     LFS_ASSERT(off  % cfg->prog_size == 0); |     LFS_ASSERT(off  % bd->cfg.prog_size == 0); | ||||||
|     LFS_ASSERT(size % cfg->prog_size == 0); |     LFS_ASSERT(size % bd->cfg.prog_size == 0); | ||||||
|     LFS_ASSERT(block < cfg->block_count); |     LFS_ASSERT(block < bd->cfg.erase_count); | ||||||
|  |  | ||||||
|     // check that data was erased? only needed for testing |     // check that data was erased? only needed for testing | ||||||
|     if (bd->cfg->erase_value != -1) { |     if (bd->cfg.erase_value != -1) { | ||||||
|         off_t res1 = lseek(bd->fd, |         off_t res1 = lseek(bd->fd, | ||||||
|                 (off_t)block*cfg->block_size + (off_t)off, SEEK_SET); |                 (off_t)block*bd->cfg.erase_size + (off_t)off, SEEK_SET); | ||||||
|         if (res1 < 0) { |         if (res1 < 0) { | ||||||
|             int err = -errno; |             int err = -errno; | ||||||
|             LFS_FILEBD_TRACE("lfs_filebd_prog -> %d", err); |             LFS_FILEBD_TRACE("lfs_filebd_prog -> %d", err); | ||||||
| @@ -135,13 +113,13 @@ int lfs_filebd_prog(const struct lfs_cfg *cfg, lfs_block_t block, | |||||||
|                 return err; |                 return err; | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             LFS_ASSERT(c == bd->cfg->erase_value); |             LFS_ASSERT(c == bd->cfg.erase_value); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // program data |     // program data | ||||||
|     off_t res1 = lseek(bd->fd, |     off_t res1 = lseek(bd->fd, | ||||||
|             (off_t)block*cfg->block_size + (off_t)off, SEEK_SET); |             (off_t)block*bd->cfg.erase_size + (off_t)off, SEEK_SET); | ||||||
|     if (res1 < 0) { |     if (res1 < 0) { | ||||||
|         int err = -errno; |         int err = -errno; | ||||||
|         LFS_FILEBD_TRACE("lfs_filebd_prog -> %d", err); |         LFS_FILEBD_TRACE("lfs_filebd_prog -> %d", err); | ||||||
| @@ -159,24 +137,23 @@ int lfs_filebd_prog(const struct lfs_cfg *cfg, lfs_block_t block, | |||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| int lfs_filebd_erase(const struct lfs_cfg *cfg, lfs_block_t block) { | int lfs_filebd_erase(lfs_filebd_t *bd, lfs_block_t block) { | ||||||
|     LFS_FILEBD_TRACE("lfs_filebd_erase(%p, 0x%"PRIx32")", (void*)cfg, block); |     LFS_FILEBD_TRACE("lfs_filebd_erase(%p, 0x%"PRIx32")", (void*)bd, block); | ||||||
|     lfs_filebd_t *bd = cfg->context; |  | ||||||
|  |  | ||||||
|     // check if erase is valid |     // check if erase is valid | ||||||
|     LFS_ASSERT(block < cfg->block_count); |     LFS_ASSERT(block < bd->cfg.erase_count); | ||||||
|  |  | ||||||
|     // erase, only needed for testing |     // erase, only needed for testing | ||||||
|     if (bd->cfg->erase_value != -1) { |     if (bd->cfg.erase_value != -1) { | ||||||
|         off_t res1 = lseek(bd->fd, (off_t)block*cfg->block_size, SEEK_SET); |         off_t res1 = lseek(bd->fd, (off_t)block*bd->cfg.erase_size, SEEK_SET); | ||||||
|         if (res1 < 0) { |         if (res1 < 0) { | ||||||
|             int err = -errno; |             int err = -errno; | ||||||
|             LFS_FILEBD_TRACE("lfs_filebd_erase -> %d", err); |             LFS_FILEBD_TRACE("lfs_filebd_erase -> %d", err); | ||||||
|             return err; |             return err; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         for (lfs_off_t i = 0; i < cfg->block_size; i++) { |         for (lfs_off_t i = 0; i < bd->cfg.erase_size; i++) { | ||||||
|             ssize_t res2 = write(bd->fd, &(uint8_t){bd->cfg->erase_value}, 1); |             ssize_t res2 = write(bd->fd, &(uint8_t){bd->cfg.erase_value}, 1); | ||||||
|             if (res2 < 0) { |             if (res2 < 0) { | ||||||
|                 int err = -errno; |                 int err = -errno; | ||||||
|                 LFS_FILEBD_TRACE("lfs_filebd_erase -> %d", err); |                 LFS_FILEBD_TRACE("lfs_filebd_erase -> %d", err); | ||||||
| @@ -189,10 +166,10 @@ int lfs_filebd_erase(const struct lfs_cfg *cfg, lfs_block_t block) { | |||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| int lfs_filebd_sync(const struct lfs_cfg *cfg) { | int lfs_filebd_sync(lfs_filebd_t *bd) { | ||||||
|     LFS_FILEBD_TRACE("lfs_filebd_sync(%p)", (void*)cfg); |     LFS_FILEBD_TRACE("lfs_filebd_sync(%p)", (void*)bd); | ||||||
|  |  | ||||||
|     // file sync |     // file sync | ||||||
|     lfs_filebd_t *bd = cfg->context; |  | ||||||
|     int err = fsync(bd->fd); |     int err = fsync(bd->fd); | ||||||
|     if (err) { |     if (err) { | ||||||
|         err = -errno; |         err = -errno; | ||||||
|   | |||||||
| @@ -10,8 +10,7 @@ | |||||||
| #include "lfs.h" | #include "lfs.h" | ||||||
|  |  | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| extern "C" | extern "C" { | ||||||
| { |  | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -24,6 +23,20 @@ extern "C" | |||||||
|  |  | ||||||
| // filebd config (optional) | // filebd config (optional) | ||||||
| struct lfs_filebd_cfg { | struct lfs_filebd_cfg { | ||||||
|  |     // Minimum size of block read. All read operations must be a | ||||||
|  |     // multiple of this value. | ||||||
|  |     lfs_size_t read_size; | ||||||
|  |  | ||||||
|  |     // Minimum size of block program. All program operations must be a | ||||||
|  |     // multiple of this value. | ||||||
|  |     lfs_size_t prog_size; | ||||||
|  |  | ||||||
|  |     // Size of an erasable block. | ||||||
|  |     lfs_size_t erase_size; | ||||||
|  |  | ||||||
|  |     // Number of erasable blocks on the device. | ||||||
|  |     lfs_size_t erase_count; | ||||||
|  |  | ||||||
|     // 8-bit erase value to use for simulating erases. -1 does not simulate |     // 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 all the extra block-device | ||||||
|     // operations to store the erase value. |     // operations to store the erase value. | ||||||
| @@ -33,40 +46,39 @@ struct lfs_filebd_cfg { | |||||||
| // filebd state | // filebd state | ||||||
| typedef struct lfs_filebd { | typedef struct lfs_filebd { | ||||||
|     int fd; |     int fd; | ||||||
|     const struct lfs_filebd_cfg *cfg; |     struct lfs_filebd_cfg cfg; | ||||||
| } lfs_filebd_t; | } lfs_filebd_t; | ||||||
|  |  | ||||||
|  |  | ||||||
| // Create a file block device using the geometry in lfs_cfg | // Create a file block device using the geometry in lfs_filebd_cfg | ||||||
| int lfs_filebd_create(const struct lfs_cfg *cfg, const char *path); | int lfs_filebd_createcfg(lfs_filebd_t *bd, const char *path, | ||||||
| int lfs_filebd_createcfg(const struct lfs_cfg *cfg, const char *path, |         const struct lfs_filebd_cfg *cfg); | ||||||
|         const struct lfs_filebd_cfg *bdcfg); |  | ||||||
|  |  | ||||||
| // Clean up memory associated with block device | // Clean up memory associated with block device | ||||||
| int lfs_filebd_destroy(const struct lfs_cfg *cfg); | int lfs_filebd_destroy(lfs_filebd_t *bd); | ||||||
|  |  | ||||||
| // Read a block | // Read a block | ||||||
| int lfs_filebd_read(const struct lfs_cfg *cfg, lfs_block_t block, | int lfs_filebd_read(lfs_filebd_t *bd, lfs_block_t block, | ||||||
|         lfs_off_t off, void *buffer, lfs_size_t size); |         lfs_off_t off, void *buffer, lfs_size_t size); | ||||||
|  |  | ||||||
| // Program a block | // Program a block | ||||||
| // | // | ||||||
| // The block must have previously been erased. | // The block must have previously been erased. | ||||||
| int lfs_filebd_prog(const struct lfs_cfg *cfg, lfs_block_t block, | int lfs_filebd_prog(lfs_filebd_t *bd, lfs_block_t block, | ||||||
|         lfs_off_t off, const void *buffer, lfs_size_t size); |         lfs_off_t off, const void *buffer, lfs_size_t size); | ||||||
|  |  | ||||||
| // Erase a block | // Erase a block | ||||||
| // | // | ||||||
| // A block must be erased before being programmed. The | // A block must be erased before being programmed. The | ||||||
| // state of an erased block is undefined. | // state of an erased block is undefined. | ||||||
| int lfs_filebd_erase(const struct lfs_cfg *cfg, lfs_block_t block); | int lfs_filebd_erase(lfs_filebd_t *bd, lfs_block_t block); | ||||||
|  |  | ||||||
| // Sync the block device | // Sync the block device | ||||||
| int lfs_filebd_sync(const struct lfs_cfg *cfg); | int lfs_filebd_sync(lfs_filebd_t *bd); | ||||||
|  |  | ||||||
|  |  | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| } /* extern "C" */ | } | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| #endif | #endif | ||||||
|   | |||||||
							
								
								
									
										109
									
								
								bd/lfs_rambd.c
									
									
									
									
									
								
							
							
						
						
									
										109
									
								
								bd/lfs_rambd.c
									
									
									
									
									
								
							| @@ -6,26 +6,24 @@ | |||||||
|  */ |  */ | ||||||
| #include "bd/lfs_rambd.h" | #include "bd/lfs_rambd.h" | ||||||
|  |  | ||||||
| int lfs_rambd_createcfg(const struct lfs_cfg *cfg, | int lfs_rambd_createcfg(lfs_rambd_t *bd, | ||||||
|         const struct lfs_rambd_cfg *bdcfg) { |         const struct lfs_rambd_cfg *cfg) { | ||||||
|     LFS_RAMBD_TRACE("lfs_rambd_createcfg(%p {.context=%p, " |     LFS_RAMBD_TRACE("lfs_filebd_createcfg(%p, %p {" | ||||||
|                 ".read=%p, .prog=%p, .erase=%p, .sync=%p, " |  | ||||||
|                 ".read_size=%"PRIu32", .prog_size=%"PRIu32", " |                 ".read_size=%"PRIu32", .prog_size=%"PRIu32", " | ||||||
|                 ".block_size=%"PRIu32", .block_count=%"PRIu32"}, " |                 ".erase_size=%"PRIu32", .erase_count=%"PRIu32", " | ||||||
|                 "%p {.erase_value=%"PRId32", .buffer=%p})", |                 ".erase_value=%"PRId32", .buffer=%p})", | ||||||
|             (void*)cfg, cfg->context, |             (void*)bd, (void*)cfg, | ||||||
|             (void*)(uintptr_t)cfg->read, (void*)(uintptr_t)cfg->prog, |             cfg->read_size, cfg->prog_size, cfg->erase_size, cfg->erase_count, | ||||||
|             (void*)(uintptr_t)cfg->erase, (void*)(uintptr_t)cfg->sync, |             cfg->erase_value, cfg->buffer); | ||||||
|             cfg->read_size, cfg->prog_size, cfg->block_size, cfg->block_count, |  | ||||||
|             (void*)bdcfg, bdcfg->erase_value, bdcfg->buffer); |     // copy over config | ||||||
|     lfs_rambd_t *bd = cfg->context; |     bd->cfg = *cfg; | ||||||
|     bd->cfg = bdcfg; |  | ||||||
|  |  | ||||||
|     // allocate buffer? |     // allocate buffer? | ||||||
|     if (bd->cfg->buffer) { |     if (bd->cfg.buffer) { | ||||||
|         bd->buffer = bd->cfg->buffer; |         bd->buffer = bd->cfg.buffer; | ||||||
|     } else { |     } else { | ||||||
|         bd->buffer = lfs_malloc(cfg->block_size * cfg->block_count); |         bd->buffer = lfs_malloc(bd->cfg.erase_size * bd->cfg.erase_count); | ||||||
|         if (!bd->buffer) { |         if (!bd->buffer) { | ||||||
|             LFS_RAMBD_TRACE("lfs_rambd_createcfg -> %d", LFS_ERR_NOMEM); |             LFS_RAMBD_TRACE("lfs_rambd_createcfg -> %d", LFS_ERR_NOMEM); | ||||||
|             return LFS_ERR_NOMEM; |             return LFS_ERR_NOMEM; | ||||||
| @@ -33,108 +31,89 @@ int lfs_rambd_createcfg(const struct lfs_cfg *cfg, | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     // zero for reproducability? |     // zero for reproducability? | ||||||
|     if (bd->cfg->erase_value != -1) { |     if (bd->cfg.erase_value != -1) { | ||||||
|         memset(bd->buffer, bd->cfg->erase_value, |         memset(bd->buffer, bd->cfg.erase_value, | ||||||
|                 cfg->block_size * cfg->block_count); |                 bd->cfg.erase_size * bd->cfg.erase_count); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     LFS_RAMBD_TRACE("lfs_rambd_createcfg -> %d", 0); |     LFS_RAMBD_TRACE("lfs_rambd_createcfg -> %d", 0); | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| int lfs_rambd_create(const struct lfs_cfg *cfg) { | int lfs_rambd_destroy(lfs_rambd_t *bd) { | ||||||
|     LFS_RAMBD_TRACE("lfs_rambd_create(%p {.context=%p, " |     LFS_RAMBD_TRACE("lfs_rambd_destroy(%p)", (void*)bd); | ||||||
|                 ".read=%p, .prog=%p, .erase=%p, .sync=%p, " |  | ||||||
|                 ".read_size=%"PRIu32", .prog_size=%"PRIu32", " |  | ||||||
|                 ".block_size=%"PRIu32", .block_count=%"PRIu32"})", |  | ||||||
|             (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); |  | ||||||
|     static const struct lfs_rambd_cfg defaults = {.erase_value=-1}; |  | ||||||
|     int err = lfs_rambd_createcfg(cfg, &defaults); |  | ||||||
|     LFS_RAMBD_TRACE("lfs_rambd_create -> %d", err); |  | ||||||
|     return err; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| int lfs_rambd_destroy(const struct lfs_cfg *cfg) { |  | ||||||
|     LFS_RAMBD_TRACE("lfs_rambd_destroy(%p)", (void*)cfg); |  | ||||||
|     // clean up memory |     // clean up memory | ||||||
|     lfs_rambd_t *bd = cfg->context; |     if (!bd->cfg.buffer) { | ||||||
|     if (!bd->cfg->buffer) { |  | ||||||
|         lfs_free(bd->buffer); |         lfs_free(bd->buffer); | ||||||
|     } |     } | ||||||
|     LFS_RAMBD_TRACE("lfs_rambd_destroy -> %d", 0); |     LFS_RAMBD_TRACE("lfs_rambd_destroy -> %d", 0); | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| int lfs_rambd_read(const struct lfs_cfg *cfg, lfs_block_t block, | int lfs_rambd_read(lfs_rambd_t *bd, lfs_block_t block, | ||||||
|         lfs_off_t off, void *buffer, lfs_size_t size) { |         lfs_off_t off, void *buffer, lfs_size_t size) { | ||||||
|     LFS_RAMBD_TRACE("lfs_rambd_read(%p, " |     LFS_RAMBD_TRACE("lfs_rambd_read(%p, " | ||||||
|                 "0x%"PRIx32", %"PRIu32", %p, %"PRIu32")", |                 "0x%"PRIx32", %"PRIu32", %p, %"PRIu32")", | ||||||
|             (void*)cfg, block, off, buffer, size); |             (void*)bd, block, off, buffer, size); | ||||||
|     lfs_rambd_t *bd = cfg->context; |  | ||||||
|  |  | ||||||
|     // check if read is valid |     // check if read is valid | ||||||
|     LFS_ASSERT(off  % cfg->read_size == 0); |     LFS_ASSERT(off  % bd->cfg.read_size == 0); | ||||||
|     LFS_ASSERT(size % cfg->read_size == 0); |     LFS_ASSERT(size % bd->cfg.read_size == 0); | ||||||
|     LFS_ASSERT(block < cfg->block_count); |     LFS_ASSERT(block < bd->cfg.erase_count); | ||||||
|  |  | ||||||
|     // read data |     // read data | ||||||
|     memcpy(buffer, &bd->buffer[block*cfg->block_size + off], size); |     memcpy(buffer, &bd->buffer[block*bd->cfg.erase_size + off], size); | ||||||
|  |  | ||||||
|     LFS_RAMBD_TRACE("lfs_rambd_read -> %d", 0); |     LFS_RAMBD_TRACE("lfs_rambd_read -> %d", 0); | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| int lfs_rambd_prog(const struct lfs_cfg *cfg, lfs_block_t block, | int lfs_rambd_prog(lfs_rambd_t *bd, lfs_block_t block, | ||||||
|         lfs_off_t off, const void *buffer, lfs_size_t size) { |         lfs_off_t off, const void *buffer, lfs_size_t size) { | ||||||
|     LFS_RAMBD_TRACE("lfs_rambd_prog(%p, " |     LFS_RAMBD_TRACE("lfs_rambd_prog(%p, " | ||||||
|                 "0x%"PRIx32", %"PRIu32", %p, %"PRIu32")", |                 "0x%"PRIx32", %"PRIu32", %p, %"PRIu32")", | ||||||
|             (void*)cfg, block, off, buffer, size); |             (void*)bd, block, off, buffer, size); | ||||||
|     lfs_rambd_t *bd = cfg->context; |  | ||||||
|  |  | ||||||
|     // check if write is valid |     // check if write is valid | ||||||
|     LFS_ASSERT(off  % cfg->prog_size == 0); |     LFS_ASSERT(off  % bd->cfg.prog_size == 0); | ||||||
|     LFS_ASSERT(size % cfg->prog_size == 0); |     LFS_ASSERT(size % bd->cfg.prog_size == 0); | ||||||
|     LFS_ASSERT(block < cfg->block_count); |     LFS_ASSERT(block < bd->cfg.erase_count); | ||||||
|  |  | ||||||
|     // check that data was erased? only needed for testing |     // check that data was erased? only needed for testing | ||||||
|     if (bd->cfg->erase_value != -1) { |     if (bd->cfg.erase_value != -1) { | ||||||
|         for (lfs_off_t i = 0; i < size; i++) { |         for (lfs_off_t i = 0; i < size; i++) { | ||||||
|             LFS_ASSERT(bd->buffer[block*cfg->block_size + off + i] == |             LFS_ASSERT(bd->buffer[block*bd->cfg.erase_size + off + i] == | ||||||
|                     bd->cfg->erase_value); |                     bd->cfg.erase_value); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // program data |     // program data | ||||||
|     memcpy(&bd->buffer[block*cfg->block_size + off], buffer, size); |     memcpy(&bd->buffer[block*bd->cfg.erase_size + off], buffer, size); | ||||||
|  |  | ||||||
|     LFS_RAMBD_TRACE("lfs_rambd_prog -> %d", 0); |     LFS_RAMBD_TRACE("lfs_rambd_prog -> %d", 0); | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| int lfs_rambd_erase(const struct lfs_cfg *cfg, lfs_block_t block) { | int lfs_rambd_erase(lfs_rambd_t *bd, lfs_block_t block) { | ||||||
|     LFS_RAMBD_TRACE("lfs_rambd_erase(%p, 0x%"PRIx32")", (void*)cfg, block); |     LFS_RAMBD_TRACE("lfs_rambd_erase(%p, 0x%"PRIx32")", (void*)bd, block); | ||||||
|     lfs_rambd_t *bd = cfg->context; |  | ||||||
|  |  | ||||||
|     // check if erase is valid |     // check if erase is valid | ||||||
|     LFS_ASSERT(block < cfg->block_count); |     LFS_ASSERT(block < bd->cfg.erase_count); | ||||||
|  |  | ||||||
|     // erase, only needed for testing |     // erase, only needed for testing | ||||||
|     if (bd->cfg->erase_value != -1) { |     if (bd->cfg.erase_value != -1) { | ||||||
|         memset(&bd->buffer[block*cfg->block_size], |         memset(&bd->buffer[block*bd->cfg.erase_size], | ||||||
|                 bd->cfg->erase_value, cfg->block_size); |                 bd->cfg.erase_value, bd->cfg.erase_size); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     LFS_RAMBD_TRACE("lfs_rambd_erase -> %d", 0); |     LFS_RAMBD_TRACE("lfs_rambd_erase -> %d", 0); | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| int lfs_rambd_sync(const struct lfs_cfg *cfg) { | int lfs_rambd_sync(lfs_rambd_t *bd) { | ||||||
|     LFS_RAMBD_TRACE("lfs_rambd_sync(%p)", (void*)cfg); |     LFS_RAMBD_TRACE("lfs_rambd_sync(%p)", (void*)bd); | ||||||
|     // sync does nothing because we aren't backed by anything real |     // sync does nothing because we aren't backed by anything real | ||||||
|     (void)cfg; |     (void)bd; | ||||||
|     LFS_RAMBD_TRACE("lfs_rambd_sync -> %d", 0); |     LFS_RAMBD_TRACE("lfs_rambd_sync -> %d", 0); | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -10,8 +10,7 @@ | |||||||
| #include "lfs.h" | #include "lfs.h" | ||||||
|  |  | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| extern "C" | extern "C" { | ||||||
| { |  | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -24,6 +23,20 @@ extern "C" | |||||||
|  |  | ||||||
| // rambd config (optional) | // rambd config (optional) | ||||||
| struct lfs_rambd_cfg { | struct lfs_rambd_cfg { | ||||||
|  |     // Minimum size of block read. All read operations must be a | ||||||
|  |     // multiple of this value. | ||||||
|  |     lfs_size_t read_size; | ||||||
|  |  | ||||||
|  |     // Minimum size of block program. All program operations must be a | ||||||
|  |     // multiple of this value. | ||||||
|  |     lfs_size_t prog_size; | ||||||
|  |  | ||||||
|  |     // Size of an erasable block. | ||||||
|  |     lfs_size_t erase_size; | ||||||
|  |  | ||||||
|  |     // Number of erasable blocks on the device. | ||||||
|  |     lfs_size_t erase_count; | ||||||
|  |  | ||||||
|     // 8-bit erase value to simulate erasing with. -1 indicates no erase |     // 8-bit erase value to simulate erasing with. -1 indicates no erase | ||||||
|     // occurs, which is still a valid block device |     // occurs, which is still a valid block device | ||||||
|     int32_t erase_value; |     int32_t erase_value; | ||||||
| @@ -35,40 +48,39 @@ struct lfs_rambd_cfg { | |||||||
| // rambd state | // rambd state | ||||||
| typedef struct lfs_rambd { | typedef struct lfs_rambd { | ||||||
|     uint8_t *buffer; |     uint8_t *buffer; | ||||||
|     const struct lfs_rambd_cfg *cfg; |     struct lfs_rambd_cfg cfg; | ||||||
| } lfs_rambd_t; | } lfs_rambd_t; | ||||||
|  |  | ||||||
|  |  | ||||||
| // Create a RAM block device using the geometry in lfs_cfg | // Create a RAM block device using the geometry in lfs_cfg | ||||||
| int lfs_rambd_create(const struct lfs_cfg *cfg); | int lfs_rambd_createcfg(lfs_rambd_t *bd, | ||||||
| int lfs_rambd_createcfg(const struct lfs_cfg *cfg, |         const struct lfs_rambd_cfg *cfg); | ||||||
|         const struct lfs_rambd_cfg *bdcfg); |  | ||||||
|  |  | ||||||
| // Clean up memory associated with block device | // Clean up memory associated with block device | ||||||
| int lfs_rambd_destroy(const struct lfs_cfg *cfg); | int lfs_rambd_destroy(lfs_rambd_t *bd); | ||||||
|  |  | ||||||
| // Read a block | // Read a block | ||||||
| int lfs_rambd_read(const struct lfs_cfg *cfg, lfs_block_t block, | int lfs_rambd_read(lfs_rambd_t *bd, lfs_block_t block, | ||||||
|         lfs_off_t off, void *buffer, lfs_size_t size); |         lfs_off_t off, void *buffer, lfs_size_t size); | ||||||
|  |  | ||||||
| // Program a block | // Program a block | ||||||
| // | // | ||||||
| // The block must have previously been erased. | // The block must have previously been erased. | ||||||
| int lfs_rambd_prog(const struct lfs_cfg *cfg, lfs_block_t block, | int lfs_rambd_prog(lfs_rambd_t *bd, lfs_block_t block, | ||||||
|         lfs_off_t off, const void *buffer, lfs_size_t size); |         lfs_off_t off, const void *buffer, lfs_size_t size); | ||||||
|  |  | ||||||
| // Erase a block | // Erase a block | ||||||
| // | // | ||||||
| // A block must be erased before being programmed. The | // A block must be erased before being programmed. The | ||||||
| // state of an erased block is undefined. | // state of an erased block is undefined. | ||||||
| int lfs_rambd_erase(const struct lfs_cfg *cfg, lfs_block_t block); | int lfs_rambd_erase(lfs_rambd_t *bd, lfs_block_t block); | ||||||
|  |  | ||||||
| // Sync the block device | // Sync the block device | ||||||
| int lfs_rambd_sync(const struct lfs_cfg *cfg); | int lfs_rambd_sync(lfs_rambd_t *bd); | ||||||
|  |  | ||||||
|  |  | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| } /* extern "C" */ | } | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| #endif | #endif | ||||||
|   | |||||||
							
								
								
									
										204
									
								
								bd/lfs_testbd.c
									
									
									
									
									
								
							
							
						
						
									
										204
									
								
								bd/lfs_testbd.c
									
									
									
									
									
								
							| @@ -10,185 +10,164 @@ | |||||||
| #include <stdlib.h> | #include <stdlib.h> | ||||||
|  |  | ||||||
|  |  | ||||||
| int lfs_testbd_createcfg(const struct lfs_cfg *cfg, const char *path, | int lfs_testbd_createcfg(lfs_testbd_t *bd, const char *path, | ||||||
|         const struct lfs_testbd_cfg *bdcfg) { |         const struct lfs_testbd_cfg *cfg) { | ||||||
|     LFS_TESTBD_TRACE("lfs_testbd_createcfg(%p {.context=%p, " |     LFS_TESTBD_TRACE("lfs_testbd_createcfg(%p, \"%s\", %p {" | ||||||
|                 ".read=%p, .prog=%p, .erase=%p, .sync=%p, " |  | ||||||
|                 ".read_size=%"PRIu32", .prog_size=%"PRIu32", " |                 ".read_size=%"PRIu32", .prog_size=%"PRIu32", " | ||||||
|                 ".block_size=%"PRIu32", .block_count=%"PRIu32"}, " |                 ".erase_size=%"PRIu32", .erase_count=%"PRIu32", " | ||||||
|                 "\"%s\", " |                 ".erase_value=%"PRId32", .erase_cycles=%"PRIu32", " | ||||||
|                 "%p {.erase_value=%"PRId32", .erase_cycles=%"PRIu32", " |  | ||||||
|                 ".badblock_behavior=%"PRIu8", .power_cycles=%"PRIu32", " |                 ".badblock_behavior=%"PRIu8", .power_cycles=%"PRIu32", " | ||||||
|                 ".buffer=%p, .wear_buffer=%p})", |                 ".buffer=%p, .wear_buffer=%p})", | ||||||
|             (void*)cfg, cfg->context, |             (void*)bd, path, (void*)cfg, | ||||||
|             (void*)(uintptr_t)cfg->read, (void*)(uintptr_t)cfg->prog, |             cfg->read_size, cfg->prog_size, cfg->erase_size, cfg->erase_count, | ||||||
|             (void*)(uintptr_t)cfg->erase, (void*)(uintptr_t)cfg->sync, |             cfg->erase_value, cfg->erase_cycles, | ||||||
|             cfg->read_size, cfg->prog_size, cfg->block_size, cfg->block_count, |             cfg->badblock_behavior, cfg->power_cycles, | ||||||
|             path, (void*)bdcfg, bdcfg->erase_value, bdcfg->erase_cycles, |             cfg->buffer, cfg->wear_buffer); | ||||||
|             bdcfg->badblock_behavior, bdcfg->power_cycles, |  | ||||||
|             bdcfg->buffer, bdcfg->wear_buffer); |     // copy over config | ||||||
|     lfs_testbd_t *bd = cfg->context; |     bd->cfg = *cfg; | ||||||
|     bd->cfg = bdcfg; |  | ||||||
|  |  | ||||||
|     // setup testing things |     // setup testing things | ||||||
|     bd->persist = path; |     bd->persist = path; | ||||||
|     bd->power_cycles = bd->cfg->power_cycles; |     bd->power_cycles = bd->cfg.power_cycles; | ||||||
|  |  | ||||||
|     if (bd->cfg->erase_cycles) { |     if (bd->cfg.erase_cycles) { | ||||||
|         if (bd->cfg->wear_buffer) { |         if (bd->cfg.wear_buffer) { | ||||||
|             bd->wear = bd->cfg->wear_buffer; |             bd->wear = bd->cfg.wear_buffer; | ||||||
|         } else { |         } else { | ||||||
|             bd->wear = lfs_malloc(sizeof(lfs_testbd_wear_t)*cfg->block_count); |             bd->wear = lfs_malloc(sizeof(lfs_testbd_wear_t)*cfg->erase_count); | ||||||
|             if (!bd->wear) { |             if (!bd->wear) { | ||||||
|                 LFS_TESTBD_TRACE("lfs_testbd_createcfg -> %d", LFS_ERR_NOMEM); |                 LFS_TESTBD_TRACE("lfs_testbd_createcfg -> %d", LFS_ERR_NOMEM); | ||||||
|                 return LFS_ERR_NOMEM; |                 return LFS_ERR_NOMEM; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         memset(bd->wear, 0, sizeof(lfs_testbd_wear_t) * cfg->block_count); |         memset(bd->wear, 0, sizeof(lfs_testbd_wear_t) * bd->cfg.erase_count); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // create underlying block device |     // create underlying block device | ||||||
|     if (bd->persist) { |     if (bd->persist) { | ||||||
|         bd->u.file.cfg = (struct lfs_filebd_cfg){ |         int err = lfs_filebd_createcfg(&bd->impl.filebd, path, | ||||||
|             .erase_value = bd->cfg->erase_value, |                 &(struct lfs_filebd_cfg){ | ||||||
|         }; |                     .read_size=bd->cfg.read_size, | ||||||
|         int err = lfs_filebd_createcfg(cfg, path, &bd->u.file.cfg); |                     .prog_size=bd->cfg.prog_size, | ||||||
|  |                     .erase_size=bd->cfg.erase_size, | ||||||
|  |                     .erase_count=bd->cfg.erase_count, | ||||||
|  |                     .erase_value=bd->cfg.erase_value}); | ||||||
|         LFS_TESTBD_TRACE("lfs_testbd_createcfg -> %d", err); |         LFS_TESTBD_TRACE("lfs_testbd_createcfg -> %d", err); | ||||||
|         return err; |         return err; | ||||||
|     } else { |     } else { | ||||||
|         bd->u.ram.cfg = (struct lfs_rambd_cfg){ |         int err = lfs_rambd_createcfg(&bd->impl.rambd, | ||||||
|             .erase_value = bd->cfg->erase_value, |                 &(struct lfs_rambd_cfg){ | ||||||
|             .buffer = bd->cfg->buffer, |                     .read_size=bd->cfg.read_size, | ||||||
|         }; |                     .prog_size=bd->cfg.prog_size, | ||||||
|         int err = lfs_rambd_createcfg(cfg, &bd->u.ram.cfg); |                     .erase_size=bd->cfg.erase_size, | ||||||
|  |                     .erase_count=bd->cfg.erase_count, | ||||||
|  |                     .erase_value=bd->cfg.erase_value, | ||||||
|  |                     .buffer=bd->cfg.buffer}); | ||||||
|         LFS_TESTBD_TRACE("lfs_testbd_createcfg -> %d", err); |         LFS_TESTBD_TRACE("lfs_testbd_createcfg -> %d", err); | ||||||
|         return err; |         return err; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| int lfs_testbd_create(const struct lfs_cfg *cfg, const char *path) { | int lfs_testbd_destroy(lfs_testbd_t *bd) { | ||||||
|     LFS_TESTBD_TRACE("lfs_testbd_create(%p {.context=%p, " |     LFS_TESTBD_TRACE("lfs_testbd_destroy(%p)", (void*)bd); | ||||||
|                 ".read=%p, .prog=%p, .erase=%p, .sync=%p, " |     if (bd->cfg.erase_cycles && !bd->cfg.wear_buffer) { | ||||||
|                 ".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 lfs_testbd_cfg defaults = {.erase_value=-1}; |  | ||||||
|     int err = lfs_testbd_createcfg(cfg, path, &defaults); |  | ||||||
|     LFS_TESTBD_TRACE("lfs_testbd_create -> %d", err); |  | ||||||
|     return err; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| int lfs_testbd_destroy(const struct lfs_cfg *cfg) { |  | ||||||
|     LFS_TESTBD_TRACE("lfs_testbd_destroy(%p)", (void*)cfg); |  | ||||||
|     lfs_testbd_t *bd = cfg->context; |  | ||||||
|     if (bd->cfg->erase_cycles && !bd->cfg->wear_buffer) { |  | ||||||
|         lfs_free(bd->wear); |         lfs_free(bd->wear); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     if (bd->persist) { |     if (bd->persist) { | ||||||
|         int err = lfs_filebd_destroy(cfg); |         int err = lfs_filebd_destroy(&bd->impl.filebd); | ||||||
|         LFS_TESTBD_TRACE("lfs_testbd_destroy -> %d", err); |         LFS_TESTBD_TRACE("lfs_testbd_destroy -> %d", err); | ||||||
|         return err; |         return err; | ||||||
|     } else { |     } else { | ||||||
|         int err = lfs_rambd_destroy(cfg); |         int err = lfs_rambd_destroy(&bd->impl.rambd); | ||||||
|         LFS_TESTBD_TRACE("lfs_testbd_destroy -> %d", err); |         LFS_TESTBD_TRACE("lfs_testbd_destroy -> %d", err); | ||||||
|         return err; |         return err; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| /// Internal mapping to block devices /// | /// Internal mapping to block devices /// | ||||||
| static int lfs_testbd_rawread(const struct lfs_cfg *cfg, lfs_block_t block, | static int lfs_testbd_rawread(lfs_testbd_t *bd, lfs_block_t block, | ||||||
|         lfs_off_t off, void *buffer, lfs_size_t size) { |         lfs_off_t off, void *buffer, lfs_size_t size) { | ||||||
|     lfs_testbd_t *bd = cfg->context; |  | ||||||
|     if (bd->persist) { |     if (bd->persist) { | ||||||
|         return lfs_filebd_read(cfg, block, off, buffer, size); |         return lfs_filebd_read(&bd->impl.filebd, block, off, buffer, size); | ||||||
|     } else { |     } else { | ||||||
|         return lfs_rambd_read(cfg, block, off, buffer, size); |         return lfs_rambd_read(&bd->impl.rambd, block, off, buffer, size); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| static int lfs_testbd_rawprog(const struct lfs_cfg *cfg, lfs_block_t block, | static int lfs_testbd_rawprog(lfs_testbd_t *bd, lfs_block_t block, | ||||||
|         lfs_off_t off, const void *buffer, lfs_size_t size) { |         lfs_off_t off, const void *buffer, lfs_size_t size) { | ||||||
|     lfs_testbd_t *bd = cfg->context; |  | ||||||
|     if (bd->persist) { |     if (bd->persist) { | ||||||
|         return lfs_filebd_prog(cfg, block, off, buffer, size); |         return lfs_filebd_prog(&bd->impl.filebd, block, off, buffer, size); | ||||||
|     } else { |     } else { | ||||||
|         return lfs_rambd_prog(cfg, block, off, buffer, size); |         return lfs_rambd_prog(&bd->impl.rambd, block, off, buffer, size); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| static int lfs_testbd_rawerase(const struct lfs_cfg *cfg, | static int lfs_testbd_rawerase(lfs_testbd_t *bd, | ||||||
|         lfs_block_t block) { |         lfs_block_t block) { | ||||||
|     lfs_testbd_t *bd = cfg->context; |  | ||||||
|     if (bd->persist) { |     if (bd->persist) { | ||||||
|         return lfs_filebd_erase(cfg, block); |         return lfs_filebd_erase(&bd->impl.filebd, block); | ||||||
|     } else { |     } else { | ||||||
|         return lfs_rambd_erase(cfg, block); |         return lfs_rambd_erase(&bd->impl.rambd, block); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| static int lfs_testbd_rawsync(const struct lfs_cfg *cfg) { | static int lfs_testbd_rawsync(lfs_testbd_t *bd) { | ||||||
|     lfs_testbd_t *bd = cfg->context; |  | ||||||
|     if (bd->persist) { |     if (bd->persist) { | ||||||
|         return lfs_filebd_sync(cfg); |         return lfs_filebd_sync(&bd->impl.filebd); | ||||||
|     } else { |     } else { | ||||||
|         return lfs_rambd_sync(cfg); |         return lfs_rambd_sync(&bd->impl.rambd); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| /// block device API /// | /// block device API /// | ||||||
| int lfs_testbd_read(const struct lfs_cfg *cfg, lfs_block_t block, | int lfs_testbd_read(lfs_testbd_t *bd, lfs_block_t block, | ||||||
|         lfs_off_t off, void *buffer, lfs_size_t size) { |         lfs_off_t off, void *buffer, lfs_size_t size) { | ||||||
|     LFS_TESTBD_TRACE("lfs_testbd_read(%p, " |     LFS_TESTBD_TRACE("lfs_testbd_read(%p, " | ||||||
|                 "0x%"PRIx32", %"PRIu32", %p, %"PRIu32")", |                 "0x%"PRIx32", %"PRIu32", %p, %"PRIu32")", | ||||||
|             (void*)cfg, block, off, buffer, size); |             (void*)bd, block, off, buffer, size); | ||||||
|     lfs_testbd_t *bd = cfg->context; |  | ||||||
|  |  | ||||||
|     // check if read is valid |     // check if read is valid | ||||||
|     LFS_ASSERT(off  % cfg->read_size == 0); |     LFS_ASSERT(off  % bd->cfg.read_size == 0); | ||||||
|     LFS_ASSERT(size % cfg->read_size == 0); |     LFS_ASSERT(size % bd->cfg.read_size == 0); | ||||||
|     LFS_ASSERT(block < cfg->block_count); |     LFS_ASSERT(block < bd->cfg.erase_count); | ||||||
|  |  | ||||||
|     // block bad? |     // block bad? | ||||||
|     if (bd->cfg->erase_cycles && bd->wear[block] >= bd->cfg->erase_cycles && |     if (bd->cfg.erase_cycles && bd->wear[block] >= bd->cfg.erase_cycles && | ||||||
|             bd->cfg->badblock_behavior == LFS_TESTBD_BADBLOCK_READERROR) { |             bd->cfg.badblock_behavior == LFS_TESTBD_BADBLOCK_READERROR) { | ||||||
|         LFS_TESTBD_TRACE("lfs_testbd_read -> %d", LFS_ERR_CORRUPT); |         LFS_TESTBD_TRACE("lfs_testbd_read -> %d", LFS_ERR_CORRUPT); | ||||||
|         return LFS_ERR_CORRUPT; |         return LFS_ERR_CORRUPT; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // read |     // read | ||||||
|     int err = lfs_testbd_rawread(cfg, block, off, buffer, size); |     int err = lfs_testbd_rawread(bd, block, off, buffer, size); | ||||||
|     LFS_TESTBD_TRACE("lfs_testbd_read -> %d", err); |     LFS_TESTBD_TRACE("lfs_testbd_read -> %d", err); | ||||||
|     return err; |     return err; | ||||||
| } | } | ||||||
|  |  | ||||||
| int lfs_testbd_prog(const struct lfs_cfg *cfg, lfs_block_t block, | int lfs_testbd_prog(lfs_testbd_t *bd, lfs_block_t block, | ||||||
|         lfs_off_t off, const void *buffer, lfs_size_t size) { |         lfs_off_t off, const void *buffer, lfs_size_t size) { | ||||||
|     LFS_TESTBD_TRACE("lfs_testbd_prog(%p, " |     LFS_TESTBD_TRACE("lfs_testbd_prog(%p, " | ||||||
|                 "0x%"PRIx32", %"PRIu32", %p, %"PRIu32")", |                 "0x%"PRIx32", %"PRIu32", %p, %"PRIu32")", | ||||||
|             (void*)cfg, block, off, buffer, size); |             (void*)bd, block, off, buffer, size); | ||||||
|     lfs_testbd_t *bd = cfg->context; |  | ||||||
|  |  | ||||||
|     // check if write is valid |     // check if write is valid | ||||||
|     LFS_ASSERT(off  % cfg->prog_size == 0); |     LFS_ASSERT(off  % bd->cfg.prog_size == 0); | ||||||
|     LFS_ASSERT(size % cfg->prog_size == 0); |     LFS_ASSERT(size % bd->cfg.prog_size == 0); | ||||||
|     LFS_ASSERT(block < cfg->block_count); |     LFS_ASSERT(block < bd->cfg.erase_count); | ||||||
|  |  | ||||||
|     // block bad? |     // block bad? | ||||||
|     if (bd->cfg->erase_cycles && bd->wear[block] >= bd->cfg->erase_cycles) { |     if (bd->cfg.erase_cycles && bd->wear[block] >= bd->cfg.erase_cycles) { | ||||||
|         if (bd->cfg->badblock_behavior == |         if (bd->cfg.badblock_behavior == | ||||||
|                 LFS_TESTBD_BADBLOCK_PROGERROR) { |                 LFS_TESTBD_BADBLOCK_PROGERROR) { | ||||||
|             LFS_TESTBD_TRACE("lfs_testbd_prog -> %d", LFS_ERR_CORRUPT); |             LFS_TESTBD_TRACE("lfs_testbd_prog -> %d", LFS_ERR_CORRUPT); | ||||||
|             return LFS_ERR_CORRUPT; |             return LFS_ERR_CORRUPT; | ||||||
|         } else if (bd->cfg->badblock_behavior == |         } else if (bd->cfg.badblock_behavior == | ||||||
|                 LFS_TESTBD_BADBLOCK_PROGNOOP || |                 LFS_TESTBD_BADBLOCK_PROGNOOP || | ||||||
|                 bd->cfg->badblock_behavior == |                 bd->cfg.badblock_behavior == | ||||||
|                 LFS_TESTBD_BADBLOCK_ERASENOOP) { |                 LFS_TESTBD_BADBLOCK_ERASENOOP) { | ||||||
|             LFS_TESTBD_TRACE("lfs_testbd_prog -> %d", 0); |             LFS_TESTBD_TRACE("lfs_testbd_prog -> %d", 0); | ||||||
|             return 0; |             return 0; | ||||||
| @@ -196,7 +175,7 @@ int lfs_testbd_prog(const struct lfs_cfg *cfg, lfs_block_t block, | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     // prog |     // prog | ||||||
|     int err = lfs_testbd_rawprog(cfg, block, off, buffer, size); |     int err = lfs_testbd_rawprog(bd, block, off, buffer, size); | ||||||
|     if (err) { |     if (err) { | ||||||
|         LFS_TESTBD_TRACE("lfs_testbd_prog -> %d", err); |         LFS_TESTBD_TRACE("lfs_testbd_prog -> %d", err); | ||||||
|         return err; |         return err; | ||||||
| @@ -207,7 +186,7 @@ int lfs_testbd_prog(const struct lfs_cfg *cfg, lfs_block_t block, | |||||||
|         bd->power_cycles -= 1; |         bd->power_cycles -= 1; | ||||||
|         if (bd->power_cycles == 0) { |         if (bd->power_cycles == 0) { | ||||||
|             // sync to make sure we persist the last changes |             // sync to make sure we persist the last changes | ||||||
|             assert(lfs_testbd_rawsync(cfg) == 0); |             assert(lfs_testbd_rawsync(bd) == 0); | ||||||
|             // simulate power loss |             // simulate power loss | ||||||
|             exit(33); |             exit(33); | ||||||
|         } |         } | ||||||
| @@ -217,21 +196,20 @@ int lfs_testbd_prog(const struct lfs_cfg *cfg, lfs_block_t block, | |||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| int lfs_testbd_erase(const struct lfs_cfg *cfg, lfs_block_t block) { | int lfs_testbd_erase(lfs_testbd_t *bd, lfs_block_t block) { | ||||||
|     LFS_TESTBD_TRACE("lfs_testbd_erase(%p, 0x%"PRIx32")", (void*)cfg, block); |     LFS_TESTBD_TRACE("lfs_testbd_erase(%p, 0x%"PRIx32")", (void*)bd, block); | ||||||
|     lfs_testbd_t *bd = cfg->context; |  | ||||||
|  |  | ||||||
|     // check if erase is valid |     // check if erase is valid | ||||||
|     LFS_ASSERT(block < cfg->block_count); |     LFS_ASSERT(block < bd->cfg.erase_count); | ||||||
|  |  | ||||||
|     // block bad? |     // block bad? | ||||||
|     if (bd->cfg->erase_cycles) { |     if (bd->cfg.erase_cycles) { | ||||||
|         if (bd->wear[block] >= bd->cfg->erase_cycles) { |         if (bd->wear[block] >= bd->cfg.erase_cycles) { | ||||||
|             if (bd->cfg->badblock_behavior == |             if (bd->cfg.badblock_behavior == | ||||||
|                     LFS_TESTBD_BADBLOCK_ERASEERROR) { |                     LFS_TESTBD_BADBLOCK_ERASEERROR) { | ||||||
|                 LFS_TESTBD_TRACE("lfs_testbd_erase -> %d", LFS_ERR_CORRUPT); |                 LFS_TESTBD_TRACE("lfs_testbd_erase -> %d", LFS_ERR_CORRUPT); | ||||||
|                 return LFS_ERR_CORRUPT; |                 return LFS_ERR_CORRUPT; | ||||||
|             } else if (bd->cfg->badblock_behavior == |             } else if (bd->cfg.badblock_behavior == | ||||||
|                     LFS_TESTBD_BADBLOCK_ERASENOOP) { |                     LFS_TESTBD_BADBLOCK_ERASENOOP) { | ||||||
|                 LFS_TESTBD_TRACE("lfs_testbd_erase -> %d", 0); |                 LFS_TESTBD_TRACE("lfs_testbd_erase -> %d", 0); | ||||||
|                 return 0; |                 return 0; | ||||||
| @@ -243,7 +221,7 @@ int lfs_testbd_erase(const struct lfs_cfg *cfg, lfs_block_t block) { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     // erase |     // erase | ||||||
|     int err = lfs_testbd_rawerase(cfg, block); |     int err = lfs_testbd_rawerase(bd, block); | ||||||
|     if (err) { |     if (err) { | ||||||
|         LFS_TESTBD_TRACE("lfs_testbd_erase -> %d", err); |         LFS_TESTBD_TRACE("lfs_testbd_erase -> %d", err); | ||||||
|         return err; |         return err; | ||||||
| @@ -254,7 +232,7 @@ int lfs_testbd_erase(const struct lfs_cfg *cfg, lfs_block_t block) { | |||||||
|         bd->power_cycles -= 1; |         bd->power_cycles -= 1; | ||||||
|         if (bd->power_cycles == 0) { |         if (bd->power_cycles == 0) { | ||||||
|             // sync to make sure we persist the last changes |             // sync to make sure we persist the last changes | ||||||
|             assert(lfs_testbd_rawsync(cfg) == 0); |             assert(lfs_testbd_rawsync(bd) == 0); | ||||||
|             // simulate power loss |             // simulate power loss | ||||||
|             exit(33); |             exit(33); | ||||||
|         } |         } | ||||||
| @@ -264,36 +242,34 @@ int lfs_testbd_erase(const struct lfs_cfg *cfg, lfs_block_t block) { | |||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| int lfs_testbd_sync(const struct lfs_cfg *cfg) { | int lfs_testbd_sync(lfs_testbd_t *bd) { | ||||||
|     LFS_TESTBD_TRACE("lfs_testbd_sync(%p)", (void*)cfg); |     LFS_TESTBD_TRACE("lfs_testbd_sync(%p)", (void*)bd); | ||||||
|     int err = lfs_testbd_rawsync(cfg); |     int err = lfs_testbd_rawsync(bd); | ||||||
|     LFS_TESTBD_TRACE("lfs_testbd_sync -> %d", err); |     LFS_TESTBD_TRACE("lfs_testbd_sync -> %d", err); | ||||||
|     return err; |     return err; | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| /// simulated wear operations /// | /// simulated wear operations /// | ||||||
| lfs_testbd_swear_t lfs_testbd_getwear(const struct lfs_cfg *cfg, | lfs_testbd_swear_t lfs_testbd_getwear(lfs_testbd_t *bd, | ||||||
|         lfs_block_t block) { |         lfs_block_t block) { | ||||||
|     LFS_TESTBD_TRACE("lfs_testbd_getwear(%p, %"PRIu32")", (void*)cfg, block); |     LFS_TESTBD_TRACE("lfs_testbd_getwear(%p, %"PRIu32")", (void*)bd, block); | ||||||
|     lfs_testbd_t *bd = cfg->context; |  | ||||||
|  |  | ||||||
|     // check if block is valid |     // check if block is valid | ||||||
|     LFS_ASSERT(bd->cfg->erase_cycles); |     LFS_ASSERT(bd->cfg.erase_cycles); | ||||||
|     LFS_ASSERT(block < cfg->block_count); |     LFS_ASSERT(block < bd->cfg.erase_count); | ||||||
|  |  | ||||||
|     LFS_TESTBD_TRACE("lfs_testbd_getwear -> %"PRIu32, bd->wear[block]); |     LFS_TESTBD_TRACE("lfs_testbd_getwear -> %"PRIu32, bd->wear[block]); | ||||||
|     return bd->wear[block]; |     return bd->wear[block]; | ||||||
| } | } | ||||||
|  |  | ||||||
| int lfs_testbd_setwear(const struct lfs_cfg *cfg, | int lfs_testbd_setwear(lfs_testbd_t *bd, | ||||||
|         lfs_block_t block, lfs_testbd_wear_t wear) { |         lfs_block_t block, lfs_testbd_wear_t wear) { | ||||||
|     LFS_TESTBD_TRACE("lfs_testbd_setwear(%p, %"PRIu32")", (void*)cfg, block); |     LFS_TESTBD_TRACE("lfs_testbd_setwear(%p, %"PRIu32")", (void*)bd, block); | ||||||
|     lfs_testbd_t *bd = cfg->context; |  | ||||||
|  |  | ||||||
|     // check if block is valid |     // check if block is valid | ||||||
|     LFS_ASSERT(bd->cfg->erase_cycles); |     LFS_ASSERT(bd->cfg.erase_cycles); | ||||||
|     LFS_ASSERT(block < cfg->block_count); |     LFS_ASSERT(block < bd->cfg.erase_count); | ||||||
|  |  | ||||||
|     bd->wear[block] = wear; |     bd->wear[block] = wear; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -13,8 +13,7 @@ | |||||||
| #include "bd/lfs_filebd.h" | #include "bd/lfs_filebd.h" | ||||||
|  |  | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| extern "C" | extern "C" { | ||||||
| { |  | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -45,6 +44,20 @@ typedef int32_t  lfs_testbd_swear_t; | |||||||
|  |  | ||||||
| // testbd config, this is required for testing | // testbd config, this is required for testing | ||||||
| struct lfs_testbd_cfg { | struct lfs_testbd_cfg { | ||||||
|  |     // Minimum size of block read. All read operations must be a | ||||||
|  |     // multiple of this value. | ||||||
|  |     lfs_size_t read_size; | ||||||
|  |  | ||||||
|  |     // Minimum size of block program. All program operations must be a | ||||||
|  |     // multiple of this value. | ||||||
|  |     lfs_size_t prog_size; | ||||||
|  |  | ||||||
|  |     // Size of an erasable block. | ||||||
|  |     lfs_size_t erase_size; | ||||||
|  |  | ||||||
|  |     // Number of erasable blocks on the device. | ||||||
|  |     lfs_size_t erase_count; | ||||||
|  |  | ||||||
|     // 8-bit erase value to use for simulating erases. -1 does not simulate |     // 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 all the extra block-device | ||||||
|     // operations to store the erase value. |     // operations to store the erase value. | ||||||
| @@ -71,21 +84,15 @@ struct lfs_testbd_cfg { | |||||||
| // testbd state | // testbd state | ||||||
| typedef struct lfs_testbd { | typedef struct lfs_testbd { | ||||||
|     union { |     union { | ||||||
|         struct { |         lfs_filebd_t filebd; | ||||||
|             lfs_filebd_t bd; |         lfs_rambd_t rambd; | ||||||
|             struct lfs_filebd_cfg cfg; |     } impl; | ||||||
|         } file; |  | ||||||
|         struct { |  | ||||||
|             lfs_rambd_t bd; |  | ||||||
|             struct lfs_rambd_cfg cfg; |  | ||||||
|         } ram; |  | ||||||
|     } u; |  | ||||||
|  |  | ||||||
|     bool persist; |     bool persist; | ||||||
|     uint32_t power_cycles; |     uint32_t power_cycles; | ||||||
|     lfs_testbd_wear_t *wear; |     lfs_testbd_wear_t *wear; | ||||||
|  |  | ||||||
|     const struct lfs_testbd_cfg *cfg; |     struct lfs_testbd_cfg cfg; | ||||||
| } lfs_testbd_t; | } lfs_testbd_t; | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -95,46 +102,45 @@ typedef struct lfs_testbd { | |||||||
| // | // | ||||||
| // Note that filebd is used if a path is provided, if path is NULL | // Note that filebd is used if a path is provided, if path is NULL | ||||||
| // testbd will use rambd which can be much faster. | // testbd will use rambd which can be much faster. | ||||||
| int lfs_testbd_create(const struct lfs_cfg *cfg, const char *path); | int lfs_testbd_createcfg(lfs_testbd_t *bd, const char *path, | ||||||
| int lfs_testbd_createcfg(const struct lfs_cfg *cfg, const char *path, |         const struct lfs_testbd_cfg *cfg); | ||||||
|         const struct lfs_testbd_cfg *bdcfg); |  | ||||||
|  |  | ||||||
| // Clean up memory associated with block device | // Clean up memory associated with block device | ||||||
| int lfs_testbd_destroy(const struct lfs_cfg *cfg); | int lfs_testbd_destroy(lfs_testbd_t *bd); | ||||||
|  |  | ||||||
| // Read a block | // Read a block | ||||||
| int lfs_testbd_read(const struct lfs_cfg *cfg, lfs_block_t block, | int lfs_testbd_read(lfs_testbd_t *bd, lfs_block_t block, | ||||||
|         lfs_off_t off, void *buffer, lfs_size_t size); |         lfs_off_t off, void *buffer, lfs_size_t size); | ||||||
|  |  | ||||||
| // Program a block | // Program a block | ||||||
| // | // | ||||||
| // The block must have previously been erased. | // The block must have previously been erased. | ||||||
| int lfs_testbd_prog(const struct lfs_cfg *cfg, lfs_block_t block, | int lfs_testbd_prog(lfs_testbd_t *bd, lfs_block_t block, | ||||||
|         lfs_off_t off, const void *buffer, lfs_size_t size); |         lfs_off_t off, const void *buffer, lfs_size_t size); | ||||||
|  |  | ||||||
| // Erase a block | // Erase a block | ||||||
| // | // | ||||||
| // A block must be erased before being programmed. The | // A block must be erased before being programmed. The | ||||||
| // state of an erased block is undefined. | // state of an erased block is undefined. | ||||||
| int lfs_testbd_erase(const struct lfs_cfg *cfg, lfs_block_t block); | int lfs_testbd_erase(lfs_testbd_t *bd, lfs_block_t block); | ||||||
|  |  | ||||||
| // Sync the block device | // Sync the block device | ||||||
| int lfs_testbd_sync(const struct lfs_cfg *cfg); | int lfs_testbd_sync(lfs_testbd_t *bd); | ||||||
|  |  | ||||||
|  |  | ||||||
| /// Additional extended API for driving test features /// | /// Additional extended API for driving test features /// | ||||||
|  |  | ||||||
| // Get simulated wear on a given block | // Get simulated wear on a given block | ||||||
| lfs_testbd_swear_t lfs_testbd_getwear(const struct lfs_cfg *cfg, | lfs_testbd_swear_t lfs_testbd_getwear(lfs_testbd_t *bd, | ||||||
|         lfs_block_t block); |         lfs_block_t block); | ||||||
|  |  | ||||||
| // Manually set simulated wear on a given block | // Manually set simulated wear on a given block | ||||||
| int lfs_testbd_setwear(const struct lfs_cfg *cfg, | int lfs_testbd_setwear(lfs_testbd_t *bd, | ||||||
|         lfs_block_t block, lfs_testbd_wear_t wear); |         lfs_block_t block, lfs_testbd_wear_t wear); | ||||||
|  |  | ||||||
|  |  | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| } /* extern "C" */ | } | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| #endif | #endif | ||||||
|   | |||||||
							
								
								
									
										20
									
								
								lfs.c
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								lfs.c
									
									
									
									
									
								
							| @@ -34,13 +34,13 @@ | |||||||
| #else | #else | ||||||
| // direct config towards dynamic lfs_cfg struct | // direct config towards dynamic lfs_cfg struct | ||||||
| #define LFS_CFG_READ(lfs, block, off, buffer, size) \ | #define LFS_CFG_READ(lfs, block, off, buffer, size) \ | ||||||
|     lfs->cfg->read(lfs->cfg, block, off, buffer, size) |     lfs->cfg->read(lfs->cfg->ctx, block, off, buffer, size) | ||||||
| #define LFS_CFG_PROG(lfs, block, off, buffer, size) \ | #define LFS_CFG_PROG(lfs, block, off, buffer, size) \ | ||||||
|     lfs->cfg->prog(lfs->cfg, block, off, buffer, size) |     lfs->cfg->prog(lfs->cfg->ctx, block, off, buffer, size) | ||||||
| #define LFS_CFG_ERASE(lfs, block) \ | #define LFS_CFG_ERASE(lfs, block) \ | ||||||
|     lfs->cfg->erase(lfs->cfg, block) |     lfs->cfg->erase(lfs->cfg->ctx, block) | ||||||
| #define LFS_CFG_SYNC(lfs) \ | #define LFS_CFG_SYNC(lfs) \ | ||||||
|     lfs->cfg->sync(lfs->cfg) |     lfs->cfg->sync(lfs->cfg->ctx) | ||||||
| #define LFS_CFG_READ_SIZE(lfs)          lfs->cfg->read_size | #define LFS_CFG_READ_SIZE(lfs)          lfs->cfg->read_size | ||||||
| #define LFS_CFG_PROG_SIZE(lfs)          lfs->cfg->prog_size | #define LFS_CFG_PROG_SIZE(lfs)          lfs->cfg->prog_size | ||||||
| #define LFS_CFG_BLOCK_SIZE(lfs)         lfs->cfg->block_size | #define LFS_CFG_BLOCK_SIZE(lfs)         lfs->cfg->block_size | ||||||
| @@ -3732,7 +3732,7 @@ int lfs_format(lfs_t *lfs) { | |||||||
|  |  | ||||||
| #if !defined(LFS_STATICCFG) | #if !defined(LFS_STATICCFG) | ||||||
| int lfs_formatcfg(lfs_t *lfs, const struct lfs_cfg *cfg) { | int lfs_formatcfg(lfs_t *lfs, const struct lfs_cfg *cfg) { | ||||||
|     LFS_TRACE("lfs_formatcfg(%p, %p {.context=%p, " |     LFS_TRACE("lfs_formatcfg(%p, %p {.ctx=%p, " | ||||||
|                 ".read=%p, .prog=%p, .erase=%p, .sync=%p, " |                 ".read=%p, .prog=%p, .erase=%p, .sync=%p, " | ||||||
|                 ".read_size=%"PRIu32", .prog_size=%"PRIu32", " |                 ".read_size=%"PRIu32", .prog_size=%"PRIu32", " | ||||||
|                 ".block_size=%"PRIu32", .block_count=%"PRIu32", " |                 ".block_size=%"PRIu32", .block_count=%"PRIu32", " | ||||||
| @@ -3741,7 +3741,7 @@ int lfs_formatcfg(lfs_t *lfs, const struct lfs_cfg *cfg) { | |||||||
|                 ".prog_buffer=%p, .lookahead_buffer=%p, " |                 ".prog_buffer=%p, .lookahead_buffer=%p, " | ||||||
|                 ".name_max=%"PRIu32", .file_max=%"PRIu32", " |                 ".name_max=%"PRIu32", .file_max=%"PRIu32", " | ||||||
|                 ".attr_max=%"PRIu32"})", |                 ".attr_max=%"PRIu32"})", | ||||||
|             (void*)lfs, (void*)cfg, cfg->context, |             (void*)lfs, (void*)cfg, cfg->ctx, | ||||||
|             (void*)(uintptr_t)cfg->read, (void*)(uintptr_t)cfg->prog, |             (void*)(uintptr_t)cfg->read, (void*)(uintptr_t)cfg->prog, | ||||||
|             (void*)(uintptr_t)cfg->erase, (void*)(uintptr_t)cfg->sync, |             (void*)(uintptr_t)cfg->erase, (void*)(uintptr_t)cfg->sync, | ||||||
|             cfg->read_size, cfg->prog_size, cfg->block_size, cfg->block_count, |             cfg->read_size, cfg->prog_size, cfg->block_size, cfg->block_count, | ||||||
| @@ -3893,7 +3893,7 @@ int lfs_mount(lfs_t *lfs) { | |||||||
|  |  | ||||||
| #if !defined(LFS_STATICCFG) | #if !defined(LFS_STATICCFG) | ||||||
| int lfs_mountcfg(lfs_t *lfs, const struct lfs_cfg *cfg) { | int lfs_mountcfg(lfs_t *lfs, const struct lfs_cfg *cfg) { | ||||||
|     LFS_TRACE("lfs_mountcfg(%p, %p {.context=%p, " |     LFS_TRACE("lfs_mountcfg(%p, %p {.ctx=%p, " | ||||||
|                 ".read=%p, .prog=%p, .erase=%p, .sync=%p, " |                 ".read=%p, .prog=%p, .erase=%p, .sync=%p, " | ||||||
|                 ".read_size=%"PRIu32", .prog_size=%"PRIu32", " |                 ".read_size=%"PRIu32", .prog_size=%"PRIu32", " | ||||||
|                 ".block_size=%"PRIu32", .block_count=%"PRIu32", " |                 ".block_size=%"PRIu32", .block_count=%"PRIu32", " | ||||||
| @@ -3902,7 +3902,7 @@ int lfs_mountcfg(lfs_t *lfs, const struct lfs_cfg *cfg) { | |||||||
|                 ".prog_buffer=%p, .lookahead_buffer=%p, " |                 ".prog_buffer=%p, .lookahead_buffer=%p, " | ||||||
|                 ".name_max=%"PRIu32", .file_max=%"PRIu32", " |                 ".name_max=%"PRIu32", .file_max=%"PRIu32", " | ||||||
|                 ".attr_max=%"PRIu32"})", |                 ".attr_max=%"PRIu32"})", | ||||||
|             (void*)lfs, (void*)cfg, cfg->context, |             (void*)lfs, (void*)cfg, cfg->ctx, | ||||||
|             (void*)(uintptr_t)cfg->read, (void*)(uintptr_t)cfg->prog, |             (void*)(uintptr_t)cfg->read, (void*)(uintptr_t)cfg->prog, | ||||||
|             (void*)(uintptr_t)cfg->erase, (void*)(uintptr_t)cfg->sync, |             (void*)(uintptr_t)cfg->erase, (void*)(uintptr_t)cfg->sync, | ||||||
|             cfg->read_size, cfg->prog_size, cfg->block_size, cfg->block_count, |             cfg->read_size, cfg->prog_size, cfg->block_size, cfg->block_count, | ||||||
| @@ -5009,7 +5009,7 @@ int lfs_migrate(lfs_t *lfs) { | |||||||
|  |  | ||||||
| #if !defined(LFS_STATICCFG) | #if !defined(LFS_STATICCFG) | ||||||
| int lfs_migratecfg(lfs_t *lfs, const struct lfs_cfg *cfg) { | int lfs_migratecfg(lfs_t *lfs, const struct lfs_cfg *cfg) { | ||||||
|     LFS_TRACE("lfs_migratecfg(%p, %p {.context=%p, " |     LFS_TRACE("lfs_migratecfg(%p, %p {.ctx=%p, " | ||||||
|                 ".read=%p, .prog=%p, .erase=%p, .sync=%p, " |                 ".read=%p, .prog=%p, .erase=%p, .sync=%p, " | ||||||
|                 ".read_size=%"PRIu32", .prog_size=%"PRIu32", " |                 ".read_size=%"PRIu32", .prog_size=%"PRIu32", " | ||||||
|                 ".block_size=%"PRIu32", .block_count=%"PRIu32", " |                 ".block_size=%"PRIu32", .block_count=%"PRIu32", " | ||||||
| @@ -5018,7 +5018,7 @@ int lfs_migratecfg(lfs_t *lfs, const struct lfs_cfg *cfg) { | |||||||
|                 ".prog_buffer=%p, .lookahead_buffer=%p, " |                 ".prog_buffer=%p, .lookahead_buffer=%p, " | ||||||
|                 ".name_max=%"PRIu32", .file_max=%"PRIu32", " |                 ".name_max=%"PRIu32", .file_max=%"PRIu32", " | ||||||
|                 ".attr_max=%"PRIu32"})", |                 ".attr_max=%"PRIu32"})", | ||||||
|             (void*)lfs, (void*)cfg, cfg->context, |             (void*)lfs, (void*)cfg, cfg->ctx, | ||||||
|             (void*)(uintptr_t)cfg->read, (void*)(uintptr_t)cfg->prog, |             (void*)(uintptr_t)cfg->read, (void*)(uintptr_t)cfg->prog, | ||||||
|             (void*)(uintptr_t)cfg->erase, (void*)(uintptr_t)cfg->sync, |             (void*)(uintptr_t)cfg->erase, (void*)(uintptr_t)cfg->sync, | ||||||
|             cfg->read_size, cfg->prog_size, cfg->block_size, cfg->block_count, |             cfg->read_size, cfg->prog_size, cfg->block_size, cfg->block_count, | ||||||
|   | |||||||
							
								
								
									
										19
									
								
								lfs.h
									
									
									
									
									
								
							
							
						
						
									
										19
									
								
								lfs.h
									
									
									
									
									
								
							| @@ -130,28 +130,28 @@ enum lfs_whence_flags { | |||||||
| struct lfs_cfg { | struct lfs_cfg { | ||||||
|     // Opaque user provided context that can be used to pass |     // Opaque user provided context that can be used to pass | ||||||
|     // information to the block device operations |     // information to the block device operations | ||||||
|     void *context; |     void *ctx; | ||||||
|  |  | ||||||
|     // Read a region in a block. Negative error codes are propogated |     // Read a region in a block. Negative error codes are propogated | ||||||
|     // to the user. |     // to the user. | ||||||
|     int (*read)(const struct lfs_cfg *c, lfs_block_t block, |     int (*read)(void *ctx, lfs_block_t block, | ||||||
|             lfs_off_t off, void *buffer, lfs_size_t size); |             lfs_off_t off, void *buffer, lfs_size_t size); | ||||||
|  |  | ||||||
|     // Program a region in a block. The block must have previously |     // Program a region in a block. The block must have previously | ||||||
|     // been erased. Negative error codes are propogated to the user. |     // been erased. Negative error codes are propogated to the user. | ||||||
|     // May return LFS_ERR_CORRUPT if the block should be considered bad. |     // May return LFS_ERR_CORRUPT if the block should be considered bad. | ||||||
|     int (*prog)(const struct lfs_cfg *c, lfs_block_t block, |     int (*prog)(void *ctx, lfs_block_t block, | ||||||
|             lfs_off_t off, const void *buffer, lfs_size_t size); |             lfs_off_t off, const void *buffer, lfs_size_t size); | ||||||
|  |  | ||||||
|     // Erase a block. A block must be erased before being programmed. |     // Erase a block. A block must be erased before being programmed. | ||||||
|     // The state of an erased block is undefined. Negative error codes |     // The state of an erased block is undefined. Negative error codes | ||||||
|     // are propogated to the user. |     // are propogated to the user. | ||||||
|     // May return LFS_ERR_CORRUPT if the block should be considered bad. |     // May return LFS_ERR_CORRUPT if the block should be considered bad. | ||||||
|     int (*erase)(const struct lfs_cfg *c, lfs_block_t block); |     int (*erase)(void *ctx, lfs_block_t block); | ||||||
|  |  | ||||||
|     // Sync the state of the underlying block device. Negative error codes |     // Sync the state of the underlying block device. Negative error codes | ||||||
|     // are propogated to the user. |     // are propogated to the user. | ||||||
|     int (*sync)(const struct lfs_cfg *c); |     int (*sync)(void *ctx); | ||||||
|  |  | ||||||
|     // Minimum size of a block read. All read operations will be a |     // Minimum size of a block read. All read operations will be a | ||||||
|     // multiple of this value. |     // multiple of this value. | ||||||
| @@ -266,15 +266,6 @@ int lfs_sync(void); | |||||||
| #ifndef LFS_LOOKAHEAD_BUFFER | #ifndef LFS_LOOKAHEAD_BUFFER | ||||||
| #define LFS_LOOKAHEAD_BUFFER NULL | #define LFS_LOOKAHEAD_BUFFER NULL | ||||||
| #endif | #endif | ||||||
| #ifndef LFS_NAME_MAX |  | ||||||
| #define LFS_NAME_MAX 0 |  | ||||||
| #endif |  | ||||||
| #ifndef LFS_FILE_MAX |  | ||||||
| #define LFS_FILE_MAX 0 |  | ||||||
| #endif |  | ||||||
| #ifndef LFS_ATTR_MAX |  | ||||||
| #define LFS_ATTR_MAX 0 |  | ||||||
| #endif |  | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| #if !defined(LFS_FILE_STATICCFG) | #if !defined(LFS_FILE_STATICCFG) | ||||||
|   | |||||||
| @@ -34,13 +34,43 @@ $(foreach target,$(SRC),$(eval $(FLATTEN))) | |||||||
| %.test: %.test.o $(foreach f,$(subst /,.,$(SRC:.c=.o)),%.$f) | %.test: %.test.o $(foreach f,$(subst /,.,$(SRC:.c=.o)),%.$f) | ||||||
|     $(CC) $(CFLAGS) $^ $(LFLAGS) -o $@ |     $(CC) $(CFLAGS) $^ $(LFLAGS) -o $@ | ||||||
| """ | """ | ||||||
| GLOBALS = """ | BEFORE_MAIN = """ | ||||||
|  | const char *lfs_testbd_path; | ||||||
|  | uint32_t lfs_testbd_cycles; | ||||||
|  |  | ||||||
|  | int lfs_testbd_readctx(void *ctx, lfs_block_t block, | ||||||
|  |         lfs_off_t off, void *buffer, lfs_size_t size) { | ||||||
|  |     return lfs_testbd_read((lfs_testbd_t*)ctx, block, off, buffer, size); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int lfs_testbd_progctx(void *ctx, lfs_block_t block, | ||||||
|  |         lfs_off_t off, const void *buffer, lfs_size_t size) { | ||||||
|  |     return lfs_testbd_prog((lfs_testbd_t*)ctx, block, off, buffer, size); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int lfs_testbd_erasectx(void *ctx, lfs_block_t block) { | ||||||
|  |     return lfs_testbd_erase((lfs_testbd_t*)ctx, block); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int lfs_testbd_syncctx(void *ctx) { | ||||||
|  |     return lfs_testbd_sync((lfs_testbd_t*)ctx); | ||||||
|  | } | ||||||
|  | """ | ||||||
|  | BEFORE_TESTS = """ | ||||||
| //////////////// AUTOGENERATED TEST //////////////// | //////////////// AUTOGENERATED TEST //////////////// | ||||||
| #include "lfs.h" | #include "lfs.h" | ||||||
| #include "bd/lfs_testbd.h" | #include "bd/lfs_testbd.h" | ||||||
| #include <stdio.h> | #include <stdio.h> | ||||||
|  |  | ||||||
| extern const char *lfs_testbd_path; | extern const char *lfs_testbd_path; | ||||||
| extern uint32_t lfs_testbd_cycles; | extern uint32_t lfs_testbd_cycles; | ||||||
|  |  | ||||||
|  | extern int lfs_testbd_readctx(void *ctx, lfs_block_t block, | ||||||
|  |         lfs_off_t off, void *buffer, lfs_size_t size); | ||||||
|  | extern int lfs_testbd_progctx(void *ctx, lfs_block_t block, | ||||||
|  |         lfs_off_t off, const void *buffer, lfs_size_t size); | ||||||
|  | extern int lfs_testbd_erasectx(void *ctx, lfs_block_t block); | ||||||
|  | extern int lfs_testbd_syncctx(void *ctx); | ||||||
| """ | """ | ||||||
| DEFINES = { | DEFINES = { | ||||||
|     'LFS_READ_SIZE': 16, |     'LFS_READ_SIZE': 16, | ||||||
| @@ -67,11 +97,11 @@ PROLOGUE = """ | |||||||
|     __attribute__((unused)) int err; |     __attribute__((unused)) int err; | ||||||
|      |      | ||||||
|     __attribute__((unused)) const struct lfs_cfg cfg = { |     __attribute__((unused)) const struct lfs_cfg cfg = { | ||||||
|         .context        = &bd, |         .ctx            = &bd, | ||||||
|         .read           = lfs_testbd_read, |         .read           = lfs_testbd_readctx, | ||||||
|         .prog           = lfs_testbd_prog, |         .prog           = lfs_testbd_progctx, | ||||||
|         .erase          = lfs_testbd_erase, |         .erase          = lfs_testbd_erasectx, | ||||||
|         .sync           = lfs_testbd_sync, |         .sync           = lfs_testbd_syncctx, | ||||||
|         .read_size      = LFS_READ_SIZE, |         .read_size      = LFS_READ_SIZE, | ||||||
|         .prog_size      = LFS_PROG_SIZE, |         .prog_size      = LFS_PROG_SIZE, | ||||||
|         .block_size     = LFS_BLOCK_SIZE, |         .block_size     = LFS_BLOCK_SIZE, | ||||||
| @@ -82,17 +112,21 @@ PROLOGUE = """ | |||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     __attribute__((unused)) const struct lfs_testbd_cfg bdcfg = { |     __attribute__((unused)) const struct lfs_testbd_cfg bdcfg = { | ||||||
|  |         .read_size          = LFS_READ_SIZE, | ||||||
|  |         .prog_size          = LFS_PROG_SIZE, | ||||||
|  |         .erase_size         = LFS_BLOCK_SIZE, | ||||||
|  |         .erase_count        = LFS_BLOCK_COUNT, | ||||||
|         .erase_value        = LFS_ERASE_VALUE, |         .erase_value        = LFS_ERASE_VALUE, | ||||||
|         .erase_cycles       = LFS_ERASE_CYCLES, |         .erase_cycles       = LFS_ERASE_CYCLES, | ||||||
|         .badblock_behavior  = LFS_BADBLOCK_BEHAVIOR, |         .badblock_behavior  = LFS_BADBLOCK_BEHAVIOR, | ||||||
|         .power_cycles       = lfs_testbd_cycles, |         .power_cycles       = lfs_testbd_cycles, | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     lfs_testbd_createcfg(&cfg, lfs_testbd_path, &bdcfg) => 0; |     lfs_testbd_createcfg(&bd, lfs_testbd_path, &bdcfg) => 0; | ||||||
| """ | """ | ||||||
| EPILOGUE = """ | EPILOGUE = """ | ||||||
|     // epilogue |     // epilogue | ||||||
|     lfs_testbd_destroy(&cfg) => 0; |     lfs_testbd_destroy(&bd) => 0; | ||||||
| """ | """ | ||||||
| PASS = '\033[32m✓\033[0m' | PASS = '\033[32m✓\033[0m' | ||||||
| FAIL = '\033[31m✗\033[0m' | FAIL = '\033[31m✗\033[0m' | ||||||
| @@ -468,7 +502,7 @@ class TestSuite: | |||||||
|     def build(self, **args): |     def build(self, **args): | ||||||
|         # build test files |         # build test files | ||||||
|         tf = open(self.path + '.test.c.t', 'w') |         tf = open(self.path + '.test.c.t', 'w') | ||||||
|         tf.write(GLOBALS) |         tf.write(BEFORE_TESTS) | ||||||
|         if self.code is not None: |         if self.code is not None: | ||||||
|             tf.write('#line %d "%s"\n' % (self.code_lineno, self.path)) |             tf.write('#line %d "%s"\n' % (self.code_lineno, self.path)) | ||||||
|             tf.write(self.code) |             tf.write(self.code) | ||||||
| @@ -483,14 +517,13 @@ class TestSuite: | |||||||
|                     for line in f: |                     for line in f: | ||||||
|                         tfs[case.in_].write(line) |                         tfs[case.in_].write(line) | ||||||
|                 tfs[case.in_].write('\n') |                 tfs[case.in_].write('\n') | ||||||
|                 tfs[case.in_].write(GLOBALS) |                 tfs[case.in_].write(BEFORE_TESTS) | ||||||
|  |  | ||||||
|             tfs[case.in_].write('\n') |             tfs[case.in_].write('\n') | ||||||
|             case.build(tfs[case.in_], **args) |             case.build(tfs[case.in_], **args) | ||||||
|  |  | ||||||
|  |         tf.write(BEFORE_MAIN) | ||||||
|         tf.write('\n') |         tf.write('\n') | ||||||
|         tf.write('const char *lfs_testbd_path;\n') |  | ||||||
|         tf.write('uint32_t lfs_testbd_cycles;\n') |  | ||||||
|         tf.write('int main(int argc, char **argv) {\n') |         tf.write('int main(int argc, char **argv) {\n') | ||||||
|         tf.write(4*' '+'int case_         = (argc > 1) ? atoi(argv[1]) : 0;\n') |         tf.write(4*' '+'int case_         = (argc > 1) ? atoi(argv[1]) : 0;\n') | ||||||
|         tf.write(4*' '+'int perm          = (argc > 2) ? atoi(argv[2]) : 0;\n') |         tf.write(4*' '+'int perm          = (argc > 2) ? atoi(argv[2]) : 0;\n') | ||||||
|   | |||||||
| @@ -362,7 +362,7 @@ code = ''' | |||||||
|  |  | ||||||
|     // but mark the head of our file as a "bad block", this is force our |     // but mark the head of our file as a "bad block", this is force our | ||||||
|     // scan to bail early |     // scan to bail early | ||||||
|     lfs_testbd_setwear(&cfg, fileblock, 0xffffffff) => 0; |     lfs_testbd_setwear(&bd, fileblock, 0xffffffff) => 0; | ||||||
|     lfs_file_open(&lfs, &file, "ghost", LFS_O_WRONLY | LFS_O_CREAT) => 0; |     lfs_file_open(&lfs, &file, "ghost", LFS_O_WRONLY | LFS_O_CREAT) => 0; | ||||||
|     strcpy((char*)buffer, "chomp"); |     strcpy((char*)buffer, "chomp"); | ||||||
|     size = strlen("chomp"); |     size = strlen("chomp"); | ||||||
| @@ -377,7 +377,7 @@ code = ''' | |||||||
|  |  | ||||||
|     // now reverse the "bad block" and try to write the file again until we |     // now reverse the "bad block" and try to write the file again until we | ||||||
|     // run out of space |     // run out of space | ||||||
|     lfs_testbd_setwear(&cfg, fileblock, 0) => 0; |     lfs_testbd_setwear(&bd, fileblock, 0) => 0; | ||||||
|     lfs_file_open(&lfs, &file, "ghost", LFS_O_WRONLY | LFS_O_CREAT) => 0; |     lfs_file_open(&lfs, &file, "ghost", LFS_O_WRONLY | LFS_O_CREAT) => 0; | ||||||
|     strcpy((char*)buffer, "chomp"); |     strcpy((char*)buffer, "chomp"); | ||||||
|     size = strlen("chomp"); |     size = strlen("chomp"); | ||||||
|   | |||||||
| @@ -16,8 +16,8 @@ define.NAMEMULT = 64 | |||||||
| define.FILEMULT = 1 | define.FILEMULT = 1 | ||||||
| code = ''' | code = ''' | ||||||
|     for (lfs_block_t badblock = 2; badblock < LFS_BLOCK_COUNT; badblock++) { |     for (lfs_block_t badblock = 2; badblock < LFS_BLOCK_COUNT; badblock++) { | ||||||
|         lfs_testbd_setwear(&cfg, badblock-1, 0) => 0; |         lfs_testbd_setwear(&bd, badblock-1, 0) => 0; | ||||||
|         lfs_testbd_setwear(&cfg, badblock, 0xffffffff) => 0; |         lfs_testbd_setwear(&bd, badblock, 0xffffffff) => 0; | ||||||
|          |          | ||||||
|         lfs_formatcfg(&lfs, &cfg) => 0; |         lfs_formatcfg(&lfs, &cfg) => 0; | ||||||
|  |  | ||||||
| @@ -90,7 +90,7 @@ define.NAMEMULT = 64 | |||||||
| define.FILEMULT = 1 | define.FILEMULT = 1 | ||||||
| code = ''' | code = ''' | ||||||
|     for (lfs_block_t i = 0; i < (LFS_BLOCK_COUNT-2)/2; i++) { |     for (lfs_block_t i = 0; i < (LFS_BLOCK_COUNT-2)/2; i++) { | ||||||
|         lfs_testbd_setwear(&cfg, i+2, 0xffffffff) => 0; |         lfs_testbd_setwear(&bd, i+2, 0xffffffff) => 0; | ||||||
|     } |     } | ||||||
|      |      | ||||||
|     lfs_formatcfg(&lfs, &cfg) => 0; |     lfs_formatcfg(&lfs, &cfg) => 0; | ||||||
| @@ -163,7 +163,7 @@ define.NAMEMULT = 64 | |||||||
| define.FILEMULT = 1 | define.FILEMULT = 1 | ||||||
| code = ''' | code = ''' | ||||||
|     for (lfs_block_t i = 0; i < (LFS_BLOCK_COUNT-2)/2; i++) { |     for (lfs_block_t i = 0; i < (LFS_BLOCK_COUNT-2)/2; i++) { | ||||||
|         lfs_testbd_setwear(&cfg, (2*i) + 2, 0xffffffff) => 0; |         lfs_testbd_setwear(&bd, (2*i) + 2, 0xffffffff) => 0; | ||||||
|     } |     } | ||||||
|      |      | ||||||
|     lfs_formatcfg(&lfs, &cfg) => 0; |     lfs_formatcfg(&lfs, &cfg) => 0; | ||||||
| @@ -233,8 +233,8 @@ define.LFS_BADBLOCK_BEHAVIOR = [ | |||||||
|     'LFS_TESTBD_BADBLOCK_ERASENOOP', |     'LFS_TESTBD_BADBLOCK_ERASENOOP', | ||||||
| ] | ] | ||||||
| code = ''' | code = ''' | ||||||
|     lfs_testbd_setwear(&cfg, 0, 0xffffffff) => 0; |     lfs_testbd_setwear(&bd, 0, 0xffffffff) => 0; | ||||||
|     lfs_testbd_setwear(&cfg, 1, 0xffffffff) => 0; |     lfs_testbd_setwear(&bd, 1, 0xffffffff) => 0; | ||||||
|  |  | ||||||
|     lfs_formatcfg(&lfs, &cfg) => LFS_ERR_NOSPC; |     lfs_formatcfg(&lfs, &cfg) => LFS_ERR_NOSPC; | ||||||
|     lfs_mountcfg(&lfs, &cfg) => LFS_ERR_CORRUPT; |     lfs_mountcfg(&lfs, &cfg) => LFS_ERR_CORRUPT; | ||||||
|   | |||||||
| @@ -158,12 +158,12 @@ code = ''' | |||||||
|     lfs_ctz_fromle32(&ctz); |     lfs_ctz_fromle32(&ctz); | ||||||
|     // rewrite block to contain bad pointer |     // rewrite block to contain bad pointer | ||||||
|     uint8_t bbuffer[LFS_BLOCK_SIZE]; |     uint8_t bbuffer[LFS_BLOCK_SIZE]; | ||||||
|     cfg.read(&cfg, ctz.head, 0, bbuffer, LFS_BLOCK_SIZE) => 0; |     lfs_testbd_read(&bd, ctz.head, 0, bbuffer, LFS_BLOCK_SIZE) => 0; | ||||||
|     uint32_t bad = lfs_tole32(0xcccccccc); |     uint32_t bad = lfs_tole32(0xcccccccc); | ||||||
|     memcpy(&bbuffer[0], &bad, sizeof(bad)); |     memcpy(&bbuffer[0], &bad, sizeof(bad)); | ||||||
|     memcpy(&bbuffer[4], &bad, sizeof(bad)); |     memcpy(&bbuffer[4], &bad, sizeof(bad)); | ||||||
|     cfg.erase(&cfg, ctz.head) => 0; |     lfs_testbd_erase(&bd, ctz.head) => 0; | ||||||
|     cfg.prog(&cfg, ctz.head, 0, bbuffer, LFS_BLOCK_SIZE) => 0; |     lfs_testbd_prog(&bd, ctz.head, 0, bbuffer, LFS_BLOCK_SIZE) => 0; | ||||||
|     lfs_deinit(&lfs) => 0; |     lfs_deinit(&lfs) => 0; | ||||||
|  |  | ||||||
|     // test that accessing our bad file fails, note there's a number |     // test that accessing our bad file fails, note there's a number | ||||||
|   | |||||||
| @@ -180,7 +180,7 @@ code = ''' | |||||||
|  |  | ||||||
|     for (int run = 0; run < 2; run++) { |     for (int run = 0; run < 2; run++) { | ||||||
|         for (lfs_block_t b = 0; b < LFS_BLOCK_COUNT; b++) { |         for (lfs_block_t b = 0; b < LFS_BLOCK_COUNT; b++) { | ||||||
|             lfs_testbd_setwear(&cfg, b, |             lfs_testbd_setwear(&bd, b, | ||||||
|                     (b < run_block_count[run]) ? 0 : LFS_ERASE_CYCLES) => 0; |                     (b < run_block_count[run]) ? 0 : LFS_ERASE_CYCLES) => 0; | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @@ -272,7 +272,7 @@ code = ''' | |||||||
|  |  | ||||||
|     for (int run = 0; run < 2; run++) { |     for (int run = 0; run < 2; run++) { | ||||||
|         for (lfs_block_t b = 0; b < LFS_BLOCK_COUNT; b++) { |         for (lfs_block_t b = 0; b < LFS_BLOCK_COUNT; b++) { | ||||||
|             lfs_testbd_setwear(&cfg, b, |             lfs_testbd_setwear(&bd, b, | ||||||
|                     (b < run_block_count[run]) ? 0 : LFS_ERASE_CYCLES) => 0; |                     (b < run_block_count[run]) ? 0 : LFS_ERASE_CYCLES) => 0; | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @@ -434,7 +434,7 @@ exhausted: | |||||||
|     lfs_testbd_wear_t maxwear = 0; |     lfs_testbd_wear_t maxwear = 0; | ||||||
|     // skip 0 and 1 as superblock movement is intentionally avoided |     // skip 0 and 1 as superblock movement is intentionally avoided | ||||||
|     for (lfs_block_t b = 2; b < LFS_BLOCK_COUNT; b++) { |     for (lfs_block_t b = 2; b < LFS_BLOCK_COUNT; b++) { | ||||||
|         lfs_testbd_wear_t wear = lfs_testbd_getwear(&cfg, b); |         lfs_testbd_wear_t wear = lfs_testbd_getwear(&bd, b); | ||||||
|         printf("%08x: wear %d\n", b, wear); |         printf("%08x: wear %d\n", b, wear); | ||||||
|         assert(wear >= 0); |         assert(wear >= 0); | ||||||
|         if (wear < minwear) { |         if (wear < minwear) { | ||||||
| @@ -453,7 +453,7 @@ exhausted: | |||||||
|     // find standard deviation^2 |     // find standard deviation^2 | ||||||
|     lfs_testbd_wear_t dev2 = 0; |     lfs_testbd_wear_t dev2 = 0; | ||||||
|     for (lfs_block_t b = 2; b < LFS_BLOCK_COUNT; b++) { |     for (lfs_block_t b = 2; b < LFS_BLOCK_COUNT; b++) { | ||||||
|         lfs_testbd_wear_t wear = lfs_testbd_getwear(&cfg, b); |         lfs_testbd_wear_t wear = lfs_testbd_getwear(&bd, b); | ||||||
|         assert(wear >= 0); |         assert(wear >= 0); | ||||||
|         lfs_testbd_swear_t diff = wear - avgwear; |         lfs_testbd_swear_t diff = wear - avgwear; | ||||||
|         dev2 += diff*diff; |         dev2 += diff*diff; | ||||||
|   | |||||||
| @@ -98,15 +98,15 @@ code = ''' | |||||||
|     lfs_dir_close(&lfs, &dir) => 0; |     lfs_dir_close(&lfs, &dir) => 0; | ||||||
|     lfs_unmount(&lfs) => 0; |     lfs_unmount(&lfs) => 0; | ||||||
|     uint8_t bbuffer[LFS_BLOCK_SIZE]; |     uint8_t bbuffer[LFS_BLOCK_SIZE]; | ||||||
|     cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; |     lfs_testbd_read(&bd, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; | ||||||
|     int off = LFS_BLOCK_SIZE-1; |     int off = LFS_BLOCK_SIZE-1; | ||||||
|     while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) { |     while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) { | ||||||
|         off -= 1; |         off -= 1; | ||||||
|     } |     } | ||||||
|     memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3); |     memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3); | ||||||
|     cfg.erase(&cfg, block) => 0; |     lfs_testbd_erase(&bd, block) => 0; | ||||||
|     cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; |     lfs_testbd_prog(&bd, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; | ||||||
|     cfg.sync(&cfg) => 0; |     lfs_testbd_sync(&bd) => 0; | ||||||
|  |  | ||||||
|     lfs_mountcfg(&lfs, &cfg) => 0; |     lfs_mountcfg(&lfs, &cfg) => 0; | ||||||
|     lfs_dir_open(&lfs, &dir, "a") => 0; |     lfs_dir_open(&lfs, &dir, "a") => 0; | ||||||
| @@ -174,15 +174,15 @@ code = ''' | |||||||
|     lfs_dir_close(&lfs, &dir) => 0; |     lfs_dir_close(&lfs, &dir) => 0; | ||||||
|     lfs_unmount(&lfs) => 0; |     lfs_unmount(&lfs) => 0; | ||||||
|     uint8_t bbuffer[LFS_BLOCK_SIZE]; |     uint8_t bbuffer[LFS_BLOCK_SIZE]; | ||||||
|     cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; |     lfs_testbd_read(&bd, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; | ||||||
|     int off = LFS_BLOCK_SIZE-1; |     int off = LFS_BLOCK_SIZE-1; | ||||||
|     while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) { |     while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) { | ||||||
|         off -= 1; |         off -= 1; | ||||||
|     } |     } | ||||||
|     memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3); |     memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3); | ||||||
|     cfg.erase(&cfg, block) => 0; |     lfs_testbd_erase(&bd, block) => 0; | ||||||
|     cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; |     lfs_testbd_prog(&bd, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; | ||||||
|     cfg.sync(&cfg) => 0; |     lfs_testbd_sync(&bd) => 0; | ||||||
|  |  | ||||||
|     // corrupt the destination |     // corrupt the destination | ||||||
|     lfs_mountcfg(&lfs, &cfg) => 0; |     lfs_mountcfg(&lfs, &cfg) => 0; | ||||||
| @@ -190,15 +190,15 @@ code = ''' | |||||||
|     block = dir.m.pair[0]; |     block = dir.m.pair[0]; | ||||||
|     lfs_dir_close(&lfs, &dir) => 0; |     lfs_dir_close(&lfs, &dir) => 0; | ||||||
|     lfs_unmount(&lfs) => 0; |     lfs_unmount(&lfs) => 0; | ||||||
|     cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; |     lfs_testbd_read(&bd, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; | ||||||
|     off = LFS_BLOCK_SIZE-1; |     off = LFS_BLOCK_SIZE-1; | ||||||
|     while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) { |     while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) { | ||||||
|         off -= 1; |         off -= 1; | ||||||
|     } |     } | ||||||
|     memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3); |     memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3); | ||||||
|     cfg.erase(&cfg, block) => 0; |     lfs_testbd_erase(&bd, block) => 0; | ||||||
|     cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; |     lfs_testbd_prog(&bd, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; | ||||||
|     cfg.sync(&cfg) => 0; |     lfs_testbd_sync(&bd) => 0; | ||||||
|  |  | ||||||
|     lfs_mountcfg(&lfs, &cfg) => 0; |     lfs_mountcfg(&lfs, &cfg) => 0; | ||||||
|     lfs_dir_open(&lfs, &dir, "a") => 0; |     lfs_dir_open(&lfs, &dir, "a") => 0; | ||||||
| @@ -266,15 +266,15 @@ code = ''' | |||||||
|     lfs_dir_close(&lfs, &dir) => 0; |     lfs_dir_close(&lfs, &dir) => 0; | ||||||
|     lfs_unmount(&lfs) => 0; |     lfs_unmount(&lfs) => 0; | ||||||
|     uint8_t bbuffer[LFS_BLOCK_SIZE]; |     uint8_t bbuffer[LFS_BLOCK_SIZE]; | ||||||
|     cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; |     lfs_testbd_read(&bd, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; | ||||||
|     int off = LFS_BLOCK_SIZE-1; |     int off = LFS_BLOCK_SIZE-1; | ||||||
|     while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) { |     while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) { | ||||||
|         off -= 1; |         off -= 1; | ||||||
|     } |     } | ||||||
|     memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3); |     memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3); | ||||||
|     cfg.erase(&cfg, block) => 0; |     lfs_testbd_erase(&bd, block) => 0; | ||||||
|     cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; |     lfs_testbd_prog(&bd, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; | ||||||
|     cfg.sync(&cfg) => 0; |     lfs_testbd_sync(&bd) => 0; | ||||||
|  |  | ||||||
|     // corrupt the destination |     // corrupt the destination | ||||||
|     lfs_mountcfg(&lfs, &cfg) => 0; |     lfs_mountcfg(&lfs, &cfg) => 0; | ||||||
| @@ -282,15 +282,15 @@ code = ''' | |||||||
|     block = dir.m.pair[0]; |     block = dir.m.pair[0]; | ||||||
|     lfs_dir_close(&lfs, &dir) => 0; |     lfs_dir_close(&lfs, &dir) => 0; | ||||||
|     lfs_unmount(&lfs) => 0; |     lfs_unmount(&lfs) => 0; | ||||||
|     cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; |     lfs_testbd_read(&bd, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; | ||||||
|     off = LFS_BLOCK_SIZE-1; |     off = LFS_BLOCK_SIZE-1; | ||||||
|     while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) { |     while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) { | ||||||
|         off -= 1; |         off -= 1; | ||||||
|     } |     } | ||||||
|     memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3); |     memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3); | ||||||
|     cfg.erase(&cfg, block) => 0; |     lfs_testbd_erase(&bd, block) => 0; | ||||||
|     cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; |     lfs_testbd_prog(&bd, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; | ||||||
|     cfg.sync(&cfg) => 0; |     lfs_testbd_sync(&bd) => 0; | ||||||
|  |  | ||||||
|     // continue move |     // continue move | ||||||
|     lfs_mountcfg(&lfs, &cfg) => 0; |     lfs_mountcfg(&lfs, &cfg) => 0; | ||||||
| @@ -536,15 +536,15 @@ code = ''' | |||||||
|     lfs_dir_close(&lfs, &dir) => 0; |     lfs_dir_close(&lfs, &dir) => 0; | ||||||
|     lfs_unmount(&lfs) => 0; |     lfs_unmount(&lfs) => 0; | ||||||
|     uint8_t bbuffer[LFS_BLOCK_SIZE]; |     uint8_t bbuffer[LFS_BLOCK_SIZE]; | ||||||
|     cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; |     lfs_testbd_read(&bd, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; | ||||||
|     int off = LFS_BLOCK_SIZE-1; |     int off = LFS_BLOCK_SIZE-1; | ||||||
|     while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) { |     while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) { | ||||||
|         off -= 1; |         off -= 1; | ||||||
|     } |     } | ||||||
|     memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3); |     memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3); | ||||||
|     cfg.erase(&cfg, block) => 0; |     lfs_testbd_erase(&bd, block) => 0; | ||||||
|     cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; |     lfs_testbd_prog(&bd, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; | ||||||
|     cfg.sync(&cfg) => 0; |     lfs_testbd_sync(&bd) => 0; | ||||||
|  |  | ||||||
|     lfs_mountcfg(&lfs, &cfg) => 0; |     lfs_mountcfg(&lfs, &cfg) => 0; | ||||||
|     lfs_dir_open(&lfs, &dir, "a") => 0; |     lfs_dir_open(&lfs, &dir, "a") => 0; | ||||||
| @@ -620,15 +620,15 @@ code = ''' | |||||||
|     lfs_dir_close(&lfs, &dir) => 0; |     lfs_dir_close(&lfs, &dir) => 0; | ||||||
|     lfs_unmount(&lfs) => 0; |     lfs_unmount(&lfs) => 0; | ||||||
|     uint8_t bbuffer[LFS_BLOCK_SIZE]; |     uint8_t bbuffer[LFS_BLOCK_SIZE]; | ||||||
|     cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; |     lfs_testbd_read(&bd, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; | ||||||
|     int off = LFS_BLOCK_SIZE-1; |     int off = LFS_BLOCK_SIZE-1; | ||||||
|     while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) { |     while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) { | ||||||
|         off -= 1; |         off -= 1; | ||||||
|     } |     } | ||||||
|     memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3); |     memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3); | ||||||
|     cfg.erase(&cfg, block) => 0; |     lfs_testbd_erase(&bd, block) => 0; | ||||||
|     cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; |     lfs_testbd_prog(&bd, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; | ||||||
|     cfg.sync(&cfg) => 0; |     lfs_testbd_sync(&bd) => 0; | ||||||
|  |  | ||||||
|     // corrupt the destination |     // corrupt the destination | ||||||
|     lfs_mountcfg(&lfs, &cfg) => 0; |     lfs_mountcfg(&lfs, &cfg) => 0; | ||||||
| @@ -636,15 +636,15 @@ code = ''' | |||||||
|     block = dir.m.pair[0]; |     block = dir.m.pair[0]; | ||||||
|     lfs_dir_close(&lfs, &dir) => 0; |     lfs_dir_close(&lfs, &dir) => 0; | ||||||
|     lfs_unmount(&lfs) => 0; |     lfs_unmount(&lfs) => 0; | ||||||
|     cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; |     lfs_testbd_read(&bd, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; | ||||||
|     off = LFS_BLOCK_SIZE-1; |     off = LFS_BLOCK_SIZE-1; | ||||||
|     while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) { |     while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) { | ||||||
|         off -= 1; |         off -= 1; | ||||||
|     } |     } | ||||||
|     memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3); |     memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3); | ||||||
|     cfg.erase(&cfg, block) => 0; |     lfs_testbd_erase(&bd, block) => 0; | ||||||
|     cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; |     lfs_testbd_prog(&bd, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; | ||||||
|     cfg.sync(&cfg) => 0; |     lfs_testbd_sync(&bd) => 0; | ||||||
|  |  | ||||||
|     lfs_mountcfg(&lfs, &cfg) => 0; |     lfs_mountcfg(&lfs, &cfg) => 0; | ||||||
|     lfs_dir_open(&lfs, &dir, "a") => 0; |     lfs_dir_open(&lfs, &dir, "a") => 0; | ||||||
| @@ -720,15 +720,15 @@ code = ''' | |||||||
|     lfs_dir_close(&lfs, &dir) => 0; |     lfs_dir_close(&lfs, &dir) => 0; | ||||||
|     lfs_unmount(&lfs) => 0; |     lfs_unmount(&lfs) => 0; | ||||||
|     uint8_t bbuffer[LFS_BLOCK_SIZE]; |     uint8_t bbuffer[LFS_BLOCK_SIZE]; | ||||||
|     cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; |     lfs_testbd_read(&bd, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; | ||||||
|     int off = LFS_BLOCK_SIZE-1; |     int off = LFS_BLOCK_SIZE-1; | ||||||
|     while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) { |     while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) { | ||||||
|         off -= 1; |         off -= 1; | ||||||
|     } |     } | ||||||
|     memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3); |     memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3); | ||||||
|     cfg.erase(&cfg, block) => 0; |     lfs_testbd_erase(&bd, block) => 0; | ||||||
|     cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; |     lfs_testbd_prog(&bd, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; | ||||||
|     cfg.sync(&cfg) => 0; |     lfs_testbd_sync(&bd) => 0; | ||||||
|  |  | ||||||
|     // corrupt the destination |     // corrupt the destination | ||||||
|     lfs_mountcfg(&lfs, &cfg) => 0; |     lfs_mountcfg(&lfs, &cfg) => 0; | ||||||
| @@ -736,15 +736,15 @@ code = ''' | |||||||
|     block = dir.m.pair[0]; |     block = dir.m.pair[0]; | ||||||
|     lfs_dir_close(&lfs, &dir) => 0; |     lfs_dir_close(&lfs, &dir) => 0; | ||||||
|     lfs_unmount(&lfs) => 0; |     lfs_unmount(&lfs) => 0; | ||||||
|     cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; |     lfs_testbd_read(&bd, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; | ||||||
|     off = LFS_BLOCK_SIZE-1; |     off = LFS_BLOCK_SIZE-1; | ||||||
|     while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) { |     while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) { | ||||||
|         off -= 1; |         off -= 1; | ||||||
|     } |     } | ||||||
|     memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3); |     memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3); | ||||||
|     cfg.erase(&cfg, block) => 0; |     lfs_testbd_erase(&bd, block) => 0; | ||||||
|     cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; |     lfs_testbd_prog(&bd, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; | ||||||
|     cfg.sync(&cfg) => 0; |     lfs_testbd_sync(&bd) => 0; | ||||||
|  |  | ||||||
|     // continue move |     // continue move | ||||||
|     lfs_mountcfg(&lfs, &cfg) => 0; |     lfs_mountcfg(&lfs, &cfg) => 0; | ||||||
| @@ -1569,14 +1569,14 @@ code = ''' | |||||||
|     // force specific directories to relocate |     // force specific directories to relocate | ||||||
|     if (RELOCATIONS & 0x1) { |     if (RELOCATIONS & 0x1) { | ||||||
|         lfs_dir_open(&lfs, &dir, "/parent"); |         lfs_dir_open(&lfs, &dir, "/parent"); | ||||||
|         lfs_testbd_setwear(&cfg, dir.m.pair[0], 0xffffffff) => 0; |         lfs_testbd_setwear(&bd, dir.m.pair[0], 0xffffffff) => 0; | ||||||
|         lfs_testbd_setwear(&cfg, dir.m.pair[1], 0xffffffff) => 0; |         lfs_testbd_setwear(&bd, dir.m.pair[1], 0xffffffff) => 0; | ||||||
|         lfs_dir_close(&lfs, &dir) => 0; |         lfs_dir_close(&lfs, &dir) => 0; | ||||||
|     } |     } | ||||||
|     if (RELOCATIONS & 0x2) { |     if (RELOCATIONS & 0x2) { | ||||||
|         lfs_dir_open(&lfs, &dir, "/parent/child"); |         lfs_dir_open(&lfs, &dir, "/parent/child"); | ||||||
|         lfs_testbd_setwear(&cfg, dir.m.pair[0], 0xffffffff) => 0; |         lfs_testbd_setwear(&bd, dir.m.pair[0], 0xffffffff) => 0; | ||||||
|         lfs_testbd_setwear(&cfg, dir.m.pair[1], 0xffffffff) => 0; |         lfs_testbd_setwear(&bd, dir.m.pair[1], 0xffffffff) => 0; | ||||||
|         lfs_dir_close(&lfs, &dir) => 0; |         lfs_dir_close(&lfs, &dir) => 0; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -1707,20 +1707,20 @@ code = ''' | |||||||
|     // force specific directories to relocate |     // force specific directories to relocate | ||||||
|     if (RELOCATIONS & 0x1) { |     if (RELOCATIONS & 0x1) { | ||||||
|         lfs_dir_open(&lfs, &dir, "/parent"); |         lfs_dir_open(&lfs, &dir, "/parent"); | ||||||
|         lfs_testbd_setwear(&cfg, dir.m.pair[0], 0xffffffff) => 0; |         lfs_testbd_setwear(&bd, dir.m.pair[0], 0xffffffff) => 0; | ||||||
|         lfs_testbd_setwear(&cfg, dir.m.pair[1], 0xffffffff) => 0; |         lfs_testbd_setwear(&bd, dir.m.pair[1], 0xffffffff) => 0; | ||||||
|         lfs_dir_close(&lfs, &dir) => 0; |         lfs_dir_close(&lfs, &dir) => 0; | ||||||
|     } |     } | ||||||
|     if (RELOCATIONS & 0x2) { |     if (RELOCATIONS & 0x2) { | ||||||
|         lfs_dir_open(&lfs, &dir, "/parent/sibling"); |         lfs_dir_open(&lfs, &dir, "/parent/sibling"); | ||||||
|         lfs_testbd_setwear(&cfg, dir.m.pair[0], 0xffffffff) => 0; |         lfs_testbd_setwear(&bd, dir.m.pair[0], 0xffffffff) => 0; | ||||||
|         lfs_testbd_setwear(&cfg, dir.m.pair[1], 0xffffffff) => 0; |         lfs_testbd_setwear(&bd, dir.m.pair[1], 0xffffffff) => 0; | ||||||
|         lfs_dir_close(&lfs, &dir) => 0; |         lfs_dir_close(&lfs, &dir) => 0; | ||||||
|     } |     } | ||||||
|     if (RELOCATIONS & 0x4) { |     if (RELOCATIONS & 0x4) { | ||||||
|         lfs_dir_open(&lfs, &dir, "/parent/child"); |         lfs_dir_open(&lfs, &dir, "/parent/child"); | ||||||
|         lfs_testbd_setwear(&cfg, dir.m.pair[0], 0xffffffff) => 0; |         lfs_testbd_setwear(&bd, dir.m.pair[0], 0xffffffff) => 0; | ||||||
|         lfs_testbd_setwear(&cfg, dir.m.pair[1], 0xffffffff) => 0; |         lfs_testbd_setwear(&bd, dir.m.pair[1], 0xffffffff) => 0; | ||||||
|         lfs_dir_close(&lfs, &dir) => 0; |         lfs_dir_close(&lfs, &dir) => 0; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -19,15 +19,15 @@ code = ''' | |||||||
|     lfs_dir_close(&lfs, &dir) => 0; |     lfs_dir_close(&lfs, &dir) => 0; | ||||||
|     lfs_unmount(&lfs) => 0; |     lfs_unmount(&lfs) => 0; | ||||||
|     uint8_t bbuffer[LFS_BLOCK_SIZE]; |     uint8_t bbuffer[LFS_BLOCK_SIZE]; | ||||||
|     cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; |     lfs_testbd_read(&bd, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; | ||||||
|     int off = LFS_BLOCK_SIZE-1; |     int off = LFS_BLOCK_SIZE-1; | ||||||
|     while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) { |     while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) { | ||||||
|         off -= 1; |         off -= 1; | ||||||
|     } |     } | ||||||
|     memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3); |     memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3); | ||||||
|     cfg.erase(&cfg, block) => 0; |     lfs_testbd_erase(&bd, block) => 0; | ||||||
|     cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; |     lfs_testbd_prog(&bd, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; | ||||||
|     cfg.sync(&cfg) => 0; |     lfs_testbd_sync(&bd) => 0; | ||||||
|  |  | ||||||
|     lfs_mountcfg(&lfs, &cfg) => 0; |     lfs_mountcfg(&lfs, &cfg) => 0; | ||||||
|     lfs_stat(&lfs, "parent/orphan", &info) => LFS_ERR_NOENT; |     lfs_stat(&lfs, "parent/orphan", &info) => LFS_ERR_NOENT; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user