xref: /dragonfly/sys/vfs/nfs/nfsm_subs.c (revision 678e8cc6)
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 			if (error == EIO)		/* unrecoverable */
823 				bp->b_flags |= B_INVAL;
824 		}
825 		bp->b_error = error;
826 		biodone(info->bio);
827 	}
828 }
829 
830 /*
831  * Caller is expected to abort if a non-zero error is returned.
832  */
833 int
834 nfsm_strtom(nfsm_info_t info, const void *data, int len, int maxlen)
835 {
836 	u_int32_t *tl;
837 	int error;
838 	int n;
839 
840 	if (len > maxlen) {
841 		m_freem(info->mreq);
842 		info->mreq = NULL;
843 		return(ENAMETOOLONG);
844 	}
845 	n = nfsm_rndup(len) + NFSX_UNSIGNED;
846 	if (n <= M_TRAILINGSPACE(info->mb)) {
847 		tl = nfsm_build(info, n);
848 		*tl++ = txdr_unsigned(len);
849 		*(tl + ((n >> 2) - 2)) = 0;
850 		bcopy(data, tl, len);
851 		error = 0;
852 	} else {
853 		error = nfsm_strtmbuf(&info->mb, &info->bpos, data, len);
854 		if (error) {
855 			m_freem(info->mreq);
856 			info->mreq = NULL;
857 		}
858 	}
859 	return (error);
860 }
861 
862 /*
863  * Caller is expected to abort if a negative value is returned.  This
864  * function sets *errorp.  Caller should not modify the error code.
865  */
866 int
867 nfsm_reply(nfsm_info_t info,
868 	   struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
869 	   int siz, int *errorp)
870 {
871 	nfsd->nd_repstat = *errorp;
872 	if (*errorp && !(nfsd->nd_flag & ND_NFSV3))
873 		siz = 0;
874 	nfs_rephead(siz, nfsd, slp, *errorp, &info->mreq,
875 		    &info->mb, &info->bpos);
876 	if (info->mrep != NULL) {
877 		m_freem(info->mrep);
878 		info->mrep = NULL;
879 	}
880 	if (*errorp && (!(nfsd->nd_flag & ND_NFSV3) || *errorp == EBADRPC)) {
881 		*errorp = 0;
882 		return(-1);
883 	}
884 	return(0);
885 }
886 
887 void
888 nfsm_writereply(nfsm_info_t info,
889 		struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
890 		int error, int siz)
891 {
892 	nfsd->nd_repstat = error;
893 	if (error && !(info->v3))
894 		siz = 0;
895 	nfs_rephead(siz, nfsd, slp, error, &info->mreq, &info->mb, &info->bpos);
896 }
897 
898 /*
899  * Caller is expected to abort if a non-zero error is returned.
900  */
901 int
902 nfsm_adv(nfsm_info_t info, int len)
903 {
904 	int error;
905 	int n;
906 
907 	n = mtod(info->md, caddr_t) + info->md->m_len - info->dpos;
908 	if (n >= len) {
909 		info->dpos += len;
910 		error = 0;
911 	} else if ((error = nfs_adv(&info->md, &info->dpos, len, n)) != 0) {
912 		m_freem(info->mrep);
913 		info->mrep = NULL;
914 	}
915 	return (error);
916 }
917 
918 /*
919  * Caller is expected to abort if a negative length is returned, but also
920  * call nfsm_reply(0) if -2 is returned.
921  *
922  * This function sets *errorp.  Caller should not modify the error code.
923  */
924 int
925 nfsm_srvmtofh(nfsm_info_t info, struct nfsrv_descript *nfsd,
926 	      fhandle_t *fhp, int *errorp)
927 {
928 	u_int32_t *tl;
929 	int fhlen;
930 
931 	if (nfsd->nd_flag & ND_NFSV3) {
932 		tl = nfsm_dissect(info, NFSX_UNSIGNED);
933 		if (tl == NULL) {
934 			*errorp = EBADRPC;
935 			return(-1);
936 		}
937 		fhlen = fxdr_unsigned(int, *tl);
938 		if (fhlen != 0 && fhlen != NFSX_V3FH) {
939 			*errorp = EBADRPC;
940 			return(-2);
941 		}
942 	} else {
943 		fhlen = NFSX_V2FH;
944 	}
945 	if (fhlen != 0) {
946 		tl = nfsm_dissect(info, fhlen);
947 		if (tl == NULL) {
948 			*errorp = EBADRPC;
949 			return(-1);
950 		}
951 		bcopy(tl, fhp, fhlen);
952 	} else {
953 		bzero(fhp, NFSX_V3FH);
954 	}
955 	return(0);
956 }
957 
958 void *
959 _nfsm_clget(nfsm_info_t info, struct mbuf **mp1, struct mbuf **mp2,
960 	    char **bp, char **be)
961 {
962 	if (*bp >= *be) {
963 		if (*mp1 == info->mb)
964 			(*mp1)->m_len += *bp - info->bpos;
965 		*mp1 = m_getcl(MB_WAIT, MT_DATA, 0);
966 		(*mp1)->m_len = MCLBYTES;
967 		(*mp2)->m_next = *mp1;
968 		*mp2 = *mp1;
969 		*bp = mtod(*mp1, caddr_t);
970 		*be = *bp + (*mp1)->m_len;
971 	}
972 	return(*bp);
973 }
974 
975 int
976 nfsm_srvsattr(nfsm_info_t info, struct vattr *vap)
977 {
978 	u_int32_t *tl;
979 	int error = 0;
980 
981 	NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED));
982 	if (*tl == nfs_true) {
983 		NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED));
984 		vap->va_mode = nfstov_mode(*tl);
985 	}
986 	NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED));
987 	if (*tl == nfs_true) {
988 		NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED));
989 		vap->va_uid = fxdr_unsigned(uid_t, *tl);
990 	}
991 	NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED));
992 	if (*tl == nfs_true) {
993 		NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED));
994 		vap->va_gid = fxdr_unsigned(gid_t, *tl);
995 	}
996 	NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED));
997 	if (*tl == nfs_true) {
998 		NULLOUT(tl = nfsm_dissect(info, 2 * NFSX_UNSIGNED));
999 		vap->va_size = fxdr_hyper(tl);
1000 	}
1001 	NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED));
1002 	switch (fxdr_unsigned(int, *tl)) {
1003 	case NFSV3SATTRTIME_TOCLIENT:
1004 		NULLOUT(tl = nfsm_dissect(info, 2 * NFSX_UNSIGNED));
1005 		fxdr_nfsv3time(tl, &vap->va_atime);
1006 		break;
1007 	case NFSV3SATTRTIME_TOSERVER:
1008 		getnanotime(&vap->va_atime);
1009 		break;
1010 	};
1011 	NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED));
1012 	switch (fxdr_unsigned(int, *tl)) {
1013 	case NFSV3SATTRTIME_TOCLIENT:
1014 		NULLOUT(tl = nfsm_dissect(info, 2 * NFSX_UNSIGNED));
1015 		fxdr_nfsv3time(tl, &vap->va_mtime);
1016 		break;
1017 	case NFSV3SATTRTIME_TOSERVER:
1018 		getnanotime(&vap->va_mtime);
1019 		break;
1020 	}
1021 nfsmout:
1022 	return (error);
1023 }
1024 
1025 /*
1026  * copies mbuf chain to the uio scatter/gather list
1027  */
1028 int
1029 nfsm_mbuftouio(struct mbuf **mrep, struct uio *uiop, int siz, caddr_t *dpos)
1030 {
1031 	char *mbufcp, *uiocp;
1032 	int xfer, left, len;
1033 	struct mbuf *mp;
1034 	long uiosiz, rem;
1035 	int error = 0;
1036 
1037 	mp = *mrep;
1038 	mbufcp = *dpos;
1039 	len = mtod(mp, caddr_t)+mp->m_len-mbufcp;
1040 	rem = nfsm_rndup(siz)-siz;
1041 	while (siz > 0) {
1042 		if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
1043 			return (EFBIG);
1044 		left = uiop->uio_iov->iov_len;
1045 		uiocp = uiop->uio_iov->iov_base;
1046 		if (left > siz)
1047 			left = siz;
1048 		uiosiz = left;
1049 		while (left > 0) {
1050 			while (len == 0) {
1051 				mp = mp->m_next;
1052 				if (mp == NULL)
1053 					return (EBADRPC);
1054 				mbufcp = mtod(mp, caddr_t);
1055 				len = mp->m_len;
1056 			}
1057 			xfer = (left > len) ? len : left;
1058 #ifdef notdef
1059 			/* Not Yet.. */
1060 			if (uiop->uio_iov->iov_op != NULL)
1061 				(*(uiop->uio_iov->iov_op))
1062 				(mbufcp, uiocp, xfer);
1063 			else
1064 #endif
1065 			if (uiop->uio_segflg == UIO_SYSSPACE)
1066 				bcopy(mbufcp, uiocp, xfer);
1067 			else
1068 				copyout(mbufcp, uiocp, xfer);
1069 			left -= xfer;
1070 			len -= xfer;
1071 			mbufcp += xfer;
1072 			uiocp += xfer;
1073 			uiop->uio_offset += xfer;
1074 			uiop->uio_resid -= xfer;
1075 		}
1076 		if (uiop->uio_iov->iov_len <= siz) {
1077 			uiop->uio_iovcnt--;
1078 			uiop->uio_iov++;
1079 		} else {
1080 			uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base + uiosiz;
1081 			uiop->uio_iov->iov_len -= uiosiz;
1082 		}
1083 		siz -= uiosiz;
1084 	}
1085 	*dpos = mbufcp;
1086 	*mrep = mp;
1087 	if (rem > 0) {
1088 		if (len < rem)
1089 			error = nfs_adv(mrep, dpos, rem, len);
1090 		else
1091 			*dpos += rem;
1092 	}
1093 	return (error);
1094 }
1095 
1096 /*
1097  * copies mbuf chain to the bio buffer
1098  */
1099 int
1100 nfsm_mbuftobio(struct mbuf **mrep, struct bio *bio, int size, caddr_t *dpos)
1101 {
1102 	struct buf *bp = bio->bio_buf;
1103 	char *mbufcp;
1104 	char *bio_cp;
1105 	int xfer, len;
1106 	struct mbuf *mp;
1107 	long rem;
1108 	int error = 0;
1109 	int bio_left;
1110 
1111 	mp = *mrep;
1112 	mbufcp = *dpos;
1113 	len = mtod(mp, caddr_t) + mp->m_len - mbufcp;
1114 	rem = nfsm_rndup(size) - size;
1115 
1116 	bio_left = bp->b_bcount;
1117 	bio_cp = bp->b_data;
1118 
1119 	while (size > 0) {
1120 		while (len == 0) {
1121 			mp = mp->m_next;
1122 			if (mp == NULL)
1123 				return (EBADRPC);
1124 			mbufcp = mtod(mp, caddr_t);
1125 			len = mp->m_len;
1126 		}
1127 		if ((xfer = len) > size)
1128 			xfer = size;
1129 		if (bio_left) {
1130 			if (xfer > bio_left)
1131 				xfer = bio_left;
1132 			bcopy(mbufcp, bio_cp, xfer);
1133 		} else {
1134 			/*
1135 			 * Not enough buffer space in the bio.
1136 			 */
1137 			return(EFBIG);
1138 		}
1139 		size -= xfer;
1140 		bio_left -= xfer;
1141 		bio_cp += xfer;
1142 		len -= xfer;
1143 		mbufcp += xfer;
1144 	}
1145 	*dpos = mbufcp;
1146 	*mrep = mp;
1147 	if (rem > 0) {
1148 		if (len < rem)
1149 			error = nfs_adv(mrep, dpos, rem, len);
1150 		else
1151 			*dpos += rem;
1152 	}
1153 	return (error);
1154 }
1155 
1156 /*
1157  * copies a uio scatter/gather list to an mbuf chain.
1158  * NOTE: can ony handle iovcnt == 1
1159  */
1160 int
1161 nfsm_uiotombuf(struct uio *uiop, struct mbuf **mq, int siz, caddr_t *bpos)
1162 {
1163 	char *uiocp;
1164 	struct mbuf *mp, *mp2;
1165 	int xfer, left, mlen;
1166 	int uiosiz, rem;
1167 	boolean_t getcluster;
1168 	char *cp;
1169 
1170 #ifdef DIAGNOSTIC
1171 	if (uiop->uio_iovcnt != 1)
1172 		panic("nfsm_uiotombuf: iovcnt != 1");
1173 #endif
1174 
1175 	if (siz >= MINCLSIZE)
1176 		getcluster = TRUE;
1177 	else
1178 		getcluster = FALSE;
1179 	rem = nfsm_rndup(siz) - siz;
1180 	mp = mp2 = *mq;
1181 	while (siz > 0) {
1182 		left = uiop->uio_iov->iov_len;
1183 		uiocp = uiop->uio_iov->iov_base;
1184 		if (left > siz)
1185 			left = siz;
1186 		uiosiz = left;
1187 		while (left > 0) {
1188 			mlen = M_TRAILINGSPACE(mp);
1189 			if (mlen == 0) {
1190 				if (getcluster)
1191 					mp = m_getcl(MB_WAIT, MT_DATA, 0);
1192 				else
1193 					mp = m_get(MB_WAIT, MT_DATA);
1194 				mp->m_len = 0;
1195 				mp2->m_next = mp;
1196 				mp2 = mp;
1197 				mlen = M_TRAILINGSPACE(mp);
1198 			}
1199 			xfer = (left > mlen) ? mlen : left;
1200 #ifdef notdef
1201 			/* Not Yet.. */
1202 			if (uiop->uio_iov->iov_op != NULL)
1203 				(*(uiop->uio_iov->iov_op))
1204 				(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
1205 			else
1206 #endif
1207 			if (uiop->uio_segflg == UIO_SYSSPACE)
1208 				bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
1209 			else
1210 				copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
1211 			mp->m_len += xfer;
1212 			left -= xfer;
1213 			uiocp += xfer;
1214 			uiop->uio_offset += xfer;
1215 			uiop->uio_resid -= xfer;
1216 		}
1217 		uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base + uiosiz;
1218 		uiop->uio_iov->iov_len -= uiosiz;
1219 		siz -= uiosiz;
1220 	}
1221 	if (rem > 0) {
1222 		if (rem > M_TRAILINGSPACE(mp)) {
1223 			MGET(mp, MB_WAIT, MT_DATA);
1224 			mp->m_len = 0;
1225 			mp2->m_next = mp;
1226 		}
1227 		cp = mtod(mp, caddr_t)+mp->m_len;
1228 		for (left = 0; left < rem; left++)
1229 			*cp++ = '\0';
1230 		mp->m_len += rem;
1231 		*bpos = cp;
1232 	} else
1233 		*bpos = mtod(mp, caddr_t)+mp->m_len;
1234 	*mq = mp;
1235 	return (0);
1236 }
1237 
1238 int
1239 nfsm_biotombuf(struct bio *bio, struct mbuf **mq, int off,
1240 	       int siz, caddr_t *bpos)
1241 {
1242 	struct buf *bp = bio->bio_buf;
1243 	struct mbuf *mp, *mp2;
1244 	char *bio_cp;
1245 	int bio_left;
1246 	int xfer, mlen;
1247 	int rem;
1248 	boolean_t getcluster;
1249 	char *cp;
1250 
1251 	if (siz >= MINCLSIZE)
1252 		getcluster = TRUE;
1253 	else
1254 		getcluster = FALSE;
1255 	rem = nfsm_rndup(siz) - siz;
1256 	mp = mp2 = *mq;
1257 
1258 	bio_cp = bp->b_data + off;
1259 	bio_left = siz;
1260 
1261 	while (bio_left) {
1262 		mlen = M_TRAILINGSPACE(mp);
1263 		if (mlen == 0) {
1264 			if (getcluster)
1265 				mp = m_getcl(MB_WAIT, MT_DATA, 0);
1266 			else
1267 				mp = m_get(MB_WAIT, MT_DATA);
1268 			mp->m_len = 0;
1269 			mp2->m_next = mp;
1270 			mp2 = mp;
1271 			mlen = M_TRAILINGSPACE(mp);
1272 		}
1273 		xfer = (bio_left < mlen) ? bio_left : mlen;
1274 		bcopy(bio_cp, mtod(mp, caddr_t) + mp->m_len, xfer);
1275 		mp->m_len += xfer;
1276 		bio_left -= xfer;
1277 		bio_cp += xfer;
1278 	}
1279 	if (rem > 0) {
1280 		if (rem > M_TRAILINGSPACE(mp)) {
1281 			MGET(mp, MB_WAIT, MT_DATA);
1282 			mp->m_len = 0;
1283 			mp2->m_next = mp;
1284 		}
1285 		cp = mtod(mp, caddr_t) + mp->m_len;
1286 		for (mlen = 0; mlen < rem; mlen++)
1287 			*cp++ = '\0';
1288 		mp->m_len += rem;
1289 		*bpos = cp;
1290 	} else {
1291 		*bpos = mtod(mp, caddr_t) + mp->m_len;
1292 	}
1293 	*mq = mp;
1294 	return(0);
1295 }
1296 
1297 /*
1298  * Help break down an mbuf chain by setting the first siz bytes contiguous
1299  * pointed to by returned val.
1300  * This is used by the macros nfsm_dissect and nfsm_dissecton for tough
1301  * cases. (The macros use the vars. dpos and dpos2)
1302  */
1303 int
1304 nfsm_disct(struct mbuf **mdp, caddr_t *dposp, int siz, int left, caddr_t *cp2)
1305 {
1306 	struct mbuf *mp, *mp2;
1307 	int siz2, xfer;
1308 	caddr_t p;
1309 
1310 	mp = *mdp;
1311 	while (left == 0) {
1312 		*mdp = mp = mp->m_next;
1313 		if (mp == NULL)
1314 			return (EBADRPC);
1315 		left = mp->m_len;
1316 		*dposp = mtod(mp, caddr_t);
1317 	}
1318 	if (left >= siz) {
1319 		*cp2 = *dposp;
1320 		*dposp += siz;
1321 	} else if (mp->m_next == NULL) {
1322 		return (EBADRPC);
1323 	} else if (siz > MHLEN) {
1324 		panic("nfs S too big");
1325 	} else {
1326 		MGET(mp2, MB_WAIT, MT_DATA);
1327 		mp2->m_next = mp->m_next;
1328 		mp->m_next = mp2;
1329 		mp->m_len -= left;
1330 		mp = mp2;
1331 		*cp2 = p = mtod(mp, caddr_t);
1332 		bcopy(*dposp, p, left);		/* Copy what was left */
1333 		siz2 = siz-left;
1334 		p += left;
1335 		mp2 = mp->m_next;
1336 		/* Loop around copying up the siz2 bytes */
1337 		while (siz2 > 0) {
1338 			if (mp2 == NULL)
1339 				return (EBADRPC);
1340 			xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2;
1341 			if (xfer > 0) {
1342 				bcopy(mtod(mp2, caddr_t), p, xfer);
1343 				mp2->m_len -= xfer;
1344 				mp2->m_data += xfer;
1345 				p += xfer;
1346 				siz2 -= xfer;
1347 			}
1348 			if (siz2 > 0)
1349 				mp2 = mp2->m_next;
1350 		}
1351 		mp->m_len = siz;
1352 		*mdp = mp2;
1353 		*dposp = mtod(mp2, caddr_t);
1354 	}
1355 	return (0);
1356 }
1357 
1358 /*
1359  * Advance the position in the mbuf chain.
1360  */
1361 int
1362 nfs_adv(struct mbuf **mdp, caddr_t *dposp, int offs, int left)
1363 {
1364 	struct mbuf *m;
1365 	int s;
1366 
1367 	m = *mdp;
1368 	s = left;
1369 	while (s < offs) {
1370 		offs -= s;
1371 		m = m->m_next;
1372 		if (m == NULL)
1373 			return (EBADRPC);
1374 		s = m->m_len;
1375 	}
1376 	*mdp = m;
1377 	*dposp = mtod(m, caddr_t)+offs;
1378 	return (0);
1379 }
1380 
1381 /*
1382  * Copy a string into mbufs for the hard cases...
1383  */
1384 int
1385 nfsm_strtmbuf(struct mbuf **mb, char **bpos, const char *cp, long siz)
1386 {
1387 	struct mbuf *m1 = NULL, *m2;
1388 	long left, xfer, len, tlen;
1389 	u_int32_t *tl;
1390 	int putsize;
1391 
1392 	putsize = 1;
1393 	m2 = *mb;
1394 	left = M_TRAILINGSPACE(m2);
1395 	if (left > 0) {
1396 		tl = ((u_int32_t *)(*bpos));
1397 		*tl++ = txdr_unsigned(siz);
1398 		putsize = 0;
1399 		left -= NFSX_UNSIGNED;
1400 		m2->m_len += NFSX_UNSIGNED;
1401 		if (left > 0) {
1402 			bcopy(cp, (caddr_t) tl, left);
1403 			siz -= left;
1404 			cp += left;
1405 			m2->m_len += left;
1406 			left = 0;
1407 		}
1408 	}
1409 	/* Loop around adding mbufs */
1410 	while (siz > 0) {
1411 		int msize;
1412 
1413 		m1 = m_getl(siz, MB_WAIT, MT_DATA, 0, &msize);
1414 		m1->m_len = msize;
1415 		m2->m_next = m1;
1416 		m2 = m1;
1417 		tl = mtod(m1, u_int32_t *);
1418 		tlen = 0;
1419 		if (putsize) {
1420 			*tl++ = txdr_unsigned(siz);
1421 			m1->m_len -= NFSX_UNSIGNED;
1422 			tlen = NFSX_UNSIGNED;
1423 			putsize = 0;
1424 		}
1425 		if (siz < m1->m_len) {
1426 			len = nfsm_rndup(siz);
1427 			xfer = siz;
1428 			if (xfer < len)
1429 				*(tl+(xfer>>2)) = 0;
1430 		} else {
1431 			xfer = len = m1->m_len;
1432 		}
1433 		bcopy(cp, (caddr_t) tl, xfer);
1434 		m1->m_len = len+tlen;
1435 		siz -= xfer;
1436 		cp += xfer;
1437 	}
1438 	*mb = m1;
1439 	*bpos = mtod(m1, caddr_t)+m1->m_len;
1440 	return (0);
1441 }
1442 
1443 /*
1444  * A fiddled version of m_adj() that ensures null fill to a long
1445  * boundary and only trims off the back end
1446  */
1447 void
1448 nfsm_adj(struct mbuf *mp, int len, int nul)
1449 {
1450 	struct mbuf *m;
1451 	int count, i;
1452 	char *cp;
1453 
1454 	/*
1455 	 * Trim from tail.  Scan the mbuf chain,
1456 	 * calculating its length and finding the last mbuf.
1457 	 * If the adjustment only affects this mbuf, then just
1458 	 * adjust and return.  Otherwise, rescan and truncate
1459 	 * after the remaining size.
1460 	 */
1461 	count = 0;
1462 	m = mp;
1463 	for (;;) {
1464 		count += m->m_len;
1465 		if (m->m_next == NULL)
1466 			break;
1467 		m = m->m_next;
1468 	}
1469 	if (m->m_len > len) {
1470 		m->m_len -= len;
1471 		if (nul > 0) {
1472 			cp = mtod(m, caddr_t)+m->m_len-nul;
1473 			for (i = 0; i < nul; i++)
1474 				*cp++ = '\0';
1475 		}
1476 		return;
1477 	}
1478 	count -= len;
1479 	if (count < 0)
1480 		count = 0;
1481 	/*
1482 	 * Correct length for chain is "count".
1483 	 * Find the mbuf with last data, adjust its length,
1484 	 * and toss data from remaining mbufs on chain.
1485 	 */
1486 	for (m = mp; m; m = m->m_next) {
1487 		if (m->m_len >= count) {
1488 			m->m_len = count;
1489 			if (nul > 0) {
1490 				cp = mtod(m, caddr_t)+m->m_len-nul;
1491 				for (i = 0; i < nul; i++)
1492 					*cp++ = '\0';
1493 			}
1494 			break;
1495 		}
1496 		count -= m->m_len;
1497 	}
1498 	for (m = m->m_next;m;m = m->m_next)
1499 		m->m_len = 0;
1500 }
1501 
1502 /*
1503  * Make these functions instead of macros, so that the kernel text size
1504  * doesn't get too big...
1505  */
1506 void
1507 nfsm_srvwcc_data(nfsm_info_t info, struct nfsrv_descript *nfsd,
1508 		 int before_ret, struct vattr *before_vap,
1509 		 int after_ret, struct vattr *after_vap)
1510 {
1511 	u_int32_t *tl;
1512 
1513 	/*
1514 	 * before_ret is 0 if before_vap is valid, non-zero if it isn't.
1515 	 */
1516 	if (before_ret) {
1517 		tl = nfsm_build(info, NFSX_UNSIGNED);
1518 		*tl = nfs_false;
1519 	} else {
1520 		tl = nfsm_build(info, 7 * NFSX_UNSIGNED);
1521 		*tl++ = nfs_true;
1522 		txdr_hyper(before_vap->va_size, tl);
1523 		tl += 2;
1524 		txdr_nfsv3time(&(before_vap->va_mtime), tl);
1525 		tl += 2;
1526 		txdr_nfsv3time(&(before_vap->va_ctime), tl);
1527 	}
1528 	nfsm_srvpostop_attr(info, nfsd, after_ret, after_vap);
1529 }
1530 
1531 void
1532 nfsm_srvpostop_attr(nfsm_info_t info, struct nfsrv_descript *nfsd,
1533 		   int after_ret, struct vattr *after_vap)
1534 {
1535 	struct nfs_fattr *fp;
1536 	u_int32_t *tl;
1537 
1538 	if (after_ret) {
1539 		tl = nfsm_build(info, NFSX_UNSIGNED);
1540 		*tl = nfs_false;
1541 	} else {
1542 		tl = nfsm_build(info, NFSX_UNSIGNED + NFSX_V3FATTR);
1543 		*tl++ = nfs_true;
1544 		fp = (struct nfs_fattr *)tl;
1545 		nfsm_srvfattr(nfsd, after_vap, fp);
1546 	}
1547 }
1548 
1549 void
1550 nfsm_srvfattr(struct nfsrv_descript *nfsd, struct vattr *vap,
1551 	      struct nfs_fattr *fp)
1552 {
1553 	/*
1554 	 * NFS seems to truncate nlink to 16 bits, don't let it overflow.
1555 	 */
1556 	if (vap->va_nlink > 65535)
1557 		fp->fa_nlink = 65535;
1558 	else
1559 		fp->fa_nlink = txdr_unsigned(vap->va_nlink);
1560 	fp->fa_uid = txdr_unsigned(vap->va_uid);
1561 	fp->fa_gid = txdr_unsigned(vap->va_gid);
1562 	if (nfsd->nd_flag & ND_NFSV3) {
1563 		fp->fa_type = vtonfsv3_type(vap->va_type);
1564 		fp->fa_mode = vtonfsv3_mode(vap->va_mode);
1565 		txdr_hyper(vap->va_size, &fp->fa3_size);
1566 		txdr_hyper(vap->va_bytes, &fp->fa3_used);
1567 		fp->fa3_rdev.specdata1 = txdr_unsigned(vap->va_rmajor);
1568 		fp->fa3_rdev.specdata2 = txdr_unsigned(vap->va_rminor);
1569 		fp->fa3_fsid.nfsuquad[0] = 0;
1570 		fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid);
1571 		txdr_hyper(vap->va_fileid, &fp->fa3_fileid);
1572 		txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime);
1573 		txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime);
1574 		txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime);
1575 	} else {
1576 		fp->fa_type = vtonfsv2_type(vap->va_type);
1577 		fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
1578 		fp->fa2_size = txdr_unsigned(vap->va_size);
1579 		fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize);
1580 		if (vap->va_type == VFIFO)
1581 			fp->fa2_rdev = 0xffffffff;
1582 		else
1583 			fp->fa2_rdev = txdr_unsigned(makeudev(vap->va_rmajor, vap->va_rminor));
1584 		fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE);
1585 		fp->fa2_fsid = txdr_unsigned(vap->va_fsid);
1586 		fp->fa2_fileid = txdr_unsigned(vap->va_fileid);
1587 		txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime);
1588 		txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime);
1589 		txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime);
1590 	}
1591 }
1592