nfs_syscalls.c revision 1.8 1 1.1 cgd /*
2 1.1 cgd * Copyright (c) 1989 The Regents of the University of California.
3 1.1 cgd * All rights reserved.
4 1.1 cgd *
5 1.1 cgd * This code is derived from software contributed to Berkeley by
6 1.1 cgd * Rick Macklem at The University of Guelph.
7 1.1 cgd *
8 1.1 cgd * Redistribution and use in source and binary forms, with or without
9 1.1 cgd * modification, are permitted provided that the following conditions
10 1.1 cgd * are met:
11 1.1 cgd * 1. Redistributions of source code must retain the above copyright
12 1.1 cgd * notice, this list of conditions and the following disclaimer.
13 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright
14 1.1 cgd * notice, this list of conditions and the following disclaimer in the
15 1.1 cgd * documentation and/or other materials provided with the distribution.
16 1.1 cgd * 3. All advertising materials mentioning features or use of this software
17 1.1 cgd * must display the following acknowledgement:
18 1.1 cgd * This product includes software developed by the University of
19 1.1 cgd * California, Berkeley and its contributors.
20 1.1 cgd * 4. Neither the name of the University nor the names of its contributors
21 1.1 cgd * may be used to endorse or promote products derived from this software
22 1.1 cgd * without specific prior written permission.
23 1.1 cgd *
24 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 1.1 cgd * SUCH DAMAGE.
35 1.1 cgd *
36 1.4 cgd * from: @(#)nfs_syscalls.c 7.26 (Berkeley) 4/16/91
37 1.8 mycroft * $Id: nfs_syscalls.c,v 1.8 1994/02/06 11:28:39 mycroft Exp $
38 1.1 cgd */
39 1.1 cgd
40 1.7 mycroft #include <sys/param.h>
41 1.7 mycroft #include <sys/systm.h>
42 1.7 mycroft #include <sys/kernel.h>
43 1.7 mycroft #include <sys/file.h>
44 1.7 mycroft #include <sys/stat.h>
45 1.7 mycroft #include <sys/namei.h>
46 1.7 mycroft #include <sys/vnode.h>
47 1.7 mycroft #include <sys/mount.h>
48 1.7 mycroft #include <sys/proc.h>
49 1.7 mycroft #include <sys/malloc.h>
50 1.7 mycroft #include <sys/buf.h>
51 1.7 mycroft #include <sys/mbuf.h>
52 1.7 mycroft #include <sys/socket.h>
53 1.7 mycroft #include <sys/socketvar.h>
54 1.7 mycroft #include <sys/domain.h>
55 1.7 mycroft #include <sys/protosw.h>
56 1.1 cgd
57 1.7 mycroft #include <netinet/in.h>
58 1.7 mycroft #include <netinet/tcp.h>
59 1.1 cgd
60 1.7 mycroft #include <nfs/nfsv2.h>
61 1.7 mycroft #include <nfs/nfs.h>
62 1.7 mycroft #include <nfs/nfsrvcache.h>
63 1.1 cgd
64 1.1 cgd /* Global defs. */
65 1.1 cgd extern u_long nfs_prog, nfs_vers;
66 1.1 cgd extern int (*nfsrv_procs[NFS_NPROCS])();
67 1.1 cgd extern struct buf nfs_bqueue;
68 1.1 cgd extern int nfs_numasync;
69 1.1 cgd extern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON];
70 1.1 cgd extern int nfs_tcpnodelay;
71 1.1 cgd struct mbuf *nfs_compress();
72 1.1 cgd
73 1.1 cgd #define TRUE 1
74 1.1 cgd #define FALSE 0
75 1.1 cgd
76 1.1 cgd static int nfs_asyncdaemon[NFS_MAXASYNCDAEMON];
77 1.1 cgd static int compressreply[NFS_NPROCS] = {
78 1.1 cgd FALSE,
79 1.1 cgd TRUE,
80 1.1 cgd TRUE,
81 1.1 cgd FALSE,
82 1.1 cgd TRUE,
83 1.1 cgd TRUE,
84 1.1 cgd FALSE,
85 1.1 cgd FALSE,
86 1.1 cgd TRUE,
87 1.1 cgd TRUE,
88 1.1 cgd TRUE,
89 1.1 cgd TRUE,
90 1.1 cgd TRUE,
91 1.1 cgd TRUE,
92 1.1 cgd TRUE,
93 1.1 cgd TRUE,
94 1.1 cgd TRUE,
95 1.1 cgd TRUE,
96 1.1 cgd };
97 1.3 glass
98 1.3 glass #ifdef NFSCLIENT
99 1.3 glass
100 1.1 cgd /*
101 1.1 cgd * NFS server system calls
102 1.1 cgd * getfh() lives here too, but maybe should move to kern/vfs_syscalls.c
103 1.1 cgd */
104 1.1 cgd
105 1.1 cgd /*
106 1.1 cgd * Get file handle system call
107 1.1 cgd */
108 1.6 mycroft struct getfh_args {
109 1.6 mycroft char *fname;
110 1.6 mycroft fhandle_t *fhp;
111 1.6 mycroft };
112 1.6 mycroft
113 1.1 cgd /* ARGSUSED */
114 1.1 cgd getfh(p, uap, retval)
115 1.1 cgd struct proc *p;
116 1.6 mycroft register struct getfh_args *uap;
117 1.1 cgd int *retval;
118 1.1 cgd {
119 1.1 cgd register struct nameidata *ndp;
120 1.1 cgd register struct vnode *vp;
121 1.1 cgd fhandle_t fh;
122 1.1 cgd int error;
123 1.1 cgd struct nameidata nd;
124 1.1 cgd
125 1.1 cgd /*
126 1.1 cgd * Must be super user
127 1.1 cgd */
128 1.1 cgd if (error = suser(p->p_ucred, &p->p_acflag))
129 1.1 cgd return (error);
130 1.1 cgd ndp = &nd;
131 1.1 cgd ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW;
132 1.1 cgd ndp->ni_segflg = UIO_USERSPACE;
133 1.1 cgd ndp->ni_dirp = uap->fname;
134 1.1 cgd if (error = namei(ndp, p))
135 1.1 cgd return (error);
136 1.1 cgd vp = ndp->ni_vp;
137 1.1 cgd bzero((caddr_t)&fh, sizeof(fh));
138 1.1 cgd fh.fh_fsid = vp->v_mount->mnt_stat.f_fsid;
139 1.1 cgd error = VFS_VPTOFH(vp, &fh.fh_fid);
140 1.1 cgd vput(vp);
141 1.1 cgd if (error)
142 1.1 cgd return (error);
143 1.1 cgd error = copyout((caddr_t)&fh, (caddr_t)uap->fhp, sizeof (fh));
144 1.1 cgd return (error);
145 1.1 cgd }
146 1.1 cgd
147 1.3 glass #endif /*NFSCLIENT*/
148 1.3 glass
149 1.3 glass #ifdef NFSSERVER
150 1.3 glass
151 1.1 cgd /*
152 1.1 cgd * Nfs server psuedo system call for the nfsd's
153 1.1 cgd * Never returns unless it fails or gets killed
154 1.1 cgd */
155 1.6 mycroft struct nfssvc_args {
156 1.6 mycroft int s;
157 1.6 mycroft caddr_t mskval;
158 1.6 mycroft int msklen;
159 1.6 mycroft caddr_t mtchval;
160 1.6 mycroft int mtchlen;
161 1.6 mycroft };
162 1.6 mycroft
163 1.1 cgd /* ARGSUSED */
164 1.1 cgd nfssvc(p, uap, retval)
165 1.1 cgd struct proc *p;
166 1.6 mycroft register struct nfssvc_args *uap;
167 1.1 cgd int *retval;
168 1.1 cgd {
169 1.1 cgd register struct mbuf *m;
170 1.1 cgd register int siz;
171 1.1 cgd register struct ucred *cr;
172 1.1 cgd struct file *fp;
173 1.1 cgd struct mbuf *mreq, *mrep, *nam, *md;
174 1.1 cgd struct mbuf msk, mtch;
175 1.1 cgd struct socket *so;
176 1.1 cgd caddr_t dpos;
177 1.1 cgd int procid, repstat, error, cacherep, wascomp;
178 1.1 cgd u_long retxid;
179 1.1 cgd
180 1.1 cgd /*
181 1.1 cgd * Must be super user
182 1.1 cgd */
183 1.1 cgd if (error = suser(p->p_ucred, &p->p_acflag))
184 1.1 cgd return (error);
185 1.1 cgd if (error = getsock(p->p_fd, uap->s, &fp))
186 1.1 cgd return (error);
187 1.1 cgd so = (struct socket *)fp->f_data;
188 1.1 cgd if (sosendallatonce(so))
189 1.1 cgd siz = NFS_MAXPACKET;
190 1.1 cgd else
191 1.1 cgd siz = NFS_MAXPACKET + sizeof(u_long);
192 1.1 cgd if (error = soreserve(so, siz, siz))
193 1.1 cgd goto bad;
194 1.1 cgd if (error = sockargs(&nam, uap->mskval, uap->msklen, MT_SONAME))
195 1.1 cgd goto bad;
196 1.1 cgd bcopy((caddr_t)nam, (caddr_t)&msk, sizeof (struct mbuf));
197 1.1 cgd msk.m_data = msk.m_dat;
198 1.1 cgd m_freem(nam);
199 1.1 cgd if (error = sockargs(&nam, uap->mtchval, uap->mtchlen, MT_SONAME))
200 1.1 cgd goto bad;
201 1.1 cgd bcopy((caddr_t)nam, (caddr_t)&mtch, sizeof (struct mbuf));
202 1.1 cgd mtch.m_data = mtch.m_dat;
203 1.1 cgd m_freem(nam);
204 1.1 cgd
205 1.1 cgd /* Copy the cred so others don't see changes */
206 1.1 cgd cr = p->p_ucred = crcopy(p->p_ucred);
207 1.1 cgd
208 1.1 cgd /*
209 1.1 cgd * Set protocol specific options { for now TCP only } and
210 1.1 cgd * reserve some space. For datagram sockets, this can get called
211 1.1 cgd * repeatedly for the same socket, but that isn't harmful.
212 1.1 cgd */
213 1.1 cgd if (so->so_proto->pr_flags & PR_CONNREQUIRED) {
214 1.1 cgd MGET(m, M_WAIT, MT_SOOPTS);
215 1.1 cgd *mtod(m, int *) = 1;
216 1.1 cgd m->m_len = sizeof(int);
217 1.1 cgd sosetopt(so, SOL_SOCKET, SO_KEEPALIVE, m);
218 1.1 cgd }
219 1.1 cgd if (so->so_proto->pr_domain->dom_family == AF_INET &&
220 1.1 cgd so->so_proto->pr_protocol == IPPROTO_TCP &&
221 1.1 cgd nfs_tcpnodelay) {
222 1.1 cgd MGET(m, M_WAIT, MT_SOOPTS);
223 1.1 cgd *mtod(m, int *) = 1;
224 1.1 cgd m->m_len = sizeof(int);
225 1.1 cgd sosetopt(so, IPPROTO_TCP, TCP_NODELAY, m);
226 1.1 cgd }
227 1.1 cgd so->so_rcv.sb_flags &= ~SB_NOINTR;
228 1.1 cgd so->so_rcv.sb_timeo = 0;
229 1.1 cgd so->so_snd.sb_flags &= ~SB_NOINTR;
230 1.1 cgd so->so_snd.sb_timeo = 0;
231 1.1 cgd
232 1.1 cgd /*
233 1.1 cgd * Just loop around doin our stuff until SIGKILL
234 1.1 cgd */
235 1.1 cgd for (;;) {
236 1.1 cgd if (error = nfs_getreq(so, nfs_prog, nfs_vers, NFS_NPROCS-1,
237 1.1 cgd &nam, &mrep, &md, &dpos, &retxid, &procid, cr,
238 1.2 cgd /* 08 Sep 92*/ &msk, &mtch, &wascomp, &repstat)) {
239 1.1 cgd if (nam)
240 1.1 cgd m_freem(nam);
241 1.1 cgd if (error == EPIPE || error == EINTR ||
242 1.1 cgd error == ERESTART) {
243 1.1 cgd error = 0;
244 1.1 cgd goto bad;
245 1.1 cgd }
246 1.1 cgd so->so_error = 0;
247 1.1 cgd continue;
248 1.1 cgd }
249 1.1 cgd
250 1.1 cgd if (nam)
251 1.1 cgd cacherep = nfsrv_getcache(nam, retxid, procid, &mreq);
252 1.1 cgd else
253 1.1 cgd cacherep = RC_DOIT;
254 1.1 cgd switch (cacherep) {
255 1.1 cgd case RC_DOIT:
256 1.1 cgd if (error = (*(nfsrv_procs[procid]))(mrep, md, dpos,
257 1.1 cgd cr, retxid, &mreq, &repstat, p)) {
258 1.1 cgd nfsstats.srv_errs++;
259 1.1 cgd if (nam) {
260 1.1 cgd nfsrv_updatecache(nam, retxid, procid,
261 1.1 cgd FALSE, repstat, mreq);
262 1.1 cgd m_freem(nam);
263 1.1 cgd }
264 1.1 cgd break;
265 1.1 cgd }
266 1.1 cgd nfsstats.srvrpccnt[procid]++;
267 1.1 cgd if (nam)
268 1.1 cgd nfsrv_updatecache(nam, retxid, procid, TRUE,
269 1.1 cgd repstat, mreq);
270 1.1 cgd mrep = (struct mbuf *)0;
271 1.1 cgd case RC_REPLY:
272 1.1 cgd m = mreq;
273 1.1 cgd siz = 0;
274 1.1 cgd while (m) {
275 1.1 cgd siz += m->m_len;
276 1.1 cgd m = m->m_next;
277 1.1 cgd }
278 1.1 cgd if (siz <= 0 || siz > NFS_MAXPACKET) {
279 1.1 cgd printf("mbuf siz=%d\n",siz);
280 1.1 cgd panic("Bad nfs svc reply");
281 1.1 cgd }
282 1.1 cgd mreq->m_pkthdr.len = siz;
283 1.1 cgd mreq->m_pkthdr.rcvif = (struct ifnet *)0;
284 1.1 cgd if (wascomp && compressreply[procid]) {
285 1.1 cgd mreq = nfs_compress(mreq);
286 1.1 cgd siz = mreq->m_pkthdr.len;
287 1.1 cgd }
288 1.1 cgd /*
289 1.1 cgd * For non-atomic protocols, prepend a Sun RPC
290 1.1 cgd * Record Mark.
291 1.1 cgd */
292 1.1 cgd if (!sosendallatonce(so)) {
293 1.1 cgd M_PREPEND(mreq, sizeof(u_long), M_WAIT);
294 1.1 cgd *mtod(mreq, u_long *) = htonl(0x80000000 | siz);
295 1.1 cgd }
296 1.1 cgd error = nfs_send(so, nam, mreq, (struct nfsreq *)0);
297 1.1 cgd if (nam)
298 1.1 cgd m_freem(nam);
299 1.1 cgd if (mrep)
300 1.1 cgd m_freem(mrep);
301 1.1 cgd if (error) {
302 1.1 cgd if (error == EPIPE || error == EINTR ||
303 1.1 cgd error == ERESTART)
304 1.1 cgd goto bad;
305 1.1 cgd so->so_error = 0;
306 1.1 cgd }
307 1.1 cgd break;
308 1.1 cgd case RC_DROPIT:
309 1.1 cgd m_freem(mrep);
310 1.1 cgd m_freem(nam);
311 1.1 cgd break;
312 1.1 cgd };
313 1.1 cgd }
314 1.1 cgd bad:
315 1.1 cgd return (error);
316 1.1 cgd }
317 1.1 cgd
318 1.3 glass #endif /* NFSSERVER */
319 1.3 glass
320 1.3 glass #ifdef NFSCLIENT
321 1.3 glass
322 1.1 cgd /*
323 1.1 cgd * Nfs pseudo system call for asynchronous i/o daemons.
324 1.1 cgd * These babies just pretend to be disk interrupt service routines
325 1.1 cgd * for client nfs. They are mainly here for read ahead/write behind.
326 1.1 cgd * Never returns unless it fails or gets killed
327 1.1 cgd */
328 1.1 cgd /* ARGSUSED */
329 1.1 cgd async_daemon(p, uap, retval)
330 1.1 cgd struct proc *p;
331 1.1 cgd struct args *uap;
332 1.1 cgd int *retval;
333 1.1 cgd {
334 1.1 cgd register struct buf *bp, *dp;
335 1.1 cgd register int i, myiod;
336 1.1 cgd int error;
337 1.1 cgd
338 1.1 cgd /*
339 1.1 cgd * Must be super user
340 1.1 cgd */
341 1.1 cgd if (error = suser(p->p_ucred, &p->p_acflag))
342 1.1 cgd return (error);
343 1.1 cgd /*
344 1.1 cgd * Assign my position or return error if too many already running
345 1.1 cgd */
346 1.1 cgd myiod = -1;
347 1.1 cgd for (i = 0; i < NFS_MAXASYNCDAEMON; i++)
348 1.1 cgd if (nfs_asyncdaemon[i] == 0) {
349 1.1 cgd nfs_asyncdaemon[i]++;
350 1.1 cgd myiod = i;
351 1.1 cgd break;
352 1.1 cgd }
353 1.1 cgd if (myiod == -1)
354 1.1 cgd return (EBUSY);
355 1.1 cgd nfs_numasync++;
356 1.1 cgd /*
357 1.1 cgd * Just loop around doin our stuff until SIGKILL
358 1.1 cgd */
359 1.1 cgd for (;;) {
360 1.8 mycroft while (nfs_bqueue.b_actf == NULL && error == 0) {
361 1.1 cgd nfs_iodwant[myiod] = p;
362 1.1 cgd error = tsleep((caddr_t)&nfs_iodwant[myiod],
363 1.1 cgd PWAIT | PCATCH, "nfsidl", 0);
364 1.1 cgd nfs_iodwant[myiod] = (struct proc *)0;
365 1.1 cgd }
366 1.8 mycroft while (nfs_bqueue.b_actf != NULL) {
367 1.8 mycroft /* Take one off the front of the list */
368 1.8 mycroft bp = nfs_bqueue.b_actf;
369 1.8 mycroft if (dp = bp->b_actf)
370 1.8 mycroft dp->b_actb = bp->b_actb;
371 1.8 mycroft else
372 1.8 mycroft nfs_bqueue.b_actb = bp->b_actb;
373 1.8 mycroft *bp->b_actb = dp;
374 1.1 cgd (void) nfs_doio(bp);
375 1.1 cgd }
376 1.1 cgd if (error) {
377 1.1 cgd nfs_asyncdaemon[myiod] = 0;
378 1.1 cgd nfs_numasync--;
379 1.1 cgd return (error);
380 1.1 cgd }
381 1.1 cgd }
382 1.1 cgd }
383 1.3 glass
384 1.3 glass #endif /* NFSCLIENT*/
385 1.3 glass
386