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;
88 extern uint32_t nfs_srvmaxio;
90 SYSCTL_DECL(_vfs_nfs);
91 SYSCTL_INT(_vfs_nfs, OID_AUTO, enable_uidtostring, CTLFLAG_RW,
92 &nfs_enable_uidtostring, 0, "Make nfs always send numeric owner_names");
94 int nfsrv_maxpnfsmirror = 1;
95 SYSCTL_INT(_vfs_nfs, OID_AUTO, pnfsmirror, CTLFLAG_RD,
96 &nfsrv_maxpnfsmirror, 0, "Mirror level for pNFS service");
99 * This array of structures indicates, for V4:
100 * retfh - which of 3 types of calling args are used
101 * 0 - doesn't change cfh or use a sfh
102 * 1 - replaces cfh with a new one (unless it returns an error status)
103 * 2 - uses cfh and sfh
104 * needscfh - if the op wants a cfh and premtime
105 * 0 - doesn't use a cfh
106 * 1 - uses a cfh, but doesn't want pre-op attributes
107 * 2 - uses a cfh and wants pre-op attributes
108 * savereply - indicates a non-idempotent Op
109 * 0 - not non-idempotent
111 * Ops that are ordered via seqid# are handled separately from these
112 * non-idempotent Ops.
113 * Define it here, since it is used by both the client and server.
115 struct nfsv4_opflag nfsv4_opflag[NFSV42_NOPS] = {
116 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* undef */
117 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* undef */
118 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* undef */
119 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Access */
120 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Close */
121 { 0, 2, 0, 1, LK_EXCLUSIVE, 1, 1 }, /* Commit */
122 { 1, 2, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Create */
123 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Delegpurge */
124 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Delegreturn */
125 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Getattr */
126 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* GetFH */
127 { 2, 1, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Link */
128 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Lock */
129 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* LockT */
130 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* LockU */
131 { 1, 2, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Lookup */
132 { 1, 2, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Lookupp */
133 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* NVerify */
134 { 1, 1, 0, 1, LK_EXCLUSIVE, 1, 0 }, /* Open */
135 { 1, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* OpenAttr */
136 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* OpenConfirm */
137 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* OpenDowngrade */
138 { 1, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* PutFH */
139 { 1, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* PutPubFH */
140 { 1, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* PutRootFH */
141 { 0, 1, 0, 0, LK_SHARED, 1, 0 }, /* Read */
142 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Readdir */
143 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* ReadLink */
144 { 0, 2, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Remove */
145 { 2, 1, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Rename */
146 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Renew */
147 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* RestoreFH */
148 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SaveFH */
149 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SecInfo */
150 { 0, 2, 1, 1, LK_EXCLUSIVE, 1, 0 }, /* Setattr */
151 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SetClientID */
152 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SetClientIDConfirm */
153 { 0, 2, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Verify (AppWrite) */
154 { 0, 2, 1, 1, LK_EXCLUSIVE, 1, 0 }, /* Write */
155 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* ReleaseLockOwner */
156 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Backchannel Ctrl */
157 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Bind Conn to Sess */
158 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Exchange ID */
159 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Create Session */
160 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Destroy Session */
161 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Free StateID */
162 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Get Dir Deleg */
163 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Get Device Info */
164 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Get Device List */
165 { 0, 1, 0, 1, LK_EXCLUSIVE, 1, 1 }, /* Layout Commit */
166 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Layout Get */
167 { 0, 1, 0, 1, LK_EXCLUSIVE, 1, 0 }, /* Layout Return */
168 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Secinfo No name */
169 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Sequence */
170 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Set SSV */
171 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Test StateID */
172 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Want Delegation */
173 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Destroy ClientID */
174 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Reclaim Complete */
175 { 0, 1, 1, 1, LK_EXCLUSIVE, 1, 0 }, /* Allocate */
176 { 2, 1, 1, 0, LK_SHARED, 1, 0 }, /* Copy */
177 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Copy Notify */
178 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Deallocate */
179 { 0, 1, 0, 0, LK_SHARED, 1, 0 }, /* IO Advise */
180 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Layout Error */
181 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Layout Stats */
182 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Offload Cancel */
183 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Offload Status */
184 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Read Plus */
185 { 0, 1, 0, 0, LK_SHARED, 1, 0 }, /* Seek */
186 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Write Same */
187 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Clone */
188 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Getxattr */
189 { 0, 1, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Setxattr */
190 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Listxattrs */
191 { 0, 1, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Removexattr */
194 static int ncl_mbuf_mhlen = MHLEN;
195 static int nfsrv_usercnt = 0;
196 static int nfsrv_dnsnamelen;
197 static u_char *nfsrv_dnsname = NULL;
198 static int nfsrv_usermax = 999999999;
199 struct nfsrv_lughash {
201 struct nfsuserhashhead lughead;
203 static struct nfsrv_lughash *nfsuserhash;
204 static struct nfsrv_lughash *nfsusernamehash;
205 static struct nfsrv_lughash *nfsgrouphash;
206 static struct nfsrv_lughash *nfsgroupnamehash;
209 * This static array indicates whether or not the RPC generates a large
210 * reply. This is used by nfs_reply() to decide whether or not an mbuf
211 * cluster should be allocated. (If a cluster is required by an RPC
212 * marked 0 in this array, the code will still work, just not quite as
215 static int nfs_bigreply[NFSV42_NPROCS] = { 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0,
216 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
217 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
218 1, 0, 0, 1, 0, 0, 0, 0, 0 };
220 /* local functions */
221 static int nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep);
222 static void nfsv4_wanted(struct nfsv4lock *lp);
223 static uint32_t nfsv4_filesavail(struct statfs *, struct mount *);
224 static int nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len);
225 static int nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name);
226 static void nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser);
227 static int nfsrv_getrefstr(struct nfsrv_descript *, u_char **, u_char **,
229 static void nfsrv_refstrbigenough(int, u_char **, u_char **, int *);
236 } nfsv4_opmap[NFSV42_NPROCS] = {
238 { NFSV4OP_GETATTR, 1, "Getattr", 7, },
239 { NFSV4OP_SETATTR, 2, "Setattr", 7, },
240 { NFSV4OP_LOOKUP, 3, "Lookup", 6, },
241 { NFSV4OP_ACCESS, 2, "Access", 6, },
242 { NFSV4OP_READLINK, 2, "Readlink", 8, },
243 { NFSV4OP_READ, 1, "Read", 4, },
244 { NFSV4OP_WRITE, 2, "Write", 5, },
245 { NFSV4OP_OPEN, 5, "Open", 4, },
246 { NFSV4OP_CREATE, 5, "Create", 6, },
247 { NFSV4OP_CREATE, 1, "Create", 6, },
248 { NFSV4OP_CREATE, 3, "Create", 6, },
249 { NFSV4OP_REMOVE, 1, "Remove", 6, },
250 { NFSV4OP_REMOVE, 1, "Remove", 6, },
251 { NFSV4OP_SAVEFH, 5, "Rename", 6, },
252 { NFSV4OP_SAVEFH, 4, "Link", 4, },
253 { NFSV4OP_READDIR, 2, "Readdir", 7, },
254 { NFSV4OP_READDIR, 2, "Readdir", 7, },
255 { NFSV4OP_GETATTR, 1, "Getattr", 7, },
256 { NFSV4OP_GETATTR, 1, "Getattr", 7, },
257 { NFSV4OP_GETATTR, 1, "Getattr", 7, },
258 { NFSV4OP_COMMIT, 2, "Commit", 6, },
259 { NFSV4OP_LOOKUPP, 3, "Lookupp", 7, },
260 { NFSV4OP_SETCLIENTID, 1, "SetClientID", 11, },
261 { NFSV4OP_SETCLIENTIDCFRM, 1, "SetClientIDConfirm", 18, },
262 { NFSV4OP_LOCK, 1, "Lock", 4, },
263 { NFSV4OP_LOCKU, 1, "LockU", 5, },
264 { NFSV4OP_OPEN, 2, "Open", 4, },
265 { NFSV4OP_CLOSE, 1, "Close", 5, },
266 { NFSV4OP_OPENCONFIRM, 1, "Openconfirm", 11, },
267 { NFSV4OP_LOCKT, 1, "LockT", 5, },
268 { NFSV4OP_OPENDOWNGRADE, 1, "Opendowngrade", 13, },
269 { NFSV4OP_RENEW, 1, "Renew", 5, },
270 { NFSV4OP_PUTROOTFH, 1, "Dirpath", 7, },
271 { NFSV4OP_RELEASELCKOWN, 1, "Rellckown", 9, },
272 { NFSV4OP_DELEGRETURN, 1, "Delegret", 8, },
273 { NFSV4OP_DELEGRETURN, 3, "DelegRemove", 11, },
274 { NFSV4OP_DELEGRETURN, 7, "DelegRename1", 12, },
275 { NFSV4OP_DELEGRETURN, 9, "DelegRename2", 12, },
276 { NFSV4OP_GETATTR, 1, "Getacl", 6, },
277 { NFSV4OP_SETATTR, 1, "Setacl", 6, },
278 { NFSV4OP_EXCHANGEID, 1, "ExchangeID", 10, },
279 { NFSV4OP_CREATESESSION, 1, "CreateSession", 13, },
280 { NFSV4OP_DESTROYSESSION, 1, "DestroySession", 14, },
281 { NFSV4OP_DESTROYCLIENTID, 1, "DestroyClient", 13, },
282 { NFSV4OP_FREESTATEID, 1, "FreeStateID", 11, },
283 { NFSV4OP_LAYOUTGET, 1, "LayoutGet", 9, },
284 { NFSV4OP_GETDEVINFO, 1, "GetDeviceInfo", 13, },
285 { NFSV4OP_LAYOUTCOMMIT, 1, "LayoutCommit", 12, },
286 { NFSV4OP_LAYOUTRETURN, 1, "LayoutReturn", 12, },
287 { NFSV4OP_RECLAIMCOMPL, 1, "ReclaimComplete", 15, },
288 { NFSV4OP_WRITE, 1, "WriteDS", 7, },
289 { NFSV4OP_READ, 1, "ReadDS", 6, },
290 { NFSV4OP_COMMIT, 1, "CommitDS", 8, },
291 { NFSV4OP_OPEN, 3, "OpenLayoutGet", 13, },
292 { NFSV4OP_OPEN, 8, "CreateLayGet", 12, },
293 { NFSV4OP_IOADVISE, 1, "Advise", 6, },
294 { NFSV4OP_ALLOCATE, 2, "Allocate", 8, },
295 { NFSV4OP_SAVEFH, 5, "Copy", 4, },
296 { NFSV4OP_SEEK, 2, "Seek", 4, },
297 { NFSV4OP_SEEK, 1, "SeekDS", 6, },
298 { NFSV4OP_GETXATTR, 2, "Getxattr", 8, },
299 { NFSV4OP_SETXATTR, 2, "Setxattr", 8, },
300 { NFSV4OP_REMOVEXATTR, 2, "Rmxattr", 7, },
301 { NFSV4OP_LISTXATTRS, 2, "Listxattr", 9, },
302 { NFSV4OP_BINDCONNTOSESS, 1, "BindConSess", 11, },
303 { NFSV4OP_LOOKUP, 5, "LookupOpen", 10, },
304 { NFSV4OP_DEALLOCATE, 2, "Deallocate", 10, },
305 { NFSV4OP_LAYOUTERROR, 1, "LayoutError", 11, },
306 { NFSV4OP_VERIFY, 3, "AppendWrite", 11, },
310 * NFS RPCS that have large request message size.
312 static int nfs_bigrequest[NFSV42_NPROCS] = {
313 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
314 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
315 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
320 * Start building a request. Mostly just put the first file handle in
324 nfscl_reqstart(struct nfsrv_descript *nd, int procnum, struct nfsmount *nmp,
325 u_int8_t *nfhp, int fhlen, u_int32_t **opcntpp, struct nfsclsession *sep,
326 int vers, int minorvers, struct ucred *cred)
331 nfsattrbit_t attrbits;
334 * First, fill in some of the fields of nd.
336 nd->nd_slotseq = NULL;
337 if (vers == NFS_VER4) {
338 nd->nd_flag = ND_NFSV4 | ND_NFSCL;
339 if (minorvers == NFSV41_MINORVERSION)
340 nd->nd_flag |= ND_NFSV41;
341 else if (minorvers == NFSV42_MINORVERSION)
342 nd->nd_flag |= (ND_NFSV41 | ND_NFSV42);
343 } else if (vers == NFS_VER3)
344 nd->nd_flag = ND_NFSV3 | ND_NFSCL;
346 if (NFSHASNFSV4(nmp)) {
347 nd->nd_flag = ND_NFSV4 | ND_NFSCL;
348 if (nmp->nm_minorvers == 1)
349 nd->nd_flag |= ND_NFSV41;
350 else if (nmp->nm_minorvers == 2)
351 nd->nd_flag |= (ND_NFSV41 | ND_NFSV42);
352 } else if (NFSHASNFSV3(nmp))
353 nd->nd_flag = ND_NFSV3 | ND_NFSCL;
355 nd->nd_flag = ND_NFSV2 | ND_NFSCL;
357 nd->nd_procnum = procnum;
359 nd->nd_maxextsiz = 0;
362 * Get the first mbuf for the request.
364 if (nfs_bigrequest[procnum])
365 NFSMCLGET(mb, M_WAITOK);
369 nd->nd_mreq = nd->nd_mb = mb;
370 nd->nd_bpos = mtod(mb, char *);
373 * And fill the first file handle into the request.
375 if (nd->nd_flag & ND_NFSV4) {
376 opcnt = nfsv4_opmap[procnum].opcnt +
377 nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh;
378 if ((nd->nd_flag & ND_NFSV41) != 0) {
379 opcnt += nfsv4_opflag[nfsv4_opmap[procnum].op].needsseq;
380 if (procnum == NFSPROC_RENEW)
382 * For the special case of Renew, just do a
386 else if (procnum == NFSPROC_WRITEDS ||
387 procnum == NFSPROC_COMMITDS)
389 * For the special case of a Writeor Commit to
390 * a DS, the opcnt == 3, for Sequence, PutFH,
396 * What should the tag really be?
398 (void) nfsm_strtom(nd, nfsv4_opmap[procnum].tag,
399 nfsv4_opmap[procnum].taglen);
400 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
401 if ((nd->nd_flag & ND_NFSV42) != 0)
402 *tl++ = txdr_unsigned(NFSV42_MINORVERSION);
403 else if ((nd->nd_flag & ND_NFSV41) != 0)
404 *tl++ = txdr_unsigned(NFSV41_MINORVERSION);
406 *tl++ = txdr_unsigned(NFSV4_MINORVERSION);
409 *tl = txdr_unsigned(opcnt);
410 if ((nd->nd_flag & ND_NFSV41) != 0 &&
411 nfsv4_opflag[nfsv4_opmap[procnum].op].needsseq > 0) {
412 if (nfsv4_opflag[nfsv4_opmap[procnum].op].loopbadsess >
414 nd->nd_flag |= ND_LOOPBADSESS;
415 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
416 *tl = txdr_unsigned(NFSV4OP_SEQUENCE);
418 sep = nfsmnt_mdssession(nmp);
420 * For MDS mount sessions, check for bad
421 * slots. If the caller does not want this
422 * check to be done, the "cred" argument can
423 * be passed in as NULL.
425 nfsv4_setsequence(nmp, nd, sep,
426 nfs_bigreply[procnum], cred);
428 nfsv4_setsequence(nmp, nd, sep,
429 nfs_bigreply[procnum], NULL);
431 if (nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh > 0) {
432 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
433 *tl = txdr_unsigned(NFSV4OP_PUTFH);
434 (void) nfsm_fhtom(nd, nfhp, fhlen, 0);
435 if (nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh
436 == 2 && procnum != NFSPROC_WRITEDS &&
437 procnum != NFSPROC_COMMITDS) {
438 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
439 *tl = txdr_unsigned(NFSV4OP_GETATTR);
441 * For Lookup Ops, we want all the directory
442 * attributes, so we can load the name cache.
444 if (procnum == NFSPROC_LOOKUP ||
445 procnum == NFSPROC_LOOKUPP)
446 NFSGETATTR_ATTRBIT(&attrbits);
448 NFSWCCATTR_ATTRBIT(&attrbits);
449 /* For AppendWrite, get the size. */
450 if (procnum == NFSPROC_APPENDWRITE)
451 NFSSETBIT_ATTRBIT(&attrbits,
453 nd->nd_flag |= ND_V4WCCATTR;
455 (void) nfsrv_putattrbit(nd, &attrbits);
458 if (procnum != NFSPROC_RENEW ||
459 (nd->nd_flag & ND_NFSV41) == 0) {
460 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
461 *tl = txdr_unsigned(nfsv4_opmap[procnum].op);
464 (void) nfsm_fhtom(nd, nfhp, fhlen, 0);
466 if (procnum < NFSV42_NPROCS)
467 NFSINCRGLOBAL(nfsstatsv1.rpccnt[procnum]);
471 * Put a state Id in the mbuf list.
474 nfsm_stateidtom(struct nfsrv_descript *nd, nfsv4stateid_t *stateidp, int flag)
478 NFSM_BUILD(st, nfsv4stateid_t *, NFSX_STATEID);
479 if (flag == NFSSTATEID_PUTALLZERO) {
484 } else if (flag == NFSSTATEID_PUTALLONE) {
485 st->seqid = 0xffffffff;
486 st->other[0] = 0xffffffff;
487 st->other[1] = 0xffffffff;
488 st->other[2] = 0xffffffff;
489 } else if (flag == NFSSTATEID_PUTSEQIDZERO) {
491 st->other[0] = stateidp->other[0];
492 st->other[1] = stateidp->other[1];
493 st->other[2] = stateidp->other[2];
495 st->seqid = stateidp->seqid;
496 st->other[0] = stateidp->other[0];
497 st->other[1] = stateidp->other[1];
498 st->other[2] = stateidp->other[2];
503 * Fill in the setable attributes. The full argument indicates whether
504 * to fill in them all or just mode and time.
507 nfscl_fillsattr(struct nfsrv_descript *nd, struct vattr *vap,
508 struct vnode *vp, int flags, u_int32_t rdev)
511 struct nfsv2_sattr *sp;
512 nfsattrbit_t attrbits;
515 switch (nd->nd_flag & (ND_NFSV2 | ND_NFSV3 | ND_NFSV4)) {
517 NFSM_BUILD(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
518 if (vap->va_mode == (mode_t)VNOVAL)
519 sp->sa_mode = newnfs_xdrneg1;
521 sp->sa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
522 if (vap->va_uid == (uid_t)VNOVAL)
523 sp->sa_uid = newnfs_xdrneg1;
525 sp->sa_uid = txdr_unsigned(vap->va_uid);
526 if (vap->va_gid == (gid_t)VNOVAL)
527 sp->sa_gid = newnfs_xdrneg1;
529 sp->sa_gid = txdr_unsigned(vap->va_gid);
530 if (flags & NFSSATTR_SIZE0)
532 else if (flags & NFSSATTR_SIZENEG1)
533 sp->sa_size = newnfs_xdrneg1;
534 else if (flags & NFSSATTR_SIZERDEV)
535 sp->sa_size = txdr_unsigned(rdev);
537 sp->sa_size = txdr_unsigned(vap->va_size);
538 txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
539 txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
542 if (vap->va_mode != (mode_t)VNOVAL) {
543 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
545 *tl = txdr_unsigned(vap->va_mode);
547 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
550 if ((flags & NFSSATTR_FULL) && vap->va_uid != (uid_t)VNOVAL) {
551 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
553 *tl = txdr_unsigned(vap->va_uid);
555 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
558 if ((flags & NFSSATTR_FULL) && vap->va_gid != (gid_t)VNOVAL) {
559 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
561 *tl = txdr_unsigned(vap->va_gid);
563 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
566 if ((flags & NFSSATTR_FULL) && vap->va_size != VNOVAL) {
567 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
569 txdr_hyper(vap->va_size, tl);
571 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
574 if (vap->va_atime.tv_sec != VNOVAL) {
575 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
576 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
577 *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
578 txdr_nfsv3time(&vap->va_atime, tl);
580 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
581 *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
584 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
585 *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
587 if (vap->va_mtime.tv_sec != VNOVAL) {
588 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
589 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
590 *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
591 txdr_nfsv3time(&vap->va_mtime, tl);
593 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
594 *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
597 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
598 *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
602 NFSZERO_ATTRBIT(&attrbits);
603 if (vap->va_mode != (mode_t)VNOVAL)
604 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_MODE);
605 if ((flags & NFSSATTR_FULL) && vap->va_uid != (uid_t)VNOVAL)
606 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
607 if ((flags & NFSSATTR_FULL) && vap->va_gid != (gid_t)VNOVAL)
608 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP);
609 if ((flags & NFSSATTR_FULL) && vap->va_size != VNOVAL)
610 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_SIZE);
611 if (vap->va_atime.tv_sec != VNOVAL)
612 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET);
613 if (vap->va_mtime.tv_sec != VNOVAL)
614 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET);
615 if (vap->va_birthtime.tv_sec != VNOVAL &&
616 strcmp(vp->v_mount->mnt_vfc->vfc_name, "nfs") == 0) {
618 * We can only test for support of TimeCreate if
619 * the "vp" argument is for an NFS vnode.
622 if (NFSISSET_ATTRBIT(&np->n_vattr.na_suppattr,
623 NFSATTRBIT_TIMECREATE))
624 NFSSETBIT_ATTRBIT(&attrbits,
625 NFSATTRBIT_TIMECREATE);
627 (void) nfsv4_fillattr(nd, vp->v_mount, vp, NULL, vap, NULL, 0,
628 &attrbits, NULL, NULL, 0, 0, 0, 0, (uint64_t)0, NULL);
635 * copies mbuf chain to the uio scatter/gather list
638 nfsm_mbufuio(struct nfsrv_descript *nd, struct uio *uiop, int siz)
640 char *mbufcp, *uiocp;
647 mbufcp = nd->nd_dpos;
648 len = mtod(mp, caddr_t) + mp->m_len - mbufcp;
649 rem = NFSM_RNDUP(siz) - siz;
651 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) {
655 left = uiop->uio_iov->iov_len;
656 uiocp = uiop->uio_iov->iov_base;
667 mbufcp = mtod(mp, caddr_t);
670 ("len %d, corrupted mbuf?", len));
672 xfer = (left > len) ? len : left;
675 if (uiop->uio_iov->iov_op != NULL)
676 (*(uiop->uio_iov->iov_op))
677 (mbufcp, uiocp, xfer);
680 if (uiop->uio_segflg == UIO_SYSSPACE)
681 NFSBCOPY(mbufcp, uiocp, xfer);
683 copyout(mbufcp, uiocp, xfer);
688 uiop->uio_offset += xfer;
689 uiop->uio_resid -= xfer;
691 if (uiop->uio_iov->iov_len <= siz) {
695 uiop->uio_iov->iov_base = (void *)
696 ((char *)uiop->uio_iov->iov_base + uiosiz);
697 uiop->uio_iov->iov_len -= uiosiz;
701 nd->nd_dpos = mbufcp;
705 error = nfsm_advance(nd, rem, len);
711 NFSEXITCODE2(error, nd);
717 * Help break down an mbuf chain by setting the first siz bytes contiguous
718 * pointed to by returned val.
719 * This is used by the macro NFSM_DISSECT for tough
723 nfsm_dissct(struct nfsrv_descript *nd, int siz, int how)
732 left = mtod(nd->nd_md, caddr_t) + nd->nd_md->m_len - nd->nd_dpos;
734 nd->nd_md = nd->nd_md->m_next;
735 if (nd->nd_md == NULL)
737 left = nd->nd_md->m_len;
738 nd->nd_dpos = mtod(nd->nd_md, caddr_t);
743 } else if (nd->nd_md->m_next == NULL) {
745 } else if (siz > ncl_mbuf_mhlen) {
746 panic("nfs S too big");
748 MGET(mp2, MT_DATA, how);
751 mp2->m_next = nd->nd_md->m_next;
752 nd->nd_md->m_next = mp2;
753 nd->nd_md->m_len -= left;
755 retp = p = mtod(mp2, caddr_t);
756 NFSBCOPY(nd->nd_dpos, p, left); /* Copy what was left */
760 /* Loop around copying up the siz2 bytes */
764 xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2;
766 NFSBCOPY(mtod(mp2, caddr_t), p, xfer);
775 nd->nd_md->m_len = siz;
777 nd->nd_dpos = mtod(mp2, caddr_t);
783 * Advance the position in the mbuf chain.
784 * If offs == 0, this is a no-op, but it is simpler to just return from
785 * here than check for offs > 0 for all calls to nfsm_advance.
786 * If left == -1, it should be calculated here.
789 nfsm_advance(struct nfsrv_descript *nd, int offs, int left)
796 * A negative offs might indicate a corrupted mbuf chain and,
797 * as such, a printf is logged.
800 printf("nfsrv_advance: negative offs\n");
806 * If left == -1, calculate it here.
809 left = mtod(nd->nd_md, caddr_t) + nd->nd_md->m_len -
813 * Loop around, advancing over the mbuf data.
815 while (offs > left) {
817 nd->nd_md = nd->nd_md->m_next;
818 if (nd->nd_md == NULL) {
822 left = nd->nd_md->m_len;
823 nd->nd_dpos = mtod(nd->nd_md, caddr_t);
833 * Copy a string into mbuf(s).
834 * Return the number of bytes output, including XDR overheads.
837 nfsm_strtom(struct nfsrv_descript *nd, const char *cp, int siz)
846 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
847 *tl = txdr_unsigned(siz);
848 rem = NFSM_RNDUP(siz) - siz;
849 bytesize = NFSX_UNSIGNED + siz + rem;
852 if ((nd->nd_flag & ND_EXTPG) != 0)
853 left = nd->nd_bextpgsiz;
855 left = M_TRAILINGSPACE(m2);
857 KASSERT(((m2->m_flags & (M_EXT | M_EXTPG)) ==
858 (M_EXT | M_EXTPG) && (nd->nd_flag & ND_EXTPG) != 0) ||
859 ((m2->m_flags & (M_EXT | M_EXTPG)) !=
860 (M_EXT | M_EXTPG) && (nd->nd_flag & ND_EXTPG) == 0),
861 ("nfsm_strtom: ext_pgs and non-ext_pgs mbufs mixed"));
863 * Loop around copying the string to mbuf(s).
867 if ((nd->nd_flag & ND_EXTPG) != 0) {
868 m2 = nfsm_add_ext_pgs(m2,
869 nd->nd_maxextsiz, &nd->nd_bextpg);
870 cp2 = (char *)(void *)PHYS_TO_DMAP(
871 m2->m_epg_pa[nd->nd_bextpg]);
872 nd->nd_bextpgsiz = left = PAGE_SIZE;
874 if (siz > ncl_mbuf_mlen)
875 NFSMCLGET(m1, M_WAITOK);
879 cp2 = mtod(m1, char *);
880 left = M_TRAILINGSPACE(m1);
889 NFSBCOPY(cp, cp2, xfer);
895 if ((nd->nd_flag & ND_EXTPG) != 0) {
896 nd->nd_bextpgsiz -= xfer;
897 m2->m_epg_last_len += xfer;
899 if (siz == 0 && rem) {
901 panic("nfsm_strtom");
905 if ((nd->nd_flag & ND_EXTPG) != 0) {
906 nd->nd_bextpgsiz -= rem;
907 m2->m_epg_last_len += rem;
912 if ((nd->nd_flag & ND_EXTPG) != 0)
915 nd->nd_bpos = mtod(m2, char *) + m2->m_len;
920 * Called once to initialize data structures...
925 static int nfs_inited = 0;
931 newnfs_true = txdr_unsigned(TRUE);
932 newnfs_false = txdr_unsigned(FALSE);
933 newnfs_xdrneg1 = txdr_unsigned(-1);
934 nfscl_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
937 NFSSETBOOTTIME(nfsboottime);
940 * Initialize reply list and start timer
942 TAILQ_INIT(&nfsd_reqq);
946 * Put a file handle in an mbuf list.
947 * If the size argument == 0, just use the default size.
948 * set_true == 1 if there should be an newnfs_true prepended on the file handle.
949 * Return the number of bytes output, including XDR overhead.
952 nfsm_fhtom(struct nfsrv_descript *nd, u_int8_t *fhp, int size, int set_true)
956 int fullsiz, rem, bytesize = 0;
960 switch (nd->nd_flag & (ND_NFSV2 | ND_NFSV3 | ND_NFSV4)) {
962 if (size > NFSX_V2FH)
963 panic("fh size > NFSX_V2FH for NFSv2");
964 NFSM_BUILD(cp, u_int8_t *, NFSX_V2FH);
965 NFSBCOPY(fhp, cp, size);
966 if (size < NFSX_V2FH)
967 NFSBZERO(cp + size, NFSX_V2FH - size);
968 bytesize = NFSX_V2FH;
972 fullsiz = NFSM_RNDUP(size);
973 rem = fullsiz - size;
975 bytesize = 2 * NFSX_UNSIGNED + fullsiz;
976 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
979 bytesize = NFSX_UNSIGNED + fullsiz;
981 (void) nfsm_strtom(nd, fhp, size);
988 * This function compares two net addresses by family and returns TRUE
989 * if they are the same host.
990 * If there is any doubt, return FALSE.
991 * The AF_INET family is handled as a special case so that address mbufs
992 * don't need to be saved to store "struct in_addr", which is only 4 bytes.
995 nfsaddr_match(int family, union nethostaddr *haddr, NFSSOCKADDR_T nam)
998 struct sockaddr_in *inetaddr;
1004 inetaddr = NFSSOCKADDR(nam, struct sockaddr_in *);
1005 if (inetaddr->sin_family == AF_INET &&
1006 inetaddr->sin_addr.s_addr == haddr->had_inet.s_addr)
1013 struct sockaddr_in6 *inetaddr6;
1015 inetaddr6 = NFSSOCKADDR(nam, struct sockaddr_in6 *);
1016 /* XXX - should test sin6_scope_id ? */
1017 if (inetaddr6->sin6_family == AF_INET6 &&
1018 IN6_ARE_ADDR_EQUAL(&inetaddr6->sin6_addr,
1029 * Similar to the above, but takes to NFSSOCKADDR_T args.
1032 nfsaddr2_match(NFSSOCKADDR_T nam1, NFSSOCKADDR_T nam2)
1034 struct sockaddr_in *addr1, *addr2;
1035 struct sockaddr *inaddr;
1037 inaddr = NFSSOCKADDR(nam1, struct sockaddr *);
1038 switch (inaddr->sa_family) {
1040 addr1 = NFSSOCKADDR(nam1, struct sockaddr_in *);
1041 addr2 = NFSSOCKADDR(nam2, struct sockaddr_in *);
1042 if (addr2->sin_family == AF_INET &&
1043 addr1->sin_addr.s_addr == addr2->sin_addr.s_addr)
1049 struct sockaddr_in6 *inet6addr1, *inet6addr2;
1051 inet6addr1 = NFSSOCKADDR(nam1, struct sockaddr_in6 *);
1052 inet6addr2 = NFSSOCKADDR(nam2, struct sockaddr_in6 *);
1053 /* XXX - should test sin6_scope_id ? */
1054 if (inet6addr2->sin6_family == AF_INET6 &&
1055 IN6_ARE_ADDR_EQUAL(&inet6addr1->sin6_addr,
1056 &inet6addr2->sin6_addr))
1066 * Dissect a file handle on the client.
1069 nfsm_getfh(struct nfsrv_descript *nd, struct nfsfh **nfhpp)
1076 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
1077 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1078 if ((len = fxdr_unsigned(int, *tl)) <= 0 ||
1085 nfhp = malloc(sizeof (struct nfsfh) + len,
1087 error = nfsrv_mtostr(nd, nfhp->nfh_fh, len);
1089 free(nfhp, M_NFSFH);
1092 nfhp->nfh_len = len;
1095 NFSEXITCODE2(error, nd);
1100 * Break down the nfsv4 acl.
1101 * If the aclp == NULL or won't fit in an acl, just discard the acl info.
1104 nfsrv_dissectacl(struct nfsrv_descript *nd, NFSACL_T *aclp, bool server,
1105 int *aclerrp, int *aclsizep, __unused NFSPROC_T *p)
1109 int acecnt, error = 0, aceerr = 0, acesize;
1115 * Parse out the ace entries and expect them to conform to
1116 * what can be supported by R/W/X bits.
1118 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1119 aclsize = NFSX_UNSIGNED;
1120 acecnt = fxdr_unsigned(int, *tl);
1122 * The RFCs do not define a fixed limit to the number of ACEs in
1123 * an ACL, but 10240 should be more than sufficient.
1125 if (acecnt < 0 || acecnt > 10240) {
1126 error = NFSERR_BADXDR;
1129 if (acecnt > ACL_MAX_ENTRIES)
1130 aceerr = NFSERR_ATTRNOTSUPP;
1131 if (nfsrv_useacl == 0)
1132 aceerr = NFSERR_ATTRNOTSUPP;
1133 for (i = 0; i < acecnt; i++) {
1134 if (aclp && !aceerr)
1135 error = nfsrv_dissectace(nd, &aclp->acl_entry[i],
1136 server, &aceerr, &acesize, p);
1138 error = nfsrv_skipace(nd, &acesize);
1143 if (aclp && !aceerr)
1144 aclp->acl_cnt = acecnt;
1148 *aclsizep = aclsize;
1150 NFSEXITCODE2(error, nd);
1155 * Skip over an NFSv4 ace entry. Just dissect the xdr and discard it.
1158 nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep)
1163 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1164 len = fxdr_unsigned(int, *(tl + 3));
1165 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
1167 *acesizep = NFSM_RNDUP(len) + (4 * NFSX_UNSIGNED);
1168 NFSEXITCODE2(error, nd);
1173 * Get attribute bits from an mbuf list.
1174 * Returns EBADRPC for a parsing error, 0 otherwise.
1175 * If the clearinvalid flag is set, clear the bits not supported.
1178 nfsrv_getattrbits(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp, int *cntp,
1185 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1186 cnt = fxdr_unsigned(int, *tl);
1188 error = NFSERR_BADXDR;
1191 if (cnt > NFSATTRBIT_MAXWORDS)
1192 outcnt = NFSATTRBIT_MAXWORDS;
1195 NFSZERO_ATTRBIT(attrbitp);
1197 NFSM_DISSECT(tl, u_int32_t *, outcnt * NFSX_UNSIGNED);
1198 for (i = 0; i < outcnt; i++)
1199 attrbitp->bits[i] = fxdr_unsigned(u_int32_t, *tl++);
1201 for (i = 0; i < (cnt - outcnt); i++) {
1202 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1203 if (retnotsupp != NULL && *tl != 0)
1204 *retnotsupp = NFSERR_ATTRNOTSUPP;
1207 *cntp = NFSX_UNSIGNED + (cnt * NFSX_UNSIGNED);
1209 NFSEXITCODE2(error, nd);
1214 * Get the attributes for V4.
1215 * If the compare flag is true, test for any attribute changes,
1216 * otherwise return the attribute values.
1217 * These attributes cover fields in "struct vattr", "struct statfs",
1218 * "struct nfsfsinfo", the file handle and the lease duration.
1219 * The value of retcmpp is set to 1 if all attributes are the same,
1221 * Returns EBADRPC if it can't be parsed, 0 otherwise.
1224 nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp,
1225 struct nfsvattr *nap, struct nfsfh **nfhpp, fhandle_t *fhp, int fhsize,
1226 struct nfsv3_pathconf *pc, struct statfs *sbp, struct nfsstatfs *sfp,
1227 struct nfsfsinfo *fsp, NFSACL_T *aclp, int compare, int *retcmpp,
1228 u_int32_t *leasep, u_int32_t *rderrp, NFSPROC_T *p, struct ucred *cred)
1231 int i = 0, j, k, l = 0, m, bitpos, attrsum = 0;
1232 int error, tfhsize, aceerr, attrsize, cnt, retnotsup;
1233 u_char *cp, *cp2, namestr[NFSV4_SMALLSTR + 1];
1234 nfsattrbit_t attrbits, retattrbits, checkattrbits;
1235 struct nfsfh *tnfhp;
1236 struct nfsreferral *refp;
1239 struct timespec temptime;
1242 u_int32_t freenum = 0, tuint;
1243 u_int64_t uquad = 0, thyp, thyp2;
1249 CTASSERT(sizeof(ino_t) == sizeof(uint64_t));
1252 error = nfsrv_getattrbits(nd, &attrbits, NULL, &retnotsup);
1254 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
1260 *retcmpp = retnotsup;
1263 * Just set default values to some of the important ones.
1266 nap->na_type = VREG;
1268 nap->na_rdev = (NFSDEV_T)0;
1269 nap->na_mtime.tv_sec = 0;
1270 nap->na_mtime.tv_nsec = 0;
1271 nap->na_btime.tv_sec = -1;
1272 nap->na_btime.tv_nsec = 0;
1275 nap->na_blocksize = NFS_FABLKSIZE;
1278 sbp->f_bsize = NFS_FABLKSIZE;
1286 fsp->fs_rtmax = 8192;
1287 fsp->fs_rtpref = 8192;
1288 fsp->fs_maxname = NFS_MAXNAMLEN;
1289 fsp->fs_wtmax = 8192;
1290 fsp->fs_wtpref = 8192;
1291 fsp->fs_wtmult = NFS_FABLKSIZE;
1292 fsp->fs_dtpref = 8192;
1293 fsp->fs_maxfilesize = 0xffffffffffffffffull;
1294 fsp->fs_timedelta.tv_sec = 0;
1295 fsp->fs_timedelta.tv_nsec = 1;
1296 fsp->fs_properties = (NFSV3_FSFLINK | NFSV3_FSFSYMLINK |
1297 NFSV3_FSFHOMOGENEOUS | NFSV3_FSFCANSETTIME);
1300 pc->pc_linkmax = NFS_LINK_MAX;
1301 pc->pc_namemax = NAME_MAX;
1303 pc->pc_chownrestricted = 0;
1304 pc->pc_caseinsensitive = 0;
1305 pc->pc_casepreserving = 1;
1308 sfp->sf_ffiles = UINT64_MAX;
1309 sfp->sf_tfiles = UINT64_MAX;
1310 sfp->sf_afiles = UINT64_MAX;
1311 sfp->sf_fbytes = UINT64_MAX;
1312 sfp->sf_tbytes = UINT64_MAX;
1313 sfp->sf_abytes = UINT64_MAX;
1318 * Loop around getting the attributes.
1320 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1321 attrsize = fxdr_unsigned(int, *tl);
1322 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
1323 if (attrsum > attrsize) {
1324 error = NFSERR_BADXDR;
1327 if (NFSISSET_ATTRBIT(&attrbits, bitpos))
1329 case NFSATTRBIT_SUPPORTEDATTRS:
1331 if (compare || nap == NULL)
1332 error = nfsrv_getattrbits(nd, &retattrbits,
1335 error = nfsrv_getattrbits(nd, &nap->na_suppattr,
1339 if (compare && !(*retcmpp)) {
1340 NFSSETSUPP_ATTRBIT(&checkattrbits, nd);
1342 /* Some filesystem do not support NFSv4ACL */
1343 if (nfsrv_useacl == 0 || nfs_supportsnfsv4acls(vp) == 0) {
1344 NFSCLRBIT_ATTRBIT(&checkattrbits, NFSATTRBIT_ACL);
1345 NFSCLRBIT_ATTRBIT(&checkattrbits, NFSATTRBIT_ACLSUPPORT);
1347 if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
1349 *retcmpp = NFSERR_NOTSAME;
1353 case NFSATTRBIT_TYPE:
1354 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1357 if (nap->na_type != nfsv34tov_type(*tl))
1358 *retcmpp = NFSERR_NOTSAME;
1360 } else if (nap != NULL) {
1361 nap->na_type = nfsv34tov_type(*tl);
1363 attrsum += NFSX_UNSIGNED;
1365 case NFSATTRBIT_FHEXPIRETYPE:
1366 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1367 if (compare && !(*retcmpp)) {
1368 if (fxdr_unsigned(int, *tl) !=
1369 NFSV4FHTYPE_PERSISTENT)
1370 *retcmpp = NFSERR_NOTSAME;
1372 attrsum += NFSX_UNSIGNED;
1374 case NFSATTRBIT_CHANGE:
1375 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1378 if (nap->na_filerev != fxdr_hyper(tl))
1379 *retcmpp = NFSERR_NOTSAME;
1381 } else if (nap != NULL) {
1382 nap->na_filerev = fxdr_hyper(tl);
1384 attrsum += NFSX_HYPER;
1386 case NFSATTRBIT_SIZE:
1387 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1390 if (nap->na_size != fxdr_hyper(tl))
1391 *retcmpp = NFSERR_NOTSAME;
1393 } else if (nap != NULL) {
1394 nap->na_size = fxdr_hyper(tl);
1396 attrsum += NFSX_HYPER;
1398 case NFSATTRBIT_LINKSUPPORT:
1399 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1402 if (fsp->fs_properties & NFSV3_FSFLINK) {
1403 if (*tl == newnfs_false)
1404 *retcmpp = NFSERR_NOTSAME;
1406 if (*tl == newnfs_true)
1407 *retcmpp = NFSERR_NOTSAME;
1410 } else if (fsp != NULL) {
1411 if (*tl == newnfs_true)
1412 fsp->fs_properties |= NFSV3_FSFLINK;
1414 fsp->fs_properties &= ~NFSV3_FSFLINK;
1416 attrsum += NFSX_UNSIGNED;
1418 case NFSATTRBIT_SYMLINKSUPPORT:
1419 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1422 if (fsp->fs_properties & NFSV3_FSFSYMLINK) {
1423 if (*tl == newnfs_false)
1424 *retcmpp = NFSERR_NOTSAME;
1426 if (*tl == newnfs_true)
1427 *retcmpp = NFSERR_NOTSAME;
1430 } else if (fsp != NULL) {
1431 if (*tl == newnfs_true)
1432 fsp->fs_properties |= NFSV3_FSFSYMLINK;
1434 fsp->fs_properties &= ~NFSV3_FSFSYMLINK;
1436 attrsum += NFSX_UNSIGNED;
1438 case NFSATTRBIT_NAMEDATTR:
1439 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1440 if (compare && !(*retcmpp)) {
1441 if (*tl != newnfs_false)
1442 *retcmpp = NFSERR_NOTSAME;
1444 attrsum += NFSX_UNSIGNED;
1446 case NFSATTRBIT_FSID:
1447 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1448 thyp = fxdr_hyper(tl);
1450 thyp2 = fxdr_hyper(tl);
1452 if (*retcmpp == 0) {
1453 if (thyp != (u_int64_t)
1454 vp->v_mount->mnt_stat.f_fsid.val[0] ||
1455 thyp2 != (u_int64_t)
1456 vp->v_mount->mnt_stat.f_fsid.val[1])
1457 *retcmpp = NFSERR_NOTSAME;
1459 } else if (nap != NULL) {
1460 nap->na_filesid[0] = thyp;
1461 nap->na_filesid[1] = thyp2;
1463 attrsum += (4 * NFSX_UNSIGNED);
1465 case NFSATTRBIT_UNIQUEHANDLES:
1466 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1467 if (compare && !(*retcmpp)) {
1468 if (*tl != newnfs_true)
1469 *retcmpp = NFSERR_NOTSAME;
1471 attrsum += NFSX_UNSIGNED;
1473 case NFSATTRBIT_LEASETIME:
1474 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1476 if (fxdr_unsigned(int, *tl) != nfsrv_lease &&
1478 *retcmpp = NFSERR_NOTSAME;
1479 } else if (leasep != NULL) {
1480 *leasep = fxdr_unsigned(u_int32_t, *tl);
1482 attrsum += NFSX_UNSIGNED;
1484 case NFSATTRBIT_RDATTRERROR:
1485 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1488 *retcmpp = NFSERR_INVAL;
1489 } else if (rderrp != NULL) {
1490 *rderrp = fxdr_unsigned(u_int32_t, *tl);
1492 attrsum += NFSX_UNSIGNED;
1494 case NFSATTRBIT_ACL:
1497 if (nfsrv_useacl && nfs_supportsnfsv4acls(vp)) {
1500 naclp = acl_alloc(M_WAITOK);
1501 error = nfsrv_dissectacl(nd, naclp, true,
1507 if (aceerr || aclp == NULL ||
1508 nfsrv_compareacl(aclp, naclp))
1509 *retcmpp = NFSERR_NOTSAME;
1512 error = nfsrv_dissectacl(nd, NULL, true,
1516 *retcmpp = NFSERR_ATTRNOTSUPP;
1520 if (vp != NULL && aclp != NULL)
1521 error = nfsrv_dissectacl(nd, aclp, false,
1524 error = nfsrv_dissectacl(nd, NULL, false,
1532 case NFSATTRBIT_ACLSUPPORT:
1533 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1534 if (compare && !(*retcmpp)) {
1535 if (nfsrv_useacl && nfs_supportsnfsv4acls(vp)) {
1536 if (fxdr_unsigned(u_int32_t, *tl) !=
1538 *retcmpp = NFSERR_NOTSAME;
1540 *retcmpp = NFSERR_ATTRNOTSUPP;
1543 attrsum += NFSX_UNSIGNED;
1545 case NFSATTRBIT_ARCHIVE:
1546 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1547 if (compare && !(*retcmpp))
1548 *retcmpp = NFSERR_ATTRNOTSUPP;
1549 attrsum += NFSX_UNSIGNED;
1551 case NFSATTRBIT_CANSETTIME:
1552 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1555 if (fsp->fs_properties & NFSV3_FSFCANSETTIME) {
1556 if (*tl == newnfs_false)
1557 *retcmpp = NFSERR_NOTSAME;
1559 if (*tl == newnfs_true)
1560 *retcmpp = NFSERR_NOTSAME;
1563 } else if (fsp != NULL) {
1564 if (*tl == newnfs_true)
1565 fsp->fs_properties |= NFSV3_FSFCANSETTIME;
1567 fsp->fs_properties &= ~NFSV3_FSFCANSETTIME;
1569 attrsum += NFSX_UNSIGNED;
1571 case NFSATTRBIT_CASEINSENSITIVE:
1572 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1575 if (*tl != newnfs_false)
1576 *retcmpp = NFSERR_NOTSAME;
1578 } else if (pc != NULL) {
1579 pc->pc_caseinsensitive =
1580 fxdr_unsigned(u_int32_t, *tl);
1582 attrsum += NFSX_UNSIGNED;
1584 case NFSATTRBIT_CASEPRESERVING:
1585 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1588 if (*tl != newnfs_true)
1589 *retcmpp = NFSERR_NOTSAME;
1591 } else if (pc != NULL) {
1592 pc->pc_casepreserving =
1593 fxdr_unsigned(u_int32_t, *tl);
1595 attrsum += NFSX_UNSIGNED;
1597 case NFSATTRBIT_CHOWNRESTRICTED:
1598 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1601 if (*tl != newnfs_true)
1602 *retcmpp = NFSERR_NOTSAME;
1604 } else if (pc != NULL) {
1605 pc->pc_chownrestricted =
1606 fxdr_unsigned(u_int32_t, *tl);
1608 attrsum += NFSX_UNSIGNED;
1610 case NFSATTRBIT_FILEHANDLE:
1611 error = nfsm_getfh(nd, &tnfhp);
1614 tfhsize = tnfhp->nfh_len;
1617 !NFSRV_CMPFH(tnfhp->nfh_fh, tfhsize,
1619 *retcmpp = NFSERR_NOTSAME;
1620 free(tnfhp, M_NFSFH);
1621 } else if (nfhpp != NULL) {
1624 free(tnfhp, M_NFSFH);
1626 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(tfhsize));
1628 case NFSATTRBIT_FILEID:
1629 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1630 thyp = fxdr_hyper(tl);
1633 if (nap->na_fileid != thyp)
1634 *retcmpp = NFSERR_NOTSAME;
1636 } else if (nap != NULL)
1637 nap->na_fileid = thyp;
1638 attrsum += NFSX_HYPER;
1640 case NFSATTRBIT_FILESAVAIL:
1641 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1643 uquad = nfsv4_filesavail(sbp, vp->v_mount);
1644 if (!(*retcmpp) && uquad != fxdr_hyper(tl))
1645 *retcmpp = NFSERR_NOTSAME;
1646 } else if (sfp != NULL) {
1647 sfp->sf_afiles = fxdr_hyper(tl);
1649 attrsum += NFSX_HYPER;
1651 case NFSATTRBIT_FILESFREE:
1652 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1654 uquad = (uint64_t)sbp->f_ffree;
1655 if (!(*retcmpp) && uquad != fxdr_hyper(tl))
1656 *retcmpp = NFSERR_NOTSAME;
1657 } else if (sfp != NULL) {
1658 sfp->sf_ffiles = fxdr_hyper(tl);
1660 attrsum += NFSX_HYPER;
1662 case NFSATTRBIT_FILESTOTAL:
1663 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1665 uquad = sbp->f_files;
1666 if (!(*retcmpp) && uquad != fxdr_hyper(tl))
1667 *retcmpp = NFSERR_NOTSAME;
1668 } else if (sfp != NULL) {
1669 sfp->sf_tfiles = fxdr_hyper(tl);
1671 attrsum += NFSX_HYPER;
1673 case NFSATTRBIT_FSLOCATIONS:
1674 error = nfsrv_getrefstr(nd, &cp, &cp2, &l, &m);
1678 if (compare && !(*retcmpp)) {
1679 refp = nfsv4root_getreferral(vp, NULL, 0);
1681 if (cp == NULL || cp2 == NULL ||
1683 strcmp(cp2, refp->nfr_srvlist))
1684 *retcmpp = NFSERR_NOTSAME;
1685 } else if (m == 0) {
1686 *retcmpp = NFSERR_NOTSAME;
1690 free(cp, M_NFSSTRING);
1692 free(cp2, M_NFSSTRING);
1694 case NFSATTRBIT_HIDDEN:
1695 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1696 if (compare && !(*retcmpp))
1697 *retcmpp = NFSERR_ATTRNOTSUPP;
1698 attrsum += NFSX_UNSIGNED;
1700 case NFSATTRBIT_HOMOGENEOUS:
1701 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1704 if (fsp->fs_properties &
1705 NFSV3_FSFHOMOGENEOUS) {
1706 if (*tl == newnfs_false)
1707 *retcmpp = NFSERR_NOTSAME;
1709 if (*tl == newnfs_true)
1710 *retcmpp = NFSERR_NOTSAME;
1713 } else if (fsp != NULL) {
1714 if (*tl == newnfs_true)
1715 fsp->fs_properties |= NFSV3_FSFHOMOGENEOUS;
1717 fsp->fs_properties &= ~NFSV3_FSFHOMOGENEOUS;
1719 attrsum += NFSX_UNSIGNED;
1721 case NFSATTRBIT_MAXFILESIZE:
1722 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1723 tnfsquad.qval = fxdr_hyper(tl);
1726 tquad = NFSRV_MAXFILESIZE;
1727 if (tquad != tnfsquad.qval)
1728 *retcmpp = NFSERR_NOTSAME;
1730 } else if (fsp != NULL) {
1731 fsp->fs_maxfilesize = tnfsquad.qval;
1733 attrsum += NFSX_HYPER;
1735 case NFSATTRBIT_MAXLINK:
1736 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1739 if (fxdr_unsigned(int, *tl) != NFS_LINK_MAX)
1740 *retcmpp = NFSERR_NOTSAME;
1742 } else if (pc != NULL) {
1743 pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl);
1745 attrsum += NFSX_UNSIGNED;
1747 case NFSATTRBIT_MAXNAME:
1748 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1751 if (fsp->fs_maxname !=
1752 fxdr_unsigned(u_int32_t, *tl))
1753 *retcmpp = NFSERR_NOTSAME;
1756 tuint = fxdr_unsigned(u_int32_t, *tl);
1758 * Some Linux NFSv4 servers report this
1759 * as 0 or 4billion, so I'll set it to
1760 * NFS_MAXNAMLEN. If a server actually creates
1761 * a name longer than NFS_MAXNAMLEN, it will
1762 * get an error back.
1764 if (tuint == 0 || tuint > NFS_MAXNAMLEN)
1765 tuint = NFS_MAXNAMLEN;
1767 fsp->fs_maxname = tuint;
1769 pc->pc_namemax = tuint;
1771 attrsum += NFSX_UNSIGNED;
1773 case NFSATTRBIT_MAXREAD:
1774 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1777 if (fsp->fs_rtmax != fxdr_unsigned(u_int32_t,
1778 *(tl + 1)) || *tl != 0)
1779 *retcmpp = NFSERR_NOTSAME;
1781 } else if (fsp != NULL) {
1782 fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *++tl);
1783 fsp->fs_rtpref = fsp->fs_rtmax;
1784 fsp->fs_dtpref = fsp->fs_rtpref;
1786 attrsum += NFSX_HYPER;
1788 case NFSATTRBIT_MAXWRITE:
1789 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1792 if (fsp->fs_wtmax != fxdr_unsigned(u_int32_t,
1793 *(tl + 1)) || *tl != 0)
1794 *retcmpp = NFSERR_NOTSAME;
1796 } else if (fsp != NULL) {
1797 fsp->fs_wtmax = fxdr_unsigned(int, *++tl);
1798 fsp->fs_wtpref = fsp->fs_wtmax;
1800 attrsum += NFSX_HYPER;
1802 case NFSATTRBIT_MIMETYPE:
1803 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1804 i = fxdr_unsigned(int, *tl);
1805 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(i));
1806 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
1809 if (compare && !(*retcmpp))
1810 *retcmpp = NFSERR_ATTRNOTSUPP;
1812 case NFSATTRBIT_MODE:
1813 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1816 if (nap->na_mode != nfstov_mode(*tl))
1817 *retcmpp = NFSERR_NOTSAME;
1819 } else if (nap != NULL) {
1820 nap->na_mode = nfstov_mode(*tl);
1822 attrsum += NFSX_UNSIGNED;
1824 case NFSATTRBIT_NOTRUNC:
1825 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1828 if (*tl != newnfs_true)
1829 *retcmpp = NFSERR_NOTSAME;
1831 } else if (pc != NULL) {
1832 pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl);
1834 attrsum += NFSX_UNSIGNED;
1836 case NFSATTRBIT_NUMLINKS:
1837 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1838 tuint = fxdr_unsigned(u_int32_t, *tl);
1841 if ((u_int32_t)nap->na_nlink != tuint)
1842 *retcmpp = NFSERR_NOTSAME;
1844 } else if (nap != NULL) {
1845 nap->na_nlink = tuint;
1847 attrsum += NFSX_UNSIGNED;
1849 case NFSATTRBIT_OWNER:
1850 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1851 j = fxdr_unsigned(int, *tl);
1852 if (j < 0 || j > NFSV4_MAXOWNERGROUPLEN) {
1853 error = NFSERR_BADXDR;
1856 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1857 if (j > NFSV4_SMALLSTR)
1858 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1861 error = nfsrv_mtostr(nd, cp, j);
1863 if (j > NFSV4_SMALLSTR)
1864 free(cp, M_NFSSTRING);
1869 if (nfsv4_strtouid(nd, cp, j, &uid) ||
1871 *retcmpp = NFSERR_NOTSAME;
1873 } else if (nap != NULL) {
1874 if (nfsv4_strtouid(nd, cp, j, &uid))
1875 nap->na_uid = nfsrv_defaultuid;
1879 if (j > NFSV4_SMALLSTR)
1880 free(cp, M_NFSSTRING);
1882 case NFSATTRBIT_OWNERGROUP:
1883 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1884 j = fxdr_unsigned(int, *tl);
1885 if (j < 0 || j > NFSV4_MAXOWNERGROUPLEN) {
1886 error = NFSERR_BADXDR;
1889 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1890 if (j > NFSV4_SMALLSTR)
1891 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1894 error = nfsrv_mtostr(nd, cp, j);
1896 if (j > NFSV4_SMALLSTR)
1897 free(cp, M_NFSSTRING);
1902 if (nfsv4_strtogid(nd, cp, j, &gid) ||
1904 *retcmpp = NFSERR_NOTSAME;
1906 } else if (nap != NULL) {
1907 if (nfsv4_strtogid(nd, cp, j, &gid))
1908 nap->na_gid = nfsrv_defaultgid;
1912 if (j > NFSV4_SMALLSTR)
1913 free(cp, M_NFSSTRING);
1915 case NFSATTRBIT_QUOTAHARD:
1916 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1918 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA))
1919 freenum = sbp->f_bfree;
1921 freenum = sbp->f_bavail;
1924 * ufs_quotactl() insists that the uid argument
1925 * equal p_ruid for non-root quota access, so
1926 * we'll just make sure that's the case.
1928 savuid = p->p_cred->p_ruid;
1929 p->p_cred->p_ruid = cred->cr_uid;
1930 if (!VFS_QUOTACTL(vp->v_mount,QCMD(Q_GETQUOTA,
1931 USRQUOTA), cred->cr_uid, &dqb))
1932 freenum = min(dqb.dqb_bhardlimit, freenum);
1933 p->p_cred->p_ruid = savuid;
1935 uquad = (u_int64_t)freenum;
1936 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1938 if (compare && !(*retcmpp)) {
1939 if (uquad != fxdr_hyper(tl))
1940 *retcmpp = NFSERR_NOTSAME;
1942 attrsum += NFSX_HYPER;
1944 case NFSATTRBIT_QUOTASOFT:
1945 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1947 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA))
1948 freenum = sbp->f_bfree;
1950 freenum = sbp->f_bavail;
1953 * ufs_quotactl() insists that the uid argument
1954 * equal p_ruid for non-root quota access, so
1955 * we'll just make sure that's the case.
1957 savuid = p->p_cred->p_ruid;
1958 p->p_cred->p_ruid = cred->cr_uid;
1959 if (!VFS_QUOTACTL(vp->v_mount,QCMD(Q_GETQUOTA,
1960 USRQUOTA), cred->cr_uid, &dqb))
1961 freenum = min(dqb.dqb_bsoftlimit, freenum);
1962 p->p_cred->p_ruid = savuid;
1964 uquad = (u_int64_t)freenum;
1965 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1967 if (compare && !(*retcmpp)) {
1968 if (uquad != fxdr_hyper(tl))
1969 *retcmpp = NFSERR_NOTSAME;
1971 attrsum += NFSX_HYPER;
1973 case NFSATTRBIT_QUOTAUSED:
1974 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1979 * ufs_quotactl() insists that the uid argument
1980 * equal p_ruid for non-root quota access, so
1981 * we'll just make sure that's the case.
1983 savuid = p->p_cred->p_ruid;
1984 p->p_cred->p_ruid = cred->cr_uid;
1985 if (!VFS_QUOTACTL(vp->v_mount,QCMD(Q_GETQUOTA,
1986 USRQUOTA), cred->cr_uid, &dqb))
1987 freenum = dqb.dqb_curblocks;
1988 p->p_cred->p_ruid = savuid;
1990 uquad = (u_int64_t)freenum;
1991 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1993 if (compare && !(*retcmpp)) {
1994 if (uquad != fxdr_hyper(tl))
1995 *retcmpp = NFSERR_NOTSAME;
1997 attrsum += NFSX_HYPER;
1999 case NFSATTRBIT_RAWDEV:
2000 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4SPECDATA);
2001 j = fxdr_unsigned(int, *tl++);
2002 k = fxdr_unsigned(int, *tl);
2005 if (nap->na_rdev != NFSMAKEDEV(j, k))
2006 *retcmpp = NFSERR_NOTSAME;
2008 } else if (nap != NULL) {
2009 nap->na_rdev = NFSMAKEDEV(j, k);
2011 attrsum += NFSX_V4SPECDATA;
2013 case NFSATTRBIT_SPACEAVAIL:
2014 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2016 if (priv_check_cred(cred,
2017 PRIV_VFS_BLOCKRESERVE))
2018 uquad = sbp->f_bfree;
2020 uquad = (uint64_t)sbp->f_bavail;
2021 uquad *= sbp->f_bsize;
2022 if (!(*retcmpp) && uquad != fxdr_hyper(tl))
2023 *retcmpp = NFSERR_NOTSAME;
2024 } else if (sfp != NULL) {
2025 sfp->sf_abytes = fxdr_hyper(tl);
2027 attrsum += NFSX_HYPER;
2029 case NFSATTRBIT_SPACEFREE:
2030 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2032 uquad = sbp->f_bfree;
2033 uquad *= sbp->f_bsize;
2034 if (!(*retcmpp) && uquad != fxdr_hyper(tl))
2035 *retcmpp = NFSERR_NOTSAME;
2036 } else if (sfp != NULL) {
2037 sfp->sf_fbytes = fxdr_hyper(tl);
2039 attrsum += NFSX_HYPER;
2041 case NFSATTRBIT_SPACETOTAL:
2042 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2044 uquad = sbp->f_blocks;
2045 uquad *= sbp->f_bsize;
2046 if (!(*retcmpp) && uquad != fxdr_hyper(tl))
2047 *retcmpp = NFSERR_NOTSAME;
2048 } else if (sfp != NULL) {
2049 sfp->sf_tbytes = fxdr_hyper(tl);
2051 attrsum += NFSX_HYPER;
2053 case NFSATTRBIT_SPACEUSED:
2054 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2055 thyp = fxdr_hyper(tl);
2058 if ((u_int64_t)nap->na_bytes != thyp)
2059 *retcmpp = NFSERR_NOTSAME;
2061 } else if (nap != NULL) {
2062 nap->na_bytes = thyp;
2064 attrsum += NFSX_HYPER;
2066 case NFSATTRBIT_SYSTEM:
2067 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2068 if (compare && !(*retcmpp))
2069 *retcmpp = NFSERR_ATTRNOTSUPP;
2070 attrsum += NFSX_UNSIGNED;
2072 case NFSATTRBIT_TIMEACCESS:
2073 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2074 fxdr_nfsv4time(tl, &temptime);
2077 if (!NFS_CMPTIME(temptime, nap->na_atime))
2078 *retcmpp = NFSERR_NOTSAME;
2080 } else if (nap != NULL) {
2081 nap->na_atime = temptime;
2083 attrsum += NFSX_V4TIME;
2085 case NFSATTRBIT_TIMEACCESSSET:
2086 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2087 attrsum += NFSX_UNSIGNED;
2088 i = fxdr_unsigned(int, *tl);
2089 if (i == NFSV4SATTRTIME_TOCLIENT) {
2090 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2091 attrsum += NFSX_V4TIME;
2093 if (compare && !(*retcmpp))
2094 *retcmpp = NFSERR_INVAL;
2096 case NFSATTRBIT_TIMEBACKUP:
2097 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2098 if (compare && !(*retcmpp))
2099 *retcmpp = NFSERR_ATTRNOTSUPP;
2100 attrsum += NFSX_V4TIME;
2102 case NFSATTRBIT_TIMECREATE:
2103 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2104 fxdr_nfsv4time(tl, &temptime);
2107 if (!NFS_CMPTIME(temptime, nap->na_btime))
2108 *retcmpp = NFSERR_NOTSAME;
2110 } else if (nap != NULL) {
2111 nap->na_btime = temptime;
2113 attrsum += NFSX_V4TIME;
2115 case NFSATTRBIT_TIMEDELTA:
2116 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2120 if ((u_int32_t)fsp->fs_timedelta.tv_sec !=
2121 fxdr_unsigned(u_int32_t, *(tl + 1)) ||
2122 (u_int32_t)fsp->fs_timedelta.tv_nsec !=
2123 (fxdr_unsigned(u_int32_t, *(tl + 2)) %
2126 *retcmpp = NFSERR_NOTSAME;
2129 fxdr_nfsv4time(tl, &fsp->fs_timedelta);
2132 attrsum += NFSX_V4TIME;
2134 case NFSATTRBIT_TIMEMETADATA:
2135 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2136 fxdr_nfsv4time(tl, &temptime);
2139 if (!NFS_CMPTIME(temptime, nap->na_ctime))
2140 *retcmpp = NFSERR_NOTSAME;
2142 } else if (nap != NULL) {
2143 nap->na_ctime = temptime;
2145 attrsum += NFSX_V4TIME;
2147 case NFSATTRBIT_TIMEMODIFY:
2148 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2149 fxdr_nfsv4time(tl, &temptime);
2152 if (!NFS_CMPTIME(temptime, nap->na_mtime))
2153 *retcmpp = NFSERR_NOTSAME;
2155 } else if (nap != NULL) {
2156 nap->na_mtime = temptime;
2158 attrsum += NFSX_V4TIME;
2160 case NFSATTRBIT_TIMEMODIFYSET:
2161 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2162 attrsum += NFSX_UNSIGNED;
2163 i = fxdr_unsigned(int, *tl);
2164 if (i == NFSV4SATTRTIME_TOCLIENT) {
2165 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2166 attrsum += NFSX_V4TIME;
2168 if (compare && !(*retcmpp))
2169 *retcmpp = NFSERR_INVAL;
2171 case NFSATTRBIT_MOUNTEDONFILEID:
2172 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2173 thyp = fxdr_hyper(tl);
2176 if (!vp || !nfsrv_atroot(vp, &thyp2))
2177 thyp2 = nap->na_fileid;
2179 *retcmpp = NFSERR_NOTSAME;
2181 } else if (nap != NULL)
2182 nap->na_mntonfileno = thyp;
2183 attrsum += NFSX_HYPER;
2185 case NFSATTRBIT_SUPPATTREXCLCREAT:
2187 error = nfsrv_getattrbits(nd, &retattrbits,
2191 if (compare && !(*retcmpp)) {
2192 NFSSETSUPP_ATTRBIT(&checkattrbits, nd);
2193 NFSCLRNOTSETABLE_ATTRBIT(&checkattrbits, nd);
2194 NFSCLRBIT_ATTRBIT(&checkattrbits,
2195 NFSATTRBIT_TIMEACCESSSET);
2196 if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
2198 *retcmpp = NFSERR_NOTSAME;
2202 case NFSATTRBIT_FSLAYOUTTYPE:
2203 case NFSATTRBIT_LAYOUTTYPE:
2204 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2205 attrsum += NFSX_UNSIGNED;
2206 i = fxdr_unsigned(int, *tl);
2208 * The RFCs do not define an upper limit for the
2209 * number of layout types, but 32 should be more
2212 if (i < 0 || i > 32) {
2213 error = NFSERR_BADXDR;
2217 NFSM_DISSECT(tl, u_int32_t *, i *
2219 attrsum += i * NFSX_UNSIGNED;
2220 j = fxdr_unsigned(int, *tl);
2221 if (i == 1 && compare && !(*retcmpp) &&
2222 (((nfsrv_doflexfile != 0 ||
2223 nfsrv_maxpnfsmirror > 1) &&
2224 j != NFSLAYOUT_FLEXFILE) ||
2225 (nfsrv_doflexfile == 0 &&
2226 j != NFSLAYOUT_NFSV4_1_FILES)))
2227 *retcmpp = NFSERR_NOTSAME;
2229 if (nfsrv_devidcnt == 0) {
2230 if (compare && !(*retcmpp) && i > 0)
2231 *retcmpp = NFSERR_NOTSAME;
2233 if (compare && !(*retcmpp) && i != 1)
2234 *retcmpp = NFSERR_NOTSAME;
2237 case NFSATTRBIT_LAYOUTALIGNMENT:
2238 case NFSATTRBIT_LAYOUTBLKSIZE:
2239 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2240 attrsum += NFSX_UNSIGNED;
2241 i = fxdr_unsigned(int, *tl);
2242 if (compare && !(*retcmpp) && i != nfs_srvmaxio)
2243 *retcmpp = NFSERR_NOTSAME;
2246 printf("EEK! nfsv4_loadattr unknown attr=%d\n",
2248 if (compare && !(*retcmpp))
2249 *retcmpp = NFSERR_ATTRNOTSUPP;
2251 * and get out of the loop, since we can't parse
2252 * the unknown attrbute data.
2254 bitpos = NFSATTRBIT_MAX;
2260 * some clients pad the attrlist, so we need to skip over the
2263 if (attrsum > attrsize) {
2264 error = NFSERR_BADXDR;
2266 attrsize = NFSM_RNDUP(attrsize);
2267 if (attrsum < attrsize)
2268 error = nfsm_advance(nd, attrsize - attrsum, -1);
2271 NFSEXITCODE2(error, nd);
2276 * Implement sleep locks for newnfs. The nfslock_usecnt allows for a
2277 * shared lock and the NFSXXX_LOCK flag permits an exclusive lock.
2278 * The first argument is a pointer to an nfsv4lock structure.
2279 * The second argument is 1 iff a blocking lock is wanted.
2280 * If this argument is 0, the call waits until no thread either wants nor
2281 * holds an exclusive lock.
2282 * It returns 1 if the lock was acquired, 0 otherwise.
2283 * If several processes call this function concurrently wanting the exclusive
2284 * lock, one will get the lock and the rest will return without getting the
2285 * lock. (If the caller must have the lock, it simply calls this function in a
2286 * loop until the function returns 1 to indicate the lock was acquired.)
2287 * Any usecnt must be decremented by calling nfsv4_relref() before
2288 * calling nfsv4_lock(). It was done this way, so nfsv4_lock() could
2289 * be called in a loop.
2290 * The isleptp argument is set to indicate if the call slept, iff not NULL
2291 * and the mp argument indicates to check for a forced dismount, iff not
2295 nfsv4_lock(struct nfsv4lock *lp, int iwantlock, int *isleptp,
2296 struct mtx *mutex, struct mount *mp)
2302 * If a lock is wanted, loop around until the lock is acquired by
2303 * someone and then released. If I want the lock, try to acquire it.
2304 * For a lock to be issued, no lock must be in force and the usecnt
2308 if (!(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
2309 lp->nfslock_usecnt == 0) {
2310 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
2311 lp->nfslock_lock |= NFSV4LOCK_LOCK;
2314 lp->nfslock_lock |= NFSV4LOCK_LOCKWANTED;
2316 while (lp->nfslock_lock & (NFSV4LOCK_LOCK | NFSV4LOCK_LOCKWANTED)) {
2317 if (mp != NULL && NFSCL_FORCEDISM(mp)) {
2318 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
2321 lp->nfslock_lock |= NFSV4LOCK_WANTED;
2324 msleep(&lp->nfslock_lock, mutex, PVFS, "nfsv4lck", hz);
2325 if (iwantlock && !(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
2326 lp->nfslock_usecnt == 0) {
2327 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
2328 lp->nfslock_lock |= NFSV4LOCK_LOCK;
2336 * Release the lock acquired by nfsv4_lock().
2337 * The second argument is set to 1 to indicate the nfslock_usecnt should be
2338 * incremented, as well.
2341 nfsv4_unlock(struct nfsv4lock *lp, int incref)
2344 lp->nfslock_lock &= ~NFSV4LOCK_LOCK;
2346 lp->nfslock_usecnt++;
2351 * Release a reference cnt.
2354 nfsv4_relref(struct nfsv4lock *lp)
2357 if (lp->nfslock_usecnt <= 0)
2358 panic("nfsv4root ref cnt");
2359 lp->nfslock_usecnt--;
2360 if (lp->nfslock_usecnt == 0)
2365 * Get a reference cnt.
2366 * This function will wait for any exclusive lock to be released, but will
2367 * not wait for threads that want the exclusive lock. If priority needs
2368 * to be given to threads that need the exclusive lock, a call to nfsv4_lock()
2369 * with the 2nd argument == 0 should be done before calling nfsv4_getref().
2370 * If the mp argument is not NULL, check for NFSCL_FORCEDISM() being set and
2371 * return without getting a refcnt for that case.
2374 nfsv4_getref(struct nfsv4lock *lp, int *isleptp, struct mtx *mutex,
2382 * Wait for a lock held.
2384 while (lp->nfslock_lock & NFSV4LOCK_LOCK) {
2385 if (mp != NULL && NFSCL_FORCEDISM(mp))
2387 lp->nfslock_lock |= NFSV4LOCK_WANTED;
2390 msleep(&lp->nfslock_lock, mutex, PVFS, "nfsv4gr", hz);
2392 if (mp != NULL && NFSCL_FORCEDISM(mp))
2395 lp->nfslock_usecnt++;
2399 * Get a reference as above, but return failure instead of sleeping if
2400 * an exclusive lock is held.
2403 nfsv4_getref_nonblock(struct nfsv4lock *lp)
2406 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) != 0)
2409 lp->nfslock_usecnt++;
2414 * Test for a lock. Return 1 if locked, 0 otherwise.
2417 nfsv4_testlock(struct nfsv4lock *lp)
2420 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) == 0 &&
2421 lp->nfslock_usecnt == 0)
2427 * Wake up anyone sleeping, waiting for this lock.
2430 nfsv4_wanted(struct nfsv4lock *lp)
2433 if (lp->nfslock_lock & NFSV4LOCK_WANTED) {
2434 lp->nfslock_lock &= ~NFSV4LOCK_WANTED;
2435 wakeup((caddr_t)&lp->nfslock_lock);
2440 * Copy a string from an mbuf list into a character array.
2441 * Return EBADRPC if there is an mbuf error,
2445 nfsrv_mtostr(struct nfsrv_descript *nd, char *str, int siz)
2454 len = mtod(mp, caddr_t) + mp->m_len - cp;
2455 rem = NFSM_RNDUP(siz) - siz;
2461 NFSBCOPY(cp, str, xfer);
2470 cp = mtod(mp, caddr_t);
2482 error = nfsm_advance(nd, rem, len);
2488 NFSEXITCODE2(error, nd);
2493 * Fill in the attributes as marked by the bitmap (V4).
2496 nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp,
2497 NFSACL_T *saclp, struct vattr *vap, fhandle_t *fhp, int rderror,
2498 nfsattrbit_t *attrbitp, struct ucred *cred, NFSPROC_T *p, int isdgram,
2499 int reterr, int supports_nfsv4acls, int at_root, uint64_t mounted_on_fileno,
2500 struct statfs *pnfssf)
2502 int bitpos, retnum = 0;
2504 int siz, prefixnum, error;
2505 u_char *cp, namestr[NFSV4_SMALLSTR];
2506 nfsattrbit_t attrbits, retbits;
2507 nfsattrbit_t *retbitp = &retbits;
2508 u_int32_t freenum, *retnump;
2511 struct nfsfsinfo fsinf;
2512 struct timespec temptime;
2513 NFSACL_T *aclp, *naclp = NULL;
2522 * First, set the bits that can be filled and get fsinfo.
2524 NFSSET_ATTRBIT(retbitp, attrbitp);
2526 * If both p and cred are NULL, it is a client side setattr call.
2527 * If both p and cred are not NULL, it is a server side reply call.
2528 * If p is not NULL and cred is NULL, it is a client side callback
2531 if (p == NULL && cred == NULL) {
2532 NFSCLRNOTSETABLE_ATTRBIT(retbitp, nd);
2535 NFSCLRNOTFILLABLE_ATTRBIT(retbitp, nd);
2536 naclp = acl_alloc(M_WAITOK);
2539 nfsvno_getfs(&fsinf, isdgram);
2542 * Get the VFS_STATFS(), since some attributes need them.
2544 fs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
2545 if (NFSISSETSTATFS_ATTRBIT(retbitp)) {
2546 error = VFS_STATFS(mp, fs);
2549 nd->nd_repstat = NFSERR_ACCES;
2553 NFSCLRSTATFS_ATTRBIT(retbitp);
2556 * Since NFS handles these values as unsigned on the
2557 * wire, there is no way to represent negative values,
2558 * so set them to 0. Without this, they will appear
2559 * to be very large positive values for clients like
2562 if (fs->f_bavail < 0)
2564 if (fs->f_ffree < 0)
2570 * And the NFSv4 ACL...
2572 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT) &&
2573 (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2574 supports_nfsv4acls == 0))) {
2575 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT);
2577 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACL)) {
2578 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2579 supports_nfsv4acls == 0)) {
2580 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2581 } else if (naclp != NULL) {
2582 if (NFSVOPLOCK(vp, LK_SHARED) == 0) {
2583 error = VOP_ACCESSX(vp, VREAD_ACL, cred, p);
2585 error = VOP_GETACL(vp, ACL_TYPE_NFS4,
2589 error = NFSERR_PERM;
2592 nd->nd_repstat = NFSERR_ACCES;
2596 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2601 /* Check to see if Extended Attributes are supported. */
2603 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_XATTRSUPPORT)) {
2604 if (NFSVOPLOCK(vp, LK_SHARED) == 0) {
2605 error = VOP_GETEXTATTR(vp, EXTATTR_NAMESPACE_USER,
2606 "xxx", NULL, &atsiz, cred, p);
2608 if (error != EOPNOTSUPP)
2614 * Put out the attribute bitmap for the ones being filled in
2615 * and get the field for the number of attributes returned.
2617 prefixnum = nfsrv_putattrbit(nd, retbitp);
2618 NFSM_BUILD(retnump, u_int32_t *, NFSX_UNSIGNED);
2619 prefixnum += NFSX_UNSIGNED;
2622 * Now, loop around filling in the attributes for each bit set.
2624 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
2625 if (NFSISSET_ATTRBIT(retbitp, bitpos)) {
2627 case NFSATTRBIT_SUPPORTEDATTRS:
2628 NFSSETSUPP_ATTRBIT(&attrbits, nd);
2629 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL)
2630 && supports_nfsv4acls == 0)) {
2631 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACLSUPPORT);
2632 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACL);
2634 retnum += nfsrv_putattrbit(nd, &attrbits);
2636 case NFSATTRBIT_TYPE:
2637 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2638 *tl = vtonfsv34_type(vap->va_type);
2639 retnum += NFSX_UNSIGNED;
2641 case NFSATTRBIT_FHEXPIRETYPE:
2642 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2643 *tl = txdr_unsigned(NFSV4FHTYPE_PERSISTENT);
2644 retnum += NFSX_UNSIGNED;
2646 case NFSATTRBIT_CHANGE:
2647 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2648 txdr_hyper(vap->va_filerev, tl);
2649 retnum += NFSX_HYPER;
2651 case NFSATTRBIT_SIZE:
2652 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2653 txdr_hyper(vap->va_size, tl);
2654 retnum += NFSX_HYPER;
2656 case NFSATTRBIT_LINKSUPPORT:
2657 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2658 if (fsinf.fs_properties & NFSV3FSINFO_LINK)
2662 retnum += NFSX_UNSIGNED;
2664 case NFSATTRBIT_SYMLINKSUPPORT:
2665 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2666 if (fsinf.fs_properties & NFSV3FSINFO_SYMLINK)
2670 retnum += NFSX_UNSIGNED;
2672 case NFSATTRBIT_NAMEDATTR:
2673 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2675 retnum += NFSX_UNSIGNED;
2677 case NFSATTRBIT_FSID:
2678 NFSM_BUILD(tl, u_int32_t *, NFSX_V4FSID);
2680 *tl++ = txdr_unsigned(mp->mnt_stat.f_fsid.val[0]);
2682 *tl = txdr_unsigned(mp->mnt_stat.f_fsid.val[1]);
2683 retnum += NFSX_V4FSID;
2685 case NFSATTRBIT_UNIQUEHANDLES:
2686 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2688 retnum += NFSX_UNSIGNED;
2690 case NFSATTRBIT_LEASETIME:
2691 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2692 *tl = txdr_unsigned(nfsrv_lease);
2693 retnum += NFSX_UNSIGNED;
2695 case NFSATTRBIT_RDATTRERROR:
2696 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2697 *tl = txdr_unsigned(rderror);
2698 retnum += NFSX_UNSIGNED;
2701 * Recommended Attributes. (Only the supported ones.)
2703 case NFSATTRBIT_ACL:
2704 retnum += nfsrv_buildacl(nd, aclp, vnode_vtype(vp), p);
2706 case NFSATTRBIT_ACLSUPPORT:
2707 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2708 *tl = txdr_unsigned(NFSV4ACE_SUPTYPES);
2709 retnum += NFSX_UNSIGNED;
2711 case NFSATTRBIT_CANSETTIME:
2712 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2713 if (fsinf.fs_properties & NFSV3FSINFO_CANSETTIME)
2717 retnum += NFSX_UNSIGNED;
2719 case NFSATTRBIT_CASEINSENSITIVE:
2720 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2722 retnum += NFSX_UNSIGNED;
2724 case NFSATTRBIT_CASEPRESERVING:
2725 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2727 retnum += NFSX_UNSIGNED;
2729 case NFSATTRBIT_CHOWNRESTRICTED:
2730 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2732 retnum += NFSX_UNSIGNED;
2734 case NFSATTRBIT_FILEHANDLE:
2735 retnum += nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
2737 case NFSATTRBIT_FILEID:
2738 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2739 uquad = vap->va_fileid;
2740 txdr_hyper(uquad, tl);
2741 retnum += NFSX_HYPER;
2743 case NFSATTRBIT_FILESAVAIL:
2744 freenum = nfsv4_filesavail(fs, mp);
2745 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2747 *tl = txdr_unsigned(freenum);
2748 retnum += NFSX_HYPER;
2750 case NFSATTRBIT_FILESFREE:
2751 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2753 *tl = txdr_unsigned(fs->f_ffree);
2754 retnum += NFSX_HYPER;
2756 case NFSATTRBIT_FILESTOTAL:
2757 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2759 *tl = txdr_unsigned(fs->f_files);
2760 retnum += NFSX_HYPER;
2762 case NFSATTRBIT_FSLOCATIONS:
2763 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2766 retnum += 2 * NFSX_UNSIGNED;
2768 case NFSATTRBIT_HOMOGENEOUS:
2769 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2770 if (fsinf.fs_properties & NFSV3FSINFO_HOMOGENEOUS)
2774 retnum += NFSX_UNSIGNED;
2776 case NFSATTRBIT_MAXFILESIZE:
2777 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2778 uquad = NFSRV_MAXFILESIZE;
2779 txdr_hyper(uquad, tl);
2780 retnum += NFSX_HYPER;
2782 case NFSATTRBIT_MAXLINK:
2783 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2784 *tl = txdr_unsigned(NFS_LINK_MAX);
2785 retnum += NFSX_UNSIGNED;
2787 case NFSATTRBIT_MAXNAME:
2788 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2789 *tl = txdr_unsigned(NFS_MAXNAMLEN);
2790 retnum += NFSX_UNSIGNED;
2792 case NFSATTRBIT_MAXREAD:
2793 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2795 *tl = txdr_unsigned(fsinf.fs_rtmax);
2796 retnum += NFSX_HYPER;
2798 case NFSATTRBIT_MAXWRITE:
2799 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2801 *tl = txdr_unsigned(fsinf.fs_wtmax);
2802 retnum += NFSX_HYPER;
2804 case NFSATTRBIT_MODE:
2805 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2806 *tl = vtonfsv34_mode(vap->va_mode);
2807 retnum += NFSX_UNSIGNED;
2809 case NFSATTRBIT_NOTRUNC:
2810 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2812 retnum += NFSX_UNSIGNED;
2814 case NFSATTRBIT_NUMLINKS:
2815 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2816 *tl = txdr_unsigned(vap->va_nlink);
2817 retnum += NFSX_UNSIGNED;
2819 case NFSATTRBIT_OWNER:
2821 nfsv4_uidtostr(vap->va_uid, &cp, &siz);
2822 retnum += nfsm_strtom(nd, cp, siz);
2824 free(cp, M_NFSSTRING);
2826 case NFSATTRBIT_OWNERGROUP:
2828 nfsv4_gidtostr(vap->va_gid, &cp, &siz);
2829 retnum += nfsm_strtom(nd, cp, siz);
2831 free(cp, M_NFSSTRING);
2833 case NFSATTRBIT_QUOTAHARD:
2834 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA))
2835 freenum = fs->f_bfree;
2837 freenum = fs->f_bavail;
2840 * ufs_quotactl() insists that the uid argument
2841 * equal p_ruid for non-root quota access, so
2842 * we'll just make sure that's the case.
2844 savuid = p->p_cred->p_ruid;
2845 p->p_cred->p_ruid = cred->cr_uid;
2846 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2847 cred->cr_uid, &dqb))
2848 freenum = min(dqb.dqb_bhardlimit, freenum);
2849 p->p_cred->p_ruid = savuid;
2851 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2852 uquad = (u_int64_t)freenum;
2853 NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
2854 txdr_hyper(uquad, tl);
2855 retnum += NFSX_HYPER;
2857 case NFSATTRBIT_QUOTASOFT:
2858 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA))
2859 freenum = fs->f_bfree;
2861 freenum = fs->f_bavail;
2864 * ufs_quotactl() insists that the uid argument
2865 * equal p_ruid for non-root quota access, so
2866 * we'll just make sure that's the case.
2868 savuid = p->p_cred->p_ruid;
2869 p->p_cred->p_ruid = cred->cr_uid;
2870 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2871 cred->cr_uid, &dqb))
2872 freenum = min(dqb.dqb_bsoftlimit, freenum);
2873 p->p_cred->p_ruid = savuid;
2875 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2876 uquad = (u_int64_t)freenum;
2877 NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
2878 txdr_hyper(uquad, tl);
2879 retnum += NFSX_HYPER;
2881 case NFSATTRBIT_QUOTAUSED:
2885 * ufs_quotactl() insists that the uid argument
2886 * equal p_ruid for non-root quota access, so
2887 * we'll just make sure that's the case.
2889 savuid = p->p_cred->p_ruid;
2890 p->p_cred->p_ruid = cred->cr_uid;
2891 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2892 cred->cr_uid, &dqb))
2893 freenum = dqb.dqb_curblocks;
2894 p->p_cred->p_ruid = savuid;
2896 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2897 uquad = (u_int64_t)freenum;
2898 NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
2899 txdr_hyper(uquad, tl);
2900 retnum += NFSX_HYPER;
2902 case NFSATTRBIT_RAWDEV:
2903 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SPECDATA);
2904 *tl++ = txdr_unsigned(NFSMAJOR(vap->va_rdev));
2905 *tl = txdr_unsigned(NFSMINOR(vap->va_rdev));
2906 retnum += NFSX_V4SPECDATA;
2908 case NFSATTRBIT_SPACEAVAIL:
2909 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2910 if (priv_check_cred(cred, PRIV_VFS_BLOCKRESERVE)) {
2912 uquad = (u_int64_t)pnfssf->f_bfree;
2914 uquad = (u_int64_t)fs->f_bfree;
2917 uquad = (u_int64_t)pnfssf->f_bavail;
2919 uquad = (u_int64_t)fs->f_bavail;
2922 uquad *= pnfssf->f_bsize;
2924 uquad *= fs->f_bsize;
2925 txdr_hyper(uquad, tl);
2926 retnum += NFSX_HYPER;
2928 case NFSATTRBIT_SPACEFREE:
2929 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2930 if (pnfssf != NULL) {
2931 uquad = (u_int64_t)pnfssf->f_bfree;
2932 uquad *= pnfssf->f_bsize;
2934 uquad = (u_int64_t)fs->f_bfree;
2935 uquad *= fs->f_bsize;
2937 txdr_hyper(uquad, tl);
2938 retnum += NFSX_HYPER;
2940 case NFSATTRBIT_SPACETOTAL:
2941 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2942 if (pnfssf != NULL) {
2943 uquad = (u_int64_t)pnfssf->f_blocks;
2944 uquad *= pnfssf->f_bsize;
2946 uquad = (u_int64_t)fs->f_blocks;
2947 uquad *= fs->f_bsize;
2949 txdr_hyper(uquad, tl);
2950 retnum += NFSX_HYPER;
2952 case NFSATTRBIT_SPACEUSED:
2953 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2954 txdr_hyper(vap->va_bytes, tl);
2955 retnum += NFSX_HYPER;
2957 case NFSATTRBIT_TIMEACCESS:
2958 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2959 txdr_nfsv4time(&vap->va_atime, tl);
2960 retnum += NFSX_V4TIME;
2962 case NFSATTRBIT_TIMEACCESSSET:
2963 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2964 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2965 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2966 txdr_nfsv4time(&vap->va_atime, tl);
2967 retnum += NFSX_V4SETTIME;
2969 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2970 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2971 retnum += NFSX_UNSIGNED;
2974 case NFSATTRBIT_TIMEDELTA:
2975 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2976 temptime.tv_sec = 0;
2977 temptime.tv_nsec = 1000000000 / hz;
2978 txdr_nfsv4time(&temptime, tl);
2979 retnum += NFSX_V4TIME;
2981 case NFSATTRBIT_TIMEMETADATA:
2982 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2983 txdr_nfsv4time(&vap->va_ctime, tl);
2984 retnum += NFSX_V4TIME;
2986 case NFSATTRBIT_TIMEMODIFY:
2987 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2988 txdr_nfsv4time(&vap->va_mtime, tl);
2989 retnum += NFSX_V4TIME;
2991 case NFSATTRBIT_TIMECREATE:
2992 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2993 txdr_nfsv4time(&vap->va_birthtime, tl);
2994 retnum += NFSX_V4TIME;
2996 case NFSATTRBIT_TIMEMODIFYSET:
2997 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2998 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2999 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
3000 txdr_nfsv4time(&vap->va_mtime, tl);
3001 retnum += NFSX_V4SETTIME;
3003 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3004 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
3005 retnum += NFSX_UNSIGNED;
3008 case NFSATTRBIT_MOUNTEDONFILEID:
3009 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
3011 uquad = mounted_on_fileno;
3013 uquad = vap->va_fileid;
3014 txdr_hyper(uquad, tl);
3015 retnum += NFSX_HYPER;
3017 case NFSATTRBIT_SUPPATTREXCLCREAT:
3018 NFSSETSUPP_ATTRBIT(&attrbits, nd);
3019 NFSCLRNOTSETABLE_ATTRBIT(&attrbits, nd);
3020 NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET);
3021 retnum += nfsrv_putattrbit(nd, &attrbits);
3023 case NFSATTRBIT_FSLAYOUTTYPE:
3024 case NFSATTRBIT_LAYOUTTYPE:
3025 if (nfsrv_devidcnt == 0)
3030 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3031 *tl++ = txdr_unsigned(1); /* One entry. */
3032 if (nfsrv_doflexfile != 0 ||
3033 nfsrv_maxpnfsmirror > 1)
3034 *tl = txdr_unsigned(NFSLAYOUT_FLEXFILE);
3036 *tl = txdr_unsigned(
3037 NFSLAYOUT_NFSV4_1_FILES);
3039 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3042 retnum += siz * NFSX_UNSIGNED;
3044 case NFSATTRBIT_LAYOUTALIGNMENT:
3045 case NFSATTRBIT_LAYOUTBLKSIZE:
3046 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3047 *tl = txdr_unsigned(nfs_srvmaxio);
3048 retnum += NFSX_UNSIGNED;
3050 case NFSATTRBIT_XATTRSUPPORT:
3051 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3056 retnum += NFSX_UNSIGNED;
3059 printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos);
3066 *retnump = txdr_unsigned(retnum);
3067 return (retnum + prefixnum);
3071 * Calculate the files available attribute value.
3074 nfsv4_filesavail(struct statfs *fs, struct mount *mp)
3084 * Check quota and use min(quota, f_ffree).
3086 freenum = fs->f_ffree;
3089 * This is old OpenBSD code that does not build
3090 * for FreeBSD. I do not know if doing this is
3091 * useful, so I will just leave the code here.
3095 * ufs_quotactl() insists that the uid argument
3096 * equal p_ruid for non-root quota access, so
3097 * we'll just make sure that's the case.
3099 savuid = p->p_cred->p_ruid;
3100 p->p_cred->p_ruid = cred->cr_uid;
3101 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
3102 cred->cr_uid, &dqb))
3103 freenum = min(dqb.dqb_isoftlimit-dqb.dqb_curinodes,
3105 p->p_cred->p_ruid = savuid;
3111 * Put the attribute bits onto an mbuf list.
3112 * Return the number of bytes of output generated.
3115 nfsrv_putattrbit(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp)
3118 int cnt, i, bytesize;
3120 for (cnt = NFSATTRBIT_MAXWORDS; cnt > 0; cnt--)
3121 if (attrbitp->bits[cnt - 1])
3123 bytesize = (cnt + 1) * NFSX_UNSIGNED;
3124 NFSM_BUILD(tl, u_int32_t *, bytesize);
3125 *tl++ = txdr_unsigned(cnt);
3126 for (i = 0; i < cnt; i++)
3127 *tl++ = txdr_unsigned(attrbitp->bits[i]);
3132 * Convert a uid to a string.
3133 * If the lookup fails, just output the digits.
3135 * cpp - points to a buffer of size NFSV4_SMALLSTR
3136 * (malloc a larger one, as required)
3137 * retlenp - pointer to length to be returned
3140 nfsv4_uidtostr(uid_t uid, u_char **cpp, int *retlenp)
3143 struct nfsusrgrp *usrp;
3146 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
3147 struct nfsrv_lughash *hp;
3151 if (nfsrv_dnsnamelen > 0 && !nfs_enable_uidtostring) {
3153 * Always map nfsrv_defaultuid to "nobody".
3155 if (uid == nfsrv_defaultuid) {
3156 i = nfsrv_dnsnamelen + 7;
3158 if (len > NFSV4_SMALLSTR)
3159 free(cp, M_NFSSTRING);
3160 cp = malloc(i, M_NFSSTRING, M_WAITOK);
3166 NFSBCOPY("nobody@", cp, 7);
3168 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
3172 hp = NFSUSERHASH(uid);
3174 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
3175 if (usrp->lug_uid == uid) {
3176 if (usrp->lug_expiry < NFSD_MONOSEC)
3179 * If the name doesn't already have an '@'
3180 * in it, append @domainname to it.
3182 for (i = 0; i < usrp->lug_namelen; i++) {
3183 if (usrp->lug_name[i] == '@') {
3189 i = usrp->lug_namelen;
3191 i = usrp->lug_namelen +
3192 nfsrv_dnsnamelen + 1;
3194 mtx_unlock(&hp->mtx);
3195 if (len > NFSV4_SMALLSTR)
3196 free(cp, M_NFSSTRING);
3197 cp = malloc(i, M_NFSSTRING, M_WAITOK);
3203 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
3204 if (!hasampersand) {
3205 cp += usrp->lug_namelen;
3207 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
3209 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3210 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
3212 mtx_unlock(&hp->mtx);
3216 mtx_unlock(&hp->mtx);
3218 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0, NULL);
3219 if (ret == 0 && cnt < 2)
3224 * No match, just return a string of digits.
3228 while (tmp || i == 0) {
3232 len = (i > len) ? len : i;
3236 for (i = 0; i < len; i++) {
3237 *cp-- = '0' + (tmp % 10);
3244 * Get a credential for the uid with the server's group list.
3245 * If none is found, just return the credential passed in after
3246 * logging a warning message.
3249 nfsrv_getgrpscred(struct ucred *oldcred)
3251 struct nfsusrgrp *usrp;
3252 struct ucred *newcred;
3255 struct nfsrv_lughash *hp;
3258 uid = oldcred->cr_uid;
3260 if (nfsrv_dnsnamelen > 0) {
3261 hp = NFSUSERHASH(uid);
3263 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
3264 if (usrp->lug_uid == uid) {
3265 if (usrp->lug_expiry < NFSD_MONOSEC)
3267 if (usrp->lug_cred != NULL) {
3268 newcred = crhold(usrp->lug_cred);
3272 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3273 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
3275 mtx_unlock(&hp->mtx);
3279 mtx_unlock(&hp->mtx);
3281 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0, NULL);
3282 if (ret == 0 && cnt < 2)
3289 * Convert a string to a uid.
3290 * If no conversion is possible return NFSERR_BADOWNER, otherwise
3292 * If this is called from a client side mount using AUTH_SYS and the
3293 * string is made up entirely of digits, just convert the string to
3297 nfsv4_strtouid(struct nfsrv_descript *nd, u_char *str, int len, uid_t *uidp)
3300 char *cp, *endstr, *str0;
3301 struct nfsusrgrp *usrp;
3305 struct nfsrv_lughash *hp, *hp2;
3308 error = NFSERR_BADOWNER;
3311 /* If a string of digits and an AUTH_SYS mount, just convert it. */
3313 tuid = (uid_t)strtoul(str0, &endstr, 10);
3314 if ((endstr - str0) == len) {
3315 /* A numeric string. */
3316 if ((nd->nd_flag & ND_KERBV) == 0 &&
3317 ((nd->nd_flag & ND_NFSCL) != 0 ||
3318 nfsd_enable_stringtouid != 0))
3321 error = NFSERR_BADOWNER;
3327 cp = strchr(str0, '@');
3329 i = (int)(cp++ - str0);
3335 if (nfsrv_dnsnamelen > 0) {
3337 * If an '@' is found and the domain name matches, search for
3338 * the name with dns stripped off.
3339 * Mixed case alpahbetics will match for the domain name, but
3340 * all upper case will not.
3342 if (cnt == 0 && i < len && i > 0 &&
3343 (len - 1 - i) == nfsrv_dnsnamelen &&
3344 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
3345 len -= (nfsrv_dnsnamelen + 1);
3350 * Check for the special case of "nobody".
3352 if (len == 6 && !NFSBCMP(str, "nobody", 6)) {
3353 *uidp = nfsrv_defaultuid;
3358 hp = NFSUSERNAMEHASH(str, len);
3360 TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) {
3361 if (usrp->lug_namelen == len &&
3362 !NFSBCMP(usrp->lug_name, str, len)) {
3363 if (usrp->lug_expiry < NFSD_MONOSEC)
3365 hp2 = NFSUSERHASH(usrp->lug_uid);
3366 mtx_lock(&hp2->mtx);
3367 TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash);
3368 TAILQ_INSERT_TAIL(&hp2->lughead, usrp,
3370 *uidp = usrp->lug_uid;
3371 mtx_unlock(&hp2->mtx);
3372 mtx_unlock(&hp->mtx);
3377 mtx_unlock(&hp->mtx);
3379 ret = nfsrv_getuser(RPCNFSUSERD_GETUSER, (uid_t)0, (gid_t)0,
3381 if (ret == 0 && cnt < 2)
3384 error = NFSERR_BADOWNER;
3392 * Convert a gid to a string.
3393 * gid - the group id
3394 * cpp - points to a buffer of size NFSV4_SMALLSTR
3395 * (malloc a larger one, as required)
3396 * retlenp - pointer to length to be returned
3399 nfsv4_gidtostr(gid_t gid, u_char **cpp, int *retlenp)
3402 struct nfsusrgrp *usrp;
3405 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
3406 struct nfsrv_lughash *hp;
3410 if (nfsrv_dnsnamelen > 0 && !nfs_enable_uidtostring) {
3412 * Always map nfsrv_defaultgid to "nogroup".
3414 if (gid == nfsrv_defaultgid) {
3415 i = nfsrv_dnsnamelen + 8;
3417 if (len > NFSV4_SMALLSTR)
3418 free(cp, M_NFSSTRING);
3419 cp = malloc(i, M_NFSSTRING, M_WAITOK);
3425 NFSBCOPY("nogroup@", cp, 8);
3427 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
3431 hp = NFSGROUPHASH(gid);
3433 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
3434 if (usrp->lug_gid == gid) {
3435 if (usrp->lug_expiry < NFSD_MONOSEC)
3438 * If the name doesn't already have an '@'
3439 * in it, append @domainname to it.
3441 for (i = 0; i < usrp->lug_namelen; i++) {
3442 if (usrp->lug_name[i] == '@') {
3448 i = usrp->lug_namelen;
3450 i = usrp->lug_namelen +
3451 nfsrv_dnsnamelen + 1;
3453 mtx_unlock(&hp->mtx);
3454 if (len > NFSV4_SMALLSTR)
3455 free(cp, M_NFSSTRING);
3456 cp = malloc(i, M_NFSSTRING, M_WAITOK);
3462 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
3463 if (!hasampersand) {
3464 cp += usrp->lug_namelen;
3466 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
3468 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3469 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
3471 mtx_unlock(&hp->mtx);
3475 mtx_unlock(&hp->mtx);
3477 ret = nfsrv_getuser(RPCNFSUSERD_GETGID, (uid_t)0, gid, NULL);
3478 if (ret == 0 && cnt < 2)
3483 * No match, just return a string of digits.
3487 while (tmp || i == 0) {
3491 len = (i > len) ? len : i;
3495 for (i = 0; i < len; i++) {
3496 *cp-- = '0' + (tmp % 10);
3503 * Convert a string to a gid.
3504 * If no conversion is possible return NFSERR_BADOWNER, otherwise
3506 * If this is called from a client side mount using AUTH_SYS and the
3507 * string is made up entirely of digits, just convert the string to
3511 nfsv4_strtogid(struct nfsrv_descript *nd, u_char *str, int len, gid_t *gidp)
3514 char *cp, *endstr, *str0;
3515 struct nfsusrgrp *usrp;
3519 struct nfsrv_lughash *hp, *hp2;
3522 error = NFSERR_BADOWNER;
3525 /* If a string of digits and an AUTH_SYS mount, just convert it. */
3527 tgid = (gid_t)strtoul(str0, &endstr, 10);
3528 if ((endstr - str0) == len) {
3529 /* A numeric string. */
3530 if ((nd->nd_flag & ND_KERBV) == 0 &&
3531 ((nd->nd_flag & ND_NFSCL) != 0 ||
3532 nfsd_enable_stringtouid != 0))
3535 error = NFSERR_BADOWNER;
3541 cp = strchr(str0, '@');
3543 i = (int)(cp++ - str0);
3549 if (nfsrv_dnsnamelen > 0) {
3551 * If an '@' is found and the dns name matches, search for the
3552 * name with the dns stripped off.
3554 if (cnt == 0 && i < len && i > 0 &&
3555 (len - 1 - i) == nfsrv_dnsnamelen &&
3556 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
3557 len -= (nfsrv_dnsnamelen + 1);
3562 * Check for the special case of "nogroup".
3564 if (len == 7 && !NFSBCMP(str, "nogroup", 7)) {
3565 *gidp = nfsrv_defaultgid;
3570 hp = NFSGROUPNAMEHASH(str, len);
3572 TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) {
3573 if (usrp->lug_namelen == len &&
3574 !NFSBCMP(usrp->lug_name, str, len)) {
3575 if (usrp->lug_expiry < NFSD_MONOSEC)
3577 hp2 = NFSGROUPHASH(usrp->lug_gid);
3578 mtx_lock(&hp2->mtx);
3579 TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash);
3580 TAILQ_INSERT_TAIL(&hp2->lughead, usrp,
3582 *gidp = usrp->lug_gid;
3583 mtx_unlock(&hp2->mtx);
3584 mtx_unlock(&hp->mtx);
3589 mtx_unlock(&hp->mtx);
3591 ret = nfsrv_getuser(RPCNFSUSERD_GETGROUP, (uid_t)0, (gid_t)0,
3593 if (ret == 0 && cnt < 2)
3596 error = NFSERR_BADOWNER;
3604 * Cmp len chars, allowing mixed case in the first argument to match lower
3605 * case in the second, but not if the first argument is all upper case.
3606 * Return 0 for a match, 1 otherwise.
3609 nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len)
3615 for (i = 0; i < len; i++) {
3616 if (*cp >= 'A' && *cp <= 'Z') {
3617 tmp = *cp++ + ('a' - 'A');
3620 if (tmp >= 'a' && tmp <= 'z')
3633 * Set the port for the nfsuserd.
3636 nfsrv_nfsuserdport(struct nfsuserd_args *nargs, NFSPROC_T *p)
3638 struct nfssockreq *rp;
3640 struct sockaddr_in *ad;
3643 struct sockaddr_in6 *ad6;
3644 const struct in6_addr in6loopback = IN6ADDR_LOOPBACK_INIT;
3649 if (nfsrv_nfsuserd != NOTRUNNING) {
3654 nfsrv_nfsuserd = STARTSTOP;
3656 * Set up the socket record and connect.
3657 * Set nr_client NULL before unlocking, just to ensure that no other
3658 * process/thread/core will use a bogus old value. This could only
3659 * occur if the use of the nameid lock to protect nfsrv_nfsuserd is
3662 rp = &nfsrv_nfsuserdsock;
3663 rp->nr_client = NULL;
3665 rp->nr_sotype = SOCK_DGRAM;
3666 rp->nr_soproto = IPPROTO_UDP;
3667 rp->nr_lock = (NFSR_RESERVEDPORT | NFSR_LOCALHOST);
3669 rp->nr_prog = RPCPROG_NFSUSERD;
3671 switch (nargs->nuserd_family) {
3674 rp->nr_nam = malloc(sizeof(struct sockaddr_in), M_SONAME,
3676 ad = (struct sockaddr_in *)rp->nr_nam;
3677 ad->sin_len = sizeof(struct sockaddr_in);
3678 ad->sin_family = AF_INET;
3679 ad->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
3680 ad->sin_port = nargs->nuserd_port;
3685 rp->nr_nam = malloc(sizeof(struct sockaddr_in6), M_SONAME,
3687 ad6 = (struct sockaddr_in6 *)rp->nr_nam;
3688 ad6->sin6_len = sizeof(struct sockaddr_in6);
3689 ad6->sin6_family = AF_INET6;
3690 ad6->sin6_addr = in6loopback;
3691 ad6->sin6_port = nargs->nuserd_port;
3697 rp->nr_vers = RPCNFSUSERD_VERS;
3699 error = newnfs_connect(NULL, rp, NFSPROCCRED(p), p, 0, false,
3703 nfsrv_nfsuserd = RUNNING;
3706 free(rp->nr_nam, M_SONAME);
3708 nfsrv_nfsuserd = NOTRUNNING;
3717 * Delete the nfsuserd port.
3720 nfsrv_nfsuserddelport(void)
3724 if (nfsrv_nfsuserd != RUNNING) {
3728 nfsrv_nfsuserd = STARTSTOP;
3729 /* Wait for all upcalls to complete. */
3730 while (nfsrv_userdupcalls > 0)
3731 msleep(&nfsrv_userdupcalls, NFSNAMEIDMUTEXPTR, PVFS,
3734 newnfs_disconnect(NULL, &nfsrv_nfsuserdsock);
3735 free(nfsrv_nfsuserdsock.nr_nam, M_SONAME);
3737 nfsrv_nfsuserd = NOTRUNNING;
3742 * Do upcalls to the nfsuserd, for cache misses of the owner/ownergroup
3744 * Returns 0 upon success, non-zero otherwise.
3747 nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name)
3750 struct nfsrv_descript *nd;
3752 struct nfsrv_descript nfsd;
3757 if (nfsrv_nfsuserd != RUNNING) {
3763 * Maintain a count of upcalls in progress, so that nfsrv_X()
3764 * can wait until no upcalls are in progress.
3766 nfsrv_userdupcalls++;
3768 KASSERT(nfsrv_userdupcalls > 0,
3769 ("nfsrv_getuser: non-positive upcalls"));
3771 cred = newnfs_getcred();
3772 nd->nd_flag = ND_GSSINITREPLY;
3775 nd->nd_procnum = procnum;
3776 if (procnum == RPCNFSUSERD_GETUID || procnum == RPCNFSUSERD_GETGID) {
3777 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3778 if (procnum == RPCNFSUSERD_GETUID)
3779 *tl = txdr_unsigned(uid);
3781 *tl = txdr_unsigned(gid);
3784 (void) nfsm_strtom(nd, name, len);
3786 error = newnfs_request(nd, NULL, NULL, &nfsrv_nfsuserdsock, NULL, NULL,
3787 cred, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, NULL, 0, NULL, NULL);
3789 if (--nfsrv_userdupcalls == 0 && nfsrv_nfsuserd == STARTSTOP)
3790 wakeup(&nfsrv_userdupcalls);
3794 m_freem(nd->nd_mrep);
3795 error = nd->nd_repstat;
3803 * This function is called from the nfssvc(2) system call, to update the
3804 * kernel user/group name list(s) for the V4 owner and ownergroup attributes.
3807 nfssvc_idname(struct nfsd_idargs *nidp)
3809 struct nfsusrgrp *nusrp, *usrp, *newusrp;
3810 struct nfsrv_lughash *hp_name, *hp_idnum, *thp;
3811 int i, group_locked, groupname_locked, user_locked, username_locked;
3816 static int onethread = 0;
3817 static time_t lasttime = 0;
3819 if (nidp->nid_namelen <= 0 || nidp->nid_namelen > MAXHOSTNAMELEN) {
3823 if (nidp->nid_flag & NFSID_INITIALIZE) {
3824 cp = malloc(nidp->nid_namelen + 1, M_NFSSTRING, M_WAITOK);
3825 error = copyin(nidp->nid_name, cp, nidp->nid_namelen);
3827 free(cp, M_NFSSTRING);
3830 if (atomic_cmpset_acq_int(&nfsrv_dnsnamelen, 0, 0) == 0) {
3832 * Free up all the old stuff and reinitialize hash
3833 * lists. All mutexes for both lists must be locked,
3834 * with the user/group name ones before the uid/gid
3835 * ones, to avoid a LOR.
3837 for (i = 0; i < nfsrv_lughashsize; i++)
3838 mtx_lock(&nfsusernamehash[i].mtx);
3839 for (i = 0; i < nfsrv_lughashsize; i++)
3840 mtx_lock(&nfsuserhash[i].mtx);
3841 for (i = 0; i < nfsrv_lughashsize; i++)
3842 TAILQ_FOREACH_SAFE(usrp,
3843 &nfsuserhash[i].lughead, lug_numhash, nusrp)
3844 nfsrv_removeuser(usrp, 1);
3845 for (i = 0; i < nfsrv_lughashsize; i++)
3846 mtx_unlock(&nfsuserhash[i].mtx);
3847 for (i = 0; i < nfsrv_lughashsize; i++)
3848 mtx_unlock(&nfsusernamehash[i].mtx);
3849 for (i = 0; i < nfsrv_lughashsize; i++)
3850 mtx_lock(&nfsgroupnamehash[i].mtx);
3851 for (i = 0; i < nfsrv_lughashsize; i++)
3852 mtx_lock(&nfsgrouphash[i].mtx);
3853 for (i = 0; i < nfsrv_lughashsize; i++)
3854 TAILQ_FOREACH_SAFE(usrp,
3855 &nfsgrouphash[i].lughead, lug_numhash,
3857 nfsrv_removeuser(usrp, 0);
3858 for (i = 0; i < nfsrv_lughashsize; i++)
3859 mtx_unlock(&nfsgrouphash[i].mtx);
3860 for (i = 0; i < nfsrv_lughashsize; i++)
3861 mtx_unlock(&nfsgroupnamehash[i].mtx);
3862 free(nfsrv_dnsname, M_NFSSTRING);
3863 nfsrv_dnsname = NULL;
3865 if (nfsuserhash == NULL) {
3866 /* Allocate the hash tables. */
3867 nfsuserhash = malloc(sizeof(struct nfsrv_lughash) *
3868 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3870 for (i = 0; i < nfsrv_lughashsize; i++)
3871 mtx_init(&nfsuserhash[i].mtx, "nfsuidhash",
3872 NULL, MTX_DEF | MTX_DUPOK);
3873 nfsusernamehash = malloc(sizeof(struct nfsrv_lughash) *
3874 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3876 for (i = 0; i < nfsrv_lughashsize; i++)
3877 mtx_init(&nfsusernamehash[i].mtx,
3878 "nfsusrhash", NULL, MTX_DEF |
3880 nfsgrouphash = malloc(sizeof(struct nfsrv_lughash) *
3881 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3883 for (i = 0; i < nfsrv_lughashsize; i++)
3884 mtx_init(&nfsgrouphash[i].mtx, "nfsgidhash",
3885 NULL, MTX_DEF | MTX_DUPOK);
3886 nfsgroupnamehash = malloc(sizeof(struct nfsrv_lughash) *
3887 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3889 for (i = 0; i < nfsrv_lughashsize; i++)
3890 mtx_init(&nfsgroupnamehash[i].mtx,
3891 "nfsgrphash", NULL, MTX_DEF | MTX_DUPOK);
3893 /* (Re)initialize the list heads. */
3894 for (i = 0; i < nfsrv_lughashsize; i++)
3895 TAILQ_INIT(&nfsuserhash[i].lughead);
3896 for (i = 0; i < nfsrv_lughashsize; i++)
3897 TAILQ_INIT(&nfsusernamehash[i].lughead);
3898 for (i = 0; i < nfsrv_lughashsize; i++)
3899 TAILQ_INIT(&nfsgrouphash[i].lughead);
3900 for (i = 0; i < nfsrv_lughashsize; i++)
3901 TAILQ_INIT(&nfsgroupnamehash[i].lughead);
3904 * Put name in "DNS" string.
3907 nfsrv_defaultuid = nidp->nid_uid;
3908 nfsrv_defaultgid = nidp->nid_gid;
3910 nfsrv_usermax = nidp->nid_usermax;
3911 atomic_store_rel_int(&nfsrv_dnsnamelen, nidp->nid_namelen);
3916 * malloc the new one now, so any potential sleep occurs before
3917 * manipulation of the lists.
3919 newusrp = malloc(sizeof(struct nfsusrgrp) + nidp->nid_namelen,
3920 M_NFSUSERGROUP, M_WAITOK | M_ZERO);
3921 error = copyin(nidp->nid_name, newusrp->lug_name,
3923 if (error == 0 && nidp->nid_ngroup > 0 &&
3924 (nidp->nid_flag & NFSID_ADDUID) != 0) {
3925 grps = malloc(sizeof(gid_t) * nidp->nid_ngroup, M_TEMP,
3927 error = copyin(nidp->nid_grps, grps,
3928 sizeof(gid_t) * nidp->nid_ngroup);
3931 * Create a credential just like svc_getcred(),
3932 * but using the group list provided.
3935 cr->cr_uid = cr->cr_ruid = cr->cr_svuid = nidp->nid_uid;
3936 crsetgroups(cr, nidp->nid_ngroup, grps);
3937 cr->cr_rgid = cr->cr_svgid = cr->cr_groups[0];
3938 cr->cr_prison = &prison0;
3939 prison_hold(cr->cr_prison);
3941 mac_cred_associate_nfsd(cr);
3943 newusrp->lug_cred = cr;
3948 free(newusrp, M_NFSUSERGROUP);
3951 newusrp->lug_namelen = nidp->nid_namelen;
3954 * The lock order is username[0]->[nfsrv_lughashsize - 1] followed
3955 * by uid[0]->[nfsrv_lughashsize - 1], with the same for group.
3956 * The flags user_locked, username_locked, group_locked and
3957 * groupname_locked are set to indicate all of those hash lists are
3958 * locked. hp_name != NULL and hp_idnum != NULL indicates that
3959 * the respective one mutex is locked.
3961 user_locked = username_locked = group_locked = groupname_locked = 0;
3962 hp_name = hp_idnum = NULL;
3965 * Delete old entries, as required.
3967 if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) {
3968 /* Must lock all username hash lists first, to avoid a LOR. */
3969 for (i = 0; i < nfsrv_lughashsize; i++)
3970 mtx_lock(&nfsusernamehash[i].mtx);
3971 username_locked = 1;
3972 hp_idnum = NFSUSERHASH(nidp->nid_uid);
3973 mtx_lock(&hp_idnum->mtx);
3974 TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
3976 if (usrp->lug_uid == nidp->nid_uid)
3977 nfsrv_removeuser(usrp, 1);
3979 } else if (nidp->nid_flag & (NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) {
3980 hp_name = NFSUSERNAMEHASH(newusrp->lug_name,
3981 newusrp->lug_namelen);
3982 mtx_lock(&hp_name->mtx);
3983 TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
3985 if (usrp->lug_namelen == newusrp->lug_namelen &&
3986 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3987 usrp->lug_namelen)) {
3988 thp = NFSUSERHASH(usrp->lug_uid);
3989 mtx_lock(&thp->mtx);
3990 nfsrv_removeuser(usrp, 1);
3991 mtx_unlock(&thp->mtx);
3994 hp_idnum = NFSUSERHASH(nidp->nid_uid);
3995 mtx_lock(&hp_idnum->mtx);
3996 } else if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) {
3997 /* Must lock all groupname hash lists first, to avoid a LOR. */
3998 for (i = 0; i < nfsrv_lughashsize; i++)
3999 mtx_lock(&nfsgroupnamehash[i].mtx);
4000 groupname_locked = 1;
4001 hp_idnum = NFSGROUPHASH(nidp->nid_gid);
4002 mtx_lock(&hp_idnum->mtx);
4003 TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
4005 if (usrp->lug_gid == nidp->nid_gid)
4006 nfsrv_removeuser(usrp, 0);
4008 } else if (nidp->nid_flag & (NFSID_DELGROUPNAME | NFSID_ADDGROUPNAME)) {
4009 hp_name = NFSGROUPNAMEHASH(newusrp->lug_name,
4010 newusrp->lug_namelen);
4011 mtx_lock(&hp_name->mtx);
4012 TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
4014 if (usrp->lug_namelen == newusrp->lug_namelen &&
4015 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
4016 usrp->lug_namelen)) {
4017 thp = NFSGROUPHASH(usrp->lug_gid);
4018 mtx_lock(&thp->mtx);
4019 nfsrv_removeuser(usrp, 0);
4020 mtx_unlock(&thp->mtx);
4023 hp_idnum = NFSGROUPHASH(nidp->nid_gid);
4024 mtx_lock(&hp_idnum->mtx);
4028 * Now, we can add the new one.
4030 if (nidp->nid_usertimeout)
4031 newusrp->lug_expiry = NFSD_MONOSEC + nidp->nid_usertimeout;
4033 newusrp->lug_expiry = NFSD_MONOSEC + 5;
4034 if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) {
4035 newusrp->lug_uid = nidp->nid_uid;
4036 thp = NFSUSERHASH(newusrp->lug_uid);
4037 mtx_assert(&thp->mtx, MA_OWNED);
4038 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
4039 thp = NFSUSERNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
4040 mtx_assert(&thp->mtx, MA_OWNED);
4041 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
4042 atomic_add_int(&nfsrv_usercnt, 1);
4043 } else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) {
4044 newusrp->lug_gid = nidp->nid_gid;
4045 thp = NFSGROUPHASH(newusrp->lug_gid);
4046 mtx_assert(&thp->mtx, MA_OWNED);
4047 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
4048 thp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
4049 mtx_assert(&thp->mtx, MA_OWNED);
4050 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
4051 atomic_add_int(&nfsrv_usercnt, 1);
4053 if (newusrp->lug_cred != NULL)
4054 crfree(newusrp->lug_cred);
4055 free(newusrp, M_NFSUSERGROUP);
4059 * Once per second, allow one thread to trim the cache.
4061 if (lasttime < NFSD_MONOSEC &&
4062 atomic_cmpset_acq_int(&onethread, 0, 1) != 0) {
4064 * First, unlock the single mutexes, so that all entries
4065 * can be locked and any LOR is avoided.
4067 if (hp_name != NULL) {
4068 mtx_unlock(&hp_name->mtx);
4071 if (hp_idnum != NULL) {
4072 mtx_unlock(&hp_idnum->mtx);
4076 if ((nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID |
4077 NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) != 0) {
4078 if (username_locked == 0) {
4079 for (i = 0; i < nfsrv_lughashsize; i++)
4080 mtx_lock(&nfsusernamehash[i].mtx);
4081 username_locked = 1;
4083 KASSERT(user_locked == 0,
4084 ("nfssvc_idname: user_locked"));
4085 for (i = 0; i < nfsrv_lughashsize; i++)
4086 mtx_lock(&nfsuserhash[i].mtx);
4088 for (i = 0; i < nfsrv_lughashsize; i++) {
4089 TAILQ_FOREACH_SAFE(usrp,
4090 &nfsuserhash[i].lughead, lug_numhash,
4092 if (usrp->lug_expiry < NFSD_MONOSEC)
4093 nfsrv_removeuser(usrp, 1);
4095 for (i = 0; i < nfsrv_lughashsize; i++) {
4097 * Trim the cache using an approximate LRU
4098 * algorithm. This code deletes the least
4099 * recently used entry on each hash list.
4101 if (nfsrv_usercnt <= nfsrv_usermax)
4103 usrp = TAILQ_FIRST(&nfsuserhash[i].lughead);
4105 nfsrv_removeuser(usrp, 1);
4108 if (groupname_locked == 0) {
4109 for (i = 0; i < nfsrv_lughashsize; i++)
4110 mtx_lock(&nfsgroupnamehash[i].mtx);
4111 groupname_locked = 1;
4113 KASSERT(group_locked == 0,
4114 ("nfssvc_idname: group_locked"));
4115 for (i = 0; i < nfsrv_lughashsize; i++)
4116 mtx_lock(&nfsgrouphash[i].mtx);
4118 for (i = 0; i < nfsrv_lughashsize; i++) {
4119 TAILQ_FOREACH_SAFE(usrp,
4120 &nfsgrouphash[i].lughead, lug_numhash,
4122 if (usrp->lug_expiry < NFSD_MONOSEC)
4123 nfsrv_removeuser(usrp, 0);
4125 for (i = 0; i < nfsrv_lughashsize; i++) {
4127 * Trim the cache using an approximate LRU
4128 * algorithm. This code deletes the least
4129 * recently user entry on each hash list.
4131 if (nfsrv_usercnt <= nfsrv_usermax)
4133 usrp = TAILQ_FIRST(&nfsgrouphash[i].lughead);
4135 nfsrv_removeuser(usrp, 0);
4138 lasttime = NFSD_MONOSEC;
4139 atomic_store_rel_int(&onethread, 0);
4142 /* Now, unlock all locked mutexes. */
4143 if (hp_idnum != NULL)
4144 mtx_unlock(&hp_idnum->mtx);
4145 if (hp_name != NULL)
4146 mtx_unlock(&hp_name->mtx);
4147 if (user_locked != 0)
4148 for (i = 0; i < nfsrv_lughashsize; i++)
4149 mtx_unlock(&nfsuserhash[i].mtx);
4150 if (username_locked != 0)
4151 for (i = 0; i < nfsrv_lughashsize; i++)
4152 mtx_unlock(&nfsusernamehash[i].mtx);
4153 if (group_locked != 0)
4154 for (i = 0; i < nfsrv_lughashsize; i++)
4155 mtx_unlock(&nfsgrouphash[i].mtx);
4156 if (groupname_locked != 0)
4157 for (i = 0; i < nfsrv_lughashsize; i++)
4158 mtx_unlock(&nfsgroupnamehash[i].mtx);
4165 * Remove a user/group name element.
4168 nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser)
4170 struct nfsrv_lughash *hp;
4173 hp = NFSUSERHASH(usrp->lug_uid);
4174 mtx_assert(&hp->mtx, MA_OWNED);
4175 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
4176 hp = NFSUSERNAMEHASH(usrp->lug_name, usrp->lug_namelen);
4177 mtx_assert(&hp->mtx, MA_OWNED);
4178 TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
4180 hp = NFSGROUPHASH(usrp->lug_gid);
4181 mtx_assert(&hp->mtx, MA_OWNED);
4182 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
4183 hp = NFSGROUPNAMEHASH(usrp->lug_name, usrp->lug_namelen);
4184 mtx_assert(&hp->mtx, MA_OWNED);
4185 TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
4187 atomic_add_int(&nfsrv_usercnt, -1);
4188 if (usrp->lug_cred != NULL)
4189 crfree(usrp->lug_cred);
4190 free(usrp, M_NFSUSERGROUP);
4194 * Free up all the allocations related to the name<-->id cache.
4195 * This function should only be called when the nfsuserd daemon isn't
4196 * running, since it doesn't do any locking.
4197 * This function is meant to be used when the nfscommon module is unloaded.
4200 nfsrv_cleanusergroup(void)
4202 struct nfsrv_lughash *hp, *hp2;
4203 struct nfsusrgrp *nusrp, *usrp;
4206 if (nfsuserhash == NULL)
4209 for (i = 0; i < nfsrv_lughashsize; i++) {
4210 hp = &nfsuserhash[i];
4211 TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) {
4212 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
4213 hp2 = NFSUSERNAMEHASH(usrp->lug_name,
4215 TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash);
4216 if (usrp->lug_cred != NULL)
4217 crfree(usrp->lug_cred);
4218 free(usrp, M_NFSUSERGROUP);
4220 hp = &nfsgrouphash[i];
4221 TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) {
4222 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
4223 hp2 = NFSGROUPNAMEHASH(usrp->lug_name,
4225 TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash);
4226 if (usrp->lug_cred != NULL)
4227 crfree(usrp->lug_cred);
4228 free(usrp, M_NFSUSERGROUP);
4230 mtx_destroy(&nfsuserhash[i].mtx);
4231 mtx_destroy(&nfsusernamehash[i].mtx);
4232 mtx_destroy(&nfsgroupnamehash[i].mtx);
4233 mtx_destroy(&nfsgrouphash[i].mtx);
4235 free(nfsuserhash, M_NFSUSERGROUP);
4236 free(nfsusernamehash, M_NFSUSERGROUP);
4237 free(nfsgrouphash, M_NFSUSERGROUP);
4238 free(nfsgroupnamehash, M_NFSUSERGROUP);
4239 free(nfsrv_dnsname, M_NFSSTRING);
4243 * This function scans a byte string and checks for UTF-8 compliance.
4244 * It returns 0 if it conforms and NFSERR_INVAL if not.
4247 nfsrv_checkutf8(u_int8_t *cp, int len)
4249 u_int32_t val = 0x0;
4250 int cnt = 0, gotd = 0, shift = 0;
4252 static int utf8_shift[5] = { 7, 11, 16, 21, 26 };
4256 * Here are what the variables are used for:
4257 * val - the calculated value of a multibyte char, used to check
4258 * that it was coded with the correct range
4259 * cnt - the number of 10xxxxxx bytes to follow
4260 * gotd - set for a char of Dxxx, so D800<->DFFF can be checked for
4261 * shift - lower order bits of range (ie. "val >> shift" should
4262 * not be 0, in other words, dividing by the lower bound
4263 * of the range should get a non-zero value)
4264 * byte - used to calculate cnt
4268 /* This handles the 10xxxxxx bytes */
4269 if ((*cp & 0xc0) != 0x80 ||
4270 (gotd && (*cp & 0x20))) {
4271 error = NFSERR_INVAL;
4276 val |= (*cp & 0x3f);
4278 if (cnt == 0 && (val >> shift) == 0x0) {
4279 error = NFSERR_INVAL;
4282 } else if (*cp & 0x80) {
4283 /* first byte of multi byte char */
4285 while ((byte & 0x40) && cnt < 6) {
4289 if (cnt == 0 || cnt == 6) {
4290 error = NFSERR_INVAL;
4293 val = (*cp & (0x3f >> cnt));
4294 shift = utf8_shift[cnt - 1];
4295 if (cnt == 2 && val == 0xd)
4296 /* Check for the 0xd800-0xdfff case */
4303 error = NFSERR_INVAL;
4311 * Parse the xdr for an NFSv4 FsLocations attribute. Return two malloc'd
4312 * strings, one with the root path in it and the other with the list of
4313 * locations. The list is in the same format as is found in nfr_refs.
4314 * It is a "," separated list of entries, where each of them is of the
4315 * form <server>:<rootpath>. For example
4316 * "nfsv4-test:/sub2,nfsv4-test2:/user/mnt,nfsv4-test2:/user/mnt2"
4317 * The nilp argument is set to 1 for the special case of a null fs_root
4318 * and an empty server list.
4319 * It returns NFSERR_BADXDR, if the xdr can't be parsed and returns the
4320 * number of xdr bytes parsed in sump.
4323 nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp,
4324 int *sump, int *nilp)
4327 u_char *cp = NULL, *cp2 = NULL, *cp3, *str;
4328 int i, j, len, stringlen, cnt, slen, siz, xdrsum, error = 0, nsrv;
4330 SLIST_ENTRY(list) next;
4334 SLIST_HEAD(, list) head;
4341 * Get the fs_root path and check for the special case of null path
4342 * and 0 length server list.
4344 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4345 len = fxdr_unsigned(int, *tl);
4346 if (len < 0 || len > 10240) {
4347 error = NFSERR_BADXDR;
4351 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4353 error = NFSERR_BADXDR;
4357 *sump = 2 * NFSX_UNSIGNED;
4361 cp = malloc(len + 1, M_NFSSTRING, M_WAITOK);
4362 error = nfsrv_mtostr(nd, cp, len);
4364 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4365 cnt = fxdr_unsigned(int, *tl);
4367 error = NFSERR_BADXDR;
4373 * Now, loop through the location list and make up the srvlist.
4375 xdrsum = (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
4376 cp2 = cp3 = malloc(1024, M_NFSSTRING, M_WAITOK);
4379 for (i = 0; i < cnt; i++) {
4381 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4382 nsrv = fxdr_unsigned(int, *tl);
4384 error = NFSERR_BADXDR;
4389 * Handle the first server by putting it in the srvstr.
4391 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4392 len = fxdr_unsigned(int, *tl);
4393 if (len <= 0 || len > 1024) {
4394 error = NFSERR_BADXDR;
4397 nfsrv_refstrbigenough(siz + len + 3, &cp2, &cp3, &slen);
4402 error = nfsrv_mtostr(nd, cp3, len);
4408 xdrsum += (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
4409 for (j = 1; j < nsrv; j++) {
4411 * Yuck, put them in an slist and process them later.
4413 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4414 len = fxdr_unsigned(int, *tl);
4415 if (len <= 0 || len > 1024) {
4416 error = NFSERR_BADXDR;
4419 lsp = (struct list *)malloc(sizeof (struct list)
4420 + len, M_TEMP, M_WAITOK);
4421 error = nfsrv_mtostr(nd, lsp->host, len);
4424 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
4426 SLIST_INSERT_HEAD(&head, lsp, next);
4430 * Finally, we can get the path.
4432 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4433 len = fxdr_unsigned(int, *tl);
4434 if (len <= 0 || len > 1024) {
4435 error = NFSERR_BADXDR;
4438 nfsrv_refstrbigenough(siz + len + 1, &cp2, &cp3, &slen);
4439 error = nfsrv_mtostr(nd, cp3, len);
4442 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
4447 SLIST_FOREACH_SAFE(lsp, &head, next, nlsp) {
4448 nfsrv_refstrbigenough(siz + lsp->len + stringlen + 3,
4451 NFSBCOPY(lsp->host, cp3, lsp->len);
4454 NFSBCOPY(str, cp3, stringlen);
4457 siz += (lsp->len + stringlen + 2);
4464 NFSEXITCODE2(0, nd);
4468 free(cp, M_NFSSTRING);
4470 free(cp2, M_NFSSTRING);
4471 NFSEXITCODE2(error, nd);
4476 * Make the malloc'd space large enough. This is a pain, but the xdr
4477 * doesn't set an upper bound on the side, so...
4480 nfsrv_refstrbigenough(int siz, u_char **cpp, u_char **cpp2, int *slenp)
4487 cp = malloc(siz + 1024, M_NFSSTRING, M_WAITOK);
4488 NFSBCOPY(*cpp, cp, *slenp);
4489 free(*cpp, M_NFSSTRING);
4493 *slenp = siz + 1024;
4497 * Initialize the reply header data structures.
4500 nfsrvd_rephead(struct nfsrv_descript *nd)
4504 if ((nd->nd_flag & ND_EXTPG) != 0) {
4505 mreq = mb_alloc_ext_plus_pages(PAGE_SIZE, M_WAITOK);
4506 nd->nd_mreq = nd->nd_mb = mreq;
4507 nd->nd_bpos = (char *)(void *)
4508 PHYS_TO_DMAP(mreq->m_epg_pa[0]);
4510 nd->nd_bextpgsiz = PAGE_SIZE;
4513 * If this is a big reply, use a cluster.
4515 if ((nd->nd_flag & ND_GSSINITREPLY) == 0 &&
4516 nfs_bigreply[nd->nd_procnum]) {
4517 NFSMCLGET(mreq, M_WAITOK);
4525 nd->nd_bpos = mtod(mreq, char *);
4529 if ((nd->nd_flag & ND_GSSINITREPLY) == 0)
4530 NFSM_BUILD(nd->nd_errp, int *, NFSX_UNSIGNED);
4534 * Lock a socket against others.
4535 * Currently used to serialize connect/disconnect attempts.
4538 newnfs_sndlock(int *flagp)
4543 while (*flagp & NFSR_SNDLOCK) {
4544 *flagp |= NFSR_WANTSND;
4547 (void) nfsmsleep((caddr_t)flagp, NFSSOCKMUTEXPTR,
4548 PZERO - 1, "nfsndlck", &ts);
4550 *flagp |= NFSR_SNDLOCK;
4556 * Unlock the stream socket for others.
4559 newnfs_sndunlock(int *flagp)
4563 if ((*flagp & NFSR_SNDLOCK) == 0)
4564 panic("nfs sndunlock");
4565 *flagp &= ~NFSR_SNDLOCK;
4566 if (*flagp & NFSR_WANTSND) {
4567 *flagp &= ~NFSR_WANTSND;
4568 wakeup((caddr_t)flagp);
4574 nfsv4_getipaddr(struct nfsrv_descript *nd, struct sockaddr_in *sin,
4575 struct sockaddr_in6 *sin6, sa_family_t *saf, int *isudp)
4577 struct in_addr saddr;
4578 uint32_t portnum, *tl;
4580 sa_family_t af = AF_UNSPEC;
4581 char addr[64], protocol[5], *cp;
4582 int cantparse = 0, error = 0;
4585 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4586 i = fxdr_unsigned(int, *tl);
4587 if (i >= 3 && i <= 4) {
4588 error = nfsrv_mtostr(nd, protocol, i);
4591 if (strcmp(protocol, "tcp") == 0) {
4594 } else if (strcmp(protocol, "udp") == 0) {
4597 } else if (strcmp(protocol, "tcp6") == 0) {
4600 } else if (strcmp(protocol, "udp6") == 0) {
4608 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
4613 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4614 i = fxdr_unsigned(int, *tl);
4616 error = NFSERR_BADXDR;
4618 } else if (cantparse == 0 && i >= 11 && i < 64) {
4620 * The shortest address is 11chars and the longest is < 64.
4622 error = nfsrv_mtostr(nd, addr, i);
4626 /* Find the port# at the end and extract that. */
4630 /* Count back two '.'s from end to get port# field. */
4631 for (j = 0; j < i; j++) {
4641 * The NFSv4 port# is appended as .N.N, where N is
4642 * a decimal # in the range 0-255, just like an inet4
4643 * address. Cheat and use inet_aton(), which will
4644 * return a Class A address and then shift the high
4645 * order 8bits over to convert it to the port#.
4648 if (inet_aton(cp, &saddr) == 1) {
4649 portnum = ntohl(saddr.s_addr);
4650 portv = (uint16_t)((portnum >> 16) |
4656 if (cantparse == 0) {
4657 if (af == AF_INET) {
4658 if (inet_pton(af, addr, &sin->sin_addr) == 1) {
4659 sin->sin_len = sizeof(*sin);
4660 sin->sin_family = AF_INET;
4661 sin->sin_port = htons(portv);
4666 if (inet_pton(af, addr, &sin6->sin6_addr)
4668 sin6->sin6_len = sizeof(*sin6);
4669 sin6->sin6_family = AF_INET6;
4670 sin6->sin6_port = htons(portv);
4678 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
4689 * Handle an NFSv4.1 Sequence request for the session.
4690 * If reply != NULL, use it to return the cached reply, as required.
4691 * The client gets a cached reply via this call for callbacks, however the
4692 * server gets a cached reply via the nfsv4_seqsess_cacherep() call.
4695 nfsv4_seqsession(uint32_t seqid, uint32_t slotid, uint32_t highslot,
4696 struct nfsslot *slots, struct mbuf **reply, uint16_t maxslot)
4704 if (slotid > maxslot)
4705 return (NFSERR_BADSLOT);
4706 if (seqid == slots[slotid].nfssl_seq) {
4708 if (slots[slotid].nfssl_inprog != 0)
4709 error = NFSERR_DELAY;
4710 else if (slots[slotid].nfssl_reply != NULL) {
4711 if (reply != NULL) {
4712 m = m_copym(slots[slotid].nfssl_reply, 0,
4713 M_COPYALL, M_NOWAIT);
4717 *reply = slots[slotid].nfssl_reply;
4718 slots[slotid].nfssl_reply = NULL;
4721 slots[slotid].nfssl_inprog = 1;
4722 error = NFSERR_REPLYFROMCACHE;
4724 /* No reply cached, so just do it. */
4725 slots[slotid].nfssl_inprog = 1;
4726 } else if ((slots[slotid].nfssl_seq + 1) == seqid) {
4727 if (slots[slotid].nfssl_reply != NULL)
4728 m_freem(slots[slotid].nfssl_reply);
4729 slots[slotid].nfssl_reply = NULL;
4730 slots[slotid].nfssl_inprog = 1;
4731 slots[slotid].nfssl_seq++;
4733 error = NFSERR_SEQMISORDERED;
4738 * Cache this reply for the slot.
4739 * Use the "rep" argument to return the cached reply if repstat is set to
4740 * NFSERR_REPLYFROMCACHE. The client never sets repstat to this value.
4743 nfsv4_seqsess_cacherep(uint32_t slotid, struct nfsslot *slots, int repstat,
4748 if (repstat == NFSERR_REPLYFROMCACHE) {
4749 if (slots[slotid].nfssl_reply != NULL) {
4751 * We cannot sleep here, but copy will usually
4754 m = m_copym(slots[slotid].nfssl_reply, 0, M_COPYALL,
4760 * Multiple retries would be extremely rare,
4761 * so using the cached reply will likely
4764 *rep = slots[slotid].nfssl_reply;
4765 slots[slotid].nfssl_reply = NULL;
4770 if (slots[slotid].nfssl_reply != NULL)
4771 m_freem(slots[slotid].nfssl_reply);
4772 slots[slotid].nfssl_reply = *rep;
4774 slots[slotid].nfssl_inprog = 0;
4778 * Generate the xdr for an NFSv4.1 Sequence Operation.
4781 nfsv4_setsequence(struct nfsmount *nmp, struct nfsrv_descript *nd,
4782 struct nfsclsession *sep, int dont_replycache, struct ucred *cred)
4784 uint32_t *tl, slotseq = 0;
4785 int error, maxslot, slotpos;
4786 uint8_t sessionid[NFSX_V4SESSIONID];
4789 error = nfsv4_sequencelookup(nmp, sep, &slotpos, &maxslot,
4790 &slotseq, sessionid, false);
4791 if (error == NFSERR_SEQMISORDERED) {
4792 /* If all slots are bad, Destroy the session. */
4793 nfsrpc_destroysession(nmp, sep, cred, curthread);
4797 error = nfsv4_sequencelookup(nmp, sep, &slotpos, &maxslot,
4798 &slotseq, sessionid, true);
4799 nd->nd_maxreq = sep->nfsess_maxreq;
4800 nd->nd_maxresp = sep->nfsess_maxresp;
4802 /* Build the Sequence arguments. */
4803 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 4 * NFSX_UNSIGNED);
4804 nd->nd_sequence = tl;
4805 bcopy(sessionid, tl, NFSX_V4SESSIONID);
4806 tl += NFSX_V4SESSIONID / NFSX_UNSIGNED;
4807 nd->nd_slotseq = tl;
4809 nd->nd_flag |= ND_HASSLOTID;
4810 nd->nd_slotid = slotpos;
4811 *tl++ = txdr_unsigned(slotseq);
4812 *tl++ = txdr_unsigned(slotpos);
4813 *tl++ = txdr_unsigned(maxslot);
4814 if (dont_replycache == 0)
4820 * There are two errors and the rest of the session can
4822 * NFSERR_BADSESSION: This bad session should just generate
4823 * the same error again when the RPC is retried.
4824 * ESTALE: A forced dismount is in progress and will cause the
4825 * RPC to fail later.
4832 nd->nd_flag |= ND_HASSEQUENCE;
4836 * If fnd_init is true, ignore the badslots.
4837 * If fnd_init is false, return NFSERR_SEQMISORDERED if all slots are bad.
4840 nfsv4_sequencelookup(struct nfsmount *nmp, struct nfsclsession *sep,
4841 int *slotposp, int *maxslotp, uint32_t *slotseqp, uint8_t *sessionid,
4844 int i, maxslot, slotpos;
4848 /* Find an unused slot. */
4851 mtx_lock(&sep->nfsess_mtx);
4853 if (nmp != NULL && sep->nfsess_defunct != 0) {
4854 /* Just return the bad session. */
4855 bcopy(sep->nfsess_sessionid, sessionid,
4857 mtx_unlock(&sep->nfsess_mtx);
4858 return (NFSERR_BADSESSION);
4862 for (i = 0; i < sep->nfsess_foreslots; i++) {
4863 if ((bitval & sep->nfsess_badslots) == 0 || fnd_init) {
4865 if ((bitval & sep->nfsess_slots) == 0) {
4867 sep->nfsess_slots |= bitval;
4868 sep->nfsess_slotseq[i]++;
4869 *slotseqp = sep->nfsess_slotseq[i];
4875 if (slotpos == -1) {
4877 * If a forced dismount is in progress, just return.
4878 * This RPC attempt will fail when it calls
4881 if (nmp != NULL && NFSCL_FORCEDISM(nmp->nm_mountp)) {
4882 mtx_unlock(&sep->nfsess_mtx);
4885 /* Wake up once/sec, to check for a forced dismount. */
4887 mtx_sleep(&sep->nfsess_slots, &sep->nfsess_mtx,
4888 PZERO, "nfsclseq", hz);
4890 } while (slotpos == -1 && fnd_ok);
4892 * If all slots are bad, just return slot 0 and NFSERR_SEQMISORDERED.
4893 * The caller will do a DestroySession, so that the session's use
4894 * will get a NFSERR_BADSESSION reply from the server.
4899 /* Now, find the highest slot in use. (nfsc_slots is 64bits) */
4901 for (i = 0; i < 64; i++) {
4902 if ((bitval & sep->nfsess_slots) != 0)
4906 bcopy(sep->nfsess_sessionid, sessionid, NFSX_V4SESSIONID);
4907 mtx_unlock(&sep->nfsess_mtx);
4908 *slotposp = slotpos;
4909 *maxslotp = maxslot;
4912 return (NFSERR_SEQMISORDERED);
4917 * Free a session slot.
4920 nfsv4_freeslot(struct nfsclsession *sep, int slot, bool resetseq)
4927 mtx_lock(&sep->nfsess_mtx);
4929 sep->nfsess_slotseq[slot]--;
4930 if ((bitval & sep->nfsess_slots) == 0)
4931 printf("freeing free slot!!\n");
4932 sep->nfsess_slots &= ~bitval;
4933 wakeup(&sep->nfsess_slots);
4934 mtx_unlock(&sep->nfsess_mtx);
4938 * Search for a matching pnfsd DS, based on the nmp arg.
4939 * Return one if found, NULL otherwise.
4942 nfsv4_findmirror(struct nfsmount *nmp)
4944 struct nfsdevice *ds;
4946 mtx_assert(NFSDDSMUTEXPTR, MA_OWNED);
4948 * Search the DS server list for a match with nmp.
4950 if (nfsrv_devidcnt == 0)
4952 TAILQ_FOREACH(ds, &nfsrv_devidhead, nfsdev_list) {
4953 if (ds->nfsdev_nmp == nmp) {
4954 NFSCL_DEBUG(4, "nfsv4_findmirror: fnd main ds\n");
4962 * Fill in the fields of "struct nfsrv_descript".
4965 nfsm_set(struct nfsrv_descript *nd, u_int offs)
4971 if ((m->m_flags & M_EXTPG) != 0) {
4974 if (nd->nd_bextpg == 0)
4975 rlen = m_epg_pagelen(m, 0, m->m_epg_1st_off);
4977 rlen = m_epg_pagelen(m, nd->nd_bextpg, 0);
4982 if (nd->nd_bextpg == m->m_epg_npgs) {
4983 printf("nfsm_set: build offs "
4989 nd->nd_bpos = (char *)(void *)
4990 PHYS_TO_DMAP(m->m_epg_pa[nd->nd_bextpg]);
4991 if (nd->nd_bextpg == 0)
4992 nd->nd_bpos += m->m_epg_1st_off;
4994 nd->nd_bpos += offs;
4995 nd->nd_bextpgsiz = rlen - offs;
4996 } else if (nd->nd_bextpg == 0)
4997 nd->nd_bextpgsiz = PAGE_SIZE - m->m_epg_1st_off;
4999 nd->nd_bextpgsiz = PAGE_SIZE;
5001 nd->nd_bpos = mtod(m, char *) + offs;
5005 * Grow a ext_pgs mbuf list. Either allocate another page or add
5006 * an mbuf to the list.
5009 nfsm_add_ext_pgs(struct mbuf *m, int maxextsiz, int *bextpg)
5014 if ((m->m_epg_npgs + 1) * PAGE_SIZE > maxextsiz) {
5015 mp = mb_alloc_ext_plus_pages(PAGE_SIZE, M_WAITOK);
5019 pg = vm_page_alloc_noobj(VM_ALLOC_WAITOK | VM_ALLOC_NODUMP |
5021 m->m_epg_pa[m->m_epg_npgs] = VM_PAGE_TO_PHYS(pg);
5022 *bextpg = m->m_epg_npgs;
5024 m->m_epg_last_len = 0;
5031 * Do the NFSv4.1 Destroy Session.
5034 nfsrpc_destroysession(struct nfsmount *nmp, struct nfsclsession *tsep,
5035 struct ucred *cred, NFSPROC_T *p)
5038 struct nfsrv_descript nfsd;
5039 struct nfsrv_descript *nd = &nfsd;
5042 nfscl_reqstart(nd, NFSPROC_DESTROYSESSION, nmp, NULL, 0, NULL, NULL, 0,
5044 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID);
5046 tsep = nfsmnt_mdssession(nmp);
5047 bcopy(tsep->nfsess_sessionid, tl, NFSX_V4SESSIONID);
5048 nd->nd_flag |= ND_USEGSSNAME;
5049 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
5050 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
5053 error = nd->nd_repstat;
5054 m_freem(nd->nd_mrep);