xref: /csrg-svn/sys/nfs/nfs_syscalls.c (revision 57789)
138414Smckusick /*
238414Smckusick  * Copyright (c) 1989 The Regents of the University of California.
338414Smckusick  * All rights reserved.
438414Smckusick  *
538414Smckusick  * This code is derived from software contributed to Berkeley by
638414Smckusick  * Rick Macklem at The University of Guelph.
738414Smckusick  *
844513Sbostic  * %sccs.include.redist.c%
938414Smckusick  *
10*57789Smckusick  *	@(#)nfs_syscalls.c	7.37 (Berkeley) 02/02/93
1138414Smckusick  */
1238414Smckusick 
1356469Smckusick #include <sys/param.h>
1456469Smckusick #include <sys/systm.h>
1556469Smckusick #include <sys/kernel.h>
1656469Smckusick #include <sys/file.h>
1756469Smckusick #include <sys/stat.h>
1856469Smckusick #include <sys/vnode.h>
1956469Smckusick #include <sys/mount.h>
2056469Smckusick #include <sys/proc.h>
2156469Smckusick #include <sys/uio.h>
2256469Smckusick #include <sys/malloc.h>
2356469Smckusick #include <sys/buf.h>
2456469Smckusick #include <sys/mbuf.h>
2556469Smckusick #include <sys/socket.h>
2656469Smckusick #include <sys/socketvar.h>
2756469Smckusick #include <sys/domain.h>
2856469Smckusick #include <sys/protosw.h>
2956469Smckusick #include <sys/namei.h>
30*57789Smckusick #include <sys/syslog.h>
3156535Sbostic 
3256469Smckusick #include <netinet/in.h>
3356469Smckusick #include <netinet/tcp.h>
3452196Smckusick #ifdef ISO
3556469Smckusick #include <netiso/iso.h>
3652196Smckusick #endif
3756469Smckusick #include <nfs/rpcv2.h>
3856469Smckusick #include <nfs/nfsv2.h>
3956469Smckusick #include <nfs/nfs.h>
4056469Smckusick #include <nfs/nfsrvcache.h>
4156469Smckusick #include <nfs/nfsmount.h>
4256469Smckusick #include <nfs/nqnfs.h>
43*57789Smckusick #include <nfs/nfsrtt.h>
4438414Smckusick 
4538414Smckusick /* Global defs. */
4638414Smckusick extern u_long nfs_prog, nfs_vers;
4738414Smckusick extern int (*nfsrv_procs[NFS_NPROCS])();
4856469Smckusick extern struct queue_entry nfs_bufq;
4952196Smckusick extern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON];
5046988Smckusick extern int nfs_numasync;
5152196Smckusick extern time_t nqnfsstarttime;
5252196Smckusick extern struct nfsrv_req nsrvq_head;
5352196Smckusick extern struct nfsd nfsd_head;
5452196Smckusick extern int nqsrv_writeslack;
55*57789Smckusick extern int nfsrtton;
5652196Smckusick struct nfssvc_sock *nfs_udpsock, *nfs_cltpsock;
5752196Smckusick int nuidhash_max = NFS_MAXUIDHASH;
5852196Smckusick static int nfs_numnfsd = 0;
5952196Smckusick int nfsd_waiting = 0;
6052196Smckusick static int notstarted = 1;
6152196Smckusick static int modify_flag = 0;
62*57789Smckusick static struct nfsdrt nfsdrt;
6352196Smckusick void nfsrv_cleancache(), nfsrv_rcv(), nfsrv_wakenfsd(), nfs_sndunlock();
64*57789Smckusick static void nfsd_rt();
6552981Smckusick void nfsrv_slpderef(), nfsrv_init();
6638414Smckusick 
6740252Smckusick #define	TRUE	1
6840252Smckusick #define	FALSE	0
6940252Smckusick 
7046988Smckusick static int nfs_asyncdaemon[NFS_MAXASYNCDAEMON];
7138414Smckusick /*
7238414Smckusick  * NFS server system calls
7338414Smckusick  * getfh() lives here too, but maybe should move to kern/vfs_syscalls.c
7438414Smckusick  */
7538414Smckusick 
7638414Smckusick /*
7738414Smckusick  * Get file handle system call
7838414Smckusick  */
7954918Storek struct getfh_args {
8054918Storek 	char	*fname;
8154918Storek 	fhandle_t *fhp;
8254918Storek };
8343354Smckusick getfh(p, uap, retval)
8443354Smckusick 	struct proc *p;
8554918Storek 	register struct getfh_args *uap;
8643354Smckusick 	int *retval;
8743354Smckusick {
8838414Smckusick 	register struct vnode *vp;
8938414Smckusick 	fhandle_t fh;
9038414Smckusick 	int error;
9146990Smckusick 	struct nameidata nd;
9238414Smckusick 
9338414Smckusick 	/*
9438414Smckusick 	 * Must be super user
9538414Smckusick 	 */
9646980Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
9744411Skarels 		return (error);
9852318Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
9952318Smckusick 	if (error = namei(&nd))
10044411Skarels 		return (error);
10152318Smckusick 	vp = nd.ni_vp;
10238414Smckusick 	bzero((caddr_t)&fh, sizeof(fh));
10341398Smckusick 	fh.fh_fsid = vp->v_mount->mnt_stat.f_fsid;
10438414Smckusick 	error = VFS_VPTOFH(vp, &fh.fh_fid);
10538414Smckusick 	vput(vp);
10638414Smckusick 	if (error)
10744411Skarels 		return (error);
10838414Smckusick 	error = copyout((caddr_t)&fh, (caddr_t)uap->fhp, sizeof (fh));
10944411Skarels 	return (error);
11038414Smckusick }
11138414Smckusick 
11252196Smckusick static struct nfssvc_sock nfssvc_sockhead;
11352196Smckusick 
11438414Smckusick /*
11538414Smckusick  * Nfs server psuedo system call for the nfsd's
11652196Smckusick  * Based on the flag value it either:
11752196Smckusick  * - adds a socket to the selection list
11852196Smckusick  * - remains in the kernel as an nfsd
11952196Smckusick  * - remains in the kernel as an nfsiod
12038414Smckusick  */
12154918Storek struct nfssvc_args {
12254918Storek 	int flag;
12354918Storek 	caddr_t argp;
12454918Storek };
12543354Smckusick nfssvc(p, uap, retval)
12643354Smckusick 	struct proc *p;
12754918Storek 	register struct nfssvc_args *uap;
12843354Smckusick 	int *retval;
12943354Smckusick {
13052196Smckusick 	struct nameidata nd;
13138414Smckusick 	struct file *fp;
13252196Smckusick 	struct mbuf *nam;
13352196Smckusick 	struct nfsd_args nfsdarg;
13452196Smckusick 	struct nfsd_srvargs nfsd_srvargs, *nsd = &nfsd_srvargs;
13552196Smckusick 	struct nfsd_cargs ncd;
13652196Smckusick 	struct nfsd *nfsd;
13752196Smckusick 	struct nfssvc_sock *slp;
13852196Smckusick 	struct nfsuid *nuidp, **nuh;
13952196Smckusick 	struct nfsmount *nmp;
14052196Smckusick 	int error;
14138414Smckusick 
14238414Smckusick 	/*
14338414Smckusick 	 * Must be super user
14438414Smckusick 	 */
14546980Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
14645919Smckusick 		return (error);
14752981Smckusick 	while (nfssvc_sockhead.ns_flag & SLP_INIT) {
14852981Smckusick 		nfssvc_sockhead.ns_flag |= SLP_WANTINIT;
14952981Smckusick 		(void) tsleep((caddr_t)&nfssvc_sockhead, PSOCK, "nfsd init", 0);
15052196Smckusick 	}
15152196Smckusick 	if (uap->flag & NFSSVC_BIOD)
15252196Smckusick 		error = nfssvc_iod(p);
15352196Smckusick 	else if (uap->flag & NFSSVC_MNTD) {
15452196Smckusick 		if (error = copyin(uap->argp, (caddr_t)&ncd, sizeof (ncd)))
15552196Smckusick 			return (error);
15652318Smckusick 		NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
15752318Smckusick 			ncd.ncd_dirp, p);
15852318Smckusick 		if (error = namei(&nd))
15952196Smckusick 			return (error);
16052196Smckusick 		if ((nd.ni_vp->v_flag & VROOT) == 0)
16152196Smckusick 			error = EINVAL;
16252196Smckusick 		nmp = VFSTONFS(nd.ni_vp->v_mount);
16352196Smckusick 		vput(nd.ni_vp);
16452196Smckusick 		if (error)
16552196Smckusick 			return (error);
166*57789Smckusick 		if ((nmp->nm_flag & NFSMNT_MNTD) &&
167*57789Smckusick 			(uap->flag & NFSSVC_GOTAUTH) == 0)
16852196Smckusick 			return (0);
16952196Smckusick 		nmp->nm_flag |= NFSMNT_MNTD;
17052318Smckusick 		error = nqnfs_clientd(nmp, p->p_ucred, &ncd, uap->flag,
17152318Smckusick 			uap->argp, p);
17252196Smckusick 	} else if (uap->flag & NFSSVC_ADDSOCK) {
17352318Smckusick 		if (error = copyin(uap->argp, (caddr_t)&nfsdarg,
17452318Smckusick 		    sizeof(nfsdarg)))
17552196Smckusick 			return (error);
17652196Smckusick 		if (error = getsock(p->p_fd, nfsdarg.sock, &fp))
17752196Smckusick 			return (error);
17852196Smckusick 		/*
17952196Smckusick 		 * Get the client address for connected sockets.
18052196Smckusick 		 */
18152196Smckusick 		if (nfsdarg.name == NULL || nfsdarg.namelen == 0)
18252196Smckusick 			nam = (struct mbuf *)0;
18352196Smckusick 		else if (error = sockargs(&nam, nfsdarg.name, nfsdarg.namelen,
18452196Smckusick 			MT_SONAME))
18552196Smckusick 			return (error);
18652196Smckusick 		error = nfssvc_addsock(fp, nam);
18752196Smckusick 	} else {
18852196Smckusick 		if (error = copyin(uap->argp, (caddr_t)nsd, sizeof (*nsd)))
18952196Smckusick 			return (error);
19052196Smckusick 		if ((uap->flag & NFSSVC_AUTHIN) && (nfsd = nsd->nsd_nfsd) &&
19152903Smckusick 			(nfsd->nd_slp->ns_flag & SLP_VALID)) {
19252196Smckusick 			slp = nfsd->nd_slp;
193*57789Smckusick 
194*57789Smckusick 			/*
195*57789Smckusick 			 * First check to see if another nfsd has already
196*57789Smckusick 			 * added this credential.
197*57789Smckusick 			 */
198*57789Smckusick 			nuidp = slp->ns_uidh[NUIDHASH(nsd->nsd_uid)];
199*57789Smckusick 			while (nuidp) {
200*57789Smckusick 				if (nuidp->nu_uid == nsd->nsd_uid)
201*57789Smckusick 					break;
202*57789Smckusick 				nuidp = nuidp->nu_hnext;
203*57789Smckusick 			}
204*57789Smckusick 			if (!nuidp) {
205*57789Smckusick 			    /*
206*57789Smckusick 			     * Nope, so we will.
207*57789Smckusick 			     */
208*57789Smckusick 			    if (slp->ns_numuids < nuidhash_max) {
20952196Smckusick 				slp->ns_numuids++;
21052196Smckusick 				nuidp = (struct nfsuid *)
211*57789Smckusick 				   malloc(sizeof (struct nfsuid), M_NFSUID,
212*57789Smckusick 					M_WAITOK);
213*57789Smckusick 			    } else
21452196Smckusick 				nuidp = (struct nfsuid *)0;
215*57789Smckusick 			    if ((slp->ns_flag & SLP_VALID) == 0) {
216*57789Smckusick 				if (nuidp)
217*57789Smckusick 				    free((caddr_t)nuidp, M_NFSUID);
218*57789Smckusick 			    } else {
219*57789Smckusick 				if (nuidp == (struct nfsuid *)0) {
220*57789Smckusick 				    nuidp = slp->ns_lruprev;
221*57789Smckusick 				    remque(nuidp);
222*57789Smckusick 				    if (nuidp->nu_hprev)
223*57789Smckusick 					nuidp->nu_hprev->nu_hnext =
224*57789Smckusick 					    nuidp->nu_hnext;
225*57789Smckusick 				    if (nuidp->nu_hnext)
226*57789Smckusick 					nuidp->nu_hnext->nu_hprev =
227*57789Smckusick 					    nuidp->nu_hprev;
228*57789Smckusick 			        }
229*57789Smckusick 				nuidp->nu_cr = nsd->nsd_cr;
230*57789Smckusick 				if (nuidp->nu_cr.cr_ngroups > NGROUPS)
231*57789Smckusick 					nuidp->nu_cr.cr_ngroups = NGROUPS;
232*57789Smckusick 				nuidp->nu_cr.cr_ref = 1;
233*57789Smckusick 				nuidp->nu_uid = nsd->nsd_uid;
234*57789Smckusick 				insque(nuidp, (struct nfsuid *)slp);
235*57789Smckusick 				nuh = &slp->ns_uidh[NUIDHASH(nsd->nsd_uid)];
236*57789Smckusick 				if (nuidp->nu_hnext = *nuh)
237*57789Smckusick 				    nuidp->nu_hnext->nu_hprev = nuidp;
238*57789Smckusick 				nuidp->nu_hprev = (struct nfsuid *)0;
239*57789Smckusick 				*nuh = nuidp;
24052196Smckusick 			    }
24152196Smckusick 			}
24252196Smckusick 		}
24352196Smckusick 		if ((uap->flag & NFSSVC_AUTHINFAIL) && (nfsd = nsd->nsd_nfsd))
24452196Smckusick 			nfsd->nd_flag |= NFSD_AUTHFAIL;
24552196Smckusick 		error = nfssvc_nfsd(nsd, uap->argp, p);
24652196Smckusick 	}
24752196Smckusick 	if (error == EINTR || error == ERESTART)
24852196Smckusick 		error = 0;
24952196Smckusick 	return (error);
25052196Smckusick }
25152196Smckusick 
25252196Smckusick /*
25352196Smckusick  * Adds a socket to the list for servicing by nfsds.
25452196Smckusick  */
25552196Smckusick nfssvc_addsock(fp, mynam)
25652196Smckusick 	struct file *fp;
25752196Smckusick 	struct mbuf *mynam;
25852196Smckusick {
25952196Smckusick 	register struct mbuf *m;
26052196Smckusick 	register int siz;
26152196Smckusick 	register struct nfssvc_sock *slp;
26252196Smckusick 	register struct socket *so;
26352196Smckusick 	struct nfssvc_sock *tslp;
26452196Smckusick 	int error, s;
26552196Smckusick 
26638414Smckusick 	so = (struct socket *)fp->f_data;
26752196Smckusick 	tslp = (struct nfssvc_sock *)0;
26852196Smckusick 	/*
26952196Smckusick 	 * Add it to the list, as required.
27052196Smckusick 	 */
27152196Smckusick 	if (so->so_proto->pr_protocol == IPPROTO_UDP) {
27252196Smckusick 		tslp = nfs_udpsock;
27352196Smckusick 		if (tslp->ns_flag & SLP_VALID) {
27452196Smckusick 			m_freem(mynam);
27552196Smckusick 			return (EPERM);
27652196Smckusick 		}
27752196Smckusick #ifdef ISO
27852196Smckusick 	} else if (so->so_proto->pr_protocol == ISOPROTO_CLTP) {
27952196Smckusick 		tslp = nfs_cltpsock;
28052196Smckusick 		if (tslp->ns_flag & SLP_VALID) {
28152196Smckusick 			m_freem(mynam);
28252196Smckusick 			return (EPERM);
28352196Smckusick 		}
28452196Smckusick #endif /* ISO */
28552196Smckusick 	}
28652196Smckusick 	if (so->so_type == SOCK_STREAM)
28752196Smckusick 		siz = NFS_MAXPACKET + sizeof (u_long);
28852196Smckusick 	else
28941903Smckusick 		siz = NFS_MAXPACKET;
29052196Smckusick 	if (error = soreserve(so, siz, siz)) {
29152196Smckusick 		m_freem(mynam);
29252196Smckusick 		return (error);
29352196Smckusick 	}
29441903Smckusick 
29538414Smckusick 	/*
29641903Smckusick 	 * Set protocol specific options { for now TCP only } and
29741903Smckusick 	 * reserve some space. For datagram sockets, this can get called
29841903Smckusick 	 * repeatedly for the same socket, but that isn't harmful.
29941903Smckusick 	 */
30052196Smckusick 	if (so->so_type == SOCK_STREAM) {
30141903Smckusick 		MGET(m, M_WAIT, MT_SOOPTS);
30241903Smckusick 		*mtod(m, int *) = 1;
30341903Smckusick 		m->m_len = sizeof(int);
30441903Smckusick 		sosetopt(so, SOL_SOCKET, SO_KEEPALIVE, m);
30541903Smckusick 	}
30641903Smckusick 	if (so->so_proto->pr_domain->dom_family == AF_INET &&
30752196Smckusick 	    so->so_proto->pr_protocol == IPPROTO_TCP) {
30841903Smckusick 		MGET(m, M_WAIT, MT_SOOPTS);
30941903Smckusick 		*mtod(m, int *) = 1;
31041903Smckusick 		m->m_len = sizeof(int);
31141903Smckusick 		sosetopt(so, IPPROTO_TCP, TCP_NODELAY, m);
31241903Smckusick 	}
31341903Smckusick 	so->so_rcv.sb_flags &= ~SB_NOINTR;
31441903Smckusick 	so->so_rcv.sb_timeo = 0;
31541903Smckusick 	so->so_snd.sb_flags &= ~SB_NOINTR;
31641903Smckusick 	so->so_snd.sb_timeo = 0;
31752196Smckusick 	if (tslp)
31852196Smckusick 		slp = tslp;
31952196Smckusick 	else {
32052196Smckusick 		slp = (struct nfssvc_sock *)
32152196Smckusick 			malloc(sizeof (struct nfssvc_sock), M_NFSSVC, M_WAITOK);
32252196Smckusick 		bzero((caddr_t)slp, sizeof (struct nfssvc_sock));
32352196Smckusick 		slp->ns_prev = nfssvc_sockhead.ns_prev;
32452196Smckusick 		slp->ns_prev->ns_next = slp;
32552196Smckusick 		slp->ns_next = &nfssvc_sockhead;
32652196Smckusick 		nfssvc_sockhead.ns_prev = slp;
32752196Smckusick 		slp->ns_lrunext = slp->ns_lruprev = (struct nfsuid *)slp;
32852196Smckusick 	}
32952196Smckusick 	slp->ns_so = so;
33052196Smckusick 	slp->ns_nam = mynam;
33152196Smckusick 	fp->f_count++;
33252196Smckusick 	slp->ns_fp = fp;
33352196Smckusick 	s = splnet();
33452196Smckusick 	so->so_upcallarg = (caddr_t)slp;
33552196Smckusick 	so->so_upcall = nfsrv_rcv;
33652196Smckusick 	slp->ns_flag = (SLP_VALID | SLP_NEEDQ);
33752196Smckusick 	nfsrv_wakenfsd(slp);
33852196Smckusick 	splx(s);
33952196Smckusick 	return (0);
34052196Smckusick }
34141903Smckusick 
34252196Smckusick /*
34352196Smckusick  * Called by nfssvc() for nfsds. Just loops around servicing rpc requests
34452196Smckusick  * until it is killed by a signal.
34552196Smckusick  */
34652196Smckusick nfssvc_nfsd(nsd, argp, p)
34752196Smckusick 	struct nfsd_srvargs *nsd;
34852196Smckusick 	caddr_t argp;
34952196Smckusick 	struct proc *p;
35052196Smckusick {
35152196Smckusick 	register struct mbuf *m, *nam2;
35252196Smckusick 	register int siz;
35352196Smckusick 	register struct nfssvc_sock *slp;
35452196Smckusick 	register struct socket *so;
35552196Smckusick 	register int *solockp;
35652903Smckusick 	struct nfssvc_sock *oslp;
35752196Smckusick 	struct nfsd *nd = nsd->nsd_nfsd;
35852196Smckusick 	struct mbuf *mreq, *nam;
359*57789Smckusick 	struct timeval starttime;
360*57789Smckusick 	struct nfsuid *uidp;
36152196Smckusick 	int error, cacherep, s;
36252196Smckusick 	int sotype;
36352196Smckusick 
36452903Smckusick 	s = splnet();
36552196Smckusick 	if (nd == (struct nfsd *)0) {
36652196Smckusick 		nsd->nsd_nfsd = nd = (struct nfsd *)
36752196Smckusick 			malloc(sizeof (struct nfsd), M_NFSD, M_WAITOK);
36852196Smckusick 		bzero((caddr_t)nd, sizeof (struct nfsd));
36952903Smckusick 		nd->nd_procp = p;
37052196Smckusick 		nd->nd_cr.cr_ref = 1;
37152196Smckusick 		insque(nd, &nfsd_head);
37256659Smckusick 		nd->nd_nqlflag = NQL_NOVAL;
37352196Smckusick 		nfs_numnfsd++;
37452196Smckusick 	}
37541903Smckusick 	/*
37652196Smckusick 	 * Loop getting rpc requests until SIGKILL.
37738414Smckusick 	 */
37838414Smckusick 	for (;;) {
37952196Smckusick 		if ((nd->nd_flag & NFSD_REQINPROG) == 0) {
38052196Smckusick 			while (nd->nd_slp == (struct nfssvc_sock *)0 &&
38152196Smckusick 				 (nfsd_head.nd_flag & NFSD_CHECKSLP) == 0) {
38252196Smckusick 				nd->nd_flag |= NFSD_WAITING;
38352196Smckusick 				nfsd_waiting++;
38452903Smckusick 				error = tsleep((caddr_t)nd, PSOCK | PCATCH, "nfsd", 0);
38552903Smckusick 				nfsd_waiting--;
38652903Smckusick 				if (error)
38752196Smckusick 					goto done;
38843354Smckusick 			}
38952196Smckusick 			if (nd->nd_slp == (struct nfssvc_sock *)0 &&
39052196Smckusick 				(nfsd_head.nd_flag & NFSD_CHECKSLP)) {
39152196Smckusick 				slp = nfssvc_sockhead.ns_next;
39252196Smckusick 				while (slp != &nfssvc_sockhead) {
39352903Smckusick 				    if ((slp->ns_flag & (SLP_VALID | SLP_DOREC))
39452903Smckusick 					== (SLP_VALID | SLP_DOREC)) {
39552903Smckusick 					    slp->ns_flag &= ~SLP_DOREC;
39652981Smckusick 					    slp->ns_sref++;
39752196Smckusick 					    nd->nd_slp = slp;
39852196Smckusick 					    break;
39952196Smckusick 				    }
40052196Smckusick 				    slp = slp->ns_next;
40152196Smckusick 				}
40252196Smckusick 				if (slp == &nfssvc_sockhead)
40352196Smckusick 					nfsd_head.nd_flag &= ~NFSD_CHECKSLP;
40452196Smckusick 			}
40552981Smckusick 			if ((slp = nd->nd_slp) == (struct nfssvc_sock *)0)
40652196Smckusick 				continue;
40752981Smckusick 			if (slp->ns_flag & SLP_VALID) {
40852981Smckusick 				if (slp->ns_flag & SLP_DISCONN)
40952981Smckusick 					nfsrv_zapsock(slp);
41052981Smckusick 				else if (slp->ns_flag & SLP_NEEDQ) {
41152981Smckusick 					slp->ns_flag &= ~SLP_NEEDQ;
41252981Smckusick 					(void) nfs_sndlock(&slp->ns_solock,
41352981Smckusick 						(struct nfsreq *)0);
41452981Smckusick 					nfsrv_rcv(slp->ns_so, (caddr_t)slp,
41552981Smckusick 						M_WAIT);
41652981Smckusick 					nfs_sndunlock(&slp->ns_solock);
41752981Smckusick 				}
41852981Smckusick 				error = nfsrv_dorec(slp, nd);
41952981Smckusick 				nd->nd_flag |= NFSD_REQINPROG;
42052196Smckusick 			}
42152903Smckusick 		} else {
42252903Smckusick 			error = 0;
42352196Smckusick 			slp = nd->nd_slp;
42452903Smckusick 		}
42552903Smckusick 		if (error || (slp->ns_flag & SLP_VALID) == 0) {
42652903Smckusick 			nd->nd_slp = (struct nfssvc_sock *)0;
42752903Smckusick 			nd->nd_flag &= ~NFSD_REQINPROG;
42852903Smckusick 			nfsrv_slpderef(slp);
42952903Smckusick 			continue;
43052903Smckusick 		}
43152903Smckusick 		splx(s);
43252196Smckusick 		so = slp->ns_so;
43352196Smckusick 		sotype = so->so_type;
434*57789Smckusick 		starttime = time;
43552196Smckusick 		if (so->so_proto->pr_flags & PR_CONNREQUIRED)
43652196Smckusick 			solockp = &slp->ns_solock;
43752196Smckusick 		else
43852196Smckusick 			solockp = (int *)0;
43952196Smckusick 		/*
44052196Smckusick 		 * nam == nam2 for connectionless protocols such as UDP
44152196Smckusick 		 * nam2 == NULL for connection based protocols to disable
44252196Smckusick 		 *    recent request caching.
44352196Smckusick 		 */
444*57789Smckusick 		if (nam2 = nd->nd_nam) {
44552196Smckusick 			nam = nam2;
446*57789Smckusick 			cacherep = RC_CHECKIT;
44752196Smckusick 		} else {
44852196Smckusick 			nam = slp->ns_nam;
44941903Smckusick 			cacherep = RC_DOIT;
45052196Smckusick 		}
45152196Smckusick 
45252196Smckusick 		/*
453*57789Smckusick 		 * Check to see if authorization is needed.
454*57789Smckusick 		 */
455*57789Smckusick 		if (nd->nd_flag & NFSD_NEEDAUTH) {
456*57789Smckusick 			static int logauth = 0;
457*57789Smckusick 
458*57789Smckusick 			nd->nd_flag &= ~NFSD_NEEDAUTH;
459*57789Smckusick 			/*
460*57789Smckusick 			 * Check for a mapping already installed.
461*57789Smckusick 			 */
462*57789Smckusick 			uidp = slp->ns_uidh[NUIDHASH(nd->nd_cr.cr_uid)];
463*57789Smckusick 			while (uidp) {
464*57789Smckusick 				if (uidp->nu_uid == nd->nd_cr.cr_uid)
465*57789Smckusick 					break;
466*57789Smckusick 				uidp = uidp->nu_hnext;
467*57789Smckusick 			}
468*57789Smckusick 			if (!uidp) {
469*57789Smckusick 			    nsd->nsd_uid = nd->nd_cr.cr_uid;
470*57789Smckusick 			    if (nam2 && logauth++ == 0)
471*57789Smckusick 				log(LOG_WARNING, "Kerberized NFS using UDP\n");
472*57789Smckusick 			    nsd->nsd_haddr =
473*57789Smckusick 			      mtod(nam, struct sockaddr_in *)->sin_addr.s_addr;
474*57789Smckusick 			    nsd->nsd_authlen = nd->nd_authlen;
475*57789Smckusick 			    if (copyout(nd->nd_authstr, nsd->nsd_authstr,
476*57789Smckusick 				nd->nd_authlen) == 0 &&
477*57789Smckusick 				copyout((caddr_t)nsd, argp, sizeof (*nsd)) == 0)
478*57789Smckusick 				return (ENEEDAUTH);
479*57789Smckusick 			    cacherep = RC_DROPIT;
480*57789Smckusick 			}
481*57789Smckusick 		}
482*57789Smckusick 		if (cacherep == RC_CHECKIT)
483*57789Smckusick 			cacherep = nfsrv_getcache(nam2, nd, &mreq);
484*57789Smckusick 
485*57789Smckusick 		/*
48652196Smckusick 		 * Check for just starting up for NQNFS and send
48752196Smckusick 		 * fake "try again later" replies to the NQNFS clients.
48852196Smckusick 		 */
48952196Smckusick 		if (notstarted && nqnfsstarttime <= time.tv_sec) {
49052196Smckusick 			if (modify_flag) {
49152196Smckusick 				nqnfsstarttime = time.tv_sec + nqsrv_writeslack;
49252196Smckusick 				modify_flag = 0;
49352196Smckusick 			} else
49452196Smckusick 				notstarted = 0;
49552196Smckusick 		}
49652196Smckusick 		if (notstarted) {
49752196Smckusick 			if (nd->nd_nqlflag == NQL_NOVAL)
49852196Smckusick 				cacherep = RC_DROPIT;
49952196Smckusick 			else if (nd->nd_procnum != NFSPROC_WRITE) {
50052196Smckusick 				nd->nd_procnum = NFSPROC_NOOP;
50152196Smckusick 				nd->nd_repstat = NQNFS_TRYLATER;
50252196Smckusick 				cacherep = RC_DOIT;
50352196Smckusick 			} else
50452196Smckusick 				modify_flag = 1;
50552196Smckusick 		} else if (nd->nd_flag & NFSD_AUTHFAIL) {
50652196Smckusick 			nd->nd_flag &= ~NFSD_AUTHFAIL;
50752196Smckusick 			nd->nd_procnum = NFSPROC_NOOP;
50852196Smckusick 			nd->nd_repstat = NQNFS_AUTHERR;
50952196Smckusick 			cacherep = RC_DOIT;
51052196Smckusick 		}
51152196Smckusick 
51241903Smckusick 		switch (cacherep) {
51339756Smckusick 		case RC_DOIT:
51452196Smckusick 			error = (*(nfsrv_procs[nd->nd_procnum]))(nd,
51552196Smckusick 				nd->nd_mrep, nd->nd_md, nd->nd_dpos, &nd->nd_cr,
51652196Smckusick 				nam, &mreq);
51752903Smckusick 			if (nd->nd_cr.cr_ref != 1) {
51852903Smckusick 				printf("nfssvc cref=%d\n", nd->nd_cr.cr_ref);
51952903Smckusick 				panic("nfssvc cref");
52052903Smckusick 			}
52152196Smckusick 			if (error) {
52252196Smckusick 				if (nd->nd_procnum != NQNFSPROC_VACATED)
52352196Smckusick 					nfsstats.srv_errs++;
52452196Smckusick 				if (nam2) {
52552196Smckusick 					nfsrv_updatecache(nam2, nd, FALSE, mreq);
52652196Smckusick 					m_freem(nam2);
52741903Smckusick 				}
52839756Smckusick 				break;
52939756Smckusick 			}
53052196Smckusick 			nfsstats.srvrpccnt[nd->nd_procnum]++;
53152196Smckusick 			if (nam2)
53252196Smckusick 				nfsrv_updatecache(nam2, nd, TRUE, mreq);
53352196Smckusick 			nd->nd_mrep = (struct mbuf *)0;
53439756Smckusick 		case RC_REPLY:
53539756Smckusick 			m = mreq;
53639756Smckusick 			siz = 0;
53739756Smckusick 			while (m) {
53839756Smckusick 				siz += m->m_len;
53939756Smckusick 				m = m->m_next;
54039756Smckusick 			}
54141903Smckusick 			if (siz <= 0 || siz > NFS_MAXPACKET) {
54239756Smckusick 				printf("mbuf siz=%d\n",siz);
54339756Smckusick 				panic("Bad nfs svc reply");
54439756Smckusick 			}
54552196Smckusick 			m = mreq;
54652196Smckusick 			m->m_pkthdr.len = siz;
54752196Smckusick 			m->m_pkthdr.rcvif = (struct ifnet *)0;
54841903Smckusick 			/*
54952196Smckusick 			 * For stream protocols, prepend a Sun RPC
55041903Smckusick 			 * Record Mark.
55141903Smckusick 			 */
55252196Smckusick 			if (sotype == SOCK_STREAM) {
55352196Smckusick 				M_PREPEND(m, NFSX_UNSIGNED, M_WAIT);
55452196Smckusick 				*mtod(m, u_long *) = htonl(0x80000000 | siz);
55541903Smckusick 			}
55652196Smckusick 			if (solockp)
55752196Smckusick 				(void) nfs_sndlock(solockp, (struct nfsreq *)0);
55852903Smckusick 			if (slp->ns_flag & SLP_VALID)
55952196Smckusick 			    error = nfs_send(so, nam2, m, (struct nfsreq *)0);
56052196Smckusick 			else {
56152196Smckusick 			    error = EPIPE;
56252196Smckusick 			    m_freem(m);
56341903Smckusick 			}
564*57789Smckusick 			if (nfsrtton)
565*57789Smckusick 				nfsd_rt(&starttime, sotype, nd, nam, cacherep);
56652196Smckusick 			if (nam2)
56752196Smckusick 				MFREE(nam2, m);
56852196Smckusick 			if (nd->nd_mrep)
56952196Smckusick 				m_freem(nd->nd_mrep);
57052196Smckusick 			if (error == EPIPE)
57152903Smckusick 				nfsrv_zapsock(slp);
57252196Smckusick 			if (solockp)
57352196Smckusick 				nfs_sndunlock(solockp);
57452903Smckusick 			if (error == EINTR || error == ERESTART) {
57552903Smckusick 				nfsrv_slpderef(slp);
57652903Smckusick 				s = splnet();
57752196Smckusick 				goto done;
57852903Smckusick 			}
57939756Smckusick 			break;
58039756Smckusick 		case RC_DROPIT:
581*57789Smckusick 			if (nfsrtton)
582*57789Smckusick 				nfsd_rt(&starttime, sotype, nd, nam, cacherep);
58352196Smckusick 			m_freem(nd->nd_mrep);
58452196Smckusick 			m_freem(nam2);
58539756Smckusick 			break;
58639756Smckusick 		};
58752903Smckusick 		s = splnet();
58852903Smckusick 		if (nfsrv_dorec(slp, nd)) {
58952903Smckusick 			nd->nd_flag &= ~NFSD_REQINPROG;
59052903Smckusick 			nd->nd_slp = (struct nfssvc_sock *)0;
59152903Smckusick 			nfsrv_slpderef(slp);
59252903Smckusick 		}
59338414Smckusick 	}
59452196Smckusick done:
59552196Smckusick 	remque(nd);
59652196Smckusick 	splx(s);
59752196Smckusick 	free((caddr_t)nd, M_NFSD);
59852196Smckusick 	nsd->nsd_nfsd = (struct nfsd *)0;
59952981Smckusick 	if (--nfs_numnfsd == 0)
60052981Smckusick 		nfsrv_init(TRUE);	/* Reinitialize everything */
60144411Skarels 	return (error);
60238414Smckusick }
60338884Smacklem 
60438884Smacklem /*
60552196Smckusick  * Asynchronous I/O daemons for client nfs.
606*57789Smckusick  * They do read-ahead and write-behind operations on the block I/O cache.
60752196Smckusick  * Never returns unless it fails or gets killed.
60838884Smacklem  */
60952196Smckusick nfssvc_iod(p)
61043354Smckusick 	struct proc *p;
61138884Smacklem {
61238884Smacklem 	register struct buf *bp, *dp;
61346988Smckusick 	register int i, myiod;
61452196Smckusick 	int error = 0;
61538884Smacklem 
61638884Smacklem 	/*
61739346Smckusick 	 * Assign my position or return error if too many already running
61839346Smckusick 	 */
61946988Smckusick 	myiod = -1;
62046988Smckusick 	for (i = 0; i < NFS_MAXASYNCDAEMON; i++)
62146988Smckusick 		if (nfs_asyncdaemon[i] == 0) {
62246988Smckusick 			nfs_asyncdaemon[i]++;
62346988Smckusick 			myiod = i;
62446988Smckusick 			break;
62546988Smckusick 		}
62646988Smckusick 	if (myiod == -1)
62744411Skarels 		return (EBUSY);
62846988Smckusick 	nfs_numasync++;
62938884Smacklem 	/*
63039346Smckusick 	 * Just loop around doin our stuff until SIGKILL
63138884Smacklem 	 */
63238884Smacklem 	for (;;) {
63356469Smckusick 		while (nfs_bufq.qe_next == NULL && error == 0) {
63448053Smckusick 			nfs_iodwant[myiod] = p;
63546988Smckusick 			error = tsleep((caddr_t)&nfs_iodwant[myiod],
63646988Smckusick 				PWAIT | PCATCH, "nfsidl", 0);
63738884Smacklem 		}
63856469Smckusick 		while ((bp = nfs_bufq.qe_next) != NULL) {
63956396Smckusick 			/* Take one off the front of the list */
64056469Smckusick 			queue_remove(&nfs_bufq, bp, struct buf *, b_freelist);
641*57789Smckusick 			if (bp->b_flags & B_READ)
642*57789Smckusick 			    (void) nfs_doio(bp, bp->b_rcred, (struct proc *)0);
643*57789Smckusick 			else
644*57789Smckusick 			    (void) nfs_doio(bp, bp->b_wcred, (struct proc *)0);
64538884Smacklem 		}
64646988Smckusick 		if (error) {
64746988Smckusick 			nfs_asyncdaemon[myiod] = 0;
64846988Smckusick 			nfs_numasync--;
64946988Smckusick 			return (error);
65046988Smckusick 		}
65138884Smacklem 	}
65238884Smacklem }
65352196Smckusick 
65452196Smckusick /*
65552196Smckusick  * Shut down a socket associated with an nfssvc_sock structure.
65652196Smckusick  * Should be called with the send lock set, if required.
65752196Smckusick  * The trick here is to increment the sref at the start, so that the nfsds
65852196Smckusick  * will stop using it and clear ns_flag at the end so that it will not be
65952196Smckusick  * reassigned during cleanup.
66052196Smckusick  */
66152903Smckusick nfsrv_zapsock(slp)
66252196Smckusick 	register struct nfssvc_sock *slp;
66352196Smckusick {
66452196Smckusick 	register struct nfsuid *nuidp, *onuidp;
66552196Smckusick 	register int i;
66652196Smckusick 	struct socket *so;
66752196Smckusick 	struct file *fp;
66852196Smckusick 	struct mbuf *m;
66952196Smckusick 
67052981Smckusick 	slp->ns_flag &= ~SLP_ALLFLAGS;
67152196Smckusick 	if (fp = slp->ns_fp) {
67252196Smckusick 		slp->ns_fp = (struct file *)0;
67352196Smckusick 		so = slp->ns_so;
67452903Smckusick 		so->so_upcall = NULL;
67552196Smckusick 		soshutdown(so, 2);
67652903Smckusick 		closef(fp, (struct proc *)0);
67752196Smckusick 		if (slp->ns_nam)
67852196Smckusick 			MFREE(slp->ns_nam, m);
67952196Smckusick 		m_freem(slp->ns_raw);
68052196Smckusick 		m_freem(slp->ns_rec);
68152196Smckusick 		nuidp = slp->ns_lrunext;
68252196Smckusick 		while (nuidp != (struct nfsuid *)slp) {
68352196Smckusick 			onuidp = nuidp;
68452196Smckusick 			nuidp = nuidp->nu_lrunext;
68552196Smckusick 			free((caddr_t)onuidp, M_NFSUID);
68652196Smckusick 		}
68752196Smckusick 		slp->ns_lrunext = slp->ns_lruprev = (struct nfsuid *)slp;
68852196Smckusick 		for (i = 0; i < NUIDHASHSIZ; i++)
68952196Smckusick 			slp->ns_uidh[i] = (struct nfsuid *)0;
69052196Smckusick 	}
69152196Smckusick }
69252196Smckusick 
69352196Smckusick /*
69452196Smckusick  * Get an authorization string for the uid by having the mount_nfs sitting
69552196Smckusick  * on this mount point porpous out of the kernel and do it.
69652196Smckusick  */
69752196Smckusick nfs_getauth(nmp, rep, cred, auth_type, auth_str, auth_len)
69852196Smckusick 	register struct nfsmount *nmp;
69952196Smckusick 	struct nfsreq *rep;
70052196Smckusick 	struct ucred *cred;
70152196Smckusick 	int *auth_type;
70252196Smckusick 	char **auth_str;
70352196Smckusick 	int *auth_len;
70452196Smckusick {
70552196Smckusick 	int error = 0;
70652196Smckusick 
70752196Smckusick 	while ((nmp->nm_flag & NFSMNT_WAITAUTH) == 0) {
70852196Smckusick 		nmp->nm_flag |= NFSMNT_WANTAUTH;
70952196Smckusick 		(void) tsleep((caddr_t)&nmp->nm_authtype, PSOCK,
71052196Smckusick 			"nfsauth1", 2 * hz);
71152196Smckusick 		if (error = nfs_sigintr(nmp, rep, rep->r_procp)) {
71252196Smckusick 			nmp->nm_flag &= ~NFSMNT_WANTAUTH;
71352196Smckusick 			return (error);
71452196Smckusick 		}
71552196Smckusick 	}
71652196Smckusick 	nmp->nm_flag &= ~(NFSMNT_WAITAUTH | NFSMNT_WANTAUTH);
71752196Smckusick 	nmp->nm_authstr = *auth_str = (char *)malloc(RPCAUTH_MAXSIZ, M_TEMP, M_WAITOK);
71852196Smckusick 	nmp->nm_authuid = cred->cr_uid;
71952196Smckusick 	wakeup((caddr_t)&nmp->nm_authstr);
72052196Smckusick 
72152196Smckusick 	/*
72252196Smckusick 	 * And wait for mount_nfs to do its stuff.
72352196Smckusick 	 */
72452196Smckusick 	while ((nmp->nm_flag & NFSMNT_HASAUTH) == 0 && error == 0) {
72552196Smckusick 		(void) tsleep((caddr_t)&nmp->nm_authlen, PSOCK,
72652196Smckusick 			"nfsauth2", 2 * hz);
72752196Smckusick 		error = nfs_sigintr(nmp, rep, rep->r_procp);
72852196Smckusick 	}
72952196Smckusick 	if (nmp->nm_flag & NFSMNT_AUTHERR) {
73052196Smckusick 		nmp->nm_flag &= ~NFSMNT_AUTHERR;
73152196Smckusick 		error = EAUTH;
73252196Smckusick 	}
73352196Smckusick 	if (error)
73452196Smckusick 		free((caddr_t)*auth_str, M_TEMP);
73552196Smckusick 	else {
73652196Smckusick 		*auth_type = nmp->nm_authtype;
73752196Smckusick 		*auth_len = nmp->nm_authlen;
73852196Smckusick 	}
73952196Smckusick 	nmp->nm_flag &= ~NFSMNT_HASAUTH;
74052196Smckusick 	nmp->nm_flag |= NFSMNT_WAITAUTH;
74152196Smckusick 	if (nmp->nm_flag & NFSMNT_WANTAUTH) {
74252196Smckusick 		nmp->nm_flag &= ~NFSMNT_WANTAUTH;
74352196Smckusick 		wakeup((caddr_t)&nmp->nm_authtype);
74452196Smckusick 	}
74552196Smckusick 	return (error);
74652196Smckusick }
74752903Smckusick 
74852903Smckusick /*
74952903Smckusick  * Derefence a server socket structure. If it has no more references and
75052903Smckusick  * is no longer valid, you can throw it away.
75152903Smckusick  */
75252903Smckusick void
75352903Smckusick nfsrv_slpderef(slp)
75452903Smckusick 	register struct nfssvc_sock *slp;
75552903Smckusick {
75652903Smckusick 	if (--(slp->ns_sref) == 0 && (slp->ns_flag & SLP_VALID) == 0) {
75752903Smckusick 		slp->ns_prev->ns_next = slp->ns_next;
75852903Smckusick 		slp->ns_next->ns_prev = slp->ns_prev;
75952903Smckusick 		free((caddr_t)slp, M_NFSSVC);
76052903Smckusick 	}
76152903Smckusick }
76252981Smckusick 
76352981Smckusick /*
76452981Smckusick  * Initialize the data structures for the server.
76552981Smckusick  * Handshake with any new nfsds starting up to avoid any chance of
76652981Smckusick  * corruption.
76752981Smckusick  */
76852981Smckusick void
76952981Smckusick nfsrv_init(terminating)
77052981Smckusick 	int terminating;
77152981Smckusick {
77252981Smckusick 	register struct nfssvc_sock *slp;
77352981Smckusick 	struct nfssvc_sock *oslp;
77452981Smckusick 
77552981Smckusick 	if (nfssvc_sockhead.ns_flag & SLP_INIT)
77652981Smckusick 		panic("nfsd init");
77752981Smckusick 	nfssvc_sockhead.ns_flag |= SLP_INIT;
77852981Smckusick 	if (terminating) {
77952981Smckusick 		slp = nfssvc_sockhead.ns_next;
78052981Smckusick 		while (slp != &nfssvc_sockhead) {
78152981Smckusick 			if (slp->ns_flag & SLP_VALID)
78252981Smckusick 				nfsrv_zapsock(slp);
78352981Smckusick 			slp->ns_next->ns_prev = slp->ns_prev;
78452981Smckusick 			slp->ns_prev->ns_next = slp->ns_next;
78552981Smckusick 			oslp = slp;
78652981Smckusick 			slp = slp->ns_next;
78752981Smckusick 			free((caddr_t)oslp, M_NFSSVC);
78852981Smckusick 		}
78952981Smckusick 		nfsrv_cleancache();	/* And clear out server cache */
79052981Smckusick 	}
79152981Smckusick 	nfs_udpsock = (struct nfssvc_sock *)
79252981Smckusick 	    malloc(sizeof (struct nfssvc_sock), M_NFSSVC, M_WAITOK);
79352981Smckusick 	bzero((caddr_t)nfs_udpsock, sizeof (struct nfssvc_sock));
79452981Smckusick 	nfs_cltpsock = (struct nfssvc_sock *)
79552981Smckusick 	    malloc(sizeof (struct nfssvc_sock), M_NFSSVC, M_WAITOK);
79652981Smckusick 	bzero((caddr_t)nfs_cltpsock, sizeof (struct nfssvc_sock));
79752981Smckusick 	nfssvc_sockhead.ns_next = nfs_udpsock;
79852981Smckusick 	nfs_udpsock->ns_next = nfs_cltpsock;
79952981Smckusick 	nfs_cltpsock->ns_next = &nfssvc_sockhead;
80052981Smckusick 	nfssvc_sockhead.ns_prev = nfs_cltpsock;
80152981Smckusick 	nfs_cltpsock->ns_prev = nfs_udpsock;
80252981Smckusick 	nfs_udpsock->ns_prev = &nfssvc_sockhead;
80352981Smckusick 	nfs_udpsock->ns_lrunext = nfs_udpsock->ns_lruprev =
80452981Smckusick 		(struct nfsuid *)nfs_udpsock;
80552981Smckusick 	nfs_cltpsock->ns_lrunext = nfs_cltpsock->ns_lruprev =
80652981Smckusick 		(struct nfsuid *)nfs_cltpsock;
80752981Smckusick 	nfsd_head.nd_next = nfsd_head.nd_prev = &nfsd_head;
80852981Smckusick 	nfsd_head.nd_flag = 0;
80952981Smckusick 	nfssvc_sockhead.ns_flag &= ~SLP_INIT;
81052981Smckusick 	if (nfssvc_sockhead.ns_flag & SLP_WANTINIT) {
81152981Smckusick 		nfssvc_sockhead.ns_flag &= ~SLP_WANTINIT;
81252981Smckusick 		wakeup((caddr_t)&nfssvc_sockhead);
81352981Smckusick 	}
81452981Smckusick }
815*57789Smckusick 
816*57789Smckusick /*
817*57789Smckusick  * Add entries to the server monitor log.
818*57789Smckusick  */
819*57789Smckusick static void
820*57789Smckusick nfsd_rt(startp, sotype, nd, nam, cacherep)
821*57789Smckusick 	struct timeval *startp;
822*57789Smckusick 	int sotype;
823*57789Smckusick 	register struct nfsd *nd;
824*57789Smckusick 	struct mbuf *nam;
825*57789Smckusick 	int cacherep;
826*57789Smckusick {
827*57789Smckusick 	register struct drt *rt;
828*57789Smckusick 
829*57789Smckusick 	rt = &nfsdrt.drt[nfsdrt.pos];
830*57789Smckusick 	if (cacherep == RC_DOIT)
831*57789Smckusick 		rt->flag = 0;
832*57789Smckusick 	else if (cacherep == RC_REPLY)
833*57789Smckusick 		rt->flag = DRT_CACHEREPLY;
834*57789Smckusick 	else
835*57789Smckusick 		rt->flag = DRT_CACHEDROP;
836*57789Smckusick 	if (sotype == SOCK_STREAM)
837*57789Smckusick 		rt->flag |= DRT_TCP;
838*57789Smckusick 	if (nd->nd_nqlflag != NQL_NOVAL)
839*57789Smckusick 		rt->flag |= DRT_NQNFS;
840*57789Smckusick 	rt->proc = nd->nd_procnum;
841*57789Smckusick 	if (mtod(nam, struct sockaddr *)->sa_family == AF_INET)
842*57789Smckusick 		rt->ipadr = mtod(nam, struct sockaddr_in *)->sin_addr.s_addr;
843*57789Smckusick 	else
844*57789Smckusick 		rt->ipadr = INADDR_ANY;
845*57789Smckusick 	rt->resptime = ((time.tv_sec - startp->tv_sec) * 1000000) +
846*57789Smckusick 		(time.tv_usec - startp->tv_usec);
847*57789Smckusick 	rt->tstamp = time;
848*57789Smckusick 	nfsdrt.pos = (nfsdrt.pos + 1) % NFSRTTLOGSIZ;
849*57789Smckusick }
850