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