xref: /freebsd/sys/fs/nfs/nfs_commonsubs.c (revision 5ffd83dbcc34f10e07f6d3e968ae6365869615f4)
1 /*-
2  * SPDX-License-Identifier: BSD-3-Clause
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  */
35 
36 #include <sys/cdefs.h>
37 __FBSDID("$FreeBSD$");
38 
39 /*
40  * These functions support the macros and help fiddle mbuf chains for
41  * the nfs op functions. They do things like create the rpc header and
42  * copy data between mbuf chains and uio lists.
43  */
44 #include "opt_inet.h"
45 #include "opt_inet6.h"
46 
47 #include <fs/nfs/nfsport.h>
48 
49 #include <sys/extattr.h>
50 
51 #include <security/mac/mac_framework.h>
52 
53 #include <vm/vm_param.h>
54 
55 /*
56  * Data items converted to xdr at startup, since they are constant
57  * This is kinda hokey, but may save a little time doing byte swaps
58  */
59 u_int32_t newnfs_true, newnfs_false, newnfs_xdrneg1;
60 
61 /* And other global data */
62 nfstype nfsv34_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK,
63 		      NFFIFO, NFNON };
64 enum vtype newnv2tov_type[8] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON };
65 enum vtype nv34tov_type[8]={ VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO };
66 struct timeval nfsboottime;	/* Copy boottime once, so it never changes */
67 int nfscl_ticks;
68 int nfsrv_useacl = 1;
69 struct nfssockreq nfsrv_nfsuserdsock;
70 nfsuserd_state nfsrv_nfsuserd = NOTRUNNING;
71 static int nfsrv_userdupcalls = 0;
72 struct nfsreqhead nfsd_reqq;
73 uid_t nfsrv_defaultuid = UID_NOBODY;
74 gid_t nfsrv_defaultgid = GID_NOGROUP;
75 int nfsrv_lease = NFSRV_LEASE;
76 int ncl_mbuf_mlen = MLEN;
77 int nfsd_enable_stringtouid = 0;
78 int nfsrv_doflexfile = 0;
79 static int nfs_enable_uidtostring = 0;
80 NFSNAMEIDMUTEX;
81 NFSSOCKMUTEX;
82 extern int nfsrv_lughashsize;
83 extern struct mtx nfsrv_dslock_mtx;
84 extern volatile int nfsrv_devidcnt;
85 extern int nfscl_debuglevel;
86 extern struct nfsdevicehead nfsrv_devidhead;
87 extern struct nfsstatsv1 nfsstatsv1;
88 
89 SYSCTL_DECL(_vfs_nfs);
90 SYSCTL_INT(_vfs_nfs, OID_AUTO, enable_uidtostring, CTLFLAG_RW,
91     &nfs_enable_uidtostring, 0, "Make nfs always send numeric owner_names");
92 
93 int nfsrv_maxpnfsmirror = 1;
94 SYSCTL_INT(_vfs_nfs, OID_AUTO, pnfsmirror, CTLFLAG_RD,
95     &nfsrv_maxpnfsmirror, 0, "Mirror level for pNFS service");
96 
97 int nfs_maxcopyrange = 10 * 1024 * 1024;
98 SYSCTL_INT(_vfs_nfs, OID_AUTO, maxcopyrange, CTLFLAG_RW,
99     &nfs_maxcopyrange, 0, "Max size of a Copy so RPC times reasonable");
100 
101 /*
102  * This array of structures indicates, for V4:
103  * retfh - which of 3 types of calling args are used
104  *	0 - doesn't change cfh or use a sfh
105  *	1 - replaces cfh with a new one (unless it returns an error status)
106  *	2 - uses cfh and sfh
107  * needscfh - if the op wants a cfh and premtime
108  *	0 - doesn't use a cfh
109  *	1 - uses a cfh, but doesn't want pre-op attributes
110  *	2 - uses a cfh and wants pre-op attributes
111  * savereply - indicates a non-idempotent Op
112  *	0 - not non-idempotent
113  *	1 - non-idempotent
114  * Ops that are ordered via seqid# are handled separately from these
115  * non-idempotent Ops.
116  * Define it here, since it is used by both the client and server.
117  */
118 struct nfsv4_opflag nfsv4_opflag[NFSV42_NOPS] = {
119 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* undef */
120 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* undef */
121 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* undef */
122 	{ 0, 1, 0, 0, LK_SHARED, 1, 1 },		/* Access */
123 	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 },		/* Close */
124 	{ 0, 2, 0, 1, LK_EXCLUSIVE, 1, 1 },		/* Commit */
125 	{ 1, 2, 1, 1, LK_EXCLUSIVE, 1, 1 },		/* Create */
126 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 },		/* Delegpurge */
127 	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 },		/* Delegreturn */
128 	{ 0, 1, 0, 0, LK_SHARED, 1, 1 },		/* Getattr */
129 	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* GetFH */
130 	{ 2, 1, 1, 1, LK_EXCLUSIVE, 1, 1 },		/* Link */
131 	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 },		/* Lock */
132 	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 },		/* LockT */
133 	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 },		/* LockU */
134 	{ 1, 2, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* Lookup */
135 	{ 1, 2, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* Lookupp */
136 	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* NVerify */
137 	{ 1, 1, 0, 1, LK_EXCLUSIVE, 1, 0 },		/* Open */
138 	{ 1, 1, 0, 0, LK_EXCLUSIVE, 1, 0 },		/* OpenAttr */
139 	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 },		/* OpenConfirm */
140 	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 },		/* OpenDowngrade */
141 	{ 1, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* PutFH */
142 	{ 1, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* PutPubFH */
143 	{ 1, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* PutRootFH */
144 	{ 0, 1, 0, 0, LK_SHARED, 1, 0 },		/* Read */
145 	{ 0, 1, 0, 0, LK_SHARED, 1, 1 },		/* Readdir */
146 	{ 0, 1, 0, 0, LK_SHARED, 1, 1 },		/* ReadLink */
147 	{ 0, 2, 1, 1, LK_EXCLUSIVE, 1, 1 },		/* Remove */
148 	{ 2, 1, 1, 1, LK_EXCLUSIVE, 1, 1 },		/* Rename */
149 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 },		/* Renew */
150 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* RestoreFH */
151 	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* SaveFH */
152 	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* SecInfo */
153 	{ 0, 2, 1, 1, LK_EXCLUSIVE, 1, 0 },		/* Setattr */
154 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* SetClientID */
155 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* SetClientIDConfirm */
156 	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* Verify */
157 	{ 0, 2, 1, 1, LK_EXCLUSIVE, 1, 0 },		/* Write */
158 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 },		/* ReleaseLockOwner */
159 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* Backchannel Ctrl */
160 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 },		/* Bind Conn to Sess */
161 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 },		/* Exchange ID */
162 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 },		/* Create Session */
163 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 },		/* Destroy Session */
164 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 },		/* Free StateID */
165 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* Get Dir Deleg */
166 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* Get Device Info */
167 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* Get Device List */
168 	{ 0, 1, 0, 1, LK_EXCLUSIVE, 1, 1 },		/* Layout Commit */
169 	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* Layout Get */
170 	{ 0, 1, 0, 1, LK_EXCLUSIVE, 1, 0 },		/* Layout Return */
171 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* Secinfo No name */
172 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 },		/* Sequence */
173 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* Set SSV */
174 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* Test StateID */
175 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* Want Delegation */
176 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 },		/* Destroy ClientID */
177 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 },		/* Reclaim Complete */
178 	{ 0, 1, 1, 1, LK_EXCLUSIVE, 1, 0 },		/* Allocate */
179 	{ 2, 1, 1, 0, LK_SHARED, 1, 0 },		/* Copy */
180 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* Copy Notify */
181 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* Deallocate */
182 	{ 0, 1, 0, 0, LK_SHARED, 1, 0 },		/* IO Advise */
183 	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 },		/* Layout Error */
184 	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 },		/* Layout Stats */
185 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* Offload Cancel */
186 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* Offload Status */
187 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* Read Plus */
188 	{ 0, 1, 0, 0, LK_SHARED, 1, 0 },		/* Seek */
189 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* Write Same */
190 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* Clone */
191 	{ 0, 1, 0, 0, LK_SHARED, 1, 1 },		/* Getxattr */
192 	{ 0, 1, 1, 1, LK_EXCLUSIVE, 1, 1 },		/* Setxattr */
193 	{ 0, 1, 0, 0, LK_SHARED, 1, 1 },		/* Listxattrs */
194 	{ 0, 1, 1, 1, LK_EXCLUSIVE, 1, 1 },		/* Removexattr */
195 };
196 
197 static int ncl_mbuf_mhlen = MHLEN;
198 static int nfsrv_usercnt = 0;
199 static int nfsrv_dnsnamelen;
200 static u_char *nfsrv_dnsname = NULL;
201 static int nfsrv_usermax = 999999999;
202 struct nfsrv_lughash {
203 	struct mtx		mtx;
204 	struct nfsuserhashhead	lughead;
205 };
206 static struct nfsrv_lughash	*nfsuserhash;
207 static struct nfsrv_lughash	*nfsusernamehash;
208 static struct nfsrv_lughash	*nfsgrouphash;
209 static struct nfsrv_lughash	*nfsgroupnamehash;
210 
211 /*
212  * This static array indicates whether or not the RPC generates a large
213  * reply. This is used by nfs_reply() to decide whether or not an mbuf
214  * cluster should be allocated. (If a cluster is required by an RPC
215  * marked 0 in this array, the code will still work, just not quite as
216  * efficiently.)
217  */
218 static int nfs_bigreply[NFSV42_NPROCS] = { 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0,
219     0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
220     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
221     1, 0, 0, 1 };
222 
223 /* local functions */
224 static int nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep);
225 static void nfsv4_wanted(struct nfsv4lock *lp);
226 static int nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len);
227 static int nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name);
228 static void nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser);
229 static int nfsrv_getrefstr(struct nfsrv_descript *, u_char **, u_char **,
230     int *, int *);
231 static void nfsrv_refstrbigenough(int, u_char **, u_char **, int *);
232 
233 static struct {
234 	int	op;
235 	int	opcnt;
236 	const u_char *tag;
237 	int	taglen;
238 } nfsv4_opmap[NFSV42_NPROCS] = {
239 	{ 0, 1, "Null", 4 },
240 	{ NFSV4OP_GETATTR, 1, "Getattr", 7, },
241 	{ NFSV4OP_SETATTR, 2, "Setattr", 7, },
242 	{ NFSV4OP_LOOKUP, 3, "Lookup", 6, },
243 	{ NFSV4OP_ACCESS, 2, "Access", 6, },
244 	{ NFSV4OP_READLINK, 2, "Readlink", 8, },
245 	{ NFSV4OP_READ, 1, "Read", 4, },
246 	{ NFSV4OP_WRITE, 2, "Write", 5, },
247 	{ NFSV4OP_OPEN, 5, "Open", 4, },
248 	{ NFSV4OP_CREATE, 5, "Create", 6, },
249 	{ NFSV4OP_CREATE, 1, "Create", 6, },
250 	{ NFSV4OP_CREATE, 3, "Create", 6, },
251 	{ NFSV4OP_REMOVE, 1, "Remove", 6, },
252 	{ NFSV4OP_REMOVE, 1, "Remove", 6, },
253 	{ NFSV4OP_SAVEFH, 5, "Rename", 6, },
254 	{ NFSV4OP_SAVEFH, 4, "Link", 4, },
255 	{ NFSV4OP_READDIR, 2, "Readdir", 7, },
256 	{ NFSV4OP_READDIR, 2, "Readdir", 7, },
257 	{ NFSV4OP_GETATTR, 1, "Getattr", 7, },
258 	{ NFSV4OP_GETATTR, 1, "Getattr", 7, },
259 	{ NFSV4OP_GETATTR, 1, "Getattr", 7, },
260 	{ NFSV4OP_COMMIT, 2, "Commit", 6, },
261 	{ NFSV4OP_LOOKUPP, 3, "Lookupp", 7, },
262 	{ NFSV4OP_SETCLIENTID, 1, "SetClientID", 11, },
263 	{ NFSV4OP_SETCLIENTIDCFRM, 1, "SetClientIDConfirm", 18, },
264 	{ NFSV4OP_LOCK, 1, "Lock", 4, },
265 	{ NFSV4OP_LOCKU, 1, "LockU", 5, },
266 	{ NFSV4OP_OPEN, 2, "Open", 4, },
267 	{ NFSV4OP_CLOSE, 1, "Close", 5, },
268 	{ NFSV4OP_OPENCONFIRM, 1, "Openconfirm", 11, },
269 	{ NFSV4OP_LOCKT, 1, "LockT", 5, },
270 	{ NFSV4OP_OPENDOWNGRADE, 1, "Opendowngrade", 13, },
271 	{ NFSV4OP_RENEW, 1, "Renew", 5, },
272 	{ NFSV4OP_PUTROOTFH, 1, "Dirpath", 7, },
273 	{ NFSV4OP_RELEASELCKOWN, 1, "Rellckown", 9, },
274 	{ NFSV4OP_DELEGRETURN, 1, "Delegret", 8, },
275 	{ NFSV4OP_DELEGRETURN, 3, "DelegRemove", 11, },
276 	{ NFSV4OP_DELEGRETURN, 7, "DelegRename1", 12, },
277 	{ NFSV4OP_DELEGRETURN, 9, "DelegRename2", 12, },
278 	{ NFSV4OP_GETATTR, 1, "Getacl", 6, },
279 	{ NFSV4OP_SETATTR, 1, "Setacl", 6, },
280 	{ NFSV4OP_EXCHANGEID, 1, "ExchangeID", 10, },
281 	{ NFSV4OP_CREATESESSION, 1, "CreateSession", 13, },
282 	{ NFSV4OP_DESTROYSESSION, 1, "DestroySession", 14, },
283 	{ NFSV4OP_DESTROYCLIENTID, 1, "DestroyClient", 13, },
284 	{ NFSV4OP_FREESTATEID, 1, "FreeStateID", 11, },
285 	{ NFSV4OP_LAYOUTGET, 1, "LayoutGet", 9, },
286 	{ NFSV4OP_GETDEVINFO, 1, "GetDeviceInfo", 13, },
287 	{ NFSV4OP_LAYOUTCOMMIT, 1, "LayoutCommit", 12, },
288 	{ NFSV4OP_LAYOUTRETURN, 1, "LayoutReturn", 12, },
289 	{ NFSV4OP_RECLAIMCOMPL, 1, "ReclaimComplete", 15, },
290 	{ NFSV4OP_WRITE, 1, "WriteDS", 7, },
291 	{ NFSV4OP_READ, 1, "ReadDS", 6, },
292 	{ NFSV4OP_COMMIT, 1, "CommitDS", 8, },
293 	{ NFSV4OP_OPEN, 3, "OpenLayoutGet", 13, },
294 	{ NFSV4OP_OPEN, 8, "CreateLayGet", 12, },
295 	{ NFSV4OP_IOADVISE, 1, "Advise", 6, },
296 	{ NFSV4OP_ALLOCATE, 2, "Allocate", 8, },
297 	{ NFSV4OP_SAVEFH, 5, "Copy", 4, },
298 	{ NFSV4OP_SEEK, 2, "Seek", 4, },
299 	{ NFSV4OP_SEEK, 1, "SeekDS", 6, },
300 	{ NFSV4OP_GETXATTR, 2, "Getxattr", 8, },
301 	{ NFSV4OP_SETXATTR, 2, "Setxattr", 8, },
302 	{ NFSV4OP_REMOVEXATTR, 2, "Rmxattr", 7, },
303 	{ NFSV4OP_LISTXATTRS, 2, "Listxattr", 9, },
304 };
305 
306 /*
307  * NFS RPCS that have large request message size.
308  */
309 static int nfs_bigrequest[NFSV42_NPROCS] = {
310 	0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
311 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
312 	0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0
313 };
314 
315 /*
316  * Start building a request. Mostly just put the first file handle in
317  * place.
318  */
319 void
320 nfscl_reqstart(struct nfsrv_descript *nd, int procnum, struct nfsmount *nmp,
321     u_int8_t *nfhp, int fhlen, u_int32_t **opcntpp, struct nfsclsession *sep,
322     int vers, int minorvers, bool use_ext)
323 {
324 	struct mbuf *mb;
325 	u_int32_t *tl;
326 	int opcnt;
327 	nfsattrbit_t attrbits;
328 
329 	/*
330 	 * First, fill in some of the fields of nd.
331 	 */
332 	nd->nd_slotseq = NULL;
333 	if (vers == NFS_VER4) {
334 		nd->nd_flag = ND_NFSV4 | ND_NFSCL;
335 		if (minorvers == NFSV41_MINORVERSION)
336 			nd->nd_flag |= ND_NFSV41;
337 		else if (minorvers == NFSV42_MINORVERSION)
338 			nd->nd_flag |= (ND_NFSV41 | ND_NFSV42);
339 	} else if (vers == NFS_VER3)
340 		nd->nd_flag = ND_NFSV3 | ND_NFSCL;
341 	else {
342 		if (NFSHASNFSV4(nmp)) {
343 			nd->nd_flag = ND_NFSV4 | ND_NFSCL;
344 			if (nmp->nm_minorvers == 1)
345 				nd->nd_flag |= ND_NFSV41;
346 			else if (nmp->nm_minorvers == 2)
347 				nd->nd_flag |= (ND_NFSV41 | ND_NFSV42);
348 		} else if (NFSHASNFSV3(nmp))
349 			nd->nd_flag = ND_NFSV3 | ND_NFSCL;
350 		else
351 			nd->nd_flag = ND_NFSV2 | ND_NFSCL;
352 	}
353 	nd->nd_procnum = procnum;
354 	nd->nd_repstat = 0;
355 	nd->nd_maxextsiz = 16384;
356 	if (use_ext && mb_use_ext_pgs && PMAP_HAS_DMAP != 0)
357 		nd->nd_flag |= ND_EXTPG;
358 
359 	/*
360 	 * Get the first mbuf for the request.
361 	 */
362 	if ((nd->nd_flag & ND_EXTPG) != 0) {
363 		mb = mb_alloc_ext_plus_pages(PAGE_SIZE, M_WAITOK);
364 		nd->nd_mreq = nd->nd_mb = mb;
365 		nfsm_set(nd, 0);
366 	} else {
367 		if (nfs_bigrequest[procnum])
368 			NFSMCLGET(mb, M_WAITOK);
369 		else
370 			NFSMGET(mb);
371 		mb->m_len = 0;
372 		nd->nd_mreq = nd->nd_mb = mb;
373 		nd->nd_bpos = mtod(mb, char *);
374 	}
375 
376 	/*
377 	 * And fill the first file handle into the request.
378 	 */
379 	if (nd->nd_flag & ND_NFSV4) {
380 		opcnt = nfsv4_opmap[procnum].opcnt +
381 		    nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh;
382 		if ((nd->nd_flag & ND_NFSV41) != 0) {
383 			opcnt += nfsv4_opflag[nfsv4_opmap[procnum].op].needsseq;
384 			if (procnum == NFSPROC_RENEW)
385 				/*
386 				 * For the special case of Renew, just do a
387 				 * Sequence Op.
388 				 */
389 				opcnt = 1;
390 			else if (procnum == NFSPROC_WRITEDS ||
391 			    procnum == NFSPROC_COMMITDS)
392 				/*
393 				 * For the special case of a Writeor Commit to
394 				 * a DS, the opcnt == 3, for Sequence, PutFH,
395 				 * Write/Commit.
396 				 */
397 				opcnt = 3;
398 		}
399 		/*
400 		 * What should the tag really be?
401 		 */
402 		(void) nfsm_strtom(nd, nfsv4_opmap[procnum].tag,
403 			nfsv4_opmap[procnum].taglen);
404 		NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
405 		if ((nd->nd_flag & ND_NFSV42) != 0)
406 			*tl++ = txdr_unsigned(NFSV42_MINORVERSION);
407 		else if ((nd->nd_flag & ND_NFSV41) != 0)
408 			*tl++ = txdr_unsigned(NFSV41_MINORVERSION);
409 		else
410 			*tl++ = txdr_unsigned(NFSV4_MINORVERSION);
411 		if (opcntpp != NULL)
412 			*opcntpp = tl;
413 		*tl = txdr_unsigned(opcnt);
414 		if ((nd->nd_flag & ND_NFSV41) != 0 &&
415 		    nfsv4_opflag[nfsv4_opmap[procnum].op].needsseq > 0) {
416 			if (nfsv4_opflag[nfsv4_opmap[procnum].op].loopbadsess >
417 			    0)
418 				nd->nd_flag |= ND_LOOPBADSESS;
419 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
420 			*tl = txdr_unsigned(NFSV4OP_SEQUENCE);
421 			if (sep == NULL) {
422 				sep = nfsmnt_mdssession(nmp);
423 				nfsv4_setsequence(nmp, nd, sep,
424 				    nfs_bigreply[procnum]);
425 			} else
426 				nfsv4_setsequence(nmp, nd, sep,
427 				    nfs_bigreply[procnum]);
428 		}
429 		if (nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh > 0) {
430 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
431 			*tl = txdr_unsigned(NFSV4OP_PUTFH);
432 			(void) nfsm_fhtom(nd, nfhp, fhlen, 0);
433 			if (nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh
434 			    == 2 && procnum != NFSPROC_WRITEDS &&
435 			    procnum != NFSPROC_COMMITDS) {
436 				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
437 				*tl = txdr_unsigned(NFSV4OP_GETATTR);
438 				/*
439 				 * For Lookup Ops, we want all the directory
440 				 * attributes, so we can load the name cache.
441 				 */
442 				if (procnum == NFSPROC_LOOKUP ||
443 				    procnum == NFSPROC_LOOKUPP)
444 					NFSGETATTR_ATTRBIT(&attrbits);
445 				else {
446 					NFSWCCATTR_ATTRBIT(&attrbits);
447 					nd->nd_flag |= ND_V4WCCATTR;
448 				}
449 				(void) nfsrv_putattrbit(nd, &attrbits);
450 			}
451 		}
452 		if (procnum != NFSPROC_RENEW ||
453 		    (nd->nd_flag & ND_NFSV41) == 0) {
454 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
455 			*tl = txdr_unsigned(nfsv4_opmap[procnum].op);
456 		}
457 	} else {
458 		(void) nfsm_fhtom(nd, nfhp, fhlen, 0);
459 	}
460 	if (procnum < NFSV42_NPROCS)
461 		NFSINCRGLOBAL(nfsstatsv1.rpccnt[procnum]);
462 }
463 
464 /*
465  * Put a state Id in the mbuf list.
466  */
467 void
468 nfsm_stateidtom(struct nfsrv_descript *nd, nfsv4stateid_t *stateidp, int flag)
469 {
470 	nfsv4stateid_t *st;
471 
472 	NFSM_BUILD(st, nfsv4stateid_t *, NFSX_STATEID);
473 	if (flag == NFSSTATEID_PUTALLZERO) {
474 		st->seqid = 0;
475 		st->other[0] = 0;
476 		st->other[1] = 0;
477 		st->other[2] = 0;
478 	} else if (flag == NFSSTATEID_PUTALLONE) {
479 		st->seqid = 0xffffffff;
480 		st->other[0] = 0xffffffff;
481 		st->other[1] = 0xffffffff;
482 		st->other[2] = 0xffffffff;
483 	} else if (flag == NFSSTATEID_PUTSEQIDZERO) {
484 		st->seqid = 0;
485 		st->other[0] = stateidp->other[0];
486 		st->other[1] = stateidp->other[1];
487 		st->other[2] = stateidp->other[2];
488 	} else {
489 		st->seqid = stateidp->seqid;
490 		st->other[0] = stateidp->other[0];
491 		st->other[1] = stateidp->other[1];
492 		st->other[2] = stateidp->other[2];
493 	}
494 }
495 
496 /*
497  * Fill in the setable attributes. The full argument indicates whether
498  * to fill in them all or just mode and time.
499  */
500 void
501 nfscl_fillsattr(struct nfsrv_descript *nd, struct vattr *vap,
502     struct vnode *vp, int flags, u_int32_t rdev)
503 {
504 	u_int32_t *tl;
505 	struct nfsv2_sattr *sp;
506 	nfsattrbit_t attrbits;
507 	struct nfsnode *np;
508 
509 	switch (nd->nd_flag & (ND_NFSV2 | ND_NFSV3 | ND_NFSV4)) {
510 	case ND_NFSV2:
511 		NFSM_BUILD(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
512 		if (vap->va_mode == (mode_t)VNOVAL)
513 			sp->sa_mode = newnfs_xdrneg1;
514 		else
515 			sp->sa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
516 		if (vap->va_uid == (uid_t)VNOVAL)
517 			sp->sa_uid = newnfs_xdrneg1;
518 		else
519 			sp->sa_uid = txdr_unsigned(vap->va_uid);
520 		if (vap->va_gid == (gid_t)VNOVAL)
521 			sp->sa_gid = newnfs_xdrneg1;
522 		else
523 			sp->sa_gid = txdr_unsigned(vap->va_gid);
524 		if (flags & NFSSATTR_SIZE0)
525 			sp->sa_size = 0;
526 		else if (flags & NFSSATTR_SIZENEG1)
527 			sp->sa_size = newnfs_xdrneg1;
528 		else if (flags & NFSSATTR_SIZERDEV)
529 			sp->sa_size = txdr_unsigned(rdev);
530 		else
531 			sp->sa_size = txdr_unsigned(vap->va_size);
532 		txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
533 		txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
534 		break;
535 	case ND_NFSV3:
536 		if (vap->va_mode != (mode_t)VNOVAL) {
537 			NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
538 			*tl++ = newnfs_true;
539 			*tl = txdr_unsigned(vap->va_mode);
540 		} else {
541 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
542 			*tl = newnfs_false;
543 		}
544 		if ((flags & NFSSATTR_FULL) && vap->va_uid != (uid_t)VNOVAL) {
545 			NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
546 			*tl++ = newnfs_true;
547 			*tl = txdr_unsigned(vap->va_uid);
548 		} else {
549 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
550 			*tl = newnfs_false;
551 		}
552 		if ((flags & NFSSATTR_FULL) && vap->va_gid != (gid_t)VNOVAL) {
553 			NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
554 			*tl++ = newnfs_true;
555 			*tl = txdr_unsigned(vap->va_gid);
556 		} else {
557 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
558 			*tl = newnfs_false;
559 		}
560 		if ((flags & NFSSATTR_FULL) && vap->va_size != VNOVAL) {
561 			NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
562 			*tl++ = newnfs_true;
563 			txdr_hyper(vap->va_size, tl);
564 		} else {
565 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
566 			*tl = newnfs_false;
567 		}
568 		if (vap->va_atime.tv_sec != VNOVAL) {
569 			if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
570 				NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
571 				*tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
572 				txdr_nfsv3time(&vap->va_atime, tl);
573 			} else {
574 				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
575 				*tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
576 			}
577 		} else {
578 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
579 			*tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
580 		}
581 		if (vap->va_mtime.tv_sec != VNOVAL) {
582 			if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
583 				NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
584 				*tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
585 				txdr_nfsv3time(&vap->va_mtime, tl);
586 			} else {
587 				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
588 				*tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
589 			}
590 		} else {
591 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
592 			*tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
593 		}
594 		break;
595 	case ND_NFSV4:
596 		NFSZERO_ATTRBIT(&attrbits);
597 		if (vap->va_mode != (mode_t)VNOVAL)
598 			NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_MODE);
599 		if ((flags & NFSSATTR_FULL) && vap->va_uid != (uid_t)VNOVAL)
600 			NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
601 		if ((flags & NFSSATTR_FULL) && vap->va_gid != (gid_t)VNOVAL)
602 			NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP);
603 		if ((flags & NFSSATTR_FULL) && vap->va_size != VNOVAL)
604 			NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_SIZE);
605 		if (vap->va_atime.tv_sec != VNOVAL)
606 			NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET);
607 		if (vap->va_mtime.tv_sec != VNOVAL)
608 			NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET);
609 		if (vap->va_birthtime.tv_sec != VNOVAL &&
610 		    strcmp(vp->v_mount->mnt_vfc->vfc_name, "nfs") == 0) {
611 			/*
612 			 * We can only test for support of TimeCreate if
613 			 * the "vp" argument is for an NFS vnode.
614 			 */
615 			np = VTONFS(vp);
616 			if (NFSISSET_ATTRBIT(&np->n_vattr.na_suppattr,
617 			    NFSATTRBIT_TIMECREATE))
618 				NFSSETBIT_ATTRBIT(&attrbits,
619 				    NFSATTRBIT_TIMECREATE);
620 		}
621 		(void) nfsv4_fillattr(nd, vp->v_mount, vp, NULL, vap, NULL, 0,
622 		    &attrbits, NULL, NULL, 0, 0, 0, 0, (uint64_t)0, NULL);
623 		break;
624 	}
625 }
626 
627 #ifndef APPLE
628 /*
629  * copies mbuf chain to the uio scatter/gather list
630  */
631 int
632 nfsm_mbufuio(struct nfsrv_descript *nd, struct uio *uiop, int siz)
633 {
634 	char *mbufcp, *uiocp;
635 	int xfer, left, len;
636 	struct mbuf *mp;
637 	long uiosiz, rem;
638 	int error = 0;
639 
640 	mp = nd->nd_md;
641 	mbufcp = nd->nd_dpos;
642 	len = mtod(mp, caddr_t) + mp->m_len - mbufcp;
643 	rem = NFSM_RNDUP(siz) - siz;
644 	while (siz > 0) {
645 		if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) {
646 			error = EBADRPC;
647 			goto out;
648 		}
649 		left = uiop->uio_iov->iov_len;
650 		uiocp = uiop->uio_iov->iov_base;
651 		if (left > siz)
652 			left = siz;
653 		uiosiz = left;
654 		while (left > 0) {
655 			while (len == 0) {
656 				mp = mp->m_next;
657 				if (mp == NULL) {
658 					error = EBADRPC;
659 					goto out;
660 				}
661 				mbufcp = mtod(mp, caddr_t);
662 				len = mp->m_len;
663 				KASSERT(len >= 0,
664 				    ("len %d, corrupted mbuf?", len));
665 			}
666 			xfer = (left > len) ? len : left;
667 #ifdef notdef
668 			/* Not Yet.. */
669 			if (uiop->uio_iov->iov_op != NULL)
670 				(*(uiop->uio_iov->iov_op))
671 				(mbufcp, uiocp, xfer);
672 			else
673 #endif
674 			if (uiop->uio_segflg == UIO_SYSSPACE)
675 				NFSBCOPY(mbufcp, uiocp, xfer);
676 			else
677 				copyout(mbufcp, uiocp, xfer);
678 			left -= xfer;
679 			len -= xfer;
680 			mbufcp += xfer;
681 			uiocp += xfer;
682 			uiop->uio_offset += xfer;
683 			uiop->uio_resid -= xfer;
684 		}
685 		if (uiop->uio_iov->iov_len <= siz) {
686 			uiop->uio_iovcnt--;
687 			uiop->uio_iov++;
688 		} else {
689 			uiop->uio_iov->iov_base = (void *)
690 				((char *)uiop->uio_iov->iov_base + uiosiz);
691 			uiop->uio_iov->iov_len -= uiosiz;
692 		}
693 		siz -= uiosiz;
694 	}
695 	nd->nd_dpos = mbufcp;
696 	nd->nd_md = mp;
697 	if (rem > 0) {
698 		if (len < rem)
699 			error = nfsm_advance(nd, rem, len);
700 		else
701 			nd->nd_dpos += rem;
702 	}
703 
704 out:
705 	NFSEXITCODE2(error, nd);
706 	return (error);
707 }
708 #endif	/* !APPLE */
709 
710 /*
711  * Help break down an mbuf chain by setting the first siz bytes contiguous
712  * pointed to by returned val.
713  * This is used by the macro NFSM_DISSECT for tough
714  * cases.
715  */
716 void *
717 nfsm_dissct(struct nfsrv_descript *nd, int siz, int how)
718 {
719 	struct mbuf *mp2;
720 	int siz2, xfer;
721 	caddr_t p;
722 	int left;
723 	caddr_t retp;
724 
725 	retp = NULL;
726 	left = mtod(nd->nd_md, caddr_t) + nd->nd_md->m_len - nd->nd_dpos;
727 	while (left == 0) {
728 		nd->nd_md = nd->nd_md->m_next;
729 		if (nd->nd_md == NULL)
730 			return (retp);
731 		left = nd->nd_md->m_len;
732 		nd->nd_dpos = mtod(nd->nd_md, caddr_t);
733 	}
734 	if (left >= siz) {
735 		retp = nd->nd_dpos;
736 		nd->nd_dpos += siz;
737 	} else if (nd->nd_md->m_next == NULL) {
738 		return (retp);
739 	} else if (siz > ncl_mbuf_mhlen) {
740 		panic("nfs S too big");
741 	} else {
742 		MGET(mp2, MT_DATA, how);
743 		if (mp2 == NULL)
744 			return (NULL);
745 		mp2->m_next = nd->nd_md->m_next;
746 		nd->nd_md->m_next = mp2;
747 		nd->nd_md->m_len -= left;
748 		nd->nd_md = mp2;
749 		retp = p = mtod(mp2, caddr_t);
750 		NFSBCOPY(nd->nd_dpos, p, left);	/* Copy what was left */
751 		siz2 = siz - left;
752 		p += left;
753 		mp2 = mp2->m_next;
754 		/* Loop around copying up the siz2 bytes */
755 		while (siz2 > 0) {
756 			if (mp2 == NULL)
757 				return (NULL);
758 			xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2;
759 			if (xfer > 0) {
760 				NFSBCOPY(mtod(mp2, caddr_t), p, xfer);
761 				mp2->m_data += xfer;
762 				mp2->m_len -= xfer;
763 				p += xfer;
764 				siz2 -= xfer;
765 			}
766 			if (siz2 > 0)
767 				mp2 = mp2->m_next;
768 		}
769 		nd->nd_md->m_len = siz;
770 		nd->nd_md = mp2;
771 		nd->nd_dpos = mtod(mp2, caddr_t);
772 	}
773 	return (retp);
774 }
775 
776 /*
777  * Advance the position in the mbuf chain.
778  * If offs == 0, this is a no-op, but it is simpler to just return from
779  * here than check for offs > 0 for all calls to nfsm_advance.
780  * If left == -1, it should be calculated here.
781  */
782 int
783 nfsm_advance(struct nfsrv_descript *nd, int offs, int left)
784 {
785 	int error = 0;
786 
787 	if (offs == 0)
788 		goto out;
789 	/*
790 	 * A negative offs might indicate a corrupted mbuf chain and,
791 	 * as such, a printf is logged.
792 	 */
793 	if (offs < 0) {
794 		printf("nfsrv_advance: negative offs\n");
795 		error = EBADRPC;
796 		goto out;
797 	}
798 
799 	/*
800 	 * If left == -1, calculate it here.
801 	 */
802 	if (left == -1)
803 		left = mtod(nd->nd_md, caddr_t) + nd->nd_md->m_len -
804 		    nd->nd_dpos;
805 
806 	/*
807 	 * Loop around, advancing over the mbuf data.
808 	 */
809 	while (offs > left) {
810 		offs -= left;
811 		nd->nd_md = nd->nd_md->m_next;
812 		if (nd->nd_md == NULL) {
813 			error = EBADRPC;
814 			goto out;
815 		}
816 		left = nd->nd_md->m_len;
817 		nd->nd_dpos = mtod(nd->nd_md, caddr_t);
818 	}
819 	nd->nd_dpos += offs;
820 
821 out:
822 	NFSEXITCODE(error);
823 	return (error);
824 }
825 
826 /*
827  * Copy a string into mbuf(s).
828  * Return the number of bytes output, including XDR overheads.
829  */
830 int
831 nfsm_strtom(struct nfsrv_descript *nd, const char *cp, int siz)
832 {
833 	struct mbuf *m2;
834 	int xfer, left;
835 	struct mbuf *m1;
836 	int rem, bytesize;
837 	u_int32_t *tl;
838 	char *cp2;
839 
840 	NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
841 	*tl = txdr_unsigned(siz);
842 	rem = NFSM_RNDUP(siz) - siz;
843 	bytesize = NFSX_UNSIGNED + siz + rem;
844 	m2 = nd->nd_mb;
845 	cp2 = nd->nd_bpos;
846 	if ((nd->nd_flag & ND_EXTPG) != 0)
847 		left = nd->nd_bextpgsiz;
848 	else
849 		left = M_TRAILINGSPACE(m2);
850 
851 	KASSERT(((m2->m_flags & (M_EXT | M_EXTPG)) ==
852 	    (M_EXT | M_EXTPG) && (nd->nd_flag & ND_EXTPG) != 0) ||
853 	    ((m2->m_flags & (M_EXT | M_EXTPG)) !=
854 	    (M_EXT | M_EXTPG) && (nd->nd_flag & ND_EXTPG) == 0),
855 	    ("nfsm_strtom: ext_pgs and non-ext_pgs mbufs mixed"));
856 	/*
857 	 * Loop around copying the string to mbuf(s).
858 	 */
859 	while (siz > 0) {
860 		if (left == 0) {
861 			if ((nd->nd_flag & ND_EXTPG) != 0) {
862 				m2 = nfsm_add_ext_pgs(m2,
863 				    nd->nd_maxextsiz, &nd->nd_bextpg);
864 				cp2 = (char *)(void *)PHYS_TO_DMAP(
865 				    m2->m_epg_pa[nd->nd_bextpg]);
866 				nd->nd_bextpgsiz = left = PAGE_SIZE;
867 			} else {
868 				if (siz > ncl_mbuf_mlen)
869 					NFSMCLGET(m1, M_WAITOK);
870 				else
871 					NFSMGET(m1);
872 				m1->m_len = 0;
873 				cp2 = mtod(m1, char *);
874 				left = M_TRAILINGSPACE(m1);
875 				m2->m_next = m1;
876 				m2 = m1;
877 			}
878 		}
879 		if (left >= siz)
880 			xfer = siz;
881 		else
882 			xfer = left;
883 		NFSBCOPY(cp, cp2, xfer);
884 		cp += xfer;
885 		cp2 += xfer;
886 		m2->m_len += xfer;
887 		siz -= xfer;
888 		left -= xfer;
889 		if ((nd->nd_flag & ND_EXTPG) != 0) {
890 			nd->nd_bextpgsiz -= xfer;
891 			m2->m_epg_last_len += xfer;
892 		}
893 		if (siz == 0 && rem) {
894 			if (left < rem)
895 				panic("nfsm_strtom");
896 			NFSBZERO(cp2, rem);
897 			m2->m_len += rem;
898 			cp2 += rem;
899 			if ((nd->nd_flag & ND_EXTPG) != 0) {
900 				nd->nd_bextpgsiz -= rem;
901 				m2->m_epg_last_len += rem;
902 			}
903 		}
904 	}
905 	nd->nd_mb = m2;
906 	if ((nd->nd_flag & ND_EXTPG) != 0)
907 		nd->nd_bpos = cp2;
908 	else
909 		nd->nd_bpos = mtod(m2, char *) + m2->m_len;
910 	return (bytesize);
911 }
912 
913 /*
914  * Called once to initialize data structures...
915  */
916 void
917 newnfs_init(void)
918 {
919 	static int nfs_inited = 0;
920 
921 	if (nfs_inited)
922 		return;
923 	nfs_inited = 1;
924 
925 	newnfs_true = txdr_unsigned(TRUE);
926 	newnfs_false = txdr_unsigned(FALSE);
927 	newnfs_xdrneg1 = txdr_unsigned(-1);
928 	nfscl_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
929 	if (nfscl_ticks < 1)
930 		nfscl_ticks = 1;
931 	NFSSETBOOTTIME(nfsboottime);
932 
933 	/*
934 	 * Initialize reply list and start timer
935 	 */
936 	TAILQ_INIT(&nfsd_reqq);
937 	NFS_TIMERINIT;
938 }
939 
940 /*
941  * Put a file handle in an mbuf list.
942  * If the size argument == 0, just use the default size.
943  * set_true == 1 if there should be an newnfs_true prepended on the file handle.
944  * Return the number of bytes output, including XDR overhead.
945  */
946 int
947 nfsm_fhtom(struct nfsrv_descript *nd, u_int8_t *fhp, int size, int set_true)
948 {
949 	u_int32_t *tl;
950 	u_int8_t *cp;
951 	int fullsiz, rem, bytesize = 0;
952 
953 	if (size == 0)
954 		size = NFSX_MYFH;
955 	switch (nd->nd_flag & (ND_NFSV2 | ND_NFSV3 | ND_NFSV4)) {
956 	case ND_NFSV2:
957 		if (size > NFSX_V2FH)
958 			panic("fh size > NFSX_V2FH for NFSv2");
959 		NFSM_BUILD(cp, u_int8_t *, NFSX_V2FH);
960 		NFSBCOPY(fhp, cp, size);
961 		if (size < NFSX_V2FH)
962 			NFSBZERO(cp + size, NFSX_V2FH - size);
963 		bytesize = NFSX_V2FH;
964 		break;
965 	case ND_NFSV3:
966 	case ND_NFSV4:
967 		fullsiz = NFSM_RNDUP(size);
968 		rem = fullsiz - size;
969 		if (set_true) {
970 		    bytesize = 2 * NFSX_UNSIGNED + fullsiz;
971 		    NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
972 		    *tl = newnfs_true;
973 		} else {
974 		    bytesize = NFSX_UNSIGNED + fullsiz;
975 		}
976 		(void) nfsm_strtom(nd, fhp, size);
977 		break;
978 	}
979 	return (bytesize);
980 }
981 
982 /*
983  * This function compares two net addresses by family and returns TRUE
984  * if they are the same host.
985  * If there is any doubt, return FALSE.
986  * The AF_INET family is handled as a special case so that address mbufs
987  * don't need to be saved to store "struct in_addr", which is only 4 bytes.
988  */
989 int
990 nfsaddr_match(int family, union nethostaddr *haddr, NFSSOCKADDR_T nam)
991 {
992 #ifdef INET
993 	struct sockaddr_in *inetaddr;
994 #endif
995 
996 	switch (family) {
997 #ifdef INET
998 	case AF_INET:
999 		inetaddr = NFSSOCKADDR(nam, struct sockaddr_in *);
1000 		if (inetaddr->sin_family == AF_INET &&
1001 		    inetaddr->sin_addr.s_addr == haddr->had_inet.s_addr)
1002 			return (1);
1003 		break;
1004 #endif
1005 #ifdef INET6
1006 	case AF_INET6:
1007 		{
1008 		struct sockaddr_in6 *inetaddr6;
1009 
1010 		inetaddr6 = NFSSOCKADDR(nam, struct sockaddr_in6 *);
1011 		/* XXX - should test sin6_scope_id ? */
1012 		if (inetaddr6->sin6_family == AF_INET6 &&
1013 		    IN6_ARE_ADDR_EQUAL(&inetaddr6->sin6_addr,
1014 			  &haddr->had_inet6))
1015 			return (1);
1016 		}
1017 		break;
1018 #endif
1019 	}
1020 	return (0);
1021 }
1022 
1023 /*
1024  * Similar to the above, but takes to NFSSOCKADDR_T args.
1025  */
1026 int
1027 nfsaddr2_match(NFSSOCKADDR_T nam1, NFSSOCKADDR_T nam2)
1028 {
1029 	struct sockaddr_in *addr1, *addr2;
1030 	struct sockaddr *inaddr;
1031 
1032 	inaddr = NFSSOCKADDR(nam1, struct sockaddr *);
1033 	switch (inaddr->sa_family) {
1034 	case AF_INET:
1035 		addr1 = NFSSOCKADDR(nam1, struct sockaddr_in *);
1036 		addr2 = NFSSOCKADDR(nam2, struct sockaddr_in *);
1037 		if (addr2->sin_family == AF_INET &&
1038 		    addr1->sin_addr.s_addr == addr2->sin_addr.s_addr)
1039 			return (1);
1040 		break;
1041 #ifdef INET6
1042 	case AF_INET6:
1043 		{
1044 		struct sockaddr_in6 *inet6addr1, *inet6addr2;
1045 
1046 		inet6addr1 = NFSSOCKADDR(nam1, struct sockaddr_in6 *);
1047 		inet6addr2 = NFSSOCKADDR(nam2, struct sockaddr_in6 *);
1048 		/* XXX - should test sin6_scope_id ? */
1049 		if (inet6addr2->sin6_family == AF_INET6 &&
1050 		    IN6_ARE_ADDR_EQUAL(&inet6addr1->sin6_addr,
1051 			  &inet6addr2->sin6_addr))
1052 			return (1);
1053 		}
1054 		break;
1055 #endif
1056 	}
1057 	return (0);
1058 }
1059 
1060 /*
1061  * Trim trailing data off the mbuf list being built.
1062  */
1063 void
1064 newnfs_trimtrailing(nd, mb, bpos)
1065 	struct nfsrv_descript *nd;
1066 	struct mbuf *mb;
1067 	caddr_t bpos;
1068 {
1069 
1070 	if (mb->m_next) {
1071 		m_freem(mb->m_next);
1072 		mb->m_next = NULL;
1073 	}
1074 	mb->m_len = bpos - mtod(mb, caddr_t);
1075 	nd->nd_mb = mb;
1076 	nd->nd_bpos = bpos;
1077 }
1078 
1079 /*
1080  * Dissect a file handle on the client.
1081  */
1082 int
1083 nfsm_getfh(struct nfsrv_descript *nd, struct nfsfh **nfhpp)
1084 {
1085 	u_int32_t *tl;
1086 	struct nfsfh *nfhp;
1087 	int error, len;
1088 
1089 	*nfhpp = NULL;
1090 	if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
1091 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1092 		if ((len = fxdr_unsigned(int, *tl)) <= 0 ||
1093 			len > NFSX_FHMAX) {
1094 			error = EBADRPC;
1095 			goto nfsmout;
1096 		}
1097 	} else
1098 		len = NFSX_V2FH;
1099 	nfhp = malloc(sizeof (struct nfsfh) + len,
1100 	    M_NFSFH, M_WAITOK);
1101 	error = nfsrv_mtostr(nd, nfhp->nfh_fh, len);
1102 	if (error) {
1103 		free(nfhp, M_NFSFH);
1104 		goto nfsmout;
1105 	}
1106 	nfhp->nfh_len = len;
1107 	*nfhpp = nfhp;
1108 nfsmout:
1109 	NFSEXITCODE2(error, nd);
1110 	return (error);
1111 }
1112 
1113 /*
1114  * Break down the nfsv4 acl.
1115  * If the aclp == NULL or won't fit in an acl, just discard the acl info.
1116  */
1117 int
1118 nfsrv_dissectacl(struct nfsrv_descript *nd, NFSACL_T *aclp, int *aclerrp,
1119     int *aclsizep, __unused NFSPROC_T *p)
1120 {
1121 	u_int32_t *tl;
1122 	int i, aclsize;
1123 	int acecnt, error = 0, aceerr = 0, acesize;
1124 
1125 	*aclerrp = 0;
1126 	if (aclp)
1127 		aclp->acl_cnt = 0;
1128 	/*
1129 	 * Parse out the ace entries and expect them to conform to
1130 	 * what can be supported by R/W/X bits.
1131 	 */
1132 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1133 	aclsize = NFSX_UNSIGNED;
1134 	acecnt = fxdr_unsigned(int, *tl);
1135 	if (acecnt > ACL_MAX_ENTRIES)
1136 		aceerr = NFSERR_ATTRNOTSUPP;
1137 	if (nfsrv_useacl == 0)
1138 		aceerr = NFSERR_ATTRNOTSUPP;
1139 	for (i = 0; i < acecnt; i++) {
1140 		if (aclp && !aceerr)
1141 			error = nfsrv_dissectace(nd, &aclp->acl_entry[i],
1142 			    &aceerr, &acesize, p);
1143 		else
1144 			error = nfsrv_skipace(nd, &acesize);
1145 		if (error)
1146 			goto nfsmout;
1147 		aclsize += acesize;
1148 	}
1149 	if (aclp && !aceerr)
1150 		aclp->acl_cnt = acecnt;
1151 	if (aceerr)
1152 		*aclerrp = aceerr;
1153 	if (aclsizep)
1154 		*aclsizep = aclsize;
1155 nfsmout:
1156 	NFSEXITCODE2(error, nd);
1157 	return (error);
1158 }
1159 
1160 /*
1161  * Skip over an NFSv4 ace entry. Just dissect the xdr and discard it.
1162  */
1163 static int
1164 nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep)
1165 {
1166 	u_int32_t *tl;
1167 	int error, len = 0;
1168 
1169 	NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1170 	len = fxdr_unsigned(int, *(tl + 3));
1171 	error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
1172 nfsmout:
1173 	*acesizep = NFSM_RNDUP(len) + (4 * NFSX_UNSIGNED);
1174 	NFSEXITCODE2(error, nd);
1175 	return (error);
1176 }
1177 
1178 /*
1179  * Get attribute bits from an mbuf list.
1180  * Returns EBADRPC for a parsing error, 0 otherwise.
1181  * If the clearinvalid flag is set, clear the bits not supported.
1182  */
1183 int
1184 nfsrv_getattrbits(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp, int *cntp,
1185     int *retnotsupp)
1186 {
1187 	u_int32_t *tl;
1188 	int cnt, i, outcnt;
1189 	int error = 0;
1190 
1191 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1192 	cnt = fxdr_unsigned(int, *tl);
1193 	if (cnt < 0) {
1194 		error = NFSERR_BADXDR;
1195 		goto nfsmout;
1196 	}
1197 	if (cnt > NFSATTRBIT_MAXWORDS)
1198 		outcnt = NFSATTRBIT_MAXWORDS;
1199 	else
1200 		outcnt = cnt;
1201 	NFSZERO_ATTRBIT(attrbitp);
1202 	if (outcnt > 0) {
1203 		NFSM_DISSECT(tl, u_int32_t *, outcnt * NFSX_UNSIGNED);
1204 		for (i = 0; i < outcnt; i++)
1205 			attrbitp->bits[i] = fxdr_unsigned(u_int32_t, *tl++);
1206 	}
1207 	for (i = 0; i < (cnt - outcnt); i++) {
1208 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1209 		if (retnotsupp != NULL && *tl != 0)
1210 			*retnotsupp = NFSERR_ATTRNOTSUPP;
1211 	}
1212 	if (cntp)
1213 		*cntp = NFSX_UNSIGNED + (cnt * NFSX_UNSIGNED);
1214 nfsmout:
1215 	NFSEXITCODE2(error, nd);
1216 	return (error);
1217 }
1218 
1219 /*
1220  * Get the attributes for V4.
1221  * If the compare flag is true, test for any attribute changes,
1222  * otherwise return the attribute values.
1223  * These attributes cover fields in "struct vattr", "struct statfs",
1224  * "struct nfsfsinfo", the file handle and the lease duration.
1225  * The value of retcmpp is set to 1 if all attributes are the same,
1226  * and 0 otherwise.
1227  * Returns EBADRPC if it can't be parsed, 0 otherwise.
1228  */
1229 int
1230 nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp,
1231     struct nfsvattr *nap, struct nfsfh **nfhpp, fhandle_t *fhp, int fhsize,
1232     struct nfsv3_pathconf *pc, struct statfs *sbp, struct nfsstatfs *sfp,
1233     struct nfsfsinfo *fsp, NFSACL_T *aclp, int compare, int *retcmpp,
1234     u_int32_t *leasep, u_int32_t *rderrp, NFSPROC_T *p, struct ucred *cred)
1235 {
1236 	u_int32_t *tl;
1237 	int i = 0, j, k, l = 0, m, bitpos, attrsum = 0;
1238 	int error, tfhsize, aceerr, attrsize, cnt, retnotsup;
1239 	u_char *cp, *cp2, namestr[NFSV4_SMALLSTR + 1];
1240 	nfsattrbit_t attrbits, retattrbits, checkattrbits;
1241 	struct nfsfh *tnfhp;
1242 	struct nfsreferral *refp;
1243 	u_quad_t tquad;
1244 	nfsquad_t tnfsquad;
1245 	struct timespec temptime;
1246 	uid_t uid;
1247 	gid_t gid;
1248 	u_int32_t freenum = 0, tuint;
1249 	u_int64_t uquad = 0, thyp, thyp2;
1250 #ifdef QUOTA
1251 	struct dqblk dqb;
1252 	uid_t savuid;
1253 #endif
1254 
1255 	CTASSERT(sizeof(ino_t) == sizeof(uint64_t));
1256 	if (compare) {
1257 		retnotsup = 0;
1258 		error = nfsrv_getattrbits(nd, &attrbits, NULL, &retnotsup);
1259 	} else {
1260 		error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
1261 	}
1262 	if (error)
1263 		goto nfsmout;
1264 
1265 	if (compare) {
1266 		*retcmpp = retnotsup;
1267 	} else {
1268 		/*
1269 		 * Just set default values to some of the important ones.
1270 		 */
1271 		if (nap != NULL) {
1272 			nap->na_type = VREG;
1273 			nap->na_mode = 0;
1274 			nap->na_rdev = (NFSDEV_T)0;
1275 			nap->na_mtime.tv_sec = 0;
1276 			nap->na_mtime.tv_nsec = 0;
1277 			nap->na_gen = 0;
1278 			nap->na_flags = 0;
1279 			nap->na_blocksize = NFS_FABLKSIZE;
1280 		}
1281 		if (sbp != NULL) {
1282 			sbp->f_bsize = NFS_FABLKSIZE;
1283 			sbp->f_blocks = 0;
1284 			sbp->f_bfree = 0;
1285 			sbp->f_bavail = 0;
1286 			sbp->f_files = 0;
1287 			sbp->f_ffree = 0;
1288 		}
1289 		if (fsp != NULL) {
1290 			fsp->fs_rtmax = 8192;
1291 			fsp->fs_rtpref = 8192;
1292 			fsp->fs_maxname = NFS_MAXNAMLEN;
1293 			fsp->fs_wtmax = 8192;
1294 			fsp->fs_wtpref = 8192;
1295 			fsp->fs_wtmult = NFS_FABLKSIZE;
1296 			fsp->fs_dtpref = 8192;
1297 			fsp->fs_maxfilesize = 0xffffffffffffffffull;
1298 			fsp->fs_timedelta.tv_sec = 0;
1299 			fsp->fs_timedelta.tv_nsec = 1;
1300 			fsp->fs_properties = (NFSV3_FSFLINK | NFSV3_FSFSYMLINK |
1301 				NFSV3_FSFHOMOGENEOUS | NFSV3_FSFCANSETTIME);
1302 		}
1303 		if (pc != NULL) {
1304 			pc->pc_linkmax = NFS_LINK_MAX;
1305 			pc->pc_namemax = NAME_MAX;
1306 			pc->pc_notrunc = 0;
1307 			pc->pc_chownrestricted = 0;
1308 			pc->pc_caseinsensitive = 0;
1309 			pc->pc_casepreserving = 1;
1310 		}
1311 		if (sfp != NULL) {
1312 			sfp->sf_ffiles = UINT64_MAX;
1313 			sfp->sf_tfiles = UINT64_MAX;
1314 			sfp->sf_afiles = UINT64_MAX;
1315 			sfp->sf_fbytes = UINT64_MAX;
1316 			sfp->sf_tbytes = UINT64_MAX;
1317 			sfp->sf_abytes = UINT64_MAX;
1318 		}
1319 	}
1320 
1321 	/*
1322 	 * Loop around getting the attributes.
1323 	 */
1324 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1325 	attrsize = fxdr_unsigned(int, *tl);
1326 	for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
1327 	    if (attrsum > attrsize) {
1328 		error = NFSERR_BADXDR;
1329 		goto nfsmout;
1330 	    }
1331 	    if (NFSISSET_ATTRBIT(&attrbits, bitpos))
1332 		switch (bitpos) {
1333 		case NFSATTRBIT_SUPPORTEDATTRS:
1334 			retnotsup = 0;
1335 			if (compare || nap == NULL)
1336 			    error = nfsrv_getattrbits(nd, &retattrbits,
1337 				&cnt, &retnotsup);
1338 			else
1339 			    error = nfsrv_getattrbits(nd, &nap->na_suppattr,
1340 				&cnt, &retnotsup);
1341 			if (error)
1342 			    goto nfsmout;
1343 			if (compare && !(*retcmpp)) {
1344 			   NFSSETSUPP_ATTRBIT(&checkattrbits, nd);
1345 
1346 			   /* Some filesystem do not support NFSv4ACL   */
1347 			   if (nfsrv_useacl == 0 || nfs_supportsnfsv4acls(vp) == 0) {
1348 				NFSCLRBIT_ATTRBIT(&checkattrbits, NFSATTRBIT_ACL);
1349 				NFSCLRBIT_ATTRBIT(&checkattrbits, NFSATTRBIT_ACLSUPPORT);
1350 		   	   }
1351 			   if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
1352 			       || retnotsup)
1353 				*retcmpp = NFSERR_NOTSAME;
1354 			}
1355 			attrsum += cnt;
1356 			break;
1357 		case NFSATTRBIT_TYPE:
1358 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1359 			if (compare) {
1360 				if (!(*retcmpp)) {
1361 				    if (nap->na_type != nfsv34tov_type(*tl))
1362 					*retcmpp = NFSERR_NOTSAME;
1363 				}
1364 			} else if (nap != NULL) {
1365 				nap->na_type = nfsv34tov_type(*tl);
1366 			}
1367 			attrsum += NFSX_UNSIGNED;
1368 			break;
1369 		case NFSATTRBIT_FHEXPIRETYPE:
1370 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1371 			if (compare && !(*retcmpp)) {
1372 				if (fxdr_unsigned(int, *tl) !=
1373 					NFSV4FHTYPE_PERSISTENT)
1374 					*retcmpp = NFSERR_NOTSAME;
1375 			}
1376 			attrsum += NFSX_UNSIGNED;
1377 			break;
1378 		case NFSATTRBIT_CHANGE:
1379 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1380 			if (compare) {
1381 				if (!(*retcmpp)) {
1382 				    if (nap->na_filerev != fxdr_hyper(tl))
1383 					*retcmpp = NFSERR_NOTSAME;
1384 				}
1385 			} else if (nap != NULL) {
1386 				nap->na_filerev = fxdr_hyper(tl);
1387 			}
1388 			attrsum += NFSX_HYPER;
1389 			break;
1390 		case NFSATTRBIT_SIZE:
1391 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1392 			if (compare) {
1393 				if (!(*retcmpp)) {
1394 				    if (nap->na_size != fxdr_hyper(tl))
1395 					*retcmpp = NFSERR_NOTSAME;
1396 				}
1397 			} else if (nap != NULL) {
1398 				nap->na_size = fxdr_hyper(tl);
1399 			}
1400 			attrsum += NFSX_HYPER;
1401 			break;
1402 		case NFSATTRBIT_LINKSUPPORT:
1403 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1404 			if (compare) {
1405 				if (!(*retcmpp)) {
1406 				    if (fsp->fs_properties & NFSV3_FSFLINK) {
1407 					if (*tl == newnfs_false)
1408 						*retcmpp = NFSERR_NOTSAME;
1409 				    } else {
1410 					if (*tl == newnfs_true)
1411 						*retcmpp = NFSERR_NOTSAME;
1412 				    }
1413 				}
1414 			} else if (fsp != NULL) {
1415 				if (*tl == newnfs_true)
1416 					fsp->fs_properties |= NFSV3_FSFLINK;
1417 				else
1418 					fsp->fs_properties &= ~NFSV3_FSFLINK;
1419 			}
1420 			attrsum += NFSX_UNSIGNED;
1421 			break;
1422 		case NFSATTRBIT_SYMLINKSUPPORT:
1423 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1424 			if (compare) {
1425 				if (!(*retcmpp)) {
1426 				    if (fsp->fs_properties & NFSV3_FSFSYMLINK) {
1427 					if (*tl == newnfs_false)
1428 						*retcmpp = NFSERR_NOTSAME;
1429 				    } else {
1430 					if (*tl == newnfs_true)
1431 						*retcmpp = NFSERR_NOTSAME;
1432 				    }
1433 				}
1434 			} else if (fsp != NULL) {
1435 				if (*tl == newnfs_true)
1436 					fsp->fs_properties |= NFSV3_FSFSYMLINK;
1437 				else
1438 					fsp->fs_properties &= ~NFSV3_FSFSYMLINK;
1439 			}
1440 			attrsum += NFSX_UNSIGNED;
1441 			break;
1442 		case NFSATTRBIT_NAMEDATTR:
1443 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1444 			if (compare && !(*retcmpp)) {
1445 				if (*tl != newnfs_false)
1446 					*retcmpp = NFSERR_NOTSAME;
1447 			}
1448 			attrsum += NFSX_UNSIGNED;
1449 			break;
1450 		case NFSATTRBIT_FSID:
1451 			NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1452 			thyp = fxdr_hyper(tl);
1453 			tl += 2;
1454 			thyp2 = fxdr_hyper(tl);
1455 			if (compare) {
1456 			    if (*retcmpp == 0) {
1457 				if (thyp != (u_int64_t)
1458 				    vp->v_mount->mnt_stat.f_fsid.val[0] ||
1459 				    thyp2 != (u_int64_t)
1460 				    vp->v_mount->mnt_stat.f_fsid.val[1])
1461 					*retcmpp = NFSERR_NOTSAME;
1462 			    }
1463 			} else if (nap != NULL) {
1464 				nap->na_filesid[0] = thyp;
1465 				nap->na_filesid[1] = thyp2;
1466 			}
1467 			attrsum += (4 * NFSX_UNSIGNED);
1468 			break;
1469 		case NFSATTRBIT_UNIQUEHANDLES:
1470 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1471 			if (compare && !(*retcmpp)) {
1472 				if (*tl != newnfs_true)
1473 					*retcmpp = NFSERR_NOTSAME;
1474 			}
1475 			attrsum += NFSX_UNSIGNED;
1476 			break;
1477 		case NFSATTRBIT_LEASETIME:
1478 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1479 			if (compare) {
1480 				if (fxdr_unsigned(int, *tl) != nfsrv_lease &&
1481 				    !(*retcmpp))
1482 					*retcmpp = NFSERR_NOTSAME;
1483 			} else if (leasep != NULL) {
1484 				*leasep = fxdr_unsigned(u_int32_t, *tl);
1485 			}
1486 			attrsum += NFSX_UNSIGNED;
1487 			break;
1488 		case NFSATTRBIT_RDATTRERROR:
1489 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1490 			if (compare) {
1491 				 if (!(*retcmpp))
1492 					*retcmpp = NFSERR_INVAL;
1493 			} else if (rderrp != NULL) {
1494 				*rderrp = fxdr_unsigned(u_int32_t, *tl);
1495 			}
1496 			attrsum += NFSX_UNSIGNED;
1497 			break;
1498 		case NFSATTRBIT_ACL:
1499 			if (compare) {
1500 			  if (!(*retcmpp)) {
1501 			    if (nfsrv_useacl && nfs_supportsnfsv4acls(vp)) {
1502 				NFSACL_T *naclp;
1503 
1504 				naclp = acl_alloc(M_WAITOK);
1505 				error = nfsrv_dissectacl(nd, naclp, &aceerr,
1506 				    &cnt, p);
1507 				if (error) {
1508 				    acl_free(naclp);
1509 				    goto nfsmout;
1510 				}
1511 				if (aceerr || aclp == NULL ||
1512 				    nfsrv_compareacl(aclp, naclp))
1513 				    *retcmpp = NFSERR_NOTSAME;
1514 				acl_free(naclp);
1515 			    } else {
1516 				error = nfsrv_dissectacl(nd, NULL, &aceerr,
1517 				    &cnt, p);
1518 				*retcmpp = NFSERR_ATTRNOTSUPP;
1519 			    }
1520 			  }
1521 			} else {
1522 				if (vp != NULL && aclp != NULL)
1523 				    error = nfsrv_dissectacl(nd, aclp, &aceerr,
1524 					&cnt, p);
1525 				else
1526 				    error = nfsrv_dissectacl(nd, NULL, &aceerr,
1527 					&cnt, p);
1528 				if (error)
1529 				    goto nfsmout;
1530 			}
1531 
1532 			attrsum += cnt;
1533 			break;
1534 		case NFSATTRBIT_ACLSUPPORT:
1535 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1536 			if (compare && !(*retcmpp)) {
1537 				if (nfsrv_useacl && nfs_supportsnfsv4acls(vp)) {
1538 					if (fxdr_unsigned(u_int32_t, *tl) !=
1539 					    NFSV4ACE_SUPTYPES)
1540 						*retcmpp = NFSERR_NOTSAME;
1541 				} else {
1542 					*retcmpp = NFSERR_ATTRNOTSUPP;
1543 				}
1544 			}
1545 			attrsum += NFSX_UNSIGNED;
1546 			break;
1547 		case NFSATTRBIT_ARCHIVE:
1548 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1549 			if (compare && !(*retcmpp))
1550 				*retcmpp = NFSERR_ATTRNOTSUPP;
1551 			attrsum += NFSX_UNSIGNED;
1552 			break;
1553 		case NFSATTRBIT_CANSETTIME:
1554 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1555 			if (compare) {
1556 				if (!(*retcmpp)) {
1557 				    if (fsp->fs_properties & NFSV3_FSFCANSETTIME) {
1558 					if (*tl == newnfs_false)
1559 						*retcmpp = NFSERR_NOTSAME;
1560 				    } else {
1561 					if (*tl == newnfs_true)
1562 						*retcmpp = NFSERR_NOTSAME;
1563 				    }
1564 				}
1565 			} else if (fsp != NULL) {
1566 				if (*tl == newnfs_true)
1567 					fsp->fs_properties |= NFSV3_FSFCANSETTIME;
1568 				else
1569 					fsp->fs_properties &= ~NFSV3_FSFCANSETTIME;
1570 			}
1571 			attrsum += NFSX_UNSIGNED;
1572 			break;
1573 		case NFSATTRBIT_CASEINSENSITIVE:
1574 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1575 			if (compare) {
1576 				if (!(*retcmpp)) {
1577 				    if (*tl != newnfs_false)
1578 					*retcmpp = NFSERR_NOTSAME;
1579 				}
1580 			} else if (pc != NULL) {
1581 				pc->pc_caseinsensitive =
1582 				    fxdr_unsigned(u_int32_t, *tl);
1583 			}
1584 			attrsum += NFSX_UNSIGNED;
1585 			break;
1586 		case NFSATTRBIT_CASEPRESERVING:
1587 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1588 			if (compare) {
1589 				if (!(*retcmpp)) {
1590 				    if (*tl != newnfs_true)
1591 					*retcmpp = NFSERR_NOTSAME;
1592 				}
1593 			} else if (pc != NULL) {
1594 				pc->pc_casepreserving =
1595 				    fxdr_unsigned(u_int32_t, *tl);
1596 			}
1597 			attrsum += NFSX_UNSIGNED;
1598 			break;
1599 		case NFSATTRBIT_CHOWNRESTRICTED:
1600 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1601 			if (compare) {
1602 				if (!(*retcmpp)) {
1603 				    if (*tl != newnfs_true)
1604 					*retcmpp = NFSERR_NOTSAME;
1605 				}
1606 			} else if (pc != NULL) {
1607 				pc->pc_chownrestricted =
1608 				    fxdr_unsigned(u_int32_t, *tl);
1609 			}
1610 			attrsum += NFSX_UNSIGNED;
1611 			break;
1612 		case NFSATTRBIT_FILEHANDLE:
1613 			error = nfsm_getfh(nd, &tnfhp);
1614 			if (error)
1615 				goto nfsmout;
1616 			tfhsize = tnfhp->nfh_len;
1617 			if (compare) {
1618 				if (!(*retcmpp) &&
1619 				    !NFSRV_CMPFH(tnfhp->nfh_fh, tfhsize,
1620 				     fhp, fhsize))
1621 					*retcmpp = NFSERR_NOTSAME;
1622 				free(tnfhp, M_NFSFH);
1623 			} else if (nfhpp != NULL) {
1624 				*nfhpp = tnfhp;
1625 			} else {
1626 				free(tnfhp, M_NFSFH);
1627 			}
1628 			attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(tfhsize));
1629 			break;
1630 		case NFSATTRBIT_FILEID:
1631 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1632 			thyp = fxdr_hyper(tl);
1633 			if (compare) {
1634 				if (!(*retcmpp)) {
1635 					if (nap->na_fileid != thyp)
1636 						*retcmpp = NFSERR_NOTSAME;
1637 				}
1638 			} else if (nap != NULL)
1639 				nap->na_fileid = thyp;
1640 			attrsum += NFSX_HYPER;
1641 			break;
1642 		case NFSATTRBIT_FILESAVAIL:
1643 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1644 			if (compare) {
1645 				if (!(*retcmpp) &&
1646 				    sfp->sf_afiles != fxdr_hyper(tl))
1647 					*retcmpp = NFSERR_NOTSAME;
1648 			} else if (sfp != NULL) {
1649 				sfp->sf_afiles = fxdr_hyper(tl);
1650 			}
1651 			attrsum += NFSX_HYPER;
1652 			break;
1653 		case NFSATTRBIT_FILESFREE:
1654 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1655 			if (compare) {
1656 				if (!(*retcmpp) &&
1657 				    sfp->sf_ffiles != fxdr_hyper(tl))
1658 					*retcmpp = NFSERR_NOTSAME;
1659 			} else if (sfp != NULL) {
1660 				sfp->sf_ffiles = fxdr_hyper(tl);
1661 			}
1662 			attrsum += NFSX_HYPER;
1663 			break;
1664 		case NFSATTRBIT_FILESTOTAL:
1665 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1666 			if (compare) {
1667 				if (!(*retcmpp) &&
1668 				    sfp->sf_tfiles != fxdr_hyper(tl))
1669 					*retcmpp = NFSERR_NOTSAME;
1670 			} else if (sfp != NULL) {
1671 				sfp->sf_tfiles = fxdr_hyper(tl);
1672 			}
1673 			attrsum += NFSX_HYPER;
1674 			break;
1675 		case NFSATTRBIT_FSLOCATIONS:
1676 			error = nfsrv_getrefstr(nd, &cp, &cp2, &l, &m);
1677 			if (error)
1678 				goto nfsmout;
1679 			attrsum += l;
1680 			if (compare && !(*retcmpp)) {
1681 				refp = nfsv4root_getreferral(vp, NULL, 0);
1682 				if (refp != NULL) {
1683 					if (cp == NULL || cp2 == NULL ||
1684 					    strcmp(cp, "/") ||
1685 					    strcmp(cp2, refp->nfr_srvlist))
1686 						*retcmpp = NFSERR_NOTSAME;
1687 				} else if (m == 0) {
1688 					*retcmpp = NFSERR_NOTSAME;
1689 				}
1690 			}
1691 			if (cp != NULL)
1692 				free(cp, M_NFSSTRING);
1693 			if (cp2 != NULL)
1694 				free(cp2, M_NFSSTRING);
1695 			break;
1696 		case NFSATTRBIT_HIDDEN:
1697 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1698 			if (compare && !(*retcmpp))
1699 				*retcmpp = NFSERR_ATTRNOTSUPP;
1700 			attrsum += NFSX_UNSIGNED;
1701 			break;
1702 		case NFSATTRBIT_HOMOGENEOUS:
1703 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1704 			if (compare) {
1705 				if (!(*retcmpp)) {
1706 				    if (fsp->fs_properties &
1707 					NFSV3_FSFHOMOGENEOUS) {
1708 					if (*tl == newnfs_false)
1709 						*retcmpp = NFSERR_NOTSAME;
1710 				    } else {
1711 					if (*tl == newnfs_true)
1712 						*retcmpp = NFSERR_NOTSAME;
1713 				    }
1714 				}
1715 			} else if (fsp != NULL) {
1716 				if (*tl == newnfs_true)
1717 				    fsp->fs_properties |= NFSV3_FSFHOMOGENEOUS;
1718 				else
1719 				    fsp->fs_properties &= ~NFSV3_FSFHOMOGENEOUS;
1720 			}
1721 			attrsum += NFSX_UNSIGNED;
1722 			break;
1723 		case NFSATTRBIT_MAXFILESIZE:
1724 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1725 			tnfsquad.qval = fxdr_hyper(tl);
1726 			if (compare) {
1727 				if (!(*retcmpp)) {
1728 					tquad = NFSRV_MAXFILESIZE;
1729 					if (tquad != tnfsquad.qval)
1730 						*retcmpp = NFSERR_NOTSAME;
1731 				}
1732 			} else if (fsp != NULL) {
1733 				fsp->fs_maxfilesize = tnfsquad.qval;
1734 			}
1735 			attrsum += NFSX_HYPER;
1736 			break;
1737 		case NFSATTRBIT_MAXLINK:
1738 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1739 			if (compare) {
1740 				if (!(*retcmpp)) {
1741 				    if (fxdr_unsigned(int, *tl) != NFS_LINK_MAX)
1742 					*retcmpp = NFSERR_NOTSAME;
1743 				}
1744 			} else if (pc != NULL) {
1745 				pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl);
1746 			}
1747 			attrsum += NFSX_UNSIGNED;
1748 			break;
1749 		case NFSATTRBIT_MAXNAME:
1750 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1751 			if (compare) {
1752 				if (!(*retcmpp)) {
1753 				    if (fsp->fs_maxname !=
1754 					fxdr_unsigned(u_int32_t, *tl))
1755 						*retcmpp = NFSERR_NOTSAME;
1756 				}
1757 			} else {
1758 				tuint = fxdr_unsigned(u_int32_t, *tl);
1759 				/*
1760 				 * Some Linux NFSv4 servers report this
1761 				 * as 0 or 4billion, so I'll set it to
1762 				 * NFS_MAXNAMLEN. If a server actually creates
1763 				 * a name longer than NFS_MAXNAMLEN, it will
1764 				 * get an error back.
1765 				 */
1766 				if (tuint == 0 || tuint > NFS_MAXNAMLEN)
1767 					tuint = NFS_MAXNAMLEN;
1768 				if (fsp != NULL)
1769 					fsp->fs_maxname = tuint;
1770 				if (pc != NULL)
1771 					pc->pc_namemax = tuint;
1772 			}
1773 			attrsum += NFSX_UNSIGNED;
1774 			break;
1775 		case NFSATTRBIT_MAXREAD:
1776 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1777 			if (compare) {
1778 				if (!(*retcmpp)) {
1779 				    if (fsp->fs_rtmax != fxdr_unsigned(u_int32_t,
1780 					*(tl + 1)) || *tl != 0)
1781 					*retcmpp = NFSERR_NOTSAME;
1782 				}
1783 			} else if (fsp != NULL) {
1784 				fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *++tl);
1785 				fsp->fs_rtpref = fsp->fs_rtmax;
1786 				fsp->fs_dtpref = fsp->fs_rtpref;
1787 			}
1788 			attrsum += NFSX_HYPER;
1789 			break;
1790 		case NFSATTRBIT_MAXWRITE:
1791 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1792 			if (compare) {
1793 				if (!(*retcmpp)) {
1794 				    if (fsp->fs_wtmax != fxdr_unsigned(u_int32_t,
1795 					*(tl + 1)) || *tl != 0)
1796 					*retcmpp = NFSERR_NOTSAME;
1797 				}
1798 			} else if (fsp != NULL) {
1799 				fsp->fs_wtmax = fxdr_unsigned(int, *++tl);
1800 				fsp->fs_wtpref = fsp->fs_wtmax;
1801 			}
1802 			attrsum += NFSX_HYPER;
1803 			break;
1804 		case NFSATTRBIT_MIMETYPE:
1805 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1806 			i = fxdr_unsigned(int, *tl);
1807 			attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(i));
1808 			error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
1809 			if (error)
1810 				goto nfsmout;
1811 			if (compare && !(*retcmpp))
1812 				*retcmpp = NFSERR_ATTRNOTSUPP;
1813 			break;
1814 		case NFSATTRBIT_MODE:
1815 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1816 			if (compare) {
1817 				if (!(*retcmpp)) {
1818 				    if (nap->na_mode != nfstov_mode(*tl))
1819 					*retcmpp = NFSERR_NOTSAME;
1820 				}
1821 			} else if (nap != NULL) {
1822 				nap->na_mode = nfstov_mode(*tl);
1823 			}
1824 			attrsum += NFSX_UNSIGNED;
1825 			break;
1826 		case NFSATTRBIT_NOTRUNC:
1827 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1828 			if (compare) {
1829 				if (!(*retcmpp)) {
1830 				    if (*tl != newnfs_true)
1831 					*retcmpp = NFSERR_NOTSAME;
1832 				}
1833 			} else if (pc != NULL) {
1834 				pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl);
1835 			}
1836 			attrsum += NFSX_UNSIGNED;
1837 			break;
1838 		case NFSATTRBIT_NUMLINKS:
1839 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1840 			tuint = fxdr_unsigned(u_int32_t, *tl);
1841 			if (compare) {
1842 			    if (!(*retcmpp)) {
1843 				if ((u_int32_t)nap->na_nlink != tuint)
1844 					*retcmpp = NFSERR_NOTSAME;
1845 			    }
1846 			} else if (nap != NULL) {
1847 				nap->na_nlink = tuint;
1848 			}
1849 			attrsum += NFSX_UNSIGNED;
1850 			break;
1851 		case NFSATTRBIT_OWNER:
1852 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1853 			j = fxdr_unsigned(int, *tl);
1854 			if (j < 0) {
1855 				error = NFSERR_BADXDR;
1856 				goto nfsmout;
1857 			}
1858 			attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1859 			if (j > NFSV4_SMALLSTR)
1860 				cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1861 			else
1862 				cp = namestr;
1863 			error = nfsrv_mtostr(nd, cp, j);
1864 			if (error) {
1865 				if (j > NFSV4_SMALLSTR)
1866 					free(cp, M_NFSSTRING);
1867 				goto nfsmout;
1868 			}
1869 			if (compare) {
1870 			    if (!(*retcmpp)) {
1871 				if (nfsv4_strtouid(nd, cp, j, &uid) ||
1872 				    nap->na_uid != uid)
1873 				    *retcmpp = NFSERR_NOTSAME;
1874 			    }
1875 			} else if (nap != NULL) {
1876 				if (nfsv4_strtouid(nd, cp, j, &uid))
1877 					nap->na_uid = nfsrv_defaultuid;
1878 				else
1879 					nap->na_uid = uid;
1880 			}
1881 			if (j > NFSV4_SMALLSTR)
1882 				free(cp, M_NFSSTRING);
1883 			break;
1884 		case NFSATTRBIT_OWNERGROUP:
1885 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1886 			j = fxdr_unsigned(int, *tl);
1887 			if (j < 0) {
1888 				error =  NFSERR_BADXDR;
1889 				goto nfsmout;
1890 			}
1891 			attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1892 			if (j > NFSV4_SMALLSTR)
1893 				cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1894 			else
1895 				cp = namestr;
1896 			error = nfsrv_mtostr(nd, cp, j);
1897 			if (error) {
1898 				if (j > NFSV4_SMALLSTR)
1899 					free(cp, M_NFSSTRING);
1900 				goto nfsmout;
1901 			}
1902 			if (compare) {
1903 			    if (!(*retcmpp)) {
1904 				if (nfsv4_strtogid(nd, cp, j, &gid) ||
1905 				    nap->na_gid != gid)
1906 				    *retcmpp = NFSERR_NOTSAME;
1907 			    }
1908 			} else if (nap != NULL) {
1909 				if (nfsv4_strtogid(nd, cp, j, &gid))
1910 					nap->na_gid = nfsrv_defaultgid;
1911 				else
1912 					nap->na_gid = gid;
1913 			}
1914 			if (j > NFSV4_SMALLSTR)
1915 				free(cp, M_NFSSTRING);
1916 			break;
1917 		case NFSATTRBIT_QUOTAHARD:
1918 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1919 			if (sbp != NULL) {
1920 			    if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA))
1921 				freenum = sbp->f_bfree;
1922 			    else
1923 				freenum = sbp->f_bavail;
1924 #ifdef QUOTA
1925 			    /*
1926 			     * ufs_quotactl() insists that the uid argument
1927 			     * equal p_ruid for non-root quota access, so
1928 			     * we'll just make sure that's the case.
1929 			     */
1930 			    savuid = p->p_cred->p_ruid;
1931 			    p->p_cred->p_ruid = cred->cr_uid;
1932 			    if (!VFS_QUOTACTL(vp->v_mount,QCMD(Q_GETQUOTA,
1933 				USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1934 				freenum = min(dqb.dqb_bhardlimit, freenum);
1935 			    p->p_cred->p_ruid = savuid;
1936 #endif	/* QUOTA */
1937 			    uquad = (u_int64_t)freenum;
1938 			    NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1939 			}
1940 			if (compare && !(*retcmpp)) {
1941 				if (uquad != fxdr_hyper(tl))
1942 					*retcmpp = NFSERR_NOTSAME;
1943 			}
1944 			attrsum += NFSX_HYPER;
1945 			break;
1946 		case NFSATTRBIT_QUOTASOFT:
1947 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1948 			if (sbp != NULL) {
1949 			    if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA))
1950 				freenum = sbp->f_bfree;
1951 			    else
1952 				freenum = sbp->f_bavail;
1953 #ifdef QUOTA
1954 			    /*
1955 			     * ufs_quotactl() insists that the uid argument
1956 			     * equal p_ruid for non-root quota access, so
1957 			     * we'll just make sure that's the case.
1958 			     */
1959 			    savuid = p->p_cred->p_ruid;
1960 			    p->p_cred->p_ruid = cred->cr_uid;
1961 			    if (!VFS_QUOTACTL(vp->v_mount,QCMD(Q_GETQUOTA,
1962 				USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1963 				freenum = min(dqb.dqb_bsoftlimit, freenum);
1964 			    p->p_cred->p_ruid = savuid;
1965 #endif	/* QUOTA */
1966 			    uquad = (u_int64_t)freenum;
1967 			    NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1968 			}
1969 			if (compare && !(*retcmpp)) {
1970 				if (uquad != fxdr_hyper(tl))
1971 					*retcmpp = NFSERR_NOTSAME;
1972 			}
1973 			attrsum += NFSX_HYPER;
1974 			break;
1975 		case NFSATTRBIT_QUOTAUSED:
1976 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1977 			if (sbp != NULL) {
1978 			    freenum = 0;
1979 #ifdef QUOTA
1980 			    /*
1981 			     * ufs_quotactl() insists that the uid argument
1982 			     * equal p_ruid for non-root quota access, so
1983 			     * we'll just make sure that's the case.
1984 			     */
1985 			    savuid = p->p_cred->p_ruid;
1986 			    p->p_cred->p_ruid = cred->cr_uid;
1987 			    if (!VFS_QUOTACTL(vp->v_mount,QCMD(Q_GETQUOTA,
1988 				USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1989 				freenum = dqb.dqb_curblocks;
1990 			    p->p_cred->p_ruid = savuid;
1991 #endif	/* QUOTA */
1992 			    uquad = (u_int64_t)freenum;
1993 			    NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1994 			}
1995 			if (compare && !(*retcmpp)) {
1996 				if (uquad != fxdr_hyper(tl))
1997 					*retcmpp = NFSERR_NOTSAME;
1998 			}
1999 			attrsum += NFSX_HYPER;
2000 			break;
2001 		case NFSATTRBIT_RAWDEV:
2002 			NFSM_DISSECT(tl, u_int32_t *, NFSX_V4SPECDATA);
2003 			j = fxdr_unsigned(int, *tl++);
2004 			k = fxdr_unsigned(int, *tl);
2005 			if (compare) {
2006 			    if (!(*retcmpp)) {
2007 				if (nap->na_rdev != NFSMAKEDEV(j, k))
2008 					*retcmpp = NFSERR_NOTSAME;
2009 			    }
2010 			} else if (nap != NULL) {
2011 				nap->na_rdev = NFSMAKEDEV(j, k);
2012 			}
2013 			attrsum += NFSX_V4SPECDATA;
2014 			break;
2015 		case NFSATTRBIT_SPACEAVAIL:
2016 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2017 			if (compare) {
2018 				if (!(*retcmpp) &&
2019 				    sfp->sf_abytes != fxdr_hyper(tl))
2020 					*retcmpp = NFSERR_NOTSAME;
2021 			} else if (sfp != NULL) {
2022 				sfp->sf_abytes = fxdr_hyper(tl);
2023 			}
2024 			attrsum += NFSX_HYPER;
2025 			break;
2026 		case NFSATTRBIT_SPACEFREE:
2027 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2028 			if (compare) {
2029 				if (!(*retcmpp) &&
2030 				    sfp->sf_fbytes != fxdr_hyper(tl))
2031 					*retcmpp = NFSERR_NOTSAME;
2032 			} else if (sfp != NULL) {
2033 				sfp->sf_fbytes = fxdr_hyper(tl);
2034 			}
2035 			attrsum += NFSX_HYPER;
2036 			break;
2037 		case NFSATTRBIT_SPACETOTAL:
2038 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2039 			if (compare) {
2040 				if (!(*retcmpp) &&
2041 				    sfp->sf_tbytes != fxdr_hyper(tl))
2042 					*retcmpp = NFSERR_NOTSAME;
2043 			} else if (sfp != NULL) {
2044 				sfp->sf_tbytes = fxdr_hyper(tl);
2045 			}
2046 			attrsum += NFSX_HYPER;
2047 			break;
2048 		case NFSATTRBIT_SPACEUSED:
2049 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2050 			thyp = fxdr_hyper(tl);
2051 			if (compare) {
2052 			    if (!(*retcmpp)) {
2053 				if ((u_int64_t)nap->na_bytes != thyp)
2054 					*retcmpp = NFSERR_NOTSAME;
2055 			    }
2056 			} else if (nap != NULL) {
2057 				nap->na_bytes = thyp;
2058 			}
2059 			attrsum += NFSX_HYPER;
2060 			break;
2061 		case NFSATTRBIT_SYSTEM:
2062 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2063 			if (compare && !(*retcmpp))
2064 				*retcmpp = NFSERR_ATTRNOTSUPP;
2065 			attrsum += NFSX_UNSIGNED;
2066 			break;
2067 		case NFSATTRBIT_TIMEACCESS:
2068 			NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2069 			fxdr_nfsv4time(tl, &temptime);
2070 			if (compare) {
2071 			    if (!(*retcmpp)) {
2072 				if (!NFS_CMPTIME(temptime, nap->na_atime))
2073 					*retcmpp = NFSERR_NOTSAME;
2074 			    }
2075 			} else if (nap != NULL) {
2076 				nap->na_atime = temptime;
2077 			}
2078 			attrsum += NFSX_V4TIME;
2079 			break;
2080 		case NFSATTRBIT_TIMEACCESSSET:
2081 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2082 			attrsum += NFSX_UNSIGNED;
2083 			i = fxdr_unsigned(int, *tl);
2084 			if (i == NFSV4SATTRTIME_TOCLIENT) {
2085 				NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2086 				attrsum += NFSX_V4TIME;
2087 			}
2088 			if (compare && !(*retcmpp))
2089 				*retcmpp = NFSERR_INVAL;
2090 			break;
2091 		case NFSATTRBIT_TIMEBACKUP:
2092 			NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2093 			if (compare && !(*retcmpp))
2094 				*retcmpp = NFSERR_ATTRNOTSUPP;
2095 			attrsum += NFSX_V4TIME;
2096 			break;
2097 		case NFSATTRBIT_TIMECREATE:
2098 			NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2099 			fxdr_nfsv4time(tl, &temptime);
2100 			if (compare) {
2101 			    if (!(*retcmpp)) {
2102 				if (!NFS_CMPTIME(temptime, nap->na_btime))
2103 					*retcmpp = NFSERR_NOTSAME;
2104 			    }
2105 			} else if (nap != NULL) {
2106 				nap->na_btime = temptime;
2107 			}
2108 			attrsum += NFSX_V4TIME;
2109 			break;
2110 		case NFSATTRBIT_TIMEDELTA:
2111 			NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2112 			if (fsp != NULL) {
2113 			    if (compare) {
2114 				if (!(*retcmpp)) {
2115 				    if ((u_int32_t)fsp->fs_timedelta.tv_sec !=
2116 					fxdr_unsigned(u_int32_t, *(tl + 1)) ||
2117 				        (u_int32_t)fsp->fs_timedelta.tv_nsec !=
2118 					(fxdr_unsigned(u_int32_t, *(tl + 2)) %
2119 					 1000000000) ||
2120 					*tl != 0)
2121 					    *retcmpp = NFSERR_NOTSAME;
2122 				}
2123 			    } else {
2124 				fxdr_nfsv4time(tl, &fsp->fs_timedelta);
2125 			    }
2126 			}
2127 			attrsum += NFSX_V4TIME;
2128 			break;
2129 		case NFSATTRBIT_TIMEMETADATA:
2130 			NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2131 			fxdr_nfsv4time(tl, &temptime);
2132 			if (compare) {
2133 			    if (!(*retcmpp)) {
2134 				if (!NFS_CMPTIME(temptime, nap->na_ctime))
2135 					*retcmpp = NFSERR_NOTSAME;
2136 			    }
2137 			} else if (nap != NULL) {
2138 				nap->na_ctime = temptime;
2139 			}
2140 			attrsum += NFSX_V4TIME;
2141 			break;
2142 		case NFSATTRBIT_TIMEMODIFY:
2143 			NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2144 			fxdr_nfsv4time(tl, &temptime);
2145 			if (compare) {
2146 			    if (!(*retcmpp)) {
2147 				if (!NFS_CMPTIME(temptime, nap->na_mtime))
2148 					*retcmpp = NFSERR_NOTSAME;
2149 			    }
2150 			} else if (nap != NULL) {
2151 				nap->na_mtime = temptime;
2152 			}
2153 			attrsum += NFSX_V4TIME;
2154 			break;
2155 		case NFSATTRBIT_TIMEMODIFYSET:
2156 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2157 			attrsum += NFSX_UNSIGNED;
2158 			i = fxdr_unsigned(int, *tl);
2159 			if (i == NFSV4SATTRTIME_TOCLIENT) {
2160 				NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2161 				attrsum += NFSX_V4TIME;
2162 			}
2163 			if (compare && !(*retcmpp))
2164 				*retcmpp = NFSERR_INVAL;
2165 			break;
2166 		case NFSATTRBIT_MOUNTEDONFILEID:
2167 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2168 			thyp = fxdr_hyper(tl);
2169 			if (compare) {
2170 				if (!(*retcmpp)) {
2171 					if (!vp || !nfsrv_atroot(vp, &thyp2))
2172 						thyp2 = nap->na_fileid;
2173 					if (thyp2 != thyp)
2174 						*retcmpp = NFSERR_NOTSAME;
2175 				}
2176 			} else if (nap != NULL)
2177 				nap->na_mntonfileno = thyp;
2178 			attrsum += NFSX_HYPER;
2179 			break;
2180 		case NFSATTRBIT_SUPPATTREXCLCREAT:
2181 			retnotsup = 0;
2182 			error = nfsrv_getattrbits(nd, &retattrbits,
2183 			    &cnt, &retnotsup);
2184 			if (error)
2185 			    goto nfsmout;
2186 			if (compare && !(*retcmpp)) {
2187 			   NFSSETSUPP_ATTRBIT(&checkattrbits, nd);
2188 			   NFSCLRNOTSETABLE_ATTRBIT(&checkattrbits, nd);
2189 			   NFSCLRBIT_ATTRBIT(&checkattrbits,
2190 				NFSATTRBIT_TIMEACCESSSET);
2191 			   if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
2192 			       || retnotsup)
2193 				*retcmpp = NFSERR_NOTSAME;
2194 			}
2195 			attrsum += cnt;
2196 			break;
2197 		case NFSATTRBIT_FSLAYOUTTYPE:
2198 		case NFSATTRBIT_LAYOUTTYPE:
2199 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2200 			attrsum += NFSX_UNSIGNED;
2201 			i = fxdr_unsigned(int, *tl);
2202 			if (i > 0) {
2203 				NFSM_DISSECT(tl, u_int32_t *, i *
2204 				    NFSX_UNSIGNED);
2205 				attrsum += i * NFSX_UNSIGNED;
2206 				j = fxdr_unsigned(int, *tl);
2207 				if (i == 1 && compare && !(*retcmpp) &&
2208 				    (((nfsrv_doflexfile != 0 ||
2209 				       nfsrv_maxpnfsmirror > 1) &&
2210 				      j != NFSLAYOUT_FLEXFILE) ||
2211 				    (nfsrv_doflexfile == 0 &&
2212 				     j != NFSLAYOUT_NFSV4_1_FILES)))
2213 					*retcmpp = NFSERR_NOTSAME;
2214 			}
2215 			if (nfsrv_devidcnt == 0) {
2216 				if (compare && !(*retcmpp) && i > 0)
2217 					*retcmpp = NFSERR_NOTSAME;
2218 			} else {
2219 				if (compare && !(*retcmpp) && i != 1)
2220 					*retcmpp = NFSERR_NOTSAME;
2221 			}
2222 			break;
2223 		case NFSATTRBIT_LAYOUTALIGNMENT:
2224 		case NFSATTRBIT_LAYOUTBLKSIZE:
2225 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2226 			attrsum += NFSX_UNSIGNED;
2227 			i = fxdr_unsigned(int, *tl);
2228 			if (compare && !(*retcmpp) && i != NFS_SRVMAXIO)
2229 				*retcmpp = NFSERR_NOTSAME;
2230 			break;
2231 		default:
2232 			printf("EEK! nfsv4_loadattr unknown attr=%d\n",
2233 				bitpos);
2234 			if (compare && !(*retcmpp))
2235 				*retcmpp = NFSERR_ATTRNOTSUPP;
2236 			/*
2237 			 * and get out of the loop, since we can't parse
2238 			 * the unknown attrbute data.
2239 			 */
2240 			bitpos = NFSATTRBIT_MAX;
2241 			break;
2242 		}
2243 	}
2244 
2245 	/*
2246 	 * some clients pad the attrlist, so we need to skip over the
2247 	 * padding.
2248 	 */
2249 	if (attrsum > attrsize) {
2250 		error = NFSERR_BADXDR;
2251 	} else {
2252 		attrsize = NFSM_RNDUP(attrsize);
2253 		if (attrsum < attrsize)
2254 			error = nfsm_advance(nd, attrsize - attrsum, -1);
2255 	}
2256 nfsmout:
2257 	NFSEXITCODE2(error, nd);
2258 	return (error);
2259 }
2260 
2261 /*
2262  * Implement sleep locks for newnfs. The nfslock_usecnt allows for a
2263  * shared lock and the NFSXXX_LOCK flag permits an exclusive lock.
2264  * The first argument is a pointer to an nfsv4lock structure.
2265  * The second argument is 1 iff a blocking lock is wanted.
2266  * If this argument is 0, the call waits until no thread either wants nor
2267  * holds an exclusive lock.
2268  * It returns 1 if the lock was acquired, 0 otherwise.
2269  * If several processes call this function concurrently wanting the exclusive
2270  * lock, one will get the lock and the rest will return without getting the
2271  * lock. (If the caller must have the lock, it simply calls this function in a
2272  *  loop until the function returns 1 to indicate the lock was acquired.)
2273  * Any usecnt must be decremented by calling nfsv4_relref() before
2274  * calling nfsv4_lock(). It was done this way, so nfsv4_lock() could
2275  * be called in a loop.
2276  * The isleptp argument is set to indicate if the call slept, iff not NULL
2277  * and the mp argument indicates to check for a forced dismount, iff not
2278  * NULL.
2279  */
2280 int
2281 nfsv4_lock(struct nfsv4lock *lp, int iwantlock, int *isleptp,
2282     void *mutex, struct mount *mp)
2283 {
2284 
2285 	if (isleptp)
2286 		*isleptp = 0;
2287 	/*
2288 	 * If a lock is wanted, loop around until the lock is acquired by
2289 	 * someone and then released. If I want the lock, try to acquire it.
2290 	 * For a lock to be issued, no lock must be in force and the usecnt
2291 	 * must be zero.
2292 	 */
2293 	if (iwantlock) {
2294 	    if (!(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
2295 		lp->nfslock_usecnt == 0) {
2296 		lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
2297 		lp->nfslock_lock |= NFSV4LOCK_LOCK;
2298 		return (1);
2299 	    }
2300 	    lp->nfslock_lock |= NFSV4LOCK_LOCKWANTED;
2301 	}
2302 	while (lp->nfslock_lock & (NFSV4LOCK_LOCK | NFSV4LOCK_LOCKWANTED)) {
2303 		if (mp != NULL && NFSCL_FORCEDISM(mp)) {
2304 			lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
2305 			return (0);
2306 		}
2307 		lp->nfslock_lock |= NFSV4LOCK_WANTED;
2308 		if (isleptp)
2309 			*isleptp = 1;
2310 		(void) nfsmsleep(&lp->nfslock_lock, mutex,
2311 		    PZERO - 1, "nfsv4lck", NULL);
2312 		if (iwantlock && !(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
2313 		    lp->nfslock_usecnt == 0) {
2314 			lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
2315 			lp->nfslock_lock |= NFSV4LOCK_LOCK;
2316 			return (1);
2317 		}
2318 	}
2319 	return (0);
2320 }
2321 
2322 /*
2323  * Release the lock acquired by nfsv4_lock().
2324  * The second argument is set to 1 to indicate the nfslock_usecnt should be
2325  * incremented, as well.
2326  */
2327 void
2328 nfsv4_unlock(struct nfsv4lock *lp, int incref)
2329 {
2330 
2331 	lp->nfslock_lock &= ~NFSV4LOCK_LOCK;
2332 	if (incref)
2333 		lp->nfslock_usecnt++;
2334 	nfsv4_wanted(lp);
2335 }
2336 
2337 /*
2338  * Release a reference cnt.
2339  */
2340 void
2341 nfsv4_relref(struct nfsv4lock *lp)
2342 {
2343 
2344 	if (lp->nfslock_usecnt <= 0)
2345 		panic("nfsv4root ref cnt");
2346 	lp->nfslock_usecnt--;
2347 	if (lp->nfslock_usecnt == 0)
2348 		nfsv4_wanted(lp);
2349 }
2350 
2351 /*
2352  * Get a reference cnt.
2353  * This function will wait for any exclusive lock to be released, but will
2354  * not wait for threads that want the exclusive lock. If priority needs
2355  * to be given to threads that need the exclusive lock, a call to nfsv4_lock()
2356  * with the 2nd argument == 0 should be done before calling nfsv4_getref().
2357  * If the mp argument is not NULL, check for NFSCL_FORCEDISM() being set and
2358  * return without getting a refcnt for that case.
2359  */
2360 void
2361 nfsv4_getref(struct nfsv4lock *lp, int *isleptp, void *mutex,
2362     struct mount *mp)
2363 {
2364 
2365 	if (isleptp)
2366 		*isleptp = 0;
2367 
2368 	/*
2369 	 * Wait for a lock held.
2370 	 */
2371 	while (lp->nfslock_lock & NFSV4LOCK_LOCK) {
2372 		if (mp != NULL && NFSCL_FORCEDISM(mp))
2373 			return;
2374 		lp->nfslock_lock |= NFSV4LOCK_WANTED;
2375 		if (isleptp)
2376 			*isleptp = 1;
2377 		(void) nfsmsleep(&lp->nfslock_lock, mutex,
2378 		    PZERO - 1, "nfsv4gr", NULL);
2379 	}
2380 	if (mp != NULL && NFSCL_FORCEDISM(mp))
2381 		return;
2382 
2383 	lp->nfslock_usecnt++;
2384 }
2385 
2386 /*
2387  * Get a reference as above, but return failure instead of sleeping if
2388  * an exclusive lock is held.
2389  */
2390 int
2391 nfsv4_getref_nonblock(struct nfsv4lock *lp)
2392 {
2393 
2394 	if ((lp->nfslock_lock & NFSV4LOCK_LOCK) != 0)
2395 		return (0);
2396 
2397 	lp->nfslock_usecnt++;
2398 	return (1);
2399 }
2400 
2401 /*
2402  * Test for a lock. Return 1 if locked, 0 otherwise.
2403  */
2404 int
2405 nfsv4_testlock(struct nfsv4lock *lp)
2406 {
2407 
2408 	if ((lp->nfslock_lock & NFSV4LOCK_LOCK) == 0 &&
2409 	    lp->nfslock_usecnt == 0)
2410 		return (0);
2411 	return (1);
2412 }
2413 
2414 /*
2415  * Wake up anyone sleeping, waiting for this lock.
2416  */
2417 static void
2418 nfsv4_wanted(struct nfsv4lock *lp)
2419 {
2420 
2421 	if (lp->nfslock_lock & NFSV4LOCK_WANTED) {
2422 		lp->nfslock_lock &= ~NFSV4LOCK_WANTED;
2423 		wakeup((caddr_t)&lp->nfslock_lock);
2424 	}
2425 }
2426 
2427 /*
2428  * Copy a string from an mbuf list into a character array.
2429  * Return EBADRPC if there is an mbuf error,
2430  * 0 otherwise.
2431  */
2432 int
2433 nfsrv_mtostr(struct nfsrv_descript *nd, char *str, int siz)
2434 {
2435 	char *cp;
2436 	int xfer, len;
2437 	struct mbuf *mp;
2438 	int rem, error = 0;
2439 
2440 	mp = nd->nd_md;
2441 	cp = nd->nd_dpos;
2442 	len = mtod(mp, caddr_t) + mp->m_len - cp;
2443 	rem = NFSM_RNDUP(siz) - siz;
2444 	while (siz > 0) {
2445 		if (len > siz)
2446 			xfer = siz;
2447 		else
2448 			xfer = len;
2449 		NFSBCOPY(cp, str, xfer);
2450 		str += xfer;
2451 		siz -= xfer;
2452 		if (siz > 0) {
2453 			mp = mp->m_next;
2454 			if (mp == NULL) {
2455 				error = EBADRPC;
2456 				goto out;
2457 			}
2458 			cp = mtod(mp, caddr_t);
2459 			len = mp->m_len;
2460 		} else {
2461 			cp += xfer;
2462 			len -= xfer;
2463 		}
2464 	}
2465 	*str = '\0';
2466 	nd->nd_dpos = cp;
2467 	nd->nd_md = mp;
2468 	if (rem > 0) {
2469 		if (len < rem)
2470 			error = nfsm_advance(nd, rem, len);
2471 		else
2472 			nd->nd_dpos += rem;
2473 	}
2474 
2475 out:
2476 	NFSEXITCODE2(error, nd);
2477 	return (error);
2478 }
2479 
2480 /*
2481  * Fill in the attributes as marked by the bitmap (V4).
2482  */
2483 int
2484 nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp,
2485     NFSACL_T *saclp, struct vattr *vap, fhandle_t *fhp, int rderror,
2486     nfsattrbit_t *attrbitp, struct ucred *cred, NFSPROC_T *p, int isdgram,
2487     int reterr, int supports_nfsv4acls, int at_root, uint64_t mounted_on_fileno,
2488     struct statfs *pnfssf)
2489 {
2490 	int bitpos, retnum = 0;
2491 	u_int32_t *tl;
2492 	int siz, prefixnum, error;
2493 	u_char *cp, namestr[NFSV4_SMALLSTR];
2494 	nfsattrbit_t attrbits, retbits;
2495 	nfsattrbit_t *retbitp = &retbits;
2496 	u_int32_t freenum, *retnump;
2497 	u_int64_t uquad;
2498 	struct statfs *fs;
2499 	struct nfsfsinfo fsinf;
2500 	struct timespec temptime;
2501 	NFSACL_T *aclp, *naclp = NULL;
2502 	size_t atsiz;
2503 	bool xattrsupp;
2504 #ifdef QUOTA
2505 	struct dqblk dqb;
2506 	uid_t savuid;
2507 #endif
2508 
2509 	/*
2510 	 * First, set the bits that can be filled and get fsinfo.
2511 	 */
2512 	NFSSET_ATTRBIT(retbitp, attrbitp);
2513 	/*
2514 	 * If both p and cred are NULL, it is a client side setattr call.
2515 	 * If both p and cred are not NULL, it is a server side reply call.
2516 	 * If p is not NULL and cred is NULL, it is a client side callback
2517 	 * reply call.
2518 	 */
2519 	if (p == NULL && cred == NULL) {
2520 		NFSCLRNOTSETABLE_ATTRBIT(retbitp, nd);
2521 		aclp = saclp;
2522 	} else {
2523 		NFSCLRNOTFILLABLE_ATTRBIT(retbitp, nd);
2524 		naclp = acl_alloc(M_WAITOK);
2525 		aclp = naclp;
2526 	}
2527 	nfsvno_getfs(&fsinf, isdgram);
2528 #ifndef APPLE
2529 	/*
2530 	 * Get the VFS_STATFS(), since some attributes need them.
2531 	 */
2532 	fs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
2533 	if (NFSISSETSTATFS_ATTRBIT(retbitp)) {
2534 		error = VFS_STATFS(mp, fs);
2535 		if (error != 0) {
2536 			if (reterr) {
2537 				nd->nd_repstat = NFSERR_ACCES;
2538 				free(fs, M_STATFS);
2539 				return (0);
2540 			}
2541 			NFSCLRSTATFS_ATTRBIT(retbitp);
2542 		}
2543 	}
2544 #endif
2545 
2546 	/*
2547 	 * And the NFSv4 ACL...
2548 	 */
2549 	if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT) &&
2550 	    (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2551 		supports_nfsv4acls == 0))) {
2552 		NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT);
2553 	}
2554 	if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACL)) {
2555 		if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2556 		    supports_nfsv4acls == 0)) {
2557 			NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2558 		} else if (naclp != NULL) {
2559 			if (NFSVOPLOCK(vp, LK_SHARED) == 0) {
2560 				error = VOP_ACCESSX(vp, VREAD_ACL, cred, p);
2561 				if (error == 0)
2562 					error = VOP_GETACL(vp, ACL_TYPE_NFS4,
2563 					    naclp, cred, p);
2564 				NFSVOPUNLOCK(vp);
2565 			} else
2566 				error = NFSERR_PERM;
2567 			if (error != 0) {
2568 				if (reterr) {
2569 					nd->nd_repstat = NFSERR_ACCES;
2570 					free(fs, M_STATFS);
2571 					return (0);
2572 				}
2573 				NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2574 			}
2575 		}
2576 	}
2577 
2578 	/* Check to see if Extended Attributes are supported. */
2579 	xattrsupp = false;
2580 	if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_XATTRSUPPORT)) {
2581 		if (NFSVOPLOCK(vp, LK_SHARED) == 0) {
2582 			error = VOP_GETEXTATTR(vp, EXTATTR_NAMESPACE_USER,
2583 			    "xxx", NULL, &atsiz, cred, p);
2584 			NFSVOPUNLOCK(vp);
2585 			if (error != EOPNOTSUPP)
2586 				xattrsupp = true;
2587 		}
2588 	}
2589 
2590 	/*
2591 	 * Put out the attribute bitmap for the ones being filled in
2592 	 * and get the field for the number of attributes returned.
2593 	 */
2594 	prefixnum = nfsrv_putattrbit(nd, retbitp);
2595 	NFSM_BUILD(retnump, u_int32_t *, NFSX_UNSIGNED);
2596 	prefixnum += NFSX_UNSIGNED;
2597 
2598 	/*
2599 	 * Now, loop around filling in the attributes for each bit set.
2600 	 */
2601 	for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
2602 	    if (NFSISSET_ATTRBIT(retbitp, bitpos)) {
2603 		switch (bitpos) {
2604 		case NFSATTRBIT_SUPPORTEDATTRS:
2605 			NFSSETSUPP_ATTRBIT(&attrbits, nd);
2606 			if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL)
2607 			    && supports_nfsv4acls == 0)) {
2608 			    NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACLSUPPORT);
2609 			    NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACL);
2610 			}
2611 			retnum += nfsrv_putattrbit(nd, &attrbits);
2612 			break;
2613 		case NFSATTRBIT_TYPE:
2614 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2615 			*tl = vtonfsv34_type(vap->va_type);
2616 			retnum += NFSX_UNSIGNED;
2617 			break;
2618 		case NFSATTRBIT_FHEXPIRETYPE:
2619 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2620 			*tl = txdr_unsigned(NFSV4FHTYPE_PERSISTENT);
2621 			retnum += NFSX_UNSIGNED;
2622 			break;
2623 		case NFSATTRBIT_CHANGE:
2624 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2625 			txdr_hyper(vap->va_filerev, tl);
2626 			retnum += NFSX_HYPER;
2627 			break;
2628 		case NFSATTRBIT_SIZE:
2629 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2630 			txdr_hyper(vap->va_size, tl);
2631 			retnum += NFSX_HYPER;
2632 			break;
2633 		case NFSATTRBIT_LINKSUPPORT:
2634 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2635 			if (fsinf.fs_properties & NFSV3FSINFO_LINK)
2636 				*tl = newnfs_true;
2637 			else
2638 				*tl = newnfs_false;
2639 			retnum += NFSX_UNSIGNED;
2640 			break;
2641 		case NFSATTRBIT_SYMLINKSUPPORT:
2642 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2643 			if (fsinf.fs_properties & NFSV3FSINFO_SYMLINK)
2644 				*tl = newnfs_true;
2645 			else
2646 				*tl = newnfs_false;
2647 			retnum += NFSX_UNSIGNED;
2648 			break;
2649 		case NFSATTRBIT_NAMEDATTR:
2650 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2651 			*tl = newnfs_false;
2652 			retnum += NFSX_UNSIGNED;
2653 			break;
2654 		case NFSATTRBIT_FSID:
2655 			NFSM_BUILD(tl, u_int32_t *, NFSX_V4FSID);
2656 			*tl++ = 0;
2657 			*tl++ = txdr_unsigned(mp->mnt_stat.f_fsid.val[0]);
2658 			*tl++ = 0;
2659 			*tl = txdr_unsigned(mp->mnt_stat.f_fsid.val[1]);
2660 			retnum += NFSX_V4FSID;
2661 			break;
2662 		case NFSATTRBIT_UNIQUEHANDLES:
2663 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2664 			*tl = newnfs_true;
2665 			retnum += NFSX_UNSIGNED;
2666 			break;
2667 		case NFSATTRBIT_LEASETIME:
2668 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2669 			*tl = txdr_unsigned(nfsrv_lease);
2670 			retnum += NFSX_UNSIGNED;
2671 			break;
2672 		case NFSATTRBIT_RDATTRERROR:
2673 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2674 			*tl = txdr_unsigned(rderror);
2675 			retnum += NFSX_UNSIGNED;
2676 			break;
2677 		/*
2678 		 * Recommended Attributes. (Only the supported ones.)
2679 		 */
2680 		case NFSATTRBIT_ACL:
2681 			retnum += nfsrv_buildacl(nd, aclp, vnode_vtype(vp), p);
2682 			break;
2683 		case NFSATTRBIT_ACLSUPPORT:
2684 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2685 			*tl = txdr_unsigned(NFSV4ACE_SUPTYPES);
2686 			retnum += NFSX_UNSIGNED;
2687 			break;
2688 		case NFSATTRBIT_CANSETTIME:
2689 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2690 			if (fsinf.fs_properties & NFSV3FSINFO_CANSETTIME)
2691 				*tl = newnfs_true;
2692 			else
2693 				*tl = newnfs_false;
2694 			retnum += NFSX_UNSIGNED;
2695 			break;
2696 		case NFSATTRBIT_CASEINSENSITIVE:
2697 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2698 			*tl = newnfs_false;
2699 			retnum += NFSX_UNSIGNED;
2700 			break;
2701 		case NFSATTRBIT_CASEPRESERVING:
2702 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2703 			*tl = newnfs_true;
2704 			retnum += NFSX_UNSIGNED;
2705 			break;
2706 		case NFSATTRBIT_CHOWNRESTRICTED:
2707 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2708 			*tl = newnfs_true;
2709 			retnum += NFSX_UNSIGNED;
2710 			break;
2711 		case NFSATTRBIT_FILEHANDLE:
2712 			retnum += nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
2713 			break;
2714 		case NFSATTRBIT_FILEID:
2715 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2716 			uquad = vap->va_fileid;
2717 			txdr_hyper(uquad, tl);
2718 			retnum += NFSX_HYPER;
2719 			break;
2720 		case NFSATTRBIT_FILESAVAIL:
2721 			/*
2722 			 * Check quota and use min(quota, f_ffree).
2723 			 */
2724 			freenum = fs->f_ffree;
2725 #ifdef QUOTA
2726 			/*
2727 			 * ufs_quotactl() insists that the uid argument
2728 			 * equal p_ruid for non-root quota access, so
2729 			 * we'll just make sure that's the case.
2730 			 */
2731 			savuid = p->p_cred->p_ruid;
2732 			p->p_cred->p_ruid = cred->cr_uid;
2733 			if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2734 			    cred->cr_uid, (caddr_t)&dqb))
2735 			    freenum = min(dqb.dqb_isoftlimit-dqb.dqb_curinodes,
2736 				freenum);
2737 			p->p_cred->p_ruid = savuid;
2738 #endif	/* QUOTA */
2739 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2740 			*tl++ = 0;
2741 			*tl = txdr_unsigned(freenum);
2742 			retnum += NFSX_HYPER;
2743 			break;
2744 		case NFSATTRBIT_FILESFREE:
2745 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2746 			*tl++ = 0;
2747 			*tl = txdr_unsigned(fs->f_ffree);
2748 			retnum += NFSX_HYPER;
2749 			break;
2750 		case NFSATTRBIT_FILESTOTAL:
2751 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2752 			*tl++ = 0;
2753 			*tl = txdr_unsigned(fs->f_files);
2754 			retnum += NFSX_HYPER;
2755 			break;
2756 		case NFSATTRBIT_FSLOCATIONS:
2757 			NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2758 			*tl++ = 0;
2759 			*tl = 0;
2760 			retnum += 2 * NFSX_UNSIGNED;
2761 			break;
2762 		case NFSATTRBIT_HOMOGENEOUS:
2763 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2764 			if (fsinf.fs_properties & NFSV3FSINFO_HOMOGENEOUS)
2765 				*tl = newnfs_true;
2766 			else
2767 				*tl = newnfs_false;
2768 			retnum += NFSX_UNSIGNED;
2769 			break;
2770 		case NFSATTRBIT_MAXFILESIZE:
2771 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2772 			uquad = NFSRV_MAXFILESIZE;
2773 			txdr_hyper(uquad, tl);
2774 			retnum += NFSX_HYPER;
2775 			break;
2776 		case NFSATTRBIT_MAXLINK:
2777 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2778 			*tl = txdr_unsigned(NFS_LINK_MAX);
2779 			retnum += NFSX_UNSIGNED;
2780 			break;
2781 		case NFSATTRBIT_MAXNAME:
2782 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2783 			*tl = txdr_unsigned(NFS_MAXNAMLEN);
2784 			retnum += NFSX_UNSIGNED;
2785 			break;
2786 		case NFSATTRBIT_MAXREAD:
2787 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2788 			*tl++ = 0;
2789 			*tl = txdr_unsigned(fsinf.fs_rtmax);
2790 			retnum += NFSX_HYPER;
2791 			break;
2792 		case NFSATTRBIT_MAXWRITE:
2793 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2794 			*tl++ = 0;
2795 			*tl = txdr_unsigned(fsinf.fs_wtmax);
2796 			retnum += NFSX_HYPER;
2797 			break;
2798 		case NFSATTRBIT_MODE:
2799 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2800 			*tl = vtonfsv34_mode(vap->va_mode);
2801 			retnum += NFSX_UNSIGNED;
2802 			break;
2803 		case NFSATTRBIT_NOTRUNC:
2804 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2805 			*tl = newnfs_true;
2806 			retnum += NFSX_UNSIGNED;
2807 			break;
2808 		case NFSATTRBIT_NUMLINKS:
2809 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2810 			*tl = txdr_unsigned(vap->va_nlink);
2811 			retnum += NFSX_UNSIGNED;
2812 			break;
2813 		case NFSATTRBIT_OWNER:
2814 			cp = namestr;
2815 			nfsv4_uidtostr(vap->va_uid, &cp, &siz);
2816 			retnum += nfsm_strtom(nd, cp, siz);
2817 			if (cp != namestr)
2818 				free(cp, M_NFSSTRING);
2819 			break;
2820 		case NFSATTRBIT_OWNERGROUP:
2821 			cp = namestr;
2822 			nfsv4_gidtostr(vap->va_gid, &cp, &siz);
2823 			retnum += nfsm_strtom(nd, cp, siz);
2824 			if (cp != namestr)
2825 				free(cp, M_NFSSTRING);
2826 			break;
2827 		case NFSATTRBIT_QUOTAHARD:
2828 			if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA))
2829 				freenum = fs->f_bfree;
2830 			else
2831 				freenum = fs->f_bavail;
2832 #ifdef QUOTA
2833 			/*
2834 			 * ufs_quotactl() insists that the uid argument
2835 			 * equal p_ruid for non-root quota access, so
2836 			 * we'll just make sure that's the case.
2837 			 */
2838 			savuid = p->p_cred->p_ruid;
2839 			p->p_cred->p_ruid = cred->cr_uid;
2840 			if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2841 			    cred->cr_uid, (caddr_t)&dqb))
2842 			    freenum = min(dqb.dqb_bhardlimit, freenum);
2843 			p->p_cred->p_ruid = savuid;
2844 #endif	/* QUOTA */
2845 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2846 			uquad = (u_int64_t)freenum;
2847 			NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
2848 			txdr_hyper(uquad, tl);
2849 			retnum += NFSX_HYPER;
2850 			break;
2851 		case NFSATTRBIT_QUOTASOFT:
2852 			if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA))
2853 				freenum = fs->f_bfree;
2854 			else
2855 				freenum = fs->f_bavail;
2856 #ifdef QUOTA
2857 			/*
2858 			 * ufs_quotactl() insists that the uid argument
2859 			 * equal p_ruid for non-root quota access, so
2860 			 * we'll just make sure that's the case.
2861 			 */
2862 			savuid = p->p_cred->p_ruid;
2863 			p->p_cred->p_ruid = cred->cr_uid;
2864 			if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2865 			    cred->cr_uid, (caddr_t)&dqb))
2866 			    freenum = min(dqb.dqb_bsoftlimit, freenum);
2867 			p->p_cred->p_ruid = savuid;
2868 #endif	/* QUOTA */
2869 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2870 			uquad = (u_int64_t)freenum;
2871 			NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
2872 			txdr_hyper(uquad, tl);
2873 			retnum += NFSX_HYPER;
2874 			break;
2875 		case NFSATTRBIT_QUOTAUSED:
2876 			freenum = 0;
2877 #ifdef QUOTA
2878 			/*
2879 			 * ufs_quotactl() insists that the uid argument
2880 			 * equal p_ruid for non-root quota access, so
2881 			 * we'll just make sure that's the case.
2882 			 */
2883 			savuid = p->p_cred->p_ruid;
2884 			p->p_cred->p_ruid = cred->cr_uid;
2885 			if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2886 			    cred->cr_uid, (caddr_t)&dqb))
2887 			    freenum = dqb.dqb_curblocks;
2888 			p->p_cred->p_ruid = savuid;
2889 #endif	/* QUOTA */
2890 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2891 			uquad = (u_int64_t)freenum;
2892 			NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
2893 			txdr_hyper(uquad, tl);
2894 			retnum += NFSX_HYPER;
2895 			break;
2896 		case NFSATTRBIT_RAWDEV:
2897 			NFSM_BUILD(tl, u_int32_t *, NFSX_V4SPECDATA);
2898 			*tl++ = txdr_unsigned(NFSMAJOR(vap->va_rdev));
2899 			*tl = txdr_unsigned(NFSMINOR(vap->va_rdev));
2900 			retnum += NFSX_V4SPECDATA;
2901 			break;
2902 		case NFSATTRBIT_SPACEAVAIL:
2903 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2904 			if (priv_check_cred(cred, PRIV_VFS_BLOCKRESERVE)) {
2905 				if (pnfssf != NULL)
2906 					uquad = (u_int64_t)pnfssf->f_bfree;
2907 				else
2908 					uquad = (u_int64_t)fs->f_bfree;
2909 			} else {
2910 				if (pnfssf != NULL)
2911 					uquad = (u_int64_t)pnfssf->f_bavail;
2912 				else
2913 					uquad = (u_int64_t)fs->f_bavail;
2914 			}
2915 			if (pnfssf != NULL)
2916 				uquad *= pnfssf->f_bsize;
2917 			else
2918 				uquad *= fs->f_bsize;
2919 			txdr_hyper(uquad, tl);
2920 			retnum += NFSX_HYPER;
2921 			break;
2922 		case NFSATTRBIT_SPACEFREE:
2923 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2924 			if (pnfssf != NULL) {
2925 				uquad = (u_int64_t)pnfssf->f_bfree;
2926 				uquad *= pnfssf->f_bsize;
2927 			} else {
2928 				uquad = (u_int64_t)fs->f_bfree;
2929 				uquad *= fs->f_bsize;
2930 			}
2931 			txdr_hyper(uquad, tl);
2932 			retnum += NFSX_HYPER;
2933 			break;
2934 		case NFSATTRBIT_SPACETOTAL:
2935 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2936 			if (pnfssf != NULL) {
2937 				uquad = (u_int64_t)pnfssf->f_blocks;
2938 				uquad *= pnfssf->f_bsize;
2939 			} else {
2940 				uquad = (u_int64_t)fs->f_blocks;
2941 				uquad *= fs->f_bsize;
2942 			}
2943 			txdr_hyper(uquad, tl);
2944 			retnum += NFSX_HYPER;
2945 			break;
2946 		case NFSATTRBIT_SPACEUSED:
2947 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2948 			txdr_hyper(vap->va_bytes, tl);
2949 			retnum += NFSX_HYPER;
2950 			break;
2951 		case NFSATTRBIT_TIMEACCESS:
2952 			NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2953 			txdr_nfsv4time(&vap->va_atime, tl);
2954 			retnum += NFSX_V4TIME;
2955 			break;
2956 		case NFSATTRBIT_TIMEACCESSSET:
2957 			if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2958 				NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2959 				*tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2960 				txdr_nfsv4time(&vap->va_atime, tl);
2961 				retnum += NFSX_V4SETTIME;
2962 			} else {
2963 				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2964 				*tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2965 				retnum += NFSX_UNSIGNED;
2966 			}
2967 			break;
2968 		case NFSATTRBIT_TIMEDELTA:
2969 			NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2970 			temptime.tv_sec = 0;
2971 			temptime.tv_nsec = 1000000000 / hz;
2972 			txdr_nfsv4time(&temptime, tl);
2973 			retnum += NFSX_V4TIME;
2974 			break;
2975 		case NFSATTRBIT_TIMEMETADATA:
2976 			NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2977 			txdr_nfsv4time(&vap->va_ctime, tl);
2978 			retnum += NFSX_V4TIME;
2979 			break;
2980 		case NFSATTRBIT_TIMEMODIFY:
2981 			NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2982 			txdr_nfsv4time(&vap->va_mtime, tl);
2983 			retnum += NFSX_V4TIME;
2984 			break;
2985 		case NFSATTRBIT_TIMECREATE:
2986 			NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2987 			txdr_nfsv4time(&vap->va_birthtime, tl);
2988 			retnum += NFSX_V4TIME;
2989 			break;
2990 		case NFSATTRBIT_TIMEMODIFYSET:
2991 			if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2992 				NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2993 				*tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2994 				txdr_nfsv4time(&vap->va_mtime, tl);
2995 				retnum += NFSX_V4SETTIME;
2996 			} else {
2997 				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2998 				*tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2999 				retnum += NFSX_UNSIGNED;
3000 			}
3001 			break;
3002 		case NFSATTRBIT_MOUNTEDONFILEID:
3003 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
3004 			if (at_root != 0)
3005 				uquad = mounted_on_fileno;
3006 			else
3007 				uquad = vap->va_fileid;
3008 			txdr_hyper(uquad, tl);
3009 			retnum += NFSX_HYPER;
3010 			break;
3011 		case NFSATTRBIT_SUPPATTREXCLCREAT:
3012 			NFSSETSUPP_ATTRBIT(&attrbits, nd);
3013 			NFSCLRNOTSETABLE_ATTRBIT(&attrbits, nd);
3014 			NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET);
3015 			retnum += nfsrv_putattrbit(nd, &attrbits);
3016 			break;
3017 		case NFSATTRBIT_FSLAYOUTTYPE:
3018 		case NFSATTRBIT_LAYOUTTYPE:
3019 			if (nfsrv_devidcnt == 0)
3020 				siz = 1;
3021 			else
3022 				siz = 2;
3023 			if (siz == 2) {
3024 				NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3025 				*tl++ = txdr_unsigned(1);	/* One entry. */
3026 				if (nfsrv_doflexfile != 0 ||
3027 				    nfsrv_maxpnfsmirror > 1)
3028 					*tl = txdr_unsigned(NFSLAYOUT_FLEXFILE);
3029 				else
3030 					*tl = txdr_unsigned(
3031 					    NFSLAYOUT_NFSV4_1_FILES);
3032 			} else {
3033 				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3034 				*tl = 0;
3035 			}
3036 			retnum += siz * NFSX_UNSIGNED;
3037 			break;
3038 		case NFSATTRBIT_LAYOUTALIGNMENT:
3039 		case NFSATTRBIT_LAYOUTBLKSIZE:
3040 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3041 			*tl = txdr_unsigned(NFS_SRVMAXIO);
3042 			retnum += NFSX_UNSIGNED;
3043 			break;
3044 		case NFSATTRBIT_XATTRSUPPORT:
3045 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3046 			if (xattrsupp)
3047 				*tl = newnfs_true;
3048 			else
3049 				*tl = newnfs_false;
3050 			retnum += NFSX_UNSIGNED;
3051 			break;
3052 		default:
3053 			printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos);
3054 		}
3055 	    }
3056 	}
3057 	if (naclp != NULL)
3058 		acl_free(naclp);
3059 	free(fs, M_STATFS);
3060 	*retnump = txdr_unsigned(retnum);
3061 	return (retnum + prefixnum);
3062 }
3063 
3064 /*
3065  * Put the attribute bits onto an mbuf list.
3066  * Return the number of bytes of output generated.
3067  */
3068 int
3069 nfsrv_putattrbit(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp)
3070 {
3071 	u_int32_t *tl;
3072 	int cnt, i, bytesize;
3073 
3074 	for (cnt = NFSATTRBIT_MAXWORDS; cnt > 0; cnt--)
3075 		if (attrbitp->bits[cnt - 1])
3076 			break;
3077 	bytesize = (cnt + 1) * NFSX_UNSIGNED;
3078 	NFSM_BUILD(tl, u_int32_t *, bytesize);
3079 	*tl++ = txdr_unsigned(cnt);
3080 	for (i = 0; i < cnt; i++)
3081 		*tl++ = txdr_unsigned(attrbitp->bits[i]);
3082 	return (bytesize);
3083 }
3084 
3085 /*
3086  * Convert a uid to a string.
3087  * If the lookup fails, just output the digits.
3088  * uid - the user id
3089  * cpp - points to a buffer of size NFSV4_SMALLSTR
3090  *       (malloc a larger one, as required)
3091  * retlenp - pointer to length to be returned
3092  */
3093 void
3094 nfsv4_uidtostr(uid_t uid, u_char **cpp, int *retlenp)
3095 {
3096 	int i;
3097 	struct nfsusrgrp *usrp;
3098 	u_char *cp = *cpp;
3099 	uid_t tmp;
3100 	int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
3101 	struct nfsrv_lughash *hp;
3102 
3103 	cnt = 0;
3104 tryagain:
3105 	if (nfsrv_dnsnamelen > 0 && !nfs_enable_uidtostring) {
3106 		/*
3107 		 * Always map nfsrv_defaultuid to "nobody".
3108 		 */
3109 		if (uid == nfsrv_defaultuid) {
3110 			i = nfsrv_dnsnamelen + 7;
3111 			if (i > len) {
3112 				if (len > NFSV4_SMALLSTR)
3113 					free(cp, M_NFSSTRING);
3114 				cp = malloc(i, M_NFSSTRING, M_WAITOK);
3115 				*cpp = cp;
3116 				len = i;
3117 				goto tryagain;
3118 			}
3119 			*retlenp = i;
3120 			NFSBCOPY("nobody@", cp, 7);
3121 			cp += 7;
3122 			NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
3123 			return;
3124 		}
3125 		hasampersand = 0;
3126 		hp = NFSUSERHASH(uid);
3127 		mtx_lock(&hp->mtx);
3128 		TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
3129 			if (usrp->lug_uid == uid) {
3130 				if (usrp->lug_expiry < NFSD_MONOSEC)
3131 					break;
3132 				/*
3133 				 * If the name doesn't already have an '@'
3134 				 * in it, append @domainname to it.
3135 				 */
3136 				for (i = 0; i < usrp->lug_namelen; i++) {
3137 					if (usrp->lug_name[i] == '@') {
3138 						hasampersand = 1;
3139 						break;
3140 					}
3141 				}
3142 				if (hasampersand)
3143 					i = usrp->lug_namelen;
3144 				else
3145 					i = usrp->lug_namelen +
3146 					    nfsrv_dnsnamelen + 1;
3147 				if (i > len) {
3148 					mtx_unlock(&hp->mtx);
3149 					if (len > NFSV4_SMALLSTR)
3150 						free(cp, M_NFSSTRING);
3151 					cp = malloc(i, M_NFSSTRING, M_WAITOK);
3152 					*cpp = cp;
3153 					len = i;
3154 					goto tryagain;
3155 				}
3156 				*retlenp = i;
3157 				NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
3158 				if (!hasampersand) {
3159 					cp += usrp->lug_namelen;
3160 					*cp++ = '@';
3161 					NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
3162 				}
3163 				TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3164 				TAILQ_INSERT_TAIL(&hp->lughead, usrp,
3165 				    lug_numhash);
3166 				mtx_unlock(&hp->mtx);
3167 				return;
3168 			}
3169 		}
3170 		mtx_unlock(&hp->mtx);
3171 		cnt++;
3172 		ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0, NULL);
3173 		if (ret == 0 && cnt < 2)
3174 			goto tryagain;
3175 	}
3176 
3177 	/*
3178 	 * No match, just return a string of digits.
3179 	 */
3180 	tmp = uid;
3181 	i = 0;
3182 	while (tmp || i == 0) {
3183 		tmp /= 10;
3184 		i++;
3185 	}
3186 	len = (i > len) ? len : i;
3187 	*retlenp = len;
3188 	cp += (len - 1);
3189 	tmp = uid;
3190 	for (i = 0; i < len; i++) {
3191 		*cp-- = '0' + (tmp % 10);
3192 		tmp /= 10;
3193 	}
3194 	return;
3195 }
3196 
3197 /*
3198  * Get a credential for the uid with the server's group list.
3199  * If none is found, just return the credential passed in after
3200  * logging a warning message.
3201  */
3202 struct ucred *
3203 nfsrv_getgrpscred(struct ucred *oldcred)
3204 {
3205 	struct nfsusrgrp *usrp;
3206 	struct ucred *newcred;
3207 	int cnt, ret;
3208 	uid_t uid;
3209 	struct nfsrv_lughash *hp;
3210 
3211 	cnt = 0;
3212 	uid = oldcred->cr_uid;
3213 tryagain:
3214 	if (nfsrv_dnsnamelen > 0) {
3215 		hp = NFSUSERHASH(uid);
3216 		mtx_lock(&hp->mtx);
3217 		TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
3218 			if (usrp->lug_uid == uid) {
3219 				if (usrp->lug_expiry < NFSD_MONOSEC)
3220 					break;
3221 				if (usrp->lug_cred != NULL) {
3222 					newcred = crhold(usrp->lug_cred);
3223 					crfree(oldcred);
3224 				} else
3225 					newcred = oldcred;
3226 				TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3227 				TAILQ_INSERT_TAIL(&hp->lughead, usrp,
3228 				    lug_numhash);
3229 				mtx_unlock(&hp->mtx);
3230 				return (newcred);
3231 			}
3232 		}
3233 		mtx_unlock(&hp->mtx);
3234 		cnt++;
3235 		ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0, NULL);
3236 		if (ret == 0 && cnt < 2)
3237 			goto tryagain;
3238 	}
3239 	return (oldcred);
3240 }
3241 
3242 /*
3243  * Convert a string to a uid.
3244  * If no conversion is possible return NFSERR_BADOWNER, otherwise
3245  * return 0.
3246  * If this is called from a client side mount using AUTH_SYS and the
3247  * string is made up entirely of digits, just convert the string to
3248  * a number.
3249  */
3250 int
3251 nfsv4_strtouid(struct nfsrv_descript *nd, u_char *str, int len, uid_t *uidp)
3252 {
3253 	int i;
3254 	char *cp, *endstr, *str0;
3255 	struct nfsusrgrp *usrp;
3256 	int cnt, ret;
3257 	int error = 0;
3258 	uid_t tuid;
3259 	struct nfsrv_lughash *hp, *hp2;
3260 
3261 	if (len == 0) {
3262 		error = NFSERR_BADOWNER;
3263 		goto out;
3264 	}
3265 	/* If a string of digits and an AUTH_SYS mount, just convert it. */
3266 	str0 = str;
3267 	tuid = (uid_t)strtoul(str0, &endstr, 10);
3268 	if ((endstr - str0) == len) {
3269 		/* A numeric string. */
3270 		if ((nd->nd_flag & ND_KERBV) == 0 &&
3271 		    ((nd->nd_flag & ND_NFSCL) != 0 ||
3272 		      nfsd_enable_stringtouid != 0))
3273 			*uidp = tuid;
3274 		else
3275 			error = NFSERR_BADOWNER;
3276 		goto out;
3277 	}
3278 	/*
3279 	 * Look for an '@'.
3280 	 */
3281 	cp = strchr(str0, '@');
3282 	if (cp != NULL)
3283 		i = (int)(cp++ - str0);
3284 	else
3285 		i = len;
3286 
3287 	cnt = 0;
3288 tryagain:
3289 	if (nfsrv_dnsnamelen > 0) {
3290 		/*
3291 		 * If an '@' is found and the domain name matches, search for
3292 		 * the name with dns stripped off.
3293 		 * Mixed case alpahbetics will match for the domain name, but
3294 		 * all upper case will not.
3295 		 */
3296 		if (cnt == 0 && i < len && i > 0 &&
3297 		    (len - 1 - i) == nfsrv_dnsnamelen &&
3298 		    !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
3299 			len -= (nfsrv_dnsnamelen + 1);
3300 			*(cp - 1) = '\0';
3301 		}
3302 
3303 		/*
3304 		 * Check for the special case of "nobody".
3305 		 */
3306 		if (len == 6 && !NFSBCMP(str, "nobody", 6)) {
3307 			*uidp = nfsrv_defaultuid;
3308 			error = 0;
3309 			goto out;
3310 		}
3311 
3312 		hp = NFSUSERNAMEHASH(str, len);
3313 		mtx_lock(&hp->mtx);
3314 		TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) {
3315 			if (usrp->lug_namelen == len &&
3316 			    !NFSBCMP(usrp->lug_name, str, len)) {
3317 				if (usrp->lug_expiry < NFSD_MONOSEC)
3318 					break;
3319 				hp2 = NFSUSERHASH(usrp->lug_uid);
3320 				mtx_lock(&hp2->mtx);
3321 				TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash);
3322 				TAILQ_INSERT_TAIL(&hp2->lughead, usrp,
3323 				    lug_numhash);
3324 				*uidp = usrp->lug_uid;
3325 				mtx_unlock(&hp2->mtx);
3326 				mtx_unlock(&hp->mtx);
3327 				error = 0;
3328 				goto out;
3329 			}
3330 		}
3331 		mtx_unlock(&hp->mtx);
3332 		cnt++;
3333 		ret = nfsrv_getuser(RPCNFSUSERD_GETUSER, (uid_t)0, (gid_t)0,
3334 		    str);
3335 		if (ret == 0 && cnt < 2)
3336 			goto tryagain;
3337 	}
3338 	error = NFSERR_BADOWNER;
3339 
3340 out:
3341 	NFSEXITCODE(error);
3342 	return (error);
3343 }
3344 
3345 /*
3346  * Convert a gid to a string.
3347  * gid - the group id
3348  * cpp - points to a buffer of size NFSV4_SMALLSTR
3349  *       (malloc a larger one, as required)
3350  * retlenp - pointer to length to be returned
3351  */
3352 void
3353 nfsv4_gidtostr(gid_t gid, u_char **cpp, int *retlenp)
3354 {
3355 	int i;
3356 	struct nfsusrgrp *usrp;
3357 	u_char *cp = *cpp;
3358 	gid_t tmp;
3359 	int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
3360 	struct nfsrv_lughash *hp;
3361 
3362 	cnt = 0;
3363 tryagain:
3364 	if (nfsrv_dnsnamelen > 0 && !nfs_enable_uidtostring) {
3365 		/*
3366 		 * Always map nfsrv_defaultgid to "nogroup".
3367 		 */
3368 		if (gid == nfsrv_defaultgid) {
3369 			i = nfsrv_dnsnamelen + 8;
3370 			if (i > len) {
3371 				if (len > NFSV4_SMALLSTR)
3372 					free(cp, M_NFSSTRING);
3373 				cp = malloc(i, M_NFSSTRING, M_WAITOK);
3374 				*cpp = cp;
3375 				len = i;
3376 				goto tryagain;
3377 			}
3378 			*retlenp = i;
3379 			NFSBCOPY("nogroup@", cp, 8);
3380 			cp += 8;
3381 			NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
3382 			return;
3383 		}
3384 		hasampersand = 0;
3385 		hp = NFSGROUPHASH(gid);
3386 		mtx_lock(&hp->mtx);
3387 		TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
3388 			if (usrp->lug_gid == gid) {
3389 				if (usrp->lug_expiry < NFSD_MONOSEC)
3390 					break;
3391 				/*
3392 				 * If the name doesn't already have an '@'
3393 				 * in it, append @domainname to it.
3394 				 */
3395 				for (i = 0; i < usrp->lug_namelen; i++) {
3396 					if (usrp->lug_name[i] == '@') {
3397 						hasampersand = 1;
3398 						break;
3399 					}
3400 				}
3401 				if (hasampersand)
3402 					i = usrp->lug_namelen;
3403 				else
3404 					i = usrp->lug_namelen +
3405 					    nfsrv_dnsnamelen + 1;
3406 				if (i > len) {
3407 					mtx_unlock(&hp->mtx);
3408 					if (len > NFSV4_SMALLSTR)
3409 						free(cp, M_NFSSTRING);
3410 					cp = malloc(i, M_NFSSTRING, M_WAITOK);
3411 					*cpp = cp;
3412 					len = i;
3413 					goto tryagain;
3414 				}
3415 				*retlenp = i;
3416 				NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
3417 				if (!hasampersand) {
3418 					cp += usrp->lug_namelen;
3419 					*cp++ = '@';
3420 					NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
3421 				}
3422 				TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3423 				TAILQ_INSERT_TAIL(&hp->lughead, usrp,
3424 				    lug_numhash);
3425 				mtx_unlock(&hp->mtx);
3426 				return;
3427 			}
3428 		}
3429 		mtx_unlock(&hp->mtx);
3430 		cnt++;
3431 		ret = nfsrv_getuser(RPCNFSUSERD_GETGID, (uid_t)0, gid, NULL);
3432 		if (ret == 0 && cnt < 2)
3433 			goto tryagain;
3434 	}
3435 
3436 	/*
3437 	 * No match, just return a string of digits.
3438 	 */
3439 	tmp = gid;
3440 	i = 0;
3441 	while (tmp || i == 0) {
3442 		tmp /= 10;
3443 		i++;
3444 	}
3445 	len = (i > len) ? len : i;
3446 	*retlenp = len;
3447 	cp += (len - 1);
3448 	tmp = gid;
3449 	for (i = 0; i < len; i++) {
3450 		*cp-- = '0' + (tmp % 10);
3451 		tmp /= 10;
3452 	}
3453 	return;
3454 }
3455 
3456 /*
3457  * Convert a string to a gid.
3458  * If no conversion is possible return NFSERR_BADOWNER, otherwise
3459  * return 0.
3460  * If this is called from a client side mount using AUTH_SYS and the
3461  * string is made up entirely of digits, just convert the string to
3462  * a number.
3463  */
3464 int
3465 nfsv4_strtogid(struct nfsrv_descript *nd, u_char *str, int len, gid_t *gidp)
3466 {
3467 	int i;
3468 	char *cp, *endstr, *str0;
3469 	struct nfsusrgrp *usrp;
3470 	int cnt, ret;
3471 	int error = 0;
3472 	gid_t tgid;
3473 	struct nfsrv_lughash *hp, *hp2;
3474 
3475 	if (len == 0) {
3476 		error =  NFSERR_BADOWNER;
3477 		goto out;
3478 	}
3479 	/* If a string of digits and an AUTH_SYS mount, just convert it. */
3480 	str0 = str;
3481 	tgid = (gid_t)strtoul(str0, &endstr, 10);
3482 	if ((endstr - str0) == len) {
3483 		/* A numeric string. */
3484 		if ((nd->nd_flag & ND_KERBV) == 0 &&
3485 		    ((nd->nd_flag & ND_NFSCL) != 0 ||
3486 		      nfsd_enable_stringtouid != 0))
3487 			*gidp = tgid;
3488 		else
3489 			error = NFSERR_BADOWNER;
3490 		goto out;
3491 	}
3492 	/*
3493 	 * Look for an '@'.
3494 	 */
3495 	cp = strchr(str0, '@');
3496 	if (cp != NULL)
3497 		i = (int)(cp++ - str0);
3498 	else
3499 		i = len;
3500 
3501 	cnt = 0;
3502 tryagain:
3503 	if (nfsrv_dnsnamelen > 0) {
3504 		/*
3505 		 * If an '@' is found and the dns name matches, search for the
3506 		 * name with the dns stripped off.
3507 		 */
3508 		if (cnt == 0 && i < len && i > 0 &&
3509 		    (len - 1 - i) == nfsrv_dnsnamelen &&
3510 		    !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
3511 			len -= (nfsrv_dnsnamelen + 1);
3512 			*(cp - 1) = '\0';
3513 		}
3514 
3515 		/*
3516 		 * Check for the special case of "nogroup".
3517 		 */
3518 		if (len == 7 && !NFSBCMP(str, "nogroup", 7)) {
3519 			*gidp = nfsrv_defaultgid;
3520 			error = 0;
3521 			goto out;
3522 		}
3523 
3524 		hp = NFSGROUPNAMEHASH(str, len);
3525 		mtx_lock(&hp->mtx);
3526 		TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) {
3527 			if (usrp->lug_namelen == len &&
3528 			    !NFSBCMP(usrp->lug_name, str, len)) {
3529 				if (usrp->lug_expiry < NFSD_MONOSEC)
3530 					break;
3531 				hp2 = NFSGROUPHASH(usrp->lug_gid);
3532 				mtx_lock(&hp2->mtx);
3533 				TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash);
3534 				TAILQ_INSERT_TAIL(&hp2->lughead, usrp,
3535 				    lug_numhash);
3536 				*gidp = usrp->lug_gid;
3537 				mtx_unlock(&hp2->mtx);
3538 				mtx_unlock(&hp->mtx);
3539 				error = 0;
3540 				goto out;
3541 			}
3542 		}
3543 		mtx_unlock(&hp->mtx);
3544 		cnt++;
3545 		ret = nfsrv_getuser(RPCNFSUSERD_GETGROUP, (uid_t)0, (gid_t)0,
3546 		    str);
3547 		if (ret == 0 && cnt < 2)
3548 			goto tryagain;
3549 	}
3550 	error = NFSERR_BADOWNER;
3551 
3552 out:
3553 	NFSEXITCODE(error);
3554 	return (error);
3555 }
3556 
3557 /*
3558  * Cmp len chars, allowing mixed case in the first argument to match lower
3559  * case in the second, but not if the first argument is all upper case.
3560  * Return 0 for a match, 1 otherwise.
3561  */
3562 static int
3563 nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len)
3564 {
3565 	int i;
3566 	u_char tmp;
3567 	int fndlower = 0;
3568 
3569 	for (i = 0; i < len; i++) {
3570 		if (*cp >= 'A' && *cp <= 'Z') {
3571 			tmp = *cp++ + ('a' - 'A');
3572 		} else {
3573 			tmp = *cp++;
3574 			if (tmp >= 'a' && tmp <= 'z')
3575 				fndlower = 1;
3576 		}
3577 		if (tmp != *cp2++)
3578 			return (1);
3579 	}
3580 	if (fndlower)
3581 		return (0);
3582 	else
3583 		return (1);
3584 }
3585 
3586 /*
3587  * Set the port for the nfsuserd.
3588  */
3589 int
3590 nfsrv_nfsuserdport(struct nfsuserd_args *nargs, NFSPROC_T *p)
3591 {
3592 	struct nfssockreq *rp;
3593 #ifdef INET
3594 	struct sockaddr_in *ad;
3595 #endif
3596 #ifdef INET6
3597 	struct sockaddr_in6 *ad6;
3598 	const struct in6_addr in6loopback = IN6ADDR_LOOPBACK_INIT;
3599 #endif
3600 	int error;
3601 
3602 	NFSLOCKNAMEID();
3603 	if (nfsrv_nfsuserd != NOTRUNNING) {
3604 		NFSUNLOCKNAMEID();
3605 		error = EPERM;
3606 		goto out;
3607 	}
3608 	nfsrv_nfsuserd = STARTSTOP;
3609 	/*
3610 	 * Set up the socket record and connect.
3611 	 * Set nr_client NULL before unlocking, just to ensure that no other
3612 	 * process/thread/core will use a bogus old value.  This could only
3613 	 * occur if the use of the nameid lock to protect nfsrv_nfsuserd is
3614 	 * broken.
3615 	 */
3616 	rp = &nfsrv_nfsuserdsock;
3617 	rp->nr_client = NULL;
3618 	NFSUNLOCKNAMEID();
3619 	rp->nr_sotype = SOCK_DGRAM;
3620 	rp->nr_soproto = IPPROTO_UDP;
3621 	rp->nr_lock = (NFSR_RESERVEDPORT | NFSR_LOCALHOST);
3622 	rp->nr_cred = NULL;
3623 	rp->nr_prog = RPCPROG_NFSUSERD;
3624 	error = 0;
3625 	switch (nargs->nuserd_family) {
3626 #ifdef INET
3627 	case AF_INET:
3628 		rp->nr_nam = malloc(sizeof(struct sockaddr_in), M_SONAME,
3629 		    M_WAITOK | M_ZERO);
3630  		ad = (struct sockaddr_in *)rp->nr_nam;
3631 		ad->sin_len = sizeof(struct sockaddr_in);
3632  		ad->sin_family = AF_INET;
3633 		ad->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
3634 		ad->sin_port = nargs->nuserd_port;
3635 		break;
3636 #endif
3637 #ifdef INET6
3638 	case AF_INET6:
3639 		rp->nr_nam = malloc(sizeof(struct sockaddr_in6), M_SONAME,
3640 		    M_WAITOK | M_ZERO);
3641 		ad6 = (struct sockaddr_in6 *)rp->nr_nam;
3642 		ad6->sin6_len = sizeof(struct sockaddr_in6);
3643 		ad6->sin6_family = AF_INET6;
3644 		ad6->sin6_addr = in6loopback;
3645 		ad6->sin6_port = nargs->nuserd_port;
3646 		break;
3647 #endif
3648 	default:
3649 		error = ENXIO;
3650  	}
3651 	rp->nr_vers = RPCNFSUSERD_VERS;
3652 	if (error == 0)
3653 		error = newnfs_connect(NULL, rp, NFSPROCCRED(p), p, 0);
3654 	if (error == 0) {
3655 		NFSLOCKNAMEID();
3656 		nfsrv_nfsuserd = RUNNING;
3657 		NFSUNLOCKNAMEID();
3658 	} else {
3659 		free(rp->nr_nam, M_SONAME);
3660 		NFSLOCKNAMEID();
3661 		nfsrv_nfsuserd = NOTRUNNING;
3662 		NFSUNLOCKNAMEID();
3663 	}
3664 out:
3665 	NFSEXITCODE(error);
3666 	return (error);
3667 }
3668 
3669 /*
3670  * Delete the nfsuserd port.
3671  */
3672 void
3673 nfsrv_nfsuserddelport(void)
3674 {
3675 
3676 	NFSLOCKNAMEID();
3677 	if (nfsrv_nfsuserd != RUNNING) {
3678 		NFSUNLOCKNAMEID();
3679 		return;
3680 	}
3681 	nfsrv_nfsuserd = STARTSTOP;
3682 	/* Wait for all upcalls to complete. */
3683 	while (nfsrv_userdupcalls > 0)
3684 		msleep(&nfsrv_userdupcalls, NFSNAMEIDMUTEXPTR, PVFS,
3685 		    "nfsupcalls", 0);
3686 	NFSUNLOCKNAMEID();
3687 	newnfs_disconnect(&nfsrv_nfsuserdsock);
3688 	free(nfsrv_nfsuserdsock.nr_nam, M_SONAME);
3689 	NFSLOCKNAMEID();
3690 	nfsrv_nfsuserd = NOTRUNNING;
3691 	NFSUNLOCKNAMEID();
3692 }
3693 
3694 /*
3695  * Do upcalls to the nfsuserd, for cache misses of the owner/ownergroup
3696  * name<-->id cache.
3697  * Returns 0 upon success, non-zero otherwise.
3698  */
3699 static int
3700 nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name)
3701 {
3702 	u_int32_t *tl;
3703 	struct nfsrv_descript *nd;
3704 	int len;
3705 	struct nfsrv_descript nfsd;
3706 	struct ucred *cred;
3707 	int error;
3708 
3709 	NFSLOCKNAMEID();
3710 	if (nfsrv_nfsuserd != RUNNING) {
3711 		NFSUNLOCKNAMEID();
3712 		error = EPERM;
3713 		goto out;
3714 	}
3715 	/*
3716 	 * Maintain a count of upcalls in progress, so that nfsrv_X()
3717 	 * can wait until no upcalls are in progress.
3718 	 */
3719 	nfsrv_userdupcalls++;
3720 	NFSUNLOCKNAMEID();
3721 	KASSERT(nfsrv_userdupcalls > 0,
3722 	    ("nfsrv_getuser: non-positive upcalls"));
3723 	nd = &nfsd;
3724 	cred = newnfs_getcred();
3725 	nd->nd_flag = ND_GSSINITREPLY;
3726 	nfsrvd_rephead(nd);
3727 
3728 	nd->nd_procnum = procnum;
3729 	if (procnum == RPCNFSUSERD_GETUID || procnum == RPCNFSUSERD_GETGID) {
3730 		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3731 		if (procnum == RPCNFSUSERD_GETUID)
3732 			*tl = txdr_unsigned(uid);
3733 		else
3734 			*tl = txdr_unsigned(gid);
3735 	} else {
3736 		len = strlen(name);
3737 		(void) nfsm_strtom(nd, name, len);
3738 	}
3739 	error = newnfs_request(nd, NULL, NULL, &nfsrv_nfsuserdsock, NULL, NULL,
3740 		cred, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, NULL, 0, NULL, NULL);
3741 	NFSLOCKNAMEID();
3742 	if (--nfsrv_userdupcalls == 0 && nfsrv_nfsuserd == STARTSTOP)
3743 		wakeup(&nfsrv_userdupcalls);
3744 	NFSUNLOCKNAMEID();
3745 	NFSFREECRED(cred);
3746 	if (!error) {
3747 		m_freem(nd->nd_mrep);
3748 		error = nd->nd_repstat;
3749 	}
3750 out:
3751 	NFSEXITCODE(error);
3752 	return (error);
3753 }
3754 
3755 /*
3756  * This function is called from the nfssvc(2) system call, to update the
3757  * kernel user/group name list(s) for the V4 owner and ownergroup attributes.
3758  */
3759 int
3760 nfssvc_idname(struct nfsd_idargs *nidp)
3761 {
3762 	struct nfsusrgrp *nusrp, *usrp, *newusrp;
3763 	struct nfsrv_lughash *hp_name, *hp_idnum, *thp;
3764 	int i, group_locked, groupname_locked, user_locked, username_locked;
3765 	int error = 0;
3766 	u_char *cp;
3767 	gid_t *grps;
3768 	struct ucred *cr;
3769 	static int onethread = 0;
3770 	static time_t lasttime = 0;
3771 
3772 	if (nidp->nid_namelen <= 0 || nidp->nid_namelen > MAXHOSTNAMELEN) {
3773 		error = EINVAL;
3774 		goto out;
3775 	}
3776 	if (nidp->nid_flag & NFSID_INITIALIZE) {
3777 		cp = malloc(nidp->nid_namelen + 1, M_NFSSTRING, M_WAITOK);
3778 		error = copyin(nidp->nid_name, cp, nidp->nid_namelen);
3779 		if (error != 0) {
3780 			free(cp, M_NFSSTRING);
3781 			goto out;
3782 		}
3783 		if (atomic_cmpset_acq_int(&nfsrv_dnsnamelen, 0, 0) == 0) {
3784 			/*
3785 			 * Free up all the old stuff and reinitialize hash
3786 			 * lists.  All mutexes for both lists must be locked,
3787 			 * with the user/group name ones before the uid/gid
3788 			 * ones, to avoid a LOR.
3789 			 */
3790 			for (i = 0; i < nfsrv_lughashsize; i++)
3791 				mtx_lock(&nfsusernamehash[i].mtx);
3792 			for (i = 0; i < nfsrv_lughashsize; i++)
3793 				mtx_lock(&nfsuserhash[i].mtx);
3794 			for (i = 0; i < nfsrv_lughashsize; i++)
3795 				TAILQ_FOREACH_SAFE(usrp,
3796 				    &nfsuserhash[i].lughead, lug_numhash, nusrp)
3797 					nfsrv_removeuser(usrp, 1);
3798 			for (i = 0; i < nfsrv_lughashsize; i++)
3799 				mtx_unlock(&nfsuserhash[i].mtx);
3800 			for (i = 0; i < nfsrv_lughashsize; i++)
3801 				mtx_unlock(&nfsusernamehash[i].mtx);
3802 			for (i = 0; i < nfsrv_lughashsize; i++)
3803 				mtx_lock(&nfsgroupnamehash[i].mtx);
3804 			for (i = 0; i < nfsrv_lughashsize; i++)
3805 				mtx_lock(&nfsgrouphash[i].mtx);
3806 			for (i = 0; i < nfsrv_lughashsize; i++)
3807 				TAILQ_FOREACH_SAFE(usrp,
3808 				    &nfsgrouphash[i].lughead, lug_numhash,
3809 				    nusrp)
3810 					nfsrv_removeuser(usrp, 0);
3811 			for (i = 0; i < nfsrv_lughashsize; i++)
3812 				mtx_unlock(&nfsgrouphash[i].mtx);
3813 			for (i = 0; i < nfsrv_lughashsize; i++)
3814 				mtx_unlock(&nfsgroupnamehash[i].mtx);
3815 			free(nfsrv_dnsname, M_NFSSTRING);
3816 			nfsrv_dnsname = NULL;
3817 		}
3818 		if (nfsuserhash == NULL) {
3819 			/* Allocate the hash tables. */
3820 			nfsuserhash = malloc(sizeof(struct nfsrv_lughash) *
3821 			    nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3822 			    M_ZERO);
3823 			for (i = 0; i < nfsrv_lughashsize; i++)
3824 				mtx_init(&nfsuserhash[i].mtx, "nfsuidhash",
3825 				    NULL, MTX_DEF | MTX_DUPOK);
3826 			nfsusernamehash = malloc(sizeof(struct nfsrv_lughash) *
3827 			    nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3828 			    M_ZERO);
3829 			for (i = 0; i < nfsrv_lughashsize; i++)
3830 				mtx_init(&nfsusernamehash[i].mtx,
3831 				    "nfsusrhash", NULL, MTX_DEF |
3832 				    MTX_DUPOK);
3833 			nfsgrouphash = malloc(sizeof(struct nfsrv_lughash) *
3834 			    nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3835 			    M_ZERO);
3836 			for (i = 0; i < nfsrv_lughashsize; i++)
3837 				mtx_init(&nfsgrouphash[i].mtx, "nfsgidhash",
3838 				    NULL, MTX_DEF | MTX_DUPOK);
3839 			nfsgroupnamehash = malloc(sizeof(struct nfsrv_lughash) *
3840 			    nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3841 			    M_ZERO);
3842 			for (i = 0; i < nfsrv_lughashsize; i++)
3843 			    mtx_init(&nfsgroupnamehash[i].mtx,
3844 			    "nfsgrphash", NULL, MTX_DEF | MTX_DUPOK);
3845 		}
3846 		/* (Re)initialize the list heads. */
3847 		for (i = 0; i < nfsrv_lughashsize; i++)
3848 			TAILQ_INIT(&nfsuserhash[i].lughead);
3849 		for (i = 0; i < nfsrv_lughashsize; i++)
3850 			TAILQ_INIT(&nfsusernamehash[i].lughead);
3851 		for (i = 0; i < nfsrv_lughashsize; i++)
3852 			TAILQ_INIT(&nfsgrouphash[i].lughead);
3853 		for (i = 0; i < nfsrv_lughashsize; i++)
3854 			TAILQ_INIT(&nfsgroupnamehash[i].lughead);
3855 
3856 		/*
3857 		 * Put name in "DNS" string.
3858 		 */
3859 		nfsrv_dnsname = cp;
3860 		nfsrv_defaultuid = nidp->nid_uid;
3861 		nfsrv_defaultgid = nidp->nid_gid;
3862 		nfsrv_usercnt = 0;
3863 		nfsrv_usermax = nidp->nid_usermax;
3864 		atomic_store_rel_int(&nfsrv_dnsnamelen, nidp->nid_namelen);
3865 		goto out;
3866 	}
3867 
3868 	/*
3869 	 * malloc the new one now, so any potential sleep occurs before
3870 	 * manipulation of the lists.
3871 	 */
3872 	newusrp = malloc(sizeof(struct nfsusrgrp) + nidp->nid_namelen,
3873 	    M_NFSUSERGROUP, M_WAITOK | M_ZERO);
3874 	error = copyin(nidp->nid_name, newusrp->lug_name,
3875 	    nidp->nid_namelen);
3876 	if (error == 0 && nidp->nid_ngroup > 0 &&
3877 	    (nidp->nid_flag & NFSID_ADDUID) != 0) {
3878 		grps = malloc(sizeof(gid_t) * nidp->nid_ngroup, M_TEMP,
3879 		    M_WAITOK);
3880 		error = copyin(nidp->nid_grps, grps,
3881 		    sizeof(gid_t) * nidp->nid_ngroup);
3882 		if (error == 0) {
3883 			/*
3884 			 * Create a credential just like svc_getcred(),
3885 			 * but using the group list provided.
3886 			 */
3887 			cr = crget();
3888 			cr->cr_uid = cr->cr_ruid = cr->cr_svuid = nidp->nid_uid;
3889 			crsetgroups(cr, nidp->nid_ngroup, grps);
3890 			cr->cr_rgid = cr->cr_svgid = cr->cr_groups[0];
3891 			cr->cr_prison = &prison0;
3892 			prison_hold(cr->cr_prison);
3893 #ifdef MAC
3894 			mac_cred_associate_nfsd(cr);
3895 #endif
3896 			newusrp->lug_cred = cr;
3897 		}
3898 		free(grps, M_TEMP);
3899 	}
3900 	if (error) {
3901 		free(newusrp, M_NFSUSERGROUP);
3902 		goto out;
3903 	}
3904 	newusrp->lug_namelen = nidp->nid_namelen;
3905 
3906 	/*
3907 	 * The lock order is username[0]->[nfsrv_lughashsize - 1] followed
3908 	 * by uid[0]->[nfsrv_lughashsize - 1], with the same for group.
3909 	 * The flags user_locked, username_locked, group_locked and
3910 	 * groupname_locked are set to indicate all of those hash lists are
3911 	 * locked. hp_name != NULL  and hp_idnum != NULL indicates that
3912 	 * the respective one mutex is locked.
3913 	 */
3914 	user_locked = username_locked = group_locked = groupname_locked = 0;
3915 	hp_name = hp_idnum = NULL;
3916 
3917 	/*
3918 	 * Delete old entries, as required.
3919 	 */
3920 	if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) {
3921 		/* Must lock all username hash lists first, to avoid a LOR. */
3922 		for (i = 0; i < nfsrv_lughashsize; i++)
3923 			mtx_lock(&nfsusernamehash[i].mtx);
3924 		username_locked = 1;
3925 		hp_idnum = NFSUSERHASH(nidp->nid_uid);
3926 		mtx_lock(&hp_idnum->mtx);
3927 		TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
3928 		    nusrp) {
3929 			if (usrp->lug_uid == nidp->nid_uid)
3930 				nfsrv_removeuser(usrp, 1);
3931 		}
3932 	} else if (nidp->nid_flag & (NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) {
3933 		hp_name = NFSUSERNAMEHASH(newusrp->lug_name,
3934 		    newusrp->lug_namelen);
3935 		mtx_lock(&hp_name->mtx);
3936 		TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
3937 		    nusrp) {
3938 			if (usrp->lug_namelen == newusrp->lug_namelen &&
3939 			    !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3940 			    usrp->lug_namelen)) {
3941 				thp = NFSUSERHASH(usrp->lug_uid);
3942 				mtx_lock(&thp->mtx);
3943 				nfsrv_removeuser(usrp, 1);
3944 				mtx_unlock(&thp->mtx);
3945 			}
3946 		}
3947 		hp_idnum = NFSUSERHASH(nidp->nid_uid);
3948 		mtx_lock(&hp_idnum->mtx);
3949 	} else if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) {
3950 		/* Must lock all groupname hash lists first, to avoid a LOR. */
3951 		for (i = 0; i < nfsrv_lughashsize; i++)
3952 			mtx_lock(&nfsgroupnamehash[i].mtx);
3953 		groupname_locked = 1;
3954 		hp_idnum = NFSGROUPHASH(nidp->nid_gid);
3955 		mtx_lock(&hp_idnum->mtx);
3956 		TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
3957 		    nusrp) {
3958 			if (usrp->lug_gid == nidp->nid_gid)
3959 				nfsrv_removeuser(usrp, 0);
3960 		}
3961 	} else if (nidp->nid_flag & (NFSID_DELGROUPNAME | NFSID_ADDGROUPNAME)) {
3962 		hp_name = NFSGROUPNAMEHASH(newusrp->lug_name,
3963 		    newusrp->lug_namelen);
3964 		mtx_lock(&hp_name->mtx);
3965 		TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
3966 		    nusrp) {
3967 			if (usrp->lug_namelen == newusrp->lug_namelen &&
3968 			    !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3969 			    usrp->lug_namelen)) {
3970 				thp = NFSGROUPHASH(usrp->lug_gid);
3971 				mtx_lock(&thp->mtx);
3972 				nfsrv_removeuser(usrp, 0);
3973 				mtx_unlock(&thp->mtx);
3974 			}
3975 		}
3976 		hp_idnum = NFSGROUPHASH(nidp->nid_gid);
3977 		mtx_lock(&hp_idnum->mtx);
3978 	}
3979 
3980 	/*
3981 	 * Now, we can add the new one.
3982 	 */
3983 	if (nidp->nid_usertimeout)
3984 		newusrp->lug_expiry = NFSD_MONOSEC + nidp->nid_usertimeout;
3985 	else
3986 		newusrp->lug_expiry = NFSD_MONOSEC + 5;
3987 	if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) {
3988 		newusrp->lug_uid = nidp->nid_uid;
3989 		thp = NFSUSERHASH(newusrp->lug_uid);
3990 		mtx_assert(&thp->mtx, MA_OWNED);
3991 		TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
3992 		thp = NFSUSERNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3993 		mtx_assert(&thp->mtx, MA_OWNED);
3994 		TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
3995 		atomic_add_int(&nfsrv_usercnt, 1);
3996 	} else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) {
3997 		newusrp->lug_gid = nidp->nid_gid;
3998 		thp = NFSGROUPHASH(newusrp->lug_gid);
3999 		mtx_assert(&thp->mtx, MA_OWNED);
4000 		TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
4001 		thp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
4002 		mtx_assert(&thp->mtx, MA_OWNED);
4003 		TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
4004 		atomic_add_int(&nfsrv_usercnt, 1);
4005 	} else {
4006 		if (newusrp->lug_cred != NULL)
4007 			crfree(newusrp->lug_cred);
4008 		free(newusrp, M_NFSUSERGROUP);
4009 	}
4010 
4011 	/*
4012 	 * Once per second, allow one thread to trim the cache.
4013 	 */
4014 	if (lasttime < NFSD_MONOSEC &&
4015 	    atomic_cmpset_acq_int(&onethread, 0, 1) != 0) {
4016 		/*
4017 		 * First, unlock the single mutexes, so that all entries
4018 		 * can be locked and any LOR is avoided.
4019 		 */
4020 		if (hp_name != NULL) {
4021 			mtx_unlock(&hp_name->mtx);
4022 			hp_name = NULL;
4023 		}
4024 		if (hp_idnum != NULL) {
4025 			mtx_unlock(&hp_idnum->mtx);
4026 			hp_idnum = NULL;
4027 		}
4028 
4029 		if ((nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID |
4030 		    NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) != 0) {
4031 			if (username_locked == 0) {
4032 				for (i = 0; i < nfsrv_lughashsize; i++)
4033 					mtx_lock(&nfsusernamehash[i].mtx);
4034 				username_locked = 1;
4035 			}
4036 			KASSERT(user_locked == 0,
4037 			    ("nfssvc_idname: user_locked"));
4038 			for (i = 0; i < nfsrv_lughashsize; i++)
4039 				mtx_lock(&nfsuserhash[i].mtx);
4040 			user_locked = 1;
4041 			for (i = 0; i < nfsrv_lughashsize; i++) {
4042 				TAILQ_FOREACH_SAFE(usrp,
4043 				    &nfsuserhash[i].lughead, lug_numhash,
4044 				    nusrp)
4045 					if (usrp->lug_expiry < NFSD_MONOSEC)
4046 						nfsrv_removeuser(usrp, 1);
4047 			}
4048 			for (i = 0; i < nfsrv_lughashsize; i++) {
4049 				/*
4050 				 * Trim the cache using an approximate LRU
4051 				 * algorithm.  This code deletes the least
4052 				 * recently used entry on each hash list.
4053 				 */
4054 				if (nfsrv_usercnt <= nfsrv_usermax)
4055 					break;
4056 				usrp = TAILQ_FIRST(&nfsuserhash[i].lughead);
4057 				if (usrp != NULL)
4058 					nfsrv_removeuser(usrp, 1);
4059 			}
4060 		} else {
4061 			if (groupname_locked == 0) {
4062 				for (i = 0; i < nfsrv_lughashsize; i++)
4063 					mtx_lock(&nfsgroupnamehash[i].mtx);
4064 				groupname_locked = 1;
4065 			}
4066 			KASSERT(group_locked == 0,
4067 			    ("nfssvc_idname: group_locked"));
4068 			for (i = 0; i < nfsrv_lughashsize; i++)
4069 				mtx_lock(&nfsgrouphash[i].mtx);
4070 			group_locked = 1;
4071 			for (i = 0; i < nfsrv_lughashsize; i++) {
4072 				TAILQ_FOREACH_SAFE(usrp,
4073 				    &nfsgrouphash[i].lughead, lug_numhash,
4074 				    nusrp)
4075 					if (usrp->lug_expiry < NFSD_MONOSEC)
4076 						nfsrv_removeuser(usrp, 0);
4077 			}
4078 			for (i = 0; i < nfsrv_lughashsize; i++) {
4079 				/*
4080 				 * Trim the cache using an approximate LRU
4081 				 * algorithm.  This code deletes the least
4082 				 * recently user entry on each hash list.
4083 				 */
4084 				if (nfsrv_usercnt <= nfsrv_usermax)
4085 					break;
4086 				usrp = TAILQ_FIRST(&nfsgrouphash[i].lughead);
4087 				if (usrp != NULL)
4088 					nfsrv_removeuser(usrp, 0);
4089 			}
4090 		}
4091 		lasttime = NFSD_MONOSEC;
4092 		atomic_store_rel_int(&onethread, 0);
4093 	}
4094 
4095 	/* Now, unlock all locked mutexes. */
4096 	if (hp_idnum != NULL)
4097 		mtx_unlock(&hp_idnum->mtx);
4098 	if (hp_name != NULL)
4099 		mtx_unlock(&hp_name->mtx);
4100 	if (user_locked != 0)
4101 		for (i = 0; i < nfsrv_lughashsize; i++)
4102 			mtx_unlock(&nfsuserhash[i].mtx);
4103 	if (username_locked != 0)
4104 		for (i = 0; i < nfsrv_lughashsize; i++)
4105 			mtx_unlock(&nfsusernamehash[i].mtx);
4106 	if (group_locked != 0)
4107 		for (i = 0; i < nfsrv_lughashsize; i++)
4108 			mtx_unlock(&nfsgrouphash[i].mtx);
4109 	if (groupname_locked != 0)
4110 		for (i = 0; i < nfsrv_lughashsize; i++)
4111 			mtx_unlock(&nfsgroupnamehash[i].mtx);
4112 out:
4113 	NFSEXITCODE(error);
4114 	return (error);
4115 }
4116 
4117 /*
4118  * Remove a user/group name element.
4119  */
4120 static void
4121 nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser)
4122 {
4123 	struct nfsrv_lughash *hp;
4124 
4125 	if (isuser != 0) {
4126 		hp = NFSUSERHASH(usrp->lug_uid);
4127 		mtx_assert(&hp->mtx, MA_OWNED);
4128 		TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
4129 		hp = NFSUSERNAMEHASH(usrp->lug_name, usrp->lug_namelen);
4130 		mtx_assert(&hp->mtx, MA_OWNED);
4131 		TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
4132 	} else {
4133 		hp = NFSGROUPHASH(usrp->lug_gid);
4134 		mtx_assert(&hp->mtx, MA_OWNED);
4135 		TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
4136 		hp = NFSGROUPNAMEHASH(usrp->lug_name, usrp->lug_namelen);
4137 		mtx_assert(&hp->mtx, MA_OWNED);
4138 		TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
4139 	}
4140 	atomic_add_int(&nfsrv_usercnt, -1);
4141 	if (usrp->lug_cred != NULL)
4142 		crfree(usrp->lug_cred);
4143 	free(usrp, M_NFSUSERGROUP);
4144 }
4145 
4146 /*
4147  * Free up all the allocations related to the name<-->id cache.
4148  * This function should only be called when the nfsuserd daemon isn't
4149  * running, since it doesn't do any locking.
4150  * This function is meant to be used when the nfscommon module is unloaded.
4151  */
4152 void
4153 nfsrv_cleanusergroup(void)
4154 {
4155 	struct nfsrv_lughash *hp, *hp2;
4156 	struct nfsusrgrp *nusrp, *usrp;
4157 	int i;
4158 
4159 	if (nfsuserhash == NULL)
4160 		return;
4161 
4162 	for (i = 0; i < nfsrv_lughashsize; i++) {
4163 		hp = &nfsuserhash[i];
4164 		TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) {
4165 			TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
4166 			hp2 = NFSUSERNAMEHASH(usrp->lug_name,
4167 			    usrp->lug_namelen);
4168 			TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash);
4169 			if (usrp->lug_cred != NULL)
4170 				crfree(usrp->lug_cred);
4171 			free(usrp, M_NFSUSERGROUP);
4172 		}
4173 		hp = &nfsgrouphash[i];
4174 		TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) {
4175 			TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
4176 			hp2 = NFSGROUPNAMEHASH(usrp->lug_name,
4177 			    usrp->lug_namelen);
4178 			TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash);
4179 			if (usrp->lug_cred != NULL)
4180 				crfree(usrp->lug_cred);
4181 			free(usrp, M_NFSUSERGROUP);
4182 		}
4183 		mtx_destroy(&nfsuserhash[i].mtx);
4184 		mtx_destroy(&nfsusernamehash[i].mtx);
4185 		mtx_destroy(&nfsgroupnamehash[i].mtx);
4186 		mtx_destroy(&nfsgrouphash[i].mtx);
4187 	}
4188 	free(nfsuserhash, M_NFSUSERGROUP);
4189 	free(nfsusernamehash, M_NFSUSERGROUP);
4190 	free(nfsgrouphash, M_NFSUSERGROUP);
4191 	free(nfsgroupnamehash, M_NFSUSERGROUP);
4192 	free(nfsrv_dnsname, M_NFSSTRING);
4193 }
4194 
4195 /*
4196  * This function scans a byte string and checks for UTF-8 compliance.
4197  * It returns 0 if it conforms and NFSERR_INVAL if not.
4198  */
4199 int
4200 nfsrv_checkutf8(u_int8_t *cp, int len)
4201 {
4202 	u_int32_t val = 0x0;
4203 	int cnt = 0, gotd = 0, shift = 0;
4204 	u_int8_t byte;
4205 	static int utf8_shift[5] = { 7, 11, 16, 21, 26 };
4206 	int error = 0;
4207 
4208 	/*
4209 	 * Here are what the variables are used for:
4210 	 * val - the calculated value of a multibyte char, used to check
4211 	 *       that it was coded with the correct range
4212 	 * cnt - the number of 10xxxxxx bytes to follow
4213 	 * gotd - set for a char of Dxxx, so D800<->DFFF can be checked for
4214 	 * shift - lower order bits of range (ie. "val >> shift" should
4215 	 *       not be 0, in other words, dividing by the lower bound
4216 	 *       of the range should get a non-zero value)
4217 	 * byte - used to calculate cnt
4218 	 */
4219 	while (len > 0) {
4220 		if (cnt > 0) {
4221 			/* This handles the 10xxxxxx bytes */
4222 			if ((*cp & 0xc0) != 0x80 ||
4223 			    (gotd && (*cp & 0x20))) {
4224 				error = NFSERR_INVAL;
4225 				goto out;
4226 			}
4227 			gotd = 0;
4228 			val <<= 6;
4229 			val |= (*cp & 0x3f);
4230 			cnt--;
4231 			if (cnt == 0 && (val >> shift) == 0x0) {
4232 				error = NFSERR_INVAL;
4233 				goto out;
4234 			}
4235 		} else if (*cp & 0x80) {
4236 			/* first byte of multi byte char */
4237 			byte = *cp;
4238 			while ((byte & 0x40) && cnt < 6) {
4239 				cnt++;
4240 				byte <<= 1;
4241 			}
4242 			if (cnt == 0 || cnt == 6) {
4243 				error = NFSERR_INVAL;
4244 				goto out;
4245 			}
4246 			val = (*cp & (0x3f >> cnt));
4247 			shift = utf8_shift[cnt - 1];
4248 			if (cnt == 2 && val == 0xd)
4249 				/* Check for the 0xd800-0xdfff case */
4250 				gotd = 1;
4251 		}
4252 		cp++;
4253 		len--;
4254 	}
4255 	if (cnt > 0)
4256 		error = NFSERR_INVAL;
4257 
4258 out:
4259 	NFSEXITCODE(error);
4260 	return (error);
4261 }
4262 
4263 /*
4264  * Parse the xdr for an NFSv4 FsLocations attribute. Return two malloc'd
4265  * strings, one with the root path in it and the other with the list of
4266  * locations. The list is in the same format as is found in nfr_refs.
4267  * It is a "," separated list of entries, where each of them is of the
4268  * form <server>:<rootpath>. For example
4269  * "nfsv4-test:/sub2,nfsv4-test2:/user/mnt,nfsv4-test2:/user/mnt2"
4270  * The nilp argument is set to 1 for the special case of a null fs_root
4271  * and an empty server list.
4272  * It returns NFSERR_BADXDR, if the xdr can't be parsed and returns the
4273  * number of xdr bytes parsed in sump.
4274  */
4275 static int
4276 nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp,
4277     int *sump, int *nilp)
4278 {
4279 	u_int32_t *tl;
4280 	u_char *cp = NULL, *cp2 = NULL, *cp3, *str;
4281 	int i, j, len, stringlen, cnt, slen, siz, xdrsum, error = 0, nsrv;
4282 	struct list {
4283 		SLIST_ENTRY(list) next;
4284 		int len;
4285 		u_char host[1];
4286 	} *lsp, *nlsp;
4287 	SLIST_HEAD(, list) head;
4288 
4289 	*fsrootp = NULL;
4290 	*srvp = NULL;
4291 	*nilp = 0;
4292 
4293 	/*
4294 	 * Get the fs_root path and check for the special case of null path
4295 	 * and 0 length server list.
4296 	 */
4297 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4298 	len = fxdr_unsigned(int, *tl);
4299 	if (len < 0 || len > 10240) {
4300 		error = NFSERR_BADXDR;
4301 		goto nfsmout;
4302 	}
4303 	if (len == 0) {
4304 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4305 		if (*tl != 0) {
4306 			error = NFSERR_BADXDR;
4307 			goto nfsmout;
4308 		}
4309 		*nilp = 1;
4310 		*sump = 2 * NFSX_UNSIGNED;
4311 		error = 0;
4312 		goto nfsmout;
4313 	}
4314 	cp = malloc(len + 1, M_NFSSTRING, M_WAITOK);
4315 	error = nfsrv_mtostr(nd, cp, len);
4316 	if (!error) {
4317 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4318 		cnt = fxdr_unsigned(int, *tl);
4319 		if (cnt <= 0)
4320 			error = NFSERR_BADXDR;
4321 	}
4322 	if (error)
4323 		goto nfsmout;
4324 
4325 	/*
4326 	 * Now, loop through the location list and make up the srvlist.
4327 	 */
4328 	xdrsum = (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
4329 	cp2 = cp3 = malloc(1024, M_NFSSTRING, M_WAITOK);
4330 	slen = 1024;
4331 	siz = 0;
4332 	for (i = 0; i < cnt; i++) {
4333 		SLIST_INIT(&head);
4334 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4335 		nsrv = fxdr_unsigned(int, *tl);
4336 		if (nsrv <= 0) {
4337 			error = NFSERR_BADXDR;
4338 			goto nfsmout;
4339 		}
4340 
4341 		/*
4342 		 * Handle the first server by putting it in the srvstr.
4343 		 */
4344 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4345 		len = fxdr_unsigned(int, *tl);
4346 		if (len <= 0 || len > 1024) {
4347 			error = NFSERR_BADXDR;
4348 			goto nfsmout;
4349 		}
4350 		nfsrv_refstrbigenough(siz + len + 3, &cp2, &cp3, &slen);
4351 		if (cp3 != cp2) {
4352 			*cp3++ = ',';
4353 			siz++;
4354 		}
4355 		error = nfsrv_mtostr(nd, cp3, len);
4356 		if (error)
4357 			goto nfsmout;
4358 		cp3 += len;
4359 		*cp3++ = ':';
4360 		siz += (len + 1);
4361 		xdrsum += (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
4362 		for (j = 1; j < nsrv; j++) {
4363 			/*
4364 			 * Yuck, put them in an slist and process them later.
4365 			 */
4366 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4367 			len = fxdr_unsigned(int, *tl);
4368 			if (len <= 0 || len > 1024) {
4369 				error = NFSERR_BADXDR;
4370 				goto nfsmout;
4371 			}
4372 			lsp = (struct list *)malloc(sizeof (struct list)
4373 			    + len, M_TEMP, M_WAITOK);
4374 			error = nfsrv_mtostr(nd, lsp->host, len);
4375 			if (error)
4376 				goto nfsmout;
4377 			xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
4378 			lsp->len = len;
4379 			SLIST_INSERT_HEAD(&head, lsp, next);
4380 		}
4381 
4382 		/*
4383 		 * Finally, we can get the path.
4384 		 */
4385 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4386 		len = fxdr_unsigned(int, *tl);
4387 		if (len <= 0 || len > 1024) {
4388 			error = NFSERR_BADXDR;
4389 			goto nfsmout;
4390 		}
4391 		nfsrv_refstrbigenough(siz + len + 1, &cp2, &cp3, &slen);
4392 		error = nfsrv_mtostr(nd, cp3, len);
4393 		if (error)
4394 			goto nfsmout;
4395 		xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
4396 		str = cp3;
4397 		stringlen = len;
4398 		cp3 += len;
4399 		siz += len;
4400 		SLIST_FOREACH_SAFE(lsp, &head, next, nlsp) {
4401 			nfsrv_refstrbigenough(siz + lsp->len + stringlen + 3,
4402 			    &cp2, &cp3, &slen);
4403 			*cp3++ = ',';
4404 			NFSBCOPY(lsp->host, cp3, lsp->len);
4405 			cp3 += lsp->len;
4406 			*cp3++ = ':';
4407 			NFSBCOPY(str, cp3, stringlen);
4408 			cp3 += stringlen;
4409 			*cp3 = '\0';
4410 			siz += (lsp->len + stringlen + 2);
4411 			free(lsp, M_TEMP);
4412 		}
4413 	}
4414 	*fsrootp = cp;
4415 	*srvp = cp2;
4416 	*sump = xdrsum;
4417 	NFSEXITCODE2(0, nd);
4418 	return (0);
4419 nfsmout:
4420 	if (cp != NULL)
4421 		free(cp, M_NFSSTRING);
4422 	if (cp2 != NULL)
4423 		free(cp2, M_NFSSTRING);
4424 	NFSEXITCODE2(error, nd);
4425 	return (error);
4426 }
4427 
4428 /*
4429  * Make the malloc'd space large enough. This is a pain, but the xdr
4430  * doesn't set an upper bound on the side, so...
4431  */
4432 static void
4433 nfsrv_refstrbigenough(int siz, u_char **cpp, u_char **cpp2, int *slenp)
4434 {
4435 	u_char *cp;
4436 	int i;
4437 
4438 	if (siz <= *slenp)
4439 		return;
4440 	cp = malloc(siz + 1024, M_NFSSTRING, M_WAITOK);
4441 	NFSBCOPY(*cpp, cp, *slenp);
4442 	free(*cpp, M_NFSSTRING);
4443 	i = *cpp2 - *cpp;
4444 	*cpp = cp;
4445 	*cpp2 = cp + i;
4446 	*slenp = siz + 1024;
4447 }
4448 
4449 /*
4450  * Initialize the reply header data structures.
4451  */
4452 void
4453 nfsrvd_rephead(struct nfsrv_descript *nd)
4454 {
4455 	struct mbuf *mreq;
4456 
4457 	if ((nd->nd_flag & ND_EXTPG) != 0) {
4458 		mreq = mb_alloc_ext_plus_pages(PAGE_SIZE, M_WAITOK);
4459 		nd->nd_mreq = nd->nd_mb = mreq;
4460 		nd->nd_bpos = (char *)(void *)
4461 		    PHYS_TO_DMAP(mreq->m_epg_pa[0]);
4462 		nd->nd_bextpg = 0;
4463 		nd->nd_bextpgsiz = PAGE_SIZE;
4464 	} else {
4465 		/*
4466 		 * If this is a big reply, use a cluster.
4467 		 */
4468 		if ((nd->nd_flag & ND_GSSINITREPLY) == 0 &&
4469 		    nfs_bigreply[nd->nd_procnum]) {
4470 			NFSMCLGET(mreq, M_WAITOK);
4471 			nd->nd_mreq = mreq;
4472 			nd->nd_mb = mreq;
4473 		} else {
4474 			NFSMGET(mreq);
4475 			nd->nd_mreq = mreq;
4476 			nd->nd_mb = mreq;
4477 		}
4478 		nd->nd_bpos = mtod(mreq, char *);
4479 		mreq->m_len = 0;
4480 	}
4481 
4482 	if ((nd->nd_flag & ND_GSSINITREPLY) == 0)
4483 		NFSM_BUILD(nd->nd_errp, int *, NFSX_UNSIGNED);
4484 }
4485 
4486 /*
4487  * Lock a socket against others.
4488  * Currently used to serialize connect/disconnect attempts.
4489  */
4490 int
4491 newnfs_sndlock(int *flagp)
4492 {
4493 	struct timespec ts;
4494 
4495 	NFSLOCKSOCK();
4496 	while (*flagp & NFSR_SNDLOCK) {
4497 		*flagp |= NFSR_WANTSND;
4498 		ts.tv_sec = 0;
4499 		ts.tv_nsec = 0;
4500 		(void) nfsmsleep((caddr_t)flagp, NFSSOCKMUTEXPTR,
4501 		    PZERO - 1, "nfsndlck", &ts);
4502 	}
4503 	*flagp |= NFSR_SNDLOCK;
4504 	NFSUNLOCKSOCK();
4505 	return (0);
4506 }
4507 
4508 /*
4509  * Unlock the stream socket for others.
4510  */
4511 void
4512 newnfs_sndunlock(int *flagp)
4513 {
4514 
4515 	NFSLOCKSOCK();
4516 	if ((*flagp & NFSR_SNDLOCK) == 0)
4517 		panic("nfs sndunlock");
4518 	*flagp &= ~NFSR_SNDLOCK;
4519 	if (*flagp & NFSR_WANTSND) {
4520 		*flagp &= ~NFSR_WANTSND;
4521 		wakeup((caddr_t)flagp);
4522 	}
4523 	NFSUNLOCKSOCK();
4524 }
4525 
4526 int
4527 nfsv4_getipaddr(struct nfsrv_descript *nd, struct sockaddr_in *sin,
4528     struct sockaddr_in6 *sin6, sa_family_t *saf, int *isudp)
4529 {
4530 	struct in_addr saddr;
4531 	uint32_t portnum, *tl;
4532 	int i, j, k;
4533 	sa_family_t af = AF_UNSPEC;
4534 	char addr[64], protocol[5], *cp;
4535 	int cantparse = 0, error = 0;
4536 	uint16_t portv;
4537 
4538 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4539 	i = fxdr_unsigned(int, *tl);
4540 	if (i >= 3 && i <= 4) {
4541 		error = nfsrv_mtostr(nd, protocol, i);
4542 		if (error)
4543 			goto nfsmout;
4544 		if (strcmp(protocol, "tcp") == 0) {
4545 			af = AF_INET;
4546 			*isudp = 0;
4547 		} else if (strcmp(protocol, "udp") == 0) {
4548 			af = AF_INET;
4549 			*isudp = 1;
4550 		} else if (strcmp(protocol, "tcp6") == 0) {
4551 			af = AF_INET6;
4552 			*isudp = 0;
4553 		} else if (strcmp(protocol, "udp6") == 0) {
4554 			af = AF_INET6;
4555 			*isudp = 1;
4556 		} else
4557 			cantparse = 1;
4558 	} else {
4559 		cantparse = 1;
4560 		if (i > 0) {
4561 			error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
4562 			if (error)
4563 				goto nfsmout;
4564 		}
4565 	}
4566 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4567 	i = fxdr_unsigned(int, *tl);
4568 	if (i < 0) {
4569 		error = NFSERR_BADXDR;
4570 		goto nfsmout;
4571 	} else if (cantparse == 0 && i >= 11 && i < 64) {
4572 		/*
4573 		 * The shortest address is 11chars and the longest is < 64.
4574 		 */
4575 		error = nfsrv_mtostr(nd, addr, i);
4576 		if (error)
4577 			goto nfsmout;
4578 
4579 		/* Find the port# at the end and extract that. */
4580 		i = strlen(addr);
4581 		k = 0;
4582 		cp = &addr[i - 1];
4583 		/* Count back two '.'s from end to get port# field. */
4584 		for (j = 0; j < i; j++) {
4585 			if (*cp == '.') {
4586 				k++;
4587 				if (k == 2)
4588 					break;
4589 			}
4590 			cp--;
4591 		}
4592 		if (k == 2) {
4593 			/*
4594 			 * The NFSv4 port# is appended as .N.N, where N is
4595 			 * a decimal # in the range 0-255, just like an inet4
4596 			 * address. Cheat and use inet_aton(), which will
4597 			 * return a Class A address and then shift the high
4598 			 * order 8bits over to convert it to the port#.
4599 			 */
4600 			*cp++ = '\0';
4601 			if (inet_aton(cp, &saddr) == 1) {
4602 				portnum = ntohl(saddr.s_addr);
4603 				portv = (uint16_t)((portnum >> 16) |
4604 				    (portnum & 0xff));
4605 			} else
4606 				cantparse = 1;
4607 		} else
4608 			cantparse = 1;
4609 		if (cantparse == 0) {
4610 			if (af == AF_INET) {
4611 				if (inet_pton(af, addr, &sin->sin_addr) == 1) {
4612 					sin->sin_len = sizeof(*sin);
4613 					sin->sin_family = AF_INET;
4614 					sin->sin_port = htons(portv);
4615 					*saf = af;
4616 					return (0);
4617 				}
4618 			} else {
4619 				if (inet_pton(af, addr, &sin6->sin6_addr)
4620 				    == 1) {
4621 					sin6->sin6_len = sizeof(*sin6);
4622 					sin6->sin6_family = AF_INET6;
4623 					sin6->sin6_port = htons(portv);
4624 					*saf = af;
4625 					return (0);
4626 				}
4627 			}
4628 		}
4629 	} else {
4630 		if (i > 0) {
4631 			error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
4632 			if (error)
4633 				goto nfsmout;
4634 		}
4635 	}
4636 	error = EPERM;
4637 nfsmout:
4638 	return (error);
4639 }
4640 
4641 /*
4642  * Handle an NFSv4.1 Sequence request for the session.
4643  * If reply != NULL, use it to return the cached reply, as required.
4644  * The client gets a cached reply via this call for callbacks, however the
4645  * server gets a cached reply via the nfsv4_seqsess_cachereply() call.
4646  */
4647 int
4648 nfsv4_seqsession(uint32_t seqid, uint32_t slotid, uint32_t highslot,
4649     struct nfsslot *slots, struct mbuf **reply, uint16_t maxslot)
4650 {
4651 	int error;
4652 
4653 	error = 0;
4654 	if (reply != NULL)
4655 		*reply = NULL;
4656 	if (slotid > maxslot)
4657 		return (NFSERR_BADSLOT);
4658 	if (seqid == slots[slotid].nfssl_seq) {
4659 		/* A retry. */
4660 		if (slots[slotid].nfssl_inprog != 0)
4661 			error = NFSERR_DELAY;
4662 		else if (slots[slotid].nfssl_reply != NULL) {
4663 			if (reply != NULL) {
4664 				*reply = slots[slotid].nfssl_reply;
4665 				slots[slotid].nfssl_reply = NULL;
4666 			}
4667 			slots[slotid].nfssl_inprog = 1;
4668 			error = NFSERR_REPLYFROMCACHE;
4669 		} else
4670 			/* No reply cached, so just do it. */
4671 			slots[slotid].nfssl_inprog = 1;
4672 	} else if ((slots[slotid].nfssl_seq + 1) == seqid) {
4673 		if (slots[slotid].nfssl_reply != NULL)
4674 			m_freem(slots[slotid].nfssl_reply);
4675 		slots[slotid].nfssl_reply = NULL;
4676 		slots[slotid].nfssl_inprog = 1;
4677 		slots[slotid].nfssl_seq++;
4678 	} else
4679 		error = NFSERR_SEQMISORDERED;
4680 	return (error);
4681 }
4682 
4683 /*
4684  * Cache this reply for the slot.
4685  * Use the "rep" argument to return the cached reply if repstat is set to
4686  * NFSERR_REPLYFROMCACHE. The client never sets repstat to this value.
4687  */
4688 void
4689 nfsv4_seqsess_cacherep(uint32_t slotid, struct nfsslot *slots, int repstat,
4690    struct mbuf **rep)
4691 {
4692 
4693 	if (repstat == NFSERR_REPLYFROMCACHE) {
4694 		*rep = slots[slotid].nfssl_reply;
4695 		slots[slotid].nfssl_reply = NULL;
4696 	} else {
4697 		if (slots[slotid].nfssl_reply != NULL)
4698 			m_freem(slots[slotid].nfssl_reply);
4699 		slots[slotid].nfssl_reply = *rep;
4700 	}
4701 	slots[slotid].nfssl_inprog = 0;
4702 }
4703 
4704 /*
4705  * Generate the xdr for an NFSv4.1 Sequence Operation.
4706  */
4707 void
4708 nfsv4_setsequence(struct nfsmount *nmp, struct nfsrv_descript *nd,
4709     struct nfsclsession *sep, int dont_replycache)
4710 {
4711 	uint32_t *tl, slotseq = 0;
4712 	int error, maxslot, slotpos;
4713 	uint8_t sessionid[NFSX_V4SESSIONID];
4714 
4715 	error = nfsv4_sequencelookup(nmp, sep, &slotpos, &maxslot, &slotseq,
4716 	    sessionid);
4717 	nd->nd_maxreq = sep->nfsess_maxreq;
4718 	nd->nd_maxresp = sep->nfsess_maxresp;
4719 
4720 	/* Build the Sequence arguments. */
4721 	NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 4 * NFSX_UNSIGNED);
4722 	nd->nd_sequence = tl;
4723 	bcopy(sessionid, tl, NFSX_V4SESSIONID);
4724 	tl += NFSX_V4SESSIONID / NFSX_UNSIGNED;
4725 	nd->nd_slotseq = tl;
4726 	if (error == 0) {
4727 		nd->nd_flag |= ND_HASSLOTID;
4728 		nd->nd_slotid = slotpos;
4729 		*tl++ = txdr_unsigned(slotseq);
4730 		*tl++ = txdr_unsigned(slotpos);
4731 		*tl++ = txdr_unsigned(maxslot);
4732 		if (dont_replycache == 0)
4733 			*tl = newnfs_true;
4734 		else
4735 			*tl = newnfs_false;
4736 	} else {
4737 		/*
4738 		 * There are two errors and the rest of the session can
4739 		 * just be zeros.
4740 		 * NFSERR_BADSESSION: This bad session should just generate
4741 		 *    the same error again when the RPC is retried.
4742 		 * ESTALE: A forced dismount is in progress and will cause the
4743 		 *    RPC to fail later.
4744 		 */
4745 		*tl++ = 0;
4746 		*tl++ = 0;
4747 		*tl++ = 0;
4748 		*tl = 0;
4749 	}
4750 	nd->nd_flag |= ND_HASSEQUENCE;
4751 }
4752 
4753 int
4754 nfsv4_sequencelookup(struct nfsmount *nmp, struct nfsclsession *sep,
4755     int *slotposp, int *maxslotp, uint32_t *slotseqp, uint8_t *sessionid)
4756 {
4757 	int i, maxslot, slotpos;
4758 	uint64_t bitval;
4759 
4760 	/* Find an unused slot. */
4761 	slotpos = -1;
4762 	maxslot = -1;
4763 	mtx_lock(&sep->nfsess_mtx);
4764 	do {
4765 		if (nmp != NULL && sep->nfsess_defunct != 0) {
4766 			/* Just return the bad session. */
4767 			bcopy(sep->nfsess_sessionid, sessionid,
4768 			    NFSX_V4SESSIONID);
4769 			mtx_unlock(&sep->nfsess_mtx);
4770 			return (NFSERR_BADSESSION);
4771 		}
4772 		bitval = 1;
4773 		for (i = 0; i < sep->nfsess_foreslots; i++) {
4774 			if ((bitval & sep->nfsess_slots) == 0) {
4775 				slotpos = i;
4776 				sep->nfsess_slots |= bitval;
4777 				sep->nfsess_slotseq[i]++;
4778 				*slotseqp = sep->nfsess_slotseq[i];
4779 				break;
4780 			}
4781 			bitval <<= 1;
4782 		}
4783 		if (slotpos == -1) {
4784 			/*
4785 			 * If a forced dismount is in progress, just return.
4786 			 * This RPC attempt will fail when it calls
4787 			 * newnfs_request().
4788 			 */
4789 			if (nmp != NULL && NFSCL_FORCEDISM(nmp->nm_mountp)) {
4790 				mtx_unlock(&sep->nfsess_mtx);
4791 				return (ESTALE);
4792 			}
4793 			/* Wake up once/sec, to check for a forced dismount. */
4794 			(void)mtx_sleep(&sep->nfsess_slots, &sep->nfsess_mtx,
4795 			    PZERO, "nfsclseq", hz);
4796 		}
4797 	} while (slotpos == -1);
4798 	/* Now, find the highest slot in use. (nfsc_slots is 64bits) */
4799 	bitval = 1;
4800 	for (i = 0; i < 64; i++) {
4801 		if ((bitval & sep->nfsess_slots) != 0)
4802 			maxslot = i;
4803 		bitval <<= 1;
4804 	}
4805 	bcopy(sep->nfsess_sessionid, sessionid, NFSX_V4SESSIONID);
4806 	mtx_unlock(&sep->nfsess_mtx);
4807 	*slotposp = slotpos;
4808 	*maxslotp = maxslot;
4809 	return (0);
4810 }
4811 
4812 /*
4813  * Free a session slot.
4814  */
4815 void
4816 nfsv4_freeslot(struct nfsclsession *sep, int slot)
4817 {
4818 	uint64_t bitval;
4819 
4820 	bitval = 1;
4821 	if (slot > 0)
4822 		bitval <<= slot;
4823 	mtx_lock(&sep->nfsess_mtx);
4824 	if ((bitval & sep->nfsess_slots) == 0)
4825 		printf("freeing free slot!!\n");
4826 	sep->nfsess_slots &= ~bitval;
4827 	wakeup(&sep->nfsess_slots);
4828 	mtx_unlock(&sep->nfsess_mtx);
4829 }
4830 
4831 /*
4832  * Search for a matching pnfsd DS, based on the nmp arg.
4833  * Return one if found, NULL otherwise.
4834  */
4835 struct nfsdevice *
4836 nfsv4_findmirror(struct nfsmount *nmp)
4837 {
4838 	struct nfsdevice *ds;
4839 
4840 	mtx_assert(NFSDDSMUTEXPTR, MA_OWNED);
4841 	/*
4842 	 * Search the DS server list for a match with nmp.
4843 	 */
4844 	if (nfsrv_devidcnt == 0)
4845 		return (NULL);
4846 	TAILQ_FOREACH(ds, &nfsrv_devidhead, nfsdev_list) {
4847 		if (ds->nfsdev_nmp == nmp) {
4848 			NFSCL_DEBUG(4, "nfsv4_findmirror: fnd main ds\n");
4849 			break;
4850 		}
4851 	}
4852 	return (ds);
4853 }
4854 
4855 /*
4856  * Fill in the fields of "struct nfsrv_descript".
4857  */
4858 void
4859 nfsm_set(struct nfsrv_descript *nd, u_int offs)
4860 {
4861 	struct mbuf *m;
4862 	int rlen;
4863 
4864 	m = nd->nd_mb;
4865 	if ((m->m_flags & M_EXTPG) != 0) {
4866 		nd->nd_bextpg = 0;
4867 		while (offs > 0) {
4868 			if (nd->nd_bextpg == 0)
4869 				rlen = m_epg_pagelen(m, 0, m->m_epg_1st_off);
4870 			else
4871 				rlen = m_epg_pagelen(m, nd->nd_bextpg, 0);
4872 			if (offs <= rlen)
4873 				break;
4874 			offs -= rlen;
4875 			nd->nd_bextpg++;
4876 			if (nd->nd_bextpg == m->m_epg_npgs) {
4877 				printf("nfsm_set: build offs "
4878 				    "out of range\n");
4879 				nd->nd_bextpg--;
4880 				break;
4881 			}
4882 		}
4883 		nd->nd_bpos = (char *)(void *)
4884 		    PHYS_TO_DMAP(m->m_epg_pa[nd->nd_bextpg]);
4885 		if (nd->nd_bextpg == 0)
4886 			nd->nd_bpos += m->m_epg_1st_off;
4887 		if (offs > 0) {
4888 			nd->nd_bpos += offs;
4889 			nd->nd_bextpgsiz = rlen - offs;
4890 		} else if (nd->nd_bextpg == 0)
4891 			nd->nd_bextpgsiz = PAGE_SIZE - m->m_epg_1st_off;
4892 		else
4893 			nd->nd_bextpgsiz = PAGE_SIZE;
4894 	} else
4895 		nd->nd_bpos = mtod(m, char *) + offs;
4896 }
4897 
4898 /*
4899  * Grow a ext_pgs mbuf list.  Either allocate another page or add
4900  * an mbuf to the list.
4901  */
4902 struct mbuf *
4903 nfsm_add_ext_pgs(struct mbuf *m, int maxextsiz, int *bextpg)
4904 {
4905 	struct mbuf *mp;
4906 	vm_page_t pg;
4907 
4908 	if ((m->m_epg_npgs + 1) * PAGE_SIZE > maxextsiz) {
4909 		mp = mb_alloc_ext_plus_pages(PAGE_SIZE, M_WAITOK);
4910 		*bextpg = 0;
4911 		m->m_next = mp;
4912 	} else {
4913 		do {
4914 			pg = vm_page_alloc(NULL, 0, VM_ALLOC_NORMAL |
4915 			    VM_ALLOC_NOOBJ | VM_ALLOC_NODUMP |
4916 			    VM_ALLOC_WIRED);
4917 			if (pg == NULL)
4918 				vm_wait(NULL);
4919 		} while (pg == NULL);
4920 		m->m_epg_pa[m->m_epg_npgs] = VM_PAGE_TO_PHYS(pg);
4921 		*bextpg = m->m_epg_npgs;
4922 		m->m_epg_npgs++;
4923 		m->m_epg_last_len = 0;
4924 		mp = m;
4925 	}
4926 	return (mp);
4927 }
4928