xref: /original-bsd/sys/nfs/nfs_syscalls.c (revision be1f24e8)
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.34 (Berkeley) 10/08/92
11  */
12 
13 #include <sys/param.h>
14 #include <sys/systm.h>
15 #include <sys/kernel.h>
16 #include <sys/file.h>
17 #include <sys/stat.h>
18 #include <sys/vnode.h>
19 #include <sys/mount.h>
20 #include <sys/proc.h>
21 #include <sys/uio.h>
22 #include <sys/malloc.h>
23 #include <sys/buf.h>
24 #include <sys/mbuf.h>
25 #include <sys/socket.h>
26 #include <sys/socketvar.h>
27 #include <sys/domain.h>
28 #include <sys/protosw.h>
29 #include <sys/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 <nfs/rpcv2.h>
37 #include <nfs/nfsv2.h>
38 #include <nfs/nfs.h>
39 #include <nfs/nfsrvcache.h>
40 #include <nfs/nfsmount.h>
41 #include <nfs/nqnfs.h>
42 
43 /* Global defs. */
44 extern u_long nfs_prog, nfs_vers;
45 extern int (*nfsrv_procs[NFS_NPROCS])();
46 extern struct queue_entry nfs_bufq;
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 	/*
580 	 * Just loop around doin our stuff until SIGKILL
581 	 */
582 	for (;;) {
583 		while (nfs_bufq.qe_next == NULL && error == 0) {
584 			nfs_iodwant[myiod] = p;
585 			error = tsleep((caddr_t)&nfs_iodwant[myiod],
586 				PWAIT | PCATCH, "nfsidl", 0);
587 			nfs_iodwant[myiod] = (struct proc *)0;
588 		}
589 		while ((bp = nfs_bufq.qe_next) != NULL) {
590 			/* Take one off the front of the list */
591 			queue_remove(&nfs_bufq, bp, struct buf *, b_freelist);
592 			(void) nfs_doio(bp, (struct proc *)0);
593 		}
594 		if (error) {
595 			nfs_asyncdaemon[myiod] = 0;
596 			nfs_numasync--;
597 			return (error);
598 		}
599 	}
600 }
601 
602 /*
603  * Shut down a socket associated with an nfssvc_sock structure.
604  * Should be called with the send lock set, if required.
605  * The trick here is to increment the sref at the start, so that the nfsds
606  * will stop using it and clear ns_flag at the end so that it will not be
607  * reassigned during cleanup.
608  */
609 nfsrv_zapsock(slp)
610 	register struct nfssvc_sock *slp;
611 {
612 	register struct nfsuid *nuidp, *onuidp;
613 	register int i;
614 	struct socket *so;
615 	struct file *fp;
616 	struct mbuf *m;
617 
618 	slp->ns_flag &= ~SLP_ALLFLAGS;
619 	if (fp = slp->ns_fp) {
620 		slp->ns_fp = (struct file *)0;
621 		so = slp->ns_so;
622 		so->so_upcall = NULL;
623 		soshutdown(so, 2);
624 		closef(fp, (struct proc *)0);
625 		if (slp->ns_nam)
626 			MFREE(slp->ns_nam, m);
627 		m_freem(slp->ns_raw);
628 		m_freem(slp->ns_rec);
629 		nuidp = slp->ns_lrunext;
630 		while (nuidp != (struct nfsuid *)slp) {
631 			onuidp = nuidp;
632 			nuidp = nuidp->nu_lrunext;
633 			free((caddr_t)onuidp, M_NFSUID);
634 		}
635 		slp->ns_lrunext = slp->ns_lruprev = (struct nfsuid *)slp;
636 		for (i = 0; i < NUIDHASHSIZ; i++)
637 			slp->ns_uidh[i] = (struct nfsuid *)0;
638 	}
639 }
640 
641 /*
642  * Get an authorization string for the uid by having the mount_nfs sitting
643  * on this mount point porpous out of the kernel and do it.
644  */
645 nfs_getauth(nmp, rep, cred, auth_type, auth_str, auth_len)
646 	register struct nfsmount *nmp;
647 	struct nfsreq *rep;
648 	struct ucred *cred;
649 	int *auth_type;
650 	char **auth_str;
651 	int *auth_len;
652 {
653 	int error = 0;
654 
655 	while ((nmp->nm_flag & NFSMNT_WAITAUTH) == 0) {
656 		nmp->nm_flag |= NFSMNT_WANTAUTH;
657 		(void) tsleep((caddr_t)&nmp->nm_authtype, PSOCK,
658 			"nfsauth1", 2 * hz);
659 		if (error = nfs_sigintr(nmp, rep, rep->r_procp)) {
660 			nmp->nm_flag &= ~NFSMNT_WANTAUTH;
661 			return (error);
662 		}
663 	}
664 	nmp->nm_flag &= ~(NFSMNT_WAITAUTH | NFSMNT_WANTAUTH);
665 	nmp->nm_authstr = *auth_str = (char *)malloc(RPCAUTH_MAXSIZ, M_TEMP, M_WAITOK);
666 	nmp->nm_authuid = cred->cr_uid;
667 	wakeup((caddr_t)&nmp->nm_authstr);
668 
669 	/*
670 	 * And wait for mount_nfs to do its stuff.
671 	 */
672 	while ((nmp->nm_flag & NFSMNT_HASAUTH) == 0 && error == 0) {
673 		(void) tsleep((caddr_t)&nmp->nm_authlen, PSOCK,
674 			"nfsauth2", 2 * hz);
675 		error = nfs_sigintr(nmp, rep, rep->r_procp);
676 	}
677 	if (nmp->nm_flag & NFSMNT_AUTHERR) {
678 		nmp->nm_flag &= ~NFSMNT_AUTHERR;
679 		error = EAUTH;
680 	}
681 	if (error)
682 		free((caddr_t)*auth_str, M_TEMP);
683 	else {
684 		*auth_type = nmp->nm_authtype;
685 		*auth_len = nmp->nm_authlen;
686 	}
687 	nmp->nm_flag &= ~NFSMNT_HASAUTH;
688 	nmp->nm_flag |= NFSMNT_WAITAUTH;
689 	if (nmp->nm_flag & NFSMNT_WANTAUTH) {
690 		nmp->nm_flag &= ~NFSMNT_WANTAUTH;
691 		wakeup((caddr_t)&nmp->nm_authtype);
692 	}
693 	return (error);
694 }
695 
696 /*
697  * Derefence a server socket structure. If it has no more references and
698  * is no longer valid, you can throw it away.
699  */
700 void
701 nfsrv_slpderef(slp)
702 	register struct nfssvc_sock *slp;
703 {
704 	if (--(slp->ns_sref) == 0 && (slp->ns_flag & SLP_VALID) == 0) {
705 		slp->ns_prev->ns_next = slp->ns_next;
706 		slp->ns_next->ns_prev = slp->ns_prev;
707 		free((caddr_t)slp, M_NFSSVC);
708 	}
709 }
710 
711 /*
712  * Initialize the data structures for the server.
713  * Handshake with any new nfsds starting up to avoid any chance of
714  * corruption.
715  */
716 void
717 nfsrv_init(terminating)
718 	int terminating;
719 {
720 	register struct nfssvc_sock *slp;
721 	struct nfssvc_sock *oslp;
722 
723 	if (nfssvc_sockhead.ns_flag & SLP_INIT)
724 		panic("nfsd init");
725 	nfssvc_sockhead.ns_flag |= SLP_INIT;
726 	if (terminating) {
727 		slp = nfssvc_sockhead.ns_next;
728 		while (slp != &nfssvc_sockhead) {
729 			if (slp->ns_flag & SLP_VALID)
730 				nfsrv_zapsock(slp);
731 			slp->ns_next->ns_prev = slp->ns_prev;
732 			slp->ns_prev->ns_next = slp->ns_next;
733 			oslp = slp;
734 			slp = slp->ns_next;
735 			free((caddr_t)oslp, M_NFSSVC);
736 		}
737 		nfsrv_cleancache();	/* And clear out server cache */
738 	}
739 	nfs_udpsock = (struct nfssvc_sock *)
740 	    malloc(sizeof (struct nfssvc_sock), M_NFSSVC, M_WAITOK);
741 	bzero((caddr_t)nfs_udpsock, sizeof (struct nfssvc_sock));
742 	nfs_cltpsock = (struct nfssvc_sock *)
743 	    malloc(sizeof (struct nfssvc_sock), M_NFSSVC, M_WAITOK);
744 	bzero((caddr_t)nfs_cltpsock, sizeof (struct nfssvc_sock));
745 	nfssvc_sockhead.ns_next = nfs_udpsock;
746 	nfs_udpsock->ns_next = nfs_cltpsock;
747 	nfs_cltpsock->ns_next = &nfssvc_sockhead;
748 	nfssvc_sockhead.ns_prev = nfs_cltpsock;
749 	nfs_cltpsock->ns_prev = nfs_udpsock;
750 	nfs_udpsock->ns_prev = &nfssvc_sockhead;
751 	nfs_udpsock->ns_lrunext = nfs_udpsock->ns_lruprev =
752 		(struct nfsuid *)nfs_udpsock;
753 	nfs_cltpsock->ns_lrunext = nfs_cltpsock->ns_lruprev =
754 		(struct nfsuid *)nfs_cltpsock;
755 	nfsd_head.nd_next = nfsd_head.nd_prev = &nfsd_head;
756 	nfsd_head.nd_flag = 0;
757 	nfssvc_sockhead.ns_flag &= ~SLP_INIT;
758 	if (nfssvc_sockhead.ns_flag & SLP_WANTINIT) {
759 		nfssvc_sockhead.ns_flag &= ~SLP_WANTINIT;
760 		wakeup((caddr_t)&nfssvc_sockhead);
761 	}
762 }
763