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