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