Explorar el Código

vfs: introduce options to turn off some features

CONFIG_VFS_SUPPORT_IO: for basic I/O functions support
CONFIG_VFS_SUPPORT_DIR: for file/directory functions support
CONFIG_VFS_SUPPORT_SELECT: for select support
Ivan Grokhotkov hace 5 años
padre
commit
a3c0bcb0a0

+ 54 - 1
components/vfs/Kconfig

@@ -1,7 +1,56 @@
 menu "Virtual file system"
 
+    config VFS_SUPPORT_IO
+        bool "Provide basic I/O functions"
+        default y
+        help
+            If enabled, the following functions are provided by the VFS component.
+
+            open, close, read, write, pread, pwrite, lseek, fstat, fsync, ioctl, fcntl
+
+            Filesystem drivers can then be registered to handle these functions
+            for specific paths.
+
+            Disabling this option can save memory when the support for these functions
+            is not required.
+
+    config VFS_SUPPORT_DIR
+        bool "Provide directory related functions"
+        default y
+        # If some filesystem is used, adding I/O support is probably needed and
+        # is not a big overhead, compared to code size of the filesystem,
+        # so make this depend on IO.
+        depends on VFS_SUPPORT_IO
+        help
+            If enabled, the following functions are provided by the VFS component.
+
+            stat, link, unlink, rename, utime, access, truncate, rmdir, mkdir,
+            opendir, closedir, readdir, readdir_r, seekdir, telldir, rewinddir
+
+            Filesystem drivers can then be registered to handle these functions
+            for specific paths.
+
+            Disabling this option can save memory when the support for these functions
+            is not required.
+
+    config VFS_SUPPORT_SELECT
+        bool "Provide select function"
+        default y
+        # Dependency on !LWIP_USE_ONLY_LWIP_SELECT is for compatibility
+        depends on VFS_SUPPORT_IO && !LWIP_USE_ONLY_LWIP_SELECT
+        help
+            If enabled, select function is provided by the VFS component, and can be used
+            on peripheral file descriptors (such as UART) and sockets at the same time.
+
+            If disabled, the default select implementation will be provided by LWIP for
+            sockets only.
+
+            Disabling this option can reduce code size if support for "select" on UART file
+            descriptors is not required.
+
     config VFS_SUPPRESS_SELECT_DEBUG_OUTPUT
         bool "Suppress select() related debug outputs"
+        depends on VFS_SUPPORT_SELECT
         default y
         help
             Select() related functions might produce an unconveniently lot of
@@ -10,12 +59,16 @@ menu "Virtual file system"
             option.
 
     config VFS_SUPPORT_TERMIOS
-        bool "Add support for termios.h"
+        bool "Provide termios.h functions"
         default y
+        # Very likely, only makes sense for UART VFS driver, which itself depends on VFS_SUPPORT_IO
+        depends on VFS_SUPPORT_IO
         help
             Disabling this option can save memory when the support for termios.h is not required.
 
     menu "Host File System I/O (Semihosting)"
+        depends on VFS_SUPPORT_IO
+
         config SEMIHOSTFS_MAX_MOUNT_POINTS
             int "Maximum number of the host filesystem mount points"
             default 1

+ 6 - 18
components/vfs/include/esp_vfs.h

@@ -132,6 +132,7 @@ typedef struct
         int (*fstat_p)(void* ctx, int fd, struct stat * st);                                         /*!< fstat with context pointer */
         int (*fstat)(int fd, struct stat * st);                                                      /*!< fstat without context pointer */
     };
+#ifdef CONFIG_VFS_SUPPORT_DIR
     union {
         int (*stat_p)(void* ctx, const char * path, struct stat * st);                               /*!< stat with context pointer */
         int (*stat)(const char * path, struct stat * st);                                            /*!< stat without context pointer */
@@ -180,6 +181,7 @@ typedef struct
         int (*rmdir_p)(void* ctx, const char* name);                                                /*!< rmdir with context pointer */
         int (*rmdir)(const char* name);                                                             /*!< rmdir without context pointer */
     };
