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