]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/amd/amd/nfs_start.c
This commit was generated by cvs2svn to compensate for changes in r173403,
[FreeBSD/FreeBSD.git] / contrib / amd / amd / nfs_start.c
1 /*
2  * Copyright (c) 1997-2004 Erez Zadok
3  * Copyright (c) 1990 Jan-Simon Pendry
4  * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
5  * Copyright (c) 1990 The Regents of the University of California.
6  * All rights reserved.
7  *
8  * This code is derived from software contributed to Berkeley by
9  * Jan-Simon Pendry at Imperial College, London.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. All advertising materials mentioning features or use of this software
20  *    must display the following acknowledgment:
21  *      This product includes software developed by the University of
22  *      California, Berkeley and its contributors.
23  * 4. Neither the name of the University nor the names of its contributors
24  *    may be used to endorse or promote products derived from this software
25  *    without specific prior written permission.
26  *
27  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37  * SUCH DAMAGE.
38  *
39  *      %W% (Berkeley) %G%
40  *
41  * $Id: nfs_start.c,v 1.5.2.7 2004/01/06 03:15:16 ezk Exp $
42  *
43  */
44
45 #ifdef HAVE_CONFIG_H
46 # include <config.h>
47 #endif /* HAVE_CONFIG_H */
48 #include <am_defs.h>
49 #include <amd.h>
50
51 #ifndef SELECT_MAXWAIT
52 # define SELECT_MAXWAIT 16
53 #endif /* not SELECT_MAXWAIT */
54
55 SVCXPRT *nfsxprt;
56 u_short nfs_port;
57
58 #ifndef HAVE_SIGACTION
59 # define MASKED_SIGS    (sigmask(SIGINT)|sigmask(SIGTERM)|sigmask(SIGCHLD)|sigmask(SIGHUP))
60 #endif /* not HAVE_SIGACTION */
61
62 #ifdef DEBUG
63 /*
64  * Check that we are not burning resources
65  */
66 static void
67 checkup(void)
68 {
69
70   static int max_fd = 0;
71   static char *max_mem = 0;
72
73   int next_fd = dup(0);
74   caddr_t next_mem = sbrk(0);
75   close(next_fd);
76
77   if (max_fd < next_fd) {
78     dlog("%d new fds allocated; total is %d",
79          next_fd - max_fd, next_fd);
80     max_fd = next_fd;
81   }
82   if (max_mem < next_mem) {
83 #ifdef HAVE_GETPAGESIZE
84     dlog("%#lx bytes of memory allocated; total is %#lx (%ld pages)",
85          (long) (next_mem - max_mem), (unsigned long) next_mem,
86          ((long) next_mem + getpagesize() - 1) / (long) getpagesize());
87 #else /* not HAVE_GETPAGESIZE */
88     dlog("%#lx bytes of memory allocated; total is %#lx",
89          (long) (next_mem - max_mem), (unsigned long) next_mem);
90 #endif /* not HAVE_GETPAGESIZE */
91     max_mem = next_mem;
92
93   }
94 }
95 #endif /* DEBUG */
96
97
98 static int
99 #ifdef HAVE_SIGACTION
100 do_select(sigset_t smask, int fds, fd_set *fdp, struct timeval *tvp)
101 #else /* not HAVE_SIGACTION */
102 do_select(int smask, int fds, fd_set *fdp, struct timeval *tvp)
103 #endif /* not HAVE_SIGACTION */
104 {
105
106   int sig;
107   int nsel;
108
109   if ((sig = setjmp(select_intr))) {
110     select_intr_valid = 0;
111     /* Got a signal */
112     switch (sig) {
113     case SIGINT:
114     case SIGTERM:
115       amd_state = Finishing;
116       reschedule_timeout_mp();
117       break;
118     }
119     nsel = -1;
120     errno = EINTR;
121   } else {
122     select_intr_valid = 1;
123     /*
124      * Invalidate the current clock value
125      */
126     clock_valid = 0;
127     /*
128      * Allow interrupts.  If a signal
129      * occurs, then it will cause a longjmp
130      * up above.
131      */
132 #ifdef HAVE_SIGACTION
133     sigprocmask(SIG_SETMASK, &smask, NULL);
134 #else /* not HAVE_SIGACTION */
135     (void) sigsetmask(smask);
136 #endif /* not HAVE_SIGACTION */
137
138     /*
139      * Wait for input
140      */
141     nsel = select(fds, fdp, (fd_set *) 0, (fd_set *) 0,
142                   tvp->tv_sec ? tvp : (struct timeval *) 0);
143   }
144
145 #ifdef HAVE_SIGACTION
146   sigprocmask(SIG_BLOCK, &masked_sigs, NULL);
147 #else /* not HAVE_SIGACTION */
148   (void) sigblock(MASKED_SIGS);
149 #endif /* not HAVE_SIGACTION */
150
151   /*
152    * Perhaps reload the cache?
153    */
154   if (do_mapc_reload < clocktime()) {
155     mapc_reload();
156     do_mapc_reload = clocktime() + ONE_HOUR;
157   }
158   return nsel;
159 }
160
161
162 /*
163  * Determine whether anything is left in
164  * the RPC input queue.
165  */
166 static int
167 rpc_pending_now(void)
168 {
169   struct timeval tvv;
170   int nsel;
171 #ifdef FD_SET
172   fd_set readfds;
173
174   FD_ZERO(&readfds);
175   FD_SET(fwd_sock, &readfds);
176 #else /* not FD_SET */
177   int readfds = (1 << fwd_sock);
178 #endif /* not FD_SET */
179
180   tvv.tv_sec = tvv.tv_usec = 0;
181   nsel = select(FD_SETSIZE, &readfds, (fd_set *) 0, (fd_set *) 0, &tvv);
182   if (nsel < 1)
183     return (0);
184 #ifdef FD_SET
185   if (FD_ISSET(fwd_sock, &readfds))
186     return (1);
187 #else /* not FD_SET */
188   if (readfds & (1 << fwd_sock))
189     return (1);
190 #endif /* not FD_SET */
191
192   return (0);
193 }
194
195
196 static serv_state
197 run_rpc(void)
198 {
199 #ifdef HAVE_SIGACTION
200   sigset_t smask;
201   sigprocmask(SIG_BLOCK, &masked_sigs, &smask);
202 #else /* not HAVE_SIGACTION */
203   int smask = sigblock(MASKED_SIGS);
204 #endif /* not HAVE_SIGACTION */
205
206   next_softclock = clocktime();
207
208   amd_state = Run;
209
210   /*
211    * Keep on trucking while we are in Run mode.  This state
212    * is switched to Quit after all the file systems have
213    * been unmounted.
214    */
215   while ((int) amd_state <= (int) Finishing) {
216     struct timeval tvv;
217     int nsel;
218     time_t now;
219 #ifdef HAVE_SVC_GETREQSET
220     fd_set readfds;
221
222     memmove(&readfds, &svc_fdset, sizeof(svc_fdset));
223     FD_SET(fwd_sock, &readfds);
224 #else /* not HAVE_SVC_GETREQSET */
225 # ifdef FD_SET
226     fd_set readfds;
227     FD_ZERO(&readfds);
228     readfds.fds_bits[0] = svc_fds;
229     FD_SET(fwd_sock, &readfds);
230 # else /* not FD_SET */
231     int readfds = svc_fds | (1 << fwd_sock);
232 # endif /* not FD_SET */
233 #endif /* not HAVE_SVC_GETREQSET */
234
235 #ifdef DEBUG
236     checkup();
237 #endif /* DEBUG */
238
239     /*
240      * If the full timeout code is not called,
241      * then recompute the time delta manually.
242      */
243     now = clocktime();
244
245     if (next_softclock <= now) {
246       if (amd_state == Finishing)
247         umount_exported();
248       tvv.tv_sec = softclock();
249     } else {
250       tvv.tv_sec = next_softclock - now;
251     }
252     tvv.tv_usec = 0;
253
254     if (amd_state == Finishing && last_used_map < 0) {
255       flush_mntfs();
256       amd_state = Quit;
257       break;
258     }
259     if (tvv.tv_sec <= 0)
260       tvv.tv_sec = SELECT_MAXWAIT;
261 #ifdef DEBUG
262     if (tvv.tv_sec) {
263       dlog("Select waits for %ds", (int) tvv.tv_sec);
264     } else {
265       dlog("Select waits for Godot");
266     }
267 #endif /* DEBUG */
268
269     nsel = do_select(smask, FD_SETSIZE, &readfds, &tvv);
270
271     switch (nsel) {
272     case -1:
273       if (errno == EINTR) {
274 #ifdef DEBUG
275         dlog("select interrupted");
276 #endif /* DEBUG */
277         continue;
278       }
279       plog(XLOG_ERROR, "select: %m");
280       break;
281
282     case 0:
283       break;
284
285     default:
286       /*
287        * Read all pending NFS responses at once to avoid having responses.
288        * queue up as a consequence of retransmissions.
289        */
290 #ifdef FD_SET
291       if (FD_ISSET(fwd_sock, &readfds)) {
292         FD_CLR(fwd_sock, &readfds);
293 #else /* not FD_SET */
294       if (readfds & (1 << fwd_sock)) {
295         readfds &= ~(1 << fwd_sock);
296 #endif /* not FD_SET */
297         --nsel;
298         do {
299           fwd_reply();
300         } while (rpc_pending_now() > 0);
301       }
302
303       if (nsel) {
304         /*
305          * Anything left must be a normal
306          * RPC request.
307          */
308 #ifdef HAVE_SVC_GETREQSET
309         svc_getreqset(&readfds);
310 #else /* not HAVE_SVC_GETREQSET */
311 # ifdef FD_SET
312         svc_getreq(readfds.fds_bits[0]);
313 # else /* not FD_SET */
314         svc_getreq(readfds);
315 # endif /* not FD_SET */
316 #endif /* not HAVE_SVC_GETREQSET */
317       }
318       break;
319     }
320   }
321
322 #ifdef HAVE_SIGACTION
323   sigprocmask(SIG_SETMASK, &smask, NULL);
324 #else /* not HAVE_SIGACTION */
325   (void) sigsetmask(smask);
326 #endif /* not HAVE_SIGACTION */
327
328   if (amd_state == Quit)
329     amd_state = Done;
330
331   return amd_state;
332 }
333
334
335 int
336 mount_automounter(int ppid)
337 {
338   /*
339    * Old code replaced by rpc-trash patch.
340    * Erez Zadok <ezk@cs.columbia.edu>
341    int so = socket(AF_INET, SOCK_DGRAM, 0);
342    */
343   SVCXPRT *udp_amqp = NULL, *tcp_amqp = NULL;
344   int nmount, ret;
345   int soNFS;
346   int udp_soAMQ, tcp_soAMQ;
347 #ifdef HAVE_TRANSPORT_TYPE_TLI
348   struct netconfig *udp_amqncp, *tcp_amqncp;
349 #endif /* HAVE_TRANSPORT_TYPE_TLI */
350
351   /*
352    * Create the nfs service for amd
353    */
354 #ifdef HAVE_TRANSPORT_TYPE_TLI
355   ret = create_nfs_service(&soNFS, &nfs_port, &nfsxprt, nfs_program_2);
356   if (ret != 0)
357     return ret;
358   ret = create_amq_service(&udp_soAMQ, &udp_amqp, &udp_amqncp, &tcp_soAMQ, &tcp_amqp, &tcp_amqncp);
359 #else /* not HAVE_TRANSPORT_TYPE_TLI */
360   ret = create_nfs_service(&soNFS, &nfs_port, &nfsxprt, nfs_program_2);
361   if (ret != 0)
362     return ret;
363   ret = create_amq_service(&udp_soAMQ, &udp_amqp, &tcp_soAMQ, &tcp_amqp);
364 #endif /* not HAVE_TRANSPORT_TYPE_TLI */
365   if (ret != 0)
366     return ret;
367
368   /*
369    * Start RPC forwarding
370    */
371   if (fwd_init() != 0)
372     return 3;
373
374   /*
375    * Construct the root automount node
376    */
377   make_root_node();
378
379   /*
380    * Pick up the pieces from a previous run
381    * This is likely to (indirectly) need the rpc_fwd package
382    * so it *must* come after the call to fwd_init().
383    */
384   if (gopt.flags & CFM_RESTART_EXISTING_MOUNTS)
385     restart();
386
387   /*
388    * Mount the top-level auto-mountpoints
389    */
390   nmount = mount_exported();
391
392   /*
393    * Now safe to tell parent that we are up and running
394    */
395   if (ppid)
396     kill(ppid, SIGQUIT);
397
398   if (nmount == 0) {
399     plog(XLOG_FATAL, "No work to do - quitting");
400     amd_state = Done;
401     return 0;
402   }
403
404 #ifdef DEBUG
405   amuDebug(D_AMQ) {
406 #endif /* DEBUG */
407     /*
408      * Complete registration of amq (first TCP service then UDP)
409      */
410     unregister_amq();
411
412 #ifdef HAVE_TRANSPORT_TYPE_TLI
413     ret = svc_reg(tcp_amqp, get_amd_program_number(), AMQ_VERSION,
414                   amq_program_1, tcp_amqncp);
415 #else /* not HAVE_TRANSPORT_TYPE_TLI */
416     ret = svc_register(tcp_amqp, get_amd_program_number(), AMQ_VERSION,
417                        amq_program_1, IPPROTO_TCP);
418 #endif /* not HAVE_TRANSPORT_TYPE_TLI */
419     if (ret != 1) {
420       plog(XLOG_FATAL, "unable to register (AMQ_PROGRAM=%d, AMQ_VERSION, tcp)", get_amd_program_number());
421       return 3;
422     }
423
424 #ifdef HAVE_TRANSPORT_TYPE_TLI
425     ret = svc_reg(udp_amqp, get_amd_program_number(), AMQ_VERSION,
426                   amq_program_1, udp_amqncp);
427 #else /* not HAVE_TRANSPORT_TYPE_TLI */
428     ret = svc_register(udp_amqp, get_amd_program_number(), AMQ_VERSION,
429                        amq_program_1, IPPROTO_UDP);
430 #endif /* not HAVE_TRANSPORT_TYPE_TLI */
431     if (ret != 1) {
432       plog(XLOG_FATAL, "unable to register (AMQ_PROGRAM=%d, AMQ_VERSION, udp)", get_amd_program_number());
433       return 4;
434     }
435
436 #ifdef DEBUG
437   }
438 #endif /* DEBUG */
439
440   /*
441    * Start timeout_mp rolling
442    */
443   reschedule_timeout_mp();
444
445   /*
446    * Start the server
447    */
448   if (run_rpc() != Done) {
449     plog(XLOG_FATAL, "run_rpc failed");
450     amd_state = Done;
451   }
452   return 0;
453 }