From 761ee819568a52f1934ccf17bae20fe9816ebdec 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 | 280 ++++++++++++++++++++----- fs/vfs/fs_stat.c | 4 +- fs/vfs/fs_truncate.c | 2 +- fs/vfs/fs_uio.c | 66 ++++++ fs/vfs/fs_write.c | 309 +++++++++++++++++++++++----- fs/zipfs/zip_vfs.c | 2 + graphics/nxterm/nxterm_driver.c | 8 +- include/nuttx/fs/fs.h | 16 +- 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, 836 insertions(+), 452 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 f37501fb52..cb1756f60a 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 6fbea4e8ec..3c79652e60 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 b80981a49b..58c5b1089b 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 f5531b7e7c..c2fd05013e 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 05e013afd7..0bfc860982 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 42423cd24f..654cf0aab6 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 b17e38cbff..32f6913e88 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 b4ee2eaece..62f31a18fa 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 77d2c147cc..dd3a023fe7 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 5b8c068984..5093f4df0c 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 d058d64d3e..f622463bea 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 46d0f35983..efc0b23969 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 54355f96d9..fd1a87a5a7 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 2ff13232e5..b8e296a676 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 ccaa68c8c0..fde0e9a844 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 77c73d1eca..920f30e8c0 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 906bc1ac11..5cc5a8b5f5 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 756c41a3cb..08a03481c7 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 f82656c3a8..b84697f1a5 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 487c90ed1d..8502e9b9e1 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 8fc52605f7..5dbf436994 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 7e2c6ba51b..8d701a3ddc 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 92cbd06e5a..0620979998 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 fc7dc47604..2a7579f212 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 c5e49852f6..0f81282302 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 a5ef0a9f8c..50fcec03a2 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 21db78a246..ec3d87761c 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 3c938c788e..9f4beda84a 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 674308daae..505383d673 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 a3e4501e7b..0cacc86a42 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 f855ad063c..a7c2d5a0cf 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 694ecbfbe6..0bcdef535f 100644 --- a/fs/binfs/fs_binfs.c +++ b/fs/binfs/fs_binfs.c @@ -112,6 +112,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 769639ebbe..79cfafc01a 100644 --- a/fs/cromfs/fs_cromfs.c +++ b/fs/cromfs/fs_cromfs.c @@ -192,6 +192,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 40e913ac4c..301429bbb4 100644 --- a/fs/fat/fs_fat32.c +++ b/fs/fat/fs_fat32.c @@ -132,6 +132,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 72f6cb2f9d..1f34a034f8 100644 --- a/fs/hostfs/hostfs.c +++ b/fs/hostfs/hostfs.c @@ -148,6 +148,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 249b945e7a..167ed09347 100644 --- a/fs/littlefs/lfs_vfs.c +++ b/fs/littlefs/lfs_vfs.c @@ -170,6 +170,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 219abdabca..d270242703 100644 --- a/fs/mnemofs/mnemofs.c +++ b/fs/mnemofs/mnemofs.c @@ -188,6 +188,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 3a32bc03d2..fb69a303a7 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 3e093c2f65..22c9404910 100644 --- a/fs/nxffs/nxffs_initialize.c +++ b/fs/nxffs/nxffs_initialize.c @@ -62,6 +62,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 f70b8eeaf0..d12c7acf6b 100644 --- a/fs/procfs/fs_procfs.c +++ b/fs/procfs/fs_procfs.c @@ -287,6 +287,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 3bf433435f..db0d03e5d8 100644 --- a/fs/romfs/fs_romfs.c +++ b/fs/romfs/fs_romfs.c @@ -125,6 +125,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 edf9cf687b..efea624917 100644 --- a/fs/rpmsgfs/rpmsgfs.c +++ b/fs/rpmsgfs/rpmsgfs.c @@ -165,6 +165,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 d02beec721..116a24caf2 100644 --- a/fs/shm/shmfs.c +++ b/fs/shm/shmfs.c @@ -74,6 +74,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 bc4e6477cd..3aa84f627f 100644 --- a/fs/smartfs/smartfs_smart.c +++ b/fs/smartfs/smartfs_smart.c @@ -145,6 +145,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 2160a3b63b..324162af59 100644 --- a/fs/spiffs/src/spiffs_vfs.c +++ b/fs/spiffs/src/spiffs_vfs.c @@ -145,6 +145,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 152272fd94..decc697bcd 100644 --- a/fs/tmpfs/fs_tmpfs.c +++ b/fs/tmpfs/fs_tmpfs.c @@ -187,6 +187,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 ff29050e46..1ee79d40cb 100644 --- a/fs/unionfs/fs_unionfs.c +++ b/fs/unionfs/fs_unionfs.c @@ -230,7 +230,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 893855cb5b..fc2202bdef 100644 --- a/fs/userfs/fs_userfs.c +++ b/fs/userfs/fs_userfs.c @@ -165,6 +165,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 0d1c1f4d83..8823423aa0 100644 --- a/fs/v9fs/v9fs.c +++ b/fs/v9fs/v9fs.c @@ -126,6 +126,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 36a790a3ee..99af578b77 100644 --- a/fs/vfs/CMakeLists.txt +++ b/fs/vfs/CMakeLists.txt @@ -42,6 +42,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 1e8c5b8d47..aaf1aa224f 100644 --- a/fs/vfs/Make.defs +++ b/fs/vfs/Make.defs @@ -24,7 +24,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 a3cb38df7b..8e2099bedf 100644 --- a/fs/vfs/fs_fstat.c +++ b/fs/vfs/fs_fstat.c @@ -109,12 +109,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 a8f1f46910..5dee0ee502 100644 --- a/fs/vfs/fs_open.c +++ b/fs/vfs/fs_open.c @@ -78,8 +78,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 08acce27de..f6b40a0f6f 100644 --- a/fs/vfs/fs_read.c +++ b/fs/vfs/fs_read.c @@ -36,10 +36,152 @@ #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_readv + * + * Description: + * 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, + * - It accepts a file structure instance instead of file descriptor. + * + * Input Parameters: + * filep - File structure instance + * uio - User buffer information + * + * 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_readv(FAR struct file *filep, FAR const struct uio *uio) +{ + FAR struct inode *inode; + ssize_t ret = -EBADF; + + DEBUGASSERT(filep); + inode = filep->f_inode; + + /* Was this file opened for read access? */ + + if ((filep->f_oflags & O_RDOK) == 0) + { + /* No.. File is not read-able */ + + ret = -EACCES; + } + + /* 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) + { + 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) */ + +#ifdef CONFIG_FS_NOTIFY + if (ret > 0) + { + notify_read(filep); + } +#endif + + return ret; +} + /**************************************************************************** * Name: file_read * @@ -64,46 +206,59 @@ ssize_t file_read(FAR struct file *filep, FAR void *buf, size_t nbytes) { - FAR struct inode *inode; - ssize_t ret = -EBADF; + struct iovec iov; + struct uio uio; - DEBUGASSERT(filep); - inode = filep->f_inode; + iov.iov_base = buf; + iov.iov_len = nbytes; + uio.uio_iov = &iov; + uio.uio_iovcnt = 1; + return file_readv(filep, &uio); +} - /* Was this file opened for read access? */ +/**************************************************************************** + * 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 + * 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 a negated errno value on any failure. + * + ****************************************************************************/ - if ((filep->f_oflags & O_RDOK) == 0) - { - /* No.. File is not read-able */ +ssize_t nx_readv(int fd, FAR const struct iovec *iov, int iovcnt) +{ + struct uio uio; + FAR struct file *filep; + ssize_t ret; - ret = -EACCES; - } - - /* Is a driver or mountpoint registered? If so, does it support the read - * method? + /* First, get the file structure. Note that on failure, + * fs_getfilep() will return the errno. */ - else if (inode != NULL && inode->u.i_ops && inode->u.i_ops->read) + ret = (ssize_t)fs_getfilep(fd, &filep); + if (ret < 0) { - /* 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); + return ret; } - /* Return the number of bytes read (or possibly an error code) */ - -#ifdef CONFIG_FS_NOTIFY - if (ret > 0) - { - notify_read(filep); - } -#endif + /* Then let file_read do all of the work. */ + uio.uio_iov = iov; + uio.uio_iovcnt = iovcnt; + ret = file_readv(filep, &uio); + fs_putfilep(filep); return ret; } @@ -130,23 +285,48 @@ 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) { - FAR struct file *filep; + 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 readv(int fd, FAR const struct iovec *iov, int iovcnt) +{ ssize_t ret; - /* First, get the file structure. Note that on failure, - * fs_getfilep() will return the errno. - */ + /* readv() is a cancellation point */ - ret = (ssize_t)fs_getfilep(fd, &filep); + enter_cancellation_point(); + + /* Let nx_readv() do the real work */ + + ret = nx_readv(fd, iov, iovcnt); if (ret < 0) { - return ret; + set_errno(-ret); + ret = ERROR; } - /* Then let file_read do all of the work. */ - - ret = file_read(filep, buf, nbytes); - fs_putfilep(filep); + leave_cancellation_point(); return ret; } @@ -169,21 +349,9 @@ ssize_t nx_read(int fd, FAR void *buf, size_t nbytes) ssize_t read(int fd, FAR void *buf, size_t nbytes) { - ssize_t ret; + struct iovec iov; - /* 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; + 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 b647b30b71..81eaa74e1c 100644 --- a/fs/vfs/fs_stat.c +++ b/fs/vfs/fs_stat.c @@ -379,12 +379,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 d6dc7dfb6a..681c47d61c 100644 --- a/fs/vfs/fs_truncate.c +++ b/fs/vfs/fs_truncate.c @@ -82,7 +82,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 0000000000..455d021961 --- /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 6849763a67..41ce33cf0f 100644 --- a/fs/vfs/fs_write.c +++ b/fs/vfs/fs_write.c @@ -36,10 +36,139 @@ #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_writev + * + * Description: + * Equivalent to the standard writev() function except that is accepts a + * struct file instance instead of a file descriptor. It is functionally + * equivalent to writev() 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 + * uio - User buffer information + * + * 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_writev(FAR struct file *filep, FAR const struct uio *uio) +{ + FAR struct inode *inode; + ssize_t ret = -EBADF; + + /* Was this file opened for write access? */ + + if ((filep->f_oflags & O_WROK) == 0) + { + return -EACCES; + } + + /* 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 != NULL && inode->u.i_ops) + { + 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); + } + } + +#ifdef CONFIG_FS_NOTIFY + if (ret > 0) + { + notify_write(filep); + } +#endif + + return ret; +} + /**************************************************************************** * Name: file_write * @@ -68,34 +197,64 @@ ssize_t file_write(FAR struct file *filep, FAR const void *buf, size_t nbytes) { - FAR struct inode *inode; + 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 + * - It is not a cancellation point. + * + * 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 any failure, a negated errno value is returned + * (see comments withwrite() for a description of the appropriate errno + * values). + * + ****************************************************************************/ + +ssize_t nx_writev(int fd, FAR const struct iovec *iov, int iovcnt) +{ + struct uio uio; + FAR struct file *filep; ssize_t ret; - /* Was this file opened for write access? */ + /* First, get the file structure. + * Note that fs_getfilep() will return the errno on failure. + */ - if ((filep->f_oflags & O_WROK) == 0) + ret = (ssize_t)fs_getfilep(fd, &filep); + if (ret >= 0) { - return -EACCES; + /* Perform the write operation using the file descriptor as an + * index. Note that file_write() will return the errno on failure. + */ + + uio.uio_iov = iov; + uio.uio_iovcnt = iovcnt; + ret = file_writev(filep, &uio); + fs_putfilep(filep); } - /* Is a driver registered? Does it support the write method? */ - - inode = filep->f_inode; - if (!inode || !inode->u.i_ops || !inode->u.i_ops->write) - { - return -EBADF; - } - - /* Yes, then let the driver perform the write */ - - ret = inode->u.i_ops->write(filep, buf, nbytes); -#ifdef CONFIG_FS_NOTIFY - if (ret > 0) - { - notify_write(filep); - } -#endif - return ret; } @@ -126,29 +285,79 @@ 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) { - FAR struct file *filep; + 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: + * + * 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 writev(int fd, FAR const struct iovec *iov, int iovcnt) +{ ssize_t ret; - if (buf == NULL) + /* write() is a cancellation point */ + + enter_cancellation_point(); + + /* Let nx_write() do all of the work */ + + ret = nx_writev(fd, iov, iovcnt); + if (ret < 0) { - return -EINVAL; - } - - /* First, get the file structure. - * Note that fs_getfilep() will return the errno on failure. - */ - - ret = (ssize_t)fs_getfilep(fd, &filep); - if (ret >= 0) - { - /* Perform the write operation using the file descriptor as an - * index. Note that file_write() will return the errno on failure. - */ - - ret = file_write(filep, buf, nbytes); - fs_putfilep(filep); + set_errno(-ret); + ret = ERROR; } + leave_cancellation_point(); return ret; } @@ -202,21 +411,9 @@ 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 ret; + struct iovec iov; - /* 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; + 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 50897820e4..d59d6e94a7 100644 --- a/fs/zipfs/zip_vfs.c +++ b/fs/zipfs/zip_vfs.c @@ -137,6 +137,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 4f35013937..24c1bc2f8b 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 cc9591fd05..f338d4e585 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 #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. @@ -1416,6 +1426,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 @@ -1439,6 +1450,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 @@ -1468,6 +1480,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 @@ -1495,6 +1508,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 0000000000..e864745a18 --- /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 8e27edae00..5bef5e5d1c 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 1074488fec..9dbcbf0dce 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 04620764dd..59bfb7d664 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 c16d0a673b..0000000000 --- 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 79623e64b6..0000000000 --- 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 1c3baae531..f883a50c87 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"