]> git.ipfire.org Git - thirdparty/openssh-portable.git/commitdiff
- djm@cvs.openbsd.org 2012/04/11 13:16:19
authorDamien Miller <djm@mindrot.org>
Sun, 22 Apr 2012 01:21:10 +0000 (11:21 +1000)
committerDamien Miller <djm@mindrot.org>
Sun, 22 Apr 2012 01:21:10 +0000 (11:21 +1000)
     [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@

ChangeLog
channels.c
channels.h
clientloop.c
serverloop.c

index 1b5e78a42a5cf081dc51b472b2f744b07f42384c..d19da34ae3dcb7b61944682c843dd3b933721693 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
      [channels.c channels.h servconf.c]
      Add PermitOpen none option based on patch from Loganaden Velvindron
      (bz #1949).  ok djm@
+   - 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@
 
 20120420
  - (djm) [contrib/caldera/openssh.spec contrib/redhat/openssh.spec]
index e5783b1974379bacd082f88c6e8cf9b3a3a813e9..cacd2fe5565e7f7a974121e022c37843af8782d9 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: channels.c,v 1.316 2012/03/29 23:54:36 dtucker Exp $ */
+/* $OpenBSD: channels.c,v 1.317 2012/04/11 13:16:19 djm Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * 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,
        c->istate = CHAN_INPUT_OPEN;
        c->flags = 0;
        channel_register_fds(c, rfd, wfd, efd, extusage, nonblock, 0);
+       c->notbefore = 0;
        c->self = found;
        c->type = type;
        c->ctype = ctype;
@@ -1339,6 +1340,8 @@ channel_post_x11_listener(Channel *c, fd_set *readset, fd_set *writeset)
                }
                if (newsock < 0) {
                        error("accept: %.100s", strerror(errno));
+                       if (errno == EMFILE || errno == ENFILE)
+                               c->notbefore = time(NULL) + 1;
                        return;
                }
                set_nodelay(newsock);
@@ -1482,6 +1485,8 @@ channel_post_port_listener(Channel *c, fd_set *readset, fd_set *writeset)
                newsock = accept(c->sock, (struct sockaddr *)&addr, &addrlen);
                if (newsock < 0) {
                        error("accept: %.100s", strerror(errno));
+                       if (errno == EMFILE || errno == ENFILE)
+                               c->notbefore = time(NULL) + 1;
                        return;
                }
                set_nodelay(newsock);
@@ -1514,7 +1519,10 @@ channel_post_auth_listener(Channel *c, fd_set *readset, fd_set *writeset)
                addrlen = sizeof(addr);
                newsock = accept(c->sock, (struct sockaddr *)&addr, &addrlen);
                if (newsock < 0) {
-                       error("accept from auth socket: %.100s", strerror(errno));
+                       error("accept from auth socket: %.100s",
+                           strerror(errno));
+                       if (errno == EMFILE || errno == ENFILE)
+                               c->notbefore = time(NULL) + 1;
                        return;
                }
                nc = channel_new("accepted auth socket",
@@ -1917,6 +1925,8 @@ channel_post_mux_listener(Channel *c, fd_set *readset, fd_set *writeset)
        if ((newsock = accept(c->sock, (struct sockaddr*)&addr,
            &addrlen)) == -1) {
                error("%s accept: %s", __func__, strerror(errno));
+               if (errno == EMFILE || errno == ENFILE)
+                       c->notbefore = time(NULL) + 1;
                return;
        }
 
@@ -2067,16 +2077,21 @@ channel_garbage_collect(Channel *c)
 }
 
 static void
-channel_handler(chan_fn *ftab[], fd_set *readset, fd_set *writeset)
+channel_handler(chan_fn *ftab[], fd_set *readset, fd_set *writeset,
+    time_t *unpause_secs)
 {
        static int did_init = 0;
        u_int i, oalloc;
        Channel *c;
+       time_t now;
 
        if (!did_init) {
                channel_handler_init();
                did_init = 1;
        }
+       now = time(NULL);
+       if (unpause_secs != NULL)
+               *unpause_secs = 0;
        for (i = 0, oalloc = channels_alloc; i < oalloc; i++) {
                c = channels[i];
                if (c == NULL)
@@ -2087,10 +2102,30 @@ channel_handler(chan_fn *ftab[], fd_set *readset, fd_set *writeset)
                        else
                                continue;
                }
-               if (ftab[c->type] != NULL)
-                       (*ftab[c->type])(c, readset, writeset);
+               if (ftab[c->type] != NULL) {
+                       /*
+                        * Run handlers that are not paused.
+                        */
+                       if (c->notbefore <= now)
+                               (*ftab[c->type])(c, readset, writeset);
+                       else if (unpause_secs != NULL) {
+                               /*
+                                * Collect the time that the earliest
+                                * channel comes off pause.
+                                */
+                               debug3("%s: chan %d: skip for %d more seconds",
+                                   __func__, c->self,
+                                   (int)(c->notbefore - now));
+                               if (*unpause_secs == 0 ||
+                                   (c->notbefore - now) < *unpause_secs)
+                                       *unpause_secs = c->notbefore - now;
+                       }
+               }
                channel_garbage_collect(c);
        }