+#endif // CONFIG_VFS_SUPPORT_DIR
     union {
         int (*fcntl_p)(void* ctx, int fd, int cmd, int arg);                                        /*!< fcntl with context pointer */
         int (*fcntl)(int fd, int cmd, int arg);                                                     /*!< fcntl without context pointer */
@@ -192,6 +194,7 @@ typedef struct
         int (*fsync_p)(void* ctx, int fd);                                                          /*!< fsync with context pointer */
         int (*fsync)(int fd);                                                                       /*!< fsync without context pointer */
     };
+#ifdef CONFIG_VFS_SUPPORT_DIR
     union {
         int (*access_p)(void* ctx, const char *path, int amode);                                    /*!< access with context pointer */
         int (*access)(const char *path, int amode);                                                 /*!< access without context pointer */
@@ -204,6 +207,7 @@ typedef struct
         int (*utime_p)(void* ctx, const char *path, const struct utimbuf *times);                   /*!< utime with context pointer */
         int (*utime)(const char *path, const struct utimbuf *times);                                /*!< utime without context pointer */
     };
+#endif // CONFIG_VFS_SUPPORT_DIR
 #ifdef CONFIG_VFS_SUPPORT_TERMIOS
     union {
         int (*tcsetattr_p)(void *ctx, int fd, int optional_actions, const struct termios *p);       /*!< tcsetattr with context pointer */
@@ -234,7 +238,7 @@ typedef struct
         int (*tcsendbreak)(int fd, int duration);                                                   /*!< tcsendbreak without context pointer */
     };
 #endif // CONFIG_VFS_SUPPORT_TERMIOS
-
+#ifdef CONFIG_VFS_SUPPORT_SELECT
     /** start_select is called for setting up synchronous I/O multiplexing of the desired file descriptors in the given VFS */
     esp_err_t (*start_select)(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, esp_vfs_select_sem_t sem, void **end_select_args);
     /** socket select function for socket FDs with the functionality of POSIX select(); this should be set only for the socket VFS */
@@ -247,6 +251,7 @@ typedef struct
     void* (*get_socket_select_semaphore)(void);
     /** get_socket_select_semaphore returns semaphore allocated in the socket driver; set only for the socket driver */
     esp_err_t (*end_select)(void *end_select_args);
+#endif // CONFIG_VFS_SUPPORT_SELECT
 } esp_vfs_t;
 
 
@@ -406,23 +411,6 @@ void esp_vfs_select_triggered(esp_vfs_select_sem_t sem);
  */
 void esp_vfs_select_triggered_isr(esp_vfs_select_sem_t sem, BaseType_t *woken);
 
