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