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