diff --git a/doc/reference/file_system/index.rst b/doc/reference/file_system/index.rst index 84b9d97603e..2ef9854a450 100644 --- a/doc/reference/file_system/index.rst +++ b/doc/reference/file_system/index.rst @@ -12,13 +12,15 @@ specific API or internal functions by introducing file system registration mechanisms. In Zephyr, any file system implementation or library can be plugged into or -pulled out through a file system registration API. +pulled out through a file system registration API. Each file system +implementation must have a globally unique integer identifier; use +:c:macro:`FS_TYPE_EXTERNAL_BASE` to avoid clashes with in-tree identifiers. .. code-block:: c - int fs_register(enum fs_type type, const struct fs_file_system_t *fs); + int fs_register(int type, const struct fs_file_system_t *fs); - int fs_unregister(enum fs_type type, const struct fs_file_system_t *fs); + int fs_unregister(int type, const struct fs_file_system_t *fs); Zephyr RTOS supports multiple instances of a file system by making use of the mount point as the disk volume name, which is used by the file system library diff --git a/include/fs/fs.h b/include/fs/fs.h index 8f6a001754b..76bf25bd107 100644 --- a/include/fs/fs.h +++ b/include/fs/fs.h @@ -45,12 +45,30 @@ enum fs_dir_entry_type { FS_DIR_ENTRY_DIR }; -enum fs_type { +/** @brief Enumeration to uniquely identify file system types. + * + * Zephyr supports in-tree file systems and external ones. Each + * requires a unique identifier used to register the file system + * implementation and to associate a mount point with the file system + * type. This anonymous enum defines global identifiers for the + * in-tree file systems. + * + * External file systems should be registered using unique identifiers + * starting at @c FS_TYPE_EXTERNAL_BASE. It is the responsibility of + * applications that use external file systems to ensure that these + * identifiers are unique if multiple file system implementations are + * used by the application. + */ +enum { + /** Identifier for in-tree FatFS file system. */ FS_FATFS = 0, - FS_LITTLEFS, - FS_TYPE_END, -}; + /** Identifier for in-tree LittleFS file system. */ + FS_LITTLEFS, + + /** Base identifier for external file systems. */ + FS_TYPE_EXTERNAL_BASE, +}; /** * @brief File system mount info structure @@ -65,7 +83,7 @@ enum fs_type { */ struct fs_mount_t { sys_dnode_t node; - enum fs_type type; + int type; const char *mnt_point; void *fs_data; void *storage_dev; @@ -494,7 +512,7 @@ int fs_statvfs(const char *path, struct fs_statvfs *stat); * @retval 0 Success * @retval -ERRNO errno code if error */ -int fs_register(enum fs_type type, const struct fs_file_system_t *fs); +int fs_register(int type, const struct fs_file_system_t *fs); /** * @brief Unregister a file system @@ -507,7 +525,7 @@ int fs_register(enum fs_type type, const struct fs_file_system_t *fs); * @retval 0 Success * @retval -ERRNO errno code if error */ -int fs_unregister(enum fs_type type, const struct fs_file_system_t *fs); +int fs_unregister(int type, const struct fs_file_system_t *fs); /** * @} diff --git a/subsys/fs/Kconfig b/subsys/fs/Kconfig index 4e96e77283a..dfc93291973 100644 --- a/subsys/fs/Kconfig +++ b/subsys/fs/Kconfig @@ -28,6 +28,14 @@ config FAT_FILESYSTEM_ELM help Use the ELM FAT File system implementation. +config FILE_SYSTEM_MAX_TYPES + int "Maximum number of distinct file system types allowed" + default 2 + help + Zephyr provides several file system types including FatFS and + LittleFS, but it is possible to define additional ones and + register them. A slot is required for each type. + menu "FatFs Settings" visible if FAT_FILESYSTEM_ELM diff --git a/subsys/fs/fs.c b/subsys/fs/fs.c index 6a278c960da..a662fa3d502 100644 --- a/subsys/fs/fs.c +++ b/subsys/fs/fs.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2018 Intel Corporation. + * Copyright (c) 2020 Peter Bigot Consulting, LLC * * SPDX-License-Identifier: Apache-2.0 */ @@ -23,8 +24,57 @@ static sys_dlist_t fs_mnt_list; /* lock to protect mount list operations */ static struct k_mutex mutex; -/* file system map table */ -static const struct fs_file_system_t *fs_map[FS_TYPE_END]; +/* Maps an identifier used in mount points to the file system + * implementation. + */ +struct registry_entry { + int type; + const struct fs_file_system_t *fstp; +}; +static struct registry_entry registry[CONFIG_FILE_SYSTEM_MAX_TYPES]; + +static inline void registry_clear_entry(struct registry_entry *ep) +{ + ep->fstp = NULL; +} + +static int registry_add(int type, + const struct fs_file_system_t *fstp) +{ + int rv = -ENOSPC; + + for (size_t i = 0; i < ARRAY_SIZE(registry); ++i) { + struct registry_entry *ep = ®istry[i]; + + if (ep->fstp == NULL) { + ep->type = type; + ep->fstp = fstp; + rv = 0; + break; + } + } + + return rv; +} + +static struct registry_entry *registry_find(int type) +{ + for (size_t i = 0; i < ARRAY_SIZE(registry); ++i) { + struct registry_entry *ep = ®istry[i]; + + if ((ep->fstp != NULL) && (ep->type == type)) { + return ep; + } + } + return NULL; +} + +static const struct fs_file_system_t *fs_type_get(int type) +{ + struct registry_entry *ep = registry_find(type); + + return (ep != NULL) ? ep->fstp : NULL; +} static int fs_get_mnt_point(struct fs_mount_t **mnt_pntp, const char *name, size_t *match_len) @@ -536,15 +586,15 @@ int fs_mount(struct fs_mount_t *mp) } k_mutex_lock(&mutex, K_FOREVER); - /* Check if requested file system is registered */ - if (mp->type >= FS_TYPE_END || fs_map[mp->type] == NULL) { - LOG_ERR("requested file system not registered!!"); + + /* Get file system information */ + fs = fs_type_get(mp->type); + if (fs == NULL) { + LOG_ERR("requested file system type not registered!!"); rc = -ENOENT; goto mount_err; } - /* Get fs interface from file system map */ - fs = fs_map[mp->type]; mp->mountp_len = strlen(mp->mnt_point); if ((mp->mnt_point[0] != '/') || @@ -664,39 +714,43 @@ int fs_readmount(int *number, const char **name) } /* Register File system */ -int fs_register(enum fs_type type, const struct fs_file_system_t *fs) +int fs_register(int type, const struct fs_file_system_t *fs) { int rc = 0; k_mutex_lock(&mutex, K_FOREVER); - if (type >= FS_TYPE_END) { - LOG_ERR("failed to register File system!!"); - rc = -EINVAL; - goto reg_err; + + if (fs_type_get(type) != NULL) { + rc = -EALREADY; + } else { + rc = registry_add(type, fs); } - fs_map[type] = fs; - LOG_DBG("fs registered of type(%u)", type); -reg_err: + k_mutex_unlock(&mutex); + + LOG_DBG("fs register %d: %d", type, rc); + return rc; } /* Unregister File system */ -int fs_unregister(enum fs_type type, const struct fs_file_system_t *fs) +int fs_unregister(int type, const struct fs_file_system_t *fs) { int rc = 0; + struct registry_entry *ep; k_mutex_lock(&mutex, K_FOREVER); - if ((type >= FS_TYPE_END) || - (fs_map[type] != fs)) { - LOG_ERR("failed to unregister File system!!"); + + ep = registry_find(type); + if ((ep == NULL) || (ep->fstp != fs)) { rc = -EINVAL; - goto unreg_err; + } else { + registry_clear_entry(ep); } - fs_map[type] = NULL; - LOG_DBG("fs unregistered of type(%u)", type); -unreg_err: + k_mutex_unlock(&mutex); + + LOG_DBG("fs unregister %d: %d", type, rc); return rc; }