xref: /original-bsd/sys/nfs/nfs_subs.c (revision 5429b474)
1 /*
2  * Copyright (c) 1989 The Regents of the University of California.
3  * 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  * %sccs.include.redist.c%
9  *
10  *	@(#)nfs_subs.c	7.29 (Berkeley) 07/26/90
11  */
12 
13 /*
14  * These functions support the macros and help fiddle mbuf chains for
15  * the nfs op functions. They do things like create the rpc header and
16  * copy data between mbuf chains and uio lists.
17  */
18 #include "param.h"
19 #include "user.h"
20 #include "proc.h"
21 #include "systm.h"
22 #include "kernel.h"
23 #include "mount.h"
24 #include "file.h"
25 #include "vnode.h"
26 #include "mbuf.h"
27 #include "errno.h"
28 #include "map.h"
29 #include "rpcv2.h"
30 #include "nfsv2.h"
31 #include "nfsnode.h"
32 #include "nfs.h"
33 #include "nfsiom.h"
34 #include "xdr_subs.h"
35 #include "nfsm_subs.h"
36 
37 #define TRUE	1
38 #define	FALSE	0
39 
40 /*
41  * Data items converted to xdr at startup, since they are constant
42  * This is kinda hokey, but may save a little time doing byte swaps
43  */
44 u_long nfs_procids[NFS_NPROCS];
45 u_long nfs_xdrneg1;
46 u_long rpc_call, rpc_vers, rpc_reply, rpc_msgdenied,
47 	rpc_mismatch, rpc_auth_unix, rpc_msgaccepted;
48 u_long nfs_vers, nfs_prog, nfs_true, nfs_false;
49 /* And other global data */
50 static u_long *rpc_uidp = (u_long *)0;
51 static u_long nfs_xid = 1;
52 static char *rpc_unixauth;
53 extern long hostid;
54 enum vtype ntov_type[7] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON };
55 extern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON];
56 extern struct map nfsmap[NFS_MSIZ];
57 extern struct nfsreq nfsreqh;
58 
59 /* Function ret types */
60 static char *nfs_unixauth();
61 
62 /*
63  * Maximum number of groups passed through to NFS server.
64  * According to RFC1057 it should be 16.
65  * For release 3.X systems, the maximum value is 8.
66  * For some other servers, the maximum value is 10.
67  */
68 int numgrps = 8;
69 
70 /*
71  * Create the header for an rpc request packet
72  * The function nfs_unixauth() creates a unix style authorization string
73  * and returns a ptr to it.
74  * The hsiz is the size of the rest of the nfs request header.
75  * (just used to decide if a cluster is a good idea)
76  * nb: Note that the prog, vers and procid args are already in xdr byte order
77  */
78 struct mbuf *nfsm_reqh(prog, vers, procid, cred, hsiz, bpos, mb, retxid)
79 	u_long prog;
80 	u_long vers;
81 	u_long procid;
82 	struct ucred *cred;
83 	int hsiz;
84 	caddr_t *bpos;
85 	struct mbuf **mb;
86 	u_long *retxid;
87 {
88 	register struct mbuf *mreq, *m;
89 	register u_long *p;
90 	struct mbuf *m1;
91 	char *ap;
92 	int asiz, siz;
93 
94 	NFSMGETHDR(mreq);
95 	asiz = ((((cred->cr_ngroups - 1) > numgrps) ? numgrps :
96 		  (cred->cr_ngroups - 1)) << 2);
97 #ifdef FILLINHOST
98 	asiz += nfsm_rndup(hostnamelen)+(9*NFSX_UNSIGNED);
99 #else
100 	asiz += 9*NFSX_UNSIGNED;
101 #endif
102 
103 	/* If we need a lot, alloc a cluster ?? */
104 	if ((asiz+hsiz+RPC_SIZ) > MHLEN)
105 		MCLGET(mreq, M_WAIT);
106 	mreq->m_len = NFSMSIZ(mreq);
107 	siz = mreq->m_len;
108 	m1 = mreq;
109 	/*
110 	 * Alloc enough mbufs
111 	 * We do it now to avoid all sleeps after the call to nfs_unixauth()
112 	 */
113 	while ((asiz+RPC_SIZ) > siz) {
114 		MGET(m, M_WAIT, MT_DATA);
115 		m1->m_next = m;
116 		m->m_len = MLEN;
117 		siz += MLEN;
118 		m1 = m;
119 	}
120 	p = mtod(mreq, u_long *);
121 	*p++ = *retxid = txdr_unsigned(++nfs_xid);
122 	*p++ = rpc_call;
123 	*p++ = rpc_vers;
124 	*p++ = prog;
125 	*p++ = vers;
126 	*p++ = procid;
127 
128 	/* Now we can call nfs_unixauth() and copy it in */
129 	ap = nfs_unixauth(cred);
130 	m = mreq;
131 	siz = m->m_len-RPC_SIZ;
132 	if (asiz <= siz) {
133 		bcopy(ap, (caddr_t)p, asiz);
134 		m->m_len = asiz+RPC_SIZ;
135 	} else {
136 		bcopy(ap, (caddr_t)p, siz);
137 		ap += siz;
138 		asiz -= siz;
139 		while (asiz > 0) {
140 			siz = (asiz > MLEN) ? MLEN : asiz;
141 			m = m->m_next;
142 			bcopy(ap, mtod(m, caddr_t), siz);
143 			m->m_len = siz;
144 			asiz -= siz;
145 			ap += siz;
146 		}
147 	}
148 
149 	/* Finally, return values */
150 	*mb = m;
151 	*bpos = mtod(m, caddr_t)+m->m_len;
152 	return (mreq);
153 }
154 
155 /*
156  * copies mbuf chain to the uio scatter/gather list
157  */
158 nfsm_mbuftouio(mrep, uiop, siz, dpos)
159 	struct mbuf **mrep;
160 	register struct uio *uiop;
161 	int siz;
162 	caddr_t *dpos;
163 {
164 	register char *mbufcp, *uiocp;
165 	register int xfer, left, len;
166 	register struct mbuf *mp;
167 	long uiosiz, rem;
168 	int error = 0;
169 
170 	mp = *mrep;
171 	mbufcp = *dpos;
172 	len = mtod(mp, caddr_t)+mp->m_len-mbufcp;
173 	rem = nfsm_rndup(siz)-siz;
174 	while (siz > 0) {
175 		if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
176 			return (EFBIG);
177 		left = uiop->uio_iov->iov_len;
178 		uiocp = uiop->uio_iov->iov_base;
179 		if (left > siz)
180 			left = siz;
181 		uiosiz = left;
182 		while (left > 0) {
183 			while (len == 0) {
184 				mp = mp->m_next;
185 				if (mp == NULL)
186 					return (EBADRPC);
187 				mbufcp = mtod(mp, caddr_t);
188 				len = mp->m_len;
189 			}
190 			xfer = (left > len) ? len : left;
191 #ifdef notdef
192 			/* Not Yet.. */
193 			if (uiop->uio_iov->iov_op != NULL)
194 				(*(uiop->uio_iov->iov_op))
195 				(mbufcp, uiocp, xfer);
196 			else
197 #endif
198 			if (uiop->uio_segflg == UIO_SYSSPACE)
199 				bcopy(mbufcp, uiocp, xfer);
200 			else
201 				copyout(mbufcp, uiocp, xfer);
202 			left -= xfer;
203 			len -= xfer;
204 			mbufcp += xfer;
205 			uiocp += xfer;
206 			uiop->uio_offset += xfer;
207 			uiop->uio_resid -= xfer;
208 		}
209 		if (uiop->uio_iov->iov_len <= siz) {
210 			uiop->uio_iovcnt--;
211 			uiop->uio_iov++;
212 		} else {
213 			uiop->uio_iov->iov_base += uiosiz;
214 			uiop->uio_iov->iov_len -= uiosiz;
215 		}
216 		siz -= uiosiz;
217 	}
218 	*dpos = mbufcp;
219 	*mrep = mp;
220 	if (rem > 0) {
221 		if (len < rem)
222 			error = nfs_adv(mrep, dpos, rem, len);
223 		else
224 			*dpos += rem;
225 	}
226 	return (error);
227 }
228 
229 /*
230  * copies a uio scatter/gather list to an mbuf chain...
231  */
232 nfsm_uiotombuf(uiop, mq, siz, bpos)
233 	register struct uio *uiop;
234 	struct mbuf **mq;
235 	int siz;
236 	caddr_t *bpos;
237 {
238 	register char *uiocp;
239 	register struct mbuf *mp, *mp2;
240 	register int xfer, left, len;
241 	int uiosiz, clflg, rem;
242 	char *cp;
243 
244 	if (siz > MLEN)		/* or should it >= MCLBYTES ?? */
245 		clflg = 1;
246 	else
247 		clflg = 0;
248 	rem = nfsm_rndup(siz)-siz;
249 	mp2 = *mq;
250 	while (siz > 0) {
251 		if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
252 			return (EINVAL);
253 		left = uiop->uio_iov->iov_len;
254 		uiocp = uiop->uio_iov->iov_base;
255 		if (left > siz)
256 			left = siz;
257 		uiosiz = left;
258 		while (left > 0) {
259 			MGET(mp, M_WAIT, MT_DATA);
260 			if (clflg)
261 				MCLGET(mp, M_WAIT);
262 			mp->m_len = NFSMSIZ(mp);
263 			mp2->m_next = mp;
264 			mp2 = mp;
265 			xfer = (left > mp->m_len) ? mp->m_len : left;
266 #ifdef notdef
267 			/* Not Yet.. */
268 			if (uiop->uio_iov->iov_op != NULL)
269 				(*(uiop->uio_iov->iov_op))
270 				(uiocp, mtod(mp, caddr_t), xfer);
271 			else
272 #endif
273 			if (uiop->uio_segflg == UIO_SYSSPACE)
274 				bcopy(uiocp, mtod(mp, caddr_t), xfer);
275 			else
276 				copyin(uiocp, mtod(mp, caddr_t), xfer);
277 			len = mp->m_len;
278 			mp->m_len = xfer;
279 			left -= xfer;
280 			uiocp += xfer;
281 			uiop->uio_offset += xfer;
282 			uiop->uio_resid -= xfer;
283 		}
284 		if (uiop->uio_iov->iov_len <= siz) {
285 			uiop->uio_iovcnt--;
286 			uiop->uio_iov++;
287 		} else {
288 			uiop->uio_iov->iov_base += uiosiz;
289 			uiop->uio_iov->iov_len -= uiosiz;
290 		}
291 		siz -= uiosiz;
292 	}
293 	if (rem > 0) {
294 		if (rem > (len-mp->m_len)) {
295 			MGET(mp, M_WAIT, MT_DATA);
296 			mp->m_len = 0;
297 			mp2->m_next = mp;
298 		}
299 		cp = mtod(mp, caddr_t)+mp->m_len;
300 		for (left = 0; left < rem; left++)
301 			*cp++ = '\0';
302 		mp->m_len += rem;
303 		*bpos = cp;
304 	} else
305 		*bpos = mtod(mp, caddr_t)+mp->m_len;
306 	*mq = mp;
307 	return (0);
308 }
309 
310 /*
311  * Help break down an mbuf chain by setting the first siz bytes contiguous
312  * pointed to by returned val.
313  * If Updateflg == True we can overwrite the first part of the mbuf data
314  * This is used by the macros nfsm_disect and nfsm_disecton for tough
315  * cases. (The macros use the vars. dpos and dpos2)
316  */
317 nfsm_disct(mdp, dposp, siz, left, updateflg, cp2)
318 	struct mbuf **mdp;
319 	caddr_t *dposp;
320 	int siz;
321 	int left;
322 	int updateflg;
323 	caddr_t *cp2;
324 {
325 	register struct mbuf *mp, *mp2;
326 	register int siz2, xfer;
327 	register caddr_t p;
328 
329 	mp = *mdp;
330 	while (left == 0) {
331 		*mdp = mp = mp->m_next;
332 		if (mp == NULL)
333 			return (EBADRPC);
334 		left = mp->m_len;
335 		*dposp = mtod(mp, caddr_t);
336 	}
337 	if (left >= siz) {
338 		*cp2 = *dposp;
339 		*dposp += siz;
340 	} else if (mp->m_next == NULL) {
341 		return (EBADRPC);
342 	} else if (siz > MHLEN) {
343 		panic("nfs S too big");
344 	} else {
345 		/* Iff update, you can overwrite, else must alloc new mbuf */
346 		if (updateflg) {
347 			NFSMINOFF(mp);
348 		} else {
349 			MGET(mp2, M_WAIT, MT_DATA);
350 			mp2->m_next = mp->m_next;
351 			mp->m_next = mp2;
352 			mp->m_len -= left;
353 			mp = mp2;
354 		}
355 		*cp2 = p = mtod(mp, caddr_t);
356 		bcopy(*dposp, p, left);		/* Copy what was left */
357 		siz2 = siz-left;
358 		p += left;
359 		mp2 = mp->m_next;
360 		/* Loop around copying up the siz2 bytes */
361 		while (siz2 > 0) {
362 			if (mp2 == NULL)
363 				return (EBADRPC);
364 			xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2;
365 			if (xfer > 0) {
366 				bcopy(mtod(mp2, caddr_t), p, xfer);
367 				NFSMADV(mp2, xfer);
368 				mp2->m_len -= xfer;
369 				p += xfer;
370 				siz2 -= xfer;
371 			}
372 			if (siz2 > 0)
373 				mp2 = mp2->m_next;
374 		}
375 		mp->m_len = siz;
376 		*mdp = mp2;
377 		*dposp = mtod(mp2, caddr_t);
378 	}
379 	return (0);
380 }
381 
382 /*
383  * Advance the position in the mbuf chain.
384  */
385 nfs_adv(mdp, dposp, offs, left)
386 	struct mbuf **mdp;
387 	caddr_t *dposp;
388 	int offs;
389 	int left;
390 {
391 	register struct mbuf *m;
392 	register int s;
393 
394 	m = *mdp;
395 	s = left;
396 	while (s < offs) {
397 		offs -= s;
398 		m = m->m_next;
399 		if (m == NULL)
400 			return (EBADRPC);
401 		s = m->m_len;
402 	}
403 	*mdp = m;
404 	*dposp = mtod(m, caddr_t)+offs;
405 	return (0);
406 }
407 
408 /*
409  * Copy a string into mbufs for the hard cases...
410  */
411 nfsm_strtmbuf(mb, bpos, cp, siz)
412 	struct mbuf **mb;
413 	char **bpos;
414 	char *cp;
415 	long siz;
416 {
417 	register struct mbuf *m1, *m2;
418 	long left, xfer, len, tlen;
419 	u_long *p;
420 	int putsize;
421 
422 	putsize = 1;
423 	m2 = *mb;
424 	left = NFSMSIZ(m2)-m2->m_len;
425 	if (left > 0) {
426 		p = ((u_long *)(*bpos));
427 		*p++ = txdr_unsigned(siz);
428 		putsize = 0;
429 		left -= NFSX_UNSIGNED;
430 		m2->m_len += NFSX_UNSIGNED;
431 		if (left > 0) {
432 			bcopy(cp, (caddr_t) p, left);
433 			siz -= left;
434 			cp += left;
435 			m2->m_len += left;
436 			left = 0;
437 		}
438 	}
439 	/* Loop arround adding mbufs */
440 	while (siz > 0) {
441 		MGET(m1, M_WAIT, MT_DATA);
442 		if (siz > MLEN)
443 			MCLGET(m1, M_WAIT);
444 		m1->m_len = NFSMSIZ(m1);
445 		m2->m_next = m1;
446 		m2 = m1;
447 		p = mtod(m1, u_long *);
448 		tlen = 0;
449 		if (putsize) {
450 			*p++ = txdr_unsigned(siz);
451 			m1->m_len -= NFSX_UNSIGNED;
452 			tlen = NFSX_UNSIGNED;
453 			putsize = 0;
454 		}
455 		if (siz < m1->m_len) {
456 			len = nfsm_rndup(siz);
457 			xfer = siz;
458 			if (xfer < len)
459 				*(p+(xfer>>2)) = 0;
460 		} else {
461 			xfer = len = m1->m_len;
462 		}
463 		bcopy(cp, (caddr_t) p, xfer);
464 		m1->m_len = len+tlen;
465 		siz -= xfer;
466 		cp += xfer;
467 	}
468 	*mb = m1;
469 	*bpos = mtod(m1, caddr_t)+m1->m_len;
470 	return (0);
471 }
472 
473 /*
474  * Called once to initialize data structures...
475  */
476 nfs_init()
477 {
478 	register int i;
479 
480 	rpc_vers = txdr_unsigned(RPC_VER2);
481 	rpc_call = txdr_unsigned(RPC_CALL);
482 	rpc_reply = txdr_unsigned(RPC_REPLY);
483 	rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED);
484 	rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED);
485 	rpc_mismatch = txdr_unsigned(RPC_MISMATCH);
486 	rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX);
487 	nfs_vers = txdr_unsigned(NFS_VER2);
488 	nfs_prog = txdr_unsigned(NFS_PROG);
489 	nfs_true = txdr_unsigned(TRUE);
490 	nfs_false = txdr_unsigned(FALSE);
491 	/* Loop thru nfs procids */
492 	for (i = 0; i < NFS_NPROCS; i++)
493 		nfs_procids[i] = txdr_unsigned(i);
494 	/* Ensure async daemons disabled */
495 	for (i = 0; i < NFS_MAXASYNCDAEMON; i++)
496 		nfs_iodwant[i] = (struct proc *)0;
497 	nfs_xdrneg1 = txdr_unsigned(-1);
498 	nfs_nhinit();			/* Init the nfsnode table */
499 	nfsrv_initcache();		/* Init the server request cache */
500 	rminit(nfsmap, (long)NFS_MAPREG, (long)1, "nfs mapreg", NFS_MSIZ);
501 
502 	/*
503 	 * Initialize reply list and start timer
504 	 */
505 	nfsreqh.r_prev = nfsreqh.r_next = &nfsreqh;
506 	nfs_timer();
507 }
508 
509 /*
510  * Fill in the rest of the rpc_unixauth and return it
511  */
512 static char *nfs_unixauth(cr)
513 	register struct ucred *cr;
514 {
515 	register u_long *p;
516 	register int i;
517 	int ngr;
518 
519 	/* Maybe someday there should be a cache of AUTH_SHORT's */
520 	if ((p = rpc_uidp) == NULL) {
521 #ifdef FILLINHOST
522 		i = nfsm_rndup(hostnamelen)+(25*NFSX_UNSIGNED);
523 #else
524 		i = 25*NFSX_UNSIGNED;
525 #endif
526 		MALLOC(p, u_long *, i, M_TEMP, M_WAITOK);
527 		bzero((caddr_t)p, i);
528 		rpc_unixauth = (caddr_t)p;
529 		*p++ = txdr_unsigned(RPCAUTH_UNIX);
530 		p++;	/* Fill in size later */
531 		*p++ = hostid;
532 #ifdef FILLINHOST
533 		*p++ = txdr_unsigned(hostnamelen);
534 		i = nfsm_rndup(hostnamelen);
535 		bcopy(hostname, (caddr_t)p, hostnamelen);
536 		p += (i>>2);
537 #else
538 		*p++ = 0;
539 #endif
540 		rpc_uidp = p;
541 	}
542 	*p++ = txdr_unsigned(cr->cr_uid);
543 	*p++ = txdr_unsigned(cr->cr_groups[0]);
544 	ngr = ((cr->cr_ngroups - 1) > numgrps) ? numgrps : (cr->cr_ngroups - 1);
545 	*p++ = txdr_unsigned(ngr);
546 	for (i = 1; i <= ngr; i++)
547 		*p++ = txdr_unsigned(cr->cr_groups[i]);
548 	/* And add the AUTH_NULL */
549 	*p++ = 0;
550 	*p = 0;
551 	i = (((caddr_t)p)-rpc_unixauth)-12;
552 	p = (u_long *)(rpc_unixauth+4);
553 	*p = txdr_unsigned(i);
554 	return (rpc_unixauth);
555 }
556 
557 /*
558  * Attribute cache routines.
559  * nfs_loadattrcache() - loads or updates the cache contents from attributes
560  *	that are on the mbuf list
561  * nfs_getattrcache() - returns valid attributes if found in cache, returns
562  *	error otherwise
563  */
564 
565 /*
566  * Load the attribute cache (that lives in the nfsnode entry) with
567  * the values on the mbuf list and
568  * Iff vap not NULL
569  *    copy the attributes to *vaper
570  */
571 nfs_loadattrcache(vpp, mdp, dposp, vaper)
572 	struct vnode **vpp;
573 	struct mbuf **mdp;
574 	caddr_t *dposp;
575 	struct vattr *vaper;
576 {
577 	register struct vnode *vp = *vpp;
578 	register struct vattr *vap;
579 	register struct nfsv2_fattr *fp;
580 	extern struct vnodeops spec_nfsv2nodeops;
581 	register struct nfsnode *np;
582 	register long t1;
583 	caddr_t dpos, cp2;
584 	int error = 0;
585 	struct mbuf *md;
586 	enum vtype type;
587 	long rdev;
588 	struct timeval mtime;
589 	struct vnode *nvp;
590 
591 	md = *mdp;
592 	dpos = *dposp;
593 	t1 = (mtod(md, caddr_t)+md->m_len)-dpos;
594 	if (error = nfsm_disct(&md, &dpos, NFSX_FATTR, t1, TRUE, &cp2))
595 		return (error);
596 	fp = (struct nfsv2_fattr *)cp2;
597 	type = nfstov_type(fp->fa_type);
598 	rdev = fxdr_unsigned(long, fp->fa_rdev);
599 	fxdr_time(&fp->fa_mtime, &mtime);
600 	/*
601 	 * If v_type == VNON it is a new node, so fill in the v_type,
602 	 * n_mtime fields. Check to see if it represents a special
603 	 * device, and if so, check for a possible alias. Once the
604 	 * correct vnode has been obtained, fill in the rest of the
605 	 * information.
606 	 */
607 	np = VTONFS(vp);
608 	if (vp->v_type == VNON) {
609 		if (type == VCHR && rdev == 0xffffffff)
610 			vp->v_type = type = VFIFO;
611 		else
612 			vp->v_type = type;
613 		if (vp->v_type == VFIFO) {
614 #ifdef FIFO
615 			extern struct vnodeops fifo_nfsv2nodeops;
616 			vp->v_op = &fifo_nfsv2nodeops;
617 #else
618 			return (EOPNOTSUPP);
619 #endif /* FIFO */
620 		}
621 		if (vp->v_type == VCHR || vp->v_type == VBLK) {
622 			vp->v_op = &spec_nfsv2nodeops;
623 			if (nvp = checkalias(vp, (dev_t)rdev, vp->v_mount)) {
624 				/*
625 				 * Reinitialize aliased node.
626 				 */
627 				np = VTONFS(nvp);
628 				np->n_vnode = nvp;
629 				np->n_flag = 0;
630 				nfs_lock(nvp);
631 				bcopy((caddr_t)&VTONFS(vp)->n_fh,
632 					(caddr_t)&np->n_fh, NFSX_FH);
633 				insque(np, nfs_hash(&np->n_fh));
634 				np->n_attrstamp = 0;
635 				np->n_sillyrename = (struct sillyrename *)0;
636 				/*
637 				 * Discard unneeded vnode and update actual one
638 				 */
639 				vput(vp);
640 				*vpp = nvp;
641 			}
642 		}
643 		np->n_mtime = mtime.tv_sec;
644 	}
645 	vap = &np->n_vattr;
646 	vap->va_type = type;
647 	vap->va_mode = nfstov_mode(fp->fa_mode);
648 	vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
649 	vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid);
650 	vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid);
651 	vap->va_size = fxdr_unsigned(u_long, fp->fa_size);
652 	if ((np->n_flag & NMODIFIED) == 0 || vap->va_size > np->n_size)
653 		np->n_size = vap->va_size;
654 	vap->va_size_rsv = 0;
655 	vap->va_blocksize = fxdr_unsigned(long, fp->fa_blocksize);
656 	vap->va_rdev = (dev_t)rdev;
657 	vap->va_bytes = fxdr_unsigned(long, fp->fa_blocks) * NFS_FABLKSIZE;
658 	vap->va_bytes_rsv = 0;
659 	vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
660 	vap->va_fileid = fxdr_unsigned(long, fp->fa_fileid);
661 	vap->va_atime.tv_sec = fxdr_unsigned(long, fp->fa_atime.tv_sec);
662 	vap->va_atime.tv_usec = 0;
663 	vap->va_flags = fxdr_unsigned(u_long, fp->fa_atime.tv_usec);
664 	vap->va_mtime = mtime;
665 	vap->va_ctime.tv_sec = fxdr_unsigned(long, fp->fa_ctime.tv_sec);
666 	vap->va_ctime.tv_usec = 0;
667 	vap->va_gen = fxdr_unsigned(u_long, fp->fa_ctime.tv_usec);
668 	np->n_attrstamp = time.tv_sec;
669 	*dposp = dpos;
670 	*mdp = md;
671 	if (vaper != NULL) {
672 		bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap));
673 		if ((np->n_flag & NMODIFIED) && (np->n_size > vap->va_size))
674 			vaper->va_size = np->n_size;
675 	}
676 	return (0);
677 }
678 
679 /*
680  * Check the time stamp
681  * If the cache is valid, copy contents to *vap and return 0
682  * otherwise return an error
683  */
684 nfs_getattrcache(vp, vap)
685 	register struct vnode *vp;
686 	struct vattr *vap;
687 {
688 	register struct nfsnode *np;
689 
690 	np = VTONFS(vp);
691 	if ((time.tv_sec-np->n_attrstamp) < NFS_ATTRTIMEO) {
692 		nfsstats.attrcache_hits++;
693 		bcopy((caddr_t)&np->n_vattr,(caddr_t)vap,sizeof(struct vattr));
694 		if ((np->n_flag & NMODIFIED) == 0)
695 			np->n_size = vap->va_size;
696 		else if (np->n_size > vap->va_size)
697 			vap->va_size = np->n_size;
698 		return (0);
699 	} else {
700 		nfsstats.attrcache_misses++;
701 		return (ENOENT);
702 	}
703 }
704 
705 /*
706  * Set up nameidata for a namei() call and do it
707  */
708 nfs_namei(ndp, fhp, len, mdp, dposp)
709 	register struct nameidata *ndp;
710 	fhandle_t *fhp;
711 	int len;
712 	struct mbuf **mdp;
713 	caddr_t *dposp;
714 {
715 	register int i, rem;
716 	register struct mbuf *md;
717 	register char *cp;
718 	struct vnode *dp;
719 	int flag;
720 	int error;
721 
722 	if ((ndp->ni_nameiop & HASBUF) == 0) {
723 		flag = ndp->ni_nameiop & OPFLAG;
724 		/*
725 		 * Copy the name from the mbuf list to the d_name field of ndp
726 		 * and set the various ndp fields appropriately.
727 		 */
728 		cp = *dposp;
729 		md = *mdp;
730 		rem = mtod(md, caddr_t)+md->m_len-cp;
731 		ndp->ni_hash = 0;
732 		for (i = 0; i < len;) {
733 			while (rem == 0) {
734 				md = md->m_next;
735 				if (md == NULL)
736 					return (EBADRPC);
737 				cp = mtod(md, caddr_t);
738 				rem = md->m_len;
739 			}
740 			if (*cp == '\0' || *cp == '/')
741 				return (EINVAL);
742 			if (*cp & 0200)
743 				if ((*cp&0377) == ('/'|0200) || flag != DELETE)
744 					return (EINVAL);
745 			ndp->ni_dent.d_name[i++] = *cp;
746 			ndp->ni_hash += (unsigned char)*cp * i;
747 			cp++;
748 			rem--;
749 		}
750 		*mdp = md;
751 		*dposp = cp;
752 		len = nfsm_rndup(len)-len;
753 		if (len > 0) {
754 			if (rem < len) {
755 				if (error = nfs_adv(mdp, dposp, len, rem))
756 					return (error);
757 			} else
758 				*dposp += len;
759 		}
760 	} else
761 		i = len;
762 	ndp->ni_namelen = i;
763 	ndp->ni_dent.d_namlen = i;
764 	ndp->ni_dent.d_name[i] = '\0';
765 	ndp->ni_segflg = UIO_SYSSPACE;
766 	ndp->ni_pathlen = 1;
767 	ndp->ni_pnbuf = ndp->ni_dirp = ndp->ni_ptr = &ndp->ni_dent.d_name[0];
768 	ndp->ni_next = &ndp->ni_dent.d_name[i];
769 	ndp->ni_nameiop |= (NOCROSSMOUNT | REMOTE | HASBUF);
770 
771 	if (error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cred))
772 		return (error);
773 	if (dp->v_type != VDIR) {
774 		vrele(dp);
775 		return (ENOTDIR);
776 	}
777 	/*
778 	 * Must set current directory here to avoid confusion in namei()
779 	 * called from rename()
780 	 */
781 	ndp->ni_cdir = dp;
782 	ndp->ni_rdir = NULLVP;
783 
784 	/*
785 	 * And call namei() to do the real work
786 	 */
787 	error = namei(ndp);
788 	vrele(dp);
789 	return (error);
790 }
791 
792 /*
793  * A fiddled version of m_adj() that ensures null fill to a long
794  * boundary and only trims off the back end
795  */
796 nfsm_adj(mp, len, nul)
797 	struct mbuf *mp;
798 	register int len;
799 	int nul;
800 {
801 	register struct mbuf *m;
802 	register int count, i;
803 	register char *cp;
804 
805 	/*
806 	 * Trim from tail.  Scan the mbuf chain,
807 	 * calculating its length and finding the last mbuf.
808 	 * If the adjustment only affects this mbuf, then just
809 	 * adjust and return.  Otherwise, rescan and truncate
810 	 * after the remaining size.
811 	 */
812 	count = 0;
813 	m = mp;
814 	for (;;) {
815 		count += m->m_len;
816 		if (m->m_next == (struct mbuf *)0)
817 			break;
818 		m = m->m_next;
819 	}
820 	if (m->m_len > len) {
821 		m->m_len -= len;
822 		if (nul > 0) {
823 			cp = mtod(m, caddr_t)+m->m_len-nul;
824 			for (i = 0; i < nul; i++)
825 				*cp++ = '\0';
826 		}
827 		return;
828 	}
829 	count -= len;
830 	if (count < 0)
831 		count = 0;
832 	/*
833 	 * Correct length for chain is "count".
834 	 * Find the mbuf with last data, adjust its length,
835 	 * and toss data from remaining mbufs on chain.
836 	 */
837 	for (m = mp; m; m = m->m_next) {
838 		if (m->m_len >= count) {
839 			m->m_len = count;
840 			if (nul > 0) {
841 				cp = mtod(m, caddr_t)+m->m_len-nul;
842 				for (i = 0; i < nul; i++)
843 					*cp++ = '\0';
844 			}
845 			break;
846 		}
847 		count -= m->m_len;
848 	}
849 	while (m = m->m_next)
850 		m->m_len = 0;
851 }
852 
853 /*
854  * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked)
855  * 	- look up fsid in mount list (if not found ret error)
856  *	- check that it is exported
857  *	- get vp by calling VFS_FHTOVP() macro
858  *	- if not lockflag unlock it with VOP_UNLOCK()
859  *	- if cred->cr_uid == 0 set it to m_exroot
860  */
861 nfsrv_fhtovp(fhp, lockflag, vpp, cred)
862 	fhandle_t *fhp;
863 	int lockflag;
864 	struct vnode **vpp;
865 	struct ucred *cred;
866 {
867 	register struct mount *mp;
868 
869 	if ((mp = getvfs(&fhp->fh_fsid)) == NULL)
870 		return (ESTALE);
871 	if ((mp->mnt_flag & MNT_EXPORTED) == 0)
872 		return (EACCES);
873 	if (VFS_FHTOVP(mp, &fhp->fh_fid, vpp))
874 		return (ESTALE);
875 	if (cred->cr_uid == 0)
876 		cred->cr_uid = mp->mnt_exroot;
877 	if (!lockflag)
878 		VOP_UNLOCK(*vpp);
879 	return (0);
880 }
881