xref: /original-bsd/sys/nfs/nfs_syscalls.c (revision 135ce860)
1 /*
2  * Copyright (c) 1989 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Rick Macklem at The University of Guelph.
7  *
8  * %sccs.include.redist.c%
9  *
10  *	@(#)nfs_syscalls.c	7.32 (Berkeley) 07/10/92
11  */
12 
13 #include "param.h"
14 #include "systm.h"
15 #include "kernel.h"
16 #include "file.h"
17 #include "stat.h"
18 #include "vnode.h"
19 #include "mount.h"
20 #include "proc.h"
21 #include "uio.h"
22 #include "malloc.h"
23 #include "buf.h"
24 #include "mbuf.h"
25 #include "socket.h"
26 #include "socketvar.h"
27 #include "domain.h"
28 #include "protosw.h"
29 #include "namei.h"
30 #include "netinet/in.h"
31 #include "netinet/tcp.h"
32 #ifdef ISO
33 #include "netiso/iso.h"
34 #endif
35 #include "machine/endian.h"
36 #include "rpcv2.h"
37 #include "nfsv2.h"
38 #include "nfs.h"
39 #include "nfsrvcache.h"
40 #include "nfsmount.h"
41 #include "nqnfs.h"
42 
43 /* Global defs. */
44 extern u_long nfs_prog, nfs_vers;
45 extern int (*nfsrv_procs[NFS_NPROCS])();
46 extern struct buf nfs_bqueue;
47 extern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON];
48 extern int nfs_numasync;
49 extern time_t nqnfsstarttime;
50 extern struct nfsrv_req nsrvq_head;
51 extern struct nfsd nfsd_head;
52 extern int nqsrv_writeslack;
53 struct nfssvc_sock *nfs_udpsock, *nfs_cltpsock;
54 int nuidhash_max = NFS_MAXUIDHASH;
55 static int nfs_numnfsd = 0;
56 int nfsd_waiting = 0;
57 static int notstarted = 1;
58 static int modify_flag = 0;
59 void nfsrv_cleancache(), nfsrv_rcv(), nfsrv_wakenfsd(), nfs_sndunlock();
60 void nfsrv_slpderef(), nfsrv_init();
61 
62 #define	TRUE	1
63 #define	FALSE	0
64 
65 static int nfs_asyncdaemon[NFS_MAXASYNCDAEMON];
66 /*
67  * NFS server system calls
68  * getfh() lives here too, but maybe should move to kern/vfs_syscalls.c
69  */
70 
71 /*
72  * Get file handle system call
73  */
74 struct getfh_args {
75 	char	*fname;
76 	fhandle_t *fhp;
77 };
78 getfh(p, uap, retval)
79 	struct proc *p;
80 	register struct getfh_args *uap;
81 	int *retval;
82 {
83 	register struct vnode *vp;
84 	fhandle_t fh;
85 	int error;
86 	struct nameidata nd;
87 
88 	/*
89 	 * Must be super user
90 	 */
91 	if (error = suser(p->p_ucred, &p->p_acflag))
92 		return (error);
93 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
94 	if (error = namei(&nd))
95 		return (error);
96 	vp = nd.ni_vp;
97 	bzero((caddr_t)&fh, sizeof(fh));
98 	fh.fh_fsid = vp->v_mount->mnt_stat.f_fsid;
99 	error = VFS_VPTOFH(vp, &fh.fh_fid);
100 	vput(vp);
101 	if (error)
102 		return (error);
103 	error = copyout((caddr_t)&fh, (caddr_t)uap->fhp, sizeof (fh));
104 	return (error);
105 }
106 
107 static struct nfssvc_sock nfssvc_sockhead;
108 
109 /*
110  * Nfs server psuedo system call for the nfsd's
111  * Based on the flag value it either:
112  * - adds a socket to the selection list
113  * - remains in the kernel as an nfsd
114  * - remains in the kernel as an nfsiod
115  */
116 struct nfssvc_args {
117 	int flag;
118 	caddr_t argp;
119 };
120 nfssvc(p, uap, retval)
121 	struct proc *p;
122 	register struct nfssvc_args *uap;
123 	int *retval;
124 {
125 	struct nameidata nd;
126 	struct file *fp;
127 	struct mbuf *nam;
128 	struct nfsd_args nfsdarg;
129 	struct nfsd_srvargs nfsd_srvargs, *nsd = &nfsd_srvargs;
130 	struct nfsd_cargs ncd;
131 	struct nfsd *nfsd;
132 	struct nfssvc_sock *slp;
133 	struct nfsuid *nuidp, **nuh;
134 	struct nfsmount *nmp;
135 	int error;
136 
137 	/*
138 	 * Must be super user
139 	 */
140 	if (error = suser(p->p_ucred, &p->p_acflag))
141 		return (error);
142 	while (nfssvc_sockhead.ns_flag & SLP_INIT) {
143 		nfssvc_sockhead.ns_flag |= SLP_WANTINIT;
144 		(void) tsleep((caddr_t)&nfssvc_sockhead, PSOCK, "nfsd init", 0);
145 	}
146 	if (uap->flag & NFSSVC_BIOD)
147 		error = nfssvc_iod(p);
148 	else if (uap->flag & NFSSVC_MNTD) {
149 		if (error = copyin(uap->argp, (caddr_t)&ncd, sizeof (ncd)))
150 			return (error);
151 		NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
152 			ncd.ncd_dirp, p);
153 		if (error = namei(&nd))
154 			return (error);
155 		if ((nd.ni_vp->v_flag & VROOT) == 0)
156 			error = EINVAL;
157 		nmp = VFSTONFS(nd.ni_vp->v_mount);
158 		vput(nd.ni_vp);
159 		if (error)
160 			return (error);
161 		else if (nmp->nm_flag & NFSMNT_MNTD)
162 			return (0);
163 		nmp->nm_flag |= NFSMNT_MNTD;
164 		error = nqnfs_clientd(nmp, p->p_ucred, &ncd, uap->flag,
165 			uap->argp, p);
166 	} else if (uap->flag & NFSSVC_ADDSOCK) {
167 		if (error = copyin(uap->argp, (caddr_t)&nfsdarg,
168 		    sizeof(nfsdarg)))
169 			return (error);
170 		if (error = getsock(p->p_fd, nfsdarg.sock, &fp))
171 			return (error);
172 		/*
173 		 * Get the client address for connected sockets.
174 		 */
175 		if (nfsdarg.name == NULL || nfsdarg.namelen == 0)
176 			nam = (struct mbuf *)0;
177 		else if (error = sockargs(&nam, nfsdarg.name, nfsdarg.namelen,
178 			MT_SONAME))
179 			return (error);
180 		error = nfssvc_addsock(fp, nam);
181 	} else {
182 		if (error = copyin(uap->argp, (caddr_t)nsd, sizeof (*nsd)))
183 			return (error);
184 		if ((uap->flag & NFSSVC_AUTHIN) && (nfsd = nsd->nsd_nfsd) &&
185 			(nfsd->nd_slp->ns_flag & SLP_VALID)) {
186 			slp = nfsd->nd_slp;
187 			if (slp->ns_numuids < nuidhash_max) {
188 				slp->ns_numuids++;
189 				nuidp = (struct nfsuid *)
190 				   malloc(sizeof (struct nfsuid), M_NFSUID, M_WAITOK);
191 			} else
192 				nuidp = (struct nfsuid *)0;
193 			if ((slp->ns_flag & SLP_VALID) == 0) {
194 			    if (nuidp)
195 				free((caddr_t)nuidp, M_NFSUID);
196 			} else {
197 			    if (nuidp == (struct nfsuid *)0) {
198 				nuidp = slp->ns_lruprev;
199 				remque(nuidp);
200 				if (nuidp->nu_hprev)
201 					nuidp->nu_hprev->nu_hnext = nuidp->nu_hnext;
202 				if (nuidp->nu_hnext)
203 					nuidp->nu_hnext->nu_hprev = nuidp->nu_hprev;
204 			    }
205 			    nuidp->nu_cr = nsd->nsd_cr;
206 			    nuidp->nu_cr.cr_ref = 1;
207 			    nuidp->nu_uid = nsd->nsd_uid;
208 			    insque(nuidp, (struct nfsuid *)slp);
209 			    nuh = &slp->ns_uidh[NUIDHASH(nsd->nsd_uid)];
210 			    if (nuidp->nu_hnext = *nuh)
211 				nuidp->nu_hnext->nu_hprev = nuidp;
212 			    nuidp->nu_hprev = (struct nfsuid *)0;
213 			    *nuh = nuidp;
214 			}
215 		}
216 		if ((uap->flag & NFSSVC_AUTHINFAIL) && (nfsd = nsd->nsd_nfsd))
217 			nfsd->nd_flag |= NFSD_AUTHFAIL;
218 		error = nfssvc_nfsd(nsd, uap->argp, p);
219 	}
220 	if (error == EINTR || error == ERESTART)
221 		error = 0;
222 	return (error);
223 }
224 
225 /*
226  * Adds a socket to the list for servicing by nfsds.
227  */
228 nfssvc_addsock(fp, mynam)
229 	struct file *fp;
230 	struct mbuf *mynam;
231 {
232 	register struct mbuf *m;
233 	register int siz;
234 	register struct nfssvc_sock *slp;
235 	register struct socket *so;
236 	struct nfssvc_sock *tslp;
237 	int error, s;
238 
239 	so = (struct socket *)fp->f_data;
240 	tslp = (struct nfssvc_sock *)0;
241 	/*
242 	 * Add it to the list, as required.
243 	 */
244 	if (so->so_proto->pr_protocol == IPPROTO_UDP) {
245 		tslp = nfs_udpsock;
246 		if (tslp->ns_flag & SLP_VALID) {
247 			m_freem(mynam);
248 			return (EPERM);
249 		}
250 #ifdef ISO
251 	} else if (so->so_proto->pr_protocol == ISOPROTO_CLTP) {
252 		tslp = nfs_cltpsock;
253 		if (tslp->ns_flag & SLP_VALID) {
254 			m_freem(mynam);
255 			return (EPERM);
256 		}
257 #endif /* ISO */
258 	}
259 	if (so->so_type == SOCK_STREAM)
260 		siz = NFS_MAXPACKET + sizeof (u_long);
261 	else
262 		siz = NFS_MAXPACKET;
263 	if (error = soreserve(so, siz, siz)) {
264 		m_freem(mynam);
265 		return (error);
266 	}
267 
268 	/*
269 	 * Set protocol specific options { for now TCP only } and
270 	 * reserve some space. For datagram sockets, this can get called
271 	 * repeatedly for the same socket, but that isn't harmful.
272 	 */
273 	if (so->so_type == SOCK_STREAM) {
274 		MGET(m, M_WAIT, MT_SOOPTS);
275 		*mtod(m, int *) = 1;
276 		m->m_len = sizeof(int);
277 		sosetopt(so, SOL_SOCKET, SO_KEEPALIVE, m);
278 	}
279 	if (so->so_proto->pr_domain->dom_family == AF_INET &&
280 	    so->so_proto->pr_protocol == IPPROTO_TCP) {
281 		MGET(m, M_WAIT, MT_SOOPTS);
282 		*mtod(m, int *) = 1;
283 		m->m_len = sizeof(int);
284 		sosetopt(so, IPPROTO_TCP, TCP_NODELAY, m);
285 	}
286 	so->so_rcv.sb_flags &= ~SB_NOINTR;
287 	so->so_rcv.sb_timeo = 0;
288 	so->so_snd.sb_flags &= ~SB_NOINTR;
289 	so->so_snd.sb_timeo = 0;
290 	if (tslp)
291 		slp = tslp;
292 	else {
293 		slp = (struct nfssvc_sock *)
294 			malloc(sizeof (struct nfssvc_sock), M_NFSSVC, M_WAITOK);
295 		bzero((caddr_t)slp, sizeof (struct nfssvc_sock));
296 		slp->ns_prev = nfssvc_sockhead.ns_prev;
297 		slp->ns_prev->ns_next = slp;
298 		slp->ns_next = &nfssvc_sockhead;
299 		nfssvc_sockhead.ns_prev = slp;
300 		slp->ns_lrunext = slp->ns_lruprev = (struct nfsuid *)slp;
301 	}
302 	slp->ns_so = so;
303 	slp->ns_nam = mynam;
304 	fp->f_count++;
305 	slp->ns_fp = fp;
306 	s = splnet();
307 	so->so_upcallarg = (caddr_t)slp;
308 	so->so_upcall = nfsrv_rcv;
309 	slp->ns_flag = (SLP_VALID | SLP_NEEDQ);
310 	nfsrv_wakenfsd(slp);
311 	splx(s);
312 	return (0);
313 }
314 
315 /*
316  * Called by nfssvc() for nfsds. Just loops around servicing rpc requests
317  * until it is killed by a signal.
318  */
319 nfssvc_nfsd(nsd, argp, p)
320 	struct nfsd_srvargs *nsd;
321 	caddr_t argp;
322 	struct proc *p;
323 {
324 	register struct mbuf *m, *nam2;
325 	register int siz;
326 	register struct nfssvc_sock *slp;
327 	register struct socket *so;
328 	register int *solockp;
329 	struct nfssvc_sock *oslp;
330 	struct nfsd *nd = nsd->nsd_nfsd;
331 	struct mbuf *mreq, *nam;
332 	int error, cacherep, s;
333 	int sotype;
334 
335 	s = splnet();
336 	if (nd == (struct nfsd *)0) {
337 		nsd->nsd_nfsd = nd = (struct nfsd *)
338 			malloc(sizeof (struct nfsd), M_NFSD, M_WAITOK);
339 		bzero((caddr_t)nd, sizeof (struct nfsd));
340 		nd->nd_procp = p;
341 		nd->nd_cr.cr_ref = 1;
342 		insque(nd, &nfsd_head);
343 		nfs_numnfsd++;
344 	}
345 	/*
346 	 * Loop getting rpc requests until SIGKILL.
347 	 */
348 	for (;;) {
349 		if ((nd->nd_flag & NFSD_REQINPROG) == 0) {
350 			while (nd->nd_slp == (struct nfssvc_sock *)0 &&
351 				 (nfsd_head.nd_flag & NFSD_CHECKSLP) == 0) {
352 				nd->nd_flag |= NFSD_WAITING;
353 				nfsd_waiting++;
354 				error = tsleep((caddr_t)nd, PSOCK | PCATCH, "nfsd", 0);
355 				nfsd_waiting--;
356 				if (error)
357 					goto done;
358 			}
359 			if (nd->nd_slp == (struct nfssvc_sock *)0 &&
360 				(nfsd_head.nd_flag & NFSD_CHECKSLP)) {
361 				slp = nfssvc_sockhead.ns_next;
362 				while (slp != &nfssvc_sockhead) {
363 				    if ((slp->ns_flag & (SLP_VALID | SLP_DOREC))
364 					== (SLP_VALID | SLP_DOREC)) {
365 					    slp->ns_flag &= ~SLP_DOREC;
366 					    slp->ns_sref++;
367 					    nd->nd_slp = slp;
368 					    break;
369 				    }
370 				    slp = slp->ns_next;
371 				}
372 				if (slp == &nfssvc_sockhead)
373 					nfsd_head.nd_flag &= ~NFSD_CHECKSLP;
374 			}
375 			if ((slp = nd->nd_slp) == (struct nfssvc_sock *)0)
376 				continue;
377 			if (slp->ns_flag & SLP_VALID) {
378 				if (slp->ns_flag & SLP_DISCONN)
379 					nfsrv_zapsock(slp);
380 				else if (slp->ns_flag & SLP_NEEDQ) {
381 					slp->ns_flag &= ~SLP_NEEDQ;
382 					(void) nfs_sndlock(&slp->ns_solock,
383 						(struct nfsreq *)0);
384 					nfsrv_rcv(slp->ns_so, (caddr_t)slp,
385 						M_WAIT);
386 					nfs_sndunlock(&slp->ns_solock);
387 				}
388 				error = nfsrv_dorec(slp, nd);
389 				nd->nd_flag |= NFSD_REQINPROG;
390 			}
391 		} else {
392 			error = 0;
393 			slp = nd->nd_slp;
394 		}
395 		if (error || (slp->ns_flag & SLP_VALID) == 0) {
396 			nd->nd_slp = (struct nfssvc_sock *)0;
397 			nd->nd_flag &= ~NFSD_REQINPROG;
398 			nfsrv_slpderef(slp);
399 			continue;
400 		}
401 		splx(s);
402 		so = slp->ns_so;
403 		sotype = so->so_type;
404 
405 		/*
406 		 * Check to see if authorization is needed.
407 		 */
408 		if (nd->nd_flag & NFSD_NEEDAUTH) {
409 			nd->nd_flag &= ~NFSD_NEEDAUTH;
410 			nsd->nsd_uid = nd->nd_cr.cr_uid;
411 			nsd->nsd_haddr =
412 			    mtod(slp->ns_nam, struct sockaddr_in *)->sin_addr.s_addr;
413 			nsd->nsd_authlen = nd->nd_authlen;
414 			(void) copyout(nd->nd_authstr, nsd->nsd_authstr,
415 				 nd->nd_authlen);
416 			(void) copyout((caddr_t)nsd, argp, sizeof (*nsd));
417 			return (ENEEDAUTH);
418 		}
419 		if (so->so_proto->pr_flags & PR_CONNREQUIRED)
420 			solockp = &slp->ns_solock;
421 		else
422 			solockp = (int *)0;
423 		/*
424 		 * nam == nam2 for connectionless protocols such as UDP
425 		 * nam2 == NULL for connection based protocols to disable
426 		 *    recent request caching.
427 		 */
428 		nam2 = nd->nd_nam;
429 
430 		if (nam2) {
431 			nam = nam2;
432 			cacherep = nfsrv_getcache(nam2, nd, &mreq);
433 		} else {
434 			nam = slp->ns_nam;
435 			cacherep = RC_DOIT;
436 		}
437 
438 		/*
439 		 * Check for just starting up for NQNFS and send
440 		 * fake "try again later" replies to the NQNFS clients.
441 		 */
442 		if (notstarted && nqnfsstarttime <= time.tv_sec) {
443 			if (modify_flag) {
444 				nqnfsstarttime = time.tv_sec + nqsrv_writeslack;
445 				modify_flag = 0;
446 			} else
447 				notstarted = 0;
448 		}
449 		if (notstarted) {
450 			if (nd->nd_nqlflag == NQL_NOVAL)
451 				cacherep = RC_DROPIT;
452 			else if (nd->nd_procnum != NFSPROC_WRITE) {
453 				nd->nd_procnum = NFSPROC_NOOP;
454 				nd->nd_repstat = NQNFS_TRYLATER;
455 				cacherep = RC_DOIT;
456 			} else
457 				modify_flag = 1;
458 		} else if (nd->nd_flag & NFSD_AUTHFAIL) {
459 			nd->nd_flag &= ~NFSD_AUTHFAIL;
460 			nd->nd_procnum = NFSPROC_NOOP;
461 			nd->nd_repstat = NQNFS_AUTHERR;
462 			cacherep = RC_DOIT;
463 		}
464 
465 		switch (cacherep) {
466 		case RC_DOIT:
467 			error = (*(nfsrv_procs[nd->nd_procnum]))(nd,
468 				nd->nd_mrep, nd->nd_md, nd->nd_dpos, &nd->nd_cr,
469 				nam, &mreq);
470 			if (nd->nd_cr.cr_ref != 1) {
471 				printf("nfssvc cref=%d\n", nd->nd_cr.cr_ref);
472 				panic("nfssvc cref");
473 			}
474 			if (error) {
475 				if (nd->nd_procnum != NQNFSPROC_VACATED)
476 					nfsstats.srv_errs++;
477 				if (nam2) {
478 					nfsrv_updatecache(nam2, nd, FALSE, mreq);
479 					m_freem(nam2);
480 				}
481 				break;
482 			}
483 			nfsstats.srvrpccnt[nd->nd_procnum]++;
484 			if (nam2)
485 				nfsrv_updatecache(nam2, nd, TRUE, mreq);
486 			nd->nd_mrep = (struct mbuf *)0;
487 		case RC_REPLY:
488 			m = mreq;
489 			siz = 0;
490 			while (m) {
491 				siz += m->m_len;
492 				m = m->m_next;
493 			}
494 			if (siz <= 0 || siz > NFS_MAXPACKET) {
495 				printf("mbuf siz=%d\n",siz);
496 				panic("Bad nfs svc reply");
497 			}
498 			m = mreq;
499 			m->m_pkthdr.len = siz;
500 			m->m_pkthdr.rcvif = (struct ifnet *)0;
501 			/*
502 			 * For stream protocols, prepend a Sun RPC
503 			 * Record Mark.
504 			 */
505 			if (sotype == SOCK_STREAM) {
506 				M_PREPEND(m, NFSX_UNSIGNED, M_WAIT);
507 				*mtod(m, u_long *) = htonl(0x80000000 | siz);
508 			}
509 			if (solockp)
510 				(void) nfs_sndlock(solockp, (struct nfsreq *)0);
511 			if (slp->ns_flag & SLP_VALID)
512 			    error = nfs_send(so, nam2, m, (struct nfsreq *)0);
513 			else {
514 			    error = EPIPE;
515 			    m_freem(m);
516 			}
517 			if (nam2)
518 				MFREE(nam2, m);
519 			if (nd->nd_mrep)
520 				m_freem(nd->nd_mrep);
521 			if (error == EPIPE)
522 				nfsrv_zapsock(slp);
523 			if (solockp)
524 				nfs_sndunlock(solockp);
525 			if (error == EINTR || error == ERESTART) {
526 				nfsrv_slpderef(slp);
527 				s = splnet();
528 				goto done;
529 			}
530 			break;
531 		case RC_DROPIT:
532 			m_freem(nd->nd_mrep);
533 			m_freem(nam2);
534 			break;
535 		};
536 		s = splnet();
537 		if (nfsrv_dorec(slp, nd)) {
538 			nd->nd_flag &= ~NFSD_REQINPROG;
539 			nd->nd_slp = (struct nfssvc_sock *)0;
540 			nfsrv_slpderef(slp);
541 		}
542 	}
543 done:
544 	remque(nd);
545 	splx(s);
546 	free((caddr_t)nd, M_NFSD);
547 	nsd->nsd_nfsd = (struct nfsd *)0;
548 	if (--nfs_numnfsd == 0)
549 		nfsrv_init(TRUE);	/* Reinitialize everything */
550 	return (error);
551 }
552 
553 /*
554  * Asynchronous I/O daemons for client nfs.
555  * These babies just pretend to be disk interrupt service routines.
556  * They are mainly here for read ahead/write behind.
557  * Never returns unless it fails or gets killed.
558  */
559 nfssvc_iod(p)
560 	struct proc *p;
561 {
562 	register struct buf *bp, *dp;
563 	register int i, myiod;
564 	int error = 0;
565 
566 	/*
567 	 * Assign my position or return error if too many already running
568 	 */
569 	myiod = -1;
570 	for (i = 0; i < NFS_MAXASYNCDAEMON; i++)
571 		if (nfs_asyncdaemon[i] == 0) {
572 			nfs_asyncdaemon[i]++;
573 			myiod = i;
574 			break;
575 		}
576 	if (myiod == -1)
577 		return (EBUSY);
578 	nfs_numasync++;
579 	dp = &nfs_bqueue;
580 	/*
581 	 * Just loop around doin our stuff until SIGKILL
582 	 */
583 	for (;;) {
584 		while (dp->b_actf == NULL && error == 0) {
585 			nfs_iodwant[myiod] = p;
586 			error = tsleep((caddr_t)&nfs_iodwant[myiod],
587 				PWAIT | PCATCH, "nfsidl", 0);
588 			nfs_iodwant[myiod] = (struct proc *)0;
589 		}
590 		while (dp->b_actf != NULL) {
591 			/* Take one off the end of the list */
592 			bp = dp->b_actl;
593 			if (bp->b_actl == dp) {
594 				dp->b_actf = dp->b_actl = (struct buf *)0;
595 			} else {
596 				dp->b_actl = bp->b_actl;
597 				bp->b_actl->b_actf = dp;
598 			}
599 			(void) nfs_doio(bp, (struct proc *)0);
600 		}
601 		if (error) {
602 			nfs_asyncdaemon[myiod] = 0;
603 			nfs_numasync--;
604 			return (error);
605 		}
606 	}
607 }
608 
609 /*
610  * Shut down a socket associated with an nfssvc_sock structure.
611  * Should be called with the send lock set, if required.
612  * The trick here is to increment the sref at the start, so that the nfsds
613  * will stop using it and clear ns_flag at the end so that it will not be
614  * reassigned during cleanup.
615  */
616 nfsrv_zapsock(slp)
617 	register struct nfssvc_sock *slp;
618 {
619 	register struct nfsuid *nuidp, *onuidp;
620 	register int i;
621 	struct socket *so;
622 	struct file *fp;
623 	struct mbuf *m;
624 
625 	slp->ns_flag &= ~SLP_ALLFLAGS;
626 	if (fp = slp->ns_fp) {
627 		slp->ns_fp = (struct file *)0;
628 		so = slp->ns_so;
629 		so->so_upcall = NULL;
630 		soshutdown(so, 2);
631 		closef(fp, (struct proc *)0);
632 		if (slp->ns_nam)
633 			MFREE(slp->ns_nam, m);
634 		m_freem(slp->ns_raw);
635 		m_freem(slp->ns_rec);
636 		nuidp = slp->ns_lrunext;
637 		while (nuidp != (struct nfsuid *)slp) {
638 			onuidp = nuidp;
639 			nuidp = nuidp->nu_lrunext;
640 			free((caddr_t)onuidp, M_NFSUID);
641 		}
642 		slp->ns_lrunext = slp->ns_lruprev = (struct nfsuid *)slp;
643 		for (i = 0; i < NUIDHASHSIZ; i++)
644 			slp->ns_uidh[i] = (struct nfsuid *)0;
645 	}
646 }
647 
648 /*
649  * Get an authorization string for the uid by having the mount_nfs sitting
650  * on this mount point porpous out of the kernel and do it.
651  */
652 nfs_getauth(nmp, rep, cred, auth_type, auth_str, auth_len)
653 	register struct nfsmount *nmp;
654 	struct nfsreq *rep;
655 	struct ucred *cred;
656 	int *auth_type;
657 	char **auth_str;
658 	int *auth_len;
659 {
660 	int error = 0;
661 
662 	while ((nmp->nm_flag & NFSMNT_WAITAUTH) == 0) {
663 		nmp->nm_flag |= NFSMNT_WANTAUTH;
664 		(void) tsleep((caddr_t)&nmp->nm_authtype, PSOCK,
665 			"nfsauth1", 2 * hz);
666 		if (error = nfs_sigintr(nmp, rep, rep->r_procp)) {
667 			nmp->nm_flag &= ~NFSMNT_WANTAUTH;
668 			return (error);
669 		}
670 	}
671 	nmp->nm_flag &= ~(NFSMNT_WAITAUTH | NFSMNT_WANTAUTH);
672 	nmp->nm_authstr = *auth_str = (char *)malloc(RPCAUTH_MAXSIZ, M_TEMP, M_WAITOK);
673 	nmp->nm_authuid = cred->cr_uid;
674 	wakeup((caddr_t)&nmp->nm_authstr);
675 
676 	/*
677 	 * And wait for mount_nfs to do its stuff.
678 	 */
679 	while ((nmp->nm_flag & NFSMNT_HASAUTH) == 0 && error == 0) {
680 		(void) tsleep((caddr_t)&nmp->nm_authlen, PSOCK,
681 			"nfsauth2", 2 * hz);
682 		error = nfs_sigintr(nmp, rep, rep->r_procp);
683 	}
684 	if (nmp->nm_flag & NFSMNT_AUTHERR) {
685 		nmp->nm_flag &= ~NFSMNT_AUTHERR;
686 		error = EAUTH;
687 	}
688 	if (error)
689 		free((caddr_t)*auth_str, M_TEMP);
690 	else {
691 		*auth_type = nmp->nm_authtype;
692 		*auth_len = nmp->nm_authlen;
693 	}
694 	nmp->nm_flag &= ~NFSMNT_HASAUTH;
695 	nmp->nm_flag |= NFSMNT_WAITAUTH;
696 	if (nmp->nm_flag & NFSMNT_WANTAUTH) {
697 		nmp->nm_flag &= ~NFSMNT_WANTAUTH;
698 		wakeup((caddr_t)&nmp->nm_authtype);
699 	}
700 	return (error);
701 }
702 
703 /*
704  * Derefence a server socket structure. If it has no more references and
705  * is no longer valid, you can throw it away.
706  */
707 void
708 nfsrv_slpderef(slp)
709 	register struct nfssvc_sock *slp;
710 {
711 	if (--(slp->ns_sref) == 0 && (slp->ns_flag & SLP_VALID) == 0) {
712 		slp->ns_prev->ns_next = slp->ns_next;
713 		slp->ns_next->ns_prev = slp->ns_prev;
714 		free((caddr_t)slp, M_NFSSVC);
715 	}
716 }
717 
718 /*
719  * Initialize the data structures for the server.
720  * Handshake with any new nfsds starting up to avoid any chance of
721  * corruption.
722  */
723 void
724 nfsrv_init(terminating)
725 	int terminating;
726 {
727 	register struct nfssvc_sock *slp;
728 	struct nfssvc_sock *oslp;
729 
730 	if (nfssvc_sockhead.ns_flag & SLP_INIT)
731 		panic("nfsd init");
732 	nfssvc_sockhead.ns_flag |= SLP_INIT;
733 	if (terminating) {
734 		slp = nfssvc_sockhead.ns_next;
735 		while (slp != &nfssvc_sockhead) {
736 			if (slp->ns_flag & SLP_VALID)
737 				nfsrv_zapsock(slp);
738 			slp->ns_next->ns_prev = slp->ns_prev;
739 			slp->ns_prev->ns_next = slp->ns_next;
740 			oslp = slp;
741 			slp = slp->ns_next;
742 			free((caddr_t)oslp, M_NFSSVC);
743 		}
744 		nfsrv_cleancache();	/* And clear out server cache */
745 	}
746 	nfs_udpsock = (struct nfssvc_sock *)
747 	    malloc(sizeof (struct nfssvc_sock), M_NFSSVC, M_WAITOK);
748 	bzero((caddr_t)nfs_udpsock, sizeof (struct nfssvc_sock));
749 	nfs_cltpsock = (struct nfssvc_sock *)
750 	    malloc(sizeof (struct nfssvc_sock), M_NFSSVC, M_WAITOK);
751 	bzero((caddr_t)nfs_cltpsock, sizeof (struct nfssvc_sock));
752 	nfssvc_sockhead.ns_next = nfs_udpsock;
753 	nfs_udpsock->ns_next = nfs_cltpsock;
754 	nfs_cltpsock->ns_next = &nfssvc_sockhead;
755 	nfssvc_sockhead.ns_prev = nfs_cltpsock;
756 	nfs_cltpsock->ns_prev = nfs_udpsock;
757 	nfs_udpsock->ns_prev = &nfssvc_sockhead;
758 	nfs_udpsock->ns_lrunext = nfs_udpsock->ns_lruprev =
759 		(struct nfsuid *)nfs_udpsock;
760 	nfs_cltpsock->ns_lrunext = nfs_cltpsock->ns_lruprev =
761 		(struct nfsuid *)nfs_cltpsock;
762 	nfsd_head.nd_next = nfsd_head.nd_prev = &nfsd_head;
763 	nfsd_head.nd_flag = 0;
764 	nfssvc_sockhead.ns_flag &= ~SLP_INIT;
765 	if (nfssvc_sockhead.ns_flag & SLP_WANTINIT) {
766 		nfssvc_sockhead.ns_flag &= ~SLP_WANTINIT;
767 		wakeup((caddr_t)&nfssvc_sockhead);
768 	}
769 }
770