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