diff --git a/CMakeLists.txt b/CMakeLists.txt index 77db274..8d3dd96 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,3 +30,11 @@ endif() if(CONFIG_LITTLEFS_MULTIVERSION) target_compile_definitions(${COMPONENT_LIB} PUBLIC -DLFS_MULTIVERSION) endif() + +if(CONFIG_LITTLEFS_MALLOC_STRATEGY_DISABLE) + target_compile_definitions(${COMPONENT_LIB} PUBLIC -DLFS_NO_MALLOC) +endif() + +if(NOT CONFIG_LITTLEFS_ASSERTS) + target_compile_definitions(${COMPONENT_LIB} PUBLIC -DLFS_NO_ASSERT) +endif() diff --git a/Kconfig b/Kconfig index 2f01cfd..2cdce46 100644 --- a/Kconfig +++ b/Kconfig @@ -208,4 +208,44 @@ menu "LittleFS" bool "Write LittleFS 2.0 (no forward-looking erase-state CRCs)" endchoice + + choice LITTLEFS_MALLOC_STRATEGY + prompt "Buffer allocation strategy" + default LITTLEFS_MALLOC_STRATEGY_DEFAULT + help + Maps lfs_malloc to ESP-IDF capabilities-based memory allocator or + disables dynamic allocation in favour of user-provided static buffers. + + config LITTLEFS_MALLOC_STRATEGY_DISABLE + bool "Static buffers only" + help + Disallow dynamic allocation, static buffers must be provided by the calling application. + + config LITTLEFS_MALLOC_STRATEGY_DEFAULT + bool "Default heap selection" + help + Uses an automatic allocation strategy. On systems with heap in SPIRAM, if + the allocation size does not exceed SPIRAM_MALLOC_ALWAYSINTERNAL then internal + heap allocation if preferred, otherwise allocation will be attempted from SPIRAM + heap. + + config LITTLEFS_MALLOC_STRATEGY_INTERNAL + bool "Internal heap" + help + Uses ESP-IDF heap_caps_malloc to allocate from internal heap. + + config LITTLEFS_MALLOC_STRATEGY_SPIRAM + bool "SPIRAM heap" + depends on SPIRAM_USE_MALLOC && ESP32_SPIRAM_SUPPORT + help + Uses ESP-IDF heap_caps_malloc to allocate from SPIRAM heap. + + endchoice + + config LITTLEFS_ASSERTS + bool "Enable asserts" + default "y" + help + Selects whether littlefs performs runtime assert checks. + endmenu diff --git a/src/esp_littlefs.c b/src/esp_littlefs.c index 86e9fc1..a226682 100644 --- a/src/esp_littlefs.c +++ b/src/esp_littlefs.c @@ -160,6 +160,16 @@ static esp_littlefs_t * _efs[CONFIG_LITTLEFS_MAX_PARTITIONS] = { 0 }; static const char * esp_littlefs_errno(enum lfs_error lfs_errno); #endif +static inline void * esp_littlefs_calloc(size_t __nmemb, size_t __size) { + /* Used internally by this wrapper only */ +#if defined(CONFIG_LITTLEFS_MALLOC_STRATEGY_INTERNAL) + return heap_caps_calloc(__nmemb, __size, MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL); +#elif defined(CONFIG_LITTLEFS_MALLOC_STRATEGY_SPIRAM) + return heap_caps_calloc(__nmemb, __size, MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM); +#else /* CONFIG_LITTLEFS_MALLOC_STRATEGY_DISABLE, CONFIG_LITTLEFS_MALLOC_STRATEGY_DEFAULT or not defined */ + return calloc(__nmemb, __size); +#endif +} static void esp_littlefs_free_fds(esp_littlefs_t * efs) { /* Need to free all files that were opened */ @@ -239,7 +249,7 @@ esp_err_t format_from_efs(esp_littlefs_t *efs) return ESP_FAIL; } efs->cache_size = CONFIG_LITTLEFS_FD_CACHE_MIN_SIZE; // Initial size of cache; will resize ondemand - efs->cache = calloc(sizeof(*efs->cache), efs->cache_size); + efs->cache = esp_littlefs_calloc(sizeof(*efs->cache), efs->cache_size); } ESP_LOGV(ESP_LITTLEFS_TAG, "Format Success!"); @@ -686,7 +696,7 @@ static void esp_littlefs_take_efs_lock(void) { static esp_err_t esp_littlefs_init_efs(esp_littlefs_t** efs, const esp_partition_t* partition, bool read_only) { /* Allocate Context */ - *efs = calloc(1, sizeof(esp_littlefs_t)); + *efs = esp_littlefs_calloc(1, sizeof(esp_littlefs_t)); if (*efs == NULL) { ESP_LOGE(ESP_LITTLEFS_TAG, "esp_littlefs could not be malloced"); return ESP_ERR_NO_MEM; @@ -730,7 +740,7 @@ static esp_err_t esp_littlefs_init_efs(esp_littlefs_t** efs, const esp_partition return ESP_ERR_NO_MEM; } - (*efs)->fs = calloc(1, sizeof(lfs_t)); + (*efs)->fs = esp_littlefs_calloc(1, sizeof(lfs_t)); if ((*efs)->fs == NULL) { ESP_LOGE(ESP_LITTLEFS_TAG, "littlefs could not be malloced"); return ESP_ERR_NO_MEM; @@ -829,7 +839,7 @@ static esp_err_t esp_littlefs_init(const esp_vfs_littlefs_conf_t* conf) goto exit; } efs->cache_size = 4; - efs->cache = calloc(sizeof(*efs->cache), efs->cache_size); + efs->cache = esp_littlefs_calloc(sizeof(*efs->cache), efs->cache_size); if(conf->grow_on_mount){ res = lfs_fs_grow(efs->fs, efs->partition->size / efs->cfg.block_size); @@ -935,9 +945,9 @@ static int esp_littlefs_allocate_fd(esp_littlefs_t *efs, vfs_littlefs_file_t ** /* Allocate file descriptor here now */ #ifndef CONFIG_LITTLEFS_USE_ONLY_HASH - *file = calloc(1, sizeof(**file) + path_len); + *file = esp_littlefs_calloc(1, sizeof(**file) + path_len); #else - *file = calloc(1, sizeof(**file)); + *file = esp_littlefs_calloc(1, sizeof(**file)); #endif if (*file == NULL) { @@ -1156,8 +1166,12 @@ static int vfs_littlefs_open(void* ctx, const char * path, int flags, int mode) mkdirs(efs, path); #endif // CONFIG_LITTLEFS_SPIFFS_COMPAT +#ifndef CONFIG_LITTLEFS_MALLOC_STRATEGY_DISABLE /* Open File */ res = lfs_file_open(efs->fs, &file->file, path, lfs_flags); +#else + #error "The use of static buffers is not currently supported by this VFS wrapper" +#endif #if CONFIG_LITTLEFS_OPEN_DIR if ( flags & O_DIRECTORY && res == LFS_ERR_ISDIR) { @@ -1692,7 +1706,7 @@ static DIR* vfs_littlefs_opendir(void* ctx, const char* name) { int res; vfs_littlefs_dir_t *dir = NULL; - dir = calloc(1, sizeof(vfs_littlefs_dir_t)); + dir = esp_littlefs_calloc(1, sizeof(vfs_littlefs_dir_t)); if( dir == NULL ) { ESP_LOGE(ESP_LITTLEFS_TAG, "dir struct could not be malloced"); errno = ENOMEM; diff --git a/src/lfs_config.h b/src/lfs_config.h index f57b183..1a2a506 100644 --- a/src/lfs_config.h +++ b/src/lfs_config.h @@ -12,15 +12,21 @@ #include #include #include -#include "esp_heap_caps.h" +#include "sdkconfig.h" #include "esp_log.h" -#ifndef LFS_NO_MALLOC + +#if defined(CONFIG_LITTLEFS_MALLOC_STRATEGY_DEFAULT) || \ + defined(CONFIG_LITTLEFS_MALLOC_STRATEGY_INTERNAL) || \ + defined(CONFIG_LITTLEFS_MALLOC_STRATEGY_SPIRAM) #include +#include "esp_heap_caps.h" #endif -#ifndef LFS_NO_ASSERT + +#ifdef CONFIG_LITTLEFS_ASSERTS #include #endif + #if !defined(LFS_NO_DEBUG) || \ !defined(LFS_NO_WARN) || \ !defined(LFS_NO_ERROR) || \ @@ -81,13 +87,11 @@ extern const char ESP_LITTLEFS_TAG[]; #endif // Runtime assertions -#ifndef LFS_ASSERT -#ifndef LFS_NO_ASSERT +#ifdef CONFIG_LITTLEFS_ASSERTS #define LFS_ASSERT(test) assert(test) #else #define LFS_ASSERT(test) #endif -#endif // Builtin functions, these may be replaced by more efficient @@ -207,11 +211,15 @@ static inline uint32_t lfs_tobe32(uint32_t a) { uint32_t lfs_crc(uint32_t crc, const void *buffer, size_t size); // Allocate memory, only used if buffers are not provided to littlefs -// Note, memory must be 64-bit aligned +// For the lookahead buffer, memory must be 32-bit aligned static inline void *lfs_malloc(size_t size) { -#ifndef LFS_NO_MALLOC +#if defined(CONFIG_LITTLEFS_MALLOC_STRATEGY_DEFAULT) + return malloc(size); // Equivalent to heap_caps_malloc_default(size); +#elif defined(CONFIG_LITTLEFS_MALLOC_STRATEGY_INTERNAL) return heap_caps_malloc(size, MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL); -#else +#elif defined(CONFIG_LITTLEFS_MALLOC_STRATEGY_SPIRAM) + return heap_caps_malloc(size, MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM); +#else // CONFIG_LITTLEFS_MALLOC_STRATEGY_DISABLE or not defined (void)size; return NULL; #endif @@ -219,9 +227,11 @@ static inline void *lfs_malloc(size_t size) { // Deallocate memory, only used if buffers are not provided to littlefs static inline void lfs_free(void *p) { -#ifndef LFS_NO_MALLOC +#if defined(CONFIG_LITTLEFS_MALLOC_STRATEGY_DEFAULT) || \ + defined(CONFIG_LITTLEFS_MALLOC_STRATEGY_INTERNAL) || \ + defined(CONFIG_LITTLEFS_MALLOC_STRATEGY_SPIRAM) free(p); -#else +#else // CONFIG_LITTLEFS_MALLOC_STRATEGY_DISABLE or not defined (void)p; #endif }