Home | History | Annotate | Line # | Download | only in nfs
nfs_syscalls.c revision 1.1
      1  1.1  cgd /*
      2  1.1  cgd  * Copyright (c) 1989 The Regents of the University of California.
      3  1.1  cgd  * All rights reserved.
      4  1.1  cgd  *
      5  1.1  cgd  * This code is derived from software contributed to Berkeley by
      6  1.1  cgd  * Rick Macklem at The University of Guelph.
      7  1.1  cgd  *
      8  1.1  cgd  * Redistribution and use in source and binary forms, with or without
      9  1.1  cgd  * modification, are permitted provided that the following conditions
     10  1.1  cgd  * are met:
     11  1.1  cgd  * 1. Redistributions of source code must retain the above copyright
     12  1.1  cgd  *    notice, this list of conditions and the following disclaimer.
     13  1.1  cgd  * 2. Redistributions in binary form must reproduce the above copyright
     14  1.1  cgd  *    notice, this list of conditions and the following disclaimer in the
     15  1.1  cgd  *    documentation and/or other materials provided with the distribution.
     16  1.1  cgd  * 3. All advertising materials mentioning features or use of this software
     17  1.1  cgd  *    must display the following acknowledgement:
     18  1.1  cgd  *	This product includes software developed by the University of
     19  1.1  cgd  *	California, Berkeley and its contributors.
     20  1.1  cgd  * 4. Neither the name of the University nor the names of its contributors
     21  1.1  cgd  *    may be used to endorse or promote products derived from this software
     22  1.1  cgd  *    without specific prior written permission.
     23  1.1  cgd  *
     24  1.1  cgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     25  1.1  cgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     26  1.1  cgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     27  1.1  cgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     28  1.1  cgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     29  1.1  cgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     30  1.1  cgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     31  1.1  cgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     32  1.1  cgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     33  1.1  cgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     34  1.1  cgd  * SUCH DAMAGE.
     35  1.1  cgd  *
     36  1.1  cgd  *	@(#)nfs_syscalls.c	7.26 (Berkeley) 4/16/91
     37  1.1  cgd  */
     38  1.1  cgd 
     39  1.1  cgd #include "param.h"
     40  1.1  cgd #include "systm.h"
     41  1.1  cgd #include "kernel.h"
     42  1.1  cgd #include "file.h"
     43  1.1  cgd #include "stat.h"
     44  1.1  cgd #include "namei.h"
     45  1.1  cgd #include "vnode.h"
     46  1.1  cgd #include "mount.h"
     47  1.1  cgd #include "proc.h"
     48  1.1  cgd #include "malloc.h"
     49  1.1  cgd #include "buf.h"
     50  1.1  cgd #include "mbuf.h"
     51  1.1  cgd #include "socket.h"
     52  1.1  cgd #include "socketvar.h"
     53  1.1  cgd #include "domain.h"
     54  1.1  cgd #include "protosw.h"
     55  1.1  cgd 
     56  1.1  cgd #include "../netinet/in.h"
     57  1.1  cgd #include "../netinet/tcp.h"
     58  1.1  cgd 
     59  1.1  cgd #include "nfsv2.h"
     60  1.1  cgd #include "nfs.h"
     61  1.1  cgd #include "nfsrvcache.h"
     62  1.1  cgd 
     63  1.1  cgd /* Global defs. */
     64  1.1  cgd extern u_long nfs_prog, nfs_vers;
     65  1.1  cgd extern int (*nfsrv_procs[NFS_NPROCS])();
     66  1.1  cgd extern struct buf nfs_bqueue;
     67  1.1  cgd extern int nfs_numasync;
     68  1.1  cgd extern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON];
     69  1.1  cgd extern int nfs_tcpnodelay;
     70  1.1  cgd struct mbuf *nfs_compress();
     71  1.1  cgd 
     72  1.1  cgd #define	TRUE	1
     73  1.1  cgd #define	FALSE	0
     74  1.1  cgd 
     75  1.1  cgd static int nfs_asyncdaemon[NFS_MAXASYNCDAEMON];
     76  1.1  cgd static int compressreply[NFS_NPROCS] = {
     77  1.1  cgd 	FALSE,
     78  1.1  cgd 	TRUE,
     79  1.1  cgd 	TRUE,
     80  1.1  cgd 	FALSE,
     81  1.1  cgd 	TRUE,
     82  1.1  cgd 	TRUE,
     83  1.1  cgd 	FALSE,
     84  1.1  cgd 	FALSE,
     85  1.1  cgd 	TRUE,
     86  1.1  cgd 	TRUE,
     87  1.1  cgd 	TRUE,
     88  1.1  cgd 	TRUE,
     89  1.1  cgd 	TRUE,
     90  1.1  cgd 	TRUE,
     91  1.1  cgd 	TRUE,
     92  1.1  cgd 	TRUE,
     93  1.1  cgd 	TRUE,
     94  1.1  cgd 	TRUE,
     95  1.1  cgd };
     96  1.1  cgd /*
     97  1.1  cgd  * NFS server system calls
     98  1.1  cgd  * getfh() lives here too, but maybe should move to kern/vfs_syscalls.c
     99  1.1  cgd  */
    100  1.1  cgd 
    101  1.1  cgd /*
    102  1.1  cgd  * Get file handle system call
    103  1.1  cgd  */
    104  1.1  cgd /* ARGSUSED */
    105  1.1  cgd getfh(p, uap, retval)
    106  1.1  cgd 	struct proc *p;
    107  1.1  cgd 	register struct args {
    108  1.1  cgd 		char	*fname;
    109  1.1  cgd 		fhandle_t *fhp;
    110  1.1  cgd 	} *uap;
    111  1.1  cgd 	int *retval;
    112  1.1  cgd {
    113  1.1  cgd 	register struct nameidata *ndp;
    114  1.1  cgd 	register struct vnode *vp;
    115  1.1  cgd 	fhandle_t fh;
    116  1.1  cgd 	int error;
    117  1.1  cgd 	struct nameidata nd;
    118  1.1  cgd 
    119  1.1  cgd 	/*
    120  1.1  cgd 	 * Must be super user
    121  1.1  cgd 	 */
    122  1.1  cgd 	if (error = suser(p->p_ucred, &p->p_acflag))
    123  1.1  cgd 		return (error);
    124  1.1  cgd 	ndp = &nd;
    125  1.1  cgd 	ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW;
    126  1.1  cgd 	ndp->ni_segflg = UIO_USERSPACE;
    127  1.1  cgd 	ndp->ni_dirp = uap->fname;
    128  1.1  cgd 	if (error = namei(ndp, p))
    129  1.1  cgd 		return (error);
    130  1.1  cgd 	vp = ndp->ni_vp;
    131  1.1  cgd 	bzero((caddr_t)&fh, sizeof(fh));
    132  1.1  cgd 	fh.fh_fsid = vp->v_mount->mnt_stat.f_fsid;
    133  1.1  cgd 	error = VFS_VPTOFH(vp, &fh.fh_fid);
    134  1.1  cgd 	vput(vp);
    135  1.1  cgd 	if (error)
    136  1.1  cgd 		return (error);
    137  1.1  cgd 	error = copyout((caddr_t)&fh, (caddr_t)uap->fhp, sizeof (fh));
    138  1.1  cgd 	return (error);
    139  1.1  cgd }
    140  1.1  cgd 
    141  1.1  cgd /*
    142  1.1  cgd  * Nfs server psuedo system call for the nfsd's
    143  1.1  cgd  * Never returns unless it fails or gets killed
    144  1.1  cgd  */
    145  1.1  cgd /* ARGSUSED */
    146  1.1  cgd nfssvc(p, uap, retval)
    147  1.1  cgd 	struct proc *p;
    148  1.1  cgd 	register struct args {
    149  1.1  cgd 		int s;
    150  1.1  cgd 		caddr_t mskval;
    151  1.1  cgd 		int msklen;
    152  1.1  cgd 		caddr_t mtchval;
    153  1.1  cgd 		int mtchlen;
    154  1.1  cgd 	} *uap;
    155  1.1  cgd 	int *retval;
    156  1.1  cgd {
    157  1.1  cgd 	register struct mbuf *m;
    158  1.1  cgd 	register int siz;
    159  1.1  cgd 	register struct ucred *cr;
    160  1.1  cgd 	struct file *fp;
    161  1.1  cgd 	struct mbuf *mreq, *mrep, *nam, *md;
    162  1.1  cgd 	struct mbuf msk, mtch;
    163  1.1  cgd 	struct socket *so;
    164  1.1  cgd 	caddr_t dpos;
    165  1.1  cgd 	int procid, repstat, error, cacherep, wascomp;
    166  1.1  cgd 	u_long retxid;
    167  1.1  cgd 
    168  1.1  cgd 	/*
    169  1.1  cgd 	 * Must be super user
    170  1.1  cgd 	 */
    171  1.1  cgd 	if (error = suser(p->p_ucred, &p->p_acflag))
    172  1.1  cgd 		return (error);
    173  1.1  cgd 	if (error = getsock(p->p_fd, uap->s, &fp))
    174  1.1  cgd 		return (error);
    175  1.1  cgd 	so = (struct socket *)fp->f_data;
    176  1.1  cgd 	if (sosendallatonce(so))
    177  1.1  cgd 		siz = NFS_MAXPACKET;
    178  1.1  cgd 	else
    179  1.1  cgd 		siz = NFS_MAXPACKET + sizeof(u_long);
    180  1.1  cgd 	if (error = soreserve(so, siz, siz))
    181  1.1  cgd 		goto bad;
    182  1.1  cgd 	if (error = sockargs(&nam, uap->mskval, uap->msklen, MT_SONAME))
    183  1.1  cgd 		goto bad;
    184  1.1  cgd 	bcopy((caddr_t)nam, (caddr_t)&msk, sizeof (struct mbuf));
    185  1.1  cgd 	msk.m_data = msk.m_dat;
    186  1.1  cgd 	m_freem(nam);
    187  1.1  cgd 	if (error = sockargs(&nam, uap->mtchval, uap->mtchlen, MT_SONAME))
    188  1.1  cgd 		goto bad;
    189  1.1  cgd 	bcopy((caddr_t)nam, (caddr_t)&mtch, sizeof (struct mbuf));
    190  1.1  cgd 	mtch.m_data = mtch.m_dat;
    191  1.1  cgd 	m_freem(nam);
    192  1.1  cgd 
    193  1.1  cgd 	/* Copy the cred so others don't see changes */
    194  1.1  cgd 	cr = p->p_ucred = crcopy(p->p_ucred);
    195  1.1  cgd 
    196  1.1  cgd 	/*
    197  1.1  cgd 	 * Set protocol specific options { for now TCP only } and
    198  1.1  cgd 	 * reserve some space. For datagram sockets, this can get called
    199  1.1  cgd 	 * repeatedly for the same socket, but that isn't harmful.
    200  1.1  cgd 	 */
    201  1.1  cgd 	if (so->so_proto->pr_flags & PR_CONNREQUIRED) {
    202  1.1  cgd 		MGET(m, M_WAIT, MT_SOOPTS);
    203  1.1  cgd 		*mtod(m, int *) = 1;
    204  1.1  cgd 		m->m_len = sizeof(int);
    205  1.1  cgd 		sosetopt(so, SOL_SOCKET, SO_KEEPALIVE, m);
    206  1.1  cgd 	}
    207  1.1  cgd 	if (so->so_proto->pr_domain->dom_family == AF_INET &&
    208  1.1  cgd 	    so->so_proto->pr_protocol == IPPROTO_TCP &&
    209  1.1  cgd 	    nfs_tcpnodelay) {
    210  1.1  cgd 		MGET(m, M_WAIT, MT_SOOPTS);
    211  1.1  cgd 		*mtod(m, int *) = 1;
    212  1.1  cgd 		m->m_len = sizeof(int);
    213  1.1  cgd 		sosetopt(so, IPPROTO_TCP, TCP_NODELAY, m);
    214  1.1  cgd 	}
    215  1.1  cgd 	so->so_rcv.sb_flags &= ~SB_NOINTR;
    216  1.1  cgd 	so->so_rcv.sb_timeo = 0;
    217  1.1  cgd 	so->so_snd.sb_flags &= ~SB_NOINTR;
    218  1.1  cgd 	so->so_snd.sb_timeo = 0;
    219  1.1  cgd 
    220  1.1  cgd 	/*
    221  1.1  cgd 	 * Just loop around doin our stuff until SIGKILL
    222  1.1  cgd 	 */
    223  1.1  cgd 	for (;;) {
    224  1.1  cgd 		if (error = nfs_getreq(so, nfs_prog, nfs_vers, NFS_NPROCS-1,
    225  1.1  cgd 		   &nam, &mrep, &md, &dpos, &retxid, &procid, cr,
    226  1.1  cgd 		   &msk, &mtch, &wascomp)) {
    227  1.1  cgd 			if (nam)
    228  1.1  cgd 				m_freem(nam);
    229  1.1  cgd 			if (error == EPIPE || error == EINTR ||
    230  1.1  cgd 			    error == ERESTART) {
    231  1.1  cgd 				error = 0;
    232  1.1  cgd 				goto bad;
    233  1.1  cgd 			}
    234  1.1  cgd 			so->so_error = 0;
    235  1.1  cgd 			continue;
    236  1.1  cgd 		}
    237  1.1  cgd 
    238  1.1  cgd 		if (nam)
    239  1.1  cgd 			cacherep = nfsrv_getcache(nam, retxid, procid, &mreq);
    240  1.1  cgd 		else
    241  1.1  cgd 			cacherep = RC_DOIT;
    242  1.1  cgd 		switch (cacherep) {
    243  1.1  cgd 		case RC_DOIT:
    244  1.1  cgd 			if (error = (*(nfsrv_procs[procid]))(mrep, md, dpos,
    245  1.1  cgd 				cr, retxid, &mreq, &repstat, p)) {
    246  1.1  cgd 				nfsstats.srv_errs++;
    247  1.1  cgd 				if (nam) {
    248  1.1  cgd 					nfsrv_updatecache(nam, retxid, procid,
    249  1.1  cgd 						FALSE, repstat, mreq);
    250  1.1  cgd 					m_freem(nam);
    251  1.1  cgd 				}
    252  1.1  cgd 				break;
    253  1.1  cgd 			}
    254  1.1  cgd 			nfsstats.srvrpccnt[procid]++;
    255  1.1  cgd 			if (nam)
    256  1.1  cgd 				nfsrv_updatecache(nam, retxid, procid, TRUE,
    257  1.1  cgd 					repstat, mreq);
    258  1.1  cgd 			mrep = (struct mbuf *)0;
    259  1.1  cgd 		case RC_REPLY:
    260  1.1  cgd 			m = mreq;
    261  1.1  cgd 			siz = 0;
    262  1.1  cgd 			while (m) {
    263  1.1  cgd 				siz += m->m_len;
    264  1.1  cgd 				m = m->m_next;
    265  1.1  cgd 			}
    266  1.1  cgd 			if (siz <= 0 || siz > NFS_MAXPACKET) {
    267  1.1  cgd 				printf("mbuf siz=%d\n",siz);
    268  1.1  cgd 				panic("Bad nfs svc reply");
    269  1.1  cgd 			}
    270  1.1  cgd 			mreq->m_pkthdr.len = siz;
    271  1.1  cgd 			mreq->m_pkthdr.rcvif = (struct ifnet *)0;
    272  1.1  cgd 			if (wascomp && compressreply[procid]) {
    273  1.1  cgd 				mreq = nfs_compress(mreq);
    274  1.1  cgd 				siz = mreq->m_pkthdr.len;
    275  1.1  cgd 			}
    276  1.1  cgd 			/*
    277  1.1  cgd 			 * For non-atomic protocols, prepend a Sun RPC
    278  1.1  cgd 			 * Record Mark.
    279  1.1  cgd 			 */
    280  1.1  cgd 			if (!sosendallatonce(so)) {
    281  1.1  cgd 				M_PREPEND(mreq, sizeof(u_long), M_WAIT);
    282  1.1  cgd 				*mtod(mreq, u_long *) = htonl(0x80000000 | siz);
    283  1.1  cgd 			}
    284  1.1  cgd 			error = nfs_send(so, nam, mreq, (struct nfsreq *)0);
    285  1.1  cgd 			if (nam)
    286  1.1  cgd 				m_freem(nam);
    287  1.1  cgd 			if (mrep)
    288  1.1  cgd 				m_freem(mrep);
    289  1.1  cgd 			if (error) {
    290  1.1  cgd 				if (error == EPIPE || error == EINTR ||
    291  1.1  cgd 				    error == ERESTART)
    292  1.1  cgd 					goto bad;
    293  1.1  cgd 				so->so_error = 0;
    294  1.1  cgd 			}
    295  1.1  cgd 			break;
    296  1.1  cgd 		case RC_DROPIT:
    297  1.1  cgd 			m_freem(mrep);
    298  1.1  cgd 			m_freem(nam);
    299  1.1  cgd 			break;
    300  1.1  cgd 		};
    301  1.1  cgd 	}
    302  1.1  cgd bad:
    303  1.1  cgd 	return (error);
    304  1.1  cgd }
    305  1.1  cgd 
    306  1.1  cgd /*
    307  1.1  cgd  * Nfs pseudo system call for asynchronous i/o daemons.
    308  1.1  cgd  * These babies just pretend to be disk interrupt service routines
    309  1.1  cgd  * for client nfs. They are mainly here for read ahead/write behind.
    310  1.1  cgd  * Never returns unless it fails or gets killed
    311  1.1  cgd  */
    312  1.1  cgd /* ARGSUSED */
    313  1.1  cgd async_daemon(p, uap, retval)
    314  1.1  cgd 	struct proc *p;
    315  1.1  cgd 	struct args *uap;
    316  1.1  cgd 	int *retval;
    317  1.1  cgd {
    318  1.1  cgd 	register struct buf *bp, *dp;
    319  1.1  cgd 	register int i, myiod;
    320  1.1  cgd 	int error;
    321  1.1  cgd 
    322  1.1  cgd 	/*
    323  1.1  cgd 	 * Must be super user
    324  1.1  cgd 	 */
    325  1.1  cgd 	if (error = suser(p->p_ucred, &p->p_acflag))
    326  1.1  cgd 		return (error);
    327  1.1  cgd 	/*
    328  1.1  cgd 	 * Assign my position or return error if too many already running
    329  1.1  cgd 	 */
    330  1.1  cgd 	myiod = -1;
    331  1.1  cgd 	for (i = 0; i < NFS_MAXASYNCDAEMON; i++)
    332  1.1  cgd 		if (nfs_asyncdaemon[i] == 0) {
    333  1.1  cgd 			nfs_asyncdaemon[i]++;
    334  1.1  cgd 			myiod = i;
    335  1.1  cgd 			break;
    336  1.1  cgd 		}
    337  1.1  cgd 	if (myiod == -1)
    338  1.1  cgd 		return (EBUSY);
    339  1.1  cgd 	nfs_numasync++;
    340  1.1  cgd 	dp = &nfs_bqueue;
    341  1.1  cgd 	/*
    342  1.1  cgd 	 * Just loop around doin our stuff until SIGKILL
    343  1.1  cgd 	 */
    344  1.1  cgd 	for (;;) {
    345  1.1  cgd 		while (dp->b_actf == NULL && error == 0) {
    346  1.1  cgd 			nfs_iodwant[myiod] = p;
    347  1.1  cgd 			error = tsleep((caddr_t)&nfs_iodwant[myiod],
    348  1.1  cgd 				PWAIT | PCATCH, "nfsidl", 0);
    349  1.1  cgd 			nfs_iodwant[myiod] = (struct proc *)0;
    350  1.1  cgd 		}
    351  1.1  cgd 		while (dp->b_actf != NULL) {
    352  1.1  cgd 			/* Take one off the end of the list */
    353  1.1  cgd 			bp = dp->b_actl;
    354  1.1  cgd 			if (bp->b_actl == dp) {
    355  1.1  cgd 				dp->b_actf = dp->b_actl = (struct buf *)0;
    356  1.1  cgd 			} else {
    357  1.1  cgd 				dp->b_actl = bp->b_actl;
    358  1.1  cgd 				bp->b_actl->b_actf = dp;
    359  1.1  cgd 			}
    360  1.1  cgd 			(void) nfs_doio(bp);
    361  1.1  cgd 		}
    362  1.1  cgd 		if (error) {
    363  1.1  cgd 			nfs_asyncdaemon[myiod] = 0;
    364  1.1  cgd 			nfs_numasync--;
    365  1.1  cgd 			return (error);
    366  1.1  cgd 		}
    367  1.1  cgd 	}
    368  1.1  cgd }
    369