mirror of
				https://github.com/eledio-devices/thirdparty-littlefs.git
				synced 2025-11-01 08:48:31 +01:00 
			
		
		
		
	Compare commits
	
		
			1 Commits
		
	
	
		
			v2.2.0
			...
			test-revam
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | c1c0386bda | 
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -8,5 +8,3 @@ blocks/ | |||||||
| lfs | lfs | ||||||
| test.c | test.c | ||||||
| tests/*.toml.* | tests/*.toml.* | ||||||
| scripts/__pycache__ |  | ||||||
| .gdb_history |  | ||||||
|   | |||||||
| @@ -115,9 +115,6 @@ the filesystem until sync or close is called on the file. | |||||||
|  |  | ||||||
| ## Other notes | ## Other notes | ||||||
|  |  | ||||||
| Littlefs is written in C, and specifically should compile with any compiler |  | ||||||
| that conforms to the `C99` standard. |  | ||||||
|  |  | ||||||
| All littlefs calls have the potential to return a negative error code. The | All littlefs calls have the potential to return a negative error code. The | ||||||
| errors can be either one of those found in the `enum lfs_error` in | errors can be either one of those found in the `enum lfs_error` in | ||||||
| [lfs.h](lfs.h), or an error returned by the user's block device operations. | [lfs.h](lfs.h), or an error returned by the user's block device operations. | ||||||
|   | |||||||
							
								
								
									
										18
									
								
								SPEC.md
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								SPEC.md
									
									
									
									
									
								
							| @@ -289,8 +289,8 @@ Layout of the name tag: | |||||||
| ``` | ``` | ||||||
|         tag                          data |         tag                          data | ||||||
| [--      32      --][---        variable length        ---] | [--      32      --][---        variable length        ---] | ||||||
| [1| 3| 8 | 10 | 10 ][---          (size * 8)           ---] | [1| 3| 8 | 10 | 10 ][---            (size)             ---] | ||||||
|  ^  ^  ^    ^    ^- size                   ^- file name |  ^  ^  ^    ^    ^- size               ^- file name | ||||||
|  |  |  |    '------ id |  |  |  |    '------ id | ||||||
|  |  |  '----------- file type |  |  |  '----------- file type | ||||||
|  |  '-------------- type1 (0x0) |  |  '-------------- type1 (0x0) | ||||||
| @@ -470,8 +470,8 @@ Layout of the inline-struct tag: | |||||||
| ``` | ``` | ||||||
|         tag                          data |         tag                          data | ||||||
| [--      32      --][---        variable length        ---] | [--      32      --][---        variable length        ---] | ||||||
| [1|- 11 -| 10 | 10 ][---           (size * 8)          ---] | [1|- 11 -| 10 | 10 ][---            (size)             ---] | ||||||
|  ^    ^     ^    ^- size                    ^- inline data |  ^    ^     ^    ^- size               ^- inline data | ||||||
|  |    |     '------ id |  |    |     '------ id | ||||||
|  |    '------------ type (0x201) |  |    '------------ type (0x201) | ||||||
|  '----------------- valid bit |  '----------------- valid bit | ||||||
| @@ -556,8 +556,8 @@ Layout of the user-attr tag: | |||||||
| ``` | ``` | ||||||
|         tag                          data |         tag                          data | ||||||
| [--      32      --][---        variable length        ---] | [--      32      --][---        variable length        ---] | ||||||
| [1| 3| 8 | 10 | 10 ][---           (size * 8)          ---] | [1| 3| 8 | 10 | 10 ][---            (size)             ---] | ||||||
|  ^  ^  ^    ^    ^- size                    ^- attr data |  ^  ^  ^    ^    ^- size               ^- attr data | ||||||
|  |  |  |    '------ id |  |  |  |    '------ id | ||||||
|  |  |  '----------- attr type |  |  |  '----------- attr type | ||||||
|  |  '-------------- type1 (0x3) |  |  '-------------- type1 (0x3) | ||||||
| @@ -764,9 +764,9 @@ Layout of the CRC tag: | |||||||
| ``` | ``` | ||||||
|         tag                                    data |         tag                                    data | ||||||
| [--      32      --][--      32      --|---        variable length        ---] | [--      32      --][--      32      --|---        variable length        ---] | ||||||
| [1| 3| 8 | 10 | 10 ][--      32      --|---        (size * 8 - 32)        ---] | [1| 3| 8 | 10 | 10 ][--      32      --|---            (size)             ---] | ||||||
|  ^  ^  ^    ^    ^            ^- crc                             ^- padding |  ^  ^  ^    ^    ^            ^- crc                      ^- padding | ||||||
|  |  |  |    |    '- size |  |  |  |    |    '- size (12) | ||||||
|  |  |  |    '------ id (0x3ff) |  |  |  |    '------ id (0x3ff) | ||||||
|  |  |  '----------- valid state |  |  |  '----------- valid state | ||||||
|  |  '-------------- type1 (0x5) |  |  '-------------- type1 (0x5) | ||||||
|   | |||||||
| @@ -12,7 +12,7 @@ | |||||||
|  |  | ||||||
| int lfs_filebd_createcfg(const struct lfs_config *cfg, const char *path, | int lfs_filebd_createcfg(const struct lfs_config *cfg, const char *path, | ||||||
|         const struct lfs_filebd_config *bdcfg) { |         const struct lfs_filebd_config *bdcfg) { | ||||||
|     LFS_FILEBD_TRACE("lfs_filebd_createcfg(%p {.context=%p, " |     LFS_TRACE("lfs_filebd_createcfg(%p {.context=%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"}, " | ||||||
| @@ -30,16 +30,16 @@ int lfs_filebd_createcfg(const struct lfs_config *cfg, const char *path, | |||||||
|     bd->fd = open(path, O_RDWR | O_CREAT, 0666); |     bd->fd = open(path, O_RDWR | O_CREAT, 0666); | ||||||
|     if (bd->fd < 0) { |     if (bd->fd < 0) { | ||||||
|         int err = -errno; |         int err = -errno; | ||||||
|         LFS_FILEBD_TRACE("lfs_filebd_createcfg -> %d", err); |         LFS_TRACE("lfs_filebd_createcfg -> %d", err); | ||||||
|         return err; |         return err; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     LFS_FILEBD_TRACE("lfs_filebd_createcfg -> %d", 0); |     LFS_TRACE("lfs_filebd_createcfg -> %d", 0); | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| int lfs_filebd_create(const struct lfs_config *cfg, const char *path) { | int lfs_filebd_create(const struct lfs_config *cfg, const char *path) { | ||||||
|     LFS_FILEBD_TRACE("lfs_filebd_create(%p {.context=%p, " |     LFS_TRACE("lfs_filebd_create(%p {.context=%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"}, " | ||||||
| @@ -51,27 +51,26 @@ int lfs_filebd_create(const struct lfs_config *cfg, const char *path) { | |||||||
|             path); |             path); | ||||||
|     static const struct lfs_filebd_config defaults = {.erase_value=-1}; |     static const struct lfs_filebd_config defaults = {.erase_value=-1}; | ||||||
|     int err = lfs_filebd_createcfg(cfg, path, &defaults); |     int err = lfs_filebd_createcfg(cfg, path, &defaults); | ||||||
|     LFS_FILEBD_TRACE("lfs_filebd_create -> %d", err); |     LFS_TRACE("lfs_filebd_create -> %d", err); | ||||||
|     return err; |     return err; | ||||||
| } | } | ||||||
|  |  | ||||||
| int lfs_filebd_destroy(const struct lfs_config *cfg) { | int lfs_filebd_destroy(const struct lfs_config *cfg) { | ||||||
|     LFS_FILEBD_TRACE("lfs_filebd_destroy(%p)", (void*)cfg); |     LFS_TRACE("lfs_filebd_destroy(%p)", (void*)cfg); | ||||||
|     lfs_filebd_t *bd = cfg->context; |     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; | ||||||
|         LFS_FILEBD_TRACE("lfs_filebd_destroy -> %d", err); |         LFS_TRACE("lfs_filebd_destroy -> %d", err); | ||||||
|         return err; |         return err; | ||||||
|     } |     } | ||||||
|     LFS_FILEBD_TRACE("lfs_filebd_destroy -> %d", 0); |     LFS_TRACE("lfs_filebd_destroy -> %d", 0); | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| int lfs_filebd_read(const struct lfs_config *cfg, lfs_block_t block, | int lfs_filebd_read(const struct lfs_config *cfg, 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_TRACE("lfs_filebd_read(%p, 0x%"PRIx32", %"PRIu32", %p, %"PRIu32")", | ||||||
|                 "0x%"PRIx32", %"PRIu32", %p, %"PRIu32")", |  | ||||||
|             (void*)cfg, block, off, buffer, size); |             (void*)cfg, block, off, buffer, size); | ||||||
|     lfs_filebd_t *bd = cfg->context; |     lfs_filebd_t *bd = cfg->context; | ||||||
|  |  | ||||||
| @@ -90,24 +89,24 @@ int lfs_filebd_read(const struct lfs_config *cfg, lfs_block_t block, | |||||||
|             (off_t)block*cfg->block_size + (off_t)off, SEEK_SET); |             (off_t)block*cfg->block_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_TRACE("lfs_filebd_read -> %d", err); | ||||||
|         return err; |         return err; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     ssize_t res2 = read(bd->fd, buffer, size); |     ssize_t res2 = read(bd->fd, buffer, size); | ||||||
|     if (res2 < 0) { |     if (res2 < 0) { | ||||||
|         int err = -errno; |         int err = -errno; | ||||||
|         LFS_FILEBD_TRACE("lfs_filebd_read -> %d", err); |         LFS_TRACE("lfs_filebd_read -> %d", err); | ||||||
|         return err; |         return err; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     LFS_FILEBD_TRACE("lfs_filebd_read -> %d", 0); |     LFS_TRACE("lfs_filebd_read -> %d", 0); | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| int lfs_filebd_prog(const struct lfs_config *cfg, lfs_block_t block, | int lfs_filebd_prog(const struct lfs_config *cfg, 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_TRACE("lfs_filebd_prog(%p, 0x%"PRIx32", %"PRIu32", %p, %"PRIu32")", | ||||||
|             (void*)cfg, block, off, buffer, size); |             (void*)cfg, block, off, buffer, size); | ||||||
|     lfs_filebd_t *bd = cfg->context; |     lfs_filebd_t *bd = cfg->context; | ||||||
|  |  | ||||||
| @@ -122,7 +121,7 @@ int lfs_filebd_prog(const struct lfs_config *cfg, lfs_block_t block, | |||||||
|                 (off_t)block*cfg->block_size + (off_t)off, SEEK_SET); |                 (off_t)block*cfg->block_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_TRACE("lfs_filebd_prog -> %d", err); | ||||||
|             return err; |             return err; | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @@ -131,7 +130,7 @@ int lfs_filebd_prog(const struct lfs_config *cfg, lfs_block_t block, | |||||||
|             ssize_t res2 = read(bd->fd, &c, 1); |             ssize_t res2 = read(bd->fd, &c, 1); | ||||||
|             if (res2 < 0) { |             if (res2 < 0) { | ||||||
|                 int err = -errno; |                 int err = -errno; | ||||||
|                 LFS_FILEBD_TRACE("lfs_filebd_prog -> %d", err); |                 LFS_TRACE("lfs_filebd_prog -> %d", err); | ||||||
|                 return err; |                 return err; | ||||||
|             } |             } | ||||||
|  |  | ||||||
| @@ -144,23 +143,23 @@ int lfs_filebd_prog(const struct lfs_config *cfg, lfs_block_t block, | |||||||
|             (off_t)block*cfg->block_size + (off_t)off, SEEK_SET); |             (off_t)block*cfg->block_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_TRACE("lfs_filebd_prog -> %d", err); | ||||||
|         return err; |         return err; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     ssize_t res2 = write(bd->fd, buffer, size); |     ssize_t res2 = write(bd->fd, buffer, size); | ||||||
|     if (res2 < 0) { |     if (res2 < 0) { | ||||||
|         int err = -errno; |         int err = -errno; | ||||||
|         LFS_FILEBD_TRACE("lfs_filebd_prog -> %d", err); |         LFS_TRACE("lfs_filebd_prog -> %d", err); | ||||||
|         return err; |         return err; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     LFS_FILEBD_TRACE("lfs_filebd_prog -> %d", 0); |     LFS_TRACE("lfs_filebd_prog -> %d", 0); | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| int lfs_filebd_erase(const struct lfs_config *cfg, lfs_block_t block) { | int lfs_filebd_erase(const struct lfs_config *cfg, lfs_block_t block) { | ||||||
|     LFS_FILEBD_TRACE("lfs_filebd_erase(%p, 0x%"PRIx32")", (void*)cfg, block); |     LFS_TRACE("lfs_filebd_erase(%p, 0x%"PRIx32")", (void*)cfg, block); | ||||||
|     lfs_filebd_t *bd = cfg->context; |     lfs_filebd_t *bd = cfg->context; | ||||||
|  |  | ||||||
|     // check if erase is valid |     // check if erase is valid | ||||||
| @@ -171,7 +170,7 @@ int lfs_filebd_erase(const struct lfs_config *cfg, lfs_block_t block) { | |||||||
|         off_t res1 = lseek(bd->fd, (off_t)block*cfg->block_size, SEEK_SET); |         off_t res1 = lseek(bd->fd, (off_t)block*cfg->block_size, SEEK_SET); | ||||||
|         if (res1 < 0) { |         if (res1 < 0) { | ||||||
|             int err = -errno; |             int err = -errno; | ||||||
|             LFS_FILEBD_TRACE("lfs_filebd_erase -> %d", err); |             LFS_TRACE("lfs_filebd_erase -> %d", err); | ||||||
|             return err; |             return err; | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @@ -179,27 +178,27 @@ int lfs_filebd_erase(const struct lfs_config *cfg, lfs_block_t block) { | |||||||
|             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_TRACE("lfs_filebd_erase -> %d", err); | ||||||
|                 return err; |                 return err; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     LFS_FILEBD_TRACE("lfs_filebd_erase -> %d", 0); |     LFS_TRACE("lfs_filebd_erase -> %d", 0); | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| int lfs_filebd_sync(const struct lfs_config *cfg) { | int lfs_filebd_sync(const struct lfs_config *cfg) { | ||||||
|     LFS_FILEBD_TRACE("lfs_filebd_sync(%p)", (void*)cfg); |     LFS_TRACE("lfs_filebd_sync(%p)", (void*)cfg); | ||||||
|     // file sync |     // file sync | ||||||
|     lfs_filebd_t *bd = cfg->context; |     lfs_filebd_t *bd = cfg->context; | ||||||
|     int err = fsync(bd->fd); |     int err = fsync(bd->fd); | ||||||
|     if (err) { |     if (err) { | ||||||
|         err = -errno; |         err = -errno; | ||||||
|         LFS_FILEBD_TRACE("lfs_filebd_sync -> %d", 0); |         LFS_TRACE("lfs_filebd_sync -> %d", 0); | ||||||
|         return err; |         return err; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     LFS_FILEBD_TRACE("lfs_filebd_sync -> %d", 0); |     LFS_TRACE("lfs_filebd_sync -> %d", 0); | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -15,14 +15,6 @@ extern "C" | |||||||
| { | { | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  |  | ||||||
| // Block device specific tracing |  | ||||||
| #ifdef LFS_FILEBD_YES_TRACE |  | ||||||
| #define LFS_FILEBD_TRACE(...) LFS_TRACE(__VA_ARGS__) |  | ||||||
| #else |  | ||||||
| #define LFS_FILEBD_TRACE(...) |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| // filebd config (optional) | // filebd config (optional) | ||||||
| struct lfs_filebd_config { | struct lfs_filebd_config { | ||||||
|     // 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 | ||||||
|   | |||||||
| @@ -8,7 +8,7 @@ | |||||||
|  |  | ||||||
| int lfs_rambd_createcfg(const struct lfs_config *cfg, | int lfs_rambd_createcfg(const struct lfs_config *cfg, | ||||||
|         const struct lfs_rambd_config *bdcfg) { |         const struct lfs_rambd_config *bdcfg) { | ||||||
|     LFS_RAMBD_TRACE("lfs_rambd_createcfg(%p {.context=%p, " |     LFS_TRACE("lfs_rambd_createcfg(%p {.context=%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"}, " | ||||||
| @@ -27,7 +27,7 @@ int lfs_rambd_createcfg(const struct lfs_config *cfg, | |||||||
|     } else { |     } else { | ||||||
|         bd->buffer = lfs_malloc(cfg->block_size * cfg->block_count); |         bd->buffer = lfs_malloc(cfg->block_size * cfg->block_count); | ||||||
|         if (!bd->buffer) { |         if (!bd->buffer) { | ||||||
|             LFS_RAMBD_TRACE("lfs_rambd_createcfg -> %d", LFS_ERR_NOMEM); |             LFS_TRACE("lfs_rambd_createcfg -> %d", LFS_ERR_NOMEM); | ||||||
|             return LFS_ERR_NOMEM; |             return LFS_ERR_NOMEM; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @@ -38,12 +38,12 @@ int lfs_rambd_createcfg(const struct lfs_config *cfg, | |||||||
|                 cfg->block_size * cfg->block_count); |                 cfg->block_size * cfg->block_count); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     LFS_RAMBD_TRACE("lfs_rambd_createcfg -> %d", 0); |     LFS_TRACE("lfs_rambd_createcfg -> %d", 0); | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| int lfs_rambd_create(const struct lfs_config *cfg) { | int lfs_rambd_create(const struct lfs_config *cfg) { | ||||||
|     LFS_RAMBD_TRACE("lfs_rambd_create(%p {.context=%p, " |     LFS_TRACE("lfs_rambd_create(%p {.context=%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"})", | ||||||
| @@ -53,25 +53,24 @@ int lfs_rambd_create(const struct lfs_config *cfg) { | |||||||
|             cfg->read_size, cfg->prog_size, cfg->block_size, cfg->block_count); |             cfg->read_size, cfg->prog_size, cfg->block_size, cfg->block_count); | ||||||
|     static const struct lfs_rambd_config defaults = {.erase_value=-1}; |     static const struct lfs_rambd_config defaults = {.erase_value=-1}; | ||||||
|     int err = lfs_rambd_createcfg(cfg, &defaults); |     int err = lfs_rambd_createcfg(cfg, &defaults); | ||||||
|     LFS_RAMBD_TRACE("lfs_rambd_create -> %d", err); |     LFS_TRACE("lfs_rambd_create -> %d", err); | ||||||
|     return err; |     return err; | ||||||
| } | } | ||||||
|  |  | ||||||
| int lfs_rambd_destroy(const struct lfs_config *cfg) { | int lfs_rambd_destroy(const struct lfs_config *cfg) { | ||||||
|     LFS_RAMBD_TRACE("lfs_rambd_destroy(%p)", (void*)cfg); |     LFS_TRACE("lfs_rambd_destroy(%p)", (void*)cfg); | ||||||
|     // clean up memory |     // clean up memory | ||||||
|     lfs_rambd_t *bd = cfg->context; |     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_TRACE("lfs_rambd_destroy -> %d", 0); | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| int lfs_rambd_read(const struct lfs_config *cfg, lfs_block_t block, | int lfs_rambd_read(const struct lfs_config *cfg, 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_TRACE("lfs_rambd_read(%p, 0x%"PRIx32", %"PRIu32", %p, %"PRIu32")", | ||||||
|                 "0x%"PRIx32", %"PRIu32", %p, %"PRIu32")", |  | ||||||
|             (void*)cfg, block, off, buffer, size); |             (void*)cfg, block, off, buffer, size); | ||||||
|     lfs_rambd_t *bd = cfg->context; |     lfs_rambd_t *bd = cfg->context; | ||||||
|  |  | ||||||
| @@ -83,14 +82,13 @@ int lfs_rambd_read(const struct lfs_config *cfg, lfs_block_t block, | |||||||
|     // read data |     // read data | ||||||
|     memcpy(buffer, &bd->buffer[block*cfg->block_size + off], size); |     memcpy(buffer, &bd->buffer[block*cfg->block_size + off], size); | ||||||
|  |  | ||||||
|     LFS_RAMBD_TRACE("lfs_rambd_read -> %d", 0); |     LFS_TRACE("lfs_rambd_read -> %d", 0); | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| int lfs_rambd_prog(const struct lfs_config *cfg, lfs_block_t block, | int lfs_rambd_prog(const struct lfs_config *cfg, 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_TRACE("lfs_rambd_prog(%p, 0x%"PRIx32", %"PRIu32", %p, %"PRIu32")", | ||||||
|                 "0x%"PRIx32", %"PRIu32", %p, %"PRIu32")", |  | ||||||
|             (void*)cfg, block, off, buffer, size); |             (void*)cfg, block, off, buffer, size); | ||||||
|     lfs_rambd_t *bd = cfg->context; |     lfs_rambd_t *bd = cfg->context; | ||||||
|  |  | ||||||
| @@ -110,12 +108,12 @@ int lfs_rambd_prog(const struct lfs_config *cfg, lfs_block_t block, | |||||||
|     // program data |     // program data | ||||||
|     memcpy(&bd->buffer[block*cfg->block_size + off], buffer, size); |     memcpy(&bd->buffer[block*cfg->block_size + off], buffer, size); | ||||||
|  |  | ||||||
|     LFS_RAMBD_TRACE("lfs_rambd_prog -> %d", 0); |     LFS_TRACE("lfs_rambd_prog -> %d", 0); | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| int lfs_rambd_erase(const struct lfs_config *cfg, lfs_block_t block) { | int lfs_rambd_erase(const struct lfs_config *cfg, lfs_block_t block) { | ||||||
|     LFS_RAMBD_TRACE("lfs_rambd_erase(%p, 0x%"PRIx32")", (void*)cfg, block); |     LFS_TRACE("lfs_rambd_erase(%p, 0x%"PRIx32")", (void*)cfg, block); | ||||||
|     lfs_rambd_t *bd = cfg->context; |     lfs_rambd_t *bd = cfg->context; | ||||||
|  |  | ||||||
|     // check if erase is valid |     // check if erase is valid | ||||||
| @@ -127,14 +125,14 @@ int lfs_rambd_erase(const struct lfs_config *cfg, lfs_block_t block) { | |||||||
|                 bd->cfg->erase_value, cfg->block_size); |                 bd->cfg->erase_value, cfg->block_size); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     LFS_RAMBD_TRACE("lfs_rambd_erase -> %d", 0); |     LFS_TRACE("lfs_rambd_erase -> %d", 0); | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| int lfs_rambd_sync(const struct lfs_config *cfg) { | int lfs_rambd_sync(const struct lfs_config *cfg) { | ||||||
|     LFS_RAMBD_TRACE("lfs_rambd_sync(%p)", (void*)cfg); |     LFS_TRACE("lfs_rambd_sync(%p)", (void*)cfg); | ||||||
|     // 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)cfg; | ||||||
|     LFS_RAMBD_TRACE("lfs_rambd_sync -> %d", 0); |     LFS_TRACE("lfs_rambd_sync -> %d", 0); | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -15,14 +15,6 @@ extern "C" | |||||||
| { | { | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  |  | ||||||
| // Block device specific tracing |  | ||||||
| #ifdef LFS_RAMBD_YES_TRACE |  | ||||||
| #define LFS_RAMBD_TRACE(...) LFS_TRACE(__VA_ARGS__) |  | ||||||
| #else |  | ||||||
| #define LFS_RAMBD_TRACE(...) |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| // rambd config (optional) | // rambd config (optional) | ||||||
| struct lfs_rambd_config { | struct lfs_rambd_config { | ||||||
|     // 8-bit erase value to simulate erasing with. -1 indicates no erase |     // 8-bit erase value to simulate erasing with. -1 indicates no erase | ||||||
|   | |||||||
| @@ -12,7 +12,7 @@ | |||||||
|  |  | ||||||
| int lfs_testbd_createcfg(const struct lfs_config *cfg, const char *path, | int lfs_testbd_createcfg(const struct lfs_config *cfg, const char *path, | ||||||
|         const struct lfs_testbd_config *bdcfg) { |         const struct lfs_testbd_config *bdcfg) { | ||||||
|     LFS_TESTBD_TRACE("lfs_testbd_createcfg(%p {.context=%p, " |     LFS_TRACE("lfs_testbd_createcfg(%p {.context=%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"}, " | ||||||
| @@ -38,9 +38,9 @@ int lfs_testbd_createcfg(const struct lfs_config *cfg, const char *path, | |||||||
|         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->block_count); | ||||||
|             if (!bd->wear) { |             if (!bd->wear) { | ||||||
|                 LFS_TESTBD_TRACE("lfs_testbd_createcfg -> %d", LFS_ERR_NOMEM); |                 LFS_TRACE("lfs_testbd_createcfg -> %d", LFS_ERR_NOMEM); | ||||||
|                 return LFS_ERR_NOMEM; |                 return LFS_ERR_NOMEM; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| @@ -54,7 +54,7 @@ int lfs_testbd_createcfg(const struct lfs_config *cfg, const char *path, | |||||||
|             .erase_value = bd->cfg->erase_value, |             .erase_value = bd->cfg->erase_value, | ||||||
|         }; |         }; | ||||||
|         int err = lfs_filebd_createcfg(cfg, path, &bd->u.file.cfg); |         int err = lfs_filebd_createcfg(cfg, path, &bd->u.file.cfg); | ||||||
|         LFS_TESTBD_TRACE("lfs_testbd_createcfg -> %d", err); |         LFS_TRACE("lfs_testbd_createcfg -> %d", err); | ||||||
|         return err; |         return err; | ||||||
|     } else { |     } else { | ||||||
|         bd->u.ram.cfg = (struct lfs_rambd_config){ |         bd->u.ram.cfg = (struct lfs_rambd_config){ | ||||||
| @@ -62,13 +62,13 @@ int lfs_testbd_createcfg(const struct lfs_config *cfg, const char *path, | |||||||
|             .buffer = bd->cfg->buffer, |             .buffer = bd->cfg->buffer, | ||||||
|         }; |         }; | ||||||
|         int err = lfs_rambd_createcfg(cfg, &bd->u.ram.cfg); |         int err = lfs_rambd_createcfg(cfg, &bd->u.ram.cfg); | ||||||
|         LFS_TESTBD_TRACE("lfs_testbd_createcfg -> %d", err); |         LFS_TRACE("lfs_testbd_createcfg -> %d", err); | ||||||
|         return err; |         return err; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| int lfs_testbd_create(const struct lfs_config *cfg, const char *path) { | int lfs_testbd_create(const struct lfs_config *cfg, const char *path) { | ||||||
|     LFS_TESTBD_TRACE("lfs_testbd_create(%p {.context=%p, " |     LFS_TRACE("lfs_testbd_create(%p {.context=%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"}, " | ||||||
| @@ -80,12 +80,12 @@ int lfs_testbd_create(const struct lfs_config *cfg, const char *path) { | |||||||
|             path); |             path); | ||||||
|     static const struct lfs_testbd_config defaults = {.erase_value=-1}; |     static const struct lfs_testbd_config defaults = {.erase_value=-1}; | ||||||
|     int err = lfs_testbd_createcfg(cfg, path, &defaults); |     int err = lfs_testbd_createcfg(cfg, path, &defaults); | ||||||
|     LFS_TESTBD_TRACE("lfs_testbd_create -> %d", err); |     LFS_TRACE("lfs_testbd_create -> %d", err); | ||||||
|     return err; |     return err; | ||||||
| } | } | ||||||
|  |  | ||||||
| int lfs_testbd_destroy(const struct lfs_config *cfg) { | int lfs_testbd_destroy(const struct lfs_config *cfg) { | ||||||
|     LFS_TESTBD_TRACE("lfs_testbd_destroy(%p)", (void*)cfg); |     LFS_TRACE("lfs_testbd_destroy(%p)", (void*)cfg); | ||||||
|     lfs_testbd_t *bd = cfg->context; |     lfs_testbd_t *bd = cfg->context; | ||||||
|     if (bd->cfg->erase_cycles && !bd->cfg->wear_buffer) { |     if (bd->cfg->erase_cycles && !bd->cfg->wear_buffer) { | ||||||
|         lfs_free(bd->wear); |         lfs_free(bd->wear); | ||||||
| @@ -93,11 +93,11 @@ int lfs_testbd_destroy(const struct lfs_config *cfg) { | |||||||
|  |  | ||||||
|     if (bd->persist) { |     if (bd->persist) { | ||||||
|         int err = lfs_filebd_destroy(cfg); |         int err = lfs_filebd_destroy(cfg); | ||||||
|         LFS_TESTBD_TRACE("lfs_testbd_destroy -> %d", err); |         LFS_TRACE("lfs_testbd_destroy -> %d", err); | ||||||
|         return err; |         return err; | ||||||
|     } else { |     } else { | ||||||
|         int err = lfs_rambd_destroy(cfg); |         int err = lfs_rambd_destroy(cfg); | ||||||
|         LFS_TESTBD_TRACE("lfs_testbd_destroy -> %d", err); |         LFS_TRACE("lfs_testbd_destroy -> %d", err); | ||||||
|         return err; |         return err; | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @@ -145,8 +145,7 @@ static int lfs_testbd_rawsync(const struct lfs_config *cfg) { | |||||||
| /// block device API /// | /// block device API /// | ||||||
| int lfs_testbd_read(const struct lfs_config *cfg, lfs_block_t block, | int lfs_testbd_read(const struct lfs_config *cfg, lfs_block_t block, | ||||||
|         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_TRACE("lfs_testbd_read(%p, 0x%"PRIx32", %"PRIu32", %p, %"PRIu32")", | ||||||
|                 "0x%"PRIx32", %"PRIu32", %p, %"PRIu32")", |  | ||||||
|             (void*)cfg, block, off, buffer, size); |             (void*)cfg, block, off, buffer, size); | ||||||
|     lfs_testbd_t *bd = cfg->context; |     lfs_testbd_t *bd = cfg->context; | ||||||
|  |  | ||||||
| @@ -158,20 +157,19 @@ int lfs_testbd_read(const struct lfs_config *cfg, lfs_block_t block, | |||||||
|     // 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_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(cfg, block, off, buffer, size); | ||||||
|     LFS_TESTBD_TRACE("lfs_testbd_read -> %d", err); |     LFS_TRACE("lfs_testbd_read -> %d", err); | ||||||
|     return err; |     return err; | ||||||
| } | } | ||||||
|  |  | ||||||
| int lfs_testbd_prog(const struct lfs_config *cfg, lfs_block_t block, | int lfs_testbd_prog(const struct lfs_config *cfg, 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_TRACE("lfs_testbd_prog(%p, 0x%"PRIx32", %"PRIu32", %p, %"PRIu32")", | ||||||
|                 "0x%"PRIx32", %"PRIu32", %p, %"PRIu32")", |  | ||||||
|             (void*)cfg, block, off, buffer, size); |             (void*)cfg, block, off, buffer, size); | ||||||
|     lfs_testbd_t *bd = cfg->context; |     lfs_testbd_t *bd = cfg->context; | ||||||
|  |  | ||||||
| @@ -184,13 +182,13 @@ int lfs_testbd_prog(const struct lfs_config *cfg, lfs_block_t block, | |||||||
|     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_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_TRACE("lfs_testbd_prog -> %d", 0); | ||||||
|             return 0; |             return 0; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @@ -198,7 +196,7 @@ int lfs_testbd_prog(const struct lfs_config *cfg, lfs_block_t block, | |||||||
|     // prog |     // prog | ||||||
|     int err = lfs_testbd_rawprog(cfg, block, off, buffer, size); |     int err = lfs_testbd_rawprog(cfg, block, off, buffer, size); | ||||||
|     if (err) { |     if (err) { | ||||||
|         LFS_TESTBD_TRACE("lfs_testbd_prog -> %d", err); |         LFS_TRACE("lfs_testbd_prog -> %d", err); | ||||||
|         return err; |         return err; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -213,12 +211,12 @@ int lfs_testbd_prog(const struct lfs_config *cfg, lfs_block_t block, | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     LFS_TESTBD_TRACE("lfs_testbd_prog -> %d", 0); |     LFS_TRACE("lfs_testbd_prog -> %d", 0); | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| int lfs_testbd_erase(const struct lfs_config *cfg, lfs_block_t block) { | int lfs_testbd_erase(const struct lfs_config *cfg, lfs_block_t block) { | ||||||
|     LFS_TESTBD_TRACE("lfs_testbd_erase(%p, 0x%"PRIx32")", (void*)cfg, block); |     LFS_TRACE("lfs_testbd_erase(%p, 0x%"PRIx32")", (void*)cfg, block); | ||||||
|     lfs_testbd_t *bd = cfg->context; |     lfs_testbd_t *bd = cfg->context; | ||||||
|  |  | ||||||
|     // check if erase is valid |     // check if erase is valid | ||||||
| @@ -229,11 +227,11 @@ int lfs_testbd_erase(const struct lfs_config *cfg, lfs_block_t block) { | |||||||
|         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_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_TRACE("lfs_testbd_erase -> %d", 0); | ||||||
|                 return 0; |                 return 0; | ||||||
|             } |             } | ||||||
|         } else { |         } else { | ||||||
| @@ -245,7 +243,7 @@ int lfs_testbd_erase(const struct lfs_config *cfg, lfs_block_t block) { | |||||||
|     // erase |     // erase | ||||||
|     int err = lfs_testbd_rawerase(cfg, block); |     int err = lfs_testbd_rawerase(cfg, block); | ||||||
|     if (err) { |     if (err) { | ||||||
|         LFS_TESTBD_TRACE("lfs_testbd_erase -> %d", err); |         LFS_TRACE("lfs_testbd_erase -> %d", err); | ||||||
|         return err; |         return err; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -260,14 +258,14 @@ int lfs_testbd_erase(const struct lfs_config *cfg, lfs_block_t block) { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     LFS_TESTBD_TRACE("lfs_testbd_prog -> %d", 0); |     LFS_TRACE("lfs_testbd_prog -> %d", 0); | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| int lfs_testbd_sync(const struct lfs_config *cfg) { | int lfs_testbd_sync(const struct lfs_config *cfg) { | ||||||
|     LFS_TESTBD_TRACE("lfs_testbd_sync(%p)", (void*)cfg); |     LFS_TRACE("lfs_testbd_sync(%p)", (void*)cfg); | ||||||
|     int err = lfs_testbd_rawsync(cfg); |     int err = lfs_testbd_rawsync(cfg); | ||||||
|     LFS_TESTBD_TRACE("lfs_testbd_sync -> %d", err); |     LFS_TRACE("lfs_testbd_sync -> %d", err); | ||||||
|     return err; |     return err; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -275,20 +273,20 @@ int lfs_testbd_sync(const struct lfs_config *cfg) { | |||||||
| /// simulated wear operations /// | /// simulated wear operations /// | ||||||
| lfs_testbd_swear_t lfs_testbd_getwear(const struct lfs_config *cfg, | lfs_testbd_swear_t lfs_testbd_getwear(const struct lfs_config *cfg, | ||||||
|         lfs_block_t block) { |         lfs_block_t block) { | ||||||
|     LFS_TESTBD_TRACE("lfs_testbd_getwear(%p, %"PRIu32")", (void*)cfg, block); |     LFS_TRACE("lfs_testbd_getwear(%p, %"PRIu32")", (void*)cfg, block); | ||||||
|     lfs_testbd_t *bd = cfg->context; |     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 < cfg->block_count); | ||||||
|  |  | ||||||
|     LFS_TESTBD_TRACE("lfs_testbd_getwear -> %"PRIu32, bd->wear[block]); |     LFS_TRACE("lfs_testbd_getwear -> %"PRIu32, bd->wear[block]); | ||||||
|     return bd->wear[block]; |     return bd->wear[block]; | ||||||
| } | } | ||||||
|  |  | ||||||
| int lfs_testbd_setwear(const struct lfs_config *cfg, | int lfs_testbd_setwear(const struct lfs_config *cfg, | ||||||
|         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_TRACE("lfs_testbd_setwear(%p, %"PRIu32")", (void*)cfg, block); | ||||||
|     lfs_testbd_t *bd = cfg->context; |     lfs_testbd_t *bd = cfg->context; | ||||||
|  |  | ||||||
|     // check if block is valid |     // check if block is valid | ||||||
| @@ -297,6 +295,6 @@ int lfs_testbd_setwear(const struct lfs_config *cfg, | |||||||
|  |  | ||||||
|     bd->wear[block] = wear; |     bd->wear[block] = wear; | ||||||
|  |  | ||||||
|     LFS_TESTBD_TRACE("lfs_testbd_setwear -> %d", 0); |     LFS_TRACE("lfs_testbd_setwear -> %d", 0); | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -19,13 +19,6 @@ extern "C" | |||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  |  | ||||||
| // Block device specific tracing |  | ||||||
| #ifdef LFS_TESTBD_YES_TRACE |  | ||||||
| #define LFS_TESTBD_TRACE(...) LFS_TRACE(__VA_ARGS__) |  | ||||||
| #else |  | ||||||
| #define LFS_TESTBD_TRACE(...) |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| // Mode determining how "bad blocks" behave during testing. This simulates | // Mode determining how "bad blocks" behave during testing. This simulates | ||||||
| // some real-world circumstances such as progs not sticking (prog-noop), | // some real-world circumstances such as progs not sticking (prog-noop), | ||||||
| // a readonly disk (erase-noop), and ECC failures (read-error). | // a readonly disk (erase-noop), and ECC failures (read-error). | ||||||
|   | |||||||
							
								
								
									
										83
									
								
								lfs.c
									
									
									
									
									
								
							
							
						
						
									
										83
									
								
								lfs.c
									
									
									
									
									
								
							| @@ -71,21 +71,6 @@ static int lfs_bd_read(lfs_t *lfs, | |||||||
|             diff = lfs_min(diff, rcache->off-off); |             diff = lfs_min(diff, rcache->off-off); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if (size >= hint && off % lfs->cfg->read_size == 0 && |  | ||||||
|                 size >= lfs->cfg->read_size) { |  | ||||||
|             // bypass cache? |  | ||||||
|             diff = lfs_aligndown(diff, lfs->cfg->read_size); |  | ||||||
|             int err = lfs->cfg->read(lfs->cfg, block, off, data, diff); |  | ||||||
|             if (err) { |  | ||||||
|                 return err; |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             data += diff; |  | ||||||
|             off += diff; |  | ||||||
|             size -= diff; |  | ||||||
|             continue; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         // load to cache, first condition can no longer fail |         // load to cache, first condition can no longer fail | ||||||
|         LFS_ASSERT(block < lfs->cfg->block_count); |         LFS_ASSERT(block < lfs->cfg->block_count); | ||||||
|         rcache->block = block; |         rcache->block = block; | ||||||
| @@ -452,19 +437,6 @@ static int lfs_alloc_lookahead(void *p, lfs_block_t block) { | |||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| static void lfs_alloc_ack(lfs_t *lfs) { |  | ||||||
|     lfs->free.ack = lfs->cfg->block_count; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Invalidate the lookahead buffer. This is done during mounting and |  | ||||||
| // failed traversals |  | ||||||
| static void lfs_alloc_reset(lfs_t *lfs) { |  | ||||||
|     lfs->free.off = lfs->seed % lfs->cfg->block_size; |  | ||||||
|     lfs->free.size = 0; |  | ||||||
|     lfs->free.i = 0; |  | ||||||
|     lfs_alloc_ack(lfs); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static int lfs_alloc(lfs_t *lfs, lfs_block_t *block) { | static int lfs_alloc(lfs_t *lfs, lfs_block_t *block) { | ||||||
|     while (true) { |     while (true) { | ||||||
|         while (lfs->free.i != lfs->free.size) { |         while (lfs->free.i != lfs->free.size) { | ||||||
| @@ -505,12 +477,16 @@ static int lfs_alloc(lfs_t *lfs, lfs_block_t *block) { | |||||||
|         memset(lfs->free.buffer, 0, lfs->cfg->lookahead_size); |         memset(lfs->free.buffer, 0, lfs->cfg->lookahead_size); | ||||||
|         int err = lfs_fs_traverseraw(lfs, lfs_alloc_lookahead, lfs, true); |         int err = lfs_fs_traverseraw(lfs, lfs_alloc_lookahead, lfs, true); | ||||||
|         if (err) { |         if (err) { | ||||||
|             lfs_alloc_reset(lfs); |  | ||||||
|             return err; |             return err; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | static void lfs_alloc_ack(lfs_t *lfs) { | ||||||
|  |     lfs->free.ack = lfs->cfg->block_count; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
| /// Metadata pair and directory operations /// | /// Metadata pair and directory operations /// | ||||||
| static lfs_stag_t lfs_dir_getslice(lfs_t *lfs, const lfs_mdir_t *dir, | static lfs_stag_t lfs_dir_getslice(lfs_t *lfs, const lfs_mdir_t *dir, | ||||||
|         lfs_tag_t gmask, lfs_tag_t gtag, |         lfs_tag_t gmask, lfs_tag_t gtag, | ||||||
| @@ -994,7 +970,7 @@ static lfs_stag_t lfs_dir_fetchmatch(lfs_t *lfs, | |||||||
|         dir->rev = revs[(r+1)%2]; |         dir->rev = revs[(r+1)%2]; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     LFS_ERROR("Corrupted dir pair at {0x%"PRIx32", 0x%"PRIx32"}", |     LFS_ERROR("Corrupted dir pair at %"PRIx32" %"PRIx32, | ||||||
|             dir->pair[0], dir->pair[1]); |             dir->pair[0], dir->pair[1]); | ||||||
|     return LFS_ERR_CORRUPT; |     return LFS_ERR_CORRUPT; | ||||||
| } | } | ||||||
| @@ -1682,13 +1658,12 @@ relocate: | |||||||
|         relocated = true; |         relocated = true; | ||||||
|         lfs_cache_drop(lfs, &lfs->pcache); |         lfs_cache_drop(lfs, &lfs->pcache); | ||||||
|         if (!tired) { |         if (!tired) { | ||||||
|             LFS_DEBUG("Bad block at 0x%"PRIx32, dir->pair[1]); |             LFS_DEBUG("Bad block at %"PRIx32, dir->pair[1]); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         // can't relocate superblock, filesystem is now frozen |         // can't relocate superblock, filesystem is now frozen | ||||||
|         if (lfs_pair_cmp(dir->pair, (const lfs_block_t[2]){0, 1}) == 0) { |         if (lfs_pair_cmp(dir->pair, (const lfs_block_t[2]){0, 1}) == 0) { | ||||||
|             LFS_WARN("Superblock 0x%"PRIx32" has become unwritable", |             LFS_WARN("Superblock %"PRIx32" has become unwritable", dir->pair[1]); | ||||||
|                     dir->pair[1]); |  | ||||||
|             return LFS_ERR_NOSPC; |             return LFS_ERR_NOSPC; | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @@ -1704,8 +1679,7 @@ relocate: | |||||||
|  |  | ||||||
|     if (relocated) { |     if (relocated) { | ||||||
|         // update references if we relocated |         // update references if we relocated | ||||||
|         LFS_DEBUG("Relocating {0x%"PRIx32", 0x%"PRIx32"} " |         LFS_DEBUG("Relocating %"PRIx32" %"PRIx32" -> %"PRIx32" %"PRIx32, | ||||||
|                     "-> {0x%"PRIx32", 0x%"PRIx32"}", |  | ||||||
|                 oldpair[0], oldpair[1], dir->pair[0], dir->pair[1]); |                 oldpair[0], oldpair[1], dir->pair[0], dir->pair[1]); | ||||||
|         int err = lfs_fs_relocate(lfs, oldpair, dir->pair); |         int err = lfs_fs_relocate(lfs, oldpair, dir->pair); | ||||||
|         if (err) { |         if (err) { | ||||||
| @@ -2328,7 +2302,7 @@ static int lfs_ctz_extend(lfs_t *lfs, | |||||||
|         } |         } | ||||||
|  |  | ||||||
| relocate: | relocate: | ||||||
|         LFS_DEBUG("Bad block at 0x%"PRIx32, nblock); |         LFS_DEBUG("Bad block at %"PRIx32, nblock); | ||||||
|  |  | ||||||
|         // just clear cache and try a new block |         // just clear cache and try a new block | ||||||
|         lfs_cache_drop(lfs, pcache); |         lfs_cache_drop(lfs, pcache); | ||||||
| @@ -2632,7 +2606,7 @@ static int lfs_file_relocate(lfs_t *lfs, lfs_file_t *file) { | |||||||
|         return 0; |         return 0; | ||||||
|  |  | ||||||
| relocate: | relocate: | ||||||
|         LFS_DEBUG("Bad block at 0x%"PRIx32, nblock); |         LFS_DEBUG("Bad block at %"PRIx32, nblock); | ||||||
|  |  | ||||||
|         // just clear cache and try a new block |         // just clear cache and try a new block | ||||||
|         lfs_cache_drop(lfs, &lfs->pcache); |         lfs_cache_drop(lfs, &lfs->pcache); | ||||||
| @@ -2709,7 +2683,7 @@ static int lfs_file_flush(lfs_t *lfs, lfs_file_t *file) { | |||||||
|                 break; |                 break; | ||||||
|  |  | ||||||
| relocate: | relocate: | ||||||
|                 LFS_DEBUG("Bad block at 0x%"PRIx32, file->block); |                 LFS_DEBUG("Bad block at %"PRIx32, file->block); | ||||||
|                 err = lfs_file_relocate(lfs, file); |                 err = lfs_file_relocate(lfs, file); | ||||||
|                 if (err) { |                 if (err) { | ||||||
|                     return err; |                     return err; | ||||||
| @@ -3733,7 +3707,7 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) { | |||||||
|             uint16_t minor_version = (0xffff & (superblock.version >>  0)); |             uint16_t minor_version = (0xffff & (superblock.version >>  0)); | ||||||
|             if ((major_version != LFS_DISK_VERSION_MAJOR || |             if ((major_version != LFS_DISK_VERSION_MAJOR || | ||||||
|                  minor_version > LFS_DISK_VERSION_MINOR)) { |                  minor_version > LFS_DISK_VERSION_MINOR)) { | ||||||
|                 LFS_ERROR("Invalid version v%"PRIu16".%"PRIu16, |                 LFS_ERROR("Invalid version %"PRIu16".%"PRIu16, | ||||||
|                         major_version, minor_version); |                         major_version, minor_version); | ||||||
|                 err = LFS_ERR_INVAL; |                 err = LFS_ERR_INVAL; | ||||||
|                 goto cleanup; |                 goto cleanup; | ||||||
| @@ -3789,7 +3763,7 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) { | |||||||
|  |  | ||||||
|     // update littlefs with gstate |     // update littlefs with gstate | ||||||
|     if (!lfs_gstate_iszero(&lfs->gstate)) { |     if (!lfs_gstate_iszero(&lfs->gstate)) { | ||||||
|         LFS_DEBUG("Found pending gstate 0x%08"PRIx32"%08"PRIx32"%08"PRIx32, |         LFS_DEBUG("Found pending gstate %08"PRIx32" %08"PRIx32" %08"PRIx32, | ||||||
|                 lfs->gstate.tag, |                 lfs->gstate.tag, | ||||||
|                 lfs->gstate.pair[0], |                 lfs->gstate.pair[0], | ||||||
|                 lfs->gstate.pair[1]); |                 lfs->gstate.pair[1]); | ||||||
| @@ -3798,7 +3772,10 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) { | |||||||
|     lfs->gdisk = lfs->gstate; |     lfs->gdisk = lfs->gstate; | ||||||
|  |  | ||||||
|     // setup free lookahead |     // setup free lookahead | ||||||
|     lfs_alloc_reset(lfs); |     lfs->free.off = lfs->seed % lfs->cfg->block_size; | ||||||
|  |     lfs->free.size = 0; | ||||||
|  |     lfs->free.i = 0; | ||||||
|  |     lfs_alloc_ack(lfs); | ||||||
|  |  | ||||||
|     LFS_TRACE("lfs_mount -> %d", 0); |     LFS_TRACE("lfs_mount -> %d", 0); | ||||||
|     return 0; |     return 0; | ||||||
| @@ -4004,6 +3981,8 @@ static int lfs_fs_relocate(lfs_t *lfs, | |||||||
|         const lfs_block_t oldpair[2], lfs_block_t newpair[2]) { |         const lfs_block_t oldpair[2], lfs_block_t newpair[2]) { | ||||||
|     // update internal root |     // update internal root | ||||||
|     if (lfs_pair_cmp(oldpair, lfs->root) == 0) { |     if (lfs_pair_cmp(oldpair, lfs->root) == 0) { | ||||||
|  |         LFS_DEBUG("Relocating root %"PRIx32" %"PRIx32, | ||||||
|  |                 newpair[0], newpair[1]); | ||||||
|         lfs->root[0] = newpair[0]; |         lfs->root[0] = newpair[0]; | ||||||
|         lfs->root[1] = newpair[1]; |         lfs->root[1] = newpair[1]; | ||||||
|     } |     } | ||||||
| @@ -4039,7 +4018,7 @@ static int lfs_fs_relocate(lfs_t *lfs, | |||||||
|         if (lfs_gstate_hasmovehere(&lfs->gstate, parent.pair)) { |         if (lfs_gstate_hasmovehere(&lfs->gstate, parent.pair)) { | ||||||
|             moveid = lfs_tag_id(lfs->gstate.tag); |             moveid = lfs_tag_id(lfs->gstate.tag); | ||||||
|             LFS_DEBUG("Fixing move while relocating " |             LFS_DEBUG("Fixing move while relocating " | ||||||
|                     "{0x%"PRIx32", 0x%"PRIx32"} 0x%"PRIx16"\n", |                     "%"PRIx32" %"PRIx32" %"PRIx16"\n", | ||||||
|                     parent.pair[0], parent.pair[1], moveid); |                     parent.pair[0], parent.pair[1], moveid); | ||||||
|             lfs_fs_prepmove(lfs, 0x3ff, NULL); |             lfs_fs_prepmove(lfs, 0x3ff, NULL); | ||||||
|             if (moveid < lfs_tag_id(tag)) { |             if (moveid < lfs_tag_id(tag)) { | ||||||
| @@ -4075,7 +4054,7 @@ static int lfs_fs_relocate(lfs_t *lfs, | |||||||
|         if (lfs_gstate_hasmovehere(&lfs->gstate, parent.pair)) { |         if (lfs_gstate_hasmovehere(&lfs->gstate, parent.pair)) { | ||||||
|             moveid = lfs_tag_id(lfs->gstate.tag); |             moveid = lfs_tag_id(lfs->gstate.tag); | ||||||
|             LFS_DEBUG("Fixing move while relocating " |             LFS_DEBUG("Fixing move while relocating " | ||||||
|                     "{0x%"PRIx32", 0x%"PRIx32"} 0x%"PRIx16"\n", |                     "%"PRIx32" %"PRIx32" %"PRIx16"\n", | ||||||
|                     parent.pair[0], parent.pair[1], moveid); |                     parent.pair[0], parent.pair[1], moveid); | ||||||
|             lfs_fs_prepmove(lfs, 0x3ff, NULL); |             lfs_fs_prepmove(lfs, 0x3ff, NULL); | ||||||
|         } |         } | ||||||
| @@ -4116,7 +4095,7 @@ static int lfs_fs_demove(lfs_t *lfs) { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     // Fix bad moves |     // Fix bad moves | ||||||
|     LFS_DEBUG("Fixing move {0x%"PRIx32", 0x%"PRIx32"} 0x%"PRIx16, |     LFS_DEBUG("Fixing move %"PRIx32" %"PRIx32" %"PRIx16, | ||||||
|             lfs->gdisk.pair[0], |             lfs->gdisk.pair[0], | ||||||
|             lfs->gdisk.pair[1], |             lfs->gdisk.pair[1], | ||||||
|             lfs_tag_id(lfs->gdisk.tag)); |             lfs_tag_id(lfs->gdisk.tag)); | ||||||
| @@ -4167,7 +4146,7 @@ static int lfs_fs_deorphan(lfs_t *lfs) { | |||||||
|  |  | ||||||
|             if (tag == LFS_ERR_NOENT) { |             if (tag == LFS_ERR_NOENT) { | ||||||
|                 // we are an orphan |                 // we are an orphan | ||||||
|                 LFS_DEBUG("Fixing orphan {0x%"PRIx32", 0x%"PRIx32"}", |                 LFS_DEBUG("Fixing orphan %"PRIx32" %"PRIx32, | ||||||
|                         pdir.tail[0], pdir.tail[1]); |                         pdir.tail[0], pdir.tail[1]); | ||||||
|  |  | ||||||
|                 err = lfs_dir_drop(lfs, &pdir, &dir); |                 err = lfs_dir_drop(lfs, &pdir, &dir); | ||||||
| @@ -4189,8 +4168,8 @@ static int lfs_fs_deorphan(lfs_t *lfs) { | |||||||
|  |  | ||||||
|             if (!lfs_pair_sync(pair, pdir.tail)) { |             if (!lfs_pair_sync(pair, pdir.tail)) { | ||||||
|                 // we have desynced |                 // we have desynced | ||||||
|                 LFS_DEBUG("Fixing half-orphan {0x%"PRIx32", 0x%"PRIx32"} " |                 LFS_DEBUG("Fixing half-orphan " | ||||||
|                             "-> {0x%"PRIx32", 0x%"PRIx32"}", |                         "%"PRIx32" %"PRIx32" -> %"PRIx32" %"PRIx32, | ||||||
|                         pdir.tail[0], pdir.tail[1], pair[0], pair[1]); |                         pdir.tail[0], pdir.tail[1], pair[0], pair[1]); | ||||||
|  |  | ||||||
|                 lfs_pair_tole32(pair); |                 lfs_pair_tole32(pair); | ||||||
| @@ -4453,7 +4432,7 @@ static int lfs1_dir_fetch(lfs_t *lfs, | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     if (!valid) { |     if (!valid) { | ||||||
|         LFS_ERROR("Corrupted dir pair at {0x%"PRIx32", 0x%"PRIx32"}", |         LFS_ERROR("Corrupted dir pair at %" PRIx32 " %" PRIx32 , | ||||||
|                 tpair[0], tpair[1]); |                 tpair[0], tpair[1]); | ||||||
|         return LFS_ERR_CORRUPT; |         return LFS_ERR_CORRUPT; | ||||||
|     } |     } | ||||||
| @@ -4641,8 +4620,7 @@ static int lfs1_mount(lfs_t *lfs, struct lfs1 *lfs1, | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         if (err || memcmp(superblock.d.magic, "littlefs", 8) != 0) { |         if (err || memcmp(superblock.d.magic, "littlefs", 8) != 0) { | ||||||
|             LFS_ERROR("Invalid superblock at {0x%"PRIx32", 0x%"PRIx32"}", |             LFS_ERROR("Invalid superblock at %d %d", 0, 1); | ||||||
|                     0, 1); |  | ||||||
|             err = LFS_ERR_CORRUPT; |             err = LFS_ERR_CORRUPT; | ||||||
|             goto cleanup; |             goto cleanup; | ||||||
|         } |         } | ||||||
| @@ -4651,7 +4629,7 @@ static int lfs1_mount(lfs_t *lfs, struct lfs1 *lfs1, | |||||||
|         uint16_t minor_version = (0xffff & (superblock.d.version >>  0)); |         uint16_t minor_version = (0xffff & (superblock.d.version >>  0)); | ||||||
|         if ((major_version != LFS1_DISK_VERSION_MAJOR || |         if ((major_version != LFS1_DISK_VERSION_MAJOR || | ||||||
|              minor_version > LFS1_DISK_VERSION_MINOR)) { |              minor_version > LFS1_DISK_VERSION_MINOR)) { | ||||||
|             LFS_ERROR("Invalid version v%d.%d", major_version, minor_version); |             LFS_ERROR("Invalid version %d.%d", major_version, minor_version); | ||||||
|             err = LFS_ERR_INVAL; |             err = LFS_ERR_INVAL; | ||||||
|             goto cleanup; |             goto cleanup; | ||||||
|         } |         } | ||||||
| @@ -4817,8 +4795,7 @@ int lfs_migrate(lfs_t *lfs, const struct lfs_config *cfg) { | |||||||
|  |  | ||||||
|             // Copy over first block to thread into fs. Unfortunately |             // Copy over first block to thread into fs. Unfortunately | ||||||
|             // if this fails there is not much we can do. |             // if this fails there is not much we can do. | ||||||
|             LFS_DEBUG("Migrating {0x%"PRIx32", 0x%"PRIx32"} " |             LFS_DEBUG("Migrating %"PRIx32" %"PRIx32" -> %"PRIx32" %"PRIx32, | ||||||
|                         "-> {0x%"PRIx32", 0x%"PRIx32"}", |  | ||||||
|                     lfs->root[0], lfs->root[1], dir1.head[0], dir1.head[1]); |                     lfs->root[0], lfs->root[1], dir1.head[0], dir1.head[1]); | ||||||
|  |  | ||||||
|             err = lfs_bd_erase(lfs, dir1.head[1]); |             err = lfs_bd_erase(lfs, dir1.head[1]); | ||||||
|   | |||||||
							
								
								
									
										2
									
								
								lfs.h
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								lfs.h
									
									
									
									
									
								
							| @@ -21,7 +21,7 @@ extern "C" | |||||||
| // Software library version | // Software library version | ||||||
| // Major (top-nibble), incremented on backwards incompatible changes | // Major (top-nibble), incremented on backwards incompatible changes | ||||||
| // Minor (bottom-nibble), incremented on feature additions | // Minor (bottom-nibble), incremented on feature additions | ||||||
| #define LFS_VERSION 0x00020002 | #define LFS_VERSION 0x00020001 | ||||||
| #define LFS_VERSION_MAJOR (0xffff & (LFS_VERSION >> 16)) | #define LFS_VERSION_MAJOR (0xffff & (LFS_VERSION >> 16)) | ||||||
| #define LFS_VERSION_MINOR (0xffff & (LFS_VERSION >>  0)) | #define LFS_VERSION_MINOR (0xffff & (LFS_VERSION >>  0)) | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										30
									
								
								lfs_util.h
									
									
									
									
									
								
							
							
						
						
									
										30
									
								
								lfs_util.h
									
									
									
									
									
								
							| @@ -50,35 +50,31 @@ extern "C" | |||||||
|  |  | ||||||
| // Logging functions | // Logging functions | ||||||
| #ifdef LFS_YES_TRACE | #ifdef LFS_YES_TRACE | ||||||
| #define LFS_TRACE_(fmt, ...) \ | #define LFS_TRACE(fmt, ...) \ | ||||||
|     printf("%s:%d:trace: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__) |     printf("%s:%d:trace: " fmt "\n", __FILE__, __LINE__, __VA_ARGS__) | ||||||
| #define LFS_TRACE(...) LFS_TRACE_(__VA_ARGS__, "") |  | ||||||
| #else | #else | ||||||
| #define LFS_TRACE(...) | #define LFS_TRACE(fmt, ...) | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| #ifndef LFS_NO_DEBUG | #ifndef LFS_NO_DEBUG | ||||||
| #define LFS_DEBUG_(fmt, ...) \ | #define LFS_DEBUG(fmt, ...) \ | ||||||
|     printf("%s:%d:debug: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__) |     printf("%s:%d:debug: " fmt "\n", __FILE__, __LINE__, __VA_ARGS__) | ||||||
| #define LFS_DEBUG(...) LFS_DEBUG_(__VA_ARGS__, "") |  | ||||||
| #else | #else | ||||||
| #define LFS_DEBUG(...) | #define LFS_DEBUG(fmt, ...) | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| #ifndef LFS_NO_WARN | #ifndef LFS_NO_WARN | ||||||
| #define LFS_WARN_(fmt, ...) \ | #define LFS_WARN(fmt, ...) \ | ||||||
|     printf("%s:%d:warn: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__) |     printf("%s:%d:warn: " fmt "\n", __FILE__, __LINE__, __VA_ARGS__) | ||||||
| #define LFS_WARN(...) LFS_WARN_(__VA_ARGS__, "") |  | ||||||
| #else | #else | ||||||
| #define LFS_WARN(...) | #define LFS_WARN(fmt, ...) | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| #ifndef LFS_NO_ERROR | #ifndef LFS_NO_ERROR | ||||||
| #define LFS_ERROR_(fmt, ...) \ | #define LFS_ERROR(fmt, ...) \ | ||||||
|     printf("%s:%d:error: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__) |     printf("%s:%d:error: " fmt "\n", __FILE__, __LINE__, __VA_ARGS__) | ||||||
| #define LFS_ERROR(...) LFS_ERROR_(__VA_ARGS__, "") |  | ||||||
| #else | #else | ||||||
| #define LFS_ERROR(...) | #define LFS_ERROR(fmt, ...) | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| // Runtime assertions | // Runtime assertions | ||||||
| @@ -111,7 +107,7 @@ static inline uint32_t lfs_alignup(uint32_t a, uint32_t alignment) { | |||||||
|     return lfs_aligndown(a + alignment-1, alignment); |     return lfs_aligndown(a + alignment-1, alignment); | ||||||
| } | } | ||||||
|  |  | ||||||
| // Find the smallest power of 2 greater than or equal to a | // Find the next smallest power of 2 less than or equal to a | ||||||
| static inline uint32_t lfs_npw2(uint32_t a) { | static inline uint32_t lfs_npw2(uint32_t a) { | ||||||
| #if !defined(LFS_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM)) | #if !defined(LFS_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM)) | ||||||
|     return 32 - __builtin_clz(a-1); |     return 32 - __builtin_clz(a-1); | ||||||
|   | |||||||
| @@ -233,8 +233,8 @@ class MetadataPair: | |||||||
|  |  | ||||||
|     def __lt__(self, other): |     def __lt__(self, other): | ||||||
|         # corrupt blocks don't count |         # corrupt blocks don't count | ||||||
|         if not self or not other: |         if not self and other: | ||||||
|             return bool(other) |             return True | ||||||
|  |  | ||||||
|         # use sequence arithmetic to avoid overflow |         # use sequence arithmetic to avoid overflow | ||||||
|         return not ((other.rev - self.rev) & 0x80000000) |         return not ((other.rev - self.rev) & 0x80000000) | ||||||
| @@ -318,24 +318,14 @@ def main(args): | |||||||
|  |  | ||||||
|     # find most recent pair |     # find most recent pair | ||||||
|     mdir = MetadataPair(blocks) |     mdir = MetadataPair(blocks) | ||||||
|  |     print("mdir {%s} rev %d%s%s" % ( | ||||||
|     try: |  | ||||||
|         mdir.tail = mdir[Tag('tail', 0, 0)] |  | ||||||
|         if mdir.tail.size != 8 or mdir.tail.data == 8*b'\xff': |  | ||||||
|             mdir.tail = None |  | ||||||
|     except KeyError: |  | ||||||
|         mdir.tail = None |  | ||||||
|  |  | ||||||
|     print("mdir {%s} rev %d%s%s%s" % ( |  | ||||||
|         ', '.join('%#x' % b |         ', '.join('%#x' % b | ||||||
|             for b in [args.block1, args.block2] |             for b in [args.block1, args.block2] | ||||||
|             if b is not None), |             if b is not None), | ||||||
|         mdir.rev, |         mdir.rev, | ||||||
|         ' (was %s)' % ', '.join('%d' % m.rev for m in mdir.pair[1:]) |         ' (was %s)' % ', '.join('%d' % m.rev for m in mdir.pair[1:]) | ||||||
|         if len(mdir.pair) > 1 else '', |         if len(mdir.pair) > 1 else '', | ||||||
|         ' (corrupted!)' if not mdir else '', |         ' (corrupted)' if not mdir else '')) | ||||||
|         ' -> {%#x, %#x}' % struct.unpack('<II', mdir.tail.data) |  | ||||||
|         if mdir.tail else '')) |  | ||||||
|     if args.all: |     if args.all: | ||||||
|         mdir.dump_all(truncate=not args.no_truncate) |         mdir.dump_all(truncate=not args.no_truncate) | ||||||
|     elif args.log: |     elif args.log: | ||||||
|   | |||||||
| @@ -7,14 +7,97 @@ import io | |||||||
| import itertools as it | import itertools as it | ||||||
| from readmdir import Tag, MetadataPair | from readmdir import Tag, MetadataPair | ||||||
|  |  | ||||||
|  | def popc(x): | ||||||
|  |     return bin(x).count('1') | ||||||
|  |  | ||||||
|  | def ctz(x): | ||||||
|  |     return len(bin(x)) - len(bin(x).rstrip('0')) | ||||||
|  |  | ||||||
|  | def dumpentries(args, mdir, f): | ||||||
|  |     for k, id_ in enumerate(mdir.ids): | ||||||
|  |         name = mdir[Tag('name', id_, 0)] | ||||||
|  |         struct_ = mdir[Tag('struct', id_, 0)] | ||||||
|  |  | ||||||
|  |         desc = "id %d %s %s" % ( | ||||||
|  |             id_, name.typerepr(), | ||||||
|  |             json.dumps(name.data.decode('utf8'))) | ||||||
|  |         if struct_.is_('dirstruct'): | ||||||
|  |             desc += " dir {%#x, %#x}" % struct.unpack( | ||||||
|  |                 '<II', struct_.data[:8].ljust(8, b'\xff')) | ||||||
|  |         if struct_.is_('ctzstruct'): | ||||||
|  |             desc += " ctz {%#x} size %d" % struct.unpack( | ||||||
|  |                 '<II', struct_.data[:8].ljust(8, b'\xff')) | ||||||
|  |         if struct_.is_('inlinestruct'): | ||||||
|  |             desc += " inline size %d" % struct_.size | ||||||
|  |  | ||||||
|  |         data = None | ||||||
|  |         if struct_.is_('inlinestruct'): | ||||||
|  |             data = struct_.data | ||||||
|  |         elif struct_.is_('ctzstruct'): | ||||||
|  |             block, size = struct.unpack( | ||||||
|  |                 '<II', struct_.data[:8].ljust(8, b'\xff')) | ||||||
|  |             data = [] | ||||||
|  |             i = 0 if size == 0 else (size-1) // (args.block_size - 8) | ||||||
|  |             if i != 0: | ||||||
|  |                 i = ((size-1) - 4*popc(i-1)+2) // (args.block_size - 8) | ||||||
|  |             with open(args.disk, 'rb') as f2: | ||||||
|  |                 while i >= 0: | ||||||
|  |                     f2.seek(block * args.block_size) | ||||||
|  |                     dat = f2.read(args.block_size) | ||||||
|  |                     data.append(dat[4*(ctz(i)+1) if i != 0 else 0:]) | ||||||
|  |                     block, = struct.unpack('<I', dat[:4].ljust(4, b'\xff')) | ||||||
|  |                     i -= 1 | ||||||
|  |             data = bytes(it.islice( | ||||||
|  |                 it.chain.from_iterable(reversed(data)), size)) | ||||||
|  |  | ||||||
|  |         f.write("%-45s%s\n" % (desc, | ||||||
|  |             "%-23s  %-8s" % ( | ||||||
|  |                 ' '.join('%02x' % c for c in data[:8]), | ||||||
|  |                 ''.join(c if c >= ' ' and c <= '~' else '.' | ||||||
|  |                     for c in map(chr, data[:8]))) | ||||||
|  |             if not args.no_truncate and len(desc) < 45 | ||||||
|  |                 and data is not None else "")) | ||||||
|  |  | ||||||
|  |         if name.is_('superblock') and struct_.is_('inlinestruct'): | ||||||
|  |             f.write( | ||||||
|  |                 "  block_size %d\n" | ||||||
|  |                 "  block_count %d\n" | ||||||
|  |                 "  name_max %d\n" | ||||||
|  |                 "  file_max %d\n" | ||||||
|  |                 "  attr_max %d\n" % struct.unpack( | ||||||
|  |                     '<IIIII', struct_.data[4:4+20].ljust(20, b'\xff'))) | ||||||
|  |  | ||||||
|  |         for tag in mdir.tags: | ||||||
|  |             if tag.id==id_ and tag.is_('userattr'): | ||||||
|  |                 desc = "%s size %d" % (tag.typerepr(), tag.size) | ||||||
|  |                 f.write("  %-43s%s\n" % (desc, | ||||||
|  |                     "%-23s  %-8s" % ( | ||||||
|  |                         ' '.join('%02x' % c for c in tag.data[:8]), | ||||||
|  |                         ''.join(c if c >= ' ' and c <= '~' else '.' | ||||||
|  |                             for c in map(chr, tag.data[:8]))) | ||||||
|  |                     if not args.no_truncate and len(desc) < 43 else "")) | ||||||
|  |  | ||||||
|  |                 if args.no_truncate: | ||||||
|  |                     for i in range(0, len(tag.data), 16): | ||||||
|  |                         f.write("    %08x: %-47s  %-16s\n" % ( | ||||||
|  |                             i, ' '.join('%02x' % c for c in tag.data[i:i+16]), | ||||||
|  |                             ''.join(c if c >= ' ' and c <= '~' else '.' | ||||||
|  |                                 for c in map(chr, tag.data[i:i+16])))) | ||||||
|  |  | ||||||
|  |         if args.no_truncate and data is not None: | ||||||
|  |             for i in range(0, len(data), 16): | ||||||
|  |                 f.write("  %08x: %-47s  %-16s\n" % ( | ||||||
|  |                     i, ' '.join('%02x' % c for c in data[i:i+16]), | ||||||
|  |                     ''.join(c if c >= ' ' and c <= '~' else '.' | ||||||
|  |                         for c in map(chr, data[i:i+16])))) | ||||||
|  |  | ||||||
| def main(args): | def main(args): | ||||||
|     superblock = None |  | ||||||
|     gstate = b'\0\0\0\0\0\0\0\0\0\0\0\0' |  | ||||||
|     dirs = [] |  | ||||||
|     mdirs = [] |  | ||||||
|     corrupted = [] |  | ||||||
|     cycle = False |  | ||||||
|     with open(args.disk, 'rb') as f: |     with open(args.disk, 'rb') as f: | ||||||
|  |         dirs = [] | ||||||
|  |         superblock = None | ||||||
|  |         gstate = b'' | ||||||
|  |         mdirs = [] | ||||||
|  |         cycle = False | ||||||
|         tail = (args.block1, args.block2) |         tail = (args.block1, args.block2) | ||||||
|         hard = False |         hard = False | ||||||
|         while True: |         while True: | ||||||
| @@ -61,10 +144,6 @@ def main(args): | |||||||
|             except KeyError: |             except KeyError: | ||||||
|                 pass |                 pass | ||||||
|  |  | ||||||
|             # corrupted? |  | ||||||
|             if not mdir: |  | ||||||
|                 corrupted.append(mdir) |  | ||||||
|  |  | ||||||
|             # add to directories |             # add to directories | ||||||
|             mdirs.append(mdir) |             mdirs.append(mdir) | ||||||
|             if mdir.tail is None or not mdir.tail.is_('hardtail'): |             if mdir.tail is None or not mdir.tail.is_('hardtail'): | ||||||
| @@ -99,7 +178,7 @@ def main(args): | |||||||
|  |  | ||||||
|         dir[0].path = path.replace('//', '/') |         dir[0].path = path.replace('//', '/') | ||||||
|  |  | ||||||
|     # print littlefs + version info |     # dump tree | ||||||
|     version = ('?', '?') |     version = ('?', '?') | ||||||
|     if superblock: |     if superblock: | ||||||
|         version = tuple(reversed( |         version = tuple(reversed( | ||||||
| @@ -108,56 +187,53 @@ def main(args): | |||||||
|         "data (truncated, if it fits)" |         "data (truncated, if it fits)" | ||||||
|         if not any([args.no_truncate, args.tags, args.log, args.all]) else "")) |         if not any([args.no_truncate, args.tags, args.log, args.all]) else "")) | ||||||
|  |  | ||||||
|     # print gstate |     if gstate: | ||||||
|     print("gstate 0x%s" % ''.join('%02x' % c for c in gstate)) |         print("gstate 0x%s" % ''.join('%02x' % c for c in gstate)) | ||||||
|     tag = Tag(struct.unpack('<I', gstate[0:4].ljust(4, b'\xff'))[0]) |         tag = Tag(struct.unpack('<I', gstate[0:4].ljust(4, b'\xff'))[0]) | ||||||
|     blocks = struct.unpack('<II', gstate[4:4+8].ljust(8, b'\xff')) |         blocks = struct.unpack('<II', gstate[4:4+8].ljust(8, b'\xff')) | ||||||
|     if tag.size or not tag.isvalid: |         if tag.size or not tag.isvalid: | ||||||
|         print("  orphans >=%d" % max(tag.size, 1)) |             print("  orphans >=%d" % max(tag.size, 1)) | ||||||
|     if tag.type: |         if tag.type: | ||||||
|         print("  move dir {%#x, %#x} id %d" % ( |             print("  move dir {%#x, %#x} id %d" % ( | ||||||
|             blocks[0], blocks[1], tag.id)) |                 blocks[0], blocks[1], tag.id)) | ||||||
|  |  | ||||||
|     # print mdir info |  | ||||||
|     for i, dir in enumerate(dirs): |     for i, dir in enumerate(dirs): | ||||||
|         print("dir %s" % (json.dumps(dir[0].path) |         print("dir %s" % (json.dumps(dir[0].path) | ||||||
|             if hasattr(dir[0], 'path') else '(orphan)')) |             if hasattr(dir[0], 'path') else '(orphan)')) | ||||||
|  |  | ||||||
|         for j, mdir in enumerate(dir): |         for j, mdir in enumerate(dir): | ||||||
|             print("mdir {%#x, %#x} rev %d (was %d)%s%s" % ( |             print("mdir {%#x, %#x} rev %d%s" % ( | ||||||
|                 mdir.blocks[0], mdir.blocks[1], mdir.rev, mdir.pair[1].rev, |                 mdir.blocks[0], mdir.blocks[1], mdir.rev, | ||||||
|                 ' (corrupted!)' if not mdir else '', |                 ' (corrupted)' if not mdir else '')) | ||||||
|                 ' -> {%#x, %#x}' % struct.unpack('<II', mdir.tail.data) |  | ||||||
|                 if mdir.tail else '')) |  | ||||||
|  |  | ||||||
|             f = io.StringIO() |             f = io.StringIO() | ||||||
|             if args.log: |             if args.tags: | ||||||
|  |                 mdir.dump_tags(f, truncate=not args.no_truncate) | ||||||
|  |             elif args.log: | ||||||
|                 mdir.dump_log(f, truncate=not args.no_truncate) |                 mdir.dump_log(f, truncate=not args.no_truncate) | ||||||
|             elif args.all: |             elif args.all: | ||||||
|                 mdir.dump_all(f, truncate=not args.no_truncate) |                 mdir.dump_all(f, truncate=not args.no_truncate) | ||||||
|             else: |             else: | ||||||
|                 mdir.dump_tags(f, truncate=not args.no_truncate) |                 dumpentries(args, mdir, f) | ||||||
|  |  | ||||||
|             lines = list(filter(None, f.getvalue().split('\n'))) |             lines = list(filter(None, f.getvalue().split('\n'))) | ||||||
|             for k, line in enumerate(lines): |             for k, line in enumerate(lines): | ||||||
|                 print("%s %s" % ( |                 print("%s %s" % ( | ||||||
|                     ' ' if j == len(dir)-1 else |                     ' ' if i == len(dirs)-1 and j == len(dir)-1 else | ||||||
|                     'v' if k == len(lines)-1 else |                     'v' if k == len(lines)-1 else | ||||||
|  |                     '.' if j == len(dir)-1 else | ||||||
|                     '|', |                     '|', | ||||||
|                     line)) |                     line)) | ||||||
|  |  | ||||||
|     errcode = 0 |     if cycle: | ||||||
|     for mdir in corrupted: |         print("*** cycle detected! -> {%#x, %#x} ***" % (cycle[0], cycle[1])) | ||||||
|         errcode = errcode or 1 |  | ||||||
|         print("*** corrupted mdir {%#x, %#x}! ***" % ( |  | ||||||
|             mdir.blocks[0], mdir.blocks[1])) |  | ||||||
|  |  | ||||||
|     if cycle: |     if cycle: | ||||||
|         errcode = errcode or 2 |         return 2 | ||||||
|         print("*** cycle detected {%#x, %#x}! ***" % ( |     elif not all(mdir for dir in dirs for mdir in dir): | ||||||
|             cycle[0], cycle[1])) |         return 1 | ||||||
|  |     else: | ||||||
|     return errcode |         return 0; | ||||||
|  |  | ||||||
| if __name__ == "__main__": | if __name__ == "__main__": | ||||||
|     import argparse |     import argparse | ||||||
| @@ -170,10 +246,12 @@ if __name__ == "__main__": | |||||||
|         help="Size of a block in bytes.") |         help="Size of a block in bytes.") | ||||||
|     parser.add_argument('block1', nargs='?', default=0, |     parser.add_argument('block1', nargs='?', default=0, | ||||||
|         type=lambda x: int(x, 0), |         type=lambda x: int(x, 0), | ||||||
|         help="Optional first block address for finding the superblock.") |         help="Optional first block address for finding the root.") | ||||||
|     parser.add_argument('block2', nargs='?', default=1, |     parser.add_argument('block2', nargs='?', default=1, | ||||||
|         type=lambda x: int(x, 0), |         type=lambda x: int(x, 0), | ||||||
|         help="Optional second block address for finding the superblock.") |         help="Optional second block address for finding the root.") | ||||||
|  |     parser.add_argument('-t', '--tags', action='store_true', | ||||||
|  |         help="Show metadata tags instead of reconstructing entries.") | ||||||
|     parser.add_argument('-l', '--log', action='store_true', |     parser.add_argument('-l', '--log', action='store_true', | ||||||
|         help="Show tags in log.") |         help="Show tags in log.") | ||||||
|     parser.add_argument('-a', '--all', action='store_true', |     parser.add_argument('-a', '--all', action='store_true', | ||||||
|   | |||||||
| @@ -231,7 +231,7 @@ class TestCase: | |||||||
|                 ncmd.extend(['-ex', 'r']) |                 ncmd.extend(['-ex', 'r']) | ||||||
|                 if failure.assert_: |                 if failure.assert_: | ||||||
|                     ncmd.extend(['-ex', 'up 2']) |                     ncmd.extend(['-ex', 'up 2']) | ||||||
|             elif gdb == 'main': |             elif gdb == 'start': | ||||||
|                 ncmd.extend([ |                 ncmd.extend([ | ||||||
|                     '-ex', 'b %s:%d' % (self.suite.path, self.code_lineno), |                     '-ex', 'b %s:%d' % (self.suite.path, self.code_lineno), | ||||||
|                     '-ex', 'r']) |                     '-ex', 'r']) | ||||||
| @@ -760,7 +760,7 @@ if __name__ == "__main__": | |||||||
|         help="Store disk image in a file.") |         help="Store disk image in a file.") | ||||||
|     parser.add_argument('-b', '--build', action='store_true', |     parser.add_argument('-b', '--build', action='store_true', | ||||||
|         help="Only build the tests, do not execute.") |         help="Only build the tests, do not execute.") | ||||||
|     parser.add_argument('-g', '--gdb', choices=['init', 'main', 'assert'], |     parser.add_argument('-g', '--gdb', choices=['init', 'start', 'assert'], | ||||||
|         nargs='?', const='assert', |         nargs='?', const='assert', | ||||||
|         help="Drop into gdb on test failure.") |         help="Drop into gdb on test failure.") | ||||||
|     parser.add_argument('--no-internal', action='store_true', |     parser.add_argument('--no-internal', action='store_true', | ||||||
|   | |||||||
| @@ -323,90 +323,6 @@ code = ''' | |||||||
|     lfs_unmount(&lfs) => 0; |     lfs_unmount(&lfs) => 0; | ||||||
| ''' | ''' | ||||||
|  |  | ||||||
| [[case]] # what if we have a bad block during an allocation scan? |  | ||||||
| in = "lfs.c" |  | ||||||
| define.LFS_ERASE_CYCLES = 0xffffffff |  | ||||||
| define.LFS_BADBLOCK_BEHAVIOR = 'LFS_TESTBD_BADBLOCK_READERROR' |  | ||||||
| code = ''' |  | ||||||
|     lfs_format(&lfs, &cfg) => 0; |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     // first fill to exhaustion to find available space |  | ||||||
|     lfs_file_open(&lfs, &file, "pacman", LFS_O_WRONLY | LFS_O_CREAT) => 0; |  | ||||||
|     strcpy((char*)buffer, "waka"); |  | ||||||
|     size = strlen("waka"); |  | ||||||
|     lfs_size_t filesize = 0; |  | ||||||
|     while (true) { |  | ||||||
|         lfs_ssize_t res = lfs_file_write(&lfs, &file, buffer, size); |  | ||||||
|         assert(res == (lfs_ssize_t)size || res == LFS_ERR_NOSPC); |  | ||||||
|         if (res == LFS_ERR_NOSPC) { |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
|         filesize += size; |  | ||||||
|     } |  | ||||||
|     lfs_file_close(&lfs, &file) => 0; |  | ||||||
|     // now fill all but a couple of blocks of the filesystem with data |  | ||||||
|     filesize -= 3*LFS_BLOCK_SIZE; |  | ||||||
|     lfs_file_open(&lfs, &file, "pacman", LFS_O_WRONLY | LFS_O_CREAT) => 0; |  | ||||||
|     strcpy((char*)buffer, "waka"); |  | ||||||
|     size = strlen("waka"); |  | ||||||
|     for (lfs_size_t i = 0; i < filesize/size; i++) { |  | ||||||
|         lfs_file_write(&lfs, &file, buffer, size) => size; |  | ||||||
|     } |  | ||||||
|     lfs_file_close(&lfs, &file) => 0; |  | ||||||
|     // also save head of file so we can error during lookahead scan |  | ||||||
|     lfs_block_t fileblock = file.ctz.head; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
|  |  | ||||||
|     // remount to force an alloc scan |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|  |  | ||||||
|     // but mark the head of our file as a "bad block", this is force our |  | ||||||
|     // scan to bail early |  | ||||||
|     lfs_testbd_setwear(&cfg, fileblock, 0xffffffff) => 0; |  | ||||||
|     lfs_file_open(&lfs, &file, "ghost", LFS_O_WRONLY | LFS_O_CREAT) => 0; |  | ||||||
|     strcpy((char*)buffer, "chomp"); |  | ||||||
|     size = strlen("chomp"); |  | ||||||
|     while (true) { |  | ||||||
|         lfs_ssize_t res = lfs_file_write(&lfs, &file, buffer, size); |  | ||||||
|         assert(res == (lfs_ssize_t)size || res == LFS_ERR_CORRUPT); |  | ||||||
|         if (res == LFS_ERR_CORRUPT) { |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     lfs_file_close(&lfs, &file) => 0; |  | ||||||
|  |  | ||||||
|     // now reverse the "bad block" and try to write the file again until we |  | ||||||
|     // run out of space |  | ||||||
|     lfs_testbd_setwear(&cfg, fileblock, 0) => 0; |  | ||||||
|     lfs_file_open(&lfs, &file, "ghost", LFS_O_WRONLY | LFS_O_CREAT) => 0; |  | ||||||
|     strcpy((char*)buffer, "chomp"); |  | ||||||
|     size = strlen("chomp"); |  | ||||||
|     while (true) { |  | ||||||
|         lfs_ssize_t res = lfs_file_write(&lfs, &file, buffer, size); |  | ||||||
|         assert(res == (lfs_ssize_t)size || res == LFS_ERR_NOSPC); |  | ||||||
|         if (res == LFS_ERR_NOSPC) { |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     lfs_file_close(&lfs, &file) => 0; |  | ||||||
|  |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
|  |  | ||||||
|     // check that the disk isn't hurt |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_file_open(&lfs, &file, "pacman", LFS_O_RDONLY) => 0; |  | ||||||
|     strcpy((char*)buffer, "waka"); |  | ||||||
|     size = strlen("waka"); |  | ||||||
|     for (lfs_size_t i = 0; i < filesize/size; i++) { |  | ||||||
|         uint8_t rbuffer[4]; |  | ||||||
|         lfs_file_read(&lfs, &file, rbuffer, size) => size; |  | ||||||
|         assert(memcmp(rbuffer, buffer, size) == 0); |  | ||||||
|     } |  | ||||||
|     lfs_file_close(&lfs, &file) => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| ''' |  | ||||||
|  |  | ||||||
|  |  | ||||||
| # Below, I don't like these tests. They're fragile and depend _heavily_ | # Below, I don't like these tests. They're fragile and depend _heavily_ | ||||||
| # on the geometry of the block device. But they are valuable. Eventually they | # on the geometry of the block device. But they are valuable. Eventually they | ||||||
| # should be removed and replaced with generalized tests. | # should be removed and replaced with generalized tests. | ||||||
|   | |||||||
							
								
								
									
										85
									
								
								tests/test_new.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								tests/test_new.toml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,85 @@ | |||||||
|  |  | ||||||
|  | #open(1, "5file5.xxxxxxxxxxxx", 0x503) -> 0 | ||||||
|  | #  write(1, , 2007)[^ 1499 us] -> 2007 | ||||||
|  | #  write(1, , 2007)[^ 1411 us] -> 2007 | ||||||
|  | #  write(1, , 2007)[^ 1390 us] -> 2007 | ||||||
|  | #  write(1, , 2007)[^ 1401 us] -> 2007 | ||||||
|  | #  close(1) -> 0 | ||||||
|  | #  open(1, "1file1.xxxx", 0x503) -> 0 | ||||||
|  | #  mount | ||||||
|  | #  open(0, "5file5.xxxxxxxxxxxx", 0x3) -> 0 | ||||||
|  | #  open(1, "5file5.xxxxxxxxxxxx", 0x503) -> 0 | ||||||
|  | #  close(1) -> 0 | ||||||
|  | #  open(1, "1file1.xxxx", 0x2) -> 0 | ||||||
|  | #  write(0, , 63) -> 63 | ||||||
|  | #a.out: lfs.c:2169: lfs_ctz_find: Assertion `head >= 2 && head <= lfs->cfg->block_count' failed. | ||||||
|  | #  close(0)Aborted | ||||||
|  |  | ||||||
|  | [[case]] | ||||||
|  | define.FILESIZE5 = '4*CHUNKSIZE5' | ||||||
|  | define.FILESIZE1 = '4*CHUNKSIZE1' | ||||||
|  | define.CHUNKSIZE5 = 2007 | ||||||
|  | define.CHUNKSIZE1 = 63 | ||||||
|  | code = ''' | ||||||
|  |     lfs_file_t files[2]; | ||||||
|  |     uint8_t chunk5[CHUNKSIZE5]; | ||||||
|  |     memset(chunk5, 'a', CHUNKSIZE5); | ||||||
|  |     uint8_t chunk1[CHUNKSIZE1]; | ||||||
|  |     memset(chunk1, 'b', CHUNKSIZE1); | ||||||
|  |  | ||||||
|  |     lfs_format(&lfs, &cfg) => 0; | ||||||
|  |     lfs_mount(&lfs, &cfg) => 0; | ||||||
|  |     lfs_file_open(&lfs, &files[1], "5file5.xxxxxxxxxxxx", | ||||||
|  |             LFS_O_RDWR | LFS_O_CREAT | LFS_O_TRUNC) => 0; | ||||||
|  |     for (int i = 0; i < FILESIZE5/CHUNKSIZE5; i++) { | ||||||
|  |         lfs_file_write(&lfs, &files[1], chunk5, CHUNKSIZE5) => CHUNKSIZE5; | ||||||
|  |     } | ||||||
|  |     lfs_file_close(&lfs, &files[1]) => 0; | ||||||
|  |     lfs_file_open(&lfs, &files[1], "1file1.xxxx", | ||||||
|  |             LFS_O_RDWR | LFS_O_CREAT | LFS_O_TRUNC) => 0; | ||||||
|  | //  these should not change the result | ||||||
|  | //    lfs_file_close(&lfs, &files[1]) => 0; | ||||||
|  | //    lfs_unmount(&lfs) => 0; | ||||||
|  |  | ||||||
|  |     lfs_mount(&lfs, &cfg) => 0; | ||||||
|  |     lfs_file_open(&lfs, &files[0], "5file5.xxxxxxxxxxxx", | ||||||
|  |             LFS_O_RDWR) => 0; | ||||||
|  |  | ||||||
|  |     lfs_file_open(&lfs, &files[1], "5file5.xxxxxxxxxxxx", | ||||||
|  |             LFS_O_RDWR | LFS_O_CREAT | LFS_O_TRUNC) => 0; | ||||||
|  |     lfs_file_close(&lfs, &files[1]) => 0; | ||||||
|  |  | ||||||
|  |     lfs_file_open(&lfs, &files[1], "1file1.xxxx", | ||||||
|  |             LFS_O_WRONLY) => 0; | ||||||
|  |     for (int i = 0; i < FILESIZE1/CHUNKSIZE1; i++) { | ||||||
|  |         lfs_file_write(&lfs, &files[1], chunk1, CHUNKSIZE1) => CHUNKSIZE1; | ||||||
|  |     } | ||||||
|  |     lfs_file_close(&lfs, &files[1]) => 0; | ||||||
|  |  | ||||||
|  |     memset(chunk5, 'c', CHUNKSIZE5); | ||||||
|  |     for (int i = 0; i < FILESIZE5/CHUNKSIZE5; i++) { | ||||||
|  |         lfs_file_write(&lfs, &files[0], chunk5, CHUNKSIZE5) => CHUNKSIZE5; | ||||||
|  |     } | ||||||
|  |     lfs_file_close(&lfs, &files[0]) => 0; | ||||||
|  |     lfs_unmount(&lfs) => 0; | ||||||
|  |  | ||||||
|  |     // check results | ||||||
|  |     lfs_mount(&lfs, &cfg) => 0; | ||||||
|  |     lfs_file_open(&lfs, &files[0], "5file5.xxxxxxxxxxxx", | ||||||
|  |             LFS_O_RDONLY) => 0; | ||||||
|  |     for (int i = 0; i < FILESIZE5/CHUNKSIZE5; i++) { | ||||||
|  |         uint8_t rchunk[CHUNKSIZE5]; | ||||||
|  |         lfs_file_read(&lfs, &files[0], rchunk, CHUNKSIZE5) => CHUNKSIZE5; | ||||||
|  |         assert(memcmp(rchunk, chunk5, CHUNKSIZE5) == 0); | ||||||
|  |     } | ||||||
|  |     lfs_file_close(&lfs, &files[0]) => 0; | ||||||
|  |     lfs_file_open(&lfs, &files[0], "1file1.xxxx", | ||||||
|  |             LFS_O_RDONLY) => 0; | ||||||
|  |     for (int i = 0; i < FILESIZE1/CHUNKSIZE1; i++) { | ||||||
|  |         uint8_t rchunk[CHUNKSIZE1]; | ||||||
|  |         lfs_file_read(&lfs, &files[0], rchunk, CHUNKSIZE1) => CHUNKSIZE1; | ||||||
|  |         assert(memcmp(rchunk, chunk1, CHUNKSIZE1) == 0); | ||||||
|  |     } | ||||||
|  |     lfs_file_close(&lfs, &files[0]) => 0; | ||||||
|  |     lfs_unmount(&lfs) => 0; | ||||||
|  | ''' | ||||||
		Reference in New Issue
	
	Block a user