nfs_nfsiod.c revision 44112
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 3744112Sdfr * $Id: nfs_syscalls.c,v 1.46 1999/02/16 10:49:53 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 9212911Sphkstatic void nfsrv_zapsock __P((struct nfssvc_sock *slp)); 9313416Sphkstatic int nfssvc_iod __P((struct proc *)); 9412457Sbde 951541Srgrimes#define TRUE 1 961541Srgrimes#define FALSE 0 971541Srgrimes 981541Srgrimesstatic int nfs_asyncdaemon[NFS_MAXASYNCDAEMON]; 9912457Sbde 10044112SdfrSYSCTL_DECL(_vfs_nfs); 10144112Sdfr 10213416Sphk#ifndef NFS_NOSERVER 10313416Sphkint nfsd_waiting = 0; 10413416Sphkstatic struct nfsdrt nfsdrt; 10513416Sphkstatic int nfs_numnfsd = 0; 10613416Sphkstatic int notstarted = 1; 10713416Sphkstatic int modify_flag = 0; 10812457Sbdestatic void nfsd_rt __P((int sotype, struct nfsrv_descript *nd, 10912457Sbde int cacherep)); 11028270Swollmanstatic int nfssvc_addsock __P((struct file *, struct sockaddr *, 11125201Swollman struct proc *)); 11212911Sphkstatic int nfssvc_nfsd __P((struct nfsd_srvargs *,caddr_t,struct proc *)); 11324330Sguido 11424330Sguidostatic int nfs_privport = 0; 11524330SguidoSYSCTL_INT(_vfs_nfs, NFS_NFSPRIVPORT, nfs_privport, CTLFLAG_RW, &nfs_privport, 0, ""); 11625664SdfrSYSCTL_INT(_vfs_nfs, OID_AUTO, gatherdelay, CTLFLAG_RW, &nfsrvw_procrastinate, 0, ""); 11725664SdfrSYSCTL_INT(_vfs_nfs, OID_AUTO, gatherdelay_v3, CTLFLAG_RW, &nfsrvw_procrastinate_v3, 0, ""); 11824330Sguido 1191541Srgrimes/* 1201541Srgrimes * NFS server system calls 1211541Srgrimes * getfh() lives here too, but maybe should move to kern/vfs_syscalls.c 1221541Srgrimes */ 1231541Srgrimes 1241541Srgrimes/* 1251541Srgrimes * Get file handle system call 1261541Srgrimes */ 12712274Sbde#ifndef _SYS_SYSPROTO_H_ 1281541Srgrimesstruct getfh_args { 1291541Srgrimes char *fname; 1301541Srgrimes fhandle_t *fhp; 1311541Srgrimes}; 13212274Sbde#endif 1331549Srgrimesint 13430994Sphkgetfh(p, uap) 1351541Srgrimes struct proc *p; 1361541Srgrimes register struct getfh_args *uap; 1371541Srgrimes{ 1381541Srgrimes register struct vnode *vp; 1391541Srgrimes fhandle_t fh; 1401541Srgrimes int error; 1411541Srgrimes struct nameidata nd; 1421541Srgrimes 1431541Srgrimes /* 1441541Srgrimes * Must be super user 1451541Srgrimes */ 1463305Sphk error = suser(p->p_ucred, &p->p_acflag); 1473305Sphk if(error) 1481541Srgrimes return (error); 1491541Srgrimes NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 1503305Sphk error = namei(&nd); 1513305Sphk if (error) 1521541Srgrimes return (error); 1531541Srgrimes vp = nd.ni_vp; 1541541Srgrimes bzero((caddr_t)&fh, sizeof(fh)); 1551541Srgrimes fh.fh_fsid = vp->v_mount->mnt_stat.f_fsid; 1561541Srgrimes error = VFS_VPTOFH(vp, &fh.fh_fid); 1571541Srgrimes vput(vp); 1581541Srgrimes if (error) 1591541Srgrimes return (error); 1601541Srgrimes error = copyout((caddr_t)&fh, (caddr_t)uap->fhp, sizeof (fh)); 1611541Srgrimes return (error); 1621541Srgrimes} 1631541Srgrimes 16413416Sphk#endif /* NFS_NOSERVER */ 1651541Srgrimes/* 1661541Srgrimes * Nfs server psuedo system call for the nfsd's 1671541Srgrimes * Based on the flag value it either: 1681541Srgrimes * - adds a socket to the selection list 1691541Srgrimes * - remains in the kernel as an nfsd 1701541Srgrimes * - remains in the kernel as an nfsiod 1711541Srgrimes */ 17212274Sbde#ifndef _SYS_SYSPROTO_H_ 1731541Srgrimesstruct nfssvc_args { 1741541Srgrimes int flag; 1751541Srgrimes caddr_t argp; 1761541Srgrimes}; 17712274Sbde#endif 1781549Srgrimesint 17930994Sphknfssvc(p, uap) 1801541Srgrimes struct proc *p; 1811541Srgrimes register struct nfssvc_args *uap; 1821541Srgrimes{ 18313416Sphk#ifndef NFS_NOSERVER 1841541Srgrimes struct nameidata nd; 1851541Srgrimes struct file *fp; 18628270Swollman struct sockaddr *nam; 1871541Srgrimes struct nfsd_args nfsdarg; 1881541Srgrimes struct nfsd_srvargs nfsd_srvargs, *nsd = &nfsd_srvargs; 1891541Srgrimes struct nfsd_cargs ncd; 1901541Srgrimes struct nfsd *nfsd; 1911541Srgrimes struct nfssvc_sock *slp; 1923664Sphk struct nfsuid *nuidp; 1931541Srgrimes struct nfsmount *nmp; 19413416Sphk#endif /* NFS_NOSERVER */ 1951541Srgrimes int error; 1961541Srgrimes 1971541Srgrimes /* 1981541Srgrimes * Must be super user 1991541Srgrimes */ 2003305Sphk error = suser(p->p_ucred, &p->p_acflag); 2013305Sphk if(error) 2021541Srgrimes return (error); 2033664Sphk while (nfssvc_sockhead_flag & SLP_INIT) { 2043664Sphk nfssvc_sockhead_flag |= SLP_WANTINIT; 2051541Srgrimes (void) tsleep((caddr_t)&nfssvc_sockhead, PSOCK, "nfsd init", 0); 2061541Srgrimes } 2071541Srgrimes if (uap->flag & NFSSVC_BIOD) 2081541Srgrimes error = nfssvc_iod(p); 20913416Sphk#ifdef NFS_NOSERVER 21013416Sphk else 21113416Sphk error = ENXIO; 21213416Sphk#else /* !NFS_NOSERVER */ 2131541Srgrimes else if (uap->flag & NFSSVC_MNTD) { 2143305Sphk error = copyin(uap->argp, (caddr_t)&ncd, sizeof (ncd)); 2153305Sphk if (error) 2161541Srgrimes return (error); 2171541Srgrimes NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 2181541Srgrimes ncd.ncd_dirp, p); 2193305Sphk error = namei(&nd); 2203305Sphk if (error) 2211541Srgrimes return (error); 2221541Srgrimes if ((nd.ni_vp->v_flag & VROOT) == 0) 2231541Srgrimes error = EINVAL; 2241541Srgrimes nmp = VFSTONFS(nd.ni_vp->v_mount); 2251541Srgrimes vput(nd.ni_vp); 2261541Srgrimes if (error) 2271541Srgrimes return (error); 22836176Speter if ((nmp->nm_state & NFSSTA_MNTD) && 2291541Srgrimes (uap->flag & NFSSVC_GOTAUTH) == 0) 2301541Srgrimes return (0); 23136176Speter nmp->nm_state |= NFSSTA_MNTD; 2321541Srgrimes error = nqnfs_clientd(nmp, p->p_ucred, &ncd, uap->flag, 2331541Srgrimes uap->argp, p); 2341541Srgrimes } else if (uap->flag & NFSSVC_ADDSOCK) { 2353305Sphk error = copyin(uap->argp, (caddr_t)&nfsdarg, sizeof(nfsdarg)); 2363305Sphk if (error) 2371541Srgrimes return (error); 2383305Sphk error = getsock(p->p_fd, nfsdarg.sock, &fp); 2393305Sphk if (error) 2401541Srgrimes return (error); 2411541Srgrimes /* 2421541Srgrimes * Get the client address for connected sockets. 2431541Srgrimes */ 2441541Srgrimes if (nfsdarg.name == NULL || nfsdarg.namelen == 0) 24528270Swollman nam = (struct sockaddr *)0; 2463305Sphk else { 24728270Swollman error = getsockaddr(&nam, nfsdarg.name, 24828270Swollman nfsdarg.namelen); 2493305Sphk if (error) 2503305Sphk return (error); 2513305Sphk } 25225201Swollman error = nfssvc_addsock(fp, nam, p); 2531541Srgrimes } else { 2543305Sphk error = copyin(uap->argp, (caddr_t)nsd, sizeof (*nsd)); 2553305Sphk if (error) 2561541Srgrimes return (error); 25736503Speter if ((uap->flag & NFSSVC_AUTHIN) && 25836503Speter ((nfsd = nsd->nsd_nfsd)) != NULL && 25936503Speter (nfsd->nfsd_slp->ns_flag & SLP_VALID)) { 2609336Sdfr slp = nfsd->nfsd_slp; 2611541Srgrimes 2621541Srgrimes /* 2631541Srgrimes * First check to see if another nfsd has already 2641541Srgrimes * added this credential. 2651541Srgrimes */ 2669336Sdfr for (nuidp = NUIDHASH(slp,nsd->nsd_cr.cr_uid)->lh_first; 2673664Sphk nuidp != 0; nuidp = nuidp->nu_hash.le_next) { 2689336Sdfr if (nuidp->nu_cr.cr_uid == nsd->nsd_cr.cr_uid && 2699336Sdfr (!nfsd->nfsd_nd->nd_nam2 || 2709336Sdfr netaddr_match(NU_NETFAM(nuidp), 2719336Sdfr &nuidp->nu_haddr, nfsd->nfsd_nd->nd_nam2))) 2721541Srgrimes break; 2731541Srgrimes } 2749336Sdfr if (nuidp) { 2759336Sdfr nfsrv_setcred(&nuidp->nu_cr,&nfsd->nfsd_nd->nd_cr); 2769336Sdfr nfsd->nfsd_nd->nd_flag |= ND_KERBFULL; 2779336Sdfr } else { 2781541Srgrimes /* 2791541Srgrimes * Nope, so we will. 2801541Srgrimes */ 2811541Srgrimes if (slp->ns_numuids < nuidhash_max) { 2821541Srgrimes slp->ns_numuids++; 2831541Srgrimes nuidp = (struct nfsuid *) 2841541Srgrimes malloc(sizeof (struct nfsuid), M_NFSUID, 2851541Srgrimes M_WAITOK); 2861541Srgrimes } else 2871541Srgrimes nuidp = (struct nfsuid *)0; 2881541Srgrimes if ((slp->ns_flag & SLP_VALID) == 0) { 2891541Srgrimes if (nuidp) 2901541Srgrimes free((caddr_t)nuidp, M_NFSUID); 2911541Srgrimes } else { 2921541Srgrimes if (nuidp == (struct nfsuid *)0) { 2933664Sphk nuidp = slp->ns_uidlruhead.tqh_first; 2943664Sphk LIST_REMOVE(nuidp, nu_hash); 2953664Sphk TAILQ_REMOVE(&slp->ns_uidlruhead, nuidp, 2963664Sphk nu_lru); 2979336Sdfr if (nuidp->nu_flag & NU_NAM) 29828270Swollman FREE(nuidp->nu_nam, M_SONAME); 2991541Srgrimes } 3009336Sdfr nuidp->nu_flag = 0; 3011541Srgrimes nuidp->nu_cr = nsd->nsd_cr; 3021541Srgrimes if (nuidp->nu_cr.cr_ngroups > NGROUPS) 3039336Sdfr nuidp->nu_cr.cr_ngroups = NGROUPS; 3041541Srgrimes nuidp->nu_cr.cr_ref = 1; 3059336Sdfr nuidp->nu_timestamp = nsd->nsd_timestamp; 30634961Sphk nuidp->nu_expire = time_second + nsd->nsd_ttl; 3079336Sdfr /* 3089336Sdfr * and save the session key in nu_key. 3099336Sdfr */ 3109336Sdfr bcopy(nsd->nsd_key, nuidp->nu_key, 3119336Sdfr sizeof (nsd->nsd_key)); 3129336Sdfr if (nfsd->nfsd_nd->nd_nam2) { 3139336Sdfr struct sockaddr_in *saddr; 3149336Sdfr 31528270Swollman saddr = (struct sockaddr_in *) 31628270Swollman nfsd->nfsd_nd->nd_nam2; 3179336Sdfr switch (saddr->sin_family) { 3189336Sdfr case AF_INET: 3199336Sdfr nuidp->nu_flag |= NU_INETADDR; 3209336Sdfr nuidp->nu_inetaddr = 3219336Sdfr saddr->sin_addr.s_addr; 3229336Sdfr break; 3239336Sdfr case AF_ISO: 3249336Sdfr default: 3259336Sdfr nuidp->nu_flag |= NU_NAM; 32628270Swollman nuidp->nu_nam = 32728270Swollman dup_sockaddr(nfsd->nfsd_nd-> 32828270Swollman nd_nam2, 1); 3299336Sdfr break; 3309336Sdfr }; 3319336Sdfr } 3323664Sphk TAILQ_INSERT_TAIL(&slp->ns_uidlruhead, nuidp, 3333664Sphk nu_lru); 3343664Sphk LIST_INSERT_HEAD(NUIDHASH(slp, nsd->nsd_uid), 3353664Sphk nuidp, nu_hash); 3369336Sdfr nfsrv_setcred(&nuidp->nu_cr, 3379336Sdfr &nfsd->nfsd_nd->nd_cr); 3389336Sdfr nfsd->nfsd_nd->nd_flag |= ND_KERBFULL; 3391541Srgrimes } 3401541Srgrimes } 3411541Srgrimes } 3421541Srgrimes if ((uap->flag & NFSSVC_AUTHINFAIL) && (nfsd = nsd->nsd_nfsd)) 3439336Sdfr nfsd->nfsd_flag |= NFSD_AUTHFAIL; 3441541Srgrimes error = nfssvc_nfsd(nsd, uap->argp, p); 3451541Srgrimes } 34613416Sphk#endif /* NFS_NOSERVER */ 3471541Srgrimes if (error == EINTR || error == ERESTART) 3481541Srgrimes error = 0; 3491541Srgrimes return (error); 3501541Srgrimes} 3511541Srgrimes 35213416Sphk#ifndef NFS_NOSERVER 3531541Srgrimes/* 3541541Srgrimes * Adds a socket to the list for servicing by nfsds. 3551541Srgrimes */ 35612911Sphkstatic int 35725201Swollmannfssvc_addsock(fp, mynam, p) 3581541Srgrimes struct file *fp; 35928270Swollman struct sockaddr *mynam; 36025201Swollman struct proc *p; 3611541Srgrimes{ 3621541Srgrimes register int siz; 3631541Srgrimes register struct nfssvc_sock *slp; 3641541Srgrimes register struct socket *so; 3651541Srgrimes struct nfssvc_sock *tslp; 3661541Srgrimes int error, s; 3671541Srgrimes 3681541Srgrimes so = (struct socket *)fp->f_data; 3691541Srgrimes tslp = (struct nfssvc_sock *)0; 3701541Srgrimes /* 3711541Srgrimes * Add it to the list, as required. 3721541Srgrimes */ 3731541Srgrimes if (so->so_proto->pr_protocol == IPPROTO_UDP) { 3741541Srgrimes tslp = nfs_udpsock; 3751541Srgrimes if (tslp->ns_flag & SLP_VALID) { 37628270Swollman FREE(mynam, M_SONAME); 3771541Srgrimes return (EPERM); 3781541Srgrimes } 3791541Srgrimes#ifdef ISO 3801541Srgrimes } else if (so->so_proto->pr_protocol == ISOPROTO_CLTP) { 3811541Srgrimes tslp = nfs_cltpsock; 3821541Srgrimes if (tslp->ns_flag & SLP_VALID) { 38328270Swollman FREE(mynam, M_SONAME); 3841541Srgrimes return (EPERM); 3851541Srgrimes } 3861541Srgrimes#endif /* ISO */ 3871541Srgrimes } 3881541Srgrimes if (so->so_type == SOCK_STREAM) 3891541Srgrimes siz = NFS_MAXPACKET + sizeof (u_long); 3901541Srgrimes else 3911541Srgrimes siz = NFS_MAXPACKET; 3928876Srgrimes error = soreserve(so, siz, siz); 3933305Sphk if (error) { 39428270Swollman FREE(mynam, M_SONAME); 3951541Srgrimes return (error); 3961541Srgrimes } 3971541Srgrimes 3981541Srgrimes /* 3991541Srgrimes * Set protocol specific options { for now TCP only } and 4001541Srgrimes * reserve some space. For datagram sockets, this can get called 4011541Srgrimes * repeatedly for the same socket, but that isn't harmful. 4021541Srgrimes */ 4031541Srgrimes if (so->so_type == SOCK_STREAM) { 40438482Swollman struct sockopt sopt; 40538482Swollman int val; 40638482Swollman 40738482Swollman bzero(&sopt, sizeof sopt); 40838482Swollman sopt.sopt_level = SOL_SOCKET; 40938482Swollman sopt.sopt_name = SO_KEEPALIVE; 41038482Swollman sopt.sopt_val = &val; 41138482Swollman sopt.sopt_valsize = sizeof val; 41238482Swollman val = 1; 41338482Swollman sosetopt(so, &sopt); 4141541Srgrimes } 4151541Srgrimes if (so->so_proto->pr_domain->dom_family == AF_INET && 4161541Srgrimes so->so_proto->pr_protocol == IPPROTO_TCP) { 41738482Swollman struct sockopt sopt; 41838482Swollman int val; 41938482Swollman 42038482Swollman bzero(&sopt, sizeof sopt); 42138482Swollman sopt.sopt_level = IPPROTO_TCP; 42238482Swollman sopt.sopt_name = TCP_NODELAY; 42338482Swollman sopt.sopt_val = &val; 42438482Swollman sopt.sopt_valsize = sizeof val; 42538482Swollman val = 1; 42638482Swollman sosetopt(so, &sopt); 4271541Srgrimes } 4281541Srgrimes so->so_rcv.sb_flags &= ~SB_NOINTR; 4291541Srgrimes so->so_rcv.sb_timeo = 0; 4301541Srgrimes so->so_snd.sb_flags &= ~SB_NOINTR; 4311541Srgrimes so->so_snd.sb_timeo = 0; 4321541Srgrimes if (tslp) 4331541Srgrimes slp = tslp; 4341541Srgrimes else { 4351541Srgrimes slp = (struct nfssvc_sock *) 4361541Srgrimes malloc(sizeof (struct nfssvc_sock), M_NFSSVC, M_WAITOK); 4371541Srgrimes bzero((caddr_t)slp, sizeof (struct nfssvc_sock)); 43825781Sdfr STAILQ_INIT(&slp->ns_rec); 4393664Sphk TAILQ_INIT(&slp->ns_uidlruhead); 4403664Sphk TAILQ_INSERT_TAIL(&nfssvc_sockhead, slp, ns_chain); 4411541Srgrimes } 4421541Srgrimes slp->ns_so = so; 4431541Srgrimes slp->ns_nam = mynam; 4441541Srgrimes fp->f_count++; 4451541Srgrimes slp->ns_fp = fp; 4461541Srgrimes s = splnet(); 4471541Srgrimes so->so_upcallarg = (caddr_t)slp; 4481541Srgrimes so->so_upcall = nfsrv_rcv; 44936530Speter so->so_rcv.sb_flags |= SB_UPCALL; 4501541Srgrimes slp->ns_flag = (SLP_VALID | SLP_NEEDQ); 4511541Srgrimes nfsrv_wakenfsd(slp); 4521541Srgrimes splx(s); 4531541Srgrimes return (0); 4541541Srgrimes} 4551541Srgrimes 4561541Srgrimes/* 4571541Srgrimes * Called by nfssvc() for nfsds. Just loops around servicing rpc requests 4581541Srgrimes * until it is killed by a signal. 4591541Srgrimes */ 46012911Sphkstatic int 4611541Srgrimesnfssvc_nfsd(nsd, argp, p) 4621541Srgrimes struct nfsd_srvargs *nsd; 4631541Srgrimes caddr_t argp; 4641541Srgrimes struct proc *p; 4651541Srgrimes{ 4669336Sdfr register struct mbuf *m; 4671541Srgrimes register int siz; 4681541Srgrimes register struct nfssvc_sock *slp; 4691541Srgrimes register struct socket *so; 4701541Srgrimes register int *solockp; 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; 5301541Srgrimes (void) nfs_sndlock(&slp->ns_solock, 53136176Speter &slp->ns_solock, 5321541Srgrimes (struct nfsreq *)0); 5331541Srgrimes nfsrv_rcv(slp->ns_so, (caddr_t)slp, 5341541Srgrimes M_WAIT); 53536176Speter nfs_sndunlock(&slp->ns_solock, 53636176Speter &slp->ns_solock); 5371541Srgrimes } 5389336Sdfr error = nfsrv_dorec(slp, nfsd, &nd); 53934961Sphk cur_usec = nfs_curusec(); 5409336Sdfr if (error && slp->ns_tq.lh_first && 5419336Sdfr slp->ns_tq.lh_first->nd_time <= cur_usec) { 5429336Sdfr error = 0; 5439336Sdfr cacherep = RC_DOIT; 5449336Sdfr writes_todo = 1; 5459336Sdfr } else 5469336Sdfr writes_todo = 0; 5479336Sdfr nfsd->nfsd_flag |= NFSD_REQINPROG; 5481541Srgrimes } 5491541Srgrimes } else { 5501541Srgrimes error = 0; 5519336Sdfr slp = nfsd->nfsd_slp; 5521541Srgrimes } 5531541Srgrimes if (error || (slp->ns_flag & SLP_VALID) == 0) { 5549336Sdfr if (nd) { 5559336Sdfr free((caddr_t)nd, M_NFSRVDESC); 5569336Sdfr nd = NULL; 5579336Sdfr } 5589336Sdfr nfsd->nfsd_slp = (struct nfssvc_sock *)0; 5599336Sdfr nfsd->nfsd_flag &= ~NFSD_REQINPROG; 5601541Srgrimes nfsrv_slpderef(slp); 5611541Srgrimes continue; 5621541Srgrimes } 5631541Srgrimes splx(s); 5641541Srgrimes so = slp->ns_so; 5651541Srgrimes sotype = so->so_type; 5661541Srgrimes if (so->so_proto->pr_flags & PR_CONNREQUIRED) 5671541Srgrimes solockp = &slp->ns_solock; 5681541Srgrimes else 5691541Srgrimes solockp = (int *)0; 5709336Sdfr if (nd) { 57134961Sphk getmicrotime(&nd->nd_starttime); 5729336Sdfr if (nd->nd_nam2) 5739336Sdfr nd->nd_nam = nd->nd_nam2; 5749336Sdfr else 5759336Sdfr nd->nd_nam = slp->ns_nam; 5761541Srgrimes 5779336Sdfr /* 5789336Sdfr * Check to see if authorization is needed. 5799336Sdfr */ 5809336Sdfr if (nfsd->nfsd_flag & NFSD_NEEDAUTH) { 5819336Sdfr nfsd->nfsd_flag &= ~NFSD_NEEDAUTH; 58228270Swollman nsd->nsd_haddr = 58328270Swollman ((struct sockaddr_in *) 58428270Swollman nd->nd_nam)->sin_addr.s_addr; 5859336Sdfr nsd->nsd_authlen = nfsd->nfsd_authlen; 5869336Sdfr nsd->nsd_verflen = nfsd->nfsd_verflen; 5879336Sdfr if (!copyout(nfsd->nfsd_authstr,nsd->nsd_authstr, 5889336Sdfr nfsd->nfsd_authlen) && 5899336Sdfr !copyout(nfsd->nfsd_verfstr, nsd->nsd_verfstr, 5909336Sdfr nfsd->nfsd_verflen) && 5919336Sdfr !copyout((caddr_t)nsd, argp, sizeof (*nsd))) 5929336Sdfr return (ENEEDAUTH); 5939336Sdfr cacherep = RC_DROPIT; 5949336Sdfr } else 5959336Sdfr cacherep = nfsrv_getcache(nd, slp, &mreq); 5961541Srgrimes 5979336Sdfr /* 5989336Sdfr * Check for just starting up for NQNFS and send 5999336Sdfr * fake "try again later" replies to the NQNFS clients. 6009336Sdfr */ 60134961Sphk if (notstarted && nqnfsstarttime <= time_second) { 6021541Srgrimes if (modify_flag) { 60334961Sphk nqnfsstarttime = time_second + nqsrv_writeslack; 6041541Srgrimes modify_flag = 0; 6051541Srgrimes } else 6061541Srgrimes notstarted = 0; 6079336Sdfr } 6089336Sdfr if (notstarted) { 6099336Sdfr if ((nd->nd_flag & ND_NQNFS) == 0) 6101541Srgrimes cacherep = RC_DROPIT; 6111541Srgrimes else if (nd->nd_procnum != NFSPROC_WRITE) { 6121541Srgrimes nd->nd_procnum = NFSPROC_NOOP; 6131541Srgrimes nd->nd_repstat = NQNFS_TRYLATER; 6141541Srgrimes cacherep = RC_DOIT; 6151541Srgrimes } else 6161541Srgrimes modify_flag = 1; 6179336Sdfr } else if (nfsd->nfsd_flag & NFSD_AUTHFAIL) { 6189336Sdfr nfsd->nfsd_flag &= ~NFSD_AUTHFAIL; 6191541Srgrimes nd->nd_procnum = NFSPROC_NOOP; 6209336Sdfr nd->nd_repstat = (NFSERR_AUTHERR | AUTH_TOOWEAK); 6211541Srgrimes cacherep = RC_DOIT; 62224330Sguido } else if (nfs_privport) { 62324330Sguido /* Check if source port is privileged */ 62424330Sguido u_short port; 62528270Swollman struct sockaddr *nam = nd->nd_nam; 62624330Sguido struct sockaddr_in *sin; 62724330Sguido 62828270Swollman sin = (struct sockaddr_in *)nam; 62924330Sguido port = ntohs(sin->sin_port); 63025307Sdfr if (port >= IPPORT_RESERVED && 63125307Sdfr nd->nd_procnum != NFSPROC_NULL) { 63224330Sguido nd->nd_procnum = NFSPROC_NOOP; 63324330Sguido nd->nd_repstat = (NFSERR_AUTHERR | AUTH_TOOWEAK); 63424330Sguido cacherep = RC_DOIT; 63524330Sguido printf("NFS request from unprivileged port (%s:%d)\n", 63624330Sguido inet_ntoa(sin->sin_addr), port); 63724330Sguido } 6389336Sdfr } 63924330Sguido 6401541Srgrimes } 6411541Srgrimes 6429336Sdfr /* 6439336Sdfr * Loop to get all the write rpc relies that have been 6449336Sdfr * gathered together. 6459336Sdfr */ 6469336Sdfr do { 6479336Sdfr switch (cacherep) { 6489336Sdfr case RC_DOIT: 64925664Sdfr if (nd && (nd->nd_flag & ND_NFSV3)) 65025664Sdfr procrastinate = nfsrvw_procrastinate_v3; 65125664Sdfr else 65225664Sdfr procrastinate = nfsrvw_procrastinate; 6539336Sdfr if (writes_todo || (nd->nd_procnum == NFSPROC_WRITE && 65425664Sdfr procrastinate > 0 && !notstarted)) 6559336Sdfr error = nfsrv_writegather(&nd, slp, 6569336Sdfr nfsd->nfsd_procp, &mreq); 6579336Sdfr else 6589336Sdfr error = (*(nfsrv3_procs[nd->nd_procnum]))(nd, 6599336Sdfr slp, nfsd->nfsd_procp, &mreq); 6609336Sdfr if (mreq == NULL) 6619336Sdfr break; 6621541Srgrimes if (error) { 6631541Srgrimes if (nd->nd_procnum != NQNFSPROC_VACATED) 6641541Srgrimes nfsstats.srv_errs++; 6659336Sdfr nfsrv_updatecache(nd, FALSE, mreq); 6669336Sdfr if (nd->nd_nam2) 66728270Swollman FREE(nd->nd_nam2, M_SONAME); 6681541Srgrimes break; 6691541Srgrimes } 6701541Srgrimes nfsstats.srvrpccnt[nd->nd_procnum]++; 6719336Sdfr nfsrv_updatecache(nd, TRUE, mreq); 6721541Srgrimes nd->nd_mrep = (struct mbuf *)0; 6739336Sdfr case RC_REPLY: 6741541Srgrimes m = mreq; 6751541Srgrimes siz = 0; 6761541Srgrimes while (m) { 6771541Srgrimes siz += m->m_len; 6781541Srgrimes m = m->m_next; 6791541Srgrimes } 6801541Srgrimes if (siz <= 0 || siz > NFS_MAXPACKET) { 6811541Srgrimes printf("mbuf siz=%d\n",siz); 6821541Srgrimes panic("Bad nfs svc reply"); 6831541Srgrimes } 6841541Srgrimes m = mreq; 6851541Srgrimes m->m_pkthdr.len = siz; 6861541Srgrimes m->m_pkthdr.rcvif = (struct ifnet *)0; 6871541Srgrimes /* 6881541Srgrimes * For stream protocols, prepend a Sun RPC 6891541Srgrimes * Record Mark. 6901541Srgrimes */ 6911541Srgrimes if (sotype == SOCK_STREAM) { 6921541Srgrimes M_PREPEND(m, NFSX_UNSIGNED, M_WAIT); 69336541Speter *mtod(m, u_int32_t *) = htonl(0x80000000 | siz); 6941541Srgrimes } 6951541Srgrimes if (solockp) 69636176Speter (void) nfs_sndlock(solockp, solockp, 69736176Speter (struct nfsreq *)0); 6981541Srgrimes if (slp->ns_flag & SLP_VALID) 6999336Sdfr error = nfs_send(so, nd->nd_nam2, m, NULL); 7001541Srgrimes else { 7011541Srgrimes error = EPIPE; 7021541Srgrimes m_freem(m); 7031541Srgrimes } 7041541Srgrimes if (nfsrtton) 7059336Sdfr nfsd_rt(sotype, nd, cacherep); 7069336Sdfr if (nd->nd_nam2) 70728270Swollman FREE(nd->nd_nam2, M_SONAME); 7081541Srgrimes if (nd->nd_mrep) 7091541Srgrimes m_freem(nd->nd_mrep); 7101541Srgrimes if (error == EPIPE) 7111541Srgrimes nfsrv_zapsock(slp); 7121541Srgrimes if (solockp) 71336176Speter nfs_sndunlock(solockp, solockp); 7141541Srgrimes if (error == EINTR || error == ERESTART) { 7159336Sdfr free((caddr_t)nd, M_NFSRVDESC); 7161541Srgrimes nfsrv_slpderef(slp); 7171541Srgrimes s = splnet(); 7181541Srgrimes goto done; 7191541Srgrimes } 7201541Srgrimes break; 7219336Sdfr case RC_DROPIT: 7221541Srgrimes if (nfsrtton) 7239336Sdfr nfsd_rt(sotype, nd, cacherep); 7241541Srgrimes m_freem(nd->nd_mrep); 72538718Sluoqi if (nd->nd_nam2) 72638718Sluoqi FREE(nd->nd_nam2, M_SONAME); 7271541Srgrimes break; 7289336Sdfr }; 7299336Sdfr if (nd) { 7309336Sdfr FREE((caddr_t)nd, M_NFSRVDESC); 7319336Sdfr nd = NULL; 7329336Sdfr } 7339336Sdfr 7349336Sdfr /* 7359336Sdfr * Check to see if there are outstanding writes that 7369336Sdfr * need to be serviced. 7379336Sdfr */ 73834961Sphk cur_usec = nfs_curusec(); 7399336Sdfr s = splsoftclock(); 7409336Sdfr if (slp->ns_tq.lh_first && 7419336Sdfr slp->ns_tq.lh_first->nd_time <= cur_usec) { 7429336Sdfr cacherep = RC_DOIT; 7439336Sdfr writes_todo = 1; 7449336Sdfr } else 7459336Sdfr writes_todo = 0; 7469336Sdfr splx(s); 7479336Sdfr } while (writes_todo); 7481541Srgrimes s = splnet(); 7499336Sdfr if (nfsrv_dorec(slp, nfsd, &nd)) { 7509336Sdfr nfsd->nfsd_flag &= ~NFSD_REQINPROG; 7519336Sdfr nfsd->nfsd_slp = NULL; 7521541Srgrimes nfsrv_slpderef(slp); 7531541Srgrimes } 7541541Srgrimes } 7551541Srgrimesdone: 7569336Sdfr TAILQ_REMOVE(&nfsd_head, nfsd, nfsd_chain); 7571541Srgrimes splx(s); 7589336Sdfr free((caddr_t)nfsd, M_NFSD); 7591541Srgrimes nsd->nsd_nfsd = (struct nfsd *)0; 7601541Srgrimes if (--nfs_numnfsd == 0) 7611541Srgrimes nfsrv_init(TRUE); /* Reinitialize everything */ 7621541Srgrimes return (error); 7631541Srgrimes} 76436503Speter 76536503Speter/* 76636503Speter * Shut down a socket associated with an nfssvc_sock structure. 76736503Speter * Should be called with the send lock set, if required. 76836503Speter * The trick here is to increment the sref at the start, so that the nfsds 76936503Speter * will stop using it and clear ns_flag at the end so that it will not be 77036503Speter * reassigned during cleanup. 77136503Speter */ 77236503Speterstatic void 77336503Speternfsrv_zapsock(slp) 77436503Speter register struct nfssvc_sock *slp; 77536503Speter{ 77636503Speter register struct nfsuid *nuidp, *nnuidp; 77736503Speter register struct nfsrv_descript *nwp, *nnwp; 77836503Speter struct socket *so; 77936503Speter struct file *fp; 78036503Speter struct nfsrv_rec *rec; 78136503Speter int s; 78236503Speter 78336503Speter slp->ns_flag &= ~SLP_ALLFLAGS; 78436503Speter fp = slp->ns_fp; 78536503Speter if (fp) { 78636503Speter slp->ns_fp = (struct file *)0; 78736503Speter so = slp->ns_so; 78836530Speter so->so_rcv.sb_flags &= ~SB_UPCALL; 78936503Speter so->so_upcall = NULL; 79036530Speter so->so_upcallarg = NULL; 79136503Speter soshutdown(so, 2); 79236503Speter closef(fp, (struct proc *)0); 79336503Speter if (slp->ns_nam) 79436503Speter FREE(slp->ns_nam, M_SONAME); 79536503Speter m_freem(slp->ns_raw); 79643305Sdillon while ((rec = STAILQ_FIRST(&slp->ns_rec)) != NULL) { 79736503Speter STAILQ_REMOVE_HEAD(&slp->ns_rec, nr_link); 79836503Speter if (rec->nr_address) 79936503Speter FREE(rec->nr_address, M_SONAME); 80036503Speter m_freem(rec->nr_packet); 80136503Speter free(rec, M_NFSRVDESC); 80236503Speter } 80336503Speter for (nuidp = slp->ns_uidlruhead.tqh_first; nuidp != 0; 80436503Speter nuidp = nnuidp) { 80536503Speter nnuidp = nuidp->nu_lru.tqe_next; 80636503Speter LIST_REMOVE(nuidp, nu_hash); 80736503Speter TAILQ_REMOVE(&slp->ns_uidlruhead, nuidp, nu_lru); 80836503Speter if (nuidp->nu_flag & NU_NAM) 80936503Speter FREE(nuidp->nu_nam, M_SONAME); 81036503Speter free((caddr_t)nuidp, M_NFSUID); 81136503Speter } 81236503Speter s = splsoftclock(); 81336503Speter for (nwp = slp->ns_tq.lh_first; nwp; nwp = nnwp) { 81436503Speter nnwp = nwp->nd_tq.le_next; 81536503Speter LIST_REMOVE(nwp, nd_tq); 81636503Speter free((caddr_t)nwp, M_NFSRVDESC); 81736503Speter } 81836503Speter LIST_INIT(&slp->ns_tq); 81936503Speter splx(s); 82036503Speter } 82136503Speter} 82236503Speter 82336503Speter/* 82436503Speter * Derefence a server socket structure. If it has no more references and 82536503Speter * is no longer valid, you can throw it away. 82636503Speter */ 82736503Spetervoid 82836503Speternfsrv_slpderef(slp) 82936503Speter register struct nfssvc_sock *slp; 83036503Speter{ 83136503Speter if (--(slp->ns_sref) == 0 && (slp->ns_flag & SLP_VALID) == 0) { 83236503Speter TAILQ_REMOVE(&nfssvc_sockhead, slp, ns_chain); 83336503Speter free((caddr_t)slp, M_NFSSVC); 83436503Speter } 83536503Speter} 83636503Speter 83736503Speter/* 83836503Speter * Initialize the data structures for the server. 83936503Speter * Handshake with any new nfsds starting up to avoid any chance of 84036503Speter * corruption. 84136503Speter */ 84236503Spetervoid 84336503Speternfsrv_init(terminating) 84436503Speter int terminating; 84536503Speter{ 84636503Speter register struct nfssvc_sock *slp, *nslp; 84736503Speter 84836503Speter if (nfssvc_sockhead_flag & SLP_INIT) 84936503Speter panic("nfsd init"); 85036503Speter nfssvc_sockhead_flag |= SLP_INIT; 85136503Speter if (terminating) { 85236503Speter for (slp = nfssvc_sockhead.tqh_first; slp != 0; slp = nslp) { 85336503Speter nslp = slp->ns_chain.tqe_next; 85436503Speter if (slp->ns_flag & SLP_VALID) 85536503Speter nfsrv_zapsock(slp); 85636503Speter TAILQ_REMOVE(&nfssvc_sockhead, slp, ns_chain); 85736503Speter free((caddr_t)slp, M_NFSSVC); 85836503Speter } 85936503Speter nfsrv_cleancache(); /* And clear out server cache */ 86036503Speter } else 86136503Speter nfs_pub.np_valid = 0; 86236503Speter 86336503Speter TAILQ_INIT(&nfssvc_sockhead); 86436503Speter nfssvc_sockhead_flag &= ~SLP_INIT; 86536503Speter if (nfssvc_sockhead_flag & SLP_WANTINIT) { 86636503Speter nfssvc_sockhead_flag &= ~SLP_WANTINIT; 86736503Speter wakeup((caddr_t)&nfssvc_sockhead); 86836503Speter } 86936503Speter 87036503Speter TAILQ_INIT(&nfsd_head); 87136503Speter nfsd_head_flag &= ~NFSD_CHECKSLP; 87236503Speter 87336503Speter nfs_udpsock = (struct nfssvc_sock *) 87436503Speter malloc(sizeof (struct nfssvc_sock), M_NFSSVC, M_WAITOK); 87536503Speter bzero((caddr_t)nfs_udpsock, sizeof (struct nfssvc_sock)); 87636503Speter STAILQ_INIT(&nfs_udpsock->ns_rec); 87736503Speter TAILQ_INIT(&nfs_udpsock->ns_uidlruhead); 87836503Speter TAILQ_INSERT_HEAD(&nfssvc_sockhead, nfs_udpsock, ns_chain); 87936503Speter 88036503Speter nfs_cltpsock = (struct nfssvc_sock *) 88136503Speter malloc(sizeof (struct nfssvc_sock), M_NFSSVC, M_WAITOK); 88236503Speter bzero((caddr_t)nfs_cltpsock, sizeof (struct nfssvc_sock)); 88336503Speter STAILQ_INIT(&nfs_cltpsock->ns_rec); 88436503Speter TAILQ_INIT(&nfs_cltpsock->ns_uidlruhead); 88536503Speter TAILQ_INSERT_TAIL(&nfssvc_sockhead, nfs_cltpsock, ns_chain); 88636503Speter} 88736503Speter 88836503Speter/* 88936503Speter * Add entries to the server monitor log. 89036503Speter */ 89136503Speterstatic void 89236503Speternfsd_rt(sotype, nd, cacherep) 89336503Speter int sotype; 89436503Speter register struct nfsrv_descript *nd; 89536503Speter int cacherep; 89636503Speter{ 89736503Speter register struct drt *rt; 89836503Speter 89936503Speter rt = &nfsdrt.drt[nfsdrt.pos]; 90036503Speter if (cacherep == RC_DOIT) 90136503Speter rt->flag = 0; 90236503Speter else if (cacherep == RC_REPLY) 90336503Speter rt->flag = DRT_CACHEREPLY; 90436503Speter else 90536503Speter rt->flag = DRT_CACHEDROP; 90636503Speter if (sotype == SOCK_STREAM) 90736503Speter rt->flag |= DRT_TCP; 90836503Speter if (nd->nd_flag & ND_NQNFS) 90936503Speter rt->flag |= DRT_NQNFS; 91036503Speter else if (nd->nd_flag & ND_NFSV3) 91136503Speter rt->flag |= DRT_NFSV3; 91236503Speter rt->proc = nd->nd_procnum; 91336503Speter if (nd->nd_nam->sa_family == AF_INET) 91436503Speter rt->ipadr = ((struct sockaddr_in *)nd->nd_nam)->sin_addr.s_addr; 91536503Speter else 91636503Speter rt->ipadr = INADDR_ANY; 91736503Speter rt->resptime = nfs_curusec() - (nd->nd_starttime.tv_sec * 1000000 + nd->nd_starttime.tv_usec); 91836503Speter getmicrotime(&rt->tstamp); 91936503Speter nfsdrt.pos = (nfsdrt.pos + 1) % NFSRTTLOGSIZ; 92036503Speter} 92113416Sphk#endif /* NFS_NOSERVER */ 9221541Srgrimes 92333181Seivindstatic int nfs_defect = 0; 92419449SdfrSYSCTL_INT(_vfs_nfs, OID_AUTO, defect, CTLFLAG_RW, &nfs_defect, 0, ""); 92519449Sdfr 9261541Srgrimes/* 9271541Srgrimes * Asynchronous I/O daemons for client nfs. 9281541Srgrimes * They do read-ahead and write-behind operations on the block I/O cache. 9291541Srgrimes * Never returns unless it fails or gets killed. 9301541Srgrimes */ 93112911Sphkstatic int 9321541Srgrimesnfssvc_iod(p) 9331541Srgrimes struct proc *p; 9341541Srgrimes{ 93531016Sphk register struct buf *bp; 9361541Srgrimes register int i, myiod; 93719449Sdfr struct nfsmount *nmp; 93831016Sphk int error = 0; 9391541Srgrimes 9401541Srgrimes /* 9411541Srgrimes * Assign my position or return error if too many already running 9421541Srgrimes */ 9431541Srgrimes myiod = -1; 9441541Srgrimes for (i = 0; i < NFS_MAXASYNCDAEMON; i++) 9451541Srgrimes if (nfs_asyncdaemon[i] == 0) { 9461541Srgrimes nfs_asyncdaemon[i]++; 9471541Srgrimes myiod = i; 9481541Srgrimes break; 9491541Srgrimes } 9501541Srgrimes if (myiod == -1) 9511541Srgrimes return (EBUSY); 9521541Srgrimes nfs_numasync++; 9531541Srgrimes /* 9541541Srgrimes * Just loop around doin our stuff until SIGKILL 9551541Srgrimes */ 9561541Srgrimes for (;;) { 95719449Sdfr while (((nmp = nfs_iodmount[myiod]) == NULL 95819449Sdfr || nmp->nm_bufq.tqh_first == NULL) 95919449Sdfr && error == 0) { 96019449Sdfr if (nmp) 96119449Sdfr nmp->nm_bufqiods--; 9629336Sdfr nfs_iodwant[myiod] = p; 96319449Sdfr nfs_iodmount[myiod] = NULL; 9649336Sdfr error = tsleep((caddr_t)&nfs_iodwant[myiod], 9659336Sdfr PWAIT | PCATCH, "nfsidl", 0); 9669336Sdfr } 96719449Sdfr if (error) { 96819449Sdfr nfs_asyncdaemon[myiod] = 0; 96936503Speter if (nmp) 97036503Speter nmp->nm_bufqiods--; 97126952Stegge nfs_iodwant[myiod] = NULL; 97219449Sdfr nfs_iodmount[myiod] = NULL; 97319449Sdfr nfs_numasync--; 97419449Sdfr return (error); 97519449Sdfr } 97619449Sdfr while ((bp = nmp->nm_bufq.tqh_first) != NULL) { 9779336Sdfr /* Take one off the front of the list */ 97819449Sdfr TAILQ_REMOVE(&nmp->nm_bufq, bp, b_freelist); 97919449Sdfr nmp->nm_bufqlen--; 98019449Sdfr if (nmp->nm_bufqwant && nmp->nm_bufqlen < 2 * nfs_numasync) { 98119449Sdfr nmp->nm_bufqwant = FALSE; 98219449Sdfr wakeup(&nmp->nm_bufq); 98319449Sdfr } 9849336Sdfr if (bp->b_flags & B_READ) 9859336Sdfr (void) nfs_doio(bp, bp->b_rcred, (struct proc *)0); 98619449Sdfr else 9879336Sdfr (void) nfs_doio(bp, bp->b_wcred, (struct proc *)0); 98819449Sdfr /* 98919449Sdfr * If there are more than one iod on this mount, then defect 99019449Sdfr * so that the iods can be shared out fairly between the mounts 99119449Sdfr */ 99219449Sdfr if (nfs_defect && nmp->nm_bufqiods > 1) { 99319449Sdfr NFS_DPF(ASYNCIO, 99419449Sdfr ("nfssvc_iod: iod %d defecting from mount %p\n", 99519449Sdfr myiod, nmp)); 99619449Sdfr nfs_iodmount[myiod] = NULL; 99719449Sdfr nmp->nm_bufqiods--; 99819449Sdfr break; 99919449Sdfr } 10009336Sdfr } 10011541Srgrimes } 10021541Srgrimes} 10031541Srgrimes 10041541Srgrimes 10051541Srgrimes/* 10061541Srgrimes * Get an authorization string for the uid by having the mount_nfs sitting 10071541Srgrimes * on this mount point porpous out of the kernel and do it. 10081541Srgrimes */ 10091549Srgrimesint 10109336Sdfrnfs_getauth(nmp, rep, cred, auth_str, auth_len, verf_str, verf_len, key) 10111541Srgrimes register struct nfsmount *nmp; 10121541Srgrimes struct nfsreq *rep; 10131541Srgrimes struct ucred *cred; 10141541Srgrimes char **auth_str; 10151541Srgrimes int *auth_len; 10169336Sdfr char *verf_str; 10179336Sdfr int *verf_len; 10189336Sdfr NFSKERBKEY_T key; /* return session key */ 10191541Srgrimes{ 10201541Srgrimes int error = 0; 10211541Srgrimes 102236176Speter while ((nmp->nm_state & NFSSTA_WAITAUTH) == 0) { 102336176Speter nmp->nm_state |= NFSSTA_WANTAUTH; 10241541Srgrimes (void) tsleep((caddr_t)&nmp->nm_authtype, PSOCK, 10251541Srgrimes "nfsauth1", 2 * hz); 10263305Sphk error = nfs_sigintr(nmp, rep, rep->r_procp); 10273305Sphk if (error) { 102836176Speter nmp->nm_state &= ~NFSSTA_WANTAUTH; 10291541Srgrimes return (error); 10301541Srgrimes } 10311541Srgrimes } 103236176Speter nmp->nm_state &= ~(NFSSTA_WAITAUTH | NFSSTA_WANTAUTH); 10331541Srgrimes nmp->nm_authstr = *auth_str = (char *)malloc(RPCAUTH_MAXSIZ, M_TEMP, M_WAITOK); 10349336Sdfr nmp->nm_authlen = RPCAUTH_MAXSIZ; 10359336Sdfr nmp->nm_verfstr = verf_str; 10369336Sdfr nmp->nm_verflen = *verf_len; 10371541Srgrimes nmp->nm_authuid = cred->cr_uid; 10381541Srgrimes wakeup((caddr_t)&nmp->nm_authstr); 10391541Srgrimes 10401541Srgrimes /* 10411541Srgrimes * And wait for mount_nfs to do its stuff. 10421541Srgrimes */ 104336176Speter while ((nmp->nm_state & NFSSTA_HASAUTH) == 0 && error == 0) { 10441541Srgrimes (void) tsleep((caddr_t)&nmp->nm_authlen, PSOCK, 10451541Srgrimes "nfsauth2", 2 * hz); 10461541Srgrimes error = nfs_sigintr(nmp, rep, rep->r_procp); 10471541Srgrimes } 104836176Speter if (nmp->nm_state & NFSSTA_AUTHERR) { 104936176Speter nmp->nm_state &= ~NFSSTA_AUTHERR; 10501541Srgrimes error = EAUTH; 10511541Srgrimes } 10521541Srgrimes if (error) 10531541Srgrimes free((caddr_t)*auth_str, M_TEMP); 10541541Srgrimes else { 10551541Srgrimes *auth_len = nmp->nm_authlen; 10569336Sdfr *verf_len = nmp->nm_verflen; 10579336Sdfr bcopy((caddr_t)nmp->nm_key, (caddr_t)key, sizeof (key)); 10581541Srgrimes } 105936176Speter nmp->nm_state &= ~NFSSTA_HASAUTH; 106036176Speter nmp->nm_state |= NFSSTA_WAITAUTH; 106136176Speter if (nmp->nm_state & NFSSTA_WANTAUTH) { 106236176Speter nmp->nm_state &= ~NFSSTA_WANTAUTH; 10631541Srgrimes wakeup((caddr_t)&nmp->nm_authtype); 10641541Srgrimes } 10651541Srgrimes return (error); 10661541Srgrimes} 10671541Srgrimes 10681541Srgrimes/* 10699336Sdfr * Get a nickname authenticator and verifier. 10709336Sdfr */ 10719336Sdfrint 10729336Sdfrnfs_getnickauth(nmp, cred, auth_str, auth_len, verf_str, verf_len) 10739336Sdfr struct nfsmount *nmp; 10749336Sdfr struct ucred *cred; 10759336Sdfr char **auth_str; 10769336Sdfr int *auth_len; 10779336Sdfr char *verf_str; 10789336Sdfr int verf_len; 10799336Sdfr{ 10809336Sdfr register struct nfsuid *nuidp; 108136541Speter register u_int32_t *nickp, *verfp; 10829336Sdfr struct timeval ktvin, ktvout; 10839336Sdfr 10849336Sdfr#ifdef DIAGNOSTIC 10859336Sdfr if (verf_len < (4 * NFSX_UNSIGNED)) 10869336Sdfr panic("nfs_getnickauth verf too small"); 10879336Sdfr#endif 10889336Sdfr for (nuidp = NMUIDHASH(nmp, cred->cr_uid)->lh_first; 10899336Sdfr nuidp != 0; nuidp = nuidp->nu_hash.le_next) { 10909336Sdfr if (nuidp->nu_cr.cr_uid == cred->cr_uid) 10919336Sdfr break; 10929336Sdfr } 109334961Sphk if (!nuidp || nuidp->nu_expire < time_second) 10949336Sdfr return (EACCES); 10959336Sdfr 10969336Sdfr /* 10979336Sdfr * Move to the end of the lru list (end of lru == most recently used). 10989336Sdfr */ 10999336Sdfr TAILQ_REMOVE(&nmp->nm_uidlruhead, nuidp, nu_lru); 11009336Sdfr TAILQ_INSERT_TAIL(&nmp->nm_uidlruhead, nuidp, nu_lru); 11019336Sdfr 110236541Speter nickp = (u_int32_t *)malloc(2 * NFSX_UNSIGNED, M_TEMP, M_WAITOK); 11039336Sdfr *nickp++ = txdr_unsigned(RPCAKN_NICKNAME); 11049336Sdfr *nickp = txdr_unsigned(nuidp->nu_nickname); 11059336Sdfr *auth_str = (char *)nickp; 11069336Sdfr *auth_len = 2 * NFSX_UNSIGNED; 11079336Sdfr 11089336Sdfr /* 11099336Sdfr * Now we must encrypt the verifier and package it up. 11109336Sdfr */ 111136541Speter verfp = (u_int32_t *)verf_str; 11129336Sdfr *verfp++ = txdr_unsigned(RPCAKN_NICKNAME); 111334961Sphk if (time_second > nuidp->nu_timestamp.tv_sec || 111434961Sphk (time_second == nuidp->nu_timestamp.tv_sec && 111534961Sphk time_second > nuidp->nu_timestamp.tv_usec)) 111634961Sphk getmicrotime(&nuidp->nu_timestamp); 11179336Sdfr else 11189336Sdfr nuidp->nu_timestamp.tv_usec++; 11199336Sdfr ktvin.tv_sec = txdr_unsigned(nuidp->nu_timestamp.tv_sec); 11209336Sdfr ktvin.tv_usec = txdr_unsigned(nuidp->nu_timestamp.tv_usec); 11219336Sdfr 11229336Sdfr /* 11239336Sdfr * Now encrypt the timestamp verifier in ecb mode using the session 11249336Sdfr * key. 11259336Sdfr */ 11269336Sdfr#ifdef NFSKERB 11279336Sdfr XXX 11289336Sdfr#endif 11299336Sdfr 11309336Sdfr *verfp++ = ktvout.tv_sec; 11319336Sdfr *verfp++ = ktvout.tv_usec; 11329336Sdfr *verfp = 0; 11339336Sdfr return (0); 11349336Sdfr} 11359336Sdfr 11369336Sdfr/* 11379336Sdfr * Save the current nickname in a hash list entry on the mount point. 11389336Sdfr */ 11399336Sdfrint 11409336Sdfrnfs_savenickauth(nmp, cred, len, key, mdp, dposp, mrep) 11419336Sdfr register struct nfsmount *nmp; 11429336Sdfr struct ucred *cred; 11439336Sdfr int len; 11449336Sdfr NFSKERBKEY_T key; 11459336Sdfr struct mbuf **mdp; 11469336Sdfr char **dposp; 11479336Sdfr struct mbuf *mrep; 11489336Sdfr{ 11499336Sdfr register struct nfsuid *nuidp; 115036541Speter register u_int32_t *tl; 115136541Speter register int32_t t1; 11529336Sdfr struct mbuf *md = *mdp; 11539336Sdfr struct timeval ktvin, ktvout; 115436541Speter u_int32_t nick; 11559336Sdfr char *dpos = *dposp, *cp2; 11569336Sdfr int deltasec, error = 0; 11579336Sdfr 11589336Sdfr if (len == (3 * NFSX_UNSIGNED)) { 115936541Speter nfsm_dissect(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 11609336Sdfr ktvin.tv_sec = *tl++; 11619336Sdfr ktvin.tv_usec = *tl++; 116236541Speter nick = fxdr_unsigned(u_int32_t, *tl); 11639336Sdfr 11649336Sdfr /* 11659336Sdfr * Decrypt the timestamp in ecb mode. 11669336Sdfr */ 11679336Sdfr#ifdef NFSKERB 11689336Sdfr XXX 11699336Sdfr#endif 11709336Sdfr ktvout.tv_sec = fxdr_unsigned(long, ktvout.tv_sec); 11719336Sdfr ktvout.tv_usec = fxdr_unsigned(long, ktvout.tv_usec); 117234961Sphk deltasec = time_second - ktvout.tv_sec; 11739336Sdfr if (deltasec < 0) 11749336Sdfr deltasec = -deltasec; 11759336Sdfr /* 11769336Sdfr * If ok, add it to the hash list for the mount point. 11779336Sdfr */ 11789336Sdfr if (deltasec <= NFS_KERBCLOCKSKEW) { 11799336Sdfr if (nmp->nm_numuids < nuidhash_max) { 11809336Sdfr nmp->nm_numuids++; 11819336Sdfr nuidp = (struct nfsuid *) 11829336Sdfr malloc(sizeof (struct nfsuid), M_NFSUID, 11839336Sdfr M_WAITOK); 11849336Sdfr } else { 11859336Sdfr nuidp = nmp->nm_uidlruhead.tqh_first; 11869336Sdfr LIST_REMOVE(nuidp, nu_hash); 11879336Sdfr TAILQ_REMOVE(&nmp->nm_uidlruhead, nuidp, 11889336Sdfr nu_lru); 11899336Sdfr } 11909336Sdfr nuidp->nu_flag = 0; 11919336Sdfr nuidp->nu_cr.cr_uid = cred->cr_uid; 119234961Sphk nuidp->nu_expire = time_second + NFS_KERBTTL; 11939336Sdfr nuidp->nu_timestamp = ktvout; 11949336Sdfr nuidp->nu_nickname = nick; 11959336Sdfr bcopy(key, nuidp->nu_key, sizeof (key)); 11969336Sdfr TAILQ_INSERT_TAIL(&nmp->nm_uidlruhead, nuidp, 11979336Sdfr nu_lru); 11989336Sdfr LIST_INSERT_HEAD(NMUIDHASH(nmp, cred->cr_uid), 11999336Sdfr nuidp, nu_hash); 12009336Sdfr } 12019336Sdfr } else 12029336Sdfr nfsm_adv(nfsm_rndup(len)); 12039336Sdfrnfsmout: 12049336Sdfr *mdp = md; 12059336Sdfr *dposp = dpos; 12069336Sdfr return (error); 12079336Sdfr} 1208