Busybox already uses sendfile in httpd. This patch proposes to use it
globally to copy data between file descriptors.

It speeds up the copying on slow systems a lot - below are the times needed
to copy a 450Mb file with and without this option enabled on a BeagleBone
Black:

sendfile:
user    0m0.000s
sys     0m8.170s

read/write:
user    0m0.470s
sys     0m16.300s

It doesn't add a lot of bloat either:

function                                             old     new   delta
bb_full_fd_action                                    233     311     +78
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/0 up/down: 78/0)               Total: 78 bytes
   text    data     bss     dec     hex filename
 812839    4123    9552  826514   c9c92 busybox_old
 812917    4123    9552  826592   c9ce0 busybox_unstripped

This patch also moves USE_SENDFILE feature from httpd subconfiguration
to global settings.

Signed-off-by: Bartosz Golaszewski <bartekg...@gmail.com>
---
 Config.in             |  8 +++++++
 libbb/copyfd.c        | 59 ++++++++++++++++++++++++++++++++++++++++-----------
 networking/Config.src |  8 -------
 networking/httpd.c    |  6 +++---
 4 files changed, 58 insertions(+), 23 deletions(-)

diff --git a/Config.in b/Config.in
index b83beb5..4b5ea69 100644
--- a/Config.in
+++ b/Config.in
@@ -264,6 +264,14 @@ config PAM
          Use PAM in some busybox applets (currently login and httpd) instead
          of direct access to password database.
 
+config FEATURE_USE_SENDFILE
+        bool "Use sendfile system call"
+        default y
+        depends on HTTPD
+        help
+          When enabled, busybox will use the kernel sendfile() function
+          instead of read/write loops where applicable.
+
 config LONG_OPTS
        bool "Support for --long-options"
        default y
diff --git a/libbb/copyfd.c b/libbb/copyfd.c
index eda2747..e10fe82 100644
--- a/libbb/copyfd.c
+++ b/libbb/copyfd.c
@@ -9,6 +9,28 @@
 
 #include "libbb.h"
 
+#if ENABLE_FEATURE_USE_SENDFILE
+#include <sys/sendfile.h>
+#endif
+
+/*
+ * Returns 1 if all bytes have been copied, 0 otherwise.
+ */
+static int check_status(int *status, off_t *size, off_t *total, ssize_t rd)
+{
+       *total += rd;
+       if (*status < 0) { /* if we aren't copying till EOF... */
+               *size -= rd;
+               if (!(*size)) {
+                       /* 'size' bytes copied - all done */
+                       *status = 0;
+                       return 1;
+               }
+       }
+
+       return 0;
+}
+
 /* Used by NOFORK applets (e.g. cat) - must not use xmalloc.
  * size < 0 means "ignore write errors", used by tar --to-command
  * size = 0 means "copy till EOF"
@@ -18,6 +40,7 @@ static off_t bb_full_fd_action(int src_fd, int dst_fd, off_t 
size)
        int status = -1;
        off_t total = 0;
        bool continue_on_write_error = 0;
+       ssize_t rd;
 #if CONFIG_FEATURE_COPYBUF_KB <= 4
        char buffer[CONFIG_FEATURE_COPYBUF_KB * 1024];
        enum { buffer_size = sizeof(buffer) };
@@ -56,10 +79,29 @@ static off_t bb_full_fd_action(int src_fd, int dst_fd, 
off_t size)
                status = 1; /* copy until eof */
        }
 
-       while (1) {
-               ssize_t rd;
+#if ENABLE_FEATURE_USE_SENDFILE
+       {
+               ssize_t sz = size && (size < buffer_size)
+                               ? size : MAXINT(ssize_t) - 0xffff;
 
-               rd = safe_read(src_fd, buffer, size > buffer_size ? buffer_size 
: size);
+               while (1) {
+                       rd = sendfile(dst_fd, src_fd, NULL, sz);
+                       if (rd <= 0) {
+                               /* Might be EOF, might be an error,
+                                * to make sure fall back to the read-write
+                                * loop.
+                                */
+                               break;
+                       } else if (check_status(&status, &size, &total, rd)) {
+                               break;
+                       }
+               }
+       }
+#endif
+
+       while (1) {
+               rd = safe_read(src_fd, buffer,
+                               size > buffer_size ? buffer_size : size);
 
                if (!rd) { /* eof - all done */
                        status = 0;
@@ -80,15 +122,8 @@ static off_t bb_full_fd_action(int src_fd, int dst_fd, 
off_t size)
                                dst_fd = -1;
                        }
                }
-               total += rd;
-               if (status < 0) { /* if we aren't copying till EOF... */
-                       size -= rd;
-                       if (!size) {
-                               /* 'size' bytes copied - all done */
-                               status = 0;
-                               break;
-                       }
-               }
+               if (check_status(&status, &size, &total, rd))
+                       break;
        }
  out:
 
diff --git a/networking/Config.src b/networking/Config.src
index e566469..15a6968 100644
--- a/networking/Config.src
+++ b/networking/Config.src
@@ -181,14 +181,6 @@ config FEATURE_HTTPD_RANGES
          "Range: bytes=NNN-[MMM]" header. Allows for resuming interrupted
          downloads, seeking in multimedia players etc.
 
-config FEATURE_HTTPD_USE_SENDFILE
-       bool "Use sendfile system call"
-       default y
-       depends on HTTPD
-       help
-         When enabled, httpd will use the kernel sendfile() function
-         instead of read/write loop.
-
 config FEATURE_HTTPD_SETUID
        bool "Enable -u <user> option"
        default y
diff --git a/networking/httpd.c b/networking/httpd.c
index 621d9cd..9cf0804 100644
--- a/networking/httpd.c
+++ b/networking/httpd.c
@@ -133,7 +133,7 @@
 # include <security/pam_appl.h>
 # include <security/pam_misc.h>
 #endif
-#if ENABLE_FEATURE_HTTPD_USE_SENDFILE
+#if ENABLE_FEATURE_USE_SENDFILE
 # include <sys/sendfile.h>
 #endif
 /* amount of buffering in a pipe */
@@ -1624,7 +1624,7 @@ static NOINLINE void send_file_and_exit(const char *url, 
int what)
 #endif
        if (what & SEND_HEADERS)
                send_headers(HTTP_OK);
-#if ENABLE_FEATURE_HTTPD_USE_SENDFILE
+#if ENABLE_FEATURE_USE_SENDFILE
        {
                off_t offset = range_start;
                while (1) {
@@ -1654,7 +1654,7 @@ static NOINLINE void send_file_and_exit(const char *url, 
int what)
                        break;
        }
        if (count < 0) {
- IF_FEATURE_HTTPD_USE_SENDFILE(fin:)
+ IF_FEATURE_USE_SENDFILE(fin:)
                if (verbose > 1)
                        bb_perror_msg("error");
        }
-- 
2.1.1

_______________________________________________
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox

Reply via email to