-/**
- * @brief Implements the VFS layer for synchronous I/O multiplexing by poll()
- *
- * The implementation is based on esp_vfs_select. The parameters and return values are compatible with POSIX poll().
- *
- * @param fds         Pointer to the array containing file descriptors and events poll() should consider.
- * @param nfds        Number of items in the array fds.
- * @param timeout     Poll() should wait at least timeout milliseconds. If the value is 0 then it should return
- *                    immediately. If the value is -1 then it should wait (block) until the event occurs.
- *
- * @return            A positive return value indicates the number of file descriptors that have been selected. The 0
- *                    return value indicates a timed-out poll. -1 is return on failure and errno is set accordingly.
- *
- */
-int esp_vfs_poll(struct pollfd *fds, nfds_t nfds, int timeout);
-
-
 /**
  *
  * @brief Implements the VFS layer of POSIX pread()

+ 67 - 129
components/vfs/vfs.c

@@ -507,6 +507,52 @@ int esp_vfs_fstat(struct _reent *r, int fd, struct stat * st)
     return ret;
 }
 
+int esp_vfs_fcntl_r(struct _reent *r, int fd, int cmd, int arg)
+{
+    const vfs_entry_t* vfs = get_vfs_for_fd(fd);
+    const int local_fd = get_local_fd(vfs, fd);
+    if (vfs == NULL || local_fd < 0) {
+        __errno_r(r) = EBADF;
+        return -1;
+    }
+    int ret;
+    CHECK_AND_CALL(ret, r, vfs, fcntl, local_fd, cmd, arg);
+    return ret;
+}
+
+int esp_vfs_ioctl(int fd, int cmd, ...)
+{
+    const vfs_entry_t* vfs = get_vfs_for_fd(fd);
+    const int local_fd = get_local_fd(vfs, fd);
+    struct _reent* r = __getreent();
+    if (vfs == NULL || local_fd < 0) {
+        __errno_r(r) = EBADF;
+        return -1;
+    }
+    int ret;
+    va_list args;
+    va_start(args, cmd);
+    CHECK_AND_CALL(ret, r, vfs, ioctl, local_fd, cmd, args);
+    va_end(args);
+    return ret;
+}
+
+int esp_vfs_fsync(int fd)
+{
+    const vfs_entry_t* vfs = get_vfs_for_fd(fd);
+    const int local_fd = get_local_fd(vfs, fd);
+    struct _reent* r = __getreent();
+    if (vfs == NULL || local_fd < 0) {
+        __errno_r(r) = EBADF;
+        return -1;
+    }
+    int ret;
+    CHECK_AND_CALL(ret, r, vfs, fsync, local_fd);
+    return ret;
+}
+
+#ifdef CONFIG_VFS_SUPPORT_DIR
+
 int esp_vfs_stat(struct _reent *r, const char * path, struct stat * st)
 {
     const vfs_entry_t* vfs = get_vfs_for_path(path);
@@ -520,6 +566,20 @@ int esp_vfs_stat(struct _reent *r, const char * path, struct stat * st)
     return ret;
 }
 
+int esp_vfs_utime(const char *path, const struct utimbuf *times)
+{
+    int ret;
+    const vfs_entry_t* vfs = get_vfs_for_path(path);
+    struct _reent* r = __getreent();
+    if (vfs == NULL) {
+        __errno_r(r) = ENOENT;
+        return -1;
+    }
+    const char* path_within_vfs = translate_path(vfs, path);
+    CHECK_AND_CALL(ret, r, vfs, utime, path_within_vfs, times);
+    return ret;
+}
+
 int esp_vfs_link(struct _reent *r, const char* n1, const char* n2)
 {
     const vfs_entry_t* vfs = get_vfs_for_path(n1);
@@ -712,50 +772,6 @@ int rmdir(const char* name)
     return ret;
 }
 
-int _fcntl_r(struct _reent *r, int fd, int cmd, int arg)
-{
-    const vfs_entry_t* vfs = get_vfs_for_fd(fd);
-    const int local_fd = get_local_fd(vfs, fd);
-    if (vfs == NULL || local_fd < 0) {
-        __errno_r(r) = EBADF;
-        return -1;
-    }
-    int ret;
-    CHECK_AND_CALL(ret, r, vfs, fcntl, local_fd, cmd, arg);
-    return ret;
-}
-
-int ioctl(int fd, int cmd, ...)
-{
-    const vfs_entry_t* vfs = get_vfs_for_fd(fd);
-    const int local_fd = get_local_fd(vfs, fd);
-    struct _reent* r = __getreent();
-    if (vfs == NULL || local_fd < 0) {
-        __errno_r(r) = EBADF;
-        return -1;
-    }
-    int ret;
-    va_list args;
-    va_start(args, cmd);
-    CHECK_AND_CALL(ret, r, vfs, ioctl, local_fd, cmd, args);
-    va_end(args);
-    return ret;
-}
-
-int fsync(int fd)
-{
-    const vfs_entry_t* vfs = get_vfs_for_fd(fd);
-    const int local_fd = get_local_fd(vfs, fd);
-    struct _reent* r = __getreent();
-    if (vfs == NULL || local_fd < 0) {
-        __errno_r(r) = EBADF;
-        return -1;
-    }
-    int ret;
-    CHECK_AND_CALL(ret, r, vfs, fsync, local_fd);
-    return ret;
-}
-
 int access(const char *path, int amode)
 {
     int ret;
@@ -784,6 +800,10 @@ int truncate(const char *path, off_t length)
     return ret;
 }
 
+#endif // CONFIG_VFS_SUPPORT_DIR
+
+#ifdef CONFIG_VFS_SUPPORT_SELECT
+
 static void call_end_selects(int end_index, const fds_triple_t *vfs_fds_triple, void **driver_args)
 {
     for (int i = 0; i < end_index; ++i) {
@@ -1074,7 +1094,10 @@ void esp_vfs_select_triggered_isr(esp_vfs_select_sem_t sem, BaseType_t *woken)
     }
 }
 
+#endif // CONFIG_VFS_SUPPORT_SELECT
+
 #ifdef CONFIG_VFS_SUPPORT_TERMIOS
+
 int tcgetattr(int fd, struct termios *p)
 {
     const vfs_entry_t* vfs = get_vfs_for_fd(fd);
@@ -1174,95 +1197,10 @@ int tcsendbreak(int fd, int duration)
 }
 #endif // CONFIG_VFS_SUPPORT_TERMIOS
 
-int esp_vfs_utime(const char *path, const struct utimbuf *times)
-{
-    int ret;
-    const vfs_entry_t* vfs = get_vfs_for_path(path);
-    struct _reent* r = __getreent();
-    if (vfs == NULL) {
-        __errno_r(r) = ENOENT;
-        return -1;
-    }
-    const char* path_within_vfs = translate_path(vfs, path);
-    CHECK_AND_CALL(ret, r, vfs, utime, path_within_vfs, times);
-    return ret;
-}
-
-int esp_vfs_poll(struct pollfd *fds, nfds_t nfds, int timeout)
-{
-    struct timeval tv = {
-        // timeout is in milliseconds
-        .tv_sec = timeout / 1000,
-        .tv_usec = (timeout % 1000) * 1000,
-    };
-    int max_fd = -1;
-    fd_set readfds;
-    fd_set writefds;
-    fd_set errorfds;
-    struct _reent* r = __getreent();
-    int ret = 0;
 
-    if (fds == NULL) {
-        __errno_r(r) = ENOENT;
-        return -1;
-    }
 
-    FD_ZERO(&readfds);
-    FD_ZERO(&writefds);
-    FD_ZERO(&errorfds);
 
-    for (int i = 0; i < nfds; ++i) {
-        fds[i].revents = 0;
-
-        if (fds[i].fd < 0) {
-            // revents should remain 0 and events ignored (according to the documentation of poll()).
-            continue;
-        }
-
-        if (fds[i].fd >= MAX_FDS) {
-            fds[i].revents |= POLLNVAL;
-            ++ret;
-            continue;
-        }
 
-        if (fds[i].events & (POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI)) {
-            FD_SET(fds[i].fd, &readfds);
-            FD_SET(fds[i].fd, &errorfds);
-            max_fd = MAX(max_fd, fds[i].fd);
-        }
-
-        if (fds[i].events & (POLLOUT | POLLWRNORM | POLLWRBAND)) {
-            FD_SET(fds[i].fd, &writefds);
-            FD_SET(fds[i].fd, &errorfds);
-            max_fd = MAX(max_fd, fds[i].fd);
-        }
-    }
-
-    const int select_ret = esp_vfs_select(max_fd + 1, &readfds, &writefds, &errorfds, timeout < 0 ? NULL: &tv);
-
-    if (select_ret > 0) {
-        ret += select_ret;
-
-        for (int i = 0; i < nfds; ++i) {
-            if (FD_ISSET(fds[i].fd, &readfds)) {
-                fds[i].revents |= POLLIN;
-            }
-
-            if (FD_ISSET(fds[i].fd, &writefds)) {
-                fds[i].revents |= POLLOUT;
-            }
-
-            if (FD_ISSET(fds[i].fd, &errorfds)) {
-                fds[i].revents |= POLLERR;
-            }
-        }
-    } else {
-        ret = select_ret;
-        // keeping the errno from select()
-    }
-
-    return ret;
-}
 
 void vfs_include_syscalls_impl(void)
 {

+ 8 - 0
components/vfs/vfs_semihost.c

@@ -23,6 +23,14 @@
 #include "freertos/task.h"
 #include "esp_vfs.h"
 
+#ifndef CONFIG_SEMIHOSTFS_MAX_MOUNT_POINTS
+#define CONFIG_SEMIHOSTFS_MAX_MOUNT_POINTS 1
+#endif
+
+#ifndef CONFIG_SEMIHOSTFS_HOST_PATH_MAX_LEN
+#define CONFIG_SEMIHOSTFS_HOST_PATH_MAX_LEN 128
+#endif
+
 #define LOG_LOCAL_LEVEL ESP_LOG_NONE
 #include "esp_log.h"
 const static char *TAG = "esp_semihost";

+ 16 - 0
components/vfs/vfs_uart.c

@@ -116,6 +116,8 @@ static vfs_uart_context_t* s_ctx[UART_NUM] = {
 #endif
 };
 
+#ifdef CONFIG_VFS_SUPPORT_SELECT
+
 typedef struct {
     esp_vfs_select_sem_t select_sem;
     fd_set *readfds;
@@ -132,6 +134,8 @@ static portMUX_TYPE s_registered_select_lock = portMUX_INITIALIZER_UNLOCKED;
 
 static esp_err_t uart_end_select(void *end_select_args);
 
+#endif // CONFIG_VFS_SUPPORT_SELECT
+
 static int uart_open(const char * path, int flags, int mode)
 {
     // this is fairly primitive, we should check if file is opened read only,
@@ -319,6 +323,8 @@ static int uart_fcntl(int fd, int cmd, int arg)
     return result;
 }
 
+#ifdef CONFIG_VFS_SUPPORT_DIR
+
 static int uart_access(const char *path, int amode)
 {
     int ret = -1;
@@ -340,6 +346,8 @@ static int uart_access(const char *path, int amode)
     return ret;
 }
 
+#endif // CONFIG_VFS_SUPPORT_DIR
+
 static int uart_fsync(int fd)
 {
     assert(fd >= 0 && fd < 3);
@@ -349,6 +357,8 @@ static int uart_fsync(int fd)
     return 0;
 }
 
+#ifdef CONFIG_VFS_SUPPORT_SELECT
+
 static esp_err_t register_select(uart_select_args_t *args)
 {
     esp_err_t ret = ESP_ERR_INVALID_ARG;
@@ -509,6 +519,8 @@ static esp_err_t uart_end_select(void *end_select_args)
     return ret;
 }
 
+#endif // CONFIG_VFS_SUPPORT_SELECT
+
 #ifdef CONFIG_VFS_SUPPORT_TERMIOS
 static int uart_tcsetattr(int fd, int optional_actions, const struct termios *p)
 {
@@ -972,9 +984,13 @@ void esp_vfs_dev_uart_register(void)
         .read = &uart_read,
         .fcntl = &uart_fcntl,
         .fsync = &uart_fsync,
+#ifdef CONFIG_VFS_SUPPORT_DIR
         .access = &uart_access,
+#endif // CONFIG_VFS_SUPPORT_DIR
+#ifdef CONFIG_VFS_SUPPORT_SELECT
         .start_select = &uart_start_select,
         .end_select = &uart_end_select,
+#endif // CONFIG_VFS_SUPPORT_SELECT
 #ifdef CONFIG_VFS_SUPPORT_TERMIOS
         .tcsetattr = &uart_tcsetattr,
         .tcgetattr = &uart_tcgetattr,