diff --git a/drivers/loop/loop.c b/drivers/loop/loop.c index 01ccee4a9d9..2b2a412b5bd 100644 --- a/drivers/loop/loop.c +++ b/drivers/loop/loop.c @@ -40,10 +40,8 @@ * Private Function Prototypes ****************************************************************************/ -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 ssize_t loop_readv(FAR struct file *filep, FAR struct uio *uio); +static ssize_t loop_writev(FAR struct file *filep, FAR struct uio *uio); static int loop_ioctl(FAR struct file *filep, int cmd, unsigned long arg); @@ -74,8 +72,7 @@ static const struct file_operations g_loop_fops = * Name: loop_readv ****************************************************************************/ -static ssize_t loop_readv(FAR struct file *filep, - FAR const struct uio *uio) +static ssize_t loop_readv(FAR struct file *filep, FAR struct uio *uio) { return 0; /* Return EOF */ } @@ -84,10 +81,14 @@ static ssize_t loop_readv(FAR struct file *filep, * Name: loop_writev ****************************************************************************/ -static ssize_t loop_writev(FAR struct file *filep, - FAR const struct uio *uio) +static ssize_t loop_writev(FAR struct file *filep, FAR struct uio *uio) { - return uio_total_len(uio); /* Say that everything was written */ + /* Say that everything was written */ + + 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 da37ddbf8ec..0c196fc7c71 100644 --- a/drivers/misc/dev_null.c +++ b/drivers/misc/dev_null.c @@ -40,10 +40,8 @@ * Private Function Prototypes ****************************************************************************/ -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 ssize_t devnull_readv(FAR struct file *filep, FAR struct uio *uio); +static ssize_t devnull_writev(FAR struct file *filep, FAR struct uio *uio); static int devnull_poll(FAR struct file *filep, FAR struct pollfd *fds, bool setup); @@ -74,8 +72,7 @@ static const struct file_operations g_devnull_fops = * Name: devnull_readv ****************************************************************************/ -static ssize_t devnull_readv(FAR struct file *filep, - FAR const struct uio *uio) +static ssize_t devnull_readv(FAR struct file *filep, FAR struct uio *uio) { UNUSED(filep); UNUSED(uio); @@ -87,12 +84,16 @@ static ssize_t devnull_readv(FAR struct file *filep, * Name: devnull_writev ****************************************************************************/ -static ssize_t devnull_writev(FAR struct file *filep, - FAR const struct uio *uio) +static ssize_t devnull_writev(FAR struct file *filep, FAR struct uio *uio) { UNUSED(filep); - return uio_total_len(uio); /* Say that everything was written */ + /* 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 1ea18e9d982..38be2fd9fcc 100644 --- a/drivers/misc/dev_zero.c +++ b/drivers/misc/dev_zero.c @@ -40,10 +40,8 @@ * Private Function Prototypes ****************************************************************************/ -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 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); static int devzero_poll(FAR struct file *filep, FAR struct pollfd *fds, bool setup); @@ -74,26 +72,22 @@ static const struct file_operations g_devzero_fops = * Name: devzero_readv ****************************************************************************/ -static ssize_t devzero_readv(FAR struct file *filep, - FAR const struct uio *uio) +static ssize_t devzero_readv(FAR struct file *filep, FAR struct uio *uio) { - ssize_t total = uio_total_len(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); } + uio_advance(uio, total); + return total; } @@ -101,12 +95,15 @@ static ssize_t devzero_readv(FAR struct file *filep, * Name: devzero_writev ****************************************************************************/ -static ssize_t devzero_writev(FAR struct file *filep, - FAR const struct uio *uio) +static ssize_t devzero_writev(FAR struct file *filep, FAR struct uio *uio) { + size_t total; UNUSED(filep); - return uio_total_len(uio); + total = uio->uio_resid; + + uio_advance(uio, total); + return total; } /**************************************************************************** diff --git a/fs/vfs/fs_read.c b/fs/vfs/fs_read.c index fce68e0d68b..1d93af0e04b 100644 --- a/fs/vfs/fs_read.c +++ b/fs/vfs/fs_read.c @@ -50,8 +50,7 @@ * ****************************************************************************/ -static ssize_t file_readv_compat(FAR struct file *filep, - FAR const struct uio *uio) +static ssize_t file_readv_compat(FAR struct file *filep, FAR struct uio *uio) { FAR const struct iovec *iov = uio->uio_iov; int iovcnt = uio->uio_iovcnt; @@ -102,6 +101,11 @@ static ssize_t file_readv_compat(FAR struct file *filep, remaining -= nread; } + if (ntotal >= 0) + { + uio_advance(uio, ntotal); + } + return ntotal; } @@ -130,7 +134,7 @@ static ssize_t file_readv_compat(FAR struct file *filep, * ****************************************************************************/ -ssize_t file_readv(FAR struct file *filep, FAR const struct uio *uio) +ssize_t file_readv(FAR struct file *filep, FAR struct uio *uio) { FAR struct inode *inode; ssize_t ret = -EBADF; @@ -204,11 +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.uio_iov = &iov; - uio.uio_iovcnt = 1; + ret = uio_init(&uio, &iov, 1); + if (ret != 0) + { + return ret; + } + return file_readv(filep, &uio); } @@ -251,9 +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.uio_iov = iov; - uio.uio_iovcnt = 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 5c6e260d559..0ee178bfbfe 100644 --- a/fs/vfs/fs_uio.c +++ b/fs/vfs/fs_uio.c @@ -35,19 +35,19 @@ #include /**************************************************************************** - * Public Functions + * Private Functions ****************************************************************************/ /**************************************************************************** - * Name: uio_total_len + * Name: uio_calc_resid * * Description: - * Return the total length of data in bytes. - * Or -EOVERFLOW. + * Return the remaining length of data in bytes. + * Or -EINVAL. * ****************************************************************************/ -ssize_t uio_total_len(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; @@ -58,7 +58,7 @@ ssize_t uio_total_len(FAR const struct uio *uio) { if (SSIZE_MAX - len < iov[i].iov_len) { - return -EOVERFLOW; + return -EINVAL; } len += iov[i].iov_len; @@ -66,3 +66,164 @@ ssize_t uio_total_len(FAR const struct uio *uio) return len; } + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: uio_advance + * + * Description: + * Advance the pointer/offset in uio by the specified amount. + * + ****************************************************************************/ + +void uio_advance(FAR struct uio *uio, size_t sz) +{ + FAR const struct iovec *iov = uio->uio_iov; + int iovcnt = uio->uio_iovcnt; + size_t offset_in_iov = uio->uio_offset_in_iov; + + DEBUGASSERT(sz <= SSIZE_MAX); + DEBUGASSERT(uio->uio_resid <= SSIZE_MAX); + DEBUGASSERT(sz <= uio->uio_resid); + DEBUGASSERT(uio->uio_offset_in_iov + uio->uio_resid == + uio_calc_resid(uio)); + uio->uio_resid -= sz; + while (iovcnt > 0) + { + DEBUGASSERT(offset_in_iov <= iov->iov_len); + if (sz < iov->iov_len - offset_in_iov) + { + offset_in_iov += sz; + break; + } + + sz -= iov->iov_len - offset_in_iov; + iov++; + iovcnt--; + offset_in_iov = 0; + } + + uio->uio_iov = iov; + uio->uio_iovcnt = iovcnt; + uio->uio_offset_in_iov = offset_in_iov; + DEBUGASSERT(uio->uio_offset_in_iov + uio->uio_resid == + uio_calc_resid(uio)); +} + +/**************************************************************************** + * Name: uio_init + * + * Description: + * Initialize the uio structure with reasonable default values. + * + ****************************************************************************/ + +int uio_init(FAR struct uio *uio, FAR const struct iovec *iov, int iovcnt) +{ + ssize_t resid; + + memset(uio, 0, sizeof(*uio)); + uio->uio_iov = iov; + uio->uio_iovcnt = iovcnt; + resid = uio_calc_resid(uio); + if (resid < 0) + { + return -EINVAL; + } + + uio->uio_resid = resid; + return 0; +} + +/**************************************************************************** + * Name: uio_copyfrom + * + * Description: + * Copy data from the linear buffer to uio. + * + ****************************************************************************/ + +void uio_copyfrom(FAR struct uio *uio, size_t offset, FAR const void *buf, + size_t len) +{ + FAR const struct iovec *iov = uio->uio_iov; + + 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); + DEBUGASSERT(uio->uio_offset_in_iov + uio->uio_resid == + uio_calc_resid(uio)); + + offset += uio->uio_offset_in_iov; + while (offset > iov->iov_len) + { + offset -= iov->iov_len; + iov++; + } + + while (len > 0) + { + size_t blen = len; + if (blen > iov->iov_len - offset) + { + blen = iov->iov_len - offset; + } + + memcpy((FAR uint8_t *)iov->iov_base + offset, buf, blen); + + len -= blen; + buf = (const uint8_t *)buf + blen; + iov++; + offset = 0; + } +} + +/**************************************************************************** + * Name: uio_copyto + * + * Description: + * Copy data to the linear buffer from uio. + * + ****************************************************************************/ + +void uio_copyto(FAR struct uio *uio, size_t offset, FAR void *buf, + size_t len) +{ + FAR const struct iovec *iov = uio->uio_iov; + + 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); + DEBUGASSERT(uio->uio_offset_in_iov + uio->uio_resid == + uio_calc_resid(uio)); + + offset += uio->uio_offset_in_iov; + while (offset > iov->iov_len) + { + offset -= iov->iov_len; + iov++; + } + + while (len > 0) + { + size_t blen = len; + if (blen > iov->iov_len - offset) + { + blen = iov->iov_len - offset; + } + + memcpy(buf, (FAR const uint8_t *)iov->iov_base + offset, blen); + + len -= blen; + buf = (uint8_t *)buf + blen; + iov++; + offset = 0; + } +} diff --git a/fs/vfs/fs_write.c b/fs/vfs/fs_write.c index 39f49517bea..16be9ea957f 100644 --- a/fs/vfs/fs_write.c +++ b/fs/vfs/fs_write.c @@ -51,7 +51,7 @@ ****************************************************************************/ static ssize_t file_writev_compat(FAR struct file *filep, - FAR const struct uio *uio) + FAR struct uio *uio) { FAR const struct iovec *iov = uio->uio_iov; int iovcnt = uio->uio_iovcnt; @@ -102,6 +102,11 @@ static ssize_t file_writev_compat(FAR struct file *filep, remaining -= nwritten; } + if (ntotal >= 0) + { + uio_advance(uio, ntotal); + } + return ntotal; } @@ -133,7 +138,7 @@ static ssize_t file_writev_compat(FAR struct file *filep, * ****************************************************************************/ -ssize_t file_writev(FAR struct file *filep, FAR const struct uio *uio) +ssize_t file_writev(FAR struct file *filep, FAR struct uio *uio) { FAR struct inode *inode; ssize_t ret = -EBADF; @@ -202,11 +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.uio_iov = &iov; - uio.uio_iovcnt = 1; + ret = uio_init(&uio, &iov, 1); + if (ret != 0) + { + return ret; + } + return file_writev(filep, &uio); } @@ -252,9 +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.uio_iov = iov; - uio.uio_iovcnt = 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/fs.h b/include/nuttx/fs/fs.h index ed9731683f3..72edf64d655 100644 --- a/include/nuttx/fs/fs.h +++ b/include/nuttx/fs/fs.h @@ -240,8 +240,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); + CODE ssize_t (*readv)(FAR struct file *filep, FAR struct uio *uio); + CODE ssize_t (*writev)(FAR struct file *filep, FAR struct uio *uio); /* The two structures need not be common after this point */ @@ -311,8 +311,8 @@ 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); + CODE ssize_t (*readv)(FAR struct file *filep, FAR struct uio *uio); + CODE ssize_t (*writev)(FAR struct file *filep, FAR 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 @@ -1419,7 +1419,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); +ssize_t file_readv(FAR struct file *filep, FAR struct uio *uio); /**************************************************************************** * Name: nx_read @@ -1473,7 +1473,7 @@ ssize_t nx_readv(int fd, FAR const struct iovec *iov, int iovcnt); 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); +ssize_t file_writev(FAR struct file *filep, FAR struct uio *uio); /**************************************************************************** * Name: nx_write diff --git a/include/nuttx/fs/uio.h b/include/nuttx/fs/uio.h index e864745a18c..91e84a7a6c2 100644 --- a/include/nuttx/fs/uio.h +++ b/include/nuttx/fs/uio.h @@ -45,6 +45,12 @@ 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 */ + +#if 0 /* notyet; planned for pread/pwrite */ + off_t uio_offset; /* offset in the file */ +#endif }; /**************************************************************************** @@ -52,14 +58,52 @@ struct uio ****************************************************************************/ /**************************************************************************** - * Name: uio_total_len + * Name: uio_advance * * Description: - * Return the total length of data in bytes. - * Or -EOVERFLOW. + * Advance the pointer/offset in uio by the specified amount. * ****************************************************************************/ -ssize_t uio_total_len(FAR const struct uio *uio); +void uio_advance(FAR struct uio *uio, size_t sz); + +/**************************************************************************** + * Name: uio_init + * + * 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.) + * + ****************************************************************************/ + +int uio_init(FAR struct uio *uio, FAR const struct iovec *iov, int iovcnt); + +/**************************************************************************** + * Name: uio_copyto + * + * Description: + * Copy data to the linear buffer from uio. + * + ****************************************************************************/ + +void uio_copyfrom(FAR struct uio *uio, size_t offset, FAR const void *buf, + size_t len); + +/**************************************************************************** + * Name: uio_copyto + * + * Description: + * Copy data to the linear buffer from uio. + * + ****************************************************************************/ + +void uio_copyto(FAR struct uio *uio, size_t offset, FAR void *buf, + size_t len); #endif /* __INCLUDE_NUTTX_FS_UIO_H */