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:
Peter Bigot 2021-01-29 15:40:08 -06:00 committed by Anas Nashif
parent 1ee82a1c9b
commit 8ea2956ca3
3 changed files with 123 additions and 20 deletions

View file

@ -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

View file

@ -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

View file

@ -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;