You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by xi...@apache.org on 2021/07/17 05:18:46 UTC
[incubator-nuttx] 01/01: fs: Simplify sendfile implementation
This is an automated email from the ASF dual-hosted git repository.
xiaoxiang pushed a commit to branch socket
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git
commit 330b2b0e8f16711e07eaa02d349fd0c484a8fe1d
Author: Xiang Xiao <xi...@xiaomi.com>
AuthorDate: Sat Jul 10 23:52:17 2021 +0800
fs: Simplify sendfile implementation
and avoid call nx_ file API in the kernel space
Signed-off-by: Xiang Xiao <xi...@xiaomi.com>
Change-Id: Id951ca161df2c2ee267dc4b5a0d7dfa67df4c1e6
---
.../arm/cxd56xx/spresense/configs/rndis/defconfig | 2 +-
.../cxd56xx/spresense/configs/rndis_smp/defconfig | 2 +-
.../arm/cxd56xx/spresense/configs/wifi/defconfig | 2 +-
.../cxd56xx/spresense/configs/wifi_smp/defconfig | 2 +-
.../stm32/olimexino-stm32/configs/can/defconfig | 1 -
.../olimexino-stm32/configs/composite/defconfig | 1 -
.../stm32/olimexino-stm32/configs/nsh/defconfig | 1 -
.../olimexino-stm32/configs/smallnsh/defconfig | 1 -
.../stm32/olimexino-stm32/configs/tiny/defconfig | 1 -
.../stm32f4discovery/configs/mmcsdspi/defconfig | 2 +-
.../stm32/stm32f4discovery/configs/wifi/defconfig | 2 +-
fs/Kconfig | 6 +
fs/vfs/Make.defs | 18 +-
fs/vfs/fs_sendfile.c | 305 ++++++++++++++++++---
include/nuttx/fs/fs.h | 24 +-
include/nuttx/net/net.h | 2 +-
include/sys/sendfile.h | 4 +-
include/sys/syscall_lookup.h | 5 +-
libs/libc/libc.csv | 1 -
libs/libc/misc/Kconfig | 6 -
libs/libc/misc/Make.defs | 2 -
libs/libc/misc/lib_sendfile.c | 288 -------------------
net/socket/net_sendfile.c | 9 +-
syscall/syscall.csv | 2 +-
24 files changed, 297 insertions(+), 392 deletions(-)
diff --git a/boards/arm/cxd56xx/spresense/configs/rndis/defconfig b/boards/arm/cxd56xx/spresense/configs/rndis/defconfig
index 6591398..86af62c 100644
--- a/boards/arm/cxd56xx/spresense/configs/rndis/defconfig
+++ b/boards/arm/cxd56xx/spresense/configs/rndis/defconfig
@@ -62,7 +62,6 @@ CONFIG_I2C=y
CONFIG_IOB_NBUFFERS=128
CONFIG_LIBC_EXECFUNCS=y
CONFIG_LIB_ENVPATH=y
-CONFIG_LIB_SENDFILE_BUFSIZE=1024
CONFIG_MEMCPY_VIK=y
CONFIG_MEMSET_64BIT=y
CONFIG_MEMSET_OPTSPEED=y
@@ -132,6 +131,7 @@ CONFIG_SCHED_HPWORK=y
CONFIG_SCHED_LPWORK=y
CONFIG_SCHED_WAITPID=y
CONFIG_SDCLONE_DISABLE=y
+CONFIG_SENDFILE_BUFSIZE=1024
CONFIG_SMARTFS_ALIGNED_ACCESS=y
CONFIG_SMARTFS_MAXNAMLEN=30
CONFIG_SMARTFS_MULTI_ROOT_DIRS=y
diff --git a/boards/arm/cxd56xx/spresense/configs/rndis_smp/defconfig b/boards/arm/cxd56xx/spresense/configs/rndis_smp/defconfig
index ef676f8..d8f21a0 100644
--- a/boards/arm/cxd56xx/spresense/configs/rndis_smp/defconfig
+++ b/boards/arm/cxd56xx/spresense/configs/rndis_smp/defconfig
@@ -64,7 +64,6 @@ CONFIG_I2C=y
CONFIG_IOB_NBUFFERS=128
CONFIG_LIBC_EXECFUNCS=y
CONFIG_LIB_ENVPATH=y
-CONFIG_LIB_SENDFILE_BUFSIZE=1024
CONFIG_MEMCPY_VIK=y
CONFIG_MEMSET_64BIT=y
CONFIG_MEMSET_OPTSPEED=y
@@ -133,6 +132,7 @@ CONFIG_RTC_HIRES=y
CONFIG_SCHED_HPWORK=y
CONFIG_SCHED_LPWORK=y
CONFIG_SDCLONE_DISABLE=y
+CONFIG_SENDFILE_BUFSIZE=1024
CONFIG_SMARTFS_ALIGNED_ACCESS=y
CONFIG_SMARTFS_MAXNAMLEN=30
CONFIG_SMARTFS_MULTI_ROOT_DIRS=y
diff --git a/boards/arm/cxd56xx/spresense/configs/wifi/defconfig b/boards/arm/cxd56xx/spresense/configs/wifi/defconfig
index 333d906..0d59823 100644
--- a/boards/arm/cxd56xx/spresense/configs/wifi/defconfig
+++ b/boards/arm/cxd56xx/spresense/configs/wifi/defconfig
@@ -76,7 +76,6 @@ CONFIG_LCD_ILI9340=y
CONFIG_LCD_ILI9340_IFACE0=y
CONFIG_LIBC_EXECFUNCS=y
CONFIG_LIB_ENVPATH=y
-CONFIG_LIB_SENDFILE_BUFSIZE=1024
CONFIG_MEMCPY_VIK=y
CONFIG_MEMSET_64BIT=y
CONFIG_MEMSET_OPTSPEED=y
@@ -137,6 +136,7 @@ CONFIG_SCHED_HPWORK=y
CONFIG_SCHED_LPWORKPRIORITY=60
CONFIG_SCHED_WAITPID=y
CONFIG_SDCLONE_DISABLE=y
+CONFIG_SENDFILE_BUFSIZE=1024
CONFIG_SMARTFS_ALIGNED_ACCESS=y
CONFIG_SMARTFS_MAXNAMLEN=30
CONFIG_SMARTFS_MULTI_ROOT_DIRS=y
diff --git a/boards/arm/cxd56xx/spresense/configs/wifi_smp/defconfig b/boards/arm/cxd56xx/spresense/configs/wifi_smp/defconfig
index 5b04caf..abb4d34 100644
--- a/boards/arm/cxd56xx/spresense/configs/wifi_smp/defconfig
+++ b/boards/arm/cxd56xx/spresense/configs/wifi_smp/defconfig
@@ -79,7 +79,6 @@ CONFIG_LCD_ILI9340=y
CONFIG_LCD_ILI9340_IFACE0=y
CONFIG_LIBC_EXECFUNCS=y
CONFIG_LIB_ENVPATH=y
-CONFIG_LIB_SENDFILE_BUFSIZE=1024
CONFIG_MEMCPY_VIK=y
CONFIG_MEMSET_64BIT=y
CONFIG_MEMSET_OPTSPEED=y
@@ -141,6 +140,7 @@ CONFIG_RTC_HIRES=y
CONFIG_SCHED_HPWORK=y
CONFIG_SCHED_LPWORKPRIORITY=60
CONFIG_SDCLONE_DISABLE=y
+CONFIG_SENDFILE_BUFSIZE=1024
CONFIG_SMARTFS_ALIGNED_ACCESS=y
CONFIG_SMARTFS_MAXNAMLEN=30
CONFIG_SMARTFS_MULTI_ROOT_DIRS=y
diff --git a/boards/arm/stm32/olimexino-stm32/configs/can/defconfig b/boards/arm/stm32/olimexino-stm32/configs/can/defconfig
index fbca71c..15f6f3b 100644
--- a/boards/arm/stm32/olimexino-stm32/configs/can/defconfig
+++ b/boards/arm/stm32/olimexino-stm32/configs/can/defconfig
@@ -52,7 +52,6 @@ CONFIG_I2C=y
CONFIG_I2C_RESET=y
CONFIG_IDLETHREAD_STACKSIZE=300
CONFIG_INTELHEX_BINARY=y
-CONFIG_LIB_SENDFILE_BUFSIZE=0
CONFIG_MM_SMALL=y
CONFIG_NAME_MAX=8
CONFIG_NFILE_DESCRIPTORS_PER_BLOCK=5
diff --git a/boards/arm/stm32/olimexino-stm32/configs/composite/defconfig b/boards/arm/stm32/olimexino-stm32/configs/composite/defconfig
index dfc6fa0..2b6c620 100644
--- a/boards/arm/stm32/olimexino-stm32/configs/composite/defconfig
+++ b/boards/arm/stm32/olimexino-stm32/configs/composite/defconfig
@@ -70,7 +70,6 @@ CONFIG_HAVE_CXX=y
CONFIG_HAVE_CXXINITIALIZE=y
CONFIG_IDLETHREAD_STACKSIZE=300
CONFIG_INTELHEX_BINARY=y
-CONFIG_LIB_SENDFILE_BUFSIZE=0
CONFIG_MMCSD=y
CONFIG_MM_SMALL=y
CONFIG_NAME_MAX=8
diff --git a/boards/arm/stm32/olimexino-stm32/configs/nsh/defconfig b/boards/arm/stm32/olimexino-stm32/configs/nsh/defconfig
index a6ec658..c339b0c 100644
--- a/boards/arm/stm32/olimexino-stm32/configs/nsh/defconfig
+++ b/boards/arm/stm32/olimexino-stm32/configs/nsh/defconfig
@@ -58,7 +58,6 @@ CONFIG_HAVE_CXX=y
CONFIG_HAVE_CXXINITIALIZE=y
CONFIG_IDLETHREAD_STACKSIZE=300
CONFIG_INTELHEX_BINARY=y
-CONFIG_LIB_SENDFILE_BUFSIZE=0
CONFIG_MMCSD=y
CONFIG_MM_SMALL=y
CONFIG_NAME_MAX=8
diff --git a/boards/arm/stm32/olimexino-stm32/configs/smallnsh/defconfig b/boards/arm/stm32/olimexino-stm32/configs/smallnsh/defconfig
index dfa9814..7c32b1a 100644
--- a/boards/arm/stm32/olimexino-stm32/configs/smallnsh/defconfig
+++ b/boards/arm/stm32/olimexino-stm32/configs/smallnsh/defconfig
@@ -35,7 +35,6 @@ CONFIG_HAVE_CXX=y
CONFIG_HAVE_CXXINITIALIZE=y
CONFIG_IDLETHREAD_STACKSIZE=300
CONFIG_INTELHEX_BINARY=y
-CONFIG_LIB_SENDFILE_BUFSIZE=0
CONFIG_MM_SMALL=y
CONFIG_NAME_MAX=8
CONFIG_NFILE_DESCRIPTORS_PER_BLOCK=5
diff --git a/boards/arm/stm32/olimexino-stm32/configs/tiny/defconfig b/boards/arm/stm32/olimexino-stm32/configs/tiny/defconfig
index e4f31f1..5ec5973 100644
--- a/boards/arm/stm32/olimexino-stm32/configs/tiny/defconfig
+++ b/boards/arm/stm32/olimexino-stm32/configs/tiny/defconfig
@@ -36,7 +36,6 @@ CONFIG_HAVE_CXXINITIALIZE=y
CONFIG_IDLETHREAD_STACKSIZE=300
CONFIG_INTELHEX_BINARY=y
CONFIG_LIB_BOARDCTL=y
-CONFIG_LIB_SENDFILE_BUFSIZE=0
CONFIG_MM_SMALL=y
CONFIG_NAME_MAX=8
CONFIG_NFILE_DESCRIPTORS_PER_BLOCK=5
diff --git a/boards/arm/stm32/stm32f4discovery/configs/mmcsdspi/defconfig b/boards/arm/stm32/stm32f4discovery/configs/mmcsdspi/defconfig
index ea00e7c..11a1529 100644
--- a/boards/arm/stm32/stm32f4discovery/configs/mmcsdspi/defconfig
+++ b/boards/arm/stm32/stm32f4discovery/configs/mmcsdspi/defconfig
@@ -36,7 +36,6 @@ CONFIG_HAVE_CXX=y
CONFIG_HAVE_CXXINITIALIZE=y
CONFIG_HEAP_COLORATION=y
CONFIG_INTELHEX_BINARY=y
-CONFIG_LIB_SENDFILE_BUFSIZE=1024
CONFIG_MMCSD=y
CONFIG_MM_REGIONS=2
CONFIG_NETUTILS_CODECS=y
@@ -55,6 +54,7 @@ CONFIG_SCHED_LPWORK=y
CONFIG_SCHED_LPWORKPRIORITY=30
CONFIG_SCHED_WAITPID=y
CONFIG_SDCLONE_DISABLE=y
+CONFIG_SENDFILE_BUFSIZE=1024
CONFIG_STACK_COLORATION=y
CONFIG_START_DAY=17
CONFIG_START_MONTH=10
diff --git a/boards/arm/stm32/stm32f4discovery/configs/wifi/defconfig b/boards/arm/stm32/stm32f4discovery/configs/wifi/defconfig
index b977101..d8a3e2d 100644
--- a/boards/arm/stm32/stm32f4discovery/configs/wifi/defconfig
+++ b/boards/arm/stm32/stm32f4discovery/configs/wifi/defconfig
@@ -42,7 +42,6 @@ CONFIG_HEAP_COLORATION=y
CONFIG_INTELHEX_BINARY=y
CONFIG_LIBC_EXECFUNCS=y
CONFIG_LIB_ENVPATH=y
-CONFIG_LIB_SENDFILE_BUFSIZE=1024
CONFIG_MMCSD=y
CONFIG_MM_REGIONS=2
CONFIG_NET=y
@@ -78,6 +77,7 @@ CONFIG_RR_INTERVAL=200
CONFIG_SCHED_LPWORKPRIORITY=30
CONFIG_SCHED_WAITPID=y
CONFIG_SDCLONE_DISABLE=y
+CONFIG_SENDFILE_BUFSIZE=1024
CONFIG_STACK_COLORATION=y
CONFIG_START_DAY=22
CONFIG_START_MONTH=10
diff --git a/fs/Kconfig b/fs/Kconfig
index d646d06..02b62be 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -67,6 +67,12 @@ config PSEUDOFS_SOFTLINKS
to link a directory in the pseudo-file system, such as /bin, to
to a directory in a mounted volume, say /mnt/sdcard/bin.
+config SENDFILE_BUFSIZE
+ int "sendfile() buffer size"
+ default 512
+ ---help---
+ Size of the I/O buffer to allocate in sendfile(). Default: 512b
+
config EVENT_FD
bool "EventFD"
default n
diff --git a/fs/vfs/Make.defs b/fs/vfs/Make.defs
index 7b35b81..daacda4 100644
--- a/fs/vfs/Make.defs
+++ b/fs/vfs/Make.defs
@@ -20,10 +20,10 @@
# Common file/socket descriptor support
-CSRCS += fs_close.c fs_dup.c fs_dup2.c fs_fcntl.c
-CSRCS += fs_epoll.c fs_fstat.c fs_fstatfs.c fs_ioctl.c
-CSRCS += fs_lseek.c fs_mkdir.c fs_open.c fs_poll.c fs_read.c fs_rename.c
-CSRCS += fs_rmdir.c fs_statfs.c fs_stat.c fs_select.c fs_unlink.c fs_write.c
+CSRCS += fs_close.c fs_dup.c fs_dup2.c fs_fcntl.c fs_epoll.c fs_fstat.c
+CSRCS += fs_fstatfs.c fs_ioctl.c fs_lseek.c fs_mkdir.c fs_open.c fs_poll.c
+CSRCS += fs_pread.c fs_pwrite.c fs_read.c fs_rename.c fs_rmdir.c fs_select.c
+CSRCS += fs_sendfile.c fs_stat.c fs_statfs.c fs_unlink.c fs_write.c
# Certain interfaces are not available if there is no mountpoint support
@@ -31,10 +31,6 @@ ifneq ($(CONFIG_DISABLE_MOUNTPOINT),y)
CSRCS += fs_fsync.c fs_truncate.c
endif
-# Support for positional file access
-
-CSRCS += fs_pread.c fs_pwrite.c
-
ifneq ($(CONFIG_PSEUDOFS_SOFTLINKS),0)
CSRCS += fs_symlink.c fs_readlink.c
endif
@@ -45,12 +41,6 @@ ifeq ($(CONFIG_FILE_STREAM),y)
CSRCS += fs_fdopen.c
endif
-# Support for sendfile()
-
-ifeq ($(CONFIG_NET_SENDFILE),y)
-CSRCS += fs_sendfile.c
-endif
-
# Support for eventfd
ifeq ($(CONFIG_EVENT_FD),y)
diff --git a/fs/vfs/fs_sendfile.c b/fs/vfs/fs_sendfile.c
index 3d2b8cd..5b4ec2c 100644
--- a/fs/vfs/fs_sendfile.c
+++ b/fs/vfs/fs_sendfile.c
@@ -26,21 +26,256 @@
#include <sys/sendfile.h>
#include <stdbool.h>
-#include <stdlib.h>
-#include <unistd.h>
#include <errno.h>
-#include <assert.h>
-#include <nuttx/sched.h>
+#include <nuttx/kmalloc.h>
#include <nuttx/net/net.h>
-#ifdef CONFIG_NET_SENDFILE
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static ssize_t copyfile(FAR struct file *outfile, FAR struct file *infile,
+ off_t *offset, size_t count)
+{
+ FAR uint8_t *iobuffer;
+ FAR uint8_t *wrbuffer;
+ off_t startpos = 0;
+ ssize_t nbytesread;
+ ssize_t nbyteswritten;
+ size_t ntransferred;
+ bool endxfr;
+
+ /* Get the current file position. */
+
+ if (offset)
+ {
+ off_t newpos;
+
+ /* Use file_seek to get the current file position */
+
+ startpos = file_seek(infile, 0, SEEK_CUR);
+ if (startpos < 0)
+ {
+ return startpos;
+ }
+
+ /* Use file_seek again to set the new file position */
+
+ newpos = file_seek(infile, *offset, SEEK_SET);
+ if (newpos < 0)
+ {
+ return newpos;
+ }
+ }
+
+ /* Allocate an I/O buffer */
+
+ iobuffer = kmm_malloc(CONFIG_SENDFILE_BUFSIZE);
+ if (!iobuffer)
+ {
+ return -ENOMEM;
+ }
+
+ /* Now transfer 'count' bytes from the infile to the outfile */
+
+ for (ntransferred = 0, endxfr = false; ntransferred < count && !endxfr; )
+ {
+ /* Loop until the read side of the transfer comes to some conclusion */
+
+ do
+ {
+ /* Read a buffer of data from the infile */
+
+ nbytesread = count - ntransferred;
+ if (nbytesread > CONFIG_SENDFILE_BUFSIZE)
+ {
+ nbytesread = CONFIG_SENDFILE_BUFSIZE;
+ }
+
+ nbytesread = file_read(infile, iobuffer, nbytesread);
+
+ /* Check for end of file */
+
+ if (nbytesread == 0)
+ {
+ /* End of file. Break out and return current number of bytes
+ * transferred.
+ */
+
+ endxfr = true;
+ break;
+ }
+
+ /* Check for a read ERROR. EINTR is a special case. This function
+ * should break out and return an error if EINTR is returned and
+ * no data has been transferred. But what should it do if some
+ * data has been transferred? I suppose just continue?
+ */
+
+ else if (nbytesread < 0)
+ {
+ /* EINTR is not an error (but will still stop the copy) */
+
+ if (nbytesread != -EINTR || ntransferred == 0)
+ {
+ /* Read error. Break out and return the error condition. */
+
+ ntransferred = nbytesread;
+ endxfr = true;
+ break;
+ }
+ }
+ }
+ while (nbytesread < 0);
+
+ /* Was anything read? */
+
+ if (!endxfr)
+ {
+ /* Yes.. Loop until the read side of the transfer comes to some
+ * conclusion.
+ */
+
+ wrbuffer = iobuffer;
+ do
+ {
+ /* Write the buffer of data to the outfile */
+
+ nbyteswritten = file_write(outfile, wrbuffer, nbytesread);
+
+ /* Check for a complete (or partial) write. write() should not
+ * return zero.
+ */
+
+ if (nbyteswritten >= 0)
+ {
+ /* Advance the buffer pointer and decrement the number of
+ * bytes remaining in the iobuffer. Typically, nbytesread
+ * will now be zero.
+ */
+
+ wrbuffer += nbyteswritten;
+ nbytesread -= nbyteswritten;
+
+ /* Increment the total number of bytes successfully
+ * transferred.
+ */
+
+ ntransferred += nbyteswritten;
+ }
+
+ /* Otherwise an error occurred */
+
+ else
+ {
+ /* Check for a write ERROR. EINTR is a special case. This
+ * function should break out and return an error if EINTR
+ * is returned and no data has been transferred. But what
+ * should it do if some data has been transferred? I
+ * suppose just continue?
+ */
+
+ if (nbyteswritten != -EINTR || ntransferred == 0)
+ {
+ /* Write error. Break out and return the error
+ * condition.
+ */
+
+ ntransferred = nbyteswritten;
+ endxfr = true;
+ break;
+ }
+ }
+ }
+ while (nbytesread > 0);
+ }
+ }
+
+ /* Release the I/O buffer */
+
+ kmm_free(iobuffer);
+
+ /* Return the current file position */
+
+ if (offset)
+ {
+ /* Use file_seek to get the current file position */
+
+ off_t curpos = file_seek(infile, 0, SEEK_CUR);
+ if (curpos < 0)
+ {
+ return curpos;
+ }
+
+ /* Return the current file position */
+
+ *offset = curpos;
+
+ /* Use file_seek again to restore the original file position */
+
+ startpos = file_seek(infile, startpos, SEEK_SET);
+ if (startpos < 0)
+ {
+ return startpos;
+ }
+ }
+
+ /* Finally return the number of bytes actually transferred (or ERROR
+ * if any failure occurred).
+ */
+
+ return ntransferred;
+}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
+ * Name: file_sendfile
+ *
+ * Description:
+ * Equivalent to the standard sendfile function except that is accepts a
+ * struct file instance instead of a file descriptor.
+ *
+ ****************************************************************************/
+
+ssize_t file_sendfile(FAR struct file *outfile, FAR struct file *infile,
+ off_t *offset, size_t count)
+{
+#ifdef CONFIG_NET_SENDFILE
+ /* Check the destination file descriptor: Is it a (probable) file
+ * descriptor? Check the source file: Is it a normal file?
+ */
+
+ FAR struct socket *psock;
+
+ psock = file_socket(outfile);
+ if (psock != NULL)
+ {
+ /* Then let psock_sendfile do the work. */
+
+ int ret = psock_sendfile(psock, infile, offset, count);
+ if (ret >= 0 || ret != -ENOSYS)
+ {
+ return ret;
+ }
+
+ /* Fall back to the slow path if errno equals ENOSYS,
+ * because psock_sendfile fail to optimize this transfer.
+ */
+ }
+#endif
+
+ /* No... then this is probably a file-to-file transfer. The generic
+ * copyfile() can handle that case.
+ */
+
+ return copyfile(outfile, infile, offset, count);
+}
+
+/****************************************************************************
* Name: sendfile
*
* Description:
@@ -87,51 +322,31 @@
ssize_t sendfile(int outfd, int infd, off_t *offset, size_t count)
{
-#ifdef CONFIG_NET_SENDFILE
- /* Check the destination file descriptor: Is it a (probable) file
- * descriptor? Check the source file: Is it a normal file?
- */
+ FAR struct file *outfile;
+ FAR struct file *infile;
+ int ret;
- FAR struct socket *psock;
-
- psock = sockfd_socket(outfd);
- if (psock != NULL)
+ ret = fs_getfilep(outfd, &outfile);
+ if (ret < 0)
{
- FAR struct file *filep;
- int ret;
-
- /* This appears to be a file-to-socket transfer. Get the file
- * structure.
- */
-
- ret = fs_getfilep(infd, &filep);
- if (ret < 0)
- {
- set_errno(-ret);
- return ERROR;
- }
-
- DEBUGASSERT(filep != NULL);
-
- /* Then let psock_sendfile do the work. */
+ goto errout;
+ }
- ret = psock_sendfile(psock, filep, offset, count);
- if (ret >= 0 || get_errno() != ENOSYS)
- {
- return ret;
- }
+ ret = fs_getfilep(infd, &infile);
+ if (ret < 0)
+ {
+ goto errout;
+ }
- /* Fall back to the slow path if errno equals ENOSYS,
- * because psock_sendfile fail to optimize this transfer.
- */
+ ret = file_sendfile(outfile, infile, offset, count);
+ if (ret < 0)
+ {
+ goto errout;
}
-#endif
- /* No... then this is probably a file-to-file transfer. The generic
- * lib_sendfile() can handle that case.
- */
+ return ret;
- return lib_sendfile(outfd, infd, offset, count);
+errout:
+ set_errno(-ret);
+ return ERROR;
}
-
-#endif /* CONFIG_NET_SENDFILE */
diff --git a/include/nuttx/fs/fs.h b/include/nuttx/fs/fs.h
index 5210f44..edff265 100644
--- a/include/nuttx/fs/fs.h
+++ b/include/nuttx/fs/fs.h
@@ -978,18 +978,6 @@ int lib_flushall(FAR struct streamlist *list);
#endif
/****************************************************************************
- * Name: lib_sendfile
- *
- * Description:
- * Transfer a file
- *
- ****************************************************************************/
-
-#ifdef CONFIG_NET_SENDFILE
-ssize_t lib_sendfile(int outfd, int infd, off_t *offset, size_t count);
-#endif
-
-/****************************************************************************
* Name: file_read
*
* Description:
@@ -1120,6 +1108,18 @@ ssize_t file_pwrite(FAR struct file *filep, FAR const void *buf,
size_t nbytes, off_t offset);
/****************************************************************************
+ * Name: file_sendfile
+ *
+ * Description:
+ * Equivalent to the standard sendfile function except that is accepts a
+ * struct file instance instead of a file descriptor.
+ *
+ ****************************************************************************/
+
+ssize_t file_sendfile(FAR struct file *outfile, FAR struct file *infile,
+ off_t *offset, size_t count);
+
+/****************************************************************************
* Name: file_seek
*
* Description:
diff --git a/include/nuttx/net/net.h b/include/nuttx/net/net.h
index d79162e..c940e20 100644
--- a/include/nuttx/net/net.h
+++ b/include/nuttx/net/net.h
@@ -1334,7 +1334,7 @@ int psock_fstat(FAR struct socket *psock, FAR struct stat *buf);
*
* Returned Value:
* On success, returns the number of characters sent. On error,
- * -1 is returned, and errno is set appropriately:
+ * the negative errno is return appropriately:
*
* EAGAIN or EWOULDBLOCK
* The socket is marked non-blocking and the requested operation
diff --git a/include/sys/sendfile.h b/include/sys/sendfile.h
index de4a5c2..cb583a9 100644
--- a/include/sys/sendfile.h
+++ b/include/sys/sendfile.h
@@ -35,8 +35,8 @@
/* Configuration ************************************************************/
-#ifndef CONFIG_LIB_SENDFILE_BUFSIZE
-# define CONFIG_LIB_SENDFILE_BUFSIZE 512
+#ifndef CONFIG_SENDFILE_BUFSIZE
+# define CONFIG_SENDFILE_BUFSIZE 512
#endif
/****************************************************************************
diff --git a/include/sys/syscall_lookup.h b/include/sys/syscall_lookup.h
index 03de33c..5d55d9f 100644
--- a/include/sys/syscall_lookup.h
+++ b/include/sys/syscall_lookup.h
@@ -247,6 +247,7 @@ SYSCALL_LOOKUP(fstat, 2)
SYSCALL_LOOKUP(statfs, 2)
SYSCALL_LOOKUP(fstatfs, 2)
SYSCALL_LOOKUP(telldir, 1)
+SYSCALL_LOOKUP(sendfile, 4)
#if defined(CONFIG_FS_RAMMAP)
SYSCALL_LOOKUP(munmap, 2)
@@ -270,10 +271,6 @@ SYSCALL_LOOKUP(telldir, 1)
SYSCALL_LOOKUP(nxsched_get_streams, 0)
#endif
-#ifdef CONFIG_NET_SENDFILE
- SYSCALL_LOOKUP(sendfile, 4)
-#endif
-
#ifndef CONFIG_DISABLE_MOUNTPOINT
SYSCALL_LOOKUP(mount, 5)
SYSCALL_LOOKUP(fsync, 1)
diff --git a/libs/libc/libc.csv b/libs/libc/libc.csv
index cbd6c5c..f0bd9c8 100644
--- a/libs/libc/libc.csv
+++ b/libs/libc/libc.csv
@@ -150,7 +150,6 @@
"sched_get_priority_min","sched.h","","int","int"
"sem_getvalue","semaphore.h","","int","FAR sem_t *","FAR int *"
"sem_init","semaphore.h","","int","FAR sem_t *","int","unsigned int"
-"sendfile","sys/sendfile.h","","ssize_t","int","int","FAR off_t *","size_t"
"setlocale","locale.h","defined(CONFIG_LIBC_LOCALE)","FAR char *","int","FAR const char *"
"setlogmask","syslog.h","","int","int"
"sigaddset","signal.h","","int","FAR sigset_t *","int"
diff --git a/libs/libc/misc/Kconfig b/libs/libc/misc/Kconfig
index c36b785..e8f8978 100644
--- a/libs/libc/misc/Kconfig
+++ b/libs/libc/misc/Kconfig
@@ -3,12 +3,6 @@
# see the file kconfig-language.txt in the NuttX tools repository.
#
-config LIB_SENDFILE_BUFSIZE
- int "sendfile() buffer size"
- default 512
- ---help---
- Size of the I/O buffer to allocate in sendfile(). Default: 512b
-
comment "Non-standard Library Support"
config LIB_CRC64_FAST
diff --git a/libs/libc/misc/Make.defs b/libs/libc/misc/Make.defs
index f14f0ab..2168826 100644
--- a/libs/libc/misc/Make.defs
+++ b/libs/libc/misc/Make.defs
@@ -34,8 +34,6 @@ CSRCS += lib_uadd32x64.c lib_uadd64.c lib_usub64x32.c lib_usub64.c
# Add C files that depend on file OR socket descriptors
-CSRCS += lib_sendfile.c
-
ifeq ($(CONFIG_FILE_STREAM),y)
CSRCS += lib_streamsem.c
endif
diff --git a/libs/libc/misc/lib_sendfile.c b/libs/libc/misc/lib_sendfile.c
deleted file mode 100644
index b7f9d0d..0000000
--- a/libs/libc/misc/lib_sendfile.c
+++ /dev/null
@@ -1,288 +0,0 @@
-/****************************************************************************
- * libs/libc/misc/lib_sendfile.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 <nuttx/config.h>
-
-#include <sys/sendfile.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <errno.h>
-
-#include <nuttx/fs/fs.h>
-
-#include "libc.h"
-
-/****************************************************************************
- * Public Functions
- ****************************************************************************/
-
-/****************************************************************************
- * Name: sendfile / lib_sendfile
- *
- * Description:
- * sendfile() copies data between one file descriptor and another.
- * sendfile() basically just wraps a sequence of reads() and writes()
- * to perform a copy. It serves a purpose in systems where there is
- * a penalty for copies to between user and kernal space, but really
- * nothing in NuttX but provide some Linux compatible (and adding
- * another 'almost standard' interface).
- *
- * NOTE: This interface is *not* specified in POSIX.1-2001, or other
- * standards. The implementation here is very similar to the Linux
- * sendfile interface. Other UNIX systems implement sendfile() with
- * different semantics and prototypes. sendfile() should not be used
- * in portable programs.
- *
- * Input Parameters:
- * infd - A file (or socket) descriptor opened for reading
- * outfd - A descriptor opened for writing.
- * offset - If 'offset' is not NULL, then it points to a variable
- * holding the file offset from which sendfile() will start
- * reading data from 'infd'. When sendfile() returns, this
- * variable will be set to the offset of the byte following
- * the last byte that was read. If 'offset' is not NULL,
- * then sendfile() does not modify the current file offset of
- * 'infd'; otherwise the current file offset is adjusted to
- * reflect the number of bytes read from 'infd.'
- *
- * If 'offset' is NULL, then data will be read from 'infd'
- * starting at the current file offset, and the file offset
- * will be updated by the call.
- * count - The number of bytes to copy between the file descriptors.
- *
- * Returned Value:
- * If the transfer was successful, the number of bytes written to outfd is
- * returned. On error, -1 is returned, and errno is set appropriately.
- * There error values are those returned by read() or write() plus:
- *
- * EINVAL - Bad input parameters.
- * ENOMEM - Could not allocated an I/O buffer
- *
- ****************************************************************************/
-
-#ifdef CONFIG_NET_SENDFILE
-ssize_t lib_sendfile(int outfd, int infd, off_t *offset, size_t count)
-#else
-ssize_t sendfile(int outfd, int infd, off_t *offset, size_t count)
-#endif
-{
- FAR uint8_t *iobuffer;
- FAR uint8_t *wrbuffer;
- off_t startpos = 0;
- ssize_t nbytesread;
- ssize_t nbyteswritten;
- size_t ntransferred;
- bool endxfr;
-
- /* Get the current file position. */
-
- if (offset)
- {
- off_t newpos;
-
- /* Use lseek to get the current file position */
-
- startpos = _NX_SEEK(infd, 0, SEEK_CUR);
- if (startpos < 0)
- {
- int errcode = _NX_GETERRNO(startpos);
- _NX_SETERRNO(errcode);
- return ERROR;
- }
-
- /* Use lseek again to set the new file position */
-
- newpos = _NX_SEEK(infd, *offset, SEEK_SET);
- if (newpos < 0)
- {
- int errcode = _NX_GETERRNO(newpos);
- _NX_SETERRNO(errcode);
- return ERROR;
- }
- }
-
- /* Allocate an I/O buffer */
-
- iobuffer = (FAR void *)lib_malloc(CONFIG_LIB_SENDFILE_BUFSIZE);
- if (!iobuffer)
- {
- set_errno(ENOMEM);
- return ERROR;
- }
-
- /* Now transfer 'count' bytes from the infd to the outfd */
-
- for (ntransferred = 0, endxfr = false; ntransferred < count && !endxfr; )
- {
- /* Loop until the read side of the transfer comes to some conclusion */
-
- do
- {
- /* Read a buffer of data from the infd */
-
- nbytesread = _NX_READ(infd, iobuffer, CONFIG_LIB_SENDFILE_BUFSIZE);
-
- /* Check for end of file */
-
- if (nbytesread == 0)
- {
- /* End of file. Break out and return current number of bytes
- * transferred.
- */
-
- endxfr = true;
- break;
- }
-
- /* Check for a read ERROR. EINTR is a special case. This function
- * should break out and return an error if EINTR is returned and
- * no data has been transferred. But what should it do if some
- * data has been transferred? I suppose just continue?
- */
-
- else if (nbytesread < 0)
- {
- int errcode = _NX_GETERRNO(nbytesread);
-
- /* EINTR is not an error (but will still stop the copy) */
-
- if (errcode != EINTR || ntransferred == 0)
- {
- /* Read error. Break out and return the error condition. */
-
- _NX_SETERRNO(nbytesread);
- ntransferred = ERROR;
- endxfr = true;
- break;
- }
- }
- }
- while (nbytesread < 0);
-
- /* Was anything read? */
-
- if (!endxfr)
- {
- /* Yes.. Loop until the read side of the transfer comes to some
- * conclusion.
- */
-
- wrbuffer = iobuffer;
- do
- {
- /* Write the buffer of data to the outfd */
-
- nbyteswritten = _NX_WRITE(outfd, wrbuffer, nbytesread);
-
- /* Check for a complete (or parial) write. write() should not
- * return zero.
- */
-
- if (nbyteswritten >= 0)
- {
- /* Advance the buffer pointer and decrement the number of
- * bytes remaining in the iobuffer. Typically, nbytesread
- * will now be zero.
- */
-
- wrbuffer += nbyteswritten;
- nbytesread -= nbyteswritten;
-
- /* Increment the total number of bytes successfully
- * transferred.
- */
-
- ntransferred += nbyteswritten;
- }
-
- /* Otherwise an error occurred */
-
- else
- {
- int errcode = _NX_GETERRNO(nbyteswritten);
-
- /* Check for a read ERROR. EINTR is a special case. This
- * function should break out and return an error if EINTR
- * is returned and no data has been transferred. But what
- * should it do if some data has been transferred? I
- * suppose just continue?
- */
-
- if (errcode != EINTR || ntransferred == 0)
- {
- /* Write error. Break out and return the error
- * condition.
- */
-
- _NX_SETERRNO(nbyteswritten);
- ntransferred = ERROR;
- endxfr = true;
- break;
- }
- }
- }
- while (nbytesread > 0);
- }
- }
-
- /* Release the I/O buffer */
-
- lib_free(iobuffer);
-
- /* Return the current file position */
-
- if (offset)
- {
- /* Use lseek to get the current file position */
-
- off_t curpos = _NX_SEEK(infd, 0, SEEK_CUR);
- if (curpos < 0)
- {
- int errcode = _NX_GETERRNO(curpos);
- _NX_SETERRNO(errcode);
- return ERROR;
- }
-
- /* Return the current file position */
-
- *offset = curpos;
-
- /* Use lseek again to restore the original file position */
-
- startpos = _NX_SEEK(infd, startpos, SEEK_SET);
- if (startpos < 0)
- {
- int errcode = _NX_GETERRNO(startpos);
- _NX_SETERRNO(errcode);
- return ERROR;
- }
- }
-
- /* Finally return the number of bytes actually transferred (or ERROR
- * if any failure occurred).
- */
-
- return ntransferred;
-}
diff --git a/net/socket/net_sendfile.c b/net/socket/net_sendfile.c
index c9407f7..c3f7bd4 100644
--- a/net/socket/net_sendfile.c
+++ b/net/socket/net_sendfile.c
@@ -74,7 +74,7 @@
*
* Returned Value:
* On success, returns the number of characters sent. On error,
- * -1 is returned, and errno is set appropriately:
+ * the negative errno is returned appropriately:
*
* EAGAIN or EWOULDBLOCK
* The socket is marked non-blocking and the requested operation
@@ -130,8 +130,8 @@ ssize_t psock_sendfile(FAR struct socket *psock, FAR struct file *infile,
if (psock == NULL || psock->s_conn == NULL)
{
nerr("ERROR: Invalid socket\n");
- _SO_SETERRNO(psock, EBADF);
- return ERROR;
+ psock->s_error = EBADF;
+ return -EBADF;
}
/* Check if the address family supports the optimized sendfile(). If not,
@@ -151,8 +151,7 @@ ssize_t psock_sendfile(FAR struct socket *psock, FAR struct file *infile,
if (ret < 0)
{
- _SO_SETERRNO(psock, -ret);
- return ERROR;
+ psock->s_error = -ret;
}
return ret;
diff --git a/syscall/syscall.csv b/syscall/syscall.csv
index 0f96f4e..bfbe88c 100644
--- a/syscall/syscall.csv
+++ b/syscall/syscall.csv
@@ -139,7 +139,7 @@
"sem_unlink","semaphore.h","defined(CONFIG_FS_NAMED_SEMAPHORES)","int","FAR const char *"
"sem_wait","semaphore.h","","int","FAR sem_t *"
"send","sys/socket.h","defined(CONFIG_NET)","ssize_t","int","FAR const void *","size_t","int"
-"sendfile","sys/sendfile.h","defined(CONFIG_NET_SENDFILE)","ssize_t","int","int","FAR off_t *","size_t"
+"sendfile","sys/sendfile.h","","ssize_t","int","int","FAR off_t *","size_t"
"sendmsg","sys/socket.h","defined(CONFIG_NET)","ssize_t","int","FAR struct msghdr *","int"
"sendto","sys/socket.h","defined(CONFIG_NET)","ssize_t","int","FAR const void *","size_t","int","FAR const struct sockaddr *","socklen_t"
"setenv","stdlib.h","!defined(CONFIG_DISABLE_ENVIRON)","int","FAR const char *","FAR const char *","int"