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"