xref: /netbsd-src/sys/nfs/nfs_syscalls.c (revision cda4f8f6ee55684e8d311b86c99ea59191e6b74f)
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 1993/07/17 15:56:59 mycroft 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 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