+       if (unpause_secs != NULL && *unpause_secs != 0)
+               debug3("%s: first channel unpauses in %d seconds",
+                   __func__, (int)*unpause_secs);
 }
 
 /*
@@ -2099,7 +2134,7 @@ channel_handler(chan_fn *ftab[], fd_set *readset, fd_set *writeset)
  */
 void
 channel_prepare_select(fd_set **readsetp, fd_set **writesetp, int *maxfdp,
-    u_int *nallocp, int rekeying)
+    u_int *nallocp, int *minwait_secs, int rekeying)
 {
        u_int n, sz, nfdset;
 
@@ -2122,7 +2157,8 @@ channel_prepare_select(fd_set **readsetp, fd_set **writesetp, int *maxfdp,
        memset(*writesetp, 0, sz);
 
        if (!rekeying)
-               channel_handler(channel_pre, *readsetp, *writesetp);
+               channel_handler(channel_pre, *readsetp, *writesetp,
+                   minwait_secs);
 }
 
 /*
@@ -2132,7 +2168,7 @@ channel_prepare_select(fd_set **readsetp, fd_set **writesetp, int *maxfdp,
 void
 channel_after_select(fd_set *readset, fd_set *writeset)
 {
-       channel_handler(channel_post, readset, writeset);
+       channel_handler(channel_post, readset, writeset, NULL);
 }
 
 
index 6ed1ce00c9efea6872d81e75374bbcbee46c519b..d75b800f705a5870c6880e803fb76b439b93b85e 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: channels.h,v 1.110 2012/03/29 23:54:36 dtucker Exp $ */
+/* $OpenBSD: channels.h,v 1.111 2012/04/11 13:16:19 djm Exp $ */
 
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -105,6 +105,7 @@ struct Channel {
        int     wfd_isatty;     /* wfd is a tty */
        int     client_tty;     /* (client) TTY has been requested */
        int     force_drain;    /* force close on iEOF */
+       time_t  notbefore;      /* Pause IO until deadline (time_t) */
        int     delayed;        /* post-select handlers for newly created
                                 * channels are delayed until the first call
                                 * to a matching pre-select handler. 
@@ -238,7 +239,8 @@ void         channel_input_status_confirm(int, u_int32_t, void *);
 
 /* file descriptor handling (read/write) */
 
-void    channel_prepare_select(fd_set **, fd_set **, int *, u_int*, int);
+void    channel_prepare_select(fd_set **, fd_set **, int *, u_int*,
+            time_t*, int);
 void     channel_after_select(fd_set *, fd_set *);
 void     channel_output_poll(void);
 
index f69a9b025d49bd73dd06aadd966475264f5ce8a0..58357cf39865486e690f1041f5740bd463dbd834 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: clientloop.c,v 1.238 2012/01/18 21:46:43 dtucker Exp $ */
+/* $OpenBSD: clientloop.c,v 1.239 2012/04/11 13:16:19 djm Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * 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,
 {
        struct timeval tv, *tvp;
        int timeout_secs;
+       time_t minwait_secs;
        int ret;
 
        /* Add any selections by the channel mechanism. */
-       channel_prepare_select(readsetp, writesetp, maxfdp, nallocp, rekeying);
+       channel_prepare_select(readsetp, writesetp, maxfdp, nallocp,
+           &minwait_secs, rekeying);
 
        if (!compat20) {
                /* 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,
                if (timeout_secs < 0)
                        timeout_secs = 0;
        }
+       if (minwait_secs != 0)
+               timeout_secs = MIN(timeout_secs, (int)minwait_secs);
        if (timeout_secs == INT_MAX)
                tvp = NULL;
        else {
index 19b84ff27d19d74ce25973ccfd035b95973e6a8b..50be16b7cc24c1aa7b6433d695c5cc4ff127fd48 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: serverloop.c,v 1.160 2011/05/15 08:09:01 djm Exp $ */
+/* $OpenBSD: serverloop.c,v 1.161 2012/04/11 13:16:19 djm Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * 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,
 {
        struct timeval tv, *tvp;
        int ret;
+       time_t minwait_secs;
        int client_alive_scheduled = 0;
        int program_alive_scheduled = 0;
 
+       /* Allocate and update select() masks for channel descriptors. */
+       channel_prepare_select(readsetp, writesetp, maxfdp, nallocp,
+           &minwait_secs, 0);
+
+       if (minwait_secs != 0)
+               max_time_milliseconds = MIN(max_time_milliseconds,
+                   (u_int)minwait_secs * 1000);
+
        /*
         * if using client_alive, set the max timeout accordingly,
         * 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,
                max_time_milliseconds = options.client_alive_interval * 1000;
        }
 
-       /* Allocate and update select() masks for channel descriptors. */
-       channel_prepare_select(readsetp, writesetp, maxfdp, nallocp, 0);
-
        if (compat20) {
 #if 0
                /* wrong: bad condition XXX */