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