fs: littlefs: revise how per-file cache memory is allocated
Originally the file cache used a mem_pool, but that data structure has been deprecated and replaced by a heap that includes metadata in the heap area. As a result attempts to allocate all blocks will fail because some of the reservation intended for cache data is now holding metadata instead. It's not immediately clear how to adjust the required heap size to support this metadata as it depends on heap chunk units and data structures that are not visible to the application. Experimentally a value of 24 bytes works, while smaller values do not. Further the previous Kconfig API to configure the allocation pool is completely inappropriate with the new heap data structure which has such different behavior. So: Deprecate the old Kconfig API. Add a new Kconfig option to directly control the cache size. Infer a default cache size that works with the old mem_pool parameters assuming a per-block overhead. But to avoid wasted memory use the heap allocation only when the application customizes the size, and use a slab in other cases. Signed-off-by: Peter Bigot <peter.bigot@nordicsemi.no>
This commit is contained in:
parent
1ee82a1c9b
commit
8ea2956ca3
|
@ -57,7 +57,7 @@ struct fs_littlefs {
|
|||
* values are consistent with littlefs requirements.
|
||||
*
|
||||
* @note If you use a non-default configuration for cache size, you
|
||||
* must also select @option{CONFIG_FS_LITTLEFS_FC_MEM_POOL} to relax
|
||||
* must also select @option{CONFIG_FS_LITTLEFS_FC_HEAP_SIZE} to relax
|
||||
* the size constraints on per-file cache allocations.
|
||||
*
|
||||
* @param name the name for the structure. The defined object has
|
||||
|
|
|
@ -69,7 +69,7 @@ config FS_LITTLEFS_BLOCK_CYCLES
|
|||
disable leveling.
|
||||
|
||||
menuconfig FS_LITTLEFS_FC_MEM_POOL
|
||||
bool "Enable flexible file cache sizes for littlefs"
|
||||
bool "Enable flexible file cache sizes for littlefs (DEPRECATED)"
|
||||
help
|
||||
littlefs requires a per-file buffer to cache data. For
|
||||
applications that use the default configuration parameters a
|
||||
|
@ -80,25 +80,75 @@ menuconfig FS_LITTLEFS_FC_MEM_POOL
|
|||
support different cache sizes for different partitions this
|
||||
preallocation is inadequate.
|
||||
|
||||
Select this feature to enable a memory pool allocator for
|
||||
littlefs file caches.
|
||||
This API is no longer approprate as the underlying storage solution
|
||||
has been deprecated. Instead use FS_LITTLEFS_FC_HEAP_SIZE to
|
||||
configure the size of a heap used to allocate caches for open files.
|
||||
|
||||
# This option deprecated in 2.5.0
|
||||
if FS_LITTLEFS_FC_MEM_POOL
|
||||
|
||||
config FS_LITTLEFS_FC_MEM_POOL_MIN_SIZE
|
||||
int "Minimum block size for littlefs file cache memory pool"
|
||||
int "(DEPRECATED)"
|
||||
default 16
|
||||
help
|
||||
This API is no longer approprate as the underlying storage
|
||||
solution has been deprecated. Instead use
|
||||
FS_LITTLEFS_FC_HEAP to configure the size of a heap used to
|
||||
allocate caches for open files.
|
||||
|
||||
config FS_LITTLEFS_FC_MEM_POOL_MAX_SIZE
|
||||
int "Maximum block size for littlefs file cache memory pool"
|
||||
int "Block size for littlefs file cache heap (DEPRECATED)"
|
||||
default 1024
|
||||
help
|
||||
A heap for file cache data is sized so that
|
||||
FS_LITTLEFS_FC_MEM_POOL_NUM_BLOCKS allocations of size
|
||||
FS_LITTLEFS_MEM_POOL_MAX_SIZE can be active simultaneously.
|
||||
|
||||
This option configures the size.
|
||||
|
||||
This API is no longer approprate as the underlying storage solution
|
||||
has been deprecated. Instead use FS_LITTLEFS_FC_HEAP to configure
|
||||
the size of a heap used to allocate caches for open files.
|
||||
|
||||
config FS_LITTLEFS_FC_MEM_POOL_NUM_BLOCKS
|
||||
int "Number of maximum sized blocks in littlefs file cache memory pool"
|
||||
int "Number of maximum sized blocks in littlefs file cache heap (DEPRECATED)"
|
||||
default 2
|
||||
help
|
||||
A heap for file cache data is sized so that
|
||||
FS_LITTLEFS_FC_MEM_POOL_NUM_BLOCKS allocations of size
|
||||
FS_LITTLEFS_MEM_POOL_MAX_SIZE can be active simultaneously.
|
||||
|
||||
This option configures the total heap size based on the
|
||||
block size.
|
||||
|
||||
This API is no longer approprate as the underlying storage solution
|
||||
has been deprecated. Instead use FS_LITTLEFS_FC_HEAP to configure
|
||||
the size of a heap used to allocate caches for open files.
|
||||
|
||||
endif # FS_LITTLEFS_FC_MEM_POOL
|
||||
|
||||
endmenu
|
||||
endmenu # FS_LITTLEFS_FC_MEM_POOL
|
||||
|
||||
config FS_LITTLEFS_FC_HEAP_SIZE
|
||||
int "Enable flexible file cache sizes for littlefs"
|
||||
default 0
|
||||
help
|
||||
littlefs requires a per-file buffer to cache data.
|
||||
|
||||
When applications customize littlefs configurations and support
|
||||
different cache sizes for different partitions this preallocation is
|
||||
inadequate as an application might require a small number of files
|
||||
using a large cache size and a larger number of files using a
|
||||
smaller cache size. In that case application should provide a
|
||||
positive value for the heap size. Be aware that there is a
|
||||
per-allocation overhead that affects how much usable space is
|
||||
present in the heap.
|
||||
|
||||
If this option is set to a non-positive value the heap is sized to
|
||||
support up to FS_LITTLE_FS_NUM_FILES blocks of
|
||||
FS_LITTLEFS_CACHE_SIZE bytes. Until FS_LITTLEFS_FC_MEM_POOL is
|
||||
removed presence of that option changes the default to support
|
||||
FS_LITTLEFS_FC_MEM_POOL_NUM_BLOCKS allocations of size
|
||||
FS_LITTLEFS_MEM_POOL_MAX_SIZE
|
||||
|
||||
endif # FILE_SYSTEM_LITTLEFS
|
||||
|
|
|
@ -32,24 +32,78 @@ struct lfs_file_data {
|
|||
#define LFS_FILEP(fp) (&((struct lfs_file_data *)(fp->filep))->file)
|
||||
|
||||
/* Global memory pool for open files and dirs */
|
||||
K_MEM_SLAB_DEFINE(file_data_pool, sizeof(struct lfs_file_data),
|
||||
CONFIG_FS_LITTLEFS_NUM_FILES, 4);
|
||||
K_MEM_SLAB_DEFINE(lfs_dir_pool, sizeof(struct lfs_dir),
|
||||
CONFIG_FS_LITTLEFS_NUM_DIRS, 4);
|
||||
static K_MEM_SLAB_DEFINE(file_data_pool, sizeof(struct lfs_file_data),
|
||||
CONFIG_FS_LITTLEFS_NUM_FILES, 4);
|
||||
static K_MEM_SLAB_DEFINE(lfs_dir_pool, sizeof(struct lfs_dir),
|
||||
CONFIG_FS_LITTLEFS_NUM_DIRS, 4);
|
||||
|
||||
/* If either filecache memory pool is customized by either the legacy
|
||||
* mem_pool or heap Kconfig options then we need to use a heap.
|
||||
* Otherwise we can use a fixed region.
|
||||
*/
|
||||
#define FC_ON_HEAP defined(CONFIG_FS_LITTLEFS_FC_MEM_POOL) \
|
||||
|| ((CONFIG_FS_LITTLEFS_FC_HEAP_SIZE - 0) > 0)
|
||||
|
||||
#if FC_ON_HEAP
|
||||
|
||||
/* Inferred overhead, in bytes, for each k_heap_aligned allocation for
|
||||
* the filecache heap. This relates to the CHUNK_UNIT parameter in
|
||||
* the heap implementation, but that value is not visible outside the
|
||||
* kernel.
|
||||
*/
|
||||
#define FC_HEAP_PER_ALLOC_OVERHEAD 24U
|
||||
|
||||
/* If not explicitly customizing provide a default that's appropriate
|
||||
* based on other configuration options.
|
||||
*/
|
||||
#ifndef CONFIG_FS_LITTLEFS_FC_MEM_POOL
|
||||
BUILD_ASSERT(CONFIG_FS_LITTLEFS_CACHE_SIZE >= 4);
|
||||
#define CONFIG_FS_LITTLEFS_FC_MEM_POOL_MIN_SIZE 4
|
||||
#define CONFIG_FS_LITTLEFS_FC_MEM_POOL_MAX_SIZE CONFIG_FS_LITTLEFS_CACHE_SIZE
|
||||
#define CONFIG_FS_LITTLEFS_FC_MEM_POOL_NUM_BLOCKS CONFIG_FS_LITTLEFS_NUM_FILES
|
||||
#endif
|
||||
|
||||
K_HEAP_DEFINE(file_cache_pool,
|
||||
CONFIG_FS_LITTLEFS_FC_MEM_POOL_MAX_SIZE *
|
||||
CONFIG_FS_LITTLEFS_FC_MEM_POOL_NUM_BLOCKS);
|
||||
/* If not explicitly customizing infer a default from the legacy
|
||||
* mem-pool configuration options.
|
||||
*/
|
||||
#if (CONFIG_FS_LITTLEFS_FC_HEAP_SIZE - 0) <= 0
|
||||
#undef CONFIG_FS_LITTLEFS_FC_HEAP_SIZE
|
||||
#define CONFIG_FS_LITTLEFS_FC_HEAP_SIZE \
|
||||
((CONFIG_FS_LITTLEFS_FC_MEM_POOL_MAX_SIZE \
|
||||
+ FC_HEAP_PER_ALLOC_OVERHEAD) \
|
||||
* CONFIG_FS_LITTLEFS_FC_MEM_POOL_NUM_BLOCKS)
|
||||
#endif /* CONFIG_FS_LITTLEFS_FC_HEAP_SIZE */
|
||||
|
||||
static K_HEAP_DEFINE(file_cache_heap, CONFIG_FS_LITTLEFS_FC_HEAP_SIZE);
|
||||
|
||||
#else /* FC_ON_HEAP */
|
||||
|
||||
static K_MEM_SLAB_DEFINE(file_cache_slab, CONFIG_FS_LITTLEFS_CACHE_SIZE,
|
||||
CONFIG_FS_LITTLEFS_NUM_FILES, 4);
|
||||
|
||||
#endif /* FC_ON_HEAP */
|
||||
|
||||
static inline void *fc_allocate(size_t size)
|
||||
{
|
||||
void *ret = NULL;
|
||||
|
||||
#if FC_ON_HEAP
|
||||
ret = k_heap_alloc(&file_cache_heap, size, K_NO_WAIT);
|
||||
#else
|
||||
if (k_mem_slab_alloc(&file_cache_slab, &ret, K_NO_WAIT) != 0) {
|
||||
ret = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void fc_release(void *buf)
|
||||
{
|
||||
#if FC_ON_HEAP
|
||||
k_heap_free(&file_cache_heap, buf);
|
||||
#else /* FC_ON_HEAP */
|
||||
k_mem_slab_free(&file_cache_slab, &buf);
|
||||
#endif /* FC_ON_HEAP */
|
||||
}
|
||||
|
||||
static inline void fs_lock(struct fs_littlefs *fs)
|
||||
{
|
||||
|
@ -174,7 +228,7 @@ static void release_file_data(struct fs_file_t *fp)
|
|||
struct lfs_file_data *fdp = fp->filep;
|
||||
|
||||
if (fdp->config.buffer) {
|
||||
k_heap_free(&file_cache_pool, fdp->cache_block);
|
||||
fc_release(fdp->cache_block);
|
||||
}
|
||||
|
||||
k_mem_slab_free(&file_data_pool, &fp->filep);
|
||||
|
@ -212,8 +266,7 @@ static int littlefs_open(struct fs_file_t *fp, const char *path,
|
|||
|
||||
memset(fdp, 0, sizeof(*fdp));
|
||||
|
||||
fdp->cache_block = k_heap_alloc(&file_cache_pool,
|
||||
lfs->cfg->cache_size, K_NO_WAIT);
|
||||
fdp->cache_block = fc_allocate(lfs->cfg->cache_size);
|
||||
if (fdp->cache_block == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
|
|
Loading…
Reference in a new issue