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