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