2 * SPDX-License-Identifier: BSD-3-Clause
4 * Copyright (c) 1989, 1993
5 * The Regents of the University of California. All rights reserved.
7 * This code is derived from software contributed to Berkeley by
8 * Rick Macklem at The University of Guelph.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 #include <sys/cdefs.h>
37 __FBSDID("$FreeBSD$");
40 * These functions support the macros and help fiddle mbuf chains for
41 * the nfs op functions. They do things like create the rpc header and
42 * copy data between mbuf chains and uio lists.
45 #include "opt_inet6.h"
47 #include <fs/nfs/nfsport.h>
49 #include <sys/extattr.h>
51 #include <security/mac/mac_framework.h>
53 #include <vm/vm_param.h>
56 * Data items converted to xdr at startup, since they are constant
57 * This is kinda hokey, but may save a little time doing byte swaps
59 u_int32_t newnfs_true, newnfs_false, newnfs_xdrneg1;
61 /* And other global data */
62 nfstype nfsv34_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK,
64 enum vtype newnv2tov_type[8] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON };
65 enum vtype nv34tov_type[8]={ VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO };
66 struct timeval nfsboottime; /* Copy boottime once, so it never changes */
69 struct nfssockreq nfsrv_nfsuserdsock;
70 nfsuserd_state nfsrv_nfsuserd = NOTRUNNING;
71 static int nfsrv_userdupcalls = 0;
72 struct nfsreqhead nfsd_reqq;
73 uid_t nfsrv_defaultuid = UID_NOBODY;
74 gid_t nfsrv_defaultgid = GID_NOGROUP;
75 int nfsrv_lease = NFSRV_LEASE;
76 int ncl_mbuf_mlen = MLEN;
77 int nfsd_enable_stringtouid = 0;
78 int nfsrv_doflexfile = 0;
79 static int nfs_enable_uidtostring = 0;
82 extern int nfsrv_lughashsize;
83 extern struct mtx nfsrv_dslock_mtx;
84 extern volatile int nfsrv_devidcnt;
85 extern int nfscl_debuglevel;
86 extern struct nfsdevicehead nfsrv_devidhead;
87 extern struct nfsstatsv1 nfsstatsv1;
89 SYSCTL_DECL(_vfs_nfs);
90 SYSCTL_INT(_vfs_nfs, OID_AUTO, enable_uidtostring, CTLFLAG_RW,
91 &nfs_enable_uidtostring, 0, "Make nfs always send numeric owner_names");
93 int nfsrv_maxpnfsmirror = 1;
94 SYSCTL_INT(_vfs_nfs, OID_AUTO, pnfsmirror, CTLFLAG_RD,
95 &nfsrv_maxpnfsmirror, 0, "Mirror level for pNFS service");
97 int nfs_maxcopyrange = 10 * 1024 * 1024;
98 SYSCTL_INT(_vfs_nfs, OID_AUTO, maxcopyrange, CTLFLAG_RW,
99 &nfs_maxcopyrange, 0, "Max size of a Copy so RPC times reasonable");
102 * This array of structures indicates, for V4:
103 * retfh - which of 3 types of calling args are used
104 * 0 - doesn't change cfh or use a sfh
105 * 1 - replaces cfh with a new one (unless it returns an error status)
106 * 2 - uses cfh and sfh
107 * needscfh - if the op wants a cfh and premtime
108 * 0 - doesn't use a cfh
109 * 1 - uses a cfh, but doesn't want pre-op attributes
110 * 2 - uses a cfh and wants pre-op attributes
111 * savereply - indicates a non-idempotent Op
112 * 0 - not non-idempotent
114 * Ops that are ordered via seqid# are handled separately from these
115 * non-idempotent Ops.
116 * Define it here, since it is used by both the client and server.
118 struct nfsv4_opflag nfsv4_opflag[NFSV42_NOPS] = {
119 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* undef */
120 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* undef */
121 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* undef */
122 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Access */
123 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Close */
124 { 0, 2, 0, 1, LK_EXCLUSIVE, 1, 1 }, /* Commit */
125 { 1, 2, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Create */
126 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Delegpurge */
127 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Delegreturn */
128 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Getattr */
129 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* GetFH */
130 { 2, 1, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Link */
131 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Lock */
132 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* LockT */
133 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* LockU */
134 { 1, 2, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Lookup */
135 { 1, 2, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Lookupp */
136 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* NVerify */
137 { 1, 1, 0, 1, LK_EXCLUSIVE, 1, 0 }, /* Open */
138 { 1, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* OpenAttr */
139 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* OpenConfirm */
140 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* OpenDowngrade */
141 { 1, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* PutFH */
142 { 1, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* PutPubFH */
143 { 1, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* PutRootFH */
144 { 0, 1, 0, 0, LK_SHARED, 1, 0 }, /* Read */
145 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Readdir */
146 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* ReadLink */
147 { 0, 2, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Remove */
148 { 2, 1, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Rename */
149 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Renew */
150 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* RestoreFH */
151 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SaveFH */
152 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SecInfo */
153 { 0, 2, 1, 1, LK_EXCLUSIVE, 1, 0 }, /* Setattr */
154 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SetClientID */
155 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SetClientIDConfirm */
156 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Verify */
157 { 0, 2, 1, 1, LK_EXCLUSIVE, 1, 0 }, /* Write */
158 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* ReleaseLockOwner */
159 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Backchannel Ctrl */
160 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Bind Conn to Sess */
161 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Exchange ID */
162 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Create Session */
163 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Destroy Session */
164 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Free StateID */
165 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Get Dir Deleg */
166 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Get Device Info */
167 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Get Device List */
168 { 0, 1, 0, 1, LK_EXCLUSIVE, 1, 1 }, /* Layout Commit */
169 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Layout Get */
170 { 0, 1, 0, 1, LK_EXCLUSIVE, 1, 0 }, /* Layout Return */
171 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Secinfo No name */
172 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Sequence */
173 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Set SSV */
174 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Test StateID */
175 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Want Delegation */
176 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Destroy ClientID */
177 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Reclaim Complete */
178 { 0, 1, 1, 1, LK_EXCLUSIVE, 1, 0 }, /* Allocate */
179 { 2, 1, 1, 0, LK_SHARED, 1, 0 }, /* Copy */
180 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Copy Notify */
181 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Deallocate */
182 { 0, 1, 0, 0, LK_SHARED, 1, 0 }, /* IO Advise */
183 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Layout Error */
184 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Layout Stats */
185 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Offload Cancel */
186 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Offload Status */
187 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Read Plus */
188 { 0, 1, 0, 0, LK_SHARED, 1, 0 }, /* Seek */
189 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Write Same */
190 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Clone */
191 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Getxattr */
192 { 0, 1, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Setxattr */
193 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Listxattrs */
194 { 0, 1, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Removexattr */
197 static int ncl_mbuf_mhlen = MHLEN;
198 static int nfsrv_usercnt = 0;
199 static int nfsrv_dnsnamelen;
200 static u_char *nfsrv_dnsname = NULL;
201 static int nfsrv_usermax = 999999999;
202 struct nfsrv_lughash {
204 struct nfsuserhashhead lughead;
206 static struct nfsrv_lughash *nfsuserhash;
207 static struct nfsrv_lughash *nfsusernamehash;
208 static struct nfsrv_lughash *nfsgrouphash;
209 static struct nfsrv_lughash *nfsgroupnamehash;
212 * This static array indicates whether or not the RPC generates a large
213 * reply. This is used by nfs_reply() to decide whether or not an mbuf
214 * cluster should be allocated. (If a cluster is required by an RPC
215 * marked 0 in this array, the code will still work, just not quite as
218 static int nfs_bigreply[NFSV42_NPROCS] = { 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0,
219 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
220 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
223 /* local functions */
224 static int nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep);
225 static void nfsv4_wanted(struct nfsv4lock *lp);
226 static int nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len);
227 static int nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name);
228 static void nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser);
229 static int nfsrv_getrefstr(struct nfsrv_descript *, u_char **, u_char **,
231 static void nfsrv_refstrbigenough(int, u_char **, u_char **, int *);
238 } nfsv4_opmap[NFSV42_NPROCS] = {
240 { NFSV4OP_GETATTR, 1, "Getattr", 7, },
241 { NFSV4OP_SETATTR, 2, "Setattr", 7, },
242 { NFSV4OP_LOOKUP, 3, "Lookup", 6, },
243 { NFSV4OP_ACCESS, 2, "Access", 6, },
244 { NFSV4OP_READLINK, 2, "Readlink", 8, },
245 { NFSV4OP_READ, 1, "Read", 4, },
246 { NFSV4OP_WRITE, 2, "Write", 5, },
247 { NFSV4OP_OPEN, 5, "Open", 4, },
248 { NFSV4OP_CREATE, 5, "Create", 6, },
249 { NFSV4OP_CREATE, 1, "Create", 6, },
250 { NFSV4OP_CREATE, 3, "Create", 6, },
251 { NFSV4OP_REMOVE, 1, "Remove", 6, },
252 { NFSV4OP_REMOVE, 1, "Remove", 6, },
253 { NFSV4OP_SAVEFH, 5, "Rename", 6, },
254 { NFSV4OP_SAVEFH, 4, "Link", 4, },
255 { NFSV4OP_READDIR, 2, "Readdir", 7, },
256 { NFSV4OP_READDIR, 2, "Readdir", 7, },
257 { NFSV4OP_GETATTR, 1, "Getattr", 7, },
258 { NFSV4OP_GETATTR, 1, "Getattr", 7, },
259 { NFSV4OP_GETATTR, 1, "Getattr", 7, },
260 { NFSV4OP_COMMIT, 2, "Commit", 6, },
261 { NFSV4OP_LOOKUPP, 3, "Lookupp", 7, },
262 { NFSV4OP_SETCLIENTID, 1, "SetClientID", 11, },
263 { NFSV4OP_SETCLIENTIDCFRM, 1, "SetClientIDConfirm", 18, },
264 { NFSV4OP_LOCK, 1, "Lock", 4, },
265 { NFSV4OP_LOCKU, 1, "LockU", 5, },
266 { NFSV4OP_OPEN, 2, "Open", 4, },
267 { NFSV4OP_CLOSE, 1, "Close", 5, },
268 { NFSV4OP_OPENCONFIRM, 1, "Openconfirm", 11, },
269 { NFSV4OP_LOCKT, 1, "LockT", 5, },
270 { NFSV4OP_OPENDOWNGRADE, 1, "Opendowngrade", 13, },
271 { NFSV4OP_RENEW, 1, "Renew", 5, },
272 { NFSV4OP_PUTROOTFH, 1, "Dirpath", 7, },
273 { NFSV4OP_RELEASELCKOWN, 1, "Rellckown", 9, },
274 { NFSV4OP_DELEGRETURN, 1, "Delegret", 8, },
275 { NFSV4OP_DELEGRETURN, 3, "DelegRemove", 11, },
276 { NFSV4OP_DELEGRETURN, 7, "DelegRename1", 12, },
277 { NFSV4OP_DELEGRETURN, 9, "DelegRename2", 12, },
278 { NFSV4OP_GETATTR, 1, "Getacl", 6, },
279 { NFSV4OP_SETATTR, 1, "Setacl", 6, },
280 { NFSV4OP_EXCHANGEID, 1, "ExchangeID", 10, },
281 { NFSV4OP_CREATESESSION, 1, "CreateSession", 13, },
282 { NFSV4OP_DESTROYSESSION, 1, "DestroySession", 14, },
283 { NFSV4OP_DESTROYCLIENTID, 1, "DestroyClient", 13, },
284 { NFSV4OP_FREESTATEID, 1, "FreeStateID", 11, },
285 { NFSV4OP_LAYOUTGET, 1, "LayoutGet", 9, },
286 { NFSV4OP_GETDEVINFO, 1, "GetDeviceInfo", 13, },
287 { NFSV4OP_LAYOUTCOMMIT, 1, "LayoutCommit", 12, },
288 { NFSV4OP_LAYOUTRETURN, 1, "LayoutReturn", 12, },
289 { NFSV4OP_RECLAIMCOMPL, 1, "ReclaimComplete", 15, },
290 { NFSV4OP_WRITE, 1, "WriteDS", 7, },
291 { NFSV4OP_READ, 1, "ReadDS", 6, },
292 { NFSV4OP_COMMIT, 1, "CommitDS", 8, },
293 { NFSV4OP_OPEN, 3, "OpenLayoutGet", 13, },
294 { NFSV4OP_OPEN, 8, "CreateLayGet", 12, },
295 { NFSV4OP_IOADVISE, 1, "Advise", 6, },
296 { NFSV4OP_ALLOCATE, 2, "Allocate", 8, },
297 { NFSV4OP_SAVEFH, 5, "Copy", 4, },
298 { NFSV4OP_SEEK, 2, "Seek", 4, },
299 { NFSV4OP_SEEK, 1, "SeekDS", 6, },
300 { NFSV4OP_GETXATTR, 2, "Getxattr", 8, },
301 { NFSV4OP_SETXATTR, 2, "Setxattr", 8, },
302 { NFSV4OP_REMOVEXATTR, 2, "Rmxattr", 7, },
303 { NFSV4OP_LISTXATTRS, 2, "Listxattr", 9, },
307 * NFS RPCS that have large request message size.
309 static int nfs_bigrequest[NFSV42_NPROCS] = {
310 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
311 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
312 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0
316 * Start building a request. Mostly just put the first file handle in
320 nfscl_reqstart(struct nfsrv_descript *nd, int procnum, struct nfsmount *nmp,
321 u_int8_t *nfhp, int fhlen, u_int32_t **opcntpp, struct nfsclsession *sep,
322 int vers, int minorvers)
327 nfsattrbit_t attrbits;
330 * First, fill in some of the fields of nd.
332 nd->nd_slotseq = NULL;
333 if (vers == NFS_VER4) {
334 nd->nd_flag = ND_NFSV4 | ND_NFSCL;
335 if (minorvers == NFSV41_MINORVERSION)
336 nd->nd_flag |= ND_NFSV41;
337 else if (minorvers == NFSV42_MINORVERSION)
338 nd->nd_flag |= (ND_NFSV41 | ND_NFSV42);
339 } else if (vers == NFS_VER3)
340 nd->nd_flag = ND_NFSV3 | ND_NFSCL;
342 if (NFSHASNFSV4(nmp)) {
343 nd->nd_flag = ND_NFSV4 | ND_NFSCL;
344 if (nmp->nm_minorvers == 1)
345 nd->nd_flag |= ND_NFSV41;
346 else if (nmp->nm_minorvers == 2)
347 nd->nd_flag |= (ND_NFSV41 | ND_NFSV42);
348 } else if (NFSHASNFSV3(nmp))
349 nd->nd_flag = ND_NFSV3 | ND_NFSCL;
351 nd->nd_flag = ND_NFSV2 | ND_NFSCL;
353 nd->nd_procnum = procnum;
355 nd->nd_maxextsiz = 0;
358 * Get the first mbuf for the request.
360 if (nfs_bigrequest[procnum])
361 NFSMCLGET(mb, M_WAITOK);
365 nd->nd_mreq = nd->nd_mb = mb;
366 nd->nd_bpos = mtod(mb, char *);
369 * And fill the first file handle into the request.
371 if (nd->nd_flag & ND_NFSV4) {
372 opcnt = nfsv4_opmap[procnum].opcnt +
373 nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh;
374 if ((nd->nd_flag & ND_NFSV41) != 0) {
375 opcnt += nfsv4_opflag[nfsv4_opmap[procnum].op].needsseq;
376 if (procnum == NFSPROC_RENEW)
378 * For the special case of Renew, just do a
382 else if (procnum == NFSPROC_WRITEDS ||
383 procnum == NFSPROC_COMMITDS)
385 * For the special case of a Writeor Commit to
386 * a DS, the opcnt == 3, for Sequence, PutFH,
392 * What should the tag really be?
394 (void) nfsm_strtom(nd, nfsv4_opmap[procnum].tag,
395 nfsv4_opmap[procnum].taglen);
396 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
397 if ((nd->nd_flag & ND_NFSV42) != 0)
398 *tl++ = txdr_unsigned(NFSV42_MINORVERSION);
399 else if ((nd->nd_flag & ND_NFSV41) != 0)
400 *tl++ = txdr_unsigned(NFSV41_MINORVERSION);
402 *tl++ = txdr_unsigned(NFSV4_MINORVERSION);
405 *tl = txdr_unsigned(opcnt);
406 if ((nd->nd_flag & ND_NFSV41) != 0 &&
407 nfsv4_opflag[nfsv4_opmap[procnum].op].needsseq > 0) {
408 if (nfsv4_opflag[nfsv4_opmap[procnum].op].loopbadsess >
410 nd->nd_flag |= ND_LOOPBADSESS;
411 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
412 *tl = txdr_unsigned(NFSV4OP_SEQUENCE);
414 sep = nfsmnt_mdssession(nmp);
415 nfsv4_setsequence(nmp, nd, sep,
416 nfs_bigreply[procnum]);
418 nfsv4_setsequence(nmp, nd, sep,
419 nfs_bigreply[procnum]);
421 if (nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh > 0) {
422 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
423 *tl = txdr_unsigned(NFSV4OP_PUTFH);
424 (void) nfsm_fhtom(nd, nfhp, fhlen, 0);
425 if (nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh
426 == 2 && procnum != NFSPROC_WRITEDS &&
427 procnum != NFSPROC_COMMITDS) {
428 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
429 *tl = txdr_unsigned(NFSV4OP_GETATTR);
431 * For Lookup Ops, we want all the directory
432 * attributes, so we can load the name cache.
434 if (procnum == NFSPROC_LOOKUP ||
435 procnum == NFSPROC_LOOKUPP)
436 NFSGETATTR_ATTRBIT(&attrbits);
438 NFSWCCATTR_ATTRBIT(&attrbits);
439 nd->nd_flag |= ND_V4WCCATTR;
441 (void) nfsrv_putattrbit(nd, &attrbits);
444 if (procnum != NFSPROC_RENEW ||
445 (nd->nd_flag & ND_NFSV41) == 0) {
446 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
447 *tl = txdr_unsigned(nfsv4_opmap[procnum].op);
450 (void) nfsm_fhtom(nd, nfhp, fhlen, 0);
452 if (procnum < NFSV42_NPROCS)
453 NFSINCRGLOBAL(nfsstatsv1.rpccnt[procnum]);
457 * Put a state Id in the mbuf list.
460 nfsm_stateidtom(struct nfsrv_descript *nd, nfsv4stateid_t *stateidp, int flag)
464 NFSM_BUILD(st, nfsv4stateid_t *, NFSX_STATEID);
465 if (flag == NFSSTATEID_PUTALLZERO) {
470 } else if (flag == NFSSTATEID_PUTALLONE) {
471 st->seqid = 0xffffffff;
472 st->other[0] = 0xffffffff;
473 st->other[1] = 0xffffffff;
474 st->other[2] = 0xffffffff;
475 } else if (flag == NFSSTATEID_PUTSEQIDZERO) {
477 st->other[0] = stateidp->other[0];
478 st->other[1] = stateidp->other[1];
479 st->other[2] = stateidp->other[2];
481 st->seqid = stateidp->seqid;
482 st->other[0] = stateidp->other[0];
483 st->other[1] = stateidp->other[1];
484 st->other[2] = stateidp->other[2];
489 * Fill in the setable attributes. The full argument indicates whether
490 * to fill in them all or just mode and time.
493 nfscl_fillsattr(struct nfsrv_descript *nd, struct vattr *vap,
494 struct vnode *vp, int flags, u_int32_t rdev)
497 struct nfsv2_sattr *sp;
498 nfsattrbit_t attrbits;
501 switch (nd->nd_flag & (ND_NFSV2 | ND_NFSV3 | ND_NFSV4)) {
503 NFSM_BUILD(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
504 if (vap->va_mode == (mode_t)VNOVAL)
505 sp->sa_mode = newnfs_xdrneg1;
507 sp->sa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
508 if (vap->va_uid == (uid_t)VNOVAL)
509 sp->sa_uid = newnfs_xdrneg1;
511 sp->sa_uid = txdr_unsigned(vap->va_uid);
512 if (vap->va_gid == (gid_t)VNOVAL)
513 sp->sa_gid = newnfs_xdrneg1;
515 sp->sa_gid = txdr_unsigned(vap->va_gid);
516 if (flags & NFSSATTR_SIZE0)
518 else if (flags & NFSSATTR_SIZENEG1)
519 sp->sa_size = newnfs_xdrneg1;
520 else if (flags & NFSSATTR_SIZERDEV)
521 sp->sa_size = txdr_unsigned(rdev);
523 sp->sa_size = txdr_unsigned(vap->va_size);
524 txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
525 txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
528 if (vap->va_mode != (mode_t)VNOVAL) {
529 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
531 *tl = txdr_unsigned(vap->va_mode);
533 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
536 if ((flags & NFSSATTR_FULL) && vap->va_uid != (uid_t)VNOVAL) {
537 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
539 *tl = txdr_unsigned(vap->va_uid);
541 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
544 if ((flags & NFSSATTR_FULL) && vap->va_gid != (gid_t)VNOVAL) {
545 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
547 *tl = txdr_unsigned(vap->va_gid);
549 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
552 if ((flags & NFSSATTR_FULL) && vap->va_size != VNOVAL) {
553 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
555 txdr_hyper(vap->va_size, tl);
557 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
560 if (vap->va_atime.tv_sec != VNOVAL) {
561 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
562 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
563 *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
564 txdr_nfsv3time(&vap->va_atime, tl);
566 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
567 *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
570 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
571 *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
573 if (vap->va_mtime.tv_sec != VNOVAL) {
574 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
575 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
576 *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
577 txdr_nfsv3time(&vap->va_mtime, tl);
579 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
580 *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
583 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
584 *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
588 NFSZERO_ATTRBIT(&attrbits);
589 if (vap->va_mode != (mode_t)VNOVAL)
590 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_MODE);
591 if ((flags & NFSSATTR_FULL) && vap->va_uid != (uid_t)VNOVAL)
592 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
593 if ((flags & NFSSATTR_FULL) && vap->va_gid != (gid_t)VNOVAL)
594 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP);
595 if ((flags & NFSSATTR_FULL) && vap->va_size != VNOVAL)
596 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_SIZE);
597 if (vap->va_atime.tv_sec != VNOVAL)
598 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET);
599 if (vap->va_mtime.tv_sec != VNOVAL)
600 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET);
601 if (vap->va_birthtime.tv_sec != VNOVAL &&
602 strcmp(vp->v_mount->mnt_vfc->vfc_name, "nfs") == 0) {
604 * We can only test for support of TimeCreate if
605 * the "vp" argument is for an NFS vnode.
608 if (NFSISSET_ATTRBIT(&np->n_vattr.na_suppattr,
609 NFSATTRBIT_TIMECREATE))
610 NFSSETBIT_ATTRBIT(&attrbits,
611 NFSATTRBIT_TIMECREATE);
613 (void) nfsv4_fillattr(nd, vp->v_mount, vp, NULL, vap, NULL, 0,
614 &attrbits, NULL, NULL, 0, 0, 0, 0, (uint64_t)0, NULL);
621 * copies mbuf chain to the uio scatter/gather list
624 nfsm_mbufuio(struct nfsrv_descript *nd, struct uio *uiop, int siz)
626 char *mbufcp, *uiocp;
633 mbufcp = nd->nd_dpos;
634 len = mtod(mp, caddr_t) + mp->m_len - mbufcp;
635 rem = NFSM_RNDUP(siz) - siz;
637 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) {
641 left = uiop->uio_iov->iov_len;
642 uiocp = uiop->uio_iov->iov_base;
653 mbufcp = mtod(mp, caddr_t);
656 ("len %d, corrupted mbuf?", len));
658 xfer = (left > len) ? len : left;
661 if (uiop->uio_iov->iov_op != NULL)
662 (*(uiop->uio_iov->iov_op))
663 (mbufcp, uiocp, xfer);
666 if (uiop->uio_segflg == UIO_SYSSPACE)
667 NFSBCOPY(mbufcp, uiocp, xfer);
669 copyout(mbufcp, uiocp, xfer);
674 uiop->uio_offset += xfer;
675 uiop->uio_resid -= xfer;
677 if (uiop->uio_iov->iov_len <= siz) {
681 uiop->uio_iov->iov_base = (void *)
682 ((char *)uiop->uio_iov->iov_base + uiosiz);
683 uiop->uio_iov->iov_len -= uiosiz;
687 nd->nd_dpos = mbufcp;
691 error = nfsm_advance(nd, rem, len);
697 NFSEXITCODE2(error, nd);
703 * Help break down an mbuf chain by setting the first siz bytes contiguous
704 * pointed to by returned val.
705 * This is used by the macro NFSM_DISSECT for tough
709 nfsm_dissct(struct nfsrv_descript *nd, int siz, int how)
718 left = mtod(nd->nd_md, caddr_t) + nd->nd_md->m_len - nd->nd_dpos;
720 nd->nd_md = nd->nd_md->m_next;
721 if (nd->nd_md == NULL)
723 left = nd->nd_md->m_len;
724 nd->nd_dpos = mtod(nd->nd_md, caddr_t);
729 } else if (nd->nd_md->m_next == NULL) {
731 } else if (siz > ncl_mbuf_mhlen) {
732 panic("nfs S too big");
734 MGET(mp2, MT_DATA, how);
737 mp2->m_next = nd->nd_md->m_next;
738 nd->nd_md->m_next = mp2;
739 nd->nd_md->m_len -= left;
741 retp = p = mtod(mp2, caddr_t);
742 NFSBCOPY(nd->nd_dpos, p, left); /* Copy what was left */
746 /* Loop around copying up the siz2 bytes */
750 xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2;
752 NFSBCOPY(mtod(mp2, caddr_t), p, xfer);
761 nd->nd_md->m_len = siz;
763 nd->nd_dpos = mtod(mp2, caddr_t);
769 * Advance the position in the mbuf chain.
770 * If offs == 0, this is a no-op, but it is simpler to just return from
771 * here than check for offs > 0 for all calls to nfsm_advance.
772 * If left == -1, it should be calculated here.
775 nfsm_advance(struct nfsrv_descript *nd, int offs, int left)
782 * A negative offs might indicate a corrupted mbuf chain and,
783 * as such, a printf is logged.
786 printf("nfsrv_advance: negative offs\n");
792 * If left == -1, calculate it here.
795 left = mtod(nd->nd_md, caddr_t) + nd->nd_md->m_len -
799 * Loop around, advancing over the mbuf data.
801 while (offs > left) {
803 nd->nd_md = nd->nd_md->m_next;
804 if (nd->nd_md == NULL) {
808 left = nd->nd_md->m_len;
809 nd->nd_dpos = mtod(nd->nd_md, caddr_t);
819 * Copy a string into mbuf(s).
820 * Return the number of bytes output, including XDR overheads.
823 nfsm_strtom(struct nfsrv_descript *nd, const char *cp, int siz)
832 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
833 *tl = txdr_unsigned(siz);
834 rem = NFSM_RNDUP(siz) - siz;
835 bytesize = NFSX_UNSIGNED + siz + rem;
838 if ((nd->nd_flag & ND_EXTPG) != 0)
839 left = nd->nd_bextpgsiz;
841 left = M_TRAILINGSPACE(m2);
843 KASSERT(((m2->m_flags & (M_EXT | M_EXTPG)) ==
844 (M_EXT | M_EXTPG) && (nd->nd_flag & ND_EXTPG) != 0) ||
845 ((m2->m_flags & (M_EXT | M_EXTPG)) !=
846 (M_EXT | M_EXTPG) && (nd->nd_flag & ND_EXTPG) == 0),
847 ("nfsm_strtom: ext_pgs and non-ext_pgs mbufs mixed"));
849 * Loop around copying the string to mbuf(s).
853 if ((nd->nd_flag & ND_EXTPG) != 0) {
854 m2 = nfsm_add_ext_pgs(m2,
855 nd->nd_maxextsiz, &nd->nd_bextpg);
856 cp2 = (char *)(void *)PHYS_TO_DMAP(
857 m2->m_epg_pa[nd->nd_bextpg]);
858 nd->nd_bextpgsiz = left = PAGE_SIZE;
860 if (siz > ncl_mbuf_mlen)
861 NFSMCLGET(m1, M_WAITOK);
865 cp2 = mtod(m1, char *);
866 left = M_TRAILINGSPACE(m1);
875 NFSBCOPY(cp, cp2, xfer);
881 if ((nd->nd_flag & ND_EXTPG) != 0) {
882 nd->nd_bextpgsiz -= xfer;
883 m2->m_epg_last_len += xfer;
885 if (siz == 0 && rem) {
887 panic("nfsm_strtom");
891 if ((nd->nd_flag & ND_EXTPG) != 0) {
892 nd->nd_bextpgsiz -= rem;
893 m2->m_epg_last_len += rem;
898 if ((nd->nd_flag & ND_EXTPG) != 0)
901 nd->nd_bpos = mtod(m2, char *) + m2->m_len;
906 * Called once to initialize data structures...
911 static int nfs_inited = 0;
917 newnfs_true = txdr_unsigned(TRUE);
918 newnfs_false = txdr_unsigned(FALSE);
919 newnfs_xdrneg1 = txdr_unsigned(-1);
920 nfscl_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
923 NFSSETBOOTTIME(nfsboottime);
926 * Initialize reply list and start timer
928 TAILQ_INIT(&nfsd_reqq);
933 * Put a file handle in an mbuf list.
934 * If the size argument == 0, just use the default size.
935 * set_true == 1 if there should be an newnfs_true prepended on the file handle.
936 * Return the number of bytes output, including XDR overhead.
939 nfsm_fhtom(struct nfsrv_descript *nd, u_int8_t *fhp, int size, int set_true)
943 int fullsiz, rem, bytesize = 0;
947 switch (nd->nd_flag & (ND_NFSV2 | ND_NFSV3 | ND_NFSV4)) {
949 if (size > NFSX_V2FH)
950 panic("fh size > NFSX_V2FH for NFSv2");
951 NFSM_BUILD(cp, u_int8_t *, NFSX_V2FH);
952 NFSBCOPY(fhp, cp, size);
953 if (size < NFSX_V2FH)
954 NFSBZERO(cp + size, NFSX_V2FH - size);
955 bytesize = NFSX_V2FH;
959 fullsiz = NFSM_RNDUP(size);
960 rem = fullsiz - size;
962 bytesize = 2 * NFSX_UNSIGNED + fullsiz;
963 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
966 bytesize = NFSX_UNSIGNED + fullsiz;
968 (void) nfsm_strtom(nd, fhp, size);
975 * This function compares two net addresses by family and returns TRUE
976 * if they are the same host.
977 * If there is any doubt, return FALSE.
978 * The AF_INET family is handled as a special case so that address mbufs
979 * don't need to be saved to store "struct in_addr", which is only 4 bytes.
982 nfsaddr_match(int family, union nethostaddr *haddr, NFSSOCKADDR_T nam)
985 struct sockaddr_in *inetaddr;
991 inetaddr = NFSSOCKADDR(nam, struct sockaddr_in *);
992 if (inetaddr->sin_family == AF_INET &&
993 inetaddr->sin_addr.s_addr == haddr->had_inet.s_addr)
1000 struct sockaddr_in6 *inetaddr6;
1002 inetaddr6 = NFSSOCKADDR(nam, struct sockaddr_in6 *);
1003 /* XXX - should test sin6_scope_id ? */
1004 if (inetaddr6->sin6_family == AF_INET6 &&
1005 IN6_ARE_ADDR_EQUAL(&inetaddr6->sin6_addr,
1016 * Similar to the above, but takes to NFSSOCKADDR_T args.
1019 nfsaddr2_match(NFSSOCKADDR_T nam1, NFSSOCKADDR_T nam2)
1021 struct sockaddr_in *addr1, *addr2;
1022 struct sockaddr *inaddr;
1024 inaddr = NFSSOCKADDR(nam1, struct sockaddr *);
1025 switch (inaddr->sa_family) {
1027 addr1 = NFSSOCKADDR(nam1, struct sockaddr_in *);
1028 addr2 = NFSSOCKADDR(nam2, struct sockaddr_in *);
1029 if (addr2->sin_family == AF_INET &&
1030 addr1->sin_addr.s_addr == addr2->sin_addr.s_addr)
1036 struct sockaddr_in6 *inet6addr1, *inet6addr2;
1038 inet6addr1 = NFSSOCKADDR(nam1, struct sockaddr_in6 *);
1039 inet6addr2 = NFSSOCKADDR(nam2, struct sockaddr_in6 *);
1040 /* XXX - should test sin6_scope_id ? */
1041 if (inet6addr2->sin6_family == AF_INET6 &&
1042 IN6_ARE_ADDR_EQUAL(&inet6addr1->sin6_addr,
1043 &inet6addr2->sin6_addr))
1053 * Dissect a file handle on the client.
1056 nfsm_getfh(struct nfsrv_descript *nd, struct nfsfh **nfhpp)
1063 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
1064 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1065 if ((len = fxdr_unsigned(int, *tl)) <= 0 ||
1072 nfhp = malloc(sizeof (struct nfsfh) + len,
1074 error = nfsrv_mtostr(nd, nfhp->nfh_fh, len);
1076 free(nfhp, M_NFSFH);
1079 nfhp->nfh_len = len;
1082 NFSEXITCODE2(error, nd);
1087 * Break down the nfsv4 acl.
1088 * If the aclp == NULL or won't fit in an acl, just discard the acl info.
1091 nfsrv_dissectacl(struct nfsrv_descript *nd, NFSACL_T *aclp, int *aclerrp,
1092 int *aclsizep, __unused NFSPROC_T *p)
1096 int acecnt, error = 0, aceerr = 0, acesize;
1102 * Parse out the ace entries and expect them to conform to
1103 * what can be supported by R/W/X bits.
1105 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1106 aclsize = NFSX_UNSIGNED;
1107 acecnt = fxdr_unsigned(int, *tl);
1108 if (acecnt > ACL_MAX_ENTRIES)
1109 aceerr = NFSERR_ATTRNOTSUPP;
1110 if (nfsrv_useacl == 0)
1111 aceerr = NFSERR_ATTRNOTSUPP;
1112 for (i = 0; i < acecnt; i++) {
1113 if (aclp && !aceerr)
1114 error = nfsrv_dissectace(nd, &aclp->acl_entry[i],
1115 &aceerr, &acesize, p);
1117 error = nfsrv_skipace(nd, &acesize);
1122 if (aclp && !aceerr)
1123 aclp->acl_cnt = acecnt;
1127 *aclsizep = aclsize;
1129 NFSEXITCODE2(error, nd);
1134 * Skip over an NFSv4 ace entry. Just dissect the xdr and discard it.
1137 nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep)
1142 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1143 len = fxdr_unsigned(int, *(tl + 3));
1144 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
1146 *acesizep = NFSM_RNDUP(len) + (4 * NFSX_UNSIGNED);
1147 NFSEXITCODE2(error, nd);
1152 * Get attribute bits from an mbuf list.
1153 * Returns EBADRPC for a parsing error, 0 otherwise.
1154 * If the clearinvalid flag is set, clear the bits not supported.
1157 nfsrv_getattrbits(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp, int *cntp,
1164 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1165 cnt = fxdr_unsigned(int, *tl);
1167 error = NFSERR_BADXDR;
1170 if (cnt > NFSATTRBIT_MAXWORDS)
1171 outcnt = NFSATTRBIT_MAXWORDS;
1174 NFSZERO_ATTRBIT(attrbitp);
1176 NFSM_DISSECT(tl, u_int32_t *, outcnt * NFSX_UNSIGNED);
1177 for (i = 0; i < outcnt; i++)
1178 attrbitp->bits[i] = fxdr_unsigned(u_int32_t, *tl++);
1180 for (i = 0; i < (cnt - outcnt); i++) {
1181 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1182 if (retnotsupp != NULL && *tl != 0)
1183 *retnotsupp = NFSERR_ATTRNOTSUPP;
1186 *cntp = NFSX_UNSIGNED + (cnt * NFSX_UNSIGNED);
1188 NFSEXITCODE2(error, nd);
1193 * Get the attributes for V4.
1194 * If the compare flag is true, test for any attribute changes,
1195 * otherwise return the attribute values.
1196 * These attributes cover fields in "struct vattr", "struct statfs",
1197 * "struct nfsfsinfo", the file handle and the lease duration.
1198 * The value of retcmpp is set to 1 if all attributes are the same,
1200 * Returns EBADRPC if it can't be parsed, 0 otherwise.
1203 nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp,
1204 struct nfsvattr *nap, struct nfsfh **nfhpp, fhandle_t *fhp, int fhsize,
1205 struct nfsv3_pathconf *pc, struct statfs *sbp, struct nfsstatfs *sfp,
1206 struct nfsfsinfo *fsp, NFSACL_T *aclp, int compare, int *retcmpp,
1207 u_int32_t *leasep, u_int32_t *rderrp, NFSPROC_T *p, struct ucred *cred)
1210 int i = 0, j, k, l = 0, m, bitpos, attrsum = 0;
1211 int error, tfhsize, aceerr, attrsize, cnt, retnotsup;
1212 u_char *cp, *cp2, namestr[NFSV4_SMALLSTR + 1];
1213 nfsattrbit_t attrbits, retattrbits, checkattrbits;
1214 struct nfsfh *tnfhp;
1215 struct nfsreferral *refp;
1218 struct timespec temptime;
1221 u_int32_t freenum = 0, tuint;
1222 u_int64_t uquad = 0, thyp, thyp2;
1228 CTASSERT(sizeof(ino_t) == sizeof(uint64_t));
1231 error = nfsrv_getattrbits(nd, &attrbits, NULL, &retnotsup);
1233 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
1239 *retcmpp = retnotsup;
1242 * Just set default values to some of the important ones.
1245 nap->na_type = VREG;
1247 nap->na_rdev = (NFSDEV_T)0;
1248 nap->na_mtime.tv_sec = 0;
1249 nap->na_mtime.tv_nsec = 0;
1252 nap->na_blocksize = NFS_FABLKSIZE;
1255 sbp->f_bsize = NFS_FABLKSIZE;
1263 fsp->fs_rtmax = 8192;
1264 fsp->fs_rtpref = 8192;
1265 fsp->fs_maxname = NFS_MAXNAMLEN;
1266 fsp->fs_wtmax = 8192;
1267 fsp->fs_wtpref = 8192;
1268 fsp->fs_wtmult = NFS_FABLKSIZE;
1269 fsp->fs_dtpref = 8192;
1270 fsp->fs_maxfilesize = 0xffffffffffffffffull;
1271 fsp->fs_timedelta.tv_sec = 0;
1272 fsp->fs_timedelta.tv_nsec = 1;
1273 fsp->fs_properties = (NFSV3_FSFLINK | NFSV3_FSFSYMLINK |
1274 NFSV3_FSFHOMOGENEOUS | NFSV3_FSFCANSETTIME);
1277 pc->pc_linkmax = NFS_LINK_MAX;
1278 pc->pc_namemax = NAME_MAX;
1280 pc->pc_chownrestricted = 0;
1281 pc->pc_caseinsensitive = 0;
1282 pc->pc_casepreserving = 1;
1285 sfp->sf_ffiles = UINT64_MAX;
1286 sfp->sf_tfiles = UINT64_MAX;
1287 sfp->sf_afiles = UINT64_MAX;
1288 sfp->sf_fbytes = UINT64_MAX;
1289 sfp->sf_tbytes = UINT64_MAX;
1290 sfp->sf_abytes = UINT64_MAX;
1295 * Loop around getting the attributes.
1297 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1298 attrsize = fxdr_unsigned(int, *tl);
1299 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
1300 if (attrsum > attrsize) {
1301 error = NFSERR_BADXDR;
1304 if (NFSISSET_ATTRBIT(&attrbits, bitpos))
1306 case NFSATTRBIT_SUPPORTEDATTRS:
1308 if (compare || nap == NULL)
1309 error = nfsrv_getattrbits(nd, &retattrbits,
1312 error = nfsrv_getattrbits(nd, &nap->na_suppattr,
1316 if (compare && !(*retcmpp)) {
1317 NFSSETSUPP_ATTRBIT(&checkattrbits, nd);
1319 /* Some filesystem do not support NFSv4ACL */
1320 if (nfsrv_useacl == 0 || nfs_supportsnfsv4acls(vp) == 0) {
1321 NFSCLRBIT_ATTRBIT(&checkattrbits, NFSATTRBIT_ACL);
1322 NFSCLRBIT_ATTRBIT(&checkattrbits, NFSATTRBIT_ACLSUPPORT);
1324 if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
1326 *retcmpp = NFSERR_NOTSAME;
1330 case NFSATTRBIT_TYPE:
1331 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1334 if (nap->na_type != nfsv34tov_type(*tl))
1335 *retcmpp = NFSERR_NOTSAME;
1337 } else if (nap != NULL) {
1338 nap->na_type = nfsv34tov_type(*tl);
1340 attrsum += NFSX_UNSIGNED;
1342 case NFSATTRBIT_FHEXPIRETYPE:
1343 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1344 if (compare && !(*retcmpp)) {
1345 if (fxdr_unsigned(int, *tl) !=
1346 NFSV4FHTYPE_PERSISTENT)
1347 *retcmpp = NFSERR_NOTSAME;
1349 attrsum += NFSX_UNSIGNED;
1351 case NFSATTRBIT_CHANGE:
1352 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1355 if (nap->na_filerev != fxdr_hyper(tl))
1356 *retcmpp = NFSERR_NOTSAME;
1358 } else if (nap != NULL) {
1359 nap->na_filerev = fxdr_hyper(tl);
1361 attrsum += NFSX_HYPER;
1363 case NFSATTRBIT_SIZE:
1364 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1367 if (nap->na_size != fxdr_hyper(tl))
1368 *retcmpp = NFSERR_NOTSAME;
1370 } else if (nap != NULL) {
1371 nap->na_size = fxdr_hyper(tl);
1373 attrsum += NFSX_HYPER;
1375 case NFSATTRBIT_LINKSUPPORT:
1376 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1379 if (fsp->fs_properties & NFSV3_FSFLINK) {
1380 if (*tl == newnfs_false)
1381 *retcmpp = NFSERR_NOTSAME;
1383 if (*tl == newnfs_true)
1384 *retcmpp = NFSERR_NOTSAME;
1387 } else if (fsp != NULL) {
1388 if (*tl == newnfs_true)
1389 fsp->fs_properties |= NFSV3_FSFLINK;
1391 fsp->fs_properties &= ~NFSV3_FSFLINK;
1393 attrsum += NFSX_UNSIGNED;
1395 case NFSATTRBIT_SYMLINKSUPPORT:
1396 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1399 if (fsp->fs_properties & NFSV3_FSFSYMLINK) {
1400 if (*tl == newnfs_false)
1401 *retcmpp = NFSERR_NOTSAME;
1403 if (*tl == newnfs_true)
1404 *retcmpp = NFSERR_NOTSAME;
1407 } else if (fsp != NULL) {
1408 if (*tl == newnfs_true)
1409 fsp->fs_properties |= NFSV3_FSFSYMLINK;
1411 fsp->fs_properties &= ~NFSV3_FSFSYMLINK;
1413 attrsum += NFSX_UNSIGNED;
1415 case NFSATTRBIT_NAMEDATTR:
1416 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1417 if (compare && !(*retcmpp)) {
1418 if (*tl != newnfs_false)
1419 *retcmpp = NFSERR_NOTSAME;
1421 attrsum += NFSX_UNSIGNED;
1423 case NFSATTRBIT_FSID:
1424 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1425 thyp = fxdr_hyper(tl);
1427 thyp2 = fxdr_hyper(tl);
1429 if (*retcmpp == 0) {
1430 if (thyp != (u_int64_t)
1431 vp->v_mount->mnt_stat.f_fsid.val[0] ||
1432 thyp2 != (u_int64_t)
1433 vp->v_mount->mnt_stat.f_fsid.val[1])
1434 *retcmpp = NFSERR_NOTSAME;
1436 } else if (nap != NULL) {
1437 nap->na_filesid[0] = thyp;
1438 nap->na_filesid[1] = thyp2;
1440 attrsum += (4 * NFSX_UNSIGNED);
1442 case NFSATTRBIT_UNIQUEHANDLES:
1443 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1444 if (compare && !(*retcmpp)) {
1445 if (*tl != newnfs_true)
1446 *retcmpp = NFSERR_NOTSAME;
1448 attrsum += NFSX_UNSIGNED;
1450 case NFSATTRBIT_LEASETIME:
1451 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1453 if (fxdr_unsigned(int, *tl) != nfsrv_lease &&
1455 *retcmpp = NFSERR_NOTSAME;
1456 } else if (leasep != NULL) {
1457 *leasep = fxdr_unsigned(u_int32_t, *tl);
1459 attrsum += NFSX_UNSIGNED;
1461 case NFSATTRBIT_RDATTRERROR:
1462 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1465 *retcmpp = NFSERR_INVAL;
1466 } else if (rderrp != NULL) {
1467 *rderrp = fxdr_unsigned(u_int32_t, *tl);
1469 attrsum += NFSX_UNSIGNED;
1471 case NFSATTRBIT_ACL:
1474 if (nfsrv_useacl && nfs_supportsnfsv4acls(vp)) {
1477 naclp = acl_alloc(M_WAITOK);
1478 error = nfsrv_dissectacl(nd, naclp, &aceerr,
1484 if (aceerr || aclp == NULL ||
1485 nfsrv_compareacl(aclp, naclp))
1486 *retcmpp = NFSERR_NOTSAME;
1489 error = nfsrv_dissectacl(nd, NULL, &aceerr,
1491 *retcmpp = NFSERR_ATTRNOTSUPP;
1495 if (vp != NULL && aclp != NULL)
1496 error = nfsrv_dissectacl(nd, aclp, &aceerr,
1499 error = nfsrv_dissectacl(nd, NULL, &aceerr,
1507 case NFSATTRBIT_ACLSUPPORT:
1508 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1509 if (compare && !(*retcmpp)) {
1510 if (nfsrv_useacl && nfs_supportsnfsv4acls(vp)) {
1511 if (fxdr_unsigned(u_int32_t, *tl) !=
1513 *retcmpp = NFSERR_NOTSAME;
1515 *retcmpp = NFSERR_ATTRNOTSUPP;
1518 attrsum += NFSX_UNSIGNED;
1520 case NFSATTRBIT_ARCHIVE:
1521 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1522 if (compare && !(*retcmpp))
1523 *retcmpp = NFSERR_ATTRNOTSUPP;
1524 attrsum += NFSX_UNSIGNED;
1526 case NFSATTRBIT_CANSETTIME:
1527 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1530 if (fsp->fs_properties & NFSV3_FSFCANSETTIME) {
1531 if (*tl == newnfs_false)
1532 *retcmpp = NFSERR_NOTSAME;
1534 if (*tl == newnfs_true)
1535 *retcmpp = NFSERR_NOTSAME;
1538 } else if (fsp != NULL) {
1539 if (*tl == newnfs_true)
1540 fsp->fs_properties |= NFSV3_FSFCANSETTIME;
1542 fsp->fs_properties &= ~NFSV3_FSFCANSETTIME;
1544 attrsum += NFSX_UNSIGNED;
1546 case NFSATTRBIT_CASEINSENSITIVE:
1547 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1550 if (*tl != newnfs_false)
1551 *retcmpp = NFSERR_NOTSAME;
1553 } else if (pc != NULL) {
1554 pc->pc_caseinsensitive =
1555 fxdr_unsigned(u_int32_t, *tl);
1557 attrsum += NFSX_UNSIGNED;
1559 case NFSATTRBIT_CASEPRESERVING:
1560 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1563 if (*tl != newnfs_true)
1564 *retcmpp = NFSERR_NOTSAME;
1566 } else if (pc != NULL) {
1567 pc->pc_casepreserving =
1568 fxdr_unsigned(u_int32_t, *tl);
1570 attrsum += NFSX_UNSIGNED;
1572 case NFSATTRBIT_CHOWNRESTRICTED:
1573 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1576 if (*tl != newnfs_true)
1577 *retcmpp = NFSERR_NOTSAME;
1579 } else if (pc != NULL) {
1580 pc->pc_chownrestricted =
1581 fxdr_unsigned(u_int32_t, *tl);
1583 attrsum += NFSX_UNSIGNED;
1585 case NFSATTRBIT_FILEHANDLE:
1586 error = nfsm_getfh(nd, &tnfhp);
1589 tfhsize = tnfhp->nfh_len;
1592 !NFSRV_CMPFH(tnfhp->nfh_fh, tfhsize,
1594 *retcmpp = NFSERR_NOTSAME;
1595 free(tnfhp, M_NFSFH);
1596 } else if (nfhpp != NULL) {
1599 free(tnfhp, M_NFSFH);
1601 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(tfhsize));
1603 case NFSATTRBIT_FILEID:
1604 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1605 thyp = fxdr_hyper(tl);
1608 if (nap->na_fileid != thyp)
1609 *retcmpp = NFSERR_NOTSAME;
1611 } else if (nap != NULL)
1612 nap->na_fileid = thyp;
1613 attrsum += NFSX_HYPER;
1615 case NFSATTRBIT_FILESAVAIL:
1616 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1619 sfp->sf_afiles != fxdr_hyper(tl))
1620 *retcmpp = NFSERR_NOTSAME;
1621 } else if (sfp != NULL) {
1622 sfp->sf_afiles = fxdr_hyper(tl);
1624 attrsum += NFSX_HYPER;
1626 case NFSATTRBIT_FILESFREE:
1627 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1630 sfp->sf_ffiles != fxdr_hyper(tl))
1631 *retcmpp = NFSERR_NOTSAME;
1632 } else if (sfp != NULL) {
1633 sfp->sf_ffiles = fxdr_hyper(tl);
1635 attrsum += NFSX_HYPER;
1637 case NFSATTRBIT_FILESTOTAL:
1638 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1641 sfp->sf_tfiles != fxdr_hyper(tl))
1642 *retcmpp = NFSERR_NOTSAME;
1643 } else if (sfp != NULL) {
1644 sfp->sf_tfiles = fxdr_hyper(tl);
1646 attrsum += NFSX_HYPER;
1648 case NFSATTRBIT_FSLOCATIONS:
1649 error = nfsrv_getrefstr(nd, &cp, &cp2, &l, &m);
1653 if (compare && !(*retcmpp)) {
1654 refp = nfsv4root_getreferral(vp, NULL, 0);
1656 if (cp == NULL || cp2 == NULL ||
1658 strcmp(cp2, refp->nfr_srvlist))
1659 *retcmpp = NFSERR_NOTSAME;
1660 } else if (m == 0) {
1661 *retcmpp = NFSERR_NOTSAME;
1665 free(cp, M_NFSSTRING);
1667 free(cp2, M_NFSSTRING);
1669 case NFSATTRBIT_HIDDEN:
1670 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1671 if (compare && !(*retcmpp))
1672 *retcmpp = NFSERR_ATTRNOTSUPP;
1673 attrsum += NFSX_UNSIGNED;
1675 case NFSATTRBIT_HOMOGENEOUS:
1676 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1679 if (fsp->fs_properties &
1680 NFSV3_FSFHOMOGENEOUS) {
1681 if (*tl == newnfs_false)
1682 *retcmpp = NFSERR_NOTSAME;
1684 if (*tl == newnfs_true)
1685 *retcmpp = NFSERR_NOTSAME;
1688 } else if (fsp != NULL) {
1689 if (*tl == newnfs_true)
1690 fsp->fs_properties |= NFSV3_FSFHOMOGENEOUS;
1692 fsp->fs_properties &= ~NFSV3_FSFHOMOGENEOUS;
1694 attrsum += NFSX_UNSIGNED;
1696 case NFSATTRBIT_MAXFILESIZE:
1697 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1698 tnfsquad.qval = fxdr_hyper(tl);
1701 tquad = NFSRV_MAXFILESIZE;
1702 if (tquad != tnfsquad.qval)
1703 *retcmpp = NFSERR_NOTSAME;
1705 } else if (fsp != NULL) {
1706 fsp->fs_maxfilesize = tnfsquad.qval;
1708 attrsum += NFSX_HYPER;
1710 case NFSATTRBIT_MAXLINK:
1711 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1714 if (fxdr_unsigned(int, *tl) != NFS_LINK_MAX)
1715 *retcmpp = NFSERR_NOTSAME;
1717 } else if (pc != NULL) {
1718 pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl);
1720 attrsum += NFSX_UNSIGNED;
1722 case NFSATTRBIT_MAXNAME:
1723 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1726 if (fsp->fs_maxname !=
1727 fxdr_unsigned(u_int32_t, *tl))
1728 *retcmpp = NFSERR_NOTSAME;
1731 tuint = fxdr_unsigned(u_int32_t, *tl);
1733 * Some Linux NFSv4 servers report this
1734 * as 0 or 4billion, so I'll set it to
1735 * NFS_MAXNAMLEN. If a server actually creates
1736 * a name longer than NFS_MAXNAMLEN, it will
1737 * get an error back.
1739 if (tuint == 0 || tuint > NFS_MAXNAMLEN)
1740 tuint = NFS_MAXNAMLEN;
1742 fsp->fs_maxname = tuint;
1744 pc->pc_namemax = tuint;
1746 attrsum += NFSX_UNSIGNED;
1748 case NFSATTRBIT_MAXREAD:
1749 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1752 if (fsp->fs_rtmax != fxdr_unsigned(u_int32_t,
1753 *(tl + 1)) || *tl != 0)
1754 *retcmpp = NFSERR_NOTSAME;
1756 } else if (fsp != NULL) {
1757 fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *++tl);
1758 fsp->fs_rtpref = fsp->fs_rtmax;
1759 fsp->fs_dtpref = fsp->fs_rtpref;
1761 attrsum += NFSX_HYPER;
1763 case NFSATTRBIT_MAXWRITE:
1764 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1767 if (fsp->fs_wtmax != fxdr_unsigned(u_int32_t,
1768 *(tl + 1)) || *tl != 0)
1769 *retcmpp = NFSERR_NOTSAME;
1771 } else if (fsp != NULL) {
1772 fsp->fs_wtmax = fxdr_unsigned(int, *++tl);
1773 fsp->fs_wtpref = fsp->fs_wtmax;
1775 attrsum += NFSX_HYPER;
1777 case NFSATTRBIT_MIMETYPE:
1778 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1779 i = fxdr_unsigned(int, *tl);
1780 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(i));
1781 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
1784 if (compare && !(*retcmpp))
1785 *retcmpp = NFSERR_ATTRNOTSUPP;
1787 case NFSATTRBIT_MODE:
1788 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1791 if (nap->na_mode != nfstov_mode(*tl))
1792 *retcmpp = NFSERR_NOTSAME;
1794 } else if (nap != NULL) {
1795 nap->na_mode = nfstov_mode(*tl);
1797 attrsum += NFSX_UNSIGNED;
1799 case NFSATTRBIT_NOTRUNC:
1800 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1803 if (*tl != newnfs_true)
1804 *retcmpp = NFSERR_NOTSAME;
1806 } else if (pc != NULL) {
1807 pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl);
1809 attrsum += NFSX_UNSIGNED;
1811 case NFSATTRBIT_NUMLINKS:
1812 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1813 tuint = fxdr_unsigned(u_int32_t, *tl);
1816 if ((u_int32_t)nap->na_nlink != tuint)
1817 *retcmpp = NFSERR_NOTSAME;
1819 } else if (nap != NULL) {
1820 nap->na_nlink = tuint;
1822 attrsum += NFSX_UNSIGNED;
1824 case NFSATTRBIT_OWNER:
1825 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1826 j = fxdr_unsigned(int, *tl);
1828 error = NFSERR_BADXDR;
1831 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1832 if (j > NFSV4_SMALLSTR)
1833 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1836 error = nfsrv_mtostr(nd, cp, j);
1838 if (j > NFSV4_SMALLSTR)
1839 free(cp, M_NFSSTRING);
1844 if (nfsv4_strtouid(nd, cp, j, &uid) ||
1846 *retcmpp = NFSERR_NOTSAME;
1848 } else if (nap != NULL) {
1849 if (nfsv4_strtouid(nd, cp, j, &uid))
1850 nap->na_uid = nfsrv_defaultuid;
1854 if (j > NFSV4_SMALLSTR)
1855 free(cp, M_NFSSTRING);
1857 case NFSATTRBIT_OWNERGROUP:
1858 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1859 j = fxdr_unsigned(int, *tl);
1861 error = NFSERR_BADXDR;
1864 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1865 if (j > NFSV4_SMALLSTR)
1866 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1869 error = nfsrv_mtostr(nd, cp, j);
1871 if (j > NFSV4_SMALLSTR)
1872 free(cp, M_NFSSTRING);
1877 if (nfsv4_strtogid(nd, cp, j, &gid) ||
1879 *retcmpp = NFSERR_NOTSAME;
1881 } else if (nap != NULL) {
1882 if (nfsv4_strtogid(nd, cp, j, &gid))
1883 nap->na_gid = nfsrv_defaultgid;
1887 if (j > NFSV4_SMALLSTR)
1888 free(cp, M_NFSSTRING);
1890 case NFSATTRBIT_QUOTAHARD:
1891 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1893 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA))
1894 freenum = sbp->f_bfree;
1896 freenum = sbp->f_bavail;
1899 * ufs_quotactl() insists that the uid argument
1900 * equal p_ruid for non-root quota access, so
1901 * we'll just make sure that's the case.
1903 savuid = p->p_cred->p_ruid;
1904 p->p_cred->p_ruid = cred->cr_uid;
1905 if (!VFS_QUOTACTL(vp->v_mount,QCMD(Q_GETQUOTA,
1906 USRQUOTA), cred->cr_uid, &dqb))
1907 freenum = min(dqb.dqb_bhardlimit, freenum);
1908 p->p_cred->p_ruid = savuid;
1910 uquad = (u_int64_t)freenum;
1911 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1913 if (compare && !(*retcmpp)) {
1914 if (uquad != fxdr_hyper(tl))
1915 *retcmpp = NFSERR_NOTSAME;
1917 attrsum += NFSX_HYPER;
1919 case NFSATTRBIT_QUOTASOFT:
1920 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1922 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA))
1923 freenum = sbp->f_bfree;
1925 freenum = sbp->f_bavail;
1928 * ufs_quotactl() insists that the uid argument
1929 * equal p_ruid for non-root quota access, so
1930 * we'll just make sure that's the case.
1932 savuid = p->p_cred->p_ruid;
1933 p->p_cred->p_ruid = cred->cr_uid;
1934 if (!VFS_QUOTACTL(vp->v_mount,QCMD(Q_GETQUOTA,
1935 USRQUOTA), cred->cr_uid, &dqb))
1936 freenum = min(dqb.dqb_bsoftlimit, freenum);
1937 p->p_cred->p_ruid = savuid;
1939 uquad = (u_int64_t)freenum;
1940 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1942 if (compare && !(*retcmpp)) {
1943 if (uquad != fxdr_hyper(tl))
1944 *retcmpp = NFSERR_NOTSAME;
1946 attrsum += NFSX_HYPER;
1948 case NFSATTRBIT_QUOTAUSED:
1949 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1954 * ufs_quotactl() insists that the uid argument
1955 * equal p_ruid for non-root quota access, so
1956 * we'll just make sure that's the case.
1958 savuid = p->p_cred->p_ruid;
1959 p->p_cred->p_ruid = cred->cr_uid;
1960 if (!VFS_QUOTACTL(vp->v_mount,QCMD(Q_GETQUOTA,
1961 USRQUOTA), cred->cr_uid, &dqb))
1962 freenum = dqb.dqb_curblocks;
1963 p->p_cred->p_ruid = savuid;
1965 uquad = (u_int64_t)freenum;
1966 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1968 if (compare && !(*retcmpp)) {
1969 if (uquad != fxdr_hyper(tl))
1970 *retcmpp = NFSERR_NOTSAME;
1972 attrsum += NFSX_HYPER;
1974 case NFSATTRBIT_RAWDEV:
1975 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4SPECDATA);
1976 j = fxdr_unsigned(int, *tl++);
1977 k = fxdr_unsigned(int, *tl);
1980 if (nap->na_rdev != NFSMAKEDEV(j, k))
1981 *retcmpp = NFSERR_NOTSAME;
1983 } else if (nap != NULL) {
1984 nap->na_rdev = NFSMAKEDEV(j, k);
1986 attrsum += NFSX_V4SPECDATA;
1988 case NFSATTRBIT_SPACEAVAIL:
1989 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1992 sfp->sf_abytes != fxdr_hyper(tl))
1993 *retcmpp = NFSERR_NOTSAME;
1994 } else if (sfp != NULL) {
1995 sfp->sf_abytes = fxdr_hyper(tl);
1997 attrsum += NFSX_HYPER;
1999 case NFSATTRBIT_SPACEFREE:
2000 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2003 sfp->sf_fbytes != fxdr_hyper(tl))
2004 *retcmpp = NFSERR_NOTSAME;
2005 } else if (sfp != NULL) {
2006 sfp->sf_fbytes = fxdr_hyper(tl);
2008 attrsum += NFSX_HYPER;
2010 case NFSATTRBIT_SPACETOTAL:
2011 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2014 sfp->sf_tbytes != fxdr_hyper(tl))
2015 *retcmpp = NFSERR_NOTSAME;
2016 } else if (sfp != NULL) {
2017 sfp->sf_tbytes = fxdr_hyper(tl);
2019 attrsum += NFSX_HYPER;
2021 case NFSATTRBIT_SPACEUSED:
2022 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2023 thyp = fxdr_hyper(tl);
2026 if ((u_int64_t)nap->na_bytes != thyp)
2027 *retcmpp = NFSERR_NOTSAME;
2029 } else if (nap != NULL) {
2030 nap->na_bytes = thyp;
2032 attrsum += NFSX_HYPER;
2034 case NFSATTRBIT_SYSTEM:
2035 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2036 if (compare && !(*retcmpp))
2037 *retcmpp = NFSERR_ATTRNOTSUPP;
2038 attrsum += NFSX_UNSIGNED;
2040 case NFSATTRBIT_TIMEACCESS:
2041 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2042 fxdr_nfsv4time(tl, &temptime);
2045 if (!NFS_CMPTIME(temptime, nap->na_atime))
2046 *retcmpp = NFSERR_NOTSAME;
2048 } else if (nap != NULL) {
2049 nap->na_atime = temptime;
2051 attrsum += NFSX_V4TIME;
2053 case NFSATTRBIT_TIMEACCESSSET:
2054 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2055 attrsum += NFSX_UNSIGNED;
2056 i = fxdr_unsigned(int, *tl);
2057 if (i == NFSV4SATTRTIME_TOCLIENT) {
2058 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2059 attrsum += NFSX_V4TIME;
2061 if (compare && !(*retcmpp))
2062 *retcmpp = NFSERR_INVAL;
2064 case NFSATTRBIT_TIMEBACKUP:
2065 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2066 if (compare && !(*retcmpp))
2067 *retcmpp = NFSERR_ATTRNOTSUPP;
2068 attrsum += NFSX_V4TIME;
2070 case NFSATTRBIT_TIMECREATE:
2071 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2072 fxdr_nfsv4time(tl, &temptime);
2075 if (!NFS_CMPTIME(temptime, nap->na_btime))
2076 *retcmpp = NFSERR_NOTSAME;
2078 } else if (nap != NULL) {
2079 nap->na_btime = temptime;
2081 attrsum += NFSX_V4TIME;
2083 case NFSATTRBIT_TIMEDELTA:
2084 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2088 if ((u_int32_t)fsp->fs_timedelta.tv_sec !=
2089 fxdr_unsigned(u_int32_t, *(tl + 1)) ||
2090 (u_int32_t)fsp->fs_timedelta.tv_nsec !=
2091 (fxdr_unsigned(u_int32_t, *(tl + 2)) %
2094 *retcmpp = NFSERR_NOTSAME;
2097 fxdr_nfsv4time(tl, &fsp->fs_timedelta);
2100 attrsum += NFSX_V4TIME;
2102 case NFSATTRBIT_TIMEMETADATA:
2103 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2104 fxdr_nfsv4time(tl, &temptime);
2107 if (!NFS_CMPTIME(temptime, nap->na_ctime))
2108 *retcmpp = NFSERR_NOTSAME;
2110 } else if (nap != NULL) {
2111 nap->na_ctime = temptime;
2113 attrsum += NFSX_V4TIME;
2115 case NFSATTRBIT_TIMEMODIFY:
2116 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2117 fxdr_nfsv4time(tl, &temptime);
2120 if (!NFS_CMPTIME(temptime, nap->na_mtime))
2121 *retcmpp = NFSERR_NOTSAME;
2123 } else if (nap != NULL) {
2124 nap->na_mtime = temptime;
2126 attrsum += NFSX_V4TIME;
2128 case NFSATTRBIT_TIMEMODIFYSET:
2129 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2130 attrsum += NFSX_UNSIGNED;
2131 i = fxdr_unsigned(int, *tl);
2132 if (i == NFSV4SATTRTIME_TOCLIENT) {
2133 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2134 attrsum += NFSX_V4TIME;
2136 if (compare && !(*retcmpp))
2137 *retcmpp = NFSERR_INVAL;
2139 case NFSATTRBIT_MOUNTEDONFILEID:
2140 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2141 thyp = fxdr_hyper(tl);
2144 if (!vp || !nfsrv_atroot(vp, &thyp2))
2145 thyp2 = nap->na_fileid;
2147 *retcmpp = NFSERR_NOTSAME;
2149 } else if (nap != NULL)
2150 nap->na_mntonfileno = thyp;
2151 attrsum += NFSX_HYPER;
2153 case NFSATTRBIT_SUPPATTREXCLCREAT:
2155 error = nfsrv_getattrbits(nd, &retattrbits,
2159 if (compare && !(*retcmpp)) {
2160 NFSSETSUPP_ATTRBIT(&checkattrbits, nd);
2161 NFSCLRNOTSETABLE_ATTRBIT(&checkattrbits, nd);
2162 NFSCLRBIT_ATTRBIT(&checkattrbits,
2163 NFSATTRBIT_TIMEACCESSSET);
2164 if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
2166 *retcmpp = NFSERR_NOTSAME;
2170 case NFSATTRBIT_FSLAYOUTTYPE:
2171 case NFSATTRBIT_LAYOUTTYPE:
2172 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2173 attrsum += NFSX_UNSIGNED;
2174 i = fxdr_unsigned(int, *tl);
2176 NFSM_DISSECT(tl, u_int32_t *, i *
2178 attrsum += i * NFSX_UNSIGNED;
2179 j = fxdr_unsigned(int, *tl);
2180 if (i == 1 && compare && !(*retcmpp) &&
2181 (((nfsrv_doflexfile != 0 ||
2182 nfsrv_maxpnfsmirror > 1) &&
2183 j != NFSLAYOUT_FLEXFILE) ||
2184 (nfsrv_doflexfile == 0 &&
2185 j != NFSLAYOUT_NFSV4_1_FILES)))
2186 *retcmpp = NFSERR_NOTSAME;
2188 if (nfsrv_devidcnt == 0) {
2189 if (compare && !(*retcmpp) && i > 0)
2190 *retcmpp = NFSERR_NOTSAME;
2192 if (compare && !(*retcmpp) && i != 1)
2193 *retcmpp = NFSERR_NOTSAME;
2196 case NFSATTRBIT_LAYOUTALIGNMENT:
2197 case NFSATTRBIT_LAYOUTBLKSIZE:
2198 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2199 attrsum += NFSX_UNSIGNED;
2200 i = fxdr_unsigned(int, *tl);
2201 if (compare && !(*retcmpp) && i != NFS_SRVMAXIO)
2202 *retcmpp = NFSERR_NOTSAME;
2205 printf("EEK! nfsv4_loadattr unknown attr=%d\n",
2207 if (compare && !(*retcmpp))
2208 *retcmpp = NFSERR_ATTRNOTSUPP;
2210 * and get out of the loop, since we can't parse
2211 * the unknown attrbute data.
2213 bitpos = NFSATTRBIT_MAX;
2219 * some clients pad the attrlist, so we need to skip over the
2222 if (attrsum > attrsize) {
2223 error = NFSERR_BADXDR;
2225 attrsize = NFSM_RNDUP(attrsize);
2226 if (attrsum < attrsize)
2227 error = nfsm_advance(nd, attrsize - attrsum, -1);
2230 NFSEXITCODE2(error, nd);
2235 * Implement sleep locks for newnfs. The nfslock_usecnt allows for a
2236 * shared lock and the NFSXXX_LOCK flag permits an exclusive lock.
2237 * The first argument is a pointer to an nfsv4lock structure.
2238 * The second argument is 1 iff a blocking lock is wanted.
2239 * If this argument is 0, the call waits until no thread either wants nor
2240 * holds an exclusive lock.
2241 * It returns 1 if the lock was acquired, 0 otherwise.
2242 * If several processes call this function concurrently wanting the exclusive
2243 * lock, one will get the lock and the rest will return without getting the
2244 * lock. (If the caller must have the lock, it simply calls this function in a
2245 * loop until the function returns 1 to indicate the lock was acquired.)
2246 * Any usecnt must be decremented by calling nfsv4_relref() before
2247 * calling nfsv4_lock(). It was done this way, so nfsv4_lock() could
2248 * be called in a loop.
2249 * The isleptp argument is set to indicate if the call slept, iff not NULL
2250 * and the mp argument indicates to check for a forced dismount, iff not
2254 nfsv4_lock(struct nfsv4lock *lp, int iwantlock, int *isleptp,
2255 void *mutex, struct mount *mp)
2261 * If a lock is wanted, loop around until the lock is acquired by
2262 * someone and then released. If I want the lock, try to acquire it.
2263 * For a lock to be issued, no lock must be in force and the usecnt
2267 if (!(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
2268 lp->nfslock_usecnt == 0) {
2269 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
2270 lp->nfslock_lock |= NFSV4LOCK_LOCK;
2273 lp->nfslock_lock |= NFSV4LOCK_LOCKWANTED;
2275 while (lp->nfslock_lock & (NFSV4LOCK_LOCK | NFSV4LOCK_LOCKWANTED)) {
2276 if (mp != NULL && NFSCL_FORCEDISM(mp)) {
2277 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
2280 lp->nfslock_lock |= NFSV4LOCK_WANTED;
2283 (void) nfsmsleep(&lp->nfslock_lock, mutex,
2284 PZERO - 1, "nfsv4lck", NULL);
2285 if (iwantlock && !(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
2286 lp->nfslock_usecnt == 0) {
2287 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
2288 lp->nfslock_lock |= NFSV4LOCK_LOCK;
2296 * Release the lock acquired by nfsv4_lock().
2297 * The second argument is set to 1 to indicate the nfslock_usecnt should be
2298 * incremented, as well.
2301 nfsv4_unlock(struct nfsv4lock *lp, int incref)
2304 lp->nfslock_lock &= ~NFSV4LOCK_LOCK;
2306 lp->nfslock_usecnt++;
2311 * Release a reference cnt.
2314 nfsv4_relref(struct nfsv4lock *lp)
2317 if (lp->nfslock_usecnt <= 0)
2318 panic("nfsv4root ref cnt");
2319 lp->nfslock_usecnt--;
2320 if (lp->nfslock_usecnt == 0)
2325 * Get a reference cnt.
2326 * This function will wait for any exclusive lock to be released, but will
2327 * not wait for threads that want the exclusive lock. If priority needs
2328 * to be given to threads that need the exclusive lock, a call to nfsv4_lock()
2329 * with the 2nd argument == 0 should be done before calling nfsv4_getref().
2330 * If the mp argument is not NULL, check for NFSCL_FORCEDISM() being set and
2331 * return without getting a refcnt for that case.
2334 nfsv4_getref(struct nfsv4lock *lp, int *isleptp, void *mutex,
2342 * Wait for a lock held.
2344 while (lp->nfslock_lock & NFSV4LOCK_LOCK) {
2345 if (mp != NULL && NFSCL_FORCEDISM(mp))
2347 lp->nfslock_lock |= NFSV4LOCK_WANTED;
2350 (void) nfsmsleep(&lp->nfslock_lock, mutex,
2351 PZERO - 1, "nfsv4gr", NULL);
2353 if (mp != NULL && NFSCL_FORCEDISM(mp))
2356 lp->nfslock_usecnt++;
2360 * Get a reference as above, but return failure instead of sleeping if
2361 * an exclusive lock is held.
2364 nfsv4_getref_nonblock(struct nfsv4lock *lp)
2367 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) != 0)
2370 lp->nfslock_usecnt++;
2375 * Test for a lock. Return 1 if locked, 0 otherwise.
2378 nfsv4_testlock(struct nfsv4lock *lp)
2381 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) == 0 &&
2382 lp->nfslock_usecnt == 0)
2388 * Wake up anyone sleeping, waiting for this lock.
2391 nfsv4_wanted(struct nfsv4lock *lp)
2394 if (lp->nfslock_lock & NFSV4LOCK_WANTED) {
2395 lp->nfslock_lock &= ~NFSV4LOCK_WANTED;
2396 wakeup((caddr_t)&lp->nfslock_lock);
2401 * Copy a string from an mbuf list into a character array.
2402 * Return EBADRPC if there is an mbuf error,
2406 nfsrv_mtostr(struct nfsrv_descript *nd, char *str, int siz)
2415 len = mtod(mp, caddr_t) + mp->m_len - cp;
2416 rem = NFSM_RNDUP(siz) - siz;
2422 NFSBCOPY(cp, str, xfer);
2431 cp = mtod(mp, caddr_t);
2443 error = nfsm_advance(nd, rem, len);
2449 NFSEXITCODE2(error, nd);
2454 * Fill in the attributes as marked by the bitmap (V4).
2457 nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp,
2458 NFSACL_T *saclp, struct vattr *vap, fhandle_t *fhp, int rderror,
2459 nfsattrbit_t *attrbitp, struct ucred *cred, NFSPROC_T *p, int isdgram,
2460 int reterr, int supports_nfsv4acls, int at_root, uint64_t mounted_on_fileno,
2461 struct statfs *pnfssf)
2463 int bitpos, retnum = 0;
2465 int siz, prefixnum, error;
2466 u_char *cp, namestr[NFSV4_SMALLSTR];
2467 nfsattrbit_t attrbits, retbits;
2468 nfsattrbit_t *retbitp = &retbits;
2469 u_int32_t freenum, *retnump;
2472 struct nfsfsinfo fsinf;
2473 struct timespec temptime;
2474 NFSACL_T *aclp, *naclp = NULL;
2483 * First, set the bits that can be filled and get fsinfo.
2485 NFSSET_ATTRBIT(retbitp, attrbitp);
2487 * If both p and cred are NULL, it is a client side setattr call.
2488 * If both p and cred are not NULL, it is a server side reply call.
2489 * If p is not NULL and cred is NULL, it is a client side callback
2492 if (p == NULL && cred == NULL) {
2493 NFSCLRNOTSETABLE_ATTRBIT(retbitp, nd);
2496 NFSCLRNOTFILLABLE_ATTRBIT(retbitp, nd);
2497 naclp = acl_alloc(M_WAITOK);
2500 nfsvno_getfs(&fsinf, isdgram);
2503 * Get the VFS_STATFS(), since some attributes need them.
2505 fs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
2506 if (NFSISSETSTATFS_ATTRBIT(retbitp)) {
2507 error = VFS_STATFS(mp, fs);
2510 nd->nd_repstat = NFSERR_ACCES;
2514 NFSCLRSTATFS_ATTRBIT(retbitp);
2520 * And the NFSv4 ACL...
2522 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT) &&
2523 (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2524 supports_nfsv4acls == 0))) {
2525 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT);
2527 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACL)) {
2528 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2529 supports_nfsv4acls == 0)) {
2530 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2531 } else if (naclp != NULL) {
2532 if (NFSVOPLOCK(vp, LK_SHARED) == 0) {
2533 error = VOP_ACCESSX(vp, VREAD_ACL, cred, p);
2535 error = VOP_GETACL(vp, ACL_TYPE_NFS4,
2539 error = NFSERR_PERM;
2542 nd->nd_repstat = NFSERR_ACCES;
2546 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2551 /* Check to see if Extended Attributes are supported. */
2553 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_XATTRSUPPORT)) {
2554 if (NFSVOPLOCK(vp, LK_SHARED) == 0) {
2555 error = VOP_GETEXTATTR(vp, EXTATTR_NAMESPACE_USER,
2556 "xxx", NULL, &atsiz, cred, p);
2558 if (error != EOPNOTSUPP)
2564 * Put out the attribute bitmap for the ones being filled in
2565 * and get the field for the number of attributes returned.
2567 prefixnum = nfsrv_putattrbit(nd, retbitp);
2568 NFSM_BUILD(retnump, u_int32_t *, NFSX_UNSIGNED);
2569 prefixnum += NFSX_UNSIGNED;
2572 * Now, loop around filling in the attributes for each bit set.
2574 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
2575 if (NFSISSET_ATTRBIT(retbitp, bitpos)) {
2577 case NFSATTRBIT_SUPPORTEDATTRS:
2578 NFSSETSUPP_ATTRBIT(&attrbits, nd);
2579 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL)
2580 && supports_nfsv4acls == 0)) {
2581 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACLSUPPORT);
2582 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACL);
2584 retnum += nfsrv_putattrbit(nd, &attrbits);
2586 case NFSATTRBIT_TYPE:
2587 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2588 *tl = vtonfsv34_type(vap->va_type);
2589 retnum += NFSX_UNSIGNED;
2591 case NFSATTRBIT_FHEXPIRETYPE:
2592 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2593 *tl = txdr_unsigned(NFSV4FHTYPE_PERSISTENT);
2594 retnum += NFSX_UNSIGNED;
2596 case NFSATTRBIT_CHANGE:
2597 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2598 txdr_hyper(vap->va_filerev, tl);
2599 retnum += NFSX_HYPER;
2601 case NFSATTRBIT_SIZE:
2602 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2603 txdr_hyper(vap->va_size, tl);
2604 retnum += NFSX_HYPER;
2606 case NFSATTRBIT_LINKSUPPORT:
2607 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2608 if (fsinf.fs_properties & NFSV3FSINFO_LINK)
2612 retnum += NFSX_UNSIGNED;
2614 case NFSATTRBIT_SYMLINKSUPPORT:
2615 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2616 if (fsinf.fs_properties & NFSV3FSINFO_SYMLINK)
2620 retnum += NFSX_UNSIGNED;
2622 case NFSATTRBIT_NAMEDATTR:
2623 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2625 retnum += NFSX_UNSIGNED;
2627 case NFSATTRBIT_FSID:
2628 NFSM_BUILD(tl, u_int32_t *, NFSX_V4FSID);
2630 *tl++ = txdr_unsigned(mp->mnt_stat.f_fsid.val[0]);
2632 *tl = txdr_unsigned(mp->mnt_stat.f_fsid.val[1]);
2633 retnum += NFSX_V4FSID;
2635 case NFSATTRBIT_UNIQUEHANDLES:
2636 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2638 retnum += NFSX_UNSIGNED;
2640 case NFSATTRBIT_LEASETIME:
2641 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2642 *tl = txdr_unsigned(nfsrv_lease);
2643 retnum += NFSX_UNSIGNED;
2645 case NFSATTRBIT_RDATTRERROR:
2646 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2647 *tl = txdr_unsigned(rderror);
2648 retnum += NFSX_UNSIGNED;
2651 * Recommended Attributes. (Only the supported ones.)
2653 case NFSATTRBIT_ACL:
2654 retnum += nfsrv_buildacl(nd, aclp, vnode_vtype(vp), p);
2656 case NFSATTRBIT_ACLSUPPORT:
2657 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2658 *tl = txdr_unsigned(NFSV4ACE_SUPTYPES);
2659 retnum += NFSX_UNSIGNED;
2661 case NFSATTRBIT_CANSETTIME:
2662 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2663 if (fsinf.fs_properties & NFSV3FSINFO_CANSETTIME)
2667 retnum += NFSX_UNSIGNED;
2669 case NFSATTRBIT_CASEINSENSITIVE:
2670 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2672 retnum += NFSX_UNSIGNED;
2674 case NFSATTRBIT_CASEPRESERVING:
2675 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2677 retnum += NFSX_UNSIGNED;
2679 case NFSATTRBIT_CHOWNRESTRICTED:
2680 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2682 retnum += NFSX_UNSIGNED;
2684 case NFSATTRBIT_FILEHANDLE:
2685 retnum += nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
2687 case NFSATTRBIT_FILEID:
2688 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2689 uquad = vap->va_fileid;
2690 txdr_hyper(uquad, tl);
2691 retnum += NFSX_HYPER;
2693 case NFSATTRBIT_FILESAVAIL:
2695 * Check quota and use min(quota, f_ffree).
2697 freenum = fs->f_ffree;
2700 * ufs_quotactl() insists that the uid argument
2701 * equal p_ruid for non-root quota access, so
2702 * we'll just make sure that's the case.
2704 savuid = p->p_cred->p_ruid;
2705 p->p_cred->p_ruid = cred->cr_uid;
2706 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2707 cred->cr_uid, &dqb))
2708 freenum = min(dqb.dqb_isoftlimit-dqb.dqb_curinodes,
2710 p->p_cred->p_ruid = savuid;
2712 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2714 *tl = txdr_unsigned(freenum);
2715 retnum += NFSX_HYPER;
2717 case NFSATTRBIT_FILESFREE:
2718 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2720 *tl = txdr_unsigned(fs->f_ffree);
2721 retnum += NFSX_HYPER;
2723 case NFSATTRBIT_FILESTOTAL:
2724 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2726 *tl = txdr_unsigned(fs->f_files);
2727 retnum += NFSX_HYPER;
2729 case NFSATTRBIT_FSLOCATIONS:
2730 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2733 retnum += 2 * NFSX_UNSIGNED;
2735 case NFSATTRBIT_HOMOGENEOUS:
2736 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2737 if (fsinf.fs_properties & NFSV3FSINFO_HOMOGENEOUS)
2741 retnum += NFSX_UNSIGNED;
2743 case NFSATTRBIT_MAXFILESIZE:
2744 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2745 uquad = NFSRV_MAXFILESIZE;
2746 txdr_hyper(uquad, tl);
2747 retnum += NFSX_HYPER;
2749 case NFSATTRBIT_MAXLINK:
2750 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2751 *tl = txdr_unsigned(NFS_LINK_MAX);
2752 retnum += NFSX_UNSIGNED;
2754 case NFSATTRBIT_MAXNAME:
2755 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2756 *tl = txdr_unsigned(NFS_MAXNAMLEN);
2757 retnum += NFSX_UNSIGNED;
2759 case NFSATTRBIT_MAXREAD:
2760 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2762 *tl = txdr_unsigned(fsinf.fs_rtmax);
2763 retnum += NFSX_HYPER;
2765 case NFSATTRBIT_MAXWRITE:
2766 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2768 *tl = txdr_unsigned(fsinf.fs_wtmax);
2769 retnum += NFSX_HYPER;
2771 case NFSATTRBIT_MODE:
2772 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2773 *tl = vtonfsv34_mode(vap->va_mode);
2774 retnum += NFSX_UNSIGNED;
2776 case NFSATTRBIT_NOTRUNC:
2777 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2779 retnum += NFSX_UNSIGNED;
2781 case NFSATTRBIT_NUMLINKS:
2782 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2783 *tl = txdr_unsigned(vap->va_nlink);
2784 retnum += NFSX_UNSIGNED;
2786 case NFSATTRBIT_OWNER:
2788 nfsv4_uidtostr(vap->va_uid, &cp, &siz);
2789 retnum += nfsm_strtom(nd, cp, siz);
2791 free(cp, M_NFSSTRING);
2793 case NFSATTRBIT_OWNERGROUP:
2795 nfsv4_gidtostr(vap->va_gid, &cp, &siz);
2796 retnum += nfsm_strtom(nd, cp, siz);
2798 free(cp, M_NFSSTRING);
2800 case NFSATTRBIT_QUOTAHARD:
2801 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA))
2802 freenum = fs->f_bfree;
2804 freenum = fs->f_bavail;
2807 * ufs_quotactl() insists that the uid argument
2808 * equal p_ruid for non-root quota access, so
2809 * we'll just make sure that's the case.
2811 savuid = p->p_cred->p_ruid;
2812 p->p_cred->p_ruid = cred->cr_uid;
2813 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2814 cred->cr_uid, &dqb))
2815 freenum = min(dqb.dqb_bhardlimit, freenum);
2816 p->p_cred->p_ruid = savuid;
2818 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2819 uquad = (u_int64_t)freenum;
2820 NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
2821 txdr_hyper(uquad, tl);
2822 retnum += NFSX_HYPER;
2824 case NFSATTRBIT_QUOTASOFT:
2825 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA))
2826 freenum = fs->f_bfree;
2828 freenum = fs->f_bavail;
2831 * ufs_quotactl() insists that the uid argument
2832 * equal p_ruid for non-root quota access, so
2833 * we'll just make sure that's the case.
2835 savuid = p->p_cred->p_ruid;
2836 p->p_cred->p_ruid = cred->cr_uid;
2837 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2838 cred->cr_uid, &dqb))
2839 freenum = min(dqb.dqb_bsoftlimit, freenum);
2840 p->p_cred->p_ruid = savuid;
2842 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2843 uquad = (u_int64_t)freenum;
2844 NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
2845 txdr_hyper(uquad, tl);
2846 retnum += NFSX_HYPER;
2848 case NFSATTRBIT_QUOTAUSED:
2852 * ufs_quotactl() insists that the uid argument
2853 * equal p_ruid for non-root quota access, so
2854 * we'll just make sure that's the case.
2856 savuid = p->p_cred->p_ruid;
2857 p->p_cred->p_ruid = cred->cr_uid;
2858 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2859 cred->cr_uid, &dqb))
2860 freenum = dqb.dqb_curblocks;
2861 p->p_cred->p_ruid = savuid;
2863 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2864 uquad = (u_int64_t)freenum;
2865 NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
2866 txdr_hyper(uquad, tl);
2867 retnum += NFSX_HYPER;
2869 case NFSATTRBIT_RAWDEV:
2870 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SPECDATA);
2871 *tl++ = txdr_unsigned(NFSMAJOR(vap->va_rdev));
2872 *tl = txdr_unsigned(NFSMINOR(vap->va_rdev));
2873 retnum += NFSX_V4SPECDATA;
2875 case NFSATTRBIT_SPACEAVAIL:
2876 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2877 if (priv_check_cred(cred, PRIV_VFS_BLOCKRESERVE)) {
2879 uquad = (u_int64_t)pnfssf->f_bfree;
2881 uquad = (u_int64_t)fs->f_bfree;
2884 uquad = (u_int64_t)pnfssf->f_bavail;
2886 uquad = (u_int64_t)fs->f_bavail;
2889 uquad *= pnfssf->f_bsize;
2891 uquad *= fs->f_bsize;
2892 txdr_hyper(uquad, tl);
2893 retnum += NFSX_HYPER;
2895 case NFSATTRBIT_SPACEFREE:
2896 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2897 if (pnfssf != NULL) {
2898 uquad = (u_int64_t)pnfssf->f_bfree;
2899 uquad *= pnfssf->f_bsize;
2901 uquad = (u_int64_t)fs->f_bfree;
2902 uquad *= fs->f_bsize;
2904 txdr_hyper(uquad, tl);
2905 retnum += NFSX_HYPER;
2907 case NFSATTRBIT_SPACETOTAL:
2908 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2909 if (pnfssf != NULL) {
2910 uquad = (u_int64_t)pnfssf->f_blocks;
2911 uquad *= pnfssf->f_bsize;
2913 uquad = (u_int64_t)fs->f_blocks;
2914 uquad *= fs->f_bsize;
2916 txdr_hyper(uquad, tl);
2917 retnum += NFSX_HYPER;
2919 case NFSATTRBIT_SPACEUSED:
2920 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2921 txdr_hyper(vap->va_bytes, tl);
2922 retnum += NFSX_HYPER;
2924 case NFSATTRBIT_TIMEACCESS:
2925 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2926 txdr_nfsv4time(&vap->va_atime, tl);
2927 retnum += NFSX_V4TIME;
2929 case NFSATTRBIT_TIMEACCESSSET:
2930 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2931 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2932 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2933 txdr_nfsv4time(&vap->va_atime, tl);
2934 retnum += NFSX_V4SETTIME;
2936 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2937 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2938 retnum += NFSX_UNSIGNED;
2941 case NFSATTRBIT_TIMEDELTA:
2942 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2943 temptime.tv_sec = 0;
2944 temptime.tv_nsec = 1000000000 / hz;
2945 txdr_nfsv4time(&temptime, tl);
2946 retnum += NFSX_V4TIME;
2948 case NFSATTRBIT_TIMEMETADATA:
2949 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2950 txdr_nfsv4time(&vap->va_ctime, tl);
2951 retnum += NFSX_V4TIME;
2953 case NFSATTRBIT_TIMEMODIFY:
2954 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2955 txdr_nfsv4time(&vap->va_mtime, tl);
2956 retnum += NFSX_V4TIME;
2958 case NFSATTRBIT_TIMECREATE:
2959 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2960 txdr_nfsv4time(&vap->va_birthtime, tl);
2961 retnum += NFSX_V4TIME;
2963 case NFSATTRBIT_TIMEMODIFYSET:
2964 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2965 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2966 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2967 txdr_nfsv4time(&vap->va_mtime, tl);
2968 retnum += NFSX_V4SETTIME;
2970 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2971 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2972 retnum += NFSX_UNSIGNED;
2975 case NFSATTRBIT_MOUNTEDONFILEID:
2976 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2978 uquad = mounted_on_fileno;
2980 uquad = vap->va_fileid;
2981 txdr_hyper(uquad, tl);
2982 retnum += NFSX_HYPER;
2984 case NFSATTRBIT_SUPPATTREXCLCREAT:
2985 NFSSETSUPP_ATTRBIT(&attrbits, nd);
2986 NFSCLRNOTSETABLE_ATTRBIT(&attrbits, nd);
2987 NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET);
2988 retnum += nfsrv_putattrbit(nd, &attrbits);
2990 case NFSATTRBIT_FSLAYOUTTYPE:
2991 case NFSATTRBIT_LAYOUTTYPE:
2992 if (nfsrv_devidcnt == 0)
2997 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2998 *tl++ = txdr_unsigned(1); /* One entry. */
2999 if (nfsrv_doflexfile != 0 ||
3000 nfsrv_maxpnfsmirror > 1)
3001 *tl = txdr_unsigned(NFSLAYOUT_FLEXFILE);
3003 *tl = txdr_unsigned(
3004 NFSLAYOUT_NFSV4_1_FILES);
3006 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3009 retnum += siz * NFSX_UNSIGNED;
3011 case NFSATTRBIT_LAYOUTALIGNMENT:
3012 case NFSATTRBIT_LAYOUTBLKSIZE:
3013 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3014 *tl = txdr_unsigned(NFS_SRVMAXIO);
3015 retnum += NFSX_UNSIGNED;
3017 case NFSATTRBIT_XATTRSUPPORT:
3018 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3023 retnum += NFSX_UNSIGNED;
3026 printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos);
3033 *retnump = txdr_unsigned(retnum);
3034 return (retnum + prefixnum);
3038 * Put the attribute bits onto an mbuf list.
3039 * Return the number of bytes of output generated.
3042 nfsrv_putattrbit(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp)
3045 int cnt, i, bytesize;
3047 for (cnt = NFSATTRBIT_MAXWORDS; cnt > 0; cnt--)
3048 if (attrbitp->bits[cnt - 1])
3050 bytesize = (cnt + 1) * NFSX_UNSIGNED;
3051 NFSM_BUILD(tl, u_int32_t *, bytesize);
3052 *tl++ = txdr_unsigned(cnt);
3053 for (i = 0; i < cnt; i++)
3054 *tl++ = txdr_unsigned(attrbitp->bits[i]);
3059 * Convert a uid to a string.
3060 * If the lookup fails, just output the digits.
3062 * cpp - points to a buffer of size NFSV4_SMALLSTR
3063 * (malloc a larger one, as required)
3064 * retlenp - pointer to length to be returned
3067 nfsv4_uidtostr(uid_t uid, u_char **cpp, int *retlenp)
3070 struct nfsusrgrp *usrp;
3073 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
3074 struct nfsrv_lughash *hp;
3078 if (nfsrv_dnsnamelen > 0 && !nfs_enable_uidtostring) {
3080 * Always map nfsrv_defaultuid to "nobody".
3082 if (uid == nfsrv_defaultuid) {
3083 i = nfsrv_dnsnamelen + 7;
3085 if (len > NFSV4_SMALLSTR)
3086 free(cp, M_NFSSTRING);
3087 cp = malloc(i, M_NFSSTRING, M_WAITOK);
3093 NFSBCOPY("nobody@", cp, 7);
3095 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
3099 hp = NFSUSERHASH(uid);
3101 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
3102 if (usrp->lug_uid == uid) {
3103 if (usrp->lug_expiry < NFSD_MONOSEC)
3106 * If the name doesn't already have an '@'
3107 * in it, append @domainname to it.
3109 for (i = 0; i < usrp->lug_namelen; i++) {
3110 if (usrp->lug_name[i] == '@') {
3116 i = usrp->lug_namelen;
3118 i = usrp->lug_namelen +
3119 nfsrv_dnsnamelen + 1;
3121 mtx_unlock(&hp->mtx);
3122 if (len > NFSV4_SMALLSTR)
3123 free(cp, M_NFSSTRING);
3124 cp = malloc(i, M_NFSSTRING, M_WAITOK);
3130 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
3131 if (!hasampersand) {
3132 cp += usrp->lug_namelen;
3134 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
3136 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3137 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
3139 mtx_unlock(&hp->mtx);
3143 mtx_unlock(&hp->mtx);
3145 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0, NULL);
3146 if (ret == 0 && cnt < 2)
3151 * No match, just return a string of digits.
3155 while (tmp || i == 0) {
3159 len = (i > len) ? len : i;
3163 for (i = 0; i < len; i++) {
3164 *cp-- = '0' + (tmp % 10);
3171 * Get a credential for the uid with the server's group list.
3172 * If none is found, just return the credential passed in after
3173 * logging a warning message.
3176 nfsrv_getgrpscred(struct ucred *oldcred)
3178 struct nfsusrgrp *usrp;
3179 struct ucred *newcred;
3182 struct nfsrv_lughash *hp;
3185 uid = oldcred->cr_uid;
3187 if (nfsrv_dnsnamelen > 0) {
3188 hp = NFSUSERHASH(uid);
3190 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
3191 if (usrp->lug_uid == uid) {
3192 if (usrp->lug_expiry < NFSD_MONOSEC)
3194 if (usrp->lug_cred != NULL) {
3195 newcred = crhold(usrp->lug_cred);
3199 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3200 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
3202 mtx_unlock(&hp->mtx);
3206 mtx_unlock(&hp->mtx);
3208 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0, NULL);
3209 if (ret == 0 && cnt < 2)
3216 * Convert a string to a uid.
3217 * If no conversion is possible return NFSERR_BADOWNER, otherwise
3219 * If this is called from a client side mount using AUTH_SYS and the
3220 * string is made up entirely of digits, just convert the string to
3224 nfsv4_strtouid(struct nfsrv_descript *nd, u_char *str, int len, uid_t *uidp)
3227 char *cp, *endstr, *str0;
3228 struct nfsusrgrp *usrp;
3232 struct nfsrv_lughash *hp, *hp2;
3235 error = NFSERR_BADOWNER;
3238 /* If a string of digits and an AUTH_SYS mount, just convert it. */
3240 tuid = (uid_t)strtoul(str0, &endstr, 10);
3241 if ((endstr - str0) == len) {
3242 /* A numeric string. */
3243 if ((nd->nd_flag & ND_KERBV) == 0 &&
3244 ((nd->nd_flag & ND_NFSCL) != 0 ||
3245 nfsd_enable_stringtouid != 0))
3248 error = NFSERR_BADOWNER;
3254 cp = strchr(str0, '@');
3256 i = (int)(cp++ - str0);
3262 if (nfsrv_dnsnamelen > 0) {
3264 * If an '@' is found and the domain name matches, search for
3265 * the name with dns stripped off.
3266 * Mixed case alpahbetics will match for the domain name, but
3267 * all upper case will not.
3269 if (cnt == 0 && i < len && i > 0 &&
3270 (len - 1 - i) == nfsrv_dnsnamelen &&
3271 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
3272 len -= (nfsrv_dnsnamelen + 1);
3277 * Check for the special case of "nobody".
3279 if (len == 6 && !NFSBCMP(str, "nobody", 6)) {
3280 *uidp = nfsrv_defaultuid;
3285 hp = NFSUSERNAMEHASH(str, len);
3287 TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) {
3288 if (usrp->lug_namelen == len &&
3289 !NFSBCMP(usrp->lug_name, str, len)) {
3290 if (usrp->lug_expiry < NFSD_MONOSEC)
3292 hp2 = NFSUSERHASH(usrp->lug_uid);
3293 mtx_lock(&hp2->mtx);
3294 TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash);
3295 TAILQ_INSERT_TAIL(&hp2->lughead, usrp,
3297 *uidp = usrp->lug_uid;
3298 mtx_unlock(&hp2->mtx);
3299 mtx_unlock(&hp->mtx);
3304 mtx_unlock(&hp->mtx);
3306 ret = nfsrv_getuser(RPCNFSUSERD_GETUSER, (uid_t)0, (gid_t)0,
3308 if (ret == 0 && cnt < 2)
3311 error = NFSERR_BADOWNER;
3319 * Convert a gid to a string.
3320 * gid - the group id
3321 * cpp - points to a buffer of size NFSV4_SMALLSTR
3322 * (malloc a larger one, as required)
3323 * retlenp - pointer to length to be returned
3326 nfsv4_gidtostr(gid_t gid, u_char **cpp, int *retlenp)
3329 struct nfsusrgrp *usrp;
3332 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
3333 struct nfsrv_lughash *hp;
3337 if (nfsrv_dnsnamelen > 0 && !nfs_enable_uidtostring) {
3339 * Always map nfsrv_defaultgid to "nogroup".
3341 if (gid == nfsrv_defaultgid) {
3342 i = nfsrv_dnsnamelen + 8;
3344 if (len > NFSV4_SMALLSTR)
3345 free(cp, M_NFSSTRING);
3346 cp = malloc(i, M_NFSSTRING, M_WAITOK);
3352 NFSBCOPY("nogroup@", cp, 8);
3354 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
3358 hp = NFSGROUPHASH(gid);
3360 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
3361 if (usrp->lug_gid == gid) {
3362 if (usrp->lug_expiry < NFSD_MONOSEC)
3365 * If the name doesn't already have an '@'
3366 * in it, append @domainname to it.
3368 for (i = 0; i < usrp->lug_namelen; i++) {
3369 if (usrp->lug_name[i] == '@') {
3375 i = usrp->lug_namelen;
3377 i = usrp->lug_namelen +
3378 nfsrv_dnsnamelen + 1;
3380 mtx_unlock(&hp->mtx);
3381 if (len > NFSV4_SMALLSTR)
3382 free(cp, M_NFSSTRING);
3383 cp = malloc(i, M_NFSSTRING, M_WAITOK);
3389 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
3390 if (!hasampersand) {
3391 cp += usrp->lug_namelen;
3393 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
3395 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3396 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
3398 mtx_unlock(&hp->mtx);
3402 mtx_unlock(&hp->mtx);
3404 ret = nfsrv_getuser(RPCNFSUSERD_GETGID, (uid_t)0, gid, NULL);
3405 if (ret == 0 && cnt < 2)
3410 * No match, just return a string of digits.
3414 while (tmp || i == 0) {
3418 len = (i > len) ? len : i;
3422 for (i = 0; i < len; i++) {
3423 *cp-- = '0' + (tmp % 10);
3430 * Convert a string to a gid.
3431 * If no conversion is possible return NFSERR_BADOWNER, otherwise
3433 * If this is called from a client side mount using AUTH_SYS and the
3434 * string is made up entirely of digits, just convert the string to
3438 nfsv4_strtogid(struct nfsrv_descript *nd, u_char *str, int len, gid_t *gidp)
3441 char *cp, *endstr, *str0;
3442 struct nfsusrgrp *usrp;
3446 struct nfsrv_lughash *hp, *hp2;
3449 error = NFSERR_BADOWNER;
3452 /* If a string of digits and an AUTH_SYS mount, just convert it. */
3454 tgid = (gid_t)strtoul(str0, &endstr, 10);
3455 if ((endstr - str0) == len) {
3456 /* A numeric string. */
3457 if ((nd->nd_flag & ND_KERBV) == 0 &&
3458 ((nd->nd_flag & ND_NFSCL) != 0 ||
3459 nfsd_enable_stringtouid != 0))
3462 error = NFSERR_BADOWNER;
3468 cp = strchr(str0, '@');
3470 i = (int)(cp++ - str0);
3476 if (nfsrv_dnsnamelen > 0) {
3478 * If an '@' is found and the dns name matches, search for the
3479 * name with the dns stripped off.
3481 if (cnt == 0 && i < len && i > 0 &&
3482 (len - 1 - i) == nfsrv_dnsnamelen &&
3483 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
3484 len -= (nfsrv_dnsnamelen + 1);
3489 * Check for the special case of "nogroup".
3491 if (len == 7 && !NFSBCMP(str, "nogroup", 7)) {
3492 *gidp = nfsrv_defaultgid;
3497 hp = NFSGROUPNAMEHASH(str, len);
3499 TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) {
3500 if (usrp->lug_namelen == len &&
3501 !NFSBCMP(usrp->lug_name, str, len)) {
3502 if (usrp->lug_expiry < NFSD_MONOSEC)
3504 hp2 = NFSGROUPHASH(usrp->lug_gid);
3505 mtx_lock(&hp2->mtx);
3506 TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash);
3507 TAILQ_INSERT_TAIL(&hp2->lughead, usrp,
3509 *gidp = usrp->lug_gid;
3510 mtx_unlock(&hp2->mtx);
3511 mtx_unlock(&hp->mtx);
3516 mtx_unlock(&hp->mtx);
3518 ret = nfsrv_getuser(RPCNFSUSERD_GETGROUP, (uid_t)0, (gid_t)0,
3520 if (ret == 0 && cnt < 2)
3523 error = NFSERR_BADOWNER;
3531 * Cmp len chars, allowing mixed case in the first argument to match lower
3532 * case in the second, but not if the first argument is all upper case.
3533 * Return 0 for a match, 1 otherwise.
3536 nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len)
3542 for (i = 0; i < len; i++) {
3543 if (*cp >= 'A' && *cp <= 'Z') {
3544 tmp = *cp++ + ('a' - 'A');
3547 if (tmp >= 'a' && tmp <= 'z')
3560 * Set the port for the nfsuserd.
3563 nfsrv_nfsuserdport(struct nfsuserd_args *nargs, NFSPROC_T *p)
3565 struct nfssockreq *rp;
3567 struct sockaddr_in *ad;
3570 struct sockaddr_in6 *ad6;
3571 const struct in6_addr in6loopback = IN6ADDR_LOOPBACK_INIT;
3576 if (nfsrv_nfsuserd != NOTRUNNING) {
3581 nfsrv_nfsuserd = STARTSTOP;
3583 * Set up the socket record and connect.
3584 * Set nr_client NULL before unlocking, just to ensure that no other
3585 * process/thread/core will use a bogus old value. This could only
3586 * occur if the use of the nameid lock to protect nfsrv_nfsuserd is
3589 rp = &nfsrv_nfsuserdsock;
3590 rp->nr_client = NULL;
3592 rp->nr_sotype = SOCK_DGRAM;
3593 rp->nr_soproto = IPPROTO_UDP;
3594 rp->nr_lock = (NFSR_RESERVEDPORT | NFSR_LOCALHOST);
3596 rp->nr_prog = RPCPROG_NFSUSERD;
3598 switch (nargs->nuserd_family) {
3601 rp->nr_nam = malloc(sizeof(struct sockaddr_in), M_SONAME,
3603 ad = (struct sockaddr_in *)rp->nr_nam;
3604 ad->sin_len = sizeof(struct sockaddr_in);
3605 ad->sin_family = AF_INET;
3606 ad->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
3607 ad->sin_port = nargs->nuserd_port;
3612 rp->nr_nam = malloc(sizeof(struct sockaddr_in6), M_SONAME,
3614 ad6 = (struct sockaddr_in6 *)rp->nr_nam;
3615 ad6->sin6_len = sizeof(struct sockaddr_in6);
3616 ad6->sin6_family = AF_INET6;
3617 ad6->sin6_addr = in6loopback;
3618 ad6->sin6_port = nargs->nuserd_port;
3624 rp->nr_vers = RPCNFSUSERD_VERS;
3626 error = newnfs_connect(NULL, rp, NFSPROCCRED(p), p, 0, false);
3629 nfsrv_nfsuserd = RUNNING;
3632 free(rp->nr_nam, M_SONAME);
3634 nfsrv_nfsuserd = NOTRUNNING;
3643 * Delete the nfsuserd port.
3646 nfsrv_nfsuserddelport(void)
3650 if (nfsrv_nfsuserd != RUNNING) {
3654 nfsrv_nfsuserd = STARTSTOP;
3655 /* Wait for all upcalls to complete. */
3656 while (nfsrv_userdupcalls > 0)
3657 msleep(&nfsrv_userdupcalls, NFSNAMEIDMUTEXPTR, PVFS,
3660 newnfs_disconnect(&nfsrv_nfsuserdsock);
3661 free(nfsrv_nfsuserdsock.nr_nam, M_SONAME);
3663 nfsrv_nfsuserd = NOTRUNNING;
3668 * Do upcalls to the nfsuserd, for cache misses of the owner/ownergroup
3670 * Returns 0 upon success, non-zero otherwise.
3673 nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name)
3676 struct nfsrv_descript *nd;
3678 struct nfsrv_descript nfsd;
3683 if (nfsrv_nfsuserd != RUNNING) {
3689 * Maintain a count of upcalls in progress, so that nfsrv_X()
3690 * can wait until no upcalls are in progress.
3692 nfsrv_userdupcalls++;
3694 KASSERT(nfsrv_userdupcalls > 0,
3695 ("nfsrv_getuser: non-positive upcalls"));
3697 cred = newnfs_getcred();
3698 nd->nd_flag = ND_GSSINITREPLY;
3701 nd->nd_procnum = procnum;
3702 if (procnum == RPCNFSUSERD_GETUID || procnum == RPCNFSUSERD_GETGID) {
3703 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3704 if (procnum == RPCNFSUSERD_GETUID)
3705 *tl = txdr_unsigned(uid);
3707 *tl = txdr_unsigned(gid);
3710 (void) nfsm_strtom(nd, name, len);
3712 error = newnfs_request(nd, NULL, NULL, &nfsrv_nfsuserdsock, NULL, NULL,
3713 cred, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, NULL, 0, NULL, NULL);
3715 if (--nfsrv_userdupcalls == 0 && nfsrv_nfsuserd == STARTSTOP)
3716 wakeup(&nfsrv_userdupcalls);
3720 m_freem(nd->nd_mrep);
3721 error = nd->nd_repstat;
3729 * This function is called from the nfssvc(2) system call, to update the
3730 * kernel user/group name list(s) for the V4 owner and ownergroup attributes.
3733 nfssvc_idname(struct nfsd_idargs *nidp)
3735 struct nfsusrgrp *nusrp, *usrp, *newusrp;
3736 struct nfsrv_lughash *hp_name, *hp_idnum, *thp;
3737 int i, group_locked, groupname_locked, user_locked, username_locked;
3742 static int onethread = 0;
3743 static time_t lasttime = 0;
3745 if (nidp->nid_namelen <= 0 || nidp->nid_namelen > MAXHOSTNAMELEN) {
3749 if (nidp->nid_flag & NFSID_INITIALIZE) {
3750 cp = malloc(nidp->nid_namelen + 1, M_NFSSTRING, M_WAITOK);
3751 error = copyin(nidp->nid_name, cp, nidp->nid_namelen);
3753 free(cp, M_NFSSTRING);
3756 if (atomic_cmpset_acq_int(&nfsrv_dnsnamelen, 0, 0) == 0) {
3758 * Free up all the old stuff and reinitialize hash
3759 * lists. All mutexes for both lists must be locked,
3760 * with the user/group name ones before the uid/gid
3761 * ones, to avoid a LOR.
3763 for (i = 0; i < nfsrv_lughashsize; i++)
3764 mtx_lock(&nfsusernamehash[i].mtx);
3765 for (i = 0; i < nfsrv_lughashsize; i++)
3766 mtx_lock(&nfsuserhash[i].mtx);
3767 for (i = 0; i < nfsrv_lughashsize; i++)
3768 TAILQ_FOREACH_SAFE(usrp,
3769 &nfsuserhash[i].lughead, lug_numhash, nusrp)
3770 nfsrv_removeuser(usrp, 1);
3771 for (i = 0; i < nfsrv_lughashsize; i++)
3772 mtx_unlock(&nfsuserhash[i].mtx);
3773 for (i = 0; i < nfsrv_lughashsize; i++)
3774 mtx_unlock(&nfsusernamehash[i].mtx);
3775 for (i = 0; i < nfsrv_lughashsize; i++)
3776 mtx_lock(&nfsgroupnamehash[i].mtx);
3777 for (i = 0; i < nfsrv_lughashsize; i++)
3778 mtx_lock(&nfsgrouphash[i].mtx);
3779 for (i = 0; i < nfsrv_lughashsize; i++)
3780 TAILQ_FOREACH_SAFE(usrp,
3781 &nfsgrouphash[i].lughead, lug_numhash,
3783 nfsrv_removeuser(usrp, 0);
3784 for (i = 0; i < nfsrv_lughashsize; i++)
3785 mtx_unlock(&nfsgrouphash[i].mtx);
3786 for (i = 0; i < nfsrv_lughashsize; i++)
3787 mtx_unlock(&nfsgroupnamehash[i].mtx);
3788 free(nfsrv_dnsname, M_NFSSTRING);
3789 nfsrv_dnsname = NULL;
3791 if (nfsuserhash == NULL) {
3792 /* Allocate the hash tables. */
3793 nfsuserhash = malloc(sizeof(struct nfsrv_lughash) *
3794 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3796 for (i = 0; i < nfsrv_lughashsize; i++)
3797 mtx_init(&nfsuserhash[i].mtx, "nfsuidhash",
3798 NULL, MTX_DEF | MTX_DUPOK);
3799 nfsusernamehash = malloc(sizeof(struct nfsrv_lughash) *
3800 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3802 for (i = 0; i < nfsrv_lughashsize; i++)
3803 mtx_init(&nfsusernamehash[i].mtx,
3804 "nfsusrhash", NULL, MTX_DEF |
3806 nfsgrouphash = malloc(sizeof(struct nfsrv_lughash) *
3807 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3809 for (i = 0; i < nfsrv_lughashsize; i++)
3810 mtx_init(&nfsgrouphash[i].mtx, "nfsgidhash",
3811 NULL, MTX_DEF | MTX_DUPOK);
3812 nfsgroupnamehash = malloc(sizeof(struct nfsrv_lughash) *
3813 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3815 for (i = 0; i < nfsrv_lughashsize; i++)
3816 mtx_init(&nfsgroupnamehash[i].mtx,
3817 "nfsgrphash", NULL, MTX_DEF | MTX_DUPOK);
3819 /* (Re)initialize the list heads. */
3820 for (i = 0; i < nfsrv_lughashsize; i++)
3821 TAILQ_INIT(&nfsuserhash[i].lughead);
3822 for (i = 0; i < nfsrv_lughashsize; i++)
3823 TAILQ_INIT(&nfsusernamehash[i].lughead);
3824 for (i = 0; i < nfsrv_lughashsize; i++)
3825 TAILQ_INIT(&nfsgrouphash[i].lughead);
3826 for (i = 0; i < nfsrv_lughashsize; i++)
3827 TAILQ_INIT(&nfsgroupnamehash[i].lughead);
3830 * Put name in "DNS" string.
3833 nfsrv_defaultuid = nidp->nid_uid;
3834 nfsrv_defaultgid = nidp->nid_gid;
3836 nfsrv_usermax = nidp->nid_usermax;
3837 atomic_store_rel_int(&nfsrv_dnsnamelen, nidp->nid_namelen);
3842 * malloc the new one now, so any potential sleep occurs before
3843 * manipulation of the lists.
3845 newusrp = malloc(sizeof(struct nfsusrgrp) + nidp->nid_namelen,
3846 M_NFSUSERGROUP, M_WAITOK | M_ZERO);
3847 error = copyin(nidp->nid_name, newusrp->lug_name,
3849 if (error == 0 && nidp->nid_ngroup > 0 &&
3850 (nidp->nid_flag & NFSID_ADDUID) != 0) {
3851 grps = malloc(sizeof(gid_t) * nidp->nid_ngroup, M_TEMP,
3853 error = copyin(nidp->nid_grps, grps,
3854 sizeof(gid_t) * nidp->nid_ngroup);
3857 * Create a credential just like svc_getcred(),
3858 * but using the group list provided.
3861 cr->cr_uid = cr->cr_ruid = cr->cr_svuid = nidp->nid_uid;
3862 crsetgroups(cr, nidp->nid_ngroup, grps);
3863 cr->cr_rgid = cr->cr_svgid = cr->cr_groups[0];
3864 cr->cr_prison = &prison0;
3865 prison_hold(cr->cr_prison);
3867 mac_cred_associate_nfsd(cr);
3869 newusrp->lug_cred = cr;
3874 free(newusrp, M_NFSUSERGROUP);
3877 newusrp->lug_namelen = nidp->nid_namelen;
3880 * The lock order is username[0]->[nfsrv_lughashsize - 1] followed
3881 * by uid[0]->[nfsrv_lughashsize - 1], with the same for group.
3882 * The flags user_locked, username_locked, group_locked and
3883 * groupname_locked are set to indicate all of those hash lists are
3884 * locked. hp_name != NULL and hp_idnum != NULL indicates that
3885 * the respective one mutex is locked.
3887 user_locked = username_locked = group_locked = groupname_locked = 0;
3888 hp_name = hp_idnum = NULL;
3891 * Delete old entries, as required.
3893 if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) {
3894 /* Must lock all username hash lists first, to avoid a LOR. */
3895 for (i = 0; i < nfsrv_lughashsize; i++)
3896 mtx_lock(&nfsusernamehash[i].mtx);
3897 username_locked = 1;
3898 hp_idnum = NFSUSERHASH(nidp->nid_uid);
3899 mtx_lock(&hp_idnum->mtx);
3900 TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
3902 if (usrp->lug_uid == nidp->nid_uid)
3903 nfsrv_removeuser(usrp, 1);
3905 } else if (nidp->nid_flag & (NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) {
3906 hp_name = NFSUSERNAMEHASH(newusrp->lug_name,
3907 newusrp->lug_namelen);
3908 mtx_lock(&hp_name->mtx);
3909 TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
3911 if (usrp->lug_namelen == newusrp->lug_namelen &&
3912 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3913 usrp->lug_namelen)) {
3914 thp = NFSUSERHASH(usrp->lug_uid);
3915 mtx_lock(&thp->mtx);
3916 nfsrv_removeuser(usrp, 1);
3917 mtx_unlock(&thp->mtx);
3920 hp_idnum = NFSUSERHASH(nidp->nid_uid);
3921 mtx_lock(&hp_idnum->mtx);
3922 } else if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) {
3923 /* Must lock all groupname hash lists first, to avoid a LOR. */
3924 for (i = 0; i < nfsrv_lughashsize; i++)
3925 mtx_lock(&nfsgroupnamehash[i].mtx);
3926 groupname_locked = 1;
3927 hp_idnum = NFSGROUPHASH(nidp->nid_gid);
3928 mtx_lock(&hp_idnum->mtx);
3929 TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
3931 if (usrp->lug_gid == nidp->nid_gid)
3932 nfsrv_removeuser(usrp, 0);
3934 } else if (nidp->nid_flag & (NFSID_DELGROUPNAME | NFSID_ADDGROUPNAME)) {
3935 hp_name = NFSGROUPNAMEHASH(newusrp->lug_name,
3936 newusrp->lug_namelen);
3937 mtx_lock(&hp_name->mtx);
3938 TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
3940 if (usrp->lug_namelen == newusrp->lug_namelen &&
3941 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3942 usrp->lug_namelen)) {
3943 thp = NFSGROUPHASH(usrp->lug_gid);
3944 mtx_lock(&thp->mtx);
3945 nfsrv_removeuser(usrp, 0);
3946 mtx_unlock(&thp->mtx);
3949 hp_idnum = NFSGROUPHASH(nidp->nid_gid);
3950 mtx_lock(&hp_idnum->mtx);
3954 * Now, we can add the new one.
3956 if (nidp->nid_usertimeout)
3957 newusrp->lug_expiry = NFSD_MONOSEC + nidp->nid_usertimeout;
3959 newusrp->lug_expiry = NFSD_MONOSEC + 5;
3960 if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) {
3961 newusrp->lug_uid = nidp->nid_uid;
3962 thp = NFSUSERHASH(newusrp->lug_uid);
3963 mtx_assert(&thp->mtx, MA_OWNED);
3964 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
3965 thp = NFSUSERNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3966 mtx_assert(&thp->mtx, MA_OWNED);
3967 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
3968 atomic_add_int(&nfsrv_usercnt, 1);
3969 } else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) {
3970 newusrp->lug_gid = nidp->nid_gid;
3971 thp = NFSGROUPHASH(newusrp->lug_gid);
3972 mtx_assert(&thp->mtx, MA_OWNED);
3973 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
3974 thp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3975 mtx_assert(&thp->mtx, MA_OWNED);
3976 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
3977 atomic_add_int(&nfsrv_usercnt, 1);
3979 if (newusrp->lug_cred != NULL)
3980 crfree(newusrp->lug_cred);
3981 free(newusrp, M_NFSUSERGROUP);
3985 * Once per second, allow one thread to trim the cache.
3987 if (lasttime < NFSD_MONOSEC &&
3988 atomic_cmpset_acq_int(&onethread, 0, 1) != 0) {
3990 * First, unlock the single mutexes, so that all entries
3991 * can be locked and any LOR is avoided.
3993 if (hp_name != NULL) {
3994 mtx_unlock(&hp_name->mtx);
3997 if (hp_idnum != NULL) {
3998 mtx_unlock(&hp_idnum->mtx);
4002 if ((nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID |
4003 NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) != 0) {
4004 if (username_locked == 0) {
4005 for (i = 0; i < nfsrv_lughashsize; i++)
4006 mtx_lock(&nfsusernamehash[i].mtx);
4007 username_locked = 1;
4009 KASSERT(user_locked == 0,
4010 ("nfssvc_idname: user_locked"));
4011 for (i = 0; i < nfsrv_lughashsize; i++)
4012 mtx_lock(&nfsuserhash[i].mtx);
4014 for (i = 0; i < nfsrv_lughashsize; i++) {
4015 TAILQ_FOREACH_SAFE(usrp,
4016 &nfsuserhash[i].lughead, lug_numhash,
4018 if (usrp->lug_expiry < NFSD_MONOSEC)
4019 nfsrv_removeuser(usrp, 1);
4021 for (i = 0; i < nfsrv_lughashsize; i++) {
4023 * Trim the cache using an approximate LRU
4024 * algorithm. This code deletes the least
4025 * recently used entry on each hash list.
4027 if (nfsrv_usercnt <= nfsrv_usermax)
4029 usrp = TAILQ_FIRST(&nfsuserhash[i].lughead);
4031 nfsrv_removeuser(usrp, 1);
4034 if (groupname_locked == 0) {
4035 for (i = 0; i < nfsrv_lughashsize; i++)
4036 mtx_lock(&nfsgroupnamehash[i].mtx);
4037 groupname_locked = 1;
4039 KASSERT(group_locked == 0,
4040 ("nfssvc_idname: group_locked"));
4041 for (i = 0; i < nfsrv_lughashsize; i++)
4042 mtx_lock(&nfsgrouphash[i].mtx);
4044 for (i = 0; i < nfsrv_lughashsize; i++) {
4045 TAILQ_FOREACH_SAFE(usrp,
4046 &nfsgrouphash[i].lughead, lug_numhash,
4048 if (usrp->lug_expiry < NFSD_MONOSEC)
4049 nfsrv_removeuser(usrp, 0);
4051 for (i = 0; i < nfsrv_lughashsize; i++) {
4053 * Trim the cache using an approximate LRU
4054 * algorithm. This code deletes the least
4055 * recently user entry on each hash list.
4057 if (nfsrv_usercnt <= nfsrv_usermax)
4059 usrp = TAILQ_FIRST(&nfsgrouphash[i].lughead);
4061 nfsrv_removeuser(usrp, 0);
4064 lasttime = NFSD_MONOSEC;
4065 atomic_store_rel_int(&onethread, 0);
4068 /* Now, unlock all locked mutexes. */
4069 if (hp_idnum != NULL)
4070 mtx_unlock(&hp_idnum->mtx);
4071 if (hp_name != NULL)
4072 mtx_unlock(&hp_name->mtx);
4073 if (user_locked != 0)
4074 for (i = 0; i < nfsrv_lughashsize; i++)
4075 mtx_unlock(&nfsuserhash[i].mtx);
4076 if (username_locked != 0)
4077 for (i = 0; i < nfsrv_lughashsize; i++)
4078 mtx_unlock(&nfsusernamehash[i].mtx);
4079 if (group_locked != 0)
4080 for (i = 0; i < nfsrv_lughashsize; i++)
4081 mtx_unlock(&nfsgrouphash[i].mtx);
4082 if (groupname_locked != 0)
4083 for (i = 0; i < nfsrv_lughashsize; i++)
4084 mtx_unlock(&nfsgroupnamehash[i].mtx);
4091 * Remove a user/group name element.
4094 nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser)
4096 struct nfsrv_lughash *hp;
4099 hp = NFSUSERHASH(usrp->lug_uid);
4100 mtx_assert(&hp->mtx, MA_OWNED);
4101 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
4102 hp = NFSUSERNAMEHASH(usrp->lug_name, usrp->lug_namelen);
4103 mtx_assert(&hp->mtx, MA_OWNED);
4104 TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
4106 hp = NFSGROUPHASH(usrp->lug_gid);
4107 mtx_assert(&hp->mtx, MA_OWNED);
4108 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
4109 hp = NFSGROUPNAMEHASH(usrp->lug_name, usrp->lug_namelen);
4110 mtx_assert(&hp->mtx, MA_OWNED);
4111 TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
4113 atomic_add_int(&nfsrv_usercnt, -1);
4114 if (usrp->lug_cred != NULL)
4115 crfree(usrp->lug_cred);
4116 free(usrp, M_NFSUSERGROUP);
4120 * Free up all the allocations related to the name<-->id cache.
4121 * This function should only be called when the nfsuserd daemon isn't
4122 * running, since it doesn't do any locking.
4123 * This function is meant to be used when the nfscommon module is unloaded.
4126 nfsrv_cleanusergroup(void)
4128 struct nfsrv_lughash *hp, *hp2;
4129 struct nfsusrgrp *nusrp, *usrp;
4132 if (nfsuserhash == NULL)
4135 for (i = 0; i < nfsrv_lughashsize; i++) {
4136 hp = &nfsuserhash[i];
4137 TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) {
4138 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
4139 hp2 = NFSUSERNAMEHASH(usrp->lug_name,
4141 TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash);
4142 if (usrp->lug_cred != NULL)
4143 crfree(usrp->lug_cred);
4144 free(usrp, M_NFSUSERGROUP);
4146 hp = &nfsgrouphash[i];
4147 TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) {
4148 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
4149 hp2 = NFSGROUPNAMEHASH(usrp->lug_name,
4151 TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash);
4152 if (usrp->lug_cred != NULL)
4153 crfree(usrp->lug_cred);
4154 free(usrp, M_NFSUSERGROUP);
4156 mtx_destroy(&nfsuserhash[i].mtx);
4157 mtx_destroy(&nfsusernamehash[i].mtx);
4158 mtx_destroy(&nfsgroupnamehash[i].mtx);
4159 mtx_destroy(&nfsgrouphash[i].mtx);
4161 free(nfsuserhash, M_NFSUSERGROUP);
4162 free(nfsusernamehash, M_NFSUSERGROUP);
4163 free(nfsgrouphash, M_NFSUSERGROUP);
4164 free(nfsgroupnamehash, M_NFSUSERGROUP);
4165 free(nfsrv_dnsname, M_NFSSTRING);
4169 * This function scans a byte string and checks for UTF-8 compliance.
4170 * It returns 0 if it conforms and NFSERR_INVAL if not.
4173 nfsrv_checkutf8(u_int8_t *cp, int len)
4175 u_int32_t val = 0x0;
4176 int cnt = 0, gotd = 0, shift = 0;
4178 static int utf8_shift[5] = { 7, 11, 16, 21, 26 };
4182 * Here are what the variables are used for:
4183 * val - the calculated value of a multibyte char, used to check
4184 * that it was coded with the correct range
4185 * cnt - the number of 10xxxxxx bytes to follow
4186 * gotd - set for a char of Dxxx, so D800<->DFFF can be checked for
4187 * shift - lower order bits of range (ie. "val >> shift" should
4188 * not be 0, in other words, dividing by the lower bound
4189 * of the range should get a non-zero value)
4190 * byte - used to calculate cnt
4194 /* This handles the 10xxxxxx bytes */
4195 if ((*cp & 0xc0) != 0x80 ||
4196 (gotd && (*cp & 0x20))) {
4197 error = NFSERR_INVAL;
4202 val |= (*cp & 0x3f);
4204 if (cnt == 0 && (val >> shift) == 0x0) {
4205 error = NFSERR_INVAL;
4208 } else if (*cp & 0x80) {
4209 /* first byte of multi byte char */
4211 while ((byte & 0x40) && cnt < 6) {
4215 if (cnt == 0 || cnt == 6) {
4216 error = NFSERR_INVAL;
4219 val = (*cp & (0x3f >> cnt));
4220 shift = utf8_shift[cnt - 1];
4221 if (cnt == 2 && val == 0xd)
4222 /* Check for the 0xd800-0xdfff case */
4229 error = NFSERR_INVAL;
4237 * Parse the xdr for an NFSv4 FsLocations attribute. Return two malloc'd
4238 * strings, one with the root path in it and the other with the list of
4239 * locations. The list is in the same format as is found in nfr_refs.
4240 * It is a "," separated list of entries, where each of them is of the
4241 * form <server>:<rootpath>. For example
4242 * "nfsv4-test:/sub2,nfsv4-test2:/user/mnt,nfsv4-test2:/user/mnt2"
4243 * The nilp argument is set to 1 for the special case of a null fs_root
4244 * and an empty server list.
4245 * It returns NFSERR_BADXDR, if the xdr can't be parsed and returns the
4246 * number of xdr bytes parsed in sump.
4249 nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp,
4250 int *sump, int *nilp)
4253 u_char *cp = NULL, *cp2 = NULL, *cp3, *str;
4254 int i, j, len, stringlen, cnt, slen, siz, xdrsum, error = 0, nsrv;
4256 SLIST_ENTRY(list) next;
4260 SLIST_HEAD(, list) head;
4267 * Get the fs_root path and check for the special case of null path
4268 * and 0 length server list.
4270 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4271 len = fxdr_unsigned(int, *tl);
4272 if (len < 0 || len > 10240) {
4273 error = NFSERR_BADXDR;
4277 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4279 error = NFSERR_BADXDR;
4283 *sump = 2 * NFSX_UNSIGNED;
4287 cp = malloc(len + 1, M_NFSSTRING, M_WAITOK);
4288 error = nfsrv_mtostr(nd, cp, len);
4290 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4291 cnt = fxdr_unsigned(int, *tl);
4293 error = NFSERR_BADXDR;
4299 * Now, loop through the location list and make up the srvlist.
4301 xdrsum = (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
4302 cp2 = cp3 = malloc(1024, M_NFSSTRING, M_WAITOK);
4305 for (i = 0; i < cnt; i++) {
4307 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4308 nsrv = fxdr_unsigned(int, *tl);
4310 error = NFSERR_BADXDR;
4315 * Handle the first server by putting it in the srvstr.
4317 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4318 len = fxdr_unsigned(int, *tl);
4319 if (len <= 0 || len > 1024) {
4320 error = NFSERR_BADXDR;
4323 nfsrv_refstrbigenough(siz + len + 3, &cp2, &cp3, &slen);
4328 error = nfsrv_mtostr(nd, cp3, len);
4334 xdrsum += (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
4335 for (j = 1; j < nsrv; j++) {
4337 * Yuck, put them in an slist and process them later.
4339 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4340 len = fxdr_unsigned(int, *tl);
4341 if (len <= 0 || len > 1024) {
4342 error = NFSERR_BADXDR;
4345 lsp = (struct list *)malloc(sizeof (struct list)
4346 + len, M_TEMP, M_WAITOK);
4347 error = nfsrv_mtostr(nd, lsp->host, len);
4350 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
4352 SLIST_INSERT_HEAD(&head, lsp, next);
4356 * Finally, we can get the path.
4358 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4359 len = fxdr_unsigned(int, *tl);
4360 if (len <= 0 || len > 1024) {
4361 error = NFSERR_BADXDR;
4364 nfsrv_refstrbigenough(siz + len + 1, &cp2, &cp3, &slen);
4365 error = nfsrv_mtostr(nd, cp3, len);
4368 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
4373 SLIST_FOREACH_SAFE(lsp, &head, next, nlsp) {
4374 nfsrv_refstrbigenough(siz + lsp->len + stringlen + 3,
4377 NFSBCOPY(lsp->host, cp3, lsp->len);
4380 NFSBCOPY(str, cp3, stringlen);
4383 siz += (lsp->len + stringlen + 2);
4390 NFSEXITCODE2(0, nd);
4394 free(cp, M_NFSSTRING);
4396 free(cp2, M_NFSSTRING);
4397 NFSEXITCODE2(error, nd);
4402 * Make the malloc'd space large enough. This is a pain, but the xdr
4403 * doesn't set an upper bound on the side, so...
4406 nfsrv_refstrbigenough(int siz, u_char **cpp, u_char **cpp2, int *slenp)
4413 cp = malloc(siz + 1024, M_NFSSTRING, M_WAITOK);
4414 NFSBCOPY(*cpp, cp, *slenp);
4415 free(*cpp, M_NFSSTRING);
4419 *slenp = siz + 1024;
4423 * Initialize the reply header data structures.
4426 nfsrvd_rephead(struct nfsrv_descript *nd)
4430 if ((nd->nd_flag & ND_EXTPG) != 0) {
4431 mreq = mb_alloc_ext_plus_pages(PAGE_SIZE, M_WAITOK);
4432 nd->nd_mreq = nd->nd_mb = mreq;
4433 nd->nd_bpos = (char *)(void *)
4434 PHYS_TO_DMAP(mreq->m_epg_pa[0]);
4436 nd->nd_bextpgsiz = PAGE_SIZE;
4439 * If this is a big reply, use a cluster.
4441 if ((nd->nd_flag & ND_GSSINITREPLY) == 0 &&
4442 nfs_bigreply[nd->nd_procnum]) {
4443 NFSMCLGET(mreq, M_WAITOK);
4451 nd->nd_bpos = mtod(mreq, char *);
4455 if ((nd->nd_flag & ND_GSSINITREPLY) == 0)
4456 NFSM_BUILD(nd->nd_errp, int *, NFSX_UNSIGNED);
4460 * Lock a socket against others.
4461 * Currently used to serialize connect/disconnect attempts.
4464 newnfs_sndlock(int *flagp)
4469 while (*flagp & NFSR_SNDLOCK) {
4470 *flagp |= NFSR_WANTSND;
4473 (void) nfsmsleep((caddr_t)flagp, NFSSOCKMUTEXPTR,
4474 PZERO - 1, "nfsndlck", &ts);
4476 *flagp |= NFSR_SNDLOCK;
4482 * Unlock the stream socket for others.
4485 newnfs_sndunlock(int *flagp)
4489 if ((*flagp & NFSR_SNDLOCK) == 0)
4490 panic("nfs sndunlock");
4491 *flagp &= ~NFSR_SNDLOCK;
4492 if (*flagp & NFSR_WANTSND) {
4493 *flagp &= ~NFSR_WANTSND;
4494 wakeup((caddr_t)flagp);
4500 nfsv4_getipaddr(struct nfsrv_descript *nd, struct sockaddr_in *sin,
4501 struct sockaddr_in6 *sin6, sa_family_t *saf, int *isudp)
4503 struct in_addr saddr;
4504 uint32_t portnum, *tl;
4506 sa_family_t af = AF_UNSPEC;
4507 char addr[64], protocol[5], *cp;
4508 int cantparse = 0, error = 0;
4511 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4512 i = fxdr_unsigned(int, *tl);
4513 if (i >= 3 && i <= 4) {
4514 error = nfsrv_mtostr(nd, protocol, i);
4517 if (strcmp(protocol, "tcp") == 0) {
4520 } else if (strcmp(protocol, "udp") == 0) {
4523 } else if (strcmp(protocol, "tcp6") == 0) {
4526 } else if (strcmp(protocol, "udp6") == 0) {
4534 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
4539 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4540 i = fxdr_unsigned(int, *tl);
4542 error = NFSERR_BADXDR;
4544 } else if (cantparse == 0 && i >= 11 && i < 64) {
4546 * The shortest address is 11chars and the longest is < 64.
4548 error = nfsrv_mtostr(nd, addr, i);
4552 /* Find the port# at the end and extract that. */
4556 /* Count back two '.'s from end to get port# field. */
4557 for (j = 0; j < i; j++) {
4567 * The NFSv4 port# is appended as .N.N, where N is
4568 * a decimal # in the range 0-255, just like an inet4
4569 * address. Cheat and use inet_aton(), which will
4570 * return a Class A address and then shift the high
4571 * order 8bits over to convert it to the port#.
4574 if (inet_aton(cp, &saddr) == 1) {
4575 portnum = ntohl(saddr.s_addr);
4576 portv = (uint16_t)((portnum >> 16) |
4582 if (cantparse == 0) {
4583 if (af == AF_INET) {
4584 if (inet_pton(af, addr, &sin->sin_addr) == 1) {
4585 sin->sin_len = sizeof(*sin);
4586 sin->sin_family = AF_INET;
4587 sin->sin_port = htons(portv);
4592 if (inet_pton(af, addr, &sin6->sin6_addr)
4594 sin6->sin6_len = sizeof(*sin6);
4595 sin6->sin6_family = AF_INET6;
4596 sin6->sin6_port = htons(portv);
4604 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
4615 * Handle an NFSv4.1 Sequence request for the session.
4616 * If reply != NULL, use it to return the cached reply, as required.
4617 * The client gets a cached reply via this call for callbacks, however the
4618 * server gets a cached reply via the nfsv4_seqsess_cachereply() call.
4621 nfsv4_seqsession(uint32_t seqid, uint32_t slotid, uint32_t highslot,
4622 struct nfsslot *slots, struct mbuf **reply, uint16_t maxslot)
4629 if (slotid > maxslot)
4630 return (NFSERR_BADSLOT);
4631 if (seqid == slots[slotid].nfssl_seq) {
4633 if (slots[slotid].nfssl_inprog != 0)
4634 error = NFSERR_DELAY;
4635 else if (slots[slotid].nfssl_reply != NULL) {
4636 if (reply != NULL) {
4637 *reply = slots[slotid].nfssl_reply;
4638 slots[slotid].nfssl_reply = NULL;
4640 slots[slotid].nfssl_inprog = 1;
4641 error = NFSERR_REPLYFROMCACHE;
4643 /* No reply cached, so just do it. */
4644 slots[slotid].nfssl_inprog = 1;
4645 } else if ((slots[slotid].nfssl_seq + 1) == seqid) {
4646 if (slots[slotid].nfssl_reply != NULL)
4647 m_freem(slots[slotid].nfssl_reply);
4648 slots[slotid].nfssl_reply = NULL;
4649 slots[slotid].nfssl_inprog = 1;
4650 slots[slotid].nfssl_seq++;
4652 error = NFSERR_SEQMISORDERED;
4657 * Cache this reply for the slot.
4658 * Use the "rep" argument to return the cached reply if repstat is set to
4659 * NFSERR_REPLYFROMCACHE. The client never sets repstat to this value.
4662 nfsv4_seqsess_cacherep(uint32_t slotid, struct nfsslot *slots, int repstat,
4666 if (repstat == NFSERR_REPLYFROMCACHE) {
4667 *rep = slots[slotid].nfssl_reply;
4668 slots[slotid].nfssl_reply = NULL;
4670 if (slots[slotid].nfssl_reply != NULL)
4671 m_freem(slots[slotid].nfssl_reply);
4672 slots[slotid].nfssl_reply = *rep;
4674 slots[slotid].nfssl_inprog = 0;
4678 * Generate the xdr for an NFSv4.1 Sequence Operation.
4681 nfsv4_setsequence(struct nfsmount *nmp, struct nfsrv_descript *nd,
4682 struct nfsclsession *sep, int dont_replycache)
4684 uint32_t *tl, slotseq = 0;
4685 int error, maxslot, slotpos;
4686 uint8_t sessionid[NFSX_V4SESSIONID];
4688 error = nfsv4_sequencelookup(nmp, sep, &slotpos, &maxslot, &slotseq,
4690 nd->nd_maxreq = sep->nfsess_maxreq;
4691 nd->nd_maxresp = sep->nfsess_maxresp;
4693 /* Build the Sequence arguments. */
4694 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 4 * NFSX_UNSIGNED);
4695 nd->nd_sequence = tl;
4696 bcopy(sessionid, tl, NFSX_V4SESSIONID);
4697 tl += NFSX_V4SESSIONID / NFSX_UNSIGNED;
4698 nd->nd_slotseq = tl;
4700 nd->nd_flag |= ND_HASSLOTID;
4701 nd->nd_slotid = slotpos;
4702 *tl++ = txdr_unsigned(slotseq);
4703 *tl++ = txdr_unsigned(slotpos);
4704 *tl++ = txdr_unsigned(maxslot);
4705 if (dont_replycache == 0)
4711 * There are two errors and the rest of the session can
4713 * NFSERR_BADSESSION: This bad session should just generate
4714 * the same error again when the RPC is retried.
4715 * ESTALE: A forced dismount is in progress and will cause the
4716 * RPC to fail later.
4723 nd->nd_flag |= ND_HASSEQUENCE;
4727 nfsv4_sequencelookup(struct nfsmount *nmp, struct nfsclsession *sep,
4728 int *slotposp, int *maxslotp, uint32_t *slotseqp, uint8_t *sessionid)
4730 int i, maxslot, slotpos;
4733 /* Find an unused slot. */
4736 mtx_lock(&sep->nfsess_mtx);
4738 if (nmp != NULL && sep->nfsess_defunct != 0) {
4739 /* Just return the bad session. */
4740 bcopy(sep->nfsess_sessionid, sessionid,
4742 mtx_unlock(&sep->nfsess_mtx);
4743 return (NFSERR_BADSESSION);
4746 for (i = 0; i < sep->nfsess_foreslots; i++) {
4747 if ((bitval & sep->nfsess_slots) == 0) {
4749 sep->nfsess_slots |= bitval;
4750 sep->nfsess_slotseq[i]++;
4751 *slotseqp = sep->nfsess_slotseq[i];
4756 if (slotpos == -1) {
4758 * If a forced dismount is in progress, just return.
4759 * This RPC attempt will fail when it calls
4762 if (nmp != NULL && NFSCL_FORCEDISM(nmp->nm_mountp)) {
4763 mtx_unlock(&sep->nfsess_mtx);
4766 /* Wake up once/sec, to check for a forced dismount. */
4767 (void)mtx_sleep(&sep->nfsess_slots, &sep->nfsess_mtx,
4768 PZERO, "nfsclseq", hz);
4770 } while (slotpos == -1);
4771 /* Now, find the highest slot in use. (nfsc_slots is 64bits) */
4773 for (i = 0; i < 64; i++) {
4774 if ((bitval & sep->nfsess_slots) != 0)
4778 bcopy(sep->nfsess_sessionid, sessionid, NFSX_V4SESSIONID);
4779 mtx_unlock(&sep->nfsess_mtx);
4780 *slotposp = slotpos;
4781 *maxslotp = maxslot;
4786 * Free a session slot.
4789 nfsv4_freeslot(struct nfsclsession *sep, int slot)
4796 mtx_lock(&sep->nfsess_mtx);
4797 if ((bitval & sep->nfsess_slots) == 0)
4798 printf("freeing free slot!!\n");
4799 sep->nfsess_slots &= ~bitval;
4800 wakeup(&sep->nfsess_slots);
4801 mtx_unlock(&sep->nfsess_mtx);
4805 * Search for a matching pnfsd DS, based on the nmp arg.
4806 * Return one if found, NULL otherwise.
4809 nfsv4_findmirror(struct nfsmount *nmp)
4811 struct nfsdevice *ds;
4813 mtx_assert(NFSDDSMUTEXPTR, MA_OWNED);
4815 * Search the DS server list for a match with nmp.
4817 if (nfsrv_devidcnt == 0)
4819 TAILQ_FOREACH(ds, &nfsrv_devidhead, nfsdev_list) {
4820 if (ds->nfsdev_nmp == nmp) {
4821 NFSCL_DEBUG(4, "nfsv4_findmirror: fnd main ds\n");
4829 * Fill in the fields of "struct nfsrv_descript".
4832 nfsm_set(struct nfsrv_descript *nd, u_int offs)
4838 if ((m->m_flags & M_EXTPG) != 0) {
4841 if (nd->nd_bextpg == 0)
4842 rlen = m_epg_pagelen(m, 0, m->m_epg_1st_off);
4844 rlen = m_epg_pagelen(m, nd->nd_bextpg, 0);
4849 if (nd->nd_bextpg == m->m_epg_npgs) {
4850 printf("nfsm_set: build offs "
4856 nd->nd_bpos = (char *)(void *)
4857 PHYS_TO_DMAP(m->m_epg_pa[nd->nd_bextpg]);
4858 if (nd->nd_bextpg == 0)
4859 nd->nd_bpos += m->m_epg_1st_off;
4861 nd->nd_bpos += offs;
4862 nd->nd_bextpgsiz = rlen - offs;
4863 } else if (nd->nd_bextpg == 0)
4864 nd->nd_bextpgsiz = PAGE_SIZE - m->m_epg_1st_off;
4866 nd->nd_bextpgsiz = PAGE_SIZE;
4868 nd->nd_bpos = mtod(m, char *) + offs;
4872 * Grow a ext_pgs mbuf list. Either allocate another page or add
4873 * an mbuf to the list.
4876 nfsm_add_ext_pgs(struct mbuf *m, int maxextsiz, int *bextpg)
4881 if ((m->m_epg_npgs + 1) * PAGE_SIZE > maxextsiz) {
4882 mp = mb_alloc_ext_plus_pages(PAGE_SIZE, M_WAITOK);
4887 pg = vm_page_alloc(NULL, 0, VM_ALLOC_NORMAL |
4888 VM_ALLOC_NOOBJ | VM_ALLOC_NODUMP |
4892 } while (pg == NULL);
4893 m->m_epg_pa[m->m_epg_npgs] = VM_PAGE_TO_PHYS(pg);
4894 *bextpg = m->m_epg_npgs;
4896 m->m_epg_last_len = 0;