]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
3860. [bug] ioctl(DP_POLL) array size needs to be determined
authorMark Andrews <marka@isc.org>
Fri, 23 May 2014 03:05:23 +0000 (13:05 +1000)
committerMark Andrews <marka@isc.org>
Fri, 23 May 2014 03:06:25 +0000 (13:06 +1000)
                        at run time as it is limited to {OPEN_MAX}.
                        [RT #35878]

(cherry picked from commit a569e1b3213668bc704194367ea12c23456ad1d2)

CHANGES
lib/isc/unix/socket.c

diff --git a/CHANGES b/CHANGES
index 3ee9755dbcb0735950976371b52810ad848ab179..6d2b6f11386c67097794c5ec45541a67ef71e63e 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,7 @@
+3860.  [bug]           ioctl(DP_POLL) array size needs to be determined
+                       at run time as it is limited to {OPEN_MAX}.
+                       [RT #35878]
+
 3858.  [bug]           Disable GCC 4.9 "delete null pointer check".
                        [RT #35968]
 
index 0dd5bbce5e849ad39ca78f73004d75775c949423..c6c02ae2700afa81720a518939bbd85cb3376fac 100644 (file)
@@ -58,6 +58,7 @@
 #include <isc/platform.h>
 #include <isc/print.h>
 #include <isc/region.h>
+#include <isc/resource.h>
 #include <isc/socket.h>
 #include <isc/stats.h>
 #include <isc/strerror.h>
@@ -402,6 +403,8 @@ struct isc__socketmgr {
 #endif /* USE_EPOLL */
 #ifdef USE_DEVPOLL
        int                     devpoll_fd;
+       isc_resourcevalue_t     open_max;
+       unsigned int            calls;
        int                     nevents;
        struct pollfd           *events;
 #endif /* USE_DEVPOLL */
@@ -1168,8 +1171,6 @@ select_readmsg(isc__socketmgr_t *mgr, int *fd, int *msg) {
                                           "read() failed "
                                           "during watcher poke: %s"),
                            strbuf);
-
-               return;
        }
        INSIST(cc == sizeof(buf));
 
@@ -4098,8 +4099,10 @@ watcher(void *uap) {
 #elif defined (USE_EPOLL)
        const char *fnname = "epoll_wait()";
 #elif defined(USE_DEVPOLL)
+       isc_result_t result;
        const char *fnname = "ioctl(DP_POLL)";
        struct dvpoll dvp;
+       int pass;
 #elif defined (USE_SELECT)
        const char *fnname = "select()";
        int maxfd;
@@ -4126,17 +4129,45 @@ watcher(void *uap) {
                        cc = epoll_wait(manager->epoll_fd, manager->events,
                                        manager->nevents, -1);
 #elif defined(USE_DEVPOLL)
-                       dvp.dp_fds = manager->events;
-                       dvp.dp_nfds = manager->nevents;
+                       /*
+                        * Re-probe every thousand calls.
+                        */
+                       if (manager->calls++ > 1000U) {
+                               result = isc_resource_getcurlimit(
+                                                       isc_resource_openfiles,
+                                                       &manager->open_max);
+                               if (result != ISC_R_SUCCESS)
+                                       manager->open_max = 64;
+                               manager->calls == 0;
+                       }
+                       for (pass = 0; pass < 2; pass++) {
+                               dvp.dp_fds = manager->events;
+                               dvp.dp_nfds = manager->nevents;
+                               if (dvp.dp_nfds >= manager->open_max)
+                                       dvp.dp_nfds = manager->open_max - 1;
 #ifndef ISC_SOCKET_USE_POLLWATCH
-                       dvp.dp_timeout = -1;
-#else
-                       if (pollstate == poll_idle)
                                dvp.dp_timeout = -1;
-                       else
-                               dvp.dp_timeout = ISC_SOCKET_POLLWATCH_TIMEOUT;
+#else
+                               if (pollstate == poll_idle)
+                                       dvp.dp_timeout = -1;
+                               else
+                                       dvp.dp_timeout =
+                                                ISC_SOCKET_POLLWATCH_TIMEOUT;
 #endif /* ISC_SOCKET_USE_POLLWATCH */
-                       cc = ioctl(manager->devpoll_fd, DP_POLL, &dvp);
+                               cc = ioctl(manager->devpoll_fd, DP_POLL, &dvp);
+                               if (cc == -1 && errno == EINVAL) {
+                                       /*
+                                        * {OPEN_MAX} may have dropped.  Look
+                                        * up the current value and try again.
+                                        */
+                                       result = isc_resource_getcurlimit(
+                                                       isc_resource_openfiles,
+                                                       &manager->open_max);
+                                       if (result != ISC_R_SUCCESS)
+                                               manager->open_max = 64;
+                               } else
+                                       break;
+                       }
 #elif defined(USE_SELECT)
                        LOCK(&manager->lock);
                        memmove(manager->read_fds_copy, manager->read_fds,
@@ -4296,11 +4327,12 @@ setup_watcher(isc_mem_t *mctx, isc__socketmgr_t *manager) {
        }
 #endif /* USE_WATCHER_THREAD */
 #elif defined(USE_DEVPOLL)
-       /*
-        * XXXJT: /dev/poll seems to reject large numbers of events,
-        * so we should be careful about redefining ISC_SOCKET_MAXEVENTS.
-        */
        manager->nevents = ISC_SOCKET_MAXEVENTS;
+       result = isc_resource_getcurlimit(isc_resource_openfiles,
+                                         &manager->open_max);
+       if (result != ISC_R_SUCCESS)
+               manager->open_max = 64;
+       manager->calls = 0;
        manager->events = isc_mem_get(mctx, sizeof(struct pollfd) *
                                      manager->nevents);
        if (manager->events == NULL)
@@ -6149,8 +6181,6 @@ isc__socketmgr_waitevents(isc_socketmgr_t *manager0, struct timeval *tvp,
                          isc_socketwait_t **swaitp)
 {
        isc__socketmgr_t *manager = (isc__socketmgr_t *)manager0;
-
-
        int n;
 #ifdef USE_KQUEUE
        struct timespec ts, *tsp;
@@ -6159,6 +6189,8 @@ isc__socketmgr_waitevents(isc_socketmgr_t *manager0, struct timeval *tvp,
        int timeout;
 #endif
 #ifdef USE_DEVPOLL
+       isc_result_t result;
+       int pass;
        struct dvpoll dvp;
 #endif
 
@@ -6192,15 +6224,41 @@ isc__socketmgr_waitevents(isc_socketmgr_t *manager0, struct timeval *tvp,
                                           manager->nevents, timeout);
        n = swait_private.nevents;
 #elif defined(USE_DEVPOLL)
-       dvp.dp_fds = manager->events;
-       dvp.dp_nfds = manager->nevents;
-       if (tvp != NULL) {
-               dvp.dp_timeout = tvp->tv_sec * 1000 +
-                       (tvp->tv_usec + 999) / 1000;
-       } else
-               dvp.dp_timeout = -1;
-       swait_private.nevents = ioctl(manager->devpoll_fd, DP_POLL, &dvp);
-       n = swait_private.nevents;
+       /*
+        * Re-probe every thousand calls.
+        */
+       if (manager->calls++ > 1000U) {
+               result = isc_resource_getcurlimit(isc_resource_openfiles,
+                                                 &manager->open_max);
+               if (result != ISC_R_SUCCESS)
+                       manager->open_max = 64;
+               manager->calls == 0;
+       }
+       for (pass = 0; pass < 2; pass++) {
+               dvp.dp_fds = manager->events;
+               dvp.dp_nfds = manager->nevents;
+               if (dvp.dp_nfds >= manager->open_max)
+                       dvp.dp_nfds = manager->open_max - 1;
+               if (tvp != NULL) {
+                       dvp.dp_timeout = tvp->tv_sec * 1000 +
+                               (tvp->tv_usec + 999) / 1000;
+               } else
+                       dvp.dp_timeout = -1;
+               n = ioctl(manager->devpoll_fd, DP_POLL, &dvp);
+               if (n == -1 && errno == EINVAL) {
+                       /*
+                        * {OPEN_MAX} may have dropped.  Look
+                        * up the current value and try again.
+                        */
+                       result = isc_resource_getcurlimit(
+                                                       isc_resource_openfiles,
+                                                       &manager->open_max);
+                       if (result != ISC_R_SUCCESS)
+                               manager->open_max = 64;
+               } else
+                       break;
+       }
+       swait_private.nevents = n;
 #elif defined(USE_SELECT)
        memmove(manager->read_fds_copy, manager->read_fds, manager->fd_bufsize);
        memmove(manager->write_fds_copy, manager->write_fds,