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