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