diff --git a/CHANGES b/CHANGES index 3ee9755dbc..6d2b6f1138 100644 --- 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] diff --git a/lib/isc/unix/socket.c b/lib/isc/unix/socket.c index 0dd5bbce5e..c6c02ae270 100644 --- a/lib/isc/unix/socket.c +++ b/lib/isc/unix/socket.c @@ -58,6 +58,7 @@ #include #include #include +#include #include #include #include @@ -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,