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