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:45 UTC

[incubator-nuttx] branch socket created (now 330b2b0)

This is an automated email from the ASF dual-hosted git repository.

xiaoxiang pushed a change to branch socket
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git.


      at 330b2b0  fs: Simplify sendfile implementation

This branch includes the following new commits:

     new 330b2b0  fs: Simplify sendfile implementation

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


[incubator-nuttx] 01/01: fs: Simplify sendfile implementation

Posted by xi...@apache.org.
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"