xref: /xnu-8019.80.24/bsd/nfs/nfs4_vnops.c (revision a325d9c4a84054e40bbe985afedcb50ab80993ea)
1 /*
2  * Copyright (c) 2006-2020 Apple Inc. All rights reserved.
3  *
4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5  *
6  * This file contains Original Code and/or Modifications of Original Code
7  * as defined in and that are subject to the Apple Public Source License
8  * Version 2.0 (the 'License'). You may not use this file except in
9  * compliance with the License. The rights granted to you under the License
10  * may not be used to create, or enable the creation or redistribution of,
11  * unlawful or unlicensed copies of an Apple operating system, or to
12  * circumvent, violate, or enable the circumvention or violation of, any
13  * terms of an Apple operating system software license agreement.
14  *
15  * Please obtain a copy of the License at
16  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17  *
18  * The Original Code and all software distributed under the License are
19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23  * Please see the License for the specific language governing rights and
24  * limitations under the License.
25  *
26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27  */
28 
29 #include <nfs/nfs_conf.h>
30 #if CONFIG_NFS_CLIENT
31 
32 /*
33  * vnode op calls for NFS version 4
34  */
35 #include <sys/param.h>
36 #include <sys/kernel.h>
37 #include <sys/systm.h>
38 #include <sys/resourcevar.h>
39 #include <sys/proc_internal.h>
40 #include <sys/kauth.h>
41 #include <sys/mount_internal.h>
42 #include <sys/malloc.h>
43 #include <sys/kpi_mbuf.h>
44 #include <sys/conf.h>
45 #include <sys/vnode_internal.h>
46 #include <sys/dirent.h>
47 #include <sys/fcntl.h>
48 #include <sys/lockf.h>
49 #include <sys/ubc_internal.h>
50 #include <sys/attr.h>
51 #include <sys/signalvar.h>
52 #include <sys/uio_internal.h>
53 #include <sys/xattr.h>
54 #include <sys/paths.h>
55 
56 #include <vfs/vfs_support.h>
57 
58 #include <sys/vm.h>
59 
60 #include <sys/time.h>
61 #include <kern/clock.h>
62 #include <libkern/OSAtomic.h>
63 
64 #include <miscfs/fifofs/fifo.h>
65 #include <miscfs/specfs/specdev.h>
66 
67 #include <nfs/rpcv2.h>
68 #include <nfs/nfsproto.h>
69 #include <nfs/nfs.h>
70 #include <nfs/nfsnode.h>
71 #include <nfs/nfs_gss.h>
72 #include <nfs/nfsmount.h>
73 #include <nfs/nfs_lock.h>
74 #include <nfs/xdr_subs.h>
75 #include <nfs/nfsm_subs.h>
76 
77 #include <net/if.h>
78 #include <netinet/in.h>
79 #include <netinet/in_var.h>
80 #include <vm/vm_kern.h>
81 
82 #include <kern/task.h>
83 #include <kern/sched_prim.h>
84 
85 #if CONFIG_NFS4
86 
87 int
nfs4_access_rpc(nfsnode_t np,u_int32_t * access,int rpcflags,vfs_context_t ctx)88 nfs4_access_rpc(nfsnode_t np, u_int32_t *access, int rpcflags, vfs_context_t ctx)
89 {
90 	int error = 0, lockerror = ENOENT, status, numops, slot;
91 	u_int64_t xid;
92 	struct nfsm_chain nmreq, nmrep;
93 	struct timeval now;
94 	uint32_t access_result = 0, supported = 0, missing;
95 	struct nfsmount *nmp = NFSTONMP(np);
96 	int nfsvers = nmp->nm_vers;
97 	uid_t uid;
98 	struct nfsreq_secinfo_args si;
99 
100 	if (np->n_vattr.nva_flags & NFS_FFLAG_TRIGGER_REFERRAL) {
101 		return 0;
102 	}
103 
104 	NFSREQ_SECINFO_SET(&si, np, NULL, 0, NULL, 0);
105 	nfsm_chain_null(&nmreq);
106 	nfsm_chain_null(&nmrep);
107 
108 	// PUTFH, ACCESS, GETATTR
109 	numops = 3;
110 	nfsm_chain_build_alloc_init(error, &nmreq, 17 * NFSX_UNSIGNED);
111 	nfsm_chain_add_compound_header(error, &nmreq, "access", nmp->nm_minor_vers, numops);
112 	numops--;
113 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_PUTFH);
114 	nfsm_chain_add_fh(error, &nmreq, nfsvers, np->n_fhp, np->n_fhsize);
115 	numops--;
116 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_ACCESS);
117 	nfsm_chain_add_32(error, &nmreq, *access);
118 	numops--;
119 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_GETATTR);
120 	nfsm_chain_add_bitmap_supported(error, &nmreq, nfs_getattr_bitmap, nmp, np);
121 	nfsm_chain_build_done(error, &nmreq);
122 	nfsm_assert(error, (numops == 0), EPROTO);
123 	nfsmout_if(error);
124 	error = nfs_request2(np, NULL, &nmreq, NFSPROC4_COMPOUND,
125 	    vfs_context_thread(ctx), vfs_context_ucred(ctx),
126 	    &si, rpcflags, &nmrep, &xid, &status);
127 
128 	if ((lockerror = nfs_node_lock(np))) {
129 		error = lockerror;
130 	}
131 	nfsm_chain_skip_tag(error, &nmrep);
132 	nfsm_chain_get_32(error, &nmrep, numops);
133 	nfsm_chain_op_check(error, &nmrep, NFS_OP_PUTFH);
134 	nfsm_chain_op_check(error, &nmrep, NFS_OP_ACCESS);
135 	nfsm_chain_get_32(error, &nmrep, supported);
136 	nfsm_chain_get_32(error, &nmrep, access_result);
137 	nfsmout_if(error);
138 	if ((missing = (*access & ~supported))) {
139 		/* missing support for something(s) we wanted */
140 		if (missing & NFS_ACCESS_DELETE) {
141 			/*
142 			 * If the server doesn't report DELETE (possible
143 			 * on UNIX systems), we'll assume that it is OK
144 			 * and just let any subsequent delete action fail
145 			 * if it really isn't deletable.
146 			 */
147 			access_result |= NFS_ACCESS_DELETE;
148 		}
149 	}
150 	/* ".zfs" subdirectories may erroneously give a denied answer for modify/delete */
151 	if (nfs_access_dotzfs) {
152 		vnode_t dvp = NULLVP;
153 		if (np->n_flag & NISDOTZFSCHILD) { /* may be able to create/delete snapshot dirs */
154 			access_result |= (NFS_ACCESS_MODIFY | NFS_ACCESS_EXTEND | NFS_ACCESS_DELETE);
155 		} else if (((dvp = vnode_getparent(NFSTOV(np))) != NULLVP) && (VTONFS(dvp)->n_flag & NISDOTZFSCHILD)) {
156 			access_result |= NFS_ACCESS_DELETE; /* may be able to delete snapshot dirs */
157 		}
158 		if (dvp != NULLVP) {
159 			vnode_put(dvp);
160 		}
161 	}
162 	/* Some servers report DELETE support but erroneously give a denied answer. */
163 	if (nfs_access_delete && (*access & NFS_ACCESS_DELETE) && !(access_result & NFS_ACCESS_DELETE)) {
164 		access_result |= NFS_ACCESS_DELETE;
165 	}
166 	nfsm_chain_op_check(error, &nmrep, NFS_OP_GETATTR);
167 	nfsm_chain_loadattr(error, &nmrep, np, nfsvers, &xid);
168 	nfsmout_if(error);
169 
170 	if (nfs_mount_gone(nmp)) {
171 		error = ENXIO;
172 	}
173 	nfsmout_if(error);
174 
175 	if (auth_is_kerberized(np->n_auth) || auth_is_kerberized(nmp->nm_auth)) {
176 		uid = nfs_cred_getasid2uid(vfs_context_ucred(ctx));
177 	} else {
178 		uid = kauth_cred_getuid(vfs_context_ucred(ctx));
179 	}
180 	slot = nfs_node_access_slot(np, uid, 1);
181 	np->n_accessuid[slot] = uid;
182 	microuptime(&now);
183 	np->n_accessstamp[slot] = now.tv_sec;
184 	np->n_access[slot] = access_result;
185 
186 	/* pass back the access returned with this request */
187 	*access = np->n_access[slot];
188 nfsmout:
189 	if (!lockerror) {
190 		nfs_node_unlock(np);
191 	}
192 	nfsm_chain_cleanup(&nmreq);
193 	nfsm_chain_cleanup(&nmrep);
194 	return error;
195 }
196 
197 int
nfs4_getattr_rpc(nfsnode_t np,mount_t mp,u_char * fhp,size_t fhsize,int flags,vfs_context_t ctx,struct nfs_vattr * nvap,u_int64_t * xidp)198 nfs4_getattr_rpc(
199 	nfsnode_t np,
200 	mount_t mp,
201 	u_char *fhp,
202 	size_t fhsize,
203 	int flags,
204 	vfs_context_t ctx,
205 	struct nfs_vattr *nvap,
206 	u_int64_t *xidp)
207 {
208 	struct nfsmount *nmp = mp ? VFSTONFS(mp) : NFSTONMP(np);
209 	int error = 0, status, nfsvers, numops, rpcflags = 0, acls;
210 	uint32_t bitmap[NFS_ATTR_BITMAP_LEN];
211 	struct nfsm_chain nmreq, nmrep;
212 	struct nfsreq_secinfo_args si;
213 
214 	if (nfs_mount_gone(nmp)) {
215 		return ENXIO;
216 	}
217 	nfsvers = nmp->nm_vers;
218 	acls = (nmp->nm_fsattr.nfsa_flags & NFS_FSFLAG_ACL);
219 
220 	if (np && (np->n_vattr.nva_flags & NFS_FFLAG_TRIGGER_REFERRAL)) {
221 		nfs4_default_attrs_for_referral_trigger(VTONFS(np->n_parent), NULL, 0, nvap, NULL);
222 		return 0;
223 	}
224 
225 	if (flags & NGA_MONITOR) { /* vnode monitor requests should be soft */
226 		rpcflags = R_RECOVER;
227 	}
228 
229 	if (flags & NGA_SOFT) { /* Return ETIMEDOUT if server not responding */
230 		rpcflags |= R_SOFT;
231 	}
232 
233 	NFSREQ_SECINFO_SET(&si, np, NULL, 0, NULL, 0);
234 	nfsm_chain_null(&nmreq);
235 	nfsm_chain_null(&nmrep);
236 
237 	// PUTFH, GETATTR
238 	numops = 2;
239 	nfsm_chain_build_alloc_init(error, &nmreq, 15 * NFSX_UNSIGNED);
240 	nfsm_chain_add_compound_header(error, &nmreq, "getattr", nmp->nm_minor_vers, numops);
241 	numops--;
242 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_PUTFH);
243 	nfsm_chain_add_fh(error, &nmreq, nfsvers, fhp, fhsize);
244 	numops--;
245 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_GETATTR);
246 	NFS_COPY_ATTRIBUTES(nfs_getattr_bitmap, bitmap);
247 	if ((flags & NGA_ACL) && acls) {
248 		NFS_BITMAP_SET(bitmap, NFS_FATTR_ACL);
249 	}
250 	nfsm_chain_add_bitmap_supported(error, &nmreq, bitmap, nmp, np);
251 	nfsm_chain_build_done(error, &nmreq);
252 	nfsm_assert(error, (numops == 0), EPROTO);
253 	nfsmout_if(error);
254 	error = nfs_request2(np, mp, &nmreq, NFSPROC4_COMPOUND,
255 	    vfs_context_thread(ctx), vfs_context_ucred(ctx),
256 	    NULL, rpcflags, &nmrep, xidp, &status);
257 
258 	nfsm_chain_skip_tag(error, &nmrep);
259 	nfsm_chain_get_32(error, &nmrep, numops);
260 	nfsm_chain_op_check(error, &nmrep, NFS_OP_PUTFH);
261 	nfsm_chain_op_check(error, &nmrep, NFS_OP_GETATTR);
262 	nfsmout_if(error);
263 	error = nfs4_parsefattr(&nmrep, NULL, nvap, NULL, NULL, NULL);
264 	nfsmout_if(error);
265 	if ((flags & NGA_ACL) && acls && !NFS_BITMAP_ISSET(nvap->nva_bitmap, NFS_FATTR_ACL)) {
266 		/* we asked for the ACL but didn't get one... assume there isn't one */
267 		NFS_BITMAP_SET(nvap->nva_bitmap, NFS_FATTR_ACL);
268 		nvap->nva_acl = NULL;
269 	}
270 nfsmout:
271 	nfsm_chain_cleanup(&nmreq);
272 	nfsm_chain_cleanup(&nmrep);
273 	return error;
274 }
275 
276 int
nfs4_readlink_rpc(nfsnode_t np,char * buf,size_t * buflenp,vfs_context_t ctx)277 nfs4_readlink_rpc(nfsnode_t np, char *buf, size_t *buflenp, vfs_context_t ctx)
278 {
279 	struct nfsmount *nmp;
280 	int error = 0, lockerror = ENOENT, status, numops;
281 	size_t len = 0;
282 	u_int64_t xid;
283 	struct nfsm_chain nmreq, nmrep;
284 	struct nfsreq_secinfo_args si;
285 
286 	nmp = NFSTONMP(np);
287 	if (nfs_mount_gone(nmp)) {
288 		return ENXIO;
289 	}
290 	if (np->n_vattr.nva_flags & NFS_FFLAG_TRIGGER_REFERRAL) {
291 		return EINVAL;
292 	}
293 	NFSREQ_SECINFO_SET(&si, np, NULL, 0, NULL, 0);
294 	nfsm_chain_null(&nmreq);
295 	nfsm_chain_null(&nmrep);
296 
297 	// PUTFH, GETATTR, READLINK
298 	numops = 3;
299 	nfsm_chain_build_alloc_init(error, &nmreq, 16 * NFSX_UNSIGNED);
300 	nfsm_chain_add_compound_header(error, &nmreq, "readlink", nmp->nm_minor_vers, numops);
301 	numops--;
302 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_PUTFH);
303 	nfsm_chain_add_fh(error, &nmreq, NFS_VER4, np->n_fhp, np->n_fhsize);
304 	numops--;
305 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_GETATTR);
306 	nfsm_chain_add_bitmap_supported(error, &nmreq, nfs_getattr_bitmap, nmp, np);
307 	numops--;
308 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_READLINK);
309 	nfsm_chain_build_done(error, &nmreq);
310 	nfsm_assert(error, (numops == 0), EPROTO);
311 	nfsmout_if(error);
312 	error = nfs_request(np, NULL, &nmreq, NFSPROC4_COMPOUND, ctx, &si, &nmrep, &xid, &status);
313 
314 	if ((lockerror = nfs_node_lock(np))) {
315 		error = lockerror;
316 	}
317 	nfsm_chain_skip_tag(error, &nmrep);
318 	nfsm_chain_get_32(error, &nmrep, numops);
319 	nfsm_chain_op_check(error, &nmrep, NFS_OP_PUTFH);
320 	nfsm_chain_op_check(error, &nmrep, NFS_OP_GETATTR);
321 	nfsm_chain_loadattr(error, &nmrep, np, NFS_VER4, &xid);
322 	nfsm_chain_op_check(error, &nmrep, NFS_OP_READLINK);
323 	nfsm_chain_get_32(error, &nmrep, len);
324 	nfsmout_if(error);
325 	if (len >= *buflenp) {
326 		if (np->n_size && (np->n_size < *buflenp)) {
327 			len = np->n_size;
328 		} else {
329 			len = *buflenp - 1;
330 		}
331 	}
332 	nfsm_chain_get_opaque(error, &nmrep, len, buf);
333 	if (!error) {
334 		*buflenp = len;
335 	}
336 nfsmout:
337 	if (!lockerror) {
338 		nfs_node_unlock(np);
339 	}
340 	nfsm_chain_cleanup(&nmreq);
341 	nfsm_chain_cleanup(&nmrep);
342 	return error;
343 }
344 
345 int
nfs4_read_rpc_async(nfsnode_t np,off_t offset,size_t len,thread_t thd,kauth_cred_t cred,struct nfsreq_cbinfo * cb,struct nfsreq ** reqp)346 nfs4_read_rpc_async(
347 	nfsnode_t np,
348 	off_t offset,
349 	size_t len,
350 	thread_t thd,
351 	kauth_cred_t cred,
352 	struct nfsreq_cbinfo *cb,
353 	struct nfsreq **reqp)
354 {
355 	struct nfsmount *nmp;
356 	int error = 0, nfsvers, numops;
357 	nfs_stateid stateid;
358 	struct nfsm_chain nmreq;
359 	struct nfsreq_secinfo_args si;
360 
361 	nmp = NFSTONMP(np);
362 	if (nfs_mount_gone(nmp)) {
363 		return ENXIO;
364 	}
365 	nfsvers = nmp->nm_vers;
366 	if (np->n_vattr.nva_flags & NFS_FFLAG_TRIGGER_REFERRAL) {
367 		return EINVAL;
368 	}
369 
370 	NFSREQ_SECINFO_SET(&si, np, NULL, 0, NULL, 0);
371 	nfsm_chain_null(&nmreq);
372 
373 	// PUTFH, READ
374 	numops = 2;
375 	nfsm_chain_build_alloc_init(error, &nmreq, 22 * NFSX_UNSIGNED);
376 	nfsm_chain_add_compound_header(error, &nmreq, "read", nmp->nm_minor_vers, numops);
377 	numops--;
378 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_PUTFH);
379 	nfsm_chain_add_fh(error, &nmreq, nfsvers, np->n_fhp, np->n_fhsize);
380 	numops--;
381 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_READ);
382 	nfs_get_stateid(np, thd, cred, &stateid, 0);
383 	nfsm_chain_add_stateid(error, &nmreq, &stateid);
384 	nfsm_chain_add_64(error, &nmreq, offset);
385 	nfsm_chain_add_32(error, &nmreq, len);
386 	nfsm_chain_build_done(error, &nmreq);
387 	nfsm_assert(error, (numops == 0), EPROTO);
388 	nfsmout_if(error);
389 	error = nfs_request_async(np, NULL, &nmreq, NFSPROC4_COMPOUND, thd, cred, &si, 0, cb, reqp);
390 nfsmout:
391 	nfsm_chain_cleanup(&nmreq);
392 	return error;
393 }
394 
395 int
nfs4_read_rpc_async_finish(nfsnode_t np,struct nfsreq * req,uio_t uio,size_t * lenp,int * eofp)396 nfs4_read_rpc_async_finish(
397 	nfsnode_t np,
398 	struct nfsreq *req,
399 	uio_t uio,
400 	size_t *lenp,
401 	int *eofp)
402 {
403 	struct nfsmount *nmp;
404 	int error = 0, lockerror, nfsvers, numops, status, eof = 0;
405 	size_t retlen = 0;
406 	u_int64_t xid;
407 	struct nfsm_chain nmrep;
408 
409 	nmp = NFSTONMP(np);
410 	if (nfs_mount_gone(nmp)) {
411 		nfs_request_async_cancel(req);
412 		return ENXIO;
413 	}
414 	nfsvers = nmp->nm_vers;
415 
416 	nfsm_chain_null(&nmrep);
417 
418 	error = nfs_request_async_finish(req, &nmrep, &xid, &status);
419 	if (error == EINPROGRESS) { /* async request restarted */
420 		return error;
421 	}
422 
423 	if ((lockerror = nfs_node_lock(np))) {
424 		error = lockerror;
425 	}
426 	nfsm_chain_skip_tag(error, &nmrep);
427 	nfsm_chain_get_32(error, &nmrep, numops);
428 	nfsm_chain_op_check(error, &nmrep, NFS_OP_PUTFH);
429 	nfsm_chain_op_check(error, &nmrep, NFS_OP_READ);
430 	nfsm_chain_get_32(error, &nmrep, eof);
431 	nfsm_chain_get_32(error, &nmrep, retlen);
432 	if (!error) {
433 		*lenp = MIN(retlen, *lenp);
434 		error = nfsm_chain_get_uio(&nmrep, *lenp, uio);
435 	}
436 	if (!lockerror) {
437 		nfs_node_unlock(np);
438 	}
439 	if (eofp) {
440 		if (!eof && !retlen) {
441 			eof = 1;
442 		}
443 		*eofp = eof;
444 	}
445 	nfsm_chain_cleanup(&nmrep);
446 	if (np->n_vattr.nva_flags & NFS_FFLAG_IS_ATTR) {
447 		microuptime(&np->n_lastio);
448 	}
449 	return error;
450 }
451 
452 int
nfs4_write_rpc_async(nfsnode_t np,uio_t uio,size_t len,thread_t thd,kauth_cred_t cred,int iomode,struct nfsreq_cbinfo * cb,struct nfsreq ** reqp)453 nfs4_write_rpc_async(
454 	nfsnode_t np,
455 	uio_t uio,
456 	size_t len,
457 	thread_t thd,
458 	kauth_cred_t cred,
459 	int iomode,
460 	struct nfsreq_cbinfo *cb,
461 	struct nfsreq **reqp)
462 {
463 	struct nfsmount *nmp;
464 	mount_t mp;
465 	int error = 0, nfsvers, numops;
466 	nfs_stateid stateid;
467 	struct nfsm_chain nmreq;
468 	struct nfsreq_secinfo_args si;
469 
470 	nmp = NFSTONMP(np);
471 	if (nfs_mount_gone(nmp)) {
472 		return ENXIO;
473 	}
474 	nfsvers = nmp->nm_vers;
475 	if (np->n_vattr.nva_flags & NFS_FFLAG_TRIGGER_REFERRAL) {
476 		return EINVAL;
477 	}
478 
479 	/* for async mounts, don't bother sending sync write requests */
480 	if ((iomode != NFS_WRITE_UNSTABLE) && nfs_allow_async &&
481 	    ((mp = NFSTOMP(np))) && (vfs_flags(mp) & MNT_ASYNC)) {
482 		iomode = NFS_WRITE_UNSTABLE;
483 	}
484 
485 	NFSREQ_SECINFO_SET(&si, np, NULL, 0, NULL, 0);
486 	nfsm_chain_null(&nmreq);
487 
488 	// PUTFH, WRITE, GETATTR
489 	numops = 3;
490 	nfsm_chain_build_alloc_init(error, &nmreq, 25 * NFSX_UNSIGNED + len);
491 	nfsm_chain_add_compound_header(error, &nmreq, "write", nmp->nm_minor_vers, numops);
492 	numops--;
493 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_PUTFH);
494 	nfsm_chain_add_fh(error, &nmreq, nfsvers, np->n_fhp, np->n_fhsize);
495 	numops--;
496 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_WRITE);
497 	nfs_get_stateid(np, thd, cred, &stateid, 1);
498 	nfsm_chain_add_stateid(error, &nmreq, &stateid);
499 	nfsm_chain_add_64(error, &nmreq, uio_offset(uio));
500 	nfsm_chain_add_32(error, &nmreq, iomode);
501 	nfsm_chain_add_32(error, &nmreq, len);
502 	if (!error) {
503 		error = nfsm_chain_add_uio(&nmreq, uio, len);
504 	}
505 	numops--;
506 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_GETATTR);
507 	nfsm_chain_add_bitmap_supported(error, &nmreq, nfs4_getattr_write_bitmap, nmp, np);
508 	nfsm_chain_build_done(error, &nmreq);
509 	nfsm_assert(error, (numops == 0), EPROTO);
510 	nfsmout_if(error);
511 
512 	error = nfs_request_async(np, NULL, &nmreq, NFSPROC4_COMPOUND, thd, cred, &si, 0, cb, reqp);
513 nfsmout:
514 	nfsm_chain_cleanup(&nmreq);
515 	return error;
516 }
517 
518 int
nfs4_write_rpc_async_finish(nfsnode_t np,struct nfsreq * req,int * iomodep,size_t * rlenp,uint64_t * wverfp)519 nfs4_write_rpc_async_finish(
520 	nfsnode_t np,
521 	struct nfsreq *req,
522 	int *iomodep,
523 	size_t *rlenp,
524 	uint64_t *wverfp)
525 {
526 	struct nfsmount *nmp;
527 	int error = 0, lockerror = ENOENT, nfsvers, numops, status;
528 	int committed = NFS_WRITE_FILESYNC;
529 	size_t rlen = 0;
530 	u_int64_t xid, wverf;
531 	mount_t mp;
532 	struct nfsm_chain nmrep;
533 
534 	nmp = NFSTONMP(np);
535 	if (nfs_mount_gone(nmp)) {
536 		nfs_request_async_cancel(req);
537 		return ENXIO;
538 	}
539 	nfsvers = nmp->nm_vers;
540 
541 	nfsm_chain_null(&nmrep);
542 
543 	error = nfs_request_async_finish(req, &nmrep, &xid, &status);
544 	if (error == EINPROGRESS) { /* async request restarted */
545 		return error;
546 	}
547 	nmp = NFSTONMP(np);
548 	if (nfs_mount_gone(nmp)) {
549 		error = ENXIO;
550 	}
551 	if (!error && (lockerror = nfs_node_lock(np))) {
552 		error = lockerror;
553 	}
554 	nfsm_chain_skip_tag(error, &nmrep);
555 	nfsm_chain_get_32(error, &nmrep, numops);
556 	nfsm_chain_op_check(error, &nmrep, NFS_OP_PUTFH);
557 	nfsm_chain_op_check(error, &nmrep, NFS_OP_WRITE);
558 	nfsm_chain_get_32(error, &nmrep, rlen);
559 	nfsmout_if(error);
560 	*rlenp = rlen;
561 	if (rlen <= 0) {
562 		error = NFSERR_IO;
563 	}
564 	nfsm_chain_get_32(error, &nmrep, committed);
565 	nfsm_chain_get_64(error, &nmrep, wverf);
566 	nfsmout_if(error);
567 	if (wverfp) {
568 		*wverfp = wverf;
569 	}
570 	lck_mtx_lock(&nmp->nm_lock);
571 	if (!(nmp->nm_state & NFSSTA_HASWRITEVERF)) {
572 		nmp->nm_verf = wverf;
573 		nmp->nm_state |= NFSSTA_HASWRITEVERF;
574 	} else if (nmp->nm_verf != wverf) {
575 		nmp->nm_verf = wverf;
576 	}
577 	lck_mtx_unlock(&nmp->nm_lock);
578 	nfsm_chain_op_check(error, &nmrep, NFS_OP_GETATTR);
579 
580 	/*
581 	 * NFSv4 WRITE RPCs contain partial GETATTR requests - only type, change, size, metadatatime and modifytime are requested.
582 	 * In such cases,  we do not update the time stamp - but the requested attributes.
583 	 */
584 	np->n_vattr.nva_flags |= NFS_FFLAG_PARTIAL_WRITE;
585 	nfsm_chain_loadattr(error, &nmrep, np, nfsvers, &xid);
586 	np->n_vattr.nva_flags &= ~NFS_FFLAG_PARTIAL_WRITE;
587 
588 nfsmout:
589 	if (!lockerror) {
590 		nfs_node_unlock(np);
591 	}
592 	nfsm_chain_cleanup(&nmrep);
593 	if ((committed != NFS_WRITE_FILESYNC) && nfs_allow_async &&
594 	    ((mp = NFSTOMP(np))) && (vfs_flags(mp) & MNT_ASYNC)) {
595 		committed = NFS_WRITE_FILESYNC;
596 	}
597 	*iomodep = committed;
598 	if (np->n_vattr.nva_flags & NFS_FFLAG_IS_ATTR) {
599 		microuptime(&np->n_lastio);
600 	}
601 	return error;
602 }
603 
604 int
nfs4_remove_rpc(nfsnode_t dnp,char * name,int namelen,thread_t thd,kauth_cred_t cred)605 nfs4_remove_rpc(
606 	nfsnode_t dnp,
607 	char *name,
608 	int namelen,
609 	thread_t thd,
610 	kauth_cred_t cred)
611 {
612 	int error = 0, lockerror = ENOENT, remove_error = 0, status;
613 	struct nfsmount *nmp;
614 	int nfsvers, numops;
615 	u_int64_t xid;
616 	struct nfsm_chain nmreq, nmrep;
617 	struct nfsreq_secinfo_args si;
618 
619 	nmp = NFSTONMP(dnp);
620 	if (nfs_mount_gone(nmp)) {
621 		return ENXIO;
622 	}
623 	nfsvers = nmp->nm_vers;
624 	if (dnp->n_vattr.nva_flags & NFS_FFLAG_TRIGGER_REFERRAL) {
625 		return EINVAL;
626 	}
627 	NFSREQ_SECINFO_SET(&si, dnp, NULL, 0, NULL, 0);
628 restart:
629 	nfsm_chain_null(&nmreq);
630 	nfsm_chain_null(&nmrep);
631 
632 	// PUTFH, REMOVE, GETATTR
633 	numops = 3;
634 	nfsm_chain_build_alloc_init(error, &nmreq, 17 * NFSX_UNSIGNED + namelen);
635 	nfsm_chain_add_compound_header(error, &nmreq, "remove", nmp->nm_minor_vers, numops);
636 	numops--;
637 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_PUTFH);
638 	nfsm_chain_add_fh(error, &nmreq, nfsvers, dnp->n_fhp, dnp->n_fhsize);
639 	numops--;
640 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_REMOVE);
641 	nfsm_chain_add_name(error, &nmreq, name, namelen, nmp);
642 	numops--;
643 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_GETATTR);
644 	nfsm_chain_add_bitmap_supported(error, &nmreq, nfs_getattr_bitmap, nmp, dnp);
645 	nfsm_chain_build_done(error, &nmreq);
646 	nfsm_assert(error, (numops == 0), EPROTO);
647 	nfsmout_if(error);
648 
649 	error = nfs_request2(dnp, NULL, &nmreq, NFSPROC4_COMPOUND, thd, cred, &si, 0, &nmrep, &xid, &status);
650 
651 	if ((lockerror = nfs_node_lock(dnp))) {
652 		error = lockerror;
653 	}
654 	nfsm_chain_skip_tag(error, &nmrep);
655 	nfsm_chain_get_32(error, &nmrep, numops);
656 	nfsm_chain_op_check(error, &nmrep, NFS_OP_PUTFH);
657 	nfsm_chain_op_check(error, &nmrep, NFS_OP_REMOVE);
658 	remove_error = error;
659 	nfsm_chain_check_change_info(error, &nmrep, dnp);
660 	nfsm_chain_op_check(error, &nmrep, NFS_OP_GETATTR);
661 	nfsm_chain_loadattr(error, &nmrep, dnp, nfsvers, &xid);
662 	if (error && !lockerror) {
663 		NATTRINVALIDATE(dnp);
664 	}
665 nfsmout:
666 	nfsm_chain_cleanup(&nmreq);
667 	nfsm_chain_cleanup(&nmrep);
668 
669 	if (!lockerror) {
670 		dnp->n_flag |= NMODIFIED;
671 		nfs_node_unlock(dnp);
672 	}
673 	if (error == NFSERR_GRACE) {
674 		tsleep(&nmp->nm_state, (PZERO - 1), "nfsgrace", 2 * hz);
675 		goto restart;
676 	}
677 
678 	return remove_error;
679 }
680 
681 int
nfs4_rename_rpc(nfsnode_t fdnp,char * fnameptr,int fnamelen,nfsnode_t tdnp,char * tnameptr,int tnamelen,vfs_context_t ctx)682 nfs4_rename_rpc(
683 	nfsnode_t fdnp,
684 	char *fnameptr,
685 	int fnamelen,
686 	nfsnode_t tdnp,
687 	char *tnameptr,
688 	int tnamelen,
689 	vfs_context_t ctx)
690 {
691 	int error = 0, lockerror = ENOENT, status, nfsvers, numops;
692 	struct nfsmount *nmp;
693 	u_int64_t xid, savedxid;
694 	struct nfsm_chain nmreq, nmrep;
695 	struct nfsreq_secinfo_args si;
696 
697 	nmp = NFSTONMP(fdnp);
698 	if (nfs_mount_gone(nmp)) {
699 		return ENXIO;
700 	}
701 	nfsvers = nmp->nm_vers;
702 	if (fdnp->n_vattr.nva_flags & NFS_FFLAG_TRIGGER_REFERRAL) {
703 		return EINVAL;
704 	}
705 	if (tdnp->n_vattr.nva_flags & NFS_FFLAG_TRIGGER_REFERRAL) {
706 		return EINVAL;
707 	}
708 
709 	NFSREQ_SECINFO_SET(&si, fdnp, NULL, 0, NULL, 0);
710 	nfsm_chain_null(&nmreq);
711 	nfsm_chain_null(&nmrep);
712 
713 	// PUTFH(FROM), SAVEFH, PUTFH(TO), RENAME, GETATTR(TO), RESTOREFH, GETATTR(FROM)
714 	numops = 7;
715 	nfsm_chain_build_alloc_init(error, &nmreq, 30 * NFSX_UNSIGNED + fnamelen + tnamelen);
716 	nfsm_chain_add_compound_header(error, &nmreq, "rename", nmp->nm_minor_vers, numops);
717 	numops--;
718 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_PUTFH);
719 	nfsm_chain_add_fh(error, &nmreq, nfsvers, fdnp->n_fhp, fdnp->n_fhsize);
720 	numops--;
721 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_SAVEFH);
722 	numops--;
723 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_PUTFH);
724 	nfsm_chain_add_fh(error, &nmreq, nfsvers, tdnp->n_fhp, tdnp->n_fhsize);
725 	numops--;
726 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_RENAME);
727 	nfsm_chain_add_name(error, &nmreq, fnameptr, fnamelen, nmp);
728 	nfsm_chain_add_name(error, &nmreq, tnameptr, tnamelen, nmp);
729 	numops--;
730 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_GETATTR);
731 	nfsm_chain_add_bitmap_supported(error, &nmreq, nfs_getattr_bitmap, nmp, tdnp);
732 	numops--;
733 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_RESTOREFH);
734 	numops--;
735 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_GETATTR);
736 	nfsm_chain_add_bitmap_supported(error, &nmreq, nfs_getattr_bitmap, nmp, fdnp);
737 	nfsm_chain_build_done(error, &nmreq);
738 	nfsm_assert(error, (numops == 0), EPROTO);
739 	nfsmout_if(error);
740 
741 	error = nfs_request(fdnp, NULL, &nmreq, NFSPROC4_COMPOUND, ctx, &si, &nmrep, &xid, &status);
742 
743 	if ((lockerror = nfs_node_lock2(fdnp, tdnp))) {
744 		error = lockerror;
745 	}
746 	nfsm_chain_skip_tag(error, &nmrep);
747 	nfsm_chain_get_32(error, &nmrep, numops);
748 	nfsm_chain_op_check(error, &nmrep, NFS_OP_PUTFH);
749 	nfsm_chain_op_check(error, &nmrep, NFS_OP_SAVEFH);
750 	nfsm_chain_op_check(error, &nmrep, NFS_OP_PUTFH);
751 	nfsm_chain_op_check(error, &nmrep, NFS_OP_RENAME);
752 	nfsm_chain_check_change_info(error, &nmrep, fdnp);
753 	nfsm_chain_check_change_info(error, &nmrep, tdnp);
754 	/* directory attributes: if we don't get them, make sure to invalidate */
755 	nfsm_chain_op_check(error, &nmrep, NFS_OP_GETATTR);
756 	savedxid = xid;
757 	nfsm_chain_loadattr(error, &nmrep, tdnp, nfsvers, &xid);
758 	if (error && !lockerror) {
759 		NATTRINVALIDATE(tdnp);
760 	}
761 	nfsm_chain_op_check(error, &nmrep, NFS_OP_RESTOREFH);
762 	nfsm_chain_op_check(error, &nmrep, NFS_OP_GETATTR);
763 	xid = savedxid;
764 	nfsm_chain_loadattr(error, &nmrep, fdnp, nfsvers, &xid);
765 	if (error && !lockerror) {
766 		NATTRINVALIDATE(fdnp);
767 	}
768 nfsmout:
769 	nfsm_chain_cleanup(&nmreq);
770 	nfsm_chain_cleanup(&nmrep);
771 	if (!lockerror) {
772 		fdnp->n_flag |= NMODIFIED;
773 		tdnp->n_flag |= NMODIFIED;
774 		nfs_node_unlock2(fdnp, tdnp);
775 	}
776 	return error;
777 }
778 
779 /*
780  * NFS V4 readdir RPC.
781  */
782 int
nfs4_readdir_rpc(nfsnode_t dnp,struct nfsbuf * bp,vfs_context_t ctx)783 nfs4_readdir_rpc(nfsnode_t dnp, struct nfsbuf *bp, vfs_context_t ctx)
784 {
785 	struct nfsmount *nmp;
786 	int error = 0, lockerror, nfsvers, namedattr, rdirplus, bigcookies, numops;
787 	int i, status, more_entries = 1, eof, bp_dropped = 0;
788 	uint16_t namlen, reclen;
789 	uint32_t nmreaddirsize, nmrsize;
790 	uint32_t namlen32, skiplen, fhlen, xlen, attrlen;
791 	uint64_t padlen, cookie, lastcookie, xid, savedxid, space_free, space_needed;
792 	struct nfsm_chain nmreq, nmrep, nmrepsave;
793 	fhandle_t *fh;
794 	struct nfs_vattr *nvattr, *nvattrp;
795 	struct nfs_dir_buf_header *ndbhp;
796 	struct direntry *dp;
797 	char *padstart;
798 	const char *tag;
799 	uint32_t entry_attrs[NFS_ATTR_BITMAP_LEN];
800 	struct timeval now;
801 	struct nfsreq_secinfo_args si;
802 
803 	nmp = NFSTONMP(dnp);
804 	if (nfs_mount_gone(nmp)) {
805 		return ENXIO;
806 	}
807 	nfsvers = nmp->nm_vers;
808 	nmreaddirsize = nmp->nm_readdirsize;
809 	nmrsize = nmp->nm_rsize;
810 	bigcookies = nmp->nm_state & NFSSTA_BIGCOOKIES;
811 	namedattr = (dnp->n_vattr.nva_flags & NFS_FFLAG_IS_ATTR) ? 1 : 0;
812 	rdirplus = (NMFLAG(nmp, RDIRPLUS) || namedattr) ? 1 : 0;
813 	if (dnp->n_vattr.nva_flags & NFS_FFLAG_TRIGGER_REFERRAL) {
814 		return EINVAL;
815 	}
816 	NFSREQ_SECINFO_SET(&si, dnp, NULL, 0, NULL, 0);
817 
818 	/*
819 	 * Set up attribute request for entries.
820 	 * For READDIRPLUS functionality, get everything.
821 	 * Otherwise, just get what we need for struct direntry.
822 	 */
823 	if (rdirplus) {
824 		tag = "readdirplus";
825 		NFS_COPY_ATTRIBUTES(nfs_getattr_bitmap, entry_attrs);
826 		NFS_BITMAP_SET(entry_attrs, NFS_FATTR_FILEHANDLE);
827 	} else {
828 		tag = "readdir";
829 		NFS_CLEAR_ATTRIBUTES(entry_attrs);
830 		NFS_BITMAP_SET(entry_attrs, NFS_FATTR_TYPE);
831 		NFS_BITMAP_SET(entry_attrs, NFS_FATTR_FILEID);
832 		NFS_BITMAP_SET(entry_attrs, NFS_FATTR_MOUNTED_ON_FILEID);
833 	}
834 	NFS_BITMAP_SET(entry_attrs, NFS_FATTR_RDATTR_ERROR);
835 
836 	/* lock to protect access to cookie verifier */
837 	if ((lockerror = nfs_node_lock(dnp))) {
838 		return lockerror;
839 	}
840 
841 	fh = zalloc(nfs_fhandle_zone);
842 	nvattr = zalloc_flags(KT_NFS_VATTR, Z_WAITOK);
843 
844 	/* determine cookie to use, and move dp to the right offset */
845 	ndbhp = (struct nfs_dir_buf_header*)bp->nb_data;
846 	dp = NFS_DIR_BUF_FIRST_DIRENTRY(bp);
847 	if (ndbhp->ndbh_count) {
848 		for (i = 0; i < ndbhp->ndbh_count - 1; i++) {
849 			dp = NFS_DIRENTRY_NEXT(dp);
850 		}
851 		cookie = dp->d_seekoff;
852 		dp = NFS_DIRENTRY_NEXT(dp);
853 	} else {
854 		cookie = bp->nb_lblkno;
855 		/* increment with every buffer read */
856 		OSAddAtomic64(1, &nfsclntstats.readdir_bios);
857 	}
858 	lastcookie = cookie;
859 
860 	/*
861 	 * The NFS client is responsible for the "." and ".." entries in the
862 	 * directory.  So, we put them at the start of the first buffer.
863 	 * Don't bother for attribute directories.
864 	 */
865 	if (((bp->nb_lblkno == 0) && (ndbhp->ndbh_count == 0)) &&
866 	    !(dnp->n_vattr.nva_flags & NFS_FFLAG_IS_ATTR)) {
867 		fh->fh_len = 0;
868 		fhlen = rdirplus ? fh->fh_len + 1 : 0;
869 		xlen = rdirplus ? (fhlen + sizeof(time_t)) : 0;
870 		/* "." */
871 		namlen = 1;
872 		reclen = NFS_DIRENTRY_LEN_16(namlen + xlen);
873 		if (xlen) {
874 			bzero(&dp->d_name[namlen + 1], xlen);
875 		}
876 		dp->d_namlen = namlen;
877 		strlcpy(dp->d_name, ".", namlen + 1);
878 		dp->d_fileno = dnp->n_vattr.nva_fileid;
879 		dp->d_type = DT_DIR;
880 		dp->d_reclen = reclen;
881 		dp->d_seekoff = 1;
882 		padstart = dp->d_name + dp->d_namlen + 1 + xlen;
883 		dp = NFS_DIRENTRY_NEXT(dp);
884 		padlen = (char*)dp - padstart;
885 		if (padlen > 0) {
886 			bzero(padstart, padlen);
887 		}
888 		if (rdirplus) { /* zero out attributes */
889 			bzero(NFS_DIR_BUF_NVATTR(bp, 0), sizeof(struct nfs_vattr));
890 		}
891 
892 		/* ".." */
893 		namlen = 2;
894 		reclen = NFS_DIRENTRY_LEN_16(namlen + xlen);
895 		if (xlen) {
896 			bzero(&dp->d_name[namlen + 1], xlen);
897 		}
898 		dp->d_namlen = namlen;
899 		strlcpy(dp->d_name, "..", namlen + 1);
900 		if (dnp->n_parent) {
901 			dp->d_fileno = VTONFS(dnp->n_parent)->n_vattr.nva_fileid;
902 		} else {
903 			dp->d_fileno = dnp->n_vattr.nva_fileid;
904 		}
905 		dp->d_type = DT_DIR;
906 		dp->d_reclen = reclen;
907 		dp->d_seekoff = 2;
908 		padstart = dp->d_name + dp->d_namlen + 1 + xlen;
909 		dp = NFS_DIRENTRY_NEXT(dp);
910 		padlen = (char*)dp - padstart;
911 		if (padlen > 0) {
912 			bzero(padstart, padlen);
913 		}
914 		if (rdirplus) { /* zero out attributes */
915 			bzero(NFS_DIR_BUF_NVATTR(bp, 1), sizeof(struct nfs_vattr));
916 		}
917 
918 		ndbhp->ndbh_entry_end = (char*)dp - bp->nb_data;
919 		ndbhp->ndbh_count = 2;
920 	}
921 
922 	/*
923 	 * Loop around doing readdir(plus) RPCs of size nm_readdirsize until
924 	 * the buffer is full (or we hit EOF).  Then put the remainder of the
925 	 * results in the next buffer(s).
926 	 */
927 	nfsm_chain_null(&nmreq);
928 	nfsm_chain_null(&nmrep);
929 	while (nfs_dir_buf_freespace(bp, rdirplus) && !(ndbhp->ndbh_flags & NDB_FULL)) {
930 		// PUTFH, GETATTR, READDIR
931 		numops = 3;
932 		nfsm_chain_build_alloc_init(error, &nmreq, 26 * NFSX_UNSIGNED);
933 		nfsm_chain_add_compound_header(error, &nmreq, tag, nmp->nm_minor_vers, numops);
934 		numops--;
935 		nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_PUTFH);
936 		nfsm_chain_add_fh(error, &nmreq, nfsvers, dnp->n_fhp, dnp->n_fhsize);
937 		numops--;
938 		nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_GETATTR);
939 		nfsm_chain_add_bitmap_supported(error, &nmreq, nfs_getattr_bitmap, nmp, dnp);
940 		numops--;
941 		nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_READDIR);
942 		nfsm_chain_add_64(error, &nmreq, (cookie <= 2) ? 0 : cookie);
943 		nfsm_chain_add_64(error, &nmreq, dnp->n_cookieverf);
944 		nfsm_chain_add_32(error, &nmreq, nmreaddirsize);
945 		nfsm_chain_add_32(error, &nmreq, nmrsize);
946 		nfsm_chain_add_bitmap_supported(error, &nmreq, entry_attrs, nmp, dnp);
947 		nfsm_chain_build_done(error, &nmreq);
948 		nfsm_assert(error, (numops == 0), EPROTO);
949 		nfs_node_unlock(dnp);
950 		nfsmout_if(error);
951 		error = nfs_request(dnp, NULL, &nmreq, NFSPROC4_COMPOUND, ctx, &si, &nmrep, &xid, &status);
952 
953 		if ((lockerror = nfs_node_lock(dnp))) {
954 			error = lockerror;
955 		}
956 
957 		savedxid = xid;
958 		nfsm_chain_skip_tag(error, &nmrep);
959 		nfsm_chain_get_32(error, &nmrep, numops);
960 		nfsm_chain_op_check(error, &nmrep, NFS_OP_PUTFH);
961 		nfsm_chain_op_check(error, &nmrep, NFS_OP_GETATTR);
962 		nfsm_chain_loadattr(error, &nmrep, dnp, nfsvers, &xid);
963 		nfsm_chain_op_check(error, &nmrep, NFS_OP_READDIR);
964 		nfsm_chain_get_64(error, &nmrep, dnp->n_cookieverf);
965 		nfsm_chain_get_32(error, &nmrep, more_entries);
966 
967 		if (!lockerror) {
968 			nfs_node_unlock(dnp);
969 			lockerror = ENOENT;
970 		}
971 		nfsmout_if(error);
972 
973 		if (rdirplus) {
974 			microuptime(&now);
975 			if (lastcookie == 0) {
976 				dnp->n_rdirplusstamp_sof = now.tv_sec;
977 				dnp->n_rdirplusstamp_eof = 0;
978 			}
979 		}
980 
981 		/* loop through the entries packing them into the buffer */
982 		while (more_entries) {
983 			/* Entry: COOKIE, NAME, FATTR */
984 			nfsm_chain_get_64(error, &nmrep, cookie);
985 			nfsm_chain_get_32(error, &nmrep, namlen32);
986 			if (namlen32 > UINT16_MAX) {
987 				error = EBADRPC;
988 				goto nfsmout;
989 			}
990 			namlen = (uint16_t)namlen32;
991 			nfsmout_if(error);
992 			if (!bigcookies && (cookie >> 32) && (nmp == NFSTONMP(dnp))) {
993 				/* we've got a big cookie, make sure flag is set */
994 				lck_mtx_lock(&nmp->nm_lock);
995 				nmp->nm_state |= NFSSTA_BIGCOOKIES;
996 				lck_mtx_unlock(&nmp->nm_lock);
997 				bigcookies = 1;
998 			}
999 			/* just truncate names that don't fit in direntry.d_name */
1000 			if (namlen <= 0) {
1001 				error = EBADRPC;
1002 				goto nfsmout;
1003 			}
1004 			if (namlen > (sizeof(dp->d_name) - 1)) {
1005 				skiplen = namlen - sizeof(dp->d_name) + 1;
1006 				namlen = sizeof(dp->d_name) - 1;
1007 			} else {
1008 				skiplen = 0;
1009 			}
1010 			/* guess that fh size will be same as parent */
1011 			fhlen = rdirplus ? (1 + dnp->n_fhsize) : 0;
1012 			xlen = rdirplus ? (fhlen + sizeof(time_t)) : 0;
1013 			attrlen = rdirplus ? sizeof(struct nfs_vattr) : 0;
1014 			reclen = NFS_DIRENTRY_LEN_16(namlen + xlen);
1015 			space_needed = reclen + attrlen;
1016 			space_free = nfs_dir_buf_freespace(bp, rdirplus);
1017 			if (space_needed > space_free) {
1018 				/*
1019 				 * We still have entries to pack, but we've
1020 				 * run out of room in the current buffer.
1021 				 * So we need to move to the next buffer.
1022 				 * The block# for the next buffer is the
1023 				 * last cookie in the current buffer.
1024 				 */
1025 nextbuffer:
1026 				ndbhp->ndbh_flags |= NDB_FULL;
1027 				nfs_buf_release(bp, 0);
1028 				bp_dropped = 1;
1029 				bp = NULL;
1030 				error = nfs_buf_get(dnp, lastcookie, NFS_DIRBLKSIZ, vfs_context_thread(ctx), NBLK_READ, &bp);
1031 				nfsmout_if(error);
1032 				/* initialize buffer */
1033 				ndbhp = (struct nfs_dir_buf_header*)bp->nb_data;
1034 				ndbhp->ndbh_flags = 0;
1035 				ndbhp->ndbh_count = 0;
1036 				ndbhp->ndbh_entry_end = sizeof(*ndbhp);
1037 				ndbhp->ndbh_ncgen = dnp->n_ncgen;
1038 				space_free = nfs_dir_buf_freespace(bp, rdirplus);
1039 				dp = NFS_DIR_BUF_FIRST_DIRENTRY(bp);
1040 				/* increment with every buffer read */
1041 				OSAddAtomic64(1, &nfsclntstats.readdir_bios);
1042 			}
1043 			nmrepsave = nmrep;
1044 			dp->d_fileno = cookie; /* placeholder */
1045 			dp->d_seekoff = cookie;
1046 			dp->d_namlen = namlen;
1047 			dp->d_reclen = reclen;
1048 			dp->d_type = DT_UNKNOWN;
1049 			nfsm_chain_get_opaque(error, &nmrep, namlen, dp->d_name);
1050 			nfsmout_if(error);
1051 			dp->d_name[namlen] = '\0';
1052 			if (skiplen) {
1053 				nfsm_chain_adv(error, &nmrep,
1054 				    nfsm_rndup(namlen + skiplen) - nfsm_rndup(namlen));
1055 			}
1056 			nfsmout_if(error);
1057 			nvattrp = rdirplus ? NFS_DIR_BUF_NVATTR(bp, ndbhp->ndbh_count) : nvattr;
1058 			error = nfs4_parsefattr(&nmrep, NULL, nvattrp, fh, NULL, NULL);
1059 			if (!error && NFS_BITMAP_ISSET(nvattrp->nva_bitmap, NFS_FATTR_ACL)) {
1060 				/* we do NOT want ACLs returned to us here */
1061 				NFS_BITMAP_CLR(nvattrp->nva_bitmap, NFS_FATTR_ACL);
1062 				if (nvattrp->nva_acl) {
1063 					kauth_acl_free(nvattrp->nva_acl);
1064 					nvattrp->nva_acl = NULL;
1065 				}
1066 			}
1067 			if (error && NFS_BITMAP_ISSET(nvattrp->nva_bitmap, NFS_FATTR_RDATTR_ERROR)) {
1068 				/* OK, we may not have gotten all of the attributes but we will use what we can. */
1069 				if ((error == NFSERR_MOVED) || (error == NFSERR_INVAL)) {
1070 					/* set this up to look like a referral trigger */
1071 					nfs4_default_attrs_for_referral_trigger(dnp, dp->d_name, namlen, nvattrp, fh);
1072 				}
1073 				error = 0;
1074 			}
1075 			/* check for more entries after this one */
1076 			nfsm_chain_get_32(error, &nmrep, more_entries);
1077 			nfsmout_if(error);
1078 
1079 			/* Skip any "." and ".." entries returned from server. */
1080 			/* Also skip any bothersome named attribute entries. */
1081 			if (((dp->d_name[0] == '.') && ((namlen == 1) || ((namlen == 2) && (dp->d_name[1] == '.')))) ||
1082 			    (namedattr && (namlen == 11) && (!strcmp(dp->d_name, "SUNWattr_ro") || !strcmp(dp->d_name, "SUNWattr_rw")))) {
1083 				lastcookie = cookie;
1084 				continue;
1085 			}
1086 
1087 			if (NFS_BITMAP_ISSET(nvattrp->nva_bitmap, NFS_FATTR_TYPE)) {
1088 				dp->d_type = IFTODT(VTTOIF(nvattrp->nva_type));
1089 			}
1090 			if (NFS_BITMAP_ISSET(nvattrp->nva_bitmap, NFS_FATTR_FILEID)) {
1091 				dp->d_fileno = nvattrp->nva_fileid;
1092 			}
1093 			if (rdirplus) {
1094 				/* fileid is already in d_fileno, so stash xid in attrs */
1095 				nvattrp->nva_fileid = savedxid;
1096 				nvattrp->nva_flags |= NFS_FFLAG_FILEID_CONTAINS_XID;
1097 				if (NFS_BITMAP_ISSET(nvattrp->nva_bitmap, NFS_FATTR_FILEHANDLE)) {
1098 					fhlen = fh->fh_len + 1;
1099 					xlen = fhlen + sizeof(time_t);
1100 					reclen = NFS_DIRENTRY_LEN_16(namlen + xlen);
1101 					space_needed = reclen + attrlen;
1102 					if (space_needed > space_free) {
1103 						/* didn't actually have the room... move on to next buffer */
1104 						nmrep = nmrepsave;
1105 						goto nextbuffer;
1106 					}
1107 					/* pack the file handle into the record */
1108 					dp->d_name[dp->d_namlen + 1] = (unsigned char)fh->fh_len; /* No truncation because fh_len's value is checked during nfs4_parsefattr() */
1109 					bcopy(fh->fh_data, &dp->d_name[dp->d_namlen + 2], fh->fh_len);
1110 				} else {
1111 					/* mark the file handle invalid */
1112 					fh->fh_len = 0;
1113 					fhlen = fh->fh_len + 1;
1114 					xlen = fhlen + sizeof(time_t);
1115 					reclen = NFS_DIRENTRY_LEN_16(namlen + xlen);
1116 					bzero(&dp->d_name[dp->d_namlen + 1], fhlen);
1117 				}
1118 				*(time_t*)(&dp->d_name[dp->d_namlen + 1 + fhlen]) = now.tv_sec;
1119 				dp->d_reclen = reclen;
1120 				nfs_rdirplus_update_node_attrs(dnp, dp, fh, nvattrp, &savedxid);
1121 			}
1122 			padstart = dp->d_name + dp->d_namlen + 1 + xlen;
1123 			ndbhp->ndbh_count++;
1124 			lastcookie = cookie;
1125 
1126 			/* advance to next direntry in buffer */
1127 			dp = NFS_DIRENTRY_NEXT(dp);
1128 			ndbhp->ndbh_entry_end = (char*)dp - bp->nb_data;
1129 			/* zero out the pad bytes */
1130 			padlen = (char*)dp - padstart;
1131 			if (padlen > 0) {
1132 				bzero(padstart, padlen);
1133 			}
1134 		}
1135 		/* Finally, get the eof boolean */
1136 		nfsm_chain_get_32(error, &nmrep, eof);
1137 		nfsmout_if(error);
1138 		if (eof) {
1139 			ndbhp->ndbh_flags |= (NDB_FULL | NDB_EOF);
1140 			nfs_node_lock_force(dnp);
1141 			dnp->n_eofcookie = lastcookie;
1142 			if (rdirplus) {
1143 				dnp->n_rdirplusstamp_eof = now.tv_sec;
1144 			}
1145 			nfs_node_unlock(dnp);
1146 		} else {
1147 			more_entries = 1;
1148 		}
1149 		if (bp_dropped) {
1150 			nfs_buf_release(bp, 0);
1151 			bp = NULL;
1152 			break;
1153 		}
1154 		if ((lockerror = nfs_node_lock(dnp))) {
1155 			error = lockerror;
1156 		}
1157 		nfsmout_if(error);
1158 		nfsm_chain_cleanup(&nmrep);
1159 		nfsm_chain_null(&nmreq);
1160 	}
1161 nfsmout:
1162 	if (bp_dropped && bp) {
1163 		nfs_buf_release(bp, 0);
1164 	}
1165 	if (!lockerror) {
1166 		nfs_node_unlock(dnp);
1167 	}
1168 	nfsm_chain_cleanup(&nmreq);
1169 	nfsm_chain_cleanup(&nmrep);
1170 	NFS_ZFREE(nfs_fhandle_zone, fh);
1171 	zfree(KT_NFS_VATTR, nvattr);
1172 	return bp_dropped ? NFSERR_DIRBUFDROPPED : error;
1173 }
1174 
1175 int
nfs4_lookup_rpc_async(nfsnode_t dnp,char * name,int namelen,vfs_context_t ctx,struct nfsreq ** reqp)1176 nfs4_lookup_rpc_async(
1177 	nfsnode_t dnp,
1178 	char *name,
1179 	int namelen,
1180 	vfs_context_t ctx,
1181 	struct nfsreq **reqp)
1182 {
1183 	int error = 0, isdotdot = 0, nfsvers, numops;
1184 	struct nfsm_chain nmreq;
1185 	uint32_t bitmap[NFS_ATTR_BITMAP_LEN];
1186 	struct nfsmount *nmp;
1187 	struct nfsreq_secinfo_args si;
1188 
1189 	nmp = NFSTONMP(dnp);
1190 	if (nfs_mount_gone(nmp)) {
1191 		return ENXIO;
1192 	}
1193 	nfsvers = nmp->nm_vers;
1194 	if (dnp->n_vattr.nva_flags & NFS_FFLAG_TRIGGER_REFERRAL) {
1195 		return EINVAL;
1196 	}
1197 
1198 	if ((name[0] == '.') && (name[1] == '.') && (namelen == 2)) {
1199 		isdotdot = 1;
1200 		NFSREQ_SECINFO_SET(&si, dnp, NULL, 0, NULL, 0);
1201 	} else {
1202 		NFSREQ_SECINFO_SET(&si, dnp, dnp->n_fhp, dnp->n_fhsize, name, namelen);
1203 	}
1204 
1205 	nfsm_chain_null(&nmreq);
1206 
1207 	// PUTFH, GETATTR, LOOKUP(P), GETFH, GETATTR (FH)
1208 	numops = 5;
1209 	nfsm_chain_build_alloc_init(error, &nmreq, 20 * NFSX_UNSIGNED + namelen);
1210 	nfsm_chain_add_compound_header(error, &nmreq, "lookup", nmp->nm_minor_vers, numops);
1211 	numops--;
1212 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_PUTFH);
1213 	nfsm_chain_add_fh(error, &nmreq, nfsvers, dnp->n_fhp, dnp->n_fhsize);
1214 	numops--;
1215 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_GETATTR);
1216 	nfsm_chain_add_bitmap_supported(error, &nmreq, nfs_getattr_bitmap, nmp, dnp);
1217 	numops--;
1218 	if (isdotdot) {
1219 		nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_LOOKUPP);
1220 	} else {
1221 		nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_LOOKUP);
1222 		nfsm_chain_add_name(error, &nmreq, name, namelen, nmp);
1223 	}
1224 	numops--;
1225 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_GETFH);
1226 	numops--;
1227 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_GETATTR);
1228 	NFS_COPY_ATTRIBUTES(nfs_getattr_bitmap, bitmap);
1229 	/* some ".zfs" directories can't handle being asked for some attributes */
1230 	if ((dnp->n_flag & NISDOTZFS) && !isdotdot) {
1231 		NFS_BITMAP_CLR(bitmap, NFS_FATTR_NAMED_ATTR);
1232 	}
1233 	if ((dnp->n_flag & NISDOTZFSCHILD) && isdotdot) {
1234 		NFS_BITMAP_CLR(bitmap, NFS_FATTR_NAMED_ATTR);
1235 	}
1236 	if (((namelen == 4) && (name[0] == '.') && (name[1] == 'z') && (name[2] == 'f') && (name[3] == 's'))) {
1237 		NFS_BITMAP_CLR(bitmap, NFS_FATTR_NAMED_ATTR);
1238 	}
1239 	nfsm_chain_add_bitmap_supported(error, &nmreq, bitmap, nmp, NULL);
1240 	nfsm_chain_build_done(error, &nmreq);
1241 	nfsm_assert(error, (numops == 0), EPROTO);
1242 	nfsmout_if(error);
1243 	error = nfs_request_async(dnp, NULL, &nmreq, NFSPROC4_COMPOUND,
1244 	    vfs_context_thread(ctx), vfs_context_ucred(ctx), &si, 0, NULL, reqp);
1245 nfsmout:
1246 	nfsm_chain_cleanup(&nmreq);
1247 	return error;
1248 }
1249 
1250 
1251 int
nfs4_lookup_rpc_async_finish(nfsnode_t dnp,char * name,int namelen,vfs_context_t ctx,struct nfsreq * req,u_int64_t * xidp,fhandle_t * fhp,struct nfs_vattr * nvap)1252 nfs4_lookup_rpc_async_finish(
1253 	nfsnode_t dnp,
1254 	char *name,
1255 	int namelen,
1256 	vfs_context_t ctx,
1257 	struct nfsreq *req,
1258 	u_int64_t *xidp,
1259 	fhandle_t *fhp,
1260 	struct nfs_vattr *nvap)
1261 {
1262 	int error = 0, lockerror = ENOENT, status, nfsvers, numops, isdotdot = 0;
1263 	uint32_t op = NFS_OP_LOOKUP;
1264 	u_int64_t xid;
1265 	struct nfsmount *nmp;
1266 	struct nfsm_chain nmrep;
1267 
1268 	nmp = NFSTONMP(dnp);
1269 	if (nmp == NULL) {
1270 		return ENXIO;
1271 	}
1272 	nfsvers = nmp->nm_vers;
1273 	if ((name[0] == '.') && (name[1] == '.') && (namelen == 2)) {
1274 		isdotdot = 1;
1275 	}
1276 
1277 	nfsm_chain_null(&nmrep);
1278 
1279 	error = nfs_request_async_finish(req, &nmrep, &xid, &status);
1280 
1281 	if ((lockerror = nfs_node_lock(dnp))) {
1282 		error = lockerror;
1283 	}
1284 	nfsm_chain_skip_tag(error, &nmrep);
1285 	nfsm_chain_get_32(error, &nmrep, numops);
1286 	nfsm_chain_op_check(error, &nmrep, NFS_OP_PUTFH);
1287 	nfsm_chain_op_check(error, &nmrep, NFS_OP_GETATTR);
1288 	if (xidp) {
1289 		*xidp = xid;
1290 	}
1291 	nfsm_chain_loadattr(error, &nmrep, dnp, nfsvers, &xid);
1292 
1293 	nfsm_chain_op_check(error, &nmrep, (isdotdot ? NFS_OP_LOOKUPP : NFS_OP_LOOKUP));
1294 	nfsmout_if(error || !fhp || !nvap);
1295 	nfsm_chain_op_check(error, &nmrep, NFS_OP_GETFH);
1296 	nfsm_chain_get_32(error, &nmrep, fhp->fh_len);
1297 	if (error == 0 && fhp->fh_len > sizeof(fhp->fh_data)) {
1298 		error = EBADRPC;
1299 	}
1300 	nfsmout_if(error);
1301 	nfsm_chain_get_opaque(error, &nmrep, fhp->fh_len, fhp->fh_data);
1302 	nfsm_chain_op_check(error, &nmrep, NFS_OP_GETATTR);
1303 	if ((error == NFSERR_MOVED) || (error == NFSERR_INVAL)) {
1304 		/* set this up to look like a referral trigger */
1305 		nfs4_default_attrs_for_referral_trigger(dnp, name, namelen, nvap, fhp);
1306 		error = 0;
1307 	} else {
1308 		nfsmout_if(error);
1309 		error = nfs4_parsefattr(&nmrep, NULL, nvap, NULL, NULL, NULL);
1310 	}
1311 nfsmout:
1312 	if (!lockerror) {
1313 		nfs_node_unlock(dnp);
1314 	}
1315 	nfsm_chain_cleanup(&nmrep);
1316 	if (!error && (op == NFS_OP_LOOKUP) && (nmp->nm_state & NFSSTA_NEEDSECINFO)) {
1317 		/* We still need to get SECINFO to set default for mount. */
1318 		/* Do so for the first LOOKUP that returns successfully. */
1319 		struct nfs_sec sec;
1320 
1321 		sec.count = NX_MAX_SEC_FLAVORS;
1322 		error = nfs4_secinfo_rpc(nmp, &req->r_secinfo, vfs_context_ucred(ctx), sec.flavors, &sec.count);
1323 		/* [sigh] some implementations return "illegal" error for unsupported ops */
1324 		if (error == NFSERR_OP_ILLEGAL) {
1325 			error = 0;
1326 		}
1327 		if (!error) {
1328 			/* set our default security flavor to the first in the list */
1329 			lck_mtx_lock(&nmp->nm_lock);
1330 			if (sec.count) {
1331 				nmp->nm_auth = sec.flavors[0];
1332 			}
1333 			nmp->nm_state &= ~NFSSTA_NEEDSECINFO;
1334 			lck_mtx_unlock(&nmp->nm_lock);
1335 		}
1336 	}
1337 	return error;
1338 }
1339 
1340 int
nfs4_commit_rpc(nfsnode_t np,uint64_t offset,uint64_t count,kauth_cred_t cred,uint64_t wverf)1341 nfs4_commit_rpc(
1342 	nfsnode_t np,
1343 	uint64_t offset,
1344 	uint64_t count,
1345 	kauth_cred_t cred,
1346 	uint64_t wverf)
1347 {
1348 	struct nfsmount *nmp;
1349 	int error = 0, lockerror, status, nfsvers, numops;
1350 	u_int64_t xid, newwverf;
1351 	uint32_t count32;
1352 	struct nfsm_chain nmreq, nmrep;
1353 	struct nfsreq_secinfo_args si;
1354 
1355 	nmp = NFSTONMP(np);
1356 	FSDBG(521, np, offset, count, nmp ? nmp->nm_state : 0);
1357 	if (nfs_mount_gone(nmp)) {
1358 		return ENXIO;
1359 	}
1360 	if (np->n_vattr.nva_flags & NFS_FFLAG_TRIGGER_REFERRAL) {
1361 		return EINVAL;
1362 	}
1363 	if (!(nmp->nm_state & NFSSTA_HASWRITEVERF)) {
1364 		return 0;
1365 	}
1366 	nfsvers = nmp->nm_vers;
1367 	count32 = count > UINT32_MAX ? 0 : (uint32_t)count;
1368 
1369 	NFSREQ_SECINFO_SET(&si, np, NULL, 0, NULL, 0);
1370 	nfsm_chain_null(&nmreq);
1371 	nfsm_chain_null(&nmrep);
1372 
1373 	// PUTFH, COMMIT, GETATTR
1374 	numops = 3;
1375 	nfsm_chain_build_alloc_init(error, &nmreq, 19 * NFSX_UNSIGNED);
1376 	nfsm_chain_add_compound_header(error, &nmreq, "commit", nmp->nm_minor_vers, numops);
1377 	numops--;
1378 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_PUTFH);
1379 	nfsm_chain_add_fh(error, &nmreq, nfsvers, np->n_fhp, np->n_fhsize);
1380 	numops--;
1381 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_COMMIT);
1382 	nfsm_chain_add_64(error, &nmreq, offset);
1383 	nfsm_chain_add_32(error, &nmreq, count32);
1384 	numops--;
1385 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_GETATTR);
1386 	nfsm_chain_add_bitmap_supported(error, &nmreq, nfs_getattr_bitmap, nmp, np);
1387 	nfsm_chain_build_done(error, &nmreq);
1388 	nfsm_assert(error, (numops == 0), EPROTO);
1389 	nfsmout_if(error);
1390 	error = nfs_request2(np, NULL, &nmreq, NFSPROC4_COMPOUND,
1391 	    current_thread(), cred, &si, 0, &nmrep, &xid, &status);
1392 
1393 	if ((lockerror = nfs_node_lock(np))) {
1394 		error = lockerror;
1395 	}
1396 	nfsm_chain_skip_tag(error, &nmrep);
1397 	nfsm_chain_get_32(error, &nmrep, numops);
1398 	nfsm_chain_op_check(error, &nmrep, NFS_OP_PUTFH);
1399 	nfsm_chain_op_check(error, &nmrep, NFS_OP_COMMIT);
1400 	nfsm_chain_get_64(error, &nmrep, newwverf);
1401 	nfsm_chain_op_check(error, &nmrep, NFS_OP_GETATTR);
1402 	nfsm_chain_loadattr(error, &nmrep, np, nfsvers, &xid);
1403 	if (!lockerror) {
1404 		nfs_node_unlock(np);
1405 	}
1406 	nfsmout_if(error);
1407 	lck_mtx_lock(&nmp->nm_lock);
1408 	if (nmp->nm_verf != newwverf) {
1409 		nmp->nm_verf = newwverf;
1410 	}
1411 	if (wverf != newwverf) {
1412 		error = NFSERR_STALEWRITEVERF;
1413 	}
1414 	lck_mtx_unlock(&nmp->nm_lock);
1415 nfsmout:
1416 	nfsm_chain_cleanup(&nmreq);
1417 	nfsm_chain_cleanup(&nmrep);
1418 	return error;
1419 }
1420 
1421 int
nfs4_pathconf_rpc(nfsnode_t np,struct nfs_fsattr * nfsap,vfs_context_t ctx)1422 nfs4_pathconf_rpc(
1423 	nfsnode_t np,
1424 	struct nfs_fsattr *nfsap,
1425 	vfs_context_t ctx)
1426 {
1427 	u_int64_t xid;
1428 	int error = 0, lockerror, status, nfsvers, numops;
1429 	struct nfsm_chain nmreq, nmrep;
1430 	struct nfsmount *nmp = NFSTONMP(np);
1431 	uint32_t bitmap[NFS_ATTR_BITMAP_LEN];
1432 	struct nfs_vattr *nvattr;
1433 	struct nfsreq_secinfo_args si;
1434 
1435 	if (nfs_mount_gone(nmp)) {
1436 		return ENXIO;
1437 	}
1438 	nfsvers = nmp->nm_vers;
1439 	if (np->n_vattr.nva_flags & NFS_FFLAG_TRIGGER_REFERRAL) {
1440 		return EINVAL;
1441 	}
1442 
1443 	NFSREQ_SECINFO_SET(&si, np, NULL, 0, NULL, 0);
1444 	nvattr = zalloc_flags(KT_NFS_VATTR, Z_WAITOK);
1445 	NVATTR_INIT(nvattr);
1446 	nfsm_chain_null(&nmreq);
1447 	nfsm_chain_null(&nmrep);
1448 
1449 	/* NFSv4: fetch "pathconf" info for this node */
1450 	// PUTFH, GETATTR
1451 	numops = 2;
1452 	nfsm_chain_build_alloc_init(error, &nmreq, 16 * NFSX_UNSIGNED);
1453 	nfsm_chain_add_compound_header(error, &nmreq, "pathconf", nmp->nm_minor_vers, numops);
1454 	numops--;
1455 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_PUTFH);
1456 	nfsm_chain_add_fh(error, &nmreq, nfsvers, np->n_fhp, np->n_fhsize);
1457 	numops--;
1458 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_GETATTR);
1459 	NFS_COPY_ATTRIBUTES(nfs_getattr_bitmap, bitmap);
1460 	NFS_BITMAP_SET(bitmap, NFS_FATTR_MAXLINK);
1461 	NFS_BITMAP_SET(bitmap, NFS_FATTR_MAXNAME);
1462 	NFS_BITMAP_SET(bitmap, NFS_FATTR_NO_TRUNC);
1463 	NFS_BITMAP_SET(bitmap, NFS_FATTR_CHOWN_RESTRICTED);
1464 	NFS_BITMAP_SET(bitmap, NFS_FATTR_CASE_INSENSITIVE);
1465 	NFS_BITMAP_SET(bitmap, NFS_FATTR_CASE_PRESERVING);
1466 	nfsm_chain_add_bitmap_supported(error, &nmreq, bitmap, nmp, np);
1467 	nfsm_chain_build_done(error, &nmreq);
1468 	nfsm_assert(error, (numops == 0), EPROTO);
1469 	nfsmout_if(error);
1470 	error = nfs_request(np, NULL, &nmreq, NFSPROC4_COMPOUND, ctx, &si, &nmrep, &xid, &status);
1471 
1472 	nfsm_chain_skip_tag(error, &nmrep);
1473 	nfsm_chain_get_32(error, &nmrep, numops);
1474 	nfsm_chain_op_check(error, &nmrep, NFS_OP_PUTFH);
1475 	nfsm_chain_op_check(error, &nmrep, NFS_OP_GETATTR);
1476 	nfsmout_if(error);
1477 	error = nfs4_parsefattr(&nmrep, nfsap, nvattr, NULL, NULL, NULL);
1478 	nfsmout_if(error);
1479 	if ((lockerror = nfs_node_lock(np))) {
1480 		error = lockerror;
1481 	}
1482 	if (!error) {
1483 		nfs_loadattrcache(np, nvattr, &xid, 0);
1484 	}
1485 	if (!lockerror) {
1486 		nfs_node_unlock(np);
1487 	}
1488 nfsmout:
1489 	NVATTR_CLEANUP(nvattr);
1490 	zfree(KT_NFS_VATTR, nvattr);
1491 	nfsm_chain_cleanup(&nmreq);
1492 	nfsm_chain_cleanup(&nmrep);
1493 	return error;
1494 }
1495 
1496 int
nfs4_vnop_getattr(struct vnop_getattr_args * ap)1497 nfs4_vnop_getattr(
1498 	struct vnop_getattr_args /* {
1499                                   *  struct vnodeop_desc *a_desc;
1500                                   *  vnode_t a_vp;
1501                                   *  struct vnode_attr *a_vap;
1502                                   *  vfs_context_t a_context;
1503                                   *  } */*ap)
1504 {
1505 	struct vnode_attr *vap = ap->a_vap;
1506 	struct nfsmount *nmp;
1507 	struct nfs_vattr *nva;
1508 	int error, acls, ngaflags;
1509 
1510 	nmp = VTONMP(ap->a_vp);
1511 	if (nfs_mount_gone(nmp)) {
1512 		return ENXIO;
1513 	}
1514 	acls = (nmp->nm_fsattr.nfsa_flags & NFS_FSFLAG_ACL);
1515 
1516 	ngaflags = NGA_CACHED;
1517 	if (VATTR_IS_ACTIVE(vap, va_acl) && acls) {
1518 		ngaflags |= NGA_ACL;
1519 	}
1520 	nva = zalloc_flags(KT_NFS_VATTR, Z_WAITOK);
1521 	error = nfs_getattr(VTONFS(ap->a_vp), nva, ap->a_context, ngaflags);
1522 	if (error) {
1523 		goto out;
1524 	}
1525 
1526 	/* copy what we have in nva to *a_vap */
1527 	if (VATTR_IS_ACTIVE(vap, va_rdev) && NFS_BITMAP_ISSET(nva->nva_bitmap, NFS_FATTR_RAWDEV)) {
1528 		dev_t rdev = makedev(nva->nva_rawdev.specdata1, nva->nva_rawdev.specdata2);
1529 		VATTR_RETURN(vap, va_rdev, rdev);
1530 	}
1531 	if (VATTR_IS_ACTIVE(vap, va_nlink) && NFS_BITMAP_ISSET(nva->nva_bitmap, NFS_FATTR_NUMLINKS)) {
1532 		VATTR_RETURN(vap, va_nlink, nva->nva_nlink);
1533 	}
1534 	if (VATTR_IS_ACTIVE(vap, va_data_size) && NFS_BITMAP_ISSET(nva->nva_bitmap, NFS_FATTR_SIZE)) {
1535 		VATTR_RETURN(vap, va_data_size, nva->nva_size);
1536 	}
1537 	// VATTR_RETURN(vap, va_data_alloc, ???);
1538 	// VATTR_RETURN(vap, va_total_size, ???);
1539 	if (VATTR_IS_ACTIVE(vap, va_total_alloc) && NFS_BITMAP_ISSET(nva->nva_bitmap, NFS_FATTR_SPACE_USED)) {
1540 		VATTR_RETURN(vap, va_total_alloc, nva->nva_bytes);
1541 	}
1542 	if (VATTR_IS_ACTIVE(vap, va_uid) && NFS_BITMAP_ISSET(nva->nva_bitmap, NFS_FATTR_OWNER)) {
1543 		VATTR_RETURN(vap, va_uid, nva->nva_uid);
1544 	}
1545 	if (VATTR_IS_ACTIVE(vap, va_uuuid) && NFS_BITMAP_ISSET(nva->nva_bitmap, NFS_FATTR_OWNER)) {
1546 		VATTR_RETURN(vap, va_uuuid, nva->nva_uuuid);
1547 	}
1548 	if (VATTR_IS_ACTIVE(vap, va_gid) && NFS_BITMAP_ISSET(nva->nva_bitmap, NFS_FATTR_OWNER_GROUP)) {
1549 		VATTR_RETURN(vap, va_gid, nva->nva_gid);
1550 	}
1551 	if (VATTR_IS_ACTIVE(vap, va_guuid) && NFS_BITMAP_ISSET(nva->nva_bitmap, NFS_FATTR_OWNER_GROUP)) {
1552 		VATTR_RETURN(vap, va_guuid, nva->nva_guuid);
1553 	}
1554 	if (VATTR_IS_ACTIVE(vap, va_mode)) {
1555 		if (NMFLAG(nmp, ACLONLY) || !NFS_BITMAP_ISSET(nva->nva_bitmap, NFS_FATTR_MODE)) {
1556 			VATTR_RETURN(vap, va_mode, ACCESSPERMS);
1557 		} else {
1558 			VATTR_RETURN(vap, va_mode, nva->nva_mode);
1559 		}
1560 	}
1561 	if (VATTR_IS_ACTIVE(vap, va_flags) &&
1562 	    (NFS_BITMAP_ISSET(nva->nva_bitmap, NFS_FATTR_ARCHIVE) ||
1563 	    NFS_BITMAP_ISSET(nva->nva_bitmap, NFS_FATTR_HIDDEN) ||
1564 	    (nva->nva_flags & NFS_FFLAG_TRIGGER))) {
1565 		uint32_t flags = 0;
1566 		if (NFS_BITMAP_ISSET(nva->nva_bitmap, NFS_FATTR_ARCHIVE) &&
1567 		    (nva->nva_flags & NFS_FFLAG_ARCHIVED)) {
1568 			flags |= SF_ARCHIVED;
1569 		}
1570 		if (NFS_BITMAP_ISSET(nva->nva_bitmap, NFS_FATTR_HIDDEN) &&
1571 		    (nva->nva_flags & NFS_FFLAG_HIDDEN)) {
1572 			flags |= UF_HIDDEN;
1573 		}
1574 		VATTR_RETURN(vap, va_flags, flags);
1575 	}
1576 	if (VATTR_IS_ACTIVE(vap, va_create_time) && NFS_BITMAP_ISSET(nva->nva_bitmap, NFS_FATTR_TIME_CREATE)) {
1577 		vap->va_create_time.tv_sec = nva->nva_timesec[NFSTIME_CREATE];
1578 		vap->va_create_time.tv_nsec = nva->nva_timensec[NFSTIME_CREATE];
1579 		VATTR_SET_SUPPORTED(vap, va_create_time);
1580 	}
1581 	if (VATTR_IS_ACTIVE(vap, va_access_time) && NFS_BITMAP_ISSET(nva->nva_bitmap, NFS_FATTR_TIME_ACCESS)) {
1582 		vap->va_access_time.tv_sec = nva->nva_timesec[NFSTIME_ACCESS];
1583 		vap->va_access_time.tv_nsec = nva->nva_timensec[NFSTIME_ACCESS];
1584 		VATTR_SET_SUPPORTED(vap, va_access_time);
1585 	}
1586 	if (VATTR_IS_ACTIVE(vap, va_modify_time) && NFS_BITMAP_ISSET(nva->nva_bitmap, NFS_FATTR_TIME_MODIFY)) {
1587 		vap->va_modify_time.tv_sec = nva->nva_timesec[NFSTIME_MODIFY];
1588 		vap->va_modify_time.tv_nsec = nva->nva_timensec[NFSTIME_MODIFY];
1589 		VATTR_SET_SUPPORTED(vap, va_modify_time);
1590 	}
1591 	if (VATTR_IS_ACTIVE(vap, va_change_time) && NFS_BITMAP_ISSET(nva->nva_bitmap, NFS_FATTR_TIME_METADATA)) {
1592 		vap->va_change_time.tv_sec = nva->nva_timesec[NFSTIME_CHANGE];
1593 		vap->va_change_time.tv_nsec = nva->nva_timensec[NFSTIME_CHANGE];
1594 		VATTR_SET_SUPPORTED(vap, va_change_time);
1595 	}
1596 	if (VATTR_IS_ACTIVE(vap, va_backup_time) && NFS_BITMAP_ISSET(nva->nva_bitmap, NFS_FATTR_TIME_BACKUP)) {
1597 		vap->va_backup_time.tv_sec = nva->nva_timesec[NFSTIME_BACKUP];
1598 		vap->va_backup_time.tv_nsec = nva->nva_timensec[NFSTIME_BACKUP];
1599 		VATTR_SET_SUPPORTED(vap, va_backup_time);
1600 	}
1601 	if (VATTR_IS_ACTIVE(vap, va_fileid) && NFS_BITMAP_ISSET(nva->nva_bitmap, NFS_FATTR_FILEID)) {
1602 		VATTR_RETURN(vap, va_fileid, nva->nva_fileid);
1603 	}
1604 	if (VATTR_IS_ACTIVE(vap, va_type) && NFS_BITMAP_ISSET(nva->nva_bitmap, NFS_FATTR_TYPE)) {
1605 		VATTR_RETURN(vap, va_type, nva->nva_type);
1606 	}
1607 	if (VATTR_IS_ACTIVE(vap, va_filerev) && NFS_BITMAP_ISSET(nva->nva_bitmap, NFS_FATTR_CHANGE)) {
1608 		VATTR_RETURN(vap, va_filerev, nva->nva_change);
1609 	}
1610 
1611 	if (VATTR_IS_ACTIVE(vap, va_acl) && acls) {
1612 		VATTR_RETURN(vap, va_acl, nva->nva_acl);
1613 		nva->nva_acl = NULL;
1614 	}
1615 
1616 	// other attrs we might support someday:
1617 	// VATTR_RETURN(vap, va_encoding, ??? /* potentially unnormalized UTF-8? */);
1618 
1619 	NVATTR_CLEANUP(nva);
1620 out:
1621 	zfree(KT_NFS_VATTR, nva);
1622 	return NFS_MAPERR(error);
1623 }
1624 
1625 int
nfs4_setattr_rpc(nfsnode_t np,struct vnode_attr * vap,vfs_context_t ctx)1626 nfs4_setattr_rpc(
1627 	nfsnode_t np,
1628 	struct vnode_attr *vap,
1629 	vfs_context_t ctx)
1630 {
1631 	struct nfsmount *nmp = NFSTONMP(np);
1632 	int error = 0, setattr_error = 0, lockerror = ENOENT, status, nfsvers, numops;
1633 	u_int64_t xid, nextxid;
1634 	struct nfsm_chain nmreq, nmrep;
1635 	uint32_t bitmap[NFS_ATTR_BITMAP_LEN], bmlen;
1636 	uint32_t getbitmap[NFS_ATTR_BITMAP_LEN];
1637 	uint32_t setbitmap[NFS_ATTR_BITMAP_LEN];
1638 	nfs_stateid stateid;
1639 	struct nfsreq_secinfo_args si;
1640 
1641 	if (nfs_mount_gone(nmp)) {
1642 		return ENXIO;
1643 	}
1644 	bzero(&setbitmap, sizeof(setbitmap));
1645 	nfsvers = nmp->nm_vers;
1646 	if (np->n_vattr.nva_flags & NFS_FFLAG_TRIGGER_REFERRAL) {
1647 		return EINVAL;
1648 	}
1649 
1650 	if (VATTR_IS_ACTIVE(vap, va_flags) && (vap->va_flags & ~(SF_ARCHIVED | UF_HIDDEN))) {
1651 		/* we don't support setting unsupported flags (duh!) */
1652 		if (vap->va_active & ~VNODE_ATTR_va_flags) {
1653 			return EINVAL;        /* return EINVAL if other attributes also set */
1654 		} else {
1655 			return ENOTSUP;       /* return ENOTSUP for chflags(2) */
1656 		}
1657 	}
1658 
1659 	/* don't bother requesting some changes if they don't look like they are changing */
1660 	if (VATTR_IS_ACTIVE(vap, va_uid) && (vap->va_uid == np->n_vattr.nva_uid)) {
1661 		VATTR_CLEAR_ACTIVE(vap, va_uid);
1662 	}
1663 	if (VATTR_IS_ACTIVE(vap, va_gid) && (vap->va_gid == np->n_vattr.nva_gid)) {
1664 		VATTR_CLEAR_ACTIVE(vap, va_gid);
1665 	}
1666 	if (VATTR_IS_ACTIVE(vap, va_uuuid) && kauth_guid_equal(&vap->va_uuuid, &np->n_vattr.nva_uuuid)) {
1667 		VATTR_CLEAR_ACTIVE(vap, va_uuuid);
1668 	}
1669 	if (VATTR_IS_ACTIVE(vap, va_guuid) && kauth_guid_equal(&vap->va_guuid, &np->n_vattr.nva_guuid)) {
1670 		VATTR_CLEAR_ACTIVE(vap, va_guuid);
1671 	}
1672 
1673 tryagain:
1674 	/* do nothing if no attributes will be sent */
1675 	nfs_vattr_set_bitmap(nmp, bitmap, vap);
1676 	if (!bitmap[0] && !bitmap[1]) {
1677 		return 0;
1678 	}
1679 
1680 	NFSREQ_SECINFO_SET(&si, np, NULL, 0, NULL, 0);
1681 	nfsm_chain_null(&nmreq);
1682 	nfsm_chain_null(&nmrep);
1683 
1684 	/*
1685 	 * Prepare GETATTR bitmap: if we are setting the ACL or mode, we
1686 	 * need to invalidate any cached ACL.  And if we had an ACL cached,
1687 	 * we might as well also fetch the new value.
1688 	 */
1689 	NFS_COPY_ATTRIBUTES(nfs_getattr_bitmap, getbitmap);
1690 	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_ACL) ||
1691 	    NFS_BITMAP_ISSET(bitmap, NFS_FATTR_MODE)) {
1692 		if (NACLVALID(np)) {
1693 			NFS_BITMAP_SET(getbitmap, NFS_FATTR_ACL);
1694 		}
1695 		NACLINVALIDATE(np);
1696 	}
1697 
1698 	// PUTFH, SETATTR, GETATTR
1699 	numops = 3;
1700 	nfsm_chain_build_alloc_init(error, &nmreq, 40 * NFSX_UNSIGNED);
1701 	nfsm_chain_add_compound_header(error, &nmreq, "setattr", nmp->nm_minor_vers, numops);
1702 	numops--;
1703 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_PUTFH);
1704 	nfsm_chain_add_fh(error, &nmreq, nfsvers, np->n_fhp, np->n_fhsize);
1705 	numops--;
1706 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_SETATTR);
1707 	if (VATTR_IS_ACTIVE(vap, va_data_size)) {
1708 		nfs_get_stateid(np, vfs_context_thread(ctx), vfs_context_ucred(ctx), &stateid, 1);
1709 	} else {
1710 		stateid.seqid = stateid.other[0] = stateid.other[1] = stateid.other[2] = 0;
1711 	}
1712 	nfsm_chain_add_stateid(error, &nmreq, &stateid);
1713 	nfsm_chain_add_fattr4(error, &nmreq, vap, nmp);
1714 	numops--;
1715 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_GETATTR);
1716 	nfsm_chain_add_bitmap_supported(error, &nmreq, getbitmap, nmp, np);
1717 	nfsm_chain_build_done(error, &nmreq);
1718 	nfsm_assert(error, (numops == 0), EPROTO);
1719 	nfsmout_if(error);
1720 	error = nfs_request(np, NULL, &nmreq, NFSPROC4_COMPOUND, ctx, &si, &nmrep, &xid, &status);
1721 
1722 	if ((lockerror = nfs_node_lock(np))) {
1723 		error = lockerror;
1724 	}
1725 	nfsm_chain_skip_tag(error, &nmrep);
1726 	nfsm_chain_get_32(error, &nmrep, numops);
1727 	nfsm_chain_op_check(error, &nmrep, NFS_OP_PUTFH);
1728 	nfsmout_if(error);
1729 	nfsm_chain_op_check(error, &nmrep, NFS_OP_SETATTR);
1730 	nfsmout_if(error == EBADRPC);
1731 	setattr_error = error;
1732 	error = 0;
1733 	bmlen = NFS_ATTR_BITMAP_LEN;
1734 	nfsm_chain_get_bitmap(error, &nmrep, setbitmap, bmlen);
1735 	if (!error) {
1736 		if (VATTR_IS_ACTIVE(vap, va_data_size) && (np->n_vattr.nva_flags & NFS_FFLAG_IS_ATTR)) {
1737 			microuptime(&np->n_lastio);
1738 		}
1739 		nfs_vattr_set_supported(setbitmap, vap);
1740 		error = setattr_error;
1741 	}
1742 	nfsm_chain_op_check(error, &nmrep, NFS_OP_GETATTR);
1743 	nfsm_chain_loadattr(error, &nmrep, np, nfsvers, &xid);
1744 	if (error) {
1745 		NATTRINVALIDATE(np);
1746 	}
1747 	/*
1748 	 * We just changed the attributes and we want to make sure that we
1749 	 * see the latest attributes.  Get the next XID.  If it's not the
1750 	 * next XID after the SETATTR XID, then it's possible that another
1751 	 * RPC was in flight at the same time and it might put stale attributes
1752 	 * in the cache.  In that case, we invalidate the attributes and set
1753 	 * the attribute cache XID to guarantee that newer attributes will
1754 	 * get loaded next.
1755 	 */
1756 	nextxid = 0;
1757 	nfs_get_xid(&nextxid);
1758 	if (nextxid != (xid + 1)) {
1759 		np->n_xid = nextxid;
1760 		NATTRINVALIDATE(np);
1761 	}
1762 nfsmout:
1763 	if (!lockerror) {
1764 		nfs_node_unlock(np);
1765 	}
1766 	nfsm_chain_cleanup(&nmreq);
1767 	nfsm_chain_cleanup(&nmrep);
1768 	if ((setattr_error == EINVAL) && VATTR_IS_ACTIVE(vap, va_acl) && VATTR_IS_ACTIVE(vap, va_mode) && !NMFLAG(nmp, ACLONLY)) {
1769 		/*
1770 		 * Some server's may not like ACL/mode combos that get sent.
1771 		 * If it looks like that's what the server choked on, try setting
1772 		 * just the ACL and not the mode (unless it looks like everything
1773 		 * but mode was already successfully set).
1774 		 */
1775 		if (((bitmap[0] & setbitmap[0]) != bitmap[0]) ||
1776 		    ((bitmap[1] & (setbitmap[1] | NFS_FATTR_MODE)) != bitmap[1])) {
1777 			VATTR_CLEAR_ACTIVE(vap, va_mode);
1778 			error = 0;
1779 			goto tryagain;
1780 		}
1781 	}
1782 	return error;
1783 }
1784 #endif /* CONFIG_NFS4 */
1785 
1786 /*
1787  * Wait for any pending recovery to complete.
1788  */
1789 int
nfs_mount_state_wait_for_recovery(struct nfsmount * nmp)1790 nfs_mount_state_wait_for_recovery(struct nfsmount *nmp)
1791 {
1792 	struct timespec ts = { .tv_sec = 1, .tv_nsec = 0 };
1793 	int error = 0, slpflag = NMFLAG(nmp, INTR) ? PCATCH : 0;
1794 
1795 	lck_mtx_lock(&nmp->nm_lock);
1796 	while (nmp->nm_state & NFSSTA_RECOVER) {
1797 		if ((error = nfs_sigintr(nmp, NULL, current_thread(), 1))) {
1798 			break;
1799 		}
1800 		nfs_mount_sock_thread_wake(nmp);
1801 		msleep(&nmp->nm_state, &nmp->nm_lock, slpflag | (PZERO - 1), "nfsrecoverwait", &ts);
1802 		slpflag = 0;
1803 	}
1804 	lck_mtx_unlock(&nmp->nm_lock);
1805 
1806 	return error;
1807 }
1808 
1809 /*
1810  * We're about to use/manipulate NFS mount's open/lock state.
1811  * Wait for any pending state recovery to complete, then
1812  * mark the state as being in use (which will hold off
1813  * the recovery thread until we're done).
1814  */
1815 int
nfs_mount_state_in_use_start(struct nfsmount * nmp,thread_t thd)1816 nfs_mount_state_in_use_start(struct nfsmount *nmp, thread_t thd)
1817 {
1818 	struct timespec ts = { .tv_sec = 1, .tv_nsec = 0 };
1819 	int error = 0, slpflag = (NMFLAG(nmp, INTR) && thd) ? PCATCH : 0;
1820 
1821 	if (nfs_mount_gone(nmp)) {
1822 		return ENXIO;
1823 	}
1824 	lck_mtx_lock(&nmp->nm_lock);
1825 	if (nmp->nm_state & (NFSSTA_FORCE | NFSSTA_DEAD)) {
1826 		lck_mtx_unlock(&nmp->nm_lock);
1827 		return ENXIO;
1828 	}
1829 	while (nmp->nm_state & NFSSTA_RECOVER) {
1830 		if ((error = nfs_sigintr(nmp, NULL, thd, 1))) {
1831 			break;
1832 		}
1833 		nfs_mount_sock_thread_wake(nmp);
1834 		msleep(&nmp->nm_state, &nmp->nm_lock, slpflag | (PZERO - 1), "nfsrecoverwait", &ts);
1835 		slpflag = 0;
1836 	}
1837 	if (!error) {
1838 		nmp->nm_stateinuse++;
1839 	}
1840 	lck_mtx_unlock(&nmp->nm_lock);
1841 
1842 	return error;
1843 }
1844 
1845 /*
1846  * We're done using/manipulating the NFS mount's open/lock
1847  * state.  If the given error indicates that recovery should
1848  * be performed, we'll initiate recovery.
1849  */
1850 int
nfs_mount_state_in_use_end(struct nfsmount * nmp,int error)1851 nfs_mount_state_in_use_end(struct nfsmount *nmp, int error)
1852 {
1853 	int restart = nfs_mount_state_error_should_restart(error);
1854 
1855 	if (nfs_mount_gone(nmp)) {
1856 		return ENXIO;
1857 	}
1858 	lck_mtx_lock(&nmp->nm_lock);
1859 	if (restart && (error != NFSERR_OLD_STATEID) && (error != NFSERR_GRACE)) {
1860 		printf("nfs_mount_state_in_use_end: error %d, initiating recovery for %s, 0x%x\n",
1861 		    error, vfs_statfs(nmp->nm_mountp)->f_mntfromname, nmp->nm_stategenid);
1862 		nfs_need_recover(nmp, error);
1863 	}
1864 	if (nmp->nm_stateinuse > 0) {
1865 		nmp->nm_stateinuse--;
1866 	} else {
1867 		panic("NFS mount state in use count underrun");
1868 	}
1869 	if (!nmp->nm_stateinuse && (nmp->nm_state & NFSSTA_RECOVER)) {
1870 		wakeup(&nmp->nm_stateinuse);
1871 	}
1872 	lck_mtx_unlock(&nmp->nm_lock);
1873 	if (error == NFSERR_GRACE) {
1874 		tsleep(&nmp->nm_state, (PZERO - 1), "nfsgrace", 2 * hz);
1875 	}
1876 
1877 	return restart;
1878 }
1879 
1880 /*
1881  * Does the error mean we should restart/redo a state-related operation?
1882  */
1883 int
nfs_mount_state_error_should_restart(int error)1884 nfs_mount_state_error_should_restart(int error)
1885 {
1886 	switch (error) {
1887 	case NFSERR_STALE_STATEID:
1888 	case NFSERR_STALE_CLIENTID:
1889 	case NFSERR_ADMIN_REVOKED:
1890 	case NFSERR_EXPIRED:
1891 	case NFSERR_OLD_STATEID:
1892 	case NFSERR_BAD_STATEID:
1893 	case NFSERR_GRACE:
1894 		return 1;
1895 	}
1896 	return 0;
1897 }
1898 
1899 /*
1900  * In some cases we may want to limit how many times we restart a
1901  * state-related operation - e.g. we're repeatedly getting NFSERR_GRACE.
1902  * Base the limit on the lease (as long as it's not too short).
1903  */
1904 uint
nfs_mount_state_max_restarts(struct nfsmount * nmp)1905 nfs_mount_state_max_restarts(struct nfsmount *nmp)
1906 {
1907 	return MAX(nmp->nm_fsattr.nfsa_lease, 60);
1908 }
1909 
1910 /*
1911  * Does the error mean we probably lost a delegation?
1912  */
1913 int
nfs_mount_state_error_delegation_lost(int error)1914 nfs_mount_state_error_delegation_lost(int error)
1915 {
1916 	switch (error) {
1917 	case NFSERR_STALE_STATEID:
1918 	case NFSERR_ADMIN_REVOKED:
1919 	case NFSERR_EXPIRED:
1920 	case NFSERR_OLD_STATEID:
1921 	case NFSERR_BAD_STATEID:
1922 	case NFSERR_GRACE: /* ugh! (stupid) RFC 3530 specifically disallows CLAIM_DELEGATE_CUR during grace period? */
1923 		return 1;
1924 	}
1925 	return 0;
1926 }
1927 
1928 
1929 /*
1930  * Mark an NFS node's open state as busy.
1931  */
1932 int
nfs_open_state_set_busy(nfsnode_t np,thread_t thd)1933 nfs_open_state_set_busy(nfsnode_t np, thread_t thd)
1934 {
1935 	struct nfsmount *nmp;
1936 	struct timespec ts = { .tv_sec = 2, .tv_nsec = 0 };
1937 	int error = 0, slpflag;
1938 
1939 	nmp = NFSTONMP(np);
1940 	if (nfs_mount_gone(nmp)) {
1941 		return ENXIO;
1942 	}
1943 	slpflag = (NMFLAG(nmp, INTR) && thd) ? PCATCH : 0;
1944 
1945 	lck_mtx_lock(&np->n_openlock);
1946 	while (np->n_openflags & N_OPENBUSY) {
1947 		if ((error = nfs_sigintr(nmp, NULL, thd, 0))) {
1948 			break;
1949 		}
1950 		np->n_openflags |= N_OPENWANT;
1951 		msleep(&np->n_openflags, &np->n_openlock, slpflag, "nfs_open_state_set_busy", &ts);
1952 		slpflag = 0;
1953 	}
1954 	if (!error) {
1955 		np->n_openflags |= N_OPENBUSY;
1956 	}
1957 	lck_mtx_unlock(&np->n_openlock);
1958 
1959 	return error;
1960 }
1961 
1962 /*
1963  * Clear an NFS node's open state busy flag and wake up
1964  * anyone wanting it.
1965  */
1966 void
nfs_open_state_clear_busy(nfsnode_t np)1967 nfs_open_state_clear_busy(nfsnode_t np)
1968 {
1969 	int wanted;
1970 
1971 	lck_mtx_lock(&np->n_openlock);
1972 	if (!(np->n_openflags & N_OPENBUSY)) {
1973 		panic("nfs_open_state_clear_busy");
1974 	}
1975 	wanted = (np->n_openflags & N_OPENWANT);
1976 	np->n_openflags &= ~(N_OPENBUSY | N_OPENWANT);
1977 	lck_mtx_unlock(&np->n_openlock);
1978 	if (wanted) {
1979 		wakeup(&np->n_openflags);
1980 	}
1981 }
1982 
1983 static int
use_open_owner(uid_t uid1,pid_t pid1,uid_t uid2,pid_t pid2,int split_open_owner)1984 use_open_owner(uid_t uid1, pid_t pid1, uid_t uid2, pid_t pid2, int split_open_owner)
1985 {
1986 	if (uid1 != uid2) {
1987 		return 0;
1988 	}
1989 	if (!split_open_owner) {
1990 		return 1;
1991 	}
1992 
1993 	return pid1 == pid2;
1994 }
1995 /*
1996  * Search a mount's open owner list for the owner for this credential.
1997  * If not found and "alloc" is set, then allocate a new one.
1998  */
1999 struct nfs_open_owner *
nfs_open_owner_find(struct nfsmount * nmp,kauth_cred_t cred,proc_t p,int alloc)2000 nfs_open_owner_find(struct nfsmount *nmp, kauth_cred_t cred, proc_t p, int alloc)
2001 {
2002 	pid_t pid = proc_pid(p);
2003 	uid_t uid = kauth_cred_getuid(cred);
2004 	int split_open_owner = ISSET(nmp->nm_state, NFSSTA_SPLIT_OPEN_OWNER);
2005 	struct nfs_open_owner *noop, *newnoop = NULL;
2006 
2007 tryagain:
2008 	lck_mtx_lock(&nmp->nm_lock);
2009 	TAILQ_FOREACH(noop, &nmp->nm_open_owners, noo_link) {
2010 		if (use_open_owner(uid, pid, kauth_cred_getuid(noop->noo_cred), noop->noo_pid, split_open_owner)) {
2011 			break;
2012 		}
2013 	}
2014 
2015 	if (!noop && !newnoop && alloc) {
2016 		lck_mtx_unlock(&nmp->nm_lock);
2017 		newnoop = kalloc_type(struct nfs_open_owner,
2018 		    Z_WAITOK | Z_ZERO | Z_NOFAIL);
2019 		lck_mtx_init(&newnoop->noo_lock, &nfs_open_grp, LCK_ATTR_NULL);
2020 		newnoop->noo_mount = nmp;
2021 		kauth_cred_ref(cred);
2022 		newnoop->noo_cred = cred;
2023 		newnoop->noo_pid = pid;
2024 		newnoop->noo_name = OSAddAtomic(1, &nfs_open_owner_seqnum);
2025 		TAILQ_INIT(&newnoop->noo_opens);
2026 		goto tryagain;
2027 	}
2028 	if (!noop && newnoop) {
2029 		newnoop->noo_flags |= NFS_OPEN_OWNER_LINK;
2030 		os_ref_init(&newnoop->noo_refcnt, NULL);
2031 		TAILQ_INSERT_HEAD(&nmp->nm_open_owners, newnoop, noo_link);
2032 		noop = newnoop;
2033 	}
2034 	lck_mtx_unlock(&nmp->nm_lock);
2035 
2036 	if (newnoop && (noop != newnoop)) {
2037 		nfs_open_owner_destroy(newnoop);
2038 	}
2039 
2040 	if (noop) {
2041 		nfs_open_owner_ref(noop);
2042 	}
2043 
2044 	return noop;
2045 }
2046 
2047 /*
2048  * destroy an open owner that's no longer needed
2049  */
2050 void
nfs_open_owner_destroy(struct nfs_open_owner * noop)2051 nfs_open_owner_destroy(struct nfs_open_owner *noop)
2052 {
2053 	if (noop->noo_cred) {
2054 		kauth_cred_unref(&noop->noo_cred);
2055 	}
2056 	lck_mtx_destroy(&noop->noo_lock, &nfs_open_grp);
2057 	kfree_type(struct nfs_open_owner, noop);
2058 }
2059 
2060 /*
2061  * acquire a reference count on an open owner
2062  */
2063 void
nfs_open_owner_ref(struct nfs_open_owner * noop)2064 nfs_open_owner_ref(struct nfs_open_owner *noop)
2065 {
2066 	lck_mtx_lock(&noop->noo_lock);
2067 	os_ref_retain_locked(&noop->noo_refcnt);
2068 	lck_mtx_unlock(&noop->noo_lock);
2069 }
2070 
2071 /*
2072  * drop a reference count on an open owner and destroy it if
2073  * it is no longer referenced and no longer on the mount's list.
2074  */
2075 void
nfs_open_owner_rele(struct nfs_open_owner * noop)2076 nfs_open_owner_rele(struct nfs_open_owner *noop)
2077 {
2078 	os_ref_count_t newcount;
2079 
2080 	lck_mtx_lock(&noop->noo_lock);
2081 	if (os_ref_get_count(&noop->noo_refcnt) < 1) {
2082 		panic("nfs_open_owner_rele: no refcnt");
2083 	}
2084 	newcount = os_ref_release_locked(&noop->noo_refcnt);
2085 	if (!newcount && (noop->noo_flags & NFS_OPEN_OWNER_BUSY)) {
2086 		panic("nfs_open_owner_rele: busy");
2087 	}
2088 	/* XXX we may potentially want to clean up idle/unused open owner structures */
2089 	if (newcount || (noop->noo_flags & NFS_OPEN_OWNER_LINK)) {
2090 		lck_mtx_unlock(&noop->noo_lock);
2091 		return;
2092 	}
2093 	/* owner is no longer referenced or linked to mount, so destroy it */
2094 	lck_mtx_unlock(&noop->noo_lock);
2095 	nfs_open_owner_destroy(noop);
2096 }
2097 
2098 /*
2099  * Mark an open owner as busy because we are about to
2100  * start an operation that uses and updates open owner state.
2101  */
2102 int
nfs_open_owner_set_busy(struct nfs_open_owner * noop,thread_t thd)2103 nfs_open_owner_set_busy(struct nfs_open_owner *noop, thread_t thd)
2104 {
2105 	struct nfsmount *nmp;
2106 	struct timespec ts = { .tv_sec = 2, .tv_nsec = 0 };
2107 	int error = 0, slpflag;
2108 
2109 	nmp = noop->noo_mount;
2110 	if (nfs_mount_gone(nmp)) {
2111 		return ENXIO;
2112 	}
2113 	slpflag = (NMFLAG(nmp, INTR) && thd) ? PCATCH : 0;
2114 
2115 	lck_mtx_lock(&noop->noo_lock);
2116 	while (noop->noo_flags & NFS_OPEN_OWNER_BUSY) {
2117 		if ((error = nfs_sigintr(nmp, NULL, thd, 0))) {
2118 			break;
2119 		}
2120 		noop->noo_flags |= NFS_OPEN_OWNER_WANT;
2121 		msleep(noop, &noop->noo_lock, slpflag, "nfs_open_owner_set_busy", &ts);
2122 		slpflag = 0;
2123 	}
2124 	if (!error) {
2125 		noop->noo_flags |= NFS_OPEN_OWNER_BUSY;
2126 	}
2127 	lck_mtx_unlock(&noop->noo_lock);
2128 
2129 	return error;
2130 }
2131 
2132 /*
2133  * Clear the busy flag on an open owner and wake up anyone waiting
2134  * to mark it busy.
2135  */
2136 void
nfs_open_owner_clear_busy(struct nfs_open_owner * noop)2137 nfs_open_owner_clear_busy(struct nfs_open_owner *noop)
2138 {
2139 	int wanted;
2140 
2141 	lck_mtx_lock(&noop->noo_lock);
2142 	if (!(noop->noo_flags & NFS_OPEN_OWNER_BUSY)) {
2143 		panic("nfs_open_owner_clear_busy");
2144 	}
2145 	wanted = (noop->noo_flags & NFS_OPEN_OWNER_WANT);
2146 	noop->noo_flags &= ~(NFS_OPEN_OWNER_BUSY | NFS_OPEN_OWNER_WANT);
2147 	lck_mtx_unlock(&noop->noo_lock);
2148 	if (wanted) {
2149 		wakeup(noop);
2150 	}
2151 }
2152 
2153 /*
2154  * Given an open/lock owner and an error code, increment the
2155  * sequence ID if appropriate.
2156  */
2157 void
nfs_owner_seqid_increment(struct nfs_open_owner * noop,struct nfs_lock_owner * nlop,int error)2158 nfs_owner_seqid_increment(struct nfs_open_owner *noop, struct nfs_lock_owner *nlop, int error)
2159 {
2160 	switch (error) {
2161 	case NFSERR_STALE_CLIENTID:
2162 	case NFSERR_STALE_STATEID:
2163 	case NFSERR_OLD_STATEID:
2164 	case NFSERR_BAD_STATEID:
2165 	case NFSERR_BAD_SEQID:
2166 	case NFSERR_BADXDR:
2167 	case NFSERR_RESOURCE:
2168 	case NFSERR_NOFILEHANDLE:
2169 		/* do not increment the open seqid on these errors */
2170 		return;
2171 	}
2172 	if (noop) {
2173 		noop->noo_seqid++;
2174 	}
2175 	if (nlop) {
2176 		nlop->nlo_seqid++;
2177 	}
2178 }
2179 
2180 /*
2181  * Search a node's open file list for any conflicts with this request.
2182  * Also find this open owner's open file structure.
2183  * If not found and "alloc" is set, then allocate one.
2184  */
2185 int
nfs_open_file_find(nfsnode_t np,struct nfs_open_owner * noop,struct nfs_open_file ** nofpp,uint32_t accessMode,uint32_t denyMode,int alloc)2186 nfs_open_file_find(
2187 	nfsnode_t np,
2188 	struct nfs_open_owner *noop,
2189 	struct nfs_open_file **nofpp,
2190 	uint32_t accessMode,
2191 	uint32_t denyMode,
2192 	int alloc)
2193 {
2194 	*nofpp = NULL;
2195 	return nfs_open_file_find_internal(np, noop, nofpp, accessMode, denyMode, alloc);
2196 }
2197 
2198 /*
2199  * Internally, allow using a provisional nodeless nofp (passed in via *nofpp)
2200  * if an existing one is not found.  This is used in "create" scenarios to
2201  * officially add the provisional nofp to the node once the node is created.
2202  */
2203 int
nfs_open_file_find_internal(nfsnode_t np,struct nfs_open_owner * noop,struct nfs_open_file ** nofpp,uint32_t accessMode,uint32_t denyMode,int alloc)2204 nfs_open_file_find_internal(
2205 	nfsnode_t np,
2206 	struct nfs_open_owner *noop,
2207 	struct nfs_open_file **nofpp,
2208 	uint32_t accessMode,
2209 	uint32_t denyMode,
2210 	int alloc)
2211 {
2212 	struct nfs_open_file *nofp = NULL, *nofp2, *newnofp = NULL;
2213 
2214 	if (!np) {
2215 		goto alloc;
2216 	}
2217 tryagain:
2218 	lck_mtx_lock(&np->n_openlock);
2219 	TAILQ_FOREACH(nofp2, &np->n_opens, nof_link) {
2220 		if (nofp2->nof_owner == noop) {
2221 			nofp = nofp2;
2222 			if (!accessMode) {
2223 				break;
2224 			}
2225 		}
2226 		if ((accessMode & nofp2->nof_deny) || (denyMode & nofp2->nof_access)) {
2227 			/* This request conflicts with an existing open on this client. */
2228 			lck_mtx_unlock(&np->n_openlock);
2229 			return EACCES;
2230 		}
2231 	}
2232 
2233 	/*
2234 	 * If this open owner doesn't have an open
2235 	 * file structure yet, we create one for it.
2236 	 */
2237 	if (!nofp && !*nofpp && !newnofp && alloc) {
2238 		lck_mtx_unlock(&np->n_openlock);
2239 alloc:
2240 		newnofp = kalloc_type(struct nfs_open_file,
2241 		    Z_WAITOK | Z_ZERO | Z_NOFAIL);
2242 		lck_mtx_init(&newnofp->nof_lock, &nfs_open_grp, LCK_ATTR_NULL);
2243 		newnofp->nof_owner = noop;
2244 		nfs_open_owner_ref(noop);
2245 		newnofp->nof_np = np;
2246 		lck_mtx_lock(&noop->noo_lock);
2247 		TAILQ_INSERT_HEAD(&noop->noo_opens, newnofp, nof_oolink);
2248 		lck_mtx_unlock(&noop->noo_lock);
2249 		if (np) {
2250 			goto tryagain;
2251 		}
2252 	}
2253 	if (!nofp) {
2254 		if (*nofpp) {
2255 			(*nofpp)->nof_np = np;
2256 			nofp = *nofpp;
2257 		} else {
2258 			nofp = newnofp;
2259 		}
2260 		if (nofp && np) {
2261 			TAILQ_INSERT_HEAD(&np->n_opens, nofp, nof_link);
2262 		}
2263 	}
2264 	if (np) {
2265 		lck_mtx_unlock(&np->n_openlock);
2266 	}
2267 
2268 	if (alloc && newnofp && (nofp != newnofp)) {
2269 		nfs_open_file_destroy(newnofp);
2270 	}
2271 
2272 	*nofpp = nofp;
2273 	return nofp ? 0 : ESRCH;
2274 }
2275 
2276 /*
2277  * Destroy an open file structure.
2278  */
2279 void
nfs_open_file_destroy(struct nfs_open_file * nofp)2280 nfs_open_file_destroy(struct nfs_open_file *nofp)
2281 {
2282 	lck_mtx_lock(&nofp->nof_owner->noo_lock);
2283 	TAILQ_REMOVE(&nofp->nof_owner->noo_opens, nofp, nof_oolink);
2284 	lck_mtx_unlock(&nofp->nof_owner->noo_lock);
2285 	nfs_open_owner_rele(nofp->nof_owner);
2286 	lck_mtx_destroy(&nofp->nof_lock, &nfs_open_grp);
2287 	kfree_type(struct nfs_open_file, nofp);
2288 }
2289 
2290 /*
2291  * Mark an open file as busy because we are about to
2292  * start an operation that uses and updates open file state.
2293  */
2294 int
nfs_open_file_set_busy(struct nfs_open_file * nofp,thread_t thd)2295 nfs_open_file_set_busy(struct nfs_open_file *nofp, thread_t thd)
2296 {
2297 	struct nfsmount *nmp;
2298 	struct timespec ts = { .tv_sec = 2, .tv_nsec = 0 };
2299 	int error = 0, slpflag;
2300 
2301 	nmp = nofp->nof_owner->noo_mount;
2302 	if (nfs_mount_gone(nmp)) {
2303 		return ENXIO;
2304 	}
2305 	slpflag = (NMFLAG(nmp, INTR) && thd) ? PCATCH : 0;
2306 
2307 	lck_mtx_lock(&nofp->nof_lock);
2308 	while (nofp->nof_flags & NFS_OPEN_FILE_BUSY) {
2309 		if ((error = nfs_sigintr(nmp, NULL, thd, 0))) {
2310 			break;
2311 		}
2312 		nofp->nof_flags |= NFS_OPEN_FILE_WANT;
2313 		msleep(nofp, &nofp->nof_lock, slpflag, "nfs_open_file_set_busy", &ts);
2314 		slpflag = 0;
2315 	}
2316 	if (!error) {
2317 		nofp->nof_flags |= NFS_OPEN_FILE_BUSY;
2318 	}
2319 	lck_mtx_unlock(&nofp->nof_lock);
2320 
2321 	return error;
2322 }
2323 
2324 /*
2325  * Clear the busy flag on an open file and wake up anyone waiting
2326  * to mark it busy.
2327  */
2328 void
nfs_open_file_clear_busy(struct nfs_open_file * nofp)2329 nfs_open_file_clear_busy(struct nfs_open_file *nofp)
2330 {
2331 	int wanted;
2332 
2333 	lck_mtx_lock(&nofp->nof_lock);
2334 	if (!(nofp->nof_flags & NFS_OPEN_FILE_BUSY)) {
2335 		panic("nfs_open_file_clear_busy");
2336 	}
2337 	wanted = (nofp->nof_flags & NFS_OPEN_FILE_WANT);
2338 	nofp->nof_flags &= ~(NFS_OPEN_FILE_BUSY | NFS_OPEN_FILE_WANT);
2339 	lck_mtx_unlock(&nofp->nof_lock);
2340 	if (wanted) {
2341 		wakeup(nofp);
2342 	}
2343 }
2344 
2345 /*
2346  * Add the open state for the given access/deny modes to this open file.
2347  */
2348 void
nfs_open_file_add_open(struct nfs_open_file * nofp,uint32_t accessMode,uint32_t denyMode,int delegated)2349 nfs_open_file_add_open(struct nfs_open_file *nofp, uint32_t accessMode, uint32_t denyMode, int delegated)
2350 {
2351 	lck_mtx_lock(&nofp->nof_lock);
2352 	nofp->nof_access |= accessMode;
2353 	nofp->nof_deny |= denyMode;
2354 
2355 	if (delegated) {
2356 		if (denyMode == NFS_OPEN_SHARE_DENY_NONE) {
2357 			if (accessMode == NFS_OPEN_SHARE_ACCESS_READ) {
2358 				nofp->nof_d_r++;
2359 			} else if (accessMode == NFS_OPEN_SHARE_ACCESS_WRITE) {
2360 				nofp->nof_d_w++;
2361 			} else if (accessMode == NFS_OPEN_SHARE_ACCESS_BOTH) {
2362 				nofp->nof_d_rw++;
2363 			}
2364 		} else if (denyMode == NFS_OPEN_SHARE_DENY_WRITE) {
2365 			if (accessMode == NFS_OPEN_SHARE_ACCESS_READ) {
2366 				nofp->nof_d_r_dw++;
2367 			} else if (accessMode == NFS_OPEN_SHARE_ACCESS_WRITE) {
2368 				nofp->nof_d_w_dw++;
2369 			} else if (accessMode == NFS_OPEN_SHARE_ACCESS_BOTH) {
2370 				nofp->nof_d_rw_dw++;
2371 			}
2372 		} else { /* NFS_OPEN_SHARE_DENY_BOTH */
2373 			if (accessMode == NFS_OPEN_SHARE_ACCESS_READ) {
2374 				nofp->nof_d_r_drw++;
2375 			} else if (accessMode == NFS_OPEN_SHARE_ACCESS_WRITE) {
2376 				nofp->nof_d_w_drw++;
2377 			} else if (accessMode == NFS_OPEN_SHARE_ACCESS_BOTH) {
2378 				nofp->nof_d_rw_drw++;
2379 			}
2380 		}
2381 	} else {
2382 		if (denyMode == NFS_OPEN_SHARE_DENY_NONE) {
2383 			if (accessMode == NFS_OPEN_SHARE_ACCESS_READ) {
2384 				nofp->nof_r++;
2385 			} else if (accessMode == NFS_OPEN_SHARE_ACCESS_WRITE) {
2386 				nofp->nof_w++;
2387 			} else if (accessMode == NFS_OPEN_SHARE_ACCESS_BOTH) {
2388 				nofp->nof_rw++;
2389 			}
2390 		} else if (denyMode == NFS_OPEN_SHARE_DENY_WRITE) {
2391 			if (accessMode == NFS_OPEN_SHARE_ACCESS_READ) {
2392 				nofp->nof_r_dw++;
2393 			} else if (accessMode == NFS_OPEN_SHARE_ACCESS_WRITE) {
2394 				nofp->nof_w_dw++;
2395 			} else if (accessMode == NFS_OPEN_SHARE_ACCESS_BOTH) {
2396 				nofp->nof_rw_dw++;
2397 			}
2398 		} else { /* NFS_OPEN_SHARE_DENY_BOTH */
2399 			if (accessMode == NFS_OPEN_SHARE_ACCESS_READ) {
2400 				nofp->nof_r_drw++;
2401 			} else if (accessMode == NFS_OPEN_SHARE_ACCESS_WRITE) {
2402 				nofp->nof_w_drw++;
2403 			} else if (accessMode == NFS_OPEN_SHARE_ACCESS_BOTH) {
2404 				nofp->nof_rw_drw++;
2405 			}
2406 		}
2407 	}
2408 
2409 	nofp->nof_opencnt++;
2410 	lck_mtx_unlock(&nofp->nof_lock);
2411 }
2412 
2413 /*
2414  * Find which particular open combo will be closed and report what
2415  * the new modes will be and whether the open was delegated.
2416  */
2417 void
nfs_open_file_remove_open_find(struct nfs_open_file * nofp,uint32_t accessMode,uint32_t denyMode,uint8_t * newAccessMode,uint8_t * newDenyMode,int * delegated)2418 nfs_open_file_remove_open_find(
2419 	struct nfs_open_file *nofp,
2420 	uint32_t accessMode,
2421 	uint32_t denyMode,
2422 	uint8_t *newAccessMode,
2423 	uint8_t *newDenyMode,
2424 	int *delegated)
2425 {
2426 	/*
2427 	 * Calculate new modes: a mode bit gets removed when there's only
2428 	 * one count in all the corresponding counts
2429 	 */
2430 	*newAccessMode = nofp->nof_access;
2431 	*newDenyMode = nofp->nof_deny;
2432 
2433 	if ((accessMode & NFS_OPEN_SHARE_ACCESS_READ) &&
2434 	    (nofp->nof_access & NFS_OPEN_SHARE_ACCESS_READ) &&
2435 	    ((nofp->nof_r + nofp->nof_d_r +
2436 	    nofp->nof_rw + nofp->nof_d_rw +
2437 	    nofp->nof_r_dw + nofp->nof_d_r_dw +
2438 	    nofp->nof_rw_dw + nofp->nof_d_rw_dw +
2439 	    nofp->nof_r_drw + nofp->nof_d_r_drw +
2440 	    nofp->nof_rw_dw + nofp->nof_d_rw_dw) == 1)) {
2441 		*newAccessMode &= ~NFS_OPEN_SHARE_ACCESS_READ;
2442 	}
2443 	if ((accessMode & NFS_OPEN_SHARE_ACCESS_WRITE) &&
2444 	    (nofp->nof_access & NFS_OPEN_SHARE_ACCESS_WRITE) &&
2445 	    ((nofp->nof_w + nofp->nof_d_w +
2446 	    nofp->nof_rw + nofp->nof_d_rw +
2447 	    nofp->nof_w_dw + nofp->nof_d_w_dw +
2448 	    nofp->nof_rw_dw + nofp->nof_d_rw_dw +
2449 	    nofp->nof_w_drw + nofp->nof_d_w_drw +
2450 	    nofp->nof_rw_dw + nofp->nof_d_rw_dw) == 1)) {
2451 		*newAccessMode &= ~NFS_OPEN_SHARE_ACCESS_WRITE;
2452 	}
2453 	if ((denyMode & NFS_OPEN_SHARE_DENY_READ) &&
2454 	    (nofp->nof_deny & NFS_OPEN_SHARE_DENY_READ) &&
2455 	    ((nofp->nof_r_drw + nofp->nof_d_r_drw +
2456 	    nofp->nof_w_drw + nofp->nof_d_w_drw +
2457 	    nofp->nof_rw_drw + nofp->nof_d_rw_drw) == 1)) {
2458 		*newDenyMode &= ~NFS_OPEN_SHARE_DENY_READ;
2459 	}
2460 	if ((denyMode & NFS_OPEN_SHARE_DENY_WRITE) &&
2461 	    (nofp->nof_deny & NFS_OPEN_SHARE_DENY_WRITE) &&
2462 	    ((nofp->nof_r_drw + nofp->nof_d_r_drw +
2463 	    nofp->nof_w_drw + nofp->nof_d_w_drw +
2464 	    nofp->nof_rw_drw + nofp->nof_d_rw_drw +
2465 	    nofp->nof_r_dw + nofp->nof_d_r_dw +
2466 	    nofp->nof_w_dw + nofp->nof_d_w_dw +
2467 	    nofp->nof_rw_dw + nofp->nof_d_rw_dw) == 1)) {
2468 		*newDenyMode &= ~NFS_OPEN_SHARE_DENY_WRITE;
2469 	}
2470 
2471 	/* Find the corresponding open access/deny mode counter. */
2472 	if (denyMode == NFS_OPEN_SHARE_DENY_NONE) {
2473 		if (accessMode == NFS_OPEN_SHARE_ACCESS_READ) {
2474 			*delegated = (nofp->nof_d_r != 0);
2475 		} else if (accessMode == NFS_OPEN_SHARE_ACCESS_WRITE) {
2476 			*delegated = (nofp->nof_d_w != 0);
2477 		} else if (accessMode == NFS_OPEN_SHARE_ACCESS_BOTH) {
2478 			*delegated = (nofp->nof_d_rw != 0);
2479 		} else {
2480 			*delegated = 0;
2481 		}
2482 	} else if (denyMode == NFS_OPEN_SHARE_DENY_WRITE) {
2483 		if (accessMode == NFS_OPEN_SHARE_ACCESS_READ) {
2484 			*delegated = (nofp->nof_d_r_dw != 0);
2485 		} else if (accessMode == NFS_OPEN_SHARE_ACCESS_WRITE) {
2486 			*delegated = (nofp->nof_d_w_dw != 0);
2487 		} else if (accessMode == NFS_OPEN_SHARE_ACCESS_BOTH) {
2488 			*delegated = (nofp->nof_d_rw_dw != 0);
2489 		} else {
2490 			*delegated = 0;
2491 		}
2492 	} else { /* NFS_OPEN_SHARE_DENY_BOTH */
2493 		if (accessMode == NFS_OPEN_SHARE_ACCESS_READ) {
2494 			*delegated = (nofp->nof_d_r_drw != 0);
2495 		} else if (accessMode == NFS_OPEN_SHARE_ACCESS_WRITE) {
2496 			*delegated = (nofp->nof_d_w_drw != 0);
2497 		} else if (accessMode == NFS_OPEN_SHARE_ACCESS_BOTH) {
2498 			*delegated = (nofp->nof_d_rw_drw != 0);
2499 		} else {
2500 			*delegated = 0;
2501 		}
2502 	}
2503 }
2504 
2505 /*
2506  * Remove the open state for the given access/deny modes to this open file.
2507  */
2508 void
nfs_open_file_remove_open(struct nfs_open_file * nofp,uint32_t accessMode,uint32_t denyMode)2509 nfs_open_file_remove_open(struct nfs_open_file *nofp, uint32_t accessMode, uint32_t denyMode)
2510 {
2511 	uint8_t newAccessMode, newDenyMode;
2512 	int delegated = 0;
2513 
2514 	lck_mtx_lock(&nofp->nof_lock);
2515 	nfs_open_file_remove_open_find(nofp, accessMode, denyMode, &newAccessMode, &newDenyMode, &delegated);
2516 
2517 	/* Decrement the corresponding open access/deny mode counter. */
2518 	if (denyMode == NFS_OPEN_SHARE_DENY_NONE) {
2519 		if (accessMode == NFS_OPEN_SHARE_ACCESS_READ) {
2520 			if (delegated) {
2521 				if (nofp->nof_d_r == 0) {
2522 					NP(nofp->nof_np, "nfs: open(R) delegated count underrun, %d", kauth_cred_getuid(nofp->nof_owner->noo_cred));
2523 				} else {
2524 					nofp->nof_d_r--;
2525 				}
2526 			} else {
2527 				if (nofp->nof_r == 0) {
2528 					NP(nofp->nof_np, "nfs: open(R) count underrun, %d", kauth_cred_getuid(nofp->nof_owner->noo_cred));
2529 				} else {
2530 					nofp->nof_r--;
2531 				}
2532 			}
2533 		} else if (accessMode == NFS_OPEN_SHARE_ACCESS_WRITE) {
2534 			if (delegated) {
2535 				if (nofp->nof_d_w == 0) {
2536 					NP(nofp->nof_np, "nfs: open(W) delegated count underrun, %d", kauth_cred_getuid(nofp->nof_owner->noo_cred));
2537 				} else {
2538 					nofp->nof_d_w--;
2539 				}
2540 			} else {
2541 				if (nofp->nof_w == 0) {
2542 					NP(nofp->nof_np, "nfs: open(W) count underrun, %d", kauth_cred_getuid(nofp->nof_owner->noo_cred));
2543 				} else {
2544 					nofp->nof_w--;
2545 				}
2546 			}
2547 		} else if (accessMode == NFS_OPEN_SHARE_ACCESS_BOTH) {
2548 			if (delegated) {
2549 				if (nofp->nof_d_rw == 0) {
2550 					NP(nofp->nof_np, "nfs: open(RW) delegated count underrun, %d", kauth_cred_getuid(nofp->nof_owner->noo_cred));
2551 				} else {
2552 					nofp->nof_d_rw--;
2553 				}
2554 			} else {
2555 				if (nofp->nof_rw == 0) {
2556 					NP(nofp->nof_np, "nfs: open(RW) count underrun, %d", kauth_cred_getuid(nofp->nof_owner->noo_cred));
2557 				} else {
2558 					nofp->nof_rw--;
2559 				}
2560 			}
2561 		}
2562 	} else if (denyMode == NFS_OPEN_SHARE_DENY_WRITE) {
2563 		if (accessMode == NFS_OPEN_SHARE_ACCESS_READ) {
2564 			if (delegated) {
2565 				if (nofp->nof_d_r_dw == 0) {
2566 					NP(nofp->nof_np, "nfs: open(R,DW) delegated count underrun, %d", kauth_cred_getuid(nofp->nof_owner->noo_cred));
2567 				} else {
2568 					nofp->nof_d_r_dw--;
2569 				}
2570 			} else {
2571 				if (nofp->nof_r_dw == 0) {
2572 					NP(nofp->nof_np, "nfs: open(R,DW) count underrun, %d", kauth_cred_getuid(nofp->nof_owner->noo_cred));
2573 				} else {
2574 					nofp->nof_r_dw--;
2575 				}
2576 			}
2577 		} else if (accessMode == NFS_OPEN_SHARE_ACCESS_WRITE) {
2578 			if (delegated) {
2579 				if (nofp->nof_d_w_dw == 0) {
2580 					NP(nofp->nof_np, "nfs: open(W,DW) delegated count underrun, %d", kauth_cred_getuid(nofp->nof_owner->noo_cred));
2581 				} else {
2582 					nofp->nof_d_w_dw--;
2583 				}
2584 			} else {
2585 				if (nofp->nof_w_dw == 0) {
2586 					NP(nofp->nof_np, "nfs: open(W,DW) count underrun, %d", kauth_cred_getuid(nofp->nof_owner->noo_cred));
2587 				} else {
2588 					nofp->nof_w_dw--;
2589 				}
2590 			}
2591 		} else if (accessMode == NFS_OPEN_SHARE_ACCESS_BOTH) {
2592 			if (delegated) {
2593 				if (nofp->nof_d_rw_dw == 0) {
2594 					NP(nofp->nof_np, "nfs: open(RW,DW) delegated count underrun, %d", kauth_cred_getuid(nofp->nof_owner->noo_cred));
2595 				} else {
2596 					nofp->nof_d_rw_dw--;
2597 				}
2598 			} else {
2599 				if (nofp->nof_rw_dw == 0) {
2600 					NP(nofp->nof_np, "nfs: open(RW,DW) count underrun, %d", kauth_cred_getuid(nofp->nof_owner->noo_cred));
2601 				} else {
2602 					nofp->nof_rw_dw--;
2603 				}
2604 			}
2605 		}
2606 	} else { /* NFS_OPEN_SHARE_DENY_BOTH */
2607 		if (accessMode == NFS_OPEN_SHARE_ACCESS_READ) {
2608 			if (delegated) {
2609 				if (nofp->nof_d_r_drw == 0) {
2610 					NP(nofp->nof_np, "nfs: open(R,DRW) delegated count underrun, %d", kauth_cred_getuid(nofp->nof_owner->noo_cred));
2611 				} else {
2612 					nofp->nof_d_r_drw--;
2613 				}
2614 			} else {
2615 				if (nofp->nof_r_drw == 0) {
2616 					NP(nofp->nof_np, "nfs: open(R,DRW) count underrun, %d", kauth_cred_getuid(nofp->nof_owner->noo_cred));
2617 				} else {
2618 					nofp->nof_r_drw--;
2619 				}
2620 			}
2621 		} else if (accessMode == NFS_OPEN_SHARE_ACCESS_WRITE) {
2622 			if (delegated) {
2623 				if (nofp->nof_d_w_drw == 0) {
2624 					NP(nofp->nof_np, "nfs: open(W,DRW) delegated count underrun, %d", kauth_cred_getuid(nofp->nof_owner->noo_cred));
2625 				} else {
2626 					nofp->nof_d_w_drw--;
2627 				}
2628 			} else {
2629 				if (nofp->nof_w_drw == 0) {
2630 					NP(nofp->nof_np, "nfs: open(W,DRW) count underrun, %d", kauth_cred_getuid(nofp->nof_owner->noo_cred));
2631 				} else {
2632 					nofp->nof_w_drw--;
2633 				}
2634 			}
2635 		} else if (accessMode == NFS_OPEN_SHARE_ACCESS_BOTH) {
2636 			if (delegated) {
2637 				if (nofp->nof_d_rw_drw == 0) {
2638 					NP(nofp->nof_np, "nfs: open(RW,DRW) delegated count underrun, %d", kauth_cred_getuid(nofp->nof_owner->noo_cred));
2639 				} else {
2640 					nofp->nof_d_rw_drw--;
2641 				}
2642 			} else {
2643 				if (nofp->nof_rw_drw == 0) {
2644 					NP(nofp->nof_np, "nfs: open(RW,DRW) count underrun, %d", kauth_cred_getuid(nofp->nof_owner->noo_cred));
2645 				} else {
2646 					nofp->nof_rw_drw--;
2647 				}
2648 			}
2649 		}
2650 	}
2651 
2652 	/* update the modes */
2653 	nofp->nof_access = newAccessMode;
2654 	nofp->nof_deny = newDenyMode;
2655 	nofp->nof_opencnt--;
2656 	lck_mtx_unlock(&nofp->nof_lock);
2657 }
2658 
2659 #if CONFIG_NFS4
2660 /*
2661  * Get the current (delegation, lock, open, default) stateid for this node.
2662  * If node has a delegation, use that stateid.
2663  * If pid has a lock, use the lockowner's stateid.
2664  * Or use the open file's stateid.
2665  * If no open file, use a default stateid of all ones.
2666  */
2667 void
nfs_get_stateid(nfsnode_t np,thread_t thd,kauth_cred_t cred,nfs_stateid * sid,int writeaccess)2668 nfs_get_stateid(nfsnode_t np, thread_t thd, kauth_cred_t cred, nfs_stateid *sid, int writeaccess)
2669 {
2670 	struct nfsmount *nmp = NFSTONMP(np);
2671 	proc_t p = thd ? get_bsdthreadtask_info(thd) : current_proc();  // XXX async I/O requests don't have a thread
2672 	struct nfs_open_owner *noop = NULL;
2673 	struct nfs_open_file *nofp = NULL;
2674 	struct nfs_lock_owner *nlop = NULL;
2675 	nfs_stateid *s = NULL;
2676 	int readaccess = !writeaccess;
2677 
2678 	if ((readaccess && (np->n_openflags & N_DELEG_MASK)) || (writeaccess && (np->n_openflags & N_DELEG_WRITE))) {
2679 		s = &np->n_dstateid;
2680 	} else {
2681 		if (p) {
2682 			nlop = nfs_lock_owner_find(np, p, 0, 0);
2683 		}
2684 		if (nlop && !TAILQ_EMPTY(&nlop->nlo_locks)) {
2685 			/* we hold locks, use lock stateid */
2686 			s = &nlop->nlo_stateid;
2687 		} else if (((noop = nfs_open_owner_find(nmp, cred, p, 0))) &&
2688 		    (nfs_open_file_find(np, noop, &nofp, 0, 0, 0) == 0) &&
2689 		    !(nofp->nof_flags & NFS_OPEN_FILE_LOST) &&
2690 		    nofp->nof_access) {
2691 			/* we (should) have the file open, use open stateid */
2692 			if (nofp->nof_flags & NFS_OPEN_FILE_REOPEN) {
2693 				nfs4_reopen(nofp, thd);
2694 			}
2695 			if (!(nofp->nof_flags & NFS_OPEN_FILE_LOST)) {
2696 				s = &nofp->nof_stateid;
2697 			}
2698 		}
2699 	}
2700 
2701 	if (s) {
2702 		sid->seqid = s->seqid;
2703 		sid->other[0] = s->other[0];
2704 		sid->other[1] = s->other[1];
2705 		sid->other[2] = s->other[2];
2706 	} else {
2707 		/* named attributes may not have a stateid for reads, so don't complain for them */
2708 		if (!(np->n_vattr.nva_flags & NFS_FFLAG_IS_ATTR)) {
2709 			NP(np, "nfs_get_stateid: no stateid");
2710 		}
2711 		sid->seqid = sid->other[0] = sid->other[1] = sid->other[2] = 0xffffffff;
2712 	}
2713 	if (nlop) {
2714 		nfs_lock_owner_rele(np, nlop, thd, cred);
2715 	}
2716 	if (noop) {
2717 		nfs_open_owner_rele(noop);
2718 	}
2719 }
2720 
2721 
2722 /*
2723  * When we have a delegation, we may be able to perform the OPEN locally.
2724  * Perform the OPEN by checking the delegation ACE and/or checking via ACCESS.
2725  */
2726 int
nfs4_open_delegated(nfsnode_t np,struct nfs_open_file * nofp,uint32_t accessMode,uint32_t denyMode,vfs_context_t ctx)2727 nfs4_open_delegated(
2728 	nfsnode_t np,
2729 	struct nfs_open_file *nofp,
2730 	uint32_t accessMode,
2731 	uint32_t denyMode,
2732 	vfs_context_t ctx)
2733 {
2734 	int error = 0, ismember, readtoo = 0, authorized = 0;
2735 	uint32_t action;
2736 	struct kauth_acl_eval eval;
2737 	kauth_cred_t cred = vfs_context_ucred(ctx);
2738 
2739 	if (!(accessMode & NFS_OPEN_SHARE_ACCESS_READ)) {
2740 		/*
2741 		 * Try to open it for read access too,
2742 		 * so the buffer cache can read data.
2743 		 */
2744 		readtoo = 1;
2745 		accessMode |= NFS_OPEN_SHARE_ACCESS_READ;
2746 	}
2747 
2748 tryagain:
2749 	action = 0;
2750 	if (accessMode & NFS_OPEN_SHARE_ACCESS_READ) {
2751 		action |= KAUTH_VNODE_READ_DATA;
2752 	}
2753 	if (accessMode & NFS_OPEN_SHARE_ACCESS_WRITE) {
2754 		action |= KAUTH_VNODE_WRITE_DATA;
2755 	}
2756 
2757 	/* evaluate ACE (if we have one) */
2758 	if (np->n_dace.ace_flags) {
2759 		eval.ae_requested = action;
2760 		eval.ae_acl = &np->n_dace;
2761 		eval.ae_count = 1;
2762 		eval.ae_options = 0;
2763 		if (np->n_vattr.nva_uid == kauth_cred_getuid(cred)) {
2764 			eval.ae_options |= KAUTH_AEVAL_IS_OWNER;
2765 		}
2766 		error = kauth_cred_ismember_gid(cred, np->n_vattr.nva_gid, &ismember);
2767 		if (!error && ismember) {
2768 			eval.ae_options |= KAUTH_AEVAL_IN_GROUP;
2769 		}
2770 
2771 		eval.ae_exp_gall = KAUTH_VNODE_GENERIC_ALL_BITS;
2772 		eval.ae_exp_gread = KAUTH_VNODE_GENERIC_READ_BITS;
2773 		eval.ae_exp_gwrite = KAUTH_VNODE_GENERIC_WRITE_BITS;
2774 		eval.ae_exp_gexec = KAUTH_VNODE_GENERIC_EXECUTE_BITS;
2775 
2776 		error = kauth_acl_evaluate(cred, &eval);
2777 
2778 		if (!error && (eval.ae_result == KAUTH_RESULT_ALLOW)) {
2779 			authorized = 1;
2780 		}
2781 	}
2782 
2783 	if (!authorized) {
2784 		/* need to ask the server via ACCESS */
2785 		struct vnop_access_args naa;
2786 		naa.a_desc = &vnop_access_desc;
2787 		naa.a_vp = NFSTOV(np);
2788 		naa.a_action = action;
2789 		naa.a_context = ctx;
2790 		if (!(error = nfs_vnop_access(&naa))) {
2791 			authorized = 1;
2792 		}
2793 	}
2794 
2795 	if (!authorized) {
2796 		if (readtoo) {
2797 			/* try again without the extra read access */
2798 			accessMode &= ~NFS_OPEN_SHARE_ACCESS_READ;
2799 			readtoo = 0;
2800 			goto tryagain;
2801 		}
2802 		return error ? error : EACCES;
2803 	}
2804 
2805 	nfs_open_file_add_open(nofp, accessMode, denyMode, 1);
2806 
2807 	return 0;
2808 }
2809 
2810 
2811 /*
2812  * Open a file with the given access/deny modes.
2813  *
2814  * If we have a delegation, we may be able to handle the open locally.
2815  * Otherwise, we will always send the open RPC even if this open's mode is
2816  * a subset of all the existing opens.  This makes sure that we will always
2817  * be able to do a downgrade to any of the open modes.
2818  *
2819  * Note: local conflicts should have already been checked in nfs_open_file_find().
2820  */
2821 int
nfs4_open(nfsnode_t np,struct nfs_open_file * nofp,uint32_t accessMode,uint32_t denyMode,vfs_context_t ctx)2822 nfs4_open(
2823 	nfsnode_t np,
2824 	struct nfs_open_file *nofp,
2825 	uint32_t accessMode,
2826 	uint32_t denyMode,
2827 	vfs_context_t ctx)
2828 {
2829 	vnode_t vp = NFSTOV(np);
2830 	vnode_t dvp = NULL;
2831 	struct componentname cn;
2832 	const char *vname = NULL;
2833 	uint32_t namelen = 0;
2834 	char smallname[128];
2835 	char *filename = NULL;
2836 	int error = 0, readtoo = 0;
2837 
2838 	/*
2839 	 * We can handle the OPEN ourselves if we have a delegation,
2840 	 * unless it's a read delegation and the open is asking for
2841 	 * either write access or deny read.  We also don't bother to
2842 	 * use the delegation if it's being returned.
2843 	 */
2844 	if (np->n_openflags & N_DELEG_MASK) {
2845 		if ((error = nfs_open_state_set_busy(np, vfs_context_thread(ctx)))) {
2846 			return error;
2847 		}
2848 		if ((np->n_openflags & N_DELEG_MASK) && !(np->n_openflags & N_DELEG_RETURN) &&
2849 		    (((np->n_openflags & N_DELEG_MASK) == N_DELEG_WRITE) ||
2850 		    (!(accessMode & NFS_OPEN_SHARE_ACCESS_WRITE) && !(denyMode & NFS_OPEN_SHARE_DENY_READ)))) {
2851 			error = nfs4_open_delegated(np, nofp, accessMode, denyMode, ctx);
2852 			nfs_open_state_clear_busy(np);
2853 			return error;
2854 		}
2855 		nfs_open_state_clear_busy(np);
2856 	}
2857 
2858 	/*
2859 	 * [sigh] We can't trust VFS to get the parent right for named
2860 	 * attribute nodes.  (It likes to reparent the nodes after we've
2861 	 * created them.)  Luckily we can probably get the right parent
2862 	 * from the n_parent we have stashed away.
2863 	 */
2864 	if ((np->n_vattr.nva_flags & NFS_FFLAG_IS_ATTR) &&
2865 	    (((dvp = np->n_parent)) && (error = vnode_get(dvp)))) {
2866 		dvp = NULL;
2867 	}
2868 	if (!dvp) {
2869 		dvp = vnode_getparent(vp);
2870 	}
2871 	vname = vnode_getname(vp);
2872 	if (!dvp || !vname) {
2873 		if (!error) {
2874 			error = EIO;
2875 		}
2876 		goto out;
2877 	}
2878 	filename = &smallname[0];
2879 	namelen = snprintf(filename, sizeof(smallname), "%s", vname);
2880 	if (namelen >= sizeof(smallname)) {
2881 		filename = kalloc_data(namelen + 1, Z_WAITOK);
2882 		if (!filename) {
2883 			error = ENOMEM;
2884 			goto out;
2885 		}
2886 		snprintf(filename, namelen + 1, "%s", vname);
2887 	}
2888 	bzero(&cn, sizeof(cn));
2889 	cn.cn_nameptr = filename;
2890 	cn.cn_namelen = namelen;
2891 
2892 	if (!(accessMode & NFS_OPEN_SHARE_ACCESS_READ)) {
2893 		/*
2894 		 * Try to open it for read access too,
2895 		 * so the buffer cache can read data.
2896 		 */
2897 		readtoo = 1;
2898 		accessMode |= NFS_OPEN_SHARE_ACCESS_READ;
2899 	}
2900 tryagain:
2901 	error = nfs4_open_rpc(nofp, ctx, &cn, NULL, dvp, &vp, NFS_OPEN_NOCREATE, accessMode, denyMode);
2902 	if (error) {
2903 		if (!nfs_mount_state_error_should_restart(error) &&
2904 		    (error != EINTR) && (error != ERESTART) && readtoo) {
2905 			/* try again without the extra read access */
2906 			accessMode &= ~NFS_OPEN_SHARE_ACCESS_READ;
2907 			readtoo = 0;
2908 			goto tryagain;
2909 		}
2910 		goto out;
2911 	}
2912 	nfs_open_file_add_open(nofp, accessMode, denyMode, 0);
2913 out:
2914 	if (filename && (filename != &smallname[0])) {
2915 		kfree_data(filename, namelen + 1);
2916 	}
2917 	if (vname) {
2918 		vnode_putname(vname);
2919 	}
2920 	if (dvp != NULLVP) {
2921 		vnode_put(dvp);
2922 	}
2923 	return error;
2924 }
2925 #endif /* CONFIG_NFS4 */
2926 
2927 int
nfs_vnop_mmap(struct vnop_mmap_args * ap)2928 nfs_vnop_mmap(
2929 	struct vnop_mmap_args /* {
2930                                *  struct vnodeop_desc *a_desc;
2931                                *  vnode_t a_vp;
2932                                *  int a_fflags;
2933                                *  vfs_context_t a_context;
2934                                *  } */*ap)
2935 {
2936 	vfs_context_t ctx = ap->a_context;
2937 	vnode_t vp = ap->a_vp;
2938 	nfsnode_t np = VTONFS(vp);
2939 	int error = 0, delegated = 0;
2940 	uint8_t accessMode, denyMode;
2941 	struct nfsmount *nmp;
2942 	struct nfs_open_owner *noop = NULL;
2943 	struct nfs_open_file *nofp = NULL;
2944 
2945 	nmp = VTONMP(vp);
2946 	if (nfs_mount_gone(nmp)) {
2947 		return ENXIO;
2948 	}
2949 
2950 	if (!vnode_isreg(vp) || !(ap->a_fflags & (PROT_READ | PROT_WRITE))) {
2951 		return EINVAL;
2952 	}
2953 	if (np->n_flag & NREVOKE) {
2954 		return EIO;
2955 	}
2956 
2957 	/*
2958 	 * fflags contains some combination of: PROT_READ, PROT_WRITE
2959 	 * Since it's not possible to mmap() without having the file open for reading,
2960 	 * read access is always there (regardless if PROT_READ is not set).
2961 	 */
2962 	accessMode = NFS_OPEN_SHARE_ACCESS_READ;
2963 	if (ap->a_fflags & PROT_WRITE) {
2964 		accessMode |= NFS_OPEN_SHARE_ACCESS_WRITE;
2965 	}
2966 	denyMode = NFS_OPEN_SHARE_DENY_NONE;
2967 
2968 	noop = nfs_open_owner_find(nmp, vfs_context_ucred(ctx), vfs_context_proc(ctx), 1);
2969 	if (!noop) {
2970 		return ENOMEM;
2971 	}
2972 
2973 restart:
2974 	error = nfs_mount_state_in_use_start(nmp, NULL);
2975 	if (error) {
2976 		nfs_open_owner_rele(noop);
2977 		return NFS_MAPERR(error);
2978 	}
2979 	if (np->n_flag & NREVOKE) {
2980 		error = EIO;
2981 		nfs_mount_state_in_use_end(nmp, 0);
2982 		nfs_open_owner_rele(noop);
2983 		return NFS_MAPERR(error);
2984 	}
2985 
2986 	error = nfs_open_file_find(np, noop, &nofp, 0, 0, 1);
2987 	if (error || (!error && (nofp->nof_flags & NFS_OPEN_FILE_LOST))) {
2988 		NP(np, "nfs_vnop_mmap: no open file for owner, error %d, %d", error, kauth_cred_getuid(noop->noo_cred));
2989 		error = EPERM;
2990 	}
2991 #if CONFIG_NFS4
2992 	if (!error && (nofp->nof_flags & NFS_OPEN_FILE_REOPEN)) {
2993 		error = nfs4_reopen(nofp, NULL);
2994 		nofp = NULL;
2995 		if (!error) {
2996 			nfs_mount_state_in_use_end(nmp, 0);
2997 			goto restart;
2998 		}
2999 	}
3000 #endif
3001 	if (!error) {
3002 		error = nfs_open_file_set_busy(nofp, NULL);
3003 	}
3004 	if (error) {
3005 		nofp = NULL;
3006 		goto out;
3007 	}
3008 
3009 	/*
3010 	 * The open reference for mmap must mirror an existing open because
3011 	 * we may need to reclaim it after the file is closed.
3012 	 * So grab another open count matching the accessMode passed in.
3013 	 * If we already had an mmap open, prefer read/write without deny mode.
3014 	 * This means we may have to drop the current mmap open first.
3015 	 *
3016 	 * N.B. We should have an open for the mmap, because, mmap was
3017 	 * called on an open descriptor, or we've created an open for read
3018 	 * from reading the first page for execve. However, if we piggy
3019 	 * backed on an existing NFS_OPEN_SHARE_ACCESS_READ/NFS_OPEN_SHARE_DENY_NONE
3020 	 * that open may have closed.
3021 	 */
3022 
3023 	if (!(nofp->nof_access & NFS_OPEN_SHARE_ACCESS_READ)) {
3024 		if (nofp->nof_flags & NFS_OPEN_FILE_NEEDCLOSE) {
3025 			/* We shouldn't get here. We've already open the file for execve */
3026 			NP(np, "nfs_vnop_mmap: File already needs close access: 0x%x, cred: %d thread: %lld",
3027 			    nofp->nof_access, kauth_cred_getuid(nofp->nof_owner->noo_cred), thread_tid(vfs_context_thread(ctx)));
3028 		}
3029 		/*
3030 		 * mmapings for execve are just for read. Get out with EPERM if the accessMode is not ACCESS_READ
3031 		 * or the access would be denied. Other accesses should have an open descriptor for the mapping.
3032 		 */
3033 		if (accessMode != NFS_OPEN_SHARE_ACCESS_READ || (accessMode & nofp->nof_deny)) {
3034 			/* not asking for just read access -> fail */
3035 			error = EPERM;
3036 			goto out;
3037 		}
3038 		/* we don't have the file open, so open it for read access */
3039 		if (nmp->nm_vers < NFS_VER4) {
3040 			/* NFS v2/v3 opens are always allowed - so just add it. */
3041 			nfs_open_file_add_open(nofp, NFS_OPEN_SHARE_ACCESS_READ, NFS_OPEN_SHARE_DENY_NONE, 0);
3042 			error = 0;
3043 		}
3044 #if CONFIG_NFS4
3045 		else {
3046 			error = nfs4_open(np, nofp, NFS_OPEN_SHARE_ACCESS_READ, NFS_OPEN_SHARE_DENY_NONE, ctx);
3047 		}
3048 #endif
3049 		if (!error) {
3050 			nofp->nof_flags |= NFS_OPEN_FILE_NEEDCLOSE;
3051 		}
3052 		if (error) {
3053 			goto out;
3054 		}
3055 	}
3056 
3057 	/* determine deny mode for open */
3058 	if (accessMode == NFS_OPEN_SHARE_ACCESS_BOTH) {
3059 		if (nofp->nof_d_rw || nofp->nof_d_rw_dw || nofp->nof_d_rw_drw) {
3060 			delegated = 1;
3061 			if (nofp->nof_d_rw) {
3062 				denyMode = NFS_OPEN_SHARE_DENY_NONE;
3063 			} else if (nofp->nof_d_rw_dw) {
3064 				denyMode = NFS_OPEN_SHARE_DENY_WRITE;
3065 			} else if (nofp->nof_d_rw_drw) {
3066 				denyMode = NFS_OPEN_SHARE_DENY_BOTH;
3067 			}
3068 		} else if (nofp->nof_rw || nofp->nof_rw_dw || nofp->nof_rw_drw) {
3069 			delegated = 0;
3070 			if (nofp->nof_rw) {
3071 				denyMode = NFS_OPEN_SHARE_DENY_NONE;
3072 			} else if (nofp->nof_rw_dw) {
3073 				denyMode = NFS_OPEN_SHARE_DENY_WRITE;
3074 			} else if (nofp->nof_rw_drw) {
3075 				denyMode = NFS_OPEN_SHARE_DENY_BOTH;
3076 			}
3077 		} else {
3078 			error = EPERM;
3079 		}
3080 	} else { /* NFS_OPEN_SHARE_ACCESS_READ */
3081 		if (nofp->nof_d_r || nofp->nof_d_r_dw || nofp->nof_d_r_drw) {
3082 			delegated = 1;
3083 			if (nofp->nof_d_r) {
3084 				denyMode = NFS_OPEN_SHARE_DENY_NONE;
3085 			} else if (nofp->nof_d_r_dw) {
3086 				denyMode = NFS_OPEN_SHARE_DENY_WRITE;
3087 			} else if (nofp->nof_d_r_drw) {
3088 				denyMode = NFS_OPEN_SHARE_DENY_BOTH;
3089 			}
3090 		} else if (nofp->nof_r || nofp->nof_r_dw || nofp->nof_r_drw) {
3091 			delegated = 0;
3092 			if (nofp->nof_r) {
3093 				denyMode = NFS_OPEN_SHARE_DENY_NONE;
3094 			} else if (nofp->nof_r_dw) {
3095 				denyMode = NFS_OPEN_SHARE_DENY_WRITE;
3096 			} else if (nofp->nof_r_drw) {
3097 				denyMode = NFS_OPEN_SHARE_DENY_BOTH;
3098 			}
3099 		} else if (nofp->nof_d_rw || nofp->nof_d_rw_dw || nofp->nof_d_rw_drw) {
3100 			/*
3101 			 * This clause and the one below is to co-opt a read write access
3102 			 * for a read only mmaping. We probably got here in that an
3103 			 * existing rw open for an executable file already exists.
3104 			 */
3105 			delegated = 1;
3106 			accessMode = NFS_OPEN_SHARE_ACCESS_BOTH;
3107 			if (nofp->nof_d_rw) {
3108 				denyMode = NFS_OPEN_SHARE_DENY_NONE;
3109 			} else if (nofp->nof_d_rw_dw) {
3110 				denyMode = NFS_OPEN_SHARE_DENY_WRITE;
3111 			} else if (nofp->nof_d_rw_drw) {
3112 				denyMode = NFS_OPEN_SHARE_DENY_BOTH;
3113 			}
3114 		} else if (nofp->nof_rw || nofp->nof_rw_dw || nofp->nof_rw_drw) {
3115 			delegated = 0;
3116 			accessMode = NFS_OPEN_SHARE_ACCESS_BOTH;
3117 			if (nofp->nof_rw) {
3118 				denyMode = NFS_OPEN_SHARE_DENY_NONE;
3119 			} else if (nofp->nof_rw_dw) {
3120 				denyMode = NFS_OPEN_SHARE_DENY_WRITE;
3121 			} else if (nofp->nof_rw_drw) {
3122 				denyMode = NFS_OPEN_SHARE_DENY_BOTH;
3123 			}
3124 		} else {
3125 			error = EPERM;
3126 		}
3127 	}
3128 	if (error) { /* mmap mode without proper open mode */
3129 		goto out;
3130 	}
3131 
3132 	/*
3133 	 * If the existing mmap access is more than the new access OR the
3134 	 * existing access is the same and the existing deny mode is less,
3135 	 * then we'll stick with the existing mmap open mode.
3136 	 */
3137 	if ((nofp->nof_mmap_access > accessMode) ||
3138 	    ((nofp->nof_mmap_access == accessMode) && (nofp->nof_mmap_deny <= denyMode))) {
3139 		goto out;
3140 	}
3141 
3142 	/* update mmap open mode */
3143 	if (nofp->nof_mmap_access) {
3144 		error = nfs_close(np, nofp, nofp->nof_mmap_access, nofp->nof_mmap_deny, ctx);
3145 		if (error) {
3146 			if (!nfs_mount_state_error_should_restart(error)) {
3147 				NP(np, "nfs_vnop_mmap: close of previous mmap mode failed: %d, %d", error, kauth_cred_getuid(nofp->nof_owner->noo_cred));
3148 			}
3149 			NP(np, "nfs_vnop_mmap: update, close error %d, %d", error, kauth_cred_getuid(nofp->nof_owner->noo_cred));
3150 			goto out;
3151 		}
3152 		nofp->nof_mmap_access = nofp->nof_mmap_deny = 0;
3153 	}
3154 
3155 	nfs_open_file_add_open(nofp, accessMode, denyMode, delegated);
3156 	nofp->nof_mmap_access = accessMode;
3157 	nofp->nof_mmap_deny = denyMode;
3158 
3159 out:
3160 	if (nofp) {
3161 		nfs_open_file_clear_busy(nofp);
3162 	}
3163 	if (nfs_mount_state_in_use_end(nmp, error)) {
3164 		nofp = NULL;
3165 		goto restart;
3166 	}
3167 	if (noop) {
3168 		nfs_open_owner_rele(noop);
3169 	}
3170 
3171 	if (!error) {
3172 		int ismapped = 0;
3173 		nfs_node_lock_force(np);
3174 		if ((np->n_flag & NISMAPPED) == 0) {
3175 			np->n_flag |= NISMAPPED;
3176 			ismapped = 1;
3177 		}
3178 		nfs_node_unlock(np);
3179 		if (ismapped) {
3180 			lck_mtx_lock(&nmp->nm_lock);
3181 			nmp->nm_state &= ~NFSSTA_SQUISHY;
3182 			nmp->nm_curdeadtimeout = nmp->nm_deadtimeout;
3183 			if (nmp->nm_curdeadtimeout <= 0) {
3184 				nmp->nm_deadto_start = 0;
3185 			}
3186 			nmp->nm_mappers++;
3187 			lck_mtx_unlock(&nmp->nm_lock);
3188 		}
3189 	}
3190 
3191 	return NFS_MAPERR(error);
3192 }
3193 
3194 int
nfs_vnop_mmap_check(struct vnop_mmap_check_args * ap)3195 nfs_vnop_mmap_check(
3196 	struct vnop_mmap_check_args /* {
3197                                      *  struct vnodeop_desc *a_desc;
3198                                      *  vnode_t a_vp;
3199                                      *  int a_flags;
3200                                      *  vfs_context_t a_context;
3201                                      *  } */*ap)
3202 {
3203 	vfs_context_t ctx = ap->a_context;
3204 	vnode_t vp = ap->a_vp;
3205 	struct nfsmount *nmp = VTONMP(vp);
3206 	struct vnop_access_args naa;
3207 	int error = 0;
3208 
3209 	if (nfs_mount_gone(nmp)) {
3210 		return ENXIO;
3211 	}
3212 
3213 	if (vnode_isreg(vp)) {
3214 		/*
3215 		 * We only need to ensure that a page-in will be
3216 		 * possible with these credentials.  Everything
3217 		 * else has been checked at other layers.
3218 		 */
3219 		naa.a_desc = &vnop_access_desc;
3220 		naa.a_vp = vp;
3221 		naa.a_action = KAUTH_VNODE_READ_DATA;
3222 		naa.a_context = ctx;
3223 
3224 		/* compute actual success/failure based on accessibility */
3225 		error = nfs_vnop_access(&naa);
3226 	}
3227 
3228 	return NFS_MAPERR(error);
3229 }
3230 
3231 int
nfs_vnop_mnomap(struct vnop_mnomap_args * ap)3232 nfs_vnop_mnomap(
3233 	struct vnop_mnomap_args /* {
3234                                  *  struct vnodeop_desc *a_desc;
3235                                  *  vnode_t a_vp;
3236                                  *  vfs_context_t a_context;
3237                                  *  } */*ap)
3238 {
3239 	vfs_context_t ctx = ap->a_context;
3240 	vnode_t vp = ap->a_vp;
3241 	nfsnode_t np = VTONFS(vp);
3242 	struct nfsmount *nmp;
3243 	struct nfs_open_file *nofp = NULL;
3244 	off_t size;
3245 	int error;
3246 	int is_mapped_flag = 0;
3247 
3248 	nmp = VTONMP(vp);
3249 	if (nfs_mount_gone(nmp)) {
3250 		return ENXIO;
3251 	}
3252 
3253 	nfs_node_lock_force(np);
3254 	if (np->n_flag & NISMAPPED) {
3255 		is_mapped_flag = 1;
3256 		np->n_flag &= ~NISMAPPED;
3257 	}
3258 	nfs_node_unlock(np);
3259 	if (is_mapped_flag) {
3260 		lck_mtx_lock(&nmp->nm_lock);
3261 		if (nmp->nm_mappers) {
3262 			nmp->nm_mappers--;
3263 		} else {
3264 			NP(np, "nfs_vnop_mnomap: removing mmap reference from mount, but mount has no files mmapped");
3265 		}
3266 		lck_mtx_unlock(&nmp->nm_lock);
3267 	}
3268 
3269 	/* flush buffers/ubc before we drop the open (in case it's our last open) */
3270 	nfs_flush(np, MNT_WAIT, vfs_context_thread(ctx), V_IGNORE_WRITEERR);
3271 	if (UBCINFOEXISTS(vp) && (size = ubc_getsize(vp))) {
3272 		ubc_msync(vp, 0, size, NULL, UBC_PUSHALL | UBC_SYNC);
3273 	}
3274 
3275 	/* walk all open files and close all mmap opens */
3276 loop:
3277 	error = nfs_mount_state_in_use_start(nmp, NULL);
3278 	if (error) {
3279 		return NFS_MAPERR(error);
3280 	}
3281 	lck_mtx_lock(&np->n_openlock);
3282 	TAILQ_FOREACH(nofp, &np->n_opens, nof_link) {
3283 		if (!nofp->nof_mmap_access) {
3284 			continue;
3285 		}
3286 		lck_mtx_unlock(&np->n_openlock);
3287 #if CONFIG_NFS4
3288 		if (nofp->nof_flags & NFS_OPEN_FILE_REOPEN) {
3289 			error = nfs4_reopen(nofp, NULL);
3290 			if (!error) {
3291 				nfs_mount_state_in_use_end(nmp, 0);
3292 				goto loop;
3293 			}
3294 		}
3295 #endif
3296 		if (!error) {
3297 			error = nfs_open_file_set_busy(nofp, NULL);
3298 		}
3299 		if (error) {
3300 			lck_mtx_lock(&np->n_openlock);
3301 			break;
3302 		}
3303 		if (nofp->nof_mmap_access) {
3304 			error = nfs_close(np, nofp, nofp->nof_mmap_access, nofp->nof_mmap_deny, ctx);
3305 			if (!nfs_mount_state_error_should_restart(error)) {
3306 				if (error) { /* not a state-operation-restarting error, so just clear the access */
3307 					NP(np, "nfs_vnop_mnomap: close of mmap mode failed: %d, %d", error, kauth_cred_getuid(nofp->nof_owner->noo_cred));
3308 				}
3309 				nofp->nof_mmap_access = nofp->nof_mmap_deny = 0;
3310 			}
3311 			if (error) {
3312 				NP(np, "nfs_vnop_mnomap: error %d, %d", error, kauth_cred_getuid(nofp->nof_owner->noo_cred));
3313 			}
3314 		}
3315 		nfs_open_file_clear_busy(nofp);
3316 		nfs_mount_state_in_use_end(nmp, error);
3317 		goto loop;
3318 	}
3319 	lck_mtx_unlock(&np->n_openlock);
3320 	nfs_mount_state_in_use_end(nmp, error);
3321 	return NFS_MAPERR(error);
3322 }
3323 
3324 /*
3325  * Search a node's lock owner list for the owner for this process.
3326  * If not found and "alloc" is set, then allocate a new one.
3327  */
3328 struct nfs_lock_owner *
nfs_lock_owner_find(nfsnode_t np,proc_t p,caddr_t lockid,int flags)3329 nfs_lock_owner_find(nfsnode_t np, proc_t p, caddr_t lockid, int flags)
3330 {
3331 	pid_t pid = proc_pid(p);
3332 	struct timeval ptv;
3333 	int alloc = flags & NFS_LOCK_OWNER_FIND_ALLOC;
3334 	int dequeue = flags & NFS_LOCK_OWNER_FIND_DEQUEUE;
3335 	struct nfs_lock_owner *nlop, *newnlop = NULL;
3336 
3337 tryagain:
3338 	lck_mtx_lock(&np->n_openlock);
3339 	TAILQ_FOREACH(nlop, &np->n_lock_owners, nlo_link) {
3340 		os_ref_count_t newcount;
3341 
3342 		if (lockid != 0 && lockid == nlop->nlo_lockid) {
3343 			break;
3344 		}
3345 		if (nlop->nlo_pid != pid) {
3346 			continue;
3347 		}
3348 		proc_starttime(p, &ptv);
3349 		if (timevalcmp(&nlop->nlo_pid_start, &ptv, ==)) {
3350 			break;
3351 		}
3352 		/* stale lock owner... reuse it if we can */
3353 		if (os_ref_get_count(&nlop->nlo_refcnt)) {
3354 			TAILQ_REMOVE(&np->n_lock_owners, nlop, nlo_link);
3355 			nlop->nlo_flags &= ~NFS_LOCK_OWNER_LINK;
3356 			newcount = os_ref_release_locked(&nlop->nlo_refcnt);
3357 			lck_mtx_unlock(&np->n_openlock);
3358 			goto tryagain;
3359 		}
3360 		proc_starttime(p, &nlop->nlo_pid_start);
3361 		nlop->nlo_seqid = 0;
3362 		nlop->nlo_stategenid = 0;
3363 		break;
3364 	}
3365 
3366 	if (dequeue && nlop && (nlop->nlo_flags & NFS_LOCK_OWNER_LINK)) {
3367 		TAILQ_REMOVE(&np->n_lock_owners, nlop, nlo_link);
3368 		nlop->nlo_flags &= ~NFS_LOCK_OWNER_LINK;
3369 	}
3370 
3371 	if (!nlop && !newnlop && alloc) {
3372 		lck_mtx_unlock(&np->n_openlock);
3373 		newnlop = kalloc_type(struct nfs_lock_owner,
3374 		    Z_WAITOK | Z_ZERO | Z_NOFAIL);
3375 		lck_mtx_init(&newnlop->nlo_lock, &nfs_open_grp, LCK_ATTR_NULL);
3376 		newnlop->nlo_pid = pid;
3377 		newnlop->nlo_lockid = lockid;
3378 		proc_starttime(p, &newnlop->nlo_pid_start);
3379 		newnlop->nlo_name = OSAddAtomic(1, &nfs_lock_owner_seqnum);
3380 		TAILQ_INIT(&newnlop->nlo_locks);
3381 		goto tryagain;
3382 	}
3383 	if (!nlop && newnlop) {
3384 		newnlop->nlo_flags |= NFS_LOCK_OWNER_LINK;
3385 		os_ref_init(&newnlop->nlo_refcnt, NULL);
3386 		TAILQ_INSERT_HEAD(&np->n_lock_owners, newnlop, nlo_link);
3387 		nlop = newnlop;
3388 	}
3389 	lck_mtx_unlock(&np->n_openlock);
3390 
3391 	if (newnlop && (nlop != newnlop)) {
3392 		nfs_lock_owner_destroy(newnlop);
3393 	}
3394 
3395 	if (nlop && !dequeue) {
3396 		nfs_lock_owner_ref(nlop);
3397 	}
3398 
3399 	return nlop;
3400 }
3401 
3402 /*
3403  * destroy a lock owner that's no longer needed
3404  */
3405 void
nfs_lock_owner_destroy(struct nfs_lock_owner * nlop)3406 nfs_lock_owner_destroy(struct nfs_lock_owner *nlop)
3407 {
3408 	if (nlop->nlo_open_owner) {
3409 		nfs_open_owner_rele(nlop->nlo_open_owner);
3410 		nlop->nlo_open_owner = NULL;
3411 	}
3412 	lck_mtx_destroy(&nlop->nlo_lock, &nfs_open_grp);
3413 	kfree_type(struct nfs_lock_owner, nlop);
3414 }
3415 
3416 /*
3417  * acquire a reference count on a lock owner
3418  */
3419 void
nfs_lock_owner_ref(struct nfs_lock_owner * nlop)3420 nfs_lock_owner_ref(struct nfs_lock_owner *nlop)
3421 {
3422 	lck_mtx_lock(&nlop->nlo_lock);
3423 	os_ref_retain_locked(&nlop->nlo_refcnt);
3424 	lck_mtx_unlock(&nlop->nlo_lock);
3425 }
3426 
3427 #if !CONFIG_NFS4
3428 #define __no_nfsv4_unused      __unused
3429 #else
3430 #define __no_nfsv4_unused      /* nothing */
3431 #endif
3432 
3433 /*
3434  * drop a reference count on a lock owner and destroy it if
3435  * it is no longer referenced and no longer on the mount's list.
3436  */
3437 void
nfs_lock_owner_rele(nfsnode_t np __no_nfsv4_unused,struct nfs_lock_owner * nlop,thread_t thd __no_nfsv4_unused,kauth_cred_t cred __no_nfsv4_unused)3438 nfs_lock_owner_rele(nfsnode_t np __no_nfsv4_unused, struct nfs_lock_owner *nlop, thread_t thd __no_nfsv4_unused, kauth_cred_t cred __no_nfsv4_unused)
3439 {
3440 	os_ref_count_t newcount;
3441 
3442 	lck_mtx_lock(&nlop->nlo_lock);
3443 	if (os_ref_get_count(&nlop->nlo_refcnt) < 1) {
3444 		panic("nfs_lock_owner_rele: no refcnt");
3445 	}
3446 	newcount = os_ref_release_locked(&nlop->nlo_refcnt);
3447 	if (!newcount && (nlop->nlo_flags & NFS_LOCK_OWNER_BUSY)) {
3448 		panic("nfs_lock_owner_rele: busy");
3449 	}
3450 	/* XXX we may potentially want to clean up idle/unused lock owner structures */
3451 	if (newcount || (nlop->nlo_flags & NFS_LOCK_OWNER_LINK)) {
3452 		lck_mtx_unlock(&nlop->nlo_lock);
3453 		return;
3454 	}
3455 
3456 
3457 #if CONFIG_NFS4
3458 	if (NFSTONMP(np)->nm_vers >= NFS_VER4) {
3459 		int error = nfs4_release_lockowner_rpc(np, nlop, thd, cred);
3460 		if (error) {
3461 			NP(np, "nfs_lock_owner_rele: was not able to release lock owner. error %d", error);
3462 		}
3463 	}
3464 #endif /* CONFIG_NFS4 */
3465 
3466 	/* owner is no longer referenced or linked to mount, so destroy it */
3467 	lck_mtx_unlock(&nlop->nlo_lock);
3468 	nfs_lock_owner_destroy(nlop);
3469 }
3470 
3471 /*
3472  * Mark a lock owner as busy because we are about to
3473  * start an operation that uses and updates lock owner state.
3474  */
3475 int
nfs_lock_owner_set_busy(struct nfs_lock_owner * nlop,thread_t thd)3476 nfs_lock_owner_set_busy(struct nfs_lock_owner *nlop, thread_t thd)
3477 {
3478 	struct nfsmount *nmp;
3479 	struct timespec ts = { .tv_sec = 2, .tv_nsec = 0 };
3480 	int error = 0, slpflag;
3481 
3482 	nmp = nlop->nlo_open_owner->noo_mount;
3483 	if (nfs_mount_gone(nmp)) {
3484 		return ENXIO;
3485 	}
3486 	slpflag = (NMFLAG(nmp, INTR) && thd) ? PCATCH : 0;
3487 
3488 	lck_mtx_lock(&nlop->nlo_lock);
3489 	while (nlop->nlo_flags & NFS_LOCK_OWNER_BUSY) {
3490 		if ((error = nfs_sigintr(nmp, NULL, thd, 0))) {
3491 			break;
3492 		}
3493 		nlop->nlo_flags |= NFS_LOCK_OWNER_WANT;
3494 		msleep(nlop, &nlop->nlo_lock, slpflag, "nfs_lock_owner_set_busy", &ts);
3495 		slpflag = 0;
3496 	}
3497 	if (!error) {
3498 		nlop->nlo_flags |= NFS_LOCK_OWNER_BUSY;
3499 	}
3500 	lck_mtx_unlock(&nlop->nlo_lock);
3501 
3502 	return error;
3503 }
3504 
3505 /*
3506  * Clear the busy flag on a lock owner and wake up anyone waiting
3507  * to mark it busy.
3508  */
3509 void
nfs_lock_owner_clear_busy(struct nfs_lock_owner * nlop)3510 nfs_lock_owner_clear_busy(struct nfs_lock_owner *nlop)
3511 {
3512 	int wanted;
3513 
3514 	lck_mtx_lock(&nlop->nlo_lock);
3515 	if (!(nlop->nlo_flags & NFS_LOCK_OWNER_BUSY)) {
3516 		panic("nfs_lock_owner_clear_busy");
3517 	}
3518 	wanted = (nlop->nlo_flags & NFS_LOCK_OWNER_WANT);
3519 	nlop->nlo_flags &= ~(NFS_LOCK_OWNER_BUSY | NFS_LOCK_OWNER_WANT);
3520 	lck_mtx_unlock(&nlop->nlo_lock);
3521 	if (wanted) {
3522 		wakeup(nlop);
3523 	}
3524 }
3525 
3526 /*
3527  * Insert a held lock into a lock owner's sorted list.
3528  * (flock locks are always inserted at the head the list)
3529  */
3530 void
nfs_lock_owner_insert_held_lock(struct nfs_lock_owner * nlop,struct nfs_file_lock * newnflp)3531 nfs_lock_owner_insert_held_lock(struct nfs_lock_owner *nlop, struct nfs_file_lock *newnflp)
3532 {
3533 	struct nfs_file_lock *nflp;
3534 
3535 	/* insert new lock in lock owner's held lock list */
3536 	lck_mtx_lock(&nlop->nlo_lock);
3537 	if ((newnflp->nfl_flags & NFS_FILE_LOCK_STYLE_MASK) == NFS_FILE_LOCK_STYLE_FLOCK) {
3538 		TAILQ_INSERT_HEAD(&nlop->nlo_locks, newnflp, nfl_lolink);
3539 	} else {
3540 		TAILQ_FOREACH(nflp, &nlop->nlo_locks, nfl_lolink) {
3541 			if (newnflp->nfl_start < nflp->nfl_start) {
3542 				break;
3543 			}
3544 		}
3545 		if (nflp) {
3546 			TAILQ_INSERT_BEFORE(nflp, newnflp, nfl_lolink);
3547 		} else {
3548 			TAILQ_INSERT_TAIL(&nlop->nlo_locks, newnflp, nfl_lolink);
3549 		}
3550 	}
3551 	lck_mtx_unlock(&nlop->nlo_lock);
3552 }
3553 
3554 /*
3555  * Get a file lock structure for this lock owner.
3556  */
3557 struct nfs_file_lock *
nfs_file_lock_alloc(struct nfs_lock_owner * nlop)3558 nfs_file_lock_alloc(struct nfs_lock_owner *nlop)
3559 {
3560 	struct nfs_file_lock *nflp = NULL;
3561 
3562 	lck_mtx_lock(&nlop->nlo_lock);
3563 	if (!nlop->nlo_alock.nfl_owner) {
3564 		nflp = &nlop->nlo_alock;
3565 		nflp->nfl_owner = nlop;
3566 	}
3567 	lck_mtx_unlock(&nlop->nlo_lock);
3568 	if (!nflp) {
3569 		nflp = kalloc_type(struct nfs_file_lock,
3570 		    Z_WAITOK | Z_ZERO | Z_NOFAIL);
3571 		nflp->nfl_flags |= NFS_FILE_LOCK_ALLOC;
3572 		nflp->nfl_owner = nlop;
3573 	}
3574 	nfs_lock_owner_ref(nlop);
3575 	return nflp;
3576 }
3577 
3578 /*
3579  * destroy the given NFS file lock structure
3580  */
3581 void
nfs_file_lock_destroy(nfsnode_t np,struct nfs_file_lock * nflp,thread_t thd,kauth_cred_t cred)3582 nfs_file_lock_destroy(nfsnode_t np, struct nfs_file_lock *nflp, thread_t thd, kauth_cred_t cred)
3583 {
3584 	struct nfs_lock_owner *nlop = nflp->nfl_owner;
3585 
3586 	if (nflp->nfl_flags & NFS_FILE_LOCK_ALLOC) {
3587 		nflp->nfl_owner = NULL;
3588 		kfree_type(struct nfs_file_lock, nflp);
3589 	} else {
3590 		lck_mtx_lock(&nlop->nlo_lock);
3591 		bzero(nflp, sizeof(*nflp));
3592 		lck_mtx_unlock(&nlop->nlo_lock);
3593 	}
3594 	nfs_lock_owner_rele(np, nlop, thd, cred);
3595 }
3596 
3597 /*
3598  * Check if one file lock conflicts with another.
3599  * (nflp1 is the new lock.  nflp2 is the existing lock.)
3600  */
3601 int
nfs_file_lock_conflict(struct nfs_file_lock * nflp1,struct nfs_file_lock * nflp2,int * willsplit)3602 nfs_file_lock_conflict(struct nfs_file_lock *nflp1, struct nfs_file_lock *nflp2, int *willsplit)
3603 {
3604 	/* no conflict if lock is dead */
3605 	if ((nflp1->nfl_flags & NFS_FILE_LOCK_DEAD) || (nflp2->nfl_flags & NFS_FILE_LOCK_DEAD)) {
3606 		return 0;
3607 	}
3608 	/* no conflict if it's ours - unless the lock style doesn't match */
3609 	if ((nflp1->nfl_owner == nflp2->nfl_owner) &&
3610 	    ((nflp1->nfl_flags & NFS_FILE_LOCK_STYLE_MASK) == (nflp2->nfl_flags & NFS_FILE_LOCK_STYLE_MASK))) {
3611 		if (willsplit && (nflp1->nfl_type != nflp2->nfl_type) &&
3612 		    (nflp1->nfl_start > nflp2->nfl_start) &&
3613 		    (nflp1->nfl_end < nflp2->nfl_end)) {
3614 			*willsplit = 1;
3615 		}
3616 		return 0;
3617 	}
3618 	/* no conflict if ranges don't overlap */
3619 	if ((nflp1->nfl_start > nflp2->nfl_end) || (nflp1->nfl_end < nflp2->nfl_start)) {
3620 		return 0;
3621 	}
3622 	/* no conflict if neither lock is exclusive */
3623 	if ((nflp1->nfl_type != F_WRLCK) && (nflp2->nfl_type != F_WRLCK)) {
3624 		return 0;
3625 	}
3626 	/* conflict */
3627 	return 1;
3628 }
3629 
3630 #if CONFIG_NFS4
3631 /*
3632  * Send an NFSv4 LOCK RPC to the server.
3633  */
3634 int
nfs4_setlock_rpc(nfsnode_t np,struct nfs_open_file * nofp,struct nfs_file_lock * nflp,int reclaim,int flags,thread_t thd,kauth_cred_t cred)3635 nfs4_setlock_rpc(
3636 	nfsnode_t np,
3637 	struct nfs_open_file *nofp,
3638 	struct nfs_file_lock *nflp,
3639 	int reclaim,
3640 	int flags,
3641 	thread_t thd,
3642 	kauth_cred_t cred)
3643 {
3644 	struct nfs_lock_owner *nlop = nflp->nfl_owner;
3645 	struct nfsmount *nmp;
3646 	struct nfsm_chain nmreq, nmrep;
3647 	uint64_t xid;
3648 	uint32_t locktype;
3649 	int error = 0, lockerror = ENOENT, newlocker, numops, status;
3650 	struct nfsreq_secinfo_args si;
3651 
3652 	nmp = NFSTONMP(np);
3653 	if (nfs_mount_gone(nmp)) {
3654 		return ENXIO;
3655 	}
3656 	if (np->n_vattr.nva_flags & NFS_FFLAG_TRIGGER_REFERRAL) {
3657 		return EINVAL;
3658 	}
3659 
3660 	newlocker = (nlop->nlo_stategenid != nmp->nm_stategenid);
3661 	locktype = (nflp->nfl_flags & NFS_FILE_LOCK_WAIT) ?
3662 	    ((nflp->nfl_type == F_WRLCK) ?
3663 	    NFS_LOCK_TYPE_WRITEW :
3664 	    NFS_LOCK_TYPE_READW) :
3665 	    ((nflp->nfl_type == F_WRLCK) ?
3666 	    NFS_LOCK_TYPE_WRITE :
3667 	    NFS_LOCK_TYPE_READ);
3668 	if (newlocker) {
3669 		error = nfs_open_file_set_busy(nofp, thd);
3670 		if (error) {
3671 			return error;
3672 		}
3673 		error = nfs_open_owner_set_busy(nofp->nof_owner, thd);
3674 		if (error) {
3675 			nfs_open_file_clear_busy(nofp);
3676 			return error;
3677 		}
3678 		if (!nlop->nlo_open_owner) {
3679 			nfs_open_owner_ref(nofp->nof_owner);
3680 			nlop->nlo_open_owner = nofp->nof_owner;
3681 		}
3682 	}
3683 	error = nfs_lock_owner_set_busy(nlop, thd);
3684 	if (error) {
3685 		if (newlocker) {
3686 			nfs_open_owner_clear_busy(nofp->nof_owner);
3687 			nfs_open_file_clear_busy(nofp);
3688 		}
3689 		return error;
3690 	}
3691 
3692 	NFSREQ_SECINFO_SET(&si, np, NULL, 0, NULL, 0);
3693 	nfsm_chain_null(&nmreq);
3694 	nfsm_chain_null(&nmrep);
3695 
3696 	// PUTFH, GETATTR, LOCK
3697 	numops = 3;
3698 	nfsm_chain_build_alloc_init(error, &nmreq, 33 * NFSX_UNSIGNED);
3699 	nfsm_chain_add_compound_header(error, &nmreq, "lock", nmp->nm_minor_vers, numops);
3700 	numops--;
3701 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_PUTFH);
3702 	nfsm_chain_add_fh(error, &nmreq, NFS_VER4, np->n_fhp, np->n_fhsize);
3703 	numops--;
3704 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_GETATTR);
3705 	nfsm_chain_add_bitmap_supported(error, &nmreq, nfs_getattr_bitmap, nmp, np);
3706 	numops--;
3707 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_LOCK);
3708 	nfsm_chain_add_32(error, &nmreq, locktype);
3709 	nfsm_chain_add_32(error, &nmreq, reclaim);
3710 	nfsm_chain_add_64(error, &nmreq, nflp->nfl_start);
3711 	nfsm_chain_add_64(error, &nmreq, NFS_LOCK_LENGTH(nflp->nfl_start, nflp->nfl_end));
3712 	nfsm_chain_add_32(error, &nmreq, newlocker);
3713 	if (newlocker) {
3714 		nfsm_chain_add_32(error, &nmreq, nofp->nof_owner->noo_seqid);
3715 		nfsm_chain_add_stateid(error, &nmreq, &nofp->nof_stateid);
3716 		nfsm_chain_add_32(error, &nmreq, nlop->nlo_seqid);
3717 		nfsm_chain_add_lock_owner4(error, &nmreq, nmp, nlop);
3718 	} else {
3719 		nfsm_chain_add_stateid(error, &nmreq, &nlop->nlo_stateid);
3720 		nfsm_chain_add_32(error, &nmreq, nlop->nlo_seqid);
3721 	}
3722 	nfsm_chain_build_done(error, &nmreq);
3723 	nfsm_assert(error, (numops == 0), EPROTO);
3724 	nfsmout_if(error);
3725 
3726 	error = nfs_request2(np, NULL, &nmreq, NFSPROC4_COMPOUND, thd, cred, &si, flags | R_NOINTR, &nmrep, &xid, &status);
3727 
3728 	if ((lockerror = nfs_node_lock(np))) {
3729 		error = lockerror;
3730 	}
3731 	nfsm_chain_skip_tag(error, &nmrep);
3732 	nfsm_chain_get_32(error, &nmrep, numops);
3733 	nfsm_chain_op_check(error, &nmrep, NFS_OP_PUTFH);
3734 	nfsmout_if(error);
3735 	nfsm_chain_op_check(error, &nmrep, NFS_OP_GETATTR);
3736 	nfsm_chain_loadattr(error, &nmrep, np, NFS_VER4, &xid);
3737 	nfsmout_if(error);
3738 	nfsm_chain_op_check(error, &nmrep, NFS_OP_LOCK);
3739 	nfs_owner_seqid_increment(newlocker ? nofp->nof_owner : NULL, nlop, error);
3740 	nfsm_chain_get_stateid(error, &nmrep, &nlop->nlo_stateid);
3741 
3742 	/* Update the lock owner's stategenid once it appears the server has state for it. */
3743 	/* We determine this by noting the request was successful (we got a stateid). */
3744 	if (newlocker && !error) {
3745 		nlop->nlo_stategenid = nmp->nm_stategenid;
3746 	}
3747 nfsmout:
3748 	if (!lockerror) {
3749 		nfs_node_unlock(np);
3750 	}
3751 	nfs_lock_owner_clear_busy(nlop);
3752 	if (newlocker) {
3753 		nfs_open_owner_clear_busy(nofp->nof_owner);
3754 		nfs_open_file_clear_busy(nofp);
3755 	}
3756 	nfsm_chain_cleanup(&nmreq);
3757 	nfsm_chain_cleanup(&nmrep);
3758 	return error;
3759 }
3760 
3761 /*
3762  * Send an NFSv4 LOCKU RPC to the server.
3763  */
3764 int
nfs4_unlock_rpc(nfsnode_t np,struct nfs_lock_owner * nlop,int type,uint64_t start,uint64_t end,int flags,thread_t thd,kauth_cred_t cred)3765 nfs4_unlock_rpc(
3766 	nfsnode_t np,
3767 	struct nfs_lock_owner *nlop,
3768 	int type,
3769 	uint64_t start,
3770 	uint64_t end,
3771 	int flags,
3772 	thread_t thd,
3773 	kauth_cred_t cred)
3774 {
3775 	struct nfsmount *nmp;
3776 	struct nfsm_chain nmreq, nmrep;
3777 	uint64_t xid;
3778 	int error = 0, lockerror = ENOENT, numops, status;
3779 	struct nfsreq_secinfo_args si;
3780 
3781 	nmp = NFSTONMP(np);
3782 	if (nfs_mount_gone(nmp)) {
3783 		return ENXIO;
3784 	}
3785 	if (np->n_vattr.nva_flags & NFS_FFLAG_TRIGGER_REFERRAL) {
3786 		return EINVAL;
3787 	}
3788 
3789 	error = nfs_lock_owner_set_busy(nlop, NULL);
3790 	if (error) {
3791 		return error;
3792 	}
3793 
3794 	NFSREQ_SECINFO_SET(&si, np, NULL, 0, NULL, 0);
3795 	nfsm_chain_null(&nmreq);
3796 	nfsm_chain_null(&nmrep);
3797 
3798 	// PUTFH, GETATTR, LOCKU
3799 	numops = 3;
3800 	nfsm_chain_build_alloc_init(error, &nmreq, 26 * NFSX_UNSIGNED);
3801 	nfsm_chain_add_compound_header(error, &nmreq, "unlock", nmp->nm_minor_vers, numops);
3802 	numops--;
3803 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_PUTFH);
3804 	nfsm_chain_add_fh(error, &nmreq, NFS_VER4, np->n_fhp, np->n_fhsize);
3805 	numops--;
3806 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_GETATTR);
3807 	nfsm_chain_add_bitmap_supported(error, &nmreq, nfs_getattr_bitmap, nmp, np);
3808 	numops--;
3809 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_LOCKU);
3810 	nfsm_chain_add_32(error, &nmreq, (type == F_WRLCK) ? NFS_LOCK_TYPE_WRITE : NFS_LOCK_TYPE_READ);
3811 	nfsm_chain_add_32(error, &nmreq, nlop->nlo_seqid);
3812 	nfsm_chain_add_stateid(error, &nmreq, &nlop->nlo_stateid);
3813 	nfsm_chain_add_64(error, &nmreq, start);
3814 	nfsm_chain_add_64(error, &nmreq, NFS_LOCK_LENGTH(start, end));
3815 	nfsm_chain_build_done(error, &nmreq);
3816 	nfsm_assert(error, (numops == 0), EPROTO);
3817 	nfsmout_if(error);
3818 
3819 	error = nfs_request2(np, NULL, &nmreq, NFSPROC4_COMPOUND, thd, cred, &si, flags | R_NOINTR, &nmrep, &xid, &status);
3820 
3821 	if ((lockerror = nfs_node_lock(np))) {
3822 		error = lockerror;
3823 	}
3824 	nfsm_chain_skip_tag(error, &nmrep);
3825 	nfsm_chain_get_32(error, &nmrep, numops);
3826 	nfsm_chain_op_check(error, &nmrep, NFS_OP_PUTFH);
3827 	nfsmout_if(error);
3828 	nfsm_chain_op_check(error, &nmrep, NFS_OP_GETATTR);
3829 	nfsm_chain_loadattr(error, &nmrep, np, NFS_VER4, &xid);
3830 	nfsmout_if(error);
3831 	nfsm_chain_op_check(error, &nmrep, NFS_OP_LOCKU);
3832 	nfs_owner_seqid_increment(NULL, nlop, error);
3833 	nfsm_chain_get_stateid(error, &nmrep, &nlop->nlo_stateid);
3834 nfsmout:
3835 	if (!lockerror) {
3836 		nfs_node_unlock(np);
3837 	}
3838 	nfs_lock_owner_clear_busy(nlop);
3839 	nfsm_chain_cleanup(&nmreq);
3840 	nfsm_chain_cleanup(&nmrep);
3841 	return error;
3842 }
3843 
3844 /*
3845  * Send an NFSv4 LOCKT RPC to the server.
3846  */
3847 int
nfs4_getlock_rpc(nfsnode_t np,struct nfs_lock_owner * nlop,struct flock * fl,uint64_t start,uint64_t end,vfs_context_t ctx)3848 nfs4_getlock_rpc(
3849 	nfsnode_t np,
3850 	struct nfs_lock_owner *nlop,
3851 	struct flock *fl,
3852 	uint64_t start,
3853 	uint64_t end,
3854 	vfs_context_t ctx)
3855 {
3856 	struct nfsmount *nmp;
3857 	struct nfsm_chain nmreq, nmrep;
3858 	uint64_t xid, val64 = 0;
3859 	uint32_t val = 0;
3860 	int error = 0, lockerror, numops, status;
3861 	struct nfsreq_secinfo_args si;
3862 
3863 	nmp = NFSTONMP(np);
3864 	if (nfs_mount_gone(nmp)) {
3865 		return ENXIO;
3866 	}
3867 	if (np->n_vattr.nva_flags & NFS_FFLAG_TRIGGER_REFERRAL) {
3868 		return EINVAL;
3869 	}
3870 
3871 	lockerror = ENOENT;
3872 	NFSREQ_SECINFO_SET(&si, np, NULL, 0, NULL, 0);
3873 	nfsm_chain_null(&nmreq);
3874 	nfsm_chain_null(&nmrep);
3875 
3876 	// PUTFH, GETATTR, LOCKT
3877 	numops = 3;
3878 	nfsm_chain_build_alloc_init(error, &nmreq, 26 * NFSX_UNSIGNED);
3879 	nfsm_chain_add_compound_header(error, &nmreq, "locktest", nmp->nm_minor_vers, numops);
3880 	numops--;
3881 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_PUTFH);
3882 	nfsm_chain_add_fh(error, &nmreq, NFS_VER4, np->n_fhp, np->n_fhsize);
3883 	numops--;
3884 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_GETATTR);
3885 	nfsm_chain_add_bitmap_supported(error, &nmreq, nfs_getattr_bitmap, nmp, np);
3886 	numops--;
3887 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_LOCKT);
3888 	nfsm_chain_add_32(error, &nmreq, (fl->l_type == F_WRLCK) ? NFS_LOCK_TYPE_WRITE : NFS_LOCK_TYPE_READ);
3889 	nfsm_chain_add_64(error, &nmreq, start);
3890 	nfsm_chain_add_64(error, &nmreq, NFS_LOCK_LENGTH(start, end));
3891 	nfsm_chain_add_lock_owner4(error, &nmreq, nmp, nlop);
3892 	nfsm_chain_build_done(error, &nmreq);
3893 	nfsm_assert(error, (numops == 0), EPROTO);
3894 	nfsmout_if(error);
3895 
3896 	error = nfs_request(np, NULL, &nmreq, NFSPROC4_COMPOUND, ctx, &si, &nmrep, &xid, &status);
3897 
3898 	if ((lockerror = nfs_node_lock(np))) {
3899 		error = lockerror;
3900 	}
3901 	nfsm_chain_skip_tag(error, &nmrep);
3902 	nfsm_chain_get_32(error, &nmrep, numops);
3903 	nfsm_chain_op_check(error, &nmrep, NFS_OP_PUTFH);
3904 	nfsmout_if(error);
3905 	nfsm_chain_op_check(error, &nmrep, NFS_OP_GETATTR);
3906 	nfsm_chain_loadattr(error, &nmrep, np, NFS_VER4, &xid);
3907 	nfsmout_if(error);
3908 	nfsm_chain_op_check(error, &nmrep, NFS_OP_LOCKT);
3909 	if (error == NFSERR_DENIED) {
3910 		error = 0;
3911 		nfsm_chain_get_64(error, &nmrep, fl->l_start);
3912 		nfsm_chain_get_64(error, &nmrep, val64);
3913 		fl->l_len = (val64 == UINT64_MAX) ? 0 : val64;
3914 		nfsm_chain_get_32(error, &nmrep, val);
3915 		fl->l_type = (val == NFS_LOCK_TYPE_WRITE) ? F_WRLCK : F_RDLCK;
3916 		fl->l_pid = 0;
3917 		fl->l_whence = SEEK_SET;
3918 	} else if (!error) {
3919 		fl->l_type = F_UNLCK;
3920 	}
3921 nfsmout:
3922 	if (!lockerror) {
3923 		nfs_node_unlock(np);
3924 	}
3925 	nfsm_chain_cleanup(&nmreq);
3926 	nfsm_chain_cleanup(&nmrep);
3927 	return error;
3928 }
3929 #endif /* CONFIG_NFS4 */
3930 
3931 /*
3932  * Check for any conflicts with the given lock.
3933  *
3934  * Checking for a lock doesn't require the file to be opened.
3935  * So we skip all the open owner, open file, lock owner work
3936  * and just check for a conflicting lock.
3937  */
3938 int
nfs_advlock_getlock(nfsnode_t np,struct nfs_lock_owner * nlop,struct flock * fl,uint64_t start,uint64_t end,vfs_context_t ctx)3939 nfs_advlock_getlock(
3940 	nfsnode_t np,
3941 	struct nfs_lock_owner *nlop,
3942 	struct flock *fl,
3943 	uint64_t start,
3944 	uint64_t end,
3945 	vfs_context_t ctx)
3946 {
3947 	struct nfsmount *nmp;
3948 	struct nfs_file_lock *nflp;
3949 	int error = 0, answered = 0;
3950 
3951 	nmp = NFSTONMP(np);
3952 	if (nfs_mount_gone(nmp)) {
3953 		return ENXIO;
3954 	}
3955 
3956 restart:
3957 	if ((error = nfs_mount_state_in_use_start(nmp, vfs_context_thread(ctx)))) {
3958 		return error;
3959 	}
3960 
3961 	lck_mtx_lock(&np->n_openlock);
3962 	/* scan currently held locks for conflict */
3963 	TAILQ_FOREACH(nflp, &np->n_locks, nfl_link) {
3964 		if (nflp->nfl_flags & (NFS_FILE_LOCK_BLOCKED | NFS_FILE_LOCK_DEAD)) {
3965 			continue;
3966 		}
3967 		if ((start <= nflp->nfl_end) && (end >= nflp->nfl_start) &&
3968 		    ((fl->l_type == F_WRLCK) || (nflp->nfl_type == F_WRLCK))) {
3969 			break;
3970 		}
3971 	}
3972 	if (nflp) {
3973 		/* found a conflicting lock */
3974 		fl->l_type = nflp->nfl_type;
3975 		fl->l_pid = (nflp->nfl_flags & NFS_FILE_LOCK_STYLE_FLOCK) ? -1 : nflp->nfl_owner->nlo_pid;
3976 		fl->l_start = nflp->nfl_start;
3977 		fl->l_len = NFS_FLOCK_LENGTH(nflp->nfl_start, nflp->nfl_end);
3978 		fl->l_whence = SEEK_SET;
3979 		answered = 1;
3980 	} else if ((np->n_openflags & N_DELEG_WRITE) && !(np->n_openflags & N_DELEG_RETURN)) {
3981 		/*
3982 		 * If we have a write delegation, we know there can't be other
3983 		 * locks on the server.  So the answer is no conflicting lock found.
3984 		 */
3985 		fl->l_type = F_UNLCK;
3986 		answered = 1;
3987 	}
3988 	lck_mtx_unlock(&np->n_openlock);
3989 	if (answered) {
3990 		nfs_mount_state_in_use_end(nmp, 0);
3991 		return 0;
3992 	}
3993 
3994 	/* no conflict found locally, so ask the server */
3995 	error = nmp->nm_funcs->nf_getlock_rpc(np, nlop, fl, start, end, ctx);
3996 
3997 	if (nfs_mount_state_in_use_end(nmp, error)) {
3998 		goto restart;
3999 	}
4000 	return error;
4001 }
4002 
4003 /*
4004  * Acquire a file lock for the given range.
4005  *
4006  * Add the lock (request) to the lock queue.
4007  * Scan the lock queue for any conflicting locks.
4008  * If a conflict is found, block or return an error.
4009  * Once end of queue is reached, send request to the server.
4010  * If the server grants the lock, scan the lock queue and
4011  * update any existing locks.  Then (optionally) scan the
4012  * queue again to coalesce any locks adjacent to the new one.
4013  */
4014 int
nfs_advlock_setlock(nfsnode_t np,struct nfs_open_file * nofp,struct nfs_lock_owner * nlop,int op,uint64_t start,uint64_t end,int style,short type,vfs_context_t ctx)4015 nfs_advlock_setlock(
4016 	nfsnode_t np,
4017 	struct nfs_open_file *nofp,
4018 	struct nfs_lock_owner *nlop,
4019 	int op,
4020 	uint64_t start,
4021 	uint64_t end,
4022 	int style,
4023 	short type,
4024 	vfs_context_t ctx)
4025 {
4026 	struct nfsmount *nmp;
4027 	struct nfs_file_lock *newnflp, *nflp, *nflp2 = NULL, *nextnflp, *flocknflp = NULL;
4028 	struct nfs_file_lock *coalnflp;
4029 	int error = 0, error2, willsplit = 0, delay, slpflag, busy = 0, inuse = 0, restart, inqueue = 0;
4030 	struct timespec ts = { .tv_sec = 1, .tv_nsec = 0 };
4031 
4032 	nmp = NFSTONMP(np);
4033 	if (nfs_mount_gone(nmp)) {
4034 		return ENXIO;
4035 	}
4036 	slpflag = NMFLAG(nmp, INTR) ? PCATCH : 0;
4037 
4038 	if ((type != F_RDLCK) && (type != F_WRLCK)) {
4039 		return EINVAL;
4040 	}
4041 
4042 	/* allocate a new lock */
4043 	newnflp = nfs_file_lock_alloc(nlop);
4044 	if (!newnflp) {
4045 		return ENOLCK;
4046 	}
4047 	newnflp->nfl_start = start;
4048 	newnflp->nfl_end = end;
4049 	newnflp->nfl_type = type;
4050 	if (op == F_SETLKW) {
4051 		newnflp->nfl_flags |= NFS_FILE_LOCK_WAIT;
4052 	}
4053 	newnflp->nfl_flags |= style;
4054 	newnflp->nfl_flags |= NFS_FILE_LOCK_BLOCKED;
4055 
4056 	if ((style == NFS_FILE_LOCK_STYLE_FLOCK) && (type == F_WRLCK)) {
4057 		/*
4058 		 * For exclusive flock-style locks, if we block waiting for the
4059 		 * lock, we need to first release any currently held shared
4060 		 * flock-style lock.  So, the first thing we do is check if we
4061 		 * have a shared flock-style lock.
4062 		 */
4063 		nflp = TAILQ_FIRST(&nlop->nlo_locks);
4064 		if (nflp && ((nflp->nfl_flags & NFS_FILE_LOCK_STYLE_MASK) != NFS_FILE_LOCK_STYLE_FLOCK)) {
4065 			nflp = NULL;
4066 		}
4067 		if (nflp && (nflp->nfl_type != F_RDLCK)) {
4068 			nflp = NULL;
4069 		}
4070 		flocknflp = nflp;
4071 	}
4072 
4073 restart:
4074 	restart = 0;
4075 	error = nfs_mount_state_in_use_start(nmp, vfs_context_thread(ctx));
4076 	if (error) {
4077 		goto error_out;
4078 	}
4079 	inuse = 1;
4080 	if (np->n_flag & NREVOKE) {
4081 		error = EIO;
4082 		nfs_mount_state_in_use_end(nmp, 0);
4083 		inuse = 0;
4084 		goto error_out;
4085 	}
4086 #if CONFIG_NFS4
4087 	if (nofp->nof_flags & NFS_OPEN_FILE_REOPEN) {
4088 		nfs_mount_state_in_use_end(nmp, 0);
4089 		inuse = 0;
4090 		error = nfs4_reopen(nofp, vfs_context_thread(ctx));
4091 		if (error) {
4092 			goto error_out;
4093 		}
4094 		goto restart;
4095 	}
4096 #endif
4097 
4098 	lck_mtx_lock(&np->n_openlock);
4099 	if (!inqueue) {
4100 		/* insert new lock at beginning of list */
4101 		TAILQ_INSERT_HEAD(&np->n_locks, newnflp, nfl_link);
4102 		inqueue = 1;
4103 	}
4104 
4105 	/* scan current list of locks (held and pending) for conflicts */
4106 	for (nflp = TAILQ_NEXT(newnflp, nfl_link); nflp; nflp = nextnflp) {
4107 		nextnflp = TAILQ_NEXT(nflp, nfl_link);
4108 		if (!nfs_file_lock_conflict(newnflp, nflp, &willsplit)) {
4109 			continue;
4110 		}
4111 		/* Conflict */
4112 		if (!(newnflp->nfl_flags & NFS_FILE_LOCK_WAIT)) {
4113 			error = EAGAIN;
4114 			break;
4115 		}
4116 		/* Block until this lock is no longer held. */
4117 		if (nflp->nfl_blockcnt == UINT_MAX) {
4118 			error = ENOLCK;
4119 			break;
4120 		}
4121 		nflp->nfl_blockcnt++;
4122 		do {
4123 			if (flocknflp) {
4124 				/* release any currently held shared lock before sleeping */
4125 				lck_mtx_unlock(&np->n_openlock);
4126 				nfs_mount_state_in_use_end(nmp, 0);
4127 				inuse = 0;
4128 				error = nfs_advlock_unlock(np, nofp, nlop, 0, UINT64_MAX, NFS_FILE_LOCK_STYLE_FLOCK, ctx);
4129 				flocknflp = NULL;
4130 				if (!error) {
4131 					error = nfs_mount_state_in_use_start(nmp, vfs_context_thread(ctx));
4132 				}
4133 				if (error) {
4134 					lck_mtx_lock(&np->n_openlock);
4135 					break;
4136 				}
4137 				inuse = 1;
4138 				lck_mtx_lock(&np->n_openlock);
4139 				/* no need to block/sleep if the conflict is gone */
4140 				if (!nfs_file_lock_conflict(newnflp, nflp, NULL)) {
4141 					break;
4142 				}
4143 			}
4144 			msleep(nflp, &np->n_openlock, slpflag, "nfs_advlock_setlock_blocked", &ts);
4145 			slpflag = 0;
4146 			error = nfs_sigintr(NFSTONMP(np), NULL, vfs_context_thread(ctx), 0);
4147 			if (!error && (nmp->nm_state & NFSSTA_RECOVER)) {
4148 				/* looks like we have a recover pending... restart */
4149 				restart = 1;
4150 				lck_mtx_unlock(&np->n_openlock);
4151 				nfs_mount_state_in_use_end(nmp, 0);
4152 				inuse = 0;
4153 				lck_mtx_lock(&np->n_openlock);
4154 				break;
4155 			}
4156 			if (!error && (np->n_flag & NREVOKE)) {
4157 				error = EIO;
4158 			}
4159 		} while (!error && nfs_file_lock_conflict(newnflp, nflp, NULL));
4160 		nflp->nfl_blockcnt--;
4161 		if ((nflp->nfl_flags & NFS_FILE_LOCK_DEAD) && !nflp->nfl_blockcnt) {
4162 			TAILQ_REMOVE(&np->n_locks, nflp, nfl_link);
4163 			nfs_file_lock_destroy(np, nflp, vfs_context_thread(ctx), vfs_context_ucred(ctx));
4164 		}
4165 		if (error || restart) {
4166 			break;
4167 		}
4168 		/* We have released n_openlock and we can't trust that nextnflp is still valid. */
4169 		/* So, start this lock-scanning loop over from where it started. */
4170 		nextnflp = TAILQ_NEXT(newnflp, nfl_link);
4171 	}
4172 	lck_mtx_unlock(&np->n_openlock);
4173 	if (restart) {
4174 		goto restart;
4175 	}
4176 	if (error) {
4177 		goto error_out;
4178 	}
4179 
4180 	if (willsplit) {
4181 		/*
4182 		 * It looks like this operation is splitting a lock.
4183 		 * We allocate a new lock now so we don't have to worry
4184 		 * about the allocation failing after we've updated some state.
4185 		 */
4186 		nflp2 = nfs_file_lock_alloc(nlop);
4187 		if (!nflp2) {
4188 			error = ENOLCK;
4189 			goto error_out;
4190 		}
4191 	}
4192 
4193 	/* once scan for local conflicts is clear, send request to server */
4194 	if ((error = nfs_open_state_set_busy(np, vfs_context_thread(ctx)))) {
4195 		goto error_out;
4196 	}
4197 	busy = 1;
4198 	delay = 0;
4199 	do {
4200 #if CONFIG_NFS4
4201 		/* do we have a delegation? (that we're not returning?) */
4202 		if ((np->n_openflags & N_DELEG_MASK) && !(np->n_openflags & N_DELEG_RETURN)) {
4203 			if (np->n_openflags & N_DELEG_WRITE) {
4204 				/* with a write delegation, just take the lock delegated */
4205 				newnflp->nfl_flags |= NFS_FILE_LOCK_DELEGATED;
4206 				error = 0;
4207 				/* make sure the lock owner knows its open owner */
4208 				if (!nlop->nlo_open_owner) {
4209 					nfs_open_owner_ref(nofp->nof_owner);
4210 					nlop->nlo_open_owner = nofp->nof_owner;
4211 				}
4212 				break;
4213 			} else {
4214 				/*
4215 				 * If we don't have any non-delegated opens but we do have
4216 				 * delegated opens, then we need to first claim the delegated
4217 				 * opens so that the lock request on the server can be associated
4218 				 * with an open it knows about.
4219 				 */
4220 				if ((!nofp->nof_rw_drw && !nofp->nof_w_drw && !nofp->nof_r_drw &&
4221 				    !nofp->nof_rw_dw && !nofp->nof_w_dw && !nofp->nof_r_dw &&
4222 				    !nofp->nof_rw && !nofp->nof_w && !nofp->nof_r) &&
4223 				    (nofp->nof_d_rw_drw || nofp->nof_d_w_drw || nofp->nof_d_r_drw ||
4224 				    nofp->nof_d_rw_dw || nofp->nof_d_w_dw || nofp->nof_d_r_dw ||
4225 				    nofp->nof_d_rw || nofp->nof_d_w || nofp->nof_d_r)) {
4226 					error = nfs4_claim_delegated_state_for_open_file(nofp, 0);
4227 					if (error) {
4228 						break;
4229 					}
4230 				}
4231 			}
4232 		}
4233 #endif
4234 		if (np->n_flag & NREVOKE) {
4235 			error = EIO;
4236 		}
4237 		if (!error) {
4238 			if (busy) {
4239 				nfs_open_state_clear_busy(np);
4240 				busy = 0;
4241 			}
4242 			error = nmp->nm_funcs->nf_setlock_rpc(np, nofp, newnflp, 0, 0, vfs_context_thread(ctx), vfs_context_ucred(ctx));
4243 			if (!busy) {
4244 				error2 = nfs_open_state_set_busy(np, vfs_context_thread(ctx));
4245 				if (error2) {
4246 					error = error2;
4247 				} else {
4248 					busy = 1;
4249 				}
4250 			}
4251 		}
4252 		if (!error || ((error != NFSERR_DENIED) && (error != NFSERR_GRACE))) {
4253 			break;
4254 		}
4255 		/* request was denied due to either conflict or grace period */
4256 		if ((error == NFSERR_DENIED) && !(newnflp->nfl_flags & NFS_FILE_LOCK_WAIT)) {
4257 			error = EAGAIN;
4258 			break;
4259 		}
4260 		if (flocknflp) {
4261 			/* release any currently held shared lock before sleeping */
4262 			nfs_open_state_clear_busy(np);
4263 			busy = 0;
4264 			if (inuse) {
4265 				nfs_mount_state_in_use_end(nmp, 0);
4266 				inuse = 0;
4267 			}
4268 			error2 = nfs_advlock_unlock(np, nofp, nlop, 0, UINT64_MAX, NFS_FILE_LOCK_STYLE_FLOCK, ctx);
4269 			flocknflp = NULL;
4270 			if (!error2) {
4271 				error2 = nfs_mount_state_in_use_start(nmp, vfs_context_thread(ctx));
4272 			}
4273 			if (!error2) {
4274 				inuse = 1;
4275 				error2 = nfs_open_state_set_busy(np, vfs_context_thread(ctx));
4276 			}
4277 			if (error2) {
4278 				error = error2;
4279 				break;
4280 			}
4281 			busy = 1;
4282 		}
4283 		/*
4284 		 * Wait a little bit and send the request again.
4285 		 * Except for retries of blocked v2/v3 request where we've already waited a bit.
4286 		 */
4287 		if ((nmp->nm_vers >= NFS_VER4) || (error == NFSERR_GRACE)) {
4288 			if (error == NFSERR_GRACE) {
4289 				delay = 4;
4290 			}
4291 			if (delay < 4) {
4292 				delay++;
4293 			}
4294 			tsleep(newnflp, slpflag, "nfs_advlock_setlock_delay", delay * (hz / 2));
4295 			slpflag = 0;
4296 		}
4297 		error = nfs_sigintr(NFSTONMP(np), NULL, vfs_context_thread(ctx), 0);
4298 		if (!error && (nmp->nm_state & NFSSTA_RECOVER)) {
4299 			/* looks like we have a recover pending... restart */
4300 			nfs_open_state_clear_busy(np);
4301 			busy = 0;
4302 			if (inuse) {
4303 				nfs_mount_state_in_use_end(nmp, 0);
4304 				inuse = 0;
4305 			}
4306 			goto restart;
4307 		}
4308 		if (!error && (np->n_flag & NREVOKE)) {
4309 			error = EIO;
4310 		}
4311 	} while (!error);
4312 
4313 error_out:
4314 	if (nfs_mount_state_error_should_restart(error)) {
4315 		/* looks like we need to restart this operation */
4316 		if (busy) {
4317 			nfs_open_state_clear_busy(np);
4318 			busy = 0;
4319 		}
4320 		if (inuse) {
4321 			nfs_mount_state_in_use_end(nmp, error);
4322 			inuse = 0;
4323 		}
4324 		goto restart;
4325 	}
4326 	lck_mtx_lock(&np->n_openlock);
4327 	newnflp->nfl_flags &= ~NFS_FILE_LOCK_BLOCKED;
4328 	if (error) {
4329 		newnflp->nfl_flags |= NFS_FILE_LOCK_DEAD;
4330 		if (newnflp->nfl_blockcnt) {
4331 			/* wake up anyone blocked on this lock */
4332 			wakeup(newnflp);
4333 		} else {
4334 			/* remove newnflp from lock list and destroy */
4335 			if (inqueue) {
4336 				TAILQ_REMOVE(&np->n_locks, newnflp, nfl_link);
4337 			}
4338 			nfs_file_lock_destroy(np, newnflp, vfs_context_thread(ctx), vfs_context_ucred(ctx));
4339 		}
4340 		lck_mtx_unlock(&np->n_openlock);
4341 		if (busy) {
4342 			nfs_open_state_clear_busy(np);
4343 		}
4344 		if (inuse) {
4345 			nfs_mount_state_in_use_end(nmp, error);
4346 		}
4347 		if (nflp2) {
4348 			nfs_file_lock_destroy(np, nflp2, vfs_context_thread(ctx), vfs_context_ucred(ctx));
4349 		}
4350 		return error;
4351 	}
4352 
4353 	/* server granted the lock */
4354 
4355 	/*
4356 	 * Scan for locks to update.
4357 	 *
4358 	 * Locks completely covered are killed.
4359 	 * At most two locks may need to be clipped.
4360 	 * It's possible that a single lock may need to be split.
4361 	 */
4362 	TAILQ_FOREACH_SAFE(nflp, &np->n_locks, nfl_link, nextnflp) {
4363 		if (nflp == newnflp) {
4364 			continue;
4365 		}
4366 		if (nflp->nfl_flags & (NFS_FILE_LOCK_BLOCKED | NFS_FILE_LOCK_DEAD)) {
4367 			continue;
4368 		}
4369 		if (nflp->nfl_owner != nlop) {
4370 			continue;
4371 		}
4372 		if ((newnflp->nfl_flags & NFS_FILE_LOCK_STYLE_MASK) != (nflp->nfl_flags & NFS_FILE_LOCK_STYLE_MASK)) {
4373 			continue;
4374 		}
4375 		if ((newnflp->nfl_start > nflp->nfl_end) || (newnflp->nfl_end < nflp->nfl_start)) {
4376 			continue;
4377 		}
4378 		/* here's one to update */
4379 		if ((newnflp->nfl_start <= nflp->nfl_start) && (newnflp->nfl_end >= nflp->nfl_end)) {
4380 			/* The entire lock is being replaced. */
4381 			nflp->nfl_flags |= NFS_FILE_LOCK_DEAD;
4382 			lck_mtx_lock(&nlop->nlo_lock);
4383 			TAILQ_REMOVE(&nlop->nlo_locks, nflp, nfl_lolink);
4384 			lck_mtx_unlock(&nlop->nlo_lock);
4385 			/* lock will be destroyed below, if no waiters */
4386 		} else if ((newnflp->nfl_start > nflp->nfl_start) && (newnflp->nfl_end < nflp->nfl_end)) {
4387 			/* We're replacing a range in the middle of a lock. */
4388 			/* The current lock will be split into two locks. */
4389 			/* Update locks and insert new lock after current lock. */
4390 			nflp2->nfl_flags |= (nflp->nfl_flags & (NFS_FILE_LOCK_STYLE_MASK | NFS_FILE_LOCK_DELEGATED));
4391 			nflp2->nfl_type = nflp->nfl_type;
4392 			nflp2->nfl_start = newnflp->nfl_end + 1;
4393 			nflp2->nfl_end = nflp->nfl_end;
4394 			nflp->nfl_end = newnflp->nfl_start - 1;
4395 			TAILQ_INSERT_AFTER(&np->n_locks, nflp, nflp2, nfl_link);
4396 			nfs_lock_owner_insert_held_lock(nlop, nflp2);
4397 			nextnflp = nflp2;
4398 			nflp2 = NULL;
4399 		} else if (newnflp->nfl_start > nflp->nfl_start) {
4400 			/* We're replacing the end of a lock. */
4401 			nflp->nfl_end = newnflp->nfl_start - 1;
4402 		} else if (newnflp->nfl_end < nflp->nfl_end) {
4403 			/* We're replacing the start of a lock. */
4404 			nflp->nfl_start = newnflp->nfl_end + 1;
4405 		}
4406 		if (nflp->nfl_blockcnt) {
4407 			/* wake up anyone blocked on this lock */
4408 			wakeup(nflp);
4409 		} else if (nflp->nfl_flags & NFS_FILE_LOCK_DEAD) {
4410 			/* remove nflp from lock list and destroy */
4411 			TAILQ_REMOVE(&np->n_locks, nflp, nfl_link);
4412 			nfs_file_lock_destroy(np, nflp, vfs_context_thread(ctx), vfs_context_ucred(ctx));
4413 		}
4414 	}
4415 
4416 	nfs_lock_owner_insert_held_lock(nlop, newnflp);
4417 
4418 	/*
4419 	 * POSIX locks should be coalesced when possible.
4420 	 */
4421 	if ((style == NFS_FILE_LOCK_STYLE_POSIX) && (nofp->nof_flags & NFS_OPEN_FILE_POSIXLOCK)) {
4422 		/*
4423 		 * Walk through the lock queue and check each of our held locks with
4424 		 * the previous and next locks in the lock owner's "held lock list".
4425 		 * If the two locks can be coalesced, we merge the current lock into
4426 		 * the other (previous or next) lock.  Merging this way makes sure that
4427 		 * lock ranges are always merged forward in the lock queue.  This is
4428 		 * important because anyone blocked on the lock being "merged away"
4429 		 * will still need to block on that range and it will simply continue
4430 		 * checking locks that are further down the list.
4431 		 */
4432 		TAILQ_FOREACH_SAFE(nflp, &np->n_locks, nfl_link, nextnflp) {
4433 			if (nflp->nfl_flags & (NFS_FILE_LOCK_BLOCKED | NFS_FILE_LOCK_DEAD)) {
4434 				continue;
4435 			}
4436 			if (nflp->nfl_owner != nlop) {
4437 				continue;
4438 			}
4439 			if ((nflp->nfl_flags & NFS_FILE_LOCK_STYLE_MASK) != NFS_FILE_LOCK_STYLE_POSIX) {
4440 				continue;
4441 			}
4442 			if (((coalnflp = TAILQ_PREV(nflp, nfs_file_lock_queue, nfl_lolink))) &&
4443 			    ((coalnflp->nfl_flags & NFS_FILE_LOCK_STYLE_MASK) == NFS_FILE_LOCK_STYLE_POSIX) &&
4444 			    (coalnflp->nfl_type == nflp->nfl_type) &&
4445 			    (coalnflp->nfl_end == (nflp->nfl_start - 1))) {
4446 				coalnflp->nfl_end = nflp->nfl_end;
4447 				nflp->nfl_flags |= NFS_FILE_LOCK_DEAD;
4448 				lck_mtx_lock(&nlop->nlo_lock);
4449 				TAILQ_REMOVE(&nlop->nlo_locks, nflp, nfl_lolink);
4450 				lck_mtx_unlock(&nlop->nlo_lock);
4451 			} else if (((coalnflp = TAILQ_NEXT(nflp, nfl_lolink))) &&
4452 			    ((coalnflp->nfl_flags & NFS_FILE_LOCK_STYLE_MASK) == NFS_FILE_LOCK_STYLE_POSIX) &&
4453 			    (coalnflp->nfl_type == nflp->nfl_type) &&
4454 			    (coalnflp->nfl_start == (nflp->nfl_end + 1))) {
4455 				coalnflp->nfl_start = nflp->nfl_start;
4456 				nflp->nfl_flags |= NFS_FILE_LOCK_DEAD;
4457 				lck_mtx_lock(&nlop->nlo_lock);
4458 				TAILQ_REMOVE(&nlop->nlo_locks, nflp, nfl_lolink);
4459 				lck_mtx_unlock(&nlop->nlo_lock);
4460 			}
4461 			if (!(nflp->nfl_flags & NFS_FILE_LOCK_DEAD)) {
4462 				continue;
4463 			}
4464 			if (nflp->nfl_blockcnt) {
4465 				/* wake up anyone blocked on this lock */
4466 				wakeup(nflp);
4467 			} else {
4468 				/* remove nflp from lock list and destroy */
4469 				TAILQ_REMOVE(&np->n_locks, nflp, nfl_link);
4470 				nfs_file_lock_destroy(np, nflp, vfs_context_thread(ctx), vfs_context_ucred(ctx));
4471 			}
4472 		}
4473 	}
4474 
4475 	lck_mtx_unlock(&np->n_openlock);
4476 
4477 	if (busy) {
4478 		nfs_open_state_clear_busy(np);
4479 	}
4480 	if (inuse) {
4481 		nfs_mount_state_in_use_end(nmp, error);
4482 	}
4483 	if (nflp2) {
4484 		nfs_file_lock_destroy(np, nflp2, vfs_context_thread(ctx), vfs_context_ucred(ctx));
4485 	}
4486 	return error;
4487 }
4488 
4489 /*
4490  * Release all (same style) locks within the given range.
4491  */
4492 int
nfs_advlock_unlock(nfsnode_t np,struct nfs_open_file * nofp __unused,struct nfs_lock_owner * nlop,uint64_t start,uint64_t end,int style,vfs_context_t ctx)4493 nfs_advlock_unlock(
4494 	nfsnode_t np,
4495 	struct nfs_open_file *nofp
4496 #if !CONFIG_NFS4
4497 	__unused
4498 #endif
4499 	,
4500 	struct nfs_lock_owner *nlop,
4501 	uint64_t start,
4502 	uint64_t end,
4503 	int style,
4504 	vfs_context_t ctx)
4505 {
4506 	struct nfsmount *nmp;
4507 	struct nfs_file_lock *nflp, *nextnflp, *newnflp = NULL;
4508 	int error = 0, willsplit = 0, send_unlock_rpcs = 1;
4509 
4510 	nmp = NFSTONMP(np);
4511 	if (nfs_mount_gone(nmp)) {
4512 		return ENXIO;
4513 	}
4514 
4515 restart:
4516 	if ((error = nfs_mount_state_in_use_start(nmp, NULL))) {
4517 		return error;
4518 	}
4519 #if CONFIG_NFS4
4520 	if (nofp->nof_flags & NFS_OPEN_FILE_REOPEN) {
4521 		nfs_mount_state_in_use_end(nmp, 0);
4522 		error = nfs4_reopen(nofp, NULL);
4523 		if (error) {
4524 			return error;
4525 		}
4526 		goto restart;
4527 	}
4528 #endif
4529 	if ((error = nfs_open_state_set_busy(np, NULL))) {
4530 		nfs_mount_state_in_use_end(nmp, error);
4531 		return error;
4532 	}
4533 
4534 	lck_mtx_lock(&np->n_openlock);
4535 	if ((start > 0) && (end < UINT64_MAX) && !willsplit) {
4536 		/*
4537 		 * We may need to allocate a new lock if an existing lock gets split.
4538 		 * So, we first scan the list to check for a split, and if there's
4539 		 * going to be one, we'll allocate one now.
4540 		 */
4541 		TAILQ_FOREACH_SAFE(nflp, &np->n_locks, nfl_link, nextnflp) {
4542 			if (nflp->nfl_flags & (NFS_FILE_LOCK_BLOCKED | NFS_FILE_LOCK_DEAD)) {
4543 				continue;
4544 			}
4545 			if (nflp->nfl_owner != nlop) {
4546 				continue;
4547 			}
4548 			if ((nflp->nfl_flags & NFS_FILE_LOCK_STYLE_MASK) != style) {
4549 				continue;
4550 			}
4551 			if ((start > nflp->nfl_end) || (end < nflp->nfl_start)) {
4552 				continue;
4553 			}
4554 			if ((start > nflp->nfl_start) && (end < nflp->nfl_end)) {
4555 				willsplit = 1;
4556 				break;
4557 			}
4558 		}
4559 		if (willsplit) {
4560 			lck_mtx_unlock(&np->n_openlock);
4561 			nfs_open_state_clear_busy(np);
4562 			nfs_mount_state_in_use_end(nmp, 0);
4563 			newnflp = nfs_file_lock_alloc(nlop);
4564 			if (!newnflp) {
4565 				return ENOMEM;
4566 			}
4567 			goto restart;
4568 		}
4569 	}
4570 
4571 	/*
4572 	 * Free all of our locks in the given range.
4573 	 *
4574 	 * Note that this process requires sending requests to the server.
4575 	 * Because of this, we will release the n_openlock while performing
4576 	 * the unlock RPCs.  The N_OPENBUSY state keeps the state of *held*
4577 	 * locks from changing underneath us.  However, other entries in the
4578 	 * list may be removed.  So we need to be careful walking the list.
4579 	 */
4580 
4581 	/*
4582 	 * Don't unlock ranges that are held by other-style locks.
4583 	 * If style is posix, don't send any unlock rpcs if flock is held.
4584 	 * If we unlock an flock, don't send unlock rpcs for any posix-style
4585 	 * ranges held - instead send unlocks for the ranges not held.
4586 	 */
4587 	if ((style == NFS_FILE_LOCK_STYLE_POSIX) &&
4588 	    ((nflp = TAILQ_FIRST(&nlop->nlo_locks))) &&
4589 	    ((nflp->nfl_flags & NFS_FILE_LOCK_STYLE_MASK) == NFS_FILE_LOCK_STYLE_FLOCK)) {
4590 		send_unlock_rpcs = 0;
4591 	}
4592 	if ((style == NFS_FILE_LOCK_STYLE_FLOCK) &&
4593 	    ((nflp = TAILQ_FIRST(&nlop->nlo_locks))) &&
4594 	    ((nflp->nfl_flags & NFS_FILE_LOCK_STYLE_MASK) == NFS_FILE_LOCK_STYLE_FLOCK) &&
4595 	    ((nflp = TAILQ_NEXT(nflp, nfl_lolink))) &&
4596 	    ((nflp->nfl_flags & NFS_FILE_LOCK_STYLE_MASK) == NFS_FILE_LOCK_STYLE_POSIX)) {
4597 		uint64_t s = 0;
4598 		int type = TAILQ_FIRST(&nlop->nlo_locks)->nfl_type;
4599 		int delegated = (TAILQ_FIRST(&nlop->nlo_locks)->nfl_flags & NFS_FILE_LOCK_DELEGATED);
4600 		while (!delegated && nflp) {
4601 			if ((nflp->nfl_flags & NFS_FILE_LOCK_STYLE_MASK) == NFS_FILE_LOCK_STYLE_POSIX) {
4602 				/* unlock the range preceding this lock */
4603 				lck_mtx_unlock(&np->n_openlock);
4604 				error = nmp->nm_funcs->nf_unlock_rpc(np, nlop, type, s, nflp->nfl_start - 1, 0,
4605 				    vfs_context_thread(ctx), vfs_context_ucred(ctx));
4606 				if (nfs_mount_state_error_should_restart(error)) {
4607 					nfs_open_state_clear_busy(np);
4608 					nfs_mount_state_in_use_end(nmp, error);
4609 					goto restart;
4610 				}
4611 				lck_mtx_lock(&np->n_openlock);
4612 				if (error) {
4613 					goto out;
4614 				}
4615 				s = nflp->nfl_end + 1;
4616 			}
4617 			nflp = TAILQ_NEXT(nflp, nfl_lolink);
4618 		}
4619 		if (!delegated) {
4620 			lck_mtx_unlock(&np->n_openlock);
4621 			error = nmp->nm_funcs->nf_unlock_rpc(np, nlop, type, s, end, 0,
4622 			    vfs_context_thread(ctx), vfs_context_ucred(ctx));
4623 			if (nfs_mount_state_error_should_restart(error)) {
4624 				nfs_open_state_clear_busy(np);
4625 				nfs_mount_state_in_use_end(nmp, error);
4626 				goto restart;
4627 			}
4628 			lck_mtx_lock(&np->n_openlock);
4629 			if (error) {
4630 				goto out;
4631 			}
4632 		}
4633 		send_unlock_rpcs = 0;
4634 	}
4635 
4636 	TAILQ_FOREACH_SAFE(nflp, &np->n_locks, nfl_link, nextnflp) {
4637 		if (nflp->nfl_flags & (NFS_FILE_LOCK_BLOCKED | NFS_FILE_LOCK_DEAD)) {
4638 			continue;
4639 		}
4640 		if (nflp->nfl_owner != nlop) {
4641 			continue;
4642 		}
4643 		if ((nflp->nfl_flags & NFS_FILE_LOCK_STYLE_MASK) != style) {
4644 			continue;
4645 		}
4646 		if ((start > nflp->nfl_end) || (end < nflp->nfl_start)) {
4647 			continue;
4648 		}
4649 		/* here's one to unlock */
4650 		if ((start <= nflp->nfl_start) && (end >= nflp->nfl_end)) {
4651 			/* The entire lock is being unlocked. */
4652 			if (send_unlock_rpcs && !(nflp->nfl_flags & NFS_FILE_LOCK_DELEGATED)) {
4653 				lck_mtx_unlock(&np->n_openlock);
4654 				error = nmp->nm_funcs->nf_unlock_rpc(np, nlop, nflp->nfl_type, nflp->nfl_start, nflp->nfl_end, 0,
4655 				    vfs_context_thread(ctx), vfs_context_ucred(ctx));
4656 				if (nfs_mount_state_error_should_restart(error)) {
4657 					nfs_open_state_clear_busy(np);
4658 					nfs_mount_state_in_use_end(nmp, error);
4659 					goto restart;
4660 				}
4661 				lck_mtx_lock(&np->n_openlock);
4662 			}
4663 			nextnflp = TAILQ_NEXT(nflp, nfl_link);
4664 			if (error) {
4665 				break;
4666 			}
4667 			nflp->nfl_flags |= NFS_FILE_LOCK_DEAD;
4668 			lck_mtx_lock(&nlop->nlo_lock);
4669 			TAILQ_REMOVE(&nlop->nlo_locks, nflp, nfl_lolink);
4670 			lck_mtx_unlock(&nlop->nlo_lock);
4671 			/* lock will be destroyed below, if no waiters */
4672 		} else if ((start > nflp->nfl_start) && (end < nflp->nfl_end)) {
4673 			/* We're unlocking a range in the middle of a lock. */
4674 			/* The current lock will be split into two locks. */
4675 			if (send_unlock_rpcs && !(nflp->nfl_flags & NFS_FILE_LOCK_DELEGATED)) {
4676 				lck_mtx_unlock(&np->n_openlock);
4677 				error = nmp->nm_funcs->nf_unlock_rpc(np, nlop, nflp->nfl_type, start, end, 0,
4678 				    vfs_context_thread(ctx), vfs_context_ucred(ctx));
4679 				if (nfs_mount_state_error_should_restart(error)) {
4680 					nfs_open_state_clear_busy(np);
4681 					nfs_mount_state_in_use_end(nmp, error);
4682 					goto restart;
4683 				}
4684 				lck_mtx_lock(&np->n_openlock);
4685 			}
4686 			if (error) {
4687 				break;
4688 			}
4689 			/* update locks and insert new lock after current lock */
4690 			newnflp->nfl_flags |= (nflp->nfl_flags & (NFS_FILE_LOCK_STYLE_MASK | NFS_FILE_LOCK_DELEGATED));
4691 			newnflp->nfl_type = nflp->nfl_type;
4692 			newnflp->nfl_start = end + 1;
4693 			newnflp->nfl_end = nflp->nfl_end;
4694 			nflp->nfl_end = start - 1;
4695 			TAILQ_INSERT_AFTER(&np->n_locks, nflp, newnflp, nfl_link);
4696 			nfs_lock_owner_insert_held_lock(nlop, newnflp);
4697 			nextnflp = newnflp;
4698 			newnflp = NULL;
4699 		} else if (start > nflp->nfl_start) {
4700 			/* We're unlocking the end of a lock. */
4701 			if (send_unlock_rpcs && !(nflp->nfl_flags & NFS_FILE_LOCK_DELEGATED)) {
4702 				lck_mtx_unlock(&np->n_openlock);
4703 				error = nmp->nm_funcs->nf_unlock_rpc(np, nlop, nflp->nfl_type, start, nflp->nfl_end, 0,
4704 				    vfs_context_thread(ctx), vfs_context_ucred(ctx));
4705 				if (nfs_mount_state_error_should_restart(error)) {
4706 					nfs_open_state_clear_busy(np);
4707 					nfs_mount_state_in_use_end(nmp, error);
4708 					goto restart;
4709 				}
4710 				lck_mtx_lock(&np->n_openlock);
4711 			}
4712 			nextnflp = TAILQ_NEXT(nflp, nfl_link);
4713 			if (error) {
4714 				break;
4715 			}
4716 			nflp->nfl_end = start - 1;
4717 		} else if (end < nflp->nfl_end) {
4718 			/* We're unlocking the start of a lock. */
4719 			if (send_unlock_rpcs && !(nflp->nfl_flags & NFS_FILE_LOCK_DELEGATED)) {
4720 				lck_mtx_unlock(&np->n_openlock);
4721 				error = nmp->nm_funcs->nf_unlock_rpc(np, nlop, nflp->nfl_type, nflp->nfl_start, end, 0,
4722 				    vfs_context_thread(ctx), vfs_context_ucred(ctx));
4723 				if (nfs_mount_state_error_should_restart(error)) {
4724 					nfs_open_state_clear_busy(np);
4725 					nfs_mount_state_in_use_end(nmp, error);
4726 					goto restart;
4727 				}
4728 				lck_mtx_lock(&np->n_openlock);
4729 			}
4730 			nextnflp = TAILQ_NEXT(nflp, nfl_link);
4731 			if (error) {
4732 				break;
4733 			}
4734 			nflp->nfl_start = end + 1;
4735 		}
4736 		if (nflp->nfl_blockcnt) {
4737 			/* wake up anyone blocked on this lock */
4738 			wakeup(nflp);
4739 		} else if (nflp->nfl_flags & NFS_FILE_LOCK_DEAD) {
4740 			/* remove nflp from lock list and destroy */
4741 			TAILQ_REMOVE(&np->n_locks, nflp, nfl_link);
4742 			nfs_file_lock_destroy(np, nflp, vfs_context_thread(ctx), vfs_context_ucred(ctx));
4743 		}
4744 	}
4745 out:
4746 	lck_mtx_unlock(&np->n_openlock);
4747 	nfs_open_state_clear_busy(np);
4748 	nfs_mount_state_in_use_end(nmp, 0);
4749 
4750 	if (newnflp) {
4751 		nfs_file_lock_destroy(np, newnflp, vfs_context_thread(ctx), vfs_context_ucred(ctx));
4752 	}
4753 	return error;
4754 }
4755 
4756 /*
4757  * NFSv4 advisory file locking
4758  */
4759 int
nfs_vnop_advlock(struct vnop_advlock_args * ap)4760 nfs_vnop_advlock(
4761 	struct vnop_advlock_args /* {
4762                                   *  struct vnodeop_desc *a_desc;
4763                                   *  vnode_t a_vp;
4764                                   *  caddr_t a_id;
4765                                   *  int a_op;
4766                                   *  struct flock *a_fl;
4767                                   *  int a_flags;
4768                                   *  vfs_context_t a_context;
4769                                   *  } */*ap)
4770 {
4771 	vnode_t vp = ap->a_vp;
4772 	nfsnode_t np = VTONFS(ap->a_vp);
4773 	struct flock *fl = ap->a_fl;
4774 	int op = ap->a_op;
4775 	int flags = ap->a_flags;
4776 	caddr_t lockid = ap->a_id;
4777 	vfs_context_t ctx = ap->a_context;
4778 	struct nfsmount *nmp;
4779 	struct nfs_open_owner *noop = NULL;
4780 	struct nfs_open_file *nofp = NULL;
4781 	struct nfs_lock_owner *nlop = NULL;
4782 	off_t lstart;
4783 	uint64_t start, end;
4784 	int error = 0, modified, style;
4785 	enum vtype vtype;
4786 #define OFF_MAX QUAD_MAX
4787 
4788 	nmp = VTONMP(ap->a_vp);
4789 	if (nfs_mount_gone(nmp)) {
4790 		return ENXIO;
4791 	}
4792 	lck_mtx_lock(&nmp->nm_lock);
4793 	if ((nmp->nm_vers <= NFS_VER3) && (nmp->nm_lockmode == NFS_LOCK_MODE_DISABLED)) {
4794 		lck_mtx_unlock(&nmp->nm_lock);
4795 		return ENOTSUP;
4796 	}
4797 	lck_mtx_unlock(&nmp->nm_lock);
4798 
4799 	if (np->n_flag & NREVOKE) {
4800 		return EIO;
4801 	}
4802 	vtype = vnode_vtype(ap->a_vp);
4803 	if (vtype == VDIR) { /* ignore lock requests on directories */
4804 		return 0;
4805 	}
4806 	if (vtype != VREG) { /* anything other than regular files is invalid */
4807 		return EINVAL;
4808 	}
4809 
4810 	/* Convert the flock structure into a start and end. */
4811 	switch (fl->l_whence) {
4812 	case SEEK_SET:
4813 	case SEEK_CUR:
4814 		/*
4815 		 * Caller is responsible for adding any necessary offset
4816 		 * to fl->l_start when SEEK_CUR is used.
4817 		 */
4818 		lstart = fl->l_start;
4819 		break;
4820 	case SEEK_END:
4821 		/* need to flush, and refetch attributes to make */
4822 		/* sure we have the correct end of file offset   */
4823 		if ((error = nfs_node_lock(np))) {
4824 			return NFS_MAPERR(error);
4825 		}
4826 		modified = (np->n_flag & NMODIFIED);
4827 		nfs_node_unlock(np);
4828 		if (modified && ((error = nfs_vinvalbuf1(vp, V_SAVE, ctx, 1)))) {
4829 			return NFS_MAPERR(error);
4830 		}
4831 		if ((error = nfs_getattr(np, NULL, ctx, NGA_UNCACHED))) {
4832 			return NFS_MAPERR(error);
4833 		}
4834 		nfs_data_lock(np, NFS_DATA_LOCK_SHARED);
4835 		if ((np->n_size > OFF_MAX) ||
4836 		    ((fl->l_start > 0) && (np->n_size > (u_quad_t)(OFF_MAX - fl->l_start)))) {
4837 			error = EOVERFLOW;
4838 		}
4839 		lstart = np->n_size + fl->l_start;
4840 		nfs_data_unlock(np);
4841 		if (error) {
4842 			return NFS_MAPERR(error);
4843 		}
4844 		break;
4845 	default:
4846 		return EINVAL;
4847 	}
4848 	if (lstart < 0) {
4849 		return EINVAL;
4850 	}
4851 	start = lstart;
4852 	if (fl->l_len == 0) {
4853 		end = UINT64_MAX;
4854 	} else if (fl->l_len > 0) {
4855 		if ((fl->l_len - 1) > (OFF_MAX - lstart)) {
4856 			return EOVERFLOW;
4857 		}
4858 		end = start - 1 + fl->l_len;
4859 	} else { /* l_len is negative */
4860 		if ((lstart + fl->l_len) < 0) {
4861 			return EINVAL;
4862 		}
4863 		end = start - 1;
4864 		start += fl->l_len;
4865 	}
4866 	if ((nmp->nm_vers == NFS_VER2) && ((start > INT32_MAX) || (fl->l_len && (end > INT32_MAX)))) {
4867 		return EINVAL;
4868 	}
4869 
4870 	style = (flags & F_FLOCK) ? NFS_FILE_LOCK_STYLE_FLOCK : NFS_FILE_LOCK_STYLE_POSIX;
4871 	if ((style == NFS_FILE_LOCK_STYLE_FLOCK) && ((start != 0) || (end != UINT64_MAX))) {
4872 		return EINVAL;
4873 	}
4874 
4875 	/* find the lock owner, alloc if not unlock */
4876 	nlop = nfs_lock_owner_find(np, vfs_context_proc(ctx), lockid, (op != F_UNLCK) ? NFS_LOCK_OWNER_FIND_ALLOC : 0);
4877 	if (!nlop) {
4878 		error = (op == F_UNLCK) ? 0 : ENOMEM;
4879 		if (error) {
4880 			NP(np, "nfs_vnop_advlock: no lock owner, error %d", error);
4881 		}
4882 		goto out;
4883 	}
4884 
4885 	if (op == F_GETLK) {
4886 		error = nfs_advlock_getlock(np, nlop, fl, start, end, ctx);
4887 	} else {
4888 		/* find the open owner */
4889 		noop = nfs_open_owner_find(nmp, vfs_context_ucred(ctx), vfs_context_proc(ctx), 0);
4890 		if (!noop) {
4891 			NP(np, "nfs_vnop_advlock: no open owner %d", kauth_cred_getuid(vfs_context_ucred(ctx)));
4892 			error = EPERM;
4893 			goto out;
4894 		}
4895 		/* find the open file */
4896 #if CONFIG_NFS4
4897 restart:
4898 #endif
4899 		error = nfs_open_file_find(np, noop, &nofp, 0, 0, 0);
4900 		if (error) {
4901 			error = EBADF;
4902 		}
4903 		if (!error && (nofp->nof_flags & NFS_OPEN_FILE_LOST)) {
4904 			NP(np, "nfs_vnop_advlock: LOST %d", kauth_cred_getuid(nofp->nof_owner->noo_cred));
4905 			error = EIO;
4906 		}
4907 #if CONFIG_NFS4
4908 		if (!error && (nofp->nof_flags & NFS_OPEN_FILE_REOPEN)) {
4909 			error = nfs4_reopen(nofp, ((op == F_UNLCK) ? NULL : vfs_context_thread(ctx)));
4910 			nofp = NULL;
4911 			if (!error) {
4912 				goto restart;
4913 			}
4914 		}
4915 #endif
4916 		if (error) {
4917 			NP(np, "nfs_vnop_advlock: no open file %d, %d", error, kauth_cred_getuid(noop->noo_cred));
4918 			goto out;
4919 		}
4920 		if (op == F_UNLCK) {
4921 			error = nfs_advlock_unlock(np, nofp, nlop, start, end, style, ctx);
4922 		} else if ((op == F_SETLK) || (op == F_SETLKW)) {
4923 			if ((op == F_SETLK) && (flags & F_WAIT)) {
4924 				op = F_SETLKW;
4925 			}
4926 			error = nfs_advlock_setlock(np, nofp, nlop, op, start, end, style, fl->l_type, ctx);
4927 		} else {
4928 			/* not getlk, unlock or lock? */
4929 			error = EINVAL;
4930 		}
4931 	}
4932 
4933 out:
4934 	if (nlop) {
4935 		nfs_lock_owner_rele(np, nlop, vfs_context_thread(ctx), vfs_context_ucred(ctx));
4936 	}
4937 	if (noop) {
4938 		nfs_open_owner_rele(noop);
4939 	}
4940 	return NFS_MAPERR(error);
4941 }
4942 
4943 /*
4944  * Check if an open owner holds any locks on a file.
4945  */
4946 int
nfs_check_for_locks(struct nfs_open_owner * noop,struct nfs_open_file * nofp)4947 nfs_check_for_locks(struct nfs_open_owner *noop, struct nfs_open_file *nofp)
4948 {
4949 	struct nfs_lock_owner *nlop;
4950 
4951 	TAILQ_FOREACH(nlop, &nofp->nof_np->n_lock_owners, nlo_link) {
4952 		if (nlop->nlo_open_owner != noop) {
4953 			continue;
4954 		}
4955 		if (!TAILQ_EMPTY(&nlop->nlo_locks)) {
4956 			break;
4957 		}
4958 	}
4959 	return nlop ? 1 : 0;
4960 }
4961 
4962 #if CONFIG_NFS4
4963 /*
4964  * Reopen simple (no deny, no locks) open state that was lost.
4965  */
4966 int
nfs4_reopen(struct nfs_open_file * nofp,thread_t thd)4967 nfs4_reopen(struct nfs_open_file *nofp, thread_t thd)
4968 {
4969 	struct nfs_open_owner *noop = nofp->nof_owner;
4970 	struct nfsmount *nmp = NFSTONMP(nofp->nof_np);
4971 	nfsnode_t np = nofp->nof_np;
4972 	vnode_t vp = NFSTOV(np);
4973 	vnode_t dvp = NULL;
4974 	struct componentname cn;
4975 	const char *vname = NULL;
4976 	const char *name = NULL;
4977 	uint32_t namelen = 0;
4978 	char smallname[128];
4979 	char *filename = NULL;
4980 	int error = 0, done = 0, slpflag = NMFLAG(nmp, INTR) ? PCATCH : 0;
4981 	struct timespec ts = { .tv_sec = 1, .tv_nsec = 0 };
4982 
4983 	lck_mtx_lock(&nofp->nof_lock);
4984 	while (nofp->nof_flags & NFS_OPEN_FILE_REOPENING) {
4985 		if ((error = nfs_sigintr(nmp, NULL, thd, 0))) {
4986 			break;
4987 		}
4988 		msleep(&nofp->nof_flags, &nofp->nof_lock, slpflag | (PZERO - 1), "nfsreopenwait", &ts);
4989 		slpflag = 0;
4990 	}
4991 	if (error || !(nofp->nof_flags & NFS_OPEN_FILE_REOPEN)) {
4992 		lck_mtx_unlock(&nofp->nof_lock);
4993 		return error;
4994 	}
4995 	nofp->nof_flags |= NFS_OPEN_FILE_REOPENING;
4996 	lck_mtx_unlock(&nofp->nof_lock);
4997 
4998 	nfs_node_lock_force(np);
4999 	if ((vnode_vtype(vp) != VDIR) && np->n_sillyrename) {
5000 		/*
5001 		 * The node's been sillyrenamed, so we need to use
5002 		 * the sillyrename directory/name to do the open.
5003 		 */
5004 		struct nfs_sillyrename *nsp = np->n_sillyrename;
5005 		dvp = NFSTOV(nsp->nsr_dnp);
5006 		if ((error = vnode_get(dvp))) {
5007 			dvp = NULLVP;
5008 			nfs_node_unlock(np);
5009 			goto out;
5010 		}
5011 		name = nsp->nsr_name;
5012 	} else {
5013 		/*
5014 		 * [sigh] We can't trust VFS to get the parent right for named
5015 		 * attribute nodes.  (It likes to reparent the nodes after we've
5016 		 * created them.)  Luckily we can probably get the right parent
5017 		 * from the n_parent we have stashed away.
5018 		 */
5019 		if ((np->n_vattr.nva_flags & NFS_FFLAG_IS_ATTR) &&
5020 		    (((dvp = np->n_parent)) && (error = vnode_get(dvp)))) {
5021 			dvp = NULL;
5022 		}
5023 		if (!dvp) {
5024 			dvp = vnode_getparent(vp);
5025 		}
5026 		vname = vnode_getname(vp);
5027 		if (!dvp || !vname) {
5028 			if (!error) {
5029 				error = EIO;
5030 			}
5031 			nfs_node_unlock(np);
5032 			goto out;
5033 		}
5034 		name = vname;
5035 	}
5036 	filename = &smallname[0];
5037 	namelen = snprintf(filename, sizeof(smallname), "%s", name);
5038 	if (namelen >= sizeof(smallname)) {
5039 		filename = kalloc_data(namelen + 1, Z_WAITOK);
5040 		if (!filename) {
5041 			error = ENOMEM;
5042 			goto out;
5043 		}
5044 		snprintf(filename, namelen + 1, "%s", name);
5045 	}
5046 	nfs_node_unlock(np);
5047 	bzero(&cn, sizeof(cn));
5048 	cn.cn_nameptr = filename;
5049 	cn.cn_namelen = namelen;
5050 
5051 restart:
5052 	done = 0;
5053 	if ((error = nfs_mount_state_in_use_start(nmp, thd))) {
5054 		goto out;
5055 	}
5056 
5057 	if (nofp->nof_rw) {
5058 		error = nfs4_open_reopen_rpc(nofp, thd, noop->noo_cred, &cn, dvp, &vp, NFS_OPEN_SHARE_ACCESS_BOTH, NFS_OPEN_SHARE_DENY_NONE);
5059 	}
5060 	if (!error && nofp->nof_w) {
5061 		error = nfs4_open_reopen_rpc(nofp, thd, noop->noo_cred, &cn, dvp, &vp, NFS_OPEN_SHARE_ACCESS_WRITE, NFS_OPEN_SHARE_DENY_NONE);
5062 	}
5063 	if (!error && nofp->nof_r) {
5064 		error = nfs4_open_reopen_rpc(nofp, thd, noop->noo_cred, &cn, dvp, &vp, NFS_OPEN_SHARE_ACCESS_READ, NFS_OPEN_SHARE_DENY_NONE);
5065 	}
5066 
5067 	if (nfs_mount_state_in_use_end(nmp, error)) {
5068 		if (error == NFSERR_GRACE) {
5069 			goto restart;
5070 		}
5071 		printf("nfs4_reopen: RPC failed, error %d, lost %d, %s\n", error,
5072 		    (nofp->nof_flags & NFS_OPEN_FILE_LOST) ? 1 : 0, name ? name : "???");
5073 		error = 0;
5074 		goto out;
5075 	}
5076 	done = 1;
5077 out:
5078 	if (error && (error != EINTR) && (error != ERESTART)) {
5079 		nfs_revoke_open_state_for_node(np);
5080 	}
5081 	lck_mtx_lock(&nofp->nof_lock);
5082 	nofp->nof_flags &= ~NFS_OPEN_FILE_REOPENING;
5083 	if (done) {
5084 		nofp->nof_flags &= ~NFS_OPEN_FILE_REOPEN;
5085 	} else if (error) {
5086 		printf("nfs4_reopen: failed, error %d, lost %d, %s\n", error,
5087 		    (nofp->nof_flags & NFS_OPEN_FILE_LOST) ? 1 : 0, name ? name : "???");
5088 	}
5089 	lck_mtx_unlock(&nofp->nof_lock);
5090 	if (filename && (filename != &smallname[0])) {
5091 		kfree_data(filename, namelen + 1);
5092 	}
5093 	if (vname) {
5094 		vnode_putname(vname);
5095 	}
5096 	if (dvp != NULLVP) {
5097 		vnode_put(dvp);
5098 	}
5099 	return error;
5100 }
5101 
5102 /*
5103  * Send a normal OPEN RPC to open/create a file.
5104  */
5105 int
nfs4_open_rpc(struct nfs_open_file * nofp,vfs_context_t ctx,struct componentname * cnp,struct vnode_attr * vap,vnode_t dvp,vnode_t * vpp,int create,int share_access,int share_deny)5106 nfs4_open_rpc(
5107 	struct nfs_open_file *nofp,
5108 	vfs_context_t ctx,
5109 	struct componentname *cnp,
5110 	struct vnode_attr *vap,
5111 	vnode_t dvp,
5112 	vnode_t *vpp,
5113 	int create,
5114 	int share_access,
5115 	int share_deny)
5116 {
5117 	return nfs4_open_rpc_internal(nofp, ctx, vfs_context_thread(ctx), vfs_context_ucred(ctx),
5118 	           cnp, vap, dvp, vpp, create, share_access, share_deny);
5119 }
5120 
5121 /*
5122  * Send an OPEN RPC to reopen a file.
5123  */
5124 int
nfs4_open_reopen_rpc(struct nfs_open_file * nofp,thread_t thd,kauth_cred_t cred,struct componentname * cnp,vnode_t dvp,vnode_t * vpp,int share_access,int share_deny)5125 nfs4_open_reopen_rpc(
5126 	struct nfs_open_file *nofp,
5127 	thread_t thd,
5128 	kauth_cred_t cred,
5129 	struct componentname *cnp,
5130 	vnode_t dvp,
5131 	vnode_t *vpp,
5132 	int share_access,
5133 	int share_deny)
5134 {
5135 	return nfs4_open_rpc_internal(nofp, NULL, thd, cred, cnp, NULL, dvp, vpp, NFS_OPEN_NOCREATE, share_access, share_deny);
5136 }
5137 
5138 /*
5139  * Send an OPEN_CONFIRM RPC to confirm an OPEN.
5140  */
5141 int
nfs4_open_confirm_rpc(struct nfsmount * nmp,nfsnode_t dnp,u_char * fhp,int fhlen,struct nfs_open_owner * noop,nfs_stateid * sid,thread_t thd,kauth_cred_t cred,struct nfs_vattr * nvap,uint64_t * xidp)5142 nfs4_open_confirm_rpc(
5143 	struct nfsmount *nmp,
5144 	nfsnode_t dnp,
5145 	u_char *fhp,
5146 	int fhlen,
5147 	struct nfs_open_owner *noop,
5148 	nfs_stateid *sid,
5149 	thread_t thd,
5150 	kauth_cred_t cred,
5151 	struct nfs_vattr *nvap,
5152 	uint64_t *xidp)
5153 {
5154 	struct nfsm_chain nmreq, nmrep;
5155 	int error = 0, status, numops;
5156 	struct nfsreq_secinfo_args si;
5157 
5158 	NFSREQ_SECINFO_SET(&si, dnp, NULL, 0, NULL, 0);
5159 	nfsm_chain_null(&nmreq);
5160 	nfsm_chain_null(&nmrep);
5161 
5162 	// PUTFH, OPEN_CONFIRM, GETATTR
5163 	numops = 3;
5164 	nfsm_chain_build_alloc_init(error, &nmreq, 23 * NFSX_UNSIGNED);
5165 	nfsm_chain_add_compound_header(error, &nmreq, "open_confirm", nmp->nm_minor_vers, numops);
5166 	numops--;
5167 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_PUTFH);
5168 	nfsm_chain_add_fh(error, &nmreq, nmp->nm_vers, fhp, fhlen);
5169 	numops--;
5170 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_OPEN_CONFIRM);
5171 	nfsm_chain_add_stateid(error, &nmreq, sid);
5172 	nfsm_chain_add_32(error, &nmreq, noop->noo_seqid);
5173 	numops--;
5174 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_GETATTR);
5175 	nfsm_chain_add_bitmap_supported(error, &nmreq, nfs_getattr_bitmap, nmp, dnp);
5176 	nfsm_chain_build_done(error, &nmreq);
5177 	nfsm_assert(error, (numops == 0), EPROTO);
5178 	nfsmout_if(error);
5179 	error = nfs_request2(dnp, NULL, &nmreq, NFSPROC4_COMPOUND, thd, cred, &si, R_NOINTR, &nmrep, xidp, &status);
5180 
5181 	nfsm_chain_skip_tag(error, &nmrep);
5182 	nfsm_chain_get_32(error, &nmrep, numops);
5183 	nfsm_chain_op_check(error, &nmrep, NFS_OP_PUTFH);
5184 	nfsmout_if(error);
5185 	nfsm_chain_op_check(error, &nmrep, NFS_OP_OPEN_CONFIRM);
5186 	nfs_owner_seqid_increment(noop, NULL, error);
5187 	nfsm_chain_get_stateid(error, &nmrep, sid);
5188 	nfsm_chain_op_check(error, &nmrep, NFS_OP_GETATTR);
5189 	nfsmout_if(error);
5190 	error = nfs4_parsefattr(&nmrep, NULL, nvap, NULL, NULL, NULL);
5191 nfsmout:
5192 	nfsm_chain_cleanup(&nmreq);
5193 	nfsm_chain_cleanup(&nmrep);
5194 	return error;
5195 }
5196 
5197 /*
5198  * common OPEN RPC code
5199  *
5200  * If create is set, ctx must be passed in.
5201  * Returns a node on success if no node passed in.
5202  */
5203 int
nfs4_open_rpc_internal(struct nfs_open_file * nofp,vfs_context_t ctx,thread_t thd,kauth_cred_t cred,struct componentname * cnp,struct vnode_attr * vap,vnode_t dvp,vnode_t * vpp,int create,int share_access,int share_deny)5204 nfs4_open_rpc_internal(
5205 	struct nfs_open_file *nofp,
5206 	vfs_context_t ctx,
5207 	thread_t thd,
5208 	kauth_cred_t cred,
5209 	struct componentname *cnp,
5210 	struct vnode_attr *vap,
5211 	vnode_t dvp,
5212 	vnode_t *vpp,
5213 	int create,
5214 	int share_access,
5215 	int share_deny)
5216 {
5217 	struct nfsmount *nmp;
5218 	struct nfs_open_owner *noop = nofp->nof_owner;
5219 	struct nfs_vattr *nvattr;
5220 	int error = 0, open_error = EIO, lockerror = ENOENT, busyerror = ENOENT, status;
5221 	int nfsvers, namedattrs, numops, exclusive = 0, gotuid, gotgid;
5222 	u_int64_t xid, savedxid = 0;
5223 	nfsnode_t dnp = VTONFS(dvp);
5224 	nfsnode_t np, newnp = NULL;
5225 	vnode_t newvp = NULL;
5226 	struct nfsm_chain nmreq, nmrep;
5227 	uint32_t bitmap[NFS_ATTR_BITMAP_LEN], bmlen;
5228 	uint32_t rflags, delegation, recall;
5229 	struct nfs_stateid stateid, dstateid, *sid;
5230 	fhandle_t *fh;
5231 	struct nfsreq *req;
5232 	struct nfs_dulookup *dul;
5233 	char sbuf[64], *s;
5234 	uint32_t ace_type, ace_flags, ace_mask, len, slen;
5235 	struct kauth_ace ace;
5236 	struct nfsreq_secinfo_args si;
5237 
5238 	if (create && !ctx) {
5239 		return EINVAL;
5240 	}
5241 
5242 	nmp = VTONMP(dvp);
5243 	if (nfs_mount_gone(nmp)) {
5244 		return ENXIO;
5245 	}
5246 	nfsvers = nmp->nm_vers;
5247 	namedattrs = (nmp->nm_fsattr.nfsa_flags & NFS_FSFLAG_NAMED_ATTR);
5248 	bzero(&dstateid, sizeof(dstateid));
5249 	if (dnp->n_vattr.nva_flags & NFS_FFLAG_TRIGGER_REFERRAL) {
5250 		return EINVAL;
5251 	}
5252 
5253 	np = *vpp ? VTONFS(*vpp) : NULL;
5254 	if (create && vap) {
5255 		exclusive = (vap->va_vaflags & VA_EXCLUSIVE);
5256 		nfs_avoid_needless_id_setting_on_create(dnp, vap, ctx);
5257 		gotuid = VATTR_IS_ACTIVE(vap, va_uid);
5258 		gotgid = VATTR_IS_ACTIVE(vap, va_gid);
5259 		if (exclusive && (!VATTR_IS_ACTIVE(vap, va_access_time) || !VATTR_IS_ACTIVE(vap, va_modify_time))) {
5260 			vap->va_vaflags |= VA_UTIMES_NULL;
5261 		}
5262 	} else {
5263 		exclusive = gotuid = gotgid = 0;
5264 	}
5265 	if (nofp) {
5266 		sid = &nofp->nof_stateid;
5267 	} else {
5268 		stateid.seqid = stateid.other[0] = stateid.other[1] = stateid.other[2] = 0;
5269 		sid = &stateid;
5270 	}
5271 
5272 	if ((error = nfs_open_owner_set_busy(noop, thd))) {
5273 		return error;
5274 	}
5275 
5276 	fh = zalloc(nfs_fhandle_zone);
5277 	req = zalloc(nfs_req_zone);
5278 	dul = kalloc_type(struct nfs_dulookup, Z_WAITOK);
5279 	nvattr = zalloc_flags(KT_NFS_VATTR, Z_WAITOK);
5280 
5281 again:
5282 	rflags = delegation = recall = 0;
5283 	ace.ace_flags = 0;
5284 	s = sbuf;
5285 	slen = sizeof(sbuf);
5286 	NVATTR_INIT(nvattr);
5287 	NFSREQ_SECINFO_SET(&si, dnp, NULL, 0, cnp->cn_nameptr, cnp->cn_namelen);
5288 
5289 	nfsm_chain_null(&nmreq);
5290 	nfsm_chain_null(&nmrep);
5291 
5292 	// PUTFH, SAVEFH, OPEN(CREATE?), GETATTR(FH), RESTOREFH, GETATTR
5293 	numops = 6;
5294 	nfsm_chain_build_alloc_init(error, &nmreq, 53 * NFSX_UNSIGNED + cnp->cn_namelen);
5295 	nfsm_chain_add_compound_header(error, &nmreq, create ? "create" : "open", nmp->nm_minor_vers, numops);
5296 	numops--;
5297 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_PUTFH);
5298 	nfsm_chain_add_fh(error, &nmreq, nfsvers, dnp->n_fhp, dnp->n_fhsize);
5299 	numops--;
5300 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_SAVEFH);
5301 	numops--;
5302 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_OPEN);
5303 	nfsm_chain_add_32(error, &nmreq, noop->noo_seqid);
5304 	nfsm_chain_add_32(error, &nmreq, share_access);
5305 	nfsm_chain_add_32(error, &nmreq, share_deny);
5306 	nfsm_chain_add_openowner(error, &nmreq, nmp, noop);
5307 	nfsm_chain_add_32(error, &nmreq, create);
5308 	if (create) {
5309 		if (exclusive) {
5310 			nfsm_chain_add_32(error, &nmreq, NFS_CREATE_EXCLUSIVE);
5311 			error = nfsm_chaim_add_exclusive_create_verifier(error, &nmreq, nmp);
5312 		} else {
5313 			nfsm_chain_add_32(error, &nmreq, NFS_CREATE_UNCHECKED);
5314 			nfsm_chain_add_fattr4(error, &nmreq, vap, nmp);
5315 		}
5316 	}
5317 	nfsm_chain_add_32(error, &nmreq, NFS_CLAIM_NULL);
5318 	nfsm_chain_add_name(error, &nmreq, cnp->cn_nameptr, cnp->cn_namelen, nmp);
5319 	numops--;
5320 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_GETATTR);
5321 	NFS_COPY_ATTRIBUTES(nfs_getattr_bitmap, bitmap);
5322 	NFS_BITMAP_SET(bitmap, NFS_FATTR_FILEHANDLE);
5323 	nfsm_chain_add_bitmap_supported(error, &nmreq, bitmap, nmp, np);
5324 	numops--;
5325 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_RESTOREFH);
5326 	numops--;
5327 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_GETATTR);
5328 	nfsm_chain_add_bitmap_supported(error, &nmreq, nfs_getattr_bitmap, nmp, dnp);
5329 	nfsm_chain_build_done(error, &nmreq);
5330 	nfsm_assert(error, (numops == 0), EPROTO);
5331 	if (!error) {
5332 		error = busyerror = nfs_node_set_busy(dnp, thd);
5333 	}
5334 	nfsmout_if(error);
5335 
5336 	if (create && !namedattrs) {
5337 		nfs_dulookup_init(dul, dnp, cnp->cn_nameptr, cnp->cn_namelen, ctx);
5338 	}
5339 
5340 	error = nfs_request_async(dnp, NULL, &nmreq, NFSPROC4_COMPOUND, thd, cred, &si, R_NOINTR, NULL, &req);
5341 	if (!error) {
5342 		if (create && !namedattrs) {
5343 			nfs_dulookup_start(dul, dnp, ctx);
5344 		}
5345 		error = nfs_request_async_finish(req, &nmrep, &xid, &status);
5346 		savedxid = xid;
5347 	}
5348 
5349 	if (create && !namedattrs) {
5350 		nfs_dulookup_finish(dul, dnp, ctx);
5351 	}
5352 
5353 	if ((lockerror = nfs_node_lock(dnp))) {
5354 		error = lockerror;
5355 	}
5356 	nfsm_chain_skip_tag(error, &nmrep);
5357 	nfsm_chain_get_32(error, &nmrep, numops);
5358 	nfsm_chain_op_check(error, &nmrep, NFS_OP_PUTFH);
5359 	nfsm_chain_op_check(error, &nmrep, NFS_OP_SAVEFH);
5360 	nfsmout_if(error);
5361 	nfsm_chain_op_check(error, &nmrep, NFS_OP_OPEN);
5362 	nfs_owner_seqid_increment(noop, NULL, error);
5363 	nfsm_chain_get_stateid(error, &nmrep, sid);
5364 	nfsm_chain_check_change_info(error, &nmrep, dnp);
5365 	nfsm_chain_get_32(error, &nmrep, rflags);
5366 	bmlen = NFS_ATTR_BITMAP_LEN;
5367 	nfsm_chain_get_bitmap(error, &nmrep, bitmap, bmlen);
5368 	nfsm_chain_get_32(error, &nmrep, delegation);
5369 	if (!error) {
5370 		switch (delegation) {
5371 		case NFS_OPEN_DELEGATE_NONE:
5372 			break;
5373 		case NFS_OPEN_DELEGATE_READ:
5374 		case NFS_OPEN_DELEGATE_WRITE:
5375 			nfsm_chain_get_stateid(error, &nmrep, &dstateid);
5376 			nfsm_chain_get_32(error, &nmrep, recall);
5377 			if (delegation == NFS_OPEN_DELEGATE_WRITE) { // space (skip) XXX
5378 				nfsm_chain_adv(error, &nmrep, 3 * NFSX_UNSIGNED);
5379 			}
5380 			/* if we have any trouble accepting the ACE, just invalidate it */
5381 			ace_type = ace_flags = ace_mask = len = 0;
5382 			nfsm_chain_get_32(error, &nmrep, ace_type);
5383 			nfsm_chain_get_32(error, &nmrep, ace_flags);
5384 			nfsm_chain_get_32(error, &nmrep, ace_mask);
5385 			nfsm_chain_get_32(error, &nmrep, len);
5386 			ace.ace_flags = nfs4_ace_nfstype_to_vfstype(ace_type, &error);
5387 			ace.ace_flags |= nfs4_ace_nfsflags_to_vfsflags(ace_flags);
5388 			ace.ace_rights = nfs4_ace_nfsmask_to_vfsrights(ace_mask);
5389 			if (!error && (len >= slen)) {
5390 				s = kalloc_data(len + 1, Z_WAITOK);
5391 				if (s) {
5392 					slen = len + 1;
5393 				} else {
5394 					ace.ace_flags = 0;
5395 				}
5396 			}
5397 			if (s) {
5398 				nfsm_chain_get_opaque(error, &nmrep, len, s);
5399 			} else {
5400 				nfsm_chain_adv(error, &nmrep, nfsm_rndup(len));
5401 			}
5402 			if (!error && s) {
5403 				s[len] = '\0';
5404 				if (nfs4_id2guid(s, &ace.ace_applicable, (ace_flags & NFS_ACE_IDENTIFIER_GROUP))) {
5405 					ace.ace_flags = 0;
5406 				}
5407 			}
5408 			if (error || !s) {
5409 				ace.ace_flags = 0;
5410 			}
5411 			if (s && (s != sbuf)) {
5412 				kfree_data(s, slen);
5413 			}
5414 			break;
5415 		default:
5416 			error = EBADRPC;
5417 			break;
5418 		}
5419 	}
5420 	/* At this point if we have no error, the object was created/opened. */
5421 	open_error = error;
5422 	nfsmout_if(error);
5423 	if (create && vap && !exclusive) {
5424 		nfs_vattr_set_supported(bitmap, vap);
5425 	}
5426 	nfsm_chain_op_check(error, &nmrep, NFS_OP_GETATTR);
5427 	nfsmout_if(error);
5428 	error = nfs4_parsefattr(&nmrep, NULL, nvattr, fh, NULL, NULL);
5429 	nfsmout_if(error);
5430 	if (!NFS_BITMAP_ISSET(nvattr->nva_bitmap, NFS_FATTR_FILEHANDLE)) {
5431 		printf("nfs: open/create didn't return filehandle? %s\n", cnp->cn_nameptr);
5432 		error = EBADRPC;
5433 		goto nfsmout;
5434 	}
5435 	if (!create && np && !NFS_CMPFH(np, fh->fh_data, fh->fh_len)) {
5436 		// XXX for the open case, what if fh doesn't match the vnode we think we're opening?
5437 		// Solaris Named Attributes may do this due to a bug.... so don't warn for named attributes.
5438 		if (!(np->n_vattr.nva_flags & NFS_FFLAG_IS_ATTR)) {
5439 			NP(np, "nfs4_open_rpc: warning: file handle mismatch");
5440 		}
5441 	}
5442 	/* directory attributes: if we don't get them, make sure to invalidate */
5443 	nfsm_chain_op_check(error, &nmrep, NFS_OP_RESTOREFH);
5444 	nfsm_chain_op_check(error, &nmrep, NFS_OP_GETATTR);
5445 	nfsm_chain_loadattr(error, &nmrep, dnp, nfsvers, &xid);
5446 	if (error) {
5447 		NATTRINVALIDATE(dnp);
5448 	}
5449 	nfsmout_if(error);
5450 
5451 	if (rflags & NFS_OPEN_RESULT_LOCKTYPE_POSIX) {
5452 		nofp->nof_flags |= NFS_OPEN_FILE_POSIXLOCK;
5453 	}
5454 
5455 	if (rflags & NFS_OPEN_RESULT_CONFIRM) {
5456 		nfs_node_unlock(dnp);
5457 		lockerror = ENOENT;
5458 		NVATTR_CLEANUP(nvattr);
5459 		error = nfs4_open_confirm_rpc(nmp, dnp, fh->fh_data, fh->fh_len, noop, sid, thd, cred, nvattr, &xid);
5460 		nfsmout_if(error);
5461 		savedxid = xid;
5462 		if ((lockerror = nfs_node_lock(dnp))) {
5463 			error = lockerror;
5464 		}
5465 	}
5466 
5467 nfsmout:
5468 	nfsm_chain_cleanup(&nmreq);
5469 	nfsm_chain_cleanup(&nmrep);
5470 
5471 	if (!lockerror && create) {
5472 		if (!open_error && (dnp->n_flag & NNEGNCENTRIES)) {
5473 			dnp->n_flag &= ~NNEGNCENTRIES;
5474 			cache_purge_negatives(dvp);
5475 		}
5476 		dnp->n_flag |= NMODIFIED;
5477 		nfs_node_unlock(dnp);
5478 		lockerror = ENOENT;
5479 		nfs_getattr(dnp, NULL, ctx, NGA_CACHED);
5480 	}
5481 	if (!lockerror) {
5482 		nfs_node_unlock(dnp);
5483 	}
5484 	if (!error && !np && fh->fh_len) {
5485 		/* create the vnode with the filehandle and attributes */
5486 		xid = savedxid;
5487 		error = nfs_nget(NFSTOMP(dnp), dnp, cnp, fh->fh_data, fh->fh_len, nvattr, &xid, req->r_auth, NG_MAKEENTRY, &newnp);
5488 		if (!error) {
5489 			newvp = NFSTOV(newnp);
5490 		}
5491 	}
5492 	NVATTR_CLEANUP(nvattr);
5493 	if (!busyerror) {
5494 		nfs_node_clear_busy(dnp);
5495 	}
5496 	if ((delegation == NFS_OPEN_DELEGATE_READ) || (delegation == NFS_OPEN_DELEGATE_WRITE)) {
5497 		if (!np) {
5498 			np = newnp;
5499 		}
5500 		if (!error && np && !recall) {
5501 			/* stuff the delegation state in the node */
5502 			lck_mtx_lock(&np->n_openlock);
5503 			np->n_openflags &= ~N_DELEG_MASK;
5504 			np->n_openflags |= ((delegation == NFS_OPEN_DELEGATE_READ) ? N_DELEG_READ : N_DELEG_WRITE);
5505 			np->n_dstateid = dstateid;
5506 			np->n_dace = ace;
5507 			if (np->n_dlink.tqe_next == NFSNOLIST) {
5508 				lck_mtx_lock(&nmp->nm_lock);
5509 				if (np->n_dlink.tqe_next == NFSNOLIST) {
5510 					TAILQ_INSERT_TAIL(&nmp->nm_delegations, np, n_dlink);
5511 				}
5512 				lck_mtx_unlock(&nmp->nm_lock);
5513 			}
5514 			lck_mtx_unlock(&np->n_openlock);
5515 		} else {
5516 			/* give the delegation back */
5517 			if (np) {
5518 				if (NFS_CMPFH(np, fh->fh_data, fh->fh_len)) {
5519 					/* update delegation state and return it */
5520 					lck_mtx_lock(&np->n_openlock);
5521 					np->n_openflags &= ~N_DELEG_MASK;
5522 					np->n_openflags |= ((delegation == NFS_OPEN_DELEGATE_READ) ? N_DELEG_READ : N_DELEG_WRITE);
5523 					np->n_dstateid = dstateid;
5524 					np->n_dace = ace;
5525 					if (np->n_dlink.tqe_next == NFSNOLIST) {
5526 						lck_mtx_lock(&nmp->nm_lock);
5527 						if (np->n_dlink.tqe_next == NFSNOLIST) {
5528 							TAILQ_INSERT_TAIL(&nmp->nm_delegations, np, n_dlink);
5529 						}
5530 						lck_mtx_unlock(&nmp->nm_lock);
5531 					}
5532 					lck_mtx_unlock(&np->n_openlock);
5533 					/* don't need to send a separate delegreturn for fh */
5534 					fh->fh_len = 0;
5535 				}
5536 				/* return np's current delegation */
5537 				nfs4_delegation_return(np, 0, thd, cred);
5538 			}
5539 			if (fh->fh_len) { /* return fh's delegation if it wasn't for np */
5540 				nfs4_delegreturn_rpc(nmp, fh->fh_data, fh->fh_len, &dstateid, 0, thd, cred);
5541 			}
5542 		}
5543 	}
5544 	if (error) {
5545 		if (exclusive && (error == NFSERR_NOTSUPP)) {
5546 			exclusive = 0;
5547 			goto again;
5548 		}
5549 		if (newvp) {
5550 			nfs_node_unlock(newnp);
5551 			vnode_put(newvp);
5552 		}
5553 	} else if (create) {
5554 		nfs_node_unlock(newnp);
5555 		if (exclusive) {
5556 			error = nfs4_setattr_rpc(newnp, vap, ctx);
5557 			if (error && (gotuid || gotgid)) {
5558 				/* it's possible the server didn't like our attempt to set IDs. */
5559 				/* so, let's try it again without those */
5560 				VATTR_CLEAR_ACTIVE(vap, va_uid);
5561 				VATTR_CLEAR_ACTIVE(vap, va_gid);
5562 				error = nfs4_setattr_rpc(newnp, vap, ctx);
5563 			}
5564 		}
5565 		if (error) {
5566 			vnode_put(newvp);
5567 		} else {
5568 			*vpp = newvp;
5569 		}
5570 	}
5571 	nfs_open_owner_clear_busy(noop);
5572 	NFS_ZFREE(nfs_fhandle_zone, fh);
5573 	NFS_ZFREE(nfs_req_zone, req);
5574 	kfree_type(struct nfs_dulookup, dul);
5575 	zfree(KT_NFS_VATTR, nvattr);
5576 	return error;
5577 }
5578 
5579 
5580 /*
5581  * Send an OPEN RPC to claim a delegated open for a file
5582  */
5583 int
nfs4_claim_delegated_open_rpc(struct nfs_open_file * nofp,int share_access,int share_deny,int flags)5584 nfs4_claim_delegated_open_rpc(
5585 	struct nfs_open_file *nofp,
5586 	int share_access,
5587 	int share_deny,
5588 	int flags)
5589 {
5590 	struct nfsmount *nmp;
5591 	struct nfs_open_owner *noop = nofp->nof_owner;
5592 	struct nfs_vattr *nvattr;
5593 	int error = 0, lockerror = ENOENT, status;
5594 	int nfsvers, numops;
5595 	u_int64_t xid;
5596 	nfsnode_t np = nofp->nof_np;
5597 	struct nfsm_chain nmreq, nmrep;
5598 	uint32_t bitmap[NFS_ATTR_BITMAP_LEN], bmlen;
5599 	uint32_t rflags = 0, delegation, recall = 0;
5600 	fhandle_t *fh;
5601 	struct nfs_stateid dstateid;
5602 	char sbuf[64], *s = sbuf;
5603 	uint32_t ace_type, ace_flags, ace_mask, len, slen = sizeof(sbuf);
5604 	struct kauth_ace ace;
5605 	vnode_t dvp = NULL;
5606 	const char *vname = NULL;
5607 	const char *name = NULL;
5608 	uint32_t namelen = 0;
5609 	char smallname[128];
5610 	char *filename = NULL;
5611 	struct nfsreq_secinfo_args si;
5612 
5613 	nmp = NFSTONMP(np);
5614 	if (nfs_mount_gone(nmp)) {
5615 		return ENXIO;
5616 	}
5617 	fh = zalloc(nfs_fhandle_zone);
5618 	nvattr = zalloc_flags(KT_NFS_VATTR, Z_WAITOK);
5619 	nfsvers = nmp->nm_vers;
5620 
5621 	nfs_node_lock_force(np);
5622 	if ((vnode_vtype(NFSTOV(np)) != VDIR) && np->n_sillyrename) {
5623 		/*
5624 		 * The node's been sillyrenamed, so we need to use
5625 		 * the sillyrename directory/name to do the open.
5626 		 */
5627 		struct nfs_sillyrename *nsp = np->n_sillyrename;
5628 		dvp = NFSTOV(nsp->nsr_dnp);
5629 		if ((error = vnode_get(dvp))) {
5630 			dvp = NULLVP;
5631 			nfs_node_unlock(np);
5632 			goto out;
5633 		}
5634 		name = nsp->nsr_name;
5635 	} else {
5636 		/*
5637 		 * [sigh] We can't trust VFS to get the parent right for named
5638 		 * attribute nodes.  (It likes to reparent the nodes after we've
5639 		 * created them.)  Luckily we can probably get the right parent
5640 		 * from the n_parent we have stashed away.
5641 		 */
5642 		if ((np->n_vattr.nva_flags & NFS_FFLAG_IS_ATTR) &&
5643 		    (((dvp = np->n_parent)) && (error = vnode_get(dvp)))) {
5644 			dvp = NULL;
5645 		}
5646 		if (!dvp) {
5647 			dvp = vnode_getparent(NFSTOV(np));
5648 		}
5649 		vname = vnode_getname(NFSTOV(np));
5650 		if (!dvp || !vname) {
5651 			if (!error) {
5652 				error = EIO;
5653 			}
5654 			nfs_node_unlock(np);
5655 			goto out;
5656 		}
5657 		name = vname;
5658 	}
5659 	filename = &smallname[0];
5660 	namelen = snprintf(filename, sizeof(smallname), "%s", name);
5661 	if (namelen >= sizeof(smallname)) {
5662 		filename = kalloc_data(namelen + 1, Z_WAITOK);
5663 		if (!filename) {
5664 			error = ENOMEM;
5665 			nfs_node_unlock(np);
5666 			goto out;
5667 		}
5668 		snprintf(filename, namelen + 1, "%s", name);
5669 	}
5670 	nfs_node_unlock(np);
5671 
5672 	if ((error = nfs_open_owner_set_busy(noop, NULL))) {
5673 		goto out;
5674 	}
5675 	NVATTR_INIT(nvattr);
5676 	delegation = NFS_OPEN_DELEGATE_NONE;
5677 	dstateid = np->n_dstateid;
5678 	NFSREQ_SECINFO_SET(&si, VTONFS(dvp), NULL, 0, filename, namelen);
5679 
5680 	nfsm_chain_null(&nmreq);
5681 	nfsm_chain_null(&nmrep);
5682 
5683 	// PUTFH, OPEN, GETATTR(FH)
5684 	numops = 3;
5685 	nfsm_chain_build_alloc_init(error, &nmreq, 48 * NFSX_UNSIGNED);
5686 	nfsm_chain_add_compound_header(error, &nmreq, "open_claim_d", nmp->nm_minor_vers, numops);
5687 	numops--;
5688 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_PUTFH);
5689 	nfsm_chain_add_fh(error, &nmreq, nfsvers, VTONFS(dvp)->n_fhp, VTONFS(dvp)->n_fhsize);
5690 	numops--;
5691 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_OPEN);
5692 	nfsm_chain_add_32(error, &nmreq, noop->noo_seqid);
5693 	nfsm_chain_add_32(error, &nmreq, share_access);
5694 	nfsm_chain_add_32(error, &nmreq, share_deny);
5695 	// open owner: clientid + uid + pid?
5696 	nfsm_chain_add_openowner(error, &nmreq, nmp, noop);
5697 	// openflag4
5698 	nfsm_chain_add_32(error, &nmreq, NFS_OPEN_NOCREATE);
5699 	// open_claim4
5700 	nfsm_chain_add_32(error, &nmreq, NFS_CLAIM_DELEGATE_CUR);
5701 	nfsm_chain_add_stateid(error, &nmreq, &np->n_dstateid);
5702 	nfsm_chain_add_name(error, &nmreq, filename, namelen, nmp);
5703 	numops--;
5704 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_GETATTR);
5705 	NFS_COPY_ATTRIBUTES(nfs_getattr_bitmap, bitmap);
5706 	NFS_BITMAP_SET(bitmap, NFS_FATTR_FILEHANDLE);
5707 	nfsm_chain_add_bitmap_supported(error, &nmreq, bitmap, nmp, np);
5708 	nfsm_chain_build_done(error, &nmreq);
5709 	nfsm_assert(error, (numops == 0), EPROTO);
5710 	nfsmout_if(error);
5711 
5712 	error = nfs_request2(np, nmp->nm_mountp, &nmreq, NFSPROC4_COMPOUND, current_thread(),
5713 	    noop->noo_cred, &si, flags | R_NOINTR, &nmrep, &xid, &status);
5714 
5715 	if ((lockerror = nfs_node_lock(np))) {
5716 		error = lockerror;
5717 	}
5718 	nfsm_chain_skip_tag(error, &nmrep);
5719 	nfsm_chain_get_32(error, &nmrep, numops);
5720 	nfsm_chain_op_check(error, &nmrep, NFS_OP_PUTFH);
5721 	nfsmout_if(error);
5722 	nfsm_chain_op_check(error, &nmrep, NFS_OP_OPEN);
5723 	nfs_owner_seqid_increment(noop, NULL, error);
5724 	nfsm_chain_get_stateid(error, &nmrep, &nofp->nof_stateid);
5725 	nfsm_chain_check_change_info(error, &nmrep, np);
5726 	nfsm_chain_get_32(error, &nmrep, rflags);
5727 	bmlen = NFS_ATTR_BITMAP_LEN;
5728 	nfsm_chain_get_bitmap(error, &nmrep, bitmap, bmlen);
5729 	nfsm_chain_get_32(error, &nmrep, delegation);
5730 	if (!error) {
5731 		switch (delegation) {
5732 		case NFS_OPEN_DELEGATE_NONE:
5733 			// if (!(np->n_openflags & N_DELEG_RETURN)) /* don't warn if delegation is being returned */
5734 			//      printf("nfs: open delegated claim didn't return a delegation %s\n", filename ? filename : "???");
5735 			break;
5736 		case NFS_OPEN_DELEGATE_READ:
5737 		case NFS_OPEN_DELEGATE_WRITE:
5738 			if ((((np->n_openflags & N_DELEG_MASK) == N_DELEG_READ) &&
5739 			    (delegation == NFS_OPEN_DELEGATE_WRITE)) ||
5740 			    (((np->n_openflags & N_DELEG_MASK) == N_DELEG_WRITE) &&
5741 			    (delegation == NFS_OPEN_DELEGATE_READ))) {
5742 				printf("nfs: open delegated claim returned a different delegation type! have %s got %s %s\n",
5743 				    ((np->n_openflags & N_DELEG_MASK) == N_DELEG_WRITE) ? "W" : "R",
5744 				    (delegation == NFS_OPEN_DELEGATE_WRITE) ? "W" : "R", filename ? filename : "???");
5745 			}
5746 			nfsm_chain_get_stateid(error, &nmrep, &dstateid);
5747 			nfsm_chain_get_32(error, &nmrep, recall);
5748 			if (delegation == NFS_OPEN_DELEGATE_WRITE) { // space (skip) XXX
5749 				nfsm_chain_adv(error, &nmrep, 3 * NFSX_UNSIGNED);
5750 			}
5751 			/* if we have any trouble accepting the ACE, just invalidate it */
5752 			ace_type = ace_flags = ace_mask = len = 0;
5753 			nfsm_chain_get_32(error, &nmrep, ace_type);
5754 			nfsm_chain_get_32(error, &nmrep, ace_flags);
5755 			nfsm_chain_get_32(error, &nmrep, ace_mask);
5756 			nfsm_chain_get_32(error, &nmrep, len);
5757 			ace.ace_flags = nfs4_ace_nfstype_to_vfstype(ace_type, &error);
5758 			ace.ace_flags |= nfs4_ace_nfsflags_to_vfsflags(ace_flags);
5759 			ace.ace_rights = nfs4_ace_nfsmask_to_vfsrights(ace_mask);
5760 			if (!error && (len >= slen)) {
5761 				s = kalloc_data(len + 1, Z_WAITOK);
5762 				if (s) {
5763 					slen = len + 1;
5764 				} else {
5765 					ace.ace_flags = 0;
5766 				}
5767 			}
5768 			if (s) {
5769 				nfsm_chain_get_opaque(error, &nmrep, len, s);
5770 			} else {
5771 				nfsm_chain_adv(error, &nmrep, nfsm_rndup(len));
5772 			}
5773 			if (!error && s) {
5774 				s[len] = '\0';
5775 				if (nfs4_id2guid(s, &ace.ace_applicable, (ace_flags & NFS_ACE_IDENTIFIER_GROUP))) {
5776 					ace.ace_flags = 0;
5777 				}
5778 			}
5779 			if (error || !s) {
5780 				ace.ace_flags = 0;
5781 			}
5782 			if (s && (s != sbuf)) {
5783 				kfree_data(s, slen);
5784 			}
5785 			if (!error) {
5786 				/* stuff the latest delegation state in the node */
5787 				lck_mtx_lock(&np->n_openlock);
5788 				np->n_openflags &= ~N_DELEG_MASK;
5789 				np->n_openflags |= ((delegation == NFS_OPEN_DELEGATE_READ) ? N_DELEG_READ : N_DELEG_WRITE);
5790 				np->n_dstateid = dstateid;
5791 				np->n_dace = ace;
5792 				if (np->n_dlink.tqe_next == NFSNOLIST) {
5793 					lck_mtx_lock(&nmp->nm_lock);
5794 					if (np->n_dlink.tqe_next == NFSNOLIST) {
5795 						TAILQ_INSERT_TAIL(&nmp->nm_delegations, np, n_dlink);
5796 					}
5797 					lck_mtx_unlock(&nmp->nm_lock);
5798 				}
5799 				lck_mtx_unlock(&np->n_openlock);
5800 			}
5801 			break;
5802 		default:
5803 			error = EBADRPC;
5804 			break;
5805 		}
5806 	}
5807 	nfsmout_if(error);
5808 	nfsm_chain_op_check(error, &nmrep, NFS_OP_GETATTR);
5809 	error = nfs4_parsefattr(&nmrep, NULL, nvattr, fh, NULL, NULL);
5810 	nfsmout_if(error);
5811 	if (!NFS_BITMAP_ISSET(nvattr->nva_bitmap, NFS_FATTR_FILEHANDLE)) {
5812 		printf("nfs: open reclaim didn't return filehandle? %s\n", filename ? filename : "???");
5813 		error = EBADRPC;
5814 		goto nfsmout;
5815 	}
5816 	if (!NFS_CMPFH(np, fh->fh_data, fh->fh_len)) {
5817 		// XXX what if fh doesn't match the vnode we think we're re-opening?
5818 		// Solaris Named Attributes may do this due to a bug.... so don't warn for named attributes.
5819 		if (!(np->n_vattr.nva_flags & NFS_FFLAG_IS_ATTR)) {
5820 			printf("nfs4_claim_delegated_open_rpc: warning: file handle mismatch %s\n", filename ? filename : "???");
5821 		}
5822 	}
5823 	error = nfs_loadattrcache(np, nvattr, &xid, 1);
5824 	nfsmout_if(error);
5825 	if (rflags & NFS_OPEN_RESULT_LOCKTYPE_POSIX) {
5826 		nofp->nof_flags |= NFS_OPEN_FILE_POSIXLOCK;
5827 	}
5828 nfsmout:
5829 	NVATTR_CLEANUP(nvattr);
5830 	zfree(KT_NFS_VATTR, nvattr);
5831 	NFS_ZFREE(nfs_fhandle_zone, fh);
5832 	nfsm_chain_cleanup(&nmreq);
5833 	nfsm_chain_cleanup(&nmrep);
5834 	if (!lockerror) {
5835 		nfs_node_unlock(np);
5836 	}
5837 	nfs_open_owner_clear_busy(noop);
5838 	if ((delegation == NFS_OPEN_DELEGATE_READ) || (delegation == NFS_OPEN_DELEGATE_WRITE)) {
5839 		if (recall) {
5840 			/*
5841 			 * We're making a delegated claim.
5842 			 * Don't return the delegation here in case we have more to claim.
5843 			 * Just make sure it's queued up to be returned.
5844 			 */
5845 			nfs4_delegation_return_enqueue(np);
5846 		}
5847 	}
5848 out:
5849 	// if (!error)
5850 	//      printf("nfs: open claim delegated (%d, %d) succeeded for %s\n", share_access, share_deny, filename ? filename : "???");
5851 	if (filename && (filename != &smallname[0])) {
5852 		kfree_data(filename, namelen + 1);
5853 	}
5854 	if (vname) {
5855 		vnode_putname(vname);
5856 	}
5857 	if (dvp != NULLVP) {
5858 		vnode_put(dvp);
5859 	}
5860 	return error;
5861 }
5862 
5863 /*
5864  * Send an OPEN RPC to reclaim an open file.
5865  */
5866 int
nfs4_open_reclaim_rpc(struct nfs_open_file * nofp,int share_access,int share_deny)5867 nfs4_open_reclaim_rpc(
5868 	struct nfs_open_file *nofp,
5869 	int share_access,
5870 	int share_deny)
5871 {
5872 	struct nfsmount *nmp;
5873 	struct nfs_open_owner *noop = nofp->nof_owner;
5874 	struct nfs_vattr *nvattr;
5875 	int error = 0, lockerror = ENOENT, status;
5876 	int nfsvers, numops;
5877 	u_int64_t xid;
5878 	nfsnode_t np = nofp->nof_np;
5879 	struct nfsm_chain nmreq, nmrep;
5880 	uint32_t bitmap[NFS_ATTR_BITMAP_LEN], bmlen;
5881 	uint32_t rflags = 0, delegation, recall = 0;
5882 	fhandle_t *fh;
5883 	struct nfs_stateid dstateid;
5884 	char sbuf[64], *s = sbuf;
5885 	uint32_t ace_type, ace_flags, ace_mask, len, slen = sizeof(sbuf);
5886 	struct kauth_ace ace;
5887 	struct nfsreq_secinfo_args si;
5888 
5889 	nmp = NFSTONMP(np);
5890 	if (nfs_mount_gone(nmp)) {
5891 		return ENXIO;
5892 	}
5893 	nfsvers = nmp->nm_vers;
5894 
5895 	if ((error = nfs_open_owner_set_busy(noop, NULL))) {
5896 		return error;
5897 	}
5898 
5899 	fh = zalloc(nfs_fhandle_zone);
5900 	nvattr = zalloc_flags(KT_NFS_VATTR, Z_WAITOK);
5901 	NVATTR_INIT(nvattr);
5902 	delegation = NFS_OPEN_DELEGATE_NONE;
5903 	dstateid = np->n_dstateid;
5904 	NFSREQ_SECINFO_SET(&si, np, NULL, 0, NULL, 0);
5905 
5906 	nfsm_chain_null(&nmreq);
5907 	nfsm_chain_null(&nmrep);
5908 
5909 	// PUTFH, OPEN, GETATTR(FH)
5910 	numops = 3;
5911 	nfsm_chain_build_alloc_init(error, &nmreq, 48 * NFSX_UNSIGNED);
5912 	nfsm_chain_add_compound_header(error, &nmreq, "open_reclaim", nmp->nm_minor_vers, numops);
5913 	numops--;
5914 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_PUTFH);
5915 	nfsm_chain_add_fh(error, &nmreq, nfsvers, np->n_fhp, np->n_fhsize);
5916 	numops--;
5917 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_OPEN);
5918 	nfsm_chain_add_32(error, &nmreq, noop->noo_seqid);
5919 	nfsm_chain_add_32(error, &nmreq, share_access);
5920 	nfsm_chain_add_32(error, &nmreq, share_deny);
5921 	// open owner: clientid + uid + pid?
5922 	nfsm_chain_add_openowner(error, &nmreq, nmp, noop);
5923 	// openflag4
5924 	nfsm_chain_add_32(error, &nmreq, NFS_OPEN_NOCREATE);
5925 	// open_claim4
5926 	nfsm_chain_add_32(error, &nmreq, NFS_CLAIM_PREVIOUS);
5927 	delegation = (np->n_openflags & N_DELEG_READ) ? NFS_OPEN_DELEGATE_READ :
5928 	    (np->n_openflags & N_DELEG_WRITE) ? NFS_OPEN_DELEGATE_WRITE :
5929 	    NFS_OPEN_DELEGATE_NONE;
5930 	nfsm_chain_add_32(error, &nmreq, delegation);
5931 	delegation = NFS_OPEN_DELEGATE_NONE;
5932 	numops--;
5933 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_GETATTR);
5934 	NFS_COPY_ATTRIBUTES(nfs_getattr_bitmap, bitmap);
5935 	NFS_BITMAP_SET(bitmap, NFS_FATTR_FILEHANDLE);
5936 	nfsm_chain_add_bitmap_supported(error, &nmreq, bitmap, nmp, np);
5937 	nfsm_chain_build_done(error, &nmreq);
5938 	nfsm_assert(error, (numops == 0), EPROTO);
5939 	nfsmout_if(error);
5940 
5941 	error = nfs_request2(np, nmp->nm_mountp, &nmreq, NFSPROC4_COMPOUND, current_thread(),
5942 	    noop->noo_cred, &si, R_RECOVER | R_NOINTR, &nmrep, &xid, &status);
5943 
5944 	if ((lockerror = nfs_node_lock(np))) {
5945 		error = lockerror;
5946 	}
5947 	nfsm_chain_skip_tag(error, &nmrep);
5948 	nfsm_chain_get_32(error, &nmrep, numops);
5949 	nfsm_chain_op_check(error, &nmrep, NFS_OP_PUTFH);
5950 	nfsmout_if(error);
5951 	nfsm_chain_op_check(error, &nmrep, NFS_OP_OPEN);
5952 	nfs_owner_seqid_increment(noop, NULL, error);
5953 	nfsm_chain_get_stateid(error, &nmrep, &nofp->nof_stateid);
5954 	nfsm_chain_check_change_info(error, &nmrep, np);
5955 	nfsm_chain_get_32(error, &nmrep, rflags);
5956 	bmlen = NFS_ATTR_BITMAP_LEN;
5957 	nfsm_chain_get_bitmap(error, &nmrep, bitmap, bmlen);
5958 	nfsm_chain_get_32(error, &nmrep, delegation);
5959 	if (!error) {
5960 		switch (delegation) {
5961 		case NFS_OPEN_DELEGATE_NONE:
5962 			if (np->n_openflags & N_DELEG_MASK) {
5963 				/*
5964 				 * Hey!  We were supposed to get our delegation back even
5965 				 * if it was getting immediately recalled.  Bad server!
5966 				 *
5967 				 * Just try to return the existing delegation.
5968 				 */
5969 				// NP(np, "nfs: open reclaim didn't return delegation?");
5970 				delegation = (np->n_openflags & N_DELEG_WRITE) ? NFS_OPEN_DELEGATE_WRITE : NFS_OPEN_DELEGATE_READ;
5971 				recall = 1;
5972 			}
5973 			break;
5974 		case NFS_OPEN_DELEGATE_READ:
5975 		case NFS_OPEN_DELEGATE_WRITE:
5976 			nfsm_chain_get_stateid(error, &nmrep, &dstateid);
5977 			nfsm_chain_get_32(error, &nmrep, recall);
5978 			if (delegation == NFS_OPEN_DELEGATE_WRITE) { // space (skip) XXX
5979 				nfsm_chain_adv(error, &nmrep, 3 * NFSX_UNSIGNED);
5980 			}
5981 			/* if we have any trouble accepting the ACE, just invalidate it */
5982 			ace_type = ace_flags = ace_mask = len = 0;
5983 			nfsm_chain_get_32(error, &nmrep, ace_type);
5984 			nfsm_chain_get_32(error, &nmrep, ace_flags);
5985 			nfsm_chain_get_32(error, &nmrep, ace_mask);
5986 			nfsm_chain_get_32(error, &nmrep, len);
5987 			ace.ace_flags = nfs4_ace_nfstype_to_vfstype(ace_type, &error);
5988 			ace.ace_flags |= nfs4_ace_nfsflags_to_vfsflags(ace_flags);
5989 			ace.ace_rights = nfs4_ace_nfsmask_to_vfsrights(ace_mask);
5990 			if (!error && (len >= slen)) {
5991 				s = kalloc_data(len + 1, Z_WAITOK);
5992 				if (s) {
5993 					slen = len + 1;
5994 				} else {
5995 					ace.ace_flags = 0;
5996 				}
5997 			}
5998 			if (s) {
5999 				nfsm_chain_get_opaque(error, &nmrep, len, s);
6000 			} else {
6001 				nfsm_chain_adv(error, &nmrep, nfsm_rndup(len));
6002 			}
6003 			if (!error && s) {
6004 				s[len] = '\0';
6005 				if (nfs4_id2guid(s, &ace.ace_applicable, (ace_flags & NFS_ACE_IDENTIFIER_GROUP))) {
6006 					ace.ace_flags = 0;
6007 				}
6008 			}
6009 			if (error || !s) {
6010 				ace.ace_flags = 0;
6011 			}
6012 			if (s && (s != sbuf)) {
6013 				kfree_data(s, slen);
6014 			}
6015 			if (!error) {
6016 				/* stuff the delegation state in the node */
6017 				lck_mtx_lock(&np->n_openlock);
6018 				np->n_openflags &= ~N_DELEG_MASK;
6019 				np->n_openflags |= ((delegation == NFS_OPEN_DELEGATE_READ) ? N_DELEG_READ : N_DELEG_WRITE);
6020 				np->n_dstateid = dstateid;
6021 				np->n_dace = ace;
6022 				if (np->n_dlink.tqe_next == NFSNOLIST) {
6023 					lck_mtx_lock(&nmp->nm_lock);
6024 					if (np->n_dlink.tqe_next == NFSNOLIST) {
6025 						TAILQ_INSERT_TAIL(&nmp->nm_delegations, np, n_dlink);
6026 					}
6027 					lck_mtx_unlock(&nmp->nm_lock);
6028 				}
6029 				lck_mtx_unlock(&np->n_openlock);
6030 			}
6031 			break;
6032 		default:
6033 			error = EBADRPC;
6034 			break;
6035 		}
6036 	}
6037 	nfsmout_if(error);
6038 	nfsm_chain_op_check(error, &nmrep, NFS_OP_GETATTR);
6039 	error = nfs4_parsefattr(&nmrep, NULL, nvattr, fh, NULL, NULL);
6040 	nfsmout_if(error);
6041 	if (!NFS_BITMAP_ISSET(nvattr->nva_bitmap, NFS_FATTR_FILEHANDLE)) {
6042 		NP(np, "nfs: open reclaim didn't return filehandle?");
6043 		error = EBADRPC;
6044 		goto nfsmout;
6045 	}
6046 	if (!NFS_CMPFH(np, fh->fh_data, fh->fh_len)) {
6047 		// XXX what if fh doesn't match the vnode we think we're re-opening?
6048 		// That should be pretty hard in this case, given that we are doing
6049 		// the open reclaim using the file handle (and not a dir/name pair).
6050 		// Solaris Named Attributes may do this due to a bug.... so don't warn for named attributes.
6051 		if (!(np->n_vattr.nva_flags & NFS_FFLAG_IS_ATTR)) {
6052 			NP(np, "nfs4_open_reclaim_rpc: warning: file handle mismatch");
6053 		}
6054 	}
6055 	error = nfs_loadattrcache(np, nvattr, &xid, 1);
6056 	nfsmout_if(error);
6057 	if (rflags & NFS_OPEN_RESULT_LOCKTYPE_POSIX) {
6058 		nofp->nof_flags |= NFS_OPEN_FILE_POSIXLOCK;
6059 	}
6060 nfsmout:
6061 	// if (!error)
6062 	//      NP(np, "nfs: open reclaim (%d, %d) succeeded", share_access, share_deny);
6063 	NVATTR_CLEANUP(nvattr);
6064 	zfree(KT_NFS_VATTR, nvattr);
6065 	NFS_ZFREE(nfs_fhandle_zone, fh);
6066 	nfsm_chain_cleanup(&nmreq);
6067 	nfsm_chain_cleanup(&nmrep);
6068 	if (!lockerror) {
6069 		nfs_node_unlock(np);
6070 	}
6071 	nfs_open_owner_clear_busy(noop);
6072 	if ((delegation == NFS_OPEN_DELEGATE_READ) || (delegation == NFS_OPEN_DELEGATE_WRITE)) {
6073 		if (recall) {
6074 			nfs4_delegation_return_enqueue(np);
6075 		}
6076 	}
6077 	return error;
6078 }
6079 
6080 int
nfs4_open_downgrade_rpc(nfsnode_t np,struct nfs_open_file * nofp,vfs_context_t ctx)6081 nfs4_open_downgrade_rpc(
6082 	nfsnode_t np,
6083 	struct nfs_open_file *nofp,
6084 	vfs_context_t ctx)
6085 {
6086 	struct nfs_open_owner *noop = nofp->nof_owner;
6087 	struct nfsmount *nmp;
6088 	int error, lockerror = ENOENT, status, nfsvers, numops;
6089 	struct nfsm_chain nmreq, nmrep;
6090 	u_int64_t xid;
6091 	struct nfsreq_secinfo_args si;
6092 
6093 	nmp = NFSTONMP(np);
6094 	if (nfs_mount_gone(nmp)) {
6095 		return ENXIO;
6096 	}
6097 	nfsvers = nmp->nm_vers;
6098 
6099 	if ((error = nfs_open_owner_set_busy(noop, NULL))) {
6100 		return error;
6101 	}
6102 
6103 	NFSREQ_SECINFO_SET(&si, np, NULL, 0, NULL, 0);
6104 	nfsm_chain_null(&nmreq);
6105 	nfsm_chain_null(&nmrep);
6106 
6107 	// PUTFH, OPEN_DOWNGRADE, GETATTR
6108 	numops = 3;
6109 	nfsm_chain_build_alloc_init(error, &nmreq, 23 * NFSX_UNSIGNED);
6110 	nfsm_chain_add_compound_header(error, &nmreq, "open_downgrd", nmp->nm_minor_vers, numops);
6111 	numops--;
6112 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_PUTFH);
6113 	nfsm_chain_add_fh(error, &nmreq, nfsvers, np->n_fhp, np->n_fhsize);
6114 	numops--;
6115 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_OPEN_DOWNGRADE);
6116 	nfsm_chain_add_stateid(error, &nmreq, &nofp->nof_stateid);
6117 	nfsm_chain_add_32(error, &nmreq, noop->noo_seqid);
6118 	nfsm_chain_add_32(error, &nmreq, nofp->nof_access);
6119 	nfsm_chain_add_32(error, &nmreq, nofp->nof_deny);
6120 	numops--;
6121 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_GETATTR);
6122 	nfsm_chain_add_bitmap_supported(error, &nmreq, nfs_getattr_bitmap, nmp, np);
6123 	nfsm_chain_build_done(error, &nmreq);
6124 	nfsm_assert(error, (numops == 0), EPROTO);
6125 	nfsmout_if(error);
6126 	error = nfs_request2(np, NULL, &nmreq, NFSPROC4_COMPOUND,
6127 	    vfs_context_thread(ctx), vfs_context_ucred(ctx),
6128 	    &si, R_NOINTR, &nmrep, &xid, &status);
6129 
6130 	if ((lockerror = nfs_node_lock(np))) {
6131 		error = lockerror;
6132 	}
6133 	nfsm_chain_skip_tag(error, &nmrep);
6134 	nfsm_chain_get_32(error, &nmrep, numops);
6135 	nfsm_chain_op_check(error, &nmrep, NFS_OP_PUTFH);
6136 	nfsmout_if(error);
6137 	nfsm_chain_op_check(error, &nmrep, NFS_OP_OPEN_DOWNGRADE);
6138 	nfs_owner_seqid_increment(noop, NULL, error);
6139 	nfsm_chain_get_stateid(error, &nmrep, &nofp->nof_stateid);
6140 	nfsm_chain_op_check(error, &nmrep, NFS_OP_GETATTR);
6141 	nfsm_chain_loadattr(error, &nmrep, np, nfsvers, &xid);
6142 nfsmout:
6143 	if (!lockerror) {
6144 		nfs_node_unlock(np);
6145 	}
6146 	nfs_open_owner_clear_busy(noop);
6147 	nfsm_chain_cleanup(&nmreq);
6148 	nfsm_chain_cleanup(&nmrep);
6149 	return error;
6150 }
6151 
6152 int
nfs4_close_rpc(nfsnode_t np,struct nfs_open_file * nofp,thread_t thd,kauth_cred_t cred,int flags)6153 nfs4_close_rpc(
6154 	nfsnode_t np,
6155 	struct nfs_open_file *nofp,
6156 	thread_t thd,
6157 	kauth_cred_t cred,
6158 	int flags)
6159 {
6160 	struct nfs_open_owner *noop = nofp->nof_owner;
6161 	struct nfsmount *nmp;
6162 	int error, lockerror = ENOENT, status, nfsvers, numops;
6163 	struct nfsm_chain nmreq, nmrep;
6164 	u_int64_t xid;
6165 	struct nfsreq_secinfo_args si;
6166 
6167 	nmp = NFSTONMP(np);
6168 	if (nfs_mount_gone(nmp)) {
6169 		return ENXIO;
6170 	}
6171 	nfsvers = nmp->nm_vers;
6172 
6173 	if ((error = nfs_open_owner_set_busy(noop, NULL))) {
6174 		return error;
6175 	}
6176 
6177 	NFSREQ_SECINFO_SET(&si, np, NULL, 0, NULL, 0);
6178 	nfsm_chain_null(&nmreq);
6179 	nfsm_chain_null(&nmrep);
6180 
6181 	// PUTFH, CLOSE, GETATTR
6182 	numops = 3;
6183 	nfsm_chain_build_alloc_init(error, &nmreq, 23 * NFSX_UNSIGNED);
6184 	nfsm_chain_add_compound_header(error, &nmreq, "close", nmp->nm_minor_vers, numops);
6185 	numops--;
6186 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_PUTFH);
6187 	nfsm_chain_add_fh(error, &nmreq, nfsvers, np->n_fhp, np->n_fhsize);
6188 	numops--;
6189 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_CLOSE);
6190 	nfsm_chain_add_32(error, &nmreq, noop->noo_seqid);
6191 	nfsm_chain_add_stateid(error, &nmreq, &nofp->nof_stateid);
6192 	numops--;
6193 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_GETATTR);
6194 	nfsm_chain_add_bitmap_supported(error, &nmreq, nfs_getattr_bitmap, nmp, np);
6195 	nfsm_chain_build_done(error, &nmreq);
6196 	nfsm_assert(error, (numops == 0), EPROTO);
6197 	nfsmout_if(error);
6198 	error = nfs_request2(np, NULL, &nmreq, NFSPROC4_COMPOUND, thd, cred, &si, flags | R_NOINTR, &nmrep, &xid, &status);
6199 
6200 	if ((lockerror = nfs_node_lock(np))) {
6201 		error = lockerror;
6202 	}
6203 	nfsm_chain_skip_tag(error, &nmrep);
6204 	nfsm_chain_get_32(error, &nmrep, numops);
6205 	nfsm_chain_op_check(error, &nmrep, NFS_OP_PUTFH);
6206 	nfsmout_if(error);
6207 	nfsm_chain_op_check(error, &nmrep, NFS_OP_CLOSE);
6208 	nfs_owner_seqid_increment(noop, NULL, error);
6209 	nfsm_chain_get_stateid(error, &nmrep, &nofp->nof_stateid);
6210 	nfsm_chain_op_check(error, &nmrep, NFS_OP_GETATTR);
6211 	nfsm_chain_loadattr(error, &nmrep, np, nfsvers, &xid);
6212 nfsmout:
6213 	if (!lockerror) {
6214 		nfs_node_unlock(np);
6215 	}
6216 	nfs_open_owner_clear_busy(noop);
6217 	nfsm_chain_cleanup(&nmreq);
6218 	nfsm_chain_cleanup(&nmrep);
6219 	return error;
6220 }
6221 
6222 int
nfs4_release_lockowner_rpc(nfsnode_t np,struct nfs_lock_owner * nlop,thread_t thd,kauth_cred_t cred)6223 nfs4_release_lockowner_rpc(
6224 	nfsnode_t np,
6225 	struct nfs_lock_owner *nlop,
6226 	thread_t thd,
6227 	kauth_cred_t cred)
6228 {
6229 	struct nfsmount *nmp;
6230 	int error, status, nfsvers, numops;
6231 	struct nfsm_chain nmreq, nmrep;
6232 	u_int64_t xid;
6233 	struct nfsreq_secinfo_args si;
6234 
6235 	nmp = NFSTONMP(np);
6236 	if (nfs_mount_gone(nmp)) {
6237 		return ENXIO;
6238 	}
6239 	nfsvers = nmp->nm_vers;
6240 
6241 	NFSREQ_SECINFO_SET(&si, np, NULL, 0, NULL, 0);
6242 	nfsm_chain_null(&nmreq);
6243 	nfsm_chain_null(&nmrep);
6244 
6245 	// PUTFH, RELEASE_LOCKOWNER
6246 	numops = 2;
6247 	nfsm_chain_build_alloc_init(error, &nmreq, 23 * NFSX_UNSIGNED);
6248 	nfsm_chain_add_compound_header(error, &nmreq, "release lockowner", nmp->nm_minor_vers, numops);
6249 	numops--;
6250 	nfsm_chain_add_32(error, &nmreq, NFS_OP_PUTFH);
6251 	nfsm_chain_add_fh(error, &nmreq, nfsvers, np->n_fhp, np->n_fhsize);
6252 	numops--;
6253 	nfsm_chain_add_32(error, &nmreq, NFS_OP_RELEASE_LOCKOWNER);
6254 	nfsm_chain_add_lock_owner4(error, &nmreq, nmp, nlop);
6255 	nfsm_chain_build_done(error, &nmreq);
6256 	nfsm_assert(error, (numops == 0), EPROTO);
6257 	nfsmout_if(error);
6258 	error = nfs_request2(np, NULL, &nmreq, NFSPROC4_COMPOUND, thd, cred, &si, R_NOINTR, &nmrep, &xid, &status);
6259 
6260 	nfsm_chain_skip_tag(error, &nmrep);
6261 	nfsm_chain_get_32(error, &nmrep, numops);
6262 	nfsm_chain_op_check(error, &nmrep, NFS_OP_PUTFH);
6263 	nfsmout_if(error);
6264 	nfsm_chain_op_check(error, &nmrep, NFS_OP_RELEASE_LOCKOWNER);
6265 	nfsmout_if(error);
6266 nfsmout:
6267 	nfsm_chain_cleanup(&nmreq);
6268 	nfsm_chain_cleanup(&nmrep);
6269 	return error;
6270 }
6271 
6272 /*
6273  * Claim the delegated open combinations this open file holds.
6274  */
6275 int
nfs4_claim_delegated_state_for_open_file(struct nfs_open_file * nofp,int flags)6276 nfs4_claim_delegated_state_for_open_file(struct nfs_open_file *nofp, int flags)
6277 {
6278 	struct nfs_open_owner *noop = nofp->nof_owner;
6279 	struct nfs_lock_owner *nlop;
6280 	struct nfs_file_lock *nflp, *nextnflp;
6281 	struct nfsmount *nmp;
6282 	int error = 0, reopen = 0;
6283 
6284 	if (nofp->nof_d_rw_drw) {
6285 		error = nfs4_claim_delegated_open_rpc(nofp, NFS_OPEN_SHARE_ACCESS_BOTH, NFS_OPEN_SHARE_DENY_BOTH, flags);
6286 		if (!error) {
6287 			lck_mtx_lock(&nofp->nof_lock);
6288 			nofp->nof_rw_drw += nofp->nof_d_rw_drw;
6289 			nofp->nof_d_rw_drw = 0;
6290 			lck_mtx_unlock(&nofp->nof_lock);
6291 		}
6292 	}
6293 	if (!error && nofp->nof_d_w_drw) {
6294 		error = nfs4_claim_delegated_open_rpc(nofp, NFS_OPEN_SHARE_ACCESS_WRITE, NFS_OPEN_SHARE_DENY_BOTH, flags);
6295 		if (!error) {
6296 			lck_mtx_lock(&nofp->nof_lock);
6297 			nofp->nof_w_drw += nofp->nof_d_w_drw;
6298 			nofp->nof_d_w_drw = 0;
6299 			lck_mtx_unlock(&nofp->nof_lock);
6300 		}
6301 	}
6302 	if (!error && nofp->nof_d_r_drw) {
6303 		error = nfs4_claim_delegated_open_rpc(nofp, NFS_OPEN_SHARE_ACCESS_READ, NFS_OPEN_SHARE_DENY_BOTH, flags);
6304 		if (!error) {
6305 			lck_mtx_lock(&nofp->nof_lock);
6306 			nofp->nof_r_drw += nofp->nof_d_r_drw;
6307 			nofp->nof_d_r_drw = 0;
6308 			lck_mtx_unlock(&nofp->nof_lock);
6309 		}
6310 	}
6311 	if (!error && nofp->nof_d_rw_dw) {
6312 		error = nfs4_claim_delegated_open_rpc(nofp, NFS_OPEN_SHARE_ACCESS_BOTH, NFS_OPEN_SHARE_DENY_WRITE, flags);
6313 		if (!error) {
6314 			lck_mtx_lock(&nofp->nof_lock);
6315 			nofp->nof_rw_dw += nofp->nof_d_rw_dw;
6316 			nofp->nof_d_rw_dw = 0;
6317 			lck_mtx_unlock(&nofp->nof_lock);
6318 		}
6319 	}
6320 	if (!error && nofp->nof_d_w_dw) {
6321 		error = nfs4_claim_delegated_open_rpc(nofp, NFS_OPEN_SHARE_ACCESS_WRITE, NFS_OPEN_SHARE_DENY_WRITE, flags);
6322 		if (!error) {
6323 			lck_mtx_lock(&nofp->nof_lock);
6324 			nofp->nof_w_dw += nofp->nof_d_w_dw;
6325 			nofp->nof_d_w_dw = 0;
6326 			lck_mtx_unlock(&nofp->nof_lock);
6327 		}
6328 	}
6329 	if (!error && nofp->nof_d_r_dw) {
6330 		error = nfs4_claim_delegated_open_rpc(nofp, NFS_OPEN_SHARE_ACCESS_READ, NFS_OPEN_SHARE_DENY_WRITE, flags);
6331 		if (!error) {
6332 			lck_mtx_lock(&nofp->nof_lock);
6333 			nofp->nof_r_dw += nofp->nof_d_r_dw;
6334 			nofp->nof_d_r_dw = 0;
6335 			lck_mtx_unlock(&nofp->nof_lock);
6336 		}
6337 	}
6338 	/* non-deny-mode opens may be reopened if no locks are held */
6339 	if (!error && nofp->nof_d_rw) {
6340 		error = nfs4_claim_delegated_open_rpc(nofp, NFS_OPEN_SHARE_ACCESS_BOTH, NFS_OPEN_SHARE_DENY_NONE, flags);
6341 		/* for some errors, we should just try reopening the file */
6342 		if (nfs_mount_state_error_delegation_lost(error)) {
6343 			reopen = error;
6344 		}
6345 		if (!error || reopen) {
6346 			lck_mtx_lock(&nofp->nof_lock);
6347 			nofp->nof_rw += nofp->nof_d_rw;
6348 			nofp->nof_d_rw = 0;
6349 			lck_mtx_unlock(&nofp->nof_lock);
6350 		}
6351 	}
6352 	/* if we've already set reopen, we should move these other two opens from delegated to not delegated */
6353 	if ((!error || reopen) && nofp->nof_d_w) {
6354 		if (!error) {
6355 			error = nfs4_claim_delegated_open_rpc(nofp, NFS_OPEN_SHARE_ACCESS_WRITE, NFS_OPEN_SHARE_DENY_NONE, flags);
6356 			/* for some errors, we should just try reopening the file */
6357 			if (nfs_mount_state_error_delegation_lost(error)) {
6358 				reopen = error;
6359 			}
6360 		}
6361 		if (!error || reopen) {
6362 			lck_mtx_lock(&nofp->nof_lock);
6363 			nofp->nof_w += nofp->nof_d_w;
6364 			nofp->nof_d_w = 0;
6365 			lck_mtx_unlock(&nofp->nof_lock);
6366 		}
6367 	}
6368 	if ((!error || reopen) && nofp->nof_d_r) {
6369 		if (!error) {
6370 			error = nfs4_claim_delegated_open_rpc(nofp, NFS_OPEN_SHARE_ACCESS_READ, NFS_OPEN_SHARE_DENY_NONE, flags);
6371 			/* for some errors, we should just try reopening the file */
6372 			if (nfs_mount_state_error_delegation_lost(error)) {
6373 				reopen = error;
6374 			}
6375 		}
6376 		if (!error || reopen) {
6377 			lck_mtx_lock(&nofp->nof_lock);
6378 			nofp->nof_r += nofp->nof_d_r;
6379 			nofp->nof_d_r = 0;
6380 			lck_mtx_unlock(&nofp->nof_lock);
6381 		}
6382 	}
6383 
6384 	if (reopen) {
6385 		/*
6386 		 * Any problems with the delegation probably indicates that we
6387 		 * should review/return all of our current delegation state.
6388 		 */
6389 		if ((nmp = NFSTONMP(nofp->nof_np))) {
6390 			nfs4_delegation_return_enqueue(nofp->nof_np);
6391 			lck_mtx_lock(&nmp->nm_lock);
6392 			nfs_need_recover(nmp, NFSERR_EXPIRED);
6393 			lck_mtx_unlock(&nmp->nm_lock);
6394 		}
6395 		if (reopen && (nfs_check_for_locks(noop, nofp) == 0)) {
6396 			/* just reopen the file on next access */
6397 			NP(nofp->nof_np, "nfs4_claim_delegated_state_for_open_file: %d, need reopen, %d",
6398 			    reopen, kauth_cred_getuid(nofp->nof_owner->noo_cred));
6399 			lck_mtx_lock(&nofp->nof_lock);
6400 			nofp->nof_flags |= NFS_OPEN_FILE_REOPEN;
6401 			lck_mtx_unlock(&nofp->nof_lock);
6402 			return 0;
6403 		}
6404 		if (reopen) {
6405 			NP(nofp->nof_np, "nfs4_claim_delegated_state_for_open_file: %d, locks prevent reopen, %d",
6406 			    reopen, kauth_cred_getuid(nofp->nof_owner->noo_cred));
6407 		}
6408 	}
6409 
6410 	if (!error && ((nmp = NFSTONMP(nofp->nof_np)))) {
6411 		/* claim delegated locks */
6412 		TAILQ_FOREACH(nlop, &nofp->nof_np->n_lock_owners, nlo_link) {
6413 			if (nlop->nlo_open_owner != noop) {
6414 				continue;
6415 			}
6416 			TAILQ_FOREACH_SAFE(nflp, &nlop->nlo_locks, nfl_lolink, nextnflp) {
6417 				/* skip dead & blocked lock requests (shouldn't be any in the held lock list) */
6418 				if (nflp->nfl_flags & (NFS_FILE_LOCK_DEAD | NFS_FILE_LOCK_BLOCKED)) {
6419 					continue;
6420 				}
6421 				/* skip non-delegated locks */
6422 				if (!(nflp->nfl_flags & NFS_FILE_LOCK_DELEGATED)) {
6423 					continue;
6424 				}
6425 				error = nmp->nm_funcs->nf_setlock_rpc(nofp->nof_np, nofp, nflp, 0, flags, current_thread(), noop->noo_cred);
6426 				if (error) {
6427 					NP(nofp->nof_np, "nfs: delegated lock claim (0x%llx, 0x%llx) failed %d, %d",
6428 					    nflp->nfl_start, nflp->nfl_end, error, kauth_cred_getuid(nofp->nof_owner->noo_cred));
6429 					break;
6430 				}
6431 				// else {
6432 				//      NP(nofp->nof_np, "nfs: delegated lock claim (0x%llx, 0x%llx) succeeded, %d",
6433 				//              nflp->nfl_start, nflp->nfl_end, kauth_cred_getuid(nofp->nof_owner->noo_cred));
6434 				// }
6435 			}
6436 			if (error) {
6437 				break;
6438 			}
6439 		}
6440 	}
6441 
6442 	if (!error) { /* all state claimed successfully! */
6443 		return 0;
6444 	}
6445 
6446 	/* restart if it looks like a problem more than just losing the delegation */
6447 	if (!nfs_mount_state_error_delegation_lost(error) &&
6448 	    ((error == ETIMEDOUT) || nfs_mount_state_error_should_restart(error))) {
6449 		NP(nofp->nof_np, "nfs delegated lock claim error %d, %d", error, kauth_cred_getuid(nofp->nof_owner->noo_cred));
6450 		if ((error == ETIMEDOUT) && ((nmp = NFSTONMP(nofp->nof_np)))) {
6451 			nfs_need_reconnect(nmp);
6452 		}
6453 		return error;
6454 	}
6455 
6456 	/* delegated state lost (once held but now not claimable) */
6457 	NP(nofp->nof_np, "nfs delegated state claim error %d, state lost, %d", error, kauth_cred_getuid(nofp->nof_owner->noo_cred));
6458 
6459 	/*
6460 	 * Any problems with the delegation probably indicates that we
6461 	 * should review/return all of our current delegation state.
6462 	 */
6463 	if ((nmp = NFSTONMP(nofp->nof_np))) {
6464 		nfs4_delegation_return_enqueue(nofp->nof_np);
6465 		lck_mtx_lock(&nmp->nm_lock);
6466 		nfs_need_recover(nmp, NFSERR_EXPIRED);
6467 		lck_mtx_unlock(&nmp->nm_lock);
6468 	}
6469 
6470 	/* revoke all open file state */
6471 	nfs_revoke_open_state_for_node(nofp->nof_np);
6472 
6473 	return error;
6474 }
6475 #endif /* CONFIG_NFS4*/
6476 
6477 /*
6478  * Release all open state for the given node.
6479  */
6480 void
nfs_release_open_state_for_node(nfsnode_t np,int force)6481 nfs_release_open_state_for_node(nfsnode_t np, int force)
6482 {
6483 	struct nfsmount *nmp = NFSTONMP(np);
6484 	struct nfs_open_file *nofp;
6485 	struct nfs_file_lock *nflp, *nextnflp;
6486 
6487 	/* drop held locks */
6488 	TAILQ_FOREACH_SAFE(nflp, &np->n_locks, nfl_link, nextnflp) {
6489 		/* skip dead & blocked lock requests */
6490 		if (nflp->nfl_flags & (NFS_FILE_LOCK_DEAD | NFS_FILE_LOCK_BLOCKED)) {
6491 			continue;
6492 		}
6493 		/* send an unlock if not a delegated lock */
6494 		if (!force && nmp && !(nflp->nfl_flags & NFS_FILE_LOCK_DELEGATED)) {
6495 			nmp->nm_funcs->nf_unlock_rpc(np, nflp->nfl_owner, F_WRLCK, nflp->nfl_start, nflp->nfl_end, R_RECOVER,
6496 			    NULL, nflp->nfl_owner->nlo_open_owner->noo_cred);
6497 		}
6498 		/* kill/remove the lock */
6499 		lck_mtx_lock(&np->n_openlock);
6500 		nflp->nfl_flags |= NFS_FILE_LOCK_DEAD;
6501 		lck_mtx_lock(&nflp->nfl_owner->nlo_lock);
6502 		TAILQ_REMOVE(&nflp->nfl_owner->nlo_locks, nflp, nfl_lolink);
6503 		lck_mtx_unlock(&nflp->nfl_owner->nlo_lock);
6504 		if (nflp->nfl_blockcnt) {
6505 			/* wake up anyone blocked on this lock */
6506 			wakeup(nflp);
6507 		} else {
6508 			/* remove nflp from lock list and destroy */
6509 			TAILQ_REMOVE(&np->n_locks, nflp, nfl_link);
6510 			nfs_file_lock_destroy(np, nflp, NULL, nflp->nfl_owner->nlo_open_owner->noo_cred);
6511 		}
6512 		lck_mtx_unlock(&np->n_openlock);
6513 	}
6514 
6515 	lck_mtx_lock(&np->n_openlock);
6516 
6517 	/* drop all opens */
6518 	TAILQ_FOREACH(nofp, &np->n_opens, nof_link) {
6519 		if (nofp->nof_flags & NFS_OPEN_FILE_LOST) {
6520 			continue;
6521 		}
6522 		/* mark open state as lost */
6523 		lck_mtx_lock(&nofp->nof_lock);
6524 		nofp->nof_flags &= ~NFS_OPEN_FILE_REOPEN;
6525 		nofp->nof_flags |= NFS_OPEN_FILE_LOST;
6526 
6527 		lck_mtx_unlock(&nofp->nof_lock);
6528 #if CONFIG_NFS4
6529 		if (!force && nmp && (nmp->nm_vers >= NFS_VER4)) {
6530 			nfs4_close_rpc(np, nofp, NULL, nofp->nof_owner->noo_cred, R_RECOVER);
6531 		}
6532 #endif
6533 	}
6534 
6535 	lck_mtx_unlock(&np->n_openlock);
6536 }
6537 
6538 /*
6539  * State for a node has been lost, drop it, and revoke the node.
6540  * Attempt to return any state if possible in case the server
6541  * might somehow think we hold it.
6542  */
6543 void
nfs_revoke_open_state_for_node(nfsnode_t np)6544 nfs_revoke_open_state_for_node(nfsnode_t np)
6545 {
6546 	struct nfsmount *nmp;
6547 
6548 	/* mark node as needing to be revoked */
6549 	nfs_node_lock_force(np);
6550 	if (np->n_flag & NREVOKE) { /* already revoked? */
6551 		NP(np, "nfs_revoke_open_state_for_node(): already revoked");
6552 		nfs_node_unlock(np);
6553 		return;
6554 	}
6555 	np->n_flag |= NREVOKE;
6556 	nfs_node_unlock(np);
6557 
6558 	nfs_release_open_state_for_node(np, 0);
6559 	NP(np, "nfs: state lost for %p 0x%x", np, np->n_flag);
6560 
6561 	/* mark mount as needing a revoke scan and have the socket thread do it. */
6562 	if ((nmp = NFSTONMP(np))) {
6563 		lck_mtx_lock(&nmp->nm_lock);
6564 		nmp->nm_state |= NFSSTA_REVOKE;
6565 		nfs_mount_sock_thread_wake(nmp);
6566 		lck_mtx_unlock(&nmp->nm_lock);
6567 	}
6568 }
6569 
6570 #if CONFIG_NFS4
6571 /*
6572  * Claim the delegated open combinations that each of this node's open files hold.
6573  */
6574 int
nfs4_claim_delegated_state_for_node(nfsnode_t np,int flags)6575 nfs4_claim_delegated_state_for_node(nfsnode_t np, int flags)
6576 {
6577 	struct nfs_open_file *nofp;
6578 	int error = 0;
6579 
6580 	lck_mtx_lock(&np->n_openlock);
6581 
6582 	/* walk the open file list looking for opens with delegated state to claim */
6583 restart:
6584 	TAILQ_FOREACH(nofp, &np->n_opens, nof_link) {
6585 		if (!nofp->nof_d_rw_drw && !nofp->nof_d_w_drw && !nofp->nof_d_r_drw &&
6586 		    !nofp->nof_d_rw_dw && !nofp->nof_d_w_dw && !nofp->nof_d_r_dw &&
6587 		    !nofp->nof_d_rw && !nofp->nof_d_w && !nofp->nof_d_r) {
6588 			continue;
6589 		}
6590 		lck_mtx_unlock(&np->n_openlock);
6591 		error = nfs4_claim_delegated_state_for_open_file(nofp, flags);
6592 		lck_mtx_lock(&np->n_openlock);
6593 		if (error) {
6594 			break;
6595 		}
6596 		goto restart;
6597 	}
6598 
6599 	lck_mtx_unlock(&np->n_openlock);
6600 
6601 	return error;
6602 }
6603 
6604 /*
6605  * Mark a node as needed to have its delegation returned.
6606  * Queue it up on the delegation return queue.
6607  * Make sure the thread is running.
6608  */
6609 void
nfs4_delegation_return_enqueue(nfsnode_t np)6610 nfs4_delegation_return_enqueue(nfsnode_t np)
6611 {
6612 	struct nfsmount *nmp;
6613 
6614 	nmp = NFSTONMP(np);
6615 	if (nfs_mount_gone(nmp)) {
6616 		return;
6617 	}
6618 
6619 	lck_mtx_lock(&np->n_openlock);
6620 	np->n_openflags |= N_DELEG_RETURN;
6621 	lck_mtx_unlock(&np->n_openlock);
6622 
6623 	lck_mtx_lock(&nmp->nm_lock);
6624 	if (np->n_dreturn.tqe_next == NFSNOLIST) {
6625 		TAILQ_INSERT_TAIL(&nmp->nm_dreturnq, np, n_dreturn);
6626 	}
6627 	nfs_mount_sock_thread_wake(nmp);
6628 	lck_mtx_unlock(&nmp->nm_lock);
6629 }
6630 
6631 /*
6632  * return any delegation we may have for the given node
6633  */
6634 int
nfs4_delegation_return(nfsnode_t np,int flags,thread_t thd,kauth_cred_t cred)6635 nfs4_delegation_return(nfsnode_t np, int flags, thread_t thd, kauth_cred_t cred)
6636 {
6637 	struct nfsmount *nmp;
6638 	fhandle_t *fh;
6639 	nfs_stateid dstateid;
6640 	int error;
6641 
6642 	nmp = NFSTONMP(np);
6643 	if (nfs_mount_gone(nmp)) {
6644 		return ENXIO;
6645 	}
6646 
6647 	fh = zalloc(nfs_fhandle_zone);
6648 
6649 	/* first, make sure the node's marked for delegation return */
6650 	lck_mtx_lock(&np->n_openlock);
6651 	np->n_openflags |= (N_DELEG_RETURN | N_DELEG_RETURNING);
6652 	lck_mtx_unlock(&np->n_openlock);
6653 
6654 	/* make sure nobody else is using the delegation state */
6655 	if ((error = nfs_open_state_set_busy(np, NULL))) {
6656 		goto out;
6657 	}
6658 
6659 	/* claim any delegated state */
6660 	if ((error = nfs4_claim_delegated_state_for_node(np, flags))) {
6661 		goto out;
6662 	}
6663 
6664 	/* return the delegation */
6665 	lck_mtx_lock(&np->n_openlock);
6666 	dstateid = np->n_dstateid;
6667 	fh->fh_len = np->n_fhsize;
6668 	bcopy(np->n_fhp, fh->fh_data, fh->fh_len);
6669 	lck_mtx_unlock(&np->n_openlock);
6670 	error = nfs4_delegreturn_rpc(NFSTONMP(np), fh->fh_data, fh->fh_len, &dstateid, flags, thd, cred);
6671 	/* assume delegation is gone for all errors except ETIMEDOUT, NFSERR_*MOVED */
6672 	if ((error != ETIMEDOUT) && (error != NFSERR_MOVED) && (error != NFSERR_LEASE_MOVED)) {
6673 		lck_mtx_lock(&np->n_openlock);
6674 		np->n_openflags &= ~N_DELEG_MASK;
6675 		lck_mtx_lock(&nmp->nm_lock);
6676 		if (np->n_dlink.tqe_next != NFSNOLIST) {
6677 			TAILQ_REMOVE(&nmp->nm_delegations, np, n_dlink);
6678 			np->n_dlink.tqe_next = NFSNOLIST;
6679 		}
6680 		lck_mtx_unlock(&nmp->nm_lock);
6681 		lck_mtx_unlock(&np->n_openlock);
6682 	}
6683 
6684 out:
6685 	/* make sure it's no longer on the return queue and clear the return flags */
6686 	lck_mtx_lock(&nmp->nm_lock);
6687 	if (np->n_dreturn.tqe_next != NFSNOLIST) {
6688 		TAILQ_REMOVE(&nmp->nm_dreturnq, np, n_dreturn);
6689 		np->n_dreturn.tqe_next = NFSNOLIST;
6690 	}
6691 	lck_mtx_unlock(&nmp->nm_lock);
6692 	lck_mtx_lock(&np->n_openlock);
6693 	np->n_openflags &= ~(N_DELEG_RETURN | N_DELEG_RETURNING);
6694 	lck_mtx_unlock(&np->n_openlock);
6695 
6696 	if (error) {
6697 		NP(np, "nfs4_delegation_return, error %d", error);
6698 		if (error == ETIMEDOUT) {
6699 			nfs_need_reconnect(nmp);
6700 		}
6701 		if (nfs_mount_state_error_should_restart(error)) {
6702 			/* make sure recovery happens */
6703 			lck_mtx_lock(&nmp->nm_lock);
6704 			nfs_need_recover(nmp, nfs_mount_state_error_delegation_lost(error) ? NFSERR_EXPIRED : 0);
6705 			lck_mtx_unlock(&nmp->nm_lock);
6706 		}
6707 	}
6708 
6709 	nfs_open_state_clear_busy(np);
6710 	NFS_ZFREE(nfs_fhandle_zone, fh);
6711 	return error;
6712 }
6713 
6714 /*
6715  * RPC to return a delegation for a file handle
6716  */
6717 int
nfs4_delegreturn_rpc(struct nfsmount * nmp,u_char * fhp,int fhlen,struct nfs_stateid * sid,int flags,thread_t thd,kauth_cred_t cred)6718 nfs4_delegreturn_rpc(struct nfsmount *nmp, u_char *fhp, int fhlen, struct nfs_stateid *sid, int flags, thread_t thd, kauth_cred_t cred)
6719 {
6720 	int error = 0, status, numops;
6721 	uint64_t xid;
6722 	struct nfsm_chain nmreq, nmrep;
6723 	struct nfsreq_secinfo_args si;
6724 
6725 	NFSREQ_SECINFO_SET(&si, NULL, fhp, fhlen, NULL, 0);
6726 	nfsm_chain_null(&nmreq);
6727 	nfsm_chain_null(&nmrep);
6728 
6729 	// PUTFH, DELEGRETURN
6730 	numops = 2;
6731 	nfsm_chain_build_alloc_init(error, &nmreq, 16 * NFSX_UNSIGNED);
6732 	nfsm_chain_add_compound_header(error, &nmreq, "delegreturn", nmp->nm_minor_vers, numops);
6733 	numops--;
6734 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_PUTFH);
6735 	nfsm_chain_add_fh(error, &nmreq, nmp->nm_vers, fhp, fhlen);
6736 	numops--;
6737 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_DELEGRETURN);
6738 	nfsm_chain_add_stateid(error, &nmreq, sid);
6739 	nfsm_chain_build_done(error, &nmreq);
6740 	nfsm_assert(error, (numops == 0), EPROTO);
6741 	nfsmout_if(error);
6742 	error = nfs_request2(NULL, nmp->nm_mountp, &nmreq, NFSPROC4_COMPOUND, thd, cred, &si, flags, &nmrep, &xid, &status);
6743 	nfsm_chain_skip_tag(error, &nmrep);
6744 	nfsm_chain_get_32(error, &nmrep, numops);
6745 	nfsm_chain_op_check(error, &nmrep, NFS_OP_PUTFH);
6746 	nfsm_chain_op_check(error, &nmrep, NFS_OP_DELEGRETURN);
6747 nfsmout:
6748 	nfsm_chain_cleanup(&nmreq);
6749 	nfsm_chain_cleanup(&nmrep);
6750 	return error;
6751 }
6752 #endif /* CONFIG_NFS4 */
6753 
6754 /*
6755  * NFS read call.
6756  * Just call nfs_bioread() to do the work.
6757  *
6758  * Note: the exec code paths have a tendency to call VNOP_READ (and VNOP_MMAP)
6759  * without first calling VNOP_OPEN, so we make sure the file is open here.
6760  */
6761 int
nfs_vnop_read(struct vnop_read_args * ap)6762 nfs_vnop_read(
6763 	struct vnop_read_args /* {
6764                                *  struct vnodeop_desc *a_desc;
6765                                *  vnode_t a_vp;
6766                                *  struct uio *a_uio;
6767                                *  int a_ioflag;
6768                                *  vfs_context_t a_context;
6769                                *  } */*ap)
6770 {
6771 	vnode_t vp = ap->a_vp;
6772 	vfs_context_t ctx = ap->a_context;
6773 	nfsnode_t np;
6774 	struct nfsmount *nmp;
6775 	struct nfs_open_owner *noop;
6776 	struct nfs_open_file *nofp;
6777 	int error;
6778 
6779 	if (vnode_vtype(ap->a_vp) != VREG) {
6780 		return (vnode_vtype(vp) == VDIR) ? EISDIR : EPERM;
6781 	}
6782 
6783 	np = VTONFS(vp);
6784 	nmp = NFSTONMP(np);
6785 	if (nfs_mount_gone(nmp)) {
6786 		return ENXIO;
6787 	}
6788 	if (np->n_flag & NREVOKE) {
6789 		return EIO;
6790 	}
6791 
6792 	noop = nfs_open_owner_find(nmp, vfs_context_ucred(ctx), vfs_context_proc(ctx), 1);
6793 	if (!noop) {
6794 		return ENOMEM;
6795 	}
6796 restart:
6797 	error = nfs_open_file_find(np, noop, &nofp, 0, 0, 1);
6798 	if (!error && (nofp->nof_flags & NFS_OPEN_FILE_LOST)) {
6799 		NP(np, "nfs_vnop_read: LOST %d", kauth_cred_getuid(noop->noo_cred));
6800 		error = EIO;
6801 	}
6802 #if CONFIG_NFS4
6803 	if (!error && (nofp->nof_flags & NFS_OPEN_FILE_REOPEN)) {
6804 		error = nfs4_reopen(nofp, vfs_context_thread(ctx));
6805 		nofp = NULL;
6806 		if (!error) {
6807 			goto restart;
6808 		}
6809 	}
6810 #endif
6811 	if (error) {
6812 		nfs_open_owner_rele(noop);
6813 		return NFS_MAPERR(error);
6814 	}
6815 	/*
6816 	 * Since the read path is a hot path, if we already have
6817 	 * read access, lets go and try and do the read, without
6818 	 * busying the mount and open file node for this open owner.
6819 	 *
6820 	 * N.B. This is inherently racy w.r.t. an execve using
6821 	 * an already open file, in that the read at the end of
6822 	 * this routine will be racing with a potential close.
6823 	 * The code below ultimately has the same problem. In practice
6824 	 * this does not seem to be an issue.
6825 	 */
6826 	if (nofp->nof_access & NFS_OPEN_SHARE_ACCESS_READ) {
6827 		nfs_open_owner_rele(noop);
6828 		goto do_read;
6829 	}
6830 	error = nfs_mount_state_in_use_start(nmp, vfs_context_thread(ctx));
6831 	if (error) {
6832 		nfs_open_owner_rele(noop);
6833 		return NFS_MAPERR(error);
6834 	}
6835 	/*
6836 	 * If we don't have a file already open with the access we need (read) then
6837 	 * we need to open one. Otherwise we just co-opt an open. We might not already
6838 	 * have access because we're trying to read the first page of the
6839 	 * file for execve.
6840 	 */
6841 	error = nfs_open_file_set_busy(nofp, vfs_context_thread(ctx));
6842 	if (error) {
6843 		nfs_mount_state_in_use_end(nmp, 0);
6844 		nfs_open_owner_rele(noop);
6845 		return NFS_MAPERR(error);
6846 	}
6847 	if (!(nofp->nof_access & NFS_OPEN_SHARE_ACCESS_READ)) {
6848 		/* we don't have the file open, so open it for read access if we're not denied */
6849 		if (nofp->nof_flags & NFS_OPEN_FILE_NEEDCLOSE) {
6850 			NP(np, "nfs_vnop_read: File already needs close access: 0x%x, cred: %d thread: %lld",
6851 			    nofp->nof_access, kauth_cred_getuid(nofp->nof_owner->noo_cred), thread_tid(vfs_context_thread(ctx)));
6852 		}
6853 		if (nofp->nof_deny & NFS_OPEN_SHARE_DENY_READ) {
6854 			nfs_open_file_clear_busy(nofp);
6855 			nfs_mount_state_in_use_end(nmp, 0);
6856 			nfs_open_owner_rele(noop);
6857 			return EPERM;
6858 		}
6859 		if (np->n_flag & NREVOKE) {
6860 			error = EIO;
6861 			nfs_open_file_clear_busy(nofp);
6862 			nfs_mount_state_in_use_end(nmp, 0);
6863 			nfs_open_owner_rele(noop);
6864 			return NFS_MAPERR(error);
6865 		}
6866 		if (nmp->nm_vers < NFS_VER4) {
6867 			/* NFS v2/v3 opens are always allowed - so just add it. */
6868 			nfs_open_file_add_open(nofp, NFS_OPEN_SHARE_ACCESS_READ, NFS_OPEN_SHARE_DENY_NONE, 0);
6869 		}
6870 #if CONFIG_NFS4
6871 		else {
6872 			error = nfs4_open(np, nofp, NFS_OPEN_SHARE_ACCESS_READ, NFS_OPEN_SHARE_DENY_NONE, ctx);
6873 		}
6874 #endif
6875 		if (!error) {
6876 			nofp->nof_flags |= NFS_OPEN_FILE_NEEDCLOSE;
6877 		}
6878 	}
6879 	if (nofp) {
6880 		nfs_open_file_clear_busy(nofp);
6881 	}
6882 	if (nfs_mount_state_in_use_end(nmp, error)) {
6883 		nofp = NULL;
6884 		goto restart;
6885 	}
6886 	nfs_open_owner_rele(noop);
6887 	if (error) {
6888 		return NFS_MAPERR(error);
6889 	}
6890 do_read:
6891 	error = nfs_bioread(VTONFS(ap->a_vp), ap->a_uio, ap->a_ioflag, ap->a_context);
6892 	return NFS_MAPERR(error);
6893 }
6894 
6895 #if CONFIG_NFS4
6896 /*
6897  * Note: the NFSv4 CREATE RPC is for everything EXCEPT regular files.
6898  * Files are created using the NFSv4 OPEN RPC.  So we must open the
6899  * file to create it and then close it.
6900  */
6901 int
nfs4_vnop_create(struct vnop_create_args * ap)6902 nfs4_vnop_create(
6903 	struct vnop_create_args /* {
6904                                  *  struct vnodeop_desc *a_desc;
6905                                  *  vnode_t a_dvp;
6906                                  *  vnode_t *a_vpp;
6907                                  *  struct componentname *a_cnp;
6908                                  *  struct vnode_attr *a_vap;
6909                                  *  vfs_context_t a_context;
6910                                  *  } */*ap)
6911 {
6912 	vfs_context_t ctx = ap->a_context;
6913 	struct componentname *cnp = ap->a_cnp;
6914 	struct vnode_attr *vap = ap->a_vap;
6915 	vnode_t dvp = ap->a_dvp;
6916 	vnode_t *vpp = ap->a_vpp;
6917 	struct nfsmount *nmp;
6918 	nfsnode_t np;
6919 	int error = 0, busyerror = 0, accessMode, denyMode;
6920 	struct nfs_open_owner *noop = NULL;
6921 	struct nfs_open_file *newnofp = NULL, *nofp = NULL;
6922 
6923 	nmp = VTONMP(dvp);
6924 	if (nfs_mount_gone(nmp)) {
6925 		return ENXIO;
6926 	}
6927 
6928 	if (vap) {
6929 		nfs_avoid_needless_id_setting_on_create(VTONFS(dvp), vap, ctx);
6930 	}
6931 
6932 	noop = nfs_open_owner_find(nmp, vfs_context_ucred(ctx), vfs_context_proc(ctx), 1);
6933 	if (!noop) {
6934 		return ENOMEM;
6935 	}
6936 
6937 restart:
6938 	error = nfs_mount_state_in_use_start(nmp, vfs_context_thread(ctx));
6939 	if (error) {
6940 		nfs_open_owner_rele(noop);
6941 		return NFS_MAPERR(error);
6942 	}
6943 
6944 	/* grab a provisional, nodeless open file */
6945 	error = nfs_open_file_find(NULL, noop, &newnofp, 0, 0, 1);
6946 	if (!error && (newnofp->nof_flags & NFS_OPEN_FILE_LOST)) {
6947 		printf("nfs_vnop_create: LOST\n");
6948 		error = EIO;
6949 	}
6950 	if (!error && (newnofp->nof_flags & NFS_OPEN_FILE_REOPEN)) {
6951 		/* This shouldn't happen given that this is a new, nodeless nofp */
6952 		error = nfs4_reopen(newnofp, vfs_context_thread(ctx));
6953 		nfs_open_file_destroy(newnofp);
6954 		newnofp = NULL;
6955 		if (!error) {
6956 			nfs_mount_state_in_use_end(nmp, 0);
6957 			goto restart;
6958 		}
6959 	}
6960 	if (!error) {
6961 		error = nfs_open_file_set_busy(newnofp, vfs_context_thread(ctx));
6962 	}
6963 	if (error) {
6964 		if (newnofp) {
6965 			nfs_open_file_destroy(newnofp);
6966 		}
6967 		newnofp = NULL;
6968 		goto out;
6969 	}
6970 
6971 	/*
6972 	 * We're just trying to create the file.
6973 	 * We'll create/open it RW, and set NFS_OPEN_FILE_CREATE.
6974 	 */
6975 	accessMode = NFS_OPEN_SHARE_ACCESS_BOTH;
6976 	denyMode = NFS_OPEN_SHARE_DENY_NONE;
6977 
6978 	/* Do the open/create */
6979 	error = nfs4_open_rpc(newnofp, ctx, cnp, vap, dvp, vpp, NFS_OPEN_CREATE, accessMode, denyMode);
6980 	if ((error == EACCES) && vap && !(vap->va_vaflags & VA_EXCLUSIVE) &&
6981 	    VATTR_IS_ACTIVE(vap, va_mode) && !(vap->va_mode & S_IWUSR)) {
6982 		/*
6983 		 * Hmm... it looks like we may have a situation where the request was
6984 		 * retransmitted because we didn't get the first response which successfully
6985 		 * created/opened the file and then the second time we were denied the open
6986 		 * because the mode the file was created with doesn't allow write access.
6987 		 *
6988 		 * We'll try to work around this by temporarily updating the mode and
6989 		 * retrying the open.
6990 		 */
6991 		struct vnode_attr vattr;
6992 
6993 		/* first make sure it's there */
6994 		int error2 = nfs_lookitup(VTONFS(dvp), cnp->cn_nameptr, cnp->cn_namelen, ctx, &np);
6995 		if (!error2 && np) {
6996 			nfs_node_unlock(np);
6997 			*vpp = NFSTOV(np);
6998 			if (vnode_vtype(NFSTOV(np)) == VREG) {
6999 				VATTR_INIT(&vattr);
7000 				VATTR_SET(&vattr, va_mode, (vap->va_mode | S_IWUSR));
7001 				if (!nfs4_setattr_rpc(np, &vattr, ctx)) {
7002 					error2 = nfs4_open_rpc(newnofp, ctx, cnp, NULL, dvp, vpp, NFS_OPEN_NOCREATE, accessMode, denyMode);
7003 					VATTR_INIT(&vattr);
7004 					VATTR_SET(&vattr, va_mode, vap->va_mode);
7005 					nfs4_setattr_rpc(np, &vattr, ctx);
7006 					if (!error2) {
7007 						error = 0;
7008 					}
7009 				}
7010 			}
7011 			if (error) {
7012 				vnode_put(*vpp);
7013 				*vpp = NULL;
7014 			}
7015 		}
7016 	}
7017 	if (!error && !*vpp) {
7018 		printf("nfs4_open_rpc returned without a node?\n");
7019 		/* Hmmm... with no node, we have no filehandle and can't close it */
7020 		error = EIO;
7021 	}
7022 	if (error) {
7023 		/* need to cleanup our temporary nofp */
7024 		nfs_open_file_clear_busy(newnofp);
7025 		nfs_open_file_destroy(newnofp);
7026 		newnofp = NULL;
7027 		goto out;
7028 	}
7029 	/* After we have a node, add our open file struct to the node */
7030 	np = VTONFS(*vpp);
7031 	nfs_open_file_add_open(newnofp, accessMode, denyMode, 0);
7032 	nofp = newnofp;
7033 	error = nfs_open_file_find_internal(np, noop, &nofp, 0, 0, 0);
7034 	if (error) {
7035 		/* This shouldn't happen, because we passed in a new nofp to use. */
7036 		printf("nfs_open_file_find_internal failed! %d\n", error);
7037 		goto out;
7038 	} else if (nofp != newnofp) {
7039 		/*
7040 		 * Hmm... an open file struct already exists.
7041 		 * Mark the existing one busy and merge our open into it.
7042 		 * Then destroy the one we created.
7043 		 * Note: there's no chance of an open confict because the
7044 		 * open has already been granted.
7045 		 */
7046 		busyerror = nfs_open_file_set_busy(nofp, NULL);
7047 		nfs_open_file_add_open(nofp, accessMode, denyMode, 0);
7048 		nofp->nof_stateid = newnofp->nof_stateid;
7049 		if (newnofp->nof_flags & NFS_OPEN_FILE_POSIXLOCK) {
7050 			nofp->nof_flags |= NFS_OPEN_FILE_POSIXLOCK;
7051 		}
7052 		nfs_open_file_clear_busy(newnofp);
7053 		nfs_open_file_destroy(newnofp);
7054 	}
7055 	newnofp = NULL;
7056 	/* mark the node as holding a create-initiated open */
7057 	nofp->nof_flags |= NFS_OPEN_FILE_CREATE;
7058 	nofp->nof_creator = current_thread();
7059 out:
7060 	if (nofp && !busyerror) {
7061 		nfs_open_file_clear_busy(nofp);
7062 	}
7063 	if (nfs_mount_state_in_use_end(nmp, error)) {
7064 		nofp = newnofp = NULL;
7065 		busyerror = 0;
7066 		goto restart;
7067 	}
7068 	if (noop) {
7069 		nfs_open_owner_rele(noop);
7070 	}
7071 	return NFS_MAPERR(error);
7072 }
7073 
7074 /*
7075  * Note: the NFSv4 CREATE RPC is for everything EXCEPT regular files.
7076  */
7077 int
nfs4_create_rpc(vfs_context_t ctx,nfsnode_t dnp,struct componentname * cnp,struct vnode_attr * vap,int type,char * link,nfsnode_t * npp)7078 nfs4_create_rpc(
7079 	vfs_context_t ctx,
7080 	nfsnode_t dnp,
7081 	struct componentname *cnp,
7082 	struct vnode_attr *vap,
7083 	int type,
7084 	char *link,
7085 	nfsnode_t *npp)
7086 {
7087 	struct nfsmount *nmp;
7088 	struct nfs_vattr *nvattr;
7089 	int error = 0, create_error = EIO, lockerror = ENOENT, busyerror = ENOENT, status;
7090 	int nfsvers, namedattrs, numops;
7091 	u_int64_t xid = 0, savedxid = 0;
7092 	nfsnode_t np = NULL;
7093 	vnode_t newvp = NULL;
7094 	struct nfsm_chain nmreq, nmrep;
7095 	uint32_t bitmap[NFS_ATTR_BITMAP_LEN], bmlen;
7096 	const char *tag;
7097 	nfs_specdata sd;
7098 	fhandle_t *fh;
7099 	struct nfsreq *req;
7100 	struct nfs_dulookup *dul;
7101 	struct nfsreq_secinfo_args si;
7102 
7103 	nmp = NFSTONMP(dnp);
7104 	if (nfs_mount_gone(nmp)) {
7105 		return ENXIO;
7106 	}
7107 	nfsvers = nmp->nm_vers;
7108 	namedattrs = (nmp->nm_fsattr.nfsa_flags & NFS_FSFLAG_NAMED_ATTR);
7109 	if (dnp->n_vattr.nva_flags & NFS_FFLAG_TRIGGER_REFERRAL) {
7110 		return EINVAL;
7111 	}
7112 
7113 	sd.specdata1 = sd.specdata2 = 0;
7114 
7115 	switch (type) {
7116 	case NFLNK:
7117 		tag = "symlink";
7118 		break;
7119 	case NFBLK:
7120 	case NFCHR:
7121 		tag = "mknod";
7122 		if (!VATTR_IS_ACTIVE(vap, va_rdev)) {
7123 			return EINVAL;
7124 		}
7125 		sd.specdata1 = major(vap->va_rdev);
7126 		sd.specdata2 = minor(vap->va_rdev);
7127 		break;
7128 	case NFSOCK:
7129 	case NFFIFO:
7130 		tag = "mknod";
7131 		break;
7132 	case NFDIR:
7133 		tag = "mkdir";
7134 		break;
7135 	default:
7136 		return EINVAL;
7137 	}
7138 
7139 	fh = zalloc(nfs_fhandle_zone);
7140 	req = zalloc(nfs_req_zone);
7141 	dul = kalloc_type(struct nfs_dulookup, Z_WAITOK);
7142 	nvattr = zalloc_flags(KT_NFS_VATTR, Z_WAITOK);
7143 	nfs_avoid_needless_id_setting_on_create(dnp, vap, ctx);
7144 
7145 	error = busyerror = nfs_node_set_busy(dnp, vfs_context_thread(ctx));
7146 	if (!namedattrs) {
7147 		nfs_dulookup_init(dul, dnp, cnp->cn_nameptr, cnp->cn_namelen, ctx);
7148 	}
7149 
7150 	NFSREQ_SECINFO_SET(&si, dnp, NULL, 0, NULL, 0);
7151 	NVATTR_INIT(nvattr);
7152 	nfsm_chain_null(&nmreq);
7153 	nfsm_chain_null(&nmrep);
7154 
7155 	// PUTFH, SAVEFH, CREATE, GETATTR(FH), RESTOREFH, GETATTR
7156 	numops = 6;
7157 	nfsm_chain_build_alloc_init(error, &nmreq, 66 * NFSX_UNSIGNED);
7158 	nfsm_chain_add_compound_header(error, &nmreq, tag, nmp->nm_minor_vers, numops);
7159 	numops--;
7160 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_PUTFH);
7161 	nfsm_chain_add_fh(error, &nmreq, nfsvers, dnp->n_fhp, dnp->n_fhsize);
7162 	numops--;
7163 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_SAVEFH);
7164 	numops--;
7165 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_CREATE);
7166 	nfsm_chain_add_32(error, &nmreq, type);
7167 	if (type == NFLNK) {
7168 		nfsm_chain_add_name(error, &nmreq, link, strlen(link), nmp);
7169 	} else if ((type == NFBLK) || (type == NFCHR)) {
7170 		nfsm_chain_add_32(error, &nmreq, sd.specdata1);
7171 		nfsm_chain_add_32(error, &nmreq, sd.specdata2);
7172 	}
7173 	nfsm_chain_add_name(error, &nmreq, cnp->cn_nameptr, cnp->cn_namelen, nmp);
7174 	nfsm_chain_add_fattr4(error, &nmreq, vap, nmp);
7175 	numops--;
7176 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_GETATTR);
7177 	NFS_COPY_ATTRIBUTES(nfs_getattr_bitmap, bitmap);
7178 	NFS_BITMAP_SET(bitmap, NFS_FATTR_FILEHANDLE);
7179 	nfsm_chain_add_bitmap_supported(error, &nmreq, bitmap, nmp, NULL);
7180 	numops--;
7181 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_RESTOREFH);
7182 	numops--;
7183 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_GETATTR);
7184 	nfsm_chain_add_bitmap_supported(error, &nmreq, nfs_getattr_bitmap, nmp, dnp);
7185 	nfsm_chain_build_done(error, &nmreq);
7186 	nfsm_assert(error, (numops == 0), EPROTO);
7187 	nfsmout_if(error);
7188 
7189 	error = nfs_request_async(dnp, NULL, &nmreq, NFSPROC4_COMPOUND,
7190 	    vfs_context_thread(ctx), vfs_context_ucred(ctx), &si, 0, NULL, &req);
7191 	if (!error) {
7192 		if (!namedattrs) {
7193 			nfs_dulookup_start(dul, dnp, ctx);
7194 		}
7195 		error = nfs_request_async_finish(req, &nmrep, &xid, &status);
7196 	}
7197 
7198 	if ((lockerror = nfs_node_lock(dnp))) {
7199 		error = lockerror;
7200 	}
7201 	nfsm_chain_skip_tag(error, &nmrep);
7202 	nfsm_chain_get_32(error, &nmrep, numops);
7203 	nfsm_chain_op_check(error, &nmrep, NFS_OP_PUTFH);
7204 	nfsm_chain_op_check(error, &nmrep, NFS_OP_SAVEFH);
7205 	nfsmout_if(error);
7206 	nfsm_chain_op_check(error, &nmrep, NFS_OP_CREATE);
7207 	nfsm_chain_check_change_info(error, &nmrep, dnp);
7208 	bmlen = NFS_ATTR_BITMAP_LEN;
7209 	nfsm_chain_get_bitmap(error, &nmrep, bitmap, bmlen);
7210 	/* At this point if we have no error, the object was created. */
7211 	/* if we don't get attributes, then we should lookitup. */
7212 	create_error = error;
7213 	nfsmout_if(error);
7214 	nfs_vattr_set_supported(bitmap, vap);
7215 	nfsm_chain_op_check(error, &nmrep, NFS_OP_GETATTR);
7216 	nfsmout_if(error);
7217 	error = nfs4_parsefattr(&nmrep, NULL, nvattr, fh, NULL, NULL);
7218 	nfsmout_if(error);
7219 	if (!NFS_BITMAP_ISSET(nvattr->nva_bitmap, NFS_FATTR_FILEHANDLE)) {
7220 		printf("nfs: create/%s didn't return filehandle? %s\n", tag, cnp->cn_nameptr);
7221 		error = EBADRPC;
7222 		goto nfsmout;
7223 	}
7224 	/* directory attributes: if we don't get them, make sure to invalidate */
7225 	nfsm_chain_op_check(error, &nmrep, NFS_OP_RESTOREFH);
7226 	nfsm_chain_op_check(error, &nmrep, NFS_OP_GETATTR);
7227 	savedxid = xid;
7228 	nfsm_chain_loadattr(error, &nmrep, dnp, nfsvers, &xid);
7229 	if (error) {
7230 		NATTRINVALIDATE(dnp);
7231 	}
7232 
7233 nfsmout:
7234 	nfsm_chain_cleanup(&nmreq);
7235 	nfsm_chain_cleanup(&nmrep);
7236 
7237 	if (!lockerror) {
7238 		if (!create_error && (dnp->n_flag & NNEGNCENTRIES)) {
7239 			dnp->n_flag &= ~NNEGNCENTRIES;
7240 			cache_purge_negatives(NFSTOV(dnp));
7241 		}
7242 		dnp->n_flag |= NMODIFIED;
7243 		nfs_node_unlock(dnp);
7244 		/* nfs_getattr() will check changed and purge caches */
7245 		nfs_getattr(dnp, NULL, ctx, NGA_CACHED);
7246 	}
7247 
7248 	if (!error && fh->fh_len) {
7249 		/* create the vnode with the filehandle and attributes */
7250 		xid = savedxid;
7251 		error = nfs_nget(NFSTOMP(dnp), dnp, cnp, fh->fh_data, fh->fh_len, nvattr, &xid, req->r_auth, NG_MAKEENTRY, &np);
7252 		if (!error) {
7253 			newvp = NFSTOV(np);
7254 		}
7255 	}
7256 
7257 	if (!namedattrs) {
7258 		nfs_dulookup_finish(dul, dnp, ctx);
7259 	}
7260 
7261 	NVATTR_CLEANUP(nvattr);
7262 	NFS_ZFREE(nfs_fhandle_zone, fh);
7263 	NFS_ZFREE(nfs_req_zone, req);
7264 	kfree_type(struct nfs_dulookup, dul);
7265 	zfree(KT_NFS_VATTR, nvattr);
7266 
7267 	/*
7268 	 * Kludge: Map EEXIST => 0 assuming that you have a reply to a retry
7269 	 * if we can succeed in looking up the object.
7270 	 */
7271 	if ((create_error == EEXIST) || (!create_error && !newvp)) {
7272 		error = nfs_lookitup(dnp, cnp->cn_nameptr, cnp->cn_namelen, ctx, &np);
7273 		if (!error) {
7274 			newvp = NFSTOV(np);
7275 			if (vnode_vtype(newvp) != nfstov_type(type, nfsvers)) {
7276 				error = EEXIST;
7277 			}
7278 		}
7279 	}
7280 	if (!busyerror) {
7281 		nfs_node_clear_busy(dnp);
7282 	}
7283 	if (error) {
7284 		if (newvp) {
7285 			nfs_node_unlock(np);
7286 			vnode_put(newvp);
7287 		}
7288 	} else {
7289 		nfs_node_unlock(np);
7290 		*npp = np;
7291 	}
7292 	return error;
7293 }
7294 
7295 int
nfs4_vnop_mknod(struct vnop_mknod_args * ap)7296 nfs4_vnop_mknod(
7297 	struct vnop_mknod_args /* {
7298                                 *  struct vnodeop_desc *a_desc;
7299                                 *  vnode_t a_dvp;
7300                                 *  vnode_t *a_vpp;
7301                                 *  struct componentname *a_cnp;
7302                                 *  struct vnode_attr *a_vap;
7303                                 *  vfs_context_t a_context;
7304                                 *  } */*ap)
7305 {
7306 	nfsnode_t np = NULL;
7307 	struct nfsmount *nmp;
7308 	int error;
7309 
7310 	nmp = VTONMP(ap->a_dvp);
7311 	if (nfs_mount_gone(nmp)) {
7312 		return ENXIO;
7313 	}
7314 
7315 	if (!VATTR_IS_ACTIVE(ap->a_vap, va_type)) {
7316 		return EINVAL;
7317 	}
7318 	switch (ap->a_vap->va_type) {
7319 	case VBLK:
7320 	case VCHR:
7321 	case VFIFO:
7322 	case VSOCK:
7323 		break;
7324 	default:
7325 		return ENOTSUP;
7326 	}
7327 
7328 	error = nfs4_create_rpc(ap->a_context, VTONFS(ap->a_dvp), ap->a_cnp, ap->a_vap,
7329 	    vtonfs_type(ap->a_vap->va_type, nmp->nm_vers), NULL, &np);
7330 	if (!error) {
7331 		*ap->a_vpp = NFSTOV(np);
7332 	}
7333 	return NFS_MAPERR(error);
7334 }
7335 
7336 int
nfs4_vnop_mkdir(struct vnop_mkdir_args * ap)7337 nfs4_vnop_mkdir(
7338 	struct vnop_mkdir_args /* {
7339                                 *  struct vnodeop_desc *a_desc;
7340                                 *  vnode_t a_dvp;
7341                                 *  vnode_t *a_vpp;
7342                                 *  struct componentname *a_cnp;
7343                                 *  struct vnode_attr *a_vap;
7344                                 *  vfs_context_t a_context;
7345                                 *  } */*ap)
7346 {
7347 	nfsnode_t np = NULL;
7348 	int error;
7349 
7350 	error = nfs4_create_rpc(ap->a_context, VTONFS(ap->a_dvp), ap->a_cnp, ap->a_vap,
7351 	    NFDIR, NULL, &np);
7352 	if (!error) {
7353 		*ap->a_vpp = NFSTOV(np);
7354 	}
7355 	return NFS_MAPERR(error);
7356 }
7357 
7358 int
nfs4_vnop_symlink(struct vnop_symlink_args * ap)7359 nfs4_vnop_symlink(
7360 	struct vnop_symlink_args /* {
7361                                   *  struct vnodeop_desc *a_desc;
7362                                   *  vnode_t a_dvp;
7363                                   *  vnode_t *a_vpp;
7364                                   *  struct componentname *a_cnp;
7365                                   *  struct vnode_attr *a_vap;
7366                                   *  char *a_target;
7367                                   *  vfs_context_t a_context;
7368                                   *  } */*ap)
7369 {
7370 	nfsnode_t np = NULL;
7371 	int error;
7372 
7373 	error = nfs4_create_rpc(ap->a_context, VTONFS(ap->a_dvp), ap->a_cnp, ap->a_vap,
7374 	    NFLNK, ap->a_target, &np);
7375 	if (!error) {
7376 		*ap->a_vpp = NFSTOV(np);
7377 	}
7378 	return NFS_MAPERR(error);
7379 }
7380 
7381 int
nfs4_vnop_link(struct vnop_link_args * ap)7382 nfs4_vnop_link(
7383 	struct vnop_link_args /* {
7384                                *  struct vnodeop_desc *a_desc;
7385                                *  vnode_t a_vp;
7386                                *  vnode_t a_tdvp;
7387                                *  struct componentname *a_cnp;
7388                                *  vfs_context_t a_context;
7389                                *  } */*ap)
7390 {
7391 	vfs_context_t ctx = ap->a_context;
7392 	vnode_t vp = ap->a_vp;
7393 	vnode_t tdvp = ap->a_tdvp;
7394 	struct componentname *cnp = ap->a_cnp;
7395 	int error = 0, lockerror = ENOENT, status;
7396 	struct nfsmount *nmp;
7397 	nfsnode_t np = VTONFS(vp);
7398 	nfsnode_t tdnp = VTONFS(tdvp);
7399 	int nfsvers, numops;
7400 	u_int64_t xid, savedxid;
7401 	struct nfsm_chain nmreq, nmrep;
7402 	struct nfsreq_secinfo_args si;
7403 
7404 	if (vnode_mount(vp) != vnode_mount(tdvp)) {
7405 		return EXDEV;
7406 	}
7407 
7408 	nmp = VTONMP(vp);
7409 	if (nfs_mount_gone(nmp)) {
7410 		return ENXIO;
7411 	}
7412 	nfsvers = nmp->nm_vers;
7413 	if (np->n_vattr.nva_flags & NFS_FFLAG_TRIGGER_REFERRAL) {
7414 		return EINVAL;
7415 	}
7416 	if (tdnp->n_vattr.nva_flags & NFS_FFLAG_TRIGGER_REFERRAL) {
7417 		return EINVAL;
7418 	}
7419 
7420 	/*
7421 	 * Push all writes to the server, so that the attribute cache
7422 	 * doesn't get "out of sync" with the server.
7423 	 * XXX There should be a better way!
7424 	 */
7425 	nfs_flush(np, MNT_WAIT, vfs_context_thread(ctx), V_IGNORE_WRITEERR);
7426 
7427 	if ((error = nfs_node_set_busy2(tdnp, np, vfs_context_thread(ctx)))) {
7428 		return NFS_MAPERR(error);
7429 	}
7430 
7431 	NFSREQ_SECINFO_SET(&si, np, NULL, 0, NULL, 0);
7432 	nfsm_chain_null(&nmreq);
7433 	nfsm_chain_null(&nmrep);
7434 
7435 	// PUTFH(SOURCE), SAVEFH, PUTFH(DIR), LINK, GETATTR(DIR), RESTOREFH, GETATTR
7436 	numops = 7;
7437 	nfsm_chain_build_alloc_init(error, &nmreq, 29 * NFSX_UNSIGNED + cnp->cn_namelen);
7438 	nfsm_chain_add_compound_header(error, &nmreq, "link", nmp->nm_minor_vers, numops);
7439 	numops--;
7440 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_PUTFH);
7441 	nfsm_chain_add_fh(error, &nmreq, nfsvers, np->n_fhp, np->n_fhsize);
7442 	numops--;
7443 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_SAVEFH);
7444 	numops--;
7445 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_PUTFH);
7446 	nfsm_chain_add_fh(error, &nmreq, nfsvers, tdnp->n_fhp, tdnp->n_fhsize);
7447 	numops--;
7448 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_LINK);
7449 	nfsm_chain_add_name(error, &nmreq, cnp->cn_nameptr, cnp->cn_namelen, nmp);
7450 	numops--;
7451 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_GETATTR);
7452 	nfsm_chain_add_bitmap_supported(error, &nmreq, nfs_getattr_bitmap, nmp, tdnp);
7453 	numops--;
7454 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_RESTOREFH);
7455 	numops--;
7456 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_GETATTR);
7457 	nfsm_chain_add_bitmap_supported(error, &nmreq, nfs_getattr_bitmap, nmp, np);
7458 	nfsm_chain_build_done(error, &nmreq);
7459 	nfsm_assert(error, (numops == 0), EPROTO);
7460 	nfsmout_if(error);
7461 	error = nfs_request(tdnp, NULL, &nmreq, NFSPROC4_COMPOUND, ctx, &si, &nmrep, &xid, &status);
7462 
7463 	if ((lockerror = nfs_node_lock2(tdnp, np))) {
7464 		error = lockerror;
7465 		goto nfsmout;
7466 	}
7467 	nfsm_chain_skip_tag(error, &nmrep);
7468 	nfsm_chain_get_32(error, &nmrep, numops);
7469 	nfsm_chain_op_check(error, &nmrep, NFS_OP_PUTFH);
7470 	nfsm_chain_op_check(error, &nmrep, NFS_OP_SAVEFH);
7471 	nfsm_chain_op_check(error, &nmrep, NFS_OP_PUTFH);
7472 	nfsm_chain_op_check(error, &nmrep, NFS_OP_LINK);
7473 	nfsm_chain_check_change_info(error, &nmrep, tdnp);
7474 	/* directory attributes: if we don't get them, make sure to invalidate */
7475 	nfsm_chain_op_check(error, &nmrep, NFS_OP_GETATTR);
7476 	savedxid = xid;
7477 	nfsm_chain_loadattr(error, &nmrep, tdnp, nfsvers, &xid);
7478 	if (error) {
7479 		NATTRINVALIDATE(tdnp);
7480 	}
7481 	/* link attributes: if we don't get them, make sure to invalidate */
7482 	nfsm_chain_op_check(error, &nmrep, NFS_OP_RESTOREFH);
7483 	nfsm_chain_op_check(error, &nmrep, NFS_OP_GETATTR);
7484 	xid = savedxid;
7485 	nfsm_chain_loadattr(error, &nmrep, np, nfsvers, &xid);
7486 	if (error) {
7487 		NATTRINVALIDATE(np);
7488 	}
7489 nfsmout:
7490 	nfsm_chain_cleanup(&nmreq);
7491 	nfsm_chain_cleanup(&nmrep);
7492 	if (!lockerror) {
7493 		tdnp->n_flag |= NMODIFIED;
7494 	}
7495 	/* Kludge: Map EEXIST => 0 assuming that it is a reply to a retry. */
7496 	if (error == EEXIST) {
7497 		error = 0;
7498 	}
7499 	if (!error && (tdnp->n_flag & NNEGNCENTRIES)) {
7500 		tdnp->n_flag &= ~NNEGNCENTRIES;
7501 		cache_purge_negatives(tdvp);
7502 	}
7503 	if (!lockerror) {
7504 		nfs_node_unlock2(tdnp, np);
7505 	}
7506 	nfs_node_clear_busy2(tdnp, np);
7507 	return NFS_MAPERR(error);
7508 }
7509 
7510 int
nfs4_vnop_rmdir(struct vnop_rmdir_args * ap)7511 nfs4_vnop_rmdir(
7512 	struct vnop_rmdir_args /* {
7513                                 *  struct vnodeop_desc *a_desc;
7514                                 *  vnode_t a_dvp;
7515                                 *  vnode_t a_vp;
7516                                 *  struct componentname *a_cnp;
7517                                 *  vfs_context_t a_context;
7518                                 *  } */*ap)
7519 {
7520 	vfs_context_t ctx = ap->a_context;
7521 	vnode_t vp = ap->a_vp;
7522 	vnode_t dvp = ap->a_dvp;
7523 	struct componentname *cnp = ap->a_cnp;
7524 	struct nfsmount *nmp;
7525 	int error = 0, namedattrs;
7526 	nfsnode_t np = VTONFS(vp);
7527 	nfsnode_t dnp = VTONFS(dvp);
7528 	struct nfs_dulookup *dul;
7529 
7530 	if (vnode_vtype(vp) != VDIR) {
7531 		return EINVAL;
7532 	}
7533 
7534 	nmp = NFSTONMP(dnp);
7535 	if (nfs_mount_gone(nmp)) {
7536 		return ENXIO;
7537 	}
7538 	namedattrs = (nmp->nm_fsattr.nfsa_flags & NFS_FSFLAG_NAMED_ATTR);
7539 
7540 	if ((error = nfs_node_set_busy2(dnp, np, vfs_context_thread(ctx)))) {
7541 		return NFS_MAPERR(error);
7542 	}
7543 
7544 	dul = kalloc_type(struct nfs_dulookup, Z_WAITOK);
7545 	if (!namedattrs) {
7546 		nfs_dulookup_init(dul, dnp, cnp->cn_nameptr, cnp->cn_namelen, ctx);
7547 		nfs_dulookup_start(dul, dnp, ctx);
7548 	}
7549 
7550 	error = nfs4_remove_rpc(dnp, cnp->cn_nameptr, cnp->cn_namelen,
7551 	    vfs_context_thread(ctx), vfs_context_ucred(ctx));
7552 
7553 	nfs_name_cache_purge(dnp, np, cnp, ctx);
7554 	/* nfs_getattr() will check changed and purge caches */
7555 	nfs_getattr(dnp, NULL, ctx, NGA_CACHED);
7556 	if (!namedattrs) {
7557 		nfs_dulookup_finish(dul, dnp, ctx);
7558 	}
7559 	nfs_node_clear_busy2(dnp, np);
7560 
7561 	/*
7562 	 * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry.
7563 	 */
7564 	if (error == ENOENT) {
7565 		error = 0;
7566 	}
7567 	if (!error) {
7568 		/*
7569 		 * remove nfsnode from hash now so we can't accidentally find it
7570 		 * again if another object gets created with the same filehandle
7571 		 * before this vnode gets reclaimed
7572 		 */
7573 		lck_mtx_lock(&nfs_node_hash_mutex);
7574 		if (np->n_hflag & NHHASHED) {
7575 			LIST_REMOVE(np, n_hash);
7576 			np->n_hflag &= ~NHHASHED;
7577 			FSDBG(266, 0, np, np->n_flag, 0xb1eb1e);
7578 		}
7579 		lck_mtx_unlock(&nfs_node_hash_mutex);
7580 	}
7581 	kfree_type(struct nfs_dulookup, dul);
7582 	return NFS_MAPERR(error);
7583 }
7584 
7585 /*
7586  * NFSv4 Named Attributes
7587  *
7588  * Both the extended attributes interface and the named streams interface
7589  * are backed by NFSv4 named attributes.  The implementations for both use
7590  * a common set of routines in an attempt to reduce code duplication, to
7591  * increase efficiency, to increase caching of both names and data, and to
7592  * confine the complexity.
7593  *
7594  * Each NFS node caches its named attribute directory's file handle.
7595  * The directory nodes for the named attribute directories are handled
7596  * exactly like regular directories (with a couple minor exceptions).
7597  * Named attribute nodes are also treated as much like regular files as
7598  * possible.
7599  *
7600  * Most of the heavy lifting is done by nfs4_named_attr_get().
7601  */
7602 
7603 /*
7604  * Get the given node's attribute directory node.
7605  * If !fetch, then only return a cached node.
7606  * Otherwise, we will attempt to fetch the node from the server.
7607  * (Note: the node should be marked busy.)
7608  */
7609 nfsnode_t
nfs4_named_attr_dir_get(nfsnode_t np,int fetch,vfs_context_t ctx)7610 nfs4_named_attr_dir_get(nfsnode_t np, int fetch, vfs_context_t ctx)
7611 {
7612 	nfsnode_t adnp = NULL;
7613 	struct nfsmount *nmp;
7614 	int error = 0, status, numops;
7615 	struct nfsm_chain nmreq, nmrep;
7616 	u_int64_t xid;
7617 	uint32_t bitmap[NFS_ATTR_BITMAP_LEN];
7618 	fhandle_t *fh;
7619 	struct nfs_vattr *nvattr;
7620 	struct componentname cn;
7621 	struct nfsreq *req;
7622 	struct nfsreq_secinfo_args si;
7623 
7624 	nmp = NFSTONMP(np);
7625 	if (nfs_mount_gone(nmp)) {
7626 		return NULL;
7627 	}
7628 	if (np->n_vattr.nva_flags & NFS_FFLAG_TRIGGER_REFERRAL) {
7629 		return NULL;
7630 	}
7631 
7632 	NFSREQ_SECINFO_SET(&si, np, NULL, 0, NULL, 0);
7633 	fh = zalloc(nfs_fhandle_zone);
7634 	req = zalloc(nfs_req_zone);
7635 	nvattr = zalloc_flags(KT_NFS_VATTR, Z_WAITOK);
7636 	NVATTR_INIT(nvattr);
7637 	nfsm_chain_null(&nmreq);
7638 	nfsm_chain_null(&nmrep);
7639 
7640 	bzero(&cn, sizeof(cn));
7641 	cn.cn_nameptr = __CAST_AWAY_QUALIFIER(_PATH_FORKSPECIFIER, const, char *); /* "/..namedfork/" */
7642 	cn.cn_namelen = NFS_STRLEN_INT(_PATH_FORKSPECIFIER);
7643 	cn.cn_nameiop = LOOKUP;
7644 
7645 	if (np->n_attrdirfh) {
7646 		// XXX can't set parent correctly (to np) yet
7647 		error = nfs_nget(nmp->nm_mountp, NULL, &cn, np->n_attrdirfh + 1, *np->n_attrdirfh,
7648 		    NULL, NULL, RPCAUTH_UNKNOWN, NG_NOCREATE, &adnp);
7649 		if (adnp) {
7650 			goto nfsmout;
7651 		}
7652 	}
7653 	if (!fetch) {
7654 		error = ENOENT;
7655 		goto nfsmout;
7656 	}
7657 
7658 	// PUTFH, OPENATTR, GETATTR
7659 	numops = 3;
7660 	nfsm_chain_build_alloc_init(error, &nmreq, 22 * NFSX_UNSIGNED);
7661 	nfsm_chain_add_compound_header(error, &nmreq, "openattr", nmp->nm_minor_vers, numops);
7662 	numops--;
7663 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_PUTFH);
7664 	nfsm_chain_add_fh(error, &nmreq, nmp->nm_vers, np->n_fhp, np->n_fhsize);
7665 	numops--;
7666 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_OPENATTR);
7667 	nfsm_chain_add_32(error, &nmreq, 0);
7668 	numops--;
7669 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_GETATTR);
7670 	NFS_COPY_ATTRIBUTES(nfs_getattr_bitmap, bitmap);
7671 	NFS_BITMAP_SET(bitmap, NFS_FATTR_FILEHANDLE);
7672 	nfsm_chain_add_bitmap_masked(error, &nmreq, bitmap,
7673 	    NFS_ATTR_BITMAP_LEN, nmp->nm_fsattr.nfsa_supp_attr);
7674 	nfsm_chain_build_done(error, &nmreq);
7675 	nfsm_assert(error, (numops == 0), EPROTO);
7676 	nfsmout_if(error);
7677 	error = nfs_request_async(np, NULL, &nmreq, NFSPROC4_COMPOUND,
7678 	    vfs_context_thread(ctx), vfs_context_ucred(ctx), &si, 0, NULL, &req);
7679 	if (!error) {
7680 		error = nfs_request_async_finish(req, &nmrep, &xid, &status);
7681 	}
7682 
7683 	nfsm_chain_skip_tag(error, &nmrep);
7684 	nfsm_chain_get_32(error, &nmrep, numops);
7685 	nfsm_chain_op_check(error, &nmrep, NFS_OP_PUTFH);
7686 	nfsm_chain_op_check(error, &nmrep, NFS_OP_OPENATTR);
7687 	nfsm_chain_op_check(error, &nmrep, NFS_OP_GETATTR);
7688 	nfsmout_if(error);
7689 	error = nfs4_parsefattr(&nmrep, NULL, nvattr, fh, NULL, NULL);
7690 	nfsmout_if(error);
7691 	if (!NFS_BITMAP_ISSET(nvattr->nva_bitmap, NFS_FATTR_FILEHANDLE) || !fh->fh_len) {
7692 		error = ENOENT;
7693 		goto nfsmout;
7694 	}
7695 	if (!np->n_attrdirfh || (*np->n_attrdirfh != fh->fh_len)) {
7696 		/* (re)allocate attrdir fh buffer */
7697 		if (np->n_attrdirfh) {
7698 			kfree_data(np->n_attrdirfh, *np->n_attrdirfh + 1);
7699 		}
7700 		np->n_attrdirfh = kalloc_data(fh->fh_len + 1, Z_WAITOK);
7701 	}
7702 	if (!np->n_attrdirfh) {
7703 		error = ENOMEM;
7704 		goto nfsmout;
7705 	}
7706 	/* cache the attrdir fh in the node */
7707 	*np->n_attrdirfh = (unsigned char)fh->fh_len; /* No truncation because fh_len's value is checked during nfs4_parsefattr() */
7708 	bcopy(fh->fh_data, np->n_attrdirfh + 1, fh->fh_len);
7709 	/* create node for attrdir */
7710 	// XXX can't set parent correctly (to np) yet
7711 	error = nfs_nget(NFSTOMP(np), NULL, &cn, fh->fh_data, fh->fh_len, nvattr, &xid, req->r_auth, 0, &adnp);
7712 nfsmout:
7713 	NVATTR_CLEANUP(nvattr);
7714 	NFS_ZFREE(nfs_fhandle_zone, fh);
7715 	NFS_ZFREE(nfs_req_zone, req);
7716 	zfree(KT_NFS_VATTR, nvattr);
7717 	nfsm_chain_cleanup(&nmreq);
7718 	nfsm_chain_cleanup(&nmrep);
7719 
7720 	if (adnp) {
7721 		/* sanity check that this node is an attribute directory */
7722 		if (adnp->n_vattr.nva_type != VDIR) {
7723 			error = EINVAL;
7724 		}
7725 		if (!(adnp->n_vattr.nva_flags & NFS_FFLAG_IS_ATTR)) {
7726 			error = EINVAL;
7727 		}
7728 		nfs_node_unlock(adnp);
7729 		if (error) {
7730 			vnode_put(NFSTOV(adnp));
7731 		}
7732 	}
7733 	return error ? NULL : adnp;
7734 }
7735 
7736 /*
7737  * Get the given node's named attribute node for the name given.
7738  *
7739  * In an effort to increase the performance of named attribute access, we try
7740  * to reduce server requests by doing the following:
7741  *
7742  * - cache the node's named attribute directory file handle in the node
7743  * - maintain a directory vnode for the attribute directory
7744  * - use name cache entries (positive and negative) to speed up lookups
7745  * - optionally open the named attribute (with the given accessMode) in the same RPC
7746  * - combine attribute directory retrieval with the lookup/open RPC
7747  * - optionally prefetch the named attribute's first block of data in the same RPC
7748  *
7749  * Also, in an attempt to reduce the number of copies/variations of this code,
7750  * parts of the RPC building/processing code are conditionalized on what is
7751  * needed for any particular request (openattr, lookup vs. open, read).
7752  *
7753  * Note that because we may not have the attribute directory node when we start
7754  * the lookup/open, we lock both the node and the attribute directory node.
7755  */
7756 
7757 #define NFS_GET_NAMED_ATTR_CREATE               0x1
7758 #define NFS_GET_NAMED_ATTR_CREATE_GUARDED       0x2
7759 #define NFS_GET_NAMED_ATTR_TRUNCATE             0x4
7760 #define NFS_GET_NAMED_ATTR_PREFETCH             0x8
7761 
7762 int
nfs4_named_attr_get(nfsnode_t np,struct componentname * cnp,uint32_t accessMode,int flags,vfs_context_t ctx,nfsnode_t * anpp,struct nfs_open_file ** nofpp)7763 nfs4_named_attr_get(
7764 	nfsnode_t np,
7765 	struct componentname *cnp,
7766 	uint32_t accessMode,
7767 	int flags,
7768 	vfs_context_t ctx,
7769 	nfsnode_t *anpp,
7770 	struct nfs_open_file **nofpp)
7771 {
7772 	struct nfsmount *nmp;
7773 	int error = 0, open_error = EIO;
7774 	int inuse = 0, adlockerror = ENOENT, busyerror = ENOENT, adbusyerror = ENOENT, nofpbusyerror = ENOENT;
7775 	int create, guarded, prefetch, truncate, noopbusy = 0;
7776 	int open, status, numops, hadattrdir, negnamecache;
7777 	struct nfs_vattr *nvattr;
7778 	struct vnode_attr vattr;
7779 	nfsnode_t adnp = NULL, anp = NULL;
7780 	vnode_t avp = NULL;
7781 	u_int64_t xid = 0, savedxid = 0;
7782 	struct nfsm_chain nmreq, nmrep;
7783 	uint32_t bitmap[NFS_ATTR_BITMAP_LEN], bmlen;
7784 	uint32_t denyMode = 0, rflags, delegation, recall, eof, rlen, retlen;
7785 	nfs_stateid stateid, dstateid;
7786 	fhandle_t *fh;
7787 	struct nfs_open_owner *noop = NULL;
7788 	struct nfs_open_file *newnofp = NULL, *nofp = NULL;
7789 	struct vnop_access_args naa;
7790 	thread_t thd;
7791 	kauth_cred_t cred;
7792 	struct timeval now;
7793 	char sbuf[64], *s;
7794 	uint32_t ace_type, ace_flags, ace_mask, len, slen;
7795 	struct kauth_ace ace;
7796 	struct nfsreq *req;
7797 	struct nfsreq_secinfo_args si;
7798 
7799 	*anpp = NULL;
7800 	rflags = delegation = recall = eof = rlen = retlen = 0;
7801 	ace.ace_flags = 0;
7802 	s = sbuf;
7803 	slen = sizeof(sbuf);
7804 
7805 	nmp = NFSTONMP(np);
7806 	if (nfs_mount_gone(nmp)) {
7807 		return ENXIO;
7808 	}
7809 	fh = zalloc(nfs_fhandle_zone);
7810 	req = zalloc(nfs_req_zone);
7811 	nvattr = zalloc_flags(KT_NFS_VATTR, Z_WAITOK);
7812 	NVATTR_INIT(nvattr);
7813 	fh->fh_len = 0;
7814 	bzero(&dstateid, sizeof(dstateid));
7815 	negnamecache = !NMFLAG(nmp, NONEGNAMECACHE);
7816 	thd = vfs_context_thread(ctx);
7817 	cred = vfs_context_ucred(ctx);
7818 	create = (flags & NFS_GET_NAMED_ATTR_CREATE) ? NFS_OPEN_CREATE : NFS_OPEN_NOCREATE;
7819 	guarded = (flags & NFS_GET_NAMED_ATTR_CREATE_GUARDED) ? NFS_CREATE_GUARDED : NFS_CREATE_UNCHECKED;
7820 	truncate = (flags & NFS_GET_NAMED_ATTR_TRUNCATE);
7821 	prefetch = (flags & NFS_GET_NAMED_ATTR_PREFETCH);
7822 
7823 	if (!create) {
7824 		error = nfs_getattr(np, nvattr, ctx, NGA_CACHED);
7825 		if (error) {
7826 			goto out_free;
7827 		}
7828 		if (NFS_BITMAP_ISSET(nvattr->nva_bitmap, NFS_FATTR_NAMED_ATTR) &&
7829 		    !(nvattr->nva_flags & NFS_FFLAG_HAS_NAMED_ATTRS)) {
7830 			error = ENOATTR;
7831 			goto out_free;
7832 		}
7833 	} else if (accessMode == NFS_OPEN_SHARE_ACCESS_NONE) {
7834 		/* shouldn't happen... but just be safe */
7835 		printf("nfs4_named_attr_get: create with no access %s\n", cnp->cn_nameptr);
7836 		accessMode = NFS_OPEN_SHARE_ACCESS_READ;
7837 	}
7838 	open = (accessMode != NFS_OPEN_SHARE_ACCESS_NONE);
7839 	if (open) {
7840 		/*
7841 		 * We're trying to open the file.
7842 		 * We'll create/open it with the given access mode,
7843 		 * and set NFS_OPEN_FILE_CREATE.
7844 		 */
7845 		denyMode = NFS_OPEN_SHARE_DENY_NONE;
7846 		if (prefetch && guarded) {
7847 			prefetch = 0;  /* no sense prefetching data that can't be there */
7848 		}
7849 		noop = nfs_open_owner_find(nmp, vfs_context_ucred(ctx), vfs_context_proc(ctx), 1);
7850 		if (!noop) {
7851 			error = ENOMEM;
7852 			goto out_free;
7853 		}
7854 	}
7855 
7856 	if ((error = busyerror = nfs_node_set_busy(np, vfs_context_thread(ctx)))) {
7857 		goto out_free;
7858 	}
7859 
7860 	adnp = nfs4_named_attr_dir_get(np, 0, ctx);
7861 	hadattrdir = (adnp != NULL);
7862 	if (prefetch) {
7863 		microuptime(&now);
7864 		/* use the special state ID because we don't have a real one to send */
7865 		stateid.seqid = stateid.other[0] = stateid.other[1] = stateid.other[2] = 0;
7866 		rlen = MIN(nmp->nm_rsize, nmp->nm_biosize);
7867 	}
7868 	NFSREQ_SECINFO_SET(&si, np, NULL, 0, NULL, 0);
7869 	nfsm_chain_null(&nmreq);
7870 	nfsm_chain_null(&nmrep);
7871 
7872 	if (hadattrdir) {
7873 		if ((error = adbusyerror = nfs_node_set_busy(adnp, vfs_context_thread(ctx)))) {
7874 			goto nfsmout;
7875 		}
7876 		/* nfs_getattr() will check changed and purge caches */
7877 		error = nfs_getattr(adnp, NULL, ctx, NGA_CACHED);
7878 		nfsmout_if(error);
7879 		error = cache_lookup(NFSTOV(adnp), &avp, cnp);
7880 		switch (error) {
7881 		case ENOENT:
7882 			/* negative cache entry */
7883 			goto nfsmout;
7884 		case 0:
7885 			/* cache miss */
7886 			/* try dir buf cache lookup */
7887 			error = nfs_dir_buf_cache_lookup(adnp, &anp, cnp, ctx, 0, NULL);
7888 			if (!error && anp) {
7889 				/* dir buf cache hit */
7890 				*anpp = anp;
7891 				error = -1;
7892 			}
7893 			if (error != -1) { /* cache miss */
7894 				break;
7895 			}
7896 			OS_FALLTHROUGH;
7897 		case -1:
7898 			/* cache hit, not really an error */
7899 			OSAddAtomic64(1, &nfsclntstats.lookupcache_hits);
7900 			if (!anp && avp) {
7901 				*anpp = anp = VTONFS(avp);
7902 			}
7903 
7904 			nfs_node_clear_busy(adnp);
7905 			adbusyerror = ENOENT;
7906 
7907 			/* check for directory access */
7908 			naa.a_desc = &vnop_access_desc;
7909 			naa.a_vp = NFSTOV(adnp);
7910 			naa.a_action = KAUTH_VNODE_SEARCH;
7911 			naa.a_context = ctx;
7912 
7913 			/* compute actual success/failure based on accessibility */
7914 			error = nfs_vnop_access(&naa);
7915 			OS_FALLTHROUGH;
7916 		default:
7917 			/* we either found it, or hit an error */
7918 			if (!error && guarded) {
7919 				/* found cached entry but told not to use it */
7920 				error = EEXIST;
7921 				vnode_put(NFSTOV(anp));
7922 				*anpp = anp = NULL;
7923 			}
7924 			/* we're done if error or we don't need to open */
7925 			if (error || !open) {
7926 				goto nfsmout;
7927 			}
7928 			/* no error and we need to open... */
7929 		}
7930 	}
7931 
7932 	if (open) {
7933 restart:
7934 		error = nfs_mount_state_in_use_start(nmp, vfs_context_thread(ctx));
7935 		if (error) {
7936 			nfs_open_owner_rele(noop);
7937 			noop = NULL;
7938 			goto nfsmout;
7939 		}
7940 		inuse = 1;
7941 
7942 		/* grab an open file - possibly provisional/nodeless if cache_lookup() failed */
7943 		error = nfs_open_file_find(anp, noop, &newnofp, 0, 0, 1);
7944 		if (!error && (newnofp->nof_flags & NFS_OPEN_FILE_LOST)) {
7945 			printf("nfs4_named_attr_get: LOST %d %s\n", kauth_cred_getuid(noop->noo_cred), cnp->cn_nameptr);
7946 			error = EIO;
7947 		}
7948 		if (!error && (newnofp->nof_flags & NFS_OPEN_FILE_REOPEN)) {
7949 			error = nfs4_reopen(newnofp, vfs_context_thread(ctx));
7950 			nfs_open_file_destroy(newnofp);
7951 			newnofp = NULL;
7952 			if (!error) {
7953 				nfs_mount_state_in_use_end(nmp, 0);
7954 				inuse = 0;
7955 				goto restart;
7956 			}
7957 		}
7958 		if (!error) {
7959 			error = nfs_open_file_set_busy(newnofp, vfs_context_thread(ctx));
7960 		}
7961 		if (error) {
7962 			if (newnofp) {
7963 				nfs_open_file_destroy(newnofp);
7964 			}
7965 			newnofp = NULL;
7966 			goto nfsmout;
7967 		}
7968 		if (anp) {
7969 			/*
7970 			 * We already have the node.  So we just need to open
7971 			 * it - which we may be able to do with a delegation.
7972 			 */
7973 			open_error = error = nfs4_open(anp, newnofp, accessMode, denyMode, ctx);
7974 			if (!error) {
7975 				/* open succeeded, so our open file is no longer temporary */
7976 				nofp = newnofp;
7977 				nofpbusyerror = 0;
7978 				newnofp = NULL;
7979 				if (nofpp) {
7980 					*nofpp = nofp;
7981 				}
7982 			}
7983 			goto nfsmout;
7984 		}
7985 	}
7986 
7987 	/*
7988 	 * We either don't have the attrdir or we didn't find the attribute
7989 	 * in the name cache, so we need to talk to the server.
7990 	 *
7991 	 * If we don't have the attrdir, we'll need to ask the server for that too.
7992 	 * If the caller is requesting that the attribute be created, we need to
7993 	 * make sure the attrdir is created.
7994 	 * The caller may also request that the first block of an existing attribute
7995 	 * be retrieved at the same time.
7996 	 */
7997 
7998 	if (open) {
7999 		/* need to mark the open owner busy during the RPC */
8000 		if ((error = nfs_open_owner_set_busy(noop, thd))) {
8001 			goto nfsmout;
8002 		}
8003 		noopbusy = 1;
8004 	}
8005 
8006 	/*
8007 	 * We'd like to get updated post-open/lookup attributes for the
8008 	 * directory and we may also want to prefetch some data via READ.
8009 	 * We'd like the READ results to be last so that we can leave the
8010 	 * data in the mbufs until the end.
8011 	 *
8012 	 * At a minimum we're sending: PUTFH, LOOKUP/OPEN, GETATTR, PUTFH, GETATTR
8013 	 */
8014 	numops = 5;
8015 	if (!hadattrdir) {
8016 		numops += 3;    // also sending: OPENATTR, GETATTR, OPENATTR
8017 	}
8018 	if (prefetch) {
8019 		numops += 4;    // also sending: SAVEFH, RESTOREFH, NVERIFY, READ
8020 	}
8021 	nfsm_chain_build_alloc_init(error, &nmreq, 64 * NFSX_UNSIGNED + cnp->cn_namelen);
8022 	nfsm_chain_add_compound_header(error, &nmreq, "getnamedattr", nmp->nm_minor_vers, numops);
8023 	if (hadattrdir) {
8024 		numops--;
8025 		nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_PUTFH);
8026 		nfsm_chain_add_fh(error, &nmreq, nmp->nm_vers, adnp->n_fhp, adnp->n_fhsize);
8027 	} else {
8028 		numops--;
8029 		nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_PUTFH);
8030 		nfsm_chain_add_fh(error, &nmreq, nmp->nm_vers, np->n_fhp, np->n_fhsize);
8031 		numops--;
8032 		nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_OPENATTR);
8033 		nfsm_chain_add_32(error, &nmreq, create ? 1 : 0);
8034 		numops--;
8035 		nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_GETATTR);
8036 		NFS_COPY_ATTRIBUTES(nfs_getattr_bitmap, bitmap);
8037 		NFS_BITMAP_SET(bitmap, NFS_FATTR_FILEHANDLE);
8038 		nfsm_chain_add_bitmap_masked(error, &nmreq, bitmap,
8039 		    NFS_ATTR_BITMAP_LEN, nmp->nm_fsattr.nfsa_supp_attr);
8040 	}
8041 	if (open) {
8042 		numops--;
8043 		nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_OPEN);
8044 		nfsm_chain_add_32(error, &nmreq, noop->noo_seqid);
8045 		nfsm_chain_add_32(error, &nmreq, accessMode);
8046 		nfsm_chain_add_32(error, &nmreq, denyMode);
8047 		nfsm_chain_add_openowner(error, &nmreq, nmp, noop);
8048 		nfsm_chain_add_32(error, &nmreq, create);
8049 		if (create) {
8050 			nfsm_chain_add_32(error, &nmreq, guarded);
8051 			VATTR_INIT(&vattr);
8052 			if (truncate) {
8053 				VATTR_SET(&vattr, va_data_size, 0);
8054 			}
8055 			nfsm_chain_add_fattr4(error, &nmreq, &vattr, nmp);
8056 		}
8057 		nfsm_chain_add_32(error, &nmreq, NFS_CLAIM_NULL);
8058 		nfsm_chain_add_name(error, &nmreq, cnp->cn_nameptr, cnp->cn_namelen, nmp);
8059 	} else {
8060 		numops--;
8061 		nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_LOOKUP);
8062 		nfsm_chain_add_name(error, &nmreq, cnp->cn_nameptr, cnp->cn_namelen, nmp);
8063 	}
8064 	numops--;
8065 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_GETATTR);
8066 	NFS_COPY_ATTRIBUTES(nfs_getattr_bitmap, bitmap);
8067 	NFS_BITMAP_SET(bitmap, NFS_FATTR_FILEHANDLE);
8068 	nfsm_chain_add_bitmap_masked(error, &nmreq, bitmap,
8069 	    NFS_ATTR_BITMAP_LEN, nmp->nm_fsattr.nfsa_supp_attr);
8070 	if (prefetch) {
8071 		numops--;
8072 		nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_SAVEFH);
8073 	}
8074 	if (hadattrdir) {
8075 		numops--;
8076 		nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_PUTFH);
8077 		nfsm_chain_add_fh(error, &nmreq, nmp->nm_vers, adnp->n_fhp, adnp->n_fhsize);
8078 	} else {
8079 		numops--;
8080 		nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_PUTFH);
8081 		nfsm_chain_add_fh(error, &nmreq, nmp->nm_vers, np->n_fhp, np->n_fhsize);
8082 		numops--;
8083 		nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_OPENATTR);
8084 		nfsm_chain_add_32(error, &nmreq, 0);
8085 	}
8086 	numops--;
8087 	nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_GETATTR);
8088 	nfsm_chain_add_bitmap_masked(error, &nmreq, nfs_getattr_bitmap,
8089 	    NFS_ATTR_BITMAP_LEN, nmp->nm_fsattr.nfsa_supp_attr);
8090 	if (prefetch) {
8091 		numops--;
8092 		nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_RESTOREFH);
8093 		numops--;
8094 		nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_NVERIFY);
8095 		VATTR_INIT(&vattr);
8096 		VATTR_SET(&vattr, va_data_size, 0);
8097 		nfsm_chain_add_fattr4(error, &nmreq, &vattr, nmp);
8098 		numops--;
8099 		nfsm_chain_add_v4_op(error, &nmreq, NFS_OP_READ);
8100 		nfsm_chain_add_stateid(error, &nmreq, &stateid);
8101 		nfsm_chain_add_64(error, &nmreq, 0);
8102 		nfsm_chain_add_32(error, &nmreq, rlen);
8103 	}
8104 	nfsm_chain_build_done(error, &nmreq);
8105 	nfsm_assert(error, (numops == 0), EPROTO);
8106 	nfsmout_if(error);
8107 	error = nfs_request_async(hadattrdir ? adnp : np, NULL, &nmreq, NFSPROC4_COMPOUND,
8108 	    vfs_context_thread(ctx), vfs_context_ucred(ctx), &si, open ? R_NOINTR: 0, NULL, &req);
8109 	if (!error) {
8110 		error = nfs_request_async_finish(req, &nmrep, &xid, &status);
8111 	}
8112 
8113 	if (hadattrdir && ((adlockerror = nfs_node_lock(adnp)))) {
8114 		error = adlockerror;
8115 	}
8116 	savedxid = xid;
8117 	nfsm_chain_skip_tag(error, &nmrep);
8118 	nfsm_chain_get_32(error, &nmrep, numops);
8119 	nfsm_chain_op_check(error, &nmrep, NFS_OP_PUTFH);
8120 	if (!hadattrdir) {
8121 		nfsm_chain_op_check(error, &nmrep, NFS_OP_OPENATTR);
8122 		nfsm_chain_op_check(error, &nmrep, NFS_OP_GETATTR);
8123 		nfsmout_if(error);
8124 		error = nfs4_parsefattr(&nmrep, NULL, nvattr, fh, NULL, NULL);
8125 		nfsmout_if(error);
8126 		if (NFS_BITMAP_ISSET(nvattr->nva_bitmap, NFS_FATTR_FILEHANDLE) && fh->fh_len) {
8127 			if (!np->n_attrdirfh || (*np->n_attrdirfh != fh->fh_len)) {
8128 				/* (re)allocate attrdir fh buffer */
8129 				if (np->n_attrdirfh) {
8130 					kfree_data(np->n_attrdirfh, *np->n_attrdirfh + 1);
8131 				}
8132 				np->n_attrdirfh = kalloc_data(fh->fh_len + 1, Z_WAITOK);
8133 			}
8134 			if (np->n_attrdirfh) {
8135 				/* remember the attrdir fh in the node */
8136 				*np->n_attrdirfh = (unsigned char)fh->fh_len;  /* No truncation because fh_len's value is checked during nfs4_parsefattr() */
8137 				bcopy(fh->fh_data, np->n_attrdirfh + 1, fh->fh_len);
8138 				/* create busied node for attrdir */
8139 				struct componentname cn;
8140 				bzero(&cn, sizeof(cn));
8141 				cn.cn_nameptr = __CAST_AWAY_QUALIFIER(_PATH_FORKSPECIFIER, const, char *); /* "/..namedfork/" */
8142 				cn.cn_namelen = NFS_STRLEN_INT(_PATH_FORKSPECIFIER);
8143 				cn.cn_nameiop = LOOKUP;
8144 				// XXX can't set parent correctly (to np) yet
8145 				error = nfs_nget(NFSTOMP(np), NULL, &cn, fh->fh_data, fh->fh_len, nvattr, &xid, req->r_auth, 0, &adnp);
8146 				if (!error) {
8147 					adlockerror = 0;
8148 					/* set the node busy */
8149 					SET(adnp->n_flag, NBUSY);
8150 					adbusyerror = 0;
8151 				}
8152 				/* if no adnp, oh well... */
8153 				error = 0;
8154 			}
8155 		}
8156 		NVATTR_CLEANUP(nvattr);
8157 		fh->fh_len = 0;
8158 	}
8159 	if (open) {
8160 		nfsm_chain_op_check(error, &nmrep, NFS_OP_OPEN);
8161 		nfs_owner_seqid_increment(noop, NULL, error);
8162 		nfsm_chain_get_stateid(error, &nmrep, &newnofp->nof_stateid);
8163 		nfsm_chain_check_change_info(error, &nmrep, adnp);
8164 		nfsm_chain_get_32(error, &nmrep, rflags);
8165 		bmlen = NFS_ATTR_BITMAP_LEN;
8166 		nfsm_chain_get_bitmap(error, &nmrep, bitmap, bmlen);
8167 		nfsm_chain_get_32(error, &nmrep, delegation);
8168 		if (!error) {
8169 			switch (delegation) {
8170 			case NFS_OPEN_DELEGATE_NONE:
8171 				break;
8172 			case NFS_OPEN_DELEGATE_READ:
8173 			case NFS_OPEN_DELEGATE_WRITE:
8174 				nfsm_chain_get_stateid(error, &nmrep, &dstateid);
8175 				nfsm_chain_get_32(error, &nmrep, recall);
8176 				if (delegation == NFS_OPEN_DELEGATE_WRITE) { // space (skip) XXX
8177 					nfsm_chain_adv(error, &nmrep, 3 * NFSX_UNSIGNED);
8178 				}
8179 				/* if we have any trouble accepting the ACE, just invalidate it */
8180 				ace_type = ace_flags = ace_mask = len = 0;
8181 				nfsm_chain_get_32(error, &nmrep, ace_type);
8182 				nfsm_chain_get_32(error, &nmrep, ace_flags);
8183 				nfsm_chain_get_32(error, &nmrep, ace_mask);
8184 				nfsm_chain_get_32(error, &nmrep, len);
8185 				ace.ace_flags = nfs4_ace_nfstype_to_vfstype(ace_type, &error);
8186 				ace.ace_flags |= nfs4_ace_nfsflags_to_vfsflags(ace_flags);
8187 				ace.ace_rights = nfs4_ace_nfsmask_to_vfsrights(ace_mask);
8188 				if (!error && (len >= slen)) {
8189 					s = kalloc_data(len + 1, Z_WAITOK);
8190 					if (s) {
8191 						slen = len + 1;
8192 					} else {
8193 						ace.ace_flags = 0;
8194 					}
8195 				}
8196 				if (s) {
8197 					nfsm_chain_get_opaque(error, &nmrep, len, s);
8198 				} else {
8199 					nfsm_chain_adv(error, &nmrep, nfsm_rndup(len));
8200 				}
8201 				if (!error && s) {
8202 					s[len] = '\0';
8203 					if (nfs4_id2guid(s, &ace.ace_applicable, (ace_flags & NFS_ACE_IDENTIFIER_GROUP))) {
8204 						ace.ace_flags = 0;
8205 					}
8206 				}
8207 				if (error || !s) {
8208 					ace.ace_flags = 0;
8209 				}
8210 				if (s && (s != sbuf)) {
8211 					kfree_data(s, slen);
8212 				}
8213 				break;
8214 			default:
8215 				error = EBADRPC;
8216 				break;
8217 			}
8218 		}
8219 		/* At this point if we have no error, the object was created/opened. */
8220 		open_error = error;
8221 	} else {
8222 		nfsm_chain_op_check(error, &nmrep, NFS_OP_LOOKUP);
8223 	}
8224 	nfsm_chain_op_check(error, &nmrep, NFS_OP_GETATTR);
8225 	nfsmout_if(error);
8226 	error = nfs4_parsefattr(&nmrep, NULL, nvattr, fh, NULL, NULL);
8227 	nfsmout_if(error);
8228 	if (!NFS_BITMAP_ISSET(nvattr->nva_bitmap, NFS_FATTR_FILEHANDLE) || !fh->fh_len) {
8229 		error = EIO;
8230 		goto nfsmout;
8231 	}
8232 	if (prefetch) {
8233 		nfsm_chain_op_check(error, &nmrep, NFS_OP_SAVEFH);
8234 	}
8235 	nfsm_chain_op_check(error, &nmrep, NFS_OP_PUTFH);
8236 	if (!hadattrdir) {
8237 		nfsm_chain_op_check(error, &nmrep, NFS_OP_OPENATTR);
8238 	}
8239 	nfsm_chain_op_check(error, &nmrep, NFS_OP_GETATTR);
8240 	nfsmout_if(error);
8241 	xid = savedxid;
8242 	nfsm_chain_loadattr(error, &nmrep, adnp, nmp->nm_vers, &xid);
8243 	nfsmout_if(error);
8244 
8245 	if (open) {
8246 		if (rflags & NFS_OPEN_RESULT_LOCKTYPE_POSIX) {
8247 			newnofp->nof_flags |= NFS_OPEN_FILE_POSIXLOCK;
8248 		}
8249 		if (rflags & NFS_OPEN_RESULT_CONFIRM) {
8250 			if (adnp) {
8251 				nfs_node_unlock(adnp);
8252 				adlockerror = ENOENT;
8253 			}
8254 			NVATTR_CLEANUP(nvattr);
8255 			error = nfs4_open_confirm_rpc(nmp, adnp ? adnp : np, fh->fh_data, fh->fh_len, noop, &newnofp->nof_stateid, thd, cred, nvattr, &xid);
8256 			nfsmout_if(error);
8257 			savedxid = xid;
8258 			if ((adlockerror = nfs_node_lock(adnp))) {
8259 				error = adlockerror;
8260 			}
8261 		}
8262 	}
8263 
8264 nfsmout:
8265 	if (open && adnp && !adlockerror) {
8266 		if (!open_error && (adnp->n_flag & NNEGNCENTRIES)) {
8267 			adnp->n_flag &= ~NNEGNCENTRIES;
8268 			cache_purge_negatives(NFSTOV(adnp));
8269 		}
8270 		adnp->n_flag |= NMODIFIED;
8271 		nfs_node_unlock(adnp);
8272 		adlockerror = ENOENT;
8273 		nfs_getattr(adnp, NULL, ctx, NGA_CACHED);
8274 	}
8275 	if (adnp && !adlockerror && (error == ENOENT) &&
8276 	    (cnp->cn_flags & MAKEENTRY) && (cnp->cn_nameiop != CREATE) && negnamecache) {
8277 		/* add a negative entry in the name cache */
8278 		cache_enter(NFSTOV(adnp), NULL, cnp);
8279 		adnp->n_flag |= NNEGNCENTRIES;
8280 	}
8281 	if (adnp && !adlockerror) {
8282 		nfs_node_unlock(adnp);
8283 		adlockerror = ENOENT;
8284 	}
8285 	if (!error && !anp && fh->fh_len) {
8286 		/* create the vnode with the filehandle and attributes */
8287 		xid = savedxid;
8288 		error = nfs_nget(NFSTOMP(np), adnp, cnp, fh->fh_data, fh->fh_len, nvattr, &xid, req->r_auth, NG_MAKEENTRY, &anp);
8289 		if (!error) {
8290 			*anpp = anp;
8291 			nfs_node_unlock(anp);
8292 		}
8293 		if (!error && open) {
8294 			nfs_open_file_add_open(newnofp, accessMode, denyMode, 0);
8295 			/* After we have a node, add our open file struct to the node */
8296 			nofp = newnofp;
8297 			error = nfs_open_file_find_internal(anp, noop, &nofp, 0, 0, 0);
8298 			if (error) {
8299 				/* This shouldn't happen, because we passed in a new nofp to use. */
8300 				printf("nfs_open_file_find_internal failed! %d\n", error);
8301 				nofp = NULL;
8302 			} else if (nofp != newnofp) {
8303 				/*
8304 				 * Hmm... an open file struct already exists.
8305 				 * Mark the existing one busy and merge our open into it.
8306 				 * Then destroy the one we created.
8307 				 * Note: there's no chance of an open confict because the
8308 				 * open has already been granted.
8309 				 */
8310 				nofpbusyerror = nfs_open_file_set_busy(nofp, NULL);
8311 				nfs_open_file_add_open(nofp, accessMode, denyMode, 0);
8312 				nofp->nof_stateid = newnofp->nof_stateid;
8313 				if (newnofp->nof_flags & NFS_OPEN_FILE_POSIXLOCK) {
8314 					nofp->nof_flags |= NFS_OPEN_FILE_POSIXLOCK;
8315 				}
8316 				nfs_open_file_clear_busy(newnofp);
8317 				nfs_open_file_destroy(newnofp);
8318 				newnofp = NULL;
8319 			}
8320 			if (!error) {
8321 				newnofp = NULL;
8322 				nofpbusyerror = 0;
8323 				/* mark the node as holding a create-initiated open */
8324 				nofp->nof_flags |= NFS_OPEN_FILE_CREATE;
8325 				nofp->nof_creator = current_thread();
8326 				if (nofpp) {
8327 					*nofpp = nofp;
8328 				}
8329 			}
8330 		}
8331 	}
8332 	NVATTR_CLEANUP(nvattr);
8333 	if (open && ((delegation == NFS_OPEN_DELEGATE_READ) || (delegation == NFS_OPEN_DELEGATE_WRITE))) {
8334 		if (!error && anp && !recall) {
8335 			/* stuff the delegation state in the node */
8336 			lck_mtx_lock(&anp->n_openlock);
8337 			anp->n_openflags &= ~N_DELEG_MASK;
8338 			anp->n_openflags |= ((delegation == NFS_OPEN_DELEGATE_READ) ? N_DELEG_READ : N_DELEG_WRITE);
8339 			anp->n_dstateid = dstateid;
8340 			anp->n_dace = ace;
8341 			if (anp->n_dlink.tqe_next == NFSNOLIST) {
8342 				lck_mtx_lock(&nmp->nm_lock);
8343 				if (anp->n_dlink.tqe_next == NFSNOLIST) {
8344 					TAILQ_INSERT_TAIL(&nmp->nm_delegations, anp, n_dlink);
8345 				}
8346 				lck_mtx_unlock(&nmp->nm_lock);
8347 			}
8348 			lck_mtx_unlock(&anp->n_openlock);
8349 		} else {
8350 			/* give the delegation back */
8351 			if (anp) {
8352 				if (NFS_CMPFH(anp, fh->fh_data, fh->fh_len)) {
8353 					/* update delegation state and return it */
8354 					lck_mtx_lock(&anp->n_openlock);
8355 					anp->n_openflags &= ~N_DELEG_MASK;
8356 					anp->n_openflags |= ((delegation == NFS_OPEN_DELEGATE_READ) ? N_DELEG_READ : N_DELEG_WRITE);
8357 					anp->n_dstateid = dstateid;
8358 					anp->n_dace = ace;
8359 					if (anp->n_dlink.tqe_next == NFSNOLIST) {
8360 						lck_mtx_lock(&nmp->nm_lock);
8361 						if (anp->n_dlink.tqe_next == NFSNOLIST) {
8362 							TAILQ_INSERT_TAIL(&nmp->nm_delegations, anp, n_dlink);
8363 						}
8364 						lck_mtx_unlock(&nmp->nm_lock);
8365 					}
8366 					lck_mtx_unlock(&anp->n_openlock);
8367 					/* don't need to send a separate delegreturn for fh */
8368 					fh->fh_len = 0;
8369 				}
8370 				/* return anp's current delegation */
8371 				nfs4_delegation_return(anp, 0, thd, cred);
8372 			}
8373 			if (fh->fh_len) { /* return fh's delegation if it wasn't for anp */
8374 				nfs4_delegreturn_rpc(nmp, fh->fh_data, fh->fh_len, &dstateid, 0, thd, cred);
8375 			}
8376 		}
8377 	}
8378 	if (open) {
8379 		if (newnofp) {
8380 			/* need to cleanup our temporary nofp */
8381 			nfs_open_file_clear_busy(newnofp);
8382 			nfs_open_file_destroy(newnofp);
8383 			newnofp = NULL;
8384 		} else if (nofp && !nofpbusyerror) {
8385 			nfs_open_file_clear_busy(nofp);
8386 			nofpbusyerror = ENOENT;
8387 		}
8388 		if (inuse && nfs_mount_state_in_use_end(nmp, error)) {
8389 			inuse = 0;
8390 			nofp = newnofp = NULL;
8391 			rflags = delegation = recall = eof = rlen = retlen = 0;
8392 			ace.ace_flags = 0;
8393 			s = sbuf;
8394 			slen = sizeof(sbuf);
8395 			nfsm_chain_cleanup(&nmreq);
8396 			nfsm_chain_cleanup(&nmrep);
8397 			if (anp) {
8398 				vnode_put(NFSTOV(anp));
8399 				*anpp = anp = NULL;
8400 			}
8401 			hadattrdir = (adnp != NULL);
8402 			if (noopbusy) {
8403 				nfs_open_owner_clear_busy(noop);
8404 				noopbusy = 0;
8405 			}
8406 			goto restart;
8407 		}
8408 		inuse = 0;
8409 		if (noop) {
8410 			if (noopbusy) {
8411 				nfs_open_owner_clear_busy(noop);
8412 				noopbusy = 0;
8413 			}
8414 			nfs_open_owner_rele(noop);
8415 		}
8416 	}
8417 	if (!error && prefetch && nmrep.nmc_mhead) {
8418 		nfsm_chain_op_check(error, &nmrep, NFS_OP_RESTOREFH);
8419 		nfsm_chain_op_check(error, &nmrep, NFS_OP_NVERIFY);
8420 		nfsm_chain_op_check(error, &nmrep, NFS_OP_READ);
8421 		nfsm_chain_get_32(error, &nmrep, eof);
8422 		nfsm_chain_get_32(error, &nmrep, retlen);
8423 		if (!error && anp) {
8424 			/*
8425 			 * There can be one problem with doing the prefetch.
8426 			 * Because we don't have the node before we start the RPC, we
8427 			 * can't have the buffer busy while the READ is performed.
8428 			 * So there is a chance that other I/O occured on the same
8429 			 * range of data while we were performing this RPC.  If that
8430 			 * happens, then it's possible the data we have in the READ
8431 			 * response is no longer up to date.
8432 			 * Once we have the node and the buffer, we need to make sure
8433 			 * that there's no chance we could be putting stale data in
8434 			 * the buffer.
8435 			 * So, we check if the range read is dirty or if any I/O may
8436 			 * have occured on it while we were performing our RPC.
8437 			 */
8438 			struct nfsbuf *bp = NULL;
8439 			int lastpg;
8440 			nfsbufpgs pagemask, pagemaskand;
8441 
8442 			retlen = MIN(retlen, rlen);
8443 
8444 			/* check if node needs size update or invalidation */
8445 			if (ISSET(anp->n_flag, NUPDATESIZE)) {
8446 				nfs_data_update_size(anp, 0);
8447 			}
8448 			if (!(error = nfs_node_lock(anp))) {
8449 				if (anp->n_flag & NNEEDINVALIDATE) {
8450 					anp->n_flag &= ~NNEEDINVALIDATE;
8451 					nfs_node_unlock(anp);
8452 					error = nfs_vinvalbuf1(NFSTOV(anp), V_SAVE | V_IGNORE_WRITEERR, ctx, 1);
8453 					if (!error) { /* lets play it safe and just drop the data */
8454 						error = EIO;
8455 					}
8456 				} else {
8457 					nfs_node_unlock(anp);
8458 				}
8459 			}
8460 
8461 			/* calculate page mask for the range of data read */
8462 			lastpg = (retlen - 1) / PAGE_SIZE;
8463 			nfs_buf_pgs_get_page_mask(&pagemask, lastpg + 1);
8464 
8465 			if (!error) {
8466 				error = nfs_buf_get(anp, 0, nmp->nm_biosize, thd, NBLK_READ | NBLK_NOWAIT, &bp);
8467 			}
8468 			/* don't save the data if dirty or potential I/O conflict */
8469 			nfs_buf_pgs_bit_and(&bp->nb_dirty, &pagemask, &pagemaskand);
8470 			if (!error && bp && !bp->nb_dirtyoff && !nfs_buf_pgs_is_set(&pagemaskand) &&
8471 			    timevalcmp(&anp->n_lastio, &now, <)) {
8472 				OSAddAtomic64(1, &nfsclntstats.read_bios);
8473 				CLR(bp->nb_flags, (NB_DONE | NB_ASYNC));
8474 				SET(bp->nb_flags, NB_READ);
8475 				NFS_BUF_MAP(bp);
8476 				nfsm_chain_get_opaque(error, &nmrep, retlen, bp->nb_data);
8477 				if (error) {
8478 					bp->nb_error = error;
8479 					SET(bp->nb_flags, NB_ERROR);
8480 				} else {
8481 					bp->nb_offio = 0;
8482 					bp->nb_endio = rlen;
8483 					if ((retlen > 0) && (bp->nb_endio < (int)retlen)) {
8484 						bp->nb_endio = retlen;
8485 					}
8486 					if (eof || (retlen == 0)) {
8487 						/* zero out the remaining data (up to EOF) */
8488 						off_t rpcrem, eofrem, rem;
8489 						rpcrem = (rlen - retlen);
8490 						eofrem = anp->n_size - (NBOFF(bp) + retlen);
8491 						rem = (rpcrem < eofrem) ? rpcrem : eofrem;
8492 						if (rem > 0) {
8493 							bzero(bp->nb_data + retlen, rem);
8494 						}
8495 					} else if ((retlen < rlen) && !ISSET(bp->nb_flags, NB_ERROR)) {
8496 						/* ugh... short read ... just invalidate for now... */
8497 						SET(bp->nb_flags, NB_INVAL);
8498 					}
8499 				}
8500 				nfs_buf_read_finish(bp);
8501 				microuptime(&anp->n_lastio);
8502 			}
8503 			if (bp) {
8504 				nfs_buf_release(bp, 1);
8505 			}
8506 		}
8507 		error = 0; /* ignore any transient error in processing the prefetch */
8508 	}
8509 	if (adnp && !adbusyerror) {
8510 		nfs_node_clear_busy(adnp);
8511 		adbusyerror = ENOENT;
8512 	}
8513 	if (!busyerror) {
8514 		nfs_node_clear_busy(np);
8515 		busyerror = ENOENT;
8516 	}
8517 	if (adnp) {
8518 		vnode_put(NFSTOV(adnp));
8519 	}
8520 	if (inuse) {
8521 		nfs_mount_state_in_use_end(nmp, error);
8522 	}
8523 	if (error && *anpp) {
8524 		vnode_put(NFSTOV(*anpp));
8525 		*anpp = NULL;
8526 	}
8527 	nfsm_chain_cleanup(&nmreq);
8528 	nfsm_chain_cleanup(&nmrep);
8529 out_free:
8530 	NFS_ZFREE(nfs_fhandle_zone, fh);
8531 	NFS_ZFREE(nfs_req_zone, req);
8532 	zfree(KT_NFS_VATTR, nvattr);
8533 	return error;
8534 }
8535 
8536 /*
8537  * Remove a named attribute.
8538  */
8539 int
nfs4_named_attr_remove(nfsnode_t np,nfsnode_t anp,const char * name,vfs_context_t ctx)8540 nfs4_named_attr_remove(nfsnode_t np, nfsnode_t anp, const char *name, vfs_context_t ctx)
8541 {
8542 	nfsnode_t adnp = NULL;
8543 	struct nfsmount *nmp;
8544 	struct componentname cn;
8545 	struct vnop_remove_args vra;
8546 	int error, putanp = 0;
8547 
8548 	nmp = NFSTONMP(np);
8549 	if (nfs_mount_gone(nmp)) {
8550 		return ENXIO;
8551 	}
8552 
8553 	bzero(&cn, sizeof(cn));
8554 	cn.cn_nameptr = __CAST_AWAY_QUALIFIER(name, const, char *);
8555 	cn.cn_namelen = NFS_STRLEN_INT(name);
8556 	cn.cn_nameiop = DELETE;
8557 	cn.cn_flags = 0;
8558 
8559 	if (!anp) {
8560 		error = nfs4_named_attr_get(np, &cn, NFS_OPEN_SHARE_ACCESS_NONE,
8561 		    0, ctx, &anp, NULL);
8562 		if ((!error && !anp) || (error == ENOATTR)) {
8563 			error = ENOENT;
8564 		}
8565 		if (error) {
8566 			if (anp) {
8567 				vnode_put(NFSTOV(anp));
8568 				anp = NULL;
8569 			}
8570 			goto out;
8571 		}
8572 		putanp = 1;
8573 	}
8574 
8575 	if ((error = nfs_node_set_busy(np, vfs_context_thread(ctx)))) {
8576 		goto out;
8577 	}
8578 	adnp = nfs4_named_attr_dir_get(np, 1, ctx);
8579 	nfs_node_clear_busy(np);
8580 	if (!adnp) {
8581 		error = ENOENT;
8582 		goto out;
8583 	}
8584 
8585 	vra.a_desc = &vnop_remove_desc;
8586 	vra.a_dvp = NFSTOV(adnp);
8587 	vra.a_vp = NFSTOV(anp);
8588 	vra.a_cnp = &cn;
8589 	vra.a_flags = 0;
8590 	vra.a_context = ctx;
8591 	error = nfs_vnop_remove(&vra);
8592 out:
8593 	if (adnp) {
8594 		vnode_put(NFSTOV(adnp));
8595 	}
8596 	if (putanp) {
8597 		vnode_put(NFSTOV(anp));
8598 	}
8599 	return error;
8600 }
8601 
8602 int
nfs4_vnop_getxattr(struct vnop_getxattr_args * ap)8603 nfs4_vnop_getxattr(
8604 	struct vnop_getxattr_args /* {
8605                                    *  struct vnodeop_desc *a_desc;
8606                                    *  vnode_t a_vp;
8607                                    *  const char * a_name;
8608                                    *  uio_t a_uio;
8609                                    *  size_t *a_size;
8610                                    *  int a_options;
8611                                    *  vfs_context_t a_context;
8612                                    *  } */*ap)
8613 {
8614 	vfs_context_t ctx = ap->a_context;
8615 	struct nfsmount *nmp;
8616 	struct nfs_vattr *nvattr;
8617 	struct componentname cn;
8618 	nfsnode_t anp;
8619 	int error = 0, isrsrcfork;
8620 
8621 	nmp = VTONMP(ap->a_vp);
8622 	if (nfs_mount_gone(nmp)) {
8623 		return ENXIO;
8624 	}
8625 
8626 	if (!(nmp->nm_fsattr.nfsa_flags & NFS_FSFLAG_NAMED_ATTR)) {
8627 		return ENOTSUP;
8628 	}
8629 
8630 	nvattr = zalloc_flags(KT_NFS_VATTR, Z_WAITOK);
8631 	error = nfs_getattr(VTONFS(ap->a_vp), nvattr, ctx, NGA_CACHED);
8632 	if (error) {
8633 		goto out;
8634 	}
8635 	if (NFS_BITMAP_ISSET(nvattr->nva_bitmap, NFS_FATTR_NAMED_ATTR) &&
8636 	    !(nvattr->nva_flags & NFS_FFLAG_HAS_NAMED_ATTRS)) {
8637 		error = ENOATTR;
8638 		goto out;
8639 	}
8640 
8641 	bzero(&cn, sizeof(cn));
8642 	cn.cn_nameptr = __CAST_AWAY_QUALIFIER(ap->a_name, const, char *);
8643 	cn.cn_namelen = NFS_STRLEN_INT(ap->a_name);
8644 	cn.cn_nameiop = LOOKUP;
8645 	cn.cn_flags = MAKEENTRY;
8646 
8647 	/* we'll normally try to prefetch data for xattrs... the resource fork is really a stream */
8648 	isrsrcfork = (bcmp(ap->a_name, XATTR_RESOURCEFORK_NAME, sizeof(XATTR_RESOURCEFORK_NAME)) == 0);
8649 
8650 	error = nfs4_named_attr_get(VTONFS(ap->a_vp), &cn, NFS_OPEN_SHARE_ACCESS_NONE,
8651 	    !isrsrcfork ? NFS_GET_NAMED_ATTR_PREFETCH : 0, ctx, &anp, NULL);
8652 	if ((!error && !anp) || (error == ENOENT)) {
8653 		error = ENOATTR;
8654 	}
8655 	if (!error) {
8656 		if (ap->a_uio) {
8657 			error = nfs_bioread(anp, ap->a_uio, 0, ctx);
8658 		} else {
8659 			*ap->a_size = anp->n_size;
8660 		}
8661 	}
8662 	if (anp) {
8663 		vnode_put(NFSTOV(anp));
8664 	}
8665 out:
8666 	zfree(KT_NFS_VATTR, nvattr);
8667 	return NFS_MAPERR(error);
8668 }
8669 
8670 int
nfs4_vnop_setxattr(struct vnop_setxattr_args * ap)8671 nfs4_vnop_setxattr(
8672 	struct vnop_setxattr_args /* {
8673                                    *  struct vnodeop_desc *a_desc;
8674                                    *  vnode_t a_vp;
8675                                    *  const char * a_name;
8676                                    *  uio_t a_uio;
8677                                    *  int a_options;
8678                                    *  vfs_context_t a_context;
8679                                    *  } */*ap)
8680 {
8681 	vfs_context_t ctx = ap->a_context;
8682 	int options = ap->a_options;
8683 	uio_t uio = ap->a_uio;
8684 	const char *name = ap->a_name;
8685 	struct nfsmount *nmp;
8686 	struct componentname cn;
8687 	nfsnode_t anp = NULL;
8688 	int error = 0, closeerror = 0, flags, isrsrcfork, isfinderinfo, empty = 0, i;
8689 #define FINDERINFOSIZE 32
8690 	uint8_t finfo[FINDERINFOSIZE];
8691 	uint32_t *finfop;
8692 	struct nfs_open_file *nofp = NULL;
8693 	uio_t auio = NULL;
8694 	struct vnop_write_args vwa;
8695 
8696 	nmp = VTONMP(ap->a_vp);
8697 	if (nfs_mount_gone(nmp)) {
8698 		return ENXIO;
8699 	}
8700 
8701 	if (!(nmp->nm_fsattr.nfsa_flags & NFS_FSFLAG_NAMED_ATTR)) {
8702 		return ENOTSUP;
8703 	}
8704 
8705 	if ((options & XATTR_CREATE) && (options & XATTR_REPLACE)) {
8706 		return EINVAL;
8707 	}
8708 
8709 	/* XXX limitation based on need to back up uio on short write */
8710 	if (uio_iovcnt(uio) > 1) {
8711 		printf("nfs4_vnop_setxattr: iovcnt > 1\n");
8712 		return EINVAL;
8713 	}
8714 
8715 	bzero(&cn, sizeof(cn));
8716 	cn.cn_nameptr = __CAST_AWAY_QUALIFIER(name, const, char *);
8717 	cn.cn_namelen = NFS_STRLEN_INT(name);
8718 	cn.cn_nameiop = CREATE;
8719 	cn.cn_flags = MAKEENTRY;
8720 
8721 	isfinderinfo = (bcmp(name, XATTR_FINDERINFO_NAME, sizeof(XATTR_FINDERINFO_NAME)) == 0);
8722 	isrsrcfork = isfinderinfo ? 0 : (bcmp(name, XATTR_RESOURCEFORK_NAME, sizeof(XATTR_RESOURCEFORK_NAME)) == 0);
8723 	if (!isrsrcfork) {
8724 		uio_setoffset(uio, 0);
8725 	}
8726 	if (isfinderinfo) {
8727 		bzero(&finfo, sizeof(finfo));
8728 		if (uio_resid(uio) != sizeof(finfo)) {
8729 			return ERANGE;
8730 		}
8731 		error = uiomove((char*)&finfo, sizeof(finfo), uio);
8732 		if (error) {
8733 			return NFS_MAPERR(error);
8734 		}
8735 		/* setting a FinderInfo of all zeroes means remove the FinderInfo */
8736 		empty = 1;
8737 		for (i = 0, finfop = (uint32_t*)&finfo; i < (int)(sizeof(finfo) / sizeof(uint32_t)); i++) {
8738 			if (finfop[i]) {
8739 				empty = 0;
8740 				break;
8741 			}
8742 		}
8743 		if (empty && !(options & (XATTR_CREATE | XATTR_REPLACE))) {
8744 			error = nfs4_named_attr_remove(VTONFS(ap->a_vp), anp, name, ctx);
8745 			if (error == ENOENT) {
8746 				error = 0;
8747 			}
8748 			return NFS_MAPERR(error);
8749 		}
8750 		/* first, let's see if we get a create/replace error */
8751 	}
8752 
8753 	/*
8754 	 * create/open the xattr
8755 	 *
8756 	 * We need to make sure not to create it if XATTR_REPLACE.
8757 	 * For all xattrs except the resource fork, we also want to
8758 	 * truncate the xattr to remove any current data.  We'll do
8759 	 * that by setting the size to 0 on create/open.
8760 	 */
8761 	flags = 0;
8762 	if (!(options & XATTR_REPLACE)) {
8763 		flags |= NFS_GET_NAMED_ATTR_CREATE;
8764 	}
8765 	if (options & XATTR_CREATE) {
8766 		flags |= NFS_GET_NAMED_ATTR_CREATE_GUARDED;
8767 	}
8768 	if (!isrsrcfork) {
8769 		flags |= NFS_GET_NAMED_ATTR_TRUNCATE;
8770 	}
8771 
8772 	error = nfs4_named_attr_get(VTONFS(ap->a_vp), &cn, NFS_OPEN_SHARE_ACCESS_BOTH,
8773 	    flags, ctx, &anp, &nofp);
8774 	if (!error && !anp) {
8775 		error = ENOATTR;
8776 	}
8777 	if (error) {
8778 		goto out;
8779 	}
8780 	/* grab the open state from the get/create/open */
8781 	if (nofp && !(error = nfs_open_file_set_busy(nofp, NULL))) {
8782 		nofp->nof_flags &= ~NFS_OPEN_FILE_CREATE;
8783 		nofp->nof_creator = NULL;
8784 		nfs_open_file_clear_busy(nofp);
8785 	}
8786 
8787 	/* Setting an empty FinderInfo really means remove it, skip to the close/remove */
8788 	if (isfinderinfo && empty) {
8789 		goto doclose;
8790 	}
8791 
8792 	/*
8793 	 * Write the data out and flush.
8794 	 *
8795 	 * For FinderInfo, we've already copied the data to finfo, so do I/O from there.
8796 	 */
8797 	vwa.a_desc = &vnop_write_desc;
8798 	vwa.a_vp = NFSTOV(anp);
8799 	vwa.a_uio = NULL;
8800 	vwa.a_ioflag = 0;
8801 	vwa.a_context = ctx;
8802 	if (isfinderinfo) {
8803 		auio = uio_create(1, 0, UIO_SYSSPACE, UIO_WRITE);
8804 		uio_addiov(auio, (uintptr_t)&finfo, sizeof(finfo));
8805 		vwa.a_uio = auio;
8806 	} else if (uio_resid(uio) > 0) {
8807 		vwa.a_uio = uio;
8808 	}
8809 	if (vwa.a_uio) {
8810 		error = nfs_vnop_write(&vwa);
8811 		if (!error) {
8812 			error = nfs_flush(anp, MNT_WAIT, vfs_context_thread(ctx), 0);
8813 		}
8814 		if (isfinderinfo) {
8815 			uio_free(auio);
8816 		}
8817 	}
8818 doclose:
8819 	/* Close the xattr. */
8820 	if (nofp) {
8821 		int busyerror = nfs_open_file_set_busy(nofp, NULL);
8822 		closeerror = nfs_close(anp, nofp, NFS_OPEN_SHARE_ACCESS_BOTH, NFS_OPEN_SHARE_DENY_NONE, ctx);
8823 		if (!busyerror) {
8824 			nfs_open_file_clear_busy(nofp);
8825 		}
8826 	}
8827 	if (!error && isfinderinfo && empty) { /* Setting an empty FinderInfo really means remove it */
8828 		error = nfs4_named_attr_remove(VTONFS(ap->a_vp), anp, name, ctx);
8829 		if (error == ENOENT) {
8830 			error = 0;
8831 		}
8832 	}
8833 	if (!error) {
8834 		error = closeerror;
8835 	}
8836 out:
8837 	if (anp) {
8838 		vnode_put(NFSTOV(anp));
8839 	}
8840 	if (error == ENOENT) {
8841 		error = ENOATTR;
8842 	}
8843 	return NFS_MAPERR(error);
8844 }
8845 
8846 int
nfs4_vnop_removexattr(struct vnop_removexattr_args * ap)8847 nfs4_vnop_removexattr(
8848 	struct vnop_removexattr_args /* {
8849                                       *  struct vnodeop_desc *a_desc;
8850                                       *  vnode_t a_vp;
8851                                       *  const char * a_name;
8852                                       *  int a_options;
8853                                       *  vfs_context_t a_context;
8854                                       *  } */*ap)
8855 {
8856 	struct nfsmount *nmp = VTONMP(ap->a_vp);
8857 	int error;
8858 
8859 	if (nfs_mount_gone(nmp)) {
8860 		return ENXIO;
8861 	}
8862 	if (!(nmp->nm_fsattr.nfsa_flags & NFS_FSFLAG_NAMED_ATTR)) {
8863 		return ENOTSUP;
8864 	}
8865 
8866 	error = nfs4_named_attr_remove(VTONFS(ap->a_vp), NULL, ap->a_name, ap->a_context);
8867 	if (error == ENOENT) {
8868 		error = ENOATTR;
8869 	}
8870 	return NFS_MAPERR(error);
8871 }
8872 
8873 int
nfs4_vnop_listxattr(struct vnop_listxattr_args * ap)8874 nfs4_vnop_listxattr(
8875 	struct vnop_listxattr_args /* {
8876                                     *  struct vnodeop_desc *a_desc;
8877                                     *  vnode_t a_vp;
8878                                     *  uio_t a_uio;
8879                                     *  size_t *a_size;
8880                                     *  int a_options;
8881                                     *  vfs_context_t a_context;
8882                                     *  } */*ap)
8883 {
8884 	vfs_context_t ctx = ap->a_context;
8885 	nfsnode_t np = VTONFS(ap->a_vp);
8886 	uio_t uio = ap->a_uio;
8887 	nfsnode_t adnp = NULL;
8888 	struct nfsmount *nmp;
8889 	int error, done, i;
8890 	struct nfs_vattr *nvattr;
8891 	uint64_t cookie, nextcookie, lbn = 0;
8892 	struct nfsbuf *bp = NULL;
8893 	struct nfs_dir_buf_header *ndbhp;
8894 	struct direntry *dp;
8895 
8896 	nmp = VTONMP(ap->a_vp);
8897 	if (nfs_mount_gone(nmp)) {
8898 		return ENXIO;
8899 	}
8900 
8901 	if (!(nmp->nm_fsattr.nfsa_flags & NFS_FSFLAG_NAMED_ATTR)) {
8902 		return ENOTSUP;
8903 	}
8904 
8905 	nvattr = zalloc_flags(KT_NFS_VATTR, Z_WAITOK);
8906 	error = nfs_getattr(np, nvattr, ctx, NGA_CACHED);
8907 	if (error) {
8908 		goto out_free;
8909 	}
8910 	if (NFS_BITMAP_ISSET(nvattr->nva_bitmap, NFS_FATTR_NAMED_ATTR) &&
8911 	    !(nvattr->nva_flags & NFS_FFLAG_HAS_NAMED_ATTRS)) {
8912 		error = 0;
8913 		goto out_free;
8914 	}
8915 
8916 	if ((error = nfs_node_set_busy(np, vfs_context_thread(ctx)))) {
8917 		goto out_free;
8918 	}
8919 	adnp = nfs4_named_attr_dir_get(np, 1, ctx);
8920 	nfs_node_clear_busy(np);
8921 	if (!adnp) {
8922 		goto out;
8923 	}
8924 
8925 	if ((error = nfs_node_lock(adnp))) {
8926 		goto out;
8927 	}
8928 
8929 	if (adnp->n_flag & NNEEDINVALIDATE) {
8930 		adnp->n_flag &= ~NNEEDINVALIDATE;
8931 		nfs_invaldir(adnp);
8932 		nfs_node_unlock(adnp);
8933 		error = nfs_vinvalbuf1(NFSTOV(adnp), 0, ctx, 1);
8934 		if (!error) {
8935 			error = nfs_node_lock(adnp);
8936 		}
8937 		if (error) {
8938 			goto out;
8939 		}
8940 	}
8941 
8942 	/*
8943 	 * check for need to invalidate when (re)starting at beginning
8944 	 */
8945 	if (adnp->n_flag & NMODIFIED) {
8946 		nfs_invaldir(adnp);
8947 		nfs_node_unlock(adnp);
8948 		if ((error = nfs_vinvalbuf1(NFSTOV(adnp), 0, ctx, 1))) {
8949 			goto out;
8950 		}
8951 	} else {
8952 		nfs_node_unlock(adnp);
8953 	}
8954 	/* nfs_getattr() will check changed and purge caches */
8955 	if ((error = nfs_getattr(adnp, nvattr, ctx, NGA_CACHED))) {
8956 		goto out;
8957 	}
8958 
8959 	if (uio && (uio_resid(uio) == 0)) {
8960 		goto out;
8961 	}
8962 
8963 	done = 0;
8964 	nextcookie = lbn = 0;
8965 
8966 	while (!error && !done) {
8967 		OSAddAtomic64(1, &nfsclntstats.biocache_readdirs);
8968 		cookie = nextcookie;
8969 getbuffer:
8970 		error = nfs_buf_get(adnp, lbn, NFS_DIRBLKSIZ, vfs_context_thread(ctx), NBLK_READ, &bp);
8971 		if (error) {
8972 			goto out;
8973 		}
8974 		ndbhp = (struct nfs_dir_buf_header*)bp->nb_data;
8975 		if (!ISSET(bp->nb_flags, NB_CACHE) || !ISSET(ndbhp->ndbh_flags, NDB_FULL)) {
8976 			if (!ISSET(bp->nb_flags, NB_CACHE)) { /* initialize the buffer */
8977 				ndbhp->ndbh_flags = 0;
8978 				ndbhp->ndbh_count = 0;
8979 				ndbhp->ndbh_entry_end = sizeof(*ndbhp);
8980 				ndbhp->ndbh_ncgen = adnp->n_ncgen;
8981 			}
8982 			error = nfs_buf_readdir(bp, ctx);
8983 			if (error == NFSERR_DIRBUFDROPPED) {
8984 				goto getbuffer;
8985 			}
8986 			if (error) {
8987 				nfs_buf_release(bp, 1);
8988 			}
8989 			if (error && (error != ENXIO) && (error != ETIMEDOUT) && (error != EINTR) && (error != ERESTART)) {
8990 				if (!nfs_node_lock(adnp)) {
8991 					nfs_invaldir(adnp);
8992 					nfs_node_unlock(adnp);
8993 				}
8994 				nfs_vinvalbuf1(NFSTOV(adnp), 0, ctx, 1);
8995 				if (error == NFSERR_BAD_COOKIE) {
8996 					error = ENOENT;
8997 				}
8998 			}
8999 			if (error) {
9000 				goto out;
9001 			}
9002 		}
9003 
9004 		/* go through all the entries copying/counting */
9005 		dp = NFS_DIR_BUF_FIRST_DIRENTRY(bp);
9006 		for (i = 0; i < ndbhp->ndbh_count; i++) {
9007 			if (!xattr_protected(dp->d_name)) {
9008 				if (uio == NULL) {
9009 					*ap->a_size += dp->d_namlen + 1;
9010 				} else if (uio_resid(uio) < (dp->d_namlen + 1)) {
9011 					error = ERANGE;
9012 				} else {
9013 					error = uiomove(dp->d_name, dp->d_namlen + 1, uio);
9014 					if (error && (error != EFAULT)) {
9015 						error = ERANGE;
9016 					}
9017 				}
9018 			}
9019 			nextcookie = dp->d_seekoff;
9020 			dp = NFS_DIRENTRY_NEXT(dp);
9021 		}
9022 
9023 		if (i == ndbhp->ndbh_count) {
9024 			/* hit end of buffer, move to next buffer */
9025 			lbn = nextcookie;
9026 			/* if we also hit EOF, we're done */
9027 			if (ISSET(ndbhp->ndbh_flags, NDB_EOF)) {
9028 				done = 1;
9029 			}
9030 		}
9031 		if (!error && !done && (nextcookie == cookie)) {
9032 			printf("nfs readdir cookie didn't change 0x%llx, %d/%d\n", cookie, i, ndbhp->ndbh_count);
9033 			error = EIO;
9034 		}
9035 		nfs_buf_release(bp, 1);
9036 	}
9037 out:
9038 	if (adnp) {
9039 		vnode_put(NFSTOV(adnp));
9040 	}
9041 out_free:
9042 	zfree(KT_NFS_VATTR, nvattr);
9043 	return NFS_MAPERR(error);
9044 }
9045 
9046 #if NAMEDSTREAMS
9047 int
nfs4_vnop_getnamedstream(struct vnop_getnamedstream_args * ap)9048 nfs4_vnop_getnamedstream(
9049 	struct vnop_getnamedstream_args /* {
9050                                          *  struct vnodeop_desc *a_desc;
9051                                          *  vnode_t a_vp;
9052                                          *  vnode_t *a_svpp;
9053                                          *  const char *a_name;
9054                                          *  enum nsoperation a_operation;
9055                                          *  int a_flags;
9056                                          *  vfs_context_t a_context;
9057                                          *  } */*ap)
9058 {
9059 	vfs_context_t ctx = ap->a_context;
9060 	struct nfsmount *nmp;
9061 	struct nfs_vattr *nvattr;
9062 	struct componentname cn;
9063 	nfsnode_t anp;
9064 	int error = 0;
9065 
9066 	nmp = VTONMP(ap->a_vp);
9067 	if (nfs_mount_gone(nmp)) {
9068 		return ENXIO;
9069 	}
9070 
9071 	if (!(nmp->nm_fsattr.nfsa_flags & NFS_FSFLAG_NAMED_ATTR)) {
9072 		return ENOTSUP;
9073 	}
9074 
9075 	nvattr = zalloc_flags(KT_NFS_VATTR, Z_WAITOK);
9076 	error = nfs_getattr(VTONFS(ap->a_vp), nvattr, ctx, NGA_CACHED);
9077 	if (error) {
9078 		goto out;
9079 	}
9080 	if (NFS_BITMAP_ISSET(nvattr->nva_bitmap, NFS_FATTR_NAMED_ATTR) &&
9081 	    !(nvattr->nva_flags & NFS_FFLAG_HAS_NAMED_ATTRS)) {
9082 		error = ENOATTR;
9083 		goto out;
9084 	}
9085 
9086 	bzero(&cn, sizeof(cn));
9087 	cn.cn_nameptr = __CAST_AWAY_QUALIFIER(ap->a_name, const, char *);
9088 	cn.cn_namelen = NFS_STRLEN_INT(ap->a_name);
9089 	cn.cn_nameiop = LOOKUP;
9090 	cn.cn_flags = MAKEENTRY;
9091 
9092 	error = nfs4_named_attr_get(VTONFS(ap->a_vp), &cn, NFS_OPEN_SHARE_ACCESS_NONE,
9093 	    0, ctx, &anp, NULL);
9094 	if ((!error && !anp) || (error == ENOENT)) {
9095 		error = ENOATTR;
9096 	}
9097 	if (!error && anp) {
9098 		*ap->a_svpp = NFSTOV(anp);
9099 	} else if (anp) {
9100 		vnode_put(NFSTOV(anp));
9101 	}
9102 out:
9103 	zfree(KT_NFS_VATTR, nvattr);
9104 	return NFS_MAPERR(error);
9105 }
9106 
9107 int
nfs4_vnop_makenamedstream(struct vnop_makenamedstream_args * ap)9108 nfs4_vnop_makenamedstream(
9109 	struct vnop_makenamedstream_args /* {
9110                                           *  struct vnodeop_desc *a_desc;
9111                                           *  vnode_t *a_svpp;
9112                                           *  vnode_t a_vp;
9113                                           *  const char *a_name;
9114                                           *  int a_flags;
9115                                           *  vfs_context_t a_context;
9116                                           *  } */*ap)
9117 {
9118 	vfs_context_t ctx = ap->a_context;
9119 	struct nfsmount *nmp;
9120 	struct componentname cn;
9121 	nfsnode_t anp;
9122 	int error = 0;
9123 
9124 	nmp = VTONMP(ap->a_vp);
9125 	if (nfs_mount_gone(nmp)) {
9126 		return ENXIO;
9127 	}
9128 
9129 	if (!(nmp->nm_fsattr.nfsa_flags & NFS_FSFLAG_NAMED_ATTR)) {
9130 		return ENOTSUP;
9131 	}
9132 
9133 	bzero(&cn, sizeof(cn));
9134 	cn.cn_nameptr = __CAST_AWAY_QUALIFIER(ap->a_name, const, char *);
9135 	cn.cn_namelen = NFS_STRLEN_INT(ap->a_name);
9136 	cn.cn_nameiop = CREATE;
9137 	cn.cn_flags = MAKEENTRY;
9138 
9139 	error = nfs4_named_attr_get(VTONFS(ap->a_vp), &cn, NFS_OPEN_SHARE_ACCESS_BOTH,
9140 	    NFS_GET_NAMED_ATTR_CREATE, ctx, &anp, NULL);
9141 	if ((!error && !anp) || (error == ENOENT)) {
9142 		error = ENOATTR;
9143 	}
9144 	if (!error && anp) {
9145 		*ap->a_svpp = NFSTOV(anp);
9146 	} else if (anp) {
9147 		vnode_put(NFSTOV(anp));
9148 	}
9149 	return NFS_MAPERR(error);
9150 }
9151 
9152 int
nfs4_vnop_removenamedstream(struct vnop_removenamedstream_args * ap)9153 nfs4_vnop_removenamedstream(
9154 	struct vnop_removenamedstream_args /* {
9155                                             *  struct vnodeop_desc *a_desc;
9156                                             *  vnode_t a_vp;
9157                                             *  vnode_t a_svp;
9158                                             *  const char *a_name;
9159                                             *  int a_flags;
9160                                             *  vfs_context_t a_context;
9161                                             *  } */*ap)
9162 {
9163 	int error;
9164 	struct nfsmount *nmp = VTONMP(ap->a_vp);
9165 	nfsnode_t np = ap->a_vp ? VTONFS(ap->a_vp) : NULL;
9166 	nfsnode_t anp = ap->a_svp ? VTONFS(ap->a_svp) : NULL;
9167 
9168 	if (nfs_mount_gone(nmp)) {
9169 		return ENXIO;
9170 	}
9171 
9172 	/*
9173 	 * Given that a_svp is a named stream, checking for
9174 	 * named attribute support is kinda pointless.
9175 	 */
9176 	if (!(nmp->nm_fsattr.nfsa_flags & NFS_FSFLAG_NAMED_ATTR)) {
9177 		return ENOTSUP;
9178 	}
9179 
9180 	error = nfs4_named_attr_remove(np, anp, ap->a_name, ap->a_context);
9181 	return NFS_MAPERR(error);
9182 }
9183 
9184 #endif
9185 #endif /* CONFIG_NFS4 */
9186 
9187 #endif /* CONFIG_NFS_CLIENT */
9188