nfs_syscalls.c revision 1.6.4.1 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.4.1 1993/11/14 22:22:29 mycroft 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 = 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