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