xref: /csrg-svn/sys/nfs/nfs_syscalls.c (revision 43354)
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