2 * SPDX-License-Identifier: BSD-3-Clause
4 * Copyright (c) 1989, 1993
5 * The Regents of the University of California. All rights reserved.
7 * This code is derived from software contributed to Berkeley by
8 * Rick Macklem at The University of Guelph.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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.
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
36 #include <sys/cdefs.h>
37 __FBSDID("$FreeBSD$");
40 * These functions support the macros and help fiddle mbuf chains for
41 * the nfs op functions. They do things like create the rpc header and
42 * copy data between mbuf chains and uio lists.
45 #include "opt_inet6.h"
47 #include <fs/nfs/nfsport.h>
49 #include <sys/extattr.h>
51 #include <security/mac/mac_framework.h>
53 #include <vm/vm_param.h>
56 * Data items converted to xdr at startup, since they are constant
57 * This is kinda hokey, but may save a little time doing byte swaps
59 u_int32_t newnfs_true, newnfs_false, newnfs_xdrneg1;
61 /* And other global data */
62 nfstype nfsv34_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK,
64 enum vtype newnv2tov_type[8] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON };
65 enum vtype nv34tov_type[8]={ VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO };
66 struct timeval nfsboottime; /* Copy boottime once, so it never changes */
69 struct nfssockreq nfsrv_nfsuserdsock;
70 nfsuserd_state nfsrv_nfsuserd = NOTRUNNING;
71 static int nfsrv_userdupcalls = 0;
72 struct nfsreqhead nfsd_reqq;
73 uid_t nfsrv_defaultuid = UID_NOBODY;
74 gid_t nfsrv_defaultgid = GID_NOGROUP;
75 int nfsrv_lease = NFSRV_LEASE;
76 int ncl_mbuf_mlen = MLEN;
77 int nfsd_enable_stringtouid = 0;
78 int nfsrv_doflexfile = 0;
79 static int nfs_enable_uidtostring = 0;
82 extern int nfsrv_lughashsize;
83 extern struct mtx nfsrv_dslock_mtx;
84 extern volatile int nfsrv_devidcnt;
85 extern int nfscl_debuglevel;
86 extern struct nfsdevicehead nfsrv_devidhead;
87 extern struct nfsstatsv1 nfsstatsv1;
89 SYSCTL_DECL(_vfs_nfs);
90 SYSCTL_INT(_vfs_nfs, OID_AUTO, enable_uidtostring, CTLFLAG_RW,
91 &nfs_enable_uidtostring, 0, "Make nfs always send numeric owner_names");
93 int nfsrv_maxpnfsmirror = 1;
94 SYSCTL_INT(_vfs_nfs, OID_AUTO, pnfsmirror, CTLFLAG_RD,
95 &nfsrv_maxpnfsmirror, 0, "Mirror level for pNFS service");
97 int nfs_maxcopyrange = 10 * 1024 * 1024;
98 SYSCTL_INT(_vfs_nfs, OID_AUTO, maxcopyrange, CTLFLAG_RW,
99 &nfs_maxcopyrange, 0, "Max size of a Copy so RPC times reasonable");
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
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.
118 struct nfsv4_opflag nfsv4_opflag[NFSV42_NOPS] = {
119 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* undef */
120 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* undef */
121 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* undef */
122 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Access */
123 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Close */
124 { 0, 2, 0, 1, LK_EXCLUSIVE, 1, 1 }, /* Commit */
125 { 1, 2, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Create */
126 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Delegpurge */
127 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Delegreturn */
128 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Getattr */
129 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* GetFH */
130 { 2, 1, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Link */
131 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Lock */
132 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* LockT */
133 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* LockU */
134 { 1, 2, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Lookup */
135 { 1, 2, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Lookupp */
136 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* NVerify */
137 { 1, 1, 0, 1, LK_EXCLUSIVE, 1, 0 }, /* Open */
138 { 1, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* OpenAttr */
139 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* OpenConfirm */
140 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* OpenDowngrade */
141 { 1, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* PutFH */
142 { 1, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* PutPubFH */
143 { 1, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* PutRootFH */
144 { 0, 1, 0, 0, LK_SHARED, 1, 0 }, /* Read */
145 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Readdir */
146 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* ReadLink */
147 { 0, 2, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Remove */
148 { 2, 1, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Rename */
149 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Renew */
150 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* RestoreFH */
151 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SaveFH */
152 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SecInfo */
153 { 0, 2, 1, 1, LK_EXCLUSIVE, 1, 0 }, /* Setattr */
154 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SetClientID */
155 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SetClientIDConfirm */
156 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Verify */
157 { 0, 2, 1, 1, LK_EXCLUSIVE, 1, 0 }, /* Write */
158 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* ReleaseLockOwner */
159 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Backchannel Ctrl */
160 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Bind Conn to Sess */
161 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Exchange ID */
162 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Create Session */
163 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Destroy Session */
164 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Free StateID */
165 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Get Dir Deleg */
166 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Get Device Info */
167 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Get Device List */
168 { 0, 1, 0, 1, LK_EXCLUSIVE, 1, 1 }, /* Layout Commit */
169 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Layout Get */
170 { 0, 1, 0, 1, LK_EXCLUSIVE, 1, 0 }, /* Layout Return */
171 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Secinfo No name */
172 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Sequence */
173 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Set SSV */
174 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Test StateID */
175 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Want Delegation */
176 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Destroy ClientID */
177 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Reclaim Complete */
178 { 0, 1, 1, 1, LK_EXCLUSIVE, 1, 0 }, /* Allocate */
179 { 2, 1, 1, 0, LK_SHARED, 1, 0 }, /* Copy */
180 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Copy Notify */
181 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Deallocate */
182 { 0, 1, 0, 0, LK_SHARED, 1, 0 }, /* IO Advise */
183 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Layout Error */
184 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Layout Stats */
185 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Offload Cancel */
186 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Offload Status */
187 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Read Plus */
188 { 0, 1, 0, 0, LK_SHARED, 1, 0 }, /* Seek */
189 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Write Same */
190 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Clone */
191 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Getxattr */
192 { 0, 1, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Setxattr */
193 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Listxattrs */
194 { 0, 1, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Removexattr */
197 static int ncl_mbuf_mhlen = MHLEN;
198 static int nfsrv_usercnt = 0;
199 static int nfsrv_dnsnamelen;
200 static u_char *nfsrv_dnsname = NULL;
201 static int nfsrv_usermax = 999999999;
202 struct nfsrv_lughash {
204 struct nfsuserhashhead lughead;
206 static struct nfsrv_lughash *nfsuserhash;
207 static struct nfsrv_lughash *nfsusernamehash;
208 static struct nfsrv_lughash *nfsgrouphash;
209 static struct nfsrv_lughash *nfsgroupnamehash;
212 * This static array indicates whether or not the RPC generates a large
213 * reply. This is used by nfs_reply() to decide whether or not an mbuf
214 * cluster should be allocated. (If a cluster is required by an RPC
215 * marked 0 in this array, the code will still work, just not quite as
218 static int nfs_bigreply[NFSV42_NPROCS] = { 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0,
219 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
220 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
223 /* local functions */
224 static int nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep);
225 static void nfsv4_wanted(struct nfsv4lock *lp);
226 static int nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len);
227 static int nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name);
228 static void nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser);
229 static int nfsrv_getrefstr(struct nfsrv_descript *, u_char **, u_char **,
231 static void nfsrv_refstrbigenough(int, u_char **, u_char **, int *);
238 } nfsv4_opmap[NFSV42_NPROCS] = {
240 { NFSV4OP_GETATTR, 1, "Getattr", 7, },
241 { NFSV4OP_SETATTR, 2, "Setattr", 7, },
242 { NFSV4OP_LOOKUP, 3, "Lookup", 6, },
243 { NFSV4OP_ACCESS, 2, "Access", 6, },
244 { NFSV4OP_READLINK, 2, "Readlink", 8, },
245 { NFSV4OP_READ, 1, "Read", 4, },
246 { NFSV4OP_WRITE, 2, "Write", 5, },
247 { NFSV4OP_OPEN, 5, "Open", 4, },
248 { NFSV4OP_CREATE, 5, "Create", 6, },
249 { NFSV4OP_CREATE, 1, "Create", 6, },
250 { NFSV4OP_CREATE, 3, "Create", 6, },
251 { NFSV4OP_REMOVE, 1, "Remove", 6, },
252 { NFSV4OP_REMOVE, 1, "Remove", 6, },
253 { NFSV4OP_SAVEFH, 5, "Rename", 6, },
254 { NFSV4OP_SAVEFH, 4, "Link", 4, },
255 { NFSV4OP_READDIR, 2, "Readdir", 7, },
256 { NFSV4OP_READDIR, 2, "Readdir", 7, },
257 { NFSV4OP_GETATTR, 1, "Getattr", 7, },
258 { NFSV4OP_GETATTR, 1, "Getattr", 7, },
259 { NFSV4OP_GETATTR, 1, "Getattr", 7, },
260 { NFSV4OP_COMMIT, 2, "Commit", 6, },
261 { NFSV4OP_LOOKUPP, 3, "Lookupp", 7, },
262 { NFSV4OP_SETCLIENTID, 1, "SetClientID", 11, },
263 { NFSV4OP_SETCLIENTIDCFRM, 1, "SetClientIDConfirm", 18, },
264 { NFSV4OP_LOCK, 1, "Lock", 4, },
265 { NFSV4OP_LOCKU, 1, "LockU", 5, },
266 { NFSV4OP_OPEN, 2, "Open", 4, },
267 { NFSV4OP_CLOSE, 1, "Close", 5, },
268 { NFSV4OP_OPENCONFIRM, 1, "Openconfirm", 11, },
269 { NFSV4OP_LOCKT, 1, "LockT", 5, },
270 { NFSV4OP_OPENDOWNGRADE, 1, "Opendowngrade", 13, },
271 { NFSV4OP_RENEW, 1, "Renew", 5, },
272 { NFSV4OP_PUTROOTFH, 1, "Dirpath", 7, },
273 { NFSV4OP_RELEASELCKOWN, 1, "Rellckown", 9, },
274 { NFSV4OP_DELEGRETURN, 1, "Delegret", 8, },
275 { NFSV4OP_DELEGRETURN, 3, "DelegRemove", 11, },
276 { NFSV4OP_DELEGRETURN, 7, "DelegRename1", 12, },
277 { NFSV4OP_DELEGRETURN, 9, "DelegRename2", 12, },
278 { NFSV4OP_GETATTR, 1, "Getacl", 6, },
279 { NFSV4OP_SETATTR, 1, "Setacl", 6, },
280 { NFSV4OP_EXCHANGEID, 1, "ExchangeID", 10, },
281 { NFSV4OP_CREATESESSION, 1, "CreateSession", 13, },
282 { NFSV4OP_DESTROYSESSION, 1, "DestroySession", 14, },
283 { NFSV4OP_DESTROYCLIENTID, 1, "DestroyClient", 13, },
284 { NFSV4OP_FREESTATEID, 1, "FreeStateID", 11, },
285 { NFSV4OP_LAYOUTGET, 1, "LayoutGet", 9, },
286 { NFSV4OP_GETDEVINFO, 1, "GetDeviceInfo", 13, },
287 { NFSV4OP_LAYOUTCOMMIT, 1, "LayoutCommit", 12, },
288 { NFSV4OP_LAYOUTRETURN, 1, "LayoutReturn", 12, },
289 { NFSV4OP_RECLAIMCOMPL, 1, "ReclaimComplete", 15, },
290 { NFSV4OP_WRITE, 1, "WriteDS", 7, },
291 { NFSV4OP_READ, 1, "ReadDS", 6, },
292 { NFSV4OP_COMMIT, 1, "CommitDS", 8, },
293 { NFSV4OP_OPEN, 3, "OpenLayoutGet", 13, },
294 { NFSV4OP_OPEN, 8, "CreateLayGet", 12, },
295 { NFSV4OP_IOADVISE, 1, "Advise", 6, },
296 { NFSV4OP_ALLOCATE, 2, "Allocate", 8, },
297 { NFSV4OP_SAVEFH, 5, "Copy", 4, },
298 { NFSV4OP_SEEK, 2, "Seek", 4, },
299 { NFSV4OP_SEEK, 1, "SeekDS", 6, },
300 { NFSV4OP_GETXATTR, 2, "Getxattr", 8, },
301 { NFSV4OP_SETXATTR, 2, "Setxattr", 8, },
302 { NFSV4OP_REMOVEXATTR, 2, "Rmxattr", 7, },
303 { NFSV4OP_LISTXATTRS, 2, "Listxattr", 9, },
307 * NFS RPCS that have large request message size.
309 static int nfs_bigrequest[NFSV42_NPROCS] = {
310 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
311 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
312 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0
316 * Start building a request. Mostly just put the first file handle in
320 nfscl_reqstart(struct nfsrv_descript *nd, int procnum, struct nfsmount *nmp,
321 u_int8_t *nfhp, int fhlen, u_int32_t **opcntpp, struct nfsclsession *sep,
322 int vers, int minorvers, bool use_ext)
327 nfsattrbit_t attrbits;
330 * First, fill in some of the fields of nd.
332 nd->nd_slotseq = NULL;
333 if (vers == NFS_VER4) {
334 nd->nd_flag = ND_NFSV4 | ND_NFSCL;
335 if (minorvers == NFSV41_MINORVERSION)
336 nd->nd_flag |= ND_NFSV41;
337 else if (minorvers == NFSV42_MINORVERSION)
338 nd->nd_flag |= (ND_NFSV41 | ND_NFSV42);
339 } else if (vers == NFS_VER3)
340 nd->nd_flag = ND_NFSV3 | ND_NFSCL;
342 if (NFSHASNFSV4(nmp)) {
343 nd->nd_flag = ND_NFSV4 | ND_NFSCL;
344 if (nmp->nm_minorvers == 1)
345 nd->nd_flag |= ND_NFSV41;
346 else if (nmp->nm_minorvers == 2)
347 nd->nd_flag |= (ND_NFSV41 | ND_NFSV42);
348 } else if (NFSHASNFSV3(nmp))
349 nd->nd_flag = ND_NFSV3 | ND_NFSCL;
351 nd->nd_flag = ND_NFSV2 | ND_NFSCL;
353 nd->nd_procnum = procnum;
355 nd->nd_maxextsiz = 16384;
356 if (use_ext && mb_use_ext_pgs && PMAP_HAS_DMAP != 0)
357 nd->nd_flag |= ND_EXTPG;
360 * Get the first mbuf for the request.
362 if ((nd->nd_flag & ND_EXTPG) != 0) {
363 mb = mb_alloc_ext_plus_pages(PAGE_SIZE, M_WAITOK);
364 nd->nd_mreq = nd->nd_mb = mb;
367 if (nfs_bigrequest[procnum])
368 NFSMCLGET(mb, M_WAITOK);
372 nd->nd_mreq = nd->nd_mb = mb;
373 nd->nd_bpos = mtod(mb, char *);
377 * And fill the first file handle into the request.
379 if (nd->nd_flag & ND_NFSV4) {
380 opcnt = nfsv4_opmap[procnum].opcnt +
381 nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh;
382 if ((nd->nd_flag & ND_NFSV41) != 0) {
383 opcnt += nfsv4_opflag[nfsv4_opmap[procnum].op].needsseq;
384 if (procnum == NFSPROC_RENEW)
386 * For the special case of Renew, just do a
390 else if (procnum == NFSPROC_WRITEDS ||
391 procnum == NFSPROC_COMMITDS)
393 * For the special case of a Writeor Commit to
394 * a DS, the opcnt == 3, for Sequence, PutFH,
400 * What should the tag really be?
402 (void) nfsm_strtom(nd, nfsv4_opmap[procnum].tag,
403 nfsv4_opmap[procnum].taglen);
404 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
405 if ((nd->nd_flag & ND_NFSV42) != 0)
406 *tl++ = txdr_unsigned(NFSV42_MINORVERSION);
407 else if ((nd->nd_flag & ND_NFSV41) != 0)
408 *tl++ = txdr_unsigned(NFSV41_MINORVERSION);
410 *tl++ = txdr_unsigned(NFSV4_MINORVERSION);
413 *tl = txdr_unsigned(opcnt);
414 if ((nd->nd_flag & ND_NFSV41) != 0 &&
415 nfsv4_opflag[nfsv4_opmap[procnum].op].needsseq > 0) {
416 if (nfsv4_opflag[nfsv4_opmap[procnum].op].loopbadsess >
418 nd->nd_flag |= ND_LOOPBADSESS;
419 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
420 *tl = txdr_unsigned(NFSV4OP_SEQUENCE);
422 sep = nfsmnt_mdssession(nmp);
423 nfsv4_setsequence(nmp, nd, sep,
424 nfs_bigreply[procnum]);
426 nfsv4_setsequence(nmp, nd, sep,
427 nfs_bigreply[procnum]);
429 if (nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh > 0) {
430 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
431 *tl = txdr_unsigned(NFSV4OP_PUTFH);
432 (void) nfsm_fhtom(nd, nfhp, fhlen, 0);
433 if (nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh
434 == 2 && procnum != NFSPROC_WRITEDS &&
435 procnum != NFSPROC_COMMITDS) {
436 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
437 *tl = txdr_unsigned(NFSV4OP_GETATTR);
439 * For Lookup Ops, we want all the directory
440 * attributes, so we can load the name cache.
442 if (procnum == NFSPROC_LOOKUP ||
443 procnum == NFSPROC_LOOKUPP)
444 NFSGETATTR_ATTRBIT(&attrbits);
446 NFSWCCATTR_ATTRBIT(&attrbits);
447 nd->nd_flag |= ND_V4WCCATTR;
449 (void) nfsrv_putattrbit(nd, &attrbits);
452 if (procnum != NFSPROC_RENEW ||
453 (nd->nd_flag & ND_NFSV41) == 0) {
454 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
455 *tl = txdr_unsigned(nfsv4_opmap[procnum].op);
458 (void) nfsm_fhtom(nd, nfhp, fhlen, 0);
460 if (procnum < NFSV42_NPROCS)
461 NFSINCRGLOBAL(nfsstatsv1.rpccnt[procnum]);
465 * Put a state Id in the mbuf list.
468 nfsm_stateidtom(struct nfsrv_descript *nd, nfsv4stateid_t *stateidp, int flag)
472 NFSM_BUILD(st, nfsv4stateid_t *, NFSX_STATEID);
473 if (flag == NFSSTATEID_PUTALLZERO) {
478 } else if (flag == NFSSTATEID_PUTALLONE) {
479 st->seqid = 0xffffffff;
480 st->other[0] = 0xffffffff;
481 st->other[1] = 0xffffffff;
482 st->other[2] = 0xffffffff;
483 } else if (flag == NFSSTATEID_PUTSEQIDZERO) {
485 st->other[0] = stateidp->other[0];
486 st->other[1] = stateidp->other[1];
487 st->other[2] = stateidp->other[2];
489 st->seqid = stateidp->seqid;
490 st->other[0] = stateidp->other[0];
491 st->other[1] = stateidp->other[1];
492 st->other[2] = stateidp->other[2];
497 * Fill in the setable attributes. The full argument indicates whether
498 * to fill in them all or just mode and time.
501 nfscl_fillsattr(struct nfsrv_descript *nd, struct vattr *vap,
502 struct vnode *vp, int flags, u_int32_t rdev)
505 struct nfsv2_sattr *sp;
506 nfsattrbit_t attrbits;
508 switch (nd->nd_flag & (ND_NFSV2 | ND_NFSV3 | ND_NFSV4)) {
510 NFSM_BUILD(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
511 if (vap->va_mode == (mode_t)VNOVAL)
512 sp->sa_mode = newnfs_xdrneg1;
514 sp->sa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
515 if (vap->va_uid == (uid_t)VNOVAL)
516 sp->sa_uid = newnfs_xdrneg1;
518 sp->sa_uid = txdr_unsigned(vap->va_uid);
519 if (vap->va_gid == (gid_t)VNOVAL)
520 sp->sa_gid = newnfs_xdrneg1;
522 sp->sa_gid = txdr_unsigned(vap->va_gid);
523 if (flags & NFSSATTR_SIZE0)
525 else if (flags & NFSSATTR_SIZENEG1)
526 sp->sa_size = newnfs_xdrneg1;
527 else if (flags & NFSSATTR_SIZERDEV)
528 sp->sa_size = txdr_unsigned(rdev);
530 sp->sa_size = txdr_unsigned(vap->va_size);
531 txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
532 txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
535 if (vap->va_mode != (mode_t)VNOVAL) {
536 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
538 *tl = txdr_unsigned(vap->va_mode);
540 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
543 if ((flags & NFSSATTR_FULL) && vap->va_uid != (uid_t)VNOVAL) {
544 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
546 *tl = txdr_unsigned(vap->va_uid);
548 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
551 if ((flags & NFSSATTR_FULL) && vap->va_gid != (gid_t)VNOVAL) {
552 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
554 *tl = txdr_unsigned(vap->va_gid);
556 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
559 if ((flags & NFSSATTR_FULL) && vap->va_size != VNOVAL) {
560 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
562 txdr_hyper(vap->va_size, tl);
564 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
567 if (vap->va_atime.tv_sec != VNOVAL) {
568 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
569 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
570 *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
571 txdr_nfsv3time(&vap->va_atime, tl);
573 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
574 *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
577 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
578 *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
580 if (vap->va_mtime.tv_sec != VNOVAL) {
581 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
582 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
583 *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
584 txdr_nfsv3time(&vap->va_mtime, tl);
586 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
587 *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
590 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
591 *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
595 NFSZERO_ATTRBIT(&attrbits);
596 if (vap->va_mode != (mode_t)VNOVAL)
597 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_MODE);
598 if ((flags & NFSSATTR_FULL) && vap->va_uid != (uid_t)VNOVAL)
599 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
600 if ((flags & NFSSATTR_FULL) && vap->va_gid != (gid_t)VNOVAL)
601 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP);
602 if ((flags & NFSSATTR_FULL) && vap->va_size != VNOVAL)
603 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_SIZE);
604 if (vap->va_atime.tv_sec != VNOVAL)
605 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET);
606 if (vap->va_mtime.tv_sec != VNOVAL)
607 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET);
608 if (vap->va_birthtime.tv_sec != VNOVAL)
609 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMECREATE);
610 (void) nfsv4_fillattr(nd, vp->v_mount, vp, NULL, vap, NULL, 0,
611 &attrbits, NULL, NULL, 0, 0, 0, 0, (uint64_t)0, NULL);
618 * copies mbuf chain to the uio scatter/gather list
621 nfsm_mbufuio(struct nfsrv_descript *nd, struct uio *uiop, int siz)
623 char *mbufcp, *uiocp;
630 mbufcp = nd->nd_dpos;
631 len = mtod(mp, caddr_t) + mp->m_len - mbufcp;
632 rem = NFSM_RNDUP(siz) - siz;
634 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) {
638 left = uiop->uio_iov->iov_len;
639 uiocp = uiop->uio_iov->iov_base;
650 mbufcp = mtod(mp, caddr_t);
653 ("len %d, corrupted mbuf?", len));
655 xfer = (left > len) ? len : left;
658 if (uiop->uio_iov->iov_op != NULL)
659 (*(uiop->uio_iov->iov_op))
660 (mbufcp, uiocp, xfer);
663 if (uiop->uio_segflg == UIO_SYSSPACE)
664 NFSBCOPY(mbufcp, uiocp, xfer);
666 copyout(mbufcp, uiocp, xfer);
671 uiop->uio_offset += xfer;
672 uiop->uio_resid -= xfer;
674 if (uiop->uio_iov->iov_len <= siz) {
678 uiop->uio_iov->iov_base = (void *)
679 ((char *)uiop->uio_iov->iov_base + uiosiz);
680 uiop->uio_iov->iov_len -= uiosiz;
684 nd->nd_dpos = mbufcp;
688 error = nfsm_advance(nd, rem, len);
694 NFSEXITCODE2(error, nd);
700 * Help break down an mbuf chain by setting the first siz bytes contiguous
701 * pointed to by returned val.
702 * This is used by the macro NFSM_DISSECT for tough
706 nfsm_dissct(struct nfsrv_descript *nd, int siz, int how)
715 left = mtod(nd->nd_md, caddr_t) + nd->nd_md->m_len - nd->nd_dpos;
717 nd->nd_md = nd->nd_md->m_next;
718 if (nd->nd_md == NULL)
720 left = nd->nd_md->m_len;
721 nd->nd_dpos = mtod(nd->nd_md, caddr_t);
726 } else if (nd->nd_md->m_next == NULL) {
728 } else if (siz > ncl_mbuf_mhlen) {
729 panic("nfs S too big");
731 MGET(mp2, MT_DATA, how);
734 mp2->m_next = nd->nd_md->m_next;
735 nd->nd_md->m_next = mp2;
736 nd->nd_md->m_len -= left;
738 retp = p = mtod(mp2, caddr_t);
739 NFSBCOPY(nd->nd_dpos, p, left); /* Copy what was left */
743 /* Loop around copying up the siz2 bytes */
747 xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2;
749 NFSBCOPY(mtod(mp2, caddr_t), p, xfer);
758 nd->nd_md->m_len = siz;
760 nd->nd_dpos = mtod(mp2, caddr_t);
766 * Advance the position in the mbuf chain.
767 * If offs == 0, this is a no-op, but it is simpler to just return from
768 * here than check for offs > 0 for all calls to nfsm_advance.
769 * If left == -1, it should be calculated here.
772 nfsm_advance(struct nfsrv_descript *nd, int offs, int left)
779 * A negative offs might indicate a corrupted mbuf chain and,
780 * as such, a printf is logged.
783 printf("nfsrv_advance: negative offs\n");
789 * If left == -1, calculate it here.
792 left = mtod(nd->nd_md, caddr_t) + nd->nd_md->m_len -
796 * Loop around, advancing over the mbuf data.
798 while (offs > left) {
800 nd->nd_md = nd->nd_md->m_next;
801 if (nd->nd_md == NULL) {
805 left = nd->nd_md->m_len;
806 nd->nd_dpos = mtod(nd->nd_md, caddr_t);
816 * Copy a string into mbuf(s).
817 * Return the number of bytes output, including XDR overheads.
820 nfsm_strtom(struct nfsrv_descript *nd, const char *cp, int siz)
829 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
830 *tl = txdr_unsigned(siz);
831 rem = NFSM_RNDUP(siz) - siz;
832 bytesize = NFSX_UNSIGNED + siz + rem;
835 if ((nd->nd_flag & ND_EXTPG) != 0)
836 left = nd->nd_bextpgsiz;
838 left = M_TRAILINGSPACE(m2);
840 KASSERT(((m2->m_flags & (M_EXT | M_EXTPG)) ==
841 (M_EXT | M_EXTPG) && (nd->nd_flag & ND_EXTPG) != 0) ||
842 ((m2->m_flags & (M_EXT | M_EXTPG)) !=
843 (M_EXT | M_EXTPG) && (nd->nd_flag & ND_EXTPG) == 0),
844 ("nfsm_strtom: ext_pgs and non-ext_pgs mbufs mixed"));
846 * Loop around copying the string to mbuf(s).
850 if ((nd->nd_flag & ND_EXTPG) != 0) {
851 m2 = nfsm_add_ext_pgs(m2,
852 nd->nd_maxextsiz, &nd->nd_bextpg);
853 cp2 = (char *)(void *)PHYS_TO_DMAP(
854 m2->m_epg_pa[nd->nd_bextpg]);
855 nd->nd_bextpgsiz = left = PAGE_SIZE;
857 if (siz > ncl_mbuf_mlen)
858 NFSMCLGET(m1, M_WAITOK);
862 cp2 = mtod(m1, char *);
863 left = M_TRAILINGSPACE(m1);
872 NFSBCOPY(cp, cp2, xfer);
878 if ((nd->nd_flag & ND_EXTPG) != 0) {
879 nd->nd_bextpgsiz -= xfer;
880 m2->m_epg_last_len += xfer;
882 if (siz == 0 && rem) {
884 panic("nfsm_strtom");
888 if ((nd->nd_flag & ND_EXTPG) != 0) {
889 nd->nd_bextpgsiz -= rem;
890 m2->m_epg_last_len += rem;
895 if ((nd->nd_flag & ND_EXTPG) != 0)
898 nd->nd_bpos = mtod(m2, char *) + m2->m_len;
903 * Called once to initialize data structures...
908 static int nfs_inited = 0;
914 newnfs_true = txdr_unsigned(TRUE);
915 newnfs_false = txdr_unsigned(FALSE);
916 newnfs_xdrneg1 = txdr_unsigned(-1);
917 nfscl_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
920 NFSSETBOOTTIME(nfsboottime);
923 * Initialize reply list and start timer
925 TAILQ_INIT(&nfsd_reqq);
930 * Put a file handle in an mbuf list.
931 * If the size argument == 0, just use the default size.
932 * set_true == 1 if there should be an newnfs_true prepended on the file handle.
933 * Return the number of bytes output, including XDR overhead.
936 nfsm_fhtom(struct nfsrv_descript *nd, u_int8_t *fhp, int size, int set_true)
940 int fullsiz, rem, bytesize = 0;
944 switch (nd->nd_flag & (ND_NFSV2 | ND_NFSV3 | ND_NFSV4)) {
946 if (size > NFSX_V2FH)
947 panic("fh size > NFSX_V2FH for NFSv2");
948 NFSM_BUILD(cp, u_int8_t *, NFSX_V2FH);
949 NFSBCOPY(fhp, cp, size);
950 if (size < NFSX_V2FH)
951 NFSBZERO(cp + size, NFSX_V2FH - size);
952 bytesize = NFSX_V2FH;
956 fullsiz = NFSM_RNDUP(size);
957 rem = fullsiz - size;
959 bytesize = 2 * NFSX_UNSIGNED + fullsiz;
960 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
963 bytesize = NFSX_UNSIGNED + fullsiz;
965 (void) nfsm_strtom(nd, fhp, size);
972 * This function compares two net addresses by family and returns TRUE
973 * if they are the same host.
974 * If there is any doubt, return FALSE.
975 * The AF_INET family is handled as a special case so that address mbufs
976 * don't need to be saved to store "struct in_addr", which is only 4 bytes.
979 nfsaddr_match(int family, union nethostaddr *haddr, NFSSOCKADDR_T nam)
982 struct sockaddr_in *inetaddr;
988 inetaddr = NFSSOCKADDR(nam, struct sockaddr_in *);
989 if (inetaddr->sin_family == AF_INET &&
990 inetaddr->sin_addr.s_addr == haddr->had_inet.s_addr)
997 struct sockaddr_in6 *inetaddr6;
999 inetaddr6 = NFSSOCKADDR(nam, struct sockaddr_in6 *);
1000 /* XXX - should test sin6_scope_id ? */
1001 if (inetaddr6->sin6_family == AF_INET6 &&
1002 IN6_ARE_ADDR_EQUAL(&inetaddr6->sin6_addr,
1013 * Similar to the above, but takes to NFSSOCKADDR_T args.
1016 nfsaddr2_match(NFSSOCKADDR_T nam1, NFSSOCKADDR_T nam2)
1018 struct sockaddr_in *addr1, *addr2;
1019 struct sockaddr *inaddr;
1021 inaddr = NFSSOCKADDR(nam1, struct sockaddr *);
1022 switch (inaddr->sa_family) {
1024 addr1 = NFSSOCKADDR(nam1, struct sockaddr_in *);
1025 addr2 = NFSSOCKADDR(nam2, struct sockaddr_in *);
1026 if (addr2->sin_family == AF_INET &&
1027 addr1->sin_addr.s_addr == addr2->sin_addr.s_addr)
1033 struct sockaddr_in6 *inet6addr1, *inet6addr2;
1035 inet6addr1 = NFSSOCKADDR(nam1, struct sockaddr_in6 *);
1036 inet6addr2 = NFSSOCKADDR(nam2, struct sockaddr_in6 *);
1037 /* XXX - should test sin6_scope_id ? */
1038 if (inet6addr2->sin6_family == AF_INET6 &&
1039 IN6_ARE_ADDR_EQUAL(&inet6addr1->sin6_addr,
1040 &inet6addr2->sin6_addr))
1050 * Trim trailing data off the mbuf list being built.
1053 newnfs_trimtrailing(nd, mb, bpos)
1054 struct nfsrv_descript *nd;
1060 m_freem(mb->m_next);
1063 mb->m_len = bpos - mtod(mb, caddr_t);
1069 * Dissect a file handle on the client.
1072 nfsm_getfh(struct nfsrv_descript *nd, struct nfsfh **nfhpp)
1079 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
1080 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1081 if ((len = fxdr_unsigned(int, *tl)) <= 0 ||
1088 nfhp = malloc(sizeof (struct nfsfh) + len,
1090 error = nfsrv_mtostr(nd, nfhp->nfh_fh, len);
1092 free(nfhp, M_NFSFH);
1095 nfhp->nfh_len = len;
1098 NFSEXITCODE2(error, nd);
1103 * Break down the nfsv4 acl.
1104 * If the aclp == NULL or won't fit in an acl, just discard the acl info.
1107 nfsrv_dissectacl(struct nfsrv_descript *nd, NFSACL_T *aclp, int *aclerrp,
1108 int *aclsizep, __unused NFSPROC_T *p)
1112 int acecnt, error = 0, aceerr = 0, acesize;
1118 * Parse out the ace entries and expect them to conform to
1119 * what can be supported by R/W/X bits.
1121 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1122 aclsize = NFSX_UNSIGNED;
1123 acecnt = fxdr_unsigned(int, *tl);
1124 if (acecnt > ACL_MAX_ENTRIES)
1125 aceerr = NFSERR_ATTRNOTSUPP;
1126 if (nfsrv_useacl == 0)
1127 aceerr = NFSERR_ATTRNOTSUPP;
1128 for (i = 0; i < acecnt; i++) {
1129 if (aclp && !aceerr)
1130 error = nfsrv_dissectace(nd, &aclp->acl_entry[i],
1131 &aceerr, &acesize, p);
1133 error = nfsrv_skipace(nd, &acesize);
1138 if (aclp && !aceerr)
1139 aclp->acl_cnt = acecnt;
1143 *aclsizep = aclsize;
1145 NFSEXITCODE2(error, nd);
1150 * Skip over an NFSv4 ace entry. Just dissect the xdr and discard it.
1153 nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep)
1158 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1159 len = fxdr_unsigned(int, *(tl + 3));
1160 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
1162 *acesizep = NFSM_RNDUP(len) + (4 * NFSX_UNSIGNED);
1163 NFSEXITCODE2(error, nd);
1168 * Get attribute bits from an mbuf list.
1169 * Returns EBADRPC for a parsing error, 0 otherwise.
1170 * If the clearinvalid flag is set, clear the bits not supported.
1173 nfsrv_getattrbits(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp, int *cntp,
1180 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1181 cnt = fxdr_unsigned(int, *tl);
1183 error = NFSERR_BADXDR;
1186 if (cnt > NFSATTRBIT_MAXWORDS)
1187 outcnt = NFSATTRBIT_MAXWORDS;
1190 NFSZERO_ATTRBIT(attrbitp);
1192 NFSM_DISSECT(tl, u_int32_t *, outcnt * NFSX_UNSIGNED);
1193 for (i = 0; i < outcnt; i++)
1194 attrbitp->bits[i] = fxdr_unsigned(u_int32_t, *tl++);
1196 for (i = 0; i < (cnt - outcnt); i++) {
1197 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1198 if (retnotsupp != NULL && *tl != 0)
1199 *retnotsupp = NFSERR_ATTRNOTSUPP;
1202 *cntp = NFSX_UNSIGNED + (cnt * NFSX_UNSIGNED);
1204 NFSEXITCODE2(error, nd);
1209 * Get the attributes for V4.
1210 * If the compare flag is true, test for any attribute changes,
1211 * otherwise return the attribute values.
1212 * These attributes cover fields in "struct vattr", "struct statfs",
1213 * "struct nfsfsinfo", the file handle and the lease duration.
1214 * The value of retcmpp is set to 1 if all attributes are the same,
1216 * Returns EBADRPC if it can't be parsed, 0 otherwise.
1219 nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp,
1220 struct nfsvattr *nap, struct nfsfh **nfhpp, fhandle_t *fhp, int fhsize,
1221 struct nfsv3_pathconf *pc, struct statfs *sbp, struct nfsstatfs *sfp,
1222 struct nfsfsinfo *fsp, NFSACL_T *aclp, int compare, int *retcmpp,
1223 u_int32_t *leasep, u_int32_t *rderrp, NFSPROC_T *p, struct ucred *cred)
1226 int i = 0, j, k, l = 0, m, bitpos, attrsum = 0;
1227 int error, tfhsize, aceerr, attrsize, cnt, retnotsup;
1228 u_char *cp, *cp2, namestr[NFSV4_SMALLSTR + 1];
1229 nfsattrbit_t attrbits, retattrbits, checkattrbits;
1230 struct nfsfh *tnfhp;
1231 struct nfsreferral *refp;
1234 struct timespec temptime;
1237 u_int32_t freenum = 0, tuint;
1238 u_int64_t uquad = 0, thyp, thyp2;
1244 CTASSERT(sizeof(ino_t) == sizeof(uint64_t));
1247 error = nfsrv_getattrbits(nd, &attrbits, NULL, &retnotsup);
1249 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
1255 *retcmpp = retnotsup;
1258 * Just set default values to some of the important ones.
1261 nap->na_type = VREG;
1263 nap->na_rdev = (NFSDEV_T)0;
1264 nap->na_mtime.tv_sec = 0;
1265 nap->na_mtime.tv_nsec = 0;
1268 nap->na_blocksize = NFS_FABLKSIZE;
1271 sbp->f_bsize = NFS_FABLKSIZE;
1279 fsp->fs_rtmax = 8192;
1280 fsp->fs_rtpref = 8192;
1281 fsp->fs_maxname = NFS_MAXNAMLEN;
1282 fsp->fs_wtmax = 8192;
1283 fsp->fs_wtpref = 8192;
1284 fsp->fs_wtmult = NFS_FABLKSIZE;
1285 fsp->fs_dtpref = 8192;
1286 fsp->fs_maxfilesize = 0xffffffffffffffffull;
1287 fsp->fs_timedelta.tv_sec = 0;
1288 fsp->fs_timedelta.tv_nsec = 1;
1289 fsp->fs_properties = (NFSV3_FSFLINK | NFSV3_FSFSYMLINK |
1290 NFSV3_FSFHOMOGENEOUS | NFSV3_FSFCANSETTIME);
1293 pc->pc_linkmax = NFS_LINK_MAX;
1294 pc->pc_namemax = NAME_MAX;
1296 pc->pc_chownrestricted = 0;
1297 pc->pc_caseinsensitive = 0;
1298 pc->pc_casepreserving = 1;
1301 sfp->sf_ffiles = UINT64_MAX;
1302 sfp->sf_tfiles = UINT64_MAX;
1303 sfp->sf_afiles = UINT64_MAX;
1304 sfp->sf_fbytes = UINT64_MAX;
1305 sfp->sf_tbytes = UINT64_MAX;
1306 sfp->sf_abytes = UINT64_MAX;
1311 * Loop around getting the attributes.
1313 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1314 attrsize = fxdr_unsigned(int, *tl);
1315 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
1316 if (attrsum > attrsize) {
1317 error = NFSERR_BADXDR;
1320 if (NFSISSET_ATTRBIT(&attrbits, bitpos))
1322 case NFSATTRBIT_SUPPORTEDATTRS:
1324 if (compare || nap == NULL)
1325 error = nfsrv_getattrbits(nd, &retattrbits,
1328 error = nfsrv_getattrbits(nd, &nap->na_suppattr,
1332 if (compare && !(*retcmpp)) {
1333 NFSSETSUPP_ATTRBIT(&checkattrbits, nd);
1335 /* Some filesystem do not support NFSv4ACL */
1336 if (nfsrv_useacl == 0 || nfs_supportsnfsv4acls(vp) == 0) {
1337 NFSCLRBIT_ATTRBIT(&checkattrbits, NFSATTRBIT_ACL);
1338 NFSCLRBIT_ATTRBIT(&checkattrbits, NFSATTRBIT_ACLSUPPORT);
1340 if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
1342 *retcmpp = NFSERR_NOTSAME;
1346 case NFSATTRBIT_TYPE:
1347 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1350 if (nap->na_type != nfsv34tov_type(*tl))
1351 *retcmpp = NFSERR_NOTSAME;
1353 } else if (nap != NULL) {
1354 nap->na_type = nfsv34tov_type(*tl);
1356 attrsum += NFSX_UNSIGNED;
1358 case NFSATTRBIT_FHEXPIRETYPE:
1359 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1360 if (compare && !(*retcmpp)) {
1361 if (fxdr_unsigned(int, *tl) !=
1362 NFSV4FHTYPE_PERSISTENT)
1363 *retcmpp = NFSERR_NOTSAME;
1365 attrsum += NFSX_UNSIGNED;
1367 case NFSATTRBIT_CHANGE:
1368 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1371 if (nap->na_filerev != fxdr_hyper(tl))
1372 *retcmpp = NFSERR_NOTSAME;
1374 } else if (nap != NULL) {
1375 nap->na_filerev = fxdr_hyper(tl);
1377 attrsum += NFSX_HYPER;
1379 case NFSATTRBIT_SIZE:
1380 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1383 if (nap->na_size != fxdr_hyper(tl))
1384 *retcmpp = NFSERR_NOTSAME;
1386 } else if (nap != NULL) {
1387 nap->na_size = fxdr_hyper(tl);
1389 attrsum += NFSX_HYPER;
1391 case NFSATTRBIT_LINKSUPPORT:
1392 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1395 if (fsp->fs_properties & NFSV3_FSFLINK) {
1396 if (*tl == newnfs_false)
1397 *retcmpp = NFSERR_NOTSAME;
1399 if (*tl == newnfs_true)
1400 *retcmpp = NFSERR_NOTSAME;
1403 } else if (fsp != NULL) {
1404 if (*tl == newnfs_true)
1405 fsp->fs_properties |= NFSV3_FSFLINK;
1407 fsp->fs_properties &= ~NFSV3_FSFLINK;
1409 attrsum += NFSX_UNSIGNED;
1411 case NFSATTRBIT_SYMLINKSUPPORT:
1412 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1415 if (fsp->fs_properties & NFSV3_FSFSYMLINK) {
1416 if (*tl == newnfs_false)
1417 *retcmpp = NFSERR_NOTSAME;
1419 if (*tl == newnfs_true)
1420 *retcmpp = NFSERR_NOTSAME;
1423 } else if (fsp != NULL) {
1424 if (*tl == newnfs_true)
1425 fsp->fs_properties |= NFSV3_FSFSYMLINK;
1427 fsp->fs_properties &= ~NFSV3_FSFSYMLINK;
1429 attrsum += NFSX_UNSIGNED;
1431 case NFSATTRBIT_NAMEDATTR:
1432 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1433 if (compare && !(*retcmpp)) {
1434 if (*tl != newnfs_false)
1435 *retcmpp = NFSERR_NOTSAME;
1437 attrsum += NFSX_UNSIGNED;
1439 case NFSATTRBIT_FSID:
1440 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1441 thyp = fxdr_hyper(tl);
1443 thyp2 = fxdr_hyper(tl);
1445 if (*retcmpp == 0) {
1446 if (thyp != (u_int64_t)
1447 vp->v_mount->mnt_stat.f_fsid.val[0] ||
1448 thyp2 != (u_int64_t)
1449 vp->v_mount->mnt_stat.f_fsid.val[1])
1450 *retcmpp = NFSERR_NOTSAME;
1452 } else if (nap != NULL) {
1453 nap->na_filesid[0] = thyp;
1454 nap->na_filesid[1] = thyp2;
1456 attrsum += (4 * NFSX_UNSIGNED);
1458 case NFSATTRBIT_UNIQUEHANDLES:
1459 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1460 if (compare && !(*retcmpp)) {
1461 if (*tl != newnfs_true)
1462 *retcmpp = NFSERR_NOTSAME;
1464 attrsum += NFSX_UNSIGNED;
1466 case NFSATTRBIT_LEASETIME:
1467 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1469 if (fxdr_unsigned(int, *tl) != nfsrv_lease &&
1471 *retcmpp = NFSERR_NOTSAME;
1472 } else if (leasep != NULL) {
1473 *leasep = fxdr_unsigned(u_int32_t, *tl);
1475 attrsum += NFSX_UNSIGNED;
1477 case NFSATTRBIT_RDATTRERROR:
1478 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1481 *retcmpp = NFSERR_INVAL;
1482 } else if (rderrp != NULL) {
1483 *rderrp = fxdr_unsigned(u_int32_t, *tl);
1485 attrsum += NFSX_UNSIGNED;
1487 case NFSATTRBIT_ACL:
1490 if (nfsrv_useacl && nfs_supportsnfsv4acls(vp)) {
1493 naclp = acl_alloc(M_WAITOK);
1494 error = nfsrv_dissectacl(nd, naclp, &aceerr,
1500 if (aceerr || aclp == NULL ||
1501 nfsrv_compareacl(aclp, naclp))
1502 *retcmpp = NFSERR_NOTSAME;
1505 error = nfsrv_dissectacl(nd, NULL, &aceerr,
1507 *retcmpp = NFSERR_ATTRNOTSUPP;
1511 if (vp != NULL && aclp != NULL)
1512 error = nfsrv_dissectacl(nd, aclp, &aceerr,
1515 error = nfsrv_dissectacl(nd, NULL, &aceerr,
1523 case NFSATTRBIT_ACLSUPPORT:
1524 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1525 if (compare && !(*retcmpp)) {
1526 if (nfsrv_useacl && nfs_supportsnfsv4acls(vp)) {
1527 if (fxdr_unsigned(u_int32_t, *tl) !=
1529 *retcmpp = NFSERR_NOTSAME;
1531 *retcmpp = NFSERR_ATTRNOTSUPP;
1534 attrsum += NFSX_UNSIGNED;
1536 case NFSATTRBIT_ARCHIVE:
1537 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1538 if (compare && !(*retcmpp))
1539 *retcmpp = NFSERR_ATTRNOTSUPP;
1540 attrsum += NFSX_UNSIGNED;
1542 case NFSATTRBIT_CANSETTIME:
1543 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1546 if (fsp->fs_properties & NFSV3_FSFCANSETTIME) {
1547 if (*tl == newnfs_false)
1548 *retcmpp = NFSERR_NOTSAME;
1550 if (*tl == newnfs_true)
1551 *retcmpp = NFSERR_NOTSAME;
1554 } else if (fsp != NULL) {
1555 if (*tl == newnfs_true)
1556 fsp->fs_properties |= NFSV3_FSFCANSETTIME;
1558 fsp->fs_properties &= ~NFSV3_FSFCANSETTIME;
1560 attrsum += NFSX_UNSIGNED;
1562 case NFSATTRBIT_CASEINSENSITIVE:
1563 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1566 if (*tl != newnfs_false)
1567 *retcmpp = NFSERR_NOTSAME;
1569 } else if (pc != NULL) {
1570 pc->pc_caseinsensitive =
1571 fxdr_unsigned(u_int32_t, *tl);
1573 attrsum += NFSX_UNSIGNED;
1575 case NFSATTRBIT_CASEPRESERVING:
1576 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1579 if (*tl != newnfs_true)
1580 *retcmpp = NFSERR_NOTSAME;
1582 } else if (pc != NULL) {
1583 pc->pc_casepreserving =
1584 fxdr_unsigned(u_int32_t, *tl);
1586 attrsum += NFSX_UNSIGNED;
1588 case NFSATTRBIT_CHOWNRESTRICTED:
1589 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1592 if (*tl != newnfs_true)
1593 *retcmpp = NFSERR_NOTSAME;
1595 } else if (pc != NULL) {
1596 pc->pc_chownrestricted =
1597 fxdr_unsigned(u_int32_t, *tl);
1599 attrsum += NFSX_UNSIGNED;
1601 case NFSATTRBIT_FILEHANDLE:
1602 error = nfsm_getfh(nd, &tnfhp);
1605 tfhsize = tnfhp->nfh_len;
1608 !NFSRV_CMPFH(tnfhp->nfh_fh, tfhsize,
1610 *retcmpp = NFSERR_NOTSAME;
1611 free(tnfhp, M_NFSFH);
1612 } else if (nfhpp != NULL) {
1615 free(tnfhp, M_NFSFH);
1617 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(tfhsize));
1619 case NFSATTRBIT_FILEID:
1620 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1621 thyp = fxdr_hyper(tl);
1624 if (nap->na_fileid != thyp)
1625 *retcmpp = NFSERR_NOTSAME;
1627 } else if (nap != NULL)
1628 nap->na_fileid = thyp;
1629 attrsum += NFSX_HYPER;
1631 case NFSATTRBIT_FILESAVAIL:
1632 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1635 sfp->sf_afiles != fxdr_hyper(tl))
1636 *retcmpp = NFSERR_NOTSAME;
1637 } else if (sfp != NULL) {
1638 sfp->sf_afiles = fxdr_hyper(tl);
1640 attrsum += NFSX_HYPER;
1642 case NFSATTRBIT_FILESFREE:
1643 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1646 sfp->sf_ffiles != fxdr_hyper(tl))
1647 *retcmpp = NFSERR_NOTSAME;
1648 } else if (sfp != NULL) {
1649 sfp->sf_ffiles = fxdr_hyper(tl);
1651 attrsum += NFSX_HYPER;
1653 case NFSATTRBIT_FILESTOTAL:
1654 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1657 sfp->sf_tfiles != fxdr_hyper(tl))
1658 *retcmpp = NFSERR_NOTSAME;
1659 } else if (sfp != NULL) {
1660 sfp->sf_tfiles = fxdr_hyper(tl);
1662 attrsum += NFSX_HYPER;
1664 case NFSATTRBIT_FSLOCATIONS:
1665 error = nfsrv_getrefstr(nd, &cp, &cp2, &l, &m);
1669 if (compare && !(*retcmpp)) {
1670 refp = nfsv4root_getreferral(vp, NULL, 0);
1672 if (cp == NULL || cp2 == NULL ||
1674 strcmp(cp2, refp->nfr_srvlist))
1675 *retcmpp = NFSERR_NOTSAME;
1676 } else if (m == 0) {
1677 *retcmpp = NFSERR_NOTSAME;
1681 free(cp, M_NFSSTRING);
1683 free(cp2, M_NFSSTRING);
1685 case NFSATTRBIT_HIDDEN:
1686 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1687 if (compare && !(*retcmpp))
1688 *retcmpp = NFSERR_ATTRNOTSUPP;
1689 attrsum += NFSX_UNSIGNED;
1691 case NFSATTRBIT_HOMOGENEOUS:
1692 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1695 if (fsp->fs_properties &
1696 NFSV3_FSFHOMOGENEOUS) {
1697 if (*tl == newnfs_false)
1698 *retcmpp = NFSERR_NOTSAME;
1700 if (*tl == newnfs_true)
1701 *retcmpp = NFSERR_NOTSAME;
1704 } else if (fsp != NULL) {
1705 if (*tl == newnfs_true)
1706 fsp->fs_properties |= NFSV3_FSFHOMOGENEOUS;
1708 fsp->fs_properties &= ~NFSV3_FSFHOMOGENEOUS;
1710 attrsum += NFSX_UNSIGNED;
1712 case NFSATTRBIT_MAXFILESIZE:
1713 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1714 tnfsquad.qval = fxdr_hyper(tl);
1717 tquad = NFSRV_MAXFILESIZE;
1718 if (tquad != tnfsquad.qval)
1719 *retcmpp = NFSERR_NOTSAME;
1721 } else if (fsp != NULL) {
1722 fsp->fs_maxfilesize = tnfsquad.qval;
1724 attrsum += NFSX_HYPER;
1726 case NFSATTRBIT_MAXLINK:
1727 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1730 if (fxdr_unsigned(int, *tl) != NFS_LINK_MAX)
1731 *retcmpp = NFSERR_NOTSAME;
1733 } else if (pc != NULL) {
1734 pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl);
1736 attrsum += NFSX_UNSIGNED;
1738 case NFSATTRBIT_MAXNAME:
1739 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1742 if (fsp->fs_maxname !=
1743 fxdr_unsigned(u_int32_t, *tl))
1744 *retcmpp = NFSERR_NOTSAME;
1747 tuint = fxdr_unsigned(u_int32_t, *tl);
1749 * Some Linux NFSv4 servers report this
1750 * as 0 or 4billion, so I'll set it to
1751 * NFS_MAXNAMLEN. If a server actually creates
1752 * a name longer than NFS_MAXNAMLEN, it will
1753 * get an error back.
1755 if (tuint == 0 || tuint > NFS_MAXNAMLEN)
1756 tuint = NFS_MAXNAMLEN;
1758 fsp->fs_maxname = tuint;
1760 pc->pc_namemax = tuint;
1762 attrsum += NFSX_UNSIGNED;
1764 case NFSATTRBIT_MAXREAD:
1765 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1768 if (fsp->fs_rtmax != fxdr_unsigned(u_int32_t,
1769 *(tl + 1)) || *tl != 0)
1770 *retcmpp = NFSERR_NOTSAME;
1772 } else if (fsp != NULL) {
1773 fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *++tl);
1774 fsp->fs_rtpref = fsp->fs_rtmax;
1775 fsp->fs_dtpref = fsp->fs_rtpref;
1777 attrsum += NFSX_HYPER;
1779 case NFSATTRBIT_MAXWRITE:
1780 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1783 if (fsp->fs_wtmax != fxdr_unsigned(u_int32_t,
1784 *(tl + 1)) || *tl != 0)
1785 *retcmpp = NFSERR_NOTSAME;
1787 } else if (fsp != NULL) {
1788 fsp->fs_wtmax = fxdr_unsigned(int, *++tl);
1789 fsp->fs_wtpref = fsp->fs_wtmax;
1791 attrsum += NFSX_HYPER;
1793 case NFSATTRBIT_MIMETYPE:
1794 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1795 i = fxdr_unsigned(int, *tl);
1796 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(i));
1797 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
1800 if (compare && !(*retcmpp))
1801 *retcmpp = NFSERR_ATTRNOTSUPP;
1803 case NFSATTRBIT_MODE:
1804 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1807 if (nap->na_mode != nfstov_mode(*tl))
1808 *retcmpp = NFSERR_NOTSAME;
1810 } else if (nap != NULL) {
1811 nap->na_mode = nfstov_mode(*tl);
1813 attrsum += NFSX_UNSIGNED;
1815 case NFSATTRBIT_NOTRUNC:
1816 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1819 if (*tl != newnfs_true)
1820 *retcmpp = NFSERR_NOTSAME;
1822 } else if (pc != NULL) {
1823 pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl);
1825 attrsum += NFSX_UNSIGNED;
1827 case NFSATTRBIT_NUMLINKS:
1828 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1829 tuint = fxdr_unsigned(u_int32_t, *tl);
1832 if ((u_int32_t)nap->na_nlink != tuint)
1833 *retcmpp = NFSERR_NOTSAME;
1835 } else if (nap != NULL) {
1836 nap->na_nlink = tuint;
1838 attrsum += NFSX_UNSIGNED;
1840 case NFSATTRBIT_OWNER:
1841 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1842 j = fxdr_unsigned(int, *tl);
1844 error = NFSERR_BADXDR;
1847 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1848 if (j > NFSV4_SMALLSTR)
1849 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1852 error = nfsrv_mtostr(nd, cp, j);
1854 if (j > NFSV4_SMALLSTR)
1855 free(cp, M_NFSSTRING);
1860 if (nfsv4_strtouid(nd, cp, j, &uid) ||
1862 *retcmpp = NFSERR_NOTSAME;
1864 } else if (nap != NULL) {
1865 if (nfsv4_strtouid(nd, cp, j, &uid))
1866 nap->na_uid = nfsrv_defaultuid;
1870 if (j > NFSV4_SMALLSTR)
1871 free(cp, M_NFSSTRING);
1873 case NFSATTRBIT_OWNERGROUP:
1874 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1875 j = fxdr_unsigned(int, *tl);
1877 error = NFSERR_BADXDR;
1880 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1881 if (j > NFSV4_SMALLSTR)
1882 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1885 error = nfsrv_mtostr(nd, cp, j);
1887 if (j > NFSV4_SMALLSTR)
1888 free(cp, M_NFSSTRING);
1893 if (nfsv4_strtogid(nd, cp, j, &gid) ||
1895 *retcmpp = NFSERR_NOTSAME;
1897 } else if (nap != NULL) {
1898 if (nfsv4_strtogid(nd, cp, j, &gid))
1899 nap->na_gid = nfsrv_defaultgid;
1903 if (j > NFSV4_SMALLSTR)
1904 free(cp, M_NFSSTRING);
1906 case NFSATTRBIT_QUOTAHARD:
1907 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1909 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA))
1910 freenum = sbp->f_bfree;
1912 freenum = sbp->f_bavail;
1915 * ufs_quotactl() insists that the uid argument
1916 * equal p_ruid for non-root quota access, so
1917 * we'll just make sure that's the case.
1919 savuid = p->p_cred->p_ruid;
1920 p->p_cred->p_ruid = cred->cr_uid;
1921 if (!VFS_QUOTACTL(vp->v_mount,QCMD(Q_GETQUOTA,
1922 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1923 freenum = min(dqb.dqb_bhardlimit, freenum);
1924 p->p_cred->p_ruid = savuid;
1926 uquad = (u_int64_t)freenum;
1927 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1929 if (compare && !(*retcmpp)) {
1930 if (uquad != fxdr_hyper(tl))
1931 *retcmpp = NFSERR_NOTSAME;
1933 attrsum += NFSX_HYPER;
1935 case NFSATTRBIT_QUOTASOFT:
1936 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1938 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA))
1939 freenum = sbp->f_bfree;
1941 freenum = sbp->f_bavail;
1944 * ufs_quotactl() insists that the uid argument
1945 * equal p_ruid for non-root quota access, so
1946 * we'll just make sure that's the case.
1948 savuid = p->p_cred->p_ruid;
1949 p->p_cred->p_ruid = cred->cr_uid;
1950 if (!VFS_QUOTACTL(vp->v_mount,QCMD(Q_GETQUOTA,
1951 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1952 freenum = min(dqb.dqb_bsoftlimit, freenum);
1953 p->p_cred->p_ruid = savuid;
1955 uquad = (u_int64_t)freenum;
1956 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1958 if (compare && !(*retcmpp)) {
1959 if (uquad != fxdr_hyper(tl))
1960 *retcmpp = NFSERR_NOTSAME;
1962 attrsum += NFSX_HYPER;
1964 case NFSATTRBIT_QUOTAUSED:
1965 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1970 * ufs_quotactl() insists that the uid argument
1971 * equal p_ruid for non-root quota access, so
1972 * we'll just make sure that's the case.
1974 savuid = p->p_cred->p_ruid;
1975 p->p_cred->p_ruid = cred->cr_uid;
1976 if (!VFS_QUOTACTL(vp->v_mount,QCMD(Q_GETQUOTA,
1977 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1978 freenum = dqb.dqb_curblocks;
1979 p->p_cred->p_ruid = savuid;
1981 uquad = (u_int64_t)freenum;
1982 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1984 if (compare && !(*retcmpp)) {
1985 if (uquad != fxdr_hyper(tl))
1986 *retcmpp = NFSERR_NOTSAME;
1988 attrsum += NFSX_HYPER;
1990 case NFSATTRBIT_RAWDEV:
1991 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4SPECDATA);
1992 j = fxdr_unsigned(int, *tl++);
1993 k = fxdr_unsigned(int, *tl);
1996 if (nap->na_rdev != NFSMAKEDEV(j, k))
1997 *retcmpp = NFSERR_NOTSAME;
1999 } else if (nap != NULL) {
2000 nap->na_rdev = NFSMAKEDEV(j, k);
2002 attrsum += NFSX_V4SPECDATA;
2004 case NFSATTRBIT_SPACEAVAIL:
2005 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2008 sfp->sf_abytes != fxdr_hyper(tl))
2009 *retcmpp = NFSERR_NOTSAME;
2010 } else if (sfp != NULL) {
2011 sfp->sf_abytes = fxdr_hyper(tl);
2013 attrsum += NFSX_HYPER;
2015 case NFSATTRBIT_SPACEFREE:
2016 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2019 sfp->sf_fbytes != fxdr_hyper(tl))
2020 *retcmpp = NFSERR_NOTSAME;
2021 } else if (sfp != NULL) {
2022 sfp->sf_fbytes = fxdr_hyper(tl);
2024 attrsum += NFSX_HYPER;
2026 case NFSATTRBIT_SPACETOTAL:
2027 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2030 sfp->sf_tbytes != fxdr_hyper(tl))
2031 *retcmpp = NFSERR_NOTSAME;
2032 } else if (sfp != NULL) {
2033 sfp->sf_tbytes = fxdr_hyper(tl);
2035 attrsum += NFSX_HYPER;
2037 case NFSATTRBIT_SPACEUSED:
2038 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2039 thyp = fxdr_hyper(tl);
2042 if ((u_int64_t)nap->na_bytes != thyp)
2043 *retcmpp = NFSERR_NOTSAME;
2045 } else if (nap != NULL) {
2046 nap->na_bytes = thyp;
2048 attrsum += NFSX_HYPER;
2050 case NFSATTRBIT_SYSTEM:
2051 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2052 if (compare && !(*retcmpp))
2053 *retcmpp = NFSERR_ATTRNOTSUPP;
2054 attrsum += NFSX_UNSIGNED;
2056 case NFSATTRBIT_TIMEACCESS:
2057 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2058 fxdr_nfsv4time(tl, &temptime);
2061 if (!NFS_CMPTIME(temptime, nap->na_atime))
2062 *retcmpp = NFSERR_NOTSAME;
2064 } else if (nap != NULL) {
2065 nap->na_atime = temptime;
2067 attrsum += NFSX_V4TIME;
2069 case NFSATTRBIT_TIMEACCESSSET:
2070 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2071 attrsum += NFSX_UNSIGNED;
2072 i = fxdr_unsigned(int, *tl);
2073 if (i == NFSV4SATTRTIME_TOCLIENT) {
2074 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2075 attrsum += NFSX_V4TIME;
2077 if (compare && !(*retcmpp))
2078 *retcmpp = NFSERR_INVAL;
2080 case NFSATTRBIT_TIMEBACKUP:
2081 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2082 if (compare && !(*retcmpp))
2083 *retcmpp = NFSERR_ATTRNOTSUPP;
2084 attrsum += NFSX_V4TIME;
2086 case NFSATTRBIT_TIMECREATE:
2087 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2088 fxdr_nfsv4time(tl, &temptime);
2091 if (!NFS_CMPTIME(temptime, nap->na_btime))
2092 *retcmpp = NFSERR_NOTSAME;
2094 } else if (nap != NULL) {
2095 nap->na_btime = temptime;
2097 attrsum += NFSX_V4TIME;
2099 case NFSATTRBIT_TIMEDELTA:
2100 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2104 if ((u_int32_t)fsp->fs_timedelta.tv_sec !=
2105 fxdr_unsigned(u_int32_t, *(tl + 1)) ||
2106 (u_int32_t)fsp->fs_timedelta.tv_nsec !=
2107 (fxdr_unsigned(u_int32_t, *(tl + 2)) %
2110 *retcmpp = NFSERR_NOTSAME;
2113 fxdr_nfsv4time(tl, &fsp->fs_timedelta);
2116 attrsum += NFSX_V4TIME;
2118 case NFSATTRBIT_TIMEMETADATA:
2119 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2120 fxdr_nfsv4time(tl, &temptime);
2123 if (!NFS_CMPTIME(temptime, nap->na_ctime))
2124 *retcmpp = NFSERR_NOTSAME;
2126 } else if (nap != NULL) {
2127 nap->na_ctime = temptime;
2129 attrsum += NFSX_V4TIME;
2131 case NFSATTRBIT_TIMEMODIFY:
2132 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2133 fxdr_nfsv4time(tl, &temptime);
2136 if (!NFS_CMPTIME(temptime, nap->na_mtime))
2137 *retcmpp = NFSERR_NOTSAME;
2139 } else if (nap != NULL) {
2140 nap->na_mtime = temptime;
2142 attrsum += NFSX_V4TIME;
2144 case NFSATTRBIT_TIMEMODIFYSET:
2145 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2146 attrsum += NFSX_UNSIGNED;
2147 i = fxdr_unsigned(int, *tl);
2148 if (i == NFSV4SATTRTIME_TOCLIENT) {
2149 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2150 attrsum += NFSX_V4TIME;
2152 if (compare && !(*retcmpp))
2153 *retcmpp = NFSERR_INVAL;
2155 case NFSATTRBIT_MOUNTEDONFILEID:
2156 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2157 thyp = fxdr_hyper(tl);
2160 if (!vp || !nfsrv_atroot(vp, &thyp2))
2161 thyp2 = nap->na_fileid;
2163 *retcmpp = NFSERR_NOTSAME;
2165 } else if (nap != NULL)
2166 nap->na_mntonfileno = thyp;
2167 attrsum += NFSX_HYPER;
2169 case NFSATTRBIT_SUPPATTREXCLCREAT:
2171 error = nfsrv_getattrbits(nd, &retattrbits,
2175 if (compare && !(*retcmpp)) {
2176 NFSSETSUPP_ATTRBIT(&checkattrbits, nd);
2177 NFSCLRNOTSETABLE_ATTRBIT(&checkattrbits, nd);
2178 NFSCLRBIT_ATTRBIT(&checkattrbits,
2179 NFSATTRBIT_TIMEACCESSSET);
2180 if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
2182 *retcmpp = NFSERR_NOTSAME;
2186 case NFSATTRBIT_FSLAYOUTTYPE:
2187 case NFSATTRBIT_LAYOUTTYPE:
2188 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2189 attrsum += NFSX_UNSIGNED;
2190 i = fxdr_unsigned(int, *tl);
2192 NFSM_DISSECT(tl, u_int32_t *, i *
2194 attrsum += i * NFSX_UNSIGNED;
2195 j = fxdr_unsigned(int, *tl);
2196 if (i == 1 && compare && !(*retcmpp) &&
2197 (((nfsrv_doflexfile != 0 ||
2198 nfsrv_maxpnfsmirror > 1) &&
2199 j != NFSLAYOUT_FLEXFILE) ||
2200 (nfsrv_doflexfile == 0 &&
2201 j != NFSLAYOUT_NFSV4_1_FILES)))
2202 *retcmpp = NFSERR_NOTSAME;
2204 if (nfsrv_devidcnt == 0) {
2205 if (compare && !(*retcmpp) && i > 0)
2206 *retcmpp = NFSERR_NOTSAME;
2208 if (compare && !(*retcmpp) && i != 1)
2209 *retcmpp = NFSERR_NOTSAME;
2212 case NFSATTRBIT_LAYOUTALIGNMENT:
2213 case NFSATTRBIT_LAYOUTBLKSIZE:
2214 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2215 attrsum += NFSX_UNSIGNED;
2216 i = fxdr_unsigned(int, *tl);
2217 if (compare && !(*retcmpp) && i != NFS_SRVMAXIO)
2218 *retcmpp = NFSERR_NOTSAME;
2221 printf("EEK! nfsv4_loadattr unknown attr=%d\n",
2223 if (compare && !(*retcmpp))
2224 *retcmpp = NFSERR_ATTRNOTSUPP;
2226 * and get out of the loop, since we can't parse
2227 * the unknown attrbute data.
2229 bitpos = NFSATTRBIT_MAX;
2235 * some clients pad the attrlist, so we need to skip over the
2238 if (attrsum > attrsize) {
2239 error = NFSERR_BADXDR;
2241 attrsize = NFSM_RNDUP(attrsize);
2242 if (attrsum < attrsize)
2243 error = nfsm_advance(nd, attrsize - attrsum, -1);
2246 NFSEXITCODE2(error, nd);
2251 * Implement sleep locks for newnfs. The nfslock_usecnt allows for a
2252 * shared lock and the NFSXXX_LOCK flag permits an exclusive lock.
2253 * The first argument is a pointer to an nfsv4lock structure.
2254 * The second argument is 1 iff a blocking lock is wanted.
2255 * If this argument is 0, the call waits until no thread either wants nor
2256 * holds an exclusive lock.
2257 * It returns 1 if the lock was acquired, 0 otherwise.
2258 * If several processes call this function concurrently wanting the exclusive
2259 * lock, one will get the lock and the rest will return without getting the
2260 * lock. (If the caller must have the lock, it simply calls this function in a
2261 * loop until the function returns 1 to indicate the lock was acquired.)
2262 * Any usecnt must be decremented by calling nfsv4_relref() before
2263 * calling nfsv4_lock(). It was done this way, so nfsv4_lock() could
2264 * be called in a loop.
2265 * The isleptp argument is set to indicate if the call slept, iff not NULL
2266 * and the mp argument indicates to check for a forced dismount, iff not
2270 nfsv4_lock(struct nfsv4lock *lp, int iwantlock, int *isleptp,
2271 void *mutex, struct mount *mp)
2277 * If a lock is wanted, loop around until the lock is acquired by
2278 * someone and then released. If I want the lock, try to acquire it.
2279 * For a lock to be issued, no lock must be in force and the usecnt
2283 if (!(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
2284 lp->nfslock_usecnt == 0) {
2285 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
2286 lp->nfslock_lock |= NFSV4LOCK_LOCK;
2289 lp->nfslock_lock |= NFSV4LOCK_LOCKWANTED;
2291 while (lp->nfslock_lock & (NFSV4LOCK_LOCK | NFSV4LOCK_LOCKWANTED)) {
2292 if (mp != NULL && NFSCL_FORCEDISM(mp)) {
2293 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
2296 lp->nfslock_lock |= NFSV4LOCK_WANTED;
2299 (void) nfsmsleep(&lp->nfslock_lock, mutex,
2300 PZERO - 1, "nfsv4lck", NULL);
2301 if (iwantlock && !(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
2302 lp->nfslock_usecnt == 0) {
2303 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
2304 lp->nfslock_lock |= NFSV4LOCK_LOCK;
2312 * Release the lock acquired by nfsv4_lock().
2313 * The second argument is set to 1 to indicate the nfslock_usecnt should be
2314 * incremented, as well.
2317 nfsv4_unlock(struct nfsv4lock *lp, int incref)
2320 lp->nfslock_lock &= ~NFSV4LOCK_LOCK;
2322 lp->nfslock_usecnt++;
2327 * Release a reference cnt.
2330 nfsv4_relref(struct nfsv4lock *lp)
2333 if (lp->nfslock_usecnt <= 0)
2334 panic("nfsv4root ref cnt");
2335 lp->nfslock_usecnt--;
2336 if (lp->nfslock_usecnt == 0)
2341 * Get a reference cnt.
2342 * This function will wait for any exclusive lock to be released, but will
2343 * not wait for threads that want the exclusive lock. If priority needs
2344 * to be given to threads that need the exclusive lock, a call to nfsv4_lock()
2345 * with the 2nd argument == 0 should be done before calling nfsv4_getref().
2346 * If the mp argument is not NULL, check for NFSCL_FORCEDISM() being set and
2347 * return without getting a refcnt for that case.
2350 nfsv4_getref(struct nfsv4lock *lp, int *isleptp, void *mutex,
2358 * Wait for a lock held.
2360 while (lp->nfslock_lock & NFSV4LOCK_LOCK) {
2361 if (mp != NULL && NFSCL_FORCEDISM(mp))
2363 lp->nfslock_lock |= NFSV4LOCK_WANTED;
2366 (void) nfsmsleep(&lp->nfslock_lock, mutex,
2367 PZERO - 1, "nfsv4gr", NULL);
2369 if (mp != NULL && NFSCL_FORCEDISM(mp))
2372 lp->nfslock_usecnt++;
2376 * Get a reference as above, but return failure instead of sleeping if
2377 * an exclusive lock is held.
2380 nfsv4_getref_nonblock(struct nfsv4lock *lp)
2383 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) != 0)
2386 lp->nfslock_usecnt++;
2391 * Test for a lock. Return 1 if locked, 0 otherwise.
2394 nfsv4_testlock(struct nfsv4lock *lp)
2397 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) == 0 &&
2398 lp->nfslock_usecnt == 0)
2404 * Wake up anyone sleeping, waiting for this lock.
2407 nfsv4_wanted(struct nfsv4lock *lp)
2410 if (lp->nfslock_lock & NFSV4LOCK_WANTED) {
2411 lp->nfslock_lock &= ~NFSV4LOCK_WANTED;
2412 wakeup((caddr_t)&lp->nfslock_lock);
2417 * Copy a string from an mbuf list into a character array.
2418 * Return EBADRPC if there is an mbuf error,
2422 nfsrv_mtostr(struct nfsrv_descript *nd, char *str, int siz)
2431 len = mtod(mp, caddr_t) + mp->m_len - cp;
2432 rem = NFSM_RNDUP(siz) - siz;
2438 NFSBCOPY(cp, str, xfer);
2447 cp = mtod(mp, caddr_t);
2459 error = nfsm_advance(nd, rem, len);
2465 NFSEXITCODE2(error, nd);
2470 * Fill in the attributes as marked by the bitmap (V4).
2473 nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp,
2474 NFSACL_T *saclp, struct vattr *vap, fhandle_t *fhp, int rderror,
2475 nfsattrbit_t *attrbitp, struct ucred *cred, NFSPROC_T *p, int isdgram,
2476 int reterr, int supports_nfsv4acls, int at_root, uint64_t mounted_on_fileno,
2477 struct statfs *pnfssf)
2479 int bitpos, retnum = 0;
2481 int siz, prefixnum, error;
2482 u_char *cp, namestr[NFSV4_SMALLSTR];
2483 nfsattrbit_t attrbits, retbits;
2484 nfsattrbit_t *retbitp = &retbits;
2485 u_int32_t freenum, *retnump;
2488 struct nfsfsinfo fsinf;
2489 struct timespec temptime;
2490 NFSACL_T *aclp, *naclp = NULL;
2499 * First, set the bits that can be filled and get fsinfo.
2501 NFSSET_ATTRBIT(retbitp, attrbitp);
2503 * If both p and cred are NULL, it is a client side setattr call.
2504 * If both p and cred are not NULL, it is a server side reply call.
2505 * If p is not NULL and cred is NULL, it is a client side callback
2508 if (p == NULL && cred == NULL) {
2509 NFSCLRNOTSETABLE_ATTRBIT(retbitp, nd);
2512 NFSCLRNOTFILLABLE_ATTRBIT(retbitp, nd);
2513 naclp = acl_alloc(M_WAITOK);
2516 nfsvno_getfs(&fsinf, isdgram);
2519 * Get the VFS_STATFS(), since some attributes need them.
2521 fs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
2522 if (NFSISSETSTATFS_ATTRBIT(retbitp)) {
2523 error = VFS_STATFS(mp, fs);
2526 nd->nd_repstat = NFSERR_ACCES;
2530 NFSCLRSTATFS_ATTRBIT(retbitp);
2536 * And the NFSv4 ACL...
2538 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT) &&
2539 (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2540 supports_nfsv4acls == 0))) {
2541 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT);
2543 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACL)) {
2544 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2545 supports_nfsv4acls == 0)) {
2546 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2547 } else if (naclp != NULL) {
2548 if (NFSVOPLOCK(vp, LK_SHARED) == 0) {
2549 error = VOP_ACCESSX(vp, VREAD_ACL, cred, p);
2551 error = VOP_GETACL(vp, ACL_TYPE_NFS4,
2555 error = NFSERR_PERM;
2558 nd->nd_repstat = NFSERR_ACCES;
2562 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2567 /* Check to see if Extended Attributes are supported. */
2569 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_XATTRSUPPORT)) {
2570 if (NFSVOPLOCK(vp, LK_SHARED) == 0) {
2571 error = VOP_GETEXTATTR(vp, EXTATTR_NAMESPACE_USER,
2572 "xxx", NULL, &atsiz, cred, p);
2574 if (error != EOPNOTSUPP)
2580 * Put out the attribute bitmap for the ones being filled in
2581 * and get the field for the number of attributes returned.
2583 prefixnum = nfsrv_putattrbit(nd, retbitp);
2584 NFSM_BUILD(retnump, u_int32_t *, NFSX_UNSIGNED);
2585 prefixnum += NFSX_UNSIGNED;
2588 * Now, loop around filling in the attributes for each bit set.
2590 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
2591 if (NFSISSET_ATTRBIT(retbitp, bitpos)) {
2593 case NFSATTRBIT_SUPPORTEDATTRS:
2594 NFSSETSUPP_ATTRBIT(&attrbits, nd);
2595 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL)
2596 && supports_nfsv4acls == 0)) {
2597 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACLSUPPORT);
2598 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACL);
2600 retnum += nfsrv_putattrbit(nd, &attrbits);
2602 case NFSATTRBIT_TYPE:
2603 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2604 *tl = vtonfsv34_type(vap->va_type);
2605 retnum += NFSX_UNSIGNED;
2607 case NFSATTRBIT_FHEXPIRETYPE:
2608 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2609 *tl = txdr_unsigned(NFSV4FHTYPE_PERSISTENT);
2610 retnum += NFSX_UNSIGNED;
2612 case NFSATTRBIT_CHANGE:
2613 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2614 txdr_hyper(vap->va_filerev, tl);
2615 retnum += NFSX_HYPER;
2617 case NFSATTRBIT_SIZE:
2618 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2619 txdr_hyper(vap->va_size, tl);
2620 retnum += NFSX_HYPER;
2622 case NFSATTRBIT_LINKSUPPORT:
2623 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2624 if (fsinf.fs_properties & NFSV3FSINFO_LINK)
2628 retnum += NFSX_UNSIGNED;
2630 case NFSATTRBIT_SYMLINKSUPPORT:
2631 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2632 if (fsinf.fs_properties & NFSV3FSINFO_SYMLINK)
2636 retnum += NFSX_UNSIGNED;
2638 case NFSATTRBIT_NAMEDATTR:
2639 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2641 retnum += NFSX_UNSIGNED;
2643 case NFSATTRBIT_FSID:
2644 NFSM_BUILD(tl, u_int32_t *, NFSX_V4FSID);
2646 *tl++ = txdr_unsigned(mp->mnt_stat.f_fsid.val[0]);
2648 *tl = txdr_unsigned(mp->mnt_stat.f_fsid.val[1]);
2649 retnum += NFSX_V4FSID;
2651 case NFSATTRBIT_UNIQUEHANDLES:
2652 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2654 retnum += NFSX_UNSIGNED;
2656 case NFSATTRBIT_LEASETIME:
2657 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2658 *tl = txdr_unsigned(nfsrv_lease);
2659 retnum += NFSX_UNSIGNED;
2661 case NFSATTRBIT_RDATTRERROR:
2662 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2663 *tl = txdr_unsigned(rderror);
2664 retnum += NFSX_UNSIGNED;
2667 * Recommended Attributes. (Only the supported ones.)
2669 case NFSATTRBIT_ACL:
2670 retnum += nfsrv_buildacl(nd, aclp, vnode_vtype(vp), p);
2672 case NFSATTRBIT_ACLSUPPORT:
2673 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2674 *tl = txdr_unsigned(NFSV4ACE_SUPTYPES);
2675 retnum += NFSX_UNSIGNED;
2677 case NFSATTRBIT_CANSETTIME:
2678 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2679 if (fsinf.fs_properties & NFSV3FSINFO_CANSETTIME)
2683 retnum += NFSX_UNSIGNED;
2685 case NFSATTRBIT_CASEINSENSITIVE:
2686 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2688 retnum += NFSX_UNSIGNED;
2690 case NFSATTRBIT_CASEPRESERVING:
2691 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2693 retnum += NFSX_UNSIGNED;
2695 case NFSATTRBIT_CHOWNRESTRICTED:
2696 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2698 retnum += NFSX_UNSIGNED;
2700 case NFSATTRBIT_FILEHANDLE:
2701 retnum += nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
2703 case NFSATTRBIT_FILEID:
2704 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2705 uquad = vap->va_fileid;
2706 txdr_hyper(uquad, tl);
2707 retnum += NFSX_HYPER;
2709 case NFSATTRBIT_FILESAVAIL:
2711 * Check quota and use min(quota, f_ffree).
2713 freenum = fs->f_ffree;
2716 * ufs_quotactl() insists that the uid argument
2717 * equal p_ruid for non-root quota access, so
2718 * we'll just make sure that's the case.
2720 savuid = p->p_cred->p_ruid;
2721 p->p_cred->p_ruid = cred->cr_uid;
2722 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2723 cred->cr_uid, (caddr_t)&dqb))
2724 freenum = min(dqb.dqb_isoftlimit-dqb.dqb_curinodes,
2726 p->p_cred->p_ruid = savuid;
2728 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2730 *tl = txdr_unsigned(freenum);
2731 retnum += NFSX_HYPER;
2733 case NFSATTRBIT_FILESFREE:
2734 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2736 *tl = txdr_unsigned(fs->f_ffree);
2737 retnum += NFSX_HYPER;
2739 case NFSATTRBIT_FILESTOTAL:
2740 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2742 *tl = txdr_unsigned(fs->f_files);
2743 retnum += NFSX_HYPER;
2745 case NFSATTRBIT_FSLOCATIONS:
2746 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2749 retnum += 2 * NFSX_UNSIGNED;
2751 case NFSATTRBIT_HOMOGENEOUS:
2752 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2753 if (fsinf.fs_properties & NFSV3FSINFO_HOMOGENEOUS)
2757 retnum += NFSX_UNSIGNED;
2759 case NFSATTRBIT_MAXFILESIZE:
2760 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2761 uquad = NFSRV_MAXFILESIZE;
2762 txdr_hyper(uquad, tl);
2763 retnum += NFSX_HYPER;
2765 case NFSATTRBIT_MAXLINK:
2766 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2767 *tl = txdr_unsigned(NFS_LINK_MAX);
2768 retnum += NFSX_UNSIGNED;
2770 case NFSATTRBIT_MAXNAME:
2771 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2772 *tl = txdr_unsigned(NFS_MAXNAMLEN);
2773 retnum += NFSX_UNSIGNED;
2775 case NFSATTRBIT_MAXREAD:
2776 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2778 *tl = txdr_unsigned(fsinf.fs_rtmax);
2779 retnum += NFSX_HYPER;
2781 case NFSATTRBIT_MAXWRITE:
2782 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2784 *tl = txdr_unsigned(fsinf.fs_wtmax);
2785 retnum += NFSX_HYPER;
2787 case NFSATTRBIT_MODE:
2788 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2789 *tl = vtonfsv34_mode(vap->va_mode);
2790 retnum += NFSX_UNSIGNED;
2792 case NFSATTRBIT_NOTRUNC:
2793 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2795 retnum += NFSX_UNSIGNED;
2797 case NFSATTRBIT_NUMLINKS:
2798 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2799 *tl = txdr_unsigned(vap->va_nlink);
2800 retnum += NFSX_UNSIGNED;
2802 case NFSATTRBIT_OWNER:
2804 nfsv4_uidtostr(vap->va_uid, &cp, &siz);
2805 retnum += nfsm_strtom(nd, cp, siz);
2807 free(cp, M_NFSSTRING);
2809 case NFSATTRBIT_OWNERGROUP:
2811 nfsv4_gidtostr(vap->va_gid, &cp, &siz);
2812 retnum += nfsm_strtom(nd, cp, siz);
2814 free(cp, M_NFSSTRING);
2816 case NFSATTRBIT_QUOTAHARD:
2817 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA))
2818 freenum = fs->f_bfree;
2820 freenum = fs->f_bavail;
2823 * ufs_quotactl() insists that the uid argument
2824 * equal p_ruid for non-root quota access, so
2825 * we'll just make sure that's the case.
2827 savuid = p->p_cred->p_ruid;
2828 p->p_cred->p_ruid = cred->cr_uid;
2829 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2830 cred->cr_uid, (caddr_t)&dqb))
2831 freenum = min(dqb.dqb_bhardlimit, freenum);
2832 p->p_cred->p_ruid = savuid;
2834 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2835 uquad = (u_int64_t)freenum;
2836 NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
2837 txdr_hyper(uquad, tl);
2838 retnum += NFSX_HYPER;
2840 case NFSATTRBIT_QUOTASOFT:
2841 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA))
2842 freenum = fs->f_bfree;
2844 freenum = fs->f_bavail;
2847 * ufs_quotactl() insists that the uid argument
2848 * equal p_ruid for non-root quota access, so
2849 * we'll just make sure that's the case.
2851 savuid = p->p_cred->p_ruid;
2852 p->p_cred->p_ruid = cred->cr_uid;
2853 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2854 cred->cr_uid, (caddr_t)&dqb))
2855 freenum = min(dqb.dqb_bsoftlimit, freenum);
2856 p->p_cred->p_ruid = savuid;
2858 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2859 uquad = (u_int64_t)freenum;
2860 NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
2861 txdr_hyper(uquad, tl);
2862 retnum += NFSX_HYPER;
2864 case NFSATTRBIT_QUOTAUSED:
2868 * ufs_quotactl() insists that the uid argument
2869 * equal p_ruid for non-root quota access, so
2870 * we'll just make sure that's the case.
2872 savuid = p->p_cred->p_ruid;
2873 p->p_cred->p_ruid = cred->cr_uid;
2874 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2875 cred->cr_uid, (caddr_t)&dqb))
2876 freenum = dqb.dqb_curblocks;
2877 p->p_cred->p_ruid = savuid;
2879 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2880 uquad = (u_int64_t)freenum;
2881 NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
2882 txdr_hyper(uquad, tl);
2883 retnum += NFSX_HYPER;
2885 case NFSATTRBIT_RAWDEV:
2886 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SPECDATA);
2887 *tl++ = txdr_unsigned(NFSMAJOR(vap->va_rdev));
2888 *tl = txdr_unsigned(NFSMINOR(vap->va_rdev));
2889 retnum += NFSX_V4SPECDATA;
2891 case NFSATTRBIT_SPACEAVAIL:
2892 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2893 if (priv_check_cred(cred, PRIV_VFS_BLOCKRESERVE)) {
2895 uquad = (u_int64_t)pnfssf->f_bfree;
2897 uquad = (u_int64_t)fs->f_bfree;
2900 uquad = (u_int64_t)pnfssf->f_bavail;
2902 uquad = (u_int64_t)fs->f_bavail;
2905 uquad *= pnfssf->f_bsize;
2907 uquad *= fs->f_bsize;
2908 txdr_hyper(uquad, tl);
2909 retnum += NFSX_HYPER;
2911 case NFSATTRBIT_SPACEFREE:
2912 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2913 if (pnfssf != NULL) {
2914 uquad = (u_int64_t)pnfssf->f_bfree;
2915 uquad *= pnfssf->f_bsize;
2917 uquad = (u_int64_t)fs->f_bfree;
2918 uquad *= fs->f_bsize;
2920 txdr_hyper(uquad, tl);
2921 retnum += NFSX_HYPER;
2923 case NFSATTRBIT_SPACETOTAL:
2924 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2925 if (pnfssf != NULL) {
2926 uquad = (u_int64_t)pnfssf->f_blocks;
2927 uquad *= pnfssf->f_bsize;
2929 uquad = (u_int64_t)fs->f_blocks;
2930 uquad *= fs->f_bsize;
2932 txdr_hyper(uquad, tl);
2933 retnum += NFSX_HYPER;
2935 case NFSATTRBIT_SPACEUSED:
2936 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2937 txdr_hyper(vap->va_bytes, tl);
2938 retnum += NFSX_HYPER;
2940 case NFSATTRBIT_TIMEACCESS:
2941 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2942 txdr_nfsv4time(&vap->va_atime, tl);
2943 retnum += NFSX_V4TIME;
2945 case NFSATTRBIT_TIMEACCESSSET:
2946 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2947 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2948 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2949 txdr_nfsv4time(&vap->va_atime, tl);
2950 retnum += NFSX_V4SETTIME;
2952 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2953 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2954 retnum += NFSX_UNSIGNED;
2957 case NFSATTRBIT_TIMEDELTA:
2958 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2959 temptime.tv_sec = 0;
2960 temptime.tv_nsec = 1000000000 / hz;
2961 txdr_nfsv4time(&temptime, tl);
2962 retnum += NFSX_V4TIME;
2964 case NFSATTRBIT_TIMEMETADATA:
2965 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2966 txdr_nfsv4time(&vap->va_ctime, tl);
2967 retnum += NFSX_V4TIME;
2969 case NFSATTRBIT_TIMEMODIFY:
2970 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2971 txdr_nfsv4time(&vap->va_mtime, tl);
2972 retnum += NFSX_V4TIME;
2974 case NFSATTRBIT_TIMECREATE:
2975 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2976 txdr_nfsv4time(&vap->va_birthtime, tl);
2977 retnum += NFSX_V4TIME;
2979 case NFSATTRBIT_TIMEMODIFYSET:
2980 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2981 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2982 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2983 txdr_nfsv4time(&vap->va_mtime, tl);
2984 retnum += NFSX_V4SETTIME;
2986 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2987 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2988 retnum += NFSX_UNSIGNED;
2991 case NFSATTRBIT_MOUNTEDONFILEID:
2992 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2994 uquad = mounted_on_fileno;
2996 uquad = vap->va_fileid;
2997 txdr_hyper(uquad, tl);
2998 retnum += NFSX_HYPER;
3000 case NFSATTRBIT_SUPPATTREXCLCREAT:
3001 NFSSETSUPP_ATTRBIT(&attrbits, nd);
3002 NFSCLRNOTSETABLE_ATTRBIT(&attrbits, nd);
3003 NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET);
3004 retnum += nfsrv_putattrbit(nd, &attrbits);
3006 case NFSATTRBIT_FSLAYOUTTYPE:
3007 case NFSATTRBIT_LAYOUTTYPE:
3008 if (nfsrv_devidcnt == 0)
3013 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3014 *tl++ = txdr_unsigned(1); /* One entry. */
3015 if (nfsrv_doflexfile != 0 ||
3016 nfsrv_maxpnfsmirror > 1)
3017 *tl = txdr_unsigned(NFSLAYOUT_FLEXFILE);
3019 *tl = txdr_unsigned(
3020 NFSLAYOUT_NFSV4_1_FILES);
3022 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3025 retnum += siz * NFSX_UNSIGNED;
3027 case NFSATTRBIT_LAYOUTALIGNMENT:
3028 case NFSATTRBIT_LAYOUTBLKSIZE:
3029 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3030 *tl = txdr_unsigned(NFS_SRVMAXIO);
3031 retnum += NFSX_UNSIGNED;
3033 case NFSATTRBIT_XATTRSUPPORT:
3034 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3039 retnum += NFSX_UNSIGNED;
3042 printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos);
3049 *retnump = txdr_unsigned(retnum);
3050 return (retnum + prefixnum);
3054 * Put the attribute bits onto an mbuf list.
3055 * Return the number of bytes of output generated.
3058 nfsrv_putattrbit(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp)
3061 int cnt, i, bytesize;
3063 for (cnt = NFSATTRBIT_MAXWORDS; cnt > 0; cnt--)
3064 if (attrbitp->bits[cnt - 1])
3066 bytesize = (cnt + 1) * NFSX_UNSIGNED;
3067 NFSM_BUILD(tl, u_int32_t *, bytesize);
3068 *tl++ = txdr_unsigned(cnt);
3069 for (i = 0; i < cnt; i++)
3070 *tl++ = txdr_unsigned(attrbitp->bits[i]);
3075 * Convert a uid to a string.
3076 * If the lookup fails, just output the digits.
3078 * cpp - points to a buffer of size NFSV4_SMALLSTR
3079 * (malloc a larger one, as required)
3080 * retlenp - pointer to length to be returned
3083 nfsv4_uidtostr(uid_t uid, u_char **cpp, int *retlenp)
3086 struct nfsusrgrp *usrp;
3089 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
3090 struct nfsrv_lughash *hp;
3094 if (nfsrv_dnsnamelen > 0 && !nfs_enable_uidtostring) {
3096 * Always map nfsrv_defaultuid to "nobody".
3098 if (uid == nfsrv_defaultuid) {
3099 i = nfsrv_dnsnamelen + 7;
3101 if (len > NFSV4_SMALLSTR)
3102 free(cp, M_NFSSTRING);
3103 cp = malloc(i, M_NFSSTRING, M_WAITOK);
3109 NFSBCOPY("nobody@", cp, 7);
3111 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
3115 hp = NFSUSERHASH(uid);
3117 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
3118 if (usrp->lug_uid == uid) {
3119 if (usrp->lug_expiry < NFSD_MONOSEC)
3122 * If the name doesn't already have an '@'
3123 * in it, append @domainname to it.
3125 for (i = 0; i < usrp->lug_namelen; i++) {
3126 if (usrp->lug_name[i] == '@') {
3132 i = usrp->lug_namelen;
3134 i = usrp->lug_namelen +
3135 nfsrv_dnsnamelen + 1;
3137 mtx_unlock(&hp->mtx);
3138 if (len > NFSV4_SMALLSTR)
3139 free(cp, M_NFSSTRING);
3140 cp = malloc(i, M_NFSSTRING, M_WAITOK);
3146 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
3147 if (!hasampersand) {
3148 cp += usrp->lug_namelen;
3150 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
3152 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3153 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
3155 mtx_unlock(&hp->mtx);
3159 mtx_unlock(&hp->mtx);
3161 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0, NULL);
3162 if (ret == 0 && cnt < 2)
3167 * No match, just return a string of digits.
3171 while (tmp || i == 0) {
3175 len = (i > len) ? len : i;
3179 for (i = 0; i < len; i++) {
3180 *cp-- = '0' + (tmp % 10);
3187 * Get a credential for the uid with the server's group list.
3188 * If none is found, just return the credential passed in after
3189 * logging a warning message.
3192 nfsrv_getgrpscred(struct ucred *oldcred)
3194 struct nfsusrgrp *usrp;
3195 struct ucred *newcred;
3198 struct nfsrv_lughash *hp;
3201 uid = oldcred->cr_uid;
3203 if (nfsrv_dnsnamelen > 0) {
3204 hp = NFSUSERHASH(uid);
3206 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
3207 if (usrp->lug_uid == uid) {
3208 if (usrp->lug_expiry < NFSD_MONOSEC)
3210 if (usrp->lug_cred != NULL) {
3211 newcred = crhold(usrp->lug_cred);
3215 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3216 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
3218 mtx_unlock(&hp->mtx);
3222 mtx_unlock(&hp->mtx);
3224 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0, NULL);
3225 if (ret == 0 && cnt < 2)
3232 * Convert a string to a uid.
3233 * If no conversion is possible return NFSERR_BADOWNER, otherwise
3235 * If this is called from a client side mount using AUTH_SYS and the
3236 * string is made up entirely of digits, just convert the string to
3240 nfsv4_strtouid(struct nfsrv_descript *nd, u_char *str, int len, uid_t *uidp)
3243 char *cp, *endstr, *str0;
3244 struct nfsusrgrp *usrp;
3248 struct nfsrv_lughash *hp, *hp2;
3251 error = NFSERR_BADOWNER;
3254 /* If a string of digits and an AUTH_SYS mount, just convert it. */
3256 tuid = (uid_t)strtoul(str0, &endstr, 10);
3257 if ((endstr - str0) == len) {
3258 /* A numeric string. */
3259 if ((nd->nd_flag & ND_KERBV) == 0 &&
3260 ((nd->nd_flag & ND_NFSCL) != 0 ||
3261 nfsd_enable_stringtouid != 0))
3264 error = NFSERR_BADOWNER;
3270 cp = strchr(str0, '@');
3272 i = (int)(cp++ - str0);
3278 if (nfsrv_dnsnamelen > 0) {
3280 * If an '@' is found and the domain name matches, search for
3281 * the name with dns stripped off.
3282 * Mixed case alpahbetics will match for the domain name, but
3283 * all upper case will not.
3285 if (cnt == 0 && i < len && i > 0 &&
3286 (len - 1 - i) == nfsrv_dnsnamelen &&
3287 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
3288 len -= (nfsrv_dnsnamelen + 1);
3293 * Check for the special case of "nobody".
3295 if (len == 6 && !NFSBCMP(str, "nobody", 6)) {
3296 *uidp = nfsrv_defaultuid;
3301 hp = NFSUSERNAMEHASH(str, len);
3303 TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) {
3304 if (usrp->lug_namelen == len &&
3305 !NFSBCMP(usrp->lug_name, str, len)) {
3306 if (usrp->lug_expiry < NFSD_MONOSEC)
3308 hp2 = NFSUSERHASH(usrp->lug_uid);
3309 mtx_lock(&hp2->mtx);
3310 TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash);
3311 TAILQ_INSERT_TAIL(&hp2->lughead, usrp,
3313 *uidp = usrp->lug_uid;
3314 mtx_unlock(&hp2->mtx);
3315 mtx_unlock(&hp->mtx);
3320 mtx_unlock(&hp->mtx);
3322 ret = nfsrv_getuser(RPCNFSUSERD_GETUSER, (uid_t)0, (gid_t)0,
3324 if (ret == 0 && cnt < 2)
3327 error = NFSERR_BADOWNER;
3335 * Convert a gid to a string.
3336 * gid - the group id
3337 * cpp - points to a buffer of size NFSV4_SMALLSTR
3338 * (malloc a larger one, as required)
3339 * retlenp - pointer to length to be returned
3342 nfsv4_gidtostr(gid_t gid, u_char **cpp, int *retlenp)
3345 struct nfsusrgrp *usrp;
3348 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
3349 struct nfsrv_lughash *hp;
3353 if (nfsrv_dnsnamelen > 0 && !nfs_enable_uidtostring) {
3355 * Always map nfsrv_defaultgid to "nogroup".
3357 if (gid == nfsrv_defaultgid) {
3358 i = nfsrv_dnsnamelen + 8;
3360 if (len > NFSV4_SMALLSTR)
3361 free(cp, M_NFSSTRING);
3362 cp = malloc(i, M_NFSSTRING, M_WAITOK);
3368 NFSBCOPY("nogroup@", cp, 8);
3370 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
3374 hp = NFSGROUPHASH(gid);
3376 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
3377 if (usrp->lug_gid == gid) {
3378 if (usrp->lug_expiry < NFSD_MONOSEC)
3381 * If the name doesn't already have an '@'
3382 * in it, append @domainname to it.
3384 for (i = 0; i < usrp->lug_namelen; i++) {
3385 if (usrp->lug_name[i] == '@') {
3391 i = usrp->lug_namelen;
3393 i = usrp->lug_namelen +
3394 nfsrv_dnsnamelen + 1;
3396 mtx_unlock(&hp->mtx);
3397 if (len > NFSV4_SMALLSTR)
3398 free(cp, M_NFSSTRING);
3399 cp = malloc(i, M_NFSSTRING, M_WAITOK);
3405 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
3406 if (!hasampersand) {
3407 cp += usrp->lug_namelen;
3409 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
3411 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3412 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
3414 mtx_unlock(&hp->mtx);
3418 mtx_unlock(&hp->mtx);
3420 ret = nfsrv_getuser(RPCNFSUSERD_GETGID, (uid_t)0, gid, NULL);
3421 if (ret == 0 && cnt < 2)
3426 * No match, just return a string of digits.
3430 while (tmp || i == 0) {
3434 len = (i > len) ? len : i;
3438 for (i = 0; i < len; i++) {
3439 *cp-- = '0' + (tmp % 10);
3446 * Convert a string to a gid.
3447 * If no conversion is possible return NFSERR_BADOWNER, otherwise
3449 * If this is called from a client side mount using AUTH_SYS and the
3450 * string is made up entirely of digits, just convert the string to
3454 nfsv4_strtogid(struct nfsrv_descript *nd, u_char *str, int len, gid_t *gidp)
3457 char *cp, *endstr, *str0;
3458 struct nfsusrgrp *usrp;
3462 struct nfsrv_lughash *hp, *hp2;
3465 error = NFSERR_BADOWNER;
3468 /* If a string of digits and an AUTH_SYS mount, just convert it. */
3470 tgid = (gid_t)strtoul(str0, &endstr, 10);
3471 if ((endstr - str0) == len) {
3472 /* A numeric string. */
3473 if ((nd->nd_flag & ND_KERBV) == 0 &&
3474 ((nd->nd_flag & ND_NFSCL) != 0 ||
3475 nfsd_enable_stringtouid != 0))
3478 error = NFSERR_BADOWNER;
3484 cp = strchr(str0, '@');
3486 i = (int)(cp++ - str0);
3492 if (nfsrv_dnsnamelen > 0) {
3494 * If an '@' is found and the dns name matches, search for the
3495 * name with the dns stripped off.
3497 if (cnt == 0 && i < len && i > 0 &&
3498 (len - 1 - i) == nfsrv_dnsnamelen &&
3499 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
3500 len -= (nfsrv_dnsnamelen + 1);
3505 * Check for the special case of "nogroup".
3507 if (len == 7 && !NFSBCMP(str, "nogroup", 7)) {
3508 *gidp = nfsrv_defaultgid;
3513 hp = NFSGROUPNAMEHASH(str, len);
3515 TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) {
3516 if (usrp->lug_namelen == len &&
3517 !NFSBCMP(usrp->lug_name, str, len)) {
3518 if (usrp->lug_expiry < NFSD_MONOSEC)
3520 hp2 = NFSGROUPHASH(usrp->lug_gid);
3521 mtx_lock(&hp2->mtx);
3522 TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash);
3523 TAILQ_INSERT_TAIL(&hp2->lughead, usrp,
3525 *gidp = usrp->lug_gid;
3526 mtx_unlock(&hp2->mtx);
3527 mtx_unlock(&hp->mtx);
3532 mtx_unlock(&hp->mtx);
3534 ret = nfsrv_getuser(RPCNFSUSERD_GETGROUP, (uid_t)0, (gid_t)0,
3536 if (ret == 0 && cnt < 2)
3539 error = NFSERR_BADOWNER;
3547 * Cmp len chars, allowing mixed case in the first argument to match lower
3548 * case in the second, but not if the first argument is all upper case.
3549 * Return 0 for a match, 1 otherwise.
3552 nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len)
3558 for (i = 0; i < len; i++) {
3559 if (*cp >= 'A' && *cp <= 'Z') {
3560 tmp = *cp++ + ('a' - 'A');
3563 if (tmp >= 'a' && tmp <= 'z')
3576 * Set the port for the nfsuserd.
3579 nfsrv_nfsuserdport(struct nfsuserd_args *nargs, NFSPROC_T *p)
3581 struct nfssockreq *rp;
3583 struct sockaddr_in *ad;
3586 struct sockaddr_in6 *ad6;
3587 const struct in6_addr in6loopback = IN6ADDR_LOOPBACK_INIT;
3592 if (nfsrv_nfsuserd != NOTRUNNING) {
3597 nfsrv_nfsuserd = STARTSTOP;
3599 * Set up the socket record and connect.
3600 * Set nr_client NULL before unlocking, just to ensure that no other
3601 * process/thread/core will use a bogus old value. This could only
3602 * occur if the use of the nameid lock to protect nfsrv_nfsuserd is
3605 rp = &nfsrv_nfsuserdsock;
3606 rp->nr_client = NULL;
3608 rp->nr_sotype = SOCK_DGRAM;
3609 rp->nr_soproto = IPPROTO_UDP;
3610 rp->nr_lock = (NFSR_RESERVEDPORT | NFSR_LOCALHOST);
3612 rp->nr_prog = RPCPROG_NFSUSERD;
3614 switch (nargs->nuserd_family) {
3617 rp->nr_nam = malloc(sizeof(struct sockaddr_in), M_SONAME,
3619 ad = (struct sockaddr_in *)rp->nr_nam;
3620 ad->sin_len = sizeof(struct sockaddr_in);
3621 ad->sin_family = AF_INET;
3622 ad->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
3623 ad->sin_port = nargs->nuserd_port;
3628 rp->nr_nam = malloc(sizeof(struct sockaddr_in6), M_SONAME,
3630 ad6 = (struct sockaddr_in6 *)rp->nr_nam;
3631 ad6->sin6_len = sizeof(struct sockaddr_in6);
3632 ad6->sin6_family = AF_INET6;
3633 ad6->sin6_addr = in6loopback;
3634 ad6->sin6_port = nargs->nuserd_port;
3640 rp->nr_vers = RPCNFSUSERD_VERS;
3642 error = newnfs_connect(NULL, rp, NFSPROCCRED(p), p, 0);
3645 nfsrv_nfsuserd = RUNNING;
3648 free(rp->nr_nam, M_SONAME);
3650 nfsrv_nfsuserd = NOTRUNNING;
3659 * Delete the nfsuserd port.
3662 nfsrv_nfsuserddelport(void)
3666 if (nfsrv_nfsuserd != RUNNING) {
3670 nfsrv_nfsuserd = STARTSTOP;
3671 /* Wait for all upcalls to complete. */
3672 while (nfsrv_userdupcalls > 0)
3673 msleep(&nfsrv_userdupcalls, NFSNAMEIDMUTEXPTR, PVFS,
3676 newnfs_disconnect(&nfsrv_nfsuserdsock);
3677 free(nfsrv_nfsuserdsock.nr_nam, M_SONAME);
3679 nfsrv_nfsuserd = NOTRUNNING;
3684 * Do upcalls to the nfsuserd, for cache misses of the owner/ownergroup
3686 * Returns 0 upon success, non-zero otherwise.
3689 nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name)
3692 struct nfsrv_descript *nd;
3694 struct nfsrv_descript nfsd;
3699 if (nfsrv_nfsuserd != RUNNING) {
3705 * Maintain a count of upcalls in progress, so that nfsrv_X()
3706 * can wait until no upcalls are in progress.
3708 nfsrv_userdupcalls++;
3710 KASSERT(nfsrv_userdupcalls > 0,
3711 ("nfsrv_getuser: non-positive upcalls"));
3713 cred = newnfs_getcred();
3714 nd->nd_flag = ND_GSSINITREPLY;
3717 nd->nd_procnum = procnum;
3718 if (procnum == RPCNFSUSERD_GETUID || procnum == RPCNFSUSERD_GETGID) {
3719 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3720 if (procnum == RPCNFSUSERD_GETUID)
3721 *tl = txdr_unsigned(uid);
3723 *tl = txdr_unsigned(gid);
3726 (void) nfsm_strtom(nd, name, len);
3728 error = newnfs_request(nd, NULL, NULL, &nfsrv_nfsuserdsock, NULL, NULL,
3729 cred, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, NULL, 0, NULL, NULL);
3731 if (--nfsrv_userdupcalls == 0 && nfsrv_nfsuserd == STARTSTOP)
3732 wakeup(&nfsrv_userdupcalls);
3736 m_freem(nd->nd_mrep);
3737 error = nd->nd_repstat;
3745 * This function is called from the nfssvc(2) system call, to update the
3746 * kernel user/group name list(s) for the V4 owner and ownergroup attributes.
3749 nfssvc_idname(struct nfsd_idargs *nidp)
3751 struct nfsusrgrp *nusrp, *usrp, *newusrp;
3752 struct nfsrv_lughash *hp_name, *hp_idnum, *thp;
3753 int i, group_locked, groupname_locked, user_locked, username_locked;
3758 static int onethread = 0;
3759 static time_t lasttime = 0;
3761 if (nidp->nid_namelen <= 0 || nidp->nid_namelen > MAXHOSTNAMELEN) {
3765 if (nidp->nid_flag & NFSID_INITIALIZE) {
3766 cp = malloc(nidp->nid_namelen + 1, M_NFSSTRING, M_WAITOK);
3767 error = copyin(nidp->nid_name, cp, nidp->nid_namelen);
3769 free(cp, M_NFSSTRING);
3772 if (atomic_cmpset_acq_int(&nfsrv_dnsnamelen, 0, 0) == 0) {
3774 * Free up all the old stuff and reinitialize hash
3775 * lists. All mutexes for both lists must be locked,
3776 * with the user/group name ones before the uid/gid
3777 * ones, to avoid a LOR.
3779 for (i = 0; i < nfsrv_lughashsize; i++)
3780 mtx_lock(&nfsusernamehash[i].mtx);
3781 for (i = 0; i < nfsrv_lughashsize; i++)
3782 mtx_lock(&nfsuserhash[i].mtx);
3783 for (i = 0; i < nfsrv_lughashsize; i++)
3784 TAILQ_FOREACH_SAFE(usrp,
3785 &nfsuserhash[i].lughead, lug_numhash, nusrp)
3786 nfsrv_removeuser(usrp, 1);
3787 for (i = 0; i < nfsrv_lughashsize; i++)
3788 mtx_unlock(&nfsuserhash[i].mtx);
3789 for (i = 0; i < nfsrv_lughashsize; i++)
3790 mtx_unlock(&nfsusernamehash[i].mtx);
3791 for (i = 0; i < nfsrv_lughashsize; i++)
3792 mtx_lock(&nfsgroupnamehash[i].mtx);
3793 for (i = 0; i < nfsrv_lughashsize; i++)
3794 mtx_lock(&nfsgrouphash[i].mtx);
3795 for (i = 0; i < nfsrv_lughashsize; i++)
3796 TAILQ_FOREACH_SAFE(usrp,
3797 &nfsgrouphash[i].lughead, lug_numhash,
3799 nfsrv_removeuser(usrp, 0);
3800 for (i = 0; i < nfsrv_lughashsize; i++)
3801 mtx_unlock(&nfsgrouphash[i].mtx);
3802 for (i = 0; i < nfsrv_lughashsize; i++)
3803 mtx_unlock(&nfsgroupnamehash[i].mtx);
3804 free(nfsrv_dnsname, M_NFSSTRING);
3805 nfsrv_dnsname = NULL;
3807 if (nfsuserhash == NULL) {
3808 /* Allocate the hash tables. */
3809 nfsuserhash = malloc(sizeof(struct nfsrv_lughash) *
3810 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3812 for (i = 0; i < nfsrv_lughashsize; i++)
3813 mtx_init(&nfsuserhash[i].mtx, "nfsuidhash",
3814 NULL, MTX_DEF | MTX_DUPOK);
3815 nfsusernamehash = malloc(sizeof(struct nfsrv_lughash) *
3816 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3818 for (i = 0; i < nfsrv_lughashsize; i++)
3819 mtx_init(&nfsusernamehash[i].mtx,
3820 "nfsusrhash", NULL, MTX_DEF |
3822 nfsgrouphash = malloc(sizeof(struct nfsrv_lughash) *
3823 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3825 for (i = 0; i < nfsrv_lughashsize; i++)
3826 mtx_init(&nfsgrouphash[i].mtx, "nfsgidhash",
3827 NULL, MTX_DEF | MTX_DUPOK);
3828 nfsgroupnamehash = malloc(sizeof(struct nfsrv_lughash) *
3829 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3831 for (i = 0; i < nfsrv_lughashsize; i++)
3832 mtx_init(&nfsgroupnamehash[i].mtx,
3833 "nfsgrphash", NULL, MTX_DEF | MTX_DUPOK);
3835 /* (Re)initialize the list heads. */
3836 for (i = 0; i < nfsrv_lughashsize; i++)
3837 TAILQ_INIT(&nfsuserhash[i].lughead);
3838 for (i = 0; i < nfsrv_lughashsize; i++)
3839 TAILQ_INIT(&nfsusernamehash[i].lughead);
3840 for (i = 0; i < nfsrv_lughashsize; i++)
3841 TAILQ_INIT(&nfsgrouphash[i].lughead);
3842 for (i = 0; i < nfsrv_lughashsize; i++)
3843 TAILQ_INIT(&nfsgroupnamehash[i].lughead);
3846 * Put name in "DNS" string.
3849 nfsrv_defaultuid = nidp->nid_uid;
3850 nfsrv_defaultgid = nidp->nid_gid;
3852 nfsrv_usermax = nidp->nid_usermax;
3853 atomic_store_rel_int(&nfsrv_dnsnamelen, nidp->nid_namelen);
3858 * malloc the new one now, so any potential sleep occurs before
3859 * manipulation of the lists.
3861 newusrp = malloc(sizeof(struct nfsusrgrp) + nidp->nid_namelen,
3862 M_NFSUSERGROUP, M_WAITOK | M_ZERO);
3863 error = copyin(nidp->nid_name, newusrp->lug_name,
3865 if (error == 0 && nidp->nid_ngroup > 0 &&
3866 (nidp->nid_flag & NFSID_ADDUID) != 0) {
3867 grps = malloc(sizeof(gid_t) * nidp->nid_ngroup, M_TEMP,
3869 error = copyin(nidp->nid_grps, grps,
3870 sizeof(gid_t) * nidp->nid_ngroup);
3873 * Create a credential just like svc_getcred(),
3874 * but using the group list provided.
3877 cr->cr_uid = cr->cr_ruid = cr->cr_svuid = nidp->nid_uid;
3878 crsetgroups(cr, nidp->nid_ngroup, grps);
3879 cr->cr_rgid = cr->cr_svgid = cr->cr_groups[0];
3880 cr->cr_prison = &prison0;
3881 prison_hold(cr->cr_prison);
3883 mac_cred_associate_nfsd(cr);
3885 newusrp->lug_cred = cr;
3890 free(newusrp, M_NFSUSERGROUP);
3893 newusrp->lug_namelen = nidp->nid_namelen;
3896 * The lock order is username[0]->[nfsrv_lughashsize - 1] followed
3897 * by uid[0]->[nfsrv_lughashsize - 1], with the same for group.
3898 * The flags user_locked, username_locked, group_locked and
3899 * groupname_locked are set to indicate all of those hash lists are
3900 * locked. hp_name != NULL and hp_idnum != NULL indicates that
3901 * the respective one mutex is locked.
3903 user_locked = username_locked = group_locked = groupname_locked = 0;
3904 hp_name = hp_idnum = NULL;
3907 * Delete old entries, as required.
3909 if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) {
3910 /* Must lock all username hash lists first, to avoid a LOR. */
3911 for (i = 0; i < nfsrv_lughashsize; i++)
3912 mtx_lock(&nfsusernamehash[i].mtx);
3913 username_locked = 1;
3914 hp_idnum = NFSUSERHASH(nidp->nid_uid);
3915 mtx_lock(&hp_idnum->mtx);
3916 TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
3918 if (usrp->lug_uid == nidp->nid_uid)
3919 nfsrv_removeuser(usrp, 1);
3921 } else if (nidp->nid_flag & (NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) {
3922 hp_name = NFSUSERNAMEHASH(newusrp->lug_name,
3923 newusrp->lug_namelen);
3924 mtx_lock(&hp_name->mtx);
3925 TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
3927 if (usrp->lug_namelen == newusrp->lug_namelen &&
3928 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3929 usrp->lug_namelen)) {
3930 thp = NFSUSERHASH(usrp->lug_uid);
3931 mtx_lock(&thp->mtx);
3932 nfsrv_removeuser(usrp, 1);
3933 mtx_unlock(&thp->mtx);
3936 hp_idnum = NFSUSERHASH(nidp->nid_uid);
3937 mtx_lock(&hp_idnum->mtx);
3938 } else if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) {
3939 /* Must lock all groupname hash lists first, to avoid a LOR. */
3940 for (i = 0; i < nfsrv_lughashsize; i++)
3941 mtx_lock(&nfsgroupnamehash[i].mtx);
3942 groupname_locked = 1;
3943 hp_idnum = NFSGROUPHASH(nidp->nid_gid);
3944 mtx_lock(&hp_idnum->mtx);
3945 TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
3947 if (usrp->lug_gid == nidp->nid_gid)
3948 nfsrv_removeuser(usrp, 0);
3950 } else if (nidp->nid_flag & (NFSID_DELGROUPNAME | NFSID_ADDGROUPNAME)) {
3951 hp_name = NFSGROUPNAMEHASH(newusrp->lug_name,
3952 newusrp->lug_namelen);
3953 mtx_lock(&hp_name->mtx);
3954 TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
3956 if (usrp->lug_namelen == newusrp->lug_namelen &&
3957 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3958 usrp->lug_namelen)) {
3959 thp = NFSGROUPHASH(usrp->lug_gid);
3960 mtx_lock(&thp->mtx);
3961 nfsrv_removeuser(usrp, 0);
3962 mtx_unlock(&thp->mtx);
3965 hp_idnum = NFSGROUPHASH(nidp->nid_gid);
3966 mtx_lock(&hp_idnum->mtx);
3970 * Now, we can add the new one.
3972 if (nidp->nid_usertimeout)
3973 newusrp->lug_expiry = NFSD_MONOSEC + nidp->nid_usertimeout;
3975 newusrp->lug_expiry = NFSD_MONOSEC + 5;
3976 if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) {
3977 newusrp->lug_uid = nidp->nid_uid;
3978 thp = NFSUSERHASH(newusrp->lug_uid);
3979 mtx_assert(&thp->mtx, MA_OWNED);
3980 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
3981 thp = NFSUSERNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3982 mtx_assert(&thp->mtx, MA_OWNED);
3983 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
3984 atomic_add_int(&nfsrv_usercnt, 1);
3985 } else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) {
3986 newusrp->lug_gid = nidp->nid_gid;
3987 thp = NFSGROUPHASH(newusrp->lug_gid);
3988 mtx_assert(&thp->mtx, MA_OWNED);
3989 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
3990 thp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3991 mtx_assert(&thp->mtx, MA_OWNED);
3992 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
3993 atomic_add_int(&nfsrv_usercnt, 1);
3995 if (newusrp->lug_cred != NULL)
3996 crfree(newusrp->lug_cred);
3997 free(newusrp, M_NFSUSERGROUP);
4001 * Once per second, allow one thread to trim the cache.
4003 if (lasttime < NFSD_MONOSEC &&
4004 atomic_cmpset_acq_int(&onethread, 0, 1) != 0) {
4006 * First, unlock the single mutexes, so that all entries
4007 * can be locked and any LOR is avoided.
4009 if (hp_name != NULL) {
4010 mtx_unlock(&hp_name->mtx);
4013 if (hp_idnum != NULL) {
4014 mtx_unlock(&hp_idnum->mtx);
4018 if ((nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID |
4019 NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) != 0) {
4020 if (username_locked == 0) {
4021 for (i = 0; i < nfsrv_lughashsize; i++)
4022 mtx_lock(&nfsusernamehash[i].mtx);
4023 username_locked = 1;
4025 KASSERT(user_locked == 0,
4026 ("nfssvc_idname: user_locked"));
4027 for (i = 0; i < nfsrv_lughashsize; i++)
4028 mtx_lock(&nfsuserhash[i].mtx);
4030 for (i = 0; i < nfsrv_lughashsize; i++) {
4031 TAILQ_FOREACH_SAFE(usrp,
4032 &nfsuserhash[i].lughead, lug_numhash,
4034 if (usrp->lug_expiry < NFSD_MONOSEC)
4035 nfsrv_removeuser(usrp, 1);
4037 for (i = 0; i < nfsrv_lughashsize; i++) {
4039 * Trim the cache using an approximate LRU
4040 * algorithm. This code deletes the least
4041 * recently used entry on each hash list.
4043 if (nfsrv_usercnt <= nfsrv_usermax)
4045 usrp = TAILQ_FIRST(&nfsuserhash[i].lughead);
4047 nfsrv_removeuser(usrp, 1);
4050 if (groupname_locked == 0) {
4051 for (i = 0; i < nfsrv_lughashsize; i++)
4052 mtx_lock(&nfsgroupnamehash[i].mtx);
4053 groupname_locked = 1;
4055 KASSERT(group_locked == 0,
4056 ("nfssvc_idname: group_locked"));
4057 for (i = 0; i < nfsrv_lughashsize; i++)
4058 mtx_lock(&nfsgrouphash[i].mtx);
4060 for (i = 0; i < nfsrv_lughashsize; i++) {
4061 TAILQ_FOREACH_SAFE(usrp,
4062 &nfsgrouphash[i].lughead, lug_numhash,
4064 if (usrp->lug_expiry < NFSD_MONOSEC)
4065 nfsrv_removeuser(usrp, 0);
4067 for (i = 0; i < nfsrv_lughashsize; i++) {
4069 * Trim the cache using an approximate LRU
4070 * algorithm. This code deletes the least
4071 * recently user entry on each hash list.
4073 if (nfsrv_usercnt <= nfsrv_usermax)
4075 usrp = TAILQ_FIRST(&nfsgrouphash[i].lughead);
4077 nfsrv_removeuser(usrp, 0);
4080 lasttime = NFSD_MONOSEC;
4081 atomic_store_rel_int(&onethread, 0);
4084 /* Now, unlock all locked mutexes. */
4085 if (hp_idnum != NULL)
4086 mtx_unlock(&hp_idnum->mtx);
4087 if (hp_name != NULL)
4088 mtx_unlock(&hp_name->mtx);
4089 if (user_locked != 0)
4090 for (i = 0; i < nfsrv_lughashsize; i++)
4091 mtx_unlock(&nfsuserhash[i].mtx);
4092 if (username_locked != 0)
4093 for (i = 0; i < nfsrv_lughashsize; i++)
4094 mtx_unlock(&nfsusernamehash[i].mtx);
4095 if (group_locked != 0)
4096 for (i = 0; i < nfsrv_lughashsize; i++)
4097 mtx_unlock(&nfsgrouphash[i].mtx);
4098 if (groupname_locked != 0)
4099 for (i = 0; i < nfsrv_lughashsize; i++)
4100 mtx_unlock(&nfsgroupnamehash[i].mtx);
4107 * Remove a user/group name element.
4110 nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser)
4112 struct nfsrv_lughash *hp;
4115 hp = NFSUSERHASH(usrp->lug_uid);
4116 mtx_assert(&hp->mtx, MA_OWNED);
4117 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
4118 hp = NFSUSERNAMEHASH(usrp->lug_name, usrp->lug_namelen);
4119 mtx_assert(&hp->mtx, MA_OWNED);
4120 TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
4122 hp = NFSGROUPHASH(usrp->lug_gid);
4123 mtx_assert(&hp->mtx, MA_OWNED);
4124 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
4125 hp = NFSGROUPNAMEHASH(usrp->lug_name, usrp->lug_namelen);
4126 mtx_assert(&hp->mtx, MA_OWNED);
4127 TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
4129 atomic_add_int(&nfsrv_usercnt, -1);
4130 if (usrp->lug_cred != NULL)
4131 crfree(usrp->lug_cred);
4132 free(usrp, M_NFSUSERGROUP);
4136 * Free up all the allocations related to the name<-->id cache.
4137 * This function should only be called when the nfsuserd daemon isn't
4138 * running, since it doesn't do any locking.
4139 * This function is meant to be used when the nfscommon module is unloaded.
4142 nfsrv_cleanusergroup(void)
4144 struct nfsrv_lughash *hp, *hp2;
4145 struct nfsusrgrp *nusrp, *usrp;
4148 if (nfsuserhash == NULL)
4151 for (i = 0; i < nfsrv_lughashsize; i++) {
4152 hp = &nfsuserhash[i];
4153 TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) {
4154 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
4155 hp2 = NFSUSERNAMEHASH(usrp->lug_name,
4157 TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash);
4158 if (usrp->lug_cred != NULL)
4159 crfree(usrp->lug_cred);
4160 free(usrp, M_NFSUSERGROUP);
4162 hp = &nfsgrouphash[i];
4163 TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) {
4164 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
4165 hp2 = NFSGROUPNAMEHASH(usrp->lug_name,
4167 TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash);
4168 if (usrp->lug_cred != NULL)
4169 crfree(usrp->lug_cred);
4170 free(usrp, M_NFSUSERGROUP);
4172 mtx_destroy(&nfsuserhash[i].mtx);
4173 mtx_destroy(&nfsusernamehash[i].mtx);
4174 mtx_destroy(&nfsgroupnamehash[i].mtx);
4175 mtx_destroy(&nfsgrouphash[i].mtx);
4177 free(nfsuserhash, M_NFSUSERGROUP);
4178 free(nfsusernamehash, M_NFSUSERGROUP);
4179 free(nfsgrouphash, M_NFSUSERGROUP);
4180 free(nfsgroupnamehash, M_NFSUSERGROUP);
4181 free(nfsrv_dnsname, M_NFSSTRING);
4185 * This function scans a byte string and checks for UTF-8 compliance.
4186 * It returns 0 if it conforms and NFSERR_INVAL if not.
4189 nfsrv_checkutf8(u_int8_t *cp, int len)
4191 u_int32_t val = 0x0;
4192 int cnt = 0, gotd = 0, shift = 0;
4194 static int utf8_shift[5] = { 7, 11, 16, 21, 26 };
4198 * Here are what the variables are used for:
4199 * val - the calculated value of a multibyte char, used to check
4200 * that it was coded with the correct range
4201 * cnt - the number of 10xxxxxx bytes to follow
4202 * gotd - set for a char of Dxxx, so D800<->DFFF can be checked for
4203 * shift - lower order bits of range (ie. "val >> shift" should
4204 * not be 0, in other words, dividing by the lower bound
4205 * of the range should get a non-zero value)
4206 * byte - used to calculate cnt
4210 /* This handles the 10xxxxxx bytes */
4211 if ((*cp & 0xc0) != 0x80 ||
4212 (gotd && (*cp & 0x20))) {
4213 error = NFSERR_INVAL;
4218 val |= (*cp & 0x3f);
4220 if (cnt == 0 && (val >> shift) == 0x0) {
4221 error = NFSERR_INVAL;
4224 } else if (*cp & 0x80) {
4225 /* first byte of multi byte char */
4227 while ((byte & 0x40) && cnt < 6) {
4231 if (cnt == 0 || cnt == 6) {
4232 error = NFSERR_INVAL;
4235 val = (*cp & (0x3f >> cnt));
4236 shift = utf8_shift[cnt - 1];
4237 if (cnt == 2 && val == 0xd)
4238 /* Check for the 0xd800-0xdfff case */
4245 error = NFSERR_INVAL;
4253 * Parse the xdr for an NFSv4 FsLocations attribute. Return two malloc'd
4254 * strings, one with the root path in it and the other with the list of
4255 * locations. The list is in the same format as is found in nfr_refs.
4256 * It is a "," separated list of entries, where each of them is of the
4257 * form <server>:<rootpath>. For example
4258 * "nfsv4-test:/sub2,nfsv4-test2:/user/mnt,nfsv4-test2:/user/mnt2"
4259 * The nilp argument is set to 1 for the special case of a null fs_root
4260 * and an empty server list.
4261 * It returns NFSERR_BADXDR, if the xdr can't be parsed and returns the
4262 * number of xdr bytes parsed in sump.
4265 nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp,
4266 int *sump, int *nilp)
4269 u_char *cp = NULL, *cp2 = NULL, *cp3, *str;
4270 int i, j, len, stringlen, cnt, slen, siz, xdrsum, error = 0, nsrv;
4272 SLIST_ENTRY(list) next;
4276 SLIST_HEAD(, list) head;
4283 * Get the fs_root path and check for the special case of null path
4284 * and 0 length server list.
4286 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4287 len = fxdr_unsigned(int, *tl);
4288 if (len < 0 || len > 10240) {
4289 error = NFSERR_BADXDR;
4293 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4295 error = NFSERR_BADXDR;
4299 *sump = 2 * NFSX_UNSIGNED;
4303 cp = malloc(len + 1, M_NFSSTRING, M_WAITOK);
4304 error = nfsrv_mtostr(nd, cp, len);
4306 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4307 cnt = fxdr_unsigned(int, *tl);
4309 error = NFSERR_BADXDR;
4315 * Now, loop through the location list and make up the srvlist.
4317 xdrsum = (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
4318 cp2 = cp3 = malloc(1024, M_NFSSTRING, M_WAITOK);
4321 for (i = 0; i < cnt; i++) {
4323 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4324 nsrv = fxdr_unsigned(int, *tl);
4326 error = NFSERR_BADXDR;
4331 * Handle the first server by putting it in the srvstr.
4333 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4334 len = fxdr_unsigned(int, *tl);
4335 if (len <= 0 || len > 1024) {
4336 error = NFSERR_BADXDR;
4339 nfsrv_refstrbigenough(siz + len + 3, &cp2, &cp3, &slen);
4344 error = nfsrv_mtostr(nd, cp3, len);
4350 xdrsum += (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
4351 for (j = 1; j < nsrv; j++) {
4353 * Yuck, put them in an slist and process them later.
4355 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4356 len = fxdr_unsigned(int, *tl);
4357 if (len <= 0 || len > 1024) {
4358 error = NFSERR_BADXDR;
4361 lsp = (struct list *)malloc(sizeof (struct list)
4362 + len, M_TEMP, M_WAITOK);
4363 error = nfsrv_mtostr(nd, lsp->host, len);
4366 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
4368 SLIST_INSERT_HEAD(&head, lsp, next);
4372 * Finally, we can get the path.
4374 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4375 len = fxdr_unsigned(int, *tl);
4376 if (len <= 0 || len > 1024) {
4377 error = NFSERR_BADXDR;
4380 nfsrv_refstrbigenough(siz + len + 1, &cp2, &cp3, &slen);
4381 error = nfsrv_mtostr(nd, cp3, len);
4384 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
4389 SLIST_FOREACH_SAFE(lsp, &head, next, nlsp) {
4390 nfsrv_refstrbigenough(siz + lsp->len + stringlen + 3,
4393 NFSBCOPY(lsp->host, cp3, lsp->len);
4396 NFSBCOPY(str, cp3, stringlen);
4399 siz += (lsp->len + stringlen + 2);
4406 NFSEXITCODE2(0, nd);
4410 free(cp, M_NFSSTRING);
4412 free(cp2, M_NFSSTRING);
4413 NFSEXITCODE2(error, nd);
4418 * Make the malloc'd space large enough. This is a pain, but the xdr
4419 * doesn't set an upper bound on the side, so...
4422 nfsrv_refstrbigenough(int siz, u_char **cpp, u_char **cpp2, int *slenp)
4429 cp = malloc(siz + 1024, M_NFSSTRING, M_WAITOK);
4430 NFSBCOPY(*cpp, cp, *slenp);
4431 free(*cpp, M_NFSSTRING);
4435 *slenp = siz + 1024;
4439 * Initialize the reply header data structures.
4442 nfsrvd_rephead(struct nfsrv_descript *nd)
4446 if ((nd->nd_flag & ND_EXTPG) != 0) {
4447 mreq = mb_alloc_ext_plus_pages(PAGE_SIZE, M_WAITOK);
4448 nd->nd_mreq = nd->nd_mb = mreq;
4449 nd->nd_bpos = (char *)(void *)
4450 PHYS_TO_DMAP(mreq->m_epg_pa[0]);
4452 nd->nd_bextpgsiz = PAGE_SIZE;
4455 * If this is a big reply, use a cluster.
4457 if ((nd->nd_flag & ND_GSSINITREPLY) == 0 &&
4458 nfs_bigreply[nd->nd_procnum]) {
4459 NFSMCLGET(mreq, M_WAITOK);
4467 nd->nd_bpos = mtod(mreq, char *);
4471 if ((nd->nd_flag & ND_GSSINITREPLY) == 0)
4472 NFSM_BUILD(nd->nd_errp, int *, NFSX_UNSIGNED);
4476 * Lock a socket against others.
4477 * Currently used to serialize connect/disconnect attempts.
4480 newnfs_sndlock(int *flagp)
4485 while (*flagp & NFSR_SNDLOCK) {
4486 *flagp |= NFSR_WANTSND;
4489 (void) nfsmsleep((caddr_t)flagp, NFSSOCKMUTEXPTR,
4490 PZERO - 1, "nfsndlck", &ts);
4492 *flagp |= NFSR_SNDLOCK;
4498 * Unlock the stream socket for others.
4501 newnfs_sndunlock(int *flagp)
4505 if ((*flagp & NFSR_SNDLOCK) == 0)
4506 panic("nfs sndunlock");
4507 *flagp &= ~NFSR_SNDLOCK;
4508 if (*flagp & NFSR_WANTSND) {
4509 *flagp &= ~NFSR_WANTSND;
4510 wakeup((caddr_t)flagp);
4516 nfsv4_getipaddr(struct nfsrv_descript *nd, struct sockaddr_in *sin,
4517 struct sockaddr_in6 *sin6, sa_family_t *saf, int *isudp)
4519 struct in_addr saddr;
4520 uint32_t portnum, *tl;
4522 sa_family_t af = AF_UNSPEC;
4523 char addr[64], protocol[5], *cp;
4524 int cantparse = 0, error = 0;
4527 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4528 i = fxdr_unsigned(int, *tl);
4529 if (i >= 3 && i <= 4) {
4530 error = nfsrv_mtostr(nd, protocol, i);
4533 if (strcmp(protocol, "tcp") == 0) {
4536 } else if (strcmp(protocol, "udp") == 0) {
4539 } else if (strcmp(protocol, "tcp6") == 0) {
4542 } else if (strcmp(protocol, "udp6") == 0) {
4550 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
4555 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4556 i = fxdr_unsigned(int, *tl);
4558 error = NFSERR_BADXDR;
4560 } else if (cantparse == 0 && i >= 11 && i < 64) {
4562 * The shortest address is 11chars and the longest is < 64.
4564 error = nfsrv_mtostr(nd, addr, i);
4568 /* Find the port# at the end and extract that. */
4572 /* Count back two '.'s from end to get port# field. */
4573 for (j = 0; j < i; j++) {
4583 * The NFSv4 port# is appended as .N.N, where N is
4584 * a decimal # in the range 0-255, just like an inet4
4585 * address. Cheat and use inet_aton(), which will
4586 * return a Class A address and then shift the high
4587 * order 8bits over to convert it to the port#.
4590 if (inet_aton(cp, &saddr) == 1) {
4591 portnum = ntohl(saddr.s_addr);
4592 portv = (uint16_t)((portnum >> 16) |
4598 if (cantparse == 0) {
4599 if (af == AF_INET) {
4600 if (inet_pton(af, addr, &sin->sin_addr) == 1) {
4601 sin->sin_len = sizeof(*sin);
4602 sin->sin_family = AF_INET;
4603 sin->sin_port = htons(portv);
4608 if (inet_pton(af, addr, &sin6->sin6_addr)
4610 sin6->sin6_len = sizeof(*sin6);
4611 sin6->sin6_family = AF_INET6;
4612 sin6->sin6_port = htons(portv);
4620 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
4631 * Handle an NFSv4.1 Sequence request for the session.
4632 * If reply != NULL, use it to return the cached reply, as required.
4633 * The client gets a cached reply via this call for callbacks, however the
4634 * server gets a cached reply via the nfsv4_seqsess_cachereply() call.
4637 nfsv4_seqsession(uint32_t seqid, uint32_t slotid, uint32_t highslot,
4638 struct nfsslot *slots, struct mbuf **reply, uint16_t maxslot)
4645 if (slotid > maxslot)
4646 return (NFSERR_BADSLOT);
4647 if (seqid == slots[slotid].nfssl_seq) {
4649 if (slots[slotid].nfssl_inprog != 0)
4650 error = NFSERR_DELAY;
4651 else if (slots[slotid].nfssl_reply != NULL) {
4652 if (reply != NULL) {
4653 *reply = slots[slotid].nfssl_reply;
4654 slots[slotid].nfssl_reply = NULL;
4656 slots[slotid].nfssl_inprog = 1;
4657 error = NFSERR_REPLYFROMCACHE;
4659 /* No reply cached, so just do it. */
4660 slots[slotid].nfssl_inprog = 1;
4661 } else if ((slots[slotid].nfssl_seq + 1) == seqid) {
4662 if (slots[slotid].nfssl_reply != NULL)
4663 m_freem(slots[slotid].nfssl_reply);
4664 slots[slotid].nfssl_reply = NULL;
4665 slots[slotid].nfssl_inprog = 1;
4666 slots[slotid].nfssl_seq++;
4668 error = NFSERR_SEQMISORDERED;
4673 * Cache this reply for the slot.
4674 * Use the "rep" argument to return the cached reply if repstat is set to
4675 * NFSERR_REPLYFROMCACHE. The client never sets repstat to this value.
4678 nfsv4_seqsess_cacherep(uint32_t slotid, struct nfsslot *slots, int repstat,
4682 if (repstat == NFSERR_REPLYFROMCACHE) {
4683 *rep = slots[slotid].nfssl_reply;
4684 slots[slotid].nfssl_reply = NULL;
4686 if (slots[slotid].nfssl_reply != NULL)
4687 m_freem(slots[slotid].nfssl_reply);
4688 slots[slotid].nfssl_reply = *rep;
4690 slots[slotid].nfssl_inprog = 0;
4694 * Generate the xdr for an NFSv4.1 Sequence Operation.
4697 nfsv4_setsequence(struct nfsmount *nmp, struct nfsrv_descript *nd,
4698 struct nfsclsession *sep, int dont_replycache)
4700 uint32_t *tl, slotseq = 0;
4701 int error, maxslot, slotpos;
4702 uint8_t sessionid[NFSX_V4SESSIONID];
4704 error = nfsv4_sequencelookup(nmp, sep, &slotpos, &maxslot, &slotseq,
4706 nd->nd_maxreq = sep->nfsess_maxreq;
4707 nd->nd_maxresp = sep->nfsess_maxresp;
4709 /* Build the Sequence arguments. */
4710 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 4 * NFSX_UNSIGNED);
4711 nd->nd_sequence = tl;
4712 bcopy(sessionid, tl, NFSX_V4SESSIONID);
4713 tl += NFSX_V4SESSIONID / NFSX_UNSIGNED;
4714 nd->nd_slotseq = tl;
4716 nd->nd_flag |= ND_HASSLOTID;
4717 nd->nd_slotid = slotpos;
4718 *tl++ = txdr_unsigned(slotseq);
4719 *tl++ = txdr_unsigned(slotpos);
4720 *tl++ = txdr_unsigned(maxslot);
4721 if (dont_replycache == 0)
4727 * There are two errors and the rest of the session can
4729 * NFSERR_BADSESSION: This bad session should just generate
4730 * the same error again when the RPC is retried.
4731 * ESTALE: A forced dismount is in progress and will cause the
4732 * RPC to fail later.
4739 nd->nd_flag |= ND_HASSEQUENCE;
4743 nfsv4_sequencelookup(struct nfsmount *nmp, struct nfsclsession *sep,
4744 int *slotposp, int *maxslotp, uint32_t *slotseqp, uint8_t *sessionid)
4746 int i, maxslot, slotpos;
4749 /* Find an unused slot. */
4752 mtx_lock(&sep->nfsess_mtx);
4754 if (nmp != NULL && sep->nfsess_defunct != 0) {
4755 /* Just return the bad session. */
4756 bcopy(sep->nfsess_sessionid, sessionid,
4758 mtx_unlock(&sep->nfsess_mtx);
4759 return (NFSERR_BADSESSION);
4762 for (i = 0; i < sep->nfsess_foreslots; i++) {
4763 if ((bitval & sep->nfsess_slots) == 0) {
4765 sep->nfsess_slots |= bitval;
4766 sep->nfsess_slotseq[i]++;
4767 *slotseqp = sep->nfsess_slotseq[i];
4772 if (slotpos == -1) {
4774 * If a forced dismount is in progress, just return.
4775 * This RPC attempt will fail when it calls
4778 if (nmp != NULL && NFSCL_FORCEDISM(nmp->nm_mountp)) {
4779 mtx_unlock(&sep->nfsess_mtx);
4782 /* Wake up once/sec, to check for a forced dismount. */
4783 (void)mtx_sleep(&sep->nfsess_slots, &sep->nfsess_mtx,
4784 PZERO, "nfsclseq", hz);
4786 } while (slotpos == -1);
4787 /* Now, find the highest slot in use. (nfsc_slots is 64bits) */
4789 for (i = 0; i < 64; i++) {
4790 if ((bitval & sep->nfsess_slots) != 0)
4794 bcopy(sep->nfsess_sessionid, sessionid, NFSX_V4SESSIONID);
4795 mtx_unlock(&sep->nfsess_mtx);
4796 *slotposp = slotpos;
4797 *maxslotp = maxslot;
4802 * Free a session slot.
4805 nfsv4_freeslot(struct nfsclsession *sep, int slot)
4812 mtx_lock(&sep->nfsess_mtx);
4813 if ((bitval & sep->nfsess_slots) == 0)
4814 printf("freeing free slot!!\n");
4815 sep->nfsess_slots &= ~bitval;
4816 wakeup(&sep->nfsess_slots);
4817 mtx_unlock(&sep->nfsess_mtx);
4821 * Search for a matching pnfsd DS, based on the nmp arg.
4822 * Return one if found, NULL otherwise.
4825 nfsv4_findmirror(struct nfsmount *nmp)
4827 struct nfsdevice *ds;
4829 mtx_assert(NFSDDSMUTEXPTR, MA_OWNED);
4831 * Search the DS server list for a match with nmp.
4833 if (nfsrv_devidcnt == 0)
4835 TAILQ_FOREACH(ds, &nfsrv_devidhead, nfsdev_list) {
4836 if (ds->nfsdev_nmp == nmp) {
4837 NFSCL_DEBUG(4, "nfsv4_findmirror: fnd main ds\n");
4845 * Fill in the fields of "struct nfsrv_descript".
4848 nfsm_set(struct nfsrv_descript *nd, u_int offs)
4854 if ((m->m_flags & M_EXTPG) != 0) {
4857 if (nd->nd_bextpg == 0)
4858 rlen = m_epg_pagelen(m, 0, m->m_epg_1st_off);
4860 rlen = m_epg_pagelen(m, nd->nd_bextpg, 0);
4865 if (nd->nd_bextpg == m->m_epg_npgs) {
4866 printf("nfsm_set: build offs "
4872 nd->nd_bpos = (char *)(void *)
4873 PHYS_TO_DMAP(m->m_epg_pa[nd->nd_bextpg]);
4874 if (nd->nd_bextpg == 0)
4875 nd->nd_bpos += m->m_epg_1st_off;
4877 nd->nd_bpos += offs;
4878 nd->nd_bextpgsiz = rlen - offs;
4879 } else if (nd->nd_bextpg == 0)
4880 nd->nd_bextpgsiz = PAGE_SIZE - m->m_epg_1st_off;
4882 nd->nd_bextpgsiz = PAGE_SIZE;
4884 nd->nd_bpos = mtod(m, char *) + offs;
4888 * Grow a ext_pgs mbuf list. Either allocate another page or add
4889 * an mbuf to the list.
4892 nfsm_add_ext_pgs(struct mbuf *m, int maxextsiz, int *bextpg)
4897 if ((m->m_epg_npgs + 1) * PAGE_SIZE > maxextsiz) {
4898 mp = mb_alloc_ext_plus_pages(PAGE_SIZE, M_WAITOK);
4903 pg = vm_page_alloc(NULL, 0, VM_ALLOC_NORMAL |
4904 VM_ALLOC_NOOBJ | VM_ALLOC_NODUMP |
4908 } while (pg == NULL);
4909 m->m_epg_pa[m->m_epg_npgs] = VM_PAGE_TO_PHYS(pg);
4910 *bextpg = m->m_epg_npgs;
4912 m->m_epg_last_len = 0;