From 69ecff897a74650985c8552be01fe659cd672517 Mon Sep 17 00:00:00 2001 From: YAMAMOTO Takashi Date: Wed, 25 Dec 2024 10:23:24 +0900 Subject: [PATCH] uio_resid api tweak * add uio_resid member to struct uio * retire uio_resid() function * move the overflow check into uio_init * change the error number on the overflow from EOVERFLOW to EINVAL to match NetBSD --- drivers/loop/loop.c | 7 ++----- drivers/misc/dev_null.c | 9 ++++----- drivers/misc/dev_zero.c | 16 ++++------------ drivers/serial/serial.c | 13 ++----------- fs/vfs/fs_read.c | 16 +++++++++++++--- fs/vfs/fs_uio.c | 41 ++++++++++++++++++++++++++++------------- fs/vfs/fs_write.c | 16 +++++++++++++--- include/nuttx/fs/uio.h | 21 +++++++++------------ 8 files changed, 75 insertions(+), 64 deletions(-) diff --git a/drivers/loop/loop.c b/drivers/loop/loop.c index f0e9e9be761af..2b2a412b5bdae 100644 --- a/drivers/loop/loop.c +++ b/drivers/loop/loop.c @@ -85,12 +85,9 @@ static ssize_t loop_writev(FAR struct file *filep, FAR struct uio *uio) { /* Say that everything was written */ - ssize_t ret = uio_resid(uio); - if (ret >= 0) - { - uio_advance(uio, ret); - } + size_t ret = uio->uio_resid; + uio_advance(uio, ret); return ret; } diff --git a/drivers/misc/dev_null.c b/drivers/misc/dev_null.c index a8f5772f3ddda..0c196fc7c71d8 100644 --- a/drivers/misc/dev_null.c +++ b/drivers/misc/dev_null.c @@ -88,12 +88,11 @@ static ssize_t devnull_writev(FAR struct file *filep, FAR struct uio *uio) { UNUSED(filep); - ssize_t ret = uio_resid(uio); /* Say that everything was written */ - if (ret >= 0) - { - uio_advance(uio, ret); - } + /* Say that everything was written */ + + size_t ret = uio->uio_resid; + uio_advance(uio, ret); return ret; } diff --git a/drivers/misc/dev_zero.c b/drivers/misc/dev_zero.c index 0087ace830a27..38be2fd9fcc09 100644 --- a/drivers/misc/dev_zero.c +++ b/drivers/misc/dev_zero.c @@ -74,18 +74,13 @@ static const struct file_operations g_devzero_fops = static ssize_t devzero_readv(FAR struct file *filep, FAR struct uio *uio) { - ssize_t total = uio_resid(uio); + size_t total = uio->uio_resid; FAR const struct iovec *iov = uio->uio_iov; int iovcnt = uio->uio_iovcnt; int i; UNUSED(filep); - if (total < 0) - { - return total; - } - for (i = 0; i < iovcnt; i++) { memset(iov[i].iov_base, 0, iov[i].iov_len); @@ -102,15 +97,12 @@ static ssize_t devzero_readv(FAR struct file *filep, FAR struct uio *uio) static ssize_t devzero_writev(FAR struct file *filep, FAR struct uio *uio) { - ssize_t total; + size_t total; UNUSED(filep); - total = uio_resid(uio); - if (total >= 0) - { - uio_advance(uio, total); - } + total = uio->uio_resid; + uio_advance(uio, total); return total; } diff --git a/drivers/serial/serial.c b/drivers/serial/serial.c index 79c007e495fd7..e29d09add3a29 100644 --- a/drivers/serial/serial.c +++ b/drivers/serial/serial.c @@ -910,12 +910,6 @@ static ssize_t uart_readv(FAR struct file *filep, FAR struct uio *uio) char ch; int ret; - buflen = uio_resid(uio); - if (buflen < 0) - { - return buflen; - } - /* Only one user can access rxbuf->tail at a time */ ret = nxmutex_lock(&dev->recv.lock); @@ -934,6 +928,7 @@ static ssize_t uart_readv(FAR struct file *filep, FAR struct uio *uio) * data from the end of the buffer. */ + buflen = uio->uio_resid; while (recvd < buflen) { #ifdef CONFIG_SERIAL_REMOVABLE @@ -1424,11 +1419,7 @@ static ssize_t uart_writev(FAR struct file *filep, FAR struct uio *uio) return ret; } - buflen = nwritten = uio_resid(uio); - if (nwritten < 0) - { - return nwritten; - } + buflen = nwritten = uio->uio_resid; /* Only one user can access dev->xmit.head at a time */ diff --git a/fs/vfs/fs_read.c b/fs/vfs/fs_read.c index fc63a9a6a8d67..1d93af0e04bf1 100644 --- a/fs/vfs/fs_read.c +++ b/fs/vfs/fs_read.c @@ -208,10 +208,16 @@ ssize_t file_read(FAR struct file *filep, FAR void *buf, size_t nbytes) { struct iovec iov; struct uio uio; + ssize_t ret; iov.iov_base = buf; iov.iov_len = nbytes; - uio_init(&uio, &iov, 1); + ret = uio_init(&uio, &iov, 1); + if (ret != 0) + { + return ret; + } + return file_readv(filep, &uio); } @@ -254,8 +260,12 @@ ssize_t nx_readv(int fd, FAR const struct iovec *iov, int iovcnt) /* Then let file_readv do all of the work. */ - uio_init(&uio, iov, iovcnt); - ret = file_readv(filep, &uio); + ret = uio_init(&uio, iov, iovcnt); + if (ret == 0) + { + ret = file_readv(filep, &uio); + } + fs_putfilep(filep); return ret; } diff --git a/fs/vfs/fs_uio.c b/fs/vfs/fs_uio.c index 78a5a0ad34fc4..7d32386662efe 100644 --- a/fs/vfs/fs_uio.c +++ b/fs/vfs/fs_uio.c @@ -35,19 +35,19 @@ #include /**************************************************************************** - * Public Functions + * Private Functions ****************************************************************************/ /**************************************************************************** - * Name: uio_resid + * Name: uio_calc_resid * * Description: * Return the remaining length of data in bytes. - * Or -EOVERFLOW. + * Or -EINVAL. * ****************************************************************************/ -ssize_t uio_resid(FAR const struct uio *uio) +ssize_t uio_calc_resid(FAR const struct uio *uio) { const struct iovec *iov = uio->uio_iov; int iovcnt = uio->uio_iovcnt; @@ -60,7 +60,7 @@ ssize_t uio_resid(FAR const struct uio *uio) DEBUGASSERT(offset_in_iov <= iov[i].iov_len); if (SSIZE_MAX - len < iov[i].iov_len - offset_in_iov) { - return -EOVERFLOW; + return -EINVAL; } len += iov[i].iov_len - offset_in_iov; @@ -70,6 +70,10 @@ ssize_t uio_resid(FAR const struct uio *uio) return len; } +/**************************************************************************** + * Public Functions + ****************************************************************************/ + /**************************************************************************** * Name: uio_advance * @@ -84,7 +88,9 @@ void uio_advance(FAR struct uio *uio, size_t sz) int iovcnt = uio->uio_iovcnt; size_t offset_in_iov = uio->uio_offset_in_iov; - DEBUGASSERT(sz <= uio_resid(uio)); + DEBUGASSERT(sz <= SSIZE_MAX); + DEBUGASSERT(uio->uio_resid <= SSIZE_MAX); + DEBUGASSERT(sz <= uio->uio_resid); while (iovcnt > 0) { DEBUGASSERT(offset_in_iov <= iov->iov_len); @@ -113,11 +119,18 @@ void uio_advance(FAR struct uio *uio, size_t sz) * ****************************************************************************/ -void uio_init(FAR struct uio *uio, FAR const struct iovec *iov, int iovcnt) +int uio_init(FAR struct uio *uio, FAR const struct iovec *iov, int iovcnt) { memset(uio, 0, sizeof(*uio)); uio->uio_iov = iov; uio->uio_iovcnt = iovcnt; + uio->uio_resid = uio_calc_resid(uio); + if (uio->uio_resid < 0) + { + return -EINVAL; + } + + return 0; } /**************************************************************************** @@ -133,9 +146,10 @@ void uio_copyfrom(FAR struct uio *uio, size_t offset, FAR const void *buf, { FAR const struct iovec *iov = uio->uio_iov; - DEBUGASSERT(uio_resid(uio) >= 0); - DEBUGASSERT(len <= uio_resid(uio)); - DEBUGASSERT(offset <= uio_resid(uio) - len); + DEBUGASSERT(uio->uio_resid >= 0); + DEBUGASSERT(uio->uio_resid <= SSIZE_MAX); + DEBUGASSERT(len <= uio->uio_resid); + DEBUGASSERT(offset <= uio->uio_resid - len); DEBUGASSERT(SSIZE_MAX - offset >= uio->uio_offset_in_iov); offset += uio->uio_offset_in_iov; @@ -180,9 +194,10 @@ void uio_copyto(FAR struct uio *uio, size_t offset, FAR void *buf, { FAR const struct iovec *iov = uio->uio_iov; - DEBUGASSERT(uio_resid(uio) >= 0); - DEBUGASSERT(len <= uio_resid(uio)); - DEBUGASSERT(offset <= uio_resid(uio) - len); + DEBUGASSERT(uio->uio_resid >= 0); + DEBUGASSERT(uio->uio_resid <= SSIZE_MAX); + DEBUGASSERT(len <= uio->uio_resid); + DEBUGASSERT(offset <= uio->uio_resid - len); DEBUGASSERT(SSIZE_MAX - offset >= uio->uio_offset_in_iov); offset += uio->uio_offset_in_iov; diff --git a/fs/vfs/fs_write.c b/fs/vfs/fs_write.c index fb946bf01c3ee..16be9ea957f38 100644 --- a/fs/vfs/fs_write.c +++ b/fs/vfs/fs_write.c @@ -207,10 +207,16 @@ ssize_t file_write(FAR struct file *filep, FAR const void *buf, { struct iovec iov; struct uio uio; + ssize_t ret; iov.iov_base = (FAR void *)buf; iov.iov_len = nbytes; - uio_init(&uio, &iov, 1); + ret = uio_init(&uio, &iov, 1); + if (ret != 0) + { + return ret; + } + return file_writev(filep, &uio); } @@ -256,8 +262,12 @@ ssize_t nx_writev(int fd, FAR const struct iovec *iov, int iovcnt) * index. Note that file_writev() will return the errno on failure. */ - uio_init(&uio, iov, iovcnt); - ret = file_writev(filep, &uio); + ret = uio_init(&uio, iov, iovcnt); + if (ret == 0) + { + ret = file_writev(filep, &uio); + } + fs_putfilep(filep); } diff --git a/include/nuttx/fs/uio.h b/include/nuttx/fs/uio.h index 32ed121a345c7..eb43b1978283a 100644 --- a/include/nuttx/fs/uio.h +++ b/include/nuttx/fs/uio.h @@ -45,6 +45,7 @@ struct uio { FAR const struct iovec *uio_iov; int uio_iovcnt; + size_t uio_resid; /* the remaining bytes in the request */ size_t uio_offset_in_iov; /* offset in uio_iov[0].iov_base */ }; @@ -52,17 +53,6 @@ struct uio * Public Function Prototypes ****************************************************************************/ -/**************************************************************************** - * Name: uio_resid - * - * Description: - * Return the remaining length of data in bytes. - * Or -EOVERFLOW. - * - ****************************************************************************/ - -ssize_t uio_resid(FAR const struct uio *uio); - /**************************************************************************** * Name: uio_advance * @@ -79,9 +69,16 @@ void uio_advance(FAR struct uio *uio, size_t sz); * Description: * Initialize the uio structure with reasonable default values. * + * Return Value: + * 0 on success. A negative error number on an error. + * + * -EINVAL: The total size of the given iovec is too large. + * (Note: NetBSD's readv returns EINVAL in that case. + * I (yamamoto) couldn't find the specification in POSIX.) + * ****************************************************************************/ -void uio_init(FAR struct uio *uio, FAR const struct iovec *iov, int iovcnt); +int uio_init(FAR struct uio *uio, FAR const struct iovec *iov, int iovcnt); /**************************************************************************** * Name: uio_copyto