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