summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien Miller <djm@mindrot.org>2012-04-22 11:21:10 +1000
committerDamien Miller <djm@mindrot.org>2012-04-22 11:21:10 +1000
commita6508753db3c49910068d8fc324bd284d72ff153 (patch)
treede5d49ef31b5ba61e9086316baf0bd2afb78fd1b
parentc6081482b2b72caccce938c100c1b55f7b5e30fe (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--ChangeLog4
-rw-r--r--channels.c52
-rw-r--r--channels.h6
-rw-r--r--clientloop.c8
-rw-r--r--serverloop.c14
5 files changed, 68 insertions, 16 deletions
diff --git a/ChangeLog b/ChangeLog
index 1b5e78a42..d19da34ae 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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
2120120420 2520120420
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
2069static void 2079static void
2070channel_handler(chan_fn *ftab[], fd_set *readset, fd_set *writeset) 2080channel_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 */
2100void 2135void
2101channel_prepare_select(fd_set **readsetp, fd_set **writesetp, int *maxfdp, 2136channel_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,
2132void 2168void
2133channel_after_select(fd_set *readset, fd_set *writeset) 2169channel_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
241void channel_prepare_select(fd_set **, fd_set **, int *, u_int*, int); 242void channel_prepare_select(fd_set **, fd_set **, int *, u_int*,
243 time_t*, int);
242void channel_after_select(fd_set *, fd_set *); 244void channel_after_select(fd_set *, fd_set *);
243void channel_output_poll(void); 245void 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 */