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