From 821128f729719e919f9f8047b5293f8e6474dfa4 Mon Sep 17 00:00:00 2001 From: YAMAMOTO Takashi Date: Tue, 17 Sep 2024 15:23:07 +0900 Subject: [PATCH] move readv/writev to the kernel currently, nuttx implements readv/writev on the top of read/write. while it might work for the simplest cases, it's broken by design. for example, it's impossible to make it work correctly for files which need to preserve data boundaries without allocating a single contiguous buffer. (udp socket, some character devices, etc) this change is a start of the migration to a better design. that is, implement read/write on the top of readv/writev. to avoid a single huge change, following things will NOT be done in this commit: * fix actual bugs caused by the original readv-based-on-read design. (cf. https://github.com/apache/nuttx/pull/12674) * adapt filesystems/drivers to actually benefit from the new interface. (except a few trivial examples) * eventually retire the old interface. * retire read/write syscalls. implement them in libc instead. * pread/pwrite/preadv/pwritev (except the introduction of struct uio, which is a preparation to back these variations with the new interface.) --- arch/arm/src/cxd56xx/cxd56_hostif.c | 4 +- drivers/bch/bchdev_driver.c | 4 +- drivers/i2c/i2c_driver.c | 4 +- drivers/i2c/i2c_slave_driver.c | 4 +- drivers/i3c/i3c_driver.c | 4 +- drivers/input/gt9xx.c | 4 +- drivers/lcd/ft80x.c | 4 +- drivers/lcd/pcf8574_lcd_backpack.c | 4 +- drivers/lcd/tda19988.c | 4 +- drivers/loop/loop.c | 27 +-- drivers/misc/dev_null.c | 42 ++--- drivers/misc/dev_zero.c | 57 +++--- drivers/pci/pci_uio_ivshmem.c | 4 +- drivers/pipes/fifo.c | 4 +- drivers/sensors/aht10.c | 4 +- drivers/sensors/hdc1008.c | 4 +- drivers/sensors/scd30.c | 4 +- drivers/sensors/scd41.c | 4 +- drivers/sensors/sgp30.c | 4 +- drivers/sensors/sht21.c | 4 +- drivers/sensors/sht3x.c | 4 +- drivers/sensors/sps30.c | 4 +- drivers/serial/pty.c | 4 +- drivers/serial/serial.c | 4 +- drivers/spi/spi_driver.c | 4 +- drivers/spi/spi_slave_driver.c | 4 +- drivers/timers/rtc.c | 4 +- drivers/video/v4l2_cap.c | 2 + drivers/video/v4l2_core.c | 2 + drivers/virtio/virtio-rng.c | 2 + drivers/virtio/virtio-rpmb.c | 2 + fs/binfs/fs_binfs.c | 2 + fs/cromfs/fs_cromfs.c | 2 + fs/fat/fs_fat32.c | 3 + fs/hostfs/hostfs.c | 2 + fs/littlefs/lfs_vfs.c | 2 + fs/mnemofs/mnemofs.c | 2 + fs/nfs/nfs_vfsops.c | 2 + fs/nxffs/nxffs_initialize.c | 2 + fs/procfs/fs_procfs.c | 2 + fs/romfs/fs_romfs.c | 2 + fs/rpmsgfs/rpmsgfs.c | 2 + fs/shm/shmfs.c | 2 + fs/smartfs/smartfs_smart.c | 2 + fs/spiffs/src/spiffs_vfs.c | 2 + fs/tmpfs/fs_tmpfs.c | 2 + fs/unionfs/fs_unionfs.c | 4 +- fs/userfs/fs_userfs.c | 2 + fs/v9fs/v9fs.c | 2 + fs/vfs/CMakeLists.txt | 1 + fs/vfs/Make.defs | 2 +- fs/vfs/fs_fstat.c | 4 +- fs/vfs/fs_open.c | 4 +- fs/vfs/fs_read.c | 222 ++++++++++++++++++++--- fs/vfs/fs_stat.c | 4 +- fs/vfs/fs_truncate.c | 2 +- fs/vfs/fs_uio.c | 66 +++++++ fs/vfs/fs_write.c | 261 ++++++++++++++++++++++++---- fs/zipfs/zip_vfs.c | 2 + graphics/nxterm/nxterm_driver.c | 8 +- include/nuttx/fs/fs.h | 14 ++ include/nuttx/fs/uio.h | 65 +++++++ include/sys/syscall_lookup.h | 2 + libs/libc/uio/CMakeLists.txt | 2 +- libs/libc/uio/Make.defs | 1 - libs/libc/uio/lib_readv.c | 125 ------------- libs/libc/uio/lib_writev.c | 124 ------------- syscall/syscall.csv | 2 + 68 files changed, 782 insertions(+), 398 deletions(-) create mode 100644 fs/vfs/fs_uio.c create mode 100644 include/nuttx/fs/uio.h delete mode 100644 libs/libc/uio/lib_readv.c delete mode 100644 libs/libc/uio/lib_writev.c diff --git a/arch/arm/src/cxd56xx/cxd56_hostif.c b/arch/arm/src/cxd56xx/cxd56_hostif.c index f37501fb52e..cb1756f60a6 100644 --- a/arch/arm/src/cxd56xx/cxd56_hostif.c +++ b/arch/arm/src/cxd56xx/cxd56_hostif.c @@ -147,7 +147,9 @@ static const struct file_operations g_hif_fops = hif_ioctl, /* ioctl */ NULL, /* mmap */ NULL, /* truncate */ - hif_poll /* poll */ + hif_poll, /* poll */ + NULL, /* readv */ + NULL /* writev */ #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS , hif_unlink /* unlink */ #endif diff --git a/drivers/bch/bchdev_driver.c b/drivers/bch/bchdev_driver.c index 6fbea4e8ec9..3c79652e609 100644 --- a/drivers/bch/bchdev_driver.c +++ b/drivers/bch/bchdev_driver.c @@ -80,7 +80,9 @@ const struct file_operations g_bch_fops = bch_ioctl, /* ioctl */ NULL, /* mmap */ NULL, /* truncate */ - bch_poll /* poll */ + bch_poll, /* poll */ + NULL, /* readv */ + NULL /* writev */ #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS , bch_unlink /* unlink */ #endif diff --git a/drivers/i2c/i2c_driver.c b/drivers/i2c/i2c_driver.c index b80981a49b8..58c5b1089b8 100644 --- a/drivers/i2c/i2c_driver.c +++ b/drivers/i2c/i2c_driver.c @@ -99,7 +99,9 @@ static const struct file_operations g_i2cdrvr_fops = i2cdrvr_ioctl, /* ioctl */ NULL, /* mmap */ NULL, /* truncate */ - NULL /* poll */ + NULL, /* poll */ + NULL, /* readv */ + NULL /* writev */ #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS , i2cdrvr_unlink /* unlink */ #endif diff --git a/drivers/i2c/i2c_slave_driver.c b/drivers/i2c/i2c_slave_driver.c index f5531b7e7c6..c2fd05013ec 100644 --- a/drivers/i2c/i2c_slave_driver.c +++ b/drivers/i2c/i2c_slave_driver.c @@ -134,7 +134,9 @@ static const struct file_operations g_i2cslavefops = NULL, /* ioctl */ NULL, /* mmap */ NULL, /* truncate */ - i2c_slave_poll /* poll */ + i2c_slave_poll, /* poll */ + NULL, /* readv */ + NULL /* writev */ #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS , i2c_slave_unlink /* unlink */ #endif diff --git a/drivers/i3c/i3c_driver.c b/drivers/i3c/i3c_driver.c index 05e013afd71..0bfc860982c 100644 --- a/drivers/i3c/i3c_driver.c +++ b/drivers/i3c/i3c_driver.c @@ -96,7 +96,9 @@ static const struct file_operations g_i3cdrvr_fops = i3cdrvr_ioctl, /* ioctl */ NULL, /* mmap */ NULL, /* truncate */ - NULL /* poll */ + NULL, /* poll */ + NULL, /* readv */ + NULL /* writev */ #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS , i3cdrvr_unlink /* unlink */ #endif diff --git a/drivers/input/gt9xx.c b/drivers/input/gt9xx.c index 42423cd24f2..654cf0aab66 100644 --- a/drivers/input/gt9xx.c +++ b/drivers/input/gt9xx.c @@ -124,7 +124,9 @@ static const struct file_operations g_gt9xx_fileops = NULL, /* ioctl */ NULL, /* truncate */ NULL, /* mmap */ - gt9xx_poll /* poll */ + gt9xx_poll, /* poll */ + NULL, /* readv */ + NULL /* writev */ #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS , NULL /* unlink */ #endif diff --git a/drivers/lcd/ft80x.c b/drivers/lcd/ft80x.c index b17e38cbff3..32f6913e884 100644 --- a/drivers/lcd/ft80x.c +++ b/drivers/lcd/ft80x.c @@ -136,7 +136,9 @@ static const struct file_operations g_ft80x_fops = ft80x_ioctl, /* ioctl */ NULL, /* mmap */ NULL, /* truncate */ - NULL /* poll */ + NULL, /* poll */ + NULL, /* readv */ + NULL /* writev */ #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS , ft80x_unlink /* unlink */ #endif diff --git a/drivers/lcd/pcf8574_lcd_backpack.c b/drivers/lcd/pcf8574_lcd_backpack.c index b4ee2eaece7..62f31a18fab 100644 --- a/drivers/lcd/pcf8574_lcd_backpack.c +++ b/drivers/lcd/pcf8574_lcd_backpack.c @@ -119,7 +119,9 @@ static const struct file_operations g_pcf8574_lcd_fops = pcf8574_lcd_ioctl, /* ioctl */ NULL, /* mmap */ NULL, /* truncate */ - pcf8574_lcd_poll /* poll */ + pcf8574_lcd_poll, /* poll */ + NULL, /* readv */ + NULL /* writev */ #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS , pcf8574_lcd_unlink /* unlink */ #endif diff --git a/drivers/lcd/tda19988.c b/drivers/lcd/tda19988.c index 77d2c147cc7..dd3a023fe7d 100644 --- a/drivers/lcd/tda19988.c +++ b/drivers/lcd/tda19988.c @@ -173,7 +173,9 @@ static const struct file_operations g_tda19988_fops = tda19988_ioctl, /* ioctl */ NULL, /* mmap */ NULL, /* truncate */ - tda19988_poll /* poll */ + tda19988_poll, /* poll */ + NULL, /* readv */ + NULL /* writev */ #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS , tda19988_unlink /* unlink */ #endif diff --git a/drivers/loop/loop.c b/drivers/loop/loop.c index 5b8c068984b..5093f4df0c9 100644 --- a/drivers/loop/loop.c +++ b/drivers/loop/loop.c @@ -38,10 +38,10 @@ * Private Function Prototypes ****************************************************************************/ -static ssize_t loop_read(FAR struct file *filep, FAR char *buffer, - size_t buflen); -static ssize_t loop_write(FAR struct file *filep, FAR const char *buffer, - size_t buflen); +static ssize_t loop_readv(FAR struct file *filep, + FAR const struct uio *uio); +static ssize_t loop_writev(FAR struct file *filep, + FAR const struct uio *uio); static int loop_ioctl(FAR struct file *filep, int cmd, unsigned long arg); @@ -53,10 +53,15 @@ static const struct file_operations g_loop_fops = { NULL, /* open */ NULL, /* close */ - loop_read, /* read */ - loop_write, /* write */ + NULL, /* read */ + NULL, /* write */ NULL, /* seek */ loop_ioctl, /* ioctl */ + NULL, /* mmap */ + NULL, /* truncate */ + NULL, /* poll */ + loop_readv, /* readv */ + loop_writev /* writev */ }; /**************************************************************************** @@ -67,8 +72,8 @@ static const struct file_operations g_loop_fops = * Name: loop_read ****************************************************************************/ -static ssize_t loop_read(FAR struct file *filep, FAR char *buffer, - size_t len) +static ssize_t loop_readv(FAR struct file *filep, + FAR const struct uio *uio) { return 0; /* Return EOF */ } @@ -77,10 +82,10 @@ static ssize_t loop_read(FAR struct file *filep, FAR char *buffer, * Name: loop_write ****************************************************************************/ -static ssize_t loop_write(FAR struct file *filep, FAR const char *buffer, - size_t len) +static ssize_t loop_writev(FAR struct file *filep, + FAR const struct uio *uio) { - return len; /* Say that everything was written */ + return uio_total_len(uio); /* Say that everything was written */ } /**************************************************************************** diff --git a/drivers/misc/dev_null.c b/drivers/misc/dev_null.c index d058d64d3e2..f622463beab 100644 --- a/drivers/misc/dev_null.c +++ b/drivers/misc/dev_null.c @@ -38,10 +38,10 @@ * Private Function Prototypes ****************************************************************************/ -static ssize_t devnull_read(FAR struct file *filep, FAR char *buffer, - size_t buflen); -static ssize_t devnull_write(FAR struct file *filep, FAR const char *buffer, - size_t buflen); +static ssize_t devnull_readv(FAR struct file *filep, + FAR const struct uio *uio); +static ssize_t devnull_writev(FAR struct file *filep, + FAR const struct uio *uio); static int devnull_poll(FAR struct file *filep, FAR struct pollfd *fds, bool setup); @@ -51,15 +51,17 @@ static int devnull_poll(FAR struct file *filep, FAR struct pollfd *fds, static const struct file_operations g_devnull_fops = { - NULL, /* open */ - NULL, /* close */ - devnull_read, /* read */ - devnull_write, /* write */ - NULL, /* seek */ - NULL, /* ioctl */ - NULL, /* mmap */ - NULL, /* truncate */ - devnull_poll /* poll */ + NULL, /* open */ + NULL, /* close */ + NULL, /* read */ + NULL, /* writev */ + NULL, /* seek */ + NULL, /* ioctl */ + NULL, /* mmap */ + NULL, /* truncate */ + devnull_poll, /* poll */ + devnull_readv, /* readv */ + devnull_writev /* writev */ }; /**************************************************************************** @@ -70,12 +72,11 @@ static const struct file_operations g_devnull_fops = * Name: devnull_read ****************************************************************************/ -static ssize_t devnull_read(FAR struct file *filep, FAR char *buffer, - size_t len) +static ssize_t devnull_readv(FAR struct file *filep, + FAR const struct uio *uio) { UNUSED(filep); - UNUSED(buffer); - UNUSED(len); + UNUSED(uio); return 0; /* Return EOF */ } @@ -84,13 +85,12 @@ static ssize_t devnull_read(FAR struct file *filep, FAR char *buffer, * Name: devnull_write ****************************************************************************/ -static ssize_t devnull_write(FAR struct file *filep, FAR const char *buffer, - size_t len) +static ssize_t devnull_writev(FAR struct file *filep, + FAR const struct uio *uio) { UNUSED(filep); - UNUSED(buffer); - return len; /* Say that everything was written */ + return uio_total_len(uio); /* Say that everything was written */ } /**************************************************************************** diff --git a/drivers/misc/dev_zero.c b/drivers/misc/dev_zero.c index 46d0f359838..efc0b23969f 100644 --- a/drivers/misc/dev_zero.c +++ b/drivers/misc/dev_zero.c @@ -38,10 +38,10 @@ * Private Function Prototypes ****************************************************************************/ -static ssize_t devzero_read(FAR struct file *filep, FAR char *buffer, - size_t buflen); -static ssize_t devzero_write(FAR struct file *filep, FAR const char *buffer, - size_t buflen); +static ssize_t devzero_readv(FAR struct file *filep, + FAR const struct uio *uio); +static ssize_t devzero_writev(FAR struct file *filep, + FAR const struct uio *uio); static int devzero_poll(FAR struct file *filep, FAR struct pollfd *fds, bool setup); @@ -51,15 +51,17 @@ static int devzero_poll(FAR struct file *filep, FAR struct pollfd *fds, static const struct file_operations g_devzero_fops = { - NULL, /* open */ - NULL, /* close */ - devzero_read, /* read */ - devzero_write, /* write */ - NULL, /* seek */ - NULL, /* ioctl */ - NULL, /* mmap */ - NULL, /* truncate */ - devzero_poll /* poll */ + NULL, /* open */ + NULL, /* close */ + NULL, /* read */ + NULL, /* write */ + NULL, /* seek */ + NULL, /* ioctl */ + NULL, /* mmap */ + NULL, /* truncate */ + devzero_poll, /* poll */ + devzero_readv, /* readv */ + devzero_writev /* writev */ }; /**************************************************************************** @@ -70,26 +72,39 @@ static const struct file_operations g_devzero_fops = * Name: devzero_read ****************************************************************************/ -static ssize_t devzero_read(FAR struct file *filep, FAR char *buffer, - size_t len) +static ssize_t devzero_readv(FAR struct file *filep, + FAR const struct uio *uio) { + ssize_t total = uio_total_len(uio); + FAR const struct iovec *iov = uio->uio_iov; + int iovcnt = uio->uio_iovcnt; + int i; + UNUSED(filep); - memset(buffer, 0, len); - return len; + if (total < 0) + { + return total; + } + + for (i = 0; i < iovcnt; i++) + { + memset(iov[i].iov_base, 0, iov[i].iov_len); + } + + return total; } /**************************************************************************** * Name: devzero_write ****************************************************************************/ -static ssize_t devzero_write(FAR struct file *filep, FAR const char *buffer, - size_t len) +static ssize_t devzero_writev(FAR struct file *filep, + FAR const struct uio *uio) { UNUSED(filep); - UNUSED(buffer); - return len; + return uio_total_len(uio); } /**************************************************************************** diff --git a/drivers/pci/pci_uio_ivshmem.c b/drivers/pci/pci_uio_ivshmem.c index 54355f96d9a..fd1a87a5a78 100644 --- a/drivers/pci/pci_uio_ivshmem.c +++ b/drivers/pci/pci_uio_ivshmem.c @@ -120,7 +120,9 @@ static const struct file_operations g_uio_ivshmem_fops = NULL, /* ioctl */ uio_ivshmem_mmap, /* mmap */ NULL, /* truncate */ - uio_ivshmem_poll /* poll */ + uio_ivshmem_poll, /* poll */ + NULL, /* readv */ + NULL /* writev */ #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS , NULL /* unlink */ #endif diff --git a/drivers/pipes/fifo.c b/drivers/pipes/fifo.c index 2ff13232e54..b8e296a6765 100644 --- a/drivers/pipes/fifo.c +++ b/drivers/pipes/fifo.c @@ -49,7 +49,9 @@ static const struct file_operations g_fifo_fops = pipecommon_ioctl, /* ioctl */ NULL, /* mmap */ NULL, /* truncate */ - pipecommon_poll /* poll */ + pipecommon_poll, /* poll */ + NULL, /* readv */ + NULL /* writev */ #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS , pipecommon_unlink /* unlink */ #endif diff --git a/drivers/sensors/aht10.c b/drivers/sensors/aht10.c index ccaa68c8c05..fde0e9a8447 100644 --- a/drivers/sensors/aht10.c +++ b/drivers/sensors/aht10.c @@ -118,7 +118,9 @@ static const struct file_operations g_aht10fops = aht10_ioctl, /* ioctl */ NULL, /* mmap */ NULL, /* truncate */ - NULL /* poll */ + NULL, /* poll */ + NULL, /* readv */ + NULL /* writev */ #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS , aht10_unlink /* unlink */ #endif diff --git a/drivers/sensors/hdc1008.c b/drivers/sensors/hdc1008.c index 77c73d1eca9..920f30e8c05 100644 --- a/drivers/sensors/hdc1008.c +++ b/drivers/sensors/hdc1008.c @@ -163,7 +163,9 @@ static const struct file_operations g_hdc1008fops = hdc1008_ioctl, /* ioctl */ NULL, /* mmap */ NULL, /* truncate */ - NULL /* poll */ + NULL, /* poll */ + NULL, /* readv */ + NULL /* writev */ #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS , hdc1008_unlink /* unlink */ #endif diff --git a/drivers/sensors/scd30.c b/drivers/sensors/scd30.c index 906bc1ac115..5cc5a8b5f57 100644 --- a/drivers/sensors/scd30.c +++ b/drivers/sensors/scd30.c @@ -184,7 +184,9 @@ static const struct file_operations g_scd30fops = scd30_ioctl, /* ioctl */ NULL, /* mmap */ NULL, /* truncate */ - NULL /* poll */ + NULL, /* poll */ + NULL, /* readv */ + NULL /* writev */ #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS , scd30_unlink /* unlink */ #endif diff --git a/drivers/sensors/scd41.c b/drivers/sensors/scd41.c index 756c41a3cb6..08a03481c72 100644 --- a/drivers/sensors/scd41.c +++ b/drivers/sensors/scd41.c @@ -192,7 +192,9 @@ static const struct file_operations g_scd41fops = scd41_ioctl, /* ioctl */ NULL, /* mmap */ NULL, /* truncate */ - NULL /* poll */ + NULL, /* poll */ + NULL, /* readv */ + NULL /* writev */ #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS , scd41_unlink /* unlink */ #endif diff --git a/drivers/sensors/sgp30.c b/drivers/sensors/sgp30.c index f82656c3a8e..b84697f1a56 100644 --- a/drivers/sensors/sgp30.c +++ b/drivers/sensors/sgp30.c @@ -161,7 +161,9 @@ static const struct file_operations g_sgp30fops = sgp30_ioctl, /* ioctl */ NULL, /* mmap */ NULL, /* truncate */ - NULL /* poll */ + NULL, /* poll */ + NULL, /* readv */ + NULL /* writev */ #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS , sgp30_unlink /* unlink */ #endif diff --git a/drivers/sensors/sht21.c b/drivers/sensors/sht21.c index 487c90ed1d0..8502e9b9e18 100644 --- a/drivers/sensors/sht21.c +++ b/drivers/sensors/sht21.c @@ -133,7 +133,9 @@ static const struct file_operations g_sht21fops = sht21_ioctl, /* ioctl */ NULL, /* mmap */ NULL, /* truncate */ - NULL /* poll */ + NULL, /* poll */ + NULL, /* readv */ + NULL /* writev */ #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS , sht21_unlink /* unlink */ #endif diff --git a/drivers/sensors/sht3x.c b/drivers/sensors/sht3x.c index 8fc52605f7d..5dbf4369943 100644 --- a/drivers/sensors/sht3x.c +++ b/drivers/sensors/sht3x.c @@ -172,7 +172,9 @@ static const struct file_operations g_sht3xfops = sht3x_ioctl, /* ioctl */ NULL, /* mmap */ NULL, /* truncate */ - NULL /* poll */ + NULL, /* poll */ + NULL, /* readv */ + NULL /* writev */ #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS , sht3x_unlink /* unlink */ #endif diff --git a/drivers/sensors/sps30.c b/drivers/sensors/sps30.c index 7e2c6ba51ba..8d701a3ddcb 100644 --- a/drivers/sensors/sps30.c +++ b/drivers/sensors/sps30.c @@ -177,7 +177,9 @@ static const struct file_operations g_sps30fops = sps30_ioctl, /* ioctl */ NULL, /* mmap */ NULL, /* truncate */ - NULL /* poll */ + NULL, /* poll */ + NULL, /* readv */ + NULL /* writev */ #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS , sps30_unlink /* unlink */ #endif diff --git a/drivers/serial/pty.c b/drivers/serial/pty.c index 92cbd06e5ac..0620979998d 100644 --- a/drivers/serial/pty.c +++ b/drivers/serial/pty.c @@ -136,7 +136,9 @@ static const struct file_operations g_pty_fops = pty_ioctl, /* ioctl */ NULL, /* mmap */ NULL, /* truncate */ - pty_poll /* poll */ + pty_poll, /* poll */ + NULL, /* readv */ + NULL /* writev */ #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS , pty_unlink /* unlink */ #endif diff --git a/drivers/serial/serial.c b/drivers/serial/serial.c index 801b47edcfd..913567d9cc5 100644 --- a/drivers/serial/serial.c +++ b/drivers/serial/serial.c @@ -145,7 +145,9 @@ static const struct file_operations g_serialops = uart_ioctl, /* ioctl */ NULL, /* mmap */ NULL, /* truncate */ - uart_poll /* poll */ + uart_poll, /* poll */ + NULL, /* readv */ + NULL /* writev */ #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS , uart_unlink /* unlink */ #endif diff --git a/drivers/spi/spi_driver.c b/drivers/spi/spi_driver.c index c5e49852f6f..0f812823023 100644 --- a/drivers/spi/spi_driver.c +++ b/drivers/spi/spi_driver.c @@ -99,7 +99,9 @@ static const struct file_operations g_spidrvr_fops = spidrvr_ioctl, /* ioctl */ NULL, /* mmap */ NULL, /* truncate */ - NULL /* poll */ + NULL, /* poll */ + NULL, /* readv */ + NULL /* writev */ #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS , spidrvr_unlink /* unlink */ #endif diff --git a/drivers/spi/spi_slave_driver.c b/drivers/spi/spi_slave_driver.c index a5ef0a9f8ce..50fcec03a29 100644 --- a/drivers/spi/spi_slave_driver.c +++ b/drivers/spi/spi_slave_driver.c @@ -138,7 +138,9 @@ static const struct file_operations g_spislavefops = NULL, /* ioctl */ NULL, /* mmap */ NULL, /* truncate */ - spi_slave_poll /* poll */ + spi_slave_poll, /* poll */ + NULL, /* readv */ + NULL /* writev */ #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS , spi_slave_unlink /* unlink */ #endif diff --git a/drivers/timers/rtc.c b/drivers/timers/rtc.c index 21db78a246f..ec3d87761c3 100644 --- a/drivers/timers/rtc.c +++ b/drivers/timers/rtc.c @@ -131,7 +131,9 @@ static const struct file_operations g_rtc_fops = rtc_ioctl, /* ioctl */ NULL, /* mmap */ NULL, /* truncate */ - NULL /* poll */ + NULL, /* poll */ + NULL, /* readv */ + NULL /* writev */ #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS , rtc_unlink /* unlink */ #endif diff --git a/drivers/video/v4l2_cap.c b/drivers/video/v4l2_cap.c index 3c938c788e5..9f4beda84ab 100644 --- a/drivers/video/v4l2_cap.c +++ b/drivers/video/v4l2_cap.c @@ -351,6 +351,8 @@ static const struct file_operations g_capture_fops = capture_mmap, /* mmap */ NULL, /* truncate */ capture_poll, /* poll */ + NULL, /* readv */ + NULL, /* writev */ #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS capture_unlink, /* unlink */ #endif diff --git a/drivers/video/v4l2_core.c b/drivers/video/v4l2_core.c index 674308daaef..505383d6735 100644 --- a/drivers/video/v4l2_core.c +++ b/drivers/video/v4l2_core.c @@ -65,6 +65,8 @@ static const struct file_operations g_v4l2_fops = v4l2_mmap, /* mmap */ NULL, /* truncate */ v4l2_poll, /* poll */ + NULL, /* readv */ + NULL, /* writev */ #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS v4l2_unlink, /* unlink */ #endif diff --git a/drivers/virtio/virtio-rng.c b/drivers/virtio/virtio-rng.c index a3e4501e7be..0cacc86a420 100644 --- a/drivers/virtio/virtio-rng.c +++ b/drivers/virtio/virtio-rng.c @@ -91,6 +91,8 @@ static const struct file_operations g_virtio_rng_ops = NULL, /* mmap */ NULL, /* truncate */ NULL, /* poll */ + NULL, /* readv */ + NULL, /* writev */ #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS NULL, /* unlink */ #endif diff --git a/drivers/virtio/virtio-rpmb.c b/drivers/virtio/virtio-rpmb.c index f855ad063cf..a7c2d5a0cfc 100644 --- a/drivers/virtio/virtio-rpmb.c +++ b/drivers/virtio/virtio-rpmb.c @@ -90,6 +90,8 @@ static const struct file_operations g_virtio_rpmb_ops = NULL, /* mmap */ NULL, /* truncate */ NULL, /* poll */ + NULL, /* readv */ + NULL, /* writev */ #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS NULL, /* unlink */ #endif diff --git a/fs/binfs/fs_binfs.c b/fs/binfs/fs_binfs.c index c66d5ec0669..945ede5c985 100644 --- a/fs/binfs/fs_binfs.c +++ b/fs/binfs/fs_binfs.c @@ -114,6 +114,8 @@ const struct mountpt_operations g_binfs_operations = NULL, /* mmap */ NULL, /* truncate */ NULL, /* poll */ + NULL, /* readv */ + NULL, /* writev */ NULL, /* sync */ binfs_dup, /* dup */ diff --git a/fs/cromfs/fs_cromfs.c b/fs/cromfs/fs_cromfs.c index 831ef50c6c8..d30fa8ccac4 100644 --- a/fs/cromfs/fs_cromfs.c +++ b/fs/cromfs/fs_cromfs.c @@ -194,6 +194,8 @@ const struct mountpt_operations g_cromfs_operations = NULL, /* mmap */ NULL, /* truncate */ NULL, /* poll */ + NULL, /* readv */ + NULL, /* writev */ NULL, /* sync */ cromfs_dup, /* dup */ diff --git a/fs/fat/fs_fat32.c b/fs/fat/fs_fat32.c index ff641225f6c..cc7f4d96964 100644 --- a/fs/fat/fs_fat32.c +++ b/fs/fat/fs_fat32.c @@ -134,6 +134,9 @@ const struct mountpt_operations g_fat_operations = NULL, /* mmap */ fat_truncate, /* truncate */ NULL, /* poll */ + NULL, /* readv */ + NULL, /* writev */ + fat_sync, /* sync */ fat_dup, /* dup */ fat_fstat, /* fstat */ diff --git a/fs/hostfs/hostfs.c b/fs/hostfs/hostfs.c index 20a4d91fd7f..e1c693ef041 100644 --- a/fs/hostfs/hostfs.c +++ b/fs/hostfs/hostfs.c @@ -150,6 +150,8 @@ const struct mountpt_operations g_hostfs_operations = NULL, /* mmap */ hostfs_ftruncate, /* ftruncate */ NULL, /* poll */ + NULL, /* readv */ + NULL, /* writev */ hostfs_sync, /* sync */ hostfs_dup, /* dup */ diff --git a/fs/littlefs/lfs_vfs.c b/fs/littlefs/lfs_vfs.c index f5a8866cbd6..ff61509399e 100644 --- a/fs/littlefs/lfs_vfs.c +++ b/fs/littlefs/lfs_vfs.c @@ -172,6 +172,8 @@ const struct mountpt_operations g_littlefs_operations = NULL, /* mmap */ littlefs_truncate, /* truncate */ NULL, /* poll */ + NULL, /* readv */ + NULL, /* writev */ littlefs_sync, /* sync */ littlefs_dup, /* dup */ diff --git a/fs/mnemofs/mnemofs.c b/fs/mnemofs/mnemofs.c index 5ec61da9955..2dc5838f258 100644 --- a/fs/mnemofs/mnemofs.c +++ b/fs/mnemofs/mnemofs.c @@ -189,6 +189,8 @@ const struct mountpt_operations g_mnemofs_operations = NULL, /* mmap */ mnemofs_truncate, /* truncate */ NULL, /* poll */ + NULL, /* readv */ + NULL, /* writev */ mnemofs_sync, /* sync */ mnemofs_dup, /* dup */ diff --git a/fs/nfs/nfs_vfsops.c b/fs/nfs/nfs_vfsops.c index 5269553fd63..2d0e1af9394 100644 --- a/fs/nfs/nfs_vfsops.c +++ b/fs/nfs/nfs_vfsops.c @@ -203,6 +203,8 @@ const struct mountpt_operations g_nfs_operations = NULL, /* mmap */ nfs_truncate, /* truncate */ NULL, /* poll */ + NULL, /* readv */ + NULL, /* writev */ nfs_sync, /* sync */ nfs_dup, /* dup */ diff --git a/fs/nxffs/nxffs_initialize.c b/fs/nxffs/nxffs_initialize.c index a9e222da8c6..3878326c7a5 100644 --- a/fs/nxffs/nxffs_initialize.c +++ b/fs/nxffs/nxffs_initialize.c @@ -64,6 +64,8 @@ const struct mountpt_operations g_nxffs_operations = NULL, /* truncate */ #endif NULL, /* poll */ + NULL, /* readv */ + NULL, /* writev */ NULL, /* sync -- No buffered data */ nxffs_dup, /* dup */ diff --git a/fs/procfs/fs_procfs.c b/fs/procfs/fs_procfs.c index d2a258075b0..b820d7275e4 100644 --- a/fs/procfs/fs_procfs.c +++ b/fs/procfs/fs_procfs.c @@ -294,6 +294,8 @@ const struct mountpt_operations g_procfs_operations = NULL, /* mmap */ NULL, /* truncate */ procfs_poll, /* poll */ + NULL, /* readv */ + NULL, /* writev */ NULL, /* sync */ procfs_dup, /* dup */ diff --git a/fs/romfs/fs_romfs.c b/fs/romfs/fs_romfs.c index f76bdeda156..9ee971b3da2 100644 --- a/fs/romfs/fs_romfs.c +++ b/fs/romfs/fs_romfs.c @@ -127,6 +127,8 @@ const struct mountpt_operations g_romfs_operations = romfs_mmap, /* mmap */ NULL, /* truncate */ NULL, /* poll */ + NULL, /* readv */ + NULL, /* writev */ NULL, /* sync */ romfs_dup, /* dup */ diff --git a/fs/rpmsgfs/rpmsgfs.c b/fs/rpmsgfs/rpmsgfs.c index 2562aa8bc20..e3674dcb07f 100644 --- a/fs/rpmsgfs/rpmsgfs.c +++ b/fs/rpmsgfs/rpmsgfs.c @@ -167,6 +167,8 @@ const struct mountpt_operations g_rpmsgfs_operations = NULL, /* mmap */ rpmsgfs_truncate, /* truncate */ NULL, /* poll */ + NULL, /* readv */ + NULL, /* writev */ rpmsgfs_sync, /* sync */ rpmsgfs_dup, /* dup */ diff --git a/fs/shm/shmfs.c b/fs/shm/shmfs.c index 264d684a064..752e2d5dacd 100644 --- a/fs/shm/shmfs.c +++ b/fs/shm/shmfs.c @@ -73,6 +73,8 @@ const struct file_operations g_shmfs_operations = shmfs_mmap, /* mmap */ shmfs_truncate, /* truncate */ NULL, /* poll */ + NULL, /* readv */ + NULL, /* writev */ #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS shmfs_unlink /* unlink */ #endif diff --git a/fs/smartfs/smartfs_smart.c b/fs/smartfs/smartfs_smart.c index 4de0049cd04..2317f967cd5 100644 --- a/fs/smartfs/smartfs_smart.c +++ b/fs/smartfs/smartfs_smart.c @@ -147,6 +147,8 @@ const struct mountpt_operations g_smartfs_operations = NULL, /* mmap */ smartfs_truncate, /* truncate */ NULL, /* poll */ + NULL, /* readv */ + NULL, /* writev */ smartfs_sync, /* sync */ smartfs_dup, /* dup */ diff --git a/fs/spiffs/src/spiffs_vfs.c b/fs/spiffs/src/spiffs_vfs.c index 053f283890d..240533cecab 100644 --- a/fs/spiffs/src/spiffs_vfs.c +++ b/fs/spiffs/src/spiffs_vfs.c @@ -144,6 +144,8 @@ const struct mountpt_operations g_spiffs_operations = NULL, /* mmap */ spiffs_truncate, /* truncate */ NULL, /* poll */ + NULL, /* readv */ + NULL, /* writev */ spiffs_sync, /* sync */ spiffs_dup, /* dup */ diff --git a/fs/tmpfs/fs_tmpfs.c b/fs/tmpfs/fs_tmpfs.c index e4976b5ac6e..58c39175e0b 100644 --- a/fs/tmpfs/fs_tmpfs.c +++ b/fs/tmpfs/fs_tmpfs.c @@ -190,6 +190,8 @@ const struct mountpt_operations g_tmpfs_operations = tmpfs_mmap, /* mmap */ tmpfs_truncate, /* truncate */ NULL, /* poll */ + NULL, /* readv */ + NULL, /* writev */ tmpfs_sync, /* sync */ tmpfs_dup, /* dup */ diff --git a/fs/unionfs/fs_unionfs.c b/fs/unionfs/fs_unionfs.c index 77850a44523..c920b83b975 100644 --- a/fs/unionfs/fs_unionfs.c +++ b/fs/unionfs/fs_unionfs.c @@ -232,7 +232,9 @@ const struct mountpt_operations g_unionfs_operations = unionfs_ioctl, /* ioctl */ NULL, /* mmap */ unionfs_truncate, /* truncate */ - NULL, /* pool */ + NULL, /* poll */ + NULL, /* readv */ + NULL, /* writev */ unionfs_sync, /* sync */ unionfs_dup, /* dup */ diff --git a/fs/userfs/fs_userfs.c b/fs/userfs/fs_userfs.c index c53193701d6..8386cc8b623 100644 --- a/fs/userfs/fs_userfs.c +++ b/fs/userfs/fs_userfs.c @@ -167,6 +167,8 @@ const struct mountpt_operations g_userfs_operations = NULL, /* mmap */ userfs_truncate, /* truncate */ NULL, /* poll */ + NULL, /* readv */ + NULL, /* writev */ userfs_sync, /* sync */ userfs_dup, /* dup */ diff --git a/fs/v9fs/v9fs.c b/fs/v9fs/v9fs.c index 0a73ad9250e..1b877a4cca1 100644 --- a/fs/v9fs/v9fs.c +++ b/fs/v9fs/v9fs.c @@ -128,6 +128,8 @@ const struct mountpt_operations g_v9fs_operations = NULL, /* mmap */ v9fs_vfs_truncate, /* truncate */ NULL, /* poll */ + NULL, /* readv */ + NULL, /* writev */ v9fs_vfs_sync, /* sync */ v9fs_vfs_dup, /* dup */ diff --git a/fs/vfs/CMakeLists.txt b/fs/vfs/CMakeLists.txt index 0484484cdf1..c81e615b7ce 100644 --- a/fs/vfs/CMakeLists.txt +++ b/fs/vfs/CMakeLists.txt @@ -44,6 +44,7 @@ set(SRCS fs_stat.c fs_sendfile.c fs_statfs.c + fs_uio.c fs_unlink.c fs_write.c fs_dir.c diff --git a/fs/vfs/Make.defs b/fs/vfs/Make.defs index 6c3ed154692..30292d787fa 100644 --- a/fs/vfs/Make.defs +++ b/fs/vfs/Make.defs @@ -26,7 +26,7 @@ CSRCS += fs_chstat.c fs_close.c fs_dup.c fs_dup2.c fs_fcntl.c fs_epoll.c CSRCS += 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_unlink.c fs_write.c fs_dir.c fs_fsync.c +CSRCS += fs_statfs.c fs_uio.c fs_unlink.c fs_write.c fs_dir.c fs_fsync.c CSRCS += fs_syncfs.c fs_truncate.c # Certain interfaces are not available if there is no mountpoint support diff --git a/fs/vfs/fs_fstat.c b/fs/vfs/fs_fstat.c index 76902598f8f..c4585a79ac1 100644 --- a/fs/vfs/fs_fstat.c +++ b/fs/vfs/fs_fstat.c @@ -112,12 +112,12 @@ static int proxy_fstat(FAR struct file *filep, FAR struct inode *inode, { memset(buf, 0, sizeof(struct stat)); buf->st_mode = S_IFBLK; - if (inode->u.i_ops->read) + if (inode->u.i_ops->readv || inode->u.i_ops->read) { buf->st_mode |= S_IROTH | S_IRGRP | S_IRUSR; } - if (inode->u.i_ops->write) + if (inode->u.i_ops->writev || inode->u.i_ops->read) { buf->st_mode |= S_IWOTH | S_IWGRP | S_IWUSR; } diff --git a/fs/vfs/fs_open.c b/fs/vfs/fs_open.c index 9add7c1b719..83f1eb279b4 100644 --- a/fs/vfs/fs_open.c +++ b/fs/vfs/fs_open.c @@ -81,8 +81,8 @@ static int inode_checkflags(FAR struct inode *inode, int oflags) return -ENXIO; } - if (((oflags & O_RDOK) != 0 && !ops->read && !ops->ioctl) || - ((oflags & O_WROK) != 0 && !ops->write && !ops->ioctl)) + if (((oflags & O_RDOK) != 0 && !ops->readv && !ops->read && !ops->ioctl) || + ((oflags & O_WROK) != 0 && !ops->writev && !ops->write && !ops->ioctl)) { return -EACCES; } diff --git a/fs/vfs/fs_read.c b/fs/vfs/fs_read.c index 2c794bab307..ac06448cfd6 100644 --- a/fs/vfs/fs_read.c +++ b/fs/vfs/fs_read.c @@ -38,16 +38,89 @@ #include "notify/notify.h" #include "inode/inode.h" +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: file_readv_compat + * + * Description: + * Emulate readv using file_operation::read. + * + ****************************************************************************/ + +static ssize_t file_readv_compat(FAR struct file *filep, + FAR const struct uio *uio) +{ + FAR const struct iovec *iov = uio->uio_iov; + int iovcnt = uio->uio_iovcnt; + FAR struct inode *inode = filep->f_inode; + ssize_t ntotal; + ssize_t nread; + size_t remaining; + FAR uint8_t *buffer; + int i; + + DEBUGASSERT(inode->u.i_ops->read != NULL); + + /* Process each entry in the struct iovec array */ + + for (i = 0, ntotal = 0; i < iovcnt; i++) + { + /* Ignore zero-length reads */ + + if (iov[i].iov_len > 0) + { + buffer = iov[i].iov_base; + remaining = iov[i].iov_len; + + /* Read repeatedly as necessary to fill buffer */ + + do + { + nread = inode->u.i_ops->read(filep, (void *)buffer, + remaining); + + /* Check for a read error */ + + if (nread < 0) + { + return ntotal ? ntotal : nread; + } + + /* Check for an end-of-file condition */ + + else if (nread == 0) + { + return ntotal; + } + + /* Update pointers and counts in order to handle partial + * buffer reads. + */ + + buffer += nread; + remaining -= nread; + ntotal += nread; + } + while (remaining > 0); + } + } + + return ntotal; +} + /**************************************************************************** * Public Functions ****************************************************************************/ /**************************************************************************** - * Name: file_read + * Name: file_readv * * Description: - * file_read() is an internal OS interface. It is functionally similar to - * the standard read() interface except: + * file_readv() is an internal OS interface. It is functionally similar to + * the standard readv() interface except: * * - It does not modify the errno variable, * - It is not a cancellation point, @@ -55,8 +128,7 @@ * * Input Parameters: * filep - File structure instance - * buf - User-provided to save the data - * nbytes - The maximum size of the user-provided buffer + * uio - User buffer information * * Returned Value: * The positive non-zero number of bytes read on success, 0 on if an @@ -64,7 +136,7 @@ * ****************************************************************************/ -ssize_t file_read(FAR struct file *filep, FAR void *buf, size_t nbytes) +ssize_t file_readv(FAR struct file *filep, FAR const struct uio *uio) { FAR struct inode *inode; ssize_t ret = -EBADF; @@ -83,18 +155,21 @@ ssize_t file_read(FAR struct file *filep, FAR void *buf, size_t nbytes) /* Is a driver or mountpoint registered? If so, does it support the read * method? + * If yes, then let it perform the read. NOTE that for the case of the + * mountpoint, we depend on the read methods being identical in + * signature and position in the operations vtable. */ - else if (inode != NULL && inode->u.i_ops && inode->u.i_ops->read) + else if (inode != NULL && inode->u.i_ops) { - /* Yes.. then let it perform the read. NOTE that for the case of the - * mountpoint, we depend on the read methods being identical in - * signature and position in the operations vtable. - */ - - ret = inode->u.i_ops->read(filep, - (FAR char *)buf, - (size_t)nbytes); + if (inode->u.i_ops->readv) + { + ret = inode->u.i_ops->readv(filep, uio); + } + else if (inode->u.i_ops->read) + { + ret = file_readv_compat(filep, uio); + } } /* Return the number of bytes read (or possibly an error code) */ @@ -110,19 +185,53 @@ ssize_t file_read(FAR struct file *filep, FAR void *buf, size_t nbytes) } /**************************************************************************** - * Name: nx_read + * Name: file_read * * Description: - * nx_read() is an internal OS interface. It is functionally similar to + * file_read() is an internal OS interface. It is functionally similar to * the standard read() interface except: * + * - It does not modify the errno variable, + * - It is not a cancellation point, + * - It accepts a file structure instance instead of file descriptor. + * + * Input Parameters: + * filep - File structure instance + * buf - User-provided to save the data + * nbytes - The maximum size of the user-provided buffer + * + * Returned Value: + * The positive non-zero number of bytes read on success, 0 on if an + * end-of-file condition, or a negated errno value on any failure. + * + ****************************************************************************/ + +ssize_t file_read(FAR struct file *filep, FAR void *buf, size_t nbytes) +{ + struct iovec iov; + struct uio uio; + + iov.iov_base = buf; + iov.iov_len = nbytes; + uio.uio_iov = &iov; + uio.uio_iovcnt = 1; + return file_readv(filep, &uio); +} + +/**************************************************************************** + * Name: nx_readv + * + * Description: + * nx_readv() is an internal OS interface. It is functionally similar to + * the standard readv() interface except: + * * - It does not modify the errno variable, and * - It is not a cancellation point. * * Input Parameters: * fd - File descriptor to read from - * buf - User-provided to save the data - * nbytes - The maximum size of the user-provided buffer + * iov - User-provided iovec to save the data + * iovcnt - The number of iovec * * Returned Value: * The positive non-zero number of bytes read on success, 0 on if an @@ -130,8 +239,9 @@ ssize_t file_read(FAR struct file *filep, FAR void *buf, size_t nbytes) * ****************************************************************************/ -ssize_t nx_read(int fd, FAR void *buf, size_t nbytes) +ssize_t nx_readv(int fd, FAR const struct iovec *iov, int iovcnt) { + struct uio uio; FAR struct file *filep; ssize_t ret; @@ -147,16 +257,22 @@ ssize_t nx_read(int fd, FAR void *buf, size_t nbytes) /* Then let file_read do all of the work. */ - ret = file_read(filep, buf, nbytes); + uio.uio_iov = iov; + uio.uio_iovcnt = iovcnt; + ret = file_readv(filep, &uio); fs_putfilep(filep); return ret; } /**************************************************************************** - * Name: read + * Name: nx_read * * Description: - * The standard, POSIX read interface. + * nx_read() is an internal OS interface. It is functionally similar to + * the standard read() interface except: + * + * - It does not modify the errno variable, and + * - It is not a cancellation point. * * Input Parameters: * fd - File descriptor to read from @@ -165,21 +281,47 @@ ssize_t nx_read(int fd, FAR void *buf, size_t nbytes) * * Returned Value: * The positive non-zero number of bytes read on success, 0 on if an + * end-of-file condition, or a negated errno value on any failure. + * + ****************************************************************************/ + +ssize_t nx_read(int fd, FAR void *buf, size_t nbytes) +{ + struct iovec iov; + + iov.iov_base = buf; + iov.iov_len = nbytes; + return nx_readv(fd, &iov, 1); +} + +/**************************************************************************** + * Name: readv + * + * Description: + * The standard, POSIX read interface. + * + * Input Parameters: + * fd - File descriptor to read from + * iov - User-provided iovec to save the data + * iovcnt - The number of iovec + * + * Returned Value: + * The positive non-zero number of bytes read on success, 0 on if an * end-of-file condition, or -1 on failure with errno set appropriately. * ****************************************************************************/ -ssize_t read(int fd, FAR void *buf, size_t nbytes) +ssize_t readv(int fd, FAR const struct iovec *iov, int iovcnt) { ssize_t ret; - /* read() is a cancellation point */ + /* readv() is a cancellation point */ enter_cancellation_point(); - /* Let nx_read() do the real work */ + /* Let nx_readv() do the real work */ - ret = nx_read(fd, buf, nbytes); + ret = nx_readv(fd, iov, iovcnt); if (ret < 0) { set_errno(-ret); @@ -189,3 +331,29 @@ ssize_t read(int fd, FAR void *buf, size_t nbytes) leave_cancellation_point(); return ret; } + +/**************************************************************************** + * Name: read + * + * Description: + * The standard, POSIX read interface. + * + * Input Parameters: + * fd - File descriptor to read from + * buf - User-provided to save the data + * nbytes - The maximum size of the user-provided buffer + * + * Returned Value: + * The positive non-zero number of bytes read on success, 0 on if an + * end-of-file condition, or -1 on failure with errno set appropriately. + * + ****************************************************************************/ + +ssize_t read(int fd, FAR void *buf, size_t nbytes) +{ + struct iovec iov; + + iov.iov_base = buf; + iov.iov_len = nbytes; + return readv(fd, &iov, 1); +} diff --git a/fs/vfs/fs_stat.c b/fs/vfs/fs_stat.c index 052c89d2573..e956fd1f9eb 100644 --- a/fs/vfs/fs_stat.c +++ b/fs/vfs/fs_stat.c @@ -381,12 +381,12 @@ int inode_stat(FAR struct inode *inode, FAR struct stat *buf, int resolve) * and write methods. */ - if (inode->u.i_ops->read) + if (inode->u.i_ops->readv || inode->u.i_ops->read) { buf->st_mode = S_IROTH | S_IRGRP | S_IRUSR; } - if (inode->u.i_ops->write) + if (inode->u.i_ops->writev || inode->u.i_ops->write) { buf->st_mode |= S_IWOTH | S_IWGRP | S_IWUSR; } diff --git a/fs/vfs/fs_truncate.c b/fs/vfs/fs_truncate.c index 72eb5728627..d27d30e02a3 100644 --- a/fs/vfs/fs_truncate.c +++ b/fs/vfs/fs_truncate.c @@ -84,7 +84,7 @@ int file_truncate(FAR struct file *filep, off_t length) * possible not the only indicator -- sufficient, but not necessary") */ - if (inode->u.i_ops->write == NULL) + if (inode->u.i_ops->writev == NULL && inode->u.i_ops->write == NULL) { fwarn("WARNING: File system is read-only\n"); return -EROFS; diff --git a/fs/vfs/fs_uio.c b/fs/vfs/fs_uio.c new file mode 100644 index 00000000000..455d0219610 --- /dev/null +++ b/fs/vfs/fs_uio.c @@ -0,0 +1,66 @@ +/**************************************************************************** + * fs/vfs/fs_uio.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include + +#include +#include + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: uio_total_len + * + * Description: + * Return the total length of data in bytes. + * Or -EOVERFLOW. + * + ****************************************************************************/ + +ssize_t uio_total_len(FAR const struct uio *uio) +{ + const struct iovec *iov = uio->uio_iov; + int iovcnt = uio->uio_iovcnt; + size_t len = 0; + int i; + + for (i = 0; i < iovcnt; i++) + { + if (SSIZE_MAX - len < iov[i].iov_len) + { + return -EOVERFLOW; + } + + len += iov[i].iov_len; + } + + return len; +} diff --git a/fs/vfs/fs_write.c b/fs/vfs/fs_write.c index 3c2a5e361b8..b4ff694e1ef 100644 --- a/fs/vfs/fs_write.c +++ b/fs/vfs/fs_write.c @@ -38,17 +38,83 @@ #include "notify/notify.h" #include "inode/inode.h" +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: file_writev_compat + * + * Description: + * Emulate writev using file_operation::write. + * + ****************************************************************************/ + +static ssize_t file_writev_compat(FAR struct file *filep, + FAR const struct uio *uio) +{ + FAR const struct iovec *iov = uio->uio_iov; + int iovcnt = uio->uio_iovcnt; + FAR struct inode *inode = filep->f_inode; + ssize_t ntotal; + ssize_t nwritten; + size_t remaining; + FAR uint8_t *buffer; + int i; + + DEBUGASSERT(inode->u.i_ops->write != NULL); + + /* Process each entry in the struct iovec array */ + + for (i = 0, ntotal = 0; i < iovcnt; i++) + { + /* Ignore zero-length writes */ + + if (iov[i].iov_len > 0) + { + buffer = iov[i].iov_base; + remaining = iov[i].iov_len; + + /* Write repeatedly as necessary to write the entire buffer */ + + do + { + nwritten = inode->u.i_ops->write(filep, (void *)buffer, + remaining); + + /* Check for a write error */ + + if (nwritten < 0) + { + return ntotal ? ntotal : nwritten; + } + + /* Update pointers and counts in order to handle partial + * buffer writes. + */ + + buffer += nwritten; + remaining -= nwritten; + ntotal += nwritten; + } + while (remaining > 0); + } + } + + return ntotal; +} + /**************************************************************************** * Public Functions ****************************************************************************/ /**************************************************************************** - * Name: file_write + * Name: file_writev * * Description: - * Equivalent to the standard write() function except that is accepts a + * Equivalent to the standard writev() function except that is accepts a * struct file instance instead of a file descriptor. It is functionally - * equivalent to write() except that in addition to the differences in + * equivalent to writev() except that in addition to the differences in * input parameters: * * - It does not modify the errno variable, @@ -56,8 +122,7 @@ * * Input Parameters: * filep - Instance of struct file to use with the write - * buf - Data to write - * nbytes - Length of data to write + * uio - User buffer information * * Returned Value: * On success, the number of bytes written are returned (zero indicates @@ -67,11 +132,10 @@ * ****************************************************************************/ -ssize_t file_write(FAR struct file *filep, FAR const void *buf, - size_t nbytes) +ssize_t file_writev(FAR struct file *filep, FAR const struct uio *uio) { FAR struct inode *inode; - ssize_t ret; + ssize_t ret = -EBADF; /* Was this file opened for write access? */ @@ -80,17 +144,23 @@ ssize_t file_write(FAR struct file *filep, FAR const void *buf, return -EACCES; } - /* Is a driver registered? Does it support the write method? */ + /* Is a driver registered? Does it support the write method? + * If yes, then let the driver perform the write. + */ inode = filep->f_inode; - if (!inode || !inode->u.i_ops || !inode->u.i_ops->write) + if (inode != NULL && inode->u.i_ops) { - return -EBADF; + if (inode->u.i_ops->writev) + { + ret = inode->u.i_ops->writev(filep, uio); + } + else if (inode->u.i_ops->write) + { + ret = file_writev_compat(filep, uio); + } } - /* Yes, then let the driver perform the write */ - - ret = inode->u.i_ops->write(filep, buf, nbytes); #ifdef CONFIG_FS_NOTIFY if (ret > 0) { @@ -102,12 +172,50 @@ ssize_t file_write(FAR struct file *filep, FAR const void *buf, } /**************************************************************************** - * Name: nx_write + * Name: file_write * * Description: - * nx_write() writes up to nytes bytes to the file referenced by the file - * descriptor fd from the buffer starting at buf. nx_write() is an - * internal OS function. It is functionally equivalent to write() except + * Equivalent to the standard write() function except that is accepts a + * struct file instance instead of a file descriptor. It is functionally + * equivalent to write() except that in addition to the differences in + * input parameters: + * + * - It does not modify the errno variable, + * - It is not a cancellation point, and + * + * Input Parameters: + * filep - Instance of struct file to use with the write + * buf - Data to write + * nbytes - Length of data to write + * + * Returned Value: + * On success, the number of bytes written are returned (zero indicates + * nothing was written). On any failure, a negated errno value is returned + * (see comments withwrite() for a description of the appropriate errno + * values). + * + ****************************************************************************/ + +ssize_t file_write(FAR struct file *filep, FAR const void *buf, + size_t nbytes) +{ + struct iovec iov; + struct uio uio; + + iov.iov_base = (FAR void *)buf; + iov.iov_len = nbytes; + uio.uio_iov = &iov; + uio.uio_iovcnt = 1; + return file_writev(filep, &uio); +} + +/**************************************************************************** + * Name: nx_writev + * + * Description: + * nx_writev() writes up to nytes bytes to the file referenced by the file + * descriptor fd from the buffer starting at buf. nx_writev() is an + * internal OS function. It is functionally equivalent to writev() except * that: * * - It does not modify the errno variable, and @@ -115,8 +223,8 @@ ssize_t file_write(FAR struct file *filep, FAR const void *buf, * * Input Parameters: * fd - file descriptor to write to - * buf - Data to write - * nbytes - Length of data to write + * iov - Data to write + * iovcnt - The number of vectors * * Returned Value: * On success, the number of bytes written are returned (zero indicates @@ -126,16 +234,12 @@ ssize_t file_write(FAR struct file *filep, FAR const void *buf, * ****************************************************************************/ -ssize_t nx_write(int fd, FAR const void *buf, size_t nbytes) +ssize_t nx_writev(int fd, FAR const struct iovec *iov, int iovcnt) { + struct uio uio; FAR struct file *filep; ssize_t ret; - if (buf == NULL) - { - return -EINVAL; - } - /* First, get the file structure. * Note that fs_getfilep() will return the errno on failure. */ @@ -147,7 +251,9 @@ ssize_t nx_write(int fd, FAR const void *buf, size_t nbytes) * index. Note that file_write() will return the errno on failure. */ - ret = file_write(filep, buf, nbytes); + uio.uio_iov = iov; + uio.uio_iovcnt = iovcnt; + ret = file_writev(filep, &uio); fs_putfilep(filep); } @@ -155,11 +261,16 @@ ssize_t nx_write(int fd, FAR const void *buf, size_t nbytes) } /**************************************************************************** - * Name: write + * Name: nx_write * * Description: - * write() writes up to nytes bytes to the file referenced by the file - * descriptor fd from the buffer starting at buf. + * nx_write() writes up to nytes bytes to the file referenced by the file + * descriptor fd from the buffer starting at buf. nx_write() is an + * internal OS function. It is functionally equivalent to write() except + * that: + * + * - It does not modify the errno variable, and + * - It is not a cancellation point. * * Input Parameters: * fd - file descriptor to write to @@ -168,6 +279,35 @@ ssize_t nx_write(int fd, FAR const void *buf, size_t nbytes) * * Returned Value: * On success, the number of bytes written are returned (zero indicates + * nothing was written). On any failure, a negated errno value is returned + * (see comments withwrite() for a description of the appropriate errno + * values). + * + ****************************************************************************/ + +ssize_t nx_write(int fd, FAR const void *buf, size_t nbytes) +{ + struct iovec iov; + + iov.iov_base = (void *)buf; + iov.iov_len = nbytes; + return nx_writev(fd, &iov, 1); +} + +/**************************************************************************** + * Name: writev + * + * Description: + * writev() writes up to nytes bytes to the file referenced by the file + * descriptor fd from the buffer starting at buf. + * + * Input Parameters: + * fd - file descriptor to write to + * iov - Data to write + * iovcnt - The number of vectors + * + * Returned Value: + * On success, the number of bytes written are returned (zero indicates * nothing was written). On error, -1 is returned, and errno is set appro- * priately: * @@ -202,7 +342,7 @@ ssize_t nx_write(int fd, FAR const void *buf, size_t nbytes) * ****************************************************************************/ -ssize_t write(int fd, FAR const void *buf, size_t nbytes) +ssize_t writev(int fd, FAR const struct iovec *iov, int iovcnt) { ssize_t ret; @@ -212,7 +352,7 @@ ssize_t write(int fd, FAR const void *buf, size_t nbytes) /* Let nx_write() do all of the work */ - ret = nx_write(fd, buf, nbytes); + ret = nx_writev(fd, iov, iovcnt); if (ret < 0) { set_errno(-ret); @@ -222,3 +362,60 @@ ssize_t write(int fd, FAR const void *buf, size_t nbytes) leave_cancellation_point(); return ret; } + +/**************************************************************************** + * Name: write + * + * Description: + * write() writes up to nytes bytes to the file referenced by the file + * descriptor fd from the buffer starting at buf. + * + * Input Parameters: + * fd - file descriptor to write to + * buf - Data to write + * nbytes - Length of data to write + * + * Returned Value: + * On success, the number of bytes written are returned (zero indicates + * nothing was written). On error, -1 is returned, and errno is set appro- + * priately: + * + * EAGAIN + * Non-blocking I/O has been selected using O_NONBLOCK and the write + * would block. + * EBADF + * fd is not a valid file descriptor or is not open for writing. + * EFAULT + * buf is outside your accessible address space. + * EFBIG + * An attempt was made to write a file that exceeds the implementation + * defined maximum file size or the process's file size limit, or + * to write at a position past the maximum allowed offset. + * EINTR + * The call was interrupted by a signal before any data was written. + * EINVAL + * fd is attached to an object which is unsuitable for writing; or + * the file was opened with the O_DIRECT flag, and either the address + * specified in buf, the value specified in count, or the current + * file offset is not suitably aligned. + * EIO + * A low-level I/O error occurred while modifying the inode. + * ENOSPC + * The device containing the file referred to by fd has no room for + * the data. + * EPIPE + * fd is connected to a pipe or socket whose reading end is closed. + * When this happens the writing process will also receive a SIGPIPE + * signal. (Thus, the write return value is seen only if the program + * catches, blocks or ignores this signal.) + * + ****************************************************************************/ + +ssize_t write(int fd, FAR const void *buf, size_t nbytes) +{ + struct iovec iov; + + iov.iov_base = (void *)buf; + iov.iov_len = nbytes; + return writev(fd, &iov, 1); +} diff --git a/fs/zipfs/zip_vfs.c b/fs/zipfs/zip_vfs.c index ea1f2ea2241..30ca7f5e387 100644 --- a/fs/zipfs/zip_vfs.c +++ b/fs/zipfs/zip_vfs.c @@ -139,6 +139,8 @@ const struct mountpt_operations g_zipfs_operations = NULL, /* mmap */ NULL, /* truncate */ NULL, /* poll */ + NULL, /* readv */ + NULL, /* writev */ NULL, /* sync */ zipfs_dup, /* dup */ diff --git a/graphics/nxterm/nxterm_driver.c b/graphics/nxterm/nxterm_driver.c index 4f350139371..24c1bc2f8b0 100644 --- a/graphics/nxterm/nxterm_driver.c +++ b/graphics/nxterm/nxterm_driver.c @@ -70,7 +70,9 @@ const struct file_operations g_nxterm_drvrops = nxterm_ioctl, /* ioctl */ NULL, /* mmap */ NULL, /* truncate */ - nxterm_poll /* poll */ + nxterm_poll, /* poll */ + NULL, /* readv */ + NULL /* writev */ #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS , nxterm_unlink /* unlink */ #endif @@ -88,7 +90,9 @@ const struct file_operations g_nxterm_drvrops = nxterm_ioctl, /* ioctl */ NULL, /* mmap */ NULL, /* truncate */ - NULL /* poll */ + NULL, /* poll */ + NULL, /* readv */ + NULL /* writev */ #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS , nxterm_unlink /* unlink */ #endif diff --git a/include/nuttx/fs/fs.h b/include/nuttx/fs/fs.h index 2e06ede9317..22b88409e75 100644 --- a/include/nuttx/fs/fs.h +++ b/include/nuttx/fs/fs.h @@ -28,9 +28,13 @@ ****************************************************************************/ #include + #include +#include +#include #include + #include #include #include @@ -183,6 +187,7 @@ struct statfs; struct pollfd; struct mtd_dev_s; struct tcb_s; +struct uio; /* The internal representation of type DIR is just a container for an inode * reference, and the path of directory. @@ -233,6 +238,8 @@ struct file_operations CODE int (*poll)(FAR struct file *filep, FAR struct pollfd *fds, bool setup); + CODE ssize_t (*readv)(FAR struct file *filep, FAR const struct uio *uio); + CODE ssize_t (*writev)(FAR struct file *filep, FAR const struct uio *uio); /* The two structures need not be common after this point */ @@ -329,6 +336,9 @@ struct mountpt_operations CODE int (*truncate)(FAR struct file *filep, off_t length); CODE int (*poll)(FAR struct file *filep, FAR struct pollfd *fds, bool setup); + CODE ssize_t (*readv)(FAR struct file *filep, FAR const struct uio *uio); + CODE ssize_t (*writev)(FAR struct file *filep, FAR const struct uio *uio); + /* The two structures need not be common after this point. The following * are extended methods needed to deal with the unique needs of mounted * file systems. @@ -1407,6 +1417,7 @@ int close_mtddriver(FAR struct inode *pinode); ****************************************************************************/ ssize_t file_read(FAR struct file *filep, FAR void *buf, size_t nbytes); +ssize_t file_readv(FAR struct file *filep, FAR const struct uio *uio); /**************************************************************************** * Name: nx_read @@ -1430,6 +1441,7 @@ ssize_t file_read(FAR struct file *filep, FAR void *buf, size_t nbytes); ****************************************************************************/ ssize_t nx_read(int fd, FAR void *buf, size_t nbytes); +ssize_t nx_readv(int fd, FAR const struct iovec *iov, int iovcnt); /**************************************************************************** * Name: file_write @@ -1459,6 +1471,7 @@ ssize_t nx_read(int fd, FAR void *buf, size_t nbytes); ssize_t file_write(FAR struct file *filep, FAR const void *buf, size_t nbytes); +ssize_t file_writev(FAR struct file *filep, FAR const struct uio *uio); /**************************************************************************** * Name: nx_write @@ -1486,6 +1499,7 @@ ssize_t file_write(FAR struct file *filep, FAR const void *buf, ****************************************************************************/ ssize_t nx_write(int fd, FAR const void *buf, size_t nbytes); +ssize_t nx_writev(int fd, FAR const struct iovec *iov, int iovcnt); /**************************************************************************** * Name: file_pread diff --git a/include/nuttx/fs/uio.h b/include/nuttx/fs/uio.h new file mode 100644 index 00000000000..e864745a18c --- /dev/null +++ b/include/nuttx/fs/uio.h @@ -0,0 +1,65 @@ +/**************************************************************************** + * include/nuttx/fs/uio.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __INCLUDE_NUTTX_FS_UIO_H +#define __INCLUDE_NUTTX_FS_UIO_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Public Type Definitions + ****************************************************************************/ + +/* The structure to describe an user I/O operation. + * + * At this point, this is a bare minimum for readv/writev. + * In the future, we might extend this for other things like + * the file offset for pread/pwrite. + * + * This structure was inspired by BSDs. + * (Thus it doesn't have the NuttX-style "_s" suffix.) + */ + +struct uio +{ + FAR const struct iovec *uio_iov; + int uio_iovcnt; +}; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: uio_total_len + * + * Description: + * Return the total length of data in bytes. + * Or -EOVERFLOW. + * + ****************************************************************************/ + +ssize_t uio_total_len(FAR const struct uio *uio); + +#endif /* __INCLUDE_NUTTX_FS_UIO_H */ diff --git a/include/sys/syscall_lookup.h b/include/sys/syscall_lookup.h index 8e27edae007..5bef5e5d1ca 100644 --- a/include/sys/syscall_lookup.h +++ b/include/sys/syscall_lookup.h @@ -200,6 +200,8 @@ SYSCALL_LOOKUP(close, 1) SYSCALL_LOOKUP(ioctl, 3) SYSCALL_LOOKUP(read, 3) SYSCALL_LOOKUP(write, 3) +SYSCALL_LOOKUP(readv, 3) +SYSCALL_LOOKUP(writev, 3) SYSCALL_LOOKUP(pread, 4) SYSCALL_LOOKUP(pwrite, 4) #ifdef CONFIG_FS_AIO diff --git a/libs/libc/uio/CMakeLists.txt b/libs/libc/uio/CMakeLists.txt index 1074488fec1..9dbcbf0dce0 100644 --- a/libs/libc/uio/CMakeLists.txt +++ b/libs/libc/uio/CMakeLists.txt @@ -20,4 +20,4 @@ # # ############################################################################## -target_sources(c PRIVATE lib_readv.c lib_writev.c lib_preadv.c lib_pwritev.c) +target_sources(c PRIVATE lib_preadv.c lib_pwritev.c) diff --git a/libs/libc/uio/Make.defs b/libs/libc/uio/Make.defs index 04620764ddf..59bfb7d6640 100644 --- a/libs/libc/uio/Make.defs +++ b/libs/libc/uio/Make.defs @@ -22,7 +22,6 @@ # Add the uio.h C files to the build -CSRCS += lib_readv.c lib_writev.c CSRCS += lib_preadv.c lib_pwritev.c # Add the uio.h directory to the build diff --git a/libs/libc/uio/lib_readv.c b/libs/libc/uio/lib_readv.c deleted file mode 100644 index c16d0a673bd..00000000000 --- a/libs/libc/uio/lib_readv.c +++ /dev/null @@ -1,125 +0,0 @@ -/**************************************************************************** - * libs/libc/uio/lib_readv.c - * - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. The - * ASF licenses this file to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include -#include -#include - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: readv() - * - * Description: - * The readv() function is equivalent to read(), except as described below. - * The readv() function places the input data into the 'iovcnt' buffers - * specified by the members of the 'iov' array: iov[0], iov[1], ..., - * iov['iovcnt'-1]. The 'iovcnt' argument is valid if greater than 0 and - * less than or equal to IOV_MAX as defined in limits.h. - * - * Each iovec entry specifies the base address and length of an area in - * memory where data should be placed. The readv() function will always - * fill an area completely before proceeding to the next. - * - * TODO: pon successful completion, readv() will mark for update the - * st_atime field of the file. - * - * Input Parameters: - * filedes - The open file descriptor for the file to be read - * iov - Array of read buffer descriptors - * iovcnt - Number of elements in iov[] - * - * Returned Value: - * Upon successful completion, readv() will return a non-negative integer - * indicating the number of bytes actually read. Otherwise, the functions - * will return -1 and set errno to indicate the error. See read() for the - * list of returned errno values. In addition, the readv() function will - * fail if: - * - * EINVAL. - * The sum of the iov_len values in the iov array overflowed an ssize_t - * or The 'iovcnt' argument was less than or equal to 0, or greater than - * IOV_MAX (Not implemented). - * - ****************************************************************************/ - -ssize_t readv(int fildes, FAR const struct iovec *iov, int iovcnt) -{ - ssize_t ntotal; - ssize_t nread; - size_t remaining; - FAR uint8_t *buffer; - int i; - - /* Process each entry in the struct iovec array */ - - for (i = 0, ntotal = 0; i < iovcnt; i++) - { - /* Ignore zero-length reads */ - - if (iov[i].iov_len > 0) - { - buffer = iov[i].iov_base; - remaining = iov[i].iov_len; - - /* Read repeatedly as necessary to fill buffer */ - - do - { - /* NOTE: read() is a cancellation point */ - - nread = read(fildes, buffer, remaining); - - /* Check for a read error */ - - if (nread < 0) - { - return nread; - } - - /* Check for an end-of-file condition */ - - else if (nread == 0) - { - return ntotal; - } - - /* Update pointers and counts in order to handle partial - * buffer reads. - */ - - buffer += nread; - remaining -= nread; - ntotal += nread; - } - while (remaining > 0); - } - } - - return ntotal; -} diff --git a/libs/libc/uio/lib_writev.c b/libs/libc/uio/lib_writev.c deleted file mode 100644 index 79623e64b64..00000000000 --- a/libs/libc/uio/lib_writev.c +++ /dev/null @@ -1,124 +0,0 @@ -/**************************************************************************** - * libs/libc/uio/lib_writev.c - * - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. The - * ASF licenses this file to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include -#include -#include -#include - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: writev() - * - * Description: - * The writev() function is equivalent to write(), except as described - * below. The writev() function will gather output data from the 'iovcnt' - * buffers specified by the members of the 'iov' array: - * iov[0], iov[1], ..., iov[iovcnt-1]. - * The 'iovcnt' argument is valid if greater than 0 and less than or equal - * to IOV_MAX, as defined in limits.h. - * - * Each iovec entry specifies the base address and length of an area in - * memory from which data should be written. The writev() function always - * writes a complete area before proceeding to the next. - * - * If 'filedes' refers to a regular file and all of the iov_len members in - * the array pointed to by iov are 0, writev() will return 0 and have no - * other effect. For other file types, the behavior is unspecified. - * - * TODO: If the sum of the iov_len values is greater than SSIZE_MAX, the - * operation will fail and no data will be transferred. - * - * Input Parameters: - * filedes - The open file descriptor for the file to be write - * iov - Array of write buffer descriptors - * iovcnt - Number of elements in iov[] - * - * Returned Value: - * Upon successful completion, writev() shall return the number of bytes - * actually written. Otherwise, it shall return a value of -1, the file- - * pointer shall remain unchanged, and errno shall be set to indicate an - * error. See write for the list of returned errno values. In addition, - * the writev() function will fail if: - * - * EINVAL. - * The sum of the iov_len values in the iov array overflowed an ssize_t - * or The 'iovcnt' argument was less than or equal to 0, or greater than - * IOV_MAX (Not implemented). - * - ****************************************************************************/ - -ssize_t writev(int fildes, FAR const struct iovec *iov, int iovcnt) -{ - ssize_t ntotal; - ssize_t nwritten; - size_t remaining; - FAR uint8_t *buffer; - int i; - - /* Process each entry in the struct iovec array */ - - for (i = 0, ntotal = 0; i < iovcnt; i++) - { - /* Ignore zero-length writes */ - - if (iov[i].iov_len > 0) - { - buffer = iov[i].iov_base; - remaining = iov[i].iov_len; - - /* Write repeatedly as necessary to write the entire buffer */ - - do - { - /* NOTE: write() is a cancellation point */ - - nwritten = write(fildes, buffer, remaining); - - /* Check for a write error */ - - if (nwritten < 0) - { - return ntotal ? ntotal : ERROR; - } - - /* Update pointers and counts in order to handle partial - * buffer writes. - */ - - buffer += nwritten; - remaining -= nwritten; - ntotal += nwritten; - } - while (remaining > 0); - } - } - - return ntotal; -} diff --git a/syscall/syscall.csv b/syscall/syscall.csv index 1c3baae5315..f883a50c879 100644 --- a/syscall/syscall.csv +++ b/syscall/syscall.csv @@ -128,6 +128,7 @@ "putenv","stdlib.h","!defined(CONFIG_DISABLE_ENVIRON)","int","FAR const char *" "pwrite","unistd.h","","ssize_t","int","FAR const void *","size_t","off_t" "read","unistd.h","","ssize_t","int","FAR void *","size_t" +"readv","sys/uio.h","","ssize_t","int","FAR const struct iovec *","int" "readlink","unistd.h","defined(CONFIG_PSEUDOFS_SOFTLINKS)","ssize_t","FAR const char *","FAR char *","size_t" "recv","sys/socket.h","defined(CONFIG_NET)","ssize_t","int","FAR void *","size_t","int" "recvfrom","sys/socket.h","defined(CONFIG_NET)","ssize_t","int","FAR void*","size_t","int","FAR struct sockaddr*","FAR socklen_t*" @@ -208,3 +209,4 @@ "waitid","sys/wait.h","defined(CONFIG_SCHED_WAITPID) && defined(CONFIG_SCHED_HAVE_PARENT)","int","idtype_t","id_t"," FAR siginfo_t *","int" "waitpid","sys/wait.h","defined(CONFIG_SCHED_WAITPID)","pid_t","pid_t","FAR int *","int" "write","unistd.h","","ssize_t","int","FAR const void *","size_t" +"writev","sys/uio.h","","ssize_t","int","FAR const struct iovec *","int"