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 | } |