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 * 838414Smckusick * Redistribution and use in source and binary forms are permitted 938414Smckusick * provided that the above copyright notice and this paragraph are 1038414Smckusick * duplicated in all such forms and that any documentation, 1138414Smckusick * advertising materials, and other materials related to such 1238414Smckusick * distribution and use acknowledge that the software was developed 1338414Smckusick * by the University of California, Berkeley. The name of the 1438414Smckusick * University may not be used to endorse or promote products derived 1538414Smckusick * from this software without specific prior written permission. 1638414Smckusick * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1738414Smckusick * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1838414Smckusick * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1938414Smckusick * 20*43354Smckusick * @(#)nfs_syscalls.c 7.16 (Berkeley) 06/21/90 2138414Smckusick */ 2238414Smckusick 2338414Smckusick #include "param.h" 2438414Smckusick #include "systm.h" 25*43354Smckusick #include "syscontext.h" 2638414Smckusick #include "kernel.h" 2738414Smckusick #include "file.h" 2838414Smckusick #include "stat.h" 2938414Smckusick #include "vnode.h" 3038414Smckusick #include "mount.h" 3138414Smckusick #include "proc.h" 3238414Smckusick #include "uio.h" 3338414Smckusick #include "malloc.h" 3438884Smacklem #include "buf.h" 3538414Smckusick #include "mbuf.h" 3638414Smckusick #include "socket.h" 3738414Smckusick #include "socketvar.h" 3841903Smckusick #include "domain.h" 3941903Smckusick #include "protosw.h" 4042876Smckusick #include "../netinet/in.h" 4142876Smckusick #include "../netinet/tcp.h" 4238414Smckusick #include "nfsv2.h" 4338414Smckusick #include "nfs.h" 4439756Smckusick #include "nfsrvcache.h" 4538414Smckusick 4638414Smckusick /* Global defs. */ 4738414Smckusick extern u_long nfs_prog, nfs_vers; 4838414Smckusick extern int (*nfsrv_procs[NFS_NPROCS])(); 4938884Smacklem extern struct buf nfs_bqueue; 5039346Smckusick extern int nfs_asyncdaemons; 5141903Smckusick extern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON]; 5241903Smckusick extern int nfs_tcpnodelay; 5338414Smckusick struct file *getsock(); 5438414Smckusick 5540252Smckusick #define TRUE 1 5640252Smckusick #define FALSE 0 5740252Smckusick 5838414Smckusick /* 5938414Smckusick * NFS server system calls 6038414Smckusick * getfh() lives here too, but maybe should move to kern/vfs_syscalls.c 6138414Smckusick */ 6238414Smckusick 6338414Smckusick /* 6438414Smckusick * Get file handle system call 6538414Smckusick */ 66*43354Smckusick /* ARGSUSED */ 67*43354Smckusick getfh(p, uap, retval) 68*43354Smckusick struct proc *p; 69*43354Smckusick register struct args { 7038414Smckusick char *fname; 7138414Smckusick fhandle_t *fhp; 72*43354Smckusick } *uap; 73*43354Smckusick int *retval; 74*43354Smckusick { 7538414Smckusick register struct nameidata *ndp = &u.u_nd; 7638414Smckusick register struct vnode *vp; 7738414Smckusick fhandle_t fh; 7838414Smckusick int error; 7938414Smckusick 8038414Smckusick /* 8138414Smckusick * Must be super user 8238414Smckusick */ 83*43354Smckusick if (error = suser(ndp->ni_cred, &u.u_acflag)) 8438414Smckusick RETURN (error); 8538414Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW; 8638414Smckusick ndp->ni_segflg = UIO_USERSPACE; 8738414Smckusick ndp->ni_dirp = uap->fname; 8838414Smckusick if (error = namei(ndp)) 8938414Smckusick RETURN (error); 9038414Smckusick vp = ndp->ni_vp; 9138414Smckusick bzero((caddr_t)&fh, sizeof(fh)); 9241398Smckusick fh.fh_fsid = vp->v_mount->mnt_stat.f_fsid; 9338414Smckusick error = VFS_VPTOFH(vp, &fh.fh_fid); 9438414Smckusick vput(vp); 9538414Smckusick if (error) 9638414Smckusick RETURN (error); 9738414Smckusick error = copyout((caddr_t)&fh, (caddr_t)uap->fhp, sizeof (fh)); 9838414Smckusick RETURN (error); 9938414Smckusick } 10038414Smckusick 10138414Smckusick /* 10238414Smckusick * Nfs server psuedo system call for the nfsd's 10338414Smckusick * Never returns unless it fails or gets killed 10438414Smckusick */ 105*43354Smckusick /* ARGSUSED */ 106*43354Smckusick nfssvc(p, uap, retval) 107*43354Smckusick struct proc *p; 108*43354Smckusick register struct args { 10938414Smckusick int s; 11041903Smckusick caddr_t mskval; 11141903Smckusick int msklen; 11241903Smckusick caddr_t mtchval; 11341903Smckusick int mtchlen; 114*43354Smckusick } *uap; 115*43354Smckusick int *retval; 116*43354Smckusick { 11738414Smckusick register struct mbuf *m; 11838414Smckusick register int siz; 11938414Smckusick register struct ucred *cr; 12038414Smckusick struct file *fp; 12138414Smckusick struct mbuf *mreq, *mrep, *nam, *md; 12241903Smckusick struct mbuf msk, mtch; 12338414Smckusick struct socket *so; 12438414Smckusick caddr_t dpos; 125*43354Smckusick int procid, repstat, error, cacherep; 12638414Smckusick u_long retxid; 12738414Smckusick 12838414Smckusick /* 12938414Smckusick * Must be super user 13038414Smckusick */ 13138414Smckusick if (error = suser(u.u_cred, &u.u_acflag)) 13241903Smckusick goto bad; 13341903Smckusick fp = getsock(uap->s); 13438414Smckusick if (fp == 0) 13541903Smckusick return; 13638414Smckusick so = (struct socket *)fp->f_data; 13741903Smckusick if (sosendallatonce(so)) 13841903Smckusick siz = NFS_MAXPACKET; 13941903Smckusick else 14041903Smckusick siz = NFS_MAXPACKET + sizeof(u_long); 141*43354Smckusick if (error = soreserve(so, siz, siz)) 14241903Smckusick goto bad; 14341903Smckusick if (error = sockargs(&nam, uap->mskval, uap->msklen, MT_SONAME)) 14441903Smckusick goto bad; 14541903Smckusick bcopy((caddr_t)nam, (caddr_t)&msk, sizeof (struct mbuf)); 14641903Smckusick msk.m_data = msk.m_dat; 14741903Smckusick m_freem(nam); 14841903Smckusick if (error = sockargs(&nam, uap->mtchval, uap->mtchlen, MT_SONAME)) 14941903Smckusick goto bad; 15041903Smckusick bcopy((caddr_t)nam, (caddr_t)&mtch, sizeof (struct mbuf)); 15141903Smckusick mtch.m_data = mtch.m_dat; 15241903Smckusick m_freem(nam); 15341903Smckusick 15441903Smckusick /* Copy the cred so others don't see changes */ 15541903Smckusick cr = u.u_cred = crcopy(u.u_cred); 15641903Smckusick 15738414Smckusick /* 15841903Smckusick * Set protocol specific options { for now TCP only } and 15941903Smckusick * reserve some space. For datagram sockets, this can get called 16041903Smckusick * repeatedly for the same socket, but that isn't harmful. 16141903Smckusick */ 16241903Smckusick if (so->so_proto->pr_flags & PR_CONNREQUIRED) { 16341903Smckusick MGET(m, M_WAIT, MT_SOOPTS); 16441903Smckusick *mtod(m, int *) = 1; 16541903Smckusick m->m_len = sizeof(int); 16641903Smckusick sosetopt(so, SOL_SOCKET, SO_KEEPALIVE, m); 16741903Smckusick } 16841903Smckusick if (so->so_proto->pr_domain->dom_family == AF_INET && 16941903Smckusick so->so_proto->pr_protocol == IPPROTO_TCP && 17041903Smckusick nfs_tcpnodelay) { 17141903Smckusick MGET(m, M_WAIT, MT_SOOPTS); 17241903Smckusick *mtod(m, int *) = 1; 17341903Smckusick m->m_len = sizeof(int); 17441903Smckusick sosetopt(so, IPPROTO_TCP, TCP_NODELAY, m); 17541903Smckusick } 17641903Smckusick so->so_rcv.sb_flags &= ~SB_NOINTR; 17741903Smckusick so->so_rcv.sb_timeo = 0; 17841903Smckusick so->so_snd.sb_flags &= ~SB_NOINTR; 17941903Smckusick so->so_snd.sb_timeo = 0; 18041903Smckusick 18141903Smckusick /* 18239756Smckusick * Just loop around doin our stuff until SIGKILL 18338414Smckusick */ 18438414Smckusick for (;;) { 18538414Smckusick if (error = nfs_getreq(so, nfs_prog, nfs_vers, NFS_NPROCS-1, 186*43354Smckusick &nam, &mrep, &md, &dpos, &retxid, &procid, cr, 18741903Smckusick &msk, &mtch)) { 18840762Skarels if (nam) 18940762Skarels m_freem(nam); 19041903Smckusick if (error == EPIPE || error == EINTR || 191*43354Smckusick error == ERESTART) { 192*43354Smckusick error = 0; 19341903Smckusick goto bad; 194*43354Smckusick } 19541903Smckusick so->so_error = 0; 19638414Smckusick continue; 19738414Smckusick } 19841903Smckusick 19941903Smckusick if (nam) 20041903Smckusick cacherep = nfsrv_getcache(nam, retxid, procid, &mreq); 20141903Smckusick else 20241903Smckusick cacherep = RC_DOIT; 20341903Smckusick switch (cacherep) { 20439756Smckusick case RC_DOIT: 20539756Smckusick if (error = (*(nfsrv_procs[procid]))(mrep, md, dpos, 20639756Smckusick cr, retxid, &mreq, &repstat)) { 20739756Smckusick nfsstats.srv_errs++; 20841903Smckusick if (nam) { 20941903Smckusick nfsrv_updatecache(nam, retxid, procid, 21041903Smckusick FALSE, repstat, mreq); 21141903Smckusick m_freem(nam); 21241903Smckusick } 21339756Smckusick break; 21439756Smckusick } 21539756Smckusick nfsstats.srvrpccnt[procid]++; 21641903Smckusick if (nam) 21741903Smckusick nfsrv_updatecache(nam, retxid, procid, TRUE, 21841903Smckusick repstat, mreq); 21939756Smckusick mrep = (struct mbuf *)0; 22039756Smckusick case RC_REPLY: 22139756Smckusick m = mreq; 22239756Smckusick siz = 0; 22339756Smckusick while (m) { 22439756Smckusick siz += m->m_len; 22539756Smckusick m = m->m_next; 22639756Smckusick } 22741903Smckusick if (siz <= 0 || siz > NFS_MAXPACKET) { 22839756Smckusick printf("mbuf siz=%d\n",siz); 22939756Smckusick panic("Bad nfs svc reply"); 23039756Smckusick } 23141903Smckusick mreq->m_pkthdr.len = siz; 23241903Smckusick mreq->m_pkthdr.rcvif = (struct ifnet *)0; 23341903Smckusick /* 23441903Smckusick * For non-atomic protocols, prepend a Sun RPC 23541903Smckusick * Record Mark. 23641903Smckusick */ 23741903Smckusick if (!sosendallatonce(so)) { 23841903Smckusick M_PREPEND(mreq, sizeof(u_long), M_WAIT); 23941903Smckusick *mtod(mreq, u_long *) = htonl(0x80000000 | siz); 24041903Smckusick } 24141903Smckusick error = nfs_send(so, nam, mreq, (struct nfsreq *)0); 24241903Smckusick if (nam) 24341903Smckusick m_freem(nam); 24439756Smckusick if (mrep) 24539756Smckusick m_freem(mrep); 24641903Smckusick if (error) { 24741903Smckusick if (error == EPIPE || error == EINTR || 24841903Smckusick error == ERESTART) 24941903Smckusick goto bad; 25041903Smckusick so->so_error = 0; 25141903Smckusick } 25239756Smckusick break; 25339756Smckusick case RC_DROPIT: 25439756Smckusick m_freem(mrep); 25539756Smckusick m_freem(nam); 25639756Smckusick break; 25739756Smckusick }; 25838414Smckusick } 25941903Smckusick bad: 26041903Smckusick RETURN (error); 26138414Smckusick } 26238884Smacklem 26338884Smacklem /* 26438884Smacklem * Nfs pseudo system call for asynchronous i/o daemons. 26538884Smacklem * These babies just pretend to be disk interrupt service routines 26639346Smckusick * for client nfs. They are mainly here for read ahead/write behind. 26738884Smacklem * Never returns unless it fails or gets killed 26838884Smacklem */ 269*43354Smckusick /* ARGSUSED */ 270*43354Smckusick async_daemon(p, uap, retval) 271*43354Smckusick struct proc *p; 272*43354Smckusick struct args *uap; 273*43354Smckusick int *retval; 27438884Smacklem { 27538884Smacklem register struct buf *bp, *dp; 27638884Smacklem int error; 27739346Smckusick int myiod; 27838884Smacklem 27938884Smacklem /* 28038884Smacklem * Must be super user 28138884Smacklem */ 28238884Smacklem if (error = suser(u.u_cred, &u.u_acflag)) 28338884Smacklem RETURN (error); 28439346Smckusick /* 28539346Smckusick * Assign my position or return error if too many already running 28639346Smckusick */ 28741903Smckusick if (nfs_asyncdaemons > NFS_MAXASYNCDAEMON) 28839346Smckusick RETURN (EBUSY); 28939346Smckusick myiod = nfs_asyncdaemons++; 29038884Smacklem dp = &nfs_bqueue; 29138884Smacklem /* 29239346Smckusick * Just loop around doin our stuff until SIGKILL 29338884Smacklem */ 29438884Smacklem for (;;) { 29538884Smacklem while (dp->b_actf == NULL) { 296*43354Smckusick nfs_iodwant[myiod] = p; 29740762Skarels if (error = tsleep((caddr_t)&nfs_iodwant[myiod], 29841903Smckusick PWAIT | PCATCH, "nfsidl", 0)) 29940762Skarels RETURN (error); 30038884Smacklem } 30138884Smacklem /* Take one off the end of the list */ 30238884Smacklem bp = dp->b_actl; 30338884Smacklem if (bp->b_actl == dp) { 30438884Smacklem dp->b_actf = dp->b_actl = (struct buf *)0; 30538884Smacklem } else { 30638884Smacklem dp->b_actl = bp->b_actl; 30738884Smacklem bp->b_actl->b_actf = dp; 30838884Smacklem } 30938884Smacklem (void) nfs_doio(bp); 31038884Smacklem } 31138884Smacklem } 312