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