xref: /netbsd-src/sys/nfs/nfs_subs.c (revision d0fed6c87ddc40a8bffa6f99e7433ddfc864dd83)
1 /*	$NetBSD: nfs_subs.c,v 1.41 1997/03/27 20:40:09 thorpej Exp $	*/
2 
3 /*
4  * Copyright (c) 1989, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * This code is derived from software contributed to Berkeley by
8  * Rick Macklem at The University of Guelph.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *	This product includes software developed by the University of
21  *	California, Berkeley and its contributors.
22  * 4. Neither the name of the University nor the names of its contributors
23  *    may be used to endorse or promote products derived from this software
24  *    without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36  * SUCH DAMAGE.
37  *
38  *	@(#)nfs_subs.c	8.8 (Berkeley) 5/22/95
39  */
40 
41 
42 /*
43  * These functions support the macros and help fiddle mbuf chains for
44  * the nfs op functions. They do things like create the rpc header and
45  * copy data between mbuf chains and uio lists.
46  */
47 #include <sys/param.h>
48 #include <sys/proc.h>
49 #include <sys/systm.h>
50 #include <sys/kernel.h>
51 #include <sys/mount.h>
52 #include <sys/vnode.h>
53 #include <sys/namei.h>
54 #include <sys/mbuf.h>
55 #include <sys/socket.h>
56 #include <sys/stat.h>
57 #include <sys/malloc.h>
58 #include <sys/time.h>
59 
60 #include <vm/vm.h>
61 
62 #include <nfs/rpcv2.h>
63 #include <nfs/nfsproto.h>
64 #include <nfs/nfsnode.h>
65 #include <nfs/nfs.h>
66 #include <nfs/xdr_subs.h>
67 #include <nfs/nfsm_subs.h>
68 #include <nfs/nfsmount.h>
69 #include <nfs/nqnfs.h>
70 #include <nfs/nfsrtt.h>
71 #include <nfs/nfs_var.h>
72 
73 #include <miscfs/specfs/specdev.h>
74 
75 #include <vm/vm.h>
76 
77 #include <netinet/in.h>
78 #ifdef ISO
79 #include <netiso/iso.h>
80 #endif
81 
82 /*
83  * Data items converted to xdr at startup, since they are constant
84  * This is kinda hokey, but may save a little time doing byte swaps
85  */
86 u_int32_t nfs_xdrneg1;
87 u_int32_t rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr,
88 	rpc_mismatch, rpc_auth_unix, rpc_msgaccepted,
89 	rpc_auth_kerb;
90 u_int32_t nfs_prog, nqnfs_prog, nfs_true, nfs_false;
91 
92 /* And other global data */
93 static u_int32_t nfs_xid = 0;
94 nfstype nfsv2_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFNON,
95 		      NFCHR, NFNON };
96 nfstype nfsv3_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK,
97 		      NFFIFO, NFNON };
98 enum vtype nv2tov_type[8] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON };
99 enum vtype nv3tov_type[8]={ VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO };
100 int nfs_ticks;
101 
102 /* NFS client/server stats. */
103 struct nfsstats nfsstats;
104 
105 /*
106  * Mapping of old NFS Version 2 RPC numbers to generic numbers.
107  */
108 int nfsv3_procid[NFS_NPROCS] = {
109 	NFSPROC_NULL,
110 	NFSPROC_GETATTR,
111 	NFSPROC_SETATTR,
112 	NFSPROC_NOOP,
113 	NFSPROC_LOOKUP,
114 	NFSPROC_READLINK,
115 	NFSPROC_READ,
116 	NFSPROC_NOOP,
117 	NFSPROC_WRITE,
118 	NFSPROC_CREATE,
119 	NFSPROC_REMOVE,
120 	NFSPROC_RENAME,
121 	NFSPROC_LINK,
122 	NFSPROC_SYMLINK,
123 	NFSPROC_MKDIR,
124 	NFSPROC_RMDIR,
125 	NFSPROC_READDIR,
126 	NFSPROC_FSSTAT,
127 	NFSPROC_NOOP,
128 	NFSPROC_NOOP,
129 	NFSPROC_NOOP,
130 	NFSPROC_NOOP,
131 	NFSPROC_NOOP,
132 	NFSPROC_NOOP,
133 	NFSPROC_NOOP,
134 	NFSPROC_NOOP
135 };
136 
137 /*
138  * and the reverse mapping from generic to Version 2 procedure numbers
139  */
140 int nfsv2_procid[NFS_NPROCS] = {
141 	NFSV2PROC_NULL,
142 	NFSV2PROC_GETATTR,
143 	NFSV2PROC_SETATTR,
144 	NFSV2PROC_LOOKUP,
145 	NFSV2PROC_NOOP,
146 	NFSV2PROC_READLINK,
147 	NFSV2PROC_READ,
148 	NFSV2PROC_WRITE,
149 	NFSV2PROC_CREATE,
150 	NFSV2PROC_MKDIR,
151 	NFSV2PROC_SYMLINK,
152 	NFSV2PROC_CREATE,
153 	NFSV2PROC_REMOVE,
154 	NFSV2PROC_RMDIR,
155 	NFSV2PROC_RENAME,
156 	NFSV2PROC_LINK,
157 	NFSV2PROC_READDIR,
158 	NFSV2PROC_NOOP,
159 	NFSV2PROC_STATFS,
160 	NFSV2PROC_NOOP,
161 	NFSV2PROC_NOOP,
162 	NFSV2PROC_NOOP,
163 	NFSV2PROC_NOOP,
164 	NFSV2PROC_NOOP,
165 	NFSV2PROC_NOOP,
166 	NFSV2PROC_NOOP,
167 };
168 
169 /*
170  * Maps errno values to nfs error numbers.
171  * Use NFSERR_IO as the catch all for ones not specifically defined in
172  * RFC 1094.
173  */
174 static u_char nfsrv_v2errmap[ELAST] = {
175   NFSERR_PERM,	NFSERR_NOENT,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
176   NFSERR_NXIO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
177   NFSERR_IO,	NFSERR_IO,	NFSERR_ACCES,	NFSERR_IO,	NFSERR_IO,
178   NFSERR_IO,	NFSERR_EXIST,	NFSERR_IO,	NFSERR_NODEV,	NFSERR_NOTDIR,
179   NFSERR_ISDIR,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
180   NFSERR_IO,	NFSERR_FBIG,	NFSERR_NOSPC,	NFSERR_IO,	NFSERR_ROFS,
181   NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
182   NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
183   NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
184   NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
185   NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
186   NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
187   NFSERR_IO,	NFSERR_IO,	NFSERR_NAMETOL,	NFSERR_IO,	NFSERR_IO,
188   NFSERR_NOTEMPTY, NFSERR_IO,	NFSERR_IO,	NFSERR_DQUOT,	NFSERR_STALE,
189   NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
190   NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
191   NFSERR_IO,
192 };
193 
194 /*
195  * Maps errno values to nfs error numbers.
196  * Although it is not obvious whether or not NFS clients really care if
197  * a returned error value is in the specified list for the procedure, the
198  * safest thing to do is filter them appropriately. For Version 2, the
199  * X/Open XNFS document is the only specification that defines error values
200  * for each RPC (The RFC simply lists all possible error values for all RPCs),
201  * so I have decided to not do this for Version 2.
202  * The first entry is the default error return and the rest are the valid
203  * errors for that RPC in increasing numeric order.
204  */
205 static short nfsv3err_null[] = {
206 	0,
207 	0,
208 };
209 
210 static short nfsv3err_getattr[] = {
211 	NFSERR_IO,
212 	NFSERR_IO,
213 	NFSERR_STALE,
214 	NFSERR_BADHANDLE,
215 	NFSERR_SERVERFAULT,
216 	0,
217 };
218 
219 static short nfsv3err_setattr[] = {
220 	NFSERR_IO,
221 	NFSERR_PERM,
222 	NFSERR_IO,
223 	NFSERR_ACCES,
224 	NFSERR_INVAL,
225 	NFSERR_NOSPC,
226 	NFSERR_ROFS,
227 	NFSERR_DQUOT,
228 	NFSERR_STALE,
229 	NFSERR_BADHANDLE,
230 	NFSERR_NOT_SYNC,
231 	NFSERR_SERVERFAULT,
232 	0,
233 };
234 
235 static short nfsv3err_lookup[] = {
236 	NFSERR_IO,
237 	NFSERR_NOENT,
238 	NFSERR_IO,
239 	NFSERR_ACCES,
240 	NFSERR_NOTDIR,
241 	NFSERR_NAMETOL,
242 	NFSERR_STALE,
243 	NFSERR_BADHANDLE,
244 	NFSERR_SERVERFAULT,
245 	0,
246 };
247 
248 static short nfsv3err_access[] = {
249 	NFSERR_IO,
250 	NFSERR_IO,
251 	NFSERR_STALE,
252 	NFSERR_BADHANDLE,
253 	NFSERR_SERVERFAULT,
254 	0,
255 };
256 
257 static short nfsv3err_readlink[] = {
258 	NFSERR_IO,
259 	NFSERR_IO,
260 	NFSERR_ACCES,
261 	NFSERR_INVAL,
262 	NFSERR_STALE,
263 	NFSERR_BADHANDLE,
264 	NFSERR_NOTSUPP,
265 	NFSERR_SERVERFAULT,
266 	0,
267 };
268 
269 static short nfsv3err_read[] = {
270 	NFSERR_IO,
271 	NFSERR_IO,
272 	NFSERR_NXIO,
273 	NFSERR_ACCES,
274 	NFSERR_INVAL,
275 	NFSERR_STALE,
276 	NFSERR_BADHANDLE,
277 	NFSERR_SERVERFAULT,
278 	0,
279 };
280 
281 static short nfsv3err_write[] = {
282 	NFSERR_IO,
283 	NFSERR_IO,
284 	NFSERR_ACCES,
285 	NFSERR_INVAL,
286 	NFSERR_FBIG,
287 	NFSERR_NOSPC,
288 	NFSERR_ROFS,
289 	NFSERR_DQUOT,
290 	NFSERR_STALE,
291 	NFSERR_BADHANDLE,
292 	NFSERR_SERVERFAULT,
293 	0,
294 };
295 
296 static short nfsv3err_create[] = {
297 	NFSERR_IO,
298 	NFSERR_IO,
299 	NFSERR_ACCES,
300 	NFSERR_EXIST,
301 	NFSERR_NOTDIR,
302 	NFSERR_NOSPC,
303 	NFSERR_ROFS,
304 	NFSERR_NAMETOL,
305 	NFSERR_DQUOT,
306 	NFSERR_STALE,
307 	NFSERR_BADHANDLE,
308 	NFSERR_NOTSUPP,
309 	NFSERR_SERVERFAULT,
310 	0,
311 };
312 
313 static short nfsv3err_mkdir[] = {
314 	NFSERR_IO,
315 	NFSERR_IO,
316 	NFSERR_ACCES,
317 	NFSERR_EXIST,
318 	NFSERR_NOTDIR,
319 	NFSERR_NOSPC,
320 	NFSERR_ROFS,
321 	NFSERR_NAMETOL,
322 	NFSERR_DQUOT,
323 	NFSERR_STALE,
324 	NFSERR_BADHANDLE,
325 	NFSERR_NOTSUPP,
326 	NFSERR_SERVERFAULT,
327 	0,
328 };
329 
330 static short nfsv3err_symlink[] = {
331 	NFSERR_IO,
332 	NFSERR_IO,
333 	NFSERR_ACCES,
334 	NFSERR_EXIST,
335 	NFSERR_NOTDIR,
336 	NFSERR_NOSPC,
337 	NFSERR_ROFS,
338 	NFSERR_NAMETOL,
339 	NFSERR_DQUOT,
340 	NFSERR_STALE,
341 	NFSERR_BADHANDLE,
342 	NFSERR_NOTSUPP,
343 	NFSERR_SERVERFAULT,
344 	0,
345 };
346 
347 static short nfsv3err_mknod[] = {
348 	NFSERR_IO,
349 	NFSERR_IO,
350 	NFSERR_ACCES,
351 	NFSERR_EXIST,
352 	NFSERR_NOTDIR,
353 	NFSERR_NOSPC,
354 	NFSERR_ROFS,
355 	NFSERR_NAMETOL,
356 	NFSERR_DQUOT,
357 	NFSERR_STALE,
358 	NFSERR_BADHANDLE,
359 	NFSERR_NOTSUPP,
360 	NFSERR_SERVERFAULT,
361 	NFSERR_BADTYPE,
362 	0,
363 };
364 
365 static short nfsv3err_remove[] = {
366 	NFSERR_IO,
367 	NFSERR_NOENT,
368 	NFSERR_IO,
369 	NFSERR_ACCES,
370 	NFSERR_NOTDIR,
371 	NFSERR_ROFS,
372 	NFSERR_NAMETOL,
373 	NFSERR_STALE,
374 	NFSERR_BADHANDLE,
375 	NFSERR_SERVERFAULT,
376 	0,
377 };
378 
379 static short nfsv3err_rmdir[] = {
380 	NFSERR_IO,
381 	NFSERR_NOENT,
382 	NFSERR_IO,
383 	NFSERR_ACCES,
384 	NFSERR_EXIST,
385 	NFSERR_NOTDIR,
386 	NFSERR_INVAL,
387 	NFSERR_ROFS,
388 	NFSERR_NAMETOL,
389 	NFSERR_NOTEMPTY,
390 	NFSERR_STALE,
391 	NFSERR_BADHANDLE,
392 	NFSERR_NOTSUPP,
393 	NFSERR_SERVERFAULT,
394 	0,
395 };
396 
397 static short nfsv3err_rename[] = {
398 	NFSERR_IO,
399 	NFSERR_NOENT,
400 	NFSERR_IO,
401 	NFSERR_ACCES,
402 	NFSERR_EXIST,
403 	NFSERR_XDEV,
404 	NFSERR_NOTDIR,
405 	NFSERR_ISDIR,
406 	NFSERR_INVAL,
407 	NFSERR_NOSPC,
408 	NFSERR_ROFS,
409 	NFSERR_MLINK,
410 	NFSERR_NAMETOL,
411 	NFSERR_NOTEMPTY,
412 	NFSERR_DQUOT,
413 	NFSERR_STALE,
414 	NFSERR_BADHANDLE,
415 	NFSERR_NOTSUPP,
416 	NFSERR_SERVERFAULT,
417 	0,
418 };
419 
420 static short nfsv3err_link[] = {
421 	NFSERR_IO,
422 	NFSERR_IO,
423 	NFSERR_ACCES,
424 	NFSERR_EXIST,
425 	NFSERR_XDEV,
426 	NFSERR_NOTDIR,
427 	NFSERR_INVAL,
428 	NFSERR_NOSPC,
429 	NFSERR_ROFS,
430 	NFSERR_MLINK,
431 	NFSERR_NAMETOL,
432 	NFSERR_DQUOT,
433 	NFSERR_STALE,
434 	NFSERR_BADHANDLE,
435 	NFSERR_NOTSUPP,
436 	NFSERR_SERVERFAULT,
437 	0,
438 };
439 
440 static short nfsv3err_readdir[] = {
441 	NFSERR_IO,
442 	NFSERR_IO,
443 	NFSERR_ACCES,
444 	NFSERR_NOTDIR,
445 	NFSERR_STALE,
446 	NFSERR_BADHANDLE,
447 	NFSERR_BAD_COOKIE,
448 	NFSERR_TOOSMALL,
449 	NFSERR_SERVERFAULT,
450 	0,
451 };
452 
453 static short nfsv3err_readdirplus[] = {
454 	NFSERR_IO,
455 	NFSERR_IO,
456 	NFSERR_ACCES,
457 	NFSERR_NOTDIR,
458 	NFSERR_STALE,
459 	NFSERR_BADHANDLE,
460 	NFSERR_BAD_COOKIE,
461 	NFSERR_NOTSUPP,
462 	NFSERR_TOOSMALL,
463 	NFSERR_SERVERFAULT,
464 	0,
465 };
466 
467 static short nfsv3err_fsstat[] = {
468 	NFSERR_IO,
469 	NFSERR_IO,
470 	NFSERR_STALE,
471 	NFSERR_BADHANDLE,
472 	NFSERR_SERVERFAULT,
473 	0,
474 };
475 
476 static short nfsv3err_fsinfo[] = {
477 	NFSERR_STALE,
478 	NFSERR_STALE,
479 	NFSERR_BADHANDLE,
480 	NFSERR_SERVERFAULT,
481 	0,
482 };
483 
484 static short nfsv3err_pathconf[] = {
485 	NFSERR_STALE,
486 	NFSERR_STALE,
487 	NFSERR_BADHANDLE,
488 	NFSERR_SERVERFAULT,
489 	0,
490 };
491 
492 static short nfsv3err_commit[] = {
493 	NFSERR_IO,
494 	NFSERR_IO,
495 	NFSERR_STALE,
496 	NFSERR_BADHANDLE,
497 	NFSERR_SERVERFAULT,
498 	0,
499 };
500 
501 static short *nfsrv_v3errmap[] = {
502 	nfsv3err_null,
503 	nfsv3err_getattr,
504 	nfsv3err_setattr,
505 	nfsv3err_lookup,
506 	nfsv3err_access,
507 	nfsv3err_readlink,
508 	nfsv3err_read,
509 	nfsv3err_write,
510 	nfsv3err_create,
511 	nfsv3err_mkdir,
512 	nfsv3err_symlink,
513 	nfsv3err_mknod,
514 	nfsv3err_remove,
515 	nfsv3err_rmdir,
516 	nfsv3err_rename,
517 	nfsv3err_link,
518 	nfsv3err_readdir,
519 	nfsv3err_readdirplus,
520 	nfsv3err_fsstat,
521 	nfsv3err_fsinfo,
522 	nfsv3err_pathconf,
523 	nfsv3err_commit,
524 };
525 
526 extern struct nfsrtt nfsrtt;
527 extern time_t nqnfsstarttime;
528 extern int nqsrv_clockskew;
529 extern int nqsrv_writeslack;
530 extern int nqsrv_maxlease;
531 extern int nqnfs_piggy[NFS_NPROCS];
532 extern nfstype nfsv2_type[9];
533 extern nfstype nfsv3_type[9];
534 extern struct nfsnodehashhead *nfsnodehashtbl;
535 extern u_long nfsnodehash;
536 
537 LIST_HEAD(nfsnodehashhead, nfsnode);
538 
539 /*
540  * Create the header for an rpc request packet
541  * The hsiz is the size of the rest of the nfs request header.
542  * (just used to decide if a cluster is a good idea)
543  */
544 struct mbuf *
545 nfsm_reqh(vp, procid, hsiz, bposp)
546 	struct vnode *vp;
547 	u_long procid;
548 	int hsiz;
549 	caddr_t *bposp;
550 {
551 	register struct mbuf *mb;
552 	register u_int32_t *tl;
553 	register caddr_t bpos;
554 	struct mbuf *mb2;
555 	struct nfsmount *nmp;
556 	int nqflag;
557 
558 	MGET(mb, M_WAIT, MT_DATA);
559 	if (hsiz >= MINCLSIZE)
560 		MCLGET(mb, M_WAIT);
561 	mb->m_len = 0;
562 	bpos = mtod(mb, caddr_t);
563 
564 	/*
565 	 * For NQNFS, add lease request.
566 	 */
567 	if (vp) {
568 		nmp = VFSTONFS(vp->v_mount);
569 		if (nmp->nm_flag & NFSMNT_NQNFS) {
570 			nqflag = NQNFS_NEEDLEASE(vp, procid);
571 			if (nqflag) {
572 				nfsm_build(tl, u_int32_t *, 2*NFSX_UNSIGNED);
573 				*tl++ = txdr_unsigned(nqflag);
574 				*tl = txdr_unsigned(nmp->nm_leaseterm);
575 			} else {
576 				nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
577 				*tl = 0;
578 			}
579 		}
580 	}
581 	/* Finally, return values */
582 	*bposp = bpos;
583 	return (mb);
584 }
585 
586 /*
587  * Build the RPC header and fill in the authorization info.
588  * The authorization string argument is only used when the credentials
589  * come from outside of the kernel.
590  * Returns the head of the mbuf list.
591  */
592 struct mbuf *
593 nfsm_rpchead(cr, nmflag, procid, auth_type, auth_len, auth_str, verf_len,
594 	verf_str, mrest, mrest_len, mbp, xidp)
595 	register struct ucred *cr;
596 	int nmflag;
597 	int procid;
598 	int auth_type;
599 	int auth_len;
600 	char *auth_str;
601 	int verf_len;
602 	char *verf_str;
603 	struct mbuf *mrest;
604 	int mrest_len;
605 	struct mbuf **mbp;
606 	u_int32_t *xidp;
607 {
608 	register struct mbuf *mb;
609 	register u_int32_t *tl;
610 	register caddr_t bpos;
611 	register int i;
612 	struct mbuf *mreq, *mb2;
613 	int siz, grpsiz, authsiz;
614 	struct timeval tv;
615 	static u_int32_t base;
616 
617 	authsiz = nfsm_rndup(auth_len);
618 	MGETHDR(mb, M_WAIT, MT_DATA);
619 	if ((authsiz + 10 * NFSX_UNSIGNED) >= MINCLSIZE) {
620 		MCLGET(mb, M_WAIT);
621 	} else if ((authsiz + 10 * NFSX_UNSIGNED) < MHLEN) {
622 		MH_ALIGN(mb, authsiz + 10 * NFSX_UNSIGNED);
623 	} else {
624 		MH_ALIGN(mb, 8 * NFSX_UNSIGNED);
625 	}
626 	mb->m_len = 0;
627 	mreq = mb;
628 	bpos = mtod(mb, caddr_t);
629 
630 	/*
631 	 * First the RPC header.
632 	 */
633 	nfsm_build(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
634 
635 	/*
636 	 * derive initial xid from system time
637 	 * XXX time is invalid if root not yet mounted
638 	 */
639 	if (!base && (rootvp)) {
640 		microtime(&tv);
641 		base = tv.tv_sec << 12;
642 		nfs_xid = base;
643 	}
644 	/*
645 	 * Skip zero xid if it should ever happen.
646 	 */
647 	if (++nfs_xid == 0)
648 		nfs_xid++;
649 
650 	*tl++ = *xidp = txdr_unsigned(nfs_xid);
651 	*tl++ = rpc_call;
652 	*tl++ = rpc_vers;
653 	if (nmflag & NFSMNT_NQNFS) {
654 		*tl++ = txdr_unsigned(NQNFS_PROG);
655 		*tl++ = txdr_unsigned(NQNFS_VER3);
656 	} else {
657 		*tl++ = txdr_unsigned(NFS_PROG);
658 		if (nmflag & NFSMNT_NFSV3)
659 			*tl++ = txdr_unsigned(NFS_VER3);
660 		else
661 			*tl++ = txdr_unsigned(NFS_VER2);
662 	}
663 	if (nmflag & NFSMNT_NFSV3)
664 		*tl++ = txdr_unsigned(procid);
665 	else
666 		*tl++ = txdr_unsigned(nfsv2_procid[procid]);
667 
668 	/*
669 	 * And then the authorization cred.
670 	 */
671 	*tl++ = txdr_unsigned(auth_type);
672 	*tl = txdr_unsigned(authsiz);
673 	switch (auth_type) {
674 	case RPCAUTH_UNIX:
675 		nfsm_build(tl, u_int32_t *, auth_len);
676 		*tl++ = 0;		/* stamp ?? */
677 		*tl++ = 0;		/* NULL hostname */
678 		*tl++ = txdr_unsigned(cr->cr_uid);
679 		*tl++ = txdr_unsigned(cr->cr_gid);
680 		grpsiz = (auth_len >> 2) - 5;
681 		*tl++ = txdr_unsigned(grpsiz);
682 		for (i = 0; i < grpsiz; i++)
683 			*tl++ = txdr_unsigned(cr->cr_groups[i]);
684 		break;
685 	case RPCAUTH_KERB4:
686 		siz = auth_len;
687 		while (siz > 0) {
688 			if (M_TRAILINGSPACE(mb) == 0) {
689 				MGET(mb2, M_WAIT, MT_DATA);
690 				if (siz >= MINCLSIZE)
691 					MCLGET(mb2, M_WAIT);
692 				mb->m_next = mb2;
693 				mb = mb2;
694 				mb->m_len = 0;
695 				bpos = mtod(mb, caddr_t);
696 			}
697 			i = min(siz, M_TRAILINGSPACE(mb));
698 			bcopy(auth_str, bpos, i);
699 			mb->m_len += i;
700 			auth_str += i;
701 			bpos += i;
702 			siz -= i;
703 		}
704 		if ((siz = (nfsm_rndup(auth_len) - auth_len)) > 0) {
705 			for (i = 0; i < siz; i++)
706 				*bpos++ = '\0';
707 			mb->m_len += siz;
708 		}
709 		break;
710 	};
711 
712 	/*
713 	 * And the verifier...
714 	 */
715 	nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
716 	if (verf_str) {
717 		*tl++ = txdr_unsigned(RPCAUTH_KERB4);
718 		*tl = txdr_unsigned(verf_len);
719 		siz = verf_len;
720 		while (siz > 0) {
721 			if (M_TRAILINGSPACE(mb) == 0) {
722 				MGET(mb2, M_WAIT, MT_DATA);
723 				if (siz >= MINCLSIZE)
724 					MCLGET(mb2, M_WAIT);
725 				mb->m_next = mb2;
726 				mb = mb2;
727 				mb->m_len = 0;
728 				bpos = mtod(mb, caddr_t);
729 			}
730 			i = min(siz, M_TRAILINGSPACE(mb));
731 			bcopy(verf_str, bpos, i);
732 			mb->m_len += i;
733 			verf_str += i;
734 			bpos += i;
735 			siz -= i;
736 		}
737 		if ((siz = (nfsm_rndup(verf_len) - verf_len)) > 0) {
738 			for (i = 0; i < siz; i++)
739 				*bpos++ = '\0';
740 			mb->m_len += siz;
741 		}
742 	} else {
743 		*tl++ = txdr_unsigned(RPCAUTH_NULL);
744 		*tl = 0;
745 	}
746 	mb->m_next = mrest;
747 	mreq->m_pkthdr.len = authsiz + 10 * NFSX_UNSIGNED + mrest_len;
748 	mreq->m_pkthdr.rcvif = (struct ifnet *)0;
749 	*mbp = mb;
750 	return (mreq);
751 }
752 
753 /*
754  * copies mbuf chain to the uio scatter/gather list
755  */
756 int
757 nfsm_mbuftouio(mrep, uiop, siz, dpos)
758 	struct mbuf **mrep;
759 	register struct uio *uiop;
760 	int siz;
761 	caddr_t *dpos;
762 {
763 	register char *mbufcp, *uiocp;
764 	register int xfer, left, len;
765 	register struct mbuf *mp;
766 	long uiosiz, rem;
767 	int error = 0;
768 
769 	mp = *mrep;
770 	mbufcp = *dpos;
771 	len = mtod(mp, caddr_t)+mp->m_len-mbufcp;
772 	rem = nfsm_rndup(siz)-siz;
773 	while (siz > 0) {
774 		if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
775 			return (EFBIG);
776 		left = uiop->uio_iov->iov_len;
777 		uiocp = uiop->uio_iov->iov_base;
778 		if (left > siz)
779 			left = siz;
780 		uiosiz = left;
781 		while (left > 0) {
782 			while (len == 0) {
783 				mp = mp->m_next;
784 				if (mp == NULL)
785 					return (EBADRPC);
786 				mbufcp = mtod(mp, caddr_t);
787 				len = mp->m_len;
788 			}
789 			xfer = (left > len) ? len : left;
790 #ifdef notdef
791 			/* Not Yet.. */
792 			if (uiop->uio_iov->iov_op != NULL)
793 				(*(uiop->uio_iov->iov_op))
794 				(mbufcp, uiocp, xfer);
795 			else
796 #endif
797 			if (uiop->uio_segflg == UIO_SYSSPACE)
798 				bcopy(mbufcp, uiocp, xfer);
799 			else
800 				copyout(mbufcp, uiocp, xfer);
801 			left -= xfer;
802 			len -= xfer;
803 			mbufcp += xfer;
804 			uiocp += xfer;
805 			uiop->uio_offset += xfer;
806 			uiop->uio_resid -= xfer;
807 		}
808 		if (uiop->uio_iov->iov_len <= siz) {
809 			uiop->uio_iovcnt--;
810 			uiop->uio_iov++;
811 		} else {
812 			uiop->uio_iov->iov_base += uiosiz;
813 			uiop->uio_iov->iov_len -= uiosiz;
814 		}
815 		siz -= uiosiz;
816 	}
817 	*dpos = mbufcp;
818 	*mrep = mp;
819 	if (rem > 0) {
820 		if (len < rem)
821 			error = nfs_adv(mrep, dpos, rem, len);
822 		else
823 			*dpos += rem;
824 	}
825 	return (error);
826 }
827 
828 /*
829  * copies a uio scatter/gather list to an mbuf chain.
830  * NOTE: can ony handle iovcnt == 1
831  */
832 int
833 nfsm_uiotombuf(uiop, mq, siz, bpos)
834 	register struct uio *uiop;
835 	struct mbuf **mq;
836 	int siz;
837 	caddr_t *bpos;
838 {
839 	register char *uiocp;
840 	register struct mbuf *mp, *mp2;
841 	register int xfer, left, mlen;
842 	int uiosiz, clflg, rem;
843 	char *cp;
844 
845 #ifdef DIAGNOSTIC
846 	if (uiop->uio_iovcnt != 1)
847 		panic("nfsm_uiotombuf: iovcnt != 1");
848 #endif
849 
850 	if (siz > MLEN)		/* or should it >= MCLBYTES ?? */
851 		clflg = 1;
852 	else
853 		clflg = 0;
854 	rem = nfsm_rndup(siz)-siz;
855 	mp = mp2 = *mq;
856 	while (siz > 0) {
857 		left = uiop->uio_iov->iov_len;
858 		uiocp = uiop->uio_iov->iov_base;
859 		if (left > siz)
860 			left = siz;
861 		uiosiz = left;
862 		while (left > 0) {
863 			mlen = M_TRAILINGSPACE(mp);
864 			if (mlen == 0) {
865 				MGET(mp, M_WAIT, MT_DATA);
866 				if (clflg)
867 					MCLGET(mp, M_WAIT);
868 				mp->m_len = 0;
869 				mp2->m_next = mp;
870 				mp2 = mp;
871 				mlen = M_TRAILINGSPACE(mp);
872 			}
873 			xfer = (left > mlen) ? mlen : left;
874 #ifdef notdef
875 			/* Not Yet.. */
876 			if (uiop->uio_iov->iov_op != NULL)
877 				(*(uiop->uio_iov->iov_op))
878 				(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
879 			else
880 #endif
881 			if (uiop->uio_segflg == UIO_SYSSPACE)
882 				bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
883 			else
884 				copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
885 			mp->m_len += xfer;
886 			left -= xfer;
887 			uiocp += xfer;
888 			uiop->uio_offset += xfer;
889 			uiop->uio_resid -= xfer;
890 		}
891 		uiop->uio_iov->iov_base += uiosiz;
892 		uiop->uio_iov->iov_len -= uiosiz;
893 		siz -= uiosiz;
894 	}
895 	if (rem > 0) {
896 		if (rem > M_TRAILINGSPACE(mp)) {
897 			MGET(mp, M_WAIT, MT_DATA);
898 			mp->m_len = 0;
899 			mp2->m_next = mp;
900 		}
901 		cp = mtod(mp, caddr_t)+mp->m_len;
902 		for (left = 0; left < rem; left++)
903 			*cp++ = '\0';
904 		mp->m_len += rem;
905 		*bpos = cp;
906 	} else
907 		*bpos = mtod(mp, caddr_t)+mp->m_len;
908 	*mq = mp;
909 	return (0);
910 }
911 
912 /*
913  * Get at least "siz" bytes of correctly aligned data.
914  * When called the mbuf pointers are not necessarily correct,
915  * dsosp points to what ought to be in m_data and left contains
916  * what ought to be in m_len.
917  * This is used by the macros nfsm_dissect and nfsm_dissecton for tough
918  * cases. (The macros use the vars. dpos and dpos2)
919  */
920 int
921 nfsm_disct(mdp, dposp, siz, left, cp2)
922 	struct mbuf **mdp;
923 	caddr_t *dposp;
924 	int siz;
925 	int left;
926 	caddr_t *cp2;
927 {
928 	register struct mbuf *m1, *m2;
929 	struct mbuf *havebuf = NULL;
930 	caddr_t src = *dposp;
931 	caddr_t dst;
932 	int len;
933 
934 #ifdef DEBUG
935 	if (left < 0)
936 		panic("nfsm_disct: left < 0");
937 #endif
938 	m1 = *mdp;
939 	/*
940 	 * Skip through the mbuf chain looking for an mbuf with
941 	 * some data. If the first mbuf found has enough data
942 	 * and it is correctly aligned return it.
943 	 */
944 	while (left == 0) {
945 		havebuf = m1;
946 		*mdp = m1 = m1->m_next;
947 		if (m1 == NULL)
948 			return (EBADRPC);
949 		src = mtod(m1, caddr_t);
950 		left = m1->m_len;
951 		/*
952 		 * If we start a new mbuf and it is big enough
953 		 * and correctly aligned just return it, don't
954 		 * do any pull up.
955 		 */
956 		if (left >= siz && nfsm_aligned(src)) {
957 			*cp2 = src;
958 			*dposp = src + siz;
959 			return (0);
960 		}
961 	}
962 	if (m1->m_flags & M_EXT) {
963 		if (havebuf) {
964 			/* If the first mbuf with data has external data
965 			 * and there is a previous empty mbuf use it
966 			 * to move the data into.
967 			 */
968 			m2 = m1;
969 			*mdp = m1 = havebuf;
970 			if (m1->m_flags & M_EXT) {
971 				MEXTREMOVE(m1);
972 			}
973 		} else {
974 			/*
975 			 * If the first mbuf has a external data
976 			 * and there is no previous empty mbuf
977 			 * allocate a new mbuf and move the external
978 			 * data to the new mbuf. Also make the first
979 			 * mbuf look empty.
980 			 */
981 			m2 = m_get(M_WAIT, MT_DATA);
982 			m2->m_ext = m1->m_ext;
983 			m2->m_data = src;
984 			m2->m_len = left;
985 			MCLADDREFERENCE(m1, m2);
986 			MEXTREMOVE(m1);
987 			m2->m_next = m1->m_next;
988 			m1->m_next = m2;
989 		}
990 		m1->m_len = 0;
991 		dst = m1->m_dat;
992 	} else {
993 		/*
994 		 * If the first mbuf has no external data
995 		 * move the data to the front of the mbuf.
996 		 */
997 		if ((dst = m1->m_dat) != src)
998 			ovbcopy(src, dst, left);
999 		dst += left;
1000 		m1->m_len = left;
1001 		m2 = m1->m_next;
1002 	}
1003 	m1->m_flags &= ~M_PKTHDR;
1004 	*cp2 = m1->m_data = m1->m_dat;   /* data is at beginning of buffer */
1005 	*dposp = mtod(m1, caddr_t) + siz;
1006 	/*
1007 	 * Loop through mbufs pulling data up into first mbuf until
1008 	 * the first mbuf is full or there is no more data to
1009 	 * pullup.
1010 	 */
1011 	while ((len = (MLEN - m1->m_len)) != 0 && m2) {
1012 		if ((len = min(len, m2->m_len)) != 0)
1013 			bcopy(m2->m_data, dst, len);
1014 		m1->m_len += len;
1015 		dst += len;
1016 		m2->m_data += len;
1017 		m2->m_len -= len;
1018 		m2 = m2->m_next;
1019 	}
1020 	if (m1->m_len < siz)
1021 		return (EBADRPC);
1022 	return (0);
1023 }
1024 
1025 /*
1026  * Advance the position in the mbuf chain.
1027  */
1028 int
1029 nfs_adv(mdp, dposp, offs, left)
1030 	struct mbuf **mdp;
1031 	caddr_t *dposp;
1032 	int offs;
1033 	int left;
1034 {
1035 	register struct mbuf *m;
1036 	register int s;
1037 
1038 	m = *mdp;
1039 	s = left;
1040 	while (s < offs) {
1041 		offs -= s;
1042 		m = m->m_next;
1043 		if (m == NULL)
1044 			return (EBADRPC);
1045 		s = m->m_len;
1046 	}
1047 	*mdp = m;
1048 	*dposp = mtod(m, caddr_t)+offs;
1049 	return (0);
1050 }
1051 
1052 /*
1053  * Copy a string into mbufs for the hard cases...
1054  */
1055 int
1056 nfsm_strtmbuf(mb, bpos, cp, siz)
1057 	struct mbuf **mb;
1058 	char **bpos;
1059 	const char *cp;
1060 	long siz;
1061 {
1062 	register struct mbuf *m1 = NULL, *m2;
1063 	long left, xfer, len, tlen;
1064 	u_int32_t *tl;
1065 	int putsize;
1066 
1067 	putsize = 1;
1068 	m2 = *mb;
1069 	left = M_TRAILINGSPACE(m2);
1070 	if (left > 0) {
1071 		tl = ((u_int32_t *)(*bpos));
1072 		*tl++ = txdr_unsigned(siz);
1073 		putsize = 0;
1074 		left -= NFSX_UNSIGNED;
1075 		m2->m_len += NFSX_UNSIGNED;
1076 		if (left > 0) {
1077 			bcopy(cp, (caddr_t) tl, left);
1078 			siz -= left;
1079 			cp += left;
1080 			m2->m_len += left;
1081 			left = 0;
1082 		}
1083 	}
1084 	/* Loop around adding mbufs */
1085 	while (siz > 0) {
1086 		MGET(m1, M_WAIT, MT_DATA);
1087 		if (siz > MLEN)
1088 			MCLGET(m1, M_WAIT);
1089 		m1->m_len = NFSMSIZ(m1);
1090 		m2->m_next = m1;
1091 		m2 = m1;
1092 		tl = mtod(m1, u_int32_t *);
1093 		tlen = 0;
1094 		if (putsize) {
1095 			*tl++ = txdr_unsigned(siz);
1096 			m1->m_len -= NFSX_UNSIGNED;
1097 			tlen = NFSX_UNSIGNED;
1098 			putsize = 0;
1099 		}
1100 		if (siz < m1->m_len) {
1101 			len = nfsm_rndup(siz);
1102 			xfer = siz;
1103 			if (xfer < len)
1104 				*(tl+(xfer>>2)) = 0;
1105 		} else {
1106 			xfer = len = m1->m_len;
1107 		}
1108 		bcopy(cp, (caddr_t) tl, xfer);
1109 		m1->m_len = len+tlen;
1110 		siz -= xfer;
1111 		cp += xfer;
1112 	}
1113 	*mb = m1;
1114 	*bpos = mtod(m1, caddr_t)+m1->m_len;
1115 	return (0);
1116 }
1117 
1118 /*
1119  * Called once before VFS init to initialize shared and
1120  * server-specific data structures.
1121  */
1122 void
1123 nfs_init()
1124 {
1125 
1126 #if !defined(alpha) && defined(DIAGNOSTIC)
1127 	/*
1128 	 * Check to see if major data structures haven't bloated.
1129 	 */
1130 	if (sizeof (struct nfsnode) > NFS_NODEALLOC) {
1131 		printf("struct nfsnode bloated (> %dbytes)\n", NFS_NODEALLOC);
1132 		printf("Try reducing NFS_SMALLFH\n");
1133 	}
1134 	if (sizeof (struct nfsmount) > NFS_MNTALLOC) {
1135 		printf("struct nfsmount bloated (> %dbytes)\n", NFS_MNTALLOC);
1136 		printf("Try reducing NFS_MUIDHASHSIZ\n");
1137 	}
1138 	if (sizeof (struct nfssvc_sock) > NFS_SVCALLOC) {
1139 		printf("struct nfssvc_sock bloated (> %dbytes)\n",NFS_SVCALLOC);
1140 		printf("Try reducing NFS_UIDHASHSIZ\n");
1141 	}
1142 	if (sizeof (struct nfsuid) > NFS_UIDALLOC) {
1143 		printf("struct nfsuid bloated (> %dbytes)\n",NFS_UIDALLOC);
1144 		printf("Try unionizing the nu_nickname and nu_flag fields\n");
1145 	}
1146 #endif
1147 
1148 	nfsrtt.pos = 0;
1149 	rpc_vers = txdr_unsigned(RPC_VER2);
1150 	rpc_call = txdr_unsigned(RPC_CALL);
1151 	rpc_reply = txdr_unsigned(RPC_REPLY);
1152 	rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED);
1153 	rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED);
1154 	rpc_mismatch = txdr_unsigned(RPC_MISMATCH);
1155 	rpc_autherr = txdr_unsigned(RPC_AUTHERR);
1156 	rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX);
1157 	rpc_auth_kerb = txdr_unsigned(RPCAUTH_KERB4);
1158 	nfs_prog = txdr_unsigned(NFS_PROG);
1159 	nqnfs_prog = txdr_unsigned(NQNFS_PROG);
1160 	nfs_true = txdr_unsigned(TRUE);
1161 	nfs_false = txdr_unsigned(FALSE);
1162 	nfs_xdrneg1 = txdr_unsigned(-1);
1163 	nfs_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
1164 	if (nfs_ticks < 1)
1165 		nfs_ticks = 1;
1166 #ifdef NFSSERVER
1167 	nfsrv_init(0);			/* Init server data structures */
1168 	nfsrv_initcache();		/* Init the server request cache */
1169 #endif /* NFSSERVER */
1170 
1171 	/*
1172 	 * Initialize the nqnfs data structures.
1173 	 */
1174 	if (nqnfsstarttime == 0) {
1175 		nqnfsstarttime = boottime.tv_sec + nqsrv_maxlease
1176 			+ nqsrv_clockskew + nqsrv_writeslack;
1177 		NQLOADNOVRAM(nqnfsstarttime);
1178 		CIRCLEQ_INIT(&nqtimerhead);
1179 		nqfhhashtbl = hashinit(NQLCHSZ, M_NQLEASE, &nqfhhash);
1180 	}
1181 
1182 	/*
1183 	 * Initialize reply list and start timer
1184 	 */
1185 	TAILQ_INIT(&nfs_reqq);
1186 	nfs_timer(NULL);
1187 }
1188 
1189 #ifdef NFS
1190 /*
1191  * Called once at VFS init to initialize client-specific data structures.
1192  */
1193 void
1194 nfs_vfs_init()
1195 {
1196 	register int i;
1197 
1198 	/* Ensure async daemons disabled */
1199 	for (i = 0; i < NFS_MAXASYNCDAEMON; i++) {
1200 		nfs_iodwant[i] = (struct proc *)0;
1201 		nfs_iodmount[i] = (struct nfsmount *)0;
1202 	}
1203 	nfs_nhinit();			/* Init the nfsnode table */
1204 }
1205 
1206 /*
1207  * Attribute cache routines.
1208  * nfs_loadattrcache() - loads or updates the cache contents from attributes
1209  *	that are on the mbuf list
1210  * nfs_getattrcache() - returns valid attributes if found in cache, returns
1211  *	error otherwise
1212  */
1213 
1214 /*
1215  * Load the attribute cache (that lives in the nfsnode entry) with
1216  * the values on the mbuf list and
1217  * Iff vap not NULL
1218  *    copy the attributes to *vaper
1219  */
1220 int
1221 nfs_loadattrcache(vpp, mdp, dposp, vaper)
1222 	struct vnode **vpp;
1223 	struct mbuf **mdp;
1224 	caddr_t *dposp;
1225 	struct vattr *vaper;
1226 {
1227 	register struct vnode *vp = *vpp;
1228 	register struct vattr *vap;
1229 	register struct nfs_fattr *fp;
1230 	extern int (**spec_nfsv2nodeop_p) __P((void *));
1231 	register struct nfsnode *np;
1232 	register int32_t t1;
1233 	caddr_t cp2;
1234 	int error = 0;
1235 	int32_t rdev;
1236 	struct mbuf *md;
1237 	enum vtype vtyp;
1238 	u_short vmode;
1239 	struct timespec mtime;
1240 	struct vnode *nvp;
1241 	int v3 = NFS_ISV3(vp);
1242 
1243 	md = *mdp;
1244 	t1 = (mtod(md, caddr_t) + md->m_len) - *dposp;
1245 	error = nfsm_disct(mdp, dposp, NFSX_FATTR(v3), t1, &cp2);
1246 	if (error)
1247 		return (error);
1248 	fp = (struct nfs_fattr *)cp2;
1249 	if (v3) {
1250 		vtyp = nfsv3tov_type(fp->fa_type);
1251 		vmode = fxdr_unsigned(u_short, fp->fa_mode);
1252 		rdev = makedev(fxdr_unsigned(u_char, fp->fa3_rdev.specdata1),
1253 			fxdr_unsigned(u_char, fp->fa3_rdev.specdata2));
1254 		fxdr_nfsv3time(&fp->fa3_mtime, &mtime);
1255 	} else {
1256 		vtyp = nfsv2tov_type(fp->fa_type);
1257 		vmode = fxdr_unsigned(u_short, fp->fa_mode);
1258 		if (vtyp == VNON || vtyp == VREG)
1259 			vtyp = IFTOVT(vmode);
1260 		rdev = fxdr_unsigned(int32_t, fp->fa2_rdev);
1261 		fxdr_nfsv2time(&fp->fa2_mtime, &mtime);
1262 
1263 		/*
1264 		 * Really ugly NFSv2 kludge.
1265 		 */
1266 		if (vtyp == VCHR && rdev == 0xffffffff)
1267 			vtyp = VFIFO;
1268 	}
1269 
1270 	/*
1271 	 * If v_type == VNON it is a new node, so fill in the v_type,
1272 	 * n_mtime fields. Check to see if it represents a special
1273 	 * device, and if so, check for a possible alias. Once the
1274 	 * correct vnode has been obtained, fill in the rest of the
1275 	 * information.
1276 	 */
1277 	np = VTONFS(vp);
1278 	if (vp->v_type != vtyp) {
1279 		vp->v_type = vtyp;
1280 		if (vp->v_type == VFIFO) {
1281 #ifndef FIFO
1282 			return (EOPNOTSUPP);
1283 #else
1284 			extern int (**fifo_nfsv2nodeop_p) __P((void *));
1285 			vp->v_op = fifo_nfsv2nodeop_p;
1286 #endif /* FIFO */
1287 		}
1288 		if (vp->v_type == VCHR || vp->v_type == VBLK) {
1289 			vp->v_op = spec_nfsv2nodeop_p;
1290 			nvp = checkalias(vp, (dev_t)rdev, vp->v_mount);
1291 			if (nvp) {
1292 				/*
1293 				 * Discard unneeded vnode, but save its nfsnode.
1294 				 * Since the nfsnode does not have a lock, its
1295 				 * vnode lock has to be carried over.
1296 				 */
1297 #ifdef Lite2_integrated
1298 				nvp->v_vnlock = vp->v_vnlock;
1299 				vp->v_vnlock = NULL;
1300 #endif
1301 				nvp->v_data = vp->v_data;
1302 				vp->v_data = NULL;
1303 				vp->v_op = spec_vnodeop_p;
1304 				vrele(vp);
1305 				vgone(vp);
1306 				/*
1307 				 * Reinitialize aliased node.
1308 				 */
1309 				np->n_vnode = nvp;
1310 				*vpp = vp = nvp;
1311 			}
1312 		}
1313 		np->n_mtime = mtime.tv_sec;
1314 	}
1315 	vap = &np->n_vattr;
1316 	vap->va_type = vtyp;
1317 	vap->va_mode = (vmode & 07777);
1318 	vap->va_rdev = (dev_t)rdev;
1319 	vap->va_mtime = mtime;
1320 	vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
1321 	if (v3) {
1322 		vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
1323 		vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid);
1324 		vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid);
1325 		fxdr_hyper(&fp->fa3_size, &vap->va_size);
1326 		vap->va_blocksize = NFS_FABLKSIZE;
1327 		fxdr_hyper(&fp->fa3_used, &vap->va_bytes);
1328 		vap->va_fileid = fxdr_unsigned(int32_t,
1329 		    fp->fa3_fileid.nfsuquad[1]);
1330 		fxdr_nfsv3time(&fp->fa3_atime, &vap->va_atime);
1331 		fxdr_nfsv3time(&fp->fa3_ctime, &vap->va_ctime);
1332 		vap->va_flags = 0;
1333 		vap->va_filerev = 0;
1334 	} else {
1335 		vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
1336 		vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid);
1337 		vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid);
1338 		vap->va_size = fxdr_unsigned(u_int32_t, fp->fa2_size);
1339 		vap->va_blocksize = fxdr_unsigned(int32_t, fp->fa2_blocksize);
1340 		vap->va_bytes = fxdr_unsigned(int32_t, fp->fa2_blocks)
1341 		    * NFS_FABLKSIZE;
1342 		vap->va_fileid = fxdr_unsigned(int32_t, fp->fa2_fileid);
1343 		fxdr_nfsv2time(&fp->fa2_atime, &vap->va_atime);
1344 		vap->va_flags = 0;
1345 		vap->va_ctime.tv_sec = fxdr_unsigned(u_int32_t,
1346 		    fp->fa2_ctime.nfsv2_sec);
1347 		vap->va_ctime.tv_nsec = 0;
1348 		vap->va_gen = fxdr_unsigned(u_int32_t,fp->fa2_ctime.nfsv2_usec);
1349 		vap->va_filerev = 0;
1350 	}
1351 	if (vap->va_size != np->n_size) {
1352 		if (vap->va_type == VREG) {
1353 			if (np->n_flag & NMODIFIED) {
1354 				if (vap->va_size < np->n_size)
1355 					vap->va_size = np->n_size;
1356 				else
1357 					np->n_size = vap->va_size;
1358 			} else
1359 				np->n_size = vap->va_size;
1360 			vnode_pager_setsize(vp, (u_long)np->n_size);
1361 		} else
1362 			np->n_size = vap->va_size;
1363 	}
1364 	np->n_attrstamp = time.tv_sec;
1365 	if (vaper != NULL) {
1366 		bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap));
1367 		if (np->n_flag & NCHG) {
1368 			if (np->n_flag & NACC)
1369 				vaper->va_atime = np->n_atim;
1370 			if (np->n_flag & NUPD)
1371 				vaper->va_mtime = np->n_mtim;
1372 		}
1373 	}
1374 	return (0);
1375 }
1376 
1377 /*
1378  * Check the time stamp
1379  * If the cache is valid, copy contents to *vap and return 0
1380  * otherwise return an error
1381  */
1382 int
1383 nfs_getattrcache(vp, vaper)
1384 	register struct vnode *vp;
1385 	struct vattr *vaper;
1386 {
1387 	register struct nfsnode *np = VTONFS(vp);
1388 	register struct vattr *vap;
1389 
1390 	if ((time.tv_sec - np->n_attrstamp) >= NFS_ATTRTIMEO(np)) {
1391 		nfsstats.attrcache_misses++;
1392 		return (ENOENT);
1393 	}
1394 	nfsstats.attrcache_hits++;
1395 	vap = &np->n_vattr;
1396 	if (vap->va_size != np->n_size) {
1397 		if (vap->va_type == VREG) {
1398 			if (np->n_flag & NMODIFIED) {
1399 				if (vap->va_size < np->n_size)
1400 					vap->va_size = np->n_size;
1401 				else
1402 					np->n_size = vap->va_size;
1403 			} else
1404 				np->n_size = vap->va_size;
1405 			vnode_pager_setsize(vp, (u_long)np->n_size);
1406 		} else
1407 			np->n_size = vap->va_size;
1408 	}
1409 	bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(struct vattr));
1410 	if (np->n_flag & NCHG) {
1411 		if (np->n_flag & NACC)
1412 			vaper->va_atime = np->n_atim;
1413 		if (np->n_flag & NUPD)
1414 			vaper->va_mtime = np->n_mtim;
1415 	}
1416 	return (0);
1417 }
1418 #endif /* NFS */
1419 
1420 /*
1421  * Set up nameidata for a lookup() call and do it
1422  */
1423 int
1424 nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, retdirp, p, kerbflag)
1425 	register struct nameidata *ndp;
1426 	fhandle_t *fhp;
1427 	int len;
1428 	struct nfssvc_sock *slp;
1429 	struct mbuf *nam;
1430 	struct mbuf **mdp;
1431 	caddr_t *dposp;
1432 	struct vnode **retdirp;
1433 	struct proc *p;
1434 	int kerbflag;
1435 {
1436 	register int i, rem;
1437 	register struct mbuf *md;
1438 	register char *fromcp, *tocp;
1439 	struct vnode *dp;
1440 	int error, rdonly;
1441 	struct componentname *cnp = &ndp->ni_cnd;
1442 
1443 	*retdirp = (struct vnode *)0;
1444 	MALLOC(cnp->cn_pnbuf, char *, len + 1, M_NAMEI, M_WAITOK);
1445 	/*
1446 	 * Copy the name from the mbuf list to ndp->ni_pnbuf
1447 	 * and set the various ndp fields appropriately.
1448 	 */
1449 	fromcp = *dposp;
1450 	tocp = cnp->cn_pnbuf;
1451 	md = *mdp;
1452 	rem = mtod(md, caddr_t) + md->m_len - fromcp;
1453 	for (i = 0; i < len; i++) {
1454 		while (rem == 0) {
1455 			md = md->m_next;
1456 			if (md == NULL) {
1457 				error = EBADRPC;
1458 				goto out;
1459 			}
1460 			fromcp = mtod(md, caddr_t);
1461 			rem = md->m_len;
1462 		}
1463 		if (*fromcp == '\0' || *fromcp == '/') {
1464 			error = EACCES;
1465 			goto out;
1466 		}
1467 		*tocp++ = *fromcp++;
1468 		rem--;
1469 	}
1470 	*tocp = '\0';
1471 	*mdp = md;
1472 	*dposp = fromcp;
1473 	len = nfsm_rndup(len)-len;
1474 	if (len > 0) {
1475 		if (rem >= len)
1476 			*dposp += len;
1477 		else if ((error = nfs_adv(mdp, dposp, len, rem)) != 0)
1478 			goto out;
1479 	}
1480 	ndp->ni_pathlen = tocp - cnp->cn_pnbuf;
1481 	cnp->cn_nameptr = cnp->cn_pnbuf;
1482 	/*
1483 	 * Extract and set starting directory.
1484 	 */
1485 	error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp,
1486 	    nam, &rdonly, kerbflag);
1487 	if (error)
1488 		goto out;
1489 	if (dp->v_type != VDIR) {
1490 		vrele(dp);
1491 		error = ENOTDIR;
1492 		goto out;
1493 	}
1494 	VREF(dp);
1495 	*retdirp = dp;
1496 	ndp->ni_startdir = dp;
1497 	if (rdonly)
1498 		cnp->cn_flags |= (NOCROSSMOUNT | RDONLY);
1499 	else
1500 		cnp->cn_flags |= NOCROSSMOUNT;
1501 	/*
1502 	 * And call lookup() to do the real work
1503 	 */
1504 	cnp->cn_proc = p;
1505 	error = lookup(ndp);
1506 	if (error)
1507 		goto out;
1508 	/*
1509 	 * Check for encountering a symbolic link
1510 	 */
1511 	if (cnp->cn_flags & ISSYMLINK) {
1512 		if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1)
1513 			vput(ndp->ni_dvp);
1514 		else
1515 			vrele(ndp->ni_dvp);
1516 		vput(ndp->ni_vp);
1517 		ndp->ni_vp = NULL;
1518 		error = EINVAL;
1519 		goto out;
1520 	}
1521 	/*
1522 	 * Check for saved name request
1523 	 */
1524 	if (cnp->cn_flags & (SAVENAME | SAVESTART)) {
1525 		cnp->cn_flags |= HASBUF;
1526 		return (0);
1527 	}
1528 out:
1529 	FREE(cnp->cn_pnbuf, M_NAMEI);
1530 	return (error);
1531 }
1532 
1533 /*
1534  * A fiddled version of m_adj() that ensures null fill to a long
1535  * boundary and only trims off the back end
1536  */
1537 void
1538 nfsm_adj(mp, len, nul)
1539 	struct mbuf *mp;
1540 	register int len;
1541 	int nul;
1542 {
1543 	register struct mbuf *m;
1544 	register int count, i;
1545 	register char *cp;
1546 
1547 	/*
1548 	 * Trim from tail.  Scan the mbuf chain,
1549 	 * calculating its length and finding the last mbuf.
1550 	 * If the adjustment only affects this mbuf, then just
1551 	 * adjust and return.  Otherwise, rescan and truncate
1552 	 * after the remaining size.
1553 	 */
1554 	count = 0;
1555 	m = mp;
1556 	for (;;) {
1557 		count += m->m_len;
1558 		if (m->m_next == (struct mbuf *)0)
1559 			break;
1560 		m = m->m_next;
1561 	}
1562 	if (m->m_len > len) {
1563 		m->m_len -= len;
1564 		if (nul > 0) {
1565 			cp = mtod(m, caddr_t)+m->m_len-nul;
1566 			for (i = 0; i < nul; i++)
1567 				*cp++ = '\0';
1568 		}
1569 		return;
1570 	}
1571 	count -= len;
1572 	if (count < 0)
1573 		count = 0;
1574 	/*
1575 	 * Correct length for chain is "count".
1576 	 * Find the mbuf with last data, adjust its length,
1577 	 * and toss data from remaining mbufs on chain.
1578 	 */
1579 	for (m = mp; m; m = m->m_next) {
1580 		if (m->m_len >= count) {
1581 			m->m_len = count;
1582 			if (nul > 0) {
1583 				cp = mtod(m, caddr_t)+m->m_len-nul;
1584 				for (i = 0; i < nul; i++)
1585 					*cp++ = '\0';
1586 			}
1587 			break;
1588 		}
1589 		count -= m->m_len;
1590 	}
1591 	for (m = m->m_next;m;m = m->m_next)
1592 		m->m_len = 0;
1593 }
1594 
1595 /*
1596  * Make these functions instead of macros, so that the kernel text size
1597  * doesn't get too big...
1598  */
1599 void
1600 nfsm_srvwcc(nfsd, before_ret, before_vap, after_ret, after_vap, mbp, bposp)
1601 	struct nfsrv_descript *nfsd;
1602 	int before_ret;
1603 	register struct vattr *before_vap;
1604 	int after_ret;
1605 	struct vattr *after_vap;
1606 	struct mbuf **mbp;
1607 	char **bposp;
1608 {
1609 	register struct mbuf *mb = *mbp, *mb2;
1610 	register char *bpos = *bposp;
1611 	register u_int32_t *tl;
1612 
1613 	if (before_ret) {
1614 		nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
1615 		*tl = nfs_false;
1616 	} else {
1617 		nfsm_build(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
1618 		*tl++ = nfs_true;
1619 		txdr_hyper(&(before_vap->va_size), tl);
1620 		tl += 2;
1621 		txdr_nfsv3time(&(before_vap->va_mtime), tl);
1622 		tl += 2;
1623 		txdr_nfsv3time(&(before_vap->va_ctime), tl);
1624 	}
1625 	*bposp = bpos;
1626 	*mbp = mb;
1627 	nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp);
1628 }
1629 
1630 void
1631 nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp)
1632 	struct nfsrv_descript *nfsd;
1633 	int after_ret;
1634 	struct vattr *after_vap;
1635 	struct mbuf **mbp;
1636 	char **bposp;
1637 {
1638 	register struct mbuf *mb = *mbp, *mb2;
1639 	register char *bpos = *bposp;
1640 	register u_int32_t *tl;
1641 	register struct nfs_fattr *fp;
1642 
1643 	if (after_ret) {
1644 		nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
1645 		*tl = nfs_false;
1646 	} else {
1647 		nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_V3FATTR);
1648 		*tl++ = nfs_true;
1649 		fp = (struct nfs_fattr *)tl;
1650 		nfsm_srvfattr(nfsd, after_vap, fp);
1651 	}
1652 	*mbp = mb;
1653 	*bposp = bpos;
1654 }
1655 
1656 void
1657 nfsm_srvfattr(nfsd, vap, fp)
1658 	register struct nfsrv_descript *nfsd;
1659 	register struct vattr *vap;
1660 	register struct nfs_fattr *fp;
1661 {
1662 
1663 	fp->fa_nlink = txdr_unsigned(vap->va_nlink);
1664 	fp->fa_uid = txdr_unsigned(vap->va_uid);
1665 	fp->fa_gid = txdr_unsigned(vap->va_gid);
1666 	if (nfsd->nd_flag & ND_NFSV3) {
1667 		fp->fa_type = vtonfsv3_type(vap->va_type);
1668 		fp->fa_mode = vtonfsv3_mode(vap->va_mode);
1669 		txdr_hyper(&vap->va_size, &fp->fa3_size);
1670 		txdr_hyper(&vap->va_bytes, &fp->fa3_used);
1671 		fp->fa3_rdev.specdata1 = txdr_unsigned(major(vap->va_rdev));
1672 		fp->fa3_rdev.specdata2 = txdr_unsigned(minor(vap->va_rdev));
1673 		fp->fa3_fsid.nfsuquad[0] = 0;
1674 		fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid);
1675 		fp->fa3_fileid.nfsuquad[0] = 0;
1676 		fp->fa3_fileid.nfsuquad[1] = txdr_unsigned(vap->va_fileid);
1677 		txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime);
1678 		txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime);
1679 		txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime);
1680 	} else {
1681 		fp->fa_type = vtonfsv2_type(vap->va_type);
1682 		fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
1683 		fp->fa2_size = txdr_unsigned(vap->va_size);
1684 		fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize);
1685 		if (vap->va_type == VFIFO)
1686 			fp->fa2_rdev = 0xffffffff;
1687 		else
1688 			fp->fa2_rdev = txdr_unsigned(vap->va_rdev);
1689 		fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE);
1690 		fp->fa2_fsid = txdr_unsigned(vap->va_fsid);
1691 		fp->fa2_fileid = txdr_unsigned(vap->va_fileid);
1692 		txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime);
1693 		txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime);
1694 		txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime);
1695 	}
1696 }
1697 
1698 /*
1699  * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked)
1700  * 	- look up fsid in mount list (if not found ret error)
1701  *	- get vp and export rights by calling VFS_FHTOVP()
1702  *	- if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon
1703  *	- if not lockflag unlock it with VOP_UNLOCK()
1704  */
1705 int
1706 nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp, kerbflag)
1707 	fhandle_t *fhp;
1708 	int lockflag;
1709 	struct vnode **vpp;
1710 	struct ucred *cred;
1711 	struct nfssvc_sock *slp;
1712 	struct mbuf *nam;
1713 	int *rdonlyp;
1714 	int kerbflag;
1715 {
1716 #ifdef Lite2_integrated
1717 	struct proc *p = curproc;	/* XXX */
1718 #endif
1719 	register struct mount *mp;
1720 	register int i;
1721 	struct ucred *credanon;
1722 	int error, exflags;
1723 	struct sockaddr_in *saddr;
1724 
1725 	*vpp = (struct vnode *)0;
1726 #ifdef Lite2_integrated
1727 	mp = vfs_getvfs(&fhp->fh_fsid);
1728 #else
1729 	mp = getvfs(&fhp->fh_fsid);
1730 #endif
1731 	if (!mp)
1732 		return (ESTALE);
1733 	error = VFS_FHTOVP(mp, &fhp->fh_fid, nam, vpp, &exflags, &credanon);
1734 	if (error)
1735 		return (error);
1736 
1737 	if (!(exflags & MNT_EXNORESPORT)) {
1738 		saddr = mtod(nam, struct sockaddr_in *);
1739 		if (saddr->sin_family == AF_INET &&
1740 		    ntohs(saddr->sin_port) >= IPPORT_RESERVED) {
1741 			vput(*vpp);
1742 			return (NFSERR_AUTHERR | AUTH_TOOWEAK);
1743 		}
1744 	}
1745 	/*
1746 	 * Check/setup credentials.
1747 	 */
1748 	if (exflags & MNT_EXKERB) {
1749 		if (!kerbflag) {
1750 			vput(*vpp);
1751 			return (NFSERR_AUTHERR | AUTH_TOOWEAK);
1752 		}
1753 	} else if (kerbflag) {
1754 		vput(*vpp);
1755 		return (NFSERR_AUTHERR | AUTH_TOOWEAK);
1756 	} else if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) {
1757 		cred->cr_uid = credanon->cr_uid;
1758 		cred->cr_gid = credanon->cr_gid;
1759 		for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++)
1760 			cred->cr_groups[i] = credanon->cr_groups[i];
1761 		cred->cr_ngroups = i;
1762 	}
1763 	if (exflags & MNT_EXRDONLY)
1764 		*rdonlyp = 1;
1765 	else
1766 		*rdonlyp = 0;
1767 	if (!lockflag)
1768 #ifdef Lite2_integrated
1769 		VOP_UNLOCK(*vpp, 0, p);
1770 #else
1771 		VOP_UNLOCK(*vpp);
1772 #endif
1773 	return (0);
1774 }
1775 
1776 /*
1777  * This function compares two net addresses by family and returns TRUE
1778  * if they are the same host.
1779  * If there is any doubt, return FALSE.
1780  * The AF_INET family is handled as a special case so that address mbufs
1781  * don't need to be saved to store "struct in_addr", which is only 4 bytes.
1782  */
1783 int
1784 netaddr_match(family, haddr, nam)
1785 	int family;
1786 	union nethostaddr *haddr;
1787 	struct mbuf *nam;
1788 {
1789 	register struct sockaddr_in *inetaddr;
1790 
1791 	switch (family) {
1792 	case AF_INET:
1793 		inetaddr = mtod(nam, struct sockaddr_in *);
1794 		if (inetaddr->sin_family == AF_INET &&
1795 		    inetaddr->sin_addr.s_addr == haddr->had_inetaddr)
1796 			return (1);
1797 		break;
1798 #ifdef ISO
1799 	case AF_ISO:
1800 	    {
1801 		register struct sockaddr_iso *isoaddr1, *isoaddr2;
1802 
1803 		isoaddr1 = mtod(nam, struct sockaddr_iso *);
1804 		isoaddr2 = mtod(haddr->had_nam, struct sockaddr_iso *);
1805 		if (isoaddr1->siso_family == AF_ISO &&
1806 		    isoaddr1->siso_nlen > 0 &&
1807 		    isoaddr1->siso_nlen == isoaddr2->siso_nlen &&
1808 		    SAME_ISOADDR(isoaddr1, isoaddr2))
1809 			return (1);
1810 		break;
1811 	    }
1812 #endif	/* ISO */
1813 	default:
1814 		break;
1815 	};
1816 	return (0);
1817 }
1818 
1819 static nfsuint64 nfs_nullcookie = {{ 0, 0 }};
1820 /*
1821  * This function finds the directory cookie that corresponds to the
1822  * logical byte offset given.
1823  */
1824 nfsuint64 *
1825 nfs_getcookie(np, off, add)
1826 	register struct nfsnode *np;
1827 	off_t off;
1828 	int add;
1829 {
1830 	register struct nfsdmap *dp, *dp2;
1831 	register int pos;
1832 
1833 	pos = off / NFS_DIRBLKSIZ;
1834 	if (pos == 0) {
1835 #ifdef DIAGNOSTIC
1836 		if (add)
1837 			panic("nfs getcookie add at 0");
1838 #endif
1839 		return (&nfs_nullcookie);
1840 	}
1841 	pos--;
1842 	dp = np->n_cookies.lh_first;
1843 	if (!dp) {
1844 		if (add) {
1845 			MALLOC(dp, struct nfsdmap *, sizeof (struct nfsdmap),
1846 				M_NFSDIROFF, M_WAITOK);
1847 			dp->ndm_eocookie = 0;
1848 			LIST_INSERT_HEAD(&np->n_cookies, dp, ndm_list);
1849 		} else
1850 			return ((nfsuint64 *)0);
1851 	}
1852 	while (pos >= NFSNUMCOOKIES) {
1853 		pos -= NFSNUMCOOKIES;
1854 		if (dp->ndm_list.le_next) {
1855 			if (!add && dp->ndm_eocookie < NFSNUMCOOKIES &&
1856 				pos >= dp->ndm_eocookie)
1857 				return ((nfsuint64 *)0);
1858 			dp = dp->ndm_list.le_next;
1859 		} else if (add) {
1860 			MALLOC(dp2, struct nfsdmap *, sizeof (struct nfsdmap),
1861 				M_NFSDIROFF, M_WAITOK);
1862 			dp2->ndm_eocookie = 0;
1863 			LIST_INSERT_AFTER(dp, dp2, ndm_list);
1864 			dp = dp2;
1865 		} else
1866 			return ((nfsuint64 *)0);
1867 	}
1868 	if (pos >= dp->ndm_eocookie) {
1869 		if (add)
1870 			dp->ndm_eocookie = pos + 1;
1871 		else
1872 			return ((nfsuint64 *)0);
1873 	}
1874 	return (&dp->ndm_cookies[pos]);
1875 }
1876 
1877 /*
1878  * Invalidate cached directory information, except for the actual directory
1879  * blocks (which are invalidated separately).
1880  * Done mainly to avoid the use of stale offset cookies.
1881  */
1882 void
1883 nfs_invaldir(vp)
1884 	register struct vnode *vp;
1885 {
1886 #ifdef notdef /* XXX */
1887 	register struct nfsnode *np = VTONFS(vp);
1888 
1889 #ifdef DIAGNOSTIC
1890 	if (vp->v_type != VDIR)
1891 		panic("nfs: invaldir not dir");
1892 #endif
1893 	np->n_direofoffset = 0;
1894 	np->n_cookieverf.nfsuquad[0] = 0;
1895 	np->n_cookieverf.nfsuquad[1] = 0;
1896 	if (np->n_cookies.lh_first)
1897 		np->n_cookies.lh_first->ndm_eocookie = 0;
1898 #endif
1899 }
1900 
1901 /*
1902  * The write verifier has changed (probably due to a server reboot), so all
1903  * B_NEEDCOMMIT blocks will have to be written again. Since they are on the
1904  * dirty block list as B_DELWRI, all this takes is clearing the B_NEEDCOMMIT
1905  * flag. Once done the new write verifier can be set for the mount point.
1906  */
1907 void
1908 nfs_clearcommit(mp)
1909 	struct mount *mp;
1910 {
1911 	register struct vnode *vp, *nvp;
1912 	register struct buf *bp, *nbp;
1913 	int s;
1914 
1915 	s = splbio();
1916 loop:
1917 	for (vp = mp->mnt_vnodelist.lh_first; vp; vp = nvp) {
1918 		if (vp->v_mount != mp)	/* Paranoia */
1919 			goto loop;
1920 		nvp = vp->v_mntvnodes.le_next;
1921 		for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) {
1922 			nbp = bp->b_vnbufs.le_next;
1923 			if ((bp->b_flags & (B_BUSY | B_DELWRI | B_NEEDCOMMIT))
1924 				== (B_DELWRI | B_NEEDCOMMIT))
1925 				bp->b_flags &= ~B_NEEDCOMMIT;
1926 		}
1927 	}
1928 	splx(s);
1929 }
1930 
1931 /*
1932  * Map errnos to NFS error numbers. For Version 3 also filter out error
1933  * numbers not specified for the associated procedure.
1934  */
1935 int
1936 nfsrv_errmap(nd, err)
1937 	struct nfsrv_descript *nd;
1938 	register int err;
1939 {
1940 	register short *defaulterrp, *errp;
1941 
1942 	if (nd->nd_flag & ND_NFSV3) {
1943 	    if (nd->nd_procnum <= NFSPROC_COMMIT) {
1944 		errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum];
1945 		while (*++errp) {
1946 			if (*errp == err)
1947 				return (err);
1948 			else if (*errp > err)
1949 				break;
1950 		}
1951 		return ((int)*defaulterrp);
1952 	    } else
1953 		return (err & 0xffff);
1954 	}
1955 	if (err <= ELAST)
1956 		return ((int)nfsrv_v2errmap[err - 1]);
1957 	return (NFSERR_IO);
1958 }
1959 
1960 /*
1961  * Sort the group list in increasing numerical order.
1962  * (Insertion sort by Chris Torek, who was grossed out by the bubble sort
1963  *  that used to be here.)
1964  */
1965 void
1966 nfsrvw_sort(list, num)
1967         register gid_t *list;
1968         register int num;
1969 {
1970 	register int i, j;
1971 	gid_t v;
1972 
1973 	/* Insertion sort. */
1974 	for (i = 1; i < num; i++) {
1975 		v = list[i];
1976 		/* find correct slot for value v, moving others up */
1977 		for (j = i; --j >= 0 && v < list[j];)
1978 			list[j + 1] = list[j];
1979 		list[j + 1] = v;
1980 	}
1981 }
1982 
1983 /*
1984  * copy credentials making sure that the result can be compared with bcmp().
1985  */
1986 void
1987 nfsrv_setcred(incred, outcred)
1988 	register struct ucred *incred, *outcred;
1989 {
1990 	register int i;
1991 
1992 	bzero((caddr_t)outcred, sizeof (struct ucred));
1993 	outcred->cr_ref = 1;
1994 	outcred->cr_uid = incred->cr_uid;
1995 	outcred->cr_gid = incred->cr_gid;
1996 	outcred->cr_ngroups = incred->cr_ngroups;
1997 	for (i = 0; i < incred->cr_ngroups; i++)
1998 		outcred->cr_groups[i] = incred->cr_groups[i];
1999 	nfsrvw_sort(outcred->cr_groups, outcred->cr_ngroups);
2000 }
2001