diff options
| -rw-r--r-- | Config.in | 12 | ||||
| -rw-r--r-- | libbb/copyfd.c | 87 | ||||
| -rw-r--r-- | networking/Config.src | 8 | ||||
| -rw-r--r-- | networking/httpd.c | 6 |
4 files changed, 71 insertions, 42 deletions
| @@ -264,6 +264,18 @@ config PAM | |||
| 264 | Use PAM in some busybox applets (currently login and httpd) instead | 264 | Use PAM in some busybox applets (currently login and httpd) instead |
| 265 | of direct access to password database. | 265 | of direct access to password database. |
| 266 | 266 | ||
| 267 | config FEATURE_USE_SENDFILE | ||
| 268 | bool "Use sendfile system call" | ||
| 269 | default y | ||
| 270 | help | ||
| 271 | When enabled, busybox will use the kernel sendfile() function | ||
| 272 | instead of read/write loops to copy data between file descriptors | ||
| 273 | (for example, cp command does this a lot). | ||
| 274 | If sendfile() doesn't work, copying code falls back to read/write | ||
| 275 | loop. sendfile() was originally implemented for faster I/O | ||
| 276 | from files to sockets, but since Linux 2.6.33 it was extended | ||
| 277 | to work for many more file types. | ||
| 278 | |||
| 267 | config LONG_OPTS | 279 | config LONG_OPTS |
| 268 | bool "Support for --long-options" | 280 | bool "Support for --long-options" |
| 269 | default y | 281 | default y |
diff --git a/libbb/copyfd.c b/libbb/copyfd.c index eda2747f9..7e3531903 100644 --- a/libbb/copyfd.c +++ b/libbb/copyfd.c | |||
| @@ -8,6 +8,20 @@ | |||
| 8 | */ | 8 | */ |
| 9 | 9 | ||
| 10 | #include "libbb.h" | 10 | #include "libbb.h" |
| 11 | #if ENABLE_FEATURE_USE_SENDFILE | ||
| 12 | # include <sys/sendfile.h> | ||
| 13 | #else | ||
| 14 | # define sendfile(a,b,c,d) (-1) | ||
| 15 | #endif | ||
| 16 | |||
| 17 | /* | ||
| 18 | * We were using 0x7fff0000 as sendfile chunk size, but it | ||
| 19 | * was seen to cause largish delays when user tries to ^C a file copy. | ||
| 20 | * Let's use a saner size. | ||
| 21 | * Note: needs to be >= max(CONFIG_FEATURE_COPYBUF_KB), | ||
| 22 | * or else "copy to eof" code will use neddlesly short reads. | ||
| 23 | */ | ||
| 24 | #define SENDFILE_BIGBUF (16*1024*1024) | ||
| 11 | 25 | ||
| 12 | /* Used by NOFORK applets (e.g. cat) - must not use xmalloc. | 26 | /* Used by NOFORK applets (e.g. cat) - must not use xmalloc. |
| 13 | * size < 0 means "ignore write errors", used by tar --to-command | 27 | * size < 0 means "ignore write errors", used by tar --to-command |
| @@ -18,12 +32,13 @@ static off_t bb_full_fd_action(int src_fd, int dst_fd, off_t size) | |||
| 18 | int status = -1; | 32 | int status = -1; |
| 19 | off_t total = 0; | 33 | off_t total = 0; |
| 20 | bool continue_on_write_error = 0; | 34 | bool continue_on_write_error = 0; |
| 21 | #if CONFIG_FEATURE_COPYBUF_KB <= 4 | 35 | ssize_t sendfile_sz; |
| 36 | #if CONFIG_FEATURE_COPYBUF_KB > 4 | ||
| 37 | char *buffer = buffer; /* for compiler */ | ||
| 38 | int buffer_size = 0; | ||
| 39 | #else | ||
| 22 | char buffer[CONFIG_FEATURE_COPYBUF_KB * 1024]; | 40 | char buffer[CONFIG_FEATURE_COPYBUF_KB * 1024]; |
| 23 | enum { buffer_size = sizeof(buffer) }; | 41 | enum { buffer_size = sizeof(buffer) }; |
| 24 | #else | ||
| 25 | char *buffer; | ||
| 26 | int buffer_size; | ||
| 27 | #endif | 42 | #endif |
| 28 | 43 | ||
| 29 | if (size < 0) { | 44 | if (size < 0) { |
| @@ -31,46 +46,58 @@ static off_t bb_full_fd_action(int src_fd, int dst_fd, off_t size) | |||
| 31 | continue_on_write_error = 1; | 46 | continue_on_write_error = 1; |
| 32 | } | 47 | } |
| 33 | 48 | ||
| 34 | #if CONFIG_FEATURE_COPYBUF_KB > 4 | ||
| 35 | if (size > 0 && size <= 4 * 1024) | ||
| 36 | goto use_small_buf; | ||
| 37 | /* We want page-aligned buffer, just in case kernel is clever | ||
| 38 | * and can do page-aligned io more efficiently */ | ||
| 39 | buffer = mmap(NULL, CONFIG_FEATURE_COPYBUF_KB * 1024, | ||
| 40 | PROT_READ | PROT_WRITE, | ||
| 41 | MAP_PRIVATE | MAP_ANON, | ||
| 42 | /* ignored: */ -1, 0); | ||
| 43 | buffer_size = CONFIG_FEATURE_COPYBUF_KB * 1024; | ||
| 44 | if (buffer == MAP_FAILED) { | ||
| 45 | use_small_buf: | ||
| 46 | buffer = alloca(4 * 1024); | ||
| 47 | buffer_size = 4 * 1024; | ||
| 48 | } | ||
| 49 | #endif | ||
| 50 | |||
| 51 | if (src_fd < 0) | 49 | if (src_fd < 0) |
| 52 | goto out; | 50 | goto out; |
| 53 | 51 | ||
| 52 | sendfile_sz = !ENABLE_FEATURE_USE_SENDFILE | ||
| 53 | ? 0 | ||
| 54 | : SENDFILE_BIGBUF; | ||
| 54 | if (!size) { | 55 | if (!size) { |
| 55 | size = buffer_size; | 56 | size = SENDFILE_BIGBUF; |
| 56 | status = 1; /* copy until eof */ | 57 | status = 1; /* copy until eof */ |
| 57 | } | 58 | } |
| 58 | 59 | ||
| 59 | while (1) { | 60 | while (1) { |
| 60 | ssize_t rd; | 61 | ssize_t rd; |
| 61 | 62 | ||
| 62 | rd = safe_read(src_fd, buffer, size > buffer_size ? buffer_size : size); | 63 | if (sendfile_sz) { |
| 63 | 64 | rd = sendfile(dst_fd, src_fd, NULL, | |
| 64 | if (!rd) { /* eof - all done */ | 65 | size > sendfile_sz ? sendfile_sz : size); |
| 65 | status = 0; | 66 | if (rd >= 0) |
| 66 | break; | 67 | goto read_ok; |
| 68 | sendfile_sz = 0; /* do not try sendfile anymore */ | ||
| 69 | } | ||
| 70 | #if CONFIG_FEATURE_COPYBUF_KB > 4 | ||
| 71 | if (buffer_size == 0) { | ||
| 72 | if (size > 0 && size <= 4 * 1024) | ||
| 73 | goto use_small_buf; | ||
| 74 | /* We want page-aligned buffer, just in case kernel is clever | ||
| 75 | * and can do page-aligned io more efficiently */ | ||
| 76 | buffer = mmap(NULL, CONFIG_FEATURE_COPYBUF_KB * 1024, | ||
| 77 | PROT_READ | PROT_WRITE, | ||
| 78 | MAP_PRIVATE | MAP_ANON, | ||
| 79 | /* ignored: */ -1, 0); | ||
| 80 | buffer_size = CONFIG_FEATURE_COPYBUF_KB * 1024; | ||
| 81 | if (buffer == MAP_FAILED) { | ||
| 82 | use_small_buf: | ||
| 83 | buffer = alloca(4 * 1024); | ||
| 84 | buffer_size = 4 * 1024; | ||
| 85 | } | ||
| 67 | } | 86 | } |
| 87 | #endif | ||
| 88 | rd = safe_read(src_fd, buffer, | ||
| 89 | size > buffer_size ? buffer_size : size); | ||
| 68 | if (rd < 0) { | 90 | if (rd < 0) { |
| 69 | bb_perror_msg(bb_msg_read_error); | 91 | bb_perror_msg(bb_msg_read_error); |
| 70 | break; | 92 | break; |
| 71 | } | 93 | } |
| 94 | read_ok: | ||
| 95 | if (!rd) { /* eof - all done */ | ||
| 96 | status = 0; | ||
| 97 | break; | ||
| 98 | } | ||
| 72 | /* dst_fd == -1 is a fake, else... */ | 99 | /* dst_fd == -1 is a fake, else... */ |
| 73 | if (dst_fd >= 0) { | 100 | if (dst_fd >= 0 && !sendfile_sz) { |
| 74 | ssize_t wr = full_write(dst_fd, buffer, rd); | 101 | ssize_t wr = full_write(dst_fd, buffer, rd); |
| 75 | if (wr < rd) { | 102 | if (wr < rd) { |
| 76 | if (!continue_on_write_error) { | 103 | if (!continue_on_write_error) { |
| @@ -92,10 +119,8 @@ static off_t bb_full_fd_action(int src_fd, int dst_fd, off_t size) | |||
| 92 | } | 119 | } |
| 93 | out: | 120 | out: |
| 94 | 121 | ||
| 95 | #if CONFIG_FEATURE_COPYBUF_KB > 4 | 122 | if (buffer_size > 4 * 1024) |
| 96 | if (buffer_size != 4 * 1024) | ||
| 97 | munmap(buffer, buffer_size); | 123 | munmap(buffer, buffer_size); |
| 98 | #endif | ||
| 99 | return status ? -1 : total; | 124 | return status ? -1 : total; |
| 100 | } | 125 | } |
| 101 | 126 | ||
diff --git a/networking/Config.src b/networking/Config.src index e56646917..15a696876 100644 --- a/networking/Config.src +++ b/networking/Config.src | |||
| @@ -181,14 +181,6 @@ config FEATURE_HTTPD_RANGES | |||
| 181 | "Range: bytes=NNN-[MMM]" header. Allows for resuming interrupted | 181 | "Range: bytes=NNN-[MMM]" header. Allows for resuming interrupted |
| 182 | downloads, seeking in multimedia players etc. | 182 | downloads, seeking in multimedia players etc. |
| 183 | 183 | ||
| 184 | config FEATURE_HTTPD_USE_SENDFILE | ||
| 185 | bool "Use sendfile system call" | ||
| 186 | default y | ||
| 187 | depends on HTTPD | ||
| 188 | help | ||
| 189 | When enabled, httpd will use the kernel sendfile() function | ||
| 190 | instead of read/write loop. | ||
| 191 | |||
| 192 | config FEATURE_HTTPD_SETUID | 184 | config FEATURE_HTTPD_SETUID |
| 193 | bool "Enable -u <user> option" | 185 | bool "Enable -u <user> option" |
| 194 | default y | 186 | default y |
diff --git a/networking/httpd.c b/networking/httpd.c index 621d9cddc..9cf080401 100644 --- a/networking/httpd.c +++ b/networking/httpd.c | |||
| @@ -133,7 +133,7 @@ | |||
| 133 | # include <security/pam_appl.h> | 133 | # include <security/pam_appl.h> |
| 134 | # include <security/pam_misc.h> | 134 | # include <security/pam_misc.h> |
| 135 | #endif | 135 | #endif |
| 136 | #if ENABLE_FEATURE_HTTPD_USE_SENDFILE | 136 | #if ENABLE_FEATURE_USE_SENDFILE |
| 137 | # include <sys/sendfile.h> | 137 | # include <sys/sendfile.h> |
| 138 | #endif | 138 | #endif |
| 139 | /* amount of buffering in a pipe */ | 139 | /* amount of buffering in a pipe */ |
| @@ -1624,7 +1624,7 @@ static NOINLINE void send_file_and_exit(const char *url, int what) | |||
| 1624 | #endif | 1624 | #endif |
| 1625 | if (what & SEND_HEADERS) | 1625 | if (what & SEND_HEADERS) |
| 1626 | send_headers(HTTP_OK); | 1626 | send_headers(HTTP_OK); |
| 1627 | #if ENABLE_FEATURE_HTTPD_USE_SENDFILE | 1627 | #if ENABLE_FEATURE_USE_SENDFILE |
| 1628 | { | 1628 | { |
| 1629 | off_t offset = range_start; | 1629 | off_t offset = range_start; |
| 1630 | while (1) { | 1630 | while (1) { |
| @@ -1654,7 +1654,7 @@ static NOINLINE void send_file_and_exit(const char *url, int what) | |||
| 1654 | break; | 1654 | break; |
| 1655 | } | 1655 | } |
| 1656 | if (count < 0) { | 1656 | if (count < 0) { |
| 1657 | IF_FEATURE_HTTPD_USE_SENDFILE(fin:) | 1657 | IF_FEATURE_USE_SENDFILE(fin:) |
| 1658 | if (verbose > 1) | 1658 | if (verbose > 1) |
| 1659 | bb_perror_msg("error"); | 1659 | bb_perror_msg("error"); |
| 1660 | } | 1660 | } |
