nfs_nfsiod.c revision 44246
11541Srgrimes/* 21541Srgrimes * Copyright (c) 1989, 1993 31541Srgrimes * The Regents of the University of California. All rights reserved. 41541Srgrimes * 51541Srgrimes * This code is derived from software contributed to Berkeley by 61541Srgrimes * Rick Macklem at The University of Guelph. 71541Srgrimes * 81541Srgrimes * Redistribution and use in source and binary forms, with or without 91541Srgrimes * modification, are permitted provided that the following conditions 101541Srgrimes * are met: 111541Srgrimes * 1. Redistributions of source code must retain the above copyright 121541Srgrimes * notice, this list of conditions and the following disclaimer. 131541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 141541Srgrimes * notice, this list of conditions and the following disclaimer in the 151541Srgrimes * documentation and/or other materials provided with the distribution. 161541Srgrimes * 3. All advertising materials mentioning features or use of this software 171541Srgrimes * must display the following acknowledgement: 181541Srgrimes * This product includes software developed by the University of 191541Srgrimes * California, Berkeley and its contributors. 201541Srgrimes * 4. Neither the name of the University nor the names of its contributors 211541Srgrimes * may be used to endorse or promote products derived from this software 221541Srgrimes * without specific prior written permission. 231541Srgrimes * 241541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 251541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 261541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 271541Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 281541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 291541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 301541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 311541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 321541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 331541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 341541Srgrimes * SUCH DAMAGE. 351541Srgrimes * 3622521Sdyson * @(#)nfs_syscalls.c 8.5 (Berkeley) 3/30/95 3744246Speter * $Id: nfs_syscalls.c,v 1.47 1999/02/18 09:19:41 dfr Exp $ 381541Srgrimes */ 391541Srgrimes 401541Srgrimes#include <sys/param.h> 411541Srgrimes#include <sys/systm.h> 4212274Sbde#include <sys/sysproto.h> 431541Srgrimes#include <sys/kernel.h> 4419449Sdfr#include <sys/sysctl.h> 451541Srgrimes#include <sys/file.h> 4615480Sbde#include <sys/filedesc.h> 471541Srgrimes#include <sys/vnode.h> 4830354Sphk#include <sys/malloc.h> 491541Srgrimes#include <sys/mount.h> 501541Srgrimes#include <sys/proc.h> 511541Srgrimes#include <sys/buf.h> 521541Srgrimes#include <sys/mbuf.h> 531541Srgrimes#include <sys/socket.h> 541541Srgrimes#include <sys/socketvar.h> 551541Srgrimes#include <sys/domain.h> 561541Srgrimes#include <sys/protosw.h> 571541Srgrimes#include <sys/namei.h> 581541Srgrimes 591541Srgrimes#include <netinet/in.h> 601541Srgrimes#include <netinet/tcp.h> 611541Srgrimes#ifdef ISO 621541Srgrimes#include <netiso/iso.h> 631541Srgrimes#endif 649336Sdfr#include <nfs/xdr_subs.h> 651541Srgrimes#include <nfs/rpcv2.h> 669336Sdfr#include <nfs/nfsproto.h> 671541Srgrimes#include <nfs/nfs.h> 689336Sdfr#include <nfs/nfsm_subs.h> 691541Srgrimes#include <nfs/nfsrvcache.h> 701541Srgrimes#include <nfs/nfsmount.h> 711541Srgrimes#include <nfs/nfsnode.h> 721541Srgrimes#include <nfs/nqnfs.h> 731541Srgrimes#include <nfs/nfsrtt.h> 741541Srgrimes 7530354Sphkstatic MALLOC_DEFINE(M_NFSSVC, "NFS srvsock", "Nfs server structure"); 7630309Sphk 771541Srgrimes/* Global defs. */ 7836541Speterextern int32_t (*nfsrv3_procs[NFS_NPROCS]) __P((struct nfsrv_descript *nd, 7912457Sbde struct nfssvc_sock *slp, 8012457Sbde struct proc *procp, 8112457Sbde struct mbuf **mreqp)); 821541Srgrimesextern int nfs_numasync; 831541Srgrimesextern time_t nqnfsstarttime; 841541Srgrimesextern int nqsrv_writeslack; 851541Srgrimesextern int nfsrtton; 869336Sdfrextern struct nfsstats nfsstats; 879336Sdfrextern int nfsrvw_procrastinate; 8825664Sdfrextern int nfsrvw_procrastinate_v3; 891541Srgrimesstruct nfssvc_sock *nfs_udpsock, *nfs_cltpsock; 9012911Sphkstatic int nuidhash_max = NFS_MAXUIDHASH; 911541Srgrimes 9244246Speter#ifndef NFS_NOSERVER 9312911Sphkstatic void nfsrv_zapsock __P((struct nfssvc_sock *slp)); 9444246Speter#endif 9513416Sphkstatic int nfssvc_iod __P((struct proc *)); 9612457Sbde 971541Srgrimes#define TRUE 1 981541Srgrimes#define FALSE 0 991541Srgrimes 1001541Srgrimesstatic int nfs_asyncdaemon[NFS_MAXASYNCDAEMON]; 10112457Sbde 10244112SdfrSYSCTL_DECL(_vfs_nfs); 10344112Sdfr 10413416Sphk#ifndef NFS_NOSERVER 10513416Sphkint nfsd_waiting = 0; 10613416Sphkstatic struct nfsdrt nfsdrt; 10713416Sphkstatic int nfs_numnfsd = 0; 10813416Sphkstatic int notstarted = 1; 10913416Sphkstatic int modify_flag = 0; 11012457Sbdestatic void nfsd_rt __P((int sotype, struct nfsrv_descript *nd, 11112457Sbde int cacherep)); 11228270Swollmanstatic int nfssvc_addsock __P((struct file *, struct sockaddr *, 11325201Swollman struct proc *)); 11412911Sphkstatic int nfssvc_nfsd __P((struct nfsd_srvargs *,caddr_t,struct proc *)); 11524330Sguido 11624330Sguidostatic int nfs_privport = 0; 11724330SguidoSYSCTL_INT(_vfs_nfs, NFS_NFSPRIVPORT, nfs_privport, CTLFLAG_RW, &nfs_privport, 0, ""); 11825664SdfrSYSCTL_INT(_vfs_nfs, OID_AUTO, gatherdelay, CTLFLAG_RW, &nfsrvw_procrastinate, 0, ""); 11925664SdfrSYSCTL_INT(_vfs_nfs, OID_AUTO, gatherdelay_v3, CTLFLAG_RW, &nfsrvw_procrastinate_v3, 0, ""); 12024330Sguido 1211541Srgrimes/* 1221541Srgrimes * NFS server system calls 1231541Srgrimes * getfh() lives here too, but maybe should move to kern/vfs_syscalls.c 1241541Srgrimes */ 1251541Srgrimes 1261541Srgrimes/* 1271541Srgrimes * Get file handle system call 1281541Srgrimes */ 12912274Sbde#ifndef _SYS_SYSPROTO_H_ 1301541Srgrimesstruct getfh_args { 1311541Srgrimes char *fname; 1321541Srgrimes fhandle_t *fhp; 1331541Srgrimes}; 13412274Sbde#endif 1351549Srgrimesint 13630994Sphkgetfh(p, uap) 1371541Srgrimes struct proc *p; 1381541Srgrimes register struct getfh_args *uap; 1391541Srgrimes{ 1401541Srgrimes register struct vnode *vp; 1411541Srgrimes fhandle_t fh; 1421541Srgrimes int error; 1431541Srgrimes struct nameidata nd; 1441541Srgrimes 1451541Srgrimes /* 1461541Srgrimes * Must be super user 1471541Srgrimes */ 1483305Sphk error = suser(p->p_ucred, &p->p_acflag); 1493305Sphk if(error) 1501541Srgrimes return (error); 1511541Srgrimes NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 1523305Sphk error = namei(&nd); 1533305Sphk if (error) 1541541Srgrimes return (error); 1551541Srgrimes vp = nd.ni_vp; 1561541Srgrimes bzero((caddr_t)&fh, sizeof(fh)); 1571541Srgrimes fh.fh_fsid = vp->v_mount->mnt_stat.f_fsid; 1581541Srgrimes error = VFS_VPTOFH(vp, &fh.fh_fid); 1591541Srgrimes vput(vp); 1601541Srgrimes if (error) 1611541Srgrimes return (error); 1621541Srgrimes error = copyout((caddr_t)&fh, (caddr_t)uap->fhp, sizeof (fh)); 1631541Srgrimes return (error); 1641541Srgrimes} 1651541Srgrimes 16613416Sphk#endif /* NFS_NOSERVER */ 1671541Srgrimes/* 1681541Srgrimes * Nfs server psuedo system call for the nfsd's 1691541Srgrimes * Based on the flag value it either: 1701541Srgrimes * - adds a socket to the selection list 1711541Srgrimes * - remains in the kernel as an nfsd 1721541Srgrimes * - remains in the kernel as an nfsiod 1731541Srgrimes */ 17412274Sbde#ifndef _SYS_SYSPROTO_H_ 1751541Srgrimesstruct nfssvc_args { 1761541Srgrimes int flag; 1771541Srgrimes caddr_t argp; 1781541Srgrimes}; 17912274Sbde#endif 1801549Srgrimesint 18130994Sphknfssvc(p, uap) 1821541Srgrimes struct proc *p; 1831541Srgrimes register struct nfssvc_args *uap; 1841541Srgrimes{ 18513416Sphk#ifndef NFS_NOSERVER 1861541Srgrimes struct nameidata nd; 1871541Srgrimes struct file *fp; 18828270Swollman struct sockaddr *nam; 1891541Srgrimes struct nfsd_args nfsdarg; 1901541Srgrimes struct nfsd_srvargs nfsd_srvargs, *nsd = &nfsd_srvargs; 1911541Srgrimes struct nfsd_cargs ncd; 1921541Srgrimes struct nfsd *nfsd; 1931541Srgrimes struct nfssvc_sock *slp; 1943664Sphk struct nfsuid *nuidp; 1951541Srgrimes struct nfsmount *nmp; 19613416Sphk#endif /* NFS_NOSERVER */ 1971541Srgrimes int error; 1981541Srgrimes 1991541Srgrimes /* 2001541Srgrimes * Must be super user 2011541Srgrimes */ 2023305Sphk error = suser(p->p_ucred, &p->p_acflag); 2033305Sphk if(error) 2041541Srgrimes return (error); 2053664Sphk while (nfssvc_sockhead_flag & SLP_INIT) { 2063664Sphk nfssvc_sockhead_flag |= SLP_WANTINIT; 2071541Srgrimes (void) tsleep((caddr_t)&nfssvc_sockhead, PSOCK, "nfsd init", 0); 2081541Srgrimes } 2091541Srgrimes if (uap->flag & NFSSVC_BIOD) 2101541Srgrimes error = nfssvc_iod(p); 21113416Sphk#ifdef NFS_NOSERVER 21213416Sphk else 21313416Sphk error = ENXIO; 21413416Sphk#else /* !NFS_NOSERVER */ 2151541Srgrimes else if (uap->flag & NFSSVC_MNTD) { 2163305Sphk error = copyin(uap->argp, (caddr_t)&ncd, sizeof (ncd)); 2173305Sphk if (error) 2181541Srgrimes return (error); 2191541Srgrimes NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 2201541Srgrimes ncd.ncd_dirp, p); 2213305Sphk error = namei(&nd); 2223305Sphk if (error) 2231541Srgrimes return (error); 2241541Srgrimes if ((nd.ni_vp->v_flag & VROOT) == 0) 2251541Srgrimes error = EINVAL; 2261541Srgrimes nmp = VFSTONFS(nd.ni_vp->v_mount); 2271541Srgrimes vput(nd.ni_vp); 2281541Srgrimes if (error) 2291541Srgrimes return (error); 23036176Speter if ((nmp->nm_state & NFSSTA_MNTD) && 2311541Srgrimes (uap->flag & NFSSVC_GOTAUTH) == 0) 2321541Srgrimes return (0); 23336176Speter nmp->nm_state |= NFSSTA_MNTD; 2341541Srgrimes error = nqnfs_clientd(nmp, p->p_ucred, &ncd, uap->flag, 2351541Srgrimes uap->argp, p); 2361541Srgrimes } else if (uap->flag & NFSSVC_ADDSOCK) { 2373305Sphk error = copyin(uap->argp, (caddr_t)&nfsdarg, sizeof(nfsdarg)); 2383305Sphk if (error) 2391541Srgrimes return (error); 2403305Sphk error = getsock(p->p_fd, nfsdarg.sock, &fp); 2413305Sphk if (error) 2421541Srgrimes return (error); 2431541Srgrimes /* 2441541Srgrimes * Get the client address for connected sockets. 2451541Srgrimes */ 2461541Srgrimes if (nfsdarg.name == NULL || nfsdarg.namelen == 0) 24728270Swollman nam = (struct sockaddr *)0; 2483305Sphk else { 24928270Swollman error = getsockaddr(&nam, nfsdarg.name, 25028270Swollman nfsdarg.namelen); 2513305Sphk if (error) 2523305Sphk return (error); 2533305Sphk } 25425201Swollman error = nfssvc_addsock(fp, nam, p); 2551541Srgrimes } else { 2563305Sphk error = copyin(uap->argp, (caddr_t)nsd, sizeof (*nsd)); 2573305Sphk if (error) 2581541Srgrimes return (error); 25936503Speter if ((uap->flag & NFSSVC_AUTHIN) && 26036503Speter ((nfsd = nsd->nsd_nfsd)) != NULL && 26136503Speter (nfsd->nfsd_slp->ns_flag & SLP_VALID)) { 2629336Sdfr slp = nfsd->nfsd_slp; 2631541Srgrimes 2641541Srgrimes /* 2651541Srgrimes * First check to see if another nfsd has already 2661541Srgrimes * added this credential. 2671541Srgrimes */ 2689336Sdfr for (nuidp = NUIDHASH(slp,nsd->nsd_cr.cr_uid)->lh_first; 2693664Sphk nuidp != 0; nuidp = nuidp->nu_hash.le_next) { 2709336Sdfr if (nuidp->nu_cr.cr_uid == nsd->nsd_cr.cr_uid && 2719336Sdfr (!nfsd->nfsd_nd->nd_nam2 || 2729336Sdfr netaddr_match(NU_NETFAM(nuidp), 2739336Sdfr &nuidp->nu_haddr, nfsd->nfsd_nd->nd_nam2))) 2741541Srgrimes break; 2751541Srgrimes } 2769336Sdfr if (nuidp) { 2779336Sdfr nfsrv_setcred(&nuidp->nu_cr,&nfsd->nfsd_nd->nd_cr); 2789336Sdfr nfsd->nfsd_nd->nd_flag |= ND_KERBFULL; 2799336Sdfr } else { 2801541Srgrimes /* 2811541Srgrimes * Nope, so we will. 2821541Srgrimes */ 2831541Srgrimes if (slp->ns_numuids < nuidhash_max) { 2841541Srgrimes slp->ns_numuids++; 2851541Srgrimes nuidp = (struct nfsuid *) 2861541Srgrimes malloc(sizeof (struct nfsuid), M_NFSUID, 2871541Srgrimes M_WAITOK); 2881541Srgrimes } else 2891541Srgrimes nuidp = (struct nfsuid *)0; 2901541Srgrimes if ((slp->ns_flag & SLP_VALID) == 0) { 2911541Srgrimes if (nuidp) 2921541Srgrimes free((caddr_t)nuidp, M_NFSUID); 2931541Srgrimes } else { 2941541Srgrimes if (nuidp == (struct nfsuid *)0) { 2953664Sphk nuidp = slp->ns_uidlruhead.tqh_first; 2963664Sphk LIST_REMOVE(nuidp, nu_hash); 2973664Sphk TAILQ_REMOVE(&slp->ns_uidlruhead, nuidp, 2983664Sphk nu_lru); 2999336Sdfr if (nuidp->nu_flag & NU_NAM) 30028270Swollman FREE(nuidp->nu_nam, M_SONAME); 3011541Srgrimes } 3029336Sdfr nuidp->nu_flag = 0; 3031541Srgrimes nuidp->nu_cr = nsd->nsd_cr; 3041541Srgrimes if (nuidp->nu_cr.cr_ngroups > NGROUPS) 3059336Sdfr nuidp->nu_cr.cr_ngroups = NGROUPS; 3061541Srgrimes nuidp->nu_cr.cr_ref = 1; 3079336Sdfr nuidp->nu_timestamp = nsd->nsd_timestamp; 30834961Sphk nuidp->nu_expire = time_second + nsd->nsd_ttl; 3099336Sdfr /* 3109336Sdfr * and save the session key in nu_key. 3119336Sdfr */ 3129336Sdfr bcopy(nsd->nsd_key, nuidp->nu_key, 3139336Sdfr sizeof (nsd->nsd_key)); 3149336Sdfr if (nfsd->nfsd_nd->nd_nam2) { 3159336Sdfr struct sockaddr_in *saddr; 3169336Sdfr 31728270Swollman saddr = (struct sockaddr_in *) 31828270Swollman nfsd->nfsd_nd->nd_nam2; 3199336Sdfr switch (saddr->sin_family) { 3209336Sdfr case AF_INET: 3219336Sdfr nuidp->nu_flag |= NU_INETADDR; 3229336Sdfr nuidp->nu_inetaddr = 3239336Sdfr saddr->sin_addr.s_addr; 3249336Sdfr break; 3259336Sdfr case AF_ISO: 3269336Sdfr default: 3279336Sdfr nuidp->nu_flag |= NU_NAM; 32828270Swollman nuidp->nu_nam = 32928270Swollman dup_sockaddr(nfsd->nfsd_nd-> 33028270Swollman nd_nam2, 1); 3319336Sdfr break; 3329336Sdfr }; 3339336Sdfr } 3343664Sphk TAILQ_INSERT_TAIL(&slp->ns_uidlruhead, nuidp, 3353664Sphk nu_lru); 3363664Sphk LIST_INSERT_HEAD(NUIDHASH(slp, nsd->nsd_uid), 3373664Sphk nuidp, nu_hash); 3389336Sdfr nfsrv_setcred(&nuidp->nu_cr, 3399336Sdfr &nfsd->nfsd_nd->nd_cr); 3409336Sdfr nfsd->nfsd_nd->nd_flag |= ND_KERBFULL; 3411541Srgrimes } 3421541Srgrimes } 3431541Srgrimes } 3441541Srgrimes if ((uap->flag & NFSSVC_AUTHINFAIL) && (nfsd = nsd->nsd_nfsd)) 3459336Sdfr nfsd->nfsd_flag |= NFSD_AUTHFAIL; 3461541Srgrimes error = nfssvc_nfsd(nsd, uap->argp, p); 3471541Srgrimes } 34813416Sphk#endif /* NFS_NOSERVER */ 3491541Srgrimes if (error == EINTR || error == ERESTART) 3501541Srgrimes error = 0; 3511541Srgrimes return (error); 3521541Srgrimes} 3531541Srgrimes 35413416Sphk#ifndef NFS_NOSERVER 3551541Srgrimes/* 3561541Srgrimes * Adds a socket to the list for servicing by nfsds. 3571541Srgrimes */ 35812911Sphkstatic int 35925201Swollmannfssvc_addsock(fp, mynam, p) 3601541Srgrimes struct file *fp; 36128270Swollman struct sockaddr *mynam; 36225201Swollman struct proc *p; 3631541Srgrimes{ 3641541Srgrimes register int siz; 3651541Srgrimes register struct nfssvc_sock *slp; 3661541Srgrimes register struct socket *so; 3671541Srgrimes struct nfssvc_sock *tslp; 3681541Srgrimes int error, s; 3691541Srgrimes 3701541Srgrimes so = (struct socket *)fp->f_data; 3711541Srgrimes tslp = (struct nfssvc_sock *)0; 3721541Srgrimes /* 3731541Srgrimes * Add it to the list, as required. 3741541Srgrimes */ 3751541Srgrimes if (so->so_proto->pr_protocol == IPPROTO_UDP) { 3761541Srgrimes tslp = nfs_udpsock; 3771541Srgrimes if (tslp->ns_flag & SLP_VALID) { 37828270Swollman FREE(mynam, M_SONAME); 3791541Srgrimes return (EPERM); 3801541Srgrimes } 3811541Srgrimes#ifdef ISO 3821541Srgrimes } else if (so->so_proto->pr_protocol == ISOPROTO_CLTP) { 3831541Srgrimes tslp = nfs_cltpsock; 3841541Srgrimes if (tslp->ns_flag & SLP_VALID) { 38528270Swollman FREE(mynam, M_SONAME); 3861541Srgrimes return (EPERM); 3871541Srgrimes } 3881541Srgrimes#endif /* ISO */ 3891541Srgrimes } 3901541Srgrimes if (so->so_type == SOCK_STREAM) 3911541Srgrimes siz = NFS_MAXPACKET + sizeof (u_long); 3921541Srgrimes else 3931541Srgrimes siz = NFS_MAXPACKET; 3948876Srgrimes error = soreserve(so, siz, siz); 3953305Sphk if (error) { 39628270Swollman FREE(mynam, M_SONAME); 3971541Srgrimes return (error); 3981541Srgrimes } 3991541Srgrimes 4001541Srgrimes /* 4011541Srgrimes * Set protocol specific options { for now TCP only } and 4021541Srgrimes * reserve some space. For datagram sockets, this can get called 4031541Srgrimes * repeatedly for the same socket, but that isn't harmful. 4041541Srgrimes */ 4051541Srgrimes if (so->so_type == SOCK_STREAM) { 40638482Swollman struct sockopt sopt; 40738482Swollman int val; 40838482Swollman 40938482Swollman bzero(&sopt, sizeof sopt); 41038482Swollman sopt.sopt_level = SOL_SOCKET; 41138482Swollman sopt.sopt_name = SO_KEEPALIVE; 41238482Swollman sopt.sopt_val = &val; 41338482Swollman sopt.sopt_valsize = sizeof val; 41438482Swollman val = 1; 41538482Swollman sosetopt(so, &sopt); 4161541Srgrimes } 4171541Srgrimes if (so->so_proto->pr_domain->dom_family == AF_INET && 4181541Srgrimes so->so_proto->pr_protocol == IPPROTO_TCP) { 41938482Swollman struct sockopt sopt; 42038482Swollman int val; 42138482Swollman 42238482Swollman bzero(&sopt, sizeof sopt); 42338482Swollman sopt.sopt_level = IPPROTO_TCP; 42438482Swollman sopt.sopt_name = TCP_NODELAY; 42538482Swollman sopt.sopt_val = &val; 42638482Swollman sopt.sopt_valsize = sizeof val; 42738482Swollman val = 1; 42838482Swollman sosetopt(so, &sopt); 4291541Srgrimes } 4301541Srgrimes so->so_rcv.sb_flags &= ~SB_NOINTR; 4311541Srgrimes so->so_rcv.sb_timeo = 0; 4321541Srgrimes so->so_snd.sb_flags &= ~SB_NOINTR; 4331541Srgrimes so->so_snd.sb_timeo = 0; 4341541Srgrimes if (tslp) 4351541Srgrimes slp = tslp; 4361541Srgrimes else { 4371541Srgrimes slp = (struct nfssvc_sock *) 4381541Srgrimes malloc(sizeof (struct nfssvc_sock), M_NFSSVC, M_WAITOK); 4391541Srgrimes bzero((caddr_t)slp, sizeof (struct nfssvc_sock)); 44025781Sdfr STAILQ_INIT(&slp->ns_rec); 4413664Sphk TAILQ_INIT(&slp->ns_uidlruhead); 4423664Sphk TAILQ_INSERT_TAIL(&nfssvc_sockhead, slp, ns_chain); 4431541Srgrimes } 4441541Srgrimes slp->ns_so = so; 4451541Srgrimes slp->ns_nam = mynam; 4461541Srgrimes fp->f_count++; 4471541Srgrimes slp->ns_fp = fp; 4481541Srgrimes s = splnet(); 4491541Srgrimes so->so_upcallarg = (caddr_t)slp; 4501541Srgrimes so->so_upcall = nfsrv_rcv; 45136530Speter so->so_rcv.sb_flags |= SB_UPCALL; 4521541Srgrimes slp->ns_flag = (SLP_VALID | SLP_NEEDQ); 4531541Srgrimes nfsrv_wakenfsd(slp); 4541541Srgrimes splx(s); 4551541Srgrimes return (0); 4561541Srgrimes} 4571541Srgrimes 4581541Srgrimes/* 4591541Srgrimes * Called by nfssvc() for nfsds. Just loops around servicing rpc requests 4601541Srgrimes * until it is killed by a signal. 4611541Srgrimes */ 46212911Sphkstatic int 4631541Srgrimesnfssvc_nfsd(nsd, argp, p) 4641541Srgrimes struct nfsd_srvargs *nsd; 4651541Srgrimes caddr_t argp; 4661541Srgrimes struct proc *p; 4671541Srgrimes{ 4689336Sdfr register struct mbuf *m; 4691541Srgrimes register int siz; 4701541Srgrimes register struct nfssvc_sock *slp; 4719336Sdfr struct nfsd *nfsd = nsd->nsd_nfsd; 4729336Sdfr struct nfsrv_descript *nd = NULL; 4739336Sdfr struct mbuf *mreq; 4749336Sdfr int error = 0, cacherep, s, sotype, writes_todo; 47525664Sdfr int procrastinate; 4769336Sdfr u_quad_t cur_usec; 4771541Srgrimes 4789336Sdfr#ifndef nolint 4799336Sdfr cacherep = RC_DOIT; 4809336Sdfr writes_todo = 0; 4819336Sdfr#endif 4829336Sdfr if (nfsd == (struct nfsd *)0) { 48336503Speter nsd->nsd_nfsd = nfsd = (struct nfsd *) 4841541Srgrimes malloc(sizeof (struct nfsd), M_NFSD, M_WAITOK); 4859336Sdfr bzero((caddr_t)nfsd, sizeof (struct nfsd)); 48631391Sbde s = splnet(); 4879336Sdfr nfsd->nfsd_procp = p; 4889336Sdfr TAILQ_INSERT_TAIL(&nfsd_head, nfsd, nfsd_chain); 4891541Srgrimes nfs_numnfsd++; 49031391Sbde } else 49131391Sbde s = splnet(); 49231391Sbde 4931541Srgrimes /* 4941541Srgrimes * Loop getting rpc requests until SIGKILL. 4951541Srgrimes */ 4961541Srgrimes for (;;) { 4979336Sdfr if ((nfsd->nfsd_flag & NFSD_REQINPROG) == 0) { 4989336Sdfr while (nfsd->nfsd_slp == (struct nfssvc_sock *)0 && 4993664Sphk (nfsd_head_flag & NFSD_CHECKSLP) == 0) { 5009336Sdfr nfsd->nfsd_flag |= NFSD_WAITING; 5011541Srgrimes nfsd_waiting++; 5029336Sdfr error = tsleep((caddr_t)nfsd, PSOCK | PCATCH, 5039336Sdfr "nfsd", 0); 5041541Srgrimes nfsd_waiting--; 5051541Srgrimes if (error) 5061541Srgrimes goto done; 5071541Srgrimes } 5089336Sdfr if (nfsd->nfsd_slp == (struct nfssvc_sock *)0 && 5093664Sphk (nfsd_head_flag & NFSD_CHECKSLP) != 0) { 5103664Sphk for (slp = nfssvc_sockhead.tqh_first; slp != 0; 5113664Sphk slp = slp->ns_chain.tqe_next) { 5121541Srgrimes if ((slp->ns_flag & (SLP_VALID | SLP_DOREC)) 5131541Srgrimes == (SLP_VALID | SLP_DOREC)) { 5141541Srgrimes slp->ns_flag &= ~SLP_DOREC; 5151541Srgrimes slp->ns_sref++; 5169336Sdfr nfsd->nfsd_slp = slp; 5171541Srgrimes break; 5181541Srgrimes } 5191541Srgrimes } 5203664Sphk if (slp == 0) 5213664Sphk nfsd_head_flag &= ~NFSD_CHECKSLP; 5221541Srgrimes } 5239336Sdfr if ((slp = nfsd->nfsd_slp) == (struct nfssvc_sock *)0) 5241541Srgrimes continue; 5251541Srgrimes if (slp->ns_flag & SLP_VALID) { 5261541Srgrimes if (slp->ns_flag & SLP_DISCONN) 5271541Srgrimes nfsrv_zapsock(slp); 5281541Srgrimes else if (slp->ns_flag & SLP_NEEDQ) { 5291541Srgrimes slp->ns_flag &= ~SLP_NEEDQ; 53044246Speter (void) nfs_slplock(slp, 1); 5311541Srgrimes nfsrv_rcv(slp->ns_so, (caddr_t)slp, 5321541Srgrimes M_WAIT); 53344246Speter nfs_slpunlock(slp); 5341541Srgrimes } 5359336Sdfr error = nfsrv_dorec(slp, nfsd, &nd); 53634961Sphk cur_usec = nfs_curusec(); 5379336Sdfr if (error && slp->ns_tq.lh_first && 5389336Sdfr slp->ns_tq.lh_first->nd_time <= cur_usec) { 5399336Sdfr error = 0; 5409336Sdfr cacherep = RC_DOIT; 5419336Sdfr writes_todo = 1; 5429336Sdfr } else 5439336Sdfr writes_todo = 0; 5449336Sdfr nfsd->nfsd_flag |= NFSD_REQINPROG; 5451541Srgrimes } 5461541Srgrimes } else { 5471541Srgrimes error = 0; 5489336Sdfr slp = nfsd->nfsd_slp; 5491541Srgrimes } 5501541Srgrimes if (error || (slp->ns_flag & SLP_VALID) == 0) { 5519336Sdfr if (nd) { 5529336Sdfr free((caddr_t)nd, M_NFSRVDESC); 5539336Sdfr nd = NULL; 5549336Sdfr } 5559336Sdfr nfsd->nfsd_slp = (struct nfssvc_sock *)0; 5569336Sdfr nfsd->nfsd_flag &= ~NFSD_REQINPROG; 5571541Srgrimes nfsrv_slpderef(slp); 5581541Srgrimes continue; 5591541Srgrimes } 5601541Srgrimes splx(s); 56144246Speter sotype = slp->ns_so->so_type; 5629336Sdfr if (nd) { 56334961Sphk getmicrotime(&nd->nd_starttime); 5649336Sdfr if (nd->nd_nam2) 5659336Sdfr nd->nd_nam = nd->nd_nam2; 5669336Sdfr else 5679336Sdfr nd->nd_nam = slp->ns_nam; 5681541Srgrimes 5699336Sdfr /* 5709336Sdfr * Check to see if authorization is needed. 5719336Sdfr */ 5729336Sdfr if (nfsd->nfsd_flag & NFSD_NEEDAUTH) { 5739336Sdfr nfsd->nfsd_flag &= ~NFSD_NEEDAUTH; 57428270Swollman nsd->nsd_haddr = 57528270Swollman ((struct sockaddr_in *) 57628270Swollman nd->nd_nam)->sin_addr.s_addr; 5779336Sdfr nsd->nsd_authlen = nfsd->nfsd_authlen; 5789336Sdfr nsd->nsd_verflen = nfsd->nfsd_verflen; 5799336Sdfr if (!copyout(nfsd->nfsd_authstr,nsd->nsd_authstr, 5809336Sdfr nfsd->nfsd_authlen) && 5819336Sdfr !copyout(nfsd->nfsd_verfstr, nsd->nsd_verfstr, 5829336Sdfr nfsd->nfsd_verflen) && 5839336Sdfr !copyout((caddr_t)nsd, argp, sizeof (*nsd))) 5849336Sdfr return (ENEEDAUTH); 5859336Sdfr cacherep = RC_DROPIT; 5869336Sdfr } else 5879336Sdfr cacherep = nfsrv_getcache(nd, slp, &mreq); 5881541Srgrimes 5899336Sdfr /* 5909336Sdfr * Check for just starting up for NQNFS and send 5919336Sdfr * fake "try again later" replies to the NQNFS clients. 5929336Sdfr */ 59334961Sphk if (notstarted && nqnfsstarttime <= time_second) { 5941541Srgrimes if (modify_flag) { 59534961Sphk nqnfsstarttime = time_second + nqsrv_writeslack; 5961541Srgrimes modify_flag = 0; 5971541Srgrimes } else 5981541Srgrimes notstarted = 0; 5999336Sdfr } 6009336Sdfr if (notstarted) { 6019336Sdfr if ((nd->nd_flag & ND_NQNFS) == 0) 6021541Srgrimes cacherep = RC_DROPIT; 6031541Srgrimes else if (nd->nd_procnum != NFSPROC_WRITE) { 6041541Srgrimes nd->nd_procnum = NFSPROC_NOOP; 6051541Srgrimes nd->nd_repstat = NQNFS_TRYLATER; 6061541Srgrimes cacherep = RC_DOIT; 6071541Srgrimes } else 6081541Srgrimes modify_flag = 1; 6099336Sdfr } else if (nfsd->nfsd_flag & NFSD_AUTHFAIL) { 6109336Sdfr nfsd->nfsd_flag &= ~NFSD_AUTHFAIL; 6111541Srgrimes nd->nd_procnum = NFSPROC_NOOP; 6129336Sdfr nd->nd_repstat = (NFSERR_AUTHERR | AUTH_TOOWEAK); 6131541Srgrimes cacherep = RC_DOIT; 61424330Sguido } else if (nfs_privport) { 61524330Sguido /* Check if source port is privileged */ 61624330Sguido u_short port; 61728270Swollman struct sockaddr *nam = nd->nd_nam; 61824330Sguido struct sockaddr_in *sin; 61924330Sguido 62028270Swollman sin = (struct sockaddr_in *)nam; 62124330Sguido port = ntohs(sin->sin_port); 62225307Sdfr if (port >= IPPORT_RESERVED && 62325307Sdfr nd->nd_procnum != NFSPROC_NULL) { 62424330Sguido nd->nd_procnum = NFSPROC_NOOP; 62524330Sguido nd->nd_repstat = (NFSERR_AUTHERR | AUTH_TOOWEAK); 62624330Sguido cacherep = RC_DOIT; 62724330Sguido printf("NFS request from unprivileged port (%s:%d)\n", 62824330Sguido inet_ntoa(sin->sin_addr), port); 62924330Sguido } 6309336Sdfr } 63124330Sguido 6321541Srgrimes } 6331541Srgrimes 6349336Sdfr /* 6359336Sdfr * Loop to get all the write rpc relies that have been 6369336Sdfr * gathered together. 6379336Sdfr */ 6389336Sdfr do { 6399336Sdfr switch (cacherep) { 6409336Sdfr case RC_DOIT: 64125664Sdfr if (nd && (nd->nd_flag & ND_NFSV3)) 64225664Sdfr procrastinate = nfsrvw_procrastinate_v3; 64325664Sdfr else 64425664Sdfr procrastinate = nfsrvw_procrastinate; 6459336Sdfr if (writes_todo || (nd->nd_procnum == NFSPROC_WRITE && 64625664Sdfr procrastinate > 0 && !notstarted)) 6479336Sdfr error = nfsrv_writegather(&nd, slp, 6489336Sdfr nfsd->nfsd_procp, &mreq); 6499336Sdfr else 6509336Sdfr error = (*(nfsrv3_procs[nd->nd_procnum]))(nd, 6519336Sdfr slp, nfsd->nfsd_procp, &mreq); 6529336Sdfr if (mreq == NULL) 6539336Sdfr break; 6541541Srgrimes if (error) { 6551541Srgrimes if (nd->nd_procnum != NQNFSPROC_VACATED) 6561541Srgrimes nfsstats.srv_errs++; 6579336Sdfr nfsrv_updatecache(nd, FALSE, mreq); 6589336Sdfr if (nd->nd_nam2) 65928270Swollman FREE(nd->nd_nam2, M_SONAME); 6601541Srgrimes break; 6611541Srgrimes } 6621541Srgrimes nfsstats.srvrpccnt[nd->nd_procnum]++; 6639336Sdfr nfsrv_updatecache(nd, TRUE, mreq); 6641541Srgrimes nd->nd_mrep = (struct mbuf *)0; 6659336Sdfr case RC_REPLY: 6661541Srgrimes m = mreq; 6671541Srgrimes siz = 0; 6681541Srgrimes while (m) { 6691541Srgrimes siz += m->m_len; 6701541Srgrimes m = m->m_next; 6711541Srgrimes } 6721541Srgrimes if (siz <= 0 || siz > NFS_MAXPACKET) { 6731541Srgrimes printf("mbuf siz=%d\n",siz); 6741541Srgrimes panic("Bad nfs svc reply"); 6751541Srgrimes } 6761541Srgrimes m = mreq; 6771541Srgrimes m->m_pkthdr.len = siz; 6781541Srgrimes m->m_pkthdr.rcvif = (struct ifnet *)0; 6791541Srgrimes /* 6801541Srgrimes * For stream protocols, prepend a Sun RPC 6811541Srgrimes * Record Mark. 6821541Srgrimes */ 6831541Srgrimes if (sotype == SOCK_STREAM) { 6841541Srgrimes M_PREPEND(m, NFSX_UNSIGNED, M_WAIT); 68536541Speter *mtod(m, u_int32_t *) = htonl(0x80000000 | siz); 6861541Srgrimes } 68744246Speter if (slp->ns_so->so_proto->pr_flags & PR_CONNREQUIRED) 68844246Speter (void) nfs_slplock(slp, 1); 6891541Srgrimes if (slp->ns_flag & SLP_VALID) 69044246Speter error = nfs_send(slp->ns_so, nd->nd_nam2, m, NULL); 6911541Srgrimes else { 6921541Srgrimes error = EPIPE; 6931541Srgrimes m_freem(m); 6941541Srgrimes } 6951541Srgrimes if (nfsrtton) 6969336Sdfr nfsd_rt(sotype, nd, cacherep); 6979336Sdfr if (nd->nd_nam2) 69828270Swollman FREE(nd->nd_nam2, M_SONAME); 6991541Srgrimes if (nd->nd_mrep) 7001541Srgrimes m_freem(nd->nd_mrep); 7011541Srgrimes if (error == EPIPE) 7021541Srgrimes nfsrv_zapsock(slp); 70344246Speter if (slp->ns_so->so_proto->pr_flags & PR_CONNREQUIRED) 70444246Speter nfs_slpunlock(slp); 7051541Srgrimes if (error == EINTR || error == ERESTART) { 7069336Sdfr free((caddr_t)nd, M_NFSRVDESC); 7071541Srgrimes nfsrv_slpderef(slp); 7081541Srgrimes s = splnet(); 7091541Srgrimes goto done; 7101541Srgrimes } 7111541Srgrimes break; 7129336Sdfr case RC_DROPIT: 7131541Srgrimes if (nfsrtton) 7149336Sdfr nfsd_rt(sotype, nd, cacherep); 7151541Srgrimes m_freem(nd->nd_mrep); 71638718Sluoqi if (nd->nd_nam2) 71738718Sluoqi FREE(nd->nd_nam2, M_SONAME); 7181541Srgrimes break; 7199336Sdfr }; 7209336Sdfr if (nd) { 7219336Sdfr FREE((caddr_t)nd, M_NFSRVDESC); 7229336Sdfr nd = NULL; 7239336Sdfr } 7249336Sdfr 7259336Sdfr /* 7269336Sdfr * Check to see if there are outstanding writes that 7279336Sdfr * need to be serviced. 7289336Sdfr */ 72934961Sphk cur_usec = nfs_curusec(); 7309336Sdfr s = splsoftclock(); 7319336Sdfr if (slp->ns_tq.lh_first && 7329336Sdfr slp->ns_tq.lh_first->nd_time <= cur_usec) { 7339336Sdfr cacherep = RC_DOIT; 7349336Sdfr writes_todo = 1; 7359336Sdfr } else 7369336Sdfr writes_todo = 0; 7379336Sdfr splx(s); 7389336Sdfr } while (writes_todo); 7391541Srgrimes s = splnet(); 7409336Sdfr if (nfsrv_dorec(slp, nfsd, &nd)) { 7419336Sdfr nfsd->nfsd_flag &= ~NFSD_REQINPROG; 7429336Sdfr nfsd->nfsd_slp = NULL; 7431541Srgrimes nfsrv_slpderef(slp); 7441541Srgrimes } 7451541Srgrimes } 7461541Srgrimesdone: 7479336Sdfr TAILQ_REMOVE(&nfsd_head, nfsd, nfsd_chain); 7481541Srgrimes splx(s); 7499336Sdfr free((caddr_t)nfsd, M_NFSD); 7501541Srgrimes nsd->nsd_nfsd = (struct nfsd *)0; 7511541Srgrimes if (--nfs_numnfsd == 0) 7521541Srgrimes nfsrv_init(TRUE); /* Reinitialize everything */ 7531541Srgrimes return (error); 7541541Srgrimes} 75536503Speter 75636503Speter/* 75736503Speter * Shut down a socket associated with an nfssvc_sock structure. 75836503Speter * Should be called with the send lock set, if required. 75936503Speter * The trick here is to increment the sref at the start, so that the nfsds 76036503Speter * will stop using it and clear ns_flag at the end so that it will not be 76136503Speter * reassigned during cleanup. 76236503Speter */ 76336503Speterstatic void 76436503Speternfsrv_zapsock(slp) 76536503Speter register struct nfssvc_sock *slp; 76636503Speter{ 76736503Speter register struct nfsuid *nuidp, *nnuidp; 76836503Speter register struct nfsrv_descript *nwp, *nnwp; 76936503Speter struct socket *so; 77036503Speter struct file *fp; 77136503Speter struct nfsrv_rec *rec; 77236503Speter int s; 77336503Speter 77436503Speter slp->ns_flag &= ~SLP_ALLFLAGS; 77536503Speter fp = slp->ns_fp; 77636503Speter if (fp) { 77736503Speter slp->ns_fp = (struct file *)0; 77836503Speter so = slp->ns_so; 77936530Speter so->so_rcv.sb_flags &= ~SB_UPCALL; 78036503Speter so->so_upcall = NULL; 78136530Speter so->so_upcallarg = NULL; 78236503Speter soshutdown(so, 2); 78336503Speter closef(fp, (struct proc *)0); 78436503Speter if (slp->ns_nam) 78536503Speter FREE(slp->ns_nam, M_SONAME); 78636503Speter m_freem(slp->ns_raw); 78743305Sdillon while ((rec = STAILQ_FIRST(&slp->ns_rec)) != NULL) { 78836503Speter STAILQ_REMOVE_HEAD(&slp->ns_rec, nr_link); 78936503Speter if (rec->nr_address) 79036503Speter FREE(rec->nr_address, M_SONAME); 79136503Speter m_freem(rec->nr_packet); 79236503Speter free(rec, M_NFSRVDESC); 79336503Speter } 79436503Speter for (nuidp = slp->ns_uidlruhead.tqh_first; nuidp != 0; 79536503Speter nuidp = nnuidp) { 79636503Speter nnuidp = nuidp->nu_lru.tqe_next; 79736503Speter LIST_REMOVE(nuidp, nu_hash); 79836503Speter TAILQ_REMOVE(&slp->ns_uidlruhead, nuidp, nu_lru); 79936503Speter if (nuidp->nu_flag & NU_NAM) 80036503Speter FREE(nuidp->nu_nam, M_SONAME); 80136503Speter free((caddr_t)nuidp, M_NFSUID); 80236503Speter } 80336503Speter s = splsoftclock(); 80436503Speter for (nwp = slp->ns_tq.lh_first; nwp; nwp = nnwp) { 80536503Speter nnwp = nwp->nd_tq.le_next; 80636503Speter LIST_REMOVE(nwp, nd_tq); 80736503Speter free((caddr_t)nwp, M_NFSRVDESC); 80836503Speter } 80936503Speter LIST_INIT(&slp->ns_tq); 81036503Speter splx(s); 81136503Speter } 81236503Speter} 81336503Speter 81436503Speter/* 81536503Speter * Derefence a server socket structure. If it has no more references and 81636503Speter * is no longer valid, you can throw it away. 81736503Speter */ 81836503Spetervoid 81936503Speternfsrv_slpderef(slp) 82036503Speter register struct nfssvc_sock *slp; 82136503Speter{ 82236503Speter if (--(slp->ns_sref) == 0 && (slp->ns_flag & SLP_VALID) == 0) { 82336503Speter TAILQ_REMOVE(&nfssvc_sockhead, slp, ns_chain); 82436503Speter free((caddr_t)slp, M_NFSSVC); 82536503Speter } 82636503Speter} 82736503Speter 82836503Speter/* 82944246Speter * Lock a socket against others. 83044246Speter */ 83144246Speterint 83244246Speternfs_slplock(slp, wait) 83344246Speter register struct nfssvc_sock *slp; 83444246Speter int wait; 83544246Speter{ 83644246Speter int *statep = &slp->ns_solock; 83744246Speter 83844246Speter if (!wait && (*statep & NFSSTA_SNDLOCK)) 83944246Speter return(0); /* already locked, fail */ 84044246Speter while (*statep & NFSSTA_SNDLOCK) { 84144246Speter *statep |= NFSSTA_WANTSND; 84244246Speter (void) tsleep((caddr_t)statep, PZERO - 1, "nfsslplck", 0); 84344246Speter } 84444246Speter *statep |= NFSSTA_SNDLOCK; 84544246Speter return (1); 84644246Speter} 84744246Speter 84844246Speter/* 84944246Speter * Unlock the stream socket for others. 85044246Speter */ 85144246Spetervoid 85244246Speternfs_slpunlock(slp) 85344246Speter register struct nfssvc_sock *slp; 85444246Speter{ 85544246Speter int *statep = &slp->ns_solock; 85644246Speter 85744246Speter if ((*statep & NFSSTA_SNDLOCK) == 0) 85844246Speter panic("nfs slpunlock"); 85944246Speter *statep &= ~NFSSTA_SNDLOCK; 86044246Speter if (*statep & NFSSTA_WANTSND) { 86144246Speter *statep &= ~NFSSTA_WANTSND; 86244246Speter wakeup((caddr_t)statep); 86344246Speter } 86444246Speter} 86544246Speter 86644246Speter/* 86736503Speter * Initialize the data structures for the server. 86836503Speter * Handshake with any new nfsds starting up to avoid any chance of 86936503Speter * corruption. 87036503Speter */ 87136503Spetervoid 87236503Speternfsrv_init(terminating) 87336503Speter int terminating; 87436503Speter{ 87536503Speter register struct nfssvc_sock *slp, *nslp; 87636503Speter 87736503Speter if (nfssvc_sockhead_flag & SLP_INIT) 87836503Speter panic("nfsd init"); 87936503Speter nfssvc_sockhead_flag |= SLP_INIT; 88036503Speter if (terminating) { 88136503Speter for (slp = nfssvc_sockhead.tqh_first; slp != 0; slp = nslp) { 88236503Speter nslp = slp->ns_chain.tqe_next; 88336503Speter if (slp->ns_flag & SLP_VALID) 88436503Speter nfsrv_zapsock(slp); 88536503Speter TAILQ_REMOVE(&nfssvc_sockhead, slp, ns_chain); 88636503Speter free((caddr_t)slp, M_NFSSVC); 88736503Speter } 88836503Speter nfsrv_cleancache(); /* And clear out server cache */ 88936503Speter } else 89036503Speter nfs_pub.np_valid = 0; 89136503Speter 89236503Speter TAILQ_INIT(&nfssvc_sockhead); 89336503Speter nfssvc_sockhead_flag &= ~SLP_INIT; 89436503Speter if (nfssvc_sockhead_flag & SLP_WANTINIT) { 89536503Speter nfssvc_sockhead_flag &= ~SLP_WANTINIT; 89636503Speter wakeup((caddr_t)&nfssvc_sockhead); 89736503Speter } 89836503Speter 89936503Speter TAILQ_INIT(&nfsd_head); 90036503Speter nfsd_head_flag &= ~NFSD_CHECKSLP; 90136503Speter 90236503Speter nfs_udpsock = (struct nfssvc_sock *) 90336503Speter malloc(sizeof (struct nfssvc_sock), M_NFSSVC, M_WAITOK); 90436503Speter bzero((caddr_t)nfs_udpsock, sizeof (struct nfssvc_sock)); 90536503Speter STAILQ_INIT(&nfs_udpsock->ns_rec); 90636503Speter TAILQ_INIT(&nfs_udpsock->ns_uidlruhead); 90736503Speter TAILQ_INSERT_HEAD(&nfssvc_sockhead, nfs_udpsock, ns_chain); 90836503Speter 90936503Speter nfs_cltpsock = (struct nfssvc_sock *) 91036503Speter malloc(sizeof (struct nfssvc_sock), M_NFSSVC, M_WAITOK); 91136503Speter bzero((caddr_t)nfs_cltpsock, sizeof (struct nfssvc_sock)); 91236503Speter STAILQ_INIT(&nfs_cltpsock->ns_rec); 91336503Speter TAILQ_INIT(&nfs_cltpsock->ns_uidlruhead); 91436503Speter TAILQ_INSERT_TAIL(&nfssvc_sockhead, nfs_cltpsock, ns_chain); 91536503Speter} 91636503Speter 91736503Speter/* 91836503Speter * Add entries to the server monitor log. 91936503Speter */ 92036503Speterstatic void 92136503Speternfsd_rt(sotype, nd, cacherep) 92236503Speter int sotype; 92336503Speter register struct nfsrv_descript *nd; 92436503Speter int cacherep; 92536503Speter{ 92636503Speter register struct drt *rt; 92736503Speter 92836503Speter rt = &nfsdrt.drt[nfsdrt.pos]; 92936503Speter if (cacherep == RC_DOIT) 93036503Speter rt->flag = 0; 93136503Speter else if (cacherep == RC_REPLY) 93236503Speter rt->flag = DRT_CACHEREPLY; 93336503Speter else 93436503Speter rt->flag = DRT_CACHEDROP; 93536503Speter if (sotype == SOCK_STREAM) 93636503Speter rt->flag |= DRT_TCP; 93736503Speter if (nd->nd_flag & ND_NQNFS) 93836503Speter rt->flag |= DRT_NQNFS; 93936503Speter else if (nd->nd_flag & ND_NFSV3) 94036503Speter rt->flag |= DRT_NFSV3; 94136503Speter rt->proc = nd->nd_procnum; 94236503Speter if (nd->nd_nam->sa_family == AF_INET) 94336503Speter rt->ipadr = ((struct sockaddr_in *)nd->nd_nam)->sin_addr.s_addr; 94436503Speter else 94536503Speter rt->ipadr = INADDR_ANY; 94636503Speter rt->resptime = nfs_curusec() - (nd->nd_starttime.tv_sec * 1000000 + nd->nd_starttime.tv_usec); 94736503Speter getmicrotime(&rt->tstamp); 94836503Speter nfsdrt.pos = (nfsdrt.pos + 1) % NFSRTTLOGSIZ; 94936503Speter} 95013416Sphk#endif /* NFS_NOSERVER */ 9511541Srgrimes 95233181Seivindstatic int nfs_defect = 0; 95319449SdfrSYSCTL_INT(_vfs_nfs, OID_AUTO, defect, CTLFLAG_RW, &nfs_defect, 0, ""); 95419449Sdfr 9551541Srgrimes/* 9561541Srgrimes * Asynchronous I/O daemons for client nfs. 9571541Srgrimes * They do read-ahead and write-behind operations on the block I/O cache. 9581541Srgrimes * Never returns unless it fails or gets killed. 9591541Srgrimes */ 96012911Sphkstatic int 9611541Srgrimesnfssvc_iod(p) 9621541Srgrimes struct proc *p; 9631541Srgrimes{ 96431016Sphk register struct buf *bp; 9651541Srgrimes register int i, myiod; 96619449Sdfr struct nfsmount *nmp; 96731016Sphk int error = 0; 9681541Srgrimes 9691541Srgrimes /* 9701541Srgrimes * Assign my position or return error if too many already running 9711541Srgrimes */ 9721541Srgrimes myiod = -1; 9731541Srgrimes for (i = 0; i < NFS_MAXASYNCDAEMON; i++) 9741541Srgrimes if (nfs_asyncdaemon[i] == 0) { 9751541Srgrimes nfs_asyncdaemon[i]++; 9761541Srgrimes myiod = i; 9771541Srgrimes break; 9781541Srgrimes } 9791541Srgrimes if (myiod == -1) 9801541Srgrimes return (EBUSY); 9811541Srgrimes nfs_numasync++; 9821541Srgrimes /* 9831541Srgrimes * Just loop around doin our stuff until SIGKILL 9841541Srgrimes */ 9851541Srgrimes for (;;) { 98619449Sdfr while (((nmp = nfs_iodmount[myiod]) == NULL 98719449Sdfr || nmp->nm_bufq.tqh_first == NULL) 98819449Sdfr && error == 0) { 98919449Sdfr if (nmp) 99019449Sdfr nmp->nm_bufqiods--; 9919336Sdfr nfs_iodwant[myiod] = p; 99219449Sdfr nfs_iodmount[myiod] = NULL; 9939336Sdfr error = tsleep((caddr_t)&nfs_iodwant[myiod], 9949336Sdfr PWAIT | PCATCH, "nfsidl", 0); 9959336Sdfr } 99619449Sdfr if (error) { 99719449Sdfr nfs_asyncdaemon[myiod] = 0; 99836503Speter if (nmp) 99936503Speter nmp->nm_bufqiods--; 100026952Stegge nfs_iodwant[myiod] = NULL; 100119449Sdfr nfs_iodmount[myiod] = NULL; 100219449Sdfr nfs_numasync--; 100319449Sdfr return (error); 100419449Sdfr } 100519449Sdfr while ((bp = nmp->nm_bufq.tqh_first) != NULL) { 10069336Sdfr /* Take one off the front of the list */ 100719449Sdfr TAILQ_REMOVE(&nmp->nm_bufq, bp, b_freelist); 100819449Sdfr nmp->nm_bufqlen--; 100919449Sdfr if (nmp->nm_bufqwant && nmp->nm_bufqlen < 2 * nfs_numasync) { 101019449Sdfr nmp->nm_bufqwant = FALSE; 101119449Sdfr wakeup(&nmp->nm_bufq); 101219449Sdfr } 10139336Sdfr if (bp->b_flags & B_READ) 10149336Sdfr (void) nfs_doio(bp, bp->b_rcred, (struct proc *)0); 101519449Sdfr else 10169336Sdfr (void) nfs_doio(bp, bp->b_wcred, (struct proc *)0); 101719449Sdfr /* 101819449Sdfr * If there are more than one iod on this mount, then defect 101919449Sdfr * so that the iods can be shared out fairly between the mounts 102019449Sdfr */ 102119449Sdfr if (nfs_defect && nmp->nm_bufqiods > 1) { 102219449Sdfr NFS_DPF(ASYNCIO, 102319449Sdfr ("nfssvc_iod: iod %d defecting from mount %p\n", 102419449Sdfr myiod, nmp)); 102519449Sdfr nfs_iodmount[myiod] = NULL; 102619449Sdfr nmp->nm_bufqiods--; 102719449Sdfr break; 102819449Sdfr } 10299336Sdfr } 10301541Srgrimes } 10311541Srgrimes} 10321541Srgrimes 10331541Srgrimes 10341541Srgrimes/* 10351541Srgrimes * Get an authorization string for the uid by having the mount_nfs sitting 10361541Srgrimes * on this mount point porpous out of the kernel and do it. 10371541Srgrimes */ 10381549Srgrimesint 10399336Sdfrnfs_getauth(nmp, rep, cred, auth_str, auth_len, verf_str, verf_len, key) 10401541Srgrimes register struct nfsmount *nmp; 10411541Srgrimes struct nfsreq *rep; 10421541Srgrimes struct ucred *cred; 10431541Srgrimes char **auth_str; 10441541Srgrimes int *auth_len; 10459336Sdfr char *verf_str; 10469336Sdfr int *verf_len; 10479336Sdfr NFSKERBKEY_T key; /* return session key */ 10481541Srgrimes{ 10491541Srgrimes int error = 0; 10501541Srgrimes 105136176Speter while ((nmp->nm_state & NFSSTA_WAITAUTH) == 0) { 105236176Speter nmp->nm_state |= NFSSTA_WANTAUTH; 10531541Srgrimes (void) tsleep((caddr_t)&nmp->nm_authtype, PSOCK, 10541541Srgrimes "nfsauth1", 2 * hz); 10553305Sphk error = nfs_sigintr(nmp, rep, rep->r_procp); 10563305Sphk if (error) { 105736176Speter nmp->nm_state &= ~NFSSTA_WANTAUTH; 10581541Srgrimes return (error); 10591541Srgrimes } 10601541Srgrimes } 106136176Speter nmp->nm_state &= ~(NFSSTA_WAITAUTH | NFSSTA_WANTAUTH); 10621541Srgrimes nmp->nm_authstr = *auth_str = (char *)malloc(RPCAUTH_MAXSIZ, M_TEMP, M_WAITOK); 10639336Sdfr nmp->nm_authlen = RPCAUTH_MAXSIZ; 10649336Sdfr nmp->nm_verfstr = verf_str; 10659336Sdfr nmp->nm_verflen = *verf_len; 10661541Srgrimes nmp->nm_authuid = cred->cr_uid; 10671541Srgrimes wakeup((caddr_t)&nmp->nm_authstr); 10681541Srgrimes 10691541Srgrimes /* 10701541Srgrimes * And wait for mount_nfs to do its stuff. 10711541Srgrimes */ 107236176Speter while ((nmp->nm_state & NFSSTA_HASAUTH) == 0 && error == 0) { 10731541Srgrimes (void) tsleep((caddr_t)&nmp->nm_authlen, PSOCK, 10741541Srgrimes "nfsauth2", 2 * hz); 10751541Srgrimes error = nfs_sigintr(nmp, rep, rep->r_procp); 10761541Srgrimes } 107736176Speter if (nmp->nm_state & NFSSTA_AUTHERR) { 107836176Speter nmp->nm_state &= ~NFSSTA_AUTHERR; 10791541Srgrimes error = EAUTH; 10801541Srgrimes } 10811541Srgrimes if (error) 10821541Srgrimes free((caddr_t)*auth_str, M_TEMP); 10831541Srgrimes else { 10841541Srgrimes *auth_len = nmp->nm_authlen; 10859336Sdfr *verf_len = nmp->nm_verflen; 10869336Sdfr bcopy((caddr_t)nmp->nm_key, (caddr_t)key, sizeof (key)); 10871541Srgrimes } 108836176Speter nmp->nm_state &= ~NFSSTA_HASAUTH; 108936176Speter nmp->nm_state |= NFSSTA_WAITAUTH; 109036176Speter if (nmp->nm_state & NFSSTA_WANTAUTH) { 109136176Speter nmp->nm_state &= ~NFSSTA_WANTAUTH; 10921541Srgrimes wakeup((caddr_t)&nmp->nm_authtype); 10931541Srgrimes } 10941541Srgrimes return (error); 10951541Srgrimes} 10961541Srgrimes 10971541Srgrimes/* 10989336Sdfr * Get a nickname authenticator and verifier. 10999336Sdfr */ 11009336Sdfrint 11019336Sdfrnfs_getnickauth(nmp, cred, auth_str, auth_len, verf_str, verf_len) 11029336Sdfr struct nfsmount *nmp; 11039336Sdfr struct ucred *cred; 11049336Sdfr char **auth_str; 11059336Sdfr int *auth_len; 11069336Sdfr char *verf_str; 11079336Sdfr int verf_len; 11089336Sdfr{ 11099336Sdfr register struct nfsuid *nuidp; 111036541Speter register u_int32_t *nickp, *verfp; 11119336Sdfr struct timeval ktvin, ktvout; 11129336Sdfr 11139336Sdfr#ifdef DIAGNOSTIC 11149336Sdfr if (verf_len < (4 * NFSX_UNSIGNED)) 11159336Sdfr panic("nfs_getnickauth verf too small"); 11169336Sdfr#endif 11179336Sdfr for (nuidp = NMUIDHASH(nmp, cred->cr_uid)->lh_first; 11189336Sdfr nuidp != 0; nuidp = nuidp->nu_hash.le_next) { 11199336Sdfr if (nuidp->nu_cr.cr_uid == cred->cr_uid) 11209336Sdfr break; 11219336Sdfr } 112234961Sphk if (!nuidp || nuidp->nu_expire < time_second) 11239336Sdfr return (EACCES); 11249336Sdfr 11259336Sdfr /* 11269336Sdfr * Move to the end of the lru list (end of lru == most recently used). 11279336Sdfr */ 11289336Sdfr TAILQ_REMOVE(&nmp->nm_uidlruhead, nuidp, nu_lru); 11299336Sdfr TAILQ_INSERT_TAIL(&nmp->nm_uidlruhead, nuidp, nu_lru); 11309336Sdfr 113136541Speter nickp = (u_int32_t *)malloc(2 * NFSX_UNSIGNED, M_TEMP, M_WAITOK); 11329336Sdfr *nickp++ = txdr_unsigned(RPCAKN_NICKNAME); 11339336Sdfr *nickp = txdr_unsigned(nuidp->nu_nickname); 11349336Sdfr *auth_str = (char *)nickp; 11359336Sdfr *auth_len = 2 * NFSX_UNSIGNED; 11369336Sdfr 11379336Sdfr /* 11389336Sdfr * Now we must encrypt the verifier and package it up. 11399336Sdfr */ 114036541Speter verfp = (u_int32_t *)verf_str; 11419336Sdfr *verfp++ = txdr_unsigned(RPCAKN_NICKNAME); 114234961Sphk if (time_second > nuidp->nu_timestamp.tv_sec || 114334961Sphk (time_second == nuidp->nu_timestamp.tv_sec && 114434961Sphk time_second > nuidp->nu_timestamp.tv_usec)) 114534961Sphk getmicrotime(&nuidp->nu_timestamp); 11469336Sdfr else 11479336Sdfr nuidp->nu_timestamp.tv_usec++; 11489336Sdfr ktvin.tv_sec = txdr_unsigned(nuidp->nu_timestamp.tv_sec); 11499336Sdfr ktvin.tv_usec = txdr_unsigned(nuidp->nu_timestamp.tv_usec); 11509336Sdfr 11519336Sdfr /* 11529336Sdfr * Now encrypt the timestamp verifier in ecb mode using the session 11539336Sdfr * key. 11549336Sdfr */ 11559336Sdfr#ifdef NFSKERB 11569336Sdfr XXX 11579336Sdfr#endif 11589336Sdfr 11599336Sdfr *verfp++ = ktvout.tv_sec; 11609336Sdfr *verfp++ = ktvout.tv_usec; 11619336Sdfr *verfp = 0; 11629336Sdfr return (0); 11639336Sdfr} 11649336Sdfr 11659336Sdfr/* 11669336Sdfr * Save the current nickname in a hash list entry on the mount point. 11679336Sdfr */ 11689336Sdfrint 11699336Sdfrnfs_savenickauth(nmp, cred, len, key, mdp, dposp, mrep) 11709336Sdfr register struct nfsmount *nmp; 11719336Sdfr struct ucred *cred; 11729336Sdfr int len; 11739336Sdfr NFSKERBKEY_T key; 11749336Sdfr struct mbuf **mdp; 11759336Sdfr char **dposp; 11769336Sdfr struct mbuf *mrep; 11779336Sdfr{ 11789336Sdfr register struct nfsuid *nuidp; 117936541Speter register u_int32_t *tl; 118036541Speter register int32_t t1; 11819336Sdfr struct mbuf *md = *mdp; 11829336Sdfr struct timeval ktvin, ktvout; 118336541Speter u_int32_t nick; 11849336Sdfr char *dpos = *dposp, *cp2; 11859336Sdfr int deltasec, error = 0; 11869336Sdfr 11879336Sdfr if (len == (3 * NFSX_UNSIGNED)) { 118836541Speter nfsm_dissect(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 11899336Sdfr ktvin.tv_sec = *tl++; 11909336Sdfr ktvin.tv_usec = *tl++; 119136541Speter nick = fxdr_unsigned(u_int32_t, *tl); 11929336Sdfr 11939336Sdfr /* 11949336Sdfr * Decrypt the timestamp in ecb mode. 11959336Sdfr */ 11969336Sdfr#ifdef NFSKERB 11979336Sdfr XXX 11989336Sdfr#endif 11999336Sdfr ktvout.tv_sec = fxdr_unsigned(long, ktvout.tv_sec); 12009336Sdfr ktvout.tv_usec = fxdr_unsigned(long, ktvout.tv_usec); 120134961Sphk deltasec = time_second - ktvout.tv_sec; 12029336Sdfr if (deltasec < 0) 12039336Sdfr deltasec = -deltasec; 12049336Sdfr /* 12059336Sdfr * If ok, add it to the hash list for the mount point. 12069336Sdfr */ 12079336Sdfr if (deltasec <= NFS_KERBCLOCKSKEW) { 12089336Sdfr if (nmp->nm_numuids < nuidhash_max) { 12099336Sdfr nmp->nm_numuids++; 12109336Sdfr nuidp = (struct nfsuid *) 12119336Sdfr malloc(sizeof (struct nfsuid), M_NFSUID, 12129336Sdfr M_WAITOK); 12139336Sdfr } else { 12149336Sdfr nuidp = nmp->nm_uidlruhead.tqh_first; 12159336Sdfr LIST_REMOVE(nuidp, nu_hash); 12169336Sdfr TAILQ_REMOVE(&nmp->nm_uidlruhead, nuidp, 12179336Sdfr nu_lru); 12189336Sdfr } 12199336Sdfr nuidp->nu_flag = 0; 12209336Sdfr nuidp->nu_cr.cr_uid = cred->cr_uid; 122134961Sphk nuidp->nu_expire = time_second + NFS_KERBTTL; 12229336Sdfr nuidp->nu_timestamp = ktvout; 12239336Sdfr nuidp->nu_nickname = nick; 12249336Sdfr bcopy(key, nuidp->nu_key, sizeof (key)); 12259336Sdfr TAILQ_INSERT_TAIL(&nmp->nm_uidlruhead, nuidp, 12269336Sdfr nu_lru); 12279336Sdfr LIST_INSERT_HEAD(NMUIDHASH(nmp, cred->cr_uid), 12289336Sdfr nuidp, nu_hash); 12299336Sdfr } 12309336Sdfr } else 12319336Sdfr nfsm_adv(nfsm_rndup(len)); 12329336Sdfrnfsmout: 12339336Sdfr *mdp = md; 12349336Sdfr *dposp = dpos; 12359336Sdfr return (error); 12369336Sdfr} 1237