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