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