subsys/fs/littlefs: allow customization of file system configuration
There's desire to be able to customize parameters on a per-filesystem basis, which means we need a way to override the Kconfig defaults which are global. This also means the littlefs data structure cannot own the cache and lookahead buffers. Switch to using a macro to define the littlefs data structure. The default version uses the Kconfig constants. A custom one takes arguments providing the most likely partition-specific parameters. Finally the user is free to bypass the helper macros and set any parameters desired, though validation is limited and only present when CONFIG_DEBUG is enabled. Extend the test suite with a performance module, which confirms that these settings have an impact proportional to the log of changes to the cache or IO sizes. Signed-off-by: Peter A. Bigot <pab@pabigot.com>
This commit is contained in:
parent
a8b7a21524
commit
167eb53e74
13 changed files with 651 additions and 125 deletions
|
@ -19,19 +19,86 @@ extern "C" {
|
||||||
|
|
||||||
/** @brief Filesystem info structure for LittleFS mount */
|
/** @brief Filesystem info structure for LittleFS mount */
|
||||||
struct fs_littlefs {
|
struct fs_littlefs {
|
||||||
|
/* Defaulted in driver, customizable before mount. */
|
||||||
|
struct lfs_config cfg;
|
||||||
|
|
||||||
|
/* Must be cfg.cache_size */
|
||||||
|
u8_t *read_buffer;
|
||||||
|
|
||||||
|
/* Must be cfg.cache_size */
|
||||||
|
u8_t *prog_buffer;
|
||||||
|
|
||||||
|
/* Mustbe cfg.lookahead_size/4 elements, and
|
||||||
|
* cfg.lookahead_size must be a multiple of 8.
|
||||||
|
*/
|
||||||
|
u32_t *lookahead_buffer[CONFIG_FS_LITTLEFS_LOOKAHEAD_SIZE / sizeof(u32_t)];
|
||||||
|
|
||||||
/* These structures are filled automatically at mount. */
|
/* These structures are filled automatically at mount. */
|
||||||
struct lfs lfs;
|
struct lfs lfs;
|
||||||
struct lfs_config cfg;
|
|
||||||
const struct flash_area *area;
|
const struct flash_area *area;
|
||||||
struct k_mutex mutex;
|
struct k_mutex mutex;
|
||||||
|
|
||||||
/* Static buffers */
|
|
||||||
u8_t read_buffer[CONFIG_FS_LITTLEFS_CACHE_SIZE];
|
|
||||||
u8_t prog_buffer[CONFIG_FS_LITTLEFS_CACHE_SIZE];
|
|
||||||
/* Multiple of 8 bytes, but 4-byte aligned (littlefs #239) */
|
|
||||||
u32_t lookahead_buffer[CONFIG_FS_LITTLEFS_LOOKAHEAD_SIZE / sizeof(u32_t)];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** @brief Define a littlefs configuration with customized size
|
||||||
|
* characteristics.
|
||||||
|
*
|
||||||
|
* This defines static arrays required for caches, and initializes the
|
||||||
|
* littlefs configuration structure to use the provided values instead
|
||||||
|
* of the global Kconfig defaults. A pointer to the named object must
|
||||||
|
* be stored in the ``.fs_data`` field of a :c:type:`struct fs_mount`
|
||||||
|
* object.
|
||||||
|
*
|
||||||
|
* To define an instance for the Kconfig defaults, use
|
||||||
|
* :cpp:func:`FS_LITTLEFS_DECLARE_DEFAULT_CONFIG`.
|
||||||
|
*
|
||||||
|
* To completely control file system configuration the application can
|
||||||
|
* directly define and initialize a :c:type:`struct fs_littlefs`
|
||||||
|
* object. The application is responsible for ensuring the configured
|
||||||
|
* 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
|
||||||
|
* the size constraints on per-file cache allocations.
|
||||||
|
*
|
||||||
|
* @param name the name for the structure. The defined object has
|
||||||
|
* file scope.
|
||||||
|
* @param read_sz see :option:`CONFIG_FS_LITTLEFS_READ_SIZE`
|
||||||
|
* @param prog_sz see :option:`CONFIG_FS_LITTLEFS_PROG_SIZE`
|
||||||
|
* @param cache_sz see :option:`CONFIG_FS_LITTLEFS_CACHE_SIZE`
|
||||||
|
* @param lookahead_sz see :option:`CONFIG_FS_LITTLEFS_LOOKAHEAD_SIZE`
|
||||||
|
*/
|
||||||
|
#define FS_LITTLEFS_DECLARE_CUSTOM_CONFIG(name, read_sz, prog_sz, cache_sz, lookahead_sz) \
|
||||||
|
static u8_t name ## _read_buffer[cache_sz]; \
|
||||||
|
static u8_t name ## _prog_buffer[cache_sz]; \
|
||||||
|
static u32_t name ## _lookahead_buffer[(lookahead_sz) / sizeof(u32_t)]; \
|
||||||
|
static struct fs_littlefs name = { \
|
||||||
|
.cfg = { \
|
||||||
|
.read_size = (read_sz), \
|
||||||
|
.prog_size = (prog_sz), \
|
||||||
|
.cache_size = (cache_sz), \
|
||||||
|
.lookahead_size = (lookahead_sz), \
|
||||||
|
.read_buffer = name ## _read_buffer, \
|
||||||
|
.prog_buffer = name ## _prog_buffer, \
|
||||||
|
.lookahead_buffer = name ## _lookahead_buffer, \
|
||||||
|
}, \
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Define a littlefs configuration with default characteristics.
|
||||||
|
*
|
||||||
|
* This defines static arrays and initializes the littlefs
|
||||||
|
* configuration structure to use the default size configuration
|
||||||
|
* provided by Kconfig.
|
||||||
|
*
|
||||||
|
* @param name the name for the structure. The defined object has
|
||||||
|
* file scope.
|
||||||
|
*/
|
||||||
|
#define FS_LITTLEFS_DECLARE_DEFAULT_CONFIG(name) \
|
||||||
|
FS_LITTLEFS_DECLARE_CUSTOM_CONFIG(name, \
|
||||||
|
CONFIG_FS_LITTLEFS_READ_SIZE, \
|
||||||
|
CONFIG_FS_LITTLEFS_PROG_SIZE, \
|
||||||
|
CONFIG_FS_LITTLEFS_CACHE_SIZE, \
|
||||||
|
CONFIG_FS_LITTLEFS_LOOKAHEAD_SIZE)
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -10,8 +10,10 @@
|
||||||
# fs_dirent structures are big.
|
# fs_dirent structures are big.
|
||||||
CONFIG_MAIN_STACK_SIZE=2048
|
CONFIG_MAIN_STACK_SIZE=2048
|
||||||
|
|
||||||
|
# Let __ASSERT do its job
|
||||||
|
CONFIG_DEBUG=y
|
||||||
|
|
||||||
CONFIG_LOG=y
|
CONFIG_LOG=y
|
||||||
#CONFIG_FS_LOG_LEVEL_DBG=y
|
|
||||||
|
|
||||||
CONFIG_FLASH=y
|
CONFIG_FLASH=y
|
||||||
CONFIG_FLASH_MAP=y
|
CONFIG_FLASH_MAP=y
|
||||||
|
|
|
@ -17,10 +17,10 @@
|
||||||
/* Matches LFS_NAME_MAX */
|
/* Matches LFS_NAME_MAX */
|
||||||
#define MAX_PATH_LEN 255
|
#define MAX_PATH_LEN 255
|
||||||
|
|
||||||
static struct fs_littlefs lfs_storage;
|
FS_LITTLEFS_DECLARE_DEFAULT_CONFIG(storage);
|
||||||
static struct fs_mount_t lfs_storage_mnt = {
|
static struct fs_mount_t lfs_storage_mnt = {
|
||||||
.type = FS_LITTLEFS,
|
.type = FS_LITTLEFS,
|
||||||
.fs_data = &lfs_storage,
|
.fs_data = &storage,
|
||||||
.storage_dev = (void *)DT_FLASH_AREA_STORAGE_ID,
|
.storage_dev = (void *)DT_FLASH_AREA_STORAGE_ID,
|
||||||
.mnt_point = "/lfs",
|
.mnt_point = "/lfs",
|
||||||
};
|
};
|
||||||
|
|
|
@ -128,65 +128,9 @@ config NFFS_FILESYSTEM_MAX_BLOCK_SIZE
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
|
||||||
menu "LittleFS Settings"
|
|
||||||
visible if FILE_SYSTEM_LITTLEFS
|
|
||||||
|
|
||||||
config FS_LITTLEFS_NUM_FILES
|
|
||||||
int "Maximum number of opened files"
|
|
||||||
default 4
|
|
||||||
help
|
|
||||||
This is a global maximum across all mounted littlefs filesystems.
|
|
||||||
|
|
||||||
config FS_LITTLEFS_NUM_DIRS
|
|
||||||
int "Maximum number of opened directories"
|
|
||||||
default 4
|
|
||||||
help
|
|
||||||
This is a global maximum across all mounted littlefs filesystems.
|
|
||||||
|
|
||||||
config FS_LITTLEFS_READ_SIZE
|
|
||||||
int "Minimum size of a block read"
|
|
||||||
default 16
|
|
||||||
help
|
|
||||||
All read operations will be a multiple of this value.
|
|
||||||
|
|
||||||
config FS_LITTLEFS_PROG_SIZE
|
|
||||||
int "Minimum size of a block program"
|
|
||||||
default 16
|
|
||||||
help
|
|
||||||
All program operations will be a multiple of this value.
|
|
||||||
|
|
||||||
config FS_LITTLEFS_CACHE_SIZE
|
|
||||||
int "Size of block caches in bytes"
|
|
||||||
default 64
|
|
||||||
help
|
|
||||||
Each cache buffers a portion of a block in RAM. The littlefs
|
|
||||||
needs a read cache, a program cache, and one additional cache
|
|
||||||
per file. Larger caches can improve performance by storing
|
|
||||||
more data and reducing the number of disk accesses. Must be a
|
|
||||||
multiple of the read and program sizes of the underlying flash
|
|
||||||
device, and a factor of the block size.
|
|
||||||
|
|
||||||
config FS_LITTLEFS_LOOKAHEAD_SIZE
|
|
||||||
int "Size of lookahead buffer in bytes"
|
|
||||||
default 32
|
|
||||||
help
|
|
||||||
A larger lookahead buffer increases the number of blocks found
|
|
||||||
during an allocation pass. The lookahead buffer is stored as a
|
|
||||||
compact bitmap, so each byte of RAM can track 8 blocks. Must
|
|
||||||
be a multiple of 8.
|
|
||||||
|
|
||||||
config FS_LITTLEFS_BLOCK_CYCLES
|
|
||||||
int "Number of erase cycles before moving data to another block"
|
|
||||||
default 512
|
|
||||||
help
|
|
||||||
For dynamic wear leveling, the number of erase cycles before data
|
|
||||||
is moved to another block. Set to a non-positive value to
|
|
||||||
disable leveling.
|
|
||||||
|
|
||||||
endmenu
|
|
||||||
|
|
||||||
endif # FILE_SYSTEM
|
endif # FILE_SYSTEM
|
||||||
|
|
||||||
|
source "subsys/fs/Kconfig.littlefs"
|
||||||
source "subsys/fs/fcb/Kconfig"
|
source "subsys/fs/fcb/Kconfig"
|
||||||
source "subsys/fs/nvs/Kconfig"
|
source "subsys/fs/nvs/Kconfig"
|
||||||
|
|
||||||
|
|
95
subsys/fs/Kconfig.littlefs
Normal file
95
subsys/fs/Kconfig.littlefs
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
#
|
||||||
|
# Copyright (c) 2019 Bolt Innovation Management, LLC
|
||||||
|
# Copyright (c) 2019 Peter Bigot Consulting, LLC
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
|
||||||
|
menu "LittleFS Settings"
|
||||||
|
visible if FILE_SYSTEM_LITTLEFS
|
||||||
|
|
||||||
|
config FS_LITTLEFS_NUM_FILES
|
||||||
|
int "Maximum number of opened files"
|
||||||
|
default 4
|
||||||
|
help
|
||||||
|
This is a global maximum across all mounted littlefs filesystems.
|
||||||
|
|
||||||
|
config FS_LITTLEFS_NUM_DIRS
|
||||||
|
int "Maximum number of opened directories"
|
||||||
|
default 4
|
||||||
|
help
|
||||||
|
This is a global maximum across all mounted littlefs filesystems.
|
||||||
|
|
||||||
|
config FS_LITTLEFS_READ_SIZE
|
||||||
|
int "Minimum size of a block read"
|
||||||
|
default 16
|
||||||
|
help
|
||||||
|
All read operations will be a multiple of this value.
|
||||||
|
|
||||||
|
config FS_LITTLEFS_PROG_SIZE
|
||||||
|
int "Minimum size of a block program"
|
||||||
|
default 16
|
||||||
|
help
|
||||||
|
All program operations will be a multiple of this value.
|
||||||
|
|
||||||
|
config FS_LITTLEFS_CACHE_SIZE
|
||||||
|
int "Size of block caches in bytes"
|
||||||
|
default 64
|
||||||
|
help
|
||||||
|
Each cache buffers a portion of a block in RAM. The littlefs
|
||||||
|
needs a read cache, a program cache, and one additional cache
|
||||||
|
per file. Larger caches can improve performance by storing
|
||||||
|
more data and reducing the number of disk accesses. Must be a
|
||||||
|
multiple of the read and program sizes of the underlying flash
|
||||||
|
device, and a factor of the block size.
|
||||||
|
|
||||||
|
config FS_LITTLEFS_LOOKAHEAD_SIZE
|
||||||
|
int "Size of lookahead buffer in bytes"
|
||||||
|
default 32
|
||||||
|
help
|
||||||
|
A larger lookahead buffer increases the number of blocks found
|
||||||
|
during an allocation pass. The lookahead buffer is stored as a
|
||||||
|
compact bitmap, so each byte of RAM can track 8 blocks. Must
|
||||||
|
be a multiple of 8.
|
||||||
|
|
||||||
|
config FS_LITTLEFS_BLOCK_CYCLES
|
||||||
|
int "Number of erase cycles before moving data to another block"
|
||||||
|
default 512
|
||||||
|
help
|
||||||
|
For dynamic wear leveling, the number of erase cycles before data
|
||||||
|
is moved to another block. Set to a non-positive value to
|
||||||
|
disable leveling.
|
||||||
|
|
||||||
|
menuconfig FS_LITTLEFS_FC_MEM_POOL
|
||||||
|
bool "Enable flexible file cache sizes for littlefs"
|
||||||
|
help
|
||||||
|
littlefs requires a per-file buffer to cache data. For
|
||||||
|
applications that use the default configuration parameters a
|
||||||
|
memory slab is reserved to support up to
|
||||||
|
FS_LITTLE_FS_NUM_FILES blocks of FS_LITTLEFS_CACHE_SIZE bytes.
|
||||||
|
|
||||||
|
When applications customize littlefs configurations and
|
||||||
|
support different cache sizes for different partitions this
|
||||||
|
preallocation is inadequate.
|
||||||
|
|
||||||
|
Select this feature to enable a memory pool allocator for
|
||||||
|
littlefs file caches.
|
||||||
|
|
||||||
|
if FS_LITTLEFS_FC_MEM_POOL
|
||||||
|
|
||||||
|
config FS_LITTLEFS_FC_MEM_POOL_MIN_SIZE
|
||||||
|
int "Minimum block size for littlefs file cache memory pool"
|
||||||
|
default 16
|
||||||
|
|
||||||
|
config FS_LITTLEFS_FC_MEM_POOL_MAX_SIZE
|
||||||
|
int "Maximum block size for littlefs file cache memory pool"
|
||||||
|
default 1024
|
||||||
|
|
||||||
|
config FS_LITTLEFS_FC_MEM_POOL_NUM_BLOCKS
|
||||||
|
int "Number of maximum sized blocks in littlefs file cache memory pool"
|
||||||
|
default 2
|
||||||
|
|
||||||
|
endif # FS_LITTLEFS_FC_MEM_POOL
|
||||||
|
|
||||||
|
endmenu
|
||||||
|
|
|
@ -22,20 +22,35 @@
|
||||||
|
|
||||||
#include "fs_impl.h"
|
#include "fs_impl.h"
|
||||||
|
|
||||||
struct lfs_file_cache {
|
struct lfs_file_data {
|
||||||
struct lfs_file file;
|
struct lfs_file file;
|
||||||
struct lfs_file_config config;
|
struct lfs_file_config config;
|
||||||
u8_t cache[CONFIG_FS_LITTLEFS_CACHE_SIZE];
|
struct k_mem_block cache_block;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define LFS_FILEP(fp) (&((struct lfs_file_cache *)(fp->filep))->file)
|
#define LFS_FILEP(fp) (&((struct lfs_file_data *)(fp->filep))->file)
|
||||||
|
|
||||||
/* Global memory pool for open files and dirs */
|
/* Global memory pool for open files and dirs */
|
||||||
K_MEM_SLAB_DEFINE(lfs_file_pool, sizeof(struct lfs_file_cache),
|
K_MEM_SLAB_DEFINE(file_data_pool, sizeof(struct lfs_file_data),
|
||||||
CONFIG_FS_LITTLEFS_NUM_FILES, 4);
|
CONFIG_FS_LITTLEFS_NUM_FILES, 4);
|
||||||
K_MEM_SLAB_DEFINE(lfs_dir_pool, sizeof(struct lfs_dir),
|
K_MEM_SLAB_DEFINE(lfs_dir_pool, sizeof(struct lfs_dir),
|
||||||
CONFIG_FS_LITTLEFS_NUM_DIRS, 4);
|
CONFIG_FS_LITTLEFS_NUM_DIRS, 4);
|
||||||
|
|
||||||
|
/* 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_MEM_POOL_DEFINE(file_cache_pool,
|
||||||
|
CONFIG_FS_LITTLEFS_FC_MEM_POOL_MIN_SIZE,
|
||||||
|
CONFIG_FS_LITTLEFS_FC_MEM_POOL_MAX_SIZE,
|
||||||
|
CONFIG_FS_LITTLEFS_FC_MEM_POOL_NUM_BLOCKS, 4);
|
||||||
|
|
||||||
static inline void fs_lock(struct fs_littlefs *fs)
|
static inline void fs_lock(struct fs_littlefs *fs)
|
||||||
{
|
{
|
||||||
k_mutex_lock(&fs->mutex, K_FOREVER);
|
k_mutex_lock(&fs->mutex, K_FOREVER);
|
||||||
|
@ -154,36 +169,53 @@ static int lfs_api_sync(const struct lfs_config *c)
|
||||||
return LFS_ERR_OK;
|
return LFS_ERR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void release_file_data(struct fs_file_t *fp)
|
||||||
|
{
|
||||||
|
struct lfs_file_data *fdp = fp->filep;
|
||||||
|
|
||||||
|
if (fdp->config.buffer) {
|
||||||
|
k_mem_pool_free(&fdp->cache_block);
|
||||||
|
}
|
||||||
|
|
||||||
|
k_mem_slab_free(&file_data_pool, &fp->filep);
|
||||||
|
fp->filep = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static int littlefs_open(struct fs_file_t *fp, const char *path)
|
static int littlefs_open(struct fs_file_t *fp, const char *path)
|
||||||
{
|
{
|
||||||
struct fs_littlefs *fs = fp->mp->fs_data;
|
struct fs_littlefs *fs = fp->mp->fs_data;
|
||||||
|
struct lfs *lfs = &fs->lfs;
|
||||||
int flags = LFS_O_CREAT | LFS_O_RDWR;
|
int flags = LFS_O_CREAT | LFS_O_RDWR;
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (k_mem_slab_alloc(&lfs_file_pool, &fp->filep, K_NO_WAIT) != 0) {
|
ret = k_mem_slab_alloc(&file_data_pool, &fp->filep, K_NO_WAIT);
|
||||||
return -ENOMEM;
|
if (ret != 0) {
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct lfs_file_data *fdp = fp->filep;
|
||||||
|
|
||||||
|
memset(fdp, 0, sizeof(*fdp));
|
||||||
|
|
||||||
|
ret = k_mem_pool_alloc(&file_cache_pool, &fdp->cache_block,
|
||||||
|
lfs->cfg->cache_size, K_NO_WAIT);
|
||||||
|
LOG_DBG("alloc %u file cache: %d", lfs->cfg->cache_size, ret);
|
||||||
|
if (ret != 0) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
fdp->config.buffer = fdp->cache_block.data;
|
||||||
|
path = fs_impl_strip_prefix(path, fp->mp);
|
||||||
|
|
||||||
fs_lock(fs);
|
fs_lock(fs);
|
||||||
|
|
||||||
/* Use cache inside the slab allocation, instead of letting
|
ret = lfs_file_opencfg(&fs->lfs, &fdp->file,
|
||||||
* littlefs allocate it from the heap.
|
path, flags, &fdp->config);
|
||||||
*/
|
|
||||||
struct lfs_file_cache *fc = fp->filep;
|
|
||||||
|
|
||||||
fc->config = (struct lfs_file_config) {
|
|
||||||
.buffer = fc->cache,
|
|
||||||
};
|
|
||||||
memset(&fc->file, 0, sizeof(struct lfs_file));
|
|
||||||
|
|
||||||
path = fs_impl_strip_prefix(path, fp->mp);
|
|
||||||
|
|
||||||
int ret = lfs_file_opencfg(&fs->lfs, &fc->file,
|
|
||||||
path, flags, &fc->config);
|
|
||||||
|
|
||||||
fs_unlock(fs);
|
fs_unlock(fs);
|
||||||
|
out:
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
k_mem_slab_free(&lfs_file_pool, &fp->filep);
|
release_file_data(fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
return lfs_to_errno(ret);
|
return lfs_to_errno(ret);
|
||||||
|
@ -197,9 +229,10 @@ static int littlefs_close(struct fs_file_t *fp)
|
||||||
|
|
||||||
int ret = lfs_file_close(&fs->lfs, LFS_FILEP(fp));
|
int ret = lfs_file_close(&fs->lfs, LFS_FILEP(fp));
|
||||||
|
|
||||||
k_mem_slab_free(&lfs_file_pool, &fp->filep);
|
|
||||||
|
|
||||||
fs_unlock(fs);
|
fs_unlock(fs);
|
||||||
|
|
||||||
|
release_file_data(fp);
|
||||||
|
|
||||||
return lfs_to_errno(ret);
|
return lfs_to_errno(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -542,25 +575,64 @@ static int littlefs_mount(struct fs_mount_t *mountp)
|
||||||
BUILD_ASSERT((CONFIG_FS_LITTLEFS_CACHE_SIZE
|
BUILD_ASSERT((CONFIG_FS_LITTLEFS_CACHE_SIZE
|
||||||
% CONFIG_FS_LITTLEFS_PROG_SIZE) == 0);
|
% CONFIG_FS_LITTLEFS_PROG_SIZE) == 0);
|
||||||
|
|
||||||
lfs_size_t read_size = CONFIG_FS_LITTLEFS_READ_SIZE;
|
struct lfs_config *lcp = &fs->cfg;
|
||||||
lfs_size_t prog_size = CONFIG_FS_LITTLEFS_PROG_SIZE;
|
|
||||||
lfs_size_t block_size = get_block_size(fs->area);
|
|
||||||
s32_t block_cycles = CONFIG_FS_LITTLEFS_BLOCK_CYCLES;
|
|
||||||
lfs_size_t cache_size = CONFIG_FS_LITTLEFS_CACHE_SIZE;
|
|
||||||
lfs_size_t lookahead_size = CONFIG_FS_LITTLEFS_LOOKAHEAD_SIZE;
|
|
||||||
|
|
||||||
|
lfs_size_t read_size = lcp->read_size;
|
||||||
|
|
||||||
|
if (read_size == 0) {
|
||||||
|
read_size = CONFIG_FS_LITTLEFS_READ_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
lfs_size_t prog_size = lcp->prog_size;
|
||||||
|
|
||||||
|
if (prog_size == 0) {
|
||||||
|
prog_size = CONFIG_FS_LITTLEFS_PROG_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Yes, you can override block size. */
|
||||||
|
lfs_size_t block_size = lcp->block_size;
|
||||||
|
|
||||||
|
if (block_size == 0) {
|
||||||
|
block_size = get_block_size(fs->area);
|
||||||
|
}
|
||||||
|
|
||||||
|
s32_t block_cycles = lcp->block_cycles;
|
||||||
|
|
||||||
|
if (block_cycles == 0) {
|
||||||
|
block_cycles = CONFIG_FS_LITTLEFS_BLOCK_CYCLES;
|
||||||
|
}
|
||||||
if (block_cycles <= 0) {
|
if (block_cycles <= 0) {
|
||||||
/* Disable leveling (littlefs v2.1+ semantics) */
|
/* Disable leveling (littlefs v2.1+ semantics) */
|
||||||
block_cycles = -1;
|
block_cycles = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lfs_size_t cache_size = lcp->cache_size;
|
||||||
|
|
||||||
|
if (cache_size == 0) {
|
||||||
|
cache_size = CONFIG_FS_LITTLEFS_CACHE_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
lfs_size_t lookahead_size = lcp->lookahead_size;
|
||||||
|
|
||||||
|
if (lookahead_size == 0) {
|
||||||
|
lookahead_size = CONFIG_FS_LITTLEFS_LOOKAHEAD_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* No, you don't get to override this. */
|
||||||
lfs_size_t block_count = fs->area->fa_size / block_size;
|
lfs_size_t block_count = fs->area->fa_size / block_size;
|
||||||
|
|
||||||
LOG_DBG("FS at %s is %u 0x%x-byte blocks with %u cycle", dev->config->name,
|
LOG_INF("FS at %s:0x%x is %u 0x%x-byte blocks with %u cycle",
|
||||||
|
dev->config->name, (u32_t)fs->area->fa_off,
|
||||||
block_count, block_size, block_cycles);
|
block_count, block_size, block_cycles);
|
||||||
LOG_DBG("sizes: rd %u ; pr %u ; ca %u ; la %u",
|
LOG_INF("sizes: rd %u ; pr %u ; ca %u ; la %u",
|
||||||
read_size, prog_size, cache_size, lookahead_size);
|
read_size, prog_size, cache_size, lookahead_size);
|
||||||
|
|
||||||
|
__ASSERT_NO_MSG(prog_size != 0);
|
||||||
|
__ASSERT_NO_MSG(read_size != 0);
|
||||||
|
__ASSERT_NO_MSG(cache_size != 0);
|
||||||
|
__ASSERT_NO_MSG(block_size != 0);
|
||||||
|
|
||||||
__ASSERT((fs->area->fa_size % block_size) == 0,
|
__ASSERT((fs->area->fa_size % block_size) == 0,
|
||||||
"partition size must be multiple of block size");
|
"partition size must be multiple of block size");
|
||||||
__ASSERT((block_size % prog_size) == 0,
|
__ASSERT((block_size % prog_size) == 0,
|
||||||
|
@ -568,24 +640,19 @@ static int littlefs_mount(struct fs_mount_t *mountp)
|
||||||
__ASSERT((block_size % cache_size) == 0,
|
__ASSERT((block_size % cache_size) == 0,
|
||||||
"cache size incompatible with block size");
|
"cache size incompatible with block size");
|
||||||
|
|
||||||
/* Build littlefs config */
|
/* Set the validated/defaulted values. */
|
||||||
fs->cfg = (struct lfs_config) {
|
lcp->context = (void *)fs->area;
|
||||||
.context = (void *)fs->area,
|
lcp->read = lfs_api_read;
|
||||||
.read = lfs_api_read,
|
lcp->prog = lfs_api_prog;
|
||||||
.prog = lfs_api_prog,
|
lcp->erase = lfs_api_erase;
|
||||||
.erase = lfs_api_erase,
|
lcp->sync = lfs_api_sync;
|
||||||
.sync = lfs_api_sync,
|
lcp->read_size = read_size;
|
||||||
.read_size = read_size,
|
lcp->prog_size = prog_size;
|
||||||
.prog_size = prog_size,
|
lcp->block_size = block_size;
|
||||||
.block_size = block_size,
|
lcp->block_count = block_count;
|
||||||
.block_count = block_count,
|
lcp->block_cycles = block_cycles;
|
||||||
.block_cycles = block_cycles,
|
lcp->cache_size = cache_size;
|
||||||
.cache_size = cache_size,
|
lcp->lookahead_size = lookahead_size;
|
||||||
.lookahead_size = lookahead_size,
|
|
||||||
.read_buffer = fs->read_buffer,
|
|
||||||
.prog_buffer = fs->prog_buffer,
|
|
||||||
.lookahead_buffer = fs->lookahead_buffer
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Mount it, formatting if needed. */
|
/* Mount it, formatting if needed. */
|
||||||
ret = lfs_mount(&fs->lfs, &fs->cfg);
|
ret = lfs_mount(&fs->lfs, &fs->cfg);
|
||||||
|
|
|
@ -3,7 +3,17 @@ CONFIG_FILE_SYSTEM_LITTLEFS=y
|
||||||
|
|
||||||
CONFIG_MAIN_STACK_SIZE=4096
|
CONFIG_MAIN_STACK_SIZE=4096
|
||||||
|
|
||||||
CONFIG_LOG=y
|
# Performance tests need custom buffer allocation
|
||||||
|
CONFIG_MINIMAL_LIBC_MALLOC_ARENA_SIZE=8192
|
||||||
|
|
||||||
|
# Configuration tests require variable cache sizes
|
||||||
|
CONFIG_FS_LITTLEFS_FC_MEM_POOL=y
|
||||||
|
|
||||||
|
# FS abstraction layer is noisy so it's off. Turn it on to see the
|
||||||
|
# littlefs configuration parameters.
|
||||||
|
#CONFIG_LOG=y
|
||||||
|
#CONFIG_FS_LOG_LEVEL_DBG=y
|
||||||
|
|
||||||
CONFIG_FLASH=y
|
CONFIG_FLASH=y
|
||||||
CONFIG_FLASH_MAP=y
|
CONFIG_FLASH_MAP=y
|
||||||
CONFIG_FLASH_PAGE_LAYOUT=y
|
CONFIG_FLASH_PAGE_LAYOUT=y
|
||||||
|
|
|
@ -20,7 +20,8 @@ void test_main(void)
|
||||||
ztest_unit_test(test_util_path_extend_up),
|
ztest_unit_test(test_util_path_extend_up),
|
||||||
ztest_unit_test(test_util_path_extend_overrun),
|
ztest_unit_test(test_util_path_extend_overrun),
|
||||||
ztest_unit_test(test_lfs_basic),
|
ztest_unit_test(test_lfs_basic),
|
||||||
ztest_unit_test(test_lfs_dirops)
|
ztest_unit_test(test_lfs_dirops),
|
||||||
|
ztest_unit_test(test_lfs_perf)
|
||||||
);
|
);
|
||||||
ztest_run_test_suite(littlefs_test);
|
ztest_run_test_suite(littlefs_test);
|
||||||
}
|
}
|
||||||
|
|
|
@ -409,6 +409,70 @@ static int verify_goodbye(const struct fs_mount_t *mp)
|
||||||
return TC_PASS;
|
return TC_PASS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int check_medium(void)
|
||||||
|
{
|
||||||
|
struct fs_mount_t *mp = &testfs_medium_mnt;
|
||||||
|
struct fs_statvfs stat;
|
||||||
|
|
||||||
|
zassert_equal(clear_partition(mp), TC_PASS,
|
||||||
|
"clear partition failed");
|
||||||
|
|
||||||
|
zassert_equal(fs_mount(mp), 0,
|
||||||
|
"medium mount failed");
|
||||||
|
|
||||||
|
zassert_equal(fs_statvfs(mp->mnt_point, &stat), 0,
|
||||||
|
"statvfs failed");
|
||||||
|
|
||||||
|
TC_PRINT("%s: bsize %lu ; frsize %lu ; blocks %lu ; bfree %lu\n",
|
||||||
|
mp->mnt_point,
|
||||||
|
stat.f_bsize, stat.f_frsize, stat.f_blocks, stat.f_bfree);
|
||||||
|
zassert_equal(stat.f_bsize, MEDIUM_IO_SIZE,
|
||||||
|
"bsize fail");
|
||||||
|
zassert_equal(stat.f_frsize, 4096,
|
||||||
|
"frsize fail");
|
||||||
|
zassert_equal(stat.f_blocks, 240,
|
||||||
|
"blocks fail");
|
||||||
|
zassert_equal(stat.f_bfree, stat.f_blocks - 2U,
|
||||||
|
"bfree fail");
|
||||||
|
|
||||||
|
zassert_equal(fs_unmount(mp), 0,
|
||||||
|
"medium unmount failed");
|
||||||
|
|
||||||
|
return TC_PASS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int check_large(void)
|
||||||
|
{
|
||||||
|
struct fs_mount_t *mp = &testfs_large_mnt;
|
||||||
|
struct fs_statvfs stat;
|
||||||
|
|
||||||
|
zassert_equal(clear_partition(mp), TC_PASS,
|
||||||
|
"clear partition failed");
|
||||||
|
|
||||||
|
zassert_equal(fs_mount(mp), 0,
|
||||||
|
"large mount failed");
|
||||||
|
|
||||||
|
zassert_equal(fs_statvfs(mp->mnt_point, &stat), 0,
|
||||||
|
"statvfs failed");
|
||||||
|
|
||||||
|
TC_PRINT("%s: bsize %lu ; frsize %lu ; blocks %lu ; bfree %lu\n",
|
||||||
|
mp->mnt_point,
|
||||||
|
stat.f_bsize, stat.f_frsize, stat.f_blocks, stat.f_bfree);
|
||||||
|
zassert_equal(stat.f_bsize, LARGE_IO_SIZE,
|
||||||
|
"bsize fail");
|
||||||
|
zassert_equal(stat.f_frsize, 32768,
|
||||||
|
"frsize fail");
|
||||||
|
zassert_equal(stat.f_blocks, 96,
|
||||||
|
"blocks fail");
|
||||||
|
zassert_equal(stat.f_bfree, stat.f_blocks - 2U,
|
||||||
|
"bfree fail");
|
||||||
|
|
||||||
|
zassert_equal(fs_unmount(mp), 0,
|
||||||
|
"large unmount failed");
|
||||||
|
|
||||||
|
return TC_PASS;
|
||||||
|
}
|
||||||
|
|
||||||
void test_lfs_basic(void)
|
void test_lfs_basic(void)
|
||||||
{
|
{
|
||||||
struct fs_mount_t *mp = &testfs_small_mnt;
|
struct fs_mount_t *mp = &testfs_small_mnt;
|
||||||
|
@ -457,4 +521,11 @@ void test_lfs_basic(void)
|
||||||
|
|
||||||
zassert_equal(fs_unmount(mp), 0,
|
zassert_equal(fs_unmount(mp), 0,
|
||||||
"unmount2 small failed");
|
"unmount2 small failed");
|
||||||
|
|
||||||
|
zassert_equal(check_medium(), TC_PASS,
|
||||||
|
"check medium failed");
|
||||||
|
|
||||||
|
zassert_equal(check_large(), TC_PASS,
|
||||||
|
"check large failed");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
243
tests/subsys/fs/littlefs/src/test_lfs_perf.c
Normal file
243
tests/subsys/fs/littlefs/src/test_lfs_perf.c
Normal file
|
@ -0,0 +1,243 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 Peter Bigot Consulting, LLC
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* littlefs performance testing */
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <kernel.h>
|
||||||
|
#include <ztest.h>
|
||||||
|
#include "testfs_tests.h"
|
||||||
|
#include "testfs_lfs.h"
|
||||||
|
#include <lfs.h>
|
||||||
|
|
||||||
|
#include <fs/littlefs.h>
|
||||||
|
|
||||||
|
#define HELLO "hello"
|
||||||
|
#define GOODBYE "goodbye"
|
||||||
|
|
||||||
|
static int write_read(const char *tag,
|
||||||
|
struct fs_mount_t *mp,
|
||||||
|
size_t buf_size,
|
||||||
|
size_t nbuf)
|
||||||
|
{
|
||||||
|
const struct lfs_config *lcp = &((const struct fs_littlefs *)mp->fs_data)->cfg;
|
||||||
|
struct testfs_path path;
|
||||||
|
struct fs_statvfs vfs;
|
||||||
|
struct fs_dirent stat;
|
||||||
|
struct fs_file_t file;
|
||||||
|
size_t total = nbuf * buf_size;
|
||||||
|
u32_t t0;
|
||||||
|
u32_t t1;
|
||||||
|
u8_t *buf;
|
||||||
|
int rc;
|
||||||
|
int rv = TC_FAIL;
|
||||||
|
|
||||||
|
TC_PRINT("clearing %s for %s write/read test\n",
|
||||||
|
mp->mnt_point, tag);
|
||||||
|
if (testfs_lfs_wipe_partition(mp) != TC_PASS) {
|
||||||
|
return TC_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = fs_mount(mp);
|
||||||
|
if (rc != 0) {
|
||||||
|
TC_PRINT("Mount %s failed: %d\n", mp->mnt_point, rc);
|
||||||
|
return TC_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = fs_statvfs(mp->mnt_point, &vfs);
|
||||||
|
if (rc != 0) {
|
||||||
|
TC_PRINT("statvfs %s failed: %d\n", mp->mnt_point, rc);
|
||||||
|
goto out_mnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
TC_PRINT("%s: bsize %lu ; frsize %lu ; blocks %lu ; bfree %lu\n",
|
||||||
|
mp->mnt_point,
|
||||||
|
vfs.f_bsize, vfs.f_frsize, vfs.f_blocks, vfs.f_bfree);
|
||||||
|
TC_PRINT("read_size %u ; prog_size %u ; cache_size %u ; lookahead_size %u\n",
|
||||||
|
lcp->read_size, lcp->prog_size, lcp->cache_size, lcp->lookahead_size);
|
||||||
|
|
||||||
|
testfs_path_init(&path, mp,
|
||||||
|
"data",
|
||||||
|
TESTFS_PATH_END);
|
||||||
|
|
||||||
|
buf = calloc(buf_size, sizeof(u8_t));
|
||||||
|
if (buf == NULL) {
|
||||||
|
TC_PRINT("Failed to allocate %zu-byte buffer\n", buf_size);
|
||||||
|
goto out_mnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < buf_size; ++i) {
|
||||||
|
buf[i] = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
TC_PRINT("creating and writing %zu %zu-byte blocks\n",
|
||||||
|
nbuf, buf_size);
|
||||||
|
|
||||||
|
rc = fs_open(&file, path.path);
|
||||||
|
if (rc != 0) {
|
||||||
|
TC_PRINT("Failed to open %s for write: %d\n", path.path, rc);
|
||||||
|
goto out_buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
t0 = k_uptime_get_32();
|
||||||
|
for (size_t i = 0; i < nbuf; ++i) {
|
||||||
|
rc = fs_write(&file, buf, buf_size);
|
||||||
|
if (buf_size != rc) {
|
||||||
|
TC_PRINT("Failed to write buf %u: %d\n", i, rc);
|
||||||
|
goto out_file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
t1 = k_uptime_get_32();
|
||||||
|
|
||||||
|
(void)fs_close(&file);
|
||||||
|
|
||||||
|
rc = fs_stat(path.path, &stat);
|
||||||
|
if (rc != 0) {
|
||||||
|
TC_PRINT("Failed to stat %s: %d\n", path.path, rc);
|
||||||
|
goto out_buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stat.size != total) {
|
||||||
|
TC_PRINT("File size %zu not %zu\n", stat.size, total);
|
||||||
|
goto out_buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
TC_PRINT("%s write %zu * %zu = %zu bytes in %u ms: "
|
||||||
|
"%u By/s, %u KiBy/s\n",
|
||||||
|
tag, nbuf, buf_size, total, (t1 - t0),
|
||||||
|
(u32_t)(total * 1000U / (t1 - t0)),
|
||||||
|
(u32_t)(total * 1000U / (t1 - t0) / 1024U));
|
||||||
|
|
||||||
|
rc = fs_open(&file, path.path);
|
||||||
|
if (rc != 0) {
|
||||||
|
TC_PRINT("Failed to open %s for write: %d\n", path.path, rc);
|
||||||
|
goto out_buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
t0 = k_uptime_get_32();
|
||||||
|
for (size_t i = 0; i < nbuf; ++i) {
|
||||||
|
rc = fs_read(&file, buf, buf_size);
|
||||||
|
if (buf_size != rc) {
|
||||||
|
TC_PRINT("Failed to read buf %u: %d\n", i, rc);
|
||||||
|
goto out_file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
t1 = k_uptime_get_32();
|
||||||
|
|
||||||
|
TC_PRINT("%s read %zu * %zu = %zu bytes in %u ms: "
|
||||||
|
"%u By/s, %u KiBy/s\n",
|
||||||
|
tag, nbuf, buf_size, total, (t1 - t0),
|
||||||
|
(u32_t)(total * 1000U / (t1 - t0)),
|
||||||
|
(u32_t)(total * 1000U / (t1 - t0) / 1024U));
|
||||||
|
|
||||||
|
rv = TC_PASS;
|
||||||
|
|
||||||
|
out_file:
|
||||||
|
(void)fs_close(&file);
|
||||||
|
|
||||||
|
out_buf:
|
||||||
|
free(buf);
|
||||||
|
|
||||||
|
out_mnt:
|
||||||
|
(void)fs_unmount(mp);
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int custom_write_test(const char *tag,
|
||||||
|
const struct fs_mount_t *mp,
|
||||||
|
const struct lfs_config *cfgp,
|
||||||
|
size_t buf_size,
|
||||||
|
size_t nbuf)
|
||||||
|
{
|
||||||
|
struct fs_littlefs data = {
|
||||||
|
.cfg = *cfgp,
|
||||||
|
};
|
||||||
|
struct fs_mount_t lfs_mnt = {
|
||||||
|
.type = FS_LITTLEFS,
|
||||||
|
.fs_data = &data,
|
||||||
|
.storage_dev = mp->storage_dev,
|
||||||
|
.mnt_point = mp->mnt_point,
|
||||||
|
};
|
||||||
|
struct lfs_config *lcp = &data.cfg;
|
||||||
|
int rv = TC_FAIL;
|
||||||
|
|
||||||
|
if (lcp->cache_size == 0) {
|
||||||
|
lcp->cache_size = CONFIG_FS_LITTLEFS_CACHE_SIZE;
|
||||||
|
}
|
||||||
|
if (lcp->lookahead_size == 0) {
|
||||||
|
lcp->lookahead_size = CONFIG_FS_LITTLEFS_LOOKAHEAD_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
lcp->read_buffer = malloc(lcp->cache_size);
|
||||||
|
lcp->prog_buffer = malloc(lcp->cache_size);
|
||||||
|
lcp->lookahead_buffer = malloc(lcp->lookahead_size);
|
||||||
|
|
||||||
|
TC_PRINT("bufs %p %p %p\n", lcp->read_buffer, lcp->prog_buffer, lcp->lookahead_buffer);
|
||||||
|
|
||||||
|
if ((lcp->read_buffer == NULL)
|
||||||
|
|| (lcp->prog_buffer == NULL)
|
||||||
|
|| (lcp->lookahead_buffer == NULL)) {
|
||||||
|
TC_PRINT("%s buffer allocation failed\n", tag);
|
||||||
|
goto out_free;
|
||||||
|
}
|
||||||
|
|
||||||
|
rv = write_read(tag, &lfs_mnt, buf_size, nbuf);
|
||||||
|
|
||||||
|
out_free:
|
||||||
|
if (lcp->read_buffer) {
|
||||||
|
free(lcp->read_buffer);
|
||||||
|
}
|
||||||
|
if (lcp->prog_buffer) {
|
||||||
|
free(lcp->prog_buffer);
|
||||||
|
}
|
||||||
|
if (lcp->lookahead_buffer) {
|
||||||
|
free(lcp->lookahead_buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int small_8_1K_cust(void)
|
||||||
|
{
|
||||||
|
struct lfs_config cfg = {
|
||||||
|
.read_size = LARGE_IO_SIZE,
|
||||||
|
.prog_size = LARGE_IO_SIZE,
|
||||||
|
.cache_size = LARGE_CACHE_SIZE,
|
||||||
|
.lookahead_size = LARGE_LOOKAHEAD_SIZE
|
||||||
|
};
|
||||||
|
|
||||||
|
return custom_write_test("small 8x1K bigfile", &testfs_small_mnt, &cfg, 1024, 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_lfs_perf(void)
|
||||||
|
{
|
||||||
|
k_sleep(K_MSEC(100)); /* flush log messages */
|
||||||
|
zassert_equal(write_read("small 8x1K dflt",
|
||||||
|
&testfs_small_mnt,
|
||||||
|
1024, 8),
|
||||||
|
TC_PASS,
|
||||||
|
"failed");
|
||||||
|
|
||||||
|
k_sleep(K_MSEC(100)); /* flush log messages */
|
||||||
|
zassert_equal(small_8_1K_cust(), TC_PASS,
|
||||||
|
"failed");
|
||||||
|
|
||||||
|
k_sleep(K_MSEC(100)); /* flush log messages */
|
||||||
|
zassert_equal(write_read("medium 32x2K dflt",
|
||||||
|
&testfs_medium_mnt,
|
||||||
|
2048, 32),
|
||||||
|
TC_PASS,
|
||||||
|
"failed");
|
||||||
|
|
||||||
|
k_sleep(K_MSEC(100)); /* flush log messages */
|
||||||
|
zassert_equal(write_read("large 64x4K dflt",
|
||||||
|
&testfs_large_mnt,
|
||||||
|
4096, 64),
|
||||||
|
TC_PASS,
|
||||||
|
"failed");
|
||||||
|
}
|
|
@ -9,26 +9,41 @@
|
||||||
#include <storage/flash_map.h>
|
#include <storage/flash_map.h>
|
||||||
#include "testfs_lfs.h"
|
#include "testfs_lfs.h"
|
||||||
|
|
||||||
static struct fs_littlefs small_data;
|
FS_LITTLEFS_DECLARE_DEFAULT_CONFIG(small);
|
||||||
struct fs_mount_t testfs_small_mnt = {
|
struct fs_mount_t testfs_small_mnt = {
|
||||||
.type = FS_LITTLEFS,
|
.type = FS_LITTLEFS,
|
||||||
.fs_data = &small_data,
|
.fs_data = &small,
|
||||||
.storage_dev = (void *)DT_FLASH_AREA_SMALL_ID,
|
.storage_dev = (void *)DT_FLASH_AREA_SMALL_ID,
|
||||||
.mnt_point = TESTFS_MNT_POINT_SMALL,
|
.mnt_point = TESTFS_MNT_POINT_SMALL,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct fs_littlefs medium_data;
|
FS_LITTLEFS_DECLARE_CUSTOM_CONFIG(medium, MEDIUM_IO_SIZE, MEDIUM_IO_SIZE,
|
||||||
|
MEDIUM_CACHE_SIZE, MEDIUM_LOOKAHEAD_SIZE);
|
||||||
struct fs_mount_t testfs_medium_mnt = {
|
struct fs_mount_t testfs_medium_mnt = {
|
||||||
.type = FS_LITTLEFS,
|
.type = FS_LITTLEFS,
|
||||||
.fs_data = &medium_data,
|
.fs_data = &medium,
|
||||||
.storage_dev = (void *)DT_FLASH_AREA_MEDIUM_ID,
|
.storage_dev = (void *)DT_FLASH_AREA_MEDIUM_ID,
|
||||||
.mnt_point = TESTFS_MNT_POINT_MEDIUM,
|
.mnt_point = TESTFS_MNT_POINT_MEDIUM,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct fs_littlefs large_data;
|
static u8_t large_read_buffer[LARGE_CACHE_SIZE];
|
||||||
|
static u8_t large_prog_buffer[LARGE_CACHE_SIZE];
|
||||||
|
static u32_t large_lookahead_buffer[LARGE_LOOKAHEAD_SIZE / 4U];
|
||||||
|
static struct fs_littlefs large = {
|
||||||
|
.cfg = {
|
||||||
|
.read_size = LARGE_IO_SIZE,
|
||||||
|
.prog_size = LARGE_IO_SIZE,
|
||||||
|
.cache_size = LARGE_CACHE_SIZE,
|
||||||
|
.lookahead_size = LARGE_LOOKAHEAD_SIZE,
|
||||||
|
.block_size = 32768, /* increase erase size */
|
||||||
|
.read_buffer = large_read_buffer,
|
||||||
|
.prog_buffer = large_prog_buffer,
|
||||||
|
.lookahead_buffer = large_lookahead_buffer,
|
||||||
|
},
|
||||||
|
};
|
||||||
struct fs_mount_t testfs_large_mnt = {
|
struct fs_mount_t testfs_large_mnt = {
|
||||||
.type = FS_LITTLEFS,
|
.type = FS_LITTLEFS,
|
||||||
.fs_data = &large_data,
|
.fs_data = &large,
|
||||||
.storage_dev = (void *)DT_FLASH_AREA_LARGE_ID,
|
.storage_dev = (void *)DT_FLASH_AREA_LARGE_ID,
|
||||||
.mnt_point = TESTFS_MNT_POINT_LARGE,
|
.mnt_point = TESTFS_MNT_POINT_LARGE,
|
||||||
};
|
};
|
||||||
|
|
|
@ -18,6 +18,14 @@ extern struct fs_mount_t testfs_small_mnt;
|
||||||
extern struct fs_mount_t testfs_medium_mnt;
|
extern struct fs_mount_t testfs_medium_mnt;
|
||||||
extern struct fs_mount_t testfs_large_mnt;
|
extern struct fs_mount_t testfs_large_mnt;
|
||||||
|
|
||||||
|
#define MEDIUM_IO_SIZE 64
|
||||||
|
#define MEDIUM_CACHE_SIZE 256
|
||||||
|
#define MEDIUM_LOOKAHEAD_SIZE 64
|
||||||
|
|
||||||
|
#define LARGE_IO_SIZE 256
|
||||||
|
#define LARGE_CACHE_SIZE 1024
|
||||||
|
#define LARGE_LOOKAHEAD_SIZE 128
|
||||||
|
|
||||||
/** Wipe all data from the flash partition associated with the given
|
/** Wipe all data from the flash partition associated with the given
|
||||||
* mount point.
|
* mount point.
|
||||||
*
|
*
|
||||||
|
|
|
@ -21,4 +21,7 @@ void test_lfs_basic(void);
|
||||||
/* Tests in test_lfs_dirops */
|
/* Tests in test_lfs_dirops */
|
||||||
void test_lfs_dirops(void);
|
void test_lfs_dirops(void);
|
||||||
|
|
||||||
|
/* Tests in test_lfs_perf */
|
||||||
|
void test_lfs_perf(void);
|
||||||
|
|
||||||
#endif /* _ZEPHYR_TESTS_SUBSYS_FS_LITTLEFS_TESTFS_TESTS_H_ */
|
#endif /* _ZEPHYR_TESTS_SUBSYS_FS_LITTLEFS_TESTFS_TESTS_H_ */
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue