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