1/*	$NetBSD: nfs_subs.c,v 1.221 2011/06/12 03:35:59 rmind 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. Neither the name of the University nor the names of its contributors
19 *    may be used to endorse or promote products derived from this software
20 *    without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 *
34 *	@(#)nfs_subs.c	8.8 (Berkeley) 5/22/95
35 */
36
37/*
38 * Copyright 2000 Wasabi Systems, Inc.
39 * All rights reserved.
40 *
41 * Written by Frank van der Linden for Wasabi Systems, Inc.
42 *
43 * Redistribution and use in source and binary forms, with or without
44 * modification, are permitted provided that the following conditions
45 * are met:
46 * 1. Redistributions of source code must retain the above copyright
47 *    notice, this list of conditions and the following disclaimer.
48 * 2. Redistributions in binary form must reproduce the above copyright
49 *    notice, this list of conditions and the following disclaimer in the
50 *    documentation and/or other materials provided with the distribution.
51 * 3. All advertising materials mentioning features or use of this software
52 *    must display the following acknowledgement:
53 *      This product includes software developed for the NetBSD Project by
54 *      Wasabi Systems, Inc.
55 * 4. The name of Wasabi Systems, Inc. may not be used to endorse
56 *    or promote products derived from this software without specific prior
57 *    written permission.
58 *
59 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
60 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
61 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
62 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
63 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
64 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
65 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
66 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
67 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
68 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
69 * POSSIBILITY OF SUCH DAMAGE.
70 */
71
72#include <sys/cdefs.h>
73__KERNEL_RCSID(0, "$NetBSD: nfs_subs.c,v 1.221 2011/06/12 03:35:59 rmind Exp $");
74
75#ifdef _KERNEL_OPT
76#include "opt_nfs.h"
77#endif
78
79/*
80 * These functions support the macros and help fiddle mbuf chains for
81 * the nfs op functions. They do things like create the rpc header and
82 * copy data between mbuf chains and uio lists.
83 */
84#include <sys/param.h>
85#include <sys/proc.h>
86#include <sys/systm.h>
87#include <sys/kernel.h>
88#include <sys/kmem.h>
89#include <sys/mount.h>
90#include <sys/vnode.h>
91#include <sys/namei.h>
92#include <sys/mbuf.h>
93#include <sys/socket.h>
94#include <sys/stat.h>
95#include <sys/filedesc.h>
96#include <sys/time.h>
97#include <sys/dirent.h>
98#include <sys/once.h>
99#include <sys/kauth.h>
100#include <sys/atomic.h>
101#include <sys/cprng.h>
102
103#include <uvm/uvm.h>
104
105#include <nfs/rpcv2.h>
106#include <nfs/nfsproto.h>
107#include <nfs/nfsnode.h>
108#include <nfs/nfs.h>
109#include <nfs/xdr_subs.h>
110#include <nfs/nfsm_subs.h>
111#include <nfs/nfsmount.h>
112#include <nfs/nfsrtt.h>
113#include <nfs/nfs_var.h>
114
115#include <miscfs/specfs/specdev.h>
116
117#include <netinet/in.h>
118
119static u_int32_t nfs_xid;
120
121int nuidhash_max = NFS_MAXUIDHASH;
122/*
123 * Data items converted to xdr at startup, since they are constant
124 * This is kinda hokey, but may save a little time doing byte swaps
125 */
126u_int32_t nfs_xdrneg1;
127u_int32_t rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr,
128	rpc_mismatch, rpc_auth_unix, rpc_msgaccepted,
129	rpc_auth_kerb;
130u_int32_t nfs_prog, nfs_true, nfs_false;
131
132/* And other global data */
133const nfstype nfsv2_type[9] =
134	{ NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFNON, NFCHR, NFNON };
135const nfstype nfsv3_type[9] =
136	{ NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK, NFFIFO, NFNON };
137const enum vtype nv2tov_type[8] =
138	{ VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON };
139const enum vtype nv3tov_type[8] =
140	{ VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO };
141int nfs_ticks;
142
143/* NFS client/server stats. */
144struct nfsstats nfsstats;
145
146/*
147 * Mapping of old NFS Version 2 RPC numbers to generic numbers.
148 */
149const int nfsv3_procid[NFS_NPROCS] = {
150	NFSPROC_NULL,
151	NFSPROC_GETATTR,
152	NFSPROC_SETATTR,
153	NFSPROC_NOOP,
154	NFSPROC_LOOKUP,
155	NFSPROC_READLINK,
156	NFSPROC_READ,
157	NFSPROC_NOOP,
158	NFSPROC_WRITE,
159	NFSPROC_CREATE,
160	NFSPROC_REMOVE,
161	NFSPROC_RENAME,
162	NFSPROC_LINK,
163	NFSPROC_SYMLINK,
164	NFSPROC_MKDIR,
165	NFSPROC_RMDIR,
166	NFSPROC_READDIR,
167	NFSPROC_FSSTAT,
168	NFSPROC_NOOP,
169	NFSPROC_NOOP,
170	NFSPROC_NOOP,
171	NFSPROC_NOOP,
172	NFSPROC_NOOP
173};
174
175/*
176 * and the reverse mapping from generic to Version 2 procedure numbers
177 */
178const int nfsv2_procid[NFS_NPROCS] = {
179	NFSV2PROC_NULL,
180	NFSV2PROC_GETATTR,
181	NFSV2PROC_SETATTR,
182	NFSV2PROC_LOOKUP,
183	NFSV2PROC_NOOP,
184	NFSV2PROC_READLINK,
185	NFSV2PROC_READ,
186	NFSV2PROC_WRITE,
187	NFSV2PROC_CREATE,
188	NFSV2PROC_MKDIR,
189	NFSV2PROC_SYMLINK,
190	NFSV2PROC_CREATE,
191	NFSV2PROC_REMOVE,
192	NFSV2PROC_RMDIR,
193	NFSV2PROC_RENAME,
194	NFSV2PROC_LINK,
195	NFSV2PROC_READDIR,
196	NFSV2PROC_NOOP,
197	NFSV2PROC_STATFS,
198	NFSV2PROC_NOOP,
199	NFSV2PROC_NOOP,
200	NFSV2PROC_NOOP,
201	NFSV2PROC_NOOP,
202};
203
204/*
205 * Maps errno values to nfs error numbers.
206 * Use NFSERR_IO as the catch all for ones not specifically defined in
207 * RFC 1094.
208 */
209static const u_char nfsrv_v2errmap[ELAST] = {
210  NFSERR_PERM,	NFSERR_NOENT,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
211  NFSERR_NXIO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
212  NFSERR_IO,	NFSERR_IO,	NFSERR_ACCES,	NFSERR_IO,	NFSERR_IO,
213  NFSERR_IO,	NFSERR_EXIST,	NFSERR_IO,	NFSERR_NODEV,	NFSERR_NOTDIR,
214  NFSERR_ISDIR,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
215  NFSERR_IO,	NFSERR_FBIG,	NFSERR_NOSPC,	NFSERR_IO,	NFSERR_ROFS,
216  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
217  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
218  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
219  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
220  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
221  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
222  NFSERR_IO,	NFSERR_IO,	NFSERR_NAMETOL,	NFSERR_IO,	NFSERR_IO,
223  NFSERR_NOTEMPTY, NFSERR_IO,	NFSERR_IO,	NFSERR_DQUOT,	NFSERR_STALE,
224  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
225  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
226  NFSERR_IO,	NFSERR_IO,
227};
228
229/*
230 * Maps errno values to nfs error numbers.
231 * Although it is not obvious whether or not NFS clients really care if
232 * a returned error value is in the specified list for the procedure, the
233 * safest thing to do is filter them appropriately. For Version 2, the
234 * X/Open XNFS document is the only specification that defines error values
235 * for each RPC (The RFC simply lists all possible error values for all RPCs),
236 * so I have decided to not do this for Version 2.
237 * The first entry is the default error return and the rest are the valid
238 * errors for that RPC in increasing numeric order.
239 */
240static const short nfsv3err_null[] = {
241	0,
242	0,
243};
244
245static const short nfsv3err_getattr[] = {
246	NFSERR_IO,
247	NFSERR_IO,
248	NFSERR_STALE,
249	NFSERR_BADHANDLE,
250	NFSERR_SERVERFAULT,
251	0,
252};
253
254static const short nfsv3err_setattr[] = {
255	NFSERR_IO,
256	NFSERR_PERM,
257	NFSERR_IO,
258	NFSERR_ACCES,
259	NFSERR_INVAL,
260	NFSERR_NOSPC,
261	NFSERR_ROFS,
262	NFSERR_DQUOT,
263	NFSERR_STALE,
264	NFSERR_BADHANDLE,
265	NFSERR_NOT_SYNC,
266	NFSERR_SERVERFAULT,
267	0,
268};
269
270static const short nfsv3err_lookup[] = {
271	NFSERR_IO,
272	NFSERR_NOENT,
273	NFSERR_IO,
274	NFSERR_ACCES,
275	NFSERR_NOTDIR,
276	NFSERR_NAMETOL,
277	NFSERR_STALE,
278	NFSERR_BADHANDLE,
279	NFSERR_SERVERFAULT,
280	0,
281};
282
283static const short nfsv3err_access[] = {
284	NFSERR_IO,
285	NFSERR_IO,
286	NFSERR_STALE,
287	NFSERR_BADHANDLE,
288	NFSERR_SERVERFAULT,
289	0,
290};
291
292static const short nfsv3err_readlink[] = {
293	NFSERR_IO,
294	NFSERR_IO,
295	NFSERR_ACCES,
296	NFSERR_INVAL,
297	NFSERR_STALE,
298	NFSERR_BADHANDLE,
299	NFSERR_NOTSUPP,
300	NFSERR_SERVERFAULT,
301	0,
302};
303
304static const short nfsv3err_read[] = {
305	NFSERR_IO,
306	NFSERR_IO,
307	NFSERR_NXIO,
308	NFSERR_ACCES,
309	NFSERR_INVAL,
310	NFSERR_STALE,
311	NFSERR_BADHANDLE,
312	NFSERR_SERVERFAULT,
313	NFSERR_JUKEBOX,
314	0,
315};
316
317static const short nfsv3err_write[] = {
318	NFSERR_IO,
319	NFSERR_IO,
320	NFSERR_ACCES,
321	NFSERR_INVAL,
322	NFSERR_FBIG,
323	NFSERR_NOSPC,
324	NFSERR_ROFS,
325	NFSERR_DQUOT,
326	NFSERR_STALE,
327	NFSERR_BADHANDLE,
328	NFSERR_SERVERFAULT,
329	NFSERR_JUKEBOX,
330	0,
331};
332
333static const short nfsv3err_create[] = {
334	NFSERR_IO,
335	NFSERR_IO,
336	NFSERR_ACCES,
337	NFSERR_EXIST,
338	NFSERR_NOTDIR,
339	NFSERR_NOSPC,
340	NFSERR_ROFS,
341	NFSERR_NAMETOL,
342	NFSERR_DQUOT,
343	NFSERR_STALE,
344	NFSERR_BADHANDLE,
345	NFSERR_NOTSUPP,
346	NFSERR_SERVERFAULT,
347	0,
348};
349
350static const short nfsv3err_mkdir[] = {
351	NFSERR_IO,
352	NFSERR_IO,
353	NFSERR_ACCES,
354	NFSERR_EXIST,
355	NFSERR_NOTDIR,
356	NFSERR_NOSPC,
357	NFSERR_ROFS,
358	NFSERR_NAMETOL,
359	NFSERR_DQUOT,
360	NFSERR_STALE,
361	NFSERR_BADHANDLE,
362	NFSERR_NOTSUPP,
363	NFSERR_SERVERFAULT,
364	0,
365};
366
367static const short nfsv3err_symlink[] = {
368	NFSERR_IO,
369	NFSERR_IO,
370	NFSERR_ACCES,
371	NFSERR_EXIST,
372	NFSERR_NOTDIR,
373	NFSERR_NOSPC,
374	NFSERR_ROFS,
375	NFSERR_NAMETOL,
376	NFSERR_DQUOT,
377	NFSERR_STALE,
378	NFSERR_BADHANDLE,
379	NFSERR_NOTSUPP,
380	NFSERR_SERVERFAULT,
381	0,
382};
383
384static const short nfsv3err_mknod[] = {
385	NFSERR_IO,
386	NFSERR_IO,
387	NFSERR_ACCES,
388	NFSERR_EXIST,
389	NFSERR_NOTDIR,
390	NFSERR_NOSPC,
391	NFSERR_ROFS,
392	NFSERR_NAMETOL,
393	NFSERR_DQUOT,
394	NFSERR_STALE,
395	NFSERR_BADHANDLE,
396	NFSERR_NOTSUPP,
397	NFSERR_SERVERFAULT,
398	NFSERR_BADTYPE,
399	0,
400};
401
402static const short nfsv3err_remove[] = {
403	NFSERR_IO,
404	NFSERR_NOENT,
405	NFSERR_IO,
406	NFSERR_ACCES,
407	NFSERR_NOTDIR,
408	NFSERR_ROFS,
409	NFSERR_NAMETOL,
410	NFSERR_STALE,
411	NFSERR_BADHANDLE,
412	NFSERR_SERVERFAULT,
413	0,
414};
415
416static const short nfsv3err_rmdir[] = {
417	NFSERR_IO,
418	NFSERR_NOENT,
419	NFSERR_IO,
420	NFSERR_ACCES,
421	NFSERR_EXIST,
422	NFSERR_NOTDIR,
423	NFSERR_INVAL,
424	NFSERR_ROFS,
425	NFSERR_NAMETOL,
426	NFSERR_NOTEMPTY,
427	NFSERR_STALE,
428	NFSERR_BADHANDLE,
429	NFSERR_NOTSUPP,
430	NFSERR_SERVERFAULT,
431	0,
432};
433
434static const short nfsv3err_rename[] = {
435	NFSERR_IO,
436	NFSERR_NOENT,
437	NFSERR_IO,
438	NFSERR_ACCES,
439	NFSERR_EXIST,
440	NFSERR_XDEV,
441	NFSERR_NOTDIR,
442	NFSERR_ISDIR,
443	NFSERR_INVAL,
444	NFSERR_NOSPC,
445	NFSERR_ROFS,
446	NFSERR_MLINK,
447	NFSERR_NAMETOL,
448	NFSERR_NOTEMPTY,
449	NFSERR_DQUOT,
450	NFSERR_STALE,
451	NFSERR_BADHANDLE,
452	NFSERR_NOTSUPP,
453	NFSERR_SERVERFAULT,
454	0,
455};
456
457static const short nfsv3err_link[] = {
458	NFSERR_IO,
459	NFSERR_IO,
460	NFSERR_ACCES,
461	NFSERR_EXIST,
462	NFSERR_XDEV,
463	NFSERR_NOTDIR,
464	NFSERR_INVAL,
465	NFSERR_NOSPC,
466	NFSERR_ROFS,
467	NFSERR_MLINK,
468	NFSERR_NAMETOL,
469	NFSERR_DQUOT,
470	NFSERR_STALE,
471	NFSERR_BADHANDLE,
472	NFSERR_NOTSUPP,
473	NFSERR_SERVERFAULT,
474	0,
475};
476
477static const short nfsv3err_readdir[] = {
478	NFSERR_IO,
479	NFSERR_IO,
480	NFSERR_ACCES,
481	NFSERR_NOTDIR,
482	NFSERR_STALE,
483	NFSERR_BADHANDLE,
484	NFSERR_BAD_COOKIE,
485	NFSERR_TOOSMALL,
486	NFSERR_SERVERFAULT,
487	0,
488};
489
490static const short nfsv3err_readdirplus[] = {
491	NFSERR_IO,
492	NFSERR_IO,
493	NFSERR_ACCES,
494	NFSERR_NOTDIR,
495	NFSERR_STALE,
496	NFSERR_BADHANDLE,
497	NFSERR_BAD_COOKIE,
498	NFSERR_NOTSUPP,
499	NFSERR_TOOSMALL,
500	NFSERR_SERVERFAULT,
501	0,
502};
503
504static const short nfsv3err_fsstat[] = {
505	NFSERR_IO,
506	NFSERR_IO,
507	NFSERR_STALE,
508	NFSERR_BADHANDLE,
509	NFSERR_SERVERFAULT,
510	0,
511};
512
513static const short nfsv3err_fsinfo[] = {
514	NFSERR_STALE,
515	NFSERR_STALE,
516	NFSERR_BADHANDLE,
517	NFSERR_SERVERFAULT,
518	0,
519};
520
521static const short nfsv3err_pathconf[] = {
522	NFSERR_STALE,
523	NFSERR_STALE,
524	NFSERR_BADHANDLE,
525	NFSERR_SERVERFAULT,
526	0,
527};
528
529static const short nfsv3err_commit[] = {
530	NFSERR_IO,
531	NFSERR_IO,
532	NFSERR_STALE,
533	NFSERR_BADHANDLE,
534	NFSERR_SERVERFAULT,
535	0,
536};
537
538static const short * const nfsrv_v3errmap[] = {
539	nfsv3err_null,
540	nfsv3err_getattr,
541	nfsv3err_setattr,
542	nfsv3err_lookup,
543	nfsv3err_access,
544	nfsv3err_readlink,
545	nfsv3err_read,
546	nfsv3err_write,
547	nfsv3err_create,
548	nfsv3err_mkdir,
549	nfsv3err_symlink,
550	nfsv3err_mknod,
551	nfsv3err_remove,
552	nfsv3err_rmdir,
553	nfsv3err_rename,
554	nfsv3err_link,
555	nfsv3err_readdir,
556	nfsv3err_readdirplus,
557	nfsv3err_fsstat,
558	nfsv3err_fsinfo,
559	nfsv3err_pathconf,
560	nfsv3err_commit,
561};
562
563extern struct nfsrtt nfsrtt;
564
565u_long nfsdirhashmask;
566
567int nfs_webnamei(struct nameidata *, struct vnode *, struct proc *);
568
569/*
570 * Create the header for an rpc request packet
571 * The hsiz is the size of the rest of the nfs request header.
572 * (just used to decide if a cluster is a good idea)
573 */
574struct mbuf *
575nfsm_reqh(struct nfsnode *np, u_long procid, int hsiz, char **bposp)
576{
577	struct mbuf *mb;
578	char *bpos;
579
580	mb = m_get(M_WAIT, MT_DATA);
581	MCLAIM(mb, &nfs_mowner);
582	if (hsiz >= MINCLSIZE)
583		m_clget(mb, M_WAIT);
584	mb->m_len = 0;
585	bpos = mtod(mb, void *);
586
587	/* Finally, return values */
588	*bposp = bpos;
589	return (mb);
590}
591
592/*
593 * Build the RPC header and fill in the authorization info.
594 * The authorization string argument is only used when the credentials
595 * come from outside of the kernel.
596 * Returns the head of the mbuf list.
597 */
598struct mbuf *
599nfsm_rpchead(kauth_cred_t cr, int nmflag, int procid,
600	int auth_type, int auth_len, char *auth_str, int verf_len,
601	char *verf_str, struct mbuf *mrest, int mrest_len,
602	struct mbuf **mbp, uint32_t *xidp)
603{
604	struct mbuf *mb;
605	u_int32_t *tl;
606	char *bpos;
607	int i;
608	struct mbuf *mreq;
609	int siz, grpsiz, authsiz;
610
611	authsiz = nfsm_rndup(auth_len);
612	mb = m_gethdr(M_WAIT, MT_DATA);
613	MCLAIM(mb, &nfs_mowner);
614	if ((authsiz + 10 * NFSX_UNSIGNED) >= MINCLSIZE) {
615		m_clget(mb, M_WAIT);
616	} else if ((authsiz + 10 * NFSX_UNSIGNED) < MHLEN) {
617		MH_ALIGN(mb, authsiz + 10 * NFSX_UNSIGNED);
618	} else {
619		MH_ALIGN(mb, 8 * NFSX_UNSIGNED);
620	}
621	mb->m_len = 0;
622	mreq = mb;
623	bpos = mtod(mb, void *);
624
625	/*
626	 * First the RPC header.
627	 */
628	nfsm_build(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
629
630	*tl++ = *xidp = nfs_getxid();
631	*tl++ = rpc_call;
632	*tl++ = rpc_vers;
633	*tl++ = txdr_unsigned(NFS_PROG);
634	if (nmflag & NFSMNT_NFSV3)
635		*tl++ = txdr_unsigned(NFS_VER3);
636	else
637		*tl++ = txdr_unsigned(NFS_VER2);
638	if (nmflag & NFSMNT_NFSV3)
639		*tl++ = txdr_unsigned(procid);
640	else
641		*tl++ = txdr_unsigned(nfsv2_procid[procid]);
642
643	/*
644	 * And then the authorization cred.
645	 */
646	*tl++ = txdr_unsigned(auth_type);
647	*tl = txdr_unsigned(authsiz);
648	switch (auth_type) {
649	case RPCAUTH_UNIX:
650		nfsm_build(tl, u_int32_t *, auth_len);
651		*tl++ = 0;		/* stamp ?? */
652		*tl++ = 0;		/* NULL hostname */
653		*tl++ = txdr_unsigned(kauth_cred_geteuid(cr));
654		*tl++ = txdr_unsigned(kauth_cred_getegid(cr));
655		grpsiz = (auth_len >> 2) - 5;
656		*tl++ = txdr_unsigned(grpsiz);
657		for (i = 0; i < grpsiz; i++)
658			*tl++ = txdr_unsigned(kauth_cred_group(cr, i)); /* XXX elad review */
659		break;
660	case RPCAUTH_KERB4:
661		siz = auth_len;
662		while (siz > 0) {
663			if (M_TRAILINGSPACE(mb) == 0) {
664				struct mbuf *mb2;
665				mb2 = m_get(M_WAIT, MT_DATA);
666				MCLAIM(mb2, &nfs_mowner);
667				if (siz >= MINCLSIZE)
668					m_clget(mb2, M_WAIT);
669				mb->m_next = mb2;
670				mb = mb2;
671				mb->m_len = 0;
672				bpos = mtod(mb, void *);
673			}
674			i = min(siz, M_TRAILINGSPACE(mb));
675			memcpy(bpos, auth_str, i);
676			mb->m_len += i;
677			auth_str += i;
678			bpos += i;
679			siz -= i;
680		}
681		if ((siz = (nfsm_rndup(auth_len) - auth_len)) > 0) {
682			for (i = 0; i < siz; i++)
683				*bpos++ = '\0';
684			mb->m_len += siz;
685		}
686		break;
687	};
688
689	/*
690	 * And the verifier...
691	 */
692	nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
693	if (verf_str) {
694		*tl++ = txdr_unsigned(RPCAUTH_KERB4);
695		*tl = txdr_unsigned(verf_len);
696		siz = verf_len;
697		while (siz > 0) {
698			if (M_TRAILINGSPACE(mb) == 0) {
699				struct mbuf *mb2;
700				mb2 = m_get(M_WAIT, MT_DATA);
701				MCLAIM(mb2, &nfs_mowner);
702				if (siz >= MINCLSIZE)
703					m_clget(mb2, M_WAIT);
704				mb->m_next = mb2;
705				mb = mb2;
706				mb->m_len = 0;
707				bpos = mtod(mb, void *);
708			}
709			i = min(siz, M_TRAILINGSPACE(mb));
710			memcpy(bpos, verf_str, i);
711			mb->m_len += i;
712			verf_str += i;
713			bpos += i;
714			siz -= i;
715		}
716		if ((siz = (nfsm_rndup(verf_len) - verf_len)) > 0) {
717			for (i = 0; i < siz; i++)
718				*bpos++ = '\0';
719			mb->m_len += siz;
720		}
721	} else {
722		*tl++ = txdr_unsigned(RPCAUTH_NULL);
723		*tl = 0;
724	}
725	mb->m_next = mrest;
726	mreq->m_pkthdr.len = authsiz + 10 * NFSX_UNSIGNED + mrest_len;
727	mreq->m_pkthdr.rcvif = (struct ifnet *)0;
728	*mbp = mb;
729	return (mreq);
730}
731
732/*
733 * copies mbuf chain to the uio scatter/gather list
734 */
735int
736nfsm_mbuftouio(struct mbuf **mrep, struct uio *uiop, int siz, char **dpos)
737{
738	char *mbufcp, *uiocp;
739	int xfer, left, len;
740	struct mbuf *mp;
741	long uiosiz, rem;
742	int error = 0;
743
744	mp = *mrep;
745	mbufcp = *dpos;
746	len = mtod(mp, char *) + mp->m_len - mbufcp;
747	rem = nfsm_rndup(siz)-siz;
748	while (siz > 0) {
749		if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
750			return (EFBIG);
751		left = uiop->uio_iov->iov_len;
752		uiocp = uiop->uio_iov->iov_base;
753		if (left > siz)
754			left = siz;
755		uiosiz = left;
756		while (left > 0) {
757			while (len == 0) {
758				mp = mp->m_next;
759				if (mp == NULL)
760					return (EBADRPC);
761				mbufcp = mtod(mp, void *);
762				len = mp->m_len;
763			}
764			xfer = (left > len) ? len : left;
765			error = copyout_vmspace(uiop->uio_vmspace, mbufcp,
766			    uiocp, xfer);
767			if (error) {
768				return error;
769			}
770			left -= xfer;
771			len -= xfer;
772			mbufcp += xfer;
773			uiocp += xfer;
774			uiop->uio_offset += xfer;
775			uiop->uio_resid -= xfer;
776		}
777		if (uiop->uio_iov->iov_len <= siz) {
778			uiop->uio_iovcnt--;
779			uiop->uio_iov++;
780		} else {
781			uiop->uio_iov->iov_base =
782			    (char *)uiop->uio_iov->iov_base + uiosiz;
783			uiop->uio_iov->iov_len -= uiosiz;
784		}
785		siz -= uiosiz;
786	}
787	*dpos = mbufcp;
788	*mrep = mp;
789	if (rem > 0) {
790		if (len < rem)
791			error = nfs_adv(mrep, dpos, rem, len);
792		else
793			*dpos += rem;
794	}
795	return (error);
796}
797
798/*
799 * copies a uio scatter/gather list to an mbuf chain.
800 * NOTE: can ony handle iovcnt == 1
801 */
802int
803nfsm_uiotombuf(struct uio *uiop, struct mbuf **mq, int siz, char **bpos)
804{
805	char *uiocp;
806	struct mbuf *mp, *mp2;
807	int xfer, left, mlen;
808	int uiosiz, clflg, rem;
809	char *cp;
810	int error;
811
812#ifdef DIAGNOSTIC
813	if (uiop->uio_iovcnt != 1)
814		panic("nfsm_uiotombuf: iovcnt != 1");
815#endif
816
817	if (siz > MLEN)		/* or should it >= MCLBYTES ?? */
818		clflg = 1;
819	else
820		clflg = 0;
821	rem = nfsm_rndup(siz)-siz;
822	mp = mp2 = *mq;
823	while (siz > 0) {
824		left = uiop->uio_iov->iov_len;
825		uiocp = uiop->uio_iov->iov_base;
826		if (left > siz)
827			left = siz;
828		uiosiz = left;
829		while (left > 0) {
830			mlen = M_TRAILINGSPACE(mp);
831			if (mlen == 0) {
832				mp = m_get(M_WAIT, MT_DATA);
833				MCLAIM(mp, &nfs_mowner);
834				if (clflg)
835					m_clget(mp, M_WAIT);
836				mp->m_len = 0;
837				mp2->m_next = mp;
838				mp2 = mp;
839				mlen = M_TRAILINGSPACE(mp);
840			}
841			xfer = (left > mlen) ? mlen : left;
842			cp = mtod(mp, char *) + mp->m_len;
843			error = copyin_vmspace(uiop->uio_vmspace, uiocp, cp,
844			    xfer);
845			if (error) {
846				/* XXX */
847			}
848			mp->m_len += xfer;
849			left -= xfer;
850			uiocp += xfer;
851			uiop->uio_offset += xfer;
852			uiop->uio_resid -= xfer;
853		}
854		uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base +
855		    uiosiz;
856		uiop->uio_iov->iov_len -= uiosiz;
857		siz -= uiosiz;
858	}
859	if (rem > 0) {
860		if (rem > M_TRAILINGSPACE(mp)) {
861			mp = m_get(M_WAIT, MT_DATA);
862			MCLAIM(mp, &nfs_mowner);
863			mp->m_len = 0;
864			mp2->m_next = mp;
865		}
866		cp = mtod(mp, char *) + mp->m_len;
867		for (left = 0; left < rem; left++)
868			*cp++ = '\0';
869		mp->m_len += rem;
870		*bpos = cp;
871	} else
872		*bpos = mtod(mp, char *) + mp->m_len;
873	*mq = mp;
874	return (0);
875}
876
877/*
878 * Get at least "siz" bytes of correctly aligned data.
879 * When called the mbuf pointers are not necessarily correct,
880 * dsosp points to what ought to be in m_data and left contains
881 * what ought to be in m_len.
882 * This is used by the macros nfsm_dissect and nfsm_dissecton for tough
883 * cases. (The macros use the vars. dpos and dpos2)
884 */
885int
886nfsm_disct(struct mbuf **mdp, char **dposp, int siz, int left, char **cp2)
887{
888	struct mbuf *m1, *m2;
889	struct mbuf *havebuf = NULL;
890	char *src = *dposp;
891	char *dst;
892	int len;
893
894#ifdef DEBUG
895	if (left < 0)
896		panic("nfsm_disct: left < 0");
897#endif
898	m1 = *mdp;
899	/*
900	 * Skip through the mbuf chain looking for an mbuf with
901	 * some data. If the first mbuf found has enough data
902	 * and it is correctly aligned return it.
903	 */
904	while (left == 0) {
905		havebuf = m1;
906		*mdp = m1 = m1->m_next;
907		if (m1 == NULL)
908			return (EBADRPC);
909		src = mtod(m1, void *);
910		left = m1->m_len;
911		/*
912		 * If we start a new mbuf and it is big enough
913		 * and correctly aligned just return it, don't
914		 * do any pull up.
915		 */
916		if (left >= siz && nfsm_aligned(src)) {
917			*cp2 = src;
918			*dposp = src + siz;
919			return (0);
920		}
921	}
922	if ((m1->m_flags & M_EXT) != 0) {
923		if (havebuf && M_TRAILINGSPACE(havebuf) >= siz &&
924		    nfsm_aligned(mtod(havebuf, char *) + havebuf->m_len)) {
925			/*
926			 * If the first mbuf with data has external data
927			 * and there is a previous mbuf with some trailing
928			 * space, use it to move the data into.
929			 */
930			m2 = m1;
931			*mdp = m1 = havebuf;
932			*cp2 = mtod(m1, char *) + m1->m_len;
933		} else if (havebuf) {
934			/*
935			 * If the first mbuf has a external data
936			 * and there is no previous empty mbuf
937			 * allocate a new mbuf and move the external
938			 * data to the new mbuf. Also make the first
939			 * mbuf look empty.
940			 */
941			m2 = m1;
942			*mdp = m1 = m_get(M_WAIT, MT_DATA);
943			MCLAIM(m1, m2->m_owner);
944			if ((m2->m_flags & M_PKTHDR) != 0) {
945				/* XXX MOVE */
946				M_COPY_PKTHDR(m1, m2);
947				m_tag_delete_chain(m2, NULL);
948				m2->m_flags &= ~M_PKTHDR;
949			}
950			if (havebuf) {
951				havebuf->m_next = m1;
952			}
953			m1->m_next = m2;
954			MRESETDATA(m1);
955			m1->m_len = 0;
956			m2->m_data = src;
957			m2->m_len = left;
958			*cp2 = mtod(m1, char *);
959		} else {
960			struct mbuf **nextp = &m1->m_next;
961
962			m1->m_len -= left;
963			do {
964				m2 = m_get(M_WAIT, MT_DATA);
965				MCLAIM(m2, m1->m_owner);
966				if (left >= MINCLSIZE) {
967					MCLGET(m2, M_WAIT);
968				}
969				m2->m_next = *nextp;
970				*nextp = m2;
971				nextp = &m2->m_next;
972				len = (m2->m_flags & M_EXT) != 0 ?
973				    MCLBYTES : MLEN;
974				if (len > left) {
975					len = left;
976				}
977				memcpy(mtod(m2, char *), src, len);
978				m2->m_len = len;
979				src += len;
980				left -= len;
981			} while (left > 0);
982			*mdp = m1 = m1->m_next;
983			m2 = m1->m_next;
984			*cp2 = mtod(m1, char *);
985		}
986	} else {
987		/*
988		 * If the first mbuf has no external data
989		 * move the data to the front of the mbuf.
990		 */
991		MRESETDATA(m1);
992		dst = mtod(m1, char *);
993		if (dst != src) {
994			memmove(dst, src, left);
995		}
996		m1->m_len = left;
997		m2 = m1->m_next;
998		*cp2 = m1->m_data;
999	}
1000	*dposp = *cp2 + siz;
1001	/*
1002	 * Loop through mbufs pulling data up into first mbuf until
1003	 * the first mbuf is full or there is no more data to
1004	 * pullup.
1005	 */
1006	dst = mtod(m1, char *) + m1->m_len;
1007	while ((len = M_TRAILINGSPACE(m1)) != 0 && m2) {
1008		if ((len = min(len, m2->m_len)) != 0) {
1009			memcpy(dst, mtod(m2, char *), len);
1010		}
1011		m1->m_len += len;
1012		dst += len;
1013		m2->m_data += len;
1014		m2->m_len -= len;
1015		m2 = m2->m_next;
1016	}
1017	if (m1->m_len < siz)
1018		return (EBADRPC);
1019	return (0);
1020}
1021
1022/*
1023 * Advance the position in the mbuf chain.
1024 */
1025int
1026nfs_adv(struct mbuf **mdp, char **dposp, int offs, int left)
1027{
1028	struct mbuf *m;
1029	int s;
1030
1031	m = *mdp;
1032	s = left;
1033	while (s < offs) {
1034		offs -= s;
1035		m = m->m_next;
1036		if (m == NULL)
1037			return (EBADRPC);
1038		s = m->m_len;
1039	}
1040	*mdp = m;
1041	*dposp = mtod(m, char *) + offs;
1042	return (0);
1043}
1044
1045/*
1046 * Copy a string into mbufs for the hard cases...
1047 */
1048int
1049nfsm_strtmbuf(struct mbuf **mb, char **bpos, const char *cp, long siz)
1050{
1051	struct mbuf *m1 = NULL, *m2;
1052	long left, xfer, len, tlen;
1053	u_int32_t *tl;
1054	int putsize;
1055
1056	putsize = 1;
1057	m2 = *mb;
1058	left = M_TRAILINGSPACE(m2);
1059	if (left > 0) {
1060		tl = ((u_int32_t *)(*bpos));
1061		*tl++ = txdr_unsigned(siz);
1062		putsize = 0;
1063		left -= NFSX_UNSIGNED;
1064		m2->m_len += NFSX_UNSIGNED;
1065		if (left > 0) {
1066			memcpy((void *) tl, cp, left);
1067			siz -= left;
1068			cp += left;
1069			m2->m_len += left;
1070			left = 0;
1071		}
1072	}
1073	/* Loop around adding mbufs */
1074	while (siz > 0) {
1075		m1 = m_get(M_WAIT, MT_DATA);
1076		MCLAIM(m1, &nfs_mowner);
1077		if (siz > MLEN)
1078			m_clget(m1, M_WAIT);
1079		m1->m_len = NFSMSIZ(m1);
1080		m2->m_next = m1;
1081		m2 = m1;
1082		tl = mtod(m1, u_int32_t *);
1083		tlen = 0;
1084		if (putsize) {
1085			*tl++ = txdr_unsigned(siz);
1086			m1->m_len -= NFSX_UNSIGNED;
1087			tlen = NFSX_UNSIGNED;
1088			putsize = 0;
1089		}
1090		if (siz < m1->m_len) {
1091			len = nfsm_rndup(siz);
1092			xfer = siz;
1093			if (xfer < len)
1094				*(tl+(xfer>>2)) = 0;
1095		} else {
1096			xfer = len = m1->m_len;
1097		}
1098		memcpy((void *) tl, cp, xfer);
1099		m1->m_len = len+tlen;
1100		siz -= xfer;
1101		cp += xfer;
1102	}
1103	*mb = m1;
1104	*bpos = mtod(m1, char *) + m1->m_len;
1105	return (0);
1106}
1107
1108/*
1109 * Directory caching routines. They work as follows:
1110 * - a cache is maintained per VDIR nfsnode.
1111 * - for each offset cookie that is exported to userspace, and can
1112 *   thus be thrown back at us as an offset to VOP_READDIR, store
1113 *   information in the cache.
1114 * - cached are:
1115 *   - cookie itself
1116 *   - blocknumber (essentially just a search key in the buffer cache)
1117 *   - entry number in block.
1118 *   - offset cookie of block in which this entry is stored
1119 *   - 32 bit cookie if NFSMNT_XLATECOOKIE is used.
1120 * - entries are looked up in a hash table
1121 * - also maintained is an LRU list of entries, used to determine
1122 *   which ones to delete if the cache grows too large.
1123 * - if 32 <-> 64 translation mode is requested for a filesystem,
1124 *   the cache also functions as a translation table
1125 * - in the translation case, invalidating the cache does not mean
1126 *   flushing it, but just marking entries as invalid, except for
1127 *   the <64bit cookie, 32bitcookie> pair which is still valid, to
1128 *   still be able to use the cache as a translation table.
1129 * - 32 bit cookies are uniquely created by combining the hash table
1130 *   entry value, and one generation count per hash table entry,
1131 *   incremented each time an entry is appended to the chain.
1132 * - the cache is invalidated each time a direcory is modified
1133 * - sanity checks are also done; if an entry in a block turns
1134 *   out not to have a matching cookie, the cache is invalidated
1135 *   and a new block starting from the wanted offset is fetched from
1136 *   the server.
1137 * - directory entries as read from the server are extended to contain
1138 *   the 64bit and, optionally, the 32bit cookies, for sanity checking
1139 *   the cache and exporting them to userspace through the cookie
1140 *   argument to VOP_READDIR.
1141 */
1142
1143u_long
1144nfs_dirhash(off_t off)
1145{
1146	int i;
1147	char *cp = (char *)&off;
1148	u_long sum = 0L;
1149
1150	for (i = 0 ; i < sizeof (off); i++)
1151		sum += *cp++;
1152
1153	return sum;
1154}
1155
1156#define	_NFSDC_MTX(np)		(NFSTOV(np)->v_interlock)
1157#define	NFSDC_LOCK(np)		mutex_enter(_NFSDC_MTX(np))
1158#define	NFSDC_UNLOCK(np)	mutex_exit(_NFSDC_MTX(np))
1159#define	NFSDC_ASSERT_LOCKED(np) KASSERT(mutex_owned(_NFSDC_MTX(np)))
1160
1161void
1162nfs_initdircache(struct vnode *vp)
1163{
1164	struct nfsnode *np = VTONFS(vp);
1165	struct nfsdirhashhead *dircache;
1166
1167	dircache = hashinit(NFS_DIRHASHSIZ, HASH_LIST, true,
1168	    &nfsdirhashmask);
1169
1170	NFSDC_LOCK(np);
1171	if (np->n_dircache == NULL) {
1172		np->n_dircachesize = 0;
1173		np->n_dircache = dircache;
1174		dircache = NULL;
1175		TAILQ_INIT(&np->n_dirchain);
1176	}
1177	NFSDC_UNLOCK(np);
1178	if (dircache)
1179		hashdone(dircache, HASH_LIST, nfsdirhashmask);
1180}
1181
1182void
1183nfs_initdirxlatecookie(struct vnode *vp)
1184{
1185	struct nfsnode *np = VTONFS(vp);
1186	unsigned *dirgens;
1187
1188	KASSERT(VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_XLATECOOKIE);
1189
1190	dirgens = kmem_zalloc(NFS_DIRHASHSIZ * sizeof(unsigned), KM_SLEEP);
1191	NFSDC_LOCK(np);
1192	if (np->n_dirgens == NULL) {
1193		np->n_dirgens = dirgens;
1194		dirgens = NULL;
1195	}
1196	NFSDC_UNLOCK(np);
1197	if (dirgens)
1198		kmem_free(dirgens, NFS_DIRHASHSIZ * sizeof(unsigned));
1199}
1200
1201static const struct nfsdircache dzero;
1202
1203static void nfs_unlinkdircache(struct nfsnode *np, struct nfsdircache *);
1204static void nfs_putdircache_unlocked(struct nfsnode *,
1205    struct nfsdircache *);
1206
1207static void
1208nfs_unlinkdircache(struct nfsnode *np, struct nfsdircache *ndp)
1209{
1210
1211	NFSDC_ASSERT_LOCKED(np);
1212	KASSERT(ndp != &dzero);
1213
1214	if (LIST_NEXT(ndp, dc_hash) == (void *)-1)
1215		return;
1216
1217	TAILQ_REMOVE(&np->n_dirchain, ndp, dc_chain);
1218	LIST_REMOVE(ndp, dc_hash);
1219	LIST_NEXT(ndp, dc_hash) = (void *)-1; /* mark as unlinked */
1220
1221	nfs_putdircache_unlocked(np, ndp);
1222}
1223
1224void
1225nfs_putdircache(struct nfsnode *np, struct nfsdircache *ndp)
1226{
1227	int ref;
1228
1229	if (ndp == &dzero)
1230		return;
1231
1232	KASSERT(ndp->dc_refcnt > 0);
1233	NFSDC_LOCK(np);
1234	ref = --ndp->dc_refcnt;
1235	NFSDC_UNLOCK(np);
1236
1237	if (ref == 0)
1238		kmem_free(ndp, sizeof(*ndp));
1239}
1240
1241static void
1242nfs_putdircache_unlocked(struct nfsnode *np, struct nfsdircache *ndp)
1243{
1244	int ref;
1245
1246	NFSDC_ASSERT_LOCKED(np);
1247
1248	if (ndp == &dzero)
1249		return;
1250
1251	KASSERT(ndp->dc_refcnt > 0);
1252	ref = --ndp->dc_refcnt;
1253	if (ref == 0)
1254		kmem_free(ndp, sizeof(*ndp));
1255}
1256
1257struct nfsdircache *
1258nfs_searchdircache(struct vnode *vp, off_t off, int do32, int *hashent)
1259{
1260	struct nfsdirhashhead *ndhp;
1261	struct nfsdircache *ndp = NULL;
1262	struct nfsnode *np = VTONFS(vp);
1263	unsigned ent;
1264
1265	/*
1266	 * Zero is always a valid cookie.
1267	 */
1268	if (off == 0)
1269		/* XXXUNCONST */
1270		return (struct nfsdircache *)__UNCONST(&dzero);
1271
1272	if (!np->n_dircache)
1273		return NULL;
1274
1275	/*
1276	 * We use a 32bit cookie as search key, directly reconstruct
1277	 * the hashentry. Else use the hashfunction.
1278	 */
1279	if (do32) {
1280		ent = (u_int32_t)off >> 24;
1281		if (ent >= NFS_DIRHASHSIZ)
1282			return NULL;
1283		ndhp = &np->n_dircache[ent];
1284	} else {
1285		ndhp = NFSDIRHASH(np, off);
1286	}
1287
1288	if (hashent)
1289		*hashent = (int)(ndhp - np->n_dircache);
1290
1291	NFSDC_LOCK(np);
1292	if (do32) {
1293		LIST_FOREACH(ndp, ndhp, dc_hash) {
1294			if (ndp->dc_cookie32 == (u_int32_t)off) {
1295				/*
1296				 * An invalidated entry will become the
1297				 * start of a new block fetched from
1298				 * the server.
1299				 */
1300				if (ndp->dc_flags & NFSDC_INVALID) {
1301					ndp->dc_blkcookie = ndp->dc_cookie;
1302					ndp->dc_entry = 0;
1303					ndp->dc_flags &= ~NFSDC_INVALID;
1304				}
1305				break;
1306			}
1307		}
1308	} else {
1309		LIST_FOREACH(ndp, ndhp, dc_hash) {
1310			if (ndp->dc_cookie == off)
1311				break;
1312		}
1313	}
1314	if (ndp != NULL)
1315		ndp->dc_refcnt++;
1316	NFSDC_UNLOCK(np);
1317	return ndp;
1318}
1319
1320
1321struct nfsdircache *
1322nfs_enterdircache(struct vnode *vp, off_t off, off_t blkoff, int en,
1323    daddr_t blkno)
1324{
1325	struct nfsnode *np = VTONFS(vp);
1326	struct nfsdirhashhead *ndhp;
1327	struct nfsdircache *ndp = NULL;
1328	struct nfsdircache *newndp = NULL;
1329	struct nfsmount *nmp = VFSTONFS(vp->v_mount);
1330	int hashent = 0, gen, overwrite;	/* XXX: GCC */
1331
1332	/*
1333	 * XXX refuse entries for offset 0. amd(8) erroneously sets
1334	 * cookie 0 for the '.' entry, making this necessary. This
1335	 * isn't so bad, as 0 is a special case anyway.
1336	 */
1337	if (off == 0)
1338		/* XXXUNCONST */
1339		return (struct nfsdircache *)__UNCONST(&dzero);
1340
1341	if (!np->n_dircache)
1342		/*
1343		 * XXX would like to do this in nfs_nget but vtype
1344		 * isn't known at that time.
1345		 */
1346		nfs_initdircache(vp);
1347
1348	if ((nmp->nm_flag & NFSMNT_XLATECOOKIE) && !np->n_dirgens)
1349		nfs_initdirxlatecookie(vp);
1350
1351retry:
1352	ndp = nfs_searchdircache(vp, off, 0, &hashent);
1353
1354	NFSDC_LOCK(np);
1355	if (ndp && (ndp->dc_flags & NFSDC_INVALID) == 0) {
1356		/*
1357		 * Overwriting an old entry. Check if it's the same.
1358		 * If so, just return. If not, remove the old entry.
1359		 */
1360		if (ndp->dc_blkcookie == blkoff && ndp->dc_entry == en)
1361			goto done;
1362		nfs_unlinkdircache(np, ndp);
1363		nfs_putdircache_unlocked(np, ndp);
1364		ndp = NULL;
1365	}
1366
1367	ndhp = &np->n_dircache[hashent];
1368
1369	if (!ndp) {
1370		if (newndp == NULL) {
1371			NFSDC_UNLOCK(np);
1372			newndp = kmem_alloc(sizeof(*newndp), KM_SLEEP);
1373			newndp->dc_refcnt = 1;
1374			LIST_NEXT(newndp, dc_hash) = (void *)-1;
1375			goto retry;
1376		}
1377		ndp = newndp;
1378		newndp = NULL;
1379		overwrite = 0;
1380		if (nmp->nm_flag & NFSMNT_XLATECOOKIE) {
1381			/*
1382			 * We're allocating a new entry, so bump the
1383			 * generation number.
1384			 */
1385			KASSERT(np->n_dirgens);
1386			gen = ++np->n_dirgens[hashent];
1387			if (gen == 0) {
1388				np->n_dirgens[hashent]++;
1389				gen++;
1390			}
1391			ndp->dc_cookie32 = (hashent << 24) | (gen & 0xffffff);
1392		}
1393	} else
1394		overwrite = 1;
1395
1396	ndp->dc_cookie = off;
1397	ndp->dc_blkcookie = blkoff;
1398	ndp->dc_entry = en;
1399	ndp->dc_flags = 0;
1400
1401	if (overwrite)
1402		goto done;
1403
1404	/*
1405	 * If the maximum directory cookie cache size has been reached
1406	 * for this node, take one off the front. The idea is that
1407	 * directories are typically read front-to-back once, so that
1408	 * the oldest entries can be thrown away without much performance
1409	 * loss.
1410	 */
1411	if (np->n_dircachesize == NFS_MAXDIRCACHE) {
1412		nfs_unlinkdircache(np, TAILQ_FIRST(&np->n_dirchain));
1413	} else
1414		np->n_dircachesize++;
1415
1416	KASSERT(ndp->dc_refcnt == 1);
1417	LIST_INSERT_HEAD(ndhp, ndp, dc_hash);
1418	TAILQ_INSERT_TAIL(&np->n_dirchain, ndp, dc_chain);
1419	ndp->dc_refcnt++;
1420done:
1421	KASSERT(ndp->dc_refcnt > 0);
1422	NFSDC_UNLOCK(np);
1423	if (newndp)
1424		nfs_putdircache(np, newndp);
1425	return ndp;
1426}
1427
1428void
1429nfs_invaldircache(struct vnode *vp, int flags)
1430{
1431	struct nfsnode *np = VTONFS(vp);
1432	struct nfsdircache *ndp = NULL;
1433	struct nfsmount *nmp = VFSTONFS(vp->v_mount);
1434	const bool forcefree = flags & NFS_INVALDIRCACHE_FORCE;
1435
1436#ifdef DIAGNOSTIC
1437	if (vp->v_type != VDIR)
1438		panic("nfs: invaldircache: not dir");
1439#endif
1440
1441	if ((flags & NFS_INVALDIRCACHE_KEEPEOF) == 0)
1442		np->n_flag &= ~NEOFVALID;
1443
1444	if (!np->n_dircache)
1445		return;
1446
1447	NFSDC_LOCK(np);
1448	if (!(nmp->nm_flag & NFSMNT_XLATECOOKIE) || forcefree) {
1449		while ((ndp = TAILQ_FIRST(&np->n_dirchain)) != NULL) {
1450			KASSERT(!forcefree || ndp->dc_refcnt == 1);
1451			nfs_unlinkdircache(np, ndp);
1452		}
1453		np->n_dircachesize = 0;
1454		if (forcefree && np->n_dirgens) {
1455			kmem_free(np->n_dirgens,
1456			    NFS_DIRHASHSIZ * sizeof(unsigned));
1457			np->n_dirgens = NULL;
1458		}
1459	} else {
1460		TAILQ_FOREACH(ndp, &np->n_dirchain, dc_chain)
1461			ndp->dc_flags |= NFSDC_INVALID;
1462	}
1463
1464	NFSDC_UNLOCK(np);
1465}
1466
1467/*
1468 * Called once before VFS init to initialize shared and
1469 * server-specific data structures.
1470 */
1471static int
1472nfs_init0(void)
1473{
1474
1475	nfsrtt.pos = 0;
1476	rpc_vers = txdr_unsigned(RPC_VER2);
1477	rpc_call = txdr_unsigned(RPC_CALL);
1478	rpc_reply = txdr_unsigned(RPC_REPLY);
1479	rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED);
1480	rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED);
1481	rpc_mismatch = txdr_unsigned(RPC_MISMATCH);
1482	rpc_autherr = txdr_unsigned(RPC_AUTHERR);
1483	rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX);
1484	rpc_auth_kerb = txdr_unsigned(RPCAUTH_KERB4);
1485	nfs_prog = txdr_unsigned(NFS_PROG);
1486	nfs_true = txdr_unsigned(true);
1487	nfs_false = txdr_unsigned(false);
1488	nfs_xdrneg1 = txdr_unsigned(-1);
1489	nfs_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
1490	if (nfs_ticks < 1)
1491		nfs_ticks = 1;
1492	nfs_xid = cprng_fast32();
1493	nfsdreq_init();
1494
1495	/*
1496	 * Initialize reply list and start timer
1497	 */
1498	TAILQ_INIT(&nfs_reqq);
1499	nfs_timer_init();
1500	MOWNER_ATTACH(&nfs_mowner);
1501
1502	return 0;
1503}
1504
1505/*
1506 * This is disgusting, but it must support both modular and monolothic
1507 * configurations.  For monolithic builds NFSSERVER may not imply NFS.
1508 *
1509 * Yuck.
1510 */
1511void
1512nfs_init(void)
1513{
1514	static ONCE_DECL(nfs_init_once);
1515
1516	RUN_ONCE(&nfs_init_once, nfs_init0);
1517}
1518
1519void
1520nfs_fini(void)
1521{
1522
1523	nfsdreq_fini();
1524	nfs_timer_fini();
1525	MOWNER_DETACH(&nfs_mowner);
1526}
1527
1528/*
1529 * A fiddled version of m_adj() that ensures null fill to a 32-bit
1530 * boundary and only trims off the back end
1531 *
1532 * 1. trim off 'len' bytes as m_adj(mp, -len).
1533 * 2. add zero-padding 'nul' bytes at the end of the mbuf chain.
1534 */
1535void
1536nfs_zeropad(struct mbuf *mp, int len, int nul)
1537{
1538	struct mbuf *m;
1539	int count;
1540
1541	/*
1542	 * Trim from tail.  Scan the mbuf chain,
1543	 * calculating its length and finding the last mbuf.
1544	 * If the adjustment only affects this mbuf, then just
1545	 * adjust and return.  Otherwise, rescan and truncate
1546	 * after the remaining size.
1547	 */
1548	count = 0;
1549	m = mp;
1550	for (;;) {
1551		count += m->m_len;
1552		if (m->m_next == NULL)
1553			break;
1554		m = m->m_next;
1555	}
1556
1557	KDASSERT(count >= len);
1558
1559	if (m->m_len >= len) {
1560		m->m_len -= len;
1561	} else {
1562		count -= len;
1563		/*
1564		 * Correct length for chain is "count".
1565		 * Find the mbuf with last data, adjust its length,
1566		 * and toss data from remaining mbufs on chain.
1567		 */
1568		for (m = mp; m; m = m->m_next) {
1569			if (m->m_len >= count) {
1570				m->m_len = count;
1571				break;
1572			}
1573			count -= m->m_len;
1574		}
1575		KASSERT(m && m->m_next);
1576		m_freem(m->m_next);
1577		m->m_next = NULL;
1578	}
1579
1580	KDASSERT(m->m_next == NULL);
1581
1582	/*
1583	 * zero-padding.
1584	 */
1585	if (nul > 0) {
1586		char *cp;
1587		int i;
1588
1589		if (M_ROMAP(m) || M_TRAILINGSPACE(m) < nul) {
1590			struct mbuf *n;
1591
1592			KDASSERT(MLEN >= nul);
1593			n = m_get(M_WAIT, MT_DATA);
1594			MCLAIM(n, &nfs_mowner);
1595			n->m_len = nul;
1596			n->m_next = NULL;
1597			m->m_next = n;
1598			cp = mtod(n, void *);
1599		} else {
1600			cp = mtod(m, char *) + m->m_len;
1601			m->m_len += nul;
1602		}
1603		for (i = 0; i < nul; i++)
1604			*cp++ = '\0';
1605	}
1606	return;
1607}
1608
1609/*
1610 * Make these functions instead of macros, so that the kernel text size
1611 * doesn't get too big...
1612 */
1613void
1614nfsm_srvwcc(struct nfsrv_descript *nfsd, int before_ret, struct vattr *before_vap, int after_ret, struct vattr *after_vap, struct mbuf **mbp, char **bposp)
1615{
1616	struct mbuf *mb = *mbp;
1617	char *bpos = *bposp;
1618	u_int32_t *tl;
1619
1620	if (before_ret) {
1621		nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
1622		*tl = nfs_false;
1623	} else {
1624		nfsm_build(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
1625		*tl++ = nfs_true;
1626		txdr_hyper(before_vap->va_size, tl);
1627		tl += 2;
1628		txdr_nfsv3time(&(before_vap->va_mtime), tl);
1629		tl += 2;
1630		txdr_nfsv3time(&(before_vap->va_ctime), tl);
1631	}
1632	*bposp = bpos;
1633	*mbp = mb;
1634	nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp);
1635}
1636
1637void
1638nfsm_srvpostopattr(struct nfsrv_descript *nfsd, int after_ret, struct vattr *after_vap, struct mbuf **mbp, char **bposp)
1639{
1640	struct mbuf *mb = *mbp;
1641	char *bpos = *bposp;
1642	u_int32_t *tl;
1643	struct nfs_fattr *fp;
1644
1645	if (after_ret) {
1646		nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
1647		*tl = nfs_false;
1648	} else {
1649		nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_V3FATTR);
1650		*tl++ = nfs_true;
1651		fp = (struct nfs_fattr *)tl;
1652		nfsm_srvfattr(nfsd, after_vap, fp);
1653	}
1654	*mbp = mb;
1655	*bposp = bpos;
1656}
1657
1658void
1659nfsm_srvfattr(struct nfsrv_descript *nfsd, struct vattr *vap, struct nfs_fattr *fp)
1660{
1661
1662	fp->fa_nlink = txdr_unsigned(vap->va_nlink);
1663	fp->fa_uid = txdr_unsigned(vap->va_uid);
1664	fp->fa_gid = txdr_unsigned(vap->va_gid);
1665	if (nfsd->nd_flag & ND_NFSV3) {
1666		fp->fa_type = vtonfsv3_type(vap->va_type);
1667		fp->fa_mode = vtonfsv3_mode(vap->va_mode);
1668		txdr_hyper(vap->va_size, &fp->fa3_size);
1669		txdr_hyper(vap->va_bytes, &fp->fa3_used);
1670		fp->fa3_rdev.specdata1 = txdr_unsigned(major(vap->va_rdev));
1671		fp->fa3_rdev.specdata2 = txdr_unsigned(minor(vap->va_rdev));
1672		fp->fa3_fsid.nfsuquad[0] = 0;
1673		fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid);
1674		txdr_hyper(vap->va_fileid, &fp->fa3_fileid);
1675		txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime);
1676		txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime);
1677		txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime);
1678	} else {
1679		fp->fa_type = vtonfsv2_type(vap->va_type);
1680		fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
1681		fp->fa2_size = txdr_unsigned(vap->va_size);
1682		fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize);
1683		if (vap->va_type == VFIFO)
1684			fp->fa2_rdev = 0xffffffff;
1685		else
1686			fp->fa2_rdev = txdr_unsigned(vap->va_rdev);
1687		fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE);
1688		fp->fa2_fsid = txdr_unsigned(vap->va_fsid);
1689		fp->fa2_fileid = txdr_unsigned(vap->va_fileid);
1690		txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime);
1691		txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime);
1692		txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime);
1693	}
1694}
1695
1696/*
1697 * This function compares two net addresses by family and returns true
1698 * if they are the same host.
1699 * If there is any doubt, return false.
1700 * The AF_INET family is handled as a special case so that address mbufs
1701 * don't need to be saved to store "struct in_addr", which is only 4 bytes.
1702 */
1703int
1704netaddr_match(int family, union nethostaddr *haddr, struct mbuf *nam)
1705{
1706	struct sockaddr_in *inetaddr;
1707
1708	switch (family) {
1709	case AF_INET:
1710		inetaddr = mtod(nam, struct sockaddr_in *);
1711		if (inetaddr->sin_family == AF_INET &&
1712		    inetaddr->sin_addr.s_addr == haddr->had_inetaddr)
1713			return (1);
1714		break;
1715	case AF_INET6:
1716	    {
1717		struct sockaddr_in6 *sin6_1, *sin6_2;
1718
1719		sin6_1 = mtod(nam, struct sockaddr_in6 *);
1720		sin6_2 = mtod(haddr->had_nam, struct sockaddr_in6 *);
1721		if (sin6_1->sin6_family == AF_INET6 &&
1722		    IN6_ARE_ADDR_EQUAL(&sin6_1->sin6_addr, &sin6_2->sin6_addr))
1723			return 1;
1724	    }
1725	default:
1726		break;
1727	};
1728	return (0);
1729}
1730
1731/*
1732 * The write verifier has changed (probably due to a server reboot), so all
1733 * PG_NEEDCOMMIT pages will have to be written again. Since they are marked
1734 * as dirty or are being written out just now, all this takes is clearing
1735 * the PG_NEEDCOMMIT flag. Once done the new write verifier can be set for
1736 * the mount point.
1737 */
1738void
1739nfs_clearcommit(struct mount *mp)
1740{
1741	struct vnode *vp;
1742	struct nfsnode *np;
1743	struct vm_page *pg;
1744	struct nfsmount *nmp = VFSTONFS(mp);
1745
1746	rw_enter(&nmp->nm_writeverflock, RW_WRITER);
1747	mutex_enter(&mntvnode_lock);
1748	TAILQ_FOREACH(vp, &mp->mnt_vnodelist, v_mntvnodes) {
1749		KASSERT(vp->v_mount == mp);
1750		if (vp->v_type != VREG)
1751			continue;
1752		mutex_enter(vp->v_interlock);
1753		if (vp->v_iflag & (VI_XLOCK | VI_CLEAN)) {
1754			mutex_exit(vp->v_interlock);
1755			continue;
1756		}
1757		np = VTONFS(vp);
1758		np->n_pushlo = np->n_pushhi = np->n_pushedlo =
1759		    np->n_pushedhi = 0;
1760		np->n_commitflags &=
1761		    ~(NFS_COMMIT_PUSH_VALID | NFS_COMMIT_PUSHED_VALID);
1762		TAILQ_FOREACH(pg, &vp->v_uobj.memq, listq.queue) {
1763			pg->flags &= ~PG_NEEDCOMMIT;
1764		}
1765		mutex_exit(vp->v_interlock);
1766	}
1767	mutex_exit(&mntvnode_lock);
1768	mutex_enter(&nmp->nm_lock);
1769	nmp->nm_iflag &= ~NFSMNT_STALEWRITEVERF;
1770	mutex_exit(&nmp->nm_lock);
1771	rw_exit(&nmp->nm_writeverflock);
1772}
1773
1774void
1775nfs_merge_commit_ranges(struct vnode *vp)
1776{
1777	struct nfsnode *np = VTONFS(vp);
1778
1779	KASSERT(np->n_commitflags & NFS_COMMIT_PUSH_VALID);
1780
1781	if (!(np->n_commitflags & NFS_COMMIT_PUSHED_VALID)) {
1782		np->n_pushedlo = np->n_pushlo;
1783		np->n_pushedhi = np->n_pushhi;
1784		np->n_commitflags |= NFS_COMMIT_PUSHED_VALID;
1785	} else {
1786		if (np->n_pushlo < np->n_pushedlo)
1787			np->n_pushedlo = np->n_pushlo;
1788		if (np->n_pushhi > np->n_pushedhi)
1789			np->n_pushedhi = np->n_pushhi;
1790	}
1791
1792	np->n_pushlo = np->n_pushhi = 0;
1793	np->n_commitflags &= ~NFS_COMMIT_PUSH_VALID;
1794
1795#ifdef NFS_DEBUG_COMMIT
1796	printf("merge: committed: %u - %u\n", (unsigned)np->n_pushedlo,
1797	    (unsigned)np->n_pushedhi);
1798#endif
1799}
1800
1801int
1802nfs_in_committed_range(struct vnode *vp, off_t off, off_t len)
1803{
1804	struct nfsnode *np = VTONFS(vp);
1805	off_t lo, hi;
1806
1807	if (!(np->n_commitflags & NFS_COMMIT_PUSHED_VALID))
1808		return 0;
1809	lo = off;
1810	hi = lo + len;
1811
1812	return (lo >= np->n_pushedlo && hi <= np->n_pushedhi);
1813}
1814
1815int
1816nfs_in_tobecommitted_range(struct vnode *vp, off_t off, off_t len)
1817{
1818	struct nfsnode *np = VTONFS(vp);
1819	off_t lo, hi;
1820
1821	if (!(np->n_commitflags & NFS_COMMIT_PUSH_VALID))
1822		return 0;
1823	lo = off;
1824	hi = lo + len;
1825
1826	return (lo >= np->n_pushlo && hi <= np->n_pushhi);
1827}
1828
1829void
1830nfs_add_committed_range(struct vnode *vp, off_t off, off_t len)
1831{
1832	struct nfsnode *np = VTONFS(vp);
1833	off_t lo, hi;
1834
1835	lo = off;
1836	hi = lo + len;
1837
1838	if (!(np->n_commitflags & NFS_COMMIT_PUSHED_VALID)) {
1839		np->n_pushedlo = lo;
1840		np->n_pushedhi = hi;
1841		np->n_commitflags |= NFS_COMMIT_PUSHED_VALID;
1842	} else {
1843		if (hi > np->n_pushedhi)
1844			np->n_pushedhi = hi;
1845		if (lo < np->n_pushedlo)
1846			np->n_pushedlo = lo;
1847	}
1848#ifdef NFS_DEBUG_COMMIT
1849	printf("add: committed: %u - %u\n", (unsigned)np->n_pushedlo,
1850	    (unsigned)np->n_pushedhi);
1851#endif
1852}
1853
1854void
1855nfs_del_committed_range(struct vnode *vp, off_t off, off_t len)
1856{
1857	struct nfsnode *np = VTONFS(vp);
1858	off_t lo, hi;
1859
1860	if (!(np->n_commitflags & NFS_COMMIT_PUSHED_VALID))
1861		return;
1862
1863	lo = off;
1864	hi = lo + len;
1865
1866	if (lo > np->n_pushedhi || hi < np->n_pushedlo)
1867		return;
1868	if (lo <= np->n_pushedlo)
1869		np->n_pushedlo = hi;
1870	else if (hi >= np->n_pushedhi)
1871		np->n_pushedhi = lo;
1872	else {
1873		/*
1874		 * XXX There's only one range. If the deleted range
1875		 * is in the middle, pick the largest of the
1876		 * contiguous ranges that it leaves.
1877		 */
1878		if ((np->n_pushedlo - lo) > (hi - np->n_pushedhi))
1879			np->n_pushedhi = lo;
1880		else
1881			np->n_pushedlo = hi;
1882	}
1883#ifdef NFS_DEBUG_COMMIT
1884	printf("del: committed: %u - %u\n", (unsigned)np->n_pushedlo,
1885	    (unsigned)np->n_pushedhi);
1886#endif
1887}
1888
1889void
1890nfs_add_tobecommitted_range(struct vnode *vp, off_t off, off_t len)
1891{
1892	struct nfsnode *np = VTONFS(vp);
1893	off_t lo, hi;
1894
1895	lo = off;
1896	hi = lo + len;
1897
1898	if (!(np->n_commitflags & NFS_COMMIT_PUSH_VALID)) {
1899		np->n_pushlo = lo;
1900		np->n_pushhi = hi;
1901		np->n_commitflags |= NFS_COMMIT_PUSH_VALID;
1902	} else {
1903		if (lo < np->n_pushlo)
1904			np->n_pushlo = lo;
1905		if (hi > np->n_pushhi)
1906			np->n_pushhi = hi;
1907	}
1908#ifdef NFS_DEBUG_COMMIT
1909	printf("add: tobecommitted: %u - %u\n", (unsigned)np->n_pushlo,
1910	    (unsigned)np->n_pushhi);
1911#endif
1912}
1913
1914void
1915nfs_del_tobecommitted_range(struct vnode *vp, off_t off, off_t len)
1916{
1917	struct nfsnode *np = VTONFS(vp);
1918	off_t lo, hi;
1919
1920	if (!(np->n_commitflags & NFS_COMMIT_PUSH_VALID))
1921		return;
1922
1923	lo = off;
1924	hi = lo + len;
1925
1926	if (lo > np->n_pushhi || hi < np->n_pushlo)
1927		return;
1928
1929	if (lo <= np->n_pushlo)
1930		np->n_pushlo = hi;
1931	else if (hi >= np->n_pushhi)
1932		np->n_pushhi = lo;
1933	else {
1934		/*
1935		 * XXX There's only one range. If the deleted range
1936		 * is in the middle, pick the largest of the
1937		 * contiguous ranges that it leaves.
1938		 */
1939		if ((np->n_pushlo - lo) > (hi - np->n_pushhi))
1940			np->n_pushhi = lo;
1941		else
1942			np->n_pushlo = hi;
1943	}
1944#ifdef NFS_DEBUG_COMMIT
1945	printf("del: tobecommitted: %u - %u\n", (unsigned)np->n_pushlo,
1946	    (unsigned)np->n_pushhi);
1947#endif
1948}
1949
1950/*
1951 * Map errnos to NFS error numbers. For Version 3 also filter out error
1952 * numbers not specified for the associated procedure.
1953 */
1954int
1955nfsrv_errmap(struct nfsrv_descript *nd, int err)
1956{
1957	const short *defaulterrp, *errp;
1958
1959	if (nd->nd_flag & ND_NFSV3) {
1960	    if (nd->nd_procnum <= NFSPROC_COMMIT) {
1961		errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum];
1962		while (*++errp) {
1963			if (*errp == err)
1964				return (err);
1965			else if (*errp > err)
1966				break;
1967		}
1968		return ((int)*defaulterrp);
1969	    } else
1970		return (err & 0xffff);
1971	}
1972	if (err <= ELAST)
1973		return ((int)nfsrv_v2errmap[err - 1]);
1974	return (NFSERR_IO);
1975}
1976
1977u_int32_t
1978nfs_getxid(void)
1979{
1980	u_int32_t newxid;
1981
1982	/* get next xid.  skip 0 */
1983	do {
1984		newxid = atomic_inc_32_nv(&nfs_xid);
1985	} while (__predict_false(newxid == 0));
1986
1987	return txdr_unsigned(newxid);
1988}
1989
1990/*
1991 * assign a new xid for existing request.
1992 * used for NFSERR_JUKEBOX handling.
1993 */
1994void
1995nfs_renewxid(struct nfsreq *req)
1996{
1997	u_int32_t xid;
1998	int off;
1999
2000	xid = nfs_getxid();
2001	if (req->r_nmp->nm_sotype == SOCK_STREAM)
2002		off = sizeof(u_int32_t); /* RPC record mark */
2003	else
2004		off = 0;
2005
2006	m_copyback(req->r_mreq, off, sizeof(xid), (void *)&xid);
2007	req->r_xid = xid;
2008}
2009