xref: /dragonfly/sys/vfs/nfs/nfsm_subs.c (revision a68e0df0)
1 /*
2  * Copyright (c) 2009 The DragonFly Project.  All rights reserved.
3  *
4  * This code is derived from software contributed to The DragonFly Project
5  * by Matthew Dillon <dillon@backplane.com>
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
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
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  * 3. Neither the name of The DragonFly Project nor the names of its
18  *    contributors may be used to endorse or promote products derived
19  *    from this software without specific, prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34 /*
35  * Copyright (c) 1989, 1993
36  *	The Regents of the University of California.  All rights reserved.
37  *
38  * This code is derived from software contributed to Berkeley by
39  * Rick Macklem at The University of Guelph.
40  *
41  * Redistribution and use in source and binary forms, with or without
42  * modification, are permitted provided that the following conditions
43  * are met:
44  * 1. Redistributions of source code must retain the above copyright
45  *    notice, this list of conditions and the following disclaimer.
46  * 2. Redistributions in binary form must reproduce the above copyright
47  *    notice, this list of conditions and the following disclaimer in the
48  *    documentation and/or other materials provided with the distribution.
49  * 3. All advertising materials mentioning features or use of this software
50  *    must display the following acknowledgement:
51  *	This product includes software developed by the University of
52  *	California, Berkeley and its contributors.
53  * 4. Neither the name of the University nor the names of its contributors
54  *    may be used to endorse or promote products derived from this software
55  *    without specific prior written permission.
56  *
57  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
58  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
59  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
60  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
61  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
62  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
63  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
64  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
65  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
66  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
67  * SUCH DAMAGE.
68  */
69 
70 /*
71  * These functions support the macros and help fiddle mbuf chains for
72  * the nfs op functions. They do things like create the rpc header and
73  * copy data between mbuf chains and uio lists.
74  */
75 #include <sys/param.h>
76 #include <sys/systm.h>
77 #include <sys/kernel.h>
78 #include <sys/buf.h>
79 #include <sys/proc.h>
80 #include <sys/mount.h>
81 #include <sys/vnode.h>
82 #include <sys/nlookup.h>
83 #include <sys/namei.h>
84 #include <sys/mbuf.h>
85 #include <sys/socket.h>
86 #include <sys/stat.h>
87 #include <sys/malloc.h>
88 #include <sys/sysent.h>
89 #include <sys/syscall.h>
90 #include <sys/conf.h>
91 #include <sys/objcache.h>
92 
93 #include <vm/vm.h>
94 #include <vm/vm_object.h>
95 #include <vm/vm_extern.h>
96 #include <vm/vm_zone.h>
97 
98 #include <sys/buf2.h>
99 
100 #include "rpcv2.h"
101 #include "nfsproto.h"
102 #include "nfs.h"
103 #include "nfsmount.h"
104 #include "nfsnode.h"
105 #include "xdr_subs.h"
106 #include "nfsm_subs.h"
107 #include "nfsrtt.h"
108 
109 #include <netinet/in.h>
110 
111 static u_int32_t nfs_xid = 0;
112 
113 /*
114  * Create the header for an rpc request packet
115  * The hsiz is the size of the rest of the nfs request header.
116  * (just used to decide if a cluster is a good idea)
117  */
118 void
119 nfsm_reqhead(nfsm_info_t info, struct vnode *vp, u_long procid, int hsiz)
120 {
121 	info->mb = m_getl(hsiz, MB_WAIT, MT_DATA, 0, NULL);
122 	info->mb->m_len = 0;
123 	info->mreq = info->mb;
124 	info->bpos = mtod(info->mb, caddr_t);
125 }
126 
127 /*
128  * Build the RPC header and fill in the authorization info.
129  * The authorization string argument is only used when the credentials
130  * come from outside of the kernel.
131  * Returns the head of the mbuf list.
132  */
133 struct mbuf *
134 nfsm_rpchead(struct ucred *cr, int nmflag, int procid, int auth_type,
135 	     int auth_len, char *auth_str, int verf_len, char *verf_str,
136 	     struct mbuf *mrest, int mrest_len, struct mbuf **mbp,
137 	     u_int32_t *xidp)
138 {
139 	struct nfsm_info info;
140 	struct mbuf *mb2;
141 	u_int32_t *tl;
142 	int siz, grpsiz, authsiz, dsiz;
143 	int i;
144 
145 	authsiz = nfsm_rndup(auth_len);
146 	dsiz = authsiz + 10 * NFSX_UNSIGNED;
147 	info.mb = m_getl(dsiz, MB_WAIT, MT_DATA, M_PKTHDR, NULL);
148 	if (dsiz < MINCLSIZE) {
149 		if (dsiz < MHLEN)
150 			MH_ALIGN(info.mb, dsiz);
151 		else
152 			MH_ALIGN(info.mb, 8 * NFSX_UNSIGNED);
153 	}
154 	info.mb->m_len = info.mb->m_pkthdr.len = 0;
155 	info.mreq = info.mb;
156 	info.bpos = mtod(info.mb, caddr_t);
157 
158 	/*
159 	 * First the RPC header.
160 	 */
161 	tl = nfsm_build(&info, 8 * NFSX_UNSIGNED);
162 
163 	/* Get a pretty random xid to start with */
164 	if (!nfs_xid)
165 		nfs_xid = krandom();
166 	/*
167 	 * Skip zero xid if it should ever happen.
168 	 */
169 	if (++nfs_xid == 0)
170 		nfs_xid++;
171 
172 	*tl++ = *xidp = txdr_unsigned(nfs_xid);
173 	*tl++ = rpc_call;
174 	*tl++ = rpc_vers;
175 	*tl++ = txdr_unsigned(NFS_PROG);
176 	if (nmflag & NFSMNT_NFSV3)
177 		*tl++ = txdr_unsigned(NFS_VER3);
178 	else
179 		*tl++ = txdr_unsigned(NFS_VER2);
180 	if (nmflag & NFSMNT_NFSV3)
181 		*tl++ = txdr_unsigned(procid);
182 	else
183 		*tl++ = txdr_unsigned(nfsv2_procid[procid]);
184 
185 	/*
186 	 * And then the authorization cred.
187 	 */
188 	*tl++ = txdr_unsigned(auth_type);
189 	*tl = txdr_unsigned(authsiz);
190 	switch (auth_type) {
191 	case RPCAUTH_UNIX:
192 		tl = nfsm_build(&info, auth_len);
193 		*tl++ = 0;		/* stamp ?? */
194 		*tl++ = 0;		/* NULL hostname */
195 		*tl++ = txdr_unsigned(cr->cr_uid);
196 		*tl++ = txdr_unsigned(cr->cr_groups[0]);
197 		grpsiz = (auth_len >> 2) - 5;
198 		*tl++ = txdr_unsigned(grpsiz);
199 		for (i = 1; i <= grpsiz; i++)
200 			*tl++ = txdr_unsigned(cr->cr_groups[i]);
201 		break;
202 	case RPCAUTH_KERB4:
203 		siz = auth_len;
204 		while (siz > 0) {
205 			if (M_TRAILINGSPACE(info.mb) == 0) {
206 				mb2 = m_getl(siz, MB_WAIT, MT_DATA, 0, NULL);
207 				mb2->m_len = 0;
208 				info.mb->m_next = mb2;
209 				info.mb = mb2;
210 				info.bpos = mtod(info.mb, caddr_t);
211 			}
212 			i = min(siz, M_TRAILINGSPACE(info.mb));
213 			bcopy(auth_str, info.bpos, i);
214 			info.mb->m_len += i;
215 			auth_str += i;
216 			info.bpos += i;
217 			siz -= i;
218 		}
219 		if ((siz = (nfsm_rndup(auth_len) - auth_len)) > 0) {
220 			for (i = 0; i < siz; i++)
221 				*info.bpos++ = '\0';
222 			info.mb->m_len += siz;
223 		}
224 		break;
225 	};
226 
227 	/*
228 	 * And the verifier...
229 	 */
230 	tl = nfsm_build(&info, 2 * NFSX_UNSIGNED);
231 	if (verf_str) {
232 		*tl++ = txdr_unsigned(RPCAUTH_KERB4);
233 		*tl = txdr_unsigned(verf_len);
234 		siz = verf_len;
235 		while (siz > 0) {
236 			if (M_TRAILINGSPACE(info.mb) == 0) {
237 				mb2 = m_getl(siz, MB_WAIT, MT_DATA,
238 						  0, NULL);
239 				mb2->m_len = 0;
240 				info.mb->m_next = mb2;
241 				info.mb = mb2;
242 				info.bpos = mtod(info.mb, caddr_t);
243 			}
244 			i = min(siz, M_TRAILINGSPACE(info.mb));
245 			bcopy(verf_str, info.bpos, i);
246 			info.mb->m_len += i;
247 			verf_str += i;
248 			info.bpos += i;
249 			siz -= i;
250 		}
251 		if ((siz = (nfsm_rndup(verf_len) - verf_len)) > 0) {
252 			for (i = 0; i < siz; i++)
253 				*info.bpos++ = '\0';
254 			info.mb->m_len += siz;
255 		}
256 	} else {
257 		*tl++ = txdr_unsigned(RPCAUTH_NULL);
258 		*tl = 0;
259 	}
260 	info.mb->m_next = mrest;
261 	info.mreq->m_pkthdr.len = authsiz + 10 * NFSX_UNSIGNED + mrest_len;
262 	info.mreq->m_pkthdr.rcvif = NULL;
263 	*mbp = info.mb;
264 	return (info.mreq);
265 }
266 
267 void *
268 nfsm_build(nfsm_info_t info, int bytes)
269 {
270 	struct mbuf *mb2;
271 	void *ptr;
272 
273 	if (bytes > M_TRAILINGSPACE(info->mb)) {
274 		MGET(mb2, MB_WAIT, MT_DATA);
275 		if (bytes > MLEN)
276 			panic("build > MLEN");
277 		info->mb->m_next = mb2;
278 		info->mb = mb2;
279 		info->mb->m_len = 0;
280 		info->bpos = mtod(info->mb, caddr_t);
281 	}
282 	ptr = info->bpos;
283 	info->mb->m_len += bytes;
284 	info->bpos += bytes;
285 	return (ptr);
286 }
287 
288 /*
289  *
290  * If NULL returned caller is expected to abort with an EBADRPC error.
291  * Caller will usually use the NULLOUT macro.
292  */
293 void *
294 nfsm_dissect(nfsm_info_t info, int bytes)
295 {
296 	caddr_t cp2;
297 	void *ptr;
298 	int error;
299 	int n;
300 
301 	n = mtod(info->md, caddr_t) + info->md->m_len - info->dpos;
302 	if (bytes <= n) {
303 		ptr = info->dpos;
304 		info->dpos += bytes;
305 	} else {
306 		error = nfsm_disct(&info->md, &info->dpos, bytes, n, &cp2);
307 		if (error) {
308 			m_freem(info->mrep);
309 			info->mrep = NULL;
310 			ptr = NULL;
311 		} else {
312 			ptr = cp2;
313 		}
314 	}
315 	return (ptr);
316 }
317 
318 /*
319  *
320  * Caller is expected to abort if non-zero error is returned.
321  */
322 int
323 nfsm_fhtom(nfsm_info_t info, struct vnode *vp)
324 {
325 	u_int32_t *tl;
326 	caddr_t cp;
327 	int error;
328 	int n;
329 
330 	if (info->v3) {
331 		n = nfsm_rndup(VTONFS(vp)->n_fhsize) + NFSX_UNSIGNED;
332 		if (n <= M_TRAILINGSPACE(info->mb)) {
333 			tl = nfsm_build(info, n);
334 			*tl++ = txdr_unsigned(VTONFS(vp)->n_fhsize);
335 			*(tl + ((n >> 2) - 2)) = 0;
336 			bcopy((caddr_t)VTONFS(vp)->n_fhp,(caddr_t)tl,
337 				VTONFS(vp)->n_fhsize);
338 			error = 0;
339 		} else if ((error = nfsm_strtmbuf(&info->mb, &info->bpos,
340 						(caddr_t)VTONFS(vp)->n_fhp,
341 						VTONFS(vp)->n_fhsize)) != 0) {
342 			m_freem(info->mreq);
343 			info->mreq = NULL;
344 		}
345 	} else {
346 		cp = nfsm_build(info, NFSX_V2FH);
347 		bcopy(VTONFS(vp)->n_fhp, cp, NFSX_V2FH);
348 		error = 0;
349 	}
350 	return (error);
351 }
352 
353 void
354 nfsm_srvfhtom(nfsm_info_t info, fhandle_t *fhp)
355 {
356 	u_int32_t *tl;
357 
358 	if (info->v3) {
359 		tl = nfsm_build(info, NFSX_UNSIGNED + NFSX_V3FH);
360 		*tl++ = txdr_unsigned(NFSX_V3FH);
361 		bcopy(fhp, tl, NFSX_V3FH);
362 	} else {
363 		tl = nfsm_build(info, NFSX_V2FH);
364 		bcopy(fhp, tl, NFSX_V2FH);
365 	}
366 }
367 
368 void
369 nfsm_srvpostop_fh(nfsm_info_t info, fhandle_t *fhp)
370 {
371 	u_int32_t *tl;
372 
373 	tl = nfsm_build(info, 2 * NFSX_UNSIGNED + NFSX_V3FH);
374 	*tl++ = nfs_true;
375 	*tl++ = txdr_unsigned(NFSX_V3FH);
376 	bcopy(fhp, tl, NFSX_V3FH);
377 }
378 
379 /*
380  * Caller is expected to abort if non-zero error is returned.
381  *
382  * NOTE: (*vpp) may be loaded with a valid vnode even if (*gotvpp)
383  *	 winds up 0.  The caller is responsible for dealing with (*vpp).
384  */
385 int
386 nfsm_mtofh(nfsm_info_t info, struct vnode *dvp, struct vnode **vpp, int *gotvpp)
387 {
388 	struct nfsnode *ttnp;
389 	nfsfh_t *ttfhp;
390 	u_int32_t *tl;
391 	int ttfhsize;
392 	int error = 0;
393 
394 	if (info->v3) {
395 		tl = nfsm_dissect(info, NFSX_UNSIGNED);
396 		if (tl == NULL)
397 			return(EBADRPC);
398 		*gotvpp = fxdr_unsigned(int, *tl);
399 	} else {
400 		*gotvpp = 1;
401 	}
402 	if (*gotvpp) {
403 		NEGATIVEOUT(ttfhsize = nfsm_getfh(info, &ttfhp));
404 		error = nfs_nget(dvp->v_mount, ttfhp, ttfhsize, &ttnp);
405 		if (error) {
406 			m_freem(info->mrep);
407 			info->mrep = NULL;
408 			return (error);
409 		}
410 		*vpp = NFSTOV(ttnp);
411 	}
412 	if (info->v3) {
413 		tl = nfsm_dissect(info, NFSX_UNSIGNED);
414 		if (tl == NULL)
415 			return (EBADRPC);
416 		if (*gotvpp) {
417 			*gotvpp = fxdr_unsigned(int, *tl);
418 		} else if (fxdr_unsigned(int, *tl)) {
419 			error = nfsm_adv(info, NFSX_V3FATTR);
420 			if (error)
421 				return (error);
422 		}
423 	}
424 	if (*gotvpp)
425 		error = nfsm_loadattr(info, *vpp, NULL);
426 nfsmout:
427 	return (error);
428 }
429 
430 /*
431  *
432  * Caller is expected to abort with EBADRPC if a negative length is returned.
433  */
434 int
435 nfsm_getfh(nfsm_info_t info, nfsfh_t **fhpp)
436 {
437 	u_int32_t *tl;
438 	int n;
439 
440 	*fhpp = NULL;
441 	if (info->v3) {
442 		tl = nfsm_dissect(info, NFSX_UNSIGNED);
443 		if (tl == NULL)
444 			return(-1);
445 		if ((n = fxdr_unsigned(int, *tl)) <= 0 || n > NFSX_V3FHMAX) {
446 			m_freem(info->mrep);
447 			info->mrep = NULL;
448 			return(-1);
449 		}
450 	} else {
451 		n = NFSX_V2FH;
452 	}
453 	*fhpp = nfsm_dissect(info, nfsm_rndup(n));
454 	if (*fhpp == NULL)
455 		return(-1);
456 	return(n);
457 }
458 
459 /*
460  * Caller is expected to abort if a non-zero error is returned.
461  */
462 int
463 nfsm_loadattr(nfsm_info_t info, struct vnode *vp, struct vattr *vap)
464 {
465 	int error;
466 
467 	error = nfs_loadattrcache(vp, &info->md, &info->dpos, vap, 0);
468 	if (error) {
469 		m_freem(info->mrep);
470 		info->mrep = NULL;
471 		return (error);
472 	}
473 	return (0);
474 }
475 
476 /*
477  * Caller is expected to abort if a non-zero error is returned.
478  */
479 int
480 nfsm_postop_attr(nfsm_info_t info, struct vnode *vp, int *attrp, int lflags)
481 {
482 	u_int32_t *tl;
483 	int error;
484 
485 	tl = nfsm_dissect(info, NFSX_UNSIGNED);
486 	if (tl == NULL)
487 		return(EBADRPC);
488 	*attrp = fxdr_unsigned(int, *tl);
489 	if (*attrp) {
490 		error = nfs_loadattrcache(vp, &info->md, &info->dpos,
491 					  NULL, lflags);
492 		if (error) {
493 			*attrp = 0;
494 			m_freem(info->mrep);
495 			info->mrep = NULL;
496 			return (error);
497 		}
498 	}
499 	return (0);
500 }
501 
502 /*
503  * Caller is expected to abort if a non-zero error is returned.
504  */
505 int
506 nfsm_wcc_data(nfsm_info_t info, struct vnode *vp, int *attrp)
507 {
508 	u_int32_t *tl;
509 	int error;
510 	int ttattrf;
511 	int ttretf = 0;
512 
513 	tl = nfsm_dissect(info, NFSX_UNSIGNED);
514 	if (tl == NULL)
515 		return (EBADRPC);
516 	if (*tl == nfs_true) {
517 		tl = nfsm_dissect(info, 6 * NFSX_UNSIGNED);
518 		if (tl == NULL)
519 			return (EBADRPC);
520 		if (*attrp) {
521 			ttretf = (VTONFS(vp)->n_mtime ==
522 				fxdr_unsigned(u_int32_t, *(tl + 2)));
523 			if (ttretf == 0)
524 				VTONFS(vp)->n_flag |= NRMODIFIED;
525 		}
526 		error = nfsm_postop_attr(info, vp, &ttattrf,
527 				 NFS_LATTR_NOSHRINK|NFS_LATTR_NOMTIMECHECK);
528 		if (error)
529 			return(error);
530 	} else {
531 		error = nfsm_postop_attr(info, vp, &ttattrf,
532 					 NFS_LATTR_NOSHRINK);
533 		if (error)
534 			return(error);
535 	}
536 	if (*attrp)
537 		*attrp = ttretf;
538 	else
539 		*attrp = ttattrf;
540 	return(0);
541 }
542 
543 /*
544  * This function updates the attribute cache based on data returned in the
545  * NFS reply for NFS RPCs that modify the target file.  If the RPC succeeds
546  * a 'before' and 'after' mtime is returned that allows us to determine if
547  * the new mtime attribute represents our modification or someone else's
548  * modification.
549  *
550  * The flag argument returns non-0 if the original times matched, zero if
551  * they did not match.  NRMODIFIED is automatically set if the before time
552  * does not match the original n_mtime, and n_mtime is automatically updated
553  * to the new after time (by nfsm_postop_attr()).
554  *
555  * If full is true, set all fields, otherwise just set mode and time fields
556  */
557 void
558 nfsm_v3attrbuild(nfsm_info_t info, struct vattr *vap, int full)
559 {
560 	u_int32_t *tl;
561 
562 	if (vap->va_mode != (mode_t)VNOVAL) {
563 		tl = nfsm_build(info, 2 * NFSX_UNSIGNED);
564 		*tl++ = nfs_true;
565 		*tl = txdr_unsigned(vap->va_mode);
566 	} else {
567 		tl = nfsm_build(info, NFSX_UNSIGNED);
568 		*tl = nfs_false;
569 	}
570 	if (full && vap->va_uid != (uid_t)VNOVAL) {
571 		tl = nfsm_build(info, 2 * NFSX_UNSIGNED);
572 		*tl++ = nfs_true;
573 		*tl = txdr_unsigned(vap->va_uid);
574 	} else {
575 		tl = nfsm_build(info, NFSX_UNSIGNED);
576 		*tl = nfs_false;
577 	}
578 	if (full && vap->va_gid != (gid_t)VNOVAL) {
579 		tl = nfsm_build(info, 2 * NFSX_UNSIGNED);
580 		*tl++ = nfs_true;
581 		*tl = txdr_unsigned(vap->va_gid);
582 	} else {
583 		tl = nfsm_build(info, NFSX_UNSIGNED);
584 		*tl = nfs_false;
585 	}
586 	if (full && vap->va_size != VNOVAL) {
587 		tl = nfsm_build(info, 3 * NFSX_UNSIGNED);
588 		*tl++ = nfs_true;
589 		txdr_hyper(vap->va_size, tl);
590 	} else {
591 		tl = nfsm_build(info, NFSX_UNSIGNED);
592 		*tl = nfs_false;
593 	}
594 	if (vap->va_atime.tv_sec != VNOVAL) {
595 		if (vap->va_atime.tv_sec != time_second) {
596 			tl = nfsm_build(info, 3 * NFSX_UNSIGNED);
597 			*tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
598 			txdr_nfsv3time(&vap->va_atime, tl);
599 		} else {
600 			tl = nfsm_build(info, NFSX_UNSIGNED);
601 			*tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
602 		}
603 	} else {
604 		tl = nfsm_build(info, NFSX_UNSIGNED);
605 		*tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
606 	}
607 	if (vap->va_mtime.tv_sec != VNOVAL) {
608 		if (vap->va_mtime.tv_sec != time_second) {
609 			tl = nfsm_build(info, 3 * NFSX_UNSIGNED);
610 			*tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
611 			txdr_nfsv3time(&vap->va_mtime, tl);
612 		} else {
613 			tl = nfsm_build(info, NFSX_UNSIGNED);
614 			*tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
615 		}
616 	} else {
617 		tl = nfsm_build(info, NFSX_UNSIGNED);
618 		*tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
619 	}
620 }
621 
622 /*
623  * Caller is expected to abort with EBADRPC if a negative length is returned.
624  */
625 int
626 nfsm_strsiz(nfsm_info_t info, int maxlen)
627 {
628 	u_int32_t *tl;
629 	int len;
630 
631 	tl = nfsm_dissect(info, NFSX_UNSIGNED);
632 	if (tl == NULL)
633 		return(-1);
634 	len = fxdr_unsigned(int32_t, *tl);
635 	if (len < 0 || len > maxlen)
636 		return(-1);
637 	return (len);
638 }
639 
640 /*
641  * Caller is expected to abort if a negative length is returned, but also
642  * call nfsm_reply(0) if -2 is returned.
643  *
644  * This function sets *errorp.  Caller should not modify the error code.
645  */
646 int
647 nfsm_srvstrsiz(nfsm_info_t info, int maxlen, int *errorp)
648 {
649 	u_int32_t *tl;
650 	int len;
651 
652 	tl = nfsm_dissect(info, NFSX_UNSIGNED);
653 	if (tl == NULL) {
654 		*errorp = EBADRPC;
655 		return(-1);
656 	}
657 	len = fxdr_unsigned(int32_t,*tl);
658 	if (len > maxlen || len <= 0) {
659 		*errorp = EBADRPC;
660 		return(-2);
661 	}
662 	return(len);
663 }
664 
665 /*
666  * Caller is expected to abort if a negative length is returned, but also
667  * call nfsm_reply(0) if -2 is returned.
668  *
669  * This function sets *errorp.  Caller should not modify the error code.
670  */
671 int
672 nfsm_srvnamesiz(nfsm_info_t info, int *errorp)
673 {
674 	u_int32_t *tl;
675 	int len;
676 
677 	tl = nfsm_dissect(info, NFSX_UNSIGNED);
678 	if (tl == NULL) {
679 		*errorp = EBADRPC;
680 		return(-1);
681 	}
682 
683 	/*
684 	 * In this case if *errorp is not EBADRPC and we are NFSv3,
685 	 * nfsm_reply() will not return a negative number.  But all
686 	 * call cases assume len is valid so we really do want
687 	 * to return -1.
688 	 */
689 	len = fxdr_unsigned(int32_t,*tl);
690 	if (len > NFS_MAXNAMLEN)
691 		*errorp = NFSERR_NAMETOL;
692 	if (len <= 0)
693 		*errorp = EBADRPC;
694 	if (*errorp)
695 		return(-2);
696 	return (len);
697 }
698 
699 /*
700  * Caller is expected to abort if a non-zero error is returned.
701  */
702 int
703 nfsm_mtouio(nfsm_info_t info, struct uio *uiop, int len)
704 {
705 	int error;
706 
707 	if (len > 0 &&
708 	   (error = nfsm_mbuftouio(&info->md, uiop, len, &info->dpos)) != 0) {
709 		m_freem(info->mrep);
710 		info->mrep = NULL;
711 		return(error);
712 	}
713 	return(0);
714 }
715 
716 /*
717  * Caller is expected to abort if a non-zero error is returned.
718  */
719 int
720 nfsm_mtobio(nfsm_info_t info, struct bio *bio, int len)
721 {
722 	int error;
723 
724 	if (len > 0 &&
725 	   (error = nfsm_mbuftobio(&info->md, bio, len, &info->dpos)) != 0) {
726 		m_freem(info->mrep);
727 		info->mrep = NULL;
728 		return(error);
729        }
730        return (0);
731 }
732 
733 /*
734  * Caller is expected to abort if a non-zero error is returned.
735  */
736 int
737 nfsm_uiotom(nfsm_info_t info, struct uio *uiop, int len)
738 {
739 	int error;
740 
741 	error = nfsm_uiotombuf(uiop, &info->mb, len, &info->bpos);
742 	if (error) {
743 		m_freem(info->mreq);
744 		info->mreq = NULL;
745 		return (error);
746 	}
747 	return(0);
748 }
749 
750 int
751 nfsm_biotom(nfsm_info_t info, struct bio *bio, int off, int len)
752 {
753 	int error;
754 
755 	error = nfsm_biotombuf(bio, &info->mb, off, len, &info->bpos);
756 	if (error) {
757 		m_freem(info->mreq);
758 		info->mreq = NULL;
759 		return (error);
760 	}
761 	return(0);
762 }
763 
764 /*
765  * Caller is expected to abort if a negative value is returned.  This
766  * function sets *errorp.  Caller should not modify the error code.
767  *
768  * We load up the remaining info fields and run the request state
769  * machine until it is done.
770  *
771  * This call runs the entire state machine and does not return until
772  * the command is complete.
773  */
774 int
775 nfsm_request(nfsm_info_t info, struct vnode *vp, int procnum,
776 	     thread_t td, struct ucred *cred, int *errorp)
777 {
778 	info->state = NFSM_STATE_SETUP;
779 	info->procnum = procnum;
780 	info->vp = vp;
781 	info->td = td;
782 	info->cred = cred;
783 	info->bio = NULL;
784 	info->nmp = VFSTONFS(vp->v_mount);
785 
786 	*errorp = nfs_request(info, NFSM_STATE_SETUP, NFSM_STATE_DONE);
787 	if (*errorp) {
788 		if ((*errorp & NFSERR_RETERR) == 0)
789 			return(-1);
790 		*errorp &= ~NFSERR_RETERR;
791 	}
792 	return(0);
793 }
794 
795 /*
796  * This call starts the state machine through the initial transmission.
797  * Completion is via the bio.  The info structure must have installed
798  * a 'done' callback.
799  *
800  * If we are unable to do the initial tx we generate the bio completion
801  * ourselves.
802  */
803 void
804 nfsm_request_bio(nfsm_info_t info, struct vnode *vp, int procnum,
805 	     thread_t td, struct ucred *cred)
806 {
807 	struct buf *bp;
808 	int error;
809 
810 	info->state = NFSM_STATE_SETUP;
811 	info->procnum = procnum;
812 	info->vp = vp;
813 	info->td = td;
814 	info->cred = cred;
815 	info->nmp = VFSTONFS(vp->v_mount);
816 
817 	error = nfs_request(info, NFSM_STATE_SETUP, NFSM_STATE_WAITREPLY);
818 	if (error != EINPROGRESS) {
819 		kprintf("nfsm_request_bio: early abort %d\n", error);
820 		bp = info->bio->bio_buf;
821 		if (error)
822 			bp->b_flags |= B_ERROR;
823 		bp->b_error = error;
824 		biodone(info->bio);
825 	}
826 }
827 
828 /*
829  * Caller is expected to abort if a non-zero error is returned.
830  */
831 int
832 nfsm_strtom(nfsm_info_t info, const void *data, int len, int maxlen)
833 {
834 	u_int32_t *tl;
835 	int error;
836 	int n;
837 
838 	if (len > maxlen) {
839 		m_freem(info->mreq);
840 		info->mreq = NULL;
841 		return(ENAMETOOLONG);
842 	}
843 	n = nfsm_rndup(len) + NFSX_UNSIGNED;
844 	if (n <= M_TRAILINGSPACE(info->mb)) {
845 		tl = nfsm_build(info, n);
846 		*tl++ = txdr_unsigned(len);
847 		*(tl + ((n >> 2) - 2)) = 0;
848 		bcopy(data, tl, len);
849 		error = 0;
850 	} else {
851 		error = nfsm_strtmbuf(&info->mb, &info->bpos, data, len);
852 		if (error) {
853 			m_freem(info->mreq);
854 			info->mreq = NULL;
855 		}
856 	}
857 	return (error);
858 }
859 
860 /*
861  * Caller is expected to abort if a negative value is returned.  This
862  * function sets *errorp.  Caller should not modify the error code.
863  */
864 int
865 nfsm_reply(nfsm_info_t info,
866 	   struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
867 	   int siz, int *errorp)
868 {
869 	nfsd->nd_repstat = *errorp;
870 	if (*errorp && !(nfsd->nd_flag & ND_NFSV3))
871 		siz = 0;
872 	nfs_rephead(siz, nfsd, slp, *errorp, &info->mreq,
873 		    &info->mb, &info->bpos);
874 	if (info->mrep != NULL) {
875 		m_freem(info->mrep);
876 		info->mrep = NULL;
877 	}
878 	if (*errorp && (!(nfsd->nd_flag & ND_NFSV3) || *errorp == EBADRPC)) {
879 		*errorp = 0;
880 		return(-1);
881 	}
882 	return(0);
883 }
884 
885 void
886 nfsm_writereply(nfsm_info_t info,
887 		struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
888 		int error, int siz)
889 {
890 	nfsd->nd_repstat = error;
891 	if (error && !(info->v3))
892 		siz = 0;
893 	nfs_rephead(siz, nfsd, slp, error, &info->mreq, &info->mb, &info->bpos);
894 }
895 
896 /*
897  * Caller is expected to abort if a non-zero error is returned.
898  */
899 int
900 nfsm_adv(nfsm_info_t info, int len)
901 {
902 	int error;
903 	int n;
904 
905 	n = mtod(info->md, caddr_t) + info->md->m_len - info->dpos;
906 	if (n >= len) {
907 		info->dpos += len;
908 		error = 0;
909 	} else if ((error = nfs_adv(&info->md, &info->dpos, len, n)) != 0) {
910 		m_freem(info->mrep);
911 		info->mrep = NULL;
912 	}
913 	return (error);
914 }
915 
916 /*
917  * Caller is expected to abort if a negative length is returned, but also
918  * call nfsm_reply(0) if -2 is returned.
919  *
920  * This function sets *errorp.  Caller should not modify the error code.
921  */
922 int
923 nfsm_srvmtofh(nfsm_info_t info, struct nfsrv_descript *nfsd,
924 	      fhandle_t *fhp, int *errorp)
925 {
926 	u_int32_t *tl;
927 	int fhlen;
928 
929 	if (nfsd->nd_flag & ND_NFSV3) {
930 		tl = nfsm_dissect(info, NFSX_UNSIGNED);
931 		if (tl == NULL) {
932 			*errorp = EBADRPC;
933 			return(-1);
934 		}
935 		fhlen = fxdr_unsigned(int, *tl);
936 		if (fhlen != 0 && fhlen != NFSX_V3FH) {
937 			*errorp = EBADRPC;
938 			return(-2);
939 		}
940 	} else {
941 		fhlen = NFSX_V2FH;
942 	}
943 	if (fhlen != 0) {
944 		tl = nfsm_dissect(info, fhlen);
945 		if (tl == NULL) {
946 			*errorp = EBADRPC;
947 			return(-1);
948 		}
949 		bcopy(tl, fhp, fhlen);
950 	} else {
951 		bzero(fhp, NFSX_V3FH);
952 	}
953 	return(0);
954 }
955 
956 void *
957 _nfsm_clget(nfsm_info_t info, struct mbuf **mp1, struct mbuf **mp2,
958 	    char **bp, char **be)
959 {
960 	if (*bp >= *be) {
961 		if (*mp1 == info->mb)
962 			(*mp1)->m_len += *bp - info->bpos;
963 		*mp1 = m_getcl(MB_WAIT, MT_DATA, 0);
964 		(*mp1)->m_len = MCLBYTES;
965 		(*mp2)->m_next = *mp1;
966 		*mp2 = *mp1;
967 		*bp = mtod(*mp1, caddr_t);
968 		*be = *bp + (*mp1)->m_len;
969 	}
970 	return(*bp);
971 }
972 
973 int
974 nfsm_srvsattr(nfsm_info_t info, struct vattr *vap)
975 {
976 	u_int32_t *tl;
977 	int error = 0;
978 
979 	NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED));
980 	if (*tl == nfs_true) {
981 		NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED));
982 		vap->va_mode = nfstov_mode(*tl);
983 	}
984 	NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED));
985 	if (*tl == nfs_true) {
986 		NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED));
987 		vap->va_uid = fxdr_unsigned(uid_t, *tl);
988 	}
989 	NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED));
990 	if (*tl == nfs_true) {
991 		NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED));
992 		vap->va_gid = fxdr_unsigned(gid_t, *tl);
993 	}
994 	NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED));
995 	if (*tl == nfs_true) {
996 		NULLOUT(tl = nfsm_dissect(info, 2 * NFSX_UNSIGNED));
997 		vap->va_size = fxdr_hyper(tl);
998 	}
999 	NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED));
1000 	switch (fxdr_unsigned(int, *tl)) {
1001 	case NFSV3SATTRTIME_TOCLIENT:
1002 		NULLOUT(tl = nfsm_dissect(info, 2 * NFSX_UNSIGNED));
1003 		fxdr_nfsv3time(tl, &vap->va_atime);
1004 		break;
1005 	case NFSV3SATTRTIME_TOSERVER:
1006 		getnanotime(&vap->va_atime);
1007 		break;
1008 	};
1009 	NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED));
1010 	switch (fxdr_unsigned(int, *tl)) {
1011 	case NFSV3SATTRTIME_TOCLIENT:
1012 		NULLOUT(tl = nfsm_dissect(info, 2 * NFSX_UNSIGNED));
1013 		fxdr_nfsv3time(tl, &vap->va_mtime);
1014 		break;
1015 	case NFSV3SATTRTIME_TOSERVER:
1016 		getnanotime(&vap->va_mtime);
1017 		break;
1018 	}
1019 nfsmout:
1020 	return (error);
1021 }
1022 
1023 /*
1024  * copies mbuf chain to the uio scatter/gather list
1025  */
1026 int
1027 nfsm_mbuftouio(struct mbuf **mrep, struct uio *uiop, int siz, caddr_t *dpos)
1028 {
1029 	char *mbufcp, *uiocp;
1030 	int xfer, left, len;
1031 	struct mbuf *mp;
1032 	long uiosiz, rem;
1033 	int error = 0;
1034 
1035 	mp = *mrep;
1036 	mbufcp = *dpos;
1037 	len = mtod(mp, caddr_t)+mp->m_len-mbufcp;
1038 	rem = nfsm_rndup(siz)-siz;
1039 	while (siz > 0) {
1040 		if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
1041 			return (EFBIG);
1042 		left = uiop->uio_iov->iov_len;
1043 		uiocp = uiop->uio_iov->iov_base;
1044 		if (left > siz)
1045 			left = siz;
1046 		uiosiz = left;
1047 		while (left > 0) {
1048 			while (len == 0) {
1049 				mp = mp->m_next;
1050 				if (mp == NULL)
1051 					return (EBADRPC);
1052 				mbufcp = mtod(mp, caddr_t);
1053 				len = mp->m_len;
1054 			}
1055 			xfer = (left > len) ? len : left;
1056 #ifdef notdef
1057 			/* Not Yet.. */
1058 			if (uiop->uio_iov->iov_op != NULL)
1059 				(*(uiop->uio_iov->iov_op))
1060 				(mbufcp, uiocp, xfer);
1061 			else
1062 #endif
1063 			if (uiop->uio_segflg == UIO_SYSSPACE)
1064 				bcopy(mbufcp, uiocp, xfer);
1065 			else
1066 				copyout(mbufcp, uiocp, xfer);
1067 			left -= xfer;
1068 			len -= xfer;
1069 			mbufcp += xfer;
1070 			uiocp += xfer;
1071 			uiop->uio_offset += xfer;
1072 			uiop->uio_resid -= xfer;
1073 		}
1074 		if (uiop->uio_iov->iov_len <= siz) {
1075 			uiop->uio_iovcnt--;
1076 			uiop->uio_iov++;
1077 		} else {
1078 			uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base + uiosiz;
1079 			uiop->uio_iov->iov_len -= uiosiz;
1080 		}
1081 		siz -= uiosiz;
1082 	}
1083 	*dpos = mbufcp;
1084 	*mrep = mp;
1085 	if (rem > 0) {
1086 		if (len < rem)
1087 			error = nfs_adv(mrep, dpos, rem, len);
1088 		else
1089 			*dpos += rem;
1090 	}
1091 	return (error);
1092 }
1093 
1094 /*
1095  * copies mbuf chain to the bio buffer
1096  */
1097 int
1098 nfsm_mbuftobio(struct mbuf **mrep, struct bio *bio, int size, caddr_t *dpos)
1099 {
1100 	struct buf *bp = bio->bio_buf;
1101 	char *mbufcp;
1102 	char *bio_cp;
1103 	int xfer, len;
1104 	struct mbuf *mp;
1105 	long rem;
1106 	int error = 0;
1107 	int bio_left;
1108 
1109 	mp = *mrep;
1110 	mbufcp = *dpos;
1111 	len = mtod(mp, caddr_t) + mp->m_len - mbufcp;
1112 	rem = nfsm_rndup(size) - size;
1113 
1114 	bio_left = bp->b_bcount;
1115 	bio_cp = bp->b_data;
1116 
1117 	while (size > 0) {
1118 		while (len == 0) {
1119 			mp = mp->m_next;
1120 			if (mp == NULL)
1121 				return (EBADRPC);
1122 			mbufcp = mtod(mp, caddr_t);
1123 			len = mp->m_len;
1124 		}
1125 		if ((xfer = len) > size)
1126 			xfer = size;
1127 		if (bio_left) {
1128 			if (xfer > bio_left)
1129 				xfer = bio_left;
1130 			bcopy(mbufcp, bio_cp, xfer);
1131 		} else {
1132 			/*
1133 			 * Not enough buffer space in the bio.
1134 			 */
1135 			return(EFBIG);
1136 		}
1137 		size -= xfer;
1138 		bio_left -= xfer;
1139 		bio_cp += xfer;
1140 		len -= xfer;
1141 		mbufcp += xfer;
1142 	}
1143 	*dpos = mbufcp;
1144 	*mrep = mp;
1145 	if (rem > 0) {
1146 		if (len < rem)
1147 			error = nfs_adv(mrep, dpos, rem, len);
1148 		else
1149 			*dpos += rem;
1150 	}
1151 	return (error);
1152 }
1153 
1154 /*
1155  * copies a uio scatter/gather list to an mbuf chain.
1156  * NOTE: can ony handle iovcnt == 1
1157  */
1158 int
1159 nfsm_uiotombuf(struct uio *uiop, struct mbuf **mq, int siz, caddr_t *bpos)
1160 {
1161 	char *uiocp;
1162 	struct mbuf *mp, *mp2;
1163 	int xfer, left, mlen;
1164 	int uiosiz, rem;
1165 	boolean_t getcluster;
1166 	char *cp;
1167 
1168 #ifdef DIAGNOSTIC
1169 	if (uiop->uio_iovcnt != 1)
1170 		panic("nfsm_uiotombuf: iovcnt != 1");
1171 #endif
1172 
1173 	if (siz >= MINCLSIZE)
1174 		getcluster = TRUE;
1175 	else
1176 		getcluster = FALSE;
1177 	rem = nfsm_rndup(siz) - siz;
1178 	mp = mp2 = *mq;
1179 	while (siz > 0) {
1180 		left = uiop->uio_iov->iov_len;
1181 		uiocp = uiop->uio_iov->iov_base;
1182 		if (left > siz)
1183 			left = siz;
1184 		uiosiz = left;
1185 		while (left > 0) {
1186 			mlen = M_TRAILINGSPACE(mp);
1187 			if (mlen == 0) {
1188 				if (getcluster)
1189 					mp = m_getcl(MB_WAIT, MT_DATA, 0);
1190 				else
1191 					mp = m_get(MB_WAIT, MT_DATA);
1192 				mp->m_len = 0;
1193 				mp2->m_next = mp;
1194 				mp2 = mp;
1195 				mlen = M_TRAILINGSPACE(mp);
1196 			}
1197 			xfer = (left > mlen) ? mlen : left;
1198 #ifdef notdef
1199 			/* Not Yet.. */
1200 			if (uiop->uio_iov->iov_op != NULL)
1201 				(*(uiop->uio_iov->iov_op))
1202 				(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
1203 			else
1204 #endif
1205 			if (uiop->uio_segflg == UIO_SYSSPACE)
1206 				bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
1207 			else
1208 				copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
1209 			mp->m_len += xfer;
1210 			left -= xfer;
1211 			uiocp += xfer;
1212 			uiop->uio_offset += xfer;
1213 			uiop->uio_resid -= xfer;
1214 		}
1215 		uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base + uiosiz;
1216 		uiop->uio_iov->iov_len -= uiosiz;
1217 		siz -= uiosiz;
1218 	}
1219 	if (rem > 0) {
1220 		if (rem > M_TRAILINGSPACE(mp)) {
1221 			MGET(mp, MB_WAIT, MT_DATA);
1222 			mp->m_len = 0;
1223 			mp2->m_next = mp;
1224 		}
1225 		cp = mtod(mp, caddr_t)+mp->m_len;
1226 		for (left = 0; left < rem; left++)
1227 			*cp++ = '\0';
1228 		mp->m_len += rem;
1229 		*bpos = cp;
1230 	} else
1231 		*bpos = mtod(mp, caddr_t)+mp->m_len;
1232 	*mq = mp;
1233 	return (0);
1234 }
1235 
1236 int
1237 nfsm_biotombuf(struct bio *bio, struct mbuf **mq, int off,
1238 	       int siz, caddr_t *bpos)
1239 {
1240 	struct buf *bp = bio->bio_buf;
1241 	struct mbuf *mp, *mp2;
1242 	char *bio_cp;
1243 	int bio_left;
1244 	int xfer, mlen;
1245 	int rem;
1246 	boolean_t getcluster;
1247 	char *cp;
1248 
1249 	if (siz >= MINCLSIZE)
1250 		getcluster = TRUE;
1251 	else
1252 		getcluster = FALSE;
1253 	rem = nfsm_rndup(siz) - siz;
1254 	mp = mp2 = *mq;
1255 
1256 	bio_cp = bp->b_data + off;
1257 	bio_left = siz;
1258 
1259 	while (bio_left) {
1260 		mlen = M_TRAILINGSPACE(mp);
1261 		if (mlen == 0) {
1262 			if (getcluster)
1263 				mp = m_getcl(MB_WAIT, MT_DATA, 0);
1264 			else
1265 				mp = m_get(MB_WAIT, MT_DATA);
1266 			mp->m_len = 0;
1267 			mp2->m_next = mp;
1268 			mp2 = mp;
1269 			mlen = M_TRAILINGSPACE(mp);
1270 		}
1271 		xfer = (bio_left < mlen) ? bio_left : mlen;
1272 		bcopy(bio_cp, mtod(mp, caddr_t) + mp->m_len, xfer);
1273 		mp->m_len += xfer;
1274 		bio_left -= xfer;
1275 		bio_cp += xfer;
1276 	}
1277 	if (rem > 0) {
1278 		if (rem > M_TRAILINGSPACE(mp)) {
1279 			MGET(mp, MB_WAIT, MT_DATA);
1280 			mp->m_len = 0;
1281 			mp2->m_next = mp;
1282 		}
1283 		cp = mtod(mp, caddr_t) + mp->m_len;
1284 		for (mlen = 0; mlen < rem; mlen++)
1285 			*cp++ = '\0';
1286 		mp->m_len += rem;
1287 		*bpos = cp;
1288 	} else {
1289 		*bpos = mtod(mp, caddr_t) + mp->m_len;
1290 	}
1291 	*mq = mp;
1292 	return(0);
1293 }
1294 
1295 /*
1296  * Help break down an mbuf chain by setting the first siz bytes contiguous
1297  * pointed to by returned val.
1298  * This is used by the macros nfsm_dissect and nfsm_dissecton for tough
1299  * cases. (The macros use the vars. dpos and dpos2)
1300  */
1301 int
1302 nfsm_disct(struct mbuf **mdp, caddr_t *dposp, int siz, int left, caddr_t *cp2)
1303 {
1304 	struct mbuf *mp, *mp2;
1305 	int siz2, xfer;
1306 	caddr_t p;
1307 
1308 	mp = *mdp;
1309 	while (left == 0) {
1310 		*mdp = mp = mp->m_next;
1311 		if (mp == NULL)
1312 			return (EBADRPC);
1313 		left = mp->m_len;
1314 		*dposp = mtod(mp, caddr_t);
1315 	}
1316 	if (left >= siz) {
1317 		*cp2 = *dposp;
1318 		*dposp += siz;
1319 	} else if (mp->m_next == NULL) {
1320 		return (EBADRPC);
1321 	} else if (siz > MHLEN) {
1322 		panic("nfs S too big");
1323 	} else {
1324 		MGET(mp2, MB_WAIT, MT_DATA);
1325 		mp2->m_next = mp->m_next;
1326 		mp->m_next = mp2;
1327 		mp->m_len -= left;
1328 		mp = mp2;
1329 		*cp2 = p = mtod(mp, caddr_t);
1330 		bcopy(*dposp, p, left);		/* Copy what was left */
1331 		siz2 = siz-left;
1332 		p += left;
1333 		mp2 = mp->m_next;
1334 		/* Loop around copying up the siz2 bytes */
1335 		while (siz2 > 0) {
1336 			if (mp2 == NULL)
1337 				return (EBADRPC);
1338 			xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2;
1339 			if (xfer > 0) {
1340 				bcopy(mtod(mp2, caddr_t), p, xfer);
1341 				mp2->m_len -= xfer;
1342 				mp2->m_data += xfer;
1343 				p += xfer;
1344 				siz2 -= xfer;
1345 			}
1346 			if (siz2 > 0)
1347 				mp2 = mp2->m_next;
1348 		}
1349 		mp->m_len = siz;
1350 		*mdp = mp2;
1351 		*dposp = mtod(mp2, caddr_t);
1352 	}
1353 	return (0);
1354 }
1355 
1356 /*
1357  * Advance the position in the mbuf chain.
1358  */
1359 int
1360 nfs_adv(struct mbuf **mdp, caddr_t *dposp, int offs, int left)
1361 {
1362 	struct mbuf *m;
1363 	int s;
1364 
1365 	m = *mdp;
1366 	s = left;
1367 	while (s < offs) {
1368 		offs -= s;
1369 		m = m->m_next;
1370 		if (m == NULL)
1371 			return (EBADRPC);
1372 		s = m->m_len;
1373 	}
1374 	*mdp = m;
1375 	*dposp = mtod(m, caddr_t)+offs;
1376 	return (0);
1377 }
1378 
1379 /*
1380  * Copy a string into mbufs for the hard cases...
1381  */
1382 int
1383 nfsm_strtmbuf(struct mbuf **mb, char **bpos, const char *cp, long siz)
1384 {
1385 	struct mbuf *m1 = NULL, *m2;
1386 	long left, xfer, len, tlen;
1387 	u_int32_t *tl;
1388 	int putsize;
1389 
1390 	putsize = 1;
1391 	m2 = *mb;
1392 	left = M_TRAILINGSPACE(m2);
1393 	if (left > 0) {
1394 		tl = ((u_int32_t *)(*bpos));
1395 		*tl++ = txdr_unsigned(siz);
1396 		putsize = 0;
1397 		left -= NFSX_UNSIGNED;
1398 		m2->m_len += NFSX_UNSIGNED;
1399 		if (left > 0) {
1400 			bcopy(cp, (caddr_t) tl, left);
1401 			siz -= left;
1402 			cp += left;
1403 			m2->m_len += left;
1404 			left = 0;
1405 		}
1406 	}
1407 	/* Loop around adding mbufs */
1408 	while (siz > 0) {
1409 		int msize;
1410 
1411 		m1 = m_getl(siz, MB_WAIT, MT_DATA, 0, &msize);
1412 		m1->m_len = msize;
1413 		m2->m_next = m1;
1414 		m2 = m1;
1415 		tl = mtod(m1, u_int32_t *);
1416 		tlen = 0;
1417 		if (putsize) {
1418 			*tl++ = txdr_unsigned(siz);
1419 			m1->m_len -= NFSX_UNSIGNED;
1420 			tlen = NFSX_UNSIGNED;
1421 			putsize = 0;
1422 		}
1423 		if (siz < m1->m_len) {
1424 			len = nfsm_rndup(siz);
1425 			xfer = siz;
1426 			if (xfer < len)
1427 				*(tl+(xfer>>2)) = 0;
1428 		} else {
1429 			xfer = len = m1->m_len;
1430 		}
1431 		bcopy(cp, (caddr_t) tl, xfer);
1432 		m1->m_len = len+tlen;
1433 		siz -= xfer;
1434 		cp += xfer;
1435 	}
1436 	*mb = m1;
1437 	*bpos = mtod(m1, caddr_t)+m1->m_len;
1438 	return (0);
1439 }
1440 
1441 /*
1442  * A fiddled version of m_adj() that ensures null fill to a long
1443  * boundary and only trims off the back end
1444  */
1445 void
1446 nfsm_adj(struct mbuf *mp, int len, int nul)
1447 {
1448 	struct mbuf *m;
1449 	int count, i;
1450 	char *cp;
1451 
1452 	/*
1453 	 * Trim from tail.  Scan the mbuf chain,
1454 	 * calculating its length and finding the last mbuf.
1455 	 * If the adjustment only affects this mbuf, then just
1456 	 * adjust and return.  Otherwise, rescan and truncate
1457 	 * after the remaining size.
1458 	 */
1459 	count = 0;
1460 	m = mp;
1461 	for (;;) {
1462 		count += m->m_len;
1463 		if (m->m_next == NULL)
1464 			break;
1465 		m = m->m_next;
1466 	}
1467 	if (m->m_len > len) {
1468 		m->m_len -= len;
1469 		if (nul > 0) {
1470 			cp = mtod(m, caddr_t)+m->m_len-nul;
1471 			for (i = 0; i < nul; i++)
1472 				*cp++ = '\0';
1473 		}
1474 		return;
1475 	}
1476 	count -= len;
1477 	if (count < 0)
1478 		count = 0;
1479 	/*
1480 	 * Correct length for chain is "count".
1481 	 * Find the mbuf with last data, adjust its length,
1482 	 * and toss data from remaining mbufs on chain.
1483 	 */
1484 	for (m = mp; m; m = m->m_next) {
1485 		if (m->m_len >= count) {
1486 			m->m_len = count;
1487 			if (nul > 0) {
1488 				cp = mtod(m, caddr_t)+m->m_len-nul;
1489 				for (i = 0; i < nul; i++)
1490 					*cp++ = '\0';
1491 			}
1492 			break;
1493 		}
1494 		count -= m->m_len;
1495 	}
1496 	for (m = m->m_next;m;m = m->m_next)
1497 		m->m_len = 0;
1498 }
1499 
1500 /*
1501  * Make these functions instead of macros, so that the kernel text size
1502  * doesn't get too big...
1503  */
1504 void
1505 nfsm_srvwcc_data(nfsm_info_t info, struct nfsrv_descript *nfsd,
1506 		 int before_ret, struct vattr *before_vap,
1507 		 int after_ret, struct vattr *after_vap)
1508 {
1509 	u_int32_t *tl;
1510 
1511 	/*
1512 	 * before_ret is 0 if before_vap is valid, non-zero if it isn't.
1513 	 */
1514 	if (before_ret) {
1515 		tl = nfsm_build(info, NFSX_UNSIGNED);
1516 		*tl = nfs_false;
1517 	} else {
1518 		tl = nfsm_build(info, 7 * NFSX_UNSIGNED);
1519 		*tl++ = nfs_true;
1520 		txdr_hyper(before_vap->va_size, tl);
1521 		tl += 2;
1522 		txdr_nfsv3time(&(before_vap->va_mtime), tl);
1523 		tl += 2;
1524 		txdr_nfsv3time(&(before_vap->va_ctime), tl);
1525 	}
1526 	nfsm_srvpostop_attr(info, nfsd, after_ret, after_vap);
1527 }
1528 
1529 void
1530 nfsm_srvpostop_attr(nfsm_info_t info, struct nfsrv_descript *nfsd,
1531 		   int after_ret, struct vattr *after_vap)
1532 {
1533 	struct nfs_fattr *fp;
1534 	u_int32_t *tl;
1535 
1536 	if (after_ret) {
1537 		tl = nfsm_build(info, NFSX_UNSIGNED);
1538 		*tl = nfs_false;
1539 	} else {
1540 		tl = nfsm_build(info, NFSX_UNSIGNED + NFSX_V3FATTR);
1541 		*tl++ = nfs_true;
1542 		fp = (struct nfs_fattr *)tl;
1543 		nfsm_srvfattr(nfsd, after_vap, fp);
1544 	}
1545 }
1546 
1547 void
1548 nfsm_srvfattr(struct nfsrv_descript *nfsd, struct vattr *vap,
1549 	      struct nfs_fattr *fp)
1550 {
1551 	/*
1552 	 * NFS seems to truncate nlink to 16 bits, don't let it overflow.
1553 	 */
1554 	if (vap->va_nlink > 65535)
1555 		fp->fa_nlink = 65535;
1556 	else
1557 		fp->fa_nlink = txdr_unsigned(vap->va_nlink);
1558 	fp->fa_uid = txdr_unsigned(vap->va_uid);
1559 	fp->fa_gid = txdr_unsigned(vap->va_gid);
1560 	if (nfsd->nd_flag & ND_NFSV3) {
1561 		fp->fa_type = vtonfsv3_type(vap->va_type);
1562 		fp->fa_mode = vtonfsv3_mode(vap->va_mode);
1563 		txdr_hyper(vap->va_size, &fp->fa3_size);
1564 		txdr_hyper(vap->va_bytes, &fp->fa3_used);
1565 		fp->fa3_rdev.specdata1 = txdr_unsigned(vap->va_rmajor);
1566 		fp->fa3_rdev.specdata2 = txdr_unsigned(vap->va_rminor);
1567 		fp->fa3_fsid.nfsuquad[0] = 0;
1568 		fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid);
1569 		txdr_hyper(vap->va_fileid, &fp->fa3_fileid);
1570 		txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime);
1571 		txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime);
1572 		txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime);
1573 	} else {
1574 		fp->fa_type = vtonfsv2_type(vap->va_type);
1575 		fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
1576 		fp->fa2_size = txdr_unsigned(vap->va_size);
1577 		fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize);
1578 		if (vap->va_type == VFIFO)
1579 			fp->fa2_rdev = 0xffffffff;
1580 		else
1581 			fp->fa2_rdev = txdr_unsigned(makeudev(vap->va_rmajor, vap->va_rminor));
1582 		fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE);
1583 		fp->fa2_fsid = txdr_unsigned(vap->va_fsid);
1584 		fp->fa2_fileid = txdr_unsigned(vap->va_fileid);
1585 		txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime);
1586 		txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime);
1587 		txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime);
1588 	}
1589 }
1590