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