Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 130701790bf2d95e902edf16031ff596 > files > 90

autofs-5.0.1-0.rc2.164.el5_8.src.rpm

autofs-5.0.4 - fix select fd limit

From: Ian Kent <raven@themaw.net>

Using a large number of direct mounts causes autofs to hang. This is
because select(2) is limited to 1024 file handles (usually). To resolve
this we need to convert calls to select(2) to use poll(2).
---

 daemon/spawn.c           |   19 ++++++-----
 lib/rpc_subs.c           |   32 ++++++++++++++------
 modules/lookup_program.c |   75 ++++++++++++++++++++++++++++-------------------
 3 files changed, 78 insertions(+), 48 deletions(-)


--- autofs-5.0.1.orig/daemon/spawn.c
+++ autofs-5.0.1/daemon/spawn.c
@@ -23,6 +23,7 @@
 #include <dirent.h>
 #include <unistd.h>
 #include <time.h>
+#include <poll.h>
 #include <sys/wait.h>
 #include <sys/stat.h>
 #include <sys/mount.h>
@@ -91,21 +92,21 @@ void reset_signals(void)
 
 static int timed_read(int pipe, char *buf, size_t len, int time)
 {
-	struct timeval timeout = { 0, 0 };
-	struct timeval *tout = NULL;
-	fd_set wset, rset;
+	struct pollfd pfd[1];
+	int timeout = time;
 	int ret;
 
-	FD_ZERO(&rset);
-	FD_SET(pipe, &rset);
-	wset = rset;
+	pfd[0].fd = pipe;
+	pfd[0].events = POLLIN;
 
 	if (time != -1) {
-		timeout.tv_sec = time;
-		tout = &timeout;
+		if (time >= (INT_MAX - 1)/1000)
+			timeout = INT_MAX - 1;
+		else
+			timeout = time * 1000;
 	}
 
-	ret = select(pipe + 1, &rset, &wset, NULL, tout);
+	ret = poll(pfd, 1, timeout);
 	if (ret <= 0) {
 		if (ret == 0)
 			ret = -ETIMEDOUT;
--- autofs-5.0.1.orig/lib/rpc_subs.c
+++ autofs-5.0.1/lib/rpc_subs.c
@@ -31,6 +31,7 @@
 #include <rpcsvc/ypclnt.h>
 #include <errno.h>
 #include <sys/ioctl.h>
+#include <poll.h>
 
 #include "mount.h"
 #include "rpc_subs.h"
@@ -189,14 +190,15 @@ void rpc_destroy_udp_client(struct conn_
 /*
  *  Perform a non-blocking connect on the socket fd.
  *
- *  tout contains the timeout.  It will be modified to contain the time
- *  remaining (i.e. time provided - time elasped).
+ *  The input struct timeval always has tv_nsec set to zero,
+ *  we only ever use tv_sec for timeouts.
  */
 static int connect_nb(int fd, struct sockaddr_in *addr, struct timeval *tout)
 {
+	struct pollfd pfd[1];
+	int timeout = tout->tv_sec;
 	int flags, ret;
 	socklen_t len;
-	fd_set wset, rset;
 
 	flags = fcntl(fd, F_GETFL, 0);
 	if (flags < 0)
@@ -221,12 +223,10 @@ static int connect_nb(int fd, struct soc
 	if (ret == 0)
 		goto done;
 
-	/* now wait */
-	FD_ZERO(&rset);
-	FD_SET(fd, &rset);
-	wset = rset;
+	pfd[0].fd = fd;
+	pfd[0].events = POLLOUT;
 
-	ret = select(fd + 1, &rset, &wset, NULL, tout);
+	ret = poll(pfd, 1, timeout);
 	if (ret <= 0) {
 		if (ret == 0)
 			ret = -ETIMEDOUT;
@@ -235,13 +235,27 @@ static int connect_nb(int fd, struct soc
 		goto done;
 	}
 
-	if (FD_ISSET(fd, &rset) || FD_ISSET(fd, &wset)) {
+	if (pfd[0].revents) {
 		int status;
 
 		len = sizeof(ret);
 		status = getsockopt(fd, SOL_SOCKET, SO_ERROR, &ret, &len);
 		if (status < 0) {
+			char buf[MAX_ERR_BUF + 1];
+			char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+
+			/*
+			 * We assume getsockopt amounts to a read on the
+			 * descriptor and gives us the errno we need for
+			 * the POLLERR revent case.
+			 */
 			ret = -errno;
+
+			/* Unexpected case, log it so we know we got caught */
+			if (pfd[0].revents & POLLNVAL)
+				logerr("unexpected poll(2) error on connect:"
+				       " %s", estr);
+
 			goto done;
 		}
 
--- autofs-5.0.1.orig/modules/lookup_program.c
+++ autofs-5.0.1/modules/lookup_program.c
@@ -25,6 +25,7 @@
 #include <sys/times.h>
 #include <sys/types.h>
 #include <sys/wait.h>
+#include <poll.h>
 
 #define MODULE_LOOKUP
 #include "automount.h"
@@ -114,14 +115,12 @@ int lookup_mount(struct autofs_point *ap
 	char errbuf[1024], *errp;
 	char ch;
 	int pipefd[2], epipefd[2];
+	struct pollfd pfd[2];
 	pid_t f;
-	int files_left;
 	int status;
-	fd_set readfds, ourfds;
 	enum state { st_space, st_map, st_done } state;
 	int quoted = 0;
 	int ret = 1;
-	int max_fd;
 	int distance;
 	int alloci = 1;
 
@@ -254,30 +253,39 @@ int lookup_mount(struct autofs_point *ap
 	errp = errbuf;
 	state = st_space;
 
-	FD_ZERO(&ourfds);
-	FD_SET(pipefd[0], &ourfds);
-	FD_SET(epipefd[0], &ourfds);
+	pfd[0].fd = pipefd[0];
+	pfd[0].events = POLLIN;
+	pfd[1].fd = epipefd[0];
+	pfd[1].events = POLLIN;
 
-	max_fd = pipefd[0] > epipefd[0] ? pipefd[0] : epipefd[0];
+	while (1) {
+		int bytes;
 
-	files_left = 2;
+		if (poll(pfd, 2, -1) < 0 && errno != EINTR)
+			break;
+
+		if (pfd[0].fd == -1 && pfd[1].fd == -1)
+			break;
 
-	while (files_left != 0) {
-		readfds = ourfds;
-		if (select(max_fd + 1, &readfds, NULL, NULL, NULL) < 0 && errno != EINTR)
+		if ((pfd[0].revents & (POLLIN|POLLHUP)) == POLLHUP &&
+		    (pfd[1].revents & (POLLIN|POLLHUP)) == POLLHUP)
 			break;
 
 		/* Parse maps from stdout */
-		if (FD_ISSET(pipefd[0], &readfds)) {
-			if (read(pipefd[0], &ch, 1) < 1) {
-				FD_CLR(pipefd[0], &ourfds);
-				files_left--;
+		if (pfd[0].revents) {
+cont:
+			bytes = read(pipefd[0], &ch, 1);
+			if (bytes == 0)
+				goto next;
+			else if (bytes < 0) {
+				pfd[0].fd = -1;
 				state = st_done;
+				goto next;
 			}
 
 			if (!quoted && ch == '\\') {
 				quoted = 1;
-				continue;
+				goto cont;
 			}
 
 			switch (state) {
@@ -334,26 +342,33 @@ int lookup_mount(struct autofs_point *ap
 				/* Eat characters till there's no more output */
 				break;
 			}
+			quoted = 0;
+			goto cont;
 		}
 		quoted = 0;
-
+next:
 		/* Deal with stderr */
-		if (FD_ISSET(epipefd[0], &readfds)) {
-			if (read(epipefd[0], &ch, 1) < 1) {
-				FD_CLR(epipefd[0], &ourfds);
-				files_left--;
-			} else if (ch == '\n') {
-				*errp = '\0';
-				if (errbuf[0])
-					logmsg(">> %s", errbuf);
-				errp = errbuf;
-			} else {
-				if (errp >= &errbuf[1023]) {
+		if (pfd[1].revents) {
+			while (1) {
+				bytes = read(epipefd[0], &ch, 1);
+				if (bytes == 0)
+					break;
+				else if (bytes < 0) {
+					pfd[1].fd = -1;
+					break;
+				} else if (ch == '\n') {
 					*errp = '\0';
-					logmsg(">> %s", errbuf);
+					if (errbuf[0])
+						logmsg(">> %s", errbuf);
 					errp = errbuf;
+				} else {
+					if (errp >= &errbuf[1023]) {
+						*errp = '\0';
+						logmsg(">> %s", errbuf);
+						errp = errbuf;
+					}
+					*(errp++) = ch;
 				}
-				*(errp++) = ch;
 			}
 		}
 	}