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