xref: /netbsd-src/sys/nfs/nfs_syscalls.c (revision ae1bfcddc410612bc8c58b807e1830becb69a24c)
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.9 1994/02/14 05:58:29 cgd Exp $
38  */
39 
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/kernel.h>
43 #include <sys/file.h>
44 #include <sys/stat.h>
45 #include <sys/namei.h>
46 #include <sys/vnode.h>
47 #include <sys/mount.h>
48 #include <sys/proc.h>
49 #include <sys/malloc.h>
50 #include <sys/buf.h>
51 #include <sys/mbuf.h>
52 #include <sys/socket.h>
53 #include <sys/socketvar.h>
54 #include <sys/domain.h>
55 #include <sys/protosw.h>
56 
57 #include <netinet/in.h>
58 #include <netinet/tcp.h>
59 
60 #include <nfs/nfsv2.h>
61 #include <nfs/nfs.h>
62 #include <nfs/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 = crdup(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 		    &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 	crfree(cr);
316 	return (error);
317 }
318 
319 #endif /* NFSSERVER */
320 
321 #ifdef NFSCLIENT
322 
323 /*
324  * Nfs pseudo system call for asynchronous i/o daemons.
325  * These babies just pretend to be disk interrupt service routines
326  * for client nfs. They are mainly here for read ahead/write behind.
327  * Never returns unless it fails or gets killed
328  */
329 /* ARGSUSED */
330 async_daemon(p, uap, retval)
331 	struct proc *p;
332 	struct args *uap;
333 	int *retval;
334 {
335 	register struct buf *bp, *dp;
336 	register int i, myiod;
337 	int error;
338 
339 	/*
340 	 * Must be super user
341 	 */
342 	if (error = suser(p->p_ucred, &p->p_acflag))
343 		return (error);
344 	/*
345 	 * Assign my position or return error if too many already running
346 	 */
347 	myiod = -1;
348 	for (i = 0; i < NFS_MAXASYNCDAEMON; i++)
349 		if (nfs_asyncdaemon[i] == 0) {
350 			nfs_asyncdaemon[i]++;
351 			myiod = i;
352 			break;
353 		}
354 	if (myiod == -1)
355 		return (EBUSY);
356 	nfs_numasync++;
357 	/*
358 	 * Just loop around doin our stuff until SIGKILL
359 	 */
360 	for (;;) {
361 		while (nfs_bqueue.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 (nfs_bqueue.b_actf != NULL) {
368 			/* Take one off the front of the list */
369 			bp = nfs_bqueue.b_actf;
370 			if (dp = bp->b_actf)
371 				dp->b_actb = bp->b_actb;
372 			else
373 				nfs_bqueue.b_actb = bp->b_actb;
374 			*bp->b_actb = dp;
375 			(void) nfs_doio(bp);
376 		}
377 		if (error) {
378 			nfs_asyncdaemon[myiod] = 0;
379 			nfs_numasync--;
380 			return (error);
381 		}
382 	}
383 }
384 
385 #endif /* NFSCLIENT*/
386 
387