mirror of
				https://github.com/eledio-devices/thirdparty-littlefs.git
				synced 2025-10-31 08:42:40 +01:00 
			
		
		
		
	Exploring ideas for static configuration
As an embedded library, littlefs's configuration straddles two worlds.
In most cases the configuration is usually constant at build time, but
when integrated into OSs, the configuration needs to be dynamically
configurable.
To help with this, littlefs has a separate lfs_config struct that can be
placed into ROM when possible.
But you know what's better than ROM configuration? Truely inlinable
static configuration known at compile-time. In addition to avoiding the
RAM cost, compile-time configuration allows for additional compiler
optimizations, such as constexpr-elimination and removal of unused
code-paths.
So how to enable static configuration?
1. define LFS_STATICCFG
2. implement callbacks as global functions:
   - lfs_read
   - lfs_prog
   - lfs_erase
   - lfs_sync
2. define the now-required constants that configure littlefs:
   - LFS_READ_SIZE
   - LFS_PROG_SIZE
   - LFS_BLOCK_SIZE
   - LFS_BLOCK_COUNT
   - LFS_BLOCK_CYCLES
   - LFS_CACHE_SIZE
   - LFS_LOOKAHEAD_SIZE
   - LFS_READ_BUFFER (optional)
   - LFS_PROG_BUFFER (optional)
   - LFS_LOOKAHEAD_BUFFER (optional)
   - LFS_NAME_MAX (optional)
   - LFS_FILE_MAX (optional)
   - LFS_ATTR_MAX (optional)
Note, there is a separate configuration for the file configuration, this
can be enabled/disabled independently of LFS_STATICCFG. You will likely
want to define this as well if you are looking for the smallest code
size.
In order to avoid a mess of #ifdefs, the internals of littlefs use a
simple macro that redirects to either the dynamic or static config at
compile time:
    #ifdef LFS_STATICCFG
    #define LFS_CFG_READ_SIZE(lfs) ((void)lfs, LFS_READ_SIZE)
    #else
    #define LFS_CFG_READ_SIZE(lfs) lfs->cfg->read_size
    #endif
