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;
509 switch (nd->nd_flag & (ND_NFSV2 | ND_NFSV3 | ND_NFSV4)) {
511 NFSM_BUILD(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
512 if (vap->va_mode == (mode_t)VNOVAL)
513 sp->sa_mode = newnfs_xdrneg1;
515 sp->sa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
516 if (vap->va_uid == (uid_t)VNOVAL)
517 sp->sa_uid = newnfs_xdrneg1;
519 sp->sa_uid = txdr_unsigned(vap->va_uid);
520 if (vap->va_gid == (gid_t)VNOVAL)
521 sp->sa_gid = newnfs_xdrneg1;
523 sp->sa_gid = txdr_unsigned(vap->va_gid);
524 if (flags & NFSSATTR_SIZE0)
526 else if (flags & NFSSATTR_SIZENEG1)
527 sp->sa_size = newnfs_xdrneg1;
528 else if (flags & NFSSATTR_SIZERDEV)
529 sp->sa_size = txdr_unsigned(rdev);
531 sp->sa_size = txdr_unsigned(vap->va_size);
532 txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
533 txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
536 if (vap->va_mode != (mode_t)VNOVAL) {
537 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
539 *tl = txdr_unsigned(vap->va_mode);
541 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
544 if ((flags & NFSSATTR_FULL) && vap->va_uid != (uid_t)VNOVAL) {
545 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
547 *tl = txdr_unsigned(vap->va_uid);
549 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
552 if ((flags & NFSSATTR_FULL) && vap->va_gid != (gid_t)VNOVAL) {
553 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
555 *tl = txdr_unsigned(vap->va_gid);
557 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
560 if ((flags & NFSSATTR_FULL) && vap->va_size != VNOVAL) {
561 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
563 txdr_hyper(vap->va_size, tl);
565 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
568 if (vap->va_atime.tv_sec != VNOVAL) {
569 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
570 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
571 *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
572 txdr_nfsv3time(&vap->va_atime, tl);
574 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
575 *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
578 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
579 *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
581 if (vap->va_mtime.tv_sec != VNOVAL) {
582 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
583 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
584 *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
585 txdr_nfsv3time(&vap->va_mtime, tl);
587 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
588 *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
591 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
592 *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
596 NFSZERO_ATTRBIT(&attrbits);
597 if (vap->va_mode != (mode_t)VNOVAL)
598 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_MODE);
599 if ((flags & NFSSATTR_FULL) && vap->va_uid != (uid_t)VNOVAL)
600 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
601 if ((flags & NFSSATTR_FULL) && vap->va_gid != (gid_t)VNOVAL)
602 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP);
603 if ((flags & NFSSATTR_FULL) && vap->va_size != VNOVAL)
604 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_SIZE);
605 if (vap->va_atime.tv_sec != VNOVAL)
606 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET);
607 if (vap->va_mtime.tv_sec != VNOVAL)
608 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET);
609 if (vap->va_birthtime.tv_sec != VNOVAL &&
610 strcmp(vp->v_mount->mnt_vfc->vfc_name, "nfs") == 0) {
612 * We can only test for support of TimeCreate if
613 * the "vp" argument is for an NFS vnode.
616 if (NFSISSET_ATTRBIT(&np->n_vattr.na_suppattr,
617 NFSATTRBIT_TIMECREATE))
618 NFSSETBIT_ATTRBIT(&attrbits,
619 NFSATTRBIT_TIMECREATE);
621 (void) nfsv4_fillattr(nd, vp->v_mount, vp, NULL, vap, NULL, 0,
622 &attrbits, NULL, NULL, 0, 0, 0, 0, (uint64_t)0, NULL);
629 * copies mbuf chain to the uio scatter/gather list
632 nfsm_mbufuio(struct nfsrv_descript *nd, struct uio *uiop, int siz)
634 char *mbufcp, *uiocp;
641 mbufcp = nd->nd_dpos;
642 len = mtod(mp, caddr_t) + mp->m_len - mbufcp;
643 rem = NFSM_RNDUP(siz) - siz;
645 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) {
649 left = uiop->uio_iov->iov_len;
650 uiocp = uiop->uio_iov->iov_base;
661 mbufcp = mtod(mp, caddr_t);
664 ("len %d, corrupted mbuf?", len));
666 xfer = (left > len) ? len : left;
669 if (uiop->uio_iov->iov_op != NULL)
670 (*(uiop->uio_iov->iov_op))
671 (mbufcp, uiocp, xfer);
674 if (uiop->uio_segflg == UIO_SYSSPACE)
675 NFSBCOPY(mbufcp, uiocp, xfer);
677 copyout(mbufcp, uiocp, xfer);
682 uiop->uio_offset += xfer;
683 uiop->uio_resid -= xfer;
685 if (uiop->uio_iov->iov_len <= siz) {
689 uiop->uio_iov->iov_base = (void *)
690 ((char *)uiop->uio_iov->iov_base + uiosiz);
691 uiop->uio_iov->iov_len -= uiosiz;
695 nd->nd_dpos = mbufcp;
699 error = nfsm_advance(nd, rem, len);
705 NFSEXITCODE2(error, nd);
711 * Help break down an mbuf chain by setting the first siz bytes contiguous
712 * pointed to by returned val.
713 * This is used by the macro NFSM_DISSECT for tough
717 nfsm_dissct(struct nfsrv_descript *nd, int siz, int how)
726 left = mtod(nd->nd_md, caddr_t) + nd->nd_md->m_len - nd->nd_dpos;
728 nd->nd_md = nd->nd_md->m_next;
729 if (nd->nd_md == NULL)
731 left = nd->nd_md->m_len;
732 nd->nd_dpos = mtod(nd->nd_md, caddr_t);
737 } else if (nd->nd_md->m_next == NULL) {
739 } else if (siz > ncl_mbuf_mhlen) {
740 panic("nfs S too big");
742 MGET(mp2, MT_DATA, how);
745 mp2->m_next = nd->nd_md->m_next;
746 nd->nd_md->m_next = mp2;
747 nd->nd_md->m_len -= left;
749 retp = p = mtod(mp2, caddr_t);
750 NFSBCOPY(nd->nd_dpos, p, left); /* Copy what was left */
754 /* Loop around copying up the siz2 bytes */
758 xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2;
760 NFSBCOPY(mtod(mp2, caddr_t), p, xfer);
769 nd->nd_md->m_len = siz;
771 nd->nd_dpos = mtod(mp2, caddr_t);
777 * Advance the position in the mbuf chain.
778 * If offs == 0, this is a no-op, but it is simpler to just return from
779 * here than check for offs > 0 for all calls to nfsm_advance.
780 * If left == -1, it should be calculated here.
783 nfsm_advance(struct nfsrv_descript *nd, int offs, int left)
790 * A negative offs might indicate a corrupted mbuf chain and,
791 * as such, a printf is logged.
794 printf("nfsrv_advance: negative offs\n");
800 * If left == -1, calculate it here.
803 left = mtod(nd->nd_md, caddr_t) + nd->nd_md->m_len -
807 * Loop around, advancing over the mbuf data.
809 while (offs > left) {
811 nd->nd_md = nd->nd_md->m_next;
812 if (nd->nd_md == NULL) {
816 left = nd->nd_md->m_len;
817 nd->nd_dpos = mtod(nd->nd_md, caddr_t);
827 * Copy a string into mbuf(s).
828 * Return the number of bytes output, including XDR overheads.
831 nfsm_strtom(struct nfsrv_descript *nd, const char *cp, int siz)
840 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
841 *tl = txdr_unsigned(siz);
842 rem = NFSM_RNDUP(siz) - siz;
843 bytesize = NFSX_UNSIGNED + siz + rem;
846 if ((nd->nd_flag & ND_EXTPG) != 0)
847 left = nd->nd_bextpgsiz;
849 left = M_TRAILINGSPACE(m2);
851 KASSERT(((m2->m_flags & (M_EXT | M_EXTPG)) ==
852 (M_EXT | M_EXTPG) && (nd->nd_flag & ND_EXTPG) != 0) ||
853 ((m2->m_flags & (M_EXT | M_EXTPG)) !=
854 (M_EXT | M_EXTPG) && (nd->nd_flag & ND_EXTPG) == 0),
855 ("nfsm_strtom: ext_pgs and non-ext_pgs mbufs mixed"));
857 * Loop around copying the string to mbuf(s).
861 if ((nd->nd_flag & ND_EXTPG) != 0) {
862 m2 = nfsm_add_ext_pgs(m2,
863 nd->nd_maxextsiz, &nd->nd_bextpg);
864 cp2 = (char *)(void *)PHYS_TO_DMAP(
865 m2->m_epg_pa[nd->nd_bextpg]);
866 nd->nd_bextpgsiz = left = PAGE_SIZE;
868 if (siz > ncl_mbuf_mlen)
869 NFSMCLGET(m1, M_WAITOK);
873 cp2 = mtod(m1, char *);
874 left = M_TRAILINGSPACE(m1);
883 NFSBCOPY(cp, cp2, xfer);
889 if ((nd->nd_flag & ND_EXTPG) != 0) {
890 nd->nd_bextpgsiz -= xfer;
891 m2->m_epg_last_len += xfer;
893 if (siz == 0 && rem) {
895 panic("nfsm_strtom");
899 if ((nd->nd_flag & ND_EXTPG) != 0) {
900 nd->nd_bextpgsiz -= rem;
901 m2->m_epg_last_len += rem;
906 if ((nd->nd_flag & ND_EXTPG) != 0)
909 nd->nd_bpos = mtod(m2, char *) + m2->m_len;
914 * Called once to initialize data structures...
919 static int nfs_inited = 0;
925 newnfs_true = txdr_unsigned(TRUE);
926 newnfs_false = txdr_unsigned(FALSE);
927 newnfs_xdrneg1 = txdr_unsigned(-1);
928 nfscl_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
931 NFSSETBOOTTIME(nfsboottime);
934 * Initialize reply list and start timer
936 TAILQ_INIT(&nfsd_reqq);
941 * Put a file handle in an mbuf list.
942 * If the size argument == 0, just use the default size.
943 * set_true == 1 if there should be an newnfs_true prepended on the file handle.
944 * Return the number of bytes output, including XDR overhead.
947 nfsm_fhtom(struct nfsrv_descript *nd, u_int8_t *fhp, int size, int set_true)
951 int fullsiz, rem, bytesize = 0;
955 switch (nd->nd_flag & (ND_NFSV2 | ND_NFSV3 | ND_NFSV4)) {
957 if (size > NFSX_V2FH)
958 panic("fh size > NFSX_V2FH for NFSv2");
959 NFSM_BUILD(cp, u_int8_t *, NFSX_V2FH);
960 NFSBCOPY(fhp, cp, size);
961 if (size < NFSX_V2FH)
962 NFSBZERO(cp + size, NFSX_V2FH - size);
963 bytesize = NFSX_V2FH;
967 fullsiz = NFSM_RNDUP(size);
968 rem = fullsiz - size;
970 bytesize = 2 * NFSX_UNSIGNED + fullsiz;
971 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
974 bytesize = NFSX_UNSIGNED + fullsiz;
976 (void) nfsm_strtom(nd, fhp, size);
983 * This function compares two net addresses by family and returns TRUE
984 * if they are the same host.
985 * If there is any doubt, return FALSE.
986 * The AF_INET family is handled as a special case so that address mbufs
987 * don't need to be saved to store "struct in_addr", which is only 4 bytes.
990 nfsaddr_match(int family, union nethostaddr *haddr, NFSSOCKADDR_T nam)
993 struct sockaddr_in *inetaddr;
999 inetaddr = NFSSOCKADDR(nam, struct sockaddr_in *);
1000 if (inetaddr->sin_family == AF_INET &&
1001 inetaddr->sin_addr.s_addr == haddr->had_inet.s_addr)
1008 struct sockaddr_in6 *inetaddr6;
1010 inetaddr6 = NFSSOCKADDR(nam, struct sockaddr_in6 *);
1011 /* XXX - should test sin6_scope_id ? */
1012 if (inetaddr6->sin6_family == AF_INET6 &&
1013 IN6_ARE_ADDR_EQUAL(&inetaddr6->sin6_addr,
1024 * Similar to the above, but takes to NFSSOCKADDR_T args.
1027 nfsaddr2_match(NFSSOCKADDR_T nam1, NFSSOCKADDR_T nam2)
1029 struct sockaddr_in *addr1, *addr2;
1030 struct sockaddr *inaddr;
1032 inaddr = NFSSOCKADDR(nam1, struct sockaddr *);
1033 switch (inaddr->sa_family) {
1035 addr1 = NFSSOCKADDR(nam1, struct sockaddr_in *);
1036 addr2 = NFSSOCKADDR(nam2, struct sockaddr_in *);
1037 if (addr2->sin_family == AF_INET &&
1038 addr1->sin_addr.s_addr == addr2->sin_addr.s_addr)
1044 struct sockaddr_in6 *inet6addr1, *inet6addr2;
1046 inet6addr1 = NFSSOCKADDR(nam1, struct sockaddr_in6 *);
1047 inet6addr2 = NFSSOCKADDR(nam2, struct sockaddr_in6 *);
1048 /* XXX - should test sin6_scope_id ? */
1049 if (inet6addr2->sin6_family == AF_INET6 &&
1050 IN6_ARE_ADDR_EQUAL(&inet6addr1->sin6_addr,
1051 &inet6addr2->sin6_addr))
1061 * Trim trailing data off the mbuf list being built.
1064 newnfs_trimtrailing(nd, mb, bpos)
1065 struct nfsrv_descript *nd;
1071 m_freem(mb->m_next);
1074 mb->m_len = bpos - mtod(mb, caddr_t);
1080 * Dissect a file handle on the client.
1083 nfsm_getfh(struct nfsrv_descript *nd, struct nfsfh **nfhpp)
1090 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
1091 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1092 if ((len = fxdr_unsigned(int, *tl)) <= 0 ||
1099 nfhp = malloc(sizeof (struct nfsfh) + len,
1101 error = nfsrv_mtostr(nd, nfhp->nfh_fh, len);
1103 free(nfhp, M_NFSFH);
1106 nfhp->nfh_len = len;
1109 NFSEXITCODE2(error, nd);
1114 * Break down the nfsv4 acl.
1115 * If the aclp == NULL or won't fit in an acl, just discard the acl info.
1118 nfsrv_dissectacl(struct nfsrv_descript *nd, NFSACL_T *aclp, int *aclerrp,
1119 int *aclsizep, __unused NFSPROC_T *p)
1123 int acecnt, error = 0, aceerr = 0, acesize;
1129 * Parse out the ace entries and expect them to conform to
1130 * what can be supported by R/W/X bits.
1132 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1133 aclsize = NFSX_UNSIGNED;
1134 acecnt = fxdr_unsigned(int, *tl);
1135 if (acecnt > ACL_MAX_ENTRIES)
1136 aceerr = NFSERR_ATTRNOTSUPP;
1137 if (nfsrv_useacl == 0)
1138 aceerr = NFSERR_ATTRNOTSUPP;
1139 for (i = 0; i < acecnt; i++) {
1140 if (aclp && !aceerr)
1141 error = nfsrv_dissectace(nd, &aclp->acl_entry[i],
1142 &aceerr, &acesize, p);
1144 error = nfsrv_skipace(nd, &acesize);
1149 if (aclp && !aceerr)
1150 aclp->acl_cnt = acecnt;
1154 *aclsizep = aclsize;
1156 NFSEXITCODE2(error, nd);
1161 * Skip over an NFSv4 ace entry. Just dissect the xdr and discard it.
1164 nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep)
1169 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1170 len = fxdr_unsigned(int, *(tl + 3));
1171 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
1173 *acesizep = NFSM_RNDUP(len) + (4 * NFSX_UNSIGNED);
1174 NFSEXITCODE2(error, nd);
1179 * Get attribute bits from an mbuf list.
1180 * Returns EBADRPC for a parsing error, 0 otherwise.
1181 * If the clearinvalid flag is set, clear the bits not supported.
1184 nfsrv_getattrbits(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp, int *cntp,
1191 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1192 cnt = fxdr_unsigned(int, *tl);
1194 error = NFSERR_BADXDR;
1197 if (cnt > NFSATTRBIT_MAXWORDS)
1198 outcnt = NFSATTRBIT_MAXWORDS;
1201 NFSZERO_ATTRBIT(attrbitp);
1203 NFSM_DISSECT(tl, u_int32_t *, outcnt * NFSX_UNSIGNED);
1204 for (i = 0; i < outcnt; i++)
1205 attrbitp->bits[i] = fxdr_unsigned(u_int32_t, *tl++);
1207 for (i = 0; i < (cnt - outcnt); i++) {
1208 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1209 if (retnotsupp != NULL && *tl != 0)
1210 *retnotsupp = NFSERR_ATTRNOTSUPP;
1213 *cntp = NFSX_UNSIGNED + (cnt * NFSX_UNSIGNED);
1215 NFSEXITCODE2(error, nd);
1220 * Get the attributes for V4.
1221 * If the compare flag is true, test for any attribute changes,
1222 * otherwise return the attribute values.
1223 * These attributes cover fields in "struct vattr", "struct statfs",
1224 * "struct nfsfsinfo", the file handle and the lease duration.
1225 * The value of retcmpp is set to 1 if all attributes are the same,
1227 * Returns EBADRPC if it can't be parsed, 0 otherwise.
1230 nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp,
1231 struct nfsvattr *nap, struct nfsfh **nfhpp, fhandle_t *fhp, int fhsize,
1232 struct nfsv3_pathconf *pc, struct statfs *sbp, struct nfsstatfs *sfp,
1233 struct nfsfsinfo *fsp, NFSACL_T *aclp, int compare, int *retcmpp,
1234 u_int32_t *leasep, u_int32_t *rderrp, NFSPROC_T *p, struct ucred *cred)
1237 int i = 0, j, k, l = 0, m, bitpos, attrsum = 0;
1238 int error, tfhsize, aceerr, attrsize, cnt, retnotsup;
1239 u_char *cp, *cp2, namestr[NFSV4_SMALLSTR + 1];
1240 nfsattrbit_t attrbits, retattrbits, checkattrbits;
1241 struct nfsfh *tnfhp;
1242 struct nfsreferral *refp;
1245 struct timespec temptime;
1248 u_int32_t freenum = 0, tuint;
1249 u_int64_t uquad = 0, thyp, thyp2;
1255 CTASSERT(sizeof(ino_t) == sizeof(uint64_t));
1258 error = nfsrv_getattrbits(nd, &attrbits, NULL, &retnotsup);
1260 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
1266 *retcmpp = retnotsup;
1269 * Just set default values to some of the important ones.
1272 nap->na_type = VREG;
1274 nap->na_rdev = (NFSDEV_T)0;
1275 nap->na_mtime.tv_sec = 0;
1276 nap->na_mtime.tv_nsec = 0;
1279 nap->na_blocksize = NFS_FABLKSIZE;
1282 sbp->f_bsize = NFS_FABLKSIZE;
1290 fsp->fs_rtmax = 8192;
1291 fsp->fs_rtpref = 8192;
1292 fsp->fs_maxname = NFS_MAXNAMLEN;
1293 fsp->fs_wtmax = 8192;
1294 fsp->fs_wtpref = 8192;
1295 fsp->fs_wtmult = NFS_FABLKSIZE;
1296 fsp->fs_dtpref = 8192;
1297 fsp->fs_maxfilesize = 0xffffffffffffffffull;
1298 fsp->fs_timedelta.tv_sec = 0;
1299 fsp->fs_timedelta.tv_nsec = 1;
1300 fsp->fs_properties = (NFSV3_FSFLINK | NFSV3_FSFSYMLINK |
1301 NFSV3_FSFHOMOGENEOUS | NFSV3_FSFCANSETTIME);
1304 pc->pc_linkmax = NFS_LINK_MAX;
1305 pc->pc_namemax = NAME_MAX;
1307 pc->pc_chownrestricted = 0;
1308 pc->pc_caseinsensitive = 0;
1309 pc->pc_casepreserving = 1;
1312 sfp->sf_ffiles = UINT64_MAX;
1313 sfp->sf_tfiles = UINT64_MAX;
1314 sfp->sf_afiles = UINT64_MAX;
1315 sfp->sf_fbytes = UINT64_MAX;
1316 sfp->sf_tbytes = UINT64_MAX;
1317 sfp->sf_abytes = UINT64_MAX;
1322 * Loop around getting the attributes.
1324 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1325 attrsize = fxdr_unsigned(int, *tl);
1326 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
1327 if (attrsum > attrsize) {
1328 error = NFSERR_BADXDR;
1331 if (NFSISSET_ATTRBIT(&attrbits, bitpos))
1333 case NFSATTRBIT_SUPPORTEDATTRS:
1335 if (compare || nap == NULL)
1336 error = nfsrv_getattrbits(nd, &retattrbits,
1339 error = nfsrv_getattrbits(nd, &nap->na_suppattr,
1343 if (compare && !(*retcmpp)) {
1344 NFSSETSUPP_ATTRBIT(&checkattrbits, nd);
1346 /* Some filesystem do not support NFSv4ACL */
1347 if (nfsrv_useacl == 0 || nfs_supportsnfsv4acls(vp) == 0) {
1348 NFSCLRBIT_ATTRBIT(&checkattrbits, NFSATTRBIT_ACL);
1349 NFSCLRBIT_ATTRBIT(&checkattrbits, NFSATTRBIT_ACLSUPPORT);
1351 if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
1353 *retcmpp = NFSERR_NOTSAME;
1357 case NFSATTRBIT_TYPE:
1358 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1361 if (nap->na_type != nfsv34tov_type(*tl))
1362 *retcmpp = NFSERR_NOTSAME;
1364 } else if (nap != NULL) {
1365 nap->na_type = nfsv34tov_type(*tl);
1367 attrsum += NFSX_UNSIGNED;
1369 case NFSATTRBIT_FHEXPIRETYPE:
1370 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1371 if (compare && !(*retcmpp)) {
1372 if (fxdr_unsigned(int, *tl) !=
1373 NFSV4FHTYPE_PERSISTENT)
1374 *retcmpp = NFSERR_NOTSAME;
1376 attrsum += NFSX_UNSIGNED;
1378 case NFSATTRBIT_CHANGE:
1379 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1382 if (nap->na_filerev != fxdr_hyper(tl))
1383 *retcmpp = NFSERR_NOTSAME;
1385 } else if (nap != NULL) {
1386 nap->na_filerev = fxdr_hyper(tl);
1388 attrsum += NFSX_HYPER;
1390 case NFSATTRBIT_SIZE:
1391 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1394 if (nap->na_size != fxdr_hyper(tl))
1395 *retcmpp = NFSERR_NOTSAME;
1397 } else if (nap != NULL) {
1398 nap->na_size = fxdr_hyper(tl);
1400 attrsum += NFSX_HYPER;
1402 case NFSATTRBIT_LINKSUPPORT:
1403 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1406 if (fsp->fs_properties & NFSV3_FSFLINK) {
1407 if (*tl == newnfs_false)
1408 *retcmpp = NFSERR_NOTSAME;
1410 if (*tl == newnfs_true)
1411 *retcmpp = NFSERR_NOTSAME;
1414 } else if (fsp != NULL) {
1415 if (*tl == newnfs_true)
1416 fsp->fs_properties |= NFSV3_FSFLINK;
1418 fsp->fs_properties &= ~NFSV3_FSFLINK;
1420 attrsum += NFSX_UNSIGNED;
1422 case NFSATTRBIT_SYMLINKSUPPORT:
1423 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1426 if (fsp->fs_properties & NFSV3_FSFSYMLINK) {
1427 if (*tl == newnfs_false)
1428 *retcmpp = NFSERR_NOTSAME;
1430 if (*tl == newnfs_true)
1431 *retcmpp = NFSERR_NOTSAME;
1434 } else if (fsp != NULL) {
1435 if (*tl == newnfs_true)
1436 fsp->fs_properties |= NFSV3_FSFSYMLINK;
1438 fsp->fs_properties &= ~NFSV3_FSFSYMLINK;
1440 attrsum += NFSX_UNSIGNED;
1442 case NFSATTRBIT_NAMEDATTR:
1443 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1444 if (compare && !(*retcmpp)) {
1445 if (*tl != newnfs_false)
1446 *retcmpp = NFSERR_NOTSAME;
1448 attrsum += NFSX_UNSIGNED;
1450 case NFSATTRBIT_FSID:
1451 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1452 thyp = fxdr_hyper(tl);
1454 thyp2 = fxdr_hyper(tl);
1456 if (*retcmpp == 0) {
1457 if (thyp != (u_int64_t)
1458 vp->v_mount->mnt_stat.f_fsid.val[0] ||
1459 thyp2 != (u_int64_t)
1460 vp->v_mount->mnt_stat.f_fsid.val[1])
1461 *retcmpp = NFSERR_NOTSAME;
1463 } else if (nap != NULL) {
1464 nap->na_filesid[0] = thyp;
1465 nap->na_filesid[1] = thyp2;
1467 attrsum += (4 * NFSX_UNSIGNED);
1469 case NFSATTRBIT_UNIQUEHANDLES:
1470 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1471 if (compare && !(*retcmpp)) {
1472 if (*tl != newnfs_true)
1473 *retcmpp = NFSERR_NOTSAME;
1475 attrsum += NFSX_UNSIGNED;
1477 case NFSATTRBIT_LEASETIME:
1478 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1480 if (fxdr_unsigned(int, *tl) != nfsrv_lease &&
1482 *retcmpp = NFSERR_NOTSAME;
1483 } else if (leasep != NULL) {
1484 *leasep = fxdr_unsigned(u_int32_t, *tl);
1486 attrsum += NFSX_UNSIGNED;
1488 case NFSATTRBIT_RDATTRERROR:
1489 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1492 *retcmpp = NFSERR_INVAL;
1493 } else if (rderrp != NULL) {
1494 *rderrp = fxdr_unsigned(u_int32_t, *tl);
1496 attrsum += NFSX_UNSIGNED;
1498 case NFSATTRBIT_ACL:
1501 if (nfsrv_useacl && nfs_supportsnfsv4acls(vp)) {
1504 naclp = acl_alloc(M_WAITOK);
1505 error = nfsrv_dissectacl(nd, naclp, &aceerr,
1511 if (aceerr || aclp == NULL ||
1512 nfsrv_compareacl(aclp, naclp))
1513 *retcmpp = NFSERR_NOTSAME;
1516 error = nfsrv_dissectacl(nd, NULL, &aceerr,
1518 *retcmpp = NFSERR_ATTRNOTSUPP;
1522 if (vp != NULL && aclp != NULL)
1523 error = nfsrv_dissectacl(nd, aclp, &aceerr,
1526 error = nfsrv_dissectacl(nd, NULL, &aceerr,
1534 case NFSATTRBIT_ACLSUPPORT:
1535 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1536 if (compare && !(*retcmpp)) {
1537 if (nfsrv_useacl && nfs_supportsnfsv4acls(vp)) {
1538 if (fxdr_unsigned(u_int32_t, *tl) !=
1540 *retcmpp = NFSERR_NOTSAME;
1542 *retcmpp = NFSERR_ATTRNOTSUPP;
1545 attrsum += NFSX_UNSIGNED;
1547 case NFSATTRBIT_ARCHIVE:
1548 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1549 if (compare && !(*retcmpp))
1550 *retcmpp = NFSERR_ATTRNOTSUPP;
1551 attrsum += NFSX_UNSIGNED;
1553 case NFSATTRBIT_CANSETTIME:
1554 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1557 if (fsp->fs_properties & NFSV3_FSFCANSETTIME) {
1558 if (*tl == newnfs_false)
1559 *retcmpp = NFSERR_NOTSAME;
1561 if (*tl == newnfs_true)
1562 *retcmpp = NFSERR_NOTSAME;
1565 } else if (fsp != NULL) {
1566 if (*tl == newnfs_true)
1567 fsp->fs_properties |= NFSV3_FSFCANSETTIME;
1569 fsp->fs_properties &= ~NFSV3_FSFCANSETTIME;
1571 attrsum += NFSX_UNSIGNED;
1573 case NFSATTRBIT_CASEINSENSITIVE:
1574 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1577 if (*tl != newnfs_false)
1578 *retcmpp = NFSERR_NOTSAME;
1580 } else if (pc != NULL) {
1581 pc->pc_caseinsensitive =
1582 fxdr_unsigned(u_int32_t, *tl);
1584 attrsum += NFSX_UNSIGNED;
1586 case NFSATTRBIT_CASEPRESERVING:
1587 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1590 if (*tl != newnfs_true)
1591 *retcmpp = NFSERR_NOTSAME;
1593 } else if (pc != NULL) {
1594 pc->pc_casepreserving =
1595 fxdr_unsigned(u_int32_t, *tl);
1597 attrsum += NFSX_UNSIGNED;
1599 case NFSATTRBIT_CHOWNRESTRICTED:
1600 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1603 if (*tl != newnfs_true)
1604 *retcmpp = NFSERR_NOTSAME;
1606 } else if (pc != NULL) {
1607 pc->pc_chownrestricted =
1608 fxdr_unsigned(u_int32_t, *tl);
1610 attrsum += NFSX_UNSIGNED;
1612 case NFSATTRBIT_FILEHANDLE:
1613 error = nfsm_getfh(nd, &tnfhp);
1616 tfhsize = tnfhp->nfh_len;
1619 !NFSRV_CMPFH(tnfhp->nfh_fh, tfhsize,
1621 *retcmpp = NFSERR_NOTSAME;
1622 free(tnfhp, M_NFSFH);
1623 } else if (nfhpp != NULL) {
1626 free(tnfhp, M_NFSFH);
1628 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(tfhsize));
1630 case NFSATTRBIT_FILEID:
1631 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1632 thyp = fxdr_hyper(tl);
1635 if (nap->na_fileid != thyp)
1636 *retcmpp = NFSERR_NOTSAME;
1638 } else if (nap != NULL)
1639 nap->na_fileid = thyp;
1640 attrsum += NFSX_HYPER;
1642 case NFSATTRBIT_FILESAVAIL:
1643 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1646 sfp->sf_afiles != fxdr_hyper(tl))
1647 *retcmpp = NFSERR_NOTSAME;
1648 } else if (sfp != NULL) {
1649 sfp->sf_afiles = fxdr_hyper(tl);
1651 attrsum += NFSX_HYPER;
1653 case NFSATTRBIT_FILESFREE:
1654 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1657 sfp->sf_ffiles != fxdr_hyper(tl))
1658 *retcmpp = NFSERR_NOTSAME;
1659 } else if (sfp != NULL) {
1660 sfp->sf_ffiles = fxdr_hyper(tl);
1662 attrsum += NFSX_HYPER;
1664 case NFSATTRBIT_FILESTOTAL:
1665 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1668 sfp->sf_tfiles != fxdr_hyper(tl))
1669 *retcmpp = NFSERR_NOTSAME;
1670 } else if (sfp != NULL) {
1671 sfp->sf_tfiles = fxdr_hyper(tl);
1673 attrsum += NFSX_HYPER;
1675 case NFSATTRBIT_FSLOCATIONS:
1676 error = nfsrv_getrefstr(nd, &cp, &cp2, &l, &m);
1680 if (compare && !(*retcmpp)) {
1681 refp = nfsv4root_getreferral(vp, NULL, 0);
1683 if (cp == NULL || cp2 == NULL ||
1685 strcmp(cp2, refp->nfr_srvlist))
1686 *retcmpp = NFSERR_NOTSAME;
1687 } else if (m == 0) {
1688 *retcmpp = NFSERR_NOTSAME;
1692 free(cp, M_NFSSTRING);
1694 free(cp2, M_NFSSTRING);
1696 case NFSATTRBIT_HIDDEN:
1697 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1698 if (compare && !(*retcmpp))
1699 *retcmpp = NFSERR_ATTRNOTSUPP;
1700 attrsum += NFSX_UNSIGNED;
1702 case NFSATTRBIT_HOMOGENEOUS:
1703 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1706 if (fsp->fs_properties &
1707 NFSV3_FSFHOMOGENEOUS) {
1708 if (*tl == newnfs_false)
1709 *retcmpp = NFSERR_NOTSAME;
1711 if (*tl == newnfs_true)
1712 *retcmpp = NFSERR_NOTSAME;
1715 } else if (fsp != NULL) {
1716 if (*tl == newnfs_true)
1717 fsp->fs_properties |= NFSV3_FSFHOMOGENEOUS;
1719 fsp->fs_properties &= ~NFSV3_FSFHOMOGENEOUS;
1721 attrsum += NFSX_UNSIGNED;
1723 case NFSATTRBIT_MAXFILESIZE:
1724 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1725 tnfsquad.qval = fxdr_hyper(tl);
1728 tquad = NFSRV_MAXFILESIZE;
1729 if (tquad != tnfsquad.qval)
1730 *retcmpp = NFSERR_NOTSAME;
1732 } else if (fsp != NULL) {
1733 fsp->fs_maxfilesize = tnfsquad.qval;
1735 attrsum += NFSX_HYPER;
1737 case NFSATTRBIT_MAXLINK:
1738 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1741 if (fxdr_unsigned(int, *tl) != NFS_LINK_MAX)
1742 *retcmpp = NFSERR_NOTSAME;
1744 } else if (pc != NULL) {
1745 pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl);
1747 attrsum += NFSX_UNSIGNED;
1749 case NFSATTRBIT_MAXNAME:
1750 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1753 if (fsp->fs_maxname !=
1754 fxdr_unsigned(u_int32_t, *tl))
1755 *retcmpp = NFSERR_NOTSAME;
1758 tuint = fxdr_unsigned(u_int32_t, *tl);
1760 * Some Linux NFSv4 servers report this
1761 * as 0 or 4billion, so I'll set it to
1762 * NFS_MAXNAMLEN. If a server actually creates
1763 * a name longer than NFS_MAXNAMLEN, it will
1764 * get an error back.
1766 if (tuint == 0 || tuint > NFS_MAXNAMLEN)
1767 tuint = NFS_MAXNAMLEN;
1769 fsp->fs_maxname = tuint;
1771 pc->pc_namemax = tuint;
1773 attrsum += NFSX_UNSIGNED;
1775 case NFSATTRBIT_MAXREAD:
1776 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1779 if (fsp->fs_rtmax != fxdr_unsigned(u_int32_t,
1780 *(tl + 1)) || *tl != 0)
1781 *retcmpp = NFSERR_NOTSAME;
1783 } else if (fsp != NULL) {
1784 fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *++tl);
1785 fsp->fs_rtpref = fsp->fs_rtmax;
1786 fsp->fs_dtpref = fsp->fs_rtpref;
1788 attrsum += NFSX_HYPER;
1790 case NFSATTRBIT_MAXWRITE:
1791 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1794 if (fsp->fs_wtmax != fxdr_unsigned(u_int32_t,
1795 *(tl + 1)) || *tl != 0)
1796 *retcmpp = NFSERR_NOTSAME;
1798 } else if (fsp != NULL) {
1799 fsp->fs_wtmax = fxdr_unsigned(int, *++tl);
1800 fsp->fs_wtpref = fsp->fs_wtmax;
1802 attrsum += NFSX_HYPER;
1804 case NFSATTRBIT_MIMETYPE:
1805 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1806 i = fxdr_unsigned(int, *tl);
1807 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(i));
1808 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
1811 if (compare && !(*retcmpp))
1812 *retcmpp = NFSERR_ATTRNOTSUPP;
1814 case NFSATTRBIT_MODE:
1815 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1818 if (nap->na_mode != nfstov_mode(*tl))
1819 *retcmpp = NFSERR_NOTSAME;
1821 } else if (nap != NULL) {
1822 nap->na_mode = nfstov_mode(*tl);
1824 attrsum += NFSX_UNSIGNED;
1826 case NFSATTRBIT_NOTRUNC:
1827 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1830 if (*tl != newnfs_true)
1831 *retcmpp = NFSERR_NOTSAME;
1833 } else if (pc != NULL) {
1834 pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl);
1836 attrsum += NFSX_UNSIGNED;
1838 case NFSATTRBIT_NUMLINKS:
1839 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1840 tuint = fxdr_unsigned(u_int32_t, *tl);
1843 if ((u_int32_t)nap->na_nlink != tuint)
1844 *retcmpp = NFSERR_NOTSAME;
1846 } else if (nap != NULL) {
1847 nap->na_nlink = tuint;
1849 attrsum += NFSX_UNSIGNED;
1851 case NFSATTRBIT_OWNER:
1852 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1853 j = fxdr_unsigned(int, *tl);
1855 error = NFSERR_BADXDR;
1858 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1859 if (j > NFSV4_SMALLSTR)
1860 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1863 error = nfsrv_mtostr(nd, cp, j);
1865 if (j > NFSV4_SMALLSTR)
1866 free(cp, M_NFSSTRING);
1871 if (nfsv4_strtouid(nd, cp, j, &uid) ||
1873 *retcmpp = NFSERR_NOTSAME;
1875 } else if (nap != NULL) {
1876 if (nfsv4_strtouid(nd, cp, j, &uid))
1877 nap->na_uid = nfsrv_defaultuid;
1881 if (j > NFSV4_SMALLSTR)
1882 free(cp, M_NFSSTRING);
1884 case NFSATTRBIT_OWNERGROUP:
1885 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1886 j = fxdr_unsigned(int, *tl);
1888 error = NFSERR_BADXDR;
1891 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1892 if (j > NFSV4_SMALLSTR)
1893 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1896 error = nfsrv_mtostr(nd, cp, j);
1898 if (j > NFSV4_SMALLSTR)
1899 free(cp, M_NFSSTRING);
1904 if (nfsv4_strtogid(nd, cp, j, &gid) ||
1906 *retcmpp = NFSERR_NOTSAME;
1908 } else if (nap != NULL) {
1909 if (nfsv4_strtogid(nd, cp, j, &gid))
1910 nap->na_gid = nfsrv_defaultgid;
1914 if (j > NFSV4_SMALLSTR)
1915 free(cp, M_NFSSTRING);
1917 case NFSATTRBIT_QUOTAHARD:
1918 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1920 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA))
1921 freenum = sbp->f_bfree;
1923 freenum = sbp->f_bavail;
1926 * ufs_quotactl() insists that the uid argument
1927 * equal p_ruid for non-root quota access, so
1928 * we'll just make sure that's the case.
1930 savuid = p->p_cred->p_ruid;
1931 p->p_cred->p_ruid = cred->cr_uid;
1932 if (!VFS_QUOTACTL(vp->v_mount,QCMD(Q_GETQUOTA,
1933 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1934 freenum = min(dqb.dqb_bhardlimit, freenum);
1935 p->p_cred->p_ruid = savuid;
1937 uquad = (u_int64_t)freenum;
1938 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1940 if (compare && !(*retcmpp)) {
1941 if (uquad != fxdr_hyper(tl))
1942 *retcmpp = NFSERR_NOTSAME;
1944 attrsum += NFSX_HYPER;
1946 case NFSATTRBIT_QUOTASOFT:
1947 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1949 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA))
1950 freenum = sbp->f_bfree;
1952 freenum = sbp->f_bavail;
1955 * ufs_quotactl() insists that the uid argument
1956 * equal p_ruid for non-root quota access, so
1957 * we'll just make sure that's the case.
1959 savuid = p->p_cred->p_ruid;
1960 p->p_cred->p_ruid = cred->cr_uid;
1961 if (!VFS_QUOTACTL(vp->v_mount,QCMD(Q_GETQUOTA,
1962 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1963 freenum = min(dqb.dqb_bsoftlimit, freenum);
1964 p->p_cred->p_ruid = savuid;
1966 uquad = (u_int64_t)freenum;
1967 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1969 if (compare && !(*retcmpp)) {
1970 if (uquad != fxdr_hyper(tl))
1971 *retcmpp = NFSERR_NOTSAME;
1973 attrsum += NFSX_HYPER;
1975 case NFSATTRBIT_QUOTAUSED:
1976 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1981 * ufs_quotactl() insists that the uid argument
1982 * equal p_ruid for non-root quota access, so
1983 * we'll just make sure that's the case.
1985 savuid = p->p_cred->p_ruid;
1986 p->p_cred->p_ruid = cred->cr_uid;
1987 if (!VFS_QUOTACTL(vp->v_mount,QCMD(Q_GETQUOTA,
1988 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1989 freenum = dqb.dqb_curblocks;
1990 p->p_cred->p_ruid = savuid;
1992 uquad = (u_int64_t)freenum;
1993 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1995 if (compare && !(*retcmpp)) {
1996 if (uquad != fxdr_hyper(tl))
1997 *retcmpp = NFSERR_NOTSAME;
1999 attrsum += NFSX_HYPER;
2001 case NFSATTRBIT_RAWDEV:
2002 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4SPECDATA);
2003 j = fxdr_unsigned(int, *tl++);
2004 k = fxdr_unsigned(int, *tl);
2007 if (nap->na_rdev != NFSMAKEDEV(j, k))
2008 *retcmpp = NFSERR_NOTSAME;
2010 } else if (nap != NULL) {
2011 nap->na_rdev = NFSMAKEDEV(j, k);
2013 attrsum += NFSX_V4SPECDATA;
2015 case NFSATTRBIT_SPACEAVAIL:
2016 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2019 sfp->sf_abytes != fxdr_hyper(tl))
2020 *retcmpp = NFSERR_NOTSAME;
2021 } else if (sfp != NULL) {
2022 sfp->sf_abytes = fxdr_hyper(tl);
2024 attrsum += NFSX_HYPER;
2026 case NFSATTRBIT_SPACEFREE:
2027 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2030 sfp->sf_fbytes != fxdr_hyper(tl))
2031 *retcmpp = NFSERR_NOTSAME;
2032 } else if (sfp != NULL) {
2033 sfp->sf_fbytes = fxdr_hyper(tl);
2035 attrsum += NFSX_HYPER;
2037 case NFSATTRBIT_SPACETOTAL:
2038 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2041 sfp->sf_tbytes != fxdr_hyper(tl))
2042 *retcmpp = NFSERR_NOTSAME;
2043 } else if (sfp != NULL) {
2044 sfp->sf_tbytes = fxdr_hyper(tl);
2046 attrsum += NFSX_HYPER;
2048 case NFSATTRBIT_SPACEUSED:
2049 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2050 thyp = fxdr_hyper(tl);
2053 if ((u_int64_t)nap->na_bytes != thyp)
2054 *retcmpp = NFSERR_NOTSAME;
2056 } else if (nap != NULL) {
2057 nap->na_bytes = thyp;
2059 attrsum += NFSX_HYPER;
2061 case NFSATTRBIT_SYSTEM:
2062 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2063 if (compare && !(*retcmpp))
2064 *retcmpp = NFSERR_ATTRNOTSUPP;
2065 attrsum += NFSX_UNSIGNED;
2067 case NFSATTRBIT_TIMEACCESS:
2068 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2069 fxdr_nfsv4time(tl, &temptime);
2072 if (!NFS_CMPTIME(temptime, nap->na_atime))
2073 *retcmpp = NFSERR_NOTSAME;
2075 } else if (nap != NULL) {
2076 nap->na_atime = temptime;
2078 attrsum += NFSX_V4TIME;
2080 case NFSATTRBIT_TIMEACCESSSET:
2081 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2082 attrsum += NFSX_UNSIGNED;
2083 i = fxdr_unsigned(int, *tl);
2084 if (i == NFSV4SATTRTIME_TOCLIENT) {
2085 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2086 attrsum += NFSX_V4TIME;
2088 if (compare && !(*retcmpp))
2089 *retcmpp = NFSERR_INVAL;
2091 case NFSATTRBIT_TIMEBACKUP:
2092 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2093 if (compare && !(*retcmpp))
2094 *retcmpp = NFSERR_ATTRNOTSUPP;
2095 attrsum += NFSX_V4TIME;
2097 case NFSATTRBIT_TIMECREATE:
2098 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2099 fxdr_nfsv4time(tl, &temptime);
2102 if (!NFS_CMPTIME(temptime, nap->na_btime))
2103 *retcmpp = NFSERR_NOTSAME;
2105 } else if (nap != NULL) {
2106 nap->na_btime = temptime;
2108 attrsum += NFSX_V4TIME;
2110 case NFSATTRBIT_TIMEDELTA:
2111 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2115 if ((u_int32_t)fsp->fs_timedelta.tv_sec !=
2116 fxdr_unsigned(u_int32_t, *(tl + 1)) ||
2117 (u_int32_t)fsp->fs_timedelta.tv_nsec !=
2118 (fxdr_unsigned(u_int32_t, *(tl + 2)) %
2121 *retcmpp = NFSERR_NOTSAME;
2124 fxdr_nfsv4time(tl, &fsp->fs_timedelta);
2127 attrsum += NFSX_V4TIME;
2129 case NFSATTRBIT_TIMEMETADATA:
2130 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2131 fxdr_nfsv4time(tl, &temptime);
2134 if (!NFS_CMPTIME(temptime, nap->na_ctime))
2135 *retcmpp = NFSERR_NOTSAME;
2137 } else if (nap != NULL) {
2138 nap->na_ctime = temptime;
2140 attrsum += NFSX_V4TIME;
2142 case NFSATTRBIT_TIMEMODIFY:
2143 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2144 fxdr_nfsv4time(tl, &temptime);
2147 if (!NFS_CMPTIME(temptime, nap->na_mtime))
2148 *retcmpp = NFSERR_NOTSAME;
2150 } else if (nap != NULL) {
2151 nap->na_mtime = temptime;
2153 attrsum += NFSX_V4TIME;
2155 case NFSATTRBIT_TIMEMODIFYSET:
2156 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2157 attrsum += NFSX_UNSIGNED;
2158 i = fxdr_unsigned(int, *tl);
2159 if (i == NFSV4SATTRTIME_TOCLIENT) {
2160 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2161 attrsum += NFSX_V4TIME;
2163 if (compare && !(*retcmpp))
2164 *retcmpp = NFSERR_INVAL;
2166 case NFSATTRBIT_MOUNTEDONFILEID:
2167 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2168 thyp = fxdr_hyper(tl);
2171 if (!vp || !nfsrv_atroot(vp, &thyp2))
2172 thyp2 = nap->na_fileid;
2174 *retcmpp = NFSERR_NOTSAME;
2176 } else if (nap != NULL)
2177 nap->na_mntonfileno = thyp;
2178 attrsum += NFSX_HYPER;
2180 case NFSATTRBIT_SUPPATTREXCLCREAT:
2182 error = nfsrv_getattrbits(nd, &retattrbits,
2186 if (compare && !(*retcmpp)) {
2187 NFSSETSUPP_ATTRBIT(&checkattrbits, nd);
2188 NFSCLRNOTSETABLE_ATTRBIT(&checkattrbits, nd);
2189 NFSCLRBIT_ATTRBIT(&checkattrbits,
2190 NFSATTRBIT_TIMEACCESSSET);
2191 if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
2193 *retcmpp = NFSERR_NOTSAME;
2197 case NFSATTRBIT_FSLAYOUTTYPE:
2198 case NFSATTRBIT_LAYOUTTYPE:
2199 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2200 attrsum += NFSX_UNSIGNED;
2201 i = fxdr_unsigned(int, *tl);
2203 NFSM_DISSECT(tl, u_int32_t *, i *
2205 attrsum += i * NFSX_UNSIGNED;
2206 j = fxdr_unsigned(int, *tl);
2207 if (i == 1 && compare && !(*retcmpp) &&
2208 (((nfsrv_doflexfile != 0 ||
2209 nfsrv_maxpnfsmirror > 1) &&
2210 j != NFSLAYOUT_FLEXFILE) ||
2211 (nfsrv_doflexfile == 0 &&
2212 j != NFSLAYOUT_NFSV4_1_FILES)))
2213 *retcmpp = NFSERR_NOTSAME;
2215 if (nfsrv_devidcnt == 0) {
2216 if (compare && !(*retcmpp) && i > 0)
2217 *retcmpp = NFSERR_NOTSAME;
2219 if (compare && !(*retcmpp) && i != 1)
2220 *retcmpp = NFSERR_NOTSAME;
2223 case NFSATTRBIT_LAYOUTALIGNMENT:
2224 case NFSATTRBIT_LAYOUTBLKSIZE:
2225 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2226 attrsum += NFSX_UNSIGNED;
2227 i = fxdr_unsigned(int, *tl);
2228 if (compare && !(*retcmpp) && i != NFS_SRVMAXIO)
2229 *retcmpp = NFSERR_NOTSAME;
2232 printf("EEK! nfsv4_loadattr unknown attr=%d\n",
2234 if (compare && !(*retcmpp))
2235 *retcmpp = NFSERR_ATTRNOTSUPP;
2237 * and get out of the loop, since we can't parse
2238 * the unknown attrbute data.
2240 bitpos = NFSATTRBIT_MAX;
2246 * some clients pad the attrlist, so we need to skip over the
2249 if (attrsum > attrsize) {
2250 error = NFSERR_BADXDR;
2252 attrsize = NFSM_RNDUP(attrsize);
2253 if (attrsum < attrsize)
2254 error = nfsm_advance(nd, attrsize - attrsum, -1);
2257 NFSEXITCODE2(error, nd);
2262 * Implement sleep locks for newnfs. The nfslock_usecnt allows for a
2263 * shared lock and the NFSXXX_LOCK flag permits an exclusive lock.
2264 * The first argument is a pointer to an nfsv4lock structure.
2265 * The second argument is 1 iff a blocking lock is wanted.
2266 * If this argument is 0, the call waits until no thread either wants nor
2267 * holds an exclusive lock.
2268 * It returns 1 if the lock was acquired, 0 otherwise.
2269 * If several processes call this function concurrently wanting the exclusive
2270 * lock, one will get the lock and the rest will return without getting the
2271 * lock. (If the caller must have the lock, it simply calls this function in a
2272 * loop until the function returns 1 to indicate the lock was acquired.)
2273 * Any usecnt must be decremented by calling nfsv4_relref() before
2274 * calling nfsv4_lock(). It was done this way, so nfsv4_lock() could
2275 * be called in a loop.
2276 * The isleptp argument is set to indicate if the call slept, iff not NULL
2277 * and the mp argument indicates to check for a forced dismount, iff not
2281 nfsv4_lock(struct nfsv4lock *lp, int iwantlock, int *isleptp,
2282 void *mutex, struct mount *mp)
2288 * If a lock is wanted, loop around until the lock is acquired by
2289 * someone and then released. If I want the lock, try to acquire it.
2290 * For a lock to be issued, no lock must be in force and the usecnt
2294 if (!(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
2295 lp->nfslock_usecnt == 0) {
2296 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
2297 lp->nfslock_lock |= NFSV4LOCK_LOCK;
2300 lp->nfslock_lock |= NFSV4LOCK_LOCKWANTED;
2302 while (lp->nfslock_lock & (NFSV4LOCK_LOCK | NFSV4LOCK_LOCKWANTED)) {
2303 if (mp != NULL && NFSCL_FORCEDISM(mp)) {
2304 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
2307 lp->nfslock_lock |= NFSV4LOCK_WANTED;
2310 (void) nfsmsleep(&lp->nfslock_lock, mutex,
2311 PZERO - 1, "nfsv4lck", NULL);
2312 if (iwantlock && !(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
2313 lp->nfslock_usecnt == 0) {
2314 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
2315 lp->nfslock_lock |= NFSV4LOCK_LOCK;
2323 * Release the lock acquired by nfsv4_lock().
2324 * The second argument is set to 1 to indicate the nfslock_usecnt should be
2325 * incremented, as well.
2328 nfsv4_unlock(struct nfsv4lock *lp, int incref)
2331 lp->nfslock_lock &= ~NFSV4LOCK_LOCK;
2333 lp->nfslock_usecnt++;
2338 * Release a reference cnt.
2341 nfsv4_relref(struct nfsv4lock *lp)
2344 if (lp->nfslock_usecnt <= 0)
2345 panic("nfsv4root ref cnt");
2346 lp->nfslock_usecnt--;
2347 if (lp->nfslock_usecnt == 0)
2352 * Get a reference cnt.
2353 * This function will wait for any exclusive lock to be released, but will
2354 * not wait for threads that want the exclusive lock. If priority needs
2355 * to be given to threads that need the exclusive lock, a call to nfsv4_lock()
2356 * with the 2nd argument == 0 should be done before calling nfsv4_getref().
2357 * If the mp argument is not NULL, check for NFSCL_FORCEDISM() being set and
2358 * return without getting a refcnt for that case.
2361 nfsv4_getref(struct nfsv4lock *lp, int *isleptp, void *mutex,
2369 * Wait for a lock held.
2371 while (lp->nfslock_lock & NFSV4LOCK_LOCK) {
2372 if (mp != NULL && NFSCL_FORCEDISM(mp))
2374 lp->nfslock_lock |= NFSV4LOCK_WANTED;
2377 (void) nfsmsleep(&lp->nfslock_lock, mutex,
2378 PZERO - 1, "nfsv4gr", NULL);
2380 if (mp != NULL && NFSCL_FORCEDISM(mp))
2383 lp->nfslock_usecnt++;
2387 * Get a reference as above, but return failure instead of sleeping if
2388 * an exclusive lock is held.
2391 nfsv4_getref_nonblock(struct nfsv4lock *lp)
2394 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) != 0)
2397 lp->nfslock_usecnt++;
2402 * Test for a lock. Return 1 if locked, 0 otherwise.
2405 nfsv4_testlock(struct nfsv4lock *lp)
2408 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) == 0 &&
2409 lp->nfslock_usecnt == 0)
2415 * Wake up anyone sleeping, waiting for this lock.
2418 nfsv4_wanted(struct nfsv4lock *lp)
2421 if (lp->nfslock_lock & NFSV4LOCK_WANTED) {
2422 lp->nfslock_lock &= ~NFSV4LOCK_WANTED;
2423 wakeup((caddr_t)&lp->nfslock_lock);
2428 * Copy a string from an mbuf list into a character array.
2429 * Return EBADRPC if there is an mbuf error,
2433 nfsrv_mtostr(struct nfsrv_descript *nd, char *str, int siz)
2442 len = mtod(mp, caddr_t) + mp->m_len - cp;
2443 rem = NFSM_RNDUP(siz) - siz;
2449 NFSBCOPY(cp, str, xfer);
2458 cp = mtod(mp, caddr_t);
2470 error = nfsm_advance(nd, rem, len);
2476 NFSEXITCODE2(error, nd);
2481 * Fill in the attributes as marked by the bitmap (V4).
2484 nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp,
2485 NFSACL_T *saclp, struct vattr *vap, fhandle_t *fhp, int rderror,
2486 nfsattrbit_t *attrbitp, struct ucred *cred, NFSPROC_T *p, int isdgram,
2487 int reterr, int supports_nfsv4acls, int at_root, uint64_t mounted_on_fileno,
2488 struct statfs *pnfssf)
2490 int bitpos, retnum = 0;
2492 int siz, prefixnum, error;
2493 u_char *cp, namestr[NFSV4_SMALLSTR];
2494 nfsattrbit_t attrbits, retbits;
2495 nfsattrbit_t *retbitp = &retbits;
2496 u_int32_t freenum, *retnump;
2499 struct nfsfsinfo fsinf;
2500 struct timespec temptime;
2501 NFSACL_T *aclp, *naclp = NULL;
2510 * First, set the bits that can be filled and get fsinfo.
2512 NFSSET_ATTRBIT(retbitp, attrbitp);
2514 * If both p and cred are NULL, it is a client side setattr call.
2515 * If both p and cred are not NULL, it is a server side reply call.
2516 * If p is not NULL and cred is NULL, it is a client side callback
2519 if (p == NULL && cred == NULL) {
2520 NFSCLRNOTSETABLE_ATTRBIT(retbitp, nd);
2523 NFSCLRNOTFILLABLE_ATTRBIT(retbitp, nd);
2524 naclp = acl_alloc(M_WAITOK);
2527 nfsvno_getfs(&fsinf, isdgram);
2530 * Get the VFS_STATFS(), since some attributes need them.
2532 fs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
2533 if (NFSISSETSTATFS_ATTRBIT(retbitp)) {
2534 error = VFS_STATFS(mp, fs);
2537 nd->nd_repstat = NFSERR_ACCES;
2541 NFSCLRSTATFS_ATTRBIT(retbitp);
2547 * And the NFSv4 ACL...
2549 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT) &&
2550 (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2551 supports_nfsv4acls == 0))) {
2552 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT);
2554 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACL)) {
2555 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2556 supports_nfsv4acls == 0)) {
2557 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2558 } else if (naclp != NULL) {
2559 if (NFSVOPLOCK(vp, LK_SHARED) == 0) {
2560 error = VOP_ACCESSX(vp, VREAD_ACL, cred, p);
2562 error = VOP_GETACL(vp, ACL_TYPE_NFS4,
2566 error = NFSERR_PERM;
2569 nd->nd_repstat = NFSERR_ACCES;
2573 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2578 /* Check to see if Extended Attributes are supported. */
2580 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_XATTRSUPPORT)) {
2581 if (NFSVOPLOCK(vp, LK_SHARED) == 0) {
2582 error = VOP_GETEXTATTR(vp, EXTATTR_NAMESPACE_USER,
2583 "xxx", NULL, &atsiz, cred, p);
2585 if (error != EOPNOTSUPP)
2591 * Put out the attribute bitmap for the ones being filled in
2592 * and get the field for the number of attributes returned.
2594 prefixnum = nfsrv_putattrbit(nd, retbitp);
2595 NFSM_BUILD(retnump, u_int32_t *, NFSX_UNSIGNED);
2596 prefixnum += NFSX_UNSIGNED;
2599 * Now, loop around filling in the attributes for each bit set.
2601 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
2602 if (NFSISSET_ATTRBIT(retbitp, bitpos)) {
2604 case NFSATTRBIT_SUPPORTEDATTRS:
2605 NFSSETSUPP_ATTRBIT(&attrbits, nd);
2606 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL)
2607 && supports_nfsv4acls == 0)) {
2608 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACLSUPPORT);
2609 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACL);
2611 retnum += nfsrv_putattrbit(nd, &attrbits);
2613 case NFSATTRBIT_TYPE:
2614 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2615 *tl = vtonfsv34_type(vap->va_type);
2616 retnum += NFSX_UNSIGNED;
2618 case NFSATTRBIT_FHEXPIRETYPE:
2619 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2620 *tl = txdr_unsigned(NFSV4FHTYPE_PERSISTENT);
2621 retnum += NFSX_UNSIGNED;
2623 case NFSATTRBIT_CHANGE:
2624 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2625 txdr_hyper(vap->va_filerev, tl);
2626 retnum += NFSX_HYPER;
2628 case NFSATTRBIT_SIZE:
2629 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2630 txdr_hyper(vap->va_size, tl);
2631 retnum += NFSX_HYPER;
2633 case NFSATTRBIT_LINKSUPPORT:
2634 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2635 if (fsinf.fs_properties & NFSV3FSINFO_LINK)
2639 retnum += NFSX_UNSIGNED;
2641 case NFSATTRBIT_SYMLINKSUPPORT:
2642 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2643 if (fsinf.fs_properties & NFSV3FSINFO_SYMLINK)
2647 retnum += NFSX_UNSIGNED;
2649 case NFSATTRBIT_NAMEDATTR:
2650 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2652 retnum += NFSX_UNSIGNED;
2654 case NFSATTRBIT_FSID:
2655 NFSM_BUILD(tl, u_int32_t *, NFSX_V4FSID);
2657 *tl++ = txdr_unsigned(mp->mnt_stat.f_fsid.val[0]);
2659 *tl = txdr_unsigned(mp->mnt_stat.f_fsid.val[1]);
2660 retnum += NFSX_V4FSID;
2662 case NFSATTRBIT_UNIQUEHANDLES:
2663 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2665 retnum += NFSX_UNSIGNED;
2667 case NFSATTRBIT_LEASETIME:
2668 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2669 *tl = txdr_unsigned(nfsrv_lease);
2670 retnum += NFSX_UNSIGNED;
2672 case NFSATTRBIT_RDATTRERROR:
2673 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2674 *tl = txdr_unsigned(rderror);
2675 retnum += NFSX_UNSIGNED;
2678 * Recommended Attributes. (Only the supported ones.)
2680 case NFSATTRBIT_ACL:
2681 retnum += nfsrv_buildacl(nd, aclp, vnode_vtype(vp), p);
2683 case NFSATTRBIT_ACLSUPPORT:
2684 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2685 *tl = txdr_unsigned(NFSV4ACE_SUPTYPES);
2686 retnum += NFSX_UNSIGNED;
2688 case NFSATTRBIT_CANSETTIME:
2689 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2690 if (fsinf.fs_properties & NFSV3FSINFO_CANSETTIME)
2694 retnum += NFSX_UNSIGNED;
2696 case NFSATTRBIT_CASEINSENSITIVE:
2697 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2699 retnum += NFSX_UNSIGNED;
2701 case NFSATTRBIT_CASEPRESERVING:
2702 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2704 retnum += NFSX_UNSIGNED;
2706 case NFSATTRBIT_CHOWNRESTRICTED:
2707 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2709 retnum += NFSX_UNSIGNED;
2711 case NFSATTRBIT_FILEHANDLE:
2712 retnum += nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
2714 case NFSATTRBIT_FILEID:
2715 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2716 uquad = vap->va_fileid;
2717 txdr_hyper(uquad, tl);
2718 retnum += NFSX_HYPER;
2720 case NFSATTRBIT_FILESAVAIL:
2722 * Check quota and use min(quota, f_ffree).
2724 freenum = fs->f_ffree;
2727 * ufs_quotactl() insists that the uid argument
2728 * equal p_ruid for non-root quota access, so
2729 * we'll just make sure that's the case.
2731 savuid = p->p_cred->p_ruid;
2732 p->p_cred->p_ruid = cred->cr_uid;
2733 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2734 cred->cr_uid, (caddr_t)&dqb))
2735 freenum = min(dqb.dqb_isoftlimit-dqb.dqb_curinodes,
2737 p->p_cred->p_ruid = savuid;
2739 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2741 *tl = txdr_unsigned(freenum);
2742 retnum += NFSX_HYPER;
2744 case NFSATTRBIT_FILESFREE:
2745 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2747 *tl = txdr_unsigned(fs->f_ffree);
2748 retnum += NFSX_HYPER;
2750 case NFSATTRBIT_FILESTOTAL:
2751 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2753 *tl = txdr_unsigned(fs->f_files);
2754 retnum += NFSX_HYPER;
2756 case NFSATTRBIT_FSLOCATIONS:
2757 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2760 retnum += 2 * NFSX_UNSIGNED;
2762 case NFSATTRBIT_HOMOGENEOUS:
2763 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2764 if (fsinf.fs_properties & NFSV3FSINFO_HOMOGENEOUS)
2768 retnum += NFSX_UNSIGNED;
2770 case NFSATTRBIT_MAXFILESIZE:
2771 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2772 uquad = NFSRV_MAXFILESIZE;
2773 txdr_hyper(uquad, tl);
2774 retnum += NFSX_HYPER;
2776 case NFSATTRBIT_MAXLINK:
2777 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2778 *tl = txdr_unsigned(NFS_LINK_MAX);
2779 retnum += NFSX_UNSIGNED;
2781 case NFSATTRBIT_MAXNAME:
2782 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2783 *tl = txdr_unsigned(NFS_MAXNAMLEN);
2784 retnum += NFSX_UNSIGNED;
2786 case NFSATTRBIT_MAXREAD:
2787 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2789 *tl = txdr_unsigned(fsinf.fs_rtmax);
2790 retnum += NFSX_HYPER;
2792 case NFSATTRBIT_MAXWRITE:
2793 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2795 *tl = txdr_unsigned(fsinf.fs_wtmax);
2796 retnum += NFSX_HYPER;
2798 case NFSATTRBIT_MODE:
2799 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2800 *tl = vtonfsv34_mode(vap->va_mode);
2801 retnum += NFSX_UNSIGNED;
2803 case NFSATTRBIT_NOTRUNC:
2804 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2806 retnum += NFSX_UNSIGNED;
2808 case NFSATTRBIT_NUMLINKS:
2809 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2810 *tl = txdr_unsigned(vap->va_nlink);
2811 retnum += NFSX_UNSIGNED;
2813 case NFSATTRBIT_OWNER:
2815 nfsv4_uidtostr(vap->va_uid, &cp, &siz);
2816 retnum += nfsm_strtom(nd, cp, siz);
2818 free(cp, M_NFSSTRING);
2820 case NFSATTRBIT_OWNERGROUP:
2822 nfsv4_gidtostr(vap->va_gid, &cp, &siz);
2823 retnum += nfsm_strtom(nd, cp, siz);
2825 free(cp, M_NFSSTRING);
2827 case NFSATTRBIT_QUOTAHARD:
2828 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA))
2829 freenum = fs->f_bfree;
2831 freenum = fs->f_bavail;
2834 * ufs_quotactl() insists that the uid argument
2835 * equal p_ruid for non-root quota access, so
2836 * we'll just make sure that's the case.
2838 savuid = p->p_cred->p_ruid;
2839 p->p_cred->p_ruid = cred->cr_uid;
2840 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2841 cred->cr_uid, (caddr_t)&dqb))
2842 freenum = min(dqb.dqb_bhardlimit, freenum);
2843 p->p_cred->p_ruid = savuid;
2845 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2846 uquad = (u_int64_t)freenum;
2847 NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
2848 txdr_hyper(uquad, tl);
2849 retnum += NFSX_HYPER;
2851 case NFSATTRBIT_QUOTASOFT:
2852 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA))
2853 freenum = fs->f_bfree;
2855 freenum = fs->f_bavail;
2858 * ufs_quotactl() insists that the uid argument
2859 * equal p_ruid for non-root quota access, so
2860 * we'll just make sure that's the case.
2862 savuid = p->p_cred->p_ruid;
2863 p->p_cred->p_ruid = cred->cr_uid;
2864 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2865 cred->cr_uid, (caddr_t)&dqb))
2866 freenum = min(dqb.dqb_bsoftlimit, freenum);
2867 p->p_cred->p_ruid = savuid;
2869 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2870 uquad = (u_int64_t)freenum;
2871 NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
2872 txdr_hyper(uquad, tl);
2873 retnum += NFSX_HYPER;
2875 case NFSATTRBIT_QUOTAUSED:
2879 * ufs_quotactl() insists that the uid argument
2880 * equal p_ruid for non-root quota access, so
2881 * we'll just make sure that's the case.
2883 savuid = p->p_cred->p_ruid;
2884 p->p_cred->p_ruid = cred->cr_uid;
2885 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2886 cred->cr_uid, (caddr_t)&dqb))
2887 freenum = dqb.dqb_curblocks;
2888 p->p_cred->p_ruid = savuid;
2890 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2891 uquad = (u_int64_t)freenum;
2892 NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
2893 txdr_hyper(uquad, tl);
2894 retnum += NFSX_HYPER;
2896 case NFSATTRBIT_RAWDEV:
2897 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SPECDATA);
2898 *tl++ = txdr_unsigned(NFSMAJOR(vap->va_rdev));
2899 *tl = txdr_unsigned(NFSMINOR(vap->va_rdev));
2900 retnum += NFSX_V4SPECDATA;
2902 case NFSATTRBIT_SPACEAVAIL:
2903 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2904 if (priv_check_cred(cred, PRIV_VFS_BLOCKRESERVE)) {
2906 uquad = (u_int64_t)pnfssf->f_bfree;
2908 uquad = (u_int64_t)fs->f_bfree;
2911 uquad = (u_int64_t)pnfssf->f_bavail;
2913 uquad = (u_int64_t)fs->f_bavail;
2916 uquad *= pnfssf->f_bsize;
2918 uquad *= fs->f_bsize;
2919 txdr_hyper(uquad, tl);
2920 retnum += NFSX_HYPER;
2922 case NFSATTRBIT_SPACEFREE:
2923 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2924 if (pnfssf != NULL) {
2925 uquad = (u_int64_t)pnfssf->f_bfree;
2926 uquad *= pnfssf->f_bsize;
2928 uquad = (u_int64_t)fs->f_bfree;
2929 uquad *= fs->f_bsize;
2931 txdr_hyper(uquad, tl);
2932 retnum += NFSX_HYPER;
2934 case NFSATTRBIT_SPACETOTAL:
2935 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2936 if (pnfssf != NULL) {
2937 uquad = (u_int64_t)pnfssf->f_blocks;
2938 uquad *= pnfssf->f_bsize;
2940 uquad = (u_int64_t)fs->f_blocks;
2941 uquad *= fs->f_bsize;
2943 txdr_hyper(uquad, tl);
2944 retnum += NFSX_HYPER;
2946 case NFSATTRBIT_SPACEUSED:
2947 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2948 txdr_hyper(vap->va_bytes, tl);
2949 retnum += NFSX_HYPER;
2951 case NFSATTRBIT_TIMEACCESS:
2952 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2953 txdr_nfsv4time(&vap->va_atime, tl);
2954 retnum += NFSX_V4TIME;
2956 case NFSATTRBIT_TIMEACCESSSET:
2957 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2958 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2959 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2960 txdr_nfsv4time(&vap->va_atime, tl);
2961 retnum += NFSX_V4SETTIME;
2963 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2964 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2965 retnum += NFSX_UNSIGNED;
2968 case NFSATTRBIT_TIMEDELTA:
2969 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2970 temptime.tv_sec = 0;
2971 temptime.tv_nsec = 1000000000 / hz;
2972 txdr_nfsv4time(&temptime, tl);
2973 retnum += NFSX_V4TIME;
2975 case NFSATTRBIT_TIMEMETADATA:
2976 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2977 txdr_nfsv4time(&vap->va_ctime, tl);
2978 retnum += NFSX_V4TIME;
2980 case NFSATTRBIT_TIMEMODIFY:
2981 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2982 txdr_nfsv4time(&vap->va_mtime, tl);
2983 retnum += NFSX_V4TIME;
2985 case NFSATTRBIT_TIMECREATE:
2986 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2987 txdr_nfsv4time(&vap->va_birthtime, tl);
2988 retnum += NFSX_V4TIME;
2990 case NFSATTRBIT_TIMEMODIFYSET:
2991 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2992 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2993 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2994 txdr_nfsv4time(&vap->va_mtime, tl);
2995 retnum += NFSX_V4SETTIME;
2997 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2998 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2999 retnum += NFSX_UNSIGNED;
3002 case NFSATTRBIT_MOUNTEDONFILEID:
3003 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
3005 uquad = mounted_on_fileno;
3007 uquad = vap->va_fileid;
3008 txdr_hyper(uquad, tl);
3009 retnum += NFSX_HYPER;
3011 case NFSATTRBIT_SUPPATTREXCLCREAT:
3012 NFSSETSUPP_ATTRBIT(&attrbits, nd);
3013 NFSCLRNOTSETABLE_ATTRBIT(&attrbits, nd);
3014 NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET);
3015 retnum += nfsrv_putattrbit(nd, &attrbits);
3017 case NFSATTRBIT_FSLAYOUTTYPE:
3018 case NFSATTRBIT_LAYOUTTYPE:
3019 if (nfsrv_devidcnt == 0)
3024 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3025 *tl++ = txdr_unsigned(1); /* One entry. */
3026 if (nfsrv_doflexfile != 0 ||
3027 nfsrv_maxpnfsmirror > 1)
3028 *tl = txdr_unsigned(NFSLAYOUT_FLEXFILE);
3030 *tl = txdr_unsigned(
3031 NFSLAYOUT_NFSV4_1_FILES);
3033 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3036 retnum += siz * NFSX_UNSIGNED;
3038 case NFSATTRBIT_LAYOUTALIGNMENT:
3039 case NFSATTRBIT_LAYOUTBLKSIZE:
3040 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3041 *tl = txdr_unsigned(NFS_SRVMAXIO);
3042 retnum += NFSX_UNSIGNED;
3044 case NFSATTRBIT_XATTRSUPPORT:
3045 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3050 retnum += NFSX_UNSIGNED;
3053 printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos);
3060 *retnump = txdr_unsigned(retnum);
3061 return (retnum + prefixnum);
3065 * Put the attribute bits onto an mbuf list.
3066 * Return the number of bytes of output generated.
3069 nfsrv_putattrbit(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp)
3072 int cnt, i, bytesize;
3074 for (cnt = NFSATTRBIT_MAXWORDS; cnt > 0; cnt--)
3075 if (attrbitp->bits[cnt - 1])
3077 bytesize = (cnt + 1) * NFSX_UNSIGNED;
3078 NFSM_BUILD(tl, u_int32_t *, bytesize);
3079 *tl++ = txdr_unsigned(cnt);
3080 for (i = 0; i < cnt; i++)
3081 *tl++ = txdr_unsigned(attrbitp->bits[i]);
3086 * Convert a uid to a string.
3087 * If the lookup fails, just output the digits.
3089 * cpp - points to a buffer of size NFSV4_SMALLSTR
3090 * (malloc a larger one, as required)
3091 * retlenp - pointer to length to be returned
3094 nfsv4_uidtostr(uid_t uid, u_char **cpp, int *retlenp)
3097 struct nfsusrgrp *usrp;
3100 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
3101 struct nfsrv_lughash *hp;
3105 if (nfsrv_dnsnamelen > 0 && !nfs_enable_uidtostring) {
3107 * Always map nfsrv_defaultuid to "nobody".
3109 if (uid == nfsrv_defaultuid) {
3110 i = nfsrv_dnsnamelen + 7;
3112 if (len > NFSV4_SMALLSTR)
3113 free(cp, M_NFSSTRING);
3114 cp = malloc(i, M_NFSSTRING, M_WAITOK);
3120 NFSBCOPY("nobody@", cp, 7);
3122 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
3126 hp = NFSUSERHASH(uid);
3128 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
3129 if (usrp->lug_uid == uid) {
3130 if (usrp->lug_expiry < NFSD_MONOSEC)
3133 * If the name doesn't already have an '@'
3134 * in it, append @domainname to it.
3136 for (i = 0; i < usrp->lug_namelen; i++) {
3137 if (usrp->lug_name[i] == '@') {
3143 i = usrp->lug_namelen;
3145 i = usrp->lug_namelen +
3146 nfsrv_dnsnamelen + 1;
3148 mtx_unlock(&hp->mtx);
3149 if (len > NFSV4_SMALLSTR)
3150 free(cp, M_NFSSTRING);
3151 cp = malloc(i, M_NFSSTRING, M_WAITOK);
3157 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
3158 if (!hasampersand) {
3159 cp += usrp->lug_namelen;
3161 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
3163 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3164 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
3166 mtx_unlock(&hp->mtx);
3170 mtx_unlock(&hp->mtx);
3172 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0, NULL);
3173 if (ret == 0 && cnt < 2)
3178 * No match, just return a string of digits.
3182 while (tmp || i == 0) {
3186 len = (i > len) ? len : i;
3190 for (i = 0; i < len; i++) {
3191 *cp-- = '0' + (tmp % 10);
3198 * Get a credential for the uid with the server's group list.
3199 * If none is found, just return the credential passed in after
3200 * logging a warning message.
3203 nfsrv_getgrpscred(struct ucred *oldcred)
3205 struct nfsusrgrp *usrp;
3206 struct ucred *newcred;
3209 struct nfsrv_lughash *hp;
3212 uid = oldcred->cr_uid;
3214 if (nfsrv_dnsnamelen > 0) {
3215 hp = NFSUSERHASH(uid);
3217 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
3218 if (usrp->lug_uid == uid) {
3219 if (usrp->lug_expiry < NFSD_MONOSEC)
3221 if (usrp->lug_cred != NULL) {
3222 newcred = crhold(usrp->lug_cred);
3226 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3227 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
3229 mtx_unlock(&hp->mtx);
3233 mtx_unlock(&hp->mtx);
3235 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0, NULL);
3236 if (ret == 0 && cnt < 2)
3243 * Convert a string to a uid.
3244 * If no conversion is possible return NFSERR_BADOWNER, otherwise
3246 * If this is called from a client side mount using AUTH_SYS and the
3247 * string is made up entirely of digits, just convert the string to
3251 nfsv4_strtouid(struct nfsrv_descript *nd, u_char *str, int len, uid_t *uidp)
3254 char *cp, *endstr, *str0;
3255 struct nfsusrgrp *usrp;
3259 struct nfsrv_lughash *hp, *hp2;
3262 error = NFSERR_BADOWNER;
3265 /* If a string of digits and an AUTH_SYS mount, just convert it. */
3267 tuid = (uid_t)strtoul(str0, &endstr, 10);
3268 if ((endstr - str0) == len) {
3269 /* A numeric string. */
3270 if ((nd->nd_flag & ND_KERBV) == 0 &&
3271 ((nd->nd_flag & ND_NFSCL) != 0 ||
3272 nfsd_enable_stringtouid != 0))
3275 error = NFSERR_BADOWNER;
3281 cp = strchr(str0, '@');
3283 i = (int)(cp++ - str0);
3289 if (nfsrv_dnsnamelen > 0) {
3291 * If an '@' is found and the domain name matches, search for
3292 * the name with dns stripped off.
3293 * Mixed case alpahbetics will match for the domain name, but
3294 * all upper case will not.
3296 if (cnt == 0 && i < len && i > 0 &&
3297 (len - 1 - i) == nfsrv_dnsnamelen &&
3298 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
3299 len -= (nfsrv_dnsnamelen + 1);
3304 * Check for the special case of "nobody".
3306 if (len == 6 && !NFSBCMP(str, "nobody", 6)) {
3307 *uidp = nfsrv_defaultuid;
3312 hp = NFSUSERNAMEHASH(str, len);
3314 TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) {
3315 if (usrp->lug_namelen == len &&
3316 !NFSBCMP(usrp->lug_name, str, len)) {
3317 if (usrp->lug_expiry < NFSD_MONOSEC)
3319 hp2 = NFSUSERHASH(usrp->lug_uid);
3320 mtx_lock(&hp2->mtx);
3321 TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash);
3322 TAILQ_INSERT_TAIL(&hp2->lughead, usrp,
3324 *uidp = usrp->lug_uid;
3325 mtx_unlock(&hp2->mtx);
3326 mtx_unlock(&hp->mtx);
3331 mtx_unlock(&hp->mtx);
3333 ret = nfsrv_getuser(RPCNFSUSERD_GETUSER, (uid_t)0, (gid_t)0,
3335 if (ret == 0 && cnt < 2)
3338 error = NFSERR_BADOWNER;
3346 * Convert a gid to a string.
3347 * gid - the group id
3348 * cpp - points to a buffer of size NFSV4_SMALLSTR
3349 * (malloc a larger one, as required)
3350 * retlenp - pointer to length to be returned
3353 nfsv4_gidtostr(gid_t gid, u_char **cpp, int *retlenp)
3356 struct nfsusrgrp *usrp;
3359 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
3360 struct nfsrv_lughash *hp;
3364 if (nfsrv_dnsnamelen > 0 && !nfs_enable_uidtostring) {
3366 * Always map nfsrv_defaultgid to "nogroup".
3368 if (gid == nfsrv_defaultgid) {
3369 i = nfsrv_dnsnamelen + 8;
3371 if (len > NFSV4_SMALLSTR)
3372 free(cp, M_NFSSTRING);
3373 cp = malloc(i, M_NFSSTRING, M_WAITOK);
3379 NFSBCOPY("nogroup@", cp, 8);
3381 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
3385 hp = NFSGROUPHASH(gid);
3387 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
3388 if (usrp->lug_gid == gid) {
3389 if (usrp->lug_expiry < NFSD_MONOSEC)
3392 * If the name doesn't already have an '@'
3393 * in it, append @domainname to it.
3395 for (i = 0; i < usrp->lug_namelen; i++) {
3396 if (usrp->lug_name[i] == '@') {
3402 i = usrp->lug_namelen;
3404 i = usrp->lug_namelen +
3405 nfsrv_dnsnamelen + 1;
3407 mtx_unlock(&hp->mtx);
3408 if (len > NFSV4_SMALLSTR)
3409 free(cp, M_NFSSTRING);
3410 cp = malloc(i, M_NFSSTRING, M_WAITOK);
3416 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
3417 if (!hasampersand) {
3418 cp += usrp->lug_namelen;
3420 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
3422 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3423 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
3425 mtx_unlock(&hp->mtx);
3429 mtx_unlock(&hp->mtx);
3431 ret = nfsrv_getuser(RPCNFSUSERD_GETGID, (uid_t)0, gid, NULL);
3432 if (ret == 0 && cnt < 2)
3437 * No match, just return a string of digits.
3441 while (tmp || i == 0) {
3445 len = (i > len) ? len : i;
3449 for (i = 0; i < len; i++) {
3450 *cp-- = '0' + (tmp % 10);
3457 * Convert a string to a gid.
3458 * If no conversion is possible return NFSERR_BADOWNER, otherwise
3460 * If this is called from a client side mount using AUTH_SYS and the
3461 * string is made up entirely of digits, just convert the string to
3465 nfsv4_strtogid(struct nfsrv_descript *nd, u_char *str, int len, gid_t *gidp)
3468 char *cp, *endstr, *str0;
3469 struct nfsusrgrp *usrp;
3473 struct nfsrv_lughash *hp, *hp2;
3476 error = NFSERR_BADOWNER;
3479 /* If a string of digits and an AUTH_SYS mount, just convert it. */
3481 tgid = (gid_t)strtoul(str0, &endstr, 10);
3482 if ((endstr - str0) == len) {
3483 /* A numeric string. */
3484 if ((nd->nd_flag & ND_KERBV) == 0 &&
3485 ((nd->nd_flag & ND_NFSCL) != 0 ||
3486 nfsd_enable_stringtouid != 0))
3489 error = NFSERR_BADOWNER;
3495 cp = strchr(str0, '@');
3497 i = (int)(cp++ - str0);
3503 if (nfsrv_dnsnamelen > 0) {
3505 * If an '@' is found and the dns name matches, search for the
3506 * name with the dns stripped off.
3508 if (cnt == 0 && i < len && i > 0 &&
3509 (len - 1 - i) == nfsrv_dnsnamelen &&
3510 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
3511 len -= (nfsrv_dnsnamelen + 1);
3516 * Check for the special case of "nogroup".
3518 if (len == 7 && !NFSBCMP(str, "nogroup", 7)) {
3519 *gidp = nfsrv_defaultgid;
3524 hp = NFSGROUPNAMEHASH(str, len);
3526 TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) {
3527 if (usrp->lug_namelen == len &&
3528 !NFSBCMP(usrp->lug_name, str, len)) {
3529 if (usrp->lug_expiry < NFSD_MONOSEC)
3531 hp2 = NFSGROUPHASH(usrp->lug_gid);
3532 mtx_lock(&hp2->mtx);
3533 TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash);
3534 TAILQ_INSERT_TAIL(&hp2->lughead, usrp,
3536 *gidp = usrp->lug_gid;
3537 mtx_unlock(&hp2->mtx);
3538 mtx_unlock(&hp->mtx);
3543 mtx_unlock(&hp->mtx);
3545 ret = nfsrv_getuser(RPCNFSUSERD_GETGROUP, (uid_t)0, (gid_t)0,
3547 if (ret == 0 && cnt < 2)
3550 error = NFSERR_BADOWNER;
3558 * Cmp len chars, allowing mixed case in the first argument to match lower
3559 * case in the second, but not if the first argument is all upper case.
3560 * Return 0 for a match, 1 otherwise.
3563 nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len)
3569 for (i = 0; i < len; i++) {
3570 if (*cp >= 'A' && *cp <= 'Z') {
3571 tmp = *cp++ + ('a' - 'A');
3574 if (tmp >= 'a' && tmp <= 'z')
3587 * Set the port for the nfsuserd.
3590 nfsrv_nfsuserdport(struct nfsuserd_args *nargs, NFSPROC_T *p)
3592 struct nfssockreq *rp;
3594 struct sockaddr_in *ad;
3597 struct sockaddr_in6 *ad6;
3598 const struct in6_addr in6loopback = IN6ADDR_LOOPBACK_INIT;
3603 if (nfsrv_nfsuserd != NOTRUNNING) {
3608 nfsrv_nfsuserd = STARTSTOP;
3610 * Set up the socket record and connect.
3611 * Set nr_client NULL before unlocking, just to ensure that no other
3612 * process/thread/core will use a bogus old value. This could only
3613 * occur if the use of the nameid lock to protect nfsrv_nfsuserd is
3616 rp = &nfsrv_nfsuserdsock;
3617 rp->nr_client = NULL;
3619 rp->nr_sotype = SOCK_DGRAM;
3620 rp->nr_soproto = IPPROTO_UDP;
3621 rp->nr_lock = (NFSR_RESERVEDPORT | NFSR_LOCALHOST);
3623 rp->nr_prog = RPCPROG_NFSUSERD;
3625 switch (nargs->nuserd_family) {
3628 rp->nr_nam = malloc(sizeof(struct sockaddr_in), M_SONAME,
3630 ad = (struct sockaddr_in *)rp->nr_nam;
3631 ad->sin_len = sizeof(struct sockaddr_in);
3632 ad->sin_family = AF_INET;
3633 ad->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
3634 ad->sin_port = nargs->nuserd_port;
3639 rp->nr_nam = malloc(sizeof(struct sockaddr_in6), M_SONAME,
3641 ad6 = (struct sockaddr_in6 *)rp->nr_nam;
3642 ad6->sin6_len = sizeof(struct sockaddr_in6);
3643 ad6->sin6_family = AF_INET6;
3644 ad6->sin6_addr = in6loopback;
3645 ad6->sin6_port = nargs->nuserd_port;
3651 rp->nr_vers = RPCNFSUSERD_VERS;
3653 error = newnfs_connect(NULL, rp, NFSPROCCRED(p), p, 0);
3656 nfsrv_nfsuserd = RUNNING;
3659 free(rp->nr_nam, M_SONAME);
3661 nfsrv_nfsuserd = NOTRUNNING;
3670 * Delete the nfsuserd port.
3673 nfsrv_nfsuserddelport(void)
3677 if (nfsrv_nfsuserd != RUNNING) {
3681 nfsrv_nfsuserd = STARTSTOP;
3682 /* Wait for all upcalls to complete. */
3683 while (nfsrv_userdupcalls > 0)
3684 msleep(&nfsrv_userdupcalls, NFSNAMEIDMUTEXPTR, PVFS,
3687 newnfs_disconnect(&nfsrv_nfsuserdsock);
3688 free(nfsrv_nfsuserdsock.nr_nam, M_SONAME);
3690 nfsrv_nfsuserd = NOTRUNNING;
3695 * Do upcalls to the nfsuserd, for cache misses of the owner/ownergroup
3697 * Returns 0 upon success, non-zero otherwise.
3700 nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name)
3703 struct nfsrv_descript *nd;
3705 struct nfsrv_descript nfsd;
3710 if (nfsrv_nfsuserd != RUNNING) {
3716 * Maintain a count of upcalls in progress, so that nfsrv_X()
3717 * can wait until no upcalls are in progress.
3719 nfsrv_userdupcalls++;
3721 KASSERT(nfsrv_userdupcalls > 0,
3722 ("nfsrv_getuser: non-positive upcalls"));
3724 cred = newnfs_getcred();
3725 nd->nd_flag = ND_GSSINITREPLY;
3728 nd->nd_procnum = procnum;
3729 if (procnum == RPCNFSUSERD_GETUID || procnum == RPCNFSUSERD_GETGID) {
3730 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3731 if (procnum == RPCNFSUSERD_GETUID)
3732 *tl = txdr_unsigned(uid);
3734 *tl = txdr_unsigned(gid);
3737 (void) nfsm_strtom(nd, name, len);
3739 error = newnfs_request(nd, NULL, NULL, &nfsrv_nfsuserdsock, NULL, NULL,
3740 cred, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, NULL, 0, NULL, NULL);
3742 if (--nfsrv_userdupcalls == 0 && nfsrv_nfsuserd == STARTSTOP)
3743 wakeup(&nfsrv_userdupcalls);
3747 m_freem(nd->nd_mrep);
3748 error = nd->nd_repstat;
3756 * This function is called from the nfssvc(2) system call, to update the
3757 * kernel user/group name list(s) for the V4 owner and ownergroup attributes.
3760 nfssvc_idname(struct nfsd_idargs *nidp)
3762 struct nfsusrgrp *nusrp, *usrp, *newusrp;
3763 struct nfsrv_lughash *hp_name, *hp_idnum, *thp;
3764 int i, group_locked, groupname_locked, user_locked, username_locked;
3769 static int onethread = 0;
3770 static time_t lasttime = 0;
3772 if (nidp->nid_namelen <= 0 || nidp->nid_namelen > MAXHOSTNAMELEN) {
3776 if (nidp->nid_flag & NFSID_INITIALIZE) {
3777 cp = malloc(nidp->nid_namelen + 1, M_NFSSTRING, M_WAITOK);
3778 error = copyin(nidp->nid_name, cp, nidp->nid_namelen);
3780 free(cp, M_NFSSTRING);
3783 if (atomic_cmpset_acq_int(&nfsrv_dnsnamelen, 0, 0) == 0) {
3785 * Free up all the old stuff and reinitialize hash
3786 * lists. All mutexes for both lists must be locked,
3787 * with the user/group name ones before the uid/gid
3788 * ones, to avoid a LOR.
3790 for (i = 0; i < nfsrv_lughashsize; i++)
3791 mtx_lock(&nfsusernamehash[i].mtx);
3792 for (i = 0; i < nfsrv_lughashsize; i++)
3793 mtx_lock(&nfsuserhash[i].mtx);
3794 for (i = 0; i < nfsrv_lughashsize; i++)
3795 TAILQ_FOREACH_SAFE(usrp,
3796 &nfsuserhash[i].lughead, lug_numhash, nusrp)
3797 nfsrv_removeuser(usrp, 1);
3798 for (i = 0; i < nfsrv_lughashsize; i++)
3799 mtx_unlock(&nfsuserhash[i].mtx);
3800 for (i = 0; i < nfsrv_lughashsize; i++)
3801 mtx_unlock(&nfsusernamehash[i].mtx);
3802 for (i = 0; i < nfsrv_lughashsize; i++)
3803 mtx_lock(&nfsgroupnamehash[i].mtx);
3804 for (i = 0; i < nfsrv_lughashsize; i++)
3805 mtx_lock(&nfsgrouphash[i].mtx);
3806 for (i = 0; i < nfsrv_lughashsize; i++)
3807 TAILQ_FOREACH_SAFE(usrp,
3808 &nfsgrouphash[i].lughead, lug_numhash,
3810 nfsrv_removeuser(usrp, 0);
3811 for (i = 0; i < nfsrv_lughashsize; i++)
3812 mtx_unlock(&nfsgrouphash[i].mtx);
3813 for (i = 0; i < nfsrv_lughashsize; i++)
3814 mtx_unlock(&nfsgroupnamehash[i].mtx);
3815 free(nfsrv_dnsname, M_NFSSTRING);
3816 nfsrv_dnsname = NULL;
3818 if (nfsuserhash == NULL) {
3819 /* Allocate the hash tables. */
3820 nfsuserhash = malloc(sizeof(struct nfsrv_lughash) *
3821 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3823 for (i = 0; i < nfsrv_lughashsize; i++)
3824 mtx_init(&nfsuserhash[i].mtx, "nfsuidhash",
3825 NULL, MTX_DEF | MTX_DUPOK);
3826 nfsusernamehash = malloc(sizeof(struct nfsrv_lughash) *
3827 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3829 for (i = 0; i < nfsrv_lughashsize; i++)
3830 mtx_init(&nfsusernamehash[i].mtx,
3831 "nfsusrhash", NULL, MTX_DEF |
3833 nfsgrouphash = malloc(sizeof(struct nfsrv_lughash) *
3834 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3836 for (i = 0; i < nfsrv_lughashsize; i++)
3837 mtx_init(&nfsgrouphash[i].mtx, "nfsgidhash",
3838 NULL, MTX_DEF | MTX_DUPOK);
3839 nfsgroupnamehash = malloc(sizeof(struct nfsrv_lughash) *
3840 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3842 for (i = 0; i < nfsrv_lughashsize; i++)
3843 mtx_init(&nfsgroupnamehash[i].mtx,
3844 "nfsgrphash", NULL, MTX_DEF | MTX_DUPOK);
3846 /* (Re)initialize the list heads. */
3847 for (i = 0; i < nfsrv_lughashsize; i++)
3848 TAILQ_INIT(&nfsuserhash[i].lughead);
3849 for (i = 0; i < nfsrv_lughashsize; i++)
3850 TAILQ_INIT(&nfsusernamehash[i].lughead);
3851 for (i = 0; i < nfsrv_lughashsize; i++)
3852 TAILQ_INIT(&nfsgrouphash[i].lughead);
3853 for (i = 0; i < nfsrv_lughashsize; i++)
3854 TAILQ_INIT(&nfsgroupnamehash[i].lughead);
3857 * Put name in "DNS" string.
3860 nfsrv_defaultuid = nidp->nid_uid;
3861 nfsrv_defaultgid = nidp->nid_gid;
3863 nfsrv_usermax = nidp->nid_usermax;
3864 atomic_store_rel_int(&nfsrv_dnsnamelen, nidp->nid_namelen);
3869 * malloc the new one now, so any potential sleep occurs before
3870 * manipulation of the lists.
3872 newusrp = malloc(sizeof(struct nfsusrgrp) + nidp->nid_namelen,
3873 M_NFSUSERGROUP, M_WAITOK | M_ZERO);
3874 error = copyin(nidp->nid_name, newusrp->lug_name,
3876 if (error == 0 && nidp->nid_ngroup > 0 &&
3877 (nidp->nid_flag & NFSID_ADDUID) != 0) {
3878 grps = malloc(sizeof(gid_t) * nidp->nid_ngroup, M_TEMP,
3880 error = copyin(nidp->nid_grps, grps,
3881 sizeof(gid_t) * nidp->nid_ngroup);
3884 * Create a credential just like svc_getcred(),
3885 * but using the group list provided.
3888 cr->cr_uid = cr->cr_ruid = cr->cr_svuid = nidp->nid_uid;
3889 crsetgroups(cr, nidp->nid_ngroup, grps);
3890 cr->cr_rgid = cr->cr_svgid = cr->cr_groups[0];
3891 cr->cr_prison = &prison0;
3892 prison_hold(cr->cr_prison);
3894 mac_cred_associate_nfsd(cr);
3896 newusrp->lug_cred = cr;
3901 free(newusrp, M_NFSUSERGROUP);
3904 newusrp->lug_namelen = nidp->nid_namelen;
3907 * The lock order is username[0]->[nfsrv_lughashsize - 1] followed
3908 * by uid[0]->[nfsrv_lughashsize - 1], with the same for group.
3909 * The flags user_locked, username_locked, group_locked and
3910 * groupname_locked are set to indicate all of those hash lists are
3911 * locked. hp_name != NULL and hp_idnum != NULL indicates that
3912 * the respective one mutex is locked.
3914 user_locked = username_locked = group_locked = groupname_locked = 0;
3915 hp_name = hp_idnum = NULL;
3918 * Delete old entries, as required.
3920 if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) {
3921 /* Must lock all username hash lists first, to avoid a LOR. */
3922 for (i = 0; i < nfsrv_lughashsize; i++)
3923 mtx_lock(&nfsusernamehash[i].mtx);
3924 username_locked = 1;
3925 hp_idnum = NFSUSERHASH(nidp->nid_uid);
3926 mtx_lock(&hp_idnum->mtx);
3927 TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
3929 if (usrp->lug_uid == nidp->nid_uid)
3930 nfsrv_removeuser(usrp, 1);
3932 } else if (nidp->nid_flag & (NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) {
3933 hp_name = NFSUSERNAMEHASH(newusrp->lug_name,
3934 newusrp->lug_namelen);
3935 mtx_lock(&hp_name->mtx);
3936 TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
3938 if (usrp->lug_namelen == newusrp->lug_namelen &&
3939 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3940 usrp->lug_namelen)) {
3941 thp = NFSUSERHASH(usrp->lug_uid);
3942 mtx_lock(&thp->mtx);
3943 nfsrv_removeuser(usrp, 1);
3944 mtx_unlock(&thp->mtx);
3947 hp_idnum = NFSUSERHASH(nidp->nid_uid);
3948 mtx_lock(&hp_idnum->mtx);
3949 } else if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) {
3950 /* Must lock all groupname hash lists first, to avoid a LOR. */
3951 for (i = 0; i < nfsrv_lughashsize; i++)
3952 mtx_lock(&nfsgroupnamehash[i].mtx);
3953 groupname_locked = 1;
3954 hp_idnum = NFSGROUPHASH(nidp->nid_gid);
3955 mtx_lock(&hp_idnum->mtx);
3956 TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
3958 if (usrp->lug_gid == nidp->nid_gid)
3959 nfsrv_removeuser(usrp, 0);
3961 } else if (nidp->nid_flag & (NFSID_DELGROUPNAME | NFSID_ADDGROUPNAME)) {
3962 hp_name = NFSGROUPNAMEHASH(newusrp->lug_name,
3963 newusrp->lug_namelen);
3964 mtx_lock(&hp_name->mtx);
3965 TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
3967 if (usrp->lug_namelen == newusrp->lug_namelen &&
3968 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3969 usrp->lug_namelen)) {
3970 thp = NFSGROUPHASH(usrp->lug_gid);
3971 mtx_lock(&thp->mtx);
3972 nfsrv_removeuser(usrp, 0);
3973 mtx_unlock(&thp->mtx);
3976 hp_idnum = NFSGROUPHASH(nidp->nid_gid);
3977 mtx_lock(&hp_idnum->mtx);
3981 * Now, we can add the new one.
3983 if (nidp->nid_usertimeout)
3984 newusrp->lug_expiry = NFSD_MONOSEC + nidp->nid_usertimeout;
3986 newusrp->lug_expiry = NFSD_MONOSEC + 5;
3987 if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) {
3988 newusrp->lug_uid = nidp->nid_uid;
3989 thp = NFSUSERHASH(newusrp->lug_uid);
3990 mtx_assert(&thp->mtx, MA_OWNED);
3991 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
3992 thp = NFSUSERNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3993 mtx_assert(&thp->mtx, MA_OWNED);
3994 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
3995 atomic_add_int(&nfsrv_usercnt, 1);
3996 } else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) {
3997 newusrp->lug_gid = nidp->nid_gid;
3998 thp = NFSGROUPHASH(newusrp->lug_gid);
3999 mtx_assert(&thp->mtx, MA_OWNED);
4000 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
4001 thp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
4002 mtx_assert(&thp->mtx, MA_OWNED);
4003 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
4004 atomic_add_int(&nfsrv_usercnt, 1);
4006 if (newusrp->lug_cred != NULL)
4007 crfree(newusrp->lug_cred);
4008 free(newusrp, M_NFSUSERGROUP);
4012 * Once per second, allow one thread to trim the cache.
4014 if (lasttime < NFSD_MONOSEC &&
4015 atomic_cmpset_acq_int(&onethread, 0, 1) != 0) {
4017 * First, unlock the single mutexes, so that all entries
4018 * can be locked and any LOR is avoided.
4020 if (hp_name != NULL) {
4021 mtx_unlock(&hp_name->mtx);
4024 if (hp_idnum != NULL) {
4025 mtx_unlock(&hp_idnum->mtx);
4029 if ((nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID |
4030 NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) != 0) {
4031 if (username_locked == 0) {
4032 for (i = 0; i < nfsrv_lughashsize; i++)
4033 mtx_lock(&nfsusernamehash[i].mtx);
4034 username_locked = 1;
4036 KASSERT(user_locked == 0,
4037 ("nfssvc_idname: user_locked"));
4038 for (i = 0; i < nfsrv_lughashsize; i++)
4039 mtx_lock(&nfsuserhash[i].mtx);
4041 for (i = 0; i < nfsrv_lughashsize; i++) {
4042 TAILQ_FOREACH_SAFE(usrp,
4043 &nfsuserhash[i].lughead, lug_numhash,
4045 if (usrp->lug_expiry < NFSD_MONOSEC)
4046 nfsrv_removeuser(usrp, 1);
4048 for (i = 0; i < nfsrv_lughashsize; i++) {
4050 * Trim the cache using an approximate LRU
4051 * algorithm. This code deletes the least
4052 * recently used entry on each hash list.
4054 if (nfsrv_usercnt <= nfsrv_usermax)
4056 usrp = TAILQ_FIRST(&nfsuserhash[i].lughead);
4058 nfsrv_removeuser(usrp, 1);
4061 if (groupname_locked == 0) {
4062 for (i = 0; i < nfsrv_lughashsize; i++)
4063 mtx_lock(&nfsgroupnamehash[i].mtx);
4064 groupname_locked = 1;
4066 KASSERT(group_locked == 0,
4067 ("nfssvc_idname: group_locked"));
4068 for (i = 0; i < nfsrv_lughashsize; i++)
4069 mtx_lock(&nfsgrouphash[i].mtx);
4071 for (i = 0; i < nfsrv_lughashsize; i++) {
4072 TAILQ_FOREACH_SAFE(usrp,
4073 &nfsgrouphash[i].lughead, lug_numhash,
4075 if (usrp->lug_expiry < NFSD_MONOSEC)
4076 nfsrv_removeuser(usrp, 0);
4078 for (i = 0; i < nfsrv_lughashsize; i++) {
4080 * Trim the cache using an approximate LRU
4081 * algorithm. This code deletes the least
4082 * recently user entry on each hash list.
4084 if (nfsrv_usercnt <= nfsrv_usermax)
4086 usrp = TAILQ_FIRST(&nfsgrouphash[i].lughead);
4088 nfsrv_removeuser(usrp, 0);
4091 lasttime = NFSD_MONOSEC;
4092 atomic_store_rel_int(&onethread, 0);
4095 /* Now, unlock all locked mutexes. */
4096 if (hp_idnum != NULL)
4097 mtx_unlock(&hp_idnum->mtx);
4098 if (hp_name != NULL)
4099 mtx_unlock(&hp_name->mtx);
4100 if (user_locked != 0)
4101 for (i = 0; i < nfsrv_lughashsize; i++)
4102 mtx_unlock(&nfsuserhash[i].mtx);
4103 if (username_locked != 0)
4104 for (i = 0; i < nfsrv_lughashsize; i++)
4105 mtx_unlock(&nfsusernamehash[i].mtx);
4106 if (group_locked != 0)
4107 for (i = 0; i < nfsrv_lughashsize; i++)
4108 mtx_unlock(&nfsgrouphash[i].mtx);
4109 if (groupname_locked != 0)
4110 for (i = 0; i < nfsrv_lughashsize; i++)
4111 mtx_unlock(&nfsgroupnamehash[i].mtx);
4118 * Remove a user/group name element.
4121 nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser)
4123 struct nfsrv_lughash *hp;
4126 hp = NFSUSERHASH(usrp->lug_uid);
4127 mtx_assert(&hp->mtx, MA_OWNED);
4128 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
4129 hp = NFSUSERNAMEHASH(usrp->lug_name, usrp->lug_namelen);
4130 mtx_assert(&hp->mtx, MA_OWNED);
4131 TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
4133 hp = NFSGROUPHASH(usrp->lug_gid);
4134 mtx_assert(&hp->mtx, MA_OWNED);
4135 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
4136 hp = NFSGROUPNAMEHASH(usrp->lug_name, usrp->lug_namelen);
4137 mtx_assert(&hp->mtx, MA_OWNED);
4138 TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
4140 atomic_add_int(&nfsrv_usercnt, -1);
4141 if (usrp->lug_cred != NULL)
4142 crfree(usrp->lug_cred);
4143 free(usrp, M_NFSUSERGROUP);
4147 * Free up all the allocations related to the name<-->id cache.
4148 * This function should only be called when the nfsuserd daemon isn't
4149 * running, since it doesn't do any locking.
4150 * This function is meant to be used when the nfscommon module is unloaded.
4153 nfsrv_cleanusergroup(void)
4155 struct nfsrv_lughash *hp, *hp2;
4156 struct nfsusrgrp *nusrp, *usrp;
4159 if (nfsuserhash == NULL)
4162 for (i = 0; i < nfsrv_lughashsize; i++) {
4163 hp = &nfsuserhash[i];
4164 TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) {
4165 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
4166 hp2 = NFSUSERNAMEHASH(usrp->lug_name,
4168 TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash);
4169 if (usrp->lug_cred != NULL)
4170 crfree(usrp->lug_cred);
4171 free(usrp, M_NFSUSERGROUP);
4173 hp = &nfsgrouphash[i];
4174 TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) {
4175 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
4176 hp2 = NFSGROUPNAMEHASH(usrp->lug_name,
4178 TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash);
4179 if (usrp->lug_cred != NULL)
4180 crfree(usrp->lug_cred);
4181 free(usrp, M_NFSUSERGROUP);
4183 mtx_destroy(&nfsuserhash[i].mtx);
4184 mtx_destroy(&nfsusernamehash[i].mtx);
4185 mtx_destroy(&nfsgroupnamehash[i].mtx);
4186 mtx_destroy(&nfsgrouphash[i].mtx);
4188 free(nfsuserhash, M_NFSUSERGROUP);
4189 free(nfsusernamehash, M_NFSUSERGROUP);
4190 free(nfsgrouphash, M_NFSUSERGROUP);
4191 free(nfsgroupnamehash, M_NFSUSERGROUP);
4192 free(nfsrv_dnsname, M_NFSSTRING);
4196 * This function scans a byte string and checks for UTF-8 compliance.
4197 * It returns 0 if it conforms and NFSERR_INVAL if not.
4200 nfsrv_checkutf8(u_int8_t *cp, int len)
4202 u_int32_t val = 0x0;
4203 int cnt = 0, gotd = 0, shift = 0;
4205 static int utf8_shift[5] = { 7, 11, 16, 21, 26 };
4209 * Here are what the variables are used for:
4210 * val - the calculated value of a multibyte char, used to check
4211 * that it was coded with the correct range
4212 * cnt - the number of 10xxxxxx bytes to follow
4213 * gotd - set for a char of Dxxx, so D800<->DFFF can be checked for
4214 * shift - lower order bits of range (ie. "val >> shift" should
4215 * not be 0, in other words, dividing by the lower bound
4216 * of the range should get a non-zero value)
4217 * byte - used to calculate cnt
4221 /* This handles the 10xxxxxx bytes */
4222 if ((*cp & 0xc0) != 0x80 ||
4223 (gotd && (*cp & 0x20))) {
4224 error = NFSERR_INVAL;
4229 val |= (*cp & 0x3f);
4231 if (cnt == 0 && (val >> shift) == 0x0) {
4232 error = NFSERR_INVAL;
4235 } else if (*cp & 0x80) {
4236 /* first byte of multi byte char */
4238 while ((byte & 0x40) && cnt < 6) {
4242 if (cnt == 0 || cnt == 6) {
4243 error = NFSERR_INVAL;
4246 val = (*cp & (0x3f >> cnt));
4247 shift = utf8_shift[cnt - 1];
4248 if (cnt == 2 && val == 0xd)
4249 /* Check for the 0xd800-0xdfff case */
4256 error = NFSERR_INVAL;
4264 * Parse the xdr for an NFSv4 FsLocations attribute. Return two malloc'd
4265 * strings, one with the root path in it and the other with the list of
4266 * locations. The list is in the same format as is found in nfr_refs.
4267 * It is a "," separated list of entries, where each of them is of the
4268 * form <server>:<rootpath>. For example
4269 * "nfsv4-test:/sub2,nfsv4-test2:/user/mnt,nfsv4-test2:/user/mnt2"
4270 * The nilp argument is set to 1 for the special case of a null fs_root
4271 * and an empty server list.
4272 * It returns NFSERR_BADXDR, if the xdr can't be parsed and returns the
4273 * number of xdr bytes parsed in sump.
4276 nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp,
4277 int *sump, int *nilp)
4280 u_char *cp = NULL, *cp2 = NULL, *cp3, *str;
4281 int i, j, len, stringlen, cnt, slen, siz, xdrsum, error = 0, nsrv;
4283 SLIST_ENTRY(list) next;
4287 SLIST_HEAD(, list) head;
4294 * Get the fs_root path and check for the special case of null path
4295 * and 0 length server list.
4297 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4298 len = fxdr_unsigned(int, *tl);
4299 if (len < 0 || len > 10240) {
4300 error = NFSERR_BADXDR;
4304 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4306 error = NFSERR_BADXDR;
4310 *sump = 2 * NFSX_UNSIGNED;
4314 cp = malloc(len + 1, M_NFSSTRING, M_WAITOK);
4315 error = nfsrv_mtostr(nd, cp, len);
4317 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4318 cnt = fxdr_unsigned(int, *tl);
4320 error = NFSERR_BADXDR;
4326 * Now, loop through the location list and make up the srvlist.
4328 xdrsum = (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
4329 cp2 = cp3 = malloc(1024, M_NFSSTRING, M_WAITOK);
4332 for (i = 0; i < cnt; i++) {
4334 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4335 nsrv = fxdr_unsigned(int, *tl);
4337 error = NFSERR_BADXDR;
4342 * Handle the first server by putting it in the srvstr.
4344 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4345 len = fxdr_unsigned(int, *tl);
4346 if (len <= 0 || len > 1024) {
4347 error = NFSERR_BADXDR;
4350 nfsrv_refstrbigenough(siz + len + 3, &cp2, &cp3, &slen);
4355 error = nfsrv_mtostr(nd, cp3, len);
4361 xdrsum += (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
4362 for (j = 1; j < nsrv; j++) {
4364 * Yuck, put them in an slist and process them later.
4366 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4367 len = fxdr_unsigned(int, *tl);
4368 if (len <= 0 || len > 1024) {
4369 error = NFSERR_BADXDR;
4372 lsp = (struct list *)malloc(sizeof (struct list)
4373 + len, M_TEMP, M_WAITOK);
4374 error = nfsrv_mtostr(nd, lsp->host, len);
4377 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
4379 SLIST_INSERT_HEAD(&head, lsp, next);
4383 * Finally, we can get the path.
4385 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4386 len = fxdr_unsigned(int, *tl);
4387 if (len <= 0 || len > 1024) {
4388 error = NFSERR_BADXDR;
4391 nfsrv_refstrbigenough(siz + len + 1, &cp2, &cp3, &slen);
4392 error = nfsrv_mtostr(nd, cp3, len);
4395 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
4400 SLIST_FOREACH_SAFE(lsp, &head, next, nlsp) {
4401 nfsrv_refstrbigenough(siz + lsp->len + stringlen + 3,
4404 NFSBCOPY(lsp->host, cp3, lsp->len);
4407 NFSBCOPY(str, cp3, stringlen);
4410 siz += (lsp->len + stringlen + 2);
4417 NFSEXITCODE2(0, nd);
4421 free(cp, M_NFSSTRING);
4423 free(cp2, M_NFSSTRING);
4424 NFSEXITCODE2(error, nd);
4429 * Make the malloc'd space large enough. This is a pain, but the xdr
4430 * doesn't set an upper bound on the side, so...
4433 nfsrv_refstrbigenough(int siz, u_char **cpp, u_char **cpp2, int *slenp)
4440 cp = malloc(siz + 1024, M_NFSSTRING, M_WAITOK);
4441 NFSBCOPY(*cpp, cp, *slenp);
4442 free(*cpp, M_NFSSTRING);
4446 *slenp = siz + 1024;
4450 * Initialize the reply header data structures.
4453 nfsrvd_rephead(struct nfsrv_descript *nd)
4457 if ((nd->nd_flag & ND_EXTPG) != 0) {
4458 mreq = mb_alloc_ext_plus_pages(PAGE_SIZE, M_WAITOK);
4459 nd->nd_mreq = nd->nd_mb = mreq;
4460 nd->nd_bpos = (char *)(void *)
4461 PHYS_TO_DMAP(mreq->m_epg_pa[0]);
4463 nd->nd_bextpgsiz = PAGE_SIZE;
4466 * If this is a big reply, use a cluster.
4468 if ((nd->nd_flag & ND_GSSINITREPLY) == 0 &&
4469 nfs_bigreply[nd->nd_procnum]) {
4470 NFSMCLGET(mreq, M_WAITOK);
4478 nd->nd_bpos = mtod(mreq, char *);
4482 if ((nd->nd_flag & ND_GSSINITREPLY) == 0)
4483 NFSM_BUILD(nd->nd_errp, int *, NFSX_UNSIGNED);
4487 * Lock a socket against others.
4488 * Currently used to serialize connect/disconnect attempts.
4491 newnfs_sndlock(int *flagp)
4496 while (*flagp & NFSR_SNDLOCK) {
4497 *flagp |= NFSR_WANTSND;
4500 (void) nfsmsleep((caddr_t)flagp, NFSSOCKMUTEXPTR,
4501 PZERO - 1, "nfsndlck", &ts);
4503 *flagp |= NFSR_SNDLOCK;
4509 * Unlock the stream socket for others.
4512 newnfs_sndunlock(int *flagp)
4516 if ((*flagp & NFSR_SNDLOCK) == 0)
4517 panic("nfs sndunlock");
4518 *flagp &= ~NFSR_SNDLOCK;
4519 if (*flagp & NFSR_WANTSND) {
4520 *flagp &= ~NFSR_WANTSND;
4521 wakeup((caddr_t)flagp);
4527 nfsv4_getipaddr(struct nfsrv_descript *nd, struct sockaddr_in *sin,
4528 struct sockaddr_in6 *sin6, sa_family_t *saf, int *isudp)
4530 struct in_addr saddr;
4531 uint32_t portnum, *tl;
4533 sa_family_t af = AF_UNSPEC;
4534 char addr[64], protocol[5], *cp;
4535 int cantparse = 0, error = 0;
4538 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4539 i = fxdr_unsigned(int, *tl);
4540 if (i >= 3 && i <= 4) {
4541 error = nfsrv_mtostr(nd, protocol, i);
4544 if (strcmp(protocol, "tcp") == 0) {
4547 } else if (strcmp(protocol, "udp") == 0) {
4550 } else if (strcmp(protocol, "tcp6") == 0) {
4553 } else if (strcmp(protocol, "udp6") == 0) {
4561 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
4566 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4567 i = fxdr_unsigned(int, *tl);
4569 error = NFSERR_BADXDR;
4571 } else if (cantparse == 0 && i >= 11 && i < 64) {
4573 * The shortest address is 11chars and the longest is < 64.
4575 error = nfsrv_mtostr(nd, addr, i);
4579 /* Find the port# at the end and extract that. */
4583 /* Count back two '.'s from end to get port# field. */
4584 for (j = 0; j < i; j++) {
4594 * The NFSv4 port# is appended as .N.N, where N is
4595 * a decimal # in the range 0-255, just like an inet4
4596 * address. Cheat and use inet_aton(), which will
4597 * return a Class A address and then shift the high
4598 * order 8bits over to convert it to the port#.
4601 if (inet_aton(cp, &saddr) == 1) {
4602 portnum = ntohl(saddr.s_addr);
4603 portv = (uint16_t)((portnum >> 16) |
4609 if (cantparse == 0) {
4610 if (af == AF_INET) {
4611 if (inet_pton(af, addr, &sin->sin_addr) == 1) {
4612 sin->sin_len = sizeof(*sin);
4613 sin->sin_family = AF_INET;
4614 sin->sin_port = htons(portv);
4619 if (inet_pton(af, addr, &sin6->sin6_addr)
4621 sin6->sin6_len = sizeof(*sin6);
4622 sin6->sin6_family = AF_INET6;
4623 sin6->sin6_port = htons(portv);
4631 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
4642 * Handle an NFSv4.1 Sequence request for the session.
4643 * If reply != NULL, use it to return the cached reply, as required.
4644 * The client gets a cached reply via this call for callbacks, however the
4645 * server gets a cached reply via the nfsv4_seqsess_cachereply() call.
4648 nfsv4_seqsession(uint32_t seqid, uint32_t slotid, uint32_t highslot,
4649 struct nfsslot *slots, struct mbuf **reply, uint16_t maxslot)
4656 if (slotid > maxslot)
4657 return (NFSERR_BADSLOT);
4658 if (seqid == slots[slotid].nfssl_seq) {
4660 if (slots[slotid].nfssl_inprog != 0)
4661 error = NFSERR_DELAY;
4662 else if (slots[slotid].nfssl_reply != NULL) {
4663 if (reply != NULL) {
4664 *reply = slots[slotid].nfssl_reply;
4665 slots[slotid].nfssl_reply = NULL;
4667 slots[slotid].nfssl_inprog = 1;
4668 error = NFSERR_REPLYFROMCACHE;
4670 /* No reply cached, so just do it. */
4671 slots[slotid].nfssl_inprog = 1;
4672 } else if ((slots[slotid].nfssl_seq + 1) == seqid) {
4673 if (slots[slotid].nfssl_reply != NULL)
4674 m_freem(slots[slotid].nfssl_reply);
4675 slots[slotid].nfssl_reply = NULL;
4676 slots[slotid].nfssl_inprog = 1;
4677 slots[slotid].nfssl_seq++;
4679 error = NFSERR_SEQMISORDERED;
4684 * Cache this reply for the slot.
4685 * Use the "rep" argument to return the cached reply if repstat is set to
4686 * NFSERR_REPLYFROMCACHE. The client never sets repstat to this value.
4689 nfsv4_seqsess_cacherep(uint32_t slotid, struct nfsslot *slots, int repstat,
4693 if (repstat == NFSERR_REPLYFROMCACHE) {
4694 *rep = slots[slotid].nfssl_reply;
4695 slots[slotid].nfssl_reply = NULL;
4697 if (slots[slotid].nfssl_reply != NULL)
4698 m_freem(slots[slotid].nfssl_reply);
4699 slots[slotid].nfssl_reply = *rep;
4701 slots[slotid].nfssl_inprog = 0;
4705 * Generate the xdr for an NFSv4.1 Sequence Operation.
4708 nfsv4_setsequence(struct nfsmount *nmp, struct nfsrv_descript *nd,
4709 struct nfsclsession *sep, int dont_replycache)
4711 uint32_t *tl, slotseq = 0;
4712 int error, maxslot, slotpos;
4713 uint8_t sessionid[NFSX_V4SESSIONID];
4715 error = nfsv4_sequencelookup(nmp, sep, &slotpos, &maxslot, &slotseq,
4717 nd->nd_maxreq = sep->nfsess_maxreq;
4718 nd->nd_maxresp = sep->nfsess_maxresp;
4720 /* Build the Sequence arguments. */
4721 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 4 * NFSX_UNSIGNED);
4722 nd->nd_sequence = tl;
4723 bcopy(sessionid, tl, NFSX_V4SESSIONID);
4724 tl += NFSX_V4SESSIONID / NFSX_UNSIGNED;
4725 nd->nd_slotseq = tl;
4727 nd->nd_flag |= ND_HASSLOTID;
4728 nd->nd_slotid = slotpos;
4729 *tl++ = txdr_unsigned(slotseq);
4730 *tl++ = txdr_unsigned(slotpos);
4731 *tl++ = txdr_unsigned(maxslot);
4732 if (dont_replycache == 0)
4738 * There are two errors and the rest of the session can
4740 * NFSERR_BADSESSION: This bad session should just generate
4741 * the same error again when the RPC is retried.
4742 * ESTALE: A forced dismount is in progress and will cause the
4743 * RPC to fail later.
4750 nd->nd_flag |= ND_HASSEQUENCE;
4754 nfsv4_sequencelookup(struct nfsmount *nmp, struct nfsclsession *sep,
4755 int *slotposp, int *maxslotp, uint32_t *slotseqp, uint8_t *sessionid)
4757 int i, maxslot, slotpos;
4760 /* Find an unused slot. */
4763 mtx_lock(&sep->nfsess_mtx);
4765 if (nmp != NULL && sep->nfsess_defunct != 0) {
4766 /* Just return the bad session. */
4767 bcopy(sep->nfsess_sessionid, sessionid,
4769 mtx_unlock(&sep->nfsess_mtx);
4770 return (NFSERR_BADSESSION);
4773 for (i = 0; i < sep->nfsess_foreslots; i++) {
4774 if ((bitval & sep->nfsess_slots) == 0) {
4776 sep->nfsess_slots |= bitval;
4777 sep->nfsess_slotseq[i]++;
4778 *slotseqp = sep->nfsess_slotseq[i];
4783 if (slotpos == -1) {
4785 * If a forced dismount is in progress, just return.
4786 * This RPC attempt will fail when it calls
4789 if (nmp != NULL && NFSCL_FORCEDISM(nmp->nm_mountp)) {
4790 mtx_unlock(&sep->nfsess_mtx);
4793 /* Wake up once/sec, to check for a forced dismount. */
4794 (void)mtx_sleep(&sep->nfsess_slots, &sep->nfsess_mtx,
4795 PZERO, "nfsclseq", hz);
4797 } while (slotpos == -1);
4798 /* Now, find the highest slot in use. (nfsc_slots is 64bits) */
4800 for (i = 0; i < 64; i++) {
4801 if ((bitval & sep->nfsess_slots) != 0)
4805 bcopy(sep->nfsess_sessionid, sessionid, NFSX_V4SESSIONID);
4806 mtx_unlock(&sep->nfsess_mtx);
4807 *slotposp = slotpos;
4808 *maxslotp = maxslot;
4813 * Free a session slot.
4816 nfsv4_freeslot(struct nfsclsession *sep, int slot)
4823 mtx_lock(&sep->nfsess_mtx);
4824 if ((bitval & sep->nfsess_slots) == 0)
4825 printf("freeing free slot!!\n");
4826 sep->nfsess_slots &= ~bitval;
4827 wakeup(&sep->nfsess_slots);
4828 mtx_unlock(&sep->nfsess_mtx);
4832 * Search for a matching pnfsd DS, based on the nmp arg.
4833 * Return one if found, NULL otherwise.
4836 nfsv4_findmirror(struct nfsmount *nmp)
4838 struct nfsdevice *ds;
4840 mtx_assert(NFSDDSMUTEXPTR, MA_OWNED);
4842 * Search the DS server list for a match with nmp.
4844 if (nfsrv_devidcnt == 0)
4846 TAILQ_FOREACH(ds, &nfsrv_devidhead, nfsdev_list) {
4847 if (ds->nfsdev_nmp == nmp) {
4848 NFSCL_DEBUG(4, "nfsv4_findmirror: fnd main ds\n");
4856 * Fill in the fields of "struct nfsrv_descript".
4859 nfsm_set(struct nfsrv_descript *nd, u_int offs)
4865 if ((m->m_flags & M_EXTPG) != 0) {
4868 if (nd->nd_bextpg == 0)
4869 rlen = m_epg_pagelen(m, 0, m->m_epg_1st_off);
4871 rlen = m_epg_pagelen(m, nd->nd_bextpg, 0);
4876 if (nd->nd_bextpg == m->m_epg_npgs) {
4877 printf("nfsm_set: build offs "
4883 nd->nd_bpos = (char *)(void *)
4884 PHYS_TO_DMAP(m->m_epg_pa[nd->nd_bextpg]);
4885 if (nd->nd_bextpg == 0)
4886 nd->nd_bpos += m->m_epg_1st_off;
4888 nd->nd_bpos += offs;
4889 nd->nd_bextpgsiz = rlen - offs;
4890 } else if (nd->nd_bextpg == 0)
4891 nd->nd_bextpgsiz = PAGE_SIZE - m->m_epg_1st_off;
4893 nd->nd_bextpgsiz = PAGE_SIZE;
4895 nd->nd_bpos = mtod(m, char *) + offs;
4899 * Grow a ext_pgs mbuf list. Either allocate another page or add
4900 * an mbuf to the list.
4903 nfsm_add_ext_pgs(struct mbuf *m, int maxextsiz, int *bextpg)
4908 if ((m->m_epg_npgs + 1) * PAGE_SIZE > maxextsiz) {
4909 mp = mb_alloc_ext_plus_pages(PAGE_SIZE, M_WAITOK);
4914 pg = vm_page_alloc(NULL, 0, VM_ALLOC_NORMAL |
4915 VM_ALLOC_NOOBJ | VM_ALLOC_NODUMP |
4919 } while (pg == NULL);
4920 m->m_epg_pa[m->m_epg_npgs] = VM_PAGE_TO_PHYS(pg);
4921 *bextpg = m->m_epg_npgs;
4923 m->m_epg_last_len = 0;