Deleted Added
full compact
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.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
74#include <vm/vnode_pager.h>
75
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) {
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) {
1186 pager = (vm_pager_t) vnode_pager_alloc((caddr_t) vp, 0, 0, 0);
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}