]>
Commit | Line | Data |
---|---|---|
e5fd101c PS |
1 | autofs-5.0.4 - fix select fd limit |
2 | ||
3 | From: Ian Kent <raven@themaw.net> | |
4 | ||
5 | Using a large number of direct mounts causes autofs to hang. This is | |
6 | because select(2) is limited to 1024 file handles (usually). To resolve | |
7 | this we need to convert calls to select(2) to use poll(2). | |
8 | --- | |
9 | ||
10 | CHANGELOG | 1 + | |
11 | daemon/spawn.c | 19 ++++++------ | |
12 | lib/rpc_subs.c | 32 ++++++++++++++------ | |
13 | modules/lookup_program.c | 74 +++++++++++++++++++++++++++------------------- | |
14 | 4 files changed, 78 insertions(+), 48 deletions(-) | |
15 | ||
16 | ||
17 | diff --git a/CHANGELOG b/CHANGELOG | |
18 | index 43f3205..0fb7db5 100644 | |
19 | --- a/CHANGELOG | |
20 | +++ b/CHANGELOG | |
21 | @@ -4,6 +4,7 @@ | |
22 | - fix nested submount expire deadlock. | |
23 | - fix negative caching for non-existent map keys. | |
24 | - use CLOEXEC flag. | |
25 | +- fix select(2) fd limit. | |
26 | ||
27 | 4/11/2008 autofs-5.0.4 | |
28 | ----------------------- | |
29 | diff --git a/daemon/spawn.c b/daemon/spawn.c | |
30 | index 4ddf46f..e02d926 100644 | |
31 | --- a/daemon/spawn.c | |
32 | +++ b/daemon/spawn.c | |
33 | @@ -21,6 +21,7 @@ | |
34 | #include <sys/types.h> | |
35 | #include <dirent.h> | |
36 | #include <time.h> | |
37 | +#include <poll.h> | |
38 | #include <sys/wait.h> | |
39 | #include <sys/stat.h> | |
40 | #include <sys/mount.h> | |
41 | @@ -89,21 +90,21 @@ void reset_signals(void) | |
42 | ||
43 | static int timed_read(int pipe, char *buf, size_t len, int time) | |
44 | { | |
45 | - struct timeval timeout = { 0, 0 }; | |
46 | - struct timeval *tout = NULL; | |
47 | - fd_set wset, rset; | |
48 | + struct pollfd pfd[1]; | |
49 | + int timeout = time; | |
50 | int ret; | |
51 | ||
52 | - FD_ZERO(&rset); | |
53 | - FD_SET(pipe, &rset); | |
54 | - wset = rset; | |
55 | + pfd[0].fd = pipe; | |
56 | + pfd[0].events = POLLIN; | |
57 | ||
58 | if (time != -1) { | |
59 | - timeout.tv_sec = time; | |
60 | - tout = &timeout; | |
61 | + if (time >= (INT_MAX - 1)/1000) | |
62 | + timeout = INT_MAX - 1; | |
63 | + else | |
64 | + timeout = time * 1000; | |
65 | } | |
66 | ||
67 | - ret = select(pipe + 1, &rset, &wset, NULL, tout); | |
68 | + ret = poll(pfd, 1, timeout); | |
69 | if (ret <= 0) { | |
70 | if (ret == 0) | |
71 | ret = -ETIMEDOUT; | |
72 | diff --git a/lib/rpc_subs.c b/lib/rpc_subs.c | |
73 | index 9ac3657..7b347a7 100644 | |
74 | --- a/lib/rpc_subs.c | |
75 | +++ b/lib/rpc_subs.c | |
76 | @@ -31,6 +31,7 @@ | |
77 | #include <sys/ioctl.h> | |
78 | #include <ctype.h> | |
79 | #include <pthread.h> | |
80 | +#include <poll.h> | |
81 | ||
82 | #include "mount.h" | |
83 | #include "rpc_subs.h" | |
84 | @@ -197,14 +198,15 @@ void rpc_destroy_udp_client(struct conn_info *info) | |
85 | /* | |
86 | * Perform a non-blocking connect on the socket fd. | |
87 | * | |
88 | - * tout contains the timeout. It will be modified to contain the time | |
89 | - * remaining (i.e. time provided - time elasped). | |
90 | + * The input struct timeval always has tv_nsec set to zero, | |
91 | + * we only ever use tv_sec for timeouts. | |
92 | */ | |
93 | static int connect_nb(int fd, struct sockaddr_in *addr, struct timeval *tout) | |
94 | { | |
95 | + struct pollfd pfd[1]; | |
96 | + int timeout = tout->tv_sec; | |
97 | int flags, ret; | |
98 | socklen_t len; | |
99 | - fd_set wset, rset; | |
100 | ||
101 | flags = fcntl(fd, F_GETFL, 0); | |
102 | if (flags < 0) | |
103 | @@ -229,12 +231,10 @@ static int connect_nb(int fd, struct sockaddr_in *addr, struct timeval *tout) | |
104 | if (ret == 0) | |
105 | goto done; | |
106 | ||
107 | - /* now wait */ | |
108 | - FD_ZERO(&rset); | |
109 | - FD_SET(fd, &rset); | |
110 | - wset = rset; | |
111 | + pfd[0].fd = fd; | |
112 | + pfd[0].events = POLLOUT; | |
113 | ||
114 | - ret = select(fd + 1, &rset, &wset, NULL, tout); | |
115 | + ret = poll(pfd, 1, timeout); | |
116 | if (ret <= 0) { | |
117 | if (ret == 0) | |
118 | ret = -ETIMEDOUT; | |
119 | @@ -243,13 +243,27 @@ static int connect_nb(int fd, struct sockaddr_in *addr, struct timeval *tout) | |
120 | goto done; | |
121 | } | |
122 | ||
123 | - if (FD_ISSET(fd, &rset) || FD_ISSET(fd, &wset)) { | |
124 | + if (pfd[0].revents) { | |
125 | int status; | |
126 | ||
127 | len = sizeof(ret); | |
128 | status = getsockopt(fd, SOL_SOCKET, SO_ERROR, &ret, &len); | |
129 | if (status < 0) { | |
130 | + char buf[MAX_ERR_BUF + 1]; | |
131 | + char *estr = strerror_r(errno, buf, MAX_ERR_BUF); | |
132 | + | |
133 | + /* | |
134 | + * We assume getsockopt amounts to a read on the | |
135 | + * descriptor and gives us the errno we need for | |
136 | + * the POLLERR revent case. | |
137 | + */ | |
138 | ret = -errno; | |
139 | + | |
140 | + /* Unexpected case, log it so we know we got caught */ | |
141 | + if (pfd[0].revents & POLLNVAL) | |
142 | + logerr("unexpected poll(2) error on connect:" | |
143 | + " %s", estr); | |
144 | + | |
145 | goto done; | |
146 | } | |
147 | ||
148 | diff --git a/modules/lookup_program.c b/modules/lookup_program.c | |
149 | index 6f4e2a3..f62d3ef 100644 | |
150 | --- a/modules/lookup_program.c | |
151 | +++ b/modules/lookup_program.c | |
152 | @@ -24,6 +24,7 @@ | |
153 | #include <sys/times.h> | |
154 | #include <sys/types.h> | |
155 | #include <sys/wait.h> | |
156 | +#include <poll.h> | |
157 | ||
158 | #define MODULE_LOOKUP | |
159 | #include "automount.h" | |
160 | @@ -113,14 +114,12 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void * | |
161 | char errbuf[1024], *errp; | |
162 | char ch; | |
163 | int pipefd[2], epipefd[2]; | |
164 | + struct pollfd pfd[2]; | |
165 | pid_t f; | |
166 | - int files_left; | |
167 | int status; | |
168 | - fd_set readfds, ourfds; | |
169 | enum state { st_space, st_map, st_done } state; | |
170 | int quoted = 0; | |
171 | int ret = 1; | |
172 | - int max_fd; | |
173 | int distance; | |
174 | int alloci = 1; | |
175 | ||
176 | @@ -253,30 +252,39 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void * | |
177 | errp = errbuf; | |
178 | state = st_space; | |
179 | ||
180 | - FD_ZERO(&ourfds); | |
181 | - FD_SET(pipefd[0], &ourfds); | |
182 | - FD_SET(epipefd[0], &ourfds); | |
183 | + pfd[0].fd = pipefd[0]; | |
184 | + pfd[0].events = POLLIN; | |
185 | + pfd[1].fd = epipefd[0]; | |
186 | + pfd[1].events = POLLIN; | |
187 | ||
188 | - max_fd = pipefd[0] > epipefd[0] ? pipefd[0] : epipefd[0]; | |
189 | + while (1) { | |
190 | + int bytes; | |
191 | ||
192 | - files_left = 2; | |
193 | + if (poll(pfd, 2, -1) < 0 && errno != EINTR) | |
194 | + break; | |
195 | + | |
196 | + if (pfd[0].fd == -1 && pfd[1].fd == -1) | |
197 | + break; | |
198 | ||
199 | - while (files_left != 0) { | |
200 | - readfds = ourfds; | |
201 | - if (select(max_fd + 1, &readfds, NULL, NULL, NULL) < 0 && errno != EINTR) | |
202 | + if ((pfd[0].revents & (POLLIN|POLLHUP)) == POLLHUP && | |
203 | + (pfd[1].revents & (POLLIN|POLLHUP)) == POLLHUP) | |
204 | break; | |
205 | ||
206 | /* Parse maps from stdout */ | |
207 | - if (FD_ISSET(pipefd[0], &readfds)) { | |
208 | - if (read(pipefd[0], &ch, 1) < 1) { | |
209 | - FD_CLR(pipefd[0], &ourfds); | |
210 | - files_left--; | |
211 | + if (pfd[0].revents) { | |
212 | +cont: | |
213 | + bytes = read(pipefd[0], &ch, 1); | |
214 | + if (bytes == 0) | |
215 | + goto next; | |
216 | + else if (bytes < 0) { | |
217 | + pfd[0].fd = -1; | |
218 | state = st_done; | |
219 | + goto next; | |
220 | } | |
221 | ||
222 | if (!quoted && ch == '\\') { | |
223 | quoted = 1; | |
224 | - continue; | |
225 | + goto cont; | |
226 | } | |
227 | ||
228 | switch (state) { | |
229 | @@ -333,26 +341,32 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void * | |
230 | /* Eat characters till there's no more output */ | |
231 | break; | |
232 | } | |
233 | + goto cont; | |
234 | } | |
235 | quoted = 0; | |
236 | - | |
237 | +next: | |
238 | /* Deal with stderr */ | |
239 | - if (FD_ISSET(epipefd[0], &readfds)) { | |
240 | - if (read(epipefd[0], &ch, 1) < 1) { | |
241 | - FD_CLR(epipefd[0], &ourfds); | |
242 | - files_left--; | |
243 | - } else if (ch == '\n') { | |
244 | - *errp = '\0'; | |
245 | - if (errbuf[0]) | |
246 | - logmsg(">> %s", errbuf); | |
247 | - errp = errbuf; | |
248 | - } else { | |
249 | - if (errp >= &errbuf[1023]) { | |
250 | + if (pfd[1].revents) { | |
251 | + while (1) { | |
252 | + bytes = read(epipefd[0], &ch, 1); | |
253 | + if (bytes == 0) | |
254 | + break; | |
255 | + else if (bytes < 0) { | |
256 | + pfd[1].fd = -1; | |
257 | + break; | |
258 | + } else if (ch == '\n') { | |
259 | *errp = '\0'; | |
260 | - logmsg(">> %s", errbuf); | |
261 | + if (errbuf[0]) | |
262 | + logmsg(">> %s", errbuf); | |
263 | errp = errbuf; | |
264 | + } else { | |
265 | + if (errp >= &errbuf[1023]) { | |
266 | + *errp = '\0'; | |
267 | + logmsg(">> %s", errbuf); | |
268 | + errp = errbuf; | |
269 | + } | |
270 | + *(errp++) = ch; | |
271 | } | |
272 | - *(errp++) = ch; | |
273 | } | |
274 | } | |
275 | } |