Home | History | Annotate | Line # | Download | only in nfs
nfs_syscalls.c revision 1.6.4.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  *	from: @(#)nfs_syscalls.c	7.26 (Berkeley) 4/16/91
     37  *	$Id: nfs_syscalls.c,v 1.6.4.1 1993/11/14 22:22:29 mycroft Exp $
     38  */
     39 
     40 #include <sys/param.h>
     41 #include <sys/systm.h>
     42 #include <sys/kernel.h>
     43 #include <sys/file.h>
     44 #include <sys/stat.h>
     45 #include <sys/namei.h>
     46 #include <sys/vnode.h>
     47 #include <sys/mount.h>
     48 #include <sys/proc.h>
     49 #include <sys/malloc.h>
     50 #include <sys/buf.h>
     51 #include <sys/mbuf.h>
     52 #include <sys/socket.h>
     53 #include <sys/socketvar.h>
     54 #include <sys/domain.h>
     55 #include <sys/protosw.h>
     56 
     57 #include <netinet/in.h>
     58 #include <netinet/tcp.h>
     59 
     60 #include <nfs/nfsv2.h>
     61 #include <nfs/nfs.h>
     62 #include <nfs/nfsrvcache.h>
     63 
     64 /* Global defs. */
     65 extern u_long nfs_prog, nfs_vers;
     66 extern int (*nfsrv_procs[NFS_NPROCS])();
     67 extern struct buf nfs_bqueue;
     68 extern int nfs_numasync;
     69 extern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON];
     70 extern int nfs_tcpnodelay;
     71 struct mbuf *nfs_compress();
     72 
     73 #define	TRUE	1
     74 #define	FALSE	0
     75 
     76 static int nfs_asyncdaemon[NFS_MAXASYNCDAEMON];
     77 static int compressreply[NFS_NPROCS] = {
     78 	FALSE,
     79 	TRUE,
     80 	TRUE,
     81 	FALSE,
     82 	TRUE,
     83 	TRUE,
     84 	FALSE,
     85 	FALSE,
     86 	TRUE,
     87 	TRUE,
     88 	TRUE,
     89 	TRUE,
     90 	TRUE,
     91 	TRUE,
     92 	TRUE,
     93 	TRUE,
     94 	TRUE,
     95 	TRUE,
     96 };
     97 
     98 #ifdef NFSCLIENT
     99 
    100 /*
    101  * NFS server system calls
    102  * getfh() lives here too, but maybe should move to kern/vfs_syscalls.c
    103  */
    104 
    105 /*
    106  * Get file handle system call
    107  */
    108 struct getfh_args {
    109 	char	*fname;
    110 	fhandle_t *fhp;
    111 };
    112 
    113 /* ARGSUSED */
    114 getfh(p, uap, retval)
    115 	struct proc *p;
    116 	register struct getfh_args *uap;
    117 	int *retval;
    118 {
    119 	register struct nameidata *ndp;
    120 	register struct vnode *vp;
    121 	fhandle_t fh;
    122 	int error;
    123 	struct nameidata nd;
    124 
    125 	/*
    126 	 * Must be super user
    127 	 */
    128 	if (error = suser(p->p_ucred, &p->p_acflag))
    129 		return (error);
    130 	ndp = &nd;
    131 	ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW;
    132 	ndp->ni_segflg = UIO_USERSPACE;
    133 	ndp->ni_dirp = uap->fname;
    134 	if (error = namei(ndp, p))
    135 		return (error);
    136 	vp = ndp->ni_vp;
    137 	bzero((caddr_t)&fh, sizeof(fh));
    138 	fh.fh_fsid = vp->v_mount->mnt_stat.f_fsid;
    139 	error = VFS_VPTOFH(vp, &fh.fh_fid);
    140 	vput(vp);
    141 	if (error)
    142 		return (error);
    143 	error = copyout((caddr_t)&fh, (caddr_t)uap->fhp, sizeof (fh));
    144 	return (error);
    145 }
    146 
    147 #endif /*NFSCLIENT*/
    148 
    149 #ifdef NFSSERVER
    150 
    151 /*
    152  * Nfs server psuedo system call for the nfsd's
    153  * Never returns unless it fails or gets killed
    154  */
    155 struct nfssvc_args {
    156 	int s;
    157 	caddr_t mskval;
    158 	int msklen;
    159 	caddr_t mtchval;
    160 	int mtchlen;
    161 };
    162 
    163 /* ARGSUSED */
    164 nfssvc(p, uap, retval)
    165 	struct proc *p;
    166 	register struct nfssvc_args *uap;
    167 	int *retval;
    168 {
    169 	register struct mbuf *m;
    170 	register int siz;
    171 	register struct ucred *cr;
    172 	struct file *fp;
    173 	struct mbuf *mreq, *mrep, *nam, *md;
    174 	struct mbuf msk, mtch;
    175 	struct socket *so;
    176 	caddr_t dpos;
    177 	int procid, repstat, error, cacherep, wascomp;
    178 	u_long retxid;
    179 
    180 	/*
    181 	 * Must be super user
    182 	 */
    183 	if (error = suser(p->p_ucred, &p->p_acflag))
    184 		return (error);
    185 	if (error = getsock(p->p_fd, uap->s, &fp))
    186 		return (error);
    187 	so = (struct socket *)fp->f_data;
    188 	if (sosendallatonce(so))
    189 		siz = NFS_MAXPACKET;
    190 	else
    191 		siz = NFS_MAXPACKET + sizeof(u_long);
    192 	if (error = soreserve(so, siz, siz))
    193 		goto bad;
    194 	if (error = sockargs(&nam, uap->mskval, uap->msklen, MT_SONAME))
    195 		goto bad;
    196 	bcopy((caddr_t)nam, (caddr_t)&msk, sizeof (struct mbuf));
    197 	msk.m_data = msk.m_dat;
    198 	m_freem(nam);
    199 	if (error = sockargs(&nam, uap->mtchval, uap->mtchlen, MT_SONAME))
    200 		goto bad;
    201 	bcopy((caddr_t)nam, (caddr_t)&mtch, sizeof (struct mbuf));
    202 	mtch.m_data = mtch.m_dat;
    203 	m_freem(nam);
    204 
    205 	/* Copy the cred so others don't see changes */
    206 	cr = p->p_ucred = crcopy(p->p_ucred);
    207 
    208 	/*
    209 	 * Set protocol specific options { for now TCP only } and
    210 	 * reserve some space. For datagram sockets, this can get called
    211 	 * repeatedly for the same socket, but that isn't harmful.
    212 	 */
    213 	if (so->so_proto->pr_flags & PR_CONNREQUIRED) {
    214 		MGET(m, M_WAIT, MT_SOOPTS);
    215 		*mtod(m, int *) = 1;
    216 		m->m_len = sizeof(int);
    217 		sosetopt(so, SOL_SOCKET, SO_KEEPALIVE, m);
    218 	}
    219 	if (so->so_proto->pr_domain->dom_family == AF_INET &&
    220 	    so->so_proto->pr_protocol == IPPROTO_TCP &&
    221 	    nfs_tcpnodelay) {
    222 		MGET(m, M_WAIT, MT_SOOPTS);
    223 		*mtod(m, int *) = 1;
    224 		m->m_len = sizeof(int);
    225 		sosetopt(so, IPPROTO_TCP, TCP_NODELAY, m);
    226 	}
    227 	so->so_rcv.sb_flags &= ~SB_NOINTR;
    228 	so->so_rcv.sb_timeo = 0;
    229 	so->so_snd.sb_flags &= ~SB_NOINTR;
    230 	so->so_snd.sb_timeo = 0;
    231 
    232 	/*
    233 	 * Just loop around doin our stuff until SIGKILL
    234 	 */
    235 	for (;;) {
    236 		if (error = nfs_getreq(so, nfs_prog, nfs_vers, NFS_NPROCS-1,
    237 		   &nam, &mrep, &md, &dpos, &retxid, &procid, cr,
    238 /* 08 Sep 92*/	   &msk, &mtch, &wascomp, &repstat)) {
    239 			if (nam)
    240 				m_freem(nam);
    241 			if (error == EPIPE || error == EINTR ||
    242 			    error == ERESTART) {
    243 				error = 0;
    244 				goto bad;
    245 			}
    246 			so->so_error = 0;
    247 			continue;
    248 		}
    249 
    250 		if (nam)
    251 			cacherep = nfsrv_getcache(nam, retxid, procid, &mreq);
    252 		else
    253 			cacherep = RC_DOIT;
    254 		switch (cacherep) {
    255 		case RC_DOIT:
    256 			if (error = (*(nfsrv_procs[procid]))(mrep, md, dpos,
    257 				cr, retxid, &mreq, &repstat, p)) {
    258 				nfsstats.srv_errs++;
    259 				if (nam) {
    260 					nfsrv_updatecache(nam, retxid, procid,
    261 						FALSE, repstat, mreq);
    262 					m_freem(nam);
    263 				}
    264 				break;
    265 			}
    266 			nfsstats.srvrpccnt[procid]++;
    267 			if (nam)
    268 				nfsrv_updatecache(nam, retxid, procid, TRUE,
    269 					repstat, mreq);
    270 			mrep = (struct mbuf *)0;
    271 		case RC_REPLY:
    272 			m = mreq;
    273 			siz = 0;
    274 			while (m) {
    275 				siz += m->m_len;
    276 				m = m->m_next;
    277 			}
    278 			if (siz <= 0 || siz > NFS_MAXPACKET) {
    279 				printf("mbuf siz=%d\n",siz);
    280 				panic("Bad nfs svc reply");
    281 			}
    282 			mreq->m_pkthdr.len = siz;
    283 			mreq->m_pkthdr.rcvif = (struct ifnet *)0;
    284 			if (wascomp && compressreply[procid]) {
    285 				mreq = nfs_compress(mreq);
    286 				siz = mreq->m_pkthdr.len;
    287 			}
    288 			/*
    289 			 * For non-atomic protocols, prepend a Sun RPC
    290 			 * Record Mark.
    291 			 */
    292 			if (!sosendallatonce(so)) {
    293 				M_PREPEND(mreq, sizeof(u_long), M_WAIT);
    294 				*mtod(mreq, u_long *) = htonl(0x80000000 | siz);
    295 			}
    296 			error = nfs_send(so, nam, mreq, (struct nfsreq *)0);
    297 			if (nam)
    298 				m_freem(nam);
    299 			if (mrep)
    300 				m_freem(mrep);
    301 			if (error) {
    302 				if (error == EPIPE || error == EINTR ||
    303 				    error == ERESTART)
    304 					goto bad;
    305 				so->so_error = 0;
    306 			}
    307 			break;
    308 		case RC_DROPIT:
    309 			m_freem(mrep);
    310 			m_freem(nam);
    311 			break;
    312 		};
    313 	}
    314 bad:
    315 	return (error);
    316 }
    317 
    318 #endif /* NFSSERVER */
    319 
    320 #ifdef NFSCLIENT
    321 
    322 /*
    323  * Nfs pseudo system call for asynchronous i/o daemons.
    324  * These babies just pretend to be disk interrupt service routines
    325  * for client nfs. They are mainly here for read ahead/write behind.
    326  * Never returns unless it fails or gets killed
    327  */
    328 /* ARGSUSED */
    329 async_daemon(p, uap, retval)
    330 	struct proc *p;
    331 	struct args *uap;
    332 	int *retval;
    333 {
    334 	register struct buf *bp, *dp;
    335 	register int i, myiod;
    336 	int error;
    337 
    338 	/*
    339 	 * Must be super user
    340 	 */
    341 	if (error = suser(p->p_ucred, &p->p_acflag))
    342 		return (error);
    343 	/*
    344 	 * Assign my position or return error if too many already running
    345 	 */
    346 	myiod = -1;
    347 	for (i = 0; i < NFS_MAXASYNCDAEMON; i++)
    348 		if (nfs_asyncdaemon[i] == 0) {
    349 			nfs_asyncdaemon[i]++;
    350 			myiod = i;
    351 			break;
    352 		}
    353 	if (myiod == -1)
    354 		return (EBUSY);
    355 	nfs_numasync++;
    356 	dp = &nfs_bqueue;
    357 	/*
    358 	 * Just loop around doin our stuff until SIGKILL
    359 	 */
    360 	for (;;) {
    361 		while (dp->b_actf == NULL && error == 0) {
    362 			nfs_iodwant[myiod] = p;
    363 			error = tsleep((caddr_t)&nfs_iodwant[myiod],
    364 				PWAIT | PCATCH, "nfsidl", 0);
    365 			nfs_iodwant[myiod] = (struct proc *)0;
    366 		}
    367 		while (dp->b_actf != NULL) {
    368 			/* Take one off the end of the list */
    369 			bp = dp->b_actl;
    370 			if (bp->b_actl == dp) {
    371 				dp->b_actf = dp->b_actl = (struct buf *)0;
    372 			} else {
    373 				dp->b_actl = bp->b_actl;
    374 				bp->b_actl->b_actf = dp;
    375 			}
    376 			(void) nfs_doio(bp);
    377 		}
    378 		if (error) {
    379 			nfs_asyncdaemon[myiod] = 0;
    380 			nfs_numasync--;
    381 			return (error);
    382 		}
    383 	}
    384 }
    385 
    386 #endif /* NFSCLIENT*/
    387 
    388