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