You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by gu...@apache.org on 2021/07/17 10:39:24 UTC

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

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

gustavonihei pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git

commit 663104a2e922d1af321db7392c6865c2cc4779bf
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"