move readv/writev to the kernel

currently, nuttx implements readv/writev on the top of read/write.
while it might work for the simplest cases, it's broken by design.
for example, it's impossible to make it work correctly for files
which need to preserve data boundaries without allocating a single
contiguous buffer. (udp socket, some character devices, etc)

this change is a start of the migration to a better design.
that is, implement read/write on the top of readv/writev.

to avoid a single huge change, following things will NOT be done in
this commit:

* fix actual bugs caused by the original readv-based-on-read design.
  (cf. https://github.com/apache/nuttx/pull/12674)

* adapt filesystems/drivers to actually benefit from the new interface.
  (except a few trivial examples)

* eventually retire the old interface.

* retire read/write syscalls. implement them in libc instead.

* pread/pwrite/preadv/pwritev (except the introduction of struct uio,
  which is a preparation to back these variations with the new
  interface.)
This commit is contained in:
YAMAMOTO Takashi
2024-09-17 15:23:07 +09:00
committed by Xiang Xiao
parent e3d7d23618
commit 761ee81956
68 changed files with 836 additions and 452 deletions
+1 -1
View File
@@ -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)
-1
View File
@@ -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
-125
View File
@@ -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 <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
/****************************************************************************
* 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;
}
-124
View File
@@ -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 <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
#include <errno.h>
/****************************************************************************
* 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;
}