mirror of
https://github.com/apache/nuttx.git
synced 2026-05-31 05:55:46 +08:00
uio api tweaks
* Make readv/writev implementations update struct uio This can simplify partial result handling. * change the error number on the overflow from EOVERFLOW to EINVAL to match NetBSD * add a commented out uio_offset field. I used "#if 0" here as C comments can't nest. * add a few helper functions Note on uio_copyfrom/uio_copyto: although i'm not quite happy with the "offset" functionality, it's necessary to simplify the adaptation of some drivers like drivers/serial/serial.c, which (ab)uses the user-supplied buffer as a line-buffer.
This commit is contained in:
committed by
Xiang Xiao
parent
2749510413
commit
30ad31e9d7
+20
-8
@@ -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;
|
||||
}
|
||||
|
||||
+167
-6
@@ -35,19 +35,19 @@
|
||||
#include <errno.h>
|
||||
|
||||
/****************************************************************************
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
|
||||
+20
-7
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user