Deleted Added
full compact
nfs_srvsubs.c (6417) nfs_srvsubs.c (6420)
1/*
2 * Copyright (c) 1989, 1993
3 * The Regents of the University of California. 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_subs.c 8.3 (Berkeley) 1/4/94
1/*
2 * Copyright (c) 1989, 1993
3 * The Regents of the University of California. 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_subs.c 8.3 (Berkeley) 1/4/94
37 * $Id: nfs_subs.c,v 1.9 1995/02/06 02:20:40 davidg Exp $
37 * $Id: nfs_subs.c,v 1.10 1995/02/15 03:40:00 davidg Exp $
38 */
39
40/*
41 * These functions support the macros and help fiddle mbuf chains for
42 * the nfs op functions. They do things like create the rpc header and
43 * copy data between mbuf chains and uio lists.
44 */
45#include <sys/param.h>
46#include <sys/proc.h>
47#include <sys/systm.h>
48#include <sys/kernel.h>
49#include <sys/mount.h>
50#include <sys/vnode.h>
51#include <sys/namei.h>
52#include <sys/mbuf.h>
53#include <sys/socket.h>
54#include <sys/stat.h>
55#ifdef VFS_LKM
56#include <sys/sysent.h>
57#include <sys/syscall.h>
58#endif
59
60#include <vm/vm.h>
61
62#include <nfs/rpcv2.h>
63#include <nfs/nfsv2.h>
64#include <nfs/nfsnode.h>
65#include <nfs/nfs.h>
66#include <nfs/xdr_subs.h>
67#include <nfs/nfsm_subs.h>
68#include <nfs/nfsmount.h>
69#include <nfs/nqnfs.h>
70#include <nfs/nfsrtt.h>
71
72#include <miscfs/specfs/specdev.h>
73
38 */
39
40/*
41 * These functions support the macros and help fiddle mbuf chains for
42 * the nfs op functions. They do things like create the rpc header and
43 * copy data between mbuf chains and uio lists.
44 */
45#include <sys/param.h>
46#include <sys/proc.h>
47#include <sys/systm.h>
48#include <sys/kernel.h>
49#include <sys/mount.h>
50#include <sys/vnode.h>
51#include <sys/namei.h>
52#include <sys/mbuf.h>
53#include <sys/socket.h>
54#include <sys/stat.h>
55#ifdef VFS_LKM
56#include <sys/sysent.h>
57#include <sys/syscall.h>
58#endif
59
60#include <vm/vm.h>
61
62#include <nfs/rpcv2.h>
63#include <nfs/nfsv2.h>
64#include <nfs/nfsnode.h>
65#include <nfs/nfs.h>
66#include <nfs/xdr_subs.h>
67#include <nfs/nfsm_subs.h>
68#include <nfs/nfsmount.h>
69#include <nfs/nqnfs.h>
70#include <nfs/nfsrtt.h>
71
72#include <miscfs/specfs/specdev.h>
73
74#include <vm/vnode_pager.h>
75
74#include <netinet/in.h>
75#ifdef ISO
76#include <netiso/iso.h>
77#endif
78
79#define TRUE 1
80#define FALSE 0
81
82/*
83 * Data items converted to xdr at startup, since they are constant
84 * This is kinda hokey, but may save a little time doing byte swaps
85 */
86u_long nfs_procids[NFS_NPROCS];
87u_long nfs_xdrneg1;
88u_long rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr,
89 rpc_mismatch, rpc_auth_unix, rpc_msgaccepted, rpc_rejectedcred,
90 rpc_auth_kerb;
91u_long nfs_vers, nfs_prog, nfs_true, nfs_false;
92
93/* And other global data */
94static u_long nfs_xid = 0;
95enum vtype ntov_type[7] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON };
96extern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON];
97extern int nqnfs_piggy[NFS_NPROCS];
98extern struct nfsrtt nfsrtt;
99extern time_t nqnfsstarttime;
100extern u_long nqnfs_prog, nqnfs_vers;
101extern int nqsrv_clockskew;
102extern int nqsrv_writeslack;
103extern int nqsrv_maxlease;
104
105#ifdef VFS_LKM
106struct getfh_args;
107extern int getfh(struct proc *, struct getfh_args *, int *);
108struct nfssvc_args;
109extern int nfssvc(struct proc *, struct nfssvc_args *, int *);
110#endif
111
112LIST_HEAD(nfsnodehashhead, nfsnode);
113
114/*
115 * Create the header for an rpc request packet
116 * The hsiz is the size of the rest of the nfs request header.
117 * (just used to decide if a cluster is a good idea)
118 */
119struct mbuf *
120nfsm_reqh(vp, procid, hsiz, bposp)
121 struct vnode *vp;
122 u_long procid;
123 int hsiz;
124 caddr_t *bposp;
125{
126 register struct mbuf *mb;
127 register u_long *tl;
128 register caddr_t bpos;
129 struct mbuf *mb2;
130 struct nfsmount *nmp;
131 int nqflag;
132
133 MGET(mb, M_WAIT, MT_DATA);
134 if (hsiz >= MINCLSIZE)
135 MCLGET(mb, M_WAIT);
136 mb->m_len = 0;
137 bpos = mtod(mb, caddr_t);
138
139 /*
140 * For NQNFS, add lease request.
141 */
142 if (vp) {
143 nmp = VFSTONFS(vp->v_mount);
144 if (nmp->nm_flag & NFSMNT_NQNFS) {
145 nqflag = NQNFS_NEEDLEASE(vp, procid);
146 if (nqflag) {
147 nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
148 *tl++ = txdr_unsigned(nqflag);
149 *tl = txdr_unsigned(nmp->nm_leaseterm);
150 } else {
151 nfsm_build(tl, u_long *, NFSX_UNSIGNED);
152 *tl = 0;
153 }
154 }
155 }
156 /* Finally, return values */
157 *bposp = bpos;
158 return (mb);
159}
160
161/*
162 * Build the RPC header and fill in the authorization info.
163 * The authorization string argument is only used when the credentials
164 * come from outside of the kernel.
165 * Returns the head of the mbuf list.
166 */
167struct mbuf *
168nfsm_rpchead(cr, nqnfs, procid, auth_type, auth_len, auth_str, mrest,
169 mrest_len, mbp, xidp)
170 register struct ucred *cr;
171 int nqnfs;
172 int procid;
173 int auth_type;
174 int auth_len;
175 char *auth_str;
176 struct mbuf *mrest;
177 int mrest_len;
178 struct mbuf **mbp;
179 u_long *xidp;
180{
181 register struct mbuf *mb;
182 register u_long *tl;
183 register caddr_t bpos;
184 register int i;
185 struct mbuf *mreq, *mb2;
186 int siz, grpsiz, authsiz;
187
188 authsiz = nfsm_rndup(auth_len);
189 if (auth_type == RPCAUTH_NQNFS)
190 authsiz += 2 * NFSX_UNSIGNED;
191 MGETHDR(mb, M_WAIT, MT_DATA);
192 if ((authsiz + 10*NFSX_UNSIGNED) >= MINCLSIZE) {
193 MCLGET(mb, M_WAIT);
194 } else if ((authsiz + 10*NFSX_UNSIGNED) < MHLEN) {
195 MH_ALIGN(mb, authsiz + 10*NFSX_UNSIGNED);
196 } else {
197 MH_ALIGN(mb, 8*NFSX_UNSIGNED);
198 }
199 mb->m_len = 0;
200 mreq = mb;
201 bpos = mtod(mb, caddr_t);
202
203 /*
204 * First the RPC header.
205 */
206 nfsm_build(tl, u_long *, 8*NFSX_UNSIGNED);
207 if (++nfs_xid == 0)
208 nfs_xid++;
209 *tl++ = *xidp = txdr_unsigned(nfs_xid);
210 *tl++ = rpc_call;
211 *tl++ = rpc_vers;
212 if (nqnfs) {
213 *tl++ = txdr_unsigned(NQNFS_PROG);
214 *tl++ = txdr_unsigned(NQNFS_VER1);
215 } else {
216 *tl++ = txdr_unsigned(NFS_PROG);
217 *tl++ = txdr_unsigned(NFS_VER2);
218 }
219 *tl++ = txdr_unsigned(procid);
220
221 /*
222 * And then the authorization cred.
223 */
224 *tl++ = txdr_unsigned(auth_type);
225 *tl = txdr_unsigned(authsiz);
226 switch (auth_type) {
227 case RPCAUTH_UNIX:
228 nfsm_build(tl, u_long *, auth_len);
229 *tl++ = 0; /* stamp ?? */
230 *tl++ = 0; /* NULL hostname */
231 *tl++ = txdr_unsigned(cr->cr_uid);
232 *tl++ = txdr_unsigned(cr->cr_groups[0]);
233 grpsiz = (auth_len >> 2) - 5;
234 *tl++ = txdr_unsigned(grpsiz);
235 for (i = 1; i <= grpsiz; i++)
236 *tl++ = txdr_unsigned(cr->cr_groups[i]);
237 break;
238 case RPCAUTH_NQNFS:
239 nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
240 *tl++ = txdr_unsigned(cr->cr_uid);
241 *tl = txdr_unsigned(auth_len);
242 siz = auth_len;
243 while (siz > 0) {
244 if (M_TRAILINGSPACE(mb) == 0) {
245 MGET(mb2, M_WAIT, MT_DATA);
246 if (siz >= MINCLSIZE)
247 MCLGET(mb2, M_WAIT);
248 mb->m_next = mb2;
249 mb = mb2;
250 mb->m_len = 0;
251 bpos = mtod(mb, caddr_t);
252 }
253 i = min(siz, M_TRAILINGSPACE(mb));
254 bcopy(auth_str, bpos, i);
255 mb->m_len += i;
256 auth_str += i;
257 bpos += i;
258 siz -= i;
259 }
260 if ((siz = (nfsm_rndup(auth_len) - auth_len)) > 0) {
261 for (i = 0; i < siz; i++)
262 *bpos++ = '\0';
263 mb->m_len += siz;
264 }
265 break;
266 };
267 nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
268 *tl++ = txdr_unsigned(RPCAUTH_NULL);
269 *tl = 0;
270 mb->m_next = mrest;
271 mreq->m_pkthdr.len = authsiz + 10*NFSX_UNSIGNED + mrest_len;
272 mreq->m_pkthdr.rcvif = (struct ifnet *)0;
273 *mbp = mb;
274 return (mreq);
275}
276
277/*
278 * copies mbuf chain to the uio scatter/gather list
279 */
280int
281nfsm_mbuftouio(mrep, uiop, siz, dpos)
282 struct mbuf **mrep;
283 register struct uio *uiop;
284 int siz;
285 caddr_t *dpos;
286{
287 register char *mbufcp, *uiocp;
288 register int xfer, left, len;
289 register struct mbuf *mp;
290 long uiosiz, rem;
291 int error = 0;
292
293 mp = *mrep;
294 mbufcp = *dpos;
295 len = mtod(mp, caddr_t)+mp->m_len-mbufcp;
296 rem = nfsm_rndup(siz)-siz;
297 while (siz > 0) {
298 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
299 return (EFBIG);
300 left = uiop->uio_iov->iov_len;
301 uiocp = uiop->uio_iov->iov_base;
302 if (left > siz)
303 left = siz;
304 uiosiz = left;
305 while (left > 0) {
306 while (len == 0) {
307 mp = mp->m_next;
308 if (mp == NULL)
309 return (EBADRPC);
310 mbufcp = mtod(mp, caddr_t);
311 len = mp->m_len;
312 }
313 xfer = (left > len) ? len : left;
314#ifdef notdef
315 /* Not Yet.. */
316 if (uiop->uio_iov->iov_op != NULL)
317 (*(uiop->uio_iov->iov_op))
318 (mbufcp, uiocp, xfer);
319 else
320#endif
321 if (uiop->uio_segflg == UIO_SYSSPACE)
322 bcopy(mbufcp, uiocp, xfer);
323 else
324 copyout(mbufcp, uiocp, xfer);
325 left -= xfer;
326 len -= xfer;
327 mbufcp += xfer;
328 uiocp += xfer;
329 uiop->uio_offset += xfer;
330 uiop->uio_resid -= xfer;
331 }
332 if (uiop->uio_iov->iov_len <= siz) {
333 uiop->uio_iovcnt--;
334 uiop->uio_iov++;
335 } else {
336 uiop->uio_iov->iov_base += uiosiz;
337 uiop->uio_iov->iov_len -= uiosiz;
338 }
339 siz -= uiosiz;
340 }
341 *dpos = mbufcp;
342 *mrep = mp;
343 if (rem > 0) {
344 if (len < rem)
345 error = nfs_adv(mrep, dpos, rem, len);
346 else
347 *dpos += rem;
348 }
349 return (error);
350}
351
352/*
353 * copies a uio scatter/gather list to an mbuf chain...
354 */
355int
356nfsm_uiotombuf(uiop, mq, siz, bpos)
357 register struct uio *uiop;
358 struct mbuf **mq;
359 int siz;
360 caddr_t *bpos;
361{
362 register char *uiocp;
363 register struct mbuf *mp, *mp2;
364 register int xfer, left, mlen;
365 int uiosiz, clflg, rem;
366 char *cp;
367
368 if (siz > MLEN) /* or should it >= MCLBYTES ?? */
369 clflg = 1;
370 else
371 clflg = 0;
372 rem = nfsm_rndup(siz)-siz;
373 mp = mp2 = *mq;
374 while (siz > 0) {
375 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
376 return (EINVAL);
377 left = uiop->uio_iov->iov_len;
378 uiocp = uiop->uio_iov->iov_base;
379 if (left > siz)
380 left = siz;
381 uiosiz = left;
382 while (left > 0) {
383 mlen = M_TRAILINGSPACE(mp);
384 if (mlen == 0) {
385 MGET(mp, M_WAIT, MT_DATA);
386 if (clflg)
387 MCLGET(mp, M_WAIT);
388 mp->m_len = 0;
389 mp2->m_next = mp;
390 mp2 = mp;
391 mlen = M_TRAILINGSPACE(mp);
392 }
393 xfer = (left > mlen) ? mlen : left;
394#ifdef notdef
395 /* Not Yet.. */
396 if (uiop->uio_iov->iov_op != NULL)
397 (*(uiop->uio_iov->iov_op))
398 (uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
399 else
400#endif
401 if (uiop->uio_segflg == UIO_SYSSPACE)
402 bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
403 else
404 copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
405 mp->m_len += xfer;
406 left -= xfer;
407 uiocp += xfer;
408 uiop->uio_offset += xfer;
409 uiop->uio_resid -= xfer;
410 }
411 if (uiop->uio_iov->iov_len <= siz) {
412 uiop->uio_iovcnt--;
413 uiop->uio_iov++;
414 } else {
415 uiop->uio_iov->iov_base += uiosiz;
416 uiop->uio_iov->iov_len -= uiosiz;
417 }
418 siz -= uiosiz;
419 }
420 if (rem > 0) {
421 if (rem > M_TRAILINGSPACE(mp)) {
422 MGET(mp, M_WAIT, MT_DATA);
423 mp->m_len = 0;
424 mp2->m_next = mp;
425 }
426 cp = mtod(mp, caddr_t)+mp->m_len;
427 for (left = 0; left < rem; left++)
428 *cp++ = '\0';
429 mp->m_len += rem;
430 *bpos = cp;
431 } else
432 *bpos = mtod(mp, caddr_t)+mp->m_len;
433 *mq = mp;
434 return (0);
435}
436
437/*
438 * Help break down an mbuf chain by setting the first siz bytes contiguous
439 * pointed to by returned val.
440 * This is used by the macros nfsm_dissect and nfsm_dissecton for tough
441 * cases. (The macros use the vars. dpos and dpos2)
442 */
443int
444nfsm_disct(mdp, dposp, siz, left, cp2)
445 struct mbuf **mdp;
446 caddr_t *dposp;
447 int siz;
448 int left;
449 caddr_t *cp2;
450{
451 register struct mbuf *mp, *mp2;
452 register int siz2, xfer;
453 register caddr_t p;
454
455 mp = *mdp;
456 while (left == 0) {
457 *mdp = mp = mp->m_next;
458 if (mp == NULL)
459 return (EBADRPC);
460 left = mp->m_len;
461 *dposp = mtod(mp, caddr_t);
462 }
463 if (left >= siz) {
464 *cp2 = *dposp;
465 *dposp += siz;
466 } else if (mp->m_next == NULL) {
467 return (EBADRPC);
468 } else if (siz > MHLEN) {
469 panic("nfs S too big");
470 } else {
471 MGET(mp2, M_WAIT, MT_DATA);
472 mp2->m_next = mp->m_next;
473 mp->m_next = mp2;
474 mp->m_len -= left;
475 mp = mp2;
476 *cp2 = p = mtod(mp, caddr_t);
477 bcopy(*dposp, p, left); /* Copy what was left */
478 siz2 = siz-left;
479 p += left;
480 mp2 = mp->m_next;
481 /* Loop around copying up the siz2 bytes */
482 while (siz2 > 0) {
483 if (mp2 == NULL)
484 return (EBADRPC);
485 xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2;
486 if (xfer > 0) {
487 bcopy(mtod(mp2, caddr_t), p, xfer);
488 NFSMADV(mp2, xfer);
489 mp2->m_len -= xfer;
490 p += xfer;
491 siz2 -= xfer;
492 }
493 if (siz2 > 0)
494 mp2 = mp2->m_next;
495 }
496 mp->m_len = siz;
497 *mdp = mp2;
498 *dposp = mtod(mp2, caddr_t);
499 }
500 return (0);
501}
502
503/*
504 * Advance the position in the mbuf chain.
505 */
506int
507nfs_adv(mdp, dposp, offs, left)
508 struct mbuf **mdp;
509 caddr_t *dposp;
510 int offs;
511 int left;
512{
513 register struct mbuf *m;
514 register int s;
515
516 m = *mdp;
517 s = left;
518 while (s < offs) {
519 offs -= s;
520 m = m->m_next;
521 if (m == NULL)
522 return (EBADRPC);
523 s = m->m_len;
524 }
525 *mdp = m;
526 *dposp = mtod(m, caddr_t)+offs;
527 return (0);
528}
529
530/*
531 * Copy a string into mbufs for the hard cases...
532 */
533int
534nfsm_strtmbuf(mb, bpos, cp, siz)
535 struct mbuf **mb;
536 char **bpos;
537 char *cp;
538 long siz;
539{
540 register struct mbuf *m1 = 0, *m2;
541 long left, xfer, len, tlen;
542 u_long *tl;
543 int putsize;
544
545 putsize = 1;
546 m2 = *mb;
547 left = M_TRAILINGSPACE(m2);
548 if (left > 0) {
549 tl = ((u_long *)(*bpos));
550 *tl++ = txdr_unsigned(siz);
551 putsize = 0;
552 left -= NFSX_UNSIGNED;
553 m2->m_len += NFSX_UNSIGNED;
554 if (left > 0) {
555 bcopy(cp, (caddr_t) tl, left);
556 siz -= left;
557 cp += left;
558 m2->m_len += left;
559 left = 0;
560 }
561 }
562 /* Loop around adding mbufs */
563 while (siz > 0) {
564 MGET(m1, M_WAIT, MT_DATA);
565 if (siz > MLEN)
566 MCLGET(m1, M_WAIT);
567 m1->m_len = NFSMSIZ(m1);
568 m2->m_next = m1;
569 m2 = m1;
570 tl = mtod(m1, u_long *);
571 tlen = 0;
572 if (putsize) {
573 *tl++ = txdr_unsigned(siz);
574 m1->m_len -= NFSX_UNSIGNED;
575 tlen = NFSX_UNSIGNED;
576 putsize = 0;
577 }
578 if (siz < m1->m_len) {
579 len = nfsm_rndup(siz);
580 xfer = siz;
581 if (xfer < len)
582 *(tl+(xfer>>2)) = 0;
583 } else {
584 xfer = len = m1->m_len;
585 }
586 bcopy(cp, (caddr_t) tl, xfer);
587 m1->m_len = len+tlen;
588 siz -= xfer;
589 cp += xfer;
590 }
591 *mb = m1;
592 *bpos = mtod(m1, caddr_t)+m1->m_len;
593 return (0);
594}
595
596/*
597 * Called once to initialize data structures...
598 */
599int
600nfs_init()
601{
602 register int i;
603
604 nfsrtt.pos = 0;
605 rpc_vers = txdr_unsigned(RPC_VER2);
606 rpc_call = txdr_unsigned(RPC_CALL);
607 rpc_reply = txdr_unsigned(RPC_REPLY);
608 rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED);
609 rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED);
610 rpc_mismatch = txdr_unsigned(RPC_MISMATCH);
611 rpc_autherr = txdr_unsigned(RPC_AUTHERR);
612 rpc_rejectedcred = txdr_unsigned(AUTH_REJECTCRED);
613 rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX);
614 rpc_auth_kerb = txdr_unsigned(RPCAUTH_NQNFS);
615 nfs_vers = txdr_unsigned(NFS_VER2);
616 nfs_prog = txdr_unsigned(NFS_PROG);
617 nfs_true = txdr_unsigned(TRUE);
618 nfs_false = txdr_unsigned(FALSE);
619 nfs_xdrneg1 = txdr_unsigned(-1);
620 /* Loop thru nfs procids */
621 for (i = 0; i < NFS_NPROCS; i++)
622 nfs_procids[i] = txdr_unsigned(i);
623 /* Ensure async daemons disabled */
624 for (i = 0; i < NFS_MAXASYNCDAEMON; i++)
625 nfs_iodwant[i] = (struct proc *)0;
626 TAILQ_INIT(&nfs_bufq);
627 nfs_nhinit(); /* Init the nfsnode table */
628 nfsrv_init(0); /* Init server data structures */
629 nfsrv_initcache(); /* Init the server request cache */
630
631 /*
632 * Initialize the nqnfs server stuff.
633 */
634 if (nqnfsstarttime == 0) {
635 nqnfsstarttime = boottime.tv_sec + nqsrv_maxlease
636 + nqsrv_clockskew + nqsrv_writeslack;
637 NQLOADNOVRAM(nqnfsstarttime);
638 nqnfs_prog = txdr_unsigned(NQNFS_PROG);
639 nqnfs_vers = txdr_unsigned(NQNFS_VER1);
640 CIRCLEQ_INIT(&nqtimerhead);
641 nqfhhashtbl = hashinit(NQLCHSZ, M_NQLEASE, &nqfhhash);
642 }
643
644 /*
645 * Initialize reply list and start timer
646 */
647 TAILQ_INIT(&nfs_reqq);
648 nfs_timer(0);
649
650 /*
651 * Set up lease_check and lease_updatetime so that other parts
652 * of the system can call us, if we are loadable.
653 */
654 lease_check = nfs_lease_check;
655 lease_updatetime = nfs_lease_updatetime;
656 vfsconf[MOUNT_NFS]->vfc_refcount++; /* make us non-unloadable */
657#ifdef VFS_LKM
658 sysent[SYS_nfssvc].sy_narg = 2;
659 sysent[SYS_nfssvc].sy_call = nfssvc;
660 sysent[SYS_getfh].sy_narg = 2;
661 sysent[SYS_getfh].sy_call = getfh;
662#endif
663
664 return (0);
665}
666
667/*
668 * Attribute cache routines.
669 * nfs_loadattrcache() - loads or updates the cache contents from attributes
670 * that are on the mbuf list
671 * nfs_getattrcache() - returns valid attributes if found in cache, returns
672 * error otherwise
673 */
674
675/*
676 * Load the attribute cache (that lives in the nfsnode entry) with
677 * the values on the mbuf list and
678 * Iff vap not NULL
679 * copy the attributes to *vaper
680 */
681int
682nfs_loadattrcache(vpp, mdp, dposp, vaper)
683 struct vnode **vpp;
684 struct mbuf **mdp;
685 caddr_t *dposp;
686 struct vattr *vaper;
687{
688 register struct vnode *vp = *vpp;
689 register struct vattr *vap;
690 register struct nfsv2_fattr *fp;
691 extern int (**spec_nfsv2nodeop_p)();
692 register struct nfsnode *np;
693 register struct nfsnodehashhead *nhpp;
694 register long t1;
695 caddr_t dpos, cp2;
696 int error = 0, isnq;
697 struct mbuf *md;
698 enum vtype vtyp;
699 u_short vmode;
700 long rdev;
701 struct timespec mtime;
702 struct vnode *nvp;
703
704 md = *mdp;
705 dpos = *dposp;
706 t1 = (mtod(md, caddr_t) + md->m_len) - dpos;
707 isnq = (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS);
708 error = nfsm_disct(&md, &dpos, NFSX_FATTR(isnq), t1, &cp2);
709 if (error)
710 return (error);
711 fp = (struct nfsv2_fattr *)cp2;
712 vtyp = nfstov_type(fp->fa_type);
713 vmode = fxdr_unsigned(u_short, fp->fa_mode);
714 if (vtyp == VNON || vtyp == VREG)
715 vtyp = IFTOVT(vmode);
716 if (isnq) {
717 rdev = fxdr_unsigned(long, fp->fa_nqrdev);
718 fxdr_nqtime(&fp->fa_nqmtime, &mtime);
719 } else {
720 rdev = fxdr_unsigned(long, fp->fa_nfsrdev);
721 fxdr_nfstime(&fp->fa_nfsmtime, &mtime);
722 }
723 /*
724 * If v_type == VNON it is a new node, so fill in the v_type,
725 * n_mtime fields. Check to see if it represents a special
726 * device, and if so, check for a possible alias. Once the
727 * correct vnode has been obtained, fill in the rest of the
728 * information.
729 */
730 np = VTONFS(vp);
731 if (vp->v_type == VNON) {
732 if (vtyp == VCHR && rdev == 0xffffffff)
733 vp->v_type = vtyp = VFIFO;
734 else
735 vp->v_type = vtyp;
736 if (vp->v_type == VFIFO) {
737 extern int (**fifo_nfsv2nodeop_p)();
738 vp->v_op = fifo_nfsv2nodeop_p;
739 }
740 if (vp->v_type == VCHR || vp->v_type == VBLK) {
741 vp->v_op = spec_nfsv2nodeop_p;
742 nvp = checkalias(vp, (dev_t)rdev, vp->v_mount);
743 if (nvp) {
744 /*
745 * Discard unneeded vnode, but save its nfsnode.
746 */
747 LIST_REMOVE(np, n_hash);
748 nvp->v_data = vp->v_data;
749 vp->v_data = NULL;
750 vp->v_op = spec_vnodeop_p;
751 vrele(vp);
752 vgone(vp);
753 /*
754 * Reinitialize aliased node.
755 */
756 np->n_vnode = nvp;
757 nhpp = nfs_hash(&np->n_fh);
758 LIST_INSERT_HEAD(nhpp, np, n_hash);
759 *vpp = vp = nvp;
760 }
761 }
762 np->n_mtime = mtime.ts_sec;
763 }
764 vap = &np->n_vattr;
765 vap->va_type = vtyp;
766 vap->va_mode = (vmode & 07777);
767 vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
768 vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid);
769 vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid);
770 vap->va_rdev = (dev_t)rdev;
771 vap->va_mtime = mtime;
772 vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
773 if (isnq) {
774 fxdr_hyper(&fp->fa_nqsize, &vap->va_size);
775 vap->va_blocksize = fxdr_unsigned(long, fp->fa_nqblocksize);
776 fxdr_hyper(&fp->fa_nqbytes, &vap->va_bytes);
777 vap->va_fileid = fxdr_unsigned(long, fp->fa_nqfileid);
778 fxdr_nqtime(&fp->fa_nqatime, &vap->va_atime);
779 vap->va_flags = fxdr_unsigned(u_long, fp->fa_nqflags);
780 fxdr_nqtime(&fp->fa_nqctime, &vap->va_ctime);
781 vap->va_gen = fxdr_unsigned(u_long, fp->fa_nqgen);
782 fxdr_hyper(&fp->fa_nqfilerev, &vap->va_filerev);
783 } else {
784 vap->va_size = fxdr_unsigned(u_long, fp->fa_nfssize);
785 vap->va_blocksize = fxdr_unsigned(long, fp->fa_nfsblocksize);
786 vap->va_bytes = fxdr_unsigned(long, fp->fa_nfsblocks) * NFS_FABLKSIZE;
787 vap->va_fileid = fxdr_unsigned(long, fp->fa_nfsfileid);
788 fxdr_nfstime(&fp->fa_nfsatime, &vap->va_atime);
789 vap->va_flags = 0;
790 fxdr_nfstime(&fp->fa_nfsctime, &vap->va_ctime);
791 vap->va_gen = 0;
792 vap->va_filerev = 0;
793 }
794 if (vap->va_size != np->n_size) {
795 if (vap->va_type == VREG) {
796 if (np->n_flag & NMODIFIED) {
797 if (vap->va_size < np->n_size)
798 vap->va_size = np->n_size;
799 else
800 np->n_size = vap->va_size;
801 } else
802 np->n_size = vap->va_size;
803 vnode_pager_setsize(vp, (u_long)np->n_size);
804 } else
805 np->n_size = vap->va_size;
806 }
807 np->n_attrstamp = time.tv_sec;
808 *dposp = dpos;
809 *mdp = md;
810 if (vaper != NULL) {
811 bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap));
812#ifdef notdef
813 if ((np->n_flag & NMODIFIED) && np->n_size > vap->va_size)
814 if (np->n_size > vap->va_size)
815 vaper->va_size = np->n_size;
816#endif
817 if (np->n_flag & NCHG) {
818 if (np->n_flag & NACC) {
819 vaper->va_atime.ts_sec = np->n_atim.tv_sec;
820 vaper->va_atime.ts_nsec =
821 np->n_atim.tv_usec * 1000;
822 }
823 if (np->n_flag & NUPD) {
824 vaper->va_mtime.ts_sec = np->n_mtim.tv_sec;
825 vaper->va_mtime.ts_nsec =
826 np->n_mtim.tv_usec * 1000;
827 }
828 }
829 }
830 return (0);
831}
832
833/*
834 * Check the time stamp
835 * If the cache is valid, copy contents to *vap and return 0
836 * otherwise return an error
837 */
838int
839nfs_getattrcache(vp, vaper)
840 register struct vnode *vp;
841 struct vattr *vaper;
842{
843 register struct nfsnode *np = VTONFS(vp);
844 register struct vattr *vap;
845
846 if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQLOOKLEASE) {
847 if (!NQNFS_CKCACHABLE(vp, NQL_READ) || np->n_attrstamp == 0) {
848 nfsstats.attrcache_misses++;
849 return (ENOENT);
850 }
851 } else if ((time.tv_sec - np->n_attrstamp) >= NFS_ATTRTIMEO(np)) {
852 nfsstats.attrcache_misses++;
853 return (ENOENT);
854 }
855 nfsstats.attrcache_hits++;
856 vap = &np->n_vattr;
857 if (vap->va_size != np->n_size) {
858 if (vap->va_type == VREG) {
859 if (np->n_flag & NMODIFIED) {
860 if (vap->va_size < np->n_size)
861 vap->va_size = np->n_size;
862 else
863 np->n_size = vap->va_size;
864 } else
865 np->n_size = vap->va_size;
866 vnode_pager_setsize(vp, (u_long)np->n_size);
867 } else
868 np->n_size = vap->va_size;
869 }
870 bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(struct vattr));
871#ifdef notdef
872 if ((np->n_flag & NMODIFIED) == 0) {
873 np->n_size = vaper->va_size;
874 vnode_pager_setsize(vp, (u_long)np->n_size);
875 } else if (np->n_size > vaper->va_size)
876 if (np->n_size > vaper->va_size)
877 vaper->va_size = np->n_size;
878#endif
879 if (np->n_flag & NCHG) {
880 if (np->n_flag & NACC) {
881 vaper->va_atime.ts_sec = np->n_atim.tv_sec;
882 vaper->va_atime.ts_nsec = np->n_atim.tv_usec * 1000;
883 }
884 if (np->n_flag & NUPD) {
885 vaper->va_mtime.ts_sec = np->n_mtim.tv_sec;
886 vaper->va_mtime.ts_nsec = np->n_mtim.tv_usec * 1000;
887 }
888 }
889 return (0);
890}
891
892/*
893 * Set up nameidata for a lookup() call and do it
894 */
895int
896nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, p)
897 register struct nameidata *ndp;
898 fhandle_t *fhp;
899 int len;
900 struct nfssvc_sock *slp;
901 struct mbuf *nam;
902 struct mbuf **mdp;
903 caddr_t *dposp;
904 struct proc *p;
905{
906 register int i, rem;
907 register struct mbuf *md;
908 register char *fromcp, *tocp;
909 struct vnode *dp;
910 int error, rdonly;
911 struct componentname *cnp = &ndp->ni_cnd;
912
913 MALLOC(cnp->cn_pnbuf, char *, len + 1, M_NAMEI, M_WAITOK);
914 /*
915 * Copy the name from the mbuf list to ndp->ni_pnbuf
916 * and set the various ndp fields appropriately.
917 */
918 fromcp = *dposp;
919 tocp = cnp->cn_pnbuf;
920 md = *mdp;
921 rem = mtod(md, caddr_t) + md->m_len - fromcp;
922 cnp->cn_hash = 0;
923 for (i = 0; i < len; i++) {
924 while (rem == 0) {
925 md = md->m_next;
926 if (md == NULL) {
927 error = EBADRPC;
928 goto out;
929 }
930 fromcp = mtod(md, caddr_t);
931 rem = md->m_len;
932 }
933 if (*fromcp == '\0' || *fromcp == '/') {
934 error = EINVAL;
935 goto out;
936 }
937 cnp->cn_hash += (unsigned char)*fromcp;
938 *tocp++ = *fromcp++;
939 rem--;
940 }
941 *tocp = '\0';
942 *mdp = md;
943 *dposp = fromcp;
944 len = nfsm_rndup(len)-len;
945 if (len > 0) {
946 if (rem >= len)
947 *dposp += len;
948 else {
949 error = nfs_adv(mdp, dposp, len, rem);
950 if (error)
951 goto out;
952 }
953 }
954 ndp->ni_pathlen = tocp - cnp->cn_pnbuf;
955 cnp->cn_nameptr = cnp->cn_pnbuf;
956 /*
957 * Extract and set starting directory.
958 */
959 error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp,
960 nam, &rdonly);
961 if (error)
962 goto out;
963 if (dp->v_type != VDIR) {
964 nfsrv_vrele(dp);
965 error = ENOTDIR;
966 goto out;
967 }
968 ndp->ni_startdir = dp;
969 if (rdonly)
970 cnp->cn_flags |= (NOCROSSMOUNT | RDONLY);
971 else
972 cnp->cn_flags |= NOCROSSMOUNT;
973 /*
974 * And call lookup() to do the real work
975 */
976 cnp->cn_proc = p;
977 error = lookup(ndp);
978 if (error)
979 goto out;
980 /*
981 * Check for encountering a symbolic link
982 */
983 if (cnp->cn_flags & ISSYMLINK) {
984 if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1)
985 vput(ndp->ni_dvp);
986 else
987 vrele(ndp->ni_dvp);
988 vput(ndp->ni_vp);
989 ndp->ni_vp = NULL;
990 error = EINVAL;
991 goto out;
992 }
993 /*
994 * Check for saved name request
995 */
996 if (cnp->cn_flags & (SAVENAME | SAVESTART)) {
997 cnp->cn_flags |= HASBUF;
998 nfsrv_vmio( ndp->ni_vp);
999 return (0);
1000 }
1001out:
1002 FREE(cnp->cn_pnbuf, M_NAMEI);
1003 return (error);
1004}
1005
1006/*
1007 * A fiddled version of m_adj() that ensures null fill to a long
1008 * boundary and only trims off the back end
1009 */
1010void
1011nfsm_adj(mp, len, nul)
1012 struct mbuf *mp;
1013 register int len;
1014 int nul;
1015{
1016 register struct mbuf *m;
1017 register int count, i;
1018 register char *cp;
1019
1020 /*
1021 * Trim from tail. Scan the mbuf chain,
1022 * calculating its length and finding the last mbuf.
1023 * If the adjustment only affects this mbuf, then just
1024 * adjust and return. Otherwise, rescan and truncate
1025 * after the remaining size.
1026 */
1027 count = 0;
1028 m = mp;
1029 for (;;) {
1030 count += m->m_len;
1031 if (m->m_next == (struct mbuf *)0)
1032 break;
1033 m = m->m_next;
1034 }
1035 if (m->m_len > len) {
1036 m->m_len -= len;
1037 if (nul > 0) {
1038 cp = mtod(m, caddr_t)+m->m_len-nul;
1039 for (i = 0; i < nul; i++)
1040 *cp++ = '\0';
1041 }
1042 return;
1043 }
1044 count -= len;
1045 if (count < 0)
1046 count = 0;
1047 /*
1048 * Correct length for chain is "count".
1049 * Find the mbuf with last data, adjust its length,
1050 * and toss data from remaining mbufs on chain.
1051 */
1052 for (m = mp; m; m = m->m_next) {
1053 if (m->m_len >= count) {
1054 m->m_len = count;
1055 if (nul > 0) {
1056 cp = mtod(m, caddr_t)+m->m_len-nul;
1057 for (i = 0; i < nul; i++)
1058 *cp++ = '\0';
1059 }
1060 break;
1061 }
1062 count -= m->m_len;
1063 }
1064 for (m = m->m_next;m;m = m->m_next)
1065 m->m_len = 0;
1066}
1067
1068/*
1069 * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked)
1070 * - look up fsid in mount list (if not found ret error)
1071 * - get vp and export rights by calling VFS_FHTOVP()
1072 * - if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon
1073 * - if not lockflag unlock it with VOP_UNLOCK()
1074 */
1075int
1076nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp)
1077 fhandle_t *fhp;
1078 int lockflag;
1079 struct vnode **vpp;
1080 struct ucred *cred;
1081 struct nfssvc_sock *slp;
1082 struct mbuf *nam;
1083 int *rdonlyp;
1084{
1085 register struct mount *mp;
1086 register struct nfsuid *uidp;
1087 register int i;
1088 struct ucred *credanon;
1089 int error, exflags;
1090
1091 *vpp = (struct vnode *)0;
1092 mp = getvfs(&fhp->fh_fsid);
1093 if (!mp)
1094 return (ESTALE);
1095 error = VFS_FHTOVP(mp, &fhp->fh_fid, nam, vpp, &exflags, &credanon);
1096 if (error)
1097 return (error);
1098 /*
1099 * Check/setup credentials.
1100 */
1101 if (exflags & MNT_EXKERB) {
1102 for (uidp = NUIDHASH(slp, cred->cr_uid)->lh_first; uidp != 0;
1103 uidp = uidp->nu_hash.le_next) {
1104 if (uidp->nu_uid == cred->cr_uid)
1105 break;
1106 }
1107 if (uidp == 0) {
1108 vput(*vpp);
1109 return (NQNFS_AUTHERR);
1110 }
1111 cred->cr_uid = uidp->nu_cr.cr_uid;
1112 for (i = 0; i < uidp->nu_cr.cr_ngroups; i++)
1113 cred->cr_groups[i] = uidp->nu_cr.cr_groups[i];
1114 cred->cr_ngroups = i;
1115 } else if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) {
1116 cred->cr_uid = credanon->cr_uid;
1117 for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++)
1118 cred->cr_groups[i] = credanon->cr_groups[i];
1119 cred->cr_ngroups = i;
1120 }
1121 if (exflags & MNT_EXRDONLY)
1122 *rdonlyp = 1;
1123 else
1124 *rdonlyp = 0;
1125 if (!lockflag)
1126 VOP_UNLOCK(*vpp);
1127 nfsrv_vmio(*vpp);
1128 return (0);
1129}
1130
1131/*
1132 * This function compares two net addresses by family and returns TRUE
1133 * if they are the same host.
1134 * If there is any doubt, return FALSE.
1135 * The AF_INET family is handled as a special case so that address mbufs
1136 * don't need to be saved to store "struct in_addr", which is only 4 bytes.
1137 */
1138int
1139netaddr_match(family, haddr, nam)
1140 int family;
1141 union nethostaddr *haddr;
1142 struct mbuf *nam;
1143{
1144 register struct sockaddr_in *inetaddr;
1145
1146 switch (family) {
1147 case AF_INET:
1148 inetaddr = mtod(nam, struct sockaddr_in *);
1149 if (inetaddr->sin_family == AF_INET &&
1150 inetaddr->sin_addr.s_addr == haddr->had_inetaddr)
1151 return (1);
1152 break;
1153#ifdef ISO
1154 case AF_ISO:
1155 {
1156 register struct sockaddr_iso *isoaddr1, *isoaddr2;
1157
1158 isoaddr1 = mtod(nam, struct sockaddr_iso *);
1159 isoaddr2 = mtod(haddr->had_nam, struct sockaddr_iso *);
1160 if (isoaddr1->siso_family == AF_ISO &&
1161 isoaddr1->siso_nlen > 0 &&
1162 isoaddr1->siso_nlen == isoaddr2->siso_nlen &&
1163 SAME_ISOADDR(isoaddr1, isoaddr2))
1164 return (1);
1165 break;
1166 }
1167#endif /* ISO */
1168 default:
1169 break;
1170 };
1171 return (0);
1172}
1173
1174int
1175nfsrv_vmio( struct vnode *vp) {
76#include <netinet/in.h>
77#ifdef ISO
78#include <netiso/iso.h>
79#endif
80
81#define TRUE 1
82#define FALSE 0
83
84/*
85 * Data items converted to xdr at startup, since they are constant
86 * This is kinda hokey, but may save a little time doing byte swaps
87 */
88u_long nfs_procids[NFS_NPROCS];
89u_long nfs_xdrneg1;
90u_long rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr,
91 rpc_mismatch, rpc_auth_unix, rpc_msgaccepted, rpc_rejectedcred,
92 rpc_auth_kerb;
93u_long nfs_vers, nfs_prog, nfs_true, nfs_false;
94
95/* And other global data */
96static u_long nfs_xid = 0;
97enum vtype ntov_type[7] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON };
98extern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON];
99extern int nqnfs_piggy[NFS_NPROCS];
100extern struct nfsrtt nfsrtt;
101extern time_t nqnfsstarttime;
102extern u_long nqnfs_prog, nqnfs_vers;
103extern int nqsrv_clockskew;
104extern int nqsrv_writeslack;
105extern int nqsrv_maxlease;
106
107#ifdef VFS_LKM
108struct getfh_args;
109extern int getfh(struct proc *, struct getfh_args *, int *);
110struct nfssvc_args;
111extern int nfssvc(struct proc *, struct nfssvc_args *, int *);
112#endif
113
114LIST_HEAD(nfsnodehashhead, nfsnode);
115
116/*
117 * Create the header for an rpc request packet
118 * The hsiz is the size of the rest of the nfs request header.
119 * (just used to decide if a cluster is a good idea)
120 */
121struct mbuf *
122nfsm_reqh(vp, procid, hsiz, bposp)
123 struct vnode *vp;
124 u_long procid;
125 int hsiz;
126 caddr_t *bposp;
127{
128 register struct mbuf *mb;
129 register u_long *tl;
130 register caddr_t bpos;
131 struct mbuf *mb2;
132 struct nfsmount *nmp;
133 int nqflag;
134
135 MGET(mb, M_WAIT, MT_DATA);
136 if (hsiz >= MINCLSIZE)
137 MCLGET(mb, M_WAIT);
138 mb->m_len = 0;
139 bpos = mtod(mb, caddr_t);
140
141 /*
142 * For NQNFS, add lease request.
143 */
144 if (vp) {
145 nmp = VFSTONFS(vp->v_mount);
146 if (nmp->nm_flag & NFSMNT_NQNFS) {
147 nqflag = NQNFS_NEEDLEASE(vp, procid);
148 if (nqflag) {
149 nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
150 *tl++ = txdr_unsigned(nqflag);
151 *tl = txdr_unsigned(nmp->nm_leaseterm);
152 } else {
153 nfsm_build(tl, u_long *, NFSX_UNSIGNED);
154 *tl = 0;
155 }
156 }
157 }
158 /* Finally, return values */
159 *bposp = bpos;
160 return (mb);
161}
162
163/*
164 * Build the RPC header and fill in the authorization info.
165 * The authorization string argument is only used when the credentials
166 * come from outside of the kernel.
167 * Returns the head of the mbuf list.
168 */
169struct mbuf *
170nfsm_rpchead(cr, nqnfs, procid, auth_type, auth_len, auth_str, mrest,
171 mrest_len, mbp, xidp)
172 register struct ucred *cr;
173 int nqnfs;
174 int procid;
175 int auth_type;
176 int auth_len;
177 char *auth_str;
178 struct mbuf *mrest;
179 int mrest_len;
180 struct mbuf **mbp;
181 u_long *xidp;
182{
183 register struct mbuf *mb;
184 register u_long *tl;
185 register caddr_t bpos;
186 register int i;
187 struct mbuf *mreq, *mb2;
188 int siz, grpsiz, authsiz;
189
190 authsiz = nfsm_rndup(auth_len);
191 if (auth_type == RPCAUTH_NQNFS)
192 authsiz += 2 * NFSX_UNSIGNED;
193 MGETHDR(mb, M_WAIT, MT_DATA);
194 if ((authsiz + 10*NFSX_UNSIGNED) >= MINCLSIZE) {
195 MCLGET(mb, M_WAIT);
196 } else if ((authsiz + 10*NFSX_UNSIGNED) < MHLEN) {
197 MH_ALIGN(mb, authsiz + 10*NFSX_UNSIGNED);
198 } else {
199 MH_ALIGN(mb, 8*NFSX_UNSIGNED);
200 }
201 mb->m_len = 0;
202 mreq = mb;
203 bpos = mtod(mb, caddr_t);
204
205 /*
206 * First the RPC header.
207 */
208 nfsm_build(tl, u_long *, 8*NFSX_UNSIGNED);
209 if (++nfs_xid == 0)
210 nfs_xid++;
211 *tl++ = *xidp = txdr_unsigned(nfs_xid);
212 *tl++ = rpc_call;
213 *tl++ = rpc_vers;
214 if (nqnfs) {
215 *tl++ = txdr_unsigned(NQNFS_PROG);
216 *tl++ = txdr_unsigned(NQNFS_VER1);
217 } else {
218 *tl++ = txdr_unsigned(NFS_PROG);
219 *tl++ = txdr_unsigned(NFS_VER2);
220 }
221 *tl++ = txdr_unsigned(procid);
222
223 /*
224 * And then the authorization cred.
225 */
226 *tl++ = txdr_unsigned(auth_type);
227 *tl = txdr_unsigned(authsiz);
228 switch (auth_type) {
229 case RPCAUTH_UNIX:
230 nfsm_build(tl, u_long *, auth_len);
231 *tl++ = 0; /* stamp ?? */
232 *tl++ = 0; /* NULL hostname */
233 *tl++ = txdr_unsigned(cr->cr_uid);
234 *tl++ = txdr_unsigned(cr->cr_groups[0]);
235 grpsiz = (auth_len >> 2) - 5;
236 *tl++ = txdr_unsigned(grpsiz);
237 for (i = 1; i <= grpsiz; i++)
238 *tl++ = txdr_unsigned(cr->cr_groups[i]);
239 break;
240 case RPCAUTH_NQNFS:
241 nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
242 *tl++ = txdr_unsigned(cr->cr_uid);
243 *tl = txdr_unsigned(auth_len);
244 siz = auth_len;
245 while (siz > 0) {
246 if (M_TRAILINGSPACE(mb) == 0) {
247 MGET(mb2, M_WAIT, MT_DATA);
248 if (siz >= MINCLSIZE)
249 MCLGET(mb2, M_WAIT);
250 mb->m_next = mb2;
251 mb = mb2;
252 mb->m_len = 0;
253 bpos = mtod(mb, caddr_t);
254 }
255 i = min(siz, M_TRAILINGSPACE(mb));
256 bcopy(auth_str, bpos, i);
257 mb->m_len += i;
258 auth_str += i;
259 bpos += i;
260 siz -= i;
261 }
262 if ((siz = (nfsm_rndup(auth_len) - auth_len)) > 0) {
263 for (i = 0; i < siz; i++)
264 *bpos++ = '\0';
265 mb->m_len += siz;
266 }
267 break;
268 };
269 nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
270 *tl++ = txdr_unsigned(RPCAUTH_NULL);
271 *tl = 0;
272 mb->m_next = mrest;
273 mreq->m_pkthdr.len = authsiz + 10*NFSX_UNSIGNED + mrest_len;
274 mreq->m_pkthdr.rcvif = (struct ifnet *)0;
275 *mbp = mb;
276 return (mreq);
277}
278
279/*
280 * copies mbuf chain to the uio scatter/gather list
281 */
282int
283nfsm_mbuftouio(mrep, uiop, siz, dpos)
284 struct mbuf **mrep;
285 register struct uio *uiop;
286 int siz;
287 caddr_t *dpos;
288{
289 register char *mbufcp, *uiocp;
290 register int xfer, left, len;
291 register struct mbuf *mp;
292 long uiosiz, rem;
293 int error = 0;
294
295 mp = *mrep;
296 mbufcp = *dpos;
297 len = mtod(mp, caddr_t)+mp->m_len-mbufcp;
298 rem = nfsm_rndup(siz)-siz;
299 while (siz > 0) {
300 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
301 return (EFBIG);
302 left = uiop->uio_iov->iov_len;
303 uiocp = uiop->uio_iov->iov_base;
304 if (left > siz)
305 left = siz;
306 uiosiz = left;
307 while (left > 0) {
308 while (len == 0) {
309 mp = mp->m_next;
310 if (mp == NULL)
311 return (EBADRPC);
312 mbufcp = mtod(mp, caddr_t);
313 len = mp->m_len;
314 }
315 xfer = (left > len) ? len : left;
316#ifdef notdef
317 /* Not Yet.. */
318 if (uiop->uio_iov->iov_op != NULL)
319 (*(uiop->uio_iov->iov_op))
320 (mbufcp, uiocp, xfer);
321 else
322#endif
323 if (uiop->uio_segflg == UIO_SYSSPACE)
324 bcopy(mbufcp, uiocp, xfer);
325 else
326 copyout(mbufcp, uiocp, xfer);
327 left -= xfer;
328 len -= xfer;
329 mbufcp += xfer;
330 uiocp += xfer;
331 uiop->uio_offset += xfer;
332 uiop->uio_resid -= xfer;
333 }
334 if (uiop->uio_iov->iov_len <= siz) {
335 uiop->uio_iovcnt--;
336 uiop->uio_iov++;
337 } else {
338 uiop->uio_iov->iov_base += uiosiz;
339 uiop->uio_iov->iov_len -= uiosiz;
340 }
341 siz -= uiosiz;
342 }
343 *dpos = mbufcp;
344 *mrep = mp;
345 if (rem > 0) {
346 if (len < rem)
347 error = nfs_adv(mrep, dpos, rem, len);
348 else
349 *dpos += rem;
350 }
351 return (error);
352}
353
354/*
355 * copies a uio scatter/gather list to an mbuf chain...
356 */
357int
358nfsm_uiotombuf(uiop, mq, siz, bpos)
359 register struct uio *uiop;
360 struct mbuf **mq;
361 int siz;
362 caddr_t *bpos;
363{
364 register char *uiocp;
365 register struct mbuf *mp, *mp2;
366 register int xfer, left, mlen;
367 int uiosiz, clflg, rem;
368 char *cp;
369
370 if (siz > MLEN) /* or should it >= MCLBYTES ?? */
371 clflg = 1;
372 else
373 clflg = 0;
374 rem = nfsm_rndup(siz)-siz;
375 mp = mp2 = *mq;
376 while (siz > 0) {
377 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
378 return (EINVAL);
379 left = uiop->uio_iov->iov_len;
380 uiocp = uiop->uio_iov->iov_base;
381 if (left > siz)
382 left = siz;
383 uiosiz = left;
384 while (left > 0) {
385 mlen = M_TRAILINGSPACE(mp);
386 if (mlen == 0) {
387 MGET(mp, M_WAIT, MT_DATA);
388 if (clflg)
389 MCLGET(mp, M_WAIT);
390 mp->m_len = 0;
391 mp2->m_next = mp;
392 mp2 = mp;
393 mlen = M_TRAILINGSPACE(mp);
394 }
395 xfer = (left > mlen) ? mlen : left;
396#ifdef notdef
397 /* Not Yet.. */
398 if (uiop->uio_iov->iov_op != NULL)
399 (*(uiop->uio_iov->iov_op))
400 (uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
401 else
402#endif
403 if (uiop->uio_segflg == UIO_SYSSPACE)
404 bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
405 else
406 copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
407 mp->m_len += xfer;
408 left -= xfer;
409 uiocp += xfer;
410 uiop->uio_offset += xfer;
411 uiop->uio_resid -= xfer;
412 }
413 if (uiop->uio_iov->iov_len <= siz) {
414 uiop->uio_iovcnt--;
415 uiop->uio_iov++;
416 } else {
417 uiop->uio_iov->iov_base += uiosiz;
418 uiop->uio_iov->iov_len -= uiosiz;
419 }
420 siz -= uiosiz;
421 }
422 if (rem > 0) {
423 if (rem > M_TRAILINGSPACE(mp)) {
424 MGET(mp, M_WAIT, MT_DATA);
425 mp->m_len = 0;
426 mp2->m_next = mp;
427 }
428 cp = mtod(mp, caddr_t)+mp->m_len;
429 for (left = 0; left < rem; left++)
430 *cp++ = '\0';
431 mp->m_len += rem;
432 *bpos = cp;
433 } else
434 *bpos = mtod(mp, caddr_t)+mp->m_len;
435 *mq = mp;
436 return (0);
437}
438
439/*
440 * Help break down an mbuf chain by setting the first siz bytes contiguous
441 * pointed to by returned val.
442 * This is used by the macros nfsm_dissect and nfsm_dissecton for tough
443 * cases. (The macros use the vars. dpos and dpos2)
444 */
445int
446nfsm_disct(mdp, dposp, siz, left, cp2)
447 struct mbuf **mdp;
448 caddr_t *dposp;
449 int siz;
450 int left;
451 caddr_t *cp2;
452{
453 register struct mbuf *mp, *mp2;
454 register int siz2, xfer;
455 register caddr_t p;
456
457 mp = *mdp;
458 while (left == 0) {
459 *mdp = mp = mp->m_next;
460 if (mp == NULL)
461 return (EBADRPC);
462 left = mp->m_len;
463 *dposp = mtod(mp, caddr_t);
464 }
465 if (left >= siz) {
466 *cp2 = *dposp;
467 *dposp += siz;
468 } else if (mp->m_next == NULL) {
469 return (EBADRPC);
470 } else if (siz > MHLEN) {
471 panic("nfs S too big");
472 } else {
473 MGET(mp2, M_WAIT, MT_DATA);
474 mp2->m_next = mp->m_next;
475 mp->m_next = mp2;
476 mp->m_len -= left;
477 mp = mp2;
478 *cp2 = p = mtod(mp, caddr_t);
479 bcopy(*dposp, p, left); /* Copy what was left */
480 siz2 = siz-left;
481 p += left;
482 mp2 = mp->m_next;
483 /* Loop around copying up the siz2 bytes */
484 while (siz2 > 0) {
485 if (mp2 == NULL)
486 return (EBADRPC);
487 xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2;
488 if (xfer > 0) {
489 bcopy(mtod(mp2, caddr_t), p, xfer);
490 NFSMADV(mp2, xfer);
491 mp2->m_len -= xfer;
492 p += xfer;
493 siz2 -= xfer;
494 }
495 if (siz2 > 0)
496 mp2 = mp2->m_next;
497 }
498 mp->m_len = siz;
499 *mdp = mp2;
500 *dposp = mtod(mp2, caddr_t);
501 }
502 return (0);
503}
504
505/*
506 * Advance the position in the mbuf chain.
507 */
508int
509nfs_adv(mdp, dposp, offs, left)
510 struct mbuf **mdp;
511 caddr_t *dposp;
512 int offs;
513 int left;
514{
515 register struct mbuf *m;
516 register int s;
517
518 m = *mdp;
519 s = left;
520 while (s < offs) {
521 offs -= s;
522 m = m->m_next;
523 if (m == NULL)
524 return (EBADRPC);
525 s = m->m_len;
526 }
527 *mdp = m;
528 *dposp = mtod(m, caddr_t)+offs;
529 return (0);
530}
531
532/*
533 * Copy a string into mbufs for the hard cases...
534 */
535int
536nfsm_strtmbuf(mb, bpos, cp, siz)
537 struct mbuf **mb;
538 char **bpos;
539 char *cp;
540 long siz;
541{
542 register struct mbuf *m1 = 0, *m2;
543 long left, xfer, len, tlen;
544 u_long *tl;
545 int putsize;
546
547 putsize = 1;
548 m2 = *mb;
549 left = M_TRAILINGSPACE(m2);
550 if (left > 0) {
551 tl = ((u_long *)(*bpos));
552 *tl++ = txdr_unsigned(siz);
553 putsize = 0;
554 left -= NFSX_UNSIGNED;
555 m2->m_len += NFSX_UNSIGNED;
556 if (left > 0) {
557 bcopy(cp, (caddr_t) tl, left);
558 siz -= left;
559 cp += left;
560 m2->m_len += left;
561 left = 0;
562 }
563 }
564 /* Loop around adding mbufs */
565 while (siz > 0) {
566 MGET(m1, M_WAIT, MT_DATA);
567 if (siz > MLEN)
568 MCLGET(m1, M_WAIT);
569 m1->m_len = NFSMSIZ(m1);
570 m2->m_next = m1;
571 m2 = m1;
572 tl = mtod(m1, u_long *);
573 tlen = 0;
574 if (putsize) {
575 *tl++ = txdr_unsigned(siz);
576 m1->m_len -= NFSX_UNSIGNED;
577 tlen = NFSX_UNSIGNED;
578 putsize = 0;
579 }
580 if (siz < m1->m_len) {
581 len = nfsm_rndup(siz);
582 xfer = siz;
583 if (xfer < len)
584 *(tl+(xfer>>2)) = 0;
585 } else {
586 xfer = len = m1->m_len;
587 }
588 bcopy(cp, (caddr_t) tl, xfer);
589 m1->m_len = len+tlen;
590 siz -= xfer;
591 cp += xfer;
592 }
593 *mb = m1;
594 *bpos = mtod(m1, caddr_t)+m1->m_len;
595 return (0);
596}
597
598/*
599 * Called once to initialize data structures...
600 */
601int
602nfs_init()
603{
604 register int i;
605
606 nfsrtt.pos = 0;
607 rpc_vers = txdr_unsigned(RPC_VER2);
608 rpc_call = txdr_unsigned(RPC_CALL);
609 rpc_reply = txdr_unsigned(RPC_REPLY);
610 rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED);
611 rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED);
612 rpc_mismatch = txdr_unsigned(RPC_MISMATCH);
613 rpc_autherr = txdr_unsigned(RPC_AUTHERR);
614 rpc_rejectedcred = txdr_unsigned(AUTH_REJECTCRED);
615 rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX);
616 rpc_auth_kerb = txdr_unsigned(RPCAUTH_NQNFS);
617 nfs_vers = txdr_unsigned(NFS_VER2);
618 nfs_prog = txdr_unsigned(NFS_PROG);
619 nfs_true = txdr_unsigned(TRUE);
620 nfs_false = txdr_unsigned(FALSE);
621 nfs_xdrneg1 = txdr_unsigned(-1);
622 /* Loop thru nfs procids */
623 for (i = 0; i < NFS_NPROCS; i++)
624 nfs_procids[i] = txdr_unsigned(i);
625 /* Ensure async daemons disabled */
626 for (i = 0; i < NFS_MAXASYNCDAEMON; i++)
627 nfs_iodwant[i] = (struct proc *)0;
628 TAILQ_INIT(&nfs_bufq);
629 nfs_nhinit(); /* Init the nfsnode table */
630 nfsrv_init(0); /* Init server data structures */
631 nfsrv_initcache(); /* Init the server request cache */
632
633 /*
634 * Initialize the nqnfs server stuff.
635 */
636 if (nqnfsstarttime == 0) {
637 nqnfsstarttime = boottime.tv_sec + nqsrv_maxlease
638 + nqsrv_clockskew + nqsrv_writeslack;
639 NQLOADNOVRAM(nqnfsstarttime);
640 nqnfs_prog = txdr_unsigned(NQNFS_PROG);
641 nqnfs_vers = txdr_unsigned(NQNFS_VER1);
642 CIRCLEQ_INIT(&nqtimerhead);
643 nqfhhashtbl = hashinit(NQLCHSZ, M_NQLEASE, &nqfhhash);
644 }
645
646 /*
647 * Initialize reply list and start timer
648 */
649 TAILQ_INIT(&nfs_reqq);
650 nfs_timer(0);
651
652 /*
653 * Set up lease_check and lease_updatetime so that other parts
654 * of the system can call us, if we are loadable.
655 */
656 lease_check = nfs_lease_check;
657 lease_updatetime = nfs_lease_updatetime;
658 vfsconf[MOUNT_NFS]->vfc_refcount++; /* make us non-unloadable */
659#ifdef VFS_LKM
660 sysent[SYS_nfssvc].sy_narg = 2;
661 sysent[SYS_nfssvc].sy_call = nfssvc;
662 sysent[SYS_getfh].sy_narg = 2;
663 sysent[SYS_getfh].sy_call = getfh;
664#endif
665
666 return (0);
667}
668
669/*
670 * Attribute cache routines.
671 * nfs_loadattrcache() - loads or updates the cache contents from attributes
672 * that are on the mbuf list
673 * nfs_getattrcache() - returns valid attributes if found in cache, returns
674 * error otherwise
675 */
676
677/*
678 * Load the attribute cache (that lives in the nfsnode entry) with
679 * the values on the mbuf list and
680 * Iff vap not NULL
681 * copy the attributes to *vaper
682 */
683int
684nfs_loadattrcache(vpp, mdp, dposp, vaper)
685 struct vnode **vpp;
686 struct mbuf **mdp;
687 caddr_t *dposp;
688 struct vattr *vaper;
689{
690 register struct vnode *vp = *vpp;
691 register struct vattr *vap;
692 register struct nfsv2_fattr *fp;
693 extern int (**spec_nfsv2nodeop_p)();
694 register struct nfsnode *np;
695 register struct nfsnodehashhead *nhpp;
696 register long t1;
697 caddr_t dpos, cp2;
698 int error = 0, isnq;
699 struct mbuf *md;
700 enum vtype vtyp;
701 u_short vmode;
702 long rdev;
703 struct timespec mtime;
704 struct vnode *nvp;
705
706 md = *mdp;
707 dpos = *dposp;
708 t1 = (mtod(md, caddr_t) + md->m_len) - dpos;
709 isnq = (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS);
710 error = nfsm_disct(&md, &dpos, NFSX_FATTR(isnq), t1, &cp2);
711 if (error)
712 return (error);
713 fp = (struct nfsv2_fattr *)cp2;
714 vtyp = nfstov_type(fp->fa_type);
715 vmode = fxdr_unsigned(u_short, fp->fa_mode);
716 if (vtyp == VNON || vtyp == VREG)
717 vtyp = IFTOVT(vmode);
718 if (isnq) {
719 rdev = fxdr_unsigned(long, fp->fa_nqrdev);
720 fxdr_nqtime(&fp->fa_nqmtime, &mtime);
721 } else {
722 rdev = fxdr_unsigned(long, fp->fa_nfsrdev);
723 fxdr_nfstime(&fp->fa_nfsmtime, &mtime);
724 }
725 /*
726 * If v_type == VNON it is a new node, so fill in the v_type,
727 * n_mtime fields. Check to see if it represents a special
728 * device, and if so, check for a possible alias. Once the
729 * correct vnode has been obtained, fill in the rest of the
730 * information.
731 */
732 np = VTONFS(vp);
733 if (vp->v_type == VNON) {
734 if (vtyp == VCHR && rdev == 0xffffffff)
735 vp->v_type = vtyp = VFIFO;
736 else
737 vp->v_type = vtyp;
738 if (vp->v_type == VFIFO) {
739 extern int (**fifo_nfsv2nodeop_p)();
740 vp->v_op = fifo_nfsv2nodeop_p;
741 }
742 if (vp->v_type == VCHR || vp->v_type == VBLK) {
743 vp->v_op = spec_nfsv2nodeop_p;
744 nvp = checkalias(vp, (dev_t)rdev, vp->v_mount);
745 if (nvp) {
746 /*
747 * Discard unneeded vnode, but save its nfsnode.
748 */
749 LIST_REMOVE(np, n_hash);
750 nvp->v_data = vp->v_data;
751 vp->v_data = NULL;
752 vp->v_op = spec_vnodeop_p;
753 vrele(vp);
754 vgone(vp);
755 /*
756 * Reinitialize aliased node.
757 */
758 np->n_vnode = nvp;
759 nhpp = nfs_hash(&np->n_fh);
760 LIST_INSERT_HEAD(nhpp, np, n_hash);
761 *vpp = vp = nvp;
762 }
763 }
764 np->n_mtime = mtime.ts_sec;
765 }
766 vap = &np->n_vattr;
767 vap->va_type = vtyp;
768 vap->va_mode = (vmode & 07777);
769 vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
770 vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid);
771 vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid);
772 vap->va_rdev = (dev_t)rdev;
773 vap->va_mtime = mtime;
774 vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
775 if (isnq) {
776 fxdr_hyper(&fp->fa_nqsize, &vap->va_size);
777 vap->va_blocksize = fxdr_unsigned(long, fp->fa_nqblocksize);
778 fxdr_hyper(&fp->fa_nqbytes, &vap->va_bytes);
779 vap->va_fileid = fxdr_unsigned(long, fp->fa_nqfileid);
780 fxdr_nqtime(&fp->fa_nqatime, &vap->va_atime);
781 vap->va_flags = fxdr_unsigned(u_long, fp->fa_nqflags);
782 fxdr_nqtime(&fp->fa_nqctime, &vap->va_ctime);
783 vap->va_gen = fxdr_unsigned(u_long, fp->fa_nqgen);
784 fxdr_hyper(&fp->fa_nqfilerev, &vap->va_filerev);
785 } else {
786 vap->va_size = fxdr_unsigned(u_long, fp->fa_nfssize);
787 vap->va_blocksize = fxdr_unsigned(long, fp->fa_nfsblocksize);
788 vap->va_bytes = fxdr_unsigned(long, fp->fa_nfsblocks) * NFS_FABLKSIZE;
789 vap->va_fileid = fxdr_unsigned(long, fp->fa_nfsfileid);
790 fxdr_nfstime(&fp->fa_nfsatime, &vap->va_atime);
791 vap->va_flags = 0;
792 fxdr_nfstime(&fp->fa_nfsctime, &vap->va_ctime);
793 vap->va_gen = 0;
794 vap->va_filerev = 0;
795 }
796 if (vap->va_size != np->n_size) {
797 if (vap->va_type == VREG) {
798 if (np->n_flag & NMODIFIED) {
799 if (vap->va_size < np->n_size)
800 vap->va_size = np->n_size;
801 else
802 np->n_size = vap->va_size;
803 } else
804 np->n_size = vap->va_size;
805 vnode_pager_setsize(vp, (u_long)np->n_size);
806 } else
807 np->n_size = vap->va_size;
808 }
809 np->n_attrstamp = time.tv_sec;
810 *dposp = dpos;
811 *mdp = md;
812 if (vaper != NULL) {
813 bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap));
814#ifdef notdef
815 if ((np->n_flag & NMODIFIED) && np->n_size > vap->va_size)
816 if (np->n_size > vap->va_size)
817 vaper->va_size = np->n_size;
818#endif
819 if (np->n_flag & NCHG) {
820 if (np->n_flag & NACC) {
821 vaper->va_atime.ts_sec = np->n_atim.tv_sec;
822 vaper->va_atime.ts_nsec =
823 np->n_atim.tv_usec * 1000;
824 }
825 if (np->n_flag & NUPD) {
826 vaper->va_mtime.ts_sec = np->n_mtim.tv_sec;
827 vaper->va_mtime.ts_nsec =
828 np->n_mtim.tv_usec * 1000;
829 }
830 }
831 }
832 return (0);
833}
834
835/*
836 * Check the time stamp
837 * If the cache is valid, copy contents to *vap and return 0
838 * otherwise return an error
839 */
840int
841nfs_getattrcache(vp, vaper)
842 register struct vnode *vp;
843 struct vattr *vaper;
844{
845 register struct nfsnode *np = VTONFS(vp);
846 register struct vattr *vap;
847
848 if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQLOOKLEASE) {
849 if (!NQNFS_CKCACHABLE(vp, NQL_READ) || np->n_attrstamp == 0) {
850 nfsstats.attrcache_misses++;
851 return (ENOENT);
852 }
853 } else if ((time.tv_sec - np->n_attrstamp) >= NFS_ATTRTIMEO(np)) {
854 nfsstats.attrcache_misses++;
855 return (ENOENT);
856 }
857 nfsstats.attrcache_hits++;
858 vap = &np->n_vattr;
859 if (vap->va_size != np->n_size) {
860 if (vap->va_type == VREG) {
861 if (np->n_flag & NMODIFIED) {
862 if (vap->va_size < np->n_size)
863 vap->va_size = np->n_size;
864 else
865 np->n_size = vap->va_size;
866 } else
867 np->n_size = vap->va_size;
868 vnode_pager_setsize(vp, (u_long)np->n_size);
869 } else
870 np->n_size = vap->va_size;
871 }
872 bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(struct vattr));
873#ifdef notdef
874 if ((np->n_flag & NMODIFIED) == 0) {
875 np->n_size = vaper->va_size;
876 vnode_pager_setsize(vp, (u_long)np->n_size);
877 } else if (np->n_size > vaper->va_size)
878 if (np->n_size > vaper->va_size)
879 vaper->va_size = np->n_size;
880#endif
881 if (np->n_flag & NCHG) {
882 if (np->n_flag & NACC) {
883 vaper->va_atime.ts_sec = np->n_atim.tv_sec;
884 vaper->va_atime.ts_nsec = np->n_atim.tv_usec * 1000;
885 }
886 if (np->n_flag & NUPD) {
887 vaper->va_mtime.ts_sec = np->n_mtim.tv_sec;
888 vaper->va_mtime.ts_nsec = np->n_mtim.tv_usec * 1000;
889 }
890 }
891 return (0);
892}
893
894/*
895 * Set up nameidata for a lookup() call and do it
896 */
897int
898nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, p)
899 register struct nameidata *ndp;
900 fhandle_t *fhp;
901 int len;
902 struct nfssvc_sock *slp;
903 struct mbuf *nam;
904 struct mbuf **mdp;
905 caddr_t *dposp;
906 struct proc *p;
907{
908 register int i, rem;
909 register struct mbuf *md;
910 register char *fromcp, *tocp;
911 struct vnode *dp;
912 int error, rdonly;
913 struct componentname *cnp = &ndp->ni_cnd;
914
915 MALLOC(cnp->cn_pnbuf, char *, len + 1, M_NAMEI, M_WAITOK);
916 /*
917 * Copy the name from the mbuf list to ndp->ni_pnbuf
918 * and set the various ndp fields appropriately.
919 */
920 fromcp = *dposp;
921 tocp = cnp->cn_pnbuf;
922 md = *mdp;
923 rem = mtod(md, caddr_t) + md->m_len - fromcp;
924 cnp->cn_hash = 0;
925 for (i = 0; i < len; i++) {
926 while (rem == 0) {
927 md = md->m_next;
928 if (md == NULL) {
929 error = EBADRPC;
930 goto out;
931 }
932 fromcp = mtod(md, caddr_t);
933 rem = md->m_len;
934 }
935 if (*fromcp == '\0' || *fromcp == '/') {
936 error = EINVAL;
937 goto out;
938 }
939 cnp->cn_hash += (unsigned char)*fromcp;
940 *tocp++ = *fromcp++;
941 rem--;
942 }
943 *tocp = '\0';
944 *mdp = md;
945 *dposp = fromcp;
946 len = nfsm_rndup(len)-len;
947 if (len > 0) {
948 if (rem >= len)
949 *dposp += len;
950 else {
951 error = nfs_adv(mdp, dposp, len, rem);
952 if (error)
953 goto out;
954 }
955 }
956 ndp->ni_pathlen = tocp - cnp->cn_pnbuf;
957 cnp->cn_nameptr = cnp->cn_pnbuf;
958 /*
959 * Extract and set starting directory.
960 */
961 error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp,
962 nam, &rdonly);
963 if (error)
964 goto out;
965 if (dp->v_type != VDIR) {
966 nfsrv_vrele(dp);
967 error = ENOTDIR;
968 goto out;
969 }
970 ndp->ni_startdir = dp;
971 if (rdonly)
972 cnp->cn_flags |= (NOCROSSMOUNT | RDONLY);
973 else
974 cnp->cn_flags |= NOCROSSMOUNT;
975 /*
976 * And call lookup() to do the real work
977 */
978 cnp->cn_proc = p;
979 error = lookup(ndp);
980 if (error)
981 goto out;
982 /*
983 * Check for encountering a symbolic link
984 */
985 if (cnp->cn_flags & ISSYMLINK) {
986 if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1)
987 vput(ndp->ni_dvp);
988 else
989 vrele(ndp->ni_dvp);
990 vput(ndp->ni_vp);
991 ndp->ni_vp = NULL;
992 error = EINVAL;
993 goto out;
994 }
995 /*
996 * Check for saved name request
997 */
998 if (cnp->cn_flags & (SAVENAME | SAVESTART)) {
999 cnp->cn_flags |= HASBUF;
1000 nfsrv_vmio( ndp->ni_vp);
1001 return (0);
1002 }
1003out:
1004 FREE(cnp->cn_pnbuf, M_NAMEI);
1005 return (error);
1006}
1007
1008/*
1009 * A fiddled version of m_adj() that ensures null fill to a long
1010 * boundary and only trims off the back end
1011 */
1012void
1013nfsm_adj(mp, len, nul)
1014 struct mbuf *mp;
1015 register int len;
1016 int nul;
1017{
1018 register struct mbuf *m;
1019 register int count, i;
1020 register char *cp;
1021
1022 /*
1023 * Trim from tail. Scan the mbuf chain,
1024 * calculating its length and finding the last mbuf.
1025 * If the adjustment only affects this mbuf, then just
1026 * adjust and return. Otherwise, rescan and truncate
1027 * after the remaining size.
1028 */
1029 count = 0;
1030 m = mp;
1031 for (;;) {
1032 count += m->m_len;
1033 if (m->m_next == (struct mbuf *)0)
1034 break;
1035 m = m->m_next;
1036 }
1037 if (m->m_len > len) {
1038 m->m_len -= len;
1039 if (nul > 0) {
1040 cp = mtod(m, caddr_t)+m->m_len-nul;
1041 for (i = 0; i < nul; i++)
1042 *cp++ = '\0';
1043 }
1044 return;
1045 }
1046 count -= len;
1047 if (count < 0)
1048 count = 0;
1049 /*
1050 * Correct length for chain is "count".
1051 * Find the mbuf with last data, adjust its length,
1052 * and toss data from remaining mbufs on chain.
1053 */
1054 for (m = mp; m; m = m->m_next) {
1055 if (m->m_len >= count) {
1056 m->m_len = count;
1057 if (nul > 0) {
1058 cp = mtod(m, caddr_t)+m->m_len-nul;
1059 for (i = 0; i < nul; i++)
1060 *cp++ = '\0';
1061 }
1062 break;
1063 }
1064 count -= m->m_len;
1065 }
1066 for (m = m->m_next;m;m = m->m_next)
1067 m->m_len = 0;
1068}
1069
1070/*
1071 * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked)
1072 * - look up fsid in mount list (if not found ret error)
1073 * - get vp and export rights by calling VFS_FHTOVP()
1074 * - if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon
1075 * - if not lockflag unlock it with VOP_UNLOCK()
1076 */
1077int
1078nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp)
1079 fhandle_t *fhp;
1080 int lockflag;
1081 struct vnode **vpp;
1082 struct ucred *cred;
1083 struct nfssvc_sock *slp;
1084 struct mbuf *nam;
1085 int *rdonlyp;
1086{
1087 register struct mount *mp;
1088 register struct nfsuid *uidp;
1089 register int i;
1090 struct ucred *credanon;
1091 int error, exflags;
1092
1093 *vpp = (struct vnode *)0;
1094 mp = getvfs(&fhp->fh_fsid);
1095 if (!mp)
1096 return (ESTALE);
1097 error = VFS_FHTOVP(mp, &fhp->fh_fid, nam, vpp, &exflags, &credanon);
1098 if (error)
1099 return (error);
1100 /*
1101 * Check/setup credentials.
1102 */
1103 if (exflags & MNT_EXKERB) {
1104 for (uidp = NUIDHASH(slp, cred->cr_uid)->lh_first; uidp != 0;
1105 uidp = uidp->nu_hash.le_next) {
1106 if (uidp->nu_uid == cred->cr_uid)
1107 break;
1108 }
1109 if (uidp == 0) {
1110 vput(*vpp);
1111 return (NQNFS_AUTHERR);
1112 }
1113 cred->cr_uid = uidp->nu_cr.cr_uid;
1114 for (i = 0; i < uidp->nu_cr.cr_ngroups; i++)
1115 cred->cr_groups[i] = uidp->nu_cr.cr_groups[i];
1116 cred->cr_ngroups = i;
1117 } else if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) {
1118 cred->cr_uid = credanon->cr_uid;
1119 for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++)
1120 cred->cr_groups[i] = credanon->cr_groups[i];
1121 cred->cr_ngroups = i;
1122 }
1123 if (exflags & MNT_EXRDONLY)
1124 *rdonlyp = 1;
1125 else
1126 *rdonlyp = 0;
1127 if (!lockflag)
1128 VOP_UNLOCK(*vpp);
1129 nfsrv_vmio(*vpp);
1130 return (0);
1131}
1132
1133/*
1134 * This function compares two net addresses by family and returns TRUE
1135 * if they are the same host.
1136 * If there is any doubt, return FALSE.
1137 * The AF_INET family is handled as a special case so that address mbufs
1138 * don't need to be saved to store "struct in_addr", which is only 4 bytes.
1139 */
1140int
1141netaddr_match(family, haddr, nam)
1142 int family;
1143 union nethostaddr *haddr;
1144 struct mbuf *nam;
1145{
1146 register struct sockaddr_in *inetaddr;
1147
1148 switch (family) {
1149 case AF_INET:
1150 inetaddr = mtod(nam, struct sockaddr_in *);
1151 if (inetaddr->sin_family == AF_INET &&
1152 inetaddr->sin_addr.s_addr == haddr->had_inetaddr)
1153 return (1);
1154 break;
1155#ifdef ISO
1156 case AF_ISO:
1157 {
1158 register struct sockaddr_iso *isoaddr1, *isoaddr2;
1159
1160 isoaddr1 = mtod(nam, struct sockaddr_iso *);
1161 isoaddr2 = mtod(haddr->had_nam, struct sockaddr_iso *);
1162 if (isoaddr1->siso_family == AF_ISO &&
1163 isoaddr1->siso_nlen > 0 &&
1164 isoaddr1->siso_nlen == isoaddr2->siso_nlen &&
1165 SAME_ISOADDR(isoaddr1, isoaddr2))
1166 return (1);
1167 break;
1168 }
1169#endif /* ISO */
1170 default:
1171 break;
1172 };
1173 return (0);
1174}
1175
1176int
1177nfsrv_vmio( struct vnode *vp) {
1176 int rtval;
1177 vm_object_t object;
1178 vm_pager_t pager;
1179
1180 if( (vp == NULL) || (vp->v_type != VREG))
1181 return 1;
1182
1183retry:
1184 if( (vp->v_flag & VVMIO) == 0) {
1178 vm_object_t object;
1179 vm_pager_t pager;
1180
1181 if( (vp == NULL) || (vp->v_type != VREG))
1182 return 1;
1183
1184retry:
1185 if( (vp->v_flag & VVMIO) == 0) {
1185 pager = (vm_pager_t) vnode_pager_alloc(vp, 0, 0, 0);
1186 pager = (vm_pager_t) vnode_pager_alloc((caddr_t) vp, 0, 0, 0);
1186 object = (vm_object_t) vp->v_vmdata;
1187 if( object->pager != pager)
1188 panic("nfsrv_vmio: pager/object mismatch");
1189 (void) vm_object_lookup( pager);
1190 pager_cache( object, TRUE);
1191 vp->v_flag |= VVMIO;
1192 } else {
1193 if( (object = (vm_object_t)vp->v_vmdata) &&
1194 (object->flags & OBJ_DEAD)) {
1195 tsleep( (caddr_t) object, PVM, "nfdead", 0);
1196 goto retry;
1197 }
1198 if( !object)
1199 panic("nfsrv_vmio: VMIO object missing");
1200 pager = object->pager;
1201 if( !pager)
1202 panic("nfsrv_vmio: VMIO pager missing");
1203 (void) vm_object_lookup( pager);
1204 }
1205 return 0;
1206}
1207int
1208nfsrv_vput( struct vnode *vp) {
1209 if( (vp->v_flag & VVMIO) && vp->v_vmdata) {
1210 vput( vp);
1211 vm_object_deallocate( (vm_object_t) vp->v_vmdata);
1212 } else {
1213 vput( vp);
1214 }
1215 return 0;
1216}
1217int
1218nfsrv_vrele( struct vnode *vp) {
1219 if( (vp->v_flag & VVMIO) && vp->v_vmdata) {
1220 vrele( vp);
1221 vm_object_deallocate( (vm_object_t) vp->v_vmdata);
1222 } else {
1223 vrele( vp);
1224 }
1225 return 0;
1226}
1187 object = (vm_object_t) vp->v_vmdata;
1188 if( object->pager != pager)
1189 panic("nfsrv_vmio: pager/object mismatch");
1190 (void) vm_object_lookup( pager);
1191 pager_cache( object, TRUE);
1192 vp->v_flag |= VVMIO;
1193 } else {
1194 if( (object = (vm_object_t)vp->v_vmdata) &&
1195 (object->flags & OBJ_DEAD)) {
1196 tsleep( (caddr_t) object, PVM, "nfdead", 0);
1197 goto retry;
1198 }
1199 if( !object)
1200 panic("nfsrv_vmio: VMIO object missing");
1201 pager = object->pager;
1202 if( !pager)
1203 panic("nfsrv_vmio: VMIO pager missing");
1204 (void) vm_object_lookup( pager);
1205 }
1206 return 0;
1207}
1208int
1209nfsrv_vput( struct vnode *vp) {
1210 if( (vp->v_flag & VVMIO) && vp->v_vmdata) {
1211 vput( vp);
1212 vm_object_deallocate( (vm_object_t) vp->v_vmdata);
1213 } else {
1214 vput( vp);
1215 }
1216 return 0;
1217}
1218int
1219nfsrv_vrele( struct vnode *vp) {
1220 if( (vp->v_flag & VVMIO) && vp->v_vmdata) {
1221 vrele( vp);
1222 vm_object_deallocate( (vm_object_t) vp->v_vmdata);
1223 } else {
1224 vrele( vp);
1225 }
1226 return 0;
1227}