Unfortunately it does look like there still may be a lot of issues
related to warnings of comparisons against constants... If only C had
a way to ignore warnings on individual statements...
Original idea by apmorton
			
			
This commit is contained in:
		
							
								
								
									
										175
									
								
								lfs.h
									
									
									
									
									
								
							
							
						
						
									
										175
									
								
								lfs.h
									
									
									
									
									
								
							| @@ -125,6 +125,7 @@ enum lfs_whence_flags { | ||||
| }; | ||||
|  | ||||
|  | ||||
| #if !defined(LFS_STATICCFG) | ||||
| // Configuration provided during initialization of the littlefs | ||||
| struct lfs_config { | ||||
|     // Opaque user provided context that can be used to pass | ||||
| @@ -219,6 +220,99 @@ struct lfs_config { | ||||
|     // LFS_ATTR_MAX when zero. | ||||
|     lfs_size_t attr_max; | ||||
| }; | ||||
| #else | ||||
| // Static configuration if LFS_STATICCFG is defined, there are defaults | ||||
| // for some of these, but some are required. For full documentation, see | ||||
| // the lfs_config struct above. | ||||
|  | ||||
| // Block device operations | ||||
| int lfs_read(lfs_block_t block, | ||||
|         lfs_off_t off, void *buffer, lfs_size_t size); | ||||
| int lfs_prog(lfs_block_t block, | ||||
|         lfs_off_t off, const void *buffer, lfs_size_t size); | ||||
| int lfs_erase(lfs_block_t block); | ||||
| int lfs_sync(void); | ||||
|  | ||||
| // Required configuration | ||||
| #ifndef LFS_READ_SIZE | ||||
| #error "LFS_STATICCFG requires LFS_READ_SIZE" | ||||
| #endif | ||||
| #ifndef LFS_PROG_SIZE | ||||
| #error "LFS_STATICCFG requires LFS_PROG_SIZE" | ||||
| #endif | ||||
| #ifndef LFS_BLOCK_SIZE | ||||
| #error "LFS_STATICCFG requires LFS_BLOCK_SIZE" | ||||
| #endif | ||||
| #ifndef LFS_BLOCK_COUNT | ||||
| #error "LFS_STATICCFG requires LFS_BLOCK_COUNT" | ||||
| #endif | ||||
| #ifndef LFS_BLOCK_CYCLES | ||||
| #error "LFS_STATICCFG requires LFS_BLOCK_CYCLES" | ||||
| #endif | ||||
| #ifndef LFS_CACHE_SIZE | ||||
| #error "LFS_STATICCFG requires LFS_CACHE_SIZE" | ||||
| #endif | ||||
| #ifndef LFS_LOOKAHEAD_SIZE | ||||
| #error "LFS_STATICCFG requires LFS_LOOKAHEAD_SIZE" | ||||
| #endif | ||||
|  | ||||
| // Optional configuration | ||||
| #ifndef LFS_READ_BUFFER | ||||
| #define LFS_READ_BUFFER NULL | ||||
| #endif | ||||
| #ifndef LFS_PROG_BUFFER | ||||
| #define LFS_PROG_BUFFER NULL | ||||
| #endif | ||||
| #ifndef LFS_LOOKAHEAD_BUFFER | ||||
| #define LFS_LOOKAHEAD_BUFFER NULL | ||||
| #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 | ||||
|  | ||||
| #if !defined(LFS_FILE_STATICCFG) | ||||
| // Optional configuration provided during lfs_file_opencfg | ||||
| struct lfs_file_config { | ||||
|     // Optional statically allocated file buffer. Must be cache_size. | ||||
|     // By default lfs_malloc is used to allocate this buffer. | ||||
|     void *buffer; | ||||
|  | ||||
|     // Optional list of custom attributes related to the file. If the file | ||||
|     // is opened with read access, these attributes will be read from disk | ||||
|     // during the open call. If the file is opened with write access, the | ||||
|     // attributes will be written to disk every file sync or close. This | ||||
|     // write occurs atomically with update to the file's contents. | ||||
|     // | ||||
|     // Custom attributes are uniquely identified by an 8-bit type and limited | ||||
|     // to LFS_ATTR_MAX bytes. When read, if the stored attribute is smaller | ||||
|     // than the buffer, it will be padded with zeros. If the stored attribute | ||||
|     // is larger, then it will be silently truncated. If the attribute is not | ||||
|     // found, it will be created implicitly. | ||||
|     struct lfs_attr *attrs; | ||||
|  | ||||
|     // Number of custom attributes in the list | ||||
|     lfs_size_t attr_count; | ||||
| }; | ||||
| #else | ||||
| // Static configuration if LFS_FILE_STATICCFG is defined. For full | ||||
| // documentation, see the lfs_file_config struct above. | ||||
| #ifndef LFS_FILE_BUFFER | ||||
| #define LFS_FILE_BUFFER NULL | ||||
| #endif | ||||
| #ifndef LFS_FILE_ATTRS | ||||
| #define LFS_FILE_ATTRS ((struct lfs_attr*)NULL) | ||||
| #endif | ||||
| #ifndef LFS_FILE_ATTR_COUNT | ||||
| #define LFS_FILE_ATTR_COUNT 0 | ||||
| #endif | ||||
| #endif | ||||
|  | ||||
| // File info structure | ||||
| struct lfs_info { | ||||
| @@ -249,29 +343,6 @@ struct lfs_attr { | ||||
|     lfs_size_t size; | ||||
| }; | ||||
|  | ||||
| // Optional configuration provided during lfs_file_opencfg | ||||
| struct lfs_file_config { | ||||
|     // Optional statically allocated file buffer. Must be cache_size. | ||||
|     // By default lfs_malloc is used to allocate this buffer. | ||||
|     void *buffer; | ||||
|  | ||||
|     // Optional list of custom attributes related to the file. If the file | ||||
|     // is opened with read access, these attributes will be read from disk | ||||
|     // during the open call. If the file is opened with write access, the | ||||
|     // attributes will be written to disk every file sync or close. This | ||||
|     // write occurs atomically with update to the file's contents. | ||||
|     // | ||||
|     // Custom attributes are uniquely identified by an 8-bit type and limited | ||||
|     // to LFS_ATTR_MAX bytes. When read, if the stored attribute is smaller | ||||
|     // than the buffer, it will be padded with zeros. If the stored attribute | ||||
|     // is larger, then it will be silently truncated. If the attribute is not | ||||
|     // found, it will be created implicitly. | ||||
|     struct lfs_attr *attrs; | ||||
|  | ||||
|     // Number of custom attributes in the list | ||||
|     lfs_size_t attr_count; | ||||
| }; | ||||
|  | ||||
|  | ||||
| /// internal littlefs data structures /// | ||||
| typedef struct lfs_cache { | ||||
| @@ -321,7 +392,9 @@ typedef struct lfs_file { | ||||
|     lfs_off_t off; | ||||
|     lfs_cache_t cache; | ||||
|  | ||||
| #ifndef LFS_FILE_STATICCFG | ||||
|     const struct lfs_file_config *cfg; | ||||
| #endif | ||||
| } lfs_file_t; | ||||
|  | ||||
| typedef struct lfs_superblock { | ||||
| @@ -364,7 +437,9 @@ typedef struct lfs { | ||||
|         uint32_t *buffer; | ||||
|     } free; | ||||
|  | ||||
| #ifndef LFS_STATICCFG | ||||
|     const struct lfs_config *cfg; | ||||
| #endif | ||||
|     lfs_size_t name_max; | ||||
|     lfs_size_t file_max; | ||||
|     lfs_size_t attr_max; | ||||
| @@ -377,16 +452,38 @@ typedef struct lfs { | ||||
|  | ||||
| /// Filesystem functions /// | ||||
|  | ||||
| // Format a block device with the littlefs | ||||
| #if defined(LFS_STATICCFG) | ||||
| // Format a block device with littlefs | ||||
| // | ||||
| // Requires a littlefs object. This clobbers the littlefs object, and does | ||||
| // not leave the filesystem mounted. | ||||
| // | ||||
| // Returns a negative error code on failure. | ||||
| int lfs_format(lfs_t *lfs); | ||||
| #endif | ||||
|  | ||||
| #if !defined(LFS_STATICCFG) | ||||
| // Format a block device with littlefs with per-filesystem configuration | ||||
| // | ||||
| // Requires a littlefs object and config struct. This clobbers the littlefs | ||||
| // object, and does not leave the filesystem mounted. The config struct must | ||||
| // be zeroed for defaults and backwards compatibility. | ||||
| // | ||||
| // Returns a negative error code on failure. | ||||
| int lfs_format(lfs_t *lfs, const struct lfs_config *config); | ||||
| int lfs_formatcfg(lfs_t *lfs, const struct lfs_config *config); | ||||
| #endif | ||||
|  | ||||
| // Mounts a littlefs | ||||
| #if defined(LFS_STATICCFG) | ||||
| // Mounts littlefs | ||||
| // | ||||
| // Requires a littlefs object and static configuration. | ||||
| // | ||||
| // Returns a negative error code on failure. | ||||
| int lfs_mount(lfs_t *lfs); | ||||
| #endif | ||||
|  | ||||
| #if !defined(LFS_STATICCFG) | ||||
| // Mounts a littlefs with per-filesystem configuration | ||||
| // | ||||
| // Requires a littlefs object and config struct. Multiple filesystems | ||||
| // may be mounted simultaneously with multiple littlefs objects. Both | ||||
| @@ -394,7 +491,8 @@ int lfs_format(lfs_t *lfs, const struct lfs_config *config); | ||||
| // be zeroed for defaults and backwards compatibility. | ||||
| // | ||||
| // Returns a negative error code on failure. | ||||
| int lfs_mount(lfs_t *lfs, const struct lfs_config *config); | ||||
| int lfs_mountcfg(lfs_t *lfs, const struct lfs_config *config); | ||||
| #endif | ||||
|  | ||||
| // Unmounts a littlefs | ||||
| // | ||||
| @@ -468,7 +566,8 @@ int lfs_removeattr(lfs_t *lfs, const char *path, uint8_t type); | ||||
| int lfs_file_open(lfs_t *lfs, lfs_file_t *file, | ||||
|         const char *path, int flags); | ||||
|  | ||||
| // Open a file with extra configuration | ||||
| #if !defined(LFS_FILE_STATICCFG) | ||||
| // Open a file with per-file configuration | ||||
| // | ||||
| // The mode that the file is opened in is determined by the flags, which | ||||
| // are values from the enum lfs_open_flags that are bitwise-ored together. | ||||
| @@ -481,6 +580,7 @@ int lfs_file_open(lfs_t *lfs, lfs_file_t *file, | ||||
| int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file, | ||||
|         const char *path, int flags, | ||||
|         const struct lfs_file_config *config); | ||||
| #endif | ||||
|  | ||||
| // Close a file | ||||
| // | ||||
| @@ -610,19 +710,34 @@ lfs_ssize_t lfs_fs_size(lfs_t *lfs); | ||||
| // Returns a negative error code on failure. | ||||
| int lfs_fs_traverse(lfs_t *lfs, int (*cb)(void*, lfs_block_t), void *data); | ||||
|  | ||||
| #ifdef LFS_MIGRATE | ||||
| #if defined(LFS_MIGRATE) && defined(LFS_STATICCFG) | ||||
| // Attempts to migrate a previous version of littlefs | ||||
| // | ||||
| // Behaves similarly to the lfs_format function. Attempts to mount | ||||
| // the previous version of littlefs and update the filesystem so it can be | ||||
| // mounted with the current version of littlefs. | ||||
| // | ||||
| // Requires a littlefs object. This clobbers the littlefs object, and does | ||||
| // not leave the filesystem mounted. | ||||
| // | ||||
| // Returns a negative error code on failure. | ||||
| int lfs_migrate(lfs_t *lfs, const struct lfs_config *cfg); | ||||
| #endif | ||||
|  | ||||
| #if defined(LFS_MIGRATE) && !defined(LFS_STATICCFG) | ||||
| // Attempts to migrate a previous version of littlefs with per-filesystem | ||||
| // configuration | ||||
| // | ||||
| // Behaves similarly to the lfs_format function. Attempts to mount | ||||
| // the previous version of littlefs and update the filesystem so it can be | ||||
| // mounted with the current version of littlefs. | ||||
| // | ||||
| // Requires a littlefs object and config struct. This clobbers the littlefs | ||||
| // object, and does not leave the filesystem mounted. The config struct must | ||||
| // be zeroed for defaults and backwards compatibility. | ||||
| // | ||||
| // Returns a negative error code on failure. | ||||
| int lfs_migrate(lfs_t *lfs, const struct lfs_config *cfg); | ||||
| int lfs_migratecfg(lfs_t *lfs, const struct lfs_config *cfg); | ||||
| #endif | ||||
|  | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user