nfs_nfsiod.c revision 60041
160484Sobrien/*
233965Sjdp * Copyright (c) 1989, 1993
360484Sobrien *	The Regents of the University of California.  All rights reserved.
438889Sjdp *
538889Sjdp * This code is derived from software contributed to Berkeley by
638889Sjdp * Rick Macklem at The University of Guelph.
733965Sjdp *
833965Sjdp * Redistribution and use in source and binary forms, with or without
938889Sjdp * modification, are permitted provided that the following conditions
1038889Sjdp * are met:
1138889Sjdp * 1. Redistributions of source code must retain the above copyright
1233965Sjdp *    notice, this list of conditions and the following disclaimer.
1338889Sjdp * 2. Redistributions in binary form must reproduce the above copyright
1438889Sjdp *    notice, this list of conditions and the following disclaimer in the
1538889Sjdp *    documentation and/or other materials provided with the distribution.
1638889Sjdp * 3. All advertising materials mentioning features or use of this software
1738889Sjdp *    must display the following acknowledgement:
1833965Sjdp *	This product includes software developed by the University of
1933965Sjdp *	California, Berkeley and its contributors.
2038889Sjdp * 4. Neither the name of the University nor the names of its contributors
2133965Sjdp *    may be used to endorse or promote products derived from this software
2233965Sjdp *    without specific prior written permission.
2338889Sjdp *
2438889Sjdp * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2538889Sjdp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2638889Sjdp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2738889Sjdp * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2838889Sjdp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2933965Sjdp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3038889Sjdp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3133965Sjdp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3233965Sjdp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3338889Sjdp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3433965Sjdp * SUCH DAMAGE.
3560484Sobrien *
3660484Sobrien *	@(#)nfs_syscalls.c	8.5 (Berkeley) 3/30/95
3738889Sjdp * $FreeBSD: head/sys/nfsclient/nfs_nfsiod.c 60041 2000-05-05 09:59:14Z phk $
3838889Sjdp */
3938889Sjdp
4033965Sjdp#include <sys/param.h>
4138889Sjdp#include <sys/systm.h>
4238889Sjdp#include <sys/sysproto.h>
4338889Sjdp#include <sys/kernel.h>
4438889Sjdp#include <sys/sysctl.h>
4538889Sjdp#include <sys/file.h>
4638889Sjdp#include <sys/filedesc.h>
4738889Sjdp#include <sys/vnode.h>
4838889Sjdp#include <sys/malloc.h>
4960484Sobrien#include <sys/mount.h>
5033965Sjdp#include <sys/proc.h>
5138889Sjdp#include <sys/bio.h>
5238889Sjdp#include <sys/buf.h>
5333965Sjdp#include <sys/mbuf.h>
5438889Sjdp#include <sys/socket.h>
5538889Sjdp#include <sys/socketvar.h>
5638889Sjdp#include <sys/domain.h>
5738889Sjdp#include <sys/protosw.h>
5838889Sjdp#include <sys/namei.h>
5938889Sjdp
6038889Sjdp#include <netinet/in.h>
6138889Sjdp#include <netinet/tcp.h>
6238889Sjdp#include <nfs/xdr_subs.h>
6338889Sjdp#include <nfs/rpcv2.h>
6438889Sjdp#include <nfs/nfsproto.h>
6538889Sjdp#include <nfs/nfs.h>
6638889Sjdp#include <nfs/nfsm_subs.h>
6760484Sobrien#include <nfs/nfsrvcache.h>
6838889Sjdp#include <nfs/nfsmount.h>
6960484Sobrien#include <nfs/nfsnode.h>
7060484Sobrien#include <nfs/nqnfs.h>
7138889Sjdp#include <nfs/nfsrtt.h>
7238889Sjdp
7338889Sjdpstatic MALLOC_DEFINE(M_NFSSVC, "NFS srvsock", "Nfs server structure");
7460484Sobrien
7560484Sobrien/* Global defs. */
7633965Sjdpextern int32_t (*nfsrv3_procs[NFS_NPROCS]) __P((struct nfsrv_descript *nd,
7760484Sobrien					    struct nfssvc_sock *slp,
7860484Sobrien					    struct proc *procp,
7960484Sobrien					    struct mbuf **mreqp));
8038889Sjdpextern int nfs_numasync;
8138889Sjdpextern time_t nqnfsstarttime;
8260484Sobrienextern int nqsrv_writeslack;
8360484Sobrienextern int nfsrtton;
8460484Sobrienextern struct nfsstats nfsstats;
8560484Sobrienextern int nfsrvw_procrastinate;
8638889Sjdpextern int nfsrvw_procrastinate_v3;
8760484Sobrienstatic int nuidhash_max = NFS_MAXUIDHASH;
8860484Sobrien
8960484Sobrien#ifndef NFS_NOSERVER
9060484Sobrienstatic void	nfsrv_zapsock __P((struct nfssvc_sock *slp));
9138889Sjdp#endif
9238889Sjdpstatic int	nfssvc_iod __P((struct proc *));
9338889Sjdp
9438889Sjdp#define	TRUE	1
9560484Sobrien#define	FALSE	0
9660484Sobrien
9738889Sjdpstatic int nfs_asyncdaemon[NFS_MAXASYNCDAEMON];
9860484Sobrien
9938889SjdpSYSCTL_DECL(_vfs_nfs);
10060484Sobrien
10160484Sobrien#ifndef NFS_NOSERVER
10238889Sjdpint nfsd_waiting = 0;
10338889Sjdpstatic struct nfsdrt nfsdrt;
10460484Sobrienstatic int nfs_numnfsd = 0;
10560484Sobrienstatic int notstarted = 1;
10638889Sjdpstatic int modify_flag = 0;
10760484Sobrienstatic void	nfsd_rt __P((int sotype, struct nfsrv_descript *nd,
10838889Sjdp			     int cacherep));
10960484Sobrienstatic int	nfssvc_addsock __P((struct file *, struct sockaddr *,
11060484Sobrien				    struct proc *));
11138889Sjdpstatic int	nfssvc_nfsd __P((struct nfsd_srvargs *,caddr_t,struct proc *));
11238889Sjdp
11360484Sobrienstatic int nfs_privport = 0;
11460484SobrienSYSCTL_INT(_vfs_nfs, NFS_NFSPRIVPORT, nfs_privport, CTLFLAG_RW, &nfs_privport, 0, "");
11538889SjdpSYSCTL_INT(_vfs_nfs, OID_AUTO, gatherdelay, CTLFLAG_RW, &nfsrvw_procrastinate, 0, "");
11638889SjdpSYSCTL_INT(_vfs_nfs, OID_AUTO, gatherdelay_v3, CTLFLAG_RW, &nfsrvw_procrastinate_v3, 0, "");
11733965Sjdp
11838889Sjdp/*
11933965Sjdp * NFS server system calls
12060484Sobrien */
12138889Sjdp
12260484Sobrien#endif /* NFS_NOSERVER */
12333965Sjdp/*
12433965Sjdp * Nfs server psuedo system call for the nfsd's
12560484Sobrien * Based on the flag value it either:
12660484Sobrien * - adds a socket to the selection list
12733965Sjdp * - remains in the kernel as an nfsd
12833965Sjdp * - remains in the kernel as an nfsiod
12960484Sobrien */
13060484Sobrien#ifndef _SYS_SYSPROTO_H_
13133965Sjdpstruct nfssvc_args {
13260484Sobrien	int flag;
13333965Sjdp	caddr_t argp;
13460484Sobrien};
13560484Sobrien#endif
13633965Sjdpint
13760484Sobriennfssvc(p, uap)
13860484Sobrien	struct proc *p;
13960484Sobrien	register struct nfssvc_args *uap;
14033965Sjdp{
14133965Sjdp#ifndef NFS_NOSERVER
14233965Sjdp	struct nameidata nd;
14360484Sobrien	struct file *fp;
14433965Sjdp	struct sockaddr *nam;
14560484Sobrien	struct nfsd_args nfsdarg;
14633965Sjdp	struct nfsd_srvargs nfsd_srvargs, *nsd = &nfsd_srvargs;
14760484Sobrien	struct nfsd_cargs ncd;
14860484Sobrien	struct nfsd *nfsd;
14960484Sobrien	struct nfssvc_sock *slp;
15060484Sobrien	struct nfsuid *nuidp;
15133965Sjdp	struct nfsmount *nmp;
15260484Sobrien#endif /* NFS_NOSERVER */
15333965Sjdp	int error;
15438889Sjdp
15560484Sobrien	/*
15633965Sjdp	 * Must be super user
15733965Sjdp	 */
15860484Sobrien	error = suser(p);
15938889Sjdp	if(error)
16060484Sobrien		return (error);
16138889Sjdp	while (nfssvc_sockhead_flag & SLP_INIT) {
16260484Sobrien		 nfssvc_sockhead_flag |= SLP_WANTINIT;
16338889Sjdp		(void) tsleep((caddr_t)&nfssvc_sockhead, PSOCK, "nfsd init", 0);
16460484Sobrien	}
16560484Sobrien	if (uap->flag & NFSSVC_BIOD)
16633965Sjdp		error = nfssvc_iod(p);
16738889Sjdp#ifdef NFS_NOSERVER
16833965Sjdp	else
16933965Sjdp		error = ENXIO;
17033965Sjdp#else /* !NFS_NOSERVER */
17160484Sobrien	else if (uap->flag & NFSSVC_MNTD) {
17238889Sjdp		error = copyin(uap->argp, (caddr_t)&ncd, sizeof (ncd));
17360484Sobrien		if (error)
17433965Sjdp			return (error);
17560484Sobrien		NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
17633965Sjdp			ncd.ncd_dirp, p);
17738889Sjdp		error = namei(&nd);
17860484Sobrien		if (error)
17933965Sjdp			return (error);
18033965Sjdp		NDFREE(&nd, NDF_ONLY_PNBUF);
18160484Sobrien		if ((nd.ni_vp->v_flag & VROOT) == 0)
18260484Sobrien			error = EINVAL;
18333965Sjdp		nmp = VFSTONFS(nd.ni_vp->v_mount);
18433965Sjdp		vput(nd.ni_vp);
18533965Sjdp		if (error)
18633965Sjdp			return (error);
18738889Sjdp		if ((nmp->nm_state & NFSSTA_MNTD) &&
18860484Sobrien			(uap->flag & NFSSVC_GOTAUTH) == 0)
18960484Sobrien			return (0);
19033965Sjdp		nmp->nm_state |= NFSSTA_MNTD;
19160484Sobrien		error = nqnfs_clientd(nmp, p->p_ucred, &ncd, uap->flag,
19233965Sjdp			uap->argp, p);
19333965Sjdp	} else if (uap->flag & NFSSVC_ADDSOCK) {
19438889Sjdp		error = copyin(uap->argp, (caddr_t)&nfsdarg, sizeof(nfsdarg));
19533965Sjdp		if (error)
19660484Sobrien			return (error);
19738889Sjdp		error = getsock(p->p_fd, nfsdarg.sock, &fp);
19838889Sjdp		if (error)
19933965Sjdp			return (error);
20033965Sjdp		/*
20138889Sjdp		 * Get the client address for connected sockets.
20233965Sjdp		 */
20338889Sjdp		if (nfsdarg.name == NULL || nfsdarg.namelen == 0)
20433965Sjdp			nam = (struct sockaddr *)0;
20538889Sjdp		else {
20633965Sjdp			error = getsockaddr(&nam, nfsdarg.name,
20738889Sjdp					    nfsdarg.namelen);
20833965Sjdp			if (error)
20960484Sobrien				return (error);
21060484Sobrien		}
21133965Sjdp		error = nfssvc_addsock(fp, nam, p);
21233965Sjdp	} else {
21333965Sjdp		error = copyin(uap->argp, (caddr_t)nsd, sizeof (*nsd));
21460484Sobrien		if (error)
21533965Sjdp			return (error);
21633965Sjdp		if ((uap->flag & NFSSVC_AUTHIN) &&
21733965Sjdp		    ((nfsd = nsd->nsd_nfsd)) != NULL &&
21833965Sjdp		    (nfsd->nfsd_slp->ns_flag & SLP_VALID)) {
21960484Sobrien			slp = nfsd->nfsd_slp;
22033965Sjdp
22133965Sjdp			/*
22233965Sjdp			 * First check to see if another nfsd has already
22333965Sjdp			 * added this credential.
22433965Sjdp			 */
22533965Sjdp			for (nuidp = NUIDHASH(slp,nsd->nsd_cr.cr_uid)->lh_first;
22633965Sjdp			    nuidp != 0; nuidp = nuidp->nu_hash.le_next) {
22733965Sjdp				if (nuidp->nu_cr.cr_uid == nsd->nsd_cr.cr_uid &&
22833965Sjdp				    (!nfsd->nfsd_nd->nd_nam2 ||
22933965Sjdp				     netaddr_match(NU_NETFAM(nuidp),
23033965Sjdp				     &nuidp->nu_haddr, nfsd->nfsd_nd->nd_nam2)))
23138889Sjdp					break;
23233965Sjdp			}
23333965Sjdp			if (nuidp) {
23433965Sjdp			    nfsrv_setcred(&nuidp->nu_cr,&nfsd->nfsd_nd->nd_cr);
23560484Sobrien			    nfsd->nfsd_nd->nd_flag |= ND_KERBFULL;
23638889Sjdp			} else {
23733965Sjdp			    /*
23860484Sobrien			     * Nope, so we will.
23933965Sjdp			     */
24038889Sjdp			    if (slp->ns_numuids < nuidhash_max) {
24133965Sjdp				slp->ns_numuids++;
24260484Sobrien				nuidp = (struct nfsuid *)
24333965Sjdp				   malloc(sizeof (struct nfsuid), M_NFSUID,
24438889Sjdp					M_WAITOK);
24533965Sjdp			    } else
24660484Sobrien				nuidp = (struct nfsuid *)0;
24760484Sobrien			    if ((slp->ns_flag & SLP_VALID) == 0) {
24833965Sjdp				if (nuidp)
24960484Sobrien				    free((caddr_t)nuidp, M_NFSUID);
25060484Sobrien			    } else {
25138889Sjdp				if (nuidp == (struct nfsuid *)0) {
25233965Sjdp				    nuidp = slp->ns_uidlruhead.tqh_first;
25338889Sjdp				    LIST_REMOVE(nuidp, nu_hash);
25460484Sobrien				    TAILQ_REMOVE(&slp->ns_uidlruhead, nuidp,
25533965Sjdp					nu_lru);
25660484Sobrien				    if (nuidp->nu_flag & NU_NAM)
25760484Sobrien					FREE(nuidp->nu_nam, M_SONAME);
25833965Sjdp			        }
25960484Sobrien				nuidp->nu_flag = 0;
26060484Sobrien				nuidp->nu_cr = nsd->nsd_cr;
26133965Sjdp				if (nuidp->nu_cr.cr_ngroups > NGROUPS)
26260484Sobrien				    nuidp->nu_cr.cr_ngroups = NGROUPS;
26360484Sobrien				nuidp->nu_cr.cr_ref = 1;
26433965Sjdp				nuidp->nu_timestamp = nsd->nsd_timestamp;
26538889Sjdp				nuidp->nu_expire = time_second + nsd->nsd_ttl;
26633965Sjdp				/*
26738889Sjdp				 * and save the session key in nu_key.
26833965Sjdp				 */
26960484Sobrien				bcopy(nsd->nsd_key, nuidp->nu_key,
27060484Sobrien				    sizeof (nsd->nsd_key));
27133965Sjdp				if (nfsd->nfsd_nd->nd_nam2) {
27238889Sjdp				    struct sockaddr_in *saddr;
27333965Sjdp
27438889Sjdp				    saddr = (struct sockaddr_in *)
27533965Sjdp					    nfsd->nfsd_nd->nd_nam2;
27638889Sjdp				    switch (saddr->sin_family) {
27733965Sjdp				    case AF_INET:
27838889Sjdp					nuidp->nu_flag |= NU_INETADDR;
27960484Sobrien					nuidp->nu_inetaddr =
28033965Sjdp					     saddr->sin_addr.s_addr;
28160484Sobrien					break;
28260484Sobrien				    case AF_ISO:
28360484Sobrien				    default:
28460484Sobrien					nuidp->nu_flag |= NU_NAM;
28560484Sobrien					nuidp->nu_nam =
28638889Sjdp						dup_sockaddr(nfsd->nfsd_nd->
28738889Sjdp							     nd_nam2, 1);
28833965Sjdp					break;
28960484Sobrien				    };
29038889Sjdp				}
29138889Sjdp				TAILQ_INSERT_TAIL(&slp->ns_uidlruhead, nuidp,
29233965Sjdp					nu_lru);
29360484Sobrien				LIST_INSERT_HEAD(NUIDHASH(slp, nsd->nsd_uid),
29460484Sobrien					nuidp, nu_hash);
29560484Sobrien				nfsrv_setcred(&nuidp->nu_cr,
29660484Sobrien				    &nfsd->nfsd_nd->nd_cr);
29738889Sjdp				nfsd->nfsd_nd->nd_flag |= ND_KERBFULL;
29833965Sjdp			    }
29960484Sobrien			}
30060484Sobrien		}
30138889Sjdp		if ((uap->flag & NFSSVC_AUTHINFAIL) && (nfsd = nsd->nsd_nfsd))
30238889Sjdp			nfsd->nfsd_flag |= NFSD_AUTHFAIL;
30338889Sjdp		error = nfssvc_nfsd(nsd, uap->argp, p);
30438889Sjdp	}
30538889Sjdp#endif /* NFS_NOSERVER */
30660484Sobrien	if (error == EINTR || error == ERESTART)
30760484Sobrien		error = 0;
30860484Sobrien	return (error);
30960484Sobrien}
31038889Sjdp
31138889Sjdp#ifndef NFS_NOSERVER
31238889Sjdp/*
31338889Sjdp * Adds a socket to the list for servicing by nfsds.
31438889Sjdp */
31538889Sjdpstatic int
31638889Sjdpnfssvc_addsock(fp, mynam, p)
31738889Sjdp	struct file *fp;
31838889Sjdp	struct sockaddr *mynam;
31938889Sjdp	struct proc *p;
32038889Sjdp{
32138889Sjdp	register int siz;
32238889Sjdp	register struct nfssvc_sock *slp;
32338889Sjdp	register struct socket *so;
32438889Sjdp	int error, s;
32538889Sjdp
32638889Sjdp	so = (struct socket *)fp->f_data;
32738889Sjdp#if 0
32838889Sjdp	tslp = (struct nfssvc_sock *)0;
32938889Sjdp	/*
33038889Sjdp	 * Add it to the list, as required.
33138889Sjdp	 */
33238889Sjdp	if (so->so_proto->pr_protocol == IPPROTO_UDP) {
33360484Sobrien		tslp = nfs_udpsock;
33460484Sobrien		if (tslp->ns_flag & SLP_VALID) {
33538889Sjdp			if (mynam != NULL)
33638889Sjdp				FREE(mynam, M_SONAME);
33738889Sjdp			return (EPERM);
33860484Sobrien		}
33938889Sjdp	}
34038889Sjdp#endif
34160484Sobrien	if (so->so_type == SOCK_STREAM)
34260484Sobrien		siz = NFS_MAXPACKET + sizeof (u_long);
34360484Sobrien	else
34438889Sjdp		siz = NFS_MAXPACKET;
34538889Sjdp	error = soreserve(so, siz, siz);
34638889Sjdp	if (error) {
34738889Sjdp		if (mynam != NULL)
34838889Sjdp			FREE(mynam, M_SONAME);
34938889Sjdp		return (error);
35038889Sjdp	}
35138889Sjdp
35238889Sjdp	/*
35360484Sobrien	 * Set protocol specific options { for now TCP only } and
35460484Sobrien	 * reserve some space. For datagram sockets, this can get called
35538889Sjdp	 * repeatedly for the same socket, but that isn't harmful.
35638889Sjdp	 */
35738889Sjdp	if (so->so_type == SOCK_STREAM) {
35838889Sjdp		struct sockopt sopt;
35938889Sjdp		int val;
36038889Sjdp
36160484Sobrien		bzero(&sopt, sizeof sopt);
36260484Sobrien		sopt.sopt_level = SOL_SOCKET;
36338889Sjdp		sopt.sopt_name = SO_KEEPALIVE;
36438889Sjdp		sopt.sopt_val = &val;
36560484Sobrien		sopt.sopt_valsize = sizeof val;
36660484Sobrien		val = 1;
36738889Sjdp		sosetopt(so, &sopt);
36838889Sjdp	}
36938889Sjdp	if (so->so_proto->pr_domain->dom_family == AF_INET &&
37038889Sjdp	    so->so_proto->pr_protocol == IPPROTO_TCP) {
37138889Sjdp		struct sockopt sopt;
37238889Sjdp		int val;
37338889Sjdp
37460484Sobrien		bzero(&sopt, sizeof sopt);
37560484Sobrien		sopt.sopt_level = IPPROTO_TCP;
37660484Sobrien		sopt.sopt_name = TCP_NODELAY;
37738889Sjdp		sopt.sopt_val = &val;
37838889Sjdp		sopt.sopt_valsize = sizeof val;
37938889Sjdp		val = 1;
38038889Sjdp		sosetopt(so, &sopt);
38160484Sobrien	}
38260484Sobrien	so->so_rcv.sb_flags &= ~SB_NOINTR;
38338889Sjdp	so->so_rcv.sb_timeo = 0;
38438889Sjdp	so->so_snd.sb_flags &= ~SB_NOINTR;
38538889Sjdp	so->so_snd.sb_timeo = 0;
38660484Sobrien
38760484Sobrien	slp = (struct nfssvc_sock *)
38860484Sobrien		malloc(sizeof (struct nfssvc_sock), M_NFSSVC, M_WAITOK);
38960484Sobrien	bzero((caddr_t)slp, sizeof (struct nfssvc_sock));
39038889Sjdp	STAILQ_INIT(&slp->ns_rec);
39138889Sjdp	TAILQ_INIT(&slp->ns_uidlruhead);
39238889Sjdp	TAILQ_INSERT_TAIL(&nfssvc_sockhead, slp, ns_chain);
39338889Sjdp
39460484Sobrien	slp->ns_so = so;
39560484Sobrien	slp->ns_nam = mynam;
39660484Sobrien	fp->f_count++;
39760484Sobrien	slp->ns_fp = fp;
39838889Sjdp	s = splnet();
39938889Sjdp	so->so_upcallarg = (caddr_t)slp;
40038889Sjdp	so->so_upcall = nfsrv_rcv;
40138889Sjdp	so->so_rcv.sb_flags |= SB_UPCALL;
40238889Sjdp	slp->ns_flag = (SLP_VALID | SLP_NEEDQ);
40360484Sobrien	nfsrv_wakenfsd(slp);
40460484Sobrien	splx(s);
40538889Sjdp	return (0);
40638889Sjdp}
40760484Sobrien
40860484Sobrien/*
40960484Sobrien * Called by nfssvc() for nfsds. Just loops around servicing rpc requests
41038889Sjdp * until it is killed by a signal.
41138889Sjdp */
41238889Sjdpstatic int
41338889Sjdpnfssvc_nfsd(nsd, argp, p)
41438889Sjdp	struct nfsd_srvargs *nsd;
41560484Sobrien	caddr_t argp;
41660484Sobrien	struct proc *p;
41760484Sobrien{
41838889Sjdp	register int siz;
41960484Sobrien	register struct nfssvc_sock *slp;
42038889Sjdp	struct nfsd *nfsd = nsd->nsd_nfsd;
42160484Sobrien	struct nfsrv_descript *nd = NULL;
42260484Sobrien	struct mbuf *m, *mreq;
42338889Sjdp	int error = 0, cacherep, s, sotype, writes_todo;
42438889Sjdp	int procrastinate;
42560484Sobrien	u_quad_t cur_usec;
42638889Sjdp
42738889Sjdp#ifndef nolint
42838889Sjdp	cacherep = RC_DOIT;
42960484Sobrien	writes_todo = 0;
43038889Sjdp#endif
43138889Sjdp	if (nfsd == (struct nfsd *)0) {
43260484Sobrien		nsd->nsd_nfsd = nfsd = (struct nfsd *)
43338889Sjdp			malloc(sizeof (struct nfsd), M_NFSD, M_WAITOK);
43460484Sobrien		bzero((caddr_t)nfsd, sizeof (struct nfsd));
43538889Sjdp		s = splnet();
43638889Sjdp		nfsd->nfsd_procp = p;
43738889Sjdp		TAILQ_INSERT_TAIL(&nfsd_head, nfsd, nfsd_chain);
43860484Sobrien		nfs_numnfsd++;
43960484Sobrien	} else
44060484Sobrien		s = splnet();
44160484Sobrien
44238889Sjdp	/*
44338889Sjdp	 * Loop getting rpc requests until SIGKILL.
44438889Sjdp	 */
44538889Sjdp	for (;;) {
44660484Sobrien		if ((nfsd->nfsd_flag & NFSD_REQINPROG) == 0) {
44760484Sobrien			while (nfsd->nfsd_slp == (struct nfssvc_sock *)0 &&
44860484Sobrien			    (nfsd_head_flag & NFSD_CHECKSLP) == 0) {
44960484Sobrien				nfsd->nfsd_flag |= NFSD_WAITING;
45060484Sobrien				nfsd_waiting++;
45160484Sobrien				error = tsleep((caddr_t)nfsd, PSOCK | PCATCH,
45260484Sobrien				    "nfsd", 0);
45338889Sjdp				nfsd_waiting--;
45460484Sobrien				if (error)
45538889Sjdp					goto done;
45638889Sjdp			}
45738889Sjdp			if (nfsd->nfsd_slp == (struct nfssvc_sock *)0 &&
45838889Sjdp			    (nfsd_head_flag & NFSD_CHECKSLP) != 0) {
45938889Sjdp				for (slp = nfssvc_sockhead.tqh_first; slp != 0;
46038889Sjdp				    slp = slp->ns_chain.tqe_next) {
46138889Sjdp				    if ((slp->ns_flag & (SLP_VALID | SLP_DOREC))
46238889Sjdp					== (SLP_VALID | SLP_DOREC)) {
46338889Sjdp					    slp->ns_flag &= ~SLP_DOREC;
46438889Sjdp					    slp->ns_sref++;
46538889Sjdp					    nfsd->nfsd_slp = slp;
46638889Sjdp					    break;
46738889Sjdp				    }
46838889Sjdp				}
46938889Sjdp				if (slp == 0)
47038889Sjdp					nfsd_head_flag &= ~NFSD_CHECKSLP;
47138889Sjdp			}
47238889Sjdp			if ((slp = nfsd->nfsd_slp) == (struct nfssvc_sock *)0)
47338889Sjdp				continue;
47438889Sjdp			if (slp->ns_flag & SLP_VALID) {
47538889Sjdp				if (slp->ns_flag & SLP_DISCONN)
47660484Sobrien					nfsrv_zapsock(slp);
47738889Sjdp				else if (slp->ns_flag & SLP_NEEDQ) {
47838889Sjdp					slp->ns_flag &= ~SLP_NEEDQ;
47960484Sobrien					(void) nfs_slplock(slp, 1);
48060484Sobrien					nfsrv_rcv(slp->ns_so, (caddr_t)slp,
48138889Sjdp						M_WAIT);
48238889Sjdp					nfs_slpunlock(slp);
48338889Sjdp				}
48438889Sjdp				error = nfsrv_dorec(slp, nfsd, &nd);
48560484Sobrien				cur_usec = nfs_curusec();
48638889Sjdp				if (error && slp->ns_tq.lh_first &&
48760484Sobrien				    slp->ns_tq.lh_first->nd_time <= cur_usec) {
48838889Sjdp					error = 0;
48938889Sjdp					cacherep = RC_DOIT;
49038889Sjdp					writes_todo = 1;
49138889Sjdp				} else
49238889Sjdp					writes_todo = 0;
49338889Sjdp				nfsd->nfsd_flag |= NFSD_REQINPROG;
49438889Sjdp			}
49538889Sjdp		} else {
49638889Sjdp			error = 0;
49738889Sjdp			slp = nfsd->nfsd_slp;
49838889Sjdp		}
49938889Sjdp		if (error || (slp->ns_flag & SLP_VALID) == 0) {
50038889Sjdp			if (nd) {
50138889Sjdp				free((caddr_t)nd, M_NFSRVDESC);
50238889Sjdp				nd = NULL;
50338889Sjdp			}
50438889Sjdp			nfsd->nfsd_slp = (struct nfssvc_sock *)0;
50538889Sjdp			nfsd->nfsd_flag &= ~NFSD_REQINPROG;
50638889Sjdp			nfsrv_slpderef(slp);
50738889Sjdp			continue;
50838889Sjdp		}
50938889Sjdp		splx(s);
51038889Sjdp		sotype = slp->ns_so->so_type;
51138889Sjdp		if (nd) {
51238889Sjdp		    getmicrotime(&nd->nd_starttime);
51338889Sjdp		    if (nd->nd_nam2)
51438889Sjdp			nd->nd_nam = nd->nd_nam2;
51538889Sjdp		    else
51638889Sjdp			nd->nd_nam = slp->ns_nam;
51738889Sjdp
51838889Sjdp		    /*
51938889Sjdp		     * Check to see if authorization is needed.
52038889Sjdp		     */
52138889Sjdp		    if (nfsd->nfsd_flag & NFSD_NEEDAUTH) {
52238889Sjdp			nfsd->nfsd_flag &= ~NFSD_NEEDAUTH;
52338889Sjdp			nsd->nsd_haddr =
52438889Sjdp				((struct sockaddr_in *)
52538889Sjdp				 nd->nd_nam)->sin_addr.s_addr;
52638889Sjdp			nsd->nsd_authlen = nfsd->nfsd_authlen;
52738889Sjdp			nsd->nsd_verflen = nfsd->nfsd_verflen;
52838889Sjdp			if (!copyout(nfsd->nfsd_authstr,nsd->nsd_authstr,
52938889Sjdp				nfsd->nfsd_authlen) &&
53038889Sjdp			    !copyout(nfsd->nfsd_verfstr, nsd->nsd_verfstr,
53138889Sjdp				nfsd->nfsd_verflen) &&
53238889Sjdp			    !copyout((caddr_t)nsd, argp, sizeof (*nsd)))
53338889Sjdp			    return (ENEEDAUTH);
53438889Sjdp			cacherep = RC_DROPIT;
53538889Sjdp		    } else
53638889Sjdp			cacherep = nfsrv_getcache(nd, slp, &mreq);
53738889Sjdp
53838889Sjdp		    /*
53938889Sjdp		     * Check for just starting up for NQNFS and send
54038889Sjdp		     * fake "try again later" replies to the NQNFS clients.
54138889Sjdp		     */
54238889Sjdp		    if (notstarted && nqnfsstarttime <= time_second) {
54338889Sjdp			if (modify_flag) {
54438889Sjdp				nqnfsstarttime = time_second + nqsrv_writeslack;
54538889Sjdp				modify_flag = 0;
54638889Sjdp			} else
54738889Sjdp				notstarted = 0;
54838889Sjdp		    }
54938889Sjdp		    if (notstarted) {
55038889Sjdp			if ((nd->nd_flag & ND_NQNFS) == 0)
55138889Sjdp				cacherep = RC_DROPIT;
55238889Sjdp			else if (nd->nd_procnum != NFSPROC_WRITE) {
55338889Sjdp				nd->nd_procnum = NFSPROC_NOOP;
55438889Sjdp				nd->nd_repstat = NQNFS_TRYLATER;
55538889Sjdp				cacherep = RC_DOIT;
55638889Sjdp			} else
55738889Sjdp				modify_flag = 1;
55838889Sjdp		    } else if (nfsd->nfsd_flag & NFSD_AUTHFAIL) {
55938889Sjdp			nfsd->nfsd_flag &= ~NFSD_AUTHFAIL;
56038889Sjdp			nd->nd_procnum = NFSPROC_NOOP;
56160484Sobrien			nd->nd_repstat = (NFSERR_AUTHERR | AUTH_TOOWEAK);
56260484Sobrien			cacherep = RC_DOIT;
56360484Sobrien		    } else if (nfs_privport) {
56460484Sobrien			/* Check if source port is privileged */
56538889Sjdp			u_short port;
56638889Sjdp			struct sockaddr *nam = nd->nd_nam;
56738889Sjdp			struct sockaddr_in *sin;
56838889Sjdp
56938889Sjdp			sin = (struct sockaddr_in *)nam;
57038889Sjdp			port = ntohs(sin->sin_port);
57138889Sjdp			if (port >= IPPORT_RESERVED &&
57238889Sjdp			    nd->nd_procnum != NFSPROC_NULL) {
57338889Sjdp			    nd->nd_procnum = NFSPROC_NOOP;
57438889Sjdp			    nd->nd_repstat = (NFSERR_AUTHERR | AUTH_TOOWEAK);
57538889Sjdp			    cacherep = RC_DOIT;
57638889Sjdp			    printf("NFS request from unprivileged port (%s:%d)\n",
57738889Sjdp				   inet_ntoa(sin->sin_addr), port);
57838889Sjdp			}
57938889Sjdp		    }
58038889Sjdp
58138889Sjdp		}
58238889Sjdp
58338889Sjdp		/*
58438889Sjdp		 * Loop to get all the write rpc relies that have been
58538889Sjdp		 * gathered together.
58638889Sjdp		 */
58738889Sjdp		do {
58838889Sjdp		    switch (cacherep) {
58938889Sjdp		    case RC_DOIT:
59038889Sjdp			if (nd && (nd->nd_flag & ND_NFSV3))
59138889Sjdp			    procrastinate = nfsrvw_procrastinate_v3;
59238889Sjdp			else
59360484Sobrien			    procrastinate = nfsrvw_procrastinate;
59460484Sobrien			if (writes_todo || (nd->nd_procnum == NFSPROC_WRITE &&
59560484Sobrien			    procrastinate > 0 && !notstarted))
59660484Sobrien			    error = nfsrv_writegather(&nd, slp,
59738889Sjdp				nfsd->nfsd_procp, &mreq);
59838889Sjdp			else
59938889Sjdp			    error = (*(nfsrv3_procs[nd->nd_procnum]))(nd,
60038889Sjdp				slp, nfsd->nfsd_procp, &mreq);
60138889Sjdp			if (mreq == NULL)
60238889Sjdp				break;
60338889Sjdp			if (error != 0 && error != NFSERR_RETVOID) {
60460484Sobrien				if (nd->nd_procnum != NQNFSPROC_VACATED)
60560484Sobrien					nfsstats.srv_errs++;
60660484Sobrien				nfsrv_updatecache(nd, FALSE, mreq);
60760484Sobrien				if (nd->nd_nam2)
60860484Sobrien					FREE(nd->nd_nam2, M_SONAME);
60960484Sobrien				break;
61038889Sjdp			}
61160484Sobrien			nfsstats.srvrpccnt[nd->nd_procnum]++;
61260484Sobrien			nfsrv_updatecache(nd, TRUE, mreq);
61338889Sjdp			nd->nd_mrep = (struct mbuf *)0;
61460484Sobrien		    case RC_REPLY:
61538889Sjdp			m = mreq;
61633965Sjdp			siz = 0;
61733965Sjdp			while (m) {
61838889Sjdp				siz += m->m_len;
61938889Sjdp				m = m->m_next;
62033965Sjdp			}
62133965Sjdp			if (siz <= 0 || siz > NFS_MAXPACKET) {
62238889Sjdp				printf("mbuf siz=%d\n",siz);
62333965Sjdp				panic("Bad nfs svc reply");
62438889Sjdp			}
62538889Sjdp			m = mreq;
62638889Sjdp			m->m_pkthdr.len = siz;
62733965Sjdp			m->m_pkthdr.rcvif = (struct ifnet *)0;
62838889Sjdp			/*
62960484Sobrien			 * For stream protocols, prepend a Sun RPC
63038889Sjdp			 * Record Mark.
63133965Sjdp			 */
63238889Sjdp			if (sotype == SOCK_STREAM) {
63338889Sjdp				M_PREPEND(m, NFSX_UNSIGNED, M_WAIT);
63438889Sjdp				*mtod(m, u_int32_t *) = htonl(0x80000000 | siz);
63533965Sjdp			}
63638889Sjdp			if (slp->ns_so->so_proto->pr_flags & PR_CONNREQUIRED)
63738889Sjdp				(void) nfs_slplock(slp, 1);
63838889Sjdp			if (slp->ns_flag & SLP_VALID)
63933965Sjdp			    error = nfs_send(slp->ns_so, nd->nd_nam2, m, NULL);
64038889Sjdp			else {
64138889Sjdp			    error = EPIPE;
64238889Sjdp			    m_freem(m);
64333965Sjdp			}
64438889Sjdp			if (nfsrtton)
64560484Sobrien				nfsd_rt(sotype, nd, cacherep);
64638889Sjdp			if (nd->nd_nam2)
64760484Sobrien				FREE(nd->nd_nam2, M_SONAME);
64860484Sobrien			if (nd->nd_mrep)
64960484Sobrien				m_freem(nd->nd_mrep);
65060484Sobrien			if (error == EPIPE)
65160484Sobrien				nfsrv_zapsock(slp);
65260484Sobrien			if (slp->ns_so->so_proto->pr_flags & PR_CONNREQUIRED)
65360484Sobrien				nfs_slpunlock(slp);
65460484Sobrien			if (error == EINTR || error == ERESTART) {
65560484Sobrien				free((caddr_t)nd, M_NFSRVDESC);
65660484Sobrien				nfsrv_slpderef(slp);
65760484Sobrien				s = splnet();
65860484Sobrien				goto done;
65938889Sjdp			}
66038889Sjdp			break;
66133965Sjdp		    case RC_DROPIT:
66238889Sjdp			if (nfsrtton)
66338889Sjdp				nfsd_rt(sotype, nd, cacherep);
66460484Sobrien			m_freem(nd->nd_mrep);
66560484Sobrien			if (nd->nd_nam2)
66660484Sobrien				FREE(nd->nd_nam2, M_SONAME);
66738889Sjdp			break;
66838889Sjdp		    };
66938889Sjdp		    if (nd) {
67060484Sobrien			FREE((caddr_t)nd, M_NFSRVDESC);
67160484Sobrien			nd = NULL;
67238889Sjdp		    }
67338889Sjdp
67438889Sjdp		    /*
67538889Sjdp		     * Check to see if there are outstanding writes that
67638889Sjdp		     * need to be serviced.
67760484Sobrien		     */
67860484Sobrien		    cur_usec = nfs_curusec();
67960484Sobrien		    s = splsoftclock();
68060484Sobrien		    if (slp->ns_tq.lh_first &&
68138889Sjdp			slp->ns_tq.lh_first->nd_time <= cur_usec) {
68238889Sjdp			cacherep = RC_DOIT;
68333965Sjdp			writes_todo = 1;
68438889Sjdp		    } else
68538889Sjdp			writes_todo = 0;
68638889Sjdp		    splx(s);
68738889Sjdp		} while (writes_todo);
68838889Sjdp		s = splnet();
68960484Sobrien		if (nfsrv_dorec(slp, nfsd, &nd)) {
69060484Sobrien			nfsd->nfsd_flag &= ~NFSD_REQINPROG;
69138889Sjdp			nfsd->nfsd_slp = NULL;
69260484Sobrien			nfsrv_slpderef(slp);
69338889Sjdp		}
69460484Sobrien	}
69560484Sobriendone:
69660484Sobrien	TAILQ_REMOVE(&nfsd_head, nfsd, nfsd_chain);
69760484Sobrien	splx(s);
69838889Sjdp	free((caddr_t)nfsd, M_NFSD);
69933965Sjdp	nsd->nsd_nfsd = (struct nfsd *)0;
70038889Sjdp	if (--nfs_numnfsd == 0)
70160484Sobrien		nfsrv_init(TRUE);	/* Reinitialize everything */
70260484Sobrien	return (error);
70338889Sjdp}
70438889Sjdp
70538889Sjdp/*
70638889Sjdp * Shut down a socket associated with an nfssvc_sock structure.
70738889Sjdp * Should be called with the send lock set, if required.
70838889Sjdp * The trick here is to increment the sref at the start, so that the nfsds
70938889Sjdp * will stop using it and clear ns_flag at the end so that it will not be
71033965Sjdp * reassigned during cleanup.
71138889Sjdp */
71238889Sjdpstatic void
71338889Sjdpnfsrv_zapsock(slp)
71438889Sjdp	register struct nfssvc_sock *slp;
71538889Sjdp{
71638889Sjdp	register struct nfsuid *nuidp, *nnuidp;
71733965Sjdp	register struct nfsrv_descript *nwp, *nnwp;
71838889Sjdp	struct socket *so;
71938889Sjdp	struct file *fp;
72038889Sjdp	struct nfsrv_rec *rec;
72138889Sjdp	int s;
72238889Sjdp
72338889Sjdp	slp->ns_flag &= ~SLP_ALLFLAGS;
72438889Sjdp	fp = slp->ns_fp;
72538889Sjdp	if (fp) {
72638889Sjdp		slp->ns_fp = (struct file *)0;
72738889Sjdp		so = slp->ns_so;
72838889Sjdp		so->so_rcv.sb_flags &= ~SB_UPCALL;
72938889Sjdp		so->so_upcall = NULL;
73060484Sobrien		so->so_upcallarg = NULL;
73160484Sobrien		soshutdown(so, 2);
73260484Sobrien		closef(fp, (struct proc *)0);
73360484Sobrien		if (slp->ns_nam)
73460484Sobrien			FREE(slp->ns_nam, M_SONAME);
73560484Sobrien		m_freem(slp->ns_raw);
73660484Sobrien		while ((rec = STAILQ_FIRST(&slp->ns_rec)) != NULL) {
73760484Sobrien			STAILQ_REMOVE_HEAD(&slp->ns_rec, nr_link);
73860484Sobrien			if (rec->nr_address)
73960484Sobrien				FREE(rec->nr_address, M_SONAME);
74060484Sobrien			m_freem(rec->nr_packet);
74160484Sobrien			free(rec, M_NFSRVDESC);
74260484Sobrien		}
74360484Sobrien		for (nuidp = slp->ns_uidlruhead.tqh_first; nuidp != 0;
74460484Sobrien		    nuidp = nnuidp) {
74560484Sobrien			nnuidp = nuidp->nu_lru.tqe_next;
74660484Sobrien			LIST_REMOVE(nuidp, nu_hash);
74760484Sobrien			TAILQ_REMOVE(&slp->ns_uidlruhead, nuidp, nu_lru);
74860484Sobrien			if (nuidp->nu_flag & NU_NAM)
74960484Sobrien				FREE(nuidp->nu_nam, M_SONAME);
75060484Sobrien			free((caddr_t)nuidp, M_NFSUID);
75160484Sobrien		}
75260484Sobrien		s = splsoftclock();
75360484Sobrien		for (nwp = slp->ns_tq.lh_first; nwp; nwp = nnwp) {
75460484Sobrien			nnwp = nwp->nd_tq.le_next;
75560484Sobrien			LIST_REMOVE(nwp, nd_tq);
75660484Sobrien			free((caddr_t)nwp, M_NFSRVDESC);
75760484Sobrien		}
75860484Sobrien		LIST_INIT(&slp->ns_tq);
75960484Sobrien		splx(s);
76060484Sobrien	}
76160484Sobrien}
76260484Sobrien
76338889Sjdp/*
76460484Sobrien * Derefence a server socket structure. If it has no more references and
76560484Sobrien * is no longer valid, you can throw it away.
76638889Sjdp */
76760484Sobrienvoid
76860484Sobriennfsrv_slpderef(slp)
76938889Sjdp	register struct nfssvc_sock *slp;
77060484Sobrien{
77160484Sobrien	if (--(slp->ns_sref) == 0 && (slp->ns_flag & SLP_VALID) == 0) {
77260484Sobrien		TAILQ_REMOVE(&nfssvc_sockhead, slp, ns_chain);
77360484Sobrien		free((caddr_t)slp, M_NFSSVC);
77460484Sobrien	}
77560484Sobrien}
77638889Sjdp
77760484Sobrien/*
77860484Sobrien * Lock a socket against others.
77960484Sobrien */
78060484Sobrienint
78160484Sobriennfs_slplock(slp, wait)
78260484Sobrien	register struct nfssvc_sock *slp;
78360484Sobrien	int wait;
78460484Sobrien{
78560484Sobrien	int *statep = &slp->ns_solock;
78660484Sobrien
78760484Sobrien	if (!wait && (*statep & NFSSTA_SNDLOCK))
78860484Sobrien		return(0);	/* already locked, fail */
78960484Sobrien	while (*statep & NFSSTA_SNDLOCK) {
79060484Sobrien		*statep |= NFSSTA_WANTSND;
79160484Sobrien		(void) tsleep((caddr_t)statep, PZERO - 1, "nfsslplck", 0);
79260484Sobrien	}
79360484Sobrien	*statep |= NFSSTA_SNDLOCK;
79460484Sobrien	return (1);
79560484Sobrien}
79660484Sobrien
79760484Sobrien/*
79860484Sobrien * Unlock the stream socket for others.
79960484Sobrien */
80060484Sobrienvoid
80160484Sobriennfs_slpunlock(slp)
80260484Sobrien	register struct nfssvc_sock *slp;
80360484Sobrien{
80460484Sobrien	int *statep = &slp->ns_solock;
80560484Sobrien
80660484Sobrien	if ((*statep & NFSSTA_SNDLOCK) == 0)
80760484Sobrien		panic("nfs slpunlock");
80860484Sobrien	*statep &= ~NFSSTA_SNDLOCK;
80960484Sobrien	if (*statep & NFSSTA_WANTSND) {
81060484Sobrien		*statep &= ~NFSSTA_WANTSND;
81160484Sobrien		wakeup((caddr_t)statep);
81260484Sobrien	}
81360484Sobrien}
81460484Sobrien
81560484Sobrien/*
81660484Sobrien * Initialize the data structures for the server.
81760484Sobrien * Handshake with any new nfsds starting up to avoid any chance of
81860484Sobrien * corruption.
81960484Sobrien */
82060484Sobrienvoid
82160484Sobriennfsrv_init(terminating)
82260484Sobrien	int terminating;
82360484Sobrien{
82460484Sobrien	register struct nfssvc_sock *slp, *nslp;
82538889Sjdp
82638889Sjdp	if (nfssvc_sockhead_flag & SLP_INIT)
82738889Sjdp		panic("nfsd init");
82860484Sobrien	nfssvc_sockhead_flag |= SLP_INIT;
82960484Sobrien	if (terminating) {
83060484Sobrien		for (slp = nfssvc_sockhead.tqh_first; slp != 0; slp = nslp) {
83160484Sobrien			nslp = slp->ns_chain.tqe_next;
83238889Sjdp			if (slp->ns_flag & SLP_VALID)
83360484Sobrien				nfsrv_zapsock(slp);
83438889Sjdp			TAILQ_REMOVE(&nfssvc_sockhead, slp, ns_chain);
83560484Sobrien			free((caddr_t)slp, M_NFSSVC);
83638889Sjdp		}
83738889Sjdp		nfsrv_cleancache();	/* And clear out server cache */
83860484Sobrien	} else
83960484Sobrien		nfs_pub.np_valid = 0;
84060484Sobrien
84160484Sobrien	TAILQ_INIT(&nfssvc_sockhead);
84260484Sobrien	nfssvc_sockhead_flag &= ~SLP_INIT;
84338889Sjdp	if (nfssvc_sockhead_flag & SLP_WANTINIT) {
84438889Sjdp		nfssvc_sockhead_flag &= ~SLP_WANTINIT;
84538889Sjdp		wakeup((caddr_t)&nfssvc_sockhead);
84638889Sjdp	}
84738889Sjdp
84838889Sjdp	TAILQ_INIT(&nfsd_head);
84938889Sjdp	nfsd_head_flag &= ~NFSD_CHECKSLP;
85038889Sjdp
85138889Sjdp#if 0
85238889Sjdp	nfs_udpsock = (struct nfssvc_sock *)
85338889Sjdp	    malloc(sizeof (struct nfssvc_sock), M_NFSSVC, M_WAITOK);
85438889Sjdp	bzero((caddr_t)nfs_udpsock, sizeof (struct nfssvc_sock));
85538889Sjdp	STAILQ_INIT(&nfs_udpsock->ns_rec);
85638889Sjdp	TAILQ_INIT(&nfs_udpsock->ns_uidlruhead);
85738889Sjdp	TAILQ_INSERT_HEAD(&nfssvc_sockhead, nfs_udpsock, ns_chain);
85838889Sjdp
85938889Sjdp	nfs_cltpsock = (struct nfssvc_sock *)
86038889Sjdp	    malloc(sizeof (struct nfssvc_sock), M_NFSSVC, M_WAITOK);
86138889Sjdp	bzero((caddr_t)nfs_cltpsock, sizeof (struct nfssvc_sock));
86238889Sjdp	STAILQ_INIT(&nfs_cltpsock->ns_rec);
86338889Sjdp	TAILQ_INIT(&nfs_cltpsock->ns_uidlruhead);
86438889Sjdp	TAILQ_INSERT_TAIL(&nfssvc_sockhead, nfs_cltpsock, ns_chain);
86538889Sjdp#endif
86638889Sjdp}
86760484Sobrien
86838889Sjdp/*
86938889Sjdp * Add entries to the server monitor log.
87038889Sjdp */
87138889Sjdpstatic void
87238889Sjdpnfsd_rt(sotype, nd, cacherep)
87360484Sobrien	int sotype;
87460484Sobrien	register struct nfsrv_descript *nd;
87560484Sobrien	int cacherep;
87660484Sobrien{
87760484Sobrien	register struct drt *rt;
87860484Sobrien
87938889Sjdp	rt = &nfsdrt.drt[nfsdrt.pos];
88060484Sobrien	if (cacherep == RC_DOIT)
88160484Sobrien		rt->flag = 0;
88260484Sobrien	else if (cacherep == RC_REPLY)
88360484Sobrien		rt->flag = DRT_CACHEREPLY;
88460484Sobrien	else
88538889Sjdp		rt->flag = DRT_CACHEDROP;
88638889Sjdp	if (sotype == SOCK_STREAM)
88760484Sobrien		rt->flag |= DRT_TCP;
88838889Sjdp	if (nd->nd_flag & ND_NQNFS)
88938889Sjdp		rt->flag |= DRT_NQNFS;
89038889Sjdp	else if (nd->nd_flag & ND_NFSV3)
89160484Sobrien		rt->flag |= DRT_NFSV3;
89238889Sjdp	rt->proc = nd->nd_procnum;
89338889Sjdp	if (nd->nd_nam->sa_family == AF_INET)
89438889Sjdp	    rt->ipadr = ((struct sockaddr_in *)nd->nd_nam)->sin_addr.s_addr;
89538889Sjdp	else
89638889Sjdp	    rt->ipadr = INADDR_ANY;
89738889Sjdp	rt->resptime = nfs_curusec() - (nd->nd_starttime.tv_sec * 1000000 + nd->nd_starttime.tv_usec);
89838889Sjdp	getmicrotime(&rt->tstamp);
89960484Sobrien	nfsdrt.pos = (nfsdrt.pos + 1) % NFSRTTLOGSIZ;
90060484Sobrien}
90160484Sobrien#endif /* NFS_NOSERVER */
90260484Sobrien
90360484Sobrienstatic int nfs_defect = 0;
90460484SobrienSYSCTL_INT(_vfs_nfs, OID_AUTO, defect, CTLFLAG_RW, &nfs_defect, 0, "");
90560484Sobrien
90638889Sjdp/*
90760484Sobrien * Asynchronous I/O daemons for client nfs.
90860484Sobrien * They do read-ahead and write-behind operations on the block I/O cache.
90960484Sobrien * Never returns unless it fails or gets killed.
91060484Sobrien */
91160484Sobrienstatic int
91260484Sobriennfssvc_iod(p)
91360484Sobrien	struct proc *p;
91460484Sobrien{
91560484Sobrien	register struct buf *bp;
91660484Sobrien	register int i, myiod;
91760484Sobrien	struct nfsmount *nmp;
91838889Sjdp	int error = 0;
91938889Sjdp
92038889Sjdp	/*
92138889Sjdp	 * Assign my position or return error if too many already running
92238889Sjdp	 */
92338889Sjdp	myiod = -1;
92438889Sjdp	for (i = 0; i < NFS_MAXASYNCDAEMON; i++)
92538889Sjdp		if (nfs_asyncdaemon[i] == 0) {
92660484Sobrien			nfs_asyncdaemon[i]++;
92738889Sjdp			myiod = i;
92838889Sjdp			break;
92938889Sjdp		}
93038889Sjdp	if (myiod == -1)
93138889Sjdp		return (EBUSY);
93238889Sjdp	nfs_numasync++;
93338889Sjdp	/*
93438889Sjdp	 * Just loop around doin our stuff until SIGKILL
93538889Sjdp	 */
93638889Sjdp	for (;;) {
93738889Sjdp	    while (((nmp = nfs_iodmount[myiod]) == NULL
93838889Sjdp		    || nmp->nm_bufq.tqh_first == NULL)
93938889Sjdp		   && error == 0) {
94060484Sobrien		if (nmp)
94160484Sobrien		    nmp->nm_bufqiods--;
94238889Sjdp		nfs_iodwant[myiod] = p;
94360484Sobrien		nfs_iodmount[myiod] = NULL;
94460484Sobrien		error = tsleep((caddr_t)&nfs_iodwant[myiod],
94560484Sobrien			PWAIT | PCATCH, "nfsidl", 0);
94660484Sobrien	    }
94760484Sobrien	    if (error) {
94860484Sobrien		nfs_asyncdaemon[myiod] = 0;
94960484Sobrien		if (nmp)
95060484Sobrien		    nmp->nm_bufqiods--;
95160484Sobrien		nfs_iodwant[myiod] = NULL;
95260484Sobrien		nfs_iodmount[myiod] = NULL;
95360484Sobrien		nfs_numasync--;
95460484Sobrien		return (error);
95560484Sobrien	    }
95638889Sjdp	    while ((bp = nmp->nm_bufq.tqh_first) != NULL) {
95760484Sobrien		/* Take one off the front of the list */
95860484Sobrien		TAILQ_REMOVE(&nmp->nm_bufq, bp, b_freelist);
95938889Sjdp		nmp->nm_bufqlen--;
96060484Sobrien		if (nmp->nm_bufqwant && nmp->nm_bufqlen <= nfs_numasync) {
96160484Sobrien		    nmp->nm_bufqwant = FALSE;
96238889Sjdp		    wakeup(&nmp->nm_bufq);
96360484Sobrien		}
96460484Sobrien		if (bp->b_iocmd == BIO_READ)
96560484Sobrien		    (void) nfs_doio(bp, bp->b_rcred, (struct proc *)0);
96660484Sobrien		else
96760484Sobrien		    (void) nfs_doio(bp, bp->b_wcred, (struct proc *)0);
96860484Sobrien		/*
96960484Sobrien		 * If there are more than one iod on this mount, then defect
97038889Sjdp		 * so that the iods can be shared out fairly between the mounts
97160484Sobrien		 */
97260484Sobrien		if (nfs_defect && nmp->nm_bufqiods > 1) {
97360484Sobrien		    NFS_DPF(ASYNCIO,
97460484Sobrien			    ("nfssvc_iod: iod %d defecting from mount %p\n",
97538889Sjdp			     myiod, nmp));
97638889Sjdp		    nfs_iodmount[myiod] = NULL;
97738889Sjdp		    nmp->nm_bufqiods--;
97838889Sjdp		    break;
97938889Sjdp		}
98038889Sjdp	    }
98138889Sjdp	}
98238889Sjdp}
98338889Sjdp
98460484Sobrien
98538889Sjdp/*
98660484Sobrien * Get an authorization string for the uid by having the mount_nfs sitting
98738889Sjdp * on this mount point porpous out of the kernel and do it.
98838889Sjdp */
98960484Sobrienint
99060484Sobriennfs_getauth(nmp, rep, cred, auth_str, auth_len, verf_str, verf_len, key)
99138889Sjdp	register struct nfsmount *nmp;
99238889Sjdp	struct nfsreq *rep;
99338889Sjdp	struct ucred *cred;
99438889Sjdp	char **auth_str;
99560484Sobrien	int *auth_len;
99638889Sjdp	char *verf_str;
99760484Sobrien	int *verf_len;
99860484Sobrien	NFSKERBKEY_T key;		/* return session key */
99960484Sobrien{
100060484Sobrien	int error = 0;
100160484Sobrien
100260484Sobrien	while ((nmp->nm_state & NFSSTA_WAITAUTH) == 0) {
100360484Sobrien		nmp->nm_state |= NFSSTA_WANTAUTH;
100460484Sobrien		(void) tsleep((caddr_t)&nmp->nm_authtype, PSOCK,
100560484Sobrien			"nfsauth1", 2 * hz);
100660484Sobrien		error = nfs_sigintr(nmp, rep, rep->r_procp);
100738889Sjdp		if (error) {
100838889Sjdp			nmp->nm_state &= ~NFSSTA_WANTAUTH;
100960484Sobrien			return (error);
101060484Sobrien		}
101160484Sobrien	}
101260484Sobrien	nmp->nm_state &= ~(NFSSTA_WAITAUTH | NFSSTA_WANTAUTH);
101338889Sjdp	nmp->nm_authstr = *auth_str = (char *)malloc(RPCAUTH_MAXSIZ, M_TEMP, M_WAITOK);
101438889Sjdp	nmp->nm_authlen = RPCAUTH_MAXSIZ;
101538889Sjdp	nmp->nm_verfstr = verf_str;
101660484Sobrien	nmp->nm_verflen = *verf_len;
101738889Sjdp	nmp->nm_authuid = cred->cr_uid;
101838889Sjdp	wakeup((caddr_t)&nmp->nm_authstr);
101960484Sobrien
102060484Sobrien	/*
102138889Sjdp	 * And wait for mount_nfs to do its stuff.
102238889Sjdp	 */
102360484Sobrien	while ((nmp->nm_state & NFSSTA_HASAUTH) == 0 && error == 0) {
102460484Sobrien		(void) tsleep((caddr_t)&nmp->nm_authlen, PSOCK,
102560484Sobrien			"nfsauth2", 2 * hz);
102660484Sobrien		error = nfs_sigintr(nmp, rep, rep->r_procp);
102738889Sjdp	}
102838889Sjdp	if (nmp->nm_state & NFSSTA_AUTHERR) {
102938889Sjdp		nmp->nm_state &= ~NFSSTA_AUTHERR;
103038889Sjdp		error = EAUTH;
103138889Sjdp	}
103260484Sobrien	if (error)
103360484Sobrien		free((caddr_t)*auth_str, M_TEMP);
103460484Sobrien	else {
103560484Sobrien		*auth_len = nmp->nm_authlen;
103660484Sobrien		*verf_len = nmp->nm_verflen;
103760484Sobrien		bcopy((caddr_t)nmp->nm_key, (caddr_t)key, sizeof (key));
103860484Sobrien	}
103938889Sjdp	nmp->nm_state &= ~NFSSTA_HASAUTH;
104060484Sobrien	nmp->nm_state |= NFSSTA_WAITAUTH;
104160484Sobrien	if (nmp->nm_state & NFSSTA_WANTAUTH) {
104260484Sobrien		nmp->nm_state &= ~NFSSTA_WANTAUTH;
104360484Sobrien		wakeup((caddr_t)&nmp->nm_authtype);
104460484Sobrien	}
104560484Sobrien	return (error);
104638889Sjdp}
104760484Sobrien
104860484Sobrien/*
104960484Sobrien * Get a nickname authenticator and verifier.
105038889Sjdp */
105138889Sjdpint
105238889Sjdpnfs_getnickauth(nmp, cred, auth_str, auth_len, verf_str, verf_len)
105338889Sjdp	struct nfsmount *nmp;
105438889Sjdp	struct ucred *cred;
105538889Sjdp	char **auth_str;
105638889Sjdp	int *auth_len;
105738889Sjdp	char *verf_str;
105838889Sjdp	int verf_len;
105938889Sjdp{
106038889Sjdp	register struct nfsuid *nuidp;
106138889Sjdp	register u_int32_t *nickp, *verfp;
106238889Sjdp	struct timeval ktvin, ktvout;
106338889Sjdp
106438889Sjdp#ifdef DIAGNOSTIC
106538889Sjdp	if (verf_len < (4 * NFSX_UNSIGNED))
106638889Sjdp		panic("nfs_getnickauth verf too small");
106738889Sjdp#endif
106838889Sjdp	for (nuidp = NMUIDHASH(nmp, cred->cr_uid)->lh_first;
106938889Sjdp	    nuidp != 0; nuidp = nuidp->nu_hash.le_next) {
107038889Sjdp		if (nuidp->nu_cr.cr_uid == cred->cr_uid)
107138889Sjdp			break;
107238889Sjdp	}
107338889Sjdp	if (!nuidp || nuidp->nu_expire < time_second)
107438889Sjdp		return (EACCES);
107538889Sjdp
107638889Sjdp	/*
107738889Sjdp	 * Move to the end of the lru list (end of lru == most recently used).
107838889Sjdp	 */
107938889Sjdp	TAILQ_REMOVE(&nmp->nm_uidlruhead, nuidp, nu_lru);
108038889Sjdp	TAILQ_INSERT_TAIL(&nmp->nm_uidlruhead, nuidp, nu_lru);
108160484Sobrien
108238889Sjdp	nickp = (u_int32_t *)malloc(2 * NFSX_UNSIGNED, M_TEMP, M_WAITOK);
108338889Sjdp	*nickp++ = txdr_unsigned(RPCAKN_NICKNAME);
108438889Sjdp	*nickp = txdr_unsigned(nuidp->nu_nickname);
108538889Sjdp	*auth_str = (char *)nickp;
108638889Sjdp	*auth_len = 2 * NFSX_UNSIGNED;
108738889Sjdp
108838889Sjdp	/*
108938889Sjdp	 * Now we must encrypt the verifier and package it up.
109038889Sjdp	 */
109138889Sjdp	verfp = (u_int32_t *)verf_str;
109238889Sjdp	*verfp++ = txdr_unsigned(RPCAKN_NICKNAME);
109338889Sjdp	if (time_second > nuidp->nu_timestamp.tv_sec ||
109438889Sjdp	    (time_second == nuidp->nu_timestamp.tv_sec &&
109538889Sjdp	     time_second > nuidp->nu_timestamp.tv_usec))
109638889Sjdp		getmicrotime(&nuidp->nu_timestamp);
109738889Sjdp	else
109838889Sjdp		nuidp->nu_timestamp.tv_usec++;
109938889Sjdp	ktvin.tv_sec = txdr_unsigned(nuidp->nu_timestamp.tv_sec);
110038889Sjdp	ktvin.tv_usec = txdr_unsigned(nuidp->nu_timestamp.tv_usec);
110138889Sjdp
110238889Sjdp	/*
110338889Sjdp	 * Now encrypt the timestamp verifier in ecb mode using the session
110438889Sjdp	 * key.
110538889Sjdp	 */
110638889Sjdp#ifdef NFSKERB
110738889Sjdp	XXX
110833965Sjdp#endif
110933965Sjdp
111033965Sjdp	*verfp++ = ktvout.tv_sec;
111133965Sjdp	*verfp++ = ktvout.tv_usec;
111233965Sjdp	*verfp = 0;
111333965Sjdp	return (0);
111433965Sjdp}
111533965Sjdp
111633965Sjdp/*
111733965Sjdp * Save the current nickname in a hash list entry on the mount point.
111833965Sjdp */
111933965Sjdpint
112033965Sjdpnfs_savenickauth(nmp, cred, len, key, mdp, dposp, mrep)
112133965Sjdp	register struct nfsmount *nmp;
112233965Sjdp	struct ucred *cred;
112333965Sjdp	int len;
112460484Sobrien	NFSKERBKEY_T key;
112560484Sobrien	struct mbuf **mdp;
112660484Sobrien	char **dposp;
112760484Sobrien	struct mbuf *mrep;
112860484Sobrien{
112960484Sobrien	register struct nfsuid *nuidp;
113060484Sobrien	register u_int32_t *tl;
113133965Sjdp	register int32_t t1;
113238889Sjdp	struct mbuf *md = *mdp;
113333965Sjdp	struct timeval ktvin, ktvout;
113460484Sobrien	u_int32_t nick;
113560484Sobrien	char *dpos = *dposp, *cp2;
113660484Sobrien	int deltasec, error = 0;
113733965Sjdp
113833965Sjdp	if (len == (3 * NFSX_UNSIGNED)) {
113933965Sjdp		nfsm_dissect(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
114038889Sjdp		ktvin.tv_sec = *tl++;
114138889Sjdp		ktvin.tv_usec = *tl++;
114233965Sjdp		nick = fxdr_unsigned(u_int32_t, *tl);
114338889Sjdp
114433965Sjdp		/*
114533965Sjdp		 * Decrypt the timestamp in ecb mode.
114660484Sobrien		 */
114760484Sobrien#ifdef NFSKERB
114860484Sobrien		XXX
114960484Sobrien#endif
115060484Sobrien		ktvout.tv_sec = fxdr_unsigned(long, ktvout.tv_sec);
115160484Sobrien		ktvout.tv_usec = fxdr_unsigned(long, ktvout.tv_usec);
115233965Sjdp		deltasec = time_second - ktvout.tv_sec;
115360484Sobrien		if (deltasec < 0)
115460484Sobrien			deltasec = -deltasec;
115560484Sobrien		/*
115660484Sobrien		 * If ok, add it to the hash list for the mount point.
115760484Sobrien		 */
115833965Sjdp		if (deltasec <= NFS_KERBCLOCKSKEW) {
115933965Sjdp			if (nmp->nm_numuids < nuidhash_max) {
116038889Sjdp				nmp->nm_numuids++;
116133965Sjdp				nuidp = (struct nfsuid *)
116233965Sjdp				   malloc(sizeof (struct nfsuid), M_NFSUID,
116333965Sjdp					M_WAITOK);
116438889Sjdp			} else {
116538889Sjdp				nuidp = nmp->nm_uidlruhead.tqh_first;
116633965Sjdp				LIST_REMOVE(nuidp, nu_hash);
116760484Sobrien				TAILQ_REMOVE(&nmp->nm_uidlruhead, nuidp,
116833965Sjdp					nu_lru);
116960484Sobrien			}
117033965Sjdp			nuidp->nu_flag = 0;
117133965Sjdp			nuidp->nu_cr.cr_uid = cred->cr_uid;
117260484Sobrien			nuidp->nu_expire = time_second + NFS_KERBTTL;
117333965Sjdp			nuidp->nu_timestamp = ktvout;
117460484Sobrien			nuidp->nu_nickname = nick;
117533965Sjdp			bcopy(key, nuidp->nu_key, sizeof (key));
117633965Sjdp			TAILQ_INSERT_TAIL(&nmp->nm_uidlruhead, nuidp,
117760484Sobrien				nu_lru);
117838889Sjdp			LIST_INSERT_HEAD(NMUIDHASH(nmp, cred->cr_uid),
117960484Sobrien				nuidp, nu_hash);
118038889Sjdp		}
118133965Sjdp	} else
118238889Sjdp		nfsm_adv(nfsm_rndup(len));
118338889Sjdpnfsmout:
118433965Sjdp	*mdp = md;
118533965Sjdp	*dposp = dpos;
118633965Sjdp	return (error);
118733965Sjdp}
118833965Sjdp