This is an automated email from the ASF dual-hosted git repository.
xiaoxiang781216 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git
The following commit(s) were added to refs/heads/master by this push:
new 410fdf60bbf fs/vfs: Add CONFIG_FS_UIO to option out vector I/O
410fdf60bbf is described below
commit 410fdf60bbf4f37d56b7c68503c9f39e727b469b
Author: Swatantra Yadav <[email protected]>
AuthorDate: Fri Oct 23 01:48:46 2026 +0530
fs/vfs: Add CONFIG_FS_UIO to option out vector I/O
Provide a hidden Kconfig option CONFIG_FS_UIO (selected by subsystems
such as drivers/serial that implement vector I/O). When disabled,
file_read() and file_write() invoke the underlying driver read/write
operations directly, avoiding struct iovec stack allocations and
omitting fs_uio.c.
POSIX readv() and writev() remain available via read/write fallback
loops and are automatically stripped by the linker (--gc-sections)
when unreferenced, preserving full POSIX compliance while saving
memory on constrained targets.
Signed-off-by: Swatantra Yadav <[email protected]>
---
drivers/serial/Kconfig | 1 +
fs/Kconfig | 3 ++
fs/vfs/CMakeLists.txt | 5 ++-
fs/vfs/Make.defs | 6 ++-
fs/vfs/fs_read.c | 116 +++++++++++++++++++++++++++++++++++++++++++++----
fs/vfs/fs_write.c | 107 +++++++++++++++++++++++++++++++++++++++++----
6 files changed, 218 insertions(+), 20 deletions(-)
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 399c398627c..3b368991099 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -19,6 +19,7 @@ config ARCH_HAVE_8BIT_SERIAL_BUFSIZE
menuconfig SERIAL
bool "Serial Driver Support"
default y
+ select FS_UIO
---help---
Front-end character drivers for chip-specific UARTs. This
provide
some TTY-like functionality and are commonly used (but not
required
diff --git a/fs/Kconfig b/fs/Kconfig
index 2a37d1f30a2..2b58a632dbf 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -17,6 +17,9 @@ config DISABLE_MOUNTPOINT
bool "Disable support for mount points"
default n
+config FS_UIO
+ bool
+
config FS_LARGEFILE
bool "Large File Support"
default n
diff --git a/fs/vfs/CMakeLists.txt b/fs/vfs/CMakeLists.txt
index 9d1d2127c2a..cff84c164c9 100644
--- a/fs/vfs/CMakeLists.txt
+++ b/fs/vfs/CMakeLists.txt
@@ -45,7 +45,6 @@ set(SRCS
fs_stat.c
fs_sendfile.c
fs_statfs.c
- fs_uio.c
fs_unlink.c
fs_write.c
fs_fsync.c
@@ -53,6 +52,10 @@ set(SRCS
fs_truncate.c
fs_link.c)
+if(CONFIG_FS_UIO)
+ list(APPEND SRCS fs_uio.c)
+endif()
+
if(NOT CONFIG_DISABLE_DIRECTORY_OPERATIONS)
list(APPEND SRCS fs_dir.c)
endif()
diff --git a/fs/vfs/Make.defs b/fs/vfs/Make.defs
index 0b2b02bfcf5..89012c6a7bb 100644
--- a/fs/vfs/Make.defs
+++ b/fs/vfs/Make.defs
@@ -26,9 +26,13 @@ CSRCS += fs_chstat.c fs_close.c fs_dup.c fs_dup2.c fs_dup3.c
fs_fcntl.c
CSRCS += fs_epoll.c fs_fchstat.c fs_fstat.c fs_fstatfs.c fs_ioctl.c fs_lseek.c
CSRCS += fs_mkdir.c fs_open.c fs_poll.c fs_pread.c fs_pwrite.c fs_read.c
CSRCS += fs_rename.c fs_rmdir.c fs_select.c fs_sendfile.c fs_stat.c
-CSRCS += fs_statfs.c fs_uio.c fs_unlink.c fs_write.c fs_fsync.c
+CSRCS += fs_statfs.c fs_unlink.c fs_write.c fs_fsync.c
CSRCS += fs_syncfs.c fs_truncate.c fs_link.c
+ifeq ($(CONFIG_FS_UIO),y)
+CSRCS += fs_uio.c
+endif
+
ifneq ($(CONFIG_DISABLE_DIRECTORY_OPERATIONS),y)
CSRCS += fs_dir.c
endif
diff --git a/fs/vfs/fs_read.c b/fs/vfs/fs_read.c
index 0ffc1e9715e..584c043bc86 100644
--- a/fs/vfs/fs_read.c
+++ b/fs/vfs/fs_read.c
@@ -32,6 +32,7 @@
#include <sched.h>
#include <assert.h>
#include <errno.h>
+#include <limits.h>
#include <nuttx/cancelpt.h>
@@ -219,6 +220,7 @@ ssize_t file_readv(FAR struct file *filep,
FS_PROFILE_START(start_time);
+#ifdef CONFIG_FS_UIO
if (inode->u.i_ops->readv)
{
struct uio uio;
@@ -229,7 +231,9 @@ ssize_t file_readv(FAR struct file *filep,
ret = inode->u.i_ops->readv(filep, &uio);
}
}
- else if (inode->u.i_ops->read)
+ else
+#endif
+ if (inode->u.i_ops->read)
{
ret = file_readv_compat(filep, iov, iovcnt);
}
@@ -274,12 +278,82 @@ ssize_t file_readv(FAR struct file *filep,
ssize_t file_read(FAR struct file *filep, FAR void *buf, size_t nbytes)
{
+#ifdef CONFIG_FS_UIO
struct iovec iov;
iov.iov_base = buf;
iov.iov_len = nbytes;
return file_readv(filep, &iov, 1);
+#else
+ FAR struct inode *inode = filep->f_inode;
+ ssize_t ret = -EBADF;
+
+ DEBUGASSERT(filep);
+
+ /* Was this file opened for read access? */
+
+ if ((filep->f_oflags & O_ACCMODE) == O_WRONLY)
+ {
+ /* No.. File is not read-able */
+
+ return -EACCES;
+ }
+
+ if (nbytes == 0)
+ {
+ return 0;
+ }
+
+ if (nbytes > SSIZE_MAX)
+ {
+ return -EINVAL;
+ }
+
+ /* -------------------- DO NOT REMOVE --------------------
+ * Only for kernel builds with CONFIG_ARCH_TEXT_VBASE == 0.
+ * In this case we have to allow the NULL buffer otherwise
+ * kernel builds will fail to load elf binaries found at 0.
+ */
+
+#if !defined(CONFIG_BUILD_KERNEL) || CONFIG_ARCH_TEXT_VBASE != 0
+ if (buf == NULL)
+ {
+ return -EFAULT;
+ }
+#endif
+
+ /* Is a driver or mountpoint registered? If so, does it support the read
+ * method?
+ * If yes, then let it perform the read.
+ */
+
+ if (inode != NULL && inode->u.i_ops)
+ {
+ clock_t start_time;
+
+ FS_PROFILE_START(start_time);
+
+ if (inode->u.i_ops->read)
+ {
+ ret = inode->u.i_ops->read(filep, buf, nbytes);
+ }
+
+ FS_PROFILE_STOP(start_time, g_fs_profile.total_read_time,
+ g_fs_profile.reads);
+ }
+
+ /* Return the number of bytes read (or possibly an error code) */
+
+#ifdef CONFIG_FS_NOTIFY
+ if (ret > 0)
+ {
+ notify_read(filep);
+ }
+#endif
+
+ return ret;
+#endif
}
/****************************************************************************
@@ -348,11 +422,23 @@ ssize_t nx_readv(int fd, FAR const struct iovec *iov, int
iovcnt)
ssize_t nx_read(int fd, FAR void *buf, size_t nbytes)
{
- struct iovec iov;
+ FAR struct file *filep;
+ ssize_t ret;
- iov.iov_base = buf;
- iov.iov_len = nbytes;
- return nx_readv(fd, &iov, 1);
+ /* First, get the file structure. Note that on failure,
+ * file_get() will return the errno.
+ */
+
+ ret = file_get(fd, &filep);
+ if (ret >= 0)
+ {
+ /* Then let file_read do all of the work. */
+
+ ret = file_read(filep, buf, nbytes);
+ file_put(filep);
+ }
+
+ return ret;
}
/****************************************************************************
@@ -412,9 +498,21 @@ ssize_t readv(int fd, FAR const struct iovec *iov, int
iovcnt)
ssize_t read(int fd, FAR void *buf, size_t nbytes)
{
- struct iovec iov;
+ ssize_t ret;
- iov.iov_base = buf;
- iov.iov_len = nbytes;
- return readv(fd, &iov, 1);
+ /* read() is a cancellation point */
+
+ enter_cancellation_point();
+
+ /* Let nx_read() do the real work */
+
+ ret = nx_read(fd, buf, nbytes);
+ if (ret < 0)
+ {
+ set_errno(-ret);
+ ret = ERROR;
+ }
+
+ leave_cancellation_point();
+ return ret;
}
diff --git a/fs/vfs/fs_write.c b/fs/vfs/fs_write.c
index b61483e82fb..399e0c3ceae 100644
--- a/fs/vfs/fs_write.c
+++ b/fs/vfs/fs_write.c
@@ -32,6 +32,7 @@
#include <sched.h>
#include <errno.h>
#include <assert.h>
+#include <limits.h>
#include <nuttx/cancelpt.h>
@@ -192,6 +193,7 @@ ssize_t file_writev(FAR struct file *filep,
FS_PROFILE_START(start_time);
+#ifdef CONFIG_FS_UIO
if (inode->u.i_ops->writev)
{
struct uio uio;
@@ -202,7 +204,9 @@ ssize_t file_writev(FAR struct file *filep,
ret = inode->u.i_ops->writev(filep, &uio);
}
}
- else if (inode->u.i_ops->write)
+ else
+#endif
+ if (inode->u.i_ops->write)
{
ret = file_writev_compat(filep, iov, iovcnt);
}
@@ -249,12 +253,73 @@ ssize_t file_writev(FAR struct file *filep,
ssize_t file_write(FAR struct file *filep, FAR const void *buf,
size_t nbytes)
{
+#ifdef CONFIG_FS_UIO
struct iovec iov;
iov.iov_base = (FAR void *)buf;
iov.iov_len = nbytes;
return file_writev(filep, &iov, 1);
+#else
+ FAR struct inode *inode = filep->f_inode;
+ ssize_t ret = -EBADF;
+
+ DEBUGASSERT(filep);
+
+ /* Was this file opened for write access? */
+
+ if ((filep->f_oflags & O_ACCMODE) == O_RDONLY)
+ {
+ /* No.. File is not writable */
+
+ return -EACCES;
+ }
+
+ if (nbytes == 0)
+ {
+ return 0;
+ }
+
+ if (nbytes > SSIZE_MAX)
+ {
+ return -EINVAL;
+ }
+
+ if (buf == NULL)
+ {
+ return -EFAULT;
+ }
+
+ /* Is a driver registered? Does it support the write method?
+ * If yes, then let the driver perform the write.
+ */
+
+ if (inode != NULL && inode->u.i_ops)
+ {
+ clock_t start_time;
+
+ FS_PROFILE_START(start_time);
+
+ if (inode->u.i_ops->write)
+ {
+ ret = inode->u.i_ops->write(filep, buf, nbytes);
+ }
+
+ FS_PROFILE_STOP(start_time, g_fs_profile.total_write_time,
+ g_fs_profile.writes);
+ }
+
+ /* Return the number of bytes written (or possibly an error code) */
+
+#ifdef CONFIG_FS_NOTIFY
+ if (ret > 0)
+ {
+ notify_write(filep);
+ }
+#endif
+
+ return ret;
+#endif
}
/****************************************************************************
@@ -333,11 +398,23 @@ ssize_t nx_writev(int fd, FAR const struct iovec *iov,
int iovcnt)
ssize_t nx_write(int fd, FAR const void *buf, size_t nbytes)
{
- struct iovec iov;
+ FAR struct file *filep;
+ ssize_t ret;
- iov.iov_base = (void *)buf;
- iov.iov_len = nbytes;
- return nx_writev(fd, &iov, 1);
+ /* First, get the file structure. Note that on failure,
+ * file_get() will return the errno.
+ */
+
+ ret = file_get(fd, &filep);
+ if (ret >= 0)
+ {
+ /* Then let file_write do all of the work. */
+
+ ret = file_write(filep, buf, nbytes);
+ file_put(filep);
+ }
+
+ return ret;
}
/****************************************************************************
@@ -459,9 +536,21 @@ ssize_t writev(int fd, FAR const struct iovec *iov, int
iovcnt)
ssize_t write(int fd, FAR const void *buf, size_t nbytes)
{
- struct iovec iov;
+ ssize_t ret;
- iov.iov_base = (void *)buf;
- iov.iov_len = nbytes;
- return writev(fd, &iov, 1);
+ /* write() is a cancellation point */
+
+ enter_cancellation_point();
+
+ /* Let nx_write() do all of the work */
+
+ ret = nx_write(fd, buf, nbytes);
+ if (ret < 0)
+ {
+ set_errno(-ret);
+ ret = ERROR;
+ }
+
+ leave_cancellation_point();
+ return ret;
}