diff options
author | Damien Miller <djm@mindrot.org> | 2012-04-22 11:21:10 +1000 |
---|---|---|
committer | Damien Miller <djm@mindrot.org> | 2012-04-22 11:21:10 +1000 |
commit | a6508753db3c49910068d8fc324bd284d72ff153 (patch) | |
tree | de5d49ef31b5ba61e9086316baf0bd2afb78fd1b | |
parent | c6081482b2b72caccce938c100c1b55f7b5e30fe (diff) |
- djm@cvs.openbsd.org 2012/04/11 13:16:19
[channels.c channels.h clientloop.c serverloop.c]
don't spin in accept() when out of fds (ENFILE/ENFILE) - back off for a
while; ok deraadt@ markus@
-rw-r--r-- | ChangeLog | 4 | ||||
-rw-r--r-- | channels.c | 52 | ||||
-rw-r--r-- | channels.h | 6 | ||||
-rw-r--r-- | clientloop.c | 8 | ||||
-rw-r--r-- | serverloop.c | 14 |
5 files changed, 68 insertions, 16 deletions
@@ -17,6 +17,10 @@ | |||
17 | [channels.c channels.h servconf.c] | 17 | [channels.c channels.h servconf.c] |
18 | Add PermitOpen none option based on patch from Loganaden Velvindron | 18 | Add PermitOpen none option based on patch from Loganaden Velvindron |
19 | (bz #1949). ok djm@ | 19 | (bz #1949). ok djm@ |
20 | - djm@cvs.openbsd.org 2012/04/11 13:16:19 | ||
21 | [channels.c channels.h clientloop.c serverloop.c] | ||
22 | don't spin in accept() when out of fds (ENFILE/ENFILE) - back off for a | ||
23 | while; ok deraadt@ markus@ | ||
20 | 24 | ||
21 | 20120420 | 25 | 20120420 |
22 | - (djm) [contrib/caldera/openssh.spec contrib/redhat/openssh.spec] | 26 | - (djm) [contrib/caldera/openssh.spec contrib/redhat/openssh.spec] |
diff --git a/channels.c b/channels.c index e5783b197..cacd2fe55 100644 --- a/channels.c +++ b/channels.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: channels.c,v 1.316 2012/03/29 23:54:36 dtucker Exp $ */ | 1 | /* $OpenBSD: channels.c,v 1.317 2012/04/11 13:16:19 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -311,6 +311,7 @@ channel_new(char *ctype, int type, int rfd, int wfd, int efd, | |||
311 | c->istate = CHAN_INPUT_OPEN; | 311 | c->istate = CHAN_INPUT_OPEN; |
312 | c->flags = 0; | 312 | c->flags = 0; |
313 | channel_register_fds(c, rfd, wfd, efd, extusage, nonblock, 0); | 313 | channel_register_fds(c, rfd, wfd, efd, extusage, nonblock, 0); |
314 | c->notbefore = 0; | ||
314 | c->self = found; | 315 | c->self = found; |
315 | c->type = type; | 316 | c->type = type; |
316 | c->ctype = ctype; | 317 | c->ctype = ctype; |
@@ -1339,6 +1340,8 @@ channel_post_x11_listener(Channel *c, fd_set *readset, fd_set *writeset) | |||
1339 | } | 1340 | } |
1340 | if (newsock < 0) { | 1341 | if (newsock < 0) { |
1341 | error("accept: %.100s", strerror(errno)); | 1342 | error("accept: %.100s", strerror(errno)); |
1343 | if (errno == EMFILE || errno == ENFILE) | ||
1344 | c->notbefore = time(NULL) + 1; | ||
1342 | return; | 1345 | return; |
1343 | } | 1346 | } |
1344 | set_nodelay(newsock); | 1347 | set_nodelay(newsock); |
@@ -1482,6 +1485,8 @@ channel_post_port_listener(Channel *c, fd_set *readset, fd_set *writeset) | |||
1482 | newsock = accept(c->sock, (struct sockaddr *)&addr, &addrlen); | 1485 | newsock = accept(c->sock, (struct sockaddr *)&addr, &addrlen); |
1483 | if (newsock < 0) { | 1486 | if (newsock < 0) { |
1484 | error("accept: %.100s", strerror(errno)); | 1487 | error("accept: %.100s", strerror(errno)); |
1488 | if (errno == EMFILE || errno == ENFILE) | ||
1489 | c->notbefore = time(NULL) + 1; | ||
1485 | return; | 1490 | return; |
1486 | } | 1491 | } |
1487 | set_nodelay(newsock); | 1492 | set_nodelay(newsock); |
@@ -1514,7 +1519,10 @@ channel_post_auth_listener(Channel *c, fd_set *readset, fd_set *writeset) | |||
1514 | addrlen = sizeof(addr); | 1519 | addrlen = sizeof(addr); |
1515 | newsock = accept(c->sock, (struct sockaddr *)&addr, &addrlen); | 1520 | newsock = accept(c->sock, (struct sockaddr *)&addr, &addrlen); |
1516 | if (newsock < 0) { | 1521 | if (newsock < 0) { |
1517 | error("accept from auth socket: %.100s", strerror(errno)); | 1522 | error("accept from auth socket: %.100s", |
1523 | strerror(errno)); | ||
1524 | if (errno == EMFILE || errno == ENFILE) | ||
1525 | c->notbefore = time(NULL) + 1; | ||
1518 | return; | 1526 | return; |
1519 | } | 1527 | } |
1520 | nc = channel_new("accepted auth socket", | 1528 | nc = channel_new("accepted auth socket", |
@@ -1917,6 +1925,8 @@ channel_post_mux_listener(Channel *c, fd_set *readset, fd_set *writeset) | |||
1917 | if ((newsock = accept(c->sock, (struct sockaddr*)&addr, | 1925 | if ((newsock = accept(c->sock, (struct sockaddr*)&addr, |
1918 | &addrlen)) == -1) { | 1926 | &addrlen)) == -1) { |
1919 | error("%s accept: %s", __func__, strerror(errno)); | 1927 | error("%s accept: %s", __func__, strerror(errno)); |
1928 | if (errno == EMFILE || errno == ENFILE) | ||
1929 | c->notbefore = time(NULL) + 1; | ||
1920 | return; | 1930 | return; |
1921 | } | 1931 | } |
1922 | 1932 | ||
@@ -2067,16 +2077,21 @@ channel_garbage_collect(Channel *c) | |||
2067 | } | 2077 | } |
2068 | 2078 | ||
2069 | static void | 2079 | static void |
2070 | channel_handler(chan_fn *ftab[], fd_set *readset, fd_set *writeset) | 2080 | channel_handler(chan_fn *ftab[], fd_set *readset, fd_set *writeset, |
2081 | time_t *unpause_secs) | ||
2071 | { | 2082 | { |
2072 | static int did_init = 0; | 2083 | static int did_init = 0; |
2073 | u_int i, oalloc; | 2084 | u_int i, oalloc; |
2074 | Channel *c; | 2085 | Channel *c; |
2086 | time_t now; | ||
2075 | 2087 | ||
2076 | if (!did_init) { | 2088 | if (!did_init) { |
2077 | channel_handler_init(); | 2089 | channel_handler_init(); |
2078 | did_init = 1; | 2090 | did_init = 1; |
2079 | } | 2091 | } |
2092 | now = time(NULL); | ||
2093 | if (unpause_secs != NULL) | ||
2094 | *unpause_secs = 0; | ||
2080 | for (i = 0, oalloc = channels_alloc; i < oalloc; i++) { | 2095 | for (i = 0, oalloc = channels_alloc; i < oalloc; i++) { |
2081 | c = channels[i]; | 2096 | c = channels[i]; |
2082 | if (c == NULL) | 2097 | if (c == NULL) |
@@ -2087,10 +2102,30 @@ channel_handler(chan_fn *ftab[], fd_set *readset, fd_set *writeset) | |||
2087 | else | 2102 | else |
2088 | continue; | 2103 | continue; |
2089 | } | 2104 | } |
2090 | if (ftab[c->type] != NULL) | 2105 | if (ftab[c->type] != NULL) { |
2091 | (*ftab[c->type])(c, readset, writeset); | 2106 | /* |
2107 | * Run handlers that are not paused. | ||
2108 | */ | ||
2109 | if (c->notbefore <= now) | ||
2110 | (*ftab[c->type])(c, readset, writeset); | ||
2111 | else if (unpause_secs != NULL) { | ||
2112 | /* | ||
2113 | * Collect the time that the earliest | ||
2114 | * channel comes off pause. | ||
2115 | */ | ||
2116 | debug3("%s: chan %d: skip for %d more seconds", | ||
2117 | __func__, c->self, | ||
2118 | (int)(c->notbefore - now)); | ||
2119 | if (*unpause_secs == 0 || | ||
2120 | (c->notbefore - now) < *unpause_secs) | ||
2121 | *unpause_secs = c->notbefore - now; | ||
2122 | } | ||
2123 | } | ||
2092 | channel_garbage_collect(c); | 2124 | channel_garbage_collect(c); |
2093 | } | 2125 | } |
2126 | if (unpause_secs != NULL && *unpause_secs != 0) | ||
2127 | debug3("%s: first channel unpauses in %d seconds", | ||
2128 | __func__, (int)*unpause_secs); | ||
2094 | } | 2129 | } |
2095 | 2130 | ||
2096 | /* | 2131 | /* |
@@ -2099,7 +2134,7 @@ channel_handler(chan_fn *ftab[], fd_set *readset, fd_set *writeset) | |||
2099 | */ | 2134 | */ |
2100 | void | 2135 | void |
2101 | channel_prepare_select(fd_set **readsetp, fd_set **writesetp, int *maxfdp, | 2136 | channel_prepare_select(fd_set **readsetp, fd_set **writesetp, int *maxfdp, |
2102 | u_int *nallocp, int rekeying) | 2137 | u_int *nallocp, int *minwait_secs, int rekeying) |
2103 | { | 2138 | { |
2104 | u_int n, sz, nfdset; | 2139 | u_int n, sz, nfdset; |
2105 | 2140 | ||
@@ -2122,7 +2157,8 @@ channel_prepare_select(fd_set **readsetp, fd_set **writesetp, int *maxfdp, | |||
2122 | memset(*writesetp, 0, sz); | 2157 | memset(*writesetp, 0, sz); |
2123 | 2158 | ||
2124 | if (!rekeying) | 2159 | if (!rekeying) |
2125 | channel_handler(channel_pre, *readsetp, *writesetp); | 2160 | channel_handler(channel_pre, *readsetp, *writesetp, |
2161 | minwait_secs); | ||
2126 | } | 2162 | } |
2127 | 2163 | ||
2128 | /* | 2164 | /* |
@@ -2132,7 +2168,7 @@ channel_prepare_select(fd_set **readsetp, fd_set **writesetp, int *maxfdp, | |||
2132 | void | 2168 | void |
2133 | channel_after_select(fd_set *readset, fd_set *writeset) | 2169 | channel_after_select(fd_set *readset, fd_set *writeset) |
2134 | { | 2170 | { |
2135 | channel_handler(channel_post, readset, writeset); | 2171 | channel_handler(channel_post, readset, writeset, NULL); |
2136 | } | 2172 | } |
2137 | 2173 | ||
2138 | 2174 | ||
diff --git a/channels.h b/channels.h index 6ed1ce00c..d75b800f7 100644 --- a/channels.h +++ b/channels.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: channels.h,v 1.110 2012/03/29 23:54:36 dtucker Exp $ */ | 1 | /* $OpenBSD: channels.h,v 1.111 2012/04/11 13:16:19 djm Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
@@ -105,6 +105,7 @@ struct Channel { | |||
105 | int wfd_isatty; /* wfd is a tty */ | 105 | int wfd_isatty; /* wfd is a tty */ |
106 | int client_tty; /* (client) TTY has been requested */ | 106 | int client_tty; /* (client) TTY has been requested */ |
107 | int force_drain; /* force close on iEOF */ | 107 | int force_drain; /* force close on iEOF */ |
108 | time_t notbefore; /* Pause IO until deadline (time_t) */ | ||
108 | int delayed; /* post-select handlers for newly created | 109 | int delayed; /* post-select handlers for newly created |
109 | * channels are delayed until the first call | 110 | * channels are delayed until the first call |
110 | * to a matching pre-select handler. | 111 | * to a matching pre-select handler. |
@@ -238,7 +239,8 @@ void channel_input_status_confirm(int, u_int32_t, void *); | |||
238 | 239 | ||
239 | /* file descriptor handling (read/write) */ | 240 | /* file descriptor handling (read/write) */ |
240 | 241 | ||
241 | void channel_prepare_select(fd_set **, fd_set **, int *, u_int*, int); | 242 | void channel_prepare_select(fd_set **, fd_set **, int *, u_int*, |
243 | time_t*, int); | ||
242 | void channel_after_select(fd_set *, fd_set *); | 244 | void channel_after_select(fd_set *, fd_set *); |
243 | void channel_output_poll(void); | 245 | void channel_output_poll(void); |
244 | 246 | ||
diff --git a/clientloop.c b/clientloop.c index f69a9b025..58357cf39 100644 --- a/clientloop.c +++ b/clientloop.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: clientloop.c,v 1.238 2012/01/18 21:46:43 dtucker Exp $ */ | 1 | /* $OpenBSD: clientloop.c,v 1.239 2012/04/11 13:16:19 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -583,10 +583,12 @@ client_wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, | |||
583 | { | 583 | { |
584 | struct timeval tv, *tvp; | 584 | struct timeval tv, *tvp; |
585 | int timeout_secs; | 585 | int timeout_secs; |
586 | time_t minwait_secs; | ||
586 | int ret; | 587 | int ret; |
587 | 588 | ||
588 | /* Add any selections by the channel mechanism. */ | 589 | /* Add any selections by the channel mechanism. */ |
589 | channel_prepare_select(readsetp, writesetp, maxfdp, nallocp, rekeying); | 590 | channel_prepare_select(readsetp, writesetp, maxfdp, nallocp, |
591 | &minwait_secs, rekeying); | ||
590 | 592 | ||
591 | if (!compat20) { | 593 | if (!compat20) { |
592 | /* Read from the connection, unless our buffers are full. */ | 594 | /* Read from the connection, unless our buffers are full. */ |
@@ -639,6 +641,8 @@ client_wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, | |||
639 | if (timeout_secs < 0) | 641 | if (timeout_secs < 0) |
640 | timeout_secs = 0; | 642 | timeout_secs = 0; |
641 | } | 643 | } |
644 | if (minwait_secs != 0) | ||
645 | timeout_secs = MIN(timeout_secs, (int)minwait_secs); | ||
642 | if (timeout_secs == INT_MAX) | 646 | if (timeout_secs == INT_MAX) |
643 | tvp = NULL; | 647 | tvp = NULL; |
644 | else { | 648 | else { |
diff --git a/serverloop.c b/serverloop.c index 19b84ff27..50be16b7c 100644 --- a/serverloop.c +++ b/serverloop.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: serverloop.c,v 1.160 2011/05/15 08:09:01 djm Exp $ */ | 1 | /* $OpenBSD: serverloop.c,v 1.161 2012/04/11 13:16:19 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -281,9 +281,18 @@ wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, int *maxfdp, | |||
281 | { | 281 | { |
282 | struct timeval tv, *tvp; | 282 | struct timeval tv, *tvp; |
283 | int ret; | 283 | int ret; |
284 | time_t minwait_secs; | ||
284 | int client_alive_scheduled = 0; | 285 | int client_alive_scheduled = 0; |
285 | int program_alive_scheduled = 0; | 286 | int program_alive_scheduled = 0; |
286 | 287 | ||
288 | /* Allocate and update select() masks for channel descriptors. */ | ||
289 | channel_prepare_select(readsetp, writesetp, maxfdp, nallocp, | ||
290 | &minwait_secs, 0); | ||
291 | |||
292 | if (minwait_secs != 0) | ||
293 | max_time_milliseconds = MIN(max_time_milliseconds, | ||
294 | (u_int)minwait_secs * 1000); | ||
295 | |||
287 | /* | 296 | /* |
288 | * if using client_alive, set the max timeout accordingly, | 297 | * if using client_alive, set the max timeout accordingly, |
289 | * and indicate that this particular timeout was for client | 298 | * and indicate that this particular timeout was for client |
@@ -298,9 +307,6 @@ wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, int *maxfdp, | |||
298 | max_time_milliseconds = options.client_alive_interval * 1000; | 307 | max_time_milliseconds = options.client_alive_interval * 1000; |
299 | } | 308 | } |
300 | 309 | ||
301 | /* Allocate and update select() masks for channel descriptors. */ | ||
302 | channel_prepare_select(readsetp, writesetp, maxfdp, nallocp, 0); | ||
303 | |||
304 | if (compat20) { | 310 | if (compat20) { |
305 | #if 0 | 311 | #if 0 |
306 | /* wrong: bad condition XXX */ | 312 | /* wrong: bad condition XXX */ |