2 * Copyright (c) 2006-2007 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
30 * vnode op calls for NFS version 4
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>
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>
48 #include <sys/signalvar.h>
49 #include <sys/uio_internal.h>
51 #include <vfs/vfs_support.h>
56 #include <kern/clock.h>
57 #include <libkern/OSAtomic.h>
59 #include <miscfs/fifofs/fifo.h>
60 #include <miscfs/specfs/specdev.h>
62 #include <nfs/rpcv2.h>
63 #include <nfs/nfsproto.h>
65 #include <nfs/nfsnode.h>
66 #include <nfs/nfs_gss.h>
67 #include <nfs/nfsmount.h>
68 #include <nfs/nfs_lock.h>
69 #include <nfs/xdr_subs.h>
70 #include <nfs/nfsm_subs.h>
73 #include <netinet/in.h>
74 #include <netinet/in_var.h>
75 #include <vm/vm_kern.h>
77 #include <kern/task.h>
78 #include <kern/sched_prim.h>
82 nfs4_access_rpc(nfsnode_t np
, u_long
*mode
, vfs_context_t ctx
)
84 int error
= 0, status
, numops
, slot
;
86 struct nfsm_chain nmreq
, nmrep
;
88 uint32_t access
, supported
= 0, missing
;
89 struct nfsmount
*nmp
= NFSTONMP(np
);
90 int nfsvers
= nmp
->nm_vers
;
93 nfsm_chain_null(&nmreq
);
94 nfsm_chain_null(&nmrep
);
96 numops
= 3; // PUTFH + ACCESS + GETATTR
97 nfsm_chain_build_alloc_init(error
, &nmreq
, 17 * NFSX_UNSIGNED
);
98 nfsm_chain_add_compound_header(error
, &nmreq
, "access", numops
);
100 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_PUTFH
);
101 nfsm_chain_add_fh(error
, &nmreq
, nfsvers
, np
->n_fhp
, np
->n_fhsize
);
103 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_ACCESS
);
104 nfsm_chain_add_32(error
, &nmreq
, *mode
);
106 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_GETATTR
);
107 nfsm_chain_add_bitmap_masked(error
, &nmreq
, nfs_getattr_bitmap
,
108 NFS_ATTR_BITMAP_LEN
, nmp
->nm_fsattr
.nfsa_supp_attr
);
109 nfsm_chain_build_done(error
, &nmreq
);
110 nfsm_assert(error
, (numops
== 0), EPROTO
);
112 error
= nfs_request(np
, NULL
, &nmreq
, NFSPROC4_COMPOUND
, ctx
, &nmrep
, &xid
, &status
);
114 nfsm_chain_skip_tag(error
, &nmrep
);
115 nfsm_chain_get_32(error
, &nmrep
, numops
);
116 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_PUTFH
);
117 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_ACCESS
);
118 nfsm_chain_get_32(error
, &nmrep
, supported
);
119 nfsm_chain_get_32(error
, &nmrep
, access
);
121 if ((missing
= (*mode
& ~supported
))) {
122 /* missing support for something(s) we wanted */
123 if (missing
& NFS_ACCESS_DELETE
) {
125 * If the server doesn't report DELETE (possible
126 * on UNIX systems), we'll assume that it is OK
127 * and just let any subsequent delete action fail
128 * if it really isn't deletable.
130 access
|= NFS_ACCESS_DELETE
;
133 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_GETATTR
);
134 nfsm_chain_loadattr(error
, &nmrep
, np
, nfsvers
, NULL
, &xid
);
137 uid
= kauth_cred_getuid(vfs_context_ucred(ctx
));
138 slot
= nfs_node_mode_slot(np
, uid
, 1);
139 np
->n_modeuid
[slot
] = uid
;
141 np
->n_modestamp
[slot
] = now
.tv_sec
;
142 np
->n_mode
[slot
] = access
;
144 /* pass back the mode returned with this request */
145 *mode
= np
->n_mode
[slot
];
147 nfsm_chain_cleanup(&nmreq
);
148 nfsm_chain_cleanup(&nmrep
);
159 struct nfs_vattr
*nvap
,
162 struct nfsmount
*nmp
= mp
? VFSTONFS(mp
) : NFSTONMP(np
);
163 int error
= 0, status
, nfsvers
, numops
;
164 struct nfsm_chain nmreq
, nmrep
;
168 nfsvers
= nmp
->nm_vers
;
170 nfsm_chain_null(&nmreq
);
171 nfsm_chain_null(&nmrep
);
173 numops
= 2; // PUTFH + GETATTR
174 nfsm_chain_build_alloc_init(error
, &nmreq
, 15 * NFSX_UNSIGNED
);
175 nfsm_chain_add_compound_header(error
, &nmreq
, "getattr", numops
);
177 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_PUTFH
);
178 nfsm_chain_add_fh(error
, &nmreq
, nfsvers
, fhp
, fhsize
);
180 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_GETATTR
);
181 nfsm_chain_add_bitmap_masked(error
, &nmreq
, nfs_getattr_bitmap
,
182 NFS_ATTR_BITMAP_LEN
, nmp
->nm_fsattr
.nfsa_supp_attr
);
183 nfsm_chain_build_done(error
, &nmreq
);
184 nfsm_assert(error
, (numops
== 0), EPROTO
);
186 error
= nfs_request(np
, mp
, &nmreq
, NFSPROC4_COMPOUND
, ctx
, &nmrep
, xidp
, &status
);
188 nfsm_chain_skip_tag(error
, &nmrep
);
189 nfsm_chain_get_32(error
, &nmrep
, numops
);
190 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_PUTFH
);
191 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_GETATTR
);
193 NFS_CLEAR_ATTRIBUTES(nvap
->nva_bitmap
);
194 error
= nfs4_parsefattr(&nmrep
, NULL
, nvap
, NULL
, NULL
);
196 nfsm_chain_cleanup(&nmreq
);
197 nfsm_chain_cleanup(&nmrep
);
202 nfs4_readlink_rpc(nfsnode_t np
, char *buf
, uint32_t *buflenp
, vfs_context_t ctx
)
204 struct nfsmount
*nmp
;
205 int error
= 0, lockerror
= ENOENT
, status
, numops
;
208 struct nfsm_chain nmreq
, nmrep
;
213 nfsm_chain_null(&nmreq
);
214 nfsm_chain_null(&nmrep
);
216 numops
= 3; // PUTFH + GETATTR + READLINK
217 nfsm_chain_build_alloc_init(error
, &nmreq
, 16 * NFSX_UNSIGNED
);
218 nfsm_chain_add_compound_header(error
, &nmreq
, "readlink", numops
);
220 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_PUTFH
);
221 nfsm_chain_add_fh(error
, &nmreq
, NFS_VER4
, np
->n_fhp
, np
->n_fhsize
);
223 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_GETATTR
);
224 nfsm_chain_add_bitmap_masked(error
, &nmreq
, nfs_getattr_bitmap
,
225 NFS_ATTR_BITMAP_LEN
, nmp
->nm_fsattr
.nfsa_supp_attr
);
227 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_READLINK
);
228 nfsm_chain_build_done(error
, &nmreq
);
229 nfsm_assert(error
, (numops
== 0), EPROTO
);
231 error
= nfs_request(np
, NULL
, &nmreq
, NFSPROC4_COMPOUND
, ctx
, &nmrep
, &xid
, &status
);
233 if ((lockerror
= nfs_lock(np
, NFS_NODE_LOCK_EXCLUSIVE
)))
235 nfsm_chain_skip_tag(error
, &nmrep
);
236 nfsm_chain_get_32(error
, &nmrep
, numops
);
237 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_PUTFH
);
238 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_GETATTR
);
239 nfsm_chain_loadattr(error
, &nmrep
, np
, NFS_VER4
, NULL
, &xid
);
240 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_READLINK
);
241 nfsm_chain_get_32(error
, &nmrep
, len
);
243 if (len
>= *buflenp
) {
244 if (np
->n_size
&& (np
->n_size
< *buflenp
))
249 nfsm_chain_get_opaque(error
, &nmrep
, len
, buf
);
255 nfsm_chain_cleanup(&nmreq
);
256 nfsm_chain_cleanup(&nmrep
);
267 struct nfsreq_cbinfo
*cb
,
268 struct nfsreq
**reqp
)
270 struct nfsmount
*nmp
;
271 int error
= 0, nfsvers
, numops
;
272 struct nfsm_chain nmreq
;
277 nfsvers
= nmp
->nm_vers
;
279 nfsm_chain_null(&nmreq
);
281 // PUTFH + READ + GETATTR
283 nfsm_chain_build_alloc_init(error
, &nmreq
, 22 * NFSX_UNSIGNED
);
284 nfsm_chain_add_compound_header(error
, &nmreq
, "read", numops
);
286 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_PUTFH
);
287 nfsm_chain_add_fh(error
, &nmreq
, nfsvers
, np
->n_fhp
, np
->n_fhsize
);
289 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_READ
);
291 /* XXX use special stateid for now */
292 nfsm_chain_add_32(error
, &nmreq
, 0xffffffff);
293 nfsm_chain_add_32(error
, &nmreq
, 0xffffffff);
294 nfsm_chain_add_32(error
, &nmreq
, 0xffffffff);
295 nfsm_chain_add_32(error
, &nmreq
, 0xffffffff);
297 nfsm_chain_add_64(error
, &nmreq
, offset
);
298 nfsm_chain_add_32(error
, &nmreq
, len
);
300 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_GETATTR
);
301 nfsm_chain_add_bitmap_masked(error
, &nmreq
, nfs_getattr_bitmap
,
302 NFS_ATTR_BITMAP_LEN
, nmp
->nm_fsattr
.nfsa_supp_attr
);
303 nfsm_chain_build_done(error
, &nmreq
);
304 nfsm_assert(error
, (numops
== 0), EPROTO
);
306 error
= nfs_request_async(np
, NULL
, &nmreq
, NFSPROC4_COMPOUND
, thd
, cred
, cb
, reqp
);
308 nfsm_chain_cleanup(&nmreq
);
313 nfs4_read_rpc_async_finish(
320 struct nfsmount
*nmp
;
321 int error
= 0, lockerror
, nfsvers
, numops
, status
, eof
= 0;
324 struct nfsm_chain nmrep
;
328 nfs_request_async_cancel(req
);
331 nfsvers
= nmp
->nm_vers
;
333 nfsm_chain_null(&nmrep
);
335 error
= nfs_request_async_finish(req
, &nmrep
, &xid
, &status
);
336 if (error
== EINPROGRESS
) /* async request restarted */
339 if ((lockerror
= nfs_lock(np
, NFS_NODE_LOCK_EXCLUSIVE
)))
341 nfsm_chain_skip_tag(error
, &nmrep
);
342 nfsm_chain_get_32(error
, &nmrep
, numops
);
343 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_PUTFH
);
344 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_READ
);
345 nfsm_chain_get_32(error
, &nmrep
, eof
);
346 nfsm_chain_get_32(error
, &nmrep
, retlen
);
348 *lenp
= MIN(retlen
, *lenp
);
349 error
= nfsm_chain_get_uio(&nmrep
, *lenp
, uiop
);
351 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_GETATTR
);
352 nfsm_chain_loadattr(error
, &nmrep
, np
, nfsvers
, NULL
, &xid
);
360 nfsm_chain_cleanup(&nmrep
);
365 nfs4_write_rpc_async(
372 struct nfsreq_cbinfo
*cb
,
373 struct nfsreq
**reqp
)
375 struct nfsmount
*nmp
;
376 int error
= 0, nfsvers
, numops
;
378 struct nfsm_chain nmreq
;
383 nfsvers
= nmp
->nm_vers
;
385 offset
= uiop
->uio_offset
;
387 nfsm_chain_null(&nmreq
);
389 // PUTFH + WRITE + GETATTR
391 nfsm_chain_build_alloc_init(error
, &nmreq
, 25 * NFSX_UNSIGNED
+ len
);
392 nfsm_chain_add_compound_header(error
, &nmreq
, "write", numops
);
394 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_PUTFH
);
395 nfsm_chain_add_fh(error
, &nmreq
, nfsvers
, np
->n_fhp
, np
->n_fhsize
);
397 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_WRITE
);
399 /* XXX use special stateid for now */
400 nfsm_chain_add_32(error
, &nmreq
, 0xffffffff);
401 nfsm_chain_add_32(error
, &nmreq
, 0xffffffff);
402 nfsm_chain_add_32(error
, &nmreq
, 0xffffffff);
403 nfsm_chain_add_32(error
, &nmreq
, 0xffffffff);
405 nfsm_chain_add_64(error
, &nmreq
, uiop
->uio_offset
);
406 nfsm_chain_add_32(error
, &nmreq
, iomode
);
407 nfsm_chain_add_32(error
, &nmreq
, len
);
409 error
= nfsm_chain_add_uio(&nmreq
, uiop
, len
);
411 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_GETATTR
);
412 nfsm_chain_add_bitmap_masked(error
, &nmreq
, nfs_getattr_bitmap
,
413 NFS_ATTR_BITMAP_LEN
, nmp
->nm_fsattr
.nfsa_supp_attr
);
414 nfsm_chain_build_done(error
, &nmreq
);
415 nfsm_assert(error
, (numops
== 0), EPROTO
);
418 error
= nfs_request_async(np
, NULL
, &nmreq
, NFSPROC4_COMPOUND
, thd
, cred
, cb
, reqp
);
420 nfsm_chain_cleanup(&nmreq
);
425 nfs4_write_rpc_async_finish(
432 struct nfsmount
*nmp
;
433 int error
= 0, lockerror
= ENOENT
, nfsvers
, numops
, status
;
434 int committed
= NFS_WRITE_FILESYNC
;
436 u_int64_t xid
, wverf
;
438 struct nfsm_chain nmrep
;
442 nfs_request_async_cancel(req
);
445 nfsvers
= nmp
->nm_vers
;
447 nfsm_chain_null(&nmrep
);
449 error
= nfs_request_async_finish(req
, &nmrep
, &xid
, &status
);
450 if (error
== EINPROGRESS
) /* async request restarted */
455 if (!error
&& (lockerror
= nfs_lock(np
, NFS_NODE_LOCK_EXCLUSIVE
)))
457 nfsm_chain_skip_tag(error
, &nmrep
);
458 nfsm_chain_get_32(error
, &nmrep
, numops
);
459 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_PUTFH
);
460 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_WRITE
);
461 nfsm_chain_get_32(error
, &nmrep
, rlen
);
466 nfsm_chain_get_32(error
, &nmrep
, committed
);
467 nfsm_chain_get_64(error
, &nmrep
, wverf
);
471 lck_mtx_lock(&nmp
->nm_lock
);
472 if (!(nmp
->nm_state
& NFSSTA_HASWRITEVERF
)) {
473 nmp
->nm_verf
= wverf
;
474 nmp
->nm_state
|= NFSSTA_HASWRITEVERF
;
475 } else if (nmp
->nm_verf
!= wverf
) {
476 nmp
->nm_verf
= wverf
;
478 lck_mtx_unlock(&nmp
->nm_lock
);
479 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_GETATTR
);
480 nfsm_chain_loadattr(error
, &nmrep
, np
, nfsvers
, NULL
, &xid
);
484 nfsm_chain_cleanup(&nmrep
);
485 if ((committed
!= NFS_WRITE_FILESYNC
) && nfs_allow_async
&&
486 ((mp
= NFSTOMP(np
))) && (vfs_flags(mp
) & MNT_ASYNC
))
487 committed
= NFS_WRITE_FILESYNC
;
488 *iomodep
= committed
;
500 int error
= 0, remove_error
= 0, status
;
501 struct nfsmount
*nmp
;
504 struct nfsm_chain nmreq
, nmrep
;
509 nfsvers
= nmp
->nm_vers
;
511 nfsm_chain_null(&nmreq
);
512 nfsm_chain_null(&nmrep
);
514 // PUTFH, REMOVE, GETATTR
516 nfsm_chain_build_alloc_init(error
, &nmreq
, 17 * NFSX_UNSIGNED
+ namelen
);
517 nfsm_chain_add_compound_header(error
, &nmreq
, "remove", numops
);
519 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_PUTFH
);
520 nfsm_chain_add_fh(error
, &nmreq
, nfsvers
, dnp
->n_fhp
, dnp
->n_fhsize
);
522 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_REMOVE
);
523 nfsm_chain_add_string(error
, &nmreq
, name
, namelen
);
525 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_GETATTR
);
526 nfsm_chain_add_bitmap_masked(error
, &nmreq
, nfs_getattr_bitmap
,
527 NFS_ATTR_BITMAP_LEN
, nmp
->nm_fsattr
.nfsa_supp_attr
);
528 nfsm_chain_build_done(error
, &nmreq
);
529 nfsm_assert(error
, (numops
== 0), EPROTO
);
532 error
= nfs_request2(dnp
, NULL
, &nmreq
, NFSPROC4_COMPOUND
, thd
, cred
, 0, &nmrep
, &xid
, &status
);
534 nfsm_chain_skip_tag(error
, &nmrep
);
535 nfsm_chain_get_32(error
, &nmrep
, numops
);
536 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_PUTFH
);
537 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_REMOVE
);
538 remove_error
= error
;
539 nfsm_chain_check_change_info(error
, &nmrep
, dnp
);
540 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_GETATTR
);
541 nfsm_chain_loadattr(error
, &nmrep
, dnp
, nfsvers
, NULL
, &xid
);
543 NATTRINVALIDATE(dnp
);
545 nfsm_chain_cleanup(&nmreq
);
546 nfsm_chain_cleanup(&nmrep
);
548 dnp
->n_flag
|= NMODIFIED
;
550 return (remove_error
);
563 int error
= 0, status
, nfsvers
, numops
;
564 struct nfsmount
*nmp
;
565 u_int64_t xid
, savedxid
;
566 struct nfsm_chain nmreq
, nmrep
;
568 nmp
= NFSTONMP(fdnp
);
571 nfsvers
= nmp
->nm_vers
;
573 nfsm_chain_null(&nmreq
);
574 nfsm_chain_null(&nmrep
);
576 // PUTFH(FROM), SAVEFH, PUTFH(TO), RENAME, GETATTR(TO), RESTOREFH, GETATTR(FROM)
578 nfsm_chain_build_alloc_init(error
, &nmreq
, 30 * NFSX_UNSIGNED
+ fnamelen
+ tnamelen
);
579 nfsm_chain_add_compound_header(error
, &nmreq
, "rename", numops
);
581 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_PUTFH
);
582 nfsm_chain_add_fh(error
, &nmreq
, nfsvers
, fdnp
->n_fhp
, fdnp
->n_fhsize
);
584 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_SAVEFH
);
586 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_PUTFH
);
587 nfsm_chain_add_fh(error
, &nmreq
, nfsvers
, tdnp
->n_fhp
, tdnp
->n_fhsize
);
589 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_RENAME
);
590 nfsm_chain_add_string(error
, &nmreq
, fnameptr
, fnamelen
);
591 nfsm_chain_add_string(error
, &nmreq
, tnameptr
, tnamelen
);
593 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_GETATTR
);
594 nfsm_chain_add_bitmap_masked(error
, &nmreq
, nfs_getattr_bitmap
,
595 NFS_ATTR_BITMAP_LEN
, nmp
->nm_fsattr
.nfsa_supp_attr
);
597 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_RESTOREFH
);
599 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_GETATTR
);
600 nfsm_chain_add_bitmap_masked(error
, &nmreq
, nfs_getattr_bitmap
,
601 NFS_ATTR_BITMAP_LEN
, nmp
->nm_fsattr
.nfsa_supp_attr
);
602 nfsm_chain_build_done(error
, &nmreq
);
603 nfsm_assert(error
, (numops
== 0), EPROTO
);
606 error
= nfs_request(fdnp
, NULL
, &nmreq
, NFSPROC4_COMPOUND
, ctx
, &nmrep
, &xid
, &status
);
608 nfsm_chain_skip_tag(error
, &nmrep
);
609 nfsm_chain_get_32(error
, &nmrep
, numops
);
610 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_PUTFH
);
611 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_SAVEFH
);
612 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_PUTFH
);
613 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_RENAME
);
614 nfsm_chain_check_change_info(error
, &nmrep
, fdnp
);
615 nfsm_chain_check_change_info(error
, &nmrep
, tdnp
);
616 /* directory attributes: if we don't get them, make sure to invalidate */
617 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_GETATTR
);
619 nfsm_chain_loadattr(error
, &nmrep
, tdnp
, nfsvers
, NULL
, &xid
);
621 NATTRINVALIDATE(tdnp
);
622 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_RESTOREFH
);
623 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_GETATTR
);
625 nfsm_chain_loadattr(error
, &nmrep
, fdnp
, nfsvers
, NULL
, &xid
);
627 NATTRINVALIDATE(fdnp
);
629 nfsm_chain_cleanup(&nmreq
);
630 nfsm_chain_cleanup(&nmrep
);
631 fdnp
->n_flag
|= NMODIFIED
;
632 tdnp
->n_flag
|= NMODIFIED
;
633 /* Kludge: Map EEXIST => 0 assuming that it is a reply to a retry. */
640 * NFS V4 readdir RPC.
642 #define DIRHDSIZ ((int)(sizeof(struct dirent) - (MAXNAMLEN + 1)))
644 nfs4_readdir_rpc(nfsnode_t dnp
, struct uio
*uiop
, vfs_context_t ctx
)
646 size_t len
, tlen
, skiplen
, left
;
647 struct dirent
*dp
= NULL
;
650 struct componentname cn
, *cnp
= &cn
;
652 struct nfsmount
*nmp
;
654 int error
= 0, lockerror
, status
, more_entries
= 1, blksiz
= 0, bigenough
= 1;
655 int nfsvers
, rdirplus
, nmreaddirsize
, nmrsize
, eof
, i
, numops
;
656 u_int64_t xid
, savexid
;
657 struct nfs_vattr nvattr
;
658 struct nfsm_chain nmreq
, nmrep
;
661 uint32_t entry_attrs
[NFS_ATTR_BITMAP_LEN
];
665 /* XXX limitation based on need to adjust uio */
666 if (uiop
->uio_iovcnt
!= 1 || (uiop
->uio_offset
& (DIRBLKSIZ
- 1)) ||
667 (uio_uio_resid(uiop
) & (DIRBLKSIZ
- 1)))
668 panic("nfs4_readdir_rpc: bad uio");
673 nfsvers
= nmp
->nm_vers
;
674 nmreaddirsize
= nmp
->nm_readdirsize
;
675 nmrsize
= nmp
->nm_rsize
;
676 rdirplus
= (nmp
->nm_flag
& NFSMNT_RDIRPLUS
) ? 1 : 0;
678 bzero(cnp
, sizeof(*cnp
));
682 * Set up attribute request for entries.
683 * For READDIRPLUS functionality, get everything.
684 * Otherwise, just get what we need for struct dirent.
688 for (i
=0; i
< NFS_ATTR_BITMAP_LEN
; i
++)
690 nfs_getattr_bitmap
[i
] &
691 nmp
->nm_fsattr
.nfsa_supp_attr
[i
];
692 NFS_BITMAP_SET(entry_attrs
, NFS_FATTR_FILEHANDLE
);
695 NFS_CLEAR_ATTRIBUTES(entry_attrs
);
696 NFS_BITMAP_SET(entry_attrs
, NFS_FATTR_TYPE
);
697 NFS_BITMAP_SET(entry_attrs
, NFS_FATTR_FILEID
);
699 /* XXX NFS_BITMAP_SET(entry_attrs, NFS_FATTR_MOUNTED_ON_FILEID); */
700 NFS_BITMAP_SET(entry_attrs
, NFS_FATTR_RDATTR_ERROR
);
702 if ((lockerror
= nfs_lock(dnp
, NFS_NODE_LOCK_SHARED
)))
706 * If there is no cookie, assume directory was stale.
708 cookiep
= nfs_getcookie(dnp
, uiop
->uio_offset
, 0);
713 return (NFSERR_BAD_COOKIE
);
717 * The NFS client is responsible for the "." and ".."
718 * entries in the directory. So, we put them at the top.
720 if ((uiop
->uio_offset
== 0) &&
721 ((2*(4 + DIRHDSIZ
)) <= uio_uio_resid(uiop
))) {
724 tlen
= nfsm_rndup(len
);
725 // LP64todo - fix this!
726 dp
= (struct dirent
*) CAST_DOWN(caddr_t
, uio_iov_base(uiop
));
727 dp
->d_fileno
= dnp
->n_vattr
.nva_fileid
;
729 dp
->d_reclen
= tlen
+ DIRHDSIZ
;
731 strlcpy(dp
->d_name
, ".", len
);
732 blksiz
+= dp
->d_reclen
;
733 if (blksiz
== DIRBLKSIZ
)
735 uiop
->uio_offset
+= DIRHDSIZ
+ tlen
;
736 uio_iov_base_add(uiop
, DIRHDSIZ
+ tlen
);
737 uio_uio_resid_add(uiop
, -(DIRHDSIZ
+ tlen
));
738 uio_iov_len_add(uiop
, -(DIRHDSIZ
+ tlen
));
741 tlen
= nfsm_rndup(len
);
742 // LP64todo - fix this!
743 dp
= (struct dirent
*) CAST_DOWN(caddr_t
, uio_iov_base(uiop
));
745 dp
->d_fileno
= VTONFS(dnp
->n_parent
)->n_vattr
.nva_fileid
;
747 dp
->d_fileno
= dnp
->n_vattr
.nva_fileid
;
749 dp
->d_reclen
= tlen
+ DIRHDSIZ
;
751 strlcpy(dp
->d_name
, "..", len
);
752 blksiz
+= dp
->d_reclen
;
753 if (blksiz
== DIRBLKSIZ
)
755 uiop
->uio_offset
+= DIRHDSIZ
+ tlen
;
756 uio_iov_base_add(uiop
, DIRHDSIZ
+ tlen
);
757 uio_uio_resid_add(uiop
, -(DIRHDSIZ
+ tlen
));
758 uio_iov_len_add(uiop
, -(DIRHDSIZ
+ tlen
));
759 cookie
.nfsuquad
[0] = 0;
760 cookie
.nfsuquad
[1] = 2;
764 * Loop around doing readdir rpc's of size nm_readdirsize
765 * truncated to a multiple of DIRBLKSIZ.
766 * The stopping criteria is EOF or buffer full.
768 while (more_entries
&& bigenough
) {
769 nfsm_chain_null(&nmreq
);
770 nfsm_chain_null(&nmrep
);
771 nfsm_assert(error
, NFSTONMP(dnp
), ENXIO
);
773 numops
= 3; // PUTFH + GETATTR + READDIR
774 nfsm_chain_build_alloc_init(error
, &nmreq
, 26 * NFSX_UNSIGNED
);
775 nfsm_chain_add_compound_header(error
, &nmreq
, tag
, numops
);
777 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_PUTFH
);
778 nfsm_chain_add_fh(error
, &nmreq
, nfsvers
, dnp
->n_fhp
, dnp
->n_fhsize
);
780 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_GETATTR
);
781 nfsm_chain_add_bitmap_masked(error
, &nmreq
, nfs_getattr_bitmap
,
782 NFS_ATTR_BITMAP_LEN
, nmp
->nm_fsattr
.nfsa_supp_attr
);
784 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_READDIR
);
785 /* opaque values don't need swapping, but as long */
786 /* as we are consistent about it, it should be ok */
787 nfsm_chain_add_32(error
, &nmreq
, cookie
.nfsuquad
[0]);
788 if ((cookie
.nfsuquad
[0] == 0) && (cookie
.nfsuquad
[1] <= 2))
789 nfsm_chain_add_32(error
, &nmreq
, 0);
791 nfsm_chain_add_32(error
, &nmreq
, cookie
.nfsuquad
[1]);
792 nfsm_chain_add_32(error
, &nmreq
, dnp
->n_cookieverf
.nfsuquad
[0]);
793 nfsm_chain_add_32(error
, &nmreq
, dnp
->n_cookieverf
.nfsuquad
[1]);
794 nfsm_chain_add_32(error
, &nmreq
, nmreaddirsize
);
795 nfsm_chain_add_32(error
, &nmreq
, nmrsize
);
796 nfsm_chain_add_bitmap(error
, &nmreq
, entry_attrs
, NFS_ATTR_BITMAP_LEN
);
797 nfsm_chain_build_done(error
, &nmreq
);
798 nfsm_assert(error
, (numops
== 0), EPROTO
);
801 error
= nfs_request(dnp
, NULL
, &nmreq
, NFSPROC4_COMPOUND
, ctx
, &nmrep
, &xid
, &status
);
803 if ((lockerror
= nfs_lock(dnp
, NFS_NODE_LOCK_EXCLUSIVE
)))
806 nfsm_chain_skip_tag(error
, &nmrep
);
807 nfsm_chain_get_32(error
, &nmrep
, numops
);
808 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_PUTFH
);
809 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_GETATTR
);
810 nfsm_chain_loadattr(error
, &nmrep
, dnp
, nfsvers
, NULL
, &xid
);
811 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_READDIR
);
812 nfsm_chain_get_32(error
, &nmrep
, dnp
->n_cookieverf
.nfsuquad
[0]);
813 nfsm_chain_get_32(error
, &nmrep
, dnp
->n_cookieverf
.nfsuquad
[1]);
814 nfsm_chain_get_32(error
, &nmrep
, more_entries
);
818 /* Loop through the entries, massaging them into "dirent" form. */
819 /* If READDIRPLUS, also create the vnodes. */
820 while (more_entries
&& bigenough
) {
821 /* Entry: COOKIE, NAME, FATTR */
822 nfsm_chain_get_32(error
, &nmrep
, cookie
.nfsuquad
[0]);
823 nfsm_chain_get_32(error
, &nmrep
, cookie
.nfsuquad
[1]);
824 nfsm_chain_get_32(error
, &nmrep
, len
);
826 /* Note: NFS supports longer names, but struct dirent doesn't */
827 /* so we just truncate the names to fit */
832 if (len
> MAXNAMLEN
) {
833 skiplen
= len
- MAXNAMLEN
;
838 tlen
= nfsm_rndup(len
);
840 tlen
+= 4; /* To ensure null termination */
841 left
= DIRBLKSIZ
- blksiz
;
842 if ((tlen
+ DIRHDSIZ
) > left
) {
843 dp
->d_reclen
+= left
;
844 uio_iov_base_add(uiop
, left
);
845 uio_iov_len_add(uiop
, -left
);
846 uiop
->uio_offset
+= left
;
847 uio_uio_resid_add(uiop
, -left
);
850 if ((tlen
+ DIRHDSIZ
) > uio_uio_resid(uiop
)) {
854 // LP64todo - fix this!
855 dp
= (struct dirent
*) CAST_DOWN(caddr_t
, uio_iov_base(uiop
));
858 dp
->d_reclen
= tlen
+ DIRHDSIZ
;
859 dp
->d_type
= DT_UNKNOWN
;
860 blksiz
+= dp
->d_reclen
;
861 if (blksiz
== DIRBLKSIZ
)
863 uiop
->uio_offset
+= DIRHDSIZ
;
865 uio_uio_resid_add(uiop
, -((int64_t)DIRHDSIZ
));
866 uio_iov_len_add(uiop
, -((int64_t)DIRHDSIZ
));
868 uio_uio_resid_add(uiop
, -((int)DIRHDSIZ
));
869 uio_iov_len_add(uiop
, -((int)DIRHDSIZ
));
871 uio_iov_base_add(uiop
, DIRHDSIZ
);
872 // LP64todo - fix this!
873 cnp
->cn_nameptr
= CAST_DOWN(caddr_t
, uio_iov_base(uiop
));
874 cnp
->cn_namelen
= len
;
875 error
= nfsm_chain_get_uio(&nmrep
, len
, uiop
);
877 nfsm_chain_adv(error
, &nmrep
,
878 nfsm_rndup(len
+ skiplen
) - nfsm_rndup(len
));
880 NFS_CLEAR_ATTRIBUTES(nvattr
.nva_bitmap
);
881 error
= nfs4_parsefattr(&nmrep
, NULL
, &nvattr
, &fh
, NULL
);
882 if (error
&& NFS_BITMAP_ISSET(nvattr
.nva_bitmap
, NFS_FATTR_RDATTR_ERROR
)) {
883 /* OK, we didn't get attributes, whatever... */
884 NFS_CLEAR_ATTRIBUTES(nvattr
.nva_bitmap
);
887 nfsm_chain_get_32(error
, &nmrep
, more_entries
);
890 cp
= CAST_DOWN(caddr_t
, uio_iov_base(uiop
));
893 uio_iov_base_add(uiop
, tlen
);
894 uio_iov_len_add(uiop
, -tlen
);
895 uiop
->uio_offset
+= tlen
;
896 uio_uio_resid_add(uiop
, -tlen
);
899 * Skip any "." and ".." entries returned from server.
900 * (Actually, just leave it in place with d_fileno == 0.)
902 if ((cnp
->cn_nameptr
[0] == '.') &&
903 ((len
== 1) || ((len
== 2) && (cnp
->cn_nameptr
[1] == '.')))) {
904 /* clear the name too */
906 dp
->d_name
[0] = '\0';
910 if (NFS_BITMAP_ISSET(nvattr
.nva_bitmap
, NFS_FATTR_TYPE
))
911 dp
->d_type
= IFTODT(VTTOIF(nvattr
.nva_type
));
912 if (NFS_BITMAP_ISSET(nvattr
.nva_bitmap
, NFS_FATTR_FILEID
))
913 dp
->d_fileno
= (int)nvattr
.nva_fileid
;
914 if (rdirplus
&& NFS_BITMAP_ISSET(nvattr
.nva_bitmap
, NFS_FATTR_FILEHANDLE
) &&
915 !NFS_CMPFH(dnp
, fh
.fh_data
, fh
.fh_len
)) {
917 error
= nfs_nget(NFSTOMP(dnp
), dnp
, cnp
,
918 fh
.fh_data
, fh
.fh_len
, &nvattr
, &xid
, NG_MAKEENTRY
, &np
);
921 vnode_put(NFSTOV(np
));
926 /* If at end of rpc data, get the eof boolean */
928 nfsm_chain_get_32(error
, &nmrep
, eof
);
930 more_entries
= (eof
== 0);
932 if ((lockerror
= nfs_lock(dnp
, NFS_NODE_LOCK_SHARED
)))
935 nfsm_chain_cleanup(&nmrep
);
939 * Fill last record, iff any, out to a multiple of DIRBLKSIZ
940 * by increasing d_reclen for the last record.
943 left
= DIRBLKSIZ
- blksiz
;
944 dp
->d_reclen
+= left
;
945 uio_iov_base_add(uiop
, left
);
946 uio_iov_len_add(uiop
, -left
);
947 uiop
->uio_offset
+= left
;
948 uio_uio_resid_add(uiop
, -left
);
951 if ((lockerror
= nfs_lock(dnp
, NFS_NODE_LOCK_EXCLUSIVE
)))
956 * We are now either at the end of the directory or have filled the
960 dnp
->n_direofoffset
= uiop
->uio_offset
;
962 if (uio_uio_resid(uiop
) > 0)
963 printf("EEK! nfs4_readdir_rpc resid > 0\n");
964 cookiep
= nfs_getcookie(dnp
, uiop
->uio_offset
, 1);
971 nfsm_chain_cleanup(&nmreq
);
972 nfsm_chain_cleanup(&nmrep
);
977 nfs4_lookup_rpc_async(
982 struct nfsreq
**reqp
)
984 int error
= 0, isdotdot
= 0, getattrs
= 1, nfsvers
, numops
;
985 struct nfsm_chain nmreq
;
986 uint32_t bitmap
[NFS_ATTR_BITMAP_LEN
];
987 struct nfsmount
*nmp
;
992 nfsvers
= nmp
->nm_vers
;
994 if ((name
[0] == '.') && (name
[1] == '.') && (namelen
== 2))
997 nfsm_chain_null(&nmreq
);
999 // PUTFH, GETATTR, LOOKUP(P), GETATTR (FH)
1000 numops
= getattrs
? 4 : 3;
1001 nfsm_chain_build_alloc_init(error
, &nmreq
, 20 * NFSX_UNSIGNED
+ namelen
);
1002 nfsm_chain_add_compound_header(error
, &nmreq
, "lookup", numops
);
1004 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_PUTFH
);
1005 nfsm_chain_add_fh(error
, &nmreq
, nfsvers
, dnp
->n_fhp
, dnp
->n_fhsize
);
1007 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_GETATTR
);
1008 nfsm_chain_add_bitmap_masked(error
, &nmreq
, nfs_getattr_bitmap
,
1009 NFS_ATTR_BITMAP_LEN
, nmp
->nm_fsattr
.nfsa_supp_attr
);
1012 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_LOOKUPP
);
1014 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_LOOKUP
);
1015 nfsm_chain_add_string(error
, &nmreq
, name
, namelen
);
1019 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_GETATTR
);
1020 NFS_COPY_ATTRIBUTES(nfs_getattr_bitmap
, bitmap
);
1021 NFS_BITMAP_SET(bitmap
, NFS_FATTR_FILEHANDLE
);
1022 nfsm_chain_add_bitmap_masked(error
, &nmreq
, bitmap
,
1023 NFS_ATTR_BITMAP_LEN
, nmp
->nm_fsattr
.nfsa_supp_attr
);
1025 nfsm_chain_build_done(error
, &nmreq
);
1026 nfsm_assert(error
, (numops
== 0), EPROTO
);
1028 error
= nfs_request_async(dnp
, NULL
, &nmreq
, NFSPROC4_COMPOUND
,
1029 vfs_context_thread(ctx
), vfs_context_ucred(ctx
), NULL
, reqp
);
1031 nfsm_chain_cleanup(&nmreq
);
1036 nfs4_lookup_rpc_async_finish(
1038 __unused vfs_context_t ctx
,
1042 struct nfs_vattr
*nvap
)
1044 int error
= 0, status
, nfsvers
, numops
;
1047 struct nfsmount
*nmp
;
1048 struct nfsm_chain nmrep
;
1050 nmp
= NFSTONMP(dnp
);
1051 nfsvers
= nmp
->nm_vers
;
1053 nfsm_chain_null(&nmrep
);
1055 error
= nfs_request_async_finish(req
, &nmrep
, &xid
, &status
);
1057 nfsm_chain_skip_tag(error
, &nmrep
);
1058 nfsm_chain_get_32(error
, &nmrep
, numops
);
1059 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_PUTFH
);
1060 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_GETATTR
);
1063 nfsm_chain_loadattr(error
, &nmrep
, dnp
, nfsvers
, NULL
, &xid
);
1065 // nfsm_chain_op_check(error, &nmrep, (isdotdot ? NFS_OP_LOOKUPP : NFS_OP_LOOKUP));
1066 nfsm_chain_get_32(error
, &nmrep
, val
);
1067 nfsm_assert(error
, (val
== NFS_OP_LOOKUPP
) || (val
== NFS_OP_LOOKUP
), EBADRPC
);
1068 nfsm_chain_get_32(error
, &nmrep
, val
);
1069 nfsm_assert(error
, (val
== NFS_OK
), val
);
1071 nfsmout_if(error
|| !fhp
|| !nvap
);
1072 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_GETATTR
);
1074 NFS_CLEAR_ATTRIBUTES(nvap
->nva_bitmap
);
1075 error
= nfs4_parsefattr(&nmrep
, NULL
, nvap
, fhp
, NULL
);
1076 if (!NFS_BITMAP_ISSET(nvap
->nva_bitmap
, NFS_FATTR_FILEHANDLE
)) {
1081 nfsm_chain_cleanup(&nmrep
);
1092 struct nfsmount
*nmp
;
1093 int error
= 0, lockerror
, status
, nfsvers
, numops
;
1094 u_int64_t xid
, wverf
;
1096 struct nfsm_chain nmreq
, nmrep
;
1099 FSDBG(521, np
, offset
, count
, nmp
? nmp
->nm_state
: 0);
1102 if (!(nmp
->nm_state
& NFSSTA_HASWRITEVERF
))
1104 nfsvers
= nmp
->nm_vers
;
1106 if (count
> UINT32_MAX
)
1111 nfsm_chain_null(&nmreq
);
1112 nfsm_chain_null(&nmrep
);
1114 // PUTFH, COMMIT, GETATTR
1116 nfsm_chain_build_alloc_init(error
, &nmreq
, 19 * NFSX_UNSIGNED
);
1117 nfsm_chain_add_compound_header(error
, &nmreq
, "commit", numops
);
1119 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_PUTFH
);
1120 nfsm_chain_add_fh(error
, &nmreq
, nfsvers
, np
->n_fhp
, np
->n_fhsize
);
1122 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_COMMIT
);
1123 nfsm_chain_add_64(error
, &nmreq
, offset
);
1124 nfsm_chain_add_32(error
, &nmreq
, count32
);
1126 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_GETATTR
);
1127 nfsm_chain_add_bitmap_masked(error
, &nmreq
, nfs_getattr_bitmap
,
1128 NFS_ATTR_BITMAP_LEN
, nmp
->nm_fsattr
.nfsa_supp_attr
);
1129 nfsm_chain_build_done(error
, &nmreq
);
1130 nfsm_assert(error
, (numops
== 0), EPROTO
);
1132 error
= nfs_request2(np
, NULL
, &nmreq
, NFSPROC4_COMPOUND
,
1133 current_thread(), cred
, 0, &nmrep
, &xid
, &status
);
1135 if ((lockerror
= nfs_lock(np
, NFS_NODE_LOCK_EXCLUSIVE
)))
1137 nfsm_chain_skip_tag(error
, &nmrep
);
1138 nfsm_chain_get_32(error
, &nmrep
, numops
);
1139 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_PUTFH
);
1140 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_COMMIT
);
1141 nfsm_chain_get_64(error
, &nmrep
, wverf
);
1142 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_GETATTR
);
1143 nfsm_chain_loadattr(error
, &nmrep
, np
, nfsvers
, NULL
, &xid
);
1147 lck_mtx_lock(&nmp
->nm_lock
);
1148 if (nmp
->nm_verf
!= wverf
) {
1149 nmp
->nm_verf
= wverf
;
1150 error
= NFSERR_STALEWRITEVERF
;
1152 lck_mtx_unlock(&nmp
->nm_lock
);
1154 nfsm_chain_cleanup(&nmreq
);
1155 nfsm_chain_cleanup(&nmrep
);
1162 struct nfs_fsattr
*nfsap
,
1166 int error
= 0, lockerror
, status
, nfsvers
, numops
;
1167 struct nfsm_chain nmreq
, nmrep
;
1168 struct nfsmount
*nmp
= NFSTONMP(np
);
1169 uint32_t bitmap
[NFS_ATTR_BITMAP_LEN
];
1170 struct nfs_vattr nvattr
;
1174 nfsvers
= nmp
->nm_vers
;
1176 nfsm_chain_null(&nmreq
);
1177 nfsm_chain_null(&nmrep
);
1179 /* NFSv4: fetch "pathconf" info for this node */
1180 numops
= 2; // PUTFH + GETATTR
1181 nfsm_chain_build_alloc_init(error
, &nmreq
, 16 * NFSX_UNSIGNED
);
1182 nfsm_chain_add_compound_header(error
, &nmreq
, "pathconf", numops
);
1184 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_PUTFH
);
1185 nfsm_chain_add_fh(error
, &nmreq
, nfsvers
, np
->n_fhp
, np
->n_fhsize
);
1187 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_GETATTR
);
1188 NFS_COPY_ATTRIBUTES(nfs_getattr_bitmap
, bitmap
);
1189 NFS_BITMAP_SET(bitmap
, NFS_FATTR_MAXLINK
);
1190 NFS_BITMAP_SET(bitmap
, NFS_FATTR_MAXNAME
);
1191 NFS_BITMAP_SET(bitmap
, NFS_FATTR_NO_TRUNC
);
1192 NFS_BITMAP_SET(bitmap
, NFS_FATTR_CHOWN_RESTRICTED
);
1193 NFS_BITMAP_SET(bitmap
, NFS_FATTR_CASE_INSENSITIVE
);
1194 NFS_BITMAP_SET(bitmap
, NFS_FATTR_CASE_PRESERVING
);
1195 nfsm_chain_add_bitmap_masked(error
, &nmreq
, bitmap
,
1196 NFS_ATTR_BITMAP_LEN
, nmp
->nm_fsattr
.nfsa_supp_attr
);
1197 nfsm_chain_build_done(error
, &nmreq
);
1198 nfsm_assert(error
, (numops
== 0), EPROTO
);
1200 error
= nfs_request(np
, NULL
, &nmreq
, NFSPROC4_COMPOUND
, ctx
, &nmrep
, &xid
, &status
);
1202 nfsm_chain_skip_tag(error
, &nmrep
);
1203 nfsm_chain_get_32(error
, &nmrep
, numops
);
1204 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_PUTFH
);
1205 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_GETATTR
);
1207 NFS_CLEAR_ATTRIBUTES(nvattr
.nva_bitmap
);
1208 error
= nfs4_parsefattr(&nmrep
, nfsap
, &nvattr
, NULL
, NULL
);
1210 if ((lockerror
= nfs_lock(np
, NFS_NODE_LOCK_EXCLUSIVE
)))
1212 nfs_loadattrcache(np
, &nvattr
, &xid
, 0);
1216 nfsm_chain_cleanup(&nmreq
);
1217 nfsm_chain_cleanup(&nmrep
);
1223 struct vnop_getattr_args
/* {
1224 struct vnodeop_desc *a_desc;
1226 struct vnode_attr *a_vap;
1227 vfs_context_t a_context;
1230 struct vnode_attr
*vap
= ap
->a_vap
;
1231 struct nfs_vattr nva
;
1234 error
= nfs_getattr(VTONFS(ap
->a_vp
), &nva
, ap
->a_context
, 0);
1238 /* copy what we have in nva to *a_vap */
1239 if (NFS_BITMAP_ISSET(nva
.nva_bitmap
, NFS_FATTR_RAWDEV
)) {
1240 dev_t rdev
= makedev(nva
.nva_rawdev
.specdata1
, nva
.nva_rawdev
.specdata2
);
1241 VATTR_RETURN(vap
, va_rdev
, rdev
);
1243 if (NFS_BITMAP_ISSET(nva
.nva_bitmap
, NFS_FATTR_NUMLINKS
))
1244 VATTR_RETURN(vap
, va_nlink
, nva
.nva_nlink
);
1245 if (NFS_BITMAP_ISSET(nva
.nva_bitmap
, NFS_FATTR_SIZE
))
1246 VATTR_RETURN(vap
, va_data_size
, nva
.nva_size
);
1247 // VATTR_RETURN(vap, va_data_alloc, ???);
1248 // VATTR_RETURN(vap, va_total_size, ???);
1249 if (NFS_BITMAP_ISSET(nva
.nva_bitmap
, NFS_FATTR_SPACE_USED
))
1250 VATTR_RETURN(vap
, va_total_alloc
, nva
.nva_bytes
);
1251 if (NFS_BITMAP_ISSET(nva
.nva_bitmap
, NFS_FATTR_OWNER
))
1252 VATTR_RETURN(vap
, va_uid
, nva
.nva_uid
);
1253 if (NFS_BITMAP_ISSET(nva
.nva_bitmap
, NFS_FATTR_OWNER_GROUP
))
1254 VATTR_RETURN(vap
, va_gid
, nva
.nva_gid
);
1255 if (NFS_BITMAP_ISSET(nva
.nva_bitmap
, NFS_FATTR_MODE
))
1256 VATTR_RETURN(vap
, va_mode
, nva
.nva_mode
);
1257 if (NFS_BITMAP_ISSET(nva
.nva_bitmap
, NFS_FATTR_ARCHIVE
) ||
1258 NFS_BITMAP_ISSET(nva
.nva_bitmap
, NFS_FATTR_HIDDEN
)) {
1260 if (NFS_BITMAP_ISSET(nva
.nva_bitmap
, NFS_FATTR_ARCHIVE
))
1261 flags
|= SF_ARCHIVED
;
1262 if (NFS_BITMAP_ISSET(nva
.nva_bitmap
, NFS_FATTR_HIDDEN
))
1264 VATTR_RETURN(vap
, va_flags
, flags
);
1266 if (NFS_BITMAP_ISSET(nva
.nva_bitmap
, NFS_FATTR_TIME_CREATE
)) {
1267 vap
->va_create_time
.tv_sec
= nva
.nva_timesec
[NFSTIME_CREATE
];
1268 vap
->va_create_time
.tv_nsec
= nva
.nva_timensec
[NFSTIME_CREATE
];
1269 VATTR_SET_SUPPORTED(vap
, va_create_time
);
1271 if (NFS_BITMAP_ISSET(nva
.nva_bitmap
, NFS_FATTR_TIME_ACCESS
)) {
1272 vap
->va_access_time
.tv_sec
= nva
.nva_timesec
[NFSTIME_ACCESS
];
1273 vap
->va_access_time
.tv_nsec
= nva
.nva_timensec
[NFSTIME_ACCESS
];
1274 VATTR_SET_SUPPORTED(vap
, va_access_time
);
1276 if (NFS_BITMAP_ISSET(nva
.nva_bitmap
, NFS_FATTR_TIME_MODIFY
)) {
1277 vap
->va_modify_time
.tv_sec
= nva
.nva_timesec
[NFSTIME_MODIFY
];
1278 vap
->va_modify_time
.tv_nsec
= nva
.nva_timensec
[NFSTIME_MODIFY
];
1279 VATTR_SET_SUPPORTED(vap
, va_modify_time
);
1281 if (NFS_BITMAP_ISSET(nva
.nva_bitmap
, NFS_FATTR_TIME_METADATA
)) {
1282 vap
->va_change_time
.tv_sec
= nva
.nva_timesec
[NFSTIME_CHANGE
];
1283 vap
->va_change_time
.tv_nsec
= nva
.nva_timensec
[NFSTIME_CHANGE
];
1284 VATTR_SET_SUPPORTED(vap
, va_change_time
);
1286 if (NFS_BITMAP_ISSET(nva
.nva_bitmap
, NFS_FATTR_TIME_BACKUP
)) {
1287 vap
->va_backup_time
.tv_sec
= nva
.nva_timesec
[NFSTIME_BACKUP
];
1288 vap
->va_backup_time
.tv_nsec
= nva
.nva_timensec
[NFSTIME_BACKUP
];
1289 VATTR_SET_SUPPORTED(vap
, va_backup_time
);
1291 if (NFS_BITMAP_ISSET(nva
.nva_bitmap
, NFS_FATTR_FILEID
))
1292 VATTR_RETURN(vap
, va_fileid
, nva
.nva_fileid
);
1293 if (NFS_BITMAP_ISSET(nva
.nva_bitmap
, NFS_FATTR_TYPE
))
1294 VATTR_RETURN(vap
, va_type
, nva
.nva_type
);
1295 if (NFS_BITMAP_ISSET(nva
.nva_bitmap
, NFS_FATTR_CHANGE
))
1296 VATTR_RETURN(vap
, va_filerev
, nva
.nva_change
);
1298 // other attrs we might support someday:
1299 // VATTR_RETURN(vap, va_encoding, ??? /* potentially unnormalized UTF-8? */);
1300 // struct kauth_acl *va_acl; /* access control list */
1301 // guid_t va_uuuid; /* file owner UUID */
1302 // guid_t va_guuid; /* file group UUID */
1310 struct vnode_attr
*vap
,
1314 struct nfsmount
*nmp
= NFSTONMP(np
);
1315 int error
= 0, lockerror
= ENOENT
, status
, nfsvers
, numops
;
1317 struct nfsm_chain nmreq
, nmrep
;
1318 uint32_t bitmap
[NFS_ATTR_BITMAP_LEN
], bmlen
, stateid
;
1322 nfsvers
= nmp
->nm_vers
;
1324 if (VATTR_IS_ACTIVE(vap
, va_flags
) && (vap
->va_flags
& ~(SF_ARCHIVED
|UF_HIDDEN
))) {
1325 /* we don't support setting unsupported flags (duh!) */
1326 if (vap
->va_active
& ~VNODE_ATTR_va_flags
)
1327 return (EINVAL
); /* return EINVAL if other attributes also set */
1329 return (ENOTSUP
); /* return ENOTSUP for chflags(2) */
1332 nfsm_chain_null(&nmreq
);
1333 nfsm_chain_null(&nmrep
);
1335 // PUTFH, SETATTR, GETATTR
1337 nfsm_chain_build_alloc_init(error
, &nmreq
, 40 * NFSX_UNSIGNED
);
1338 nfsm_chain_add_compound_header(error
, &nmreq
, "setattr", numops
);
1340 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_PUTFH
);
1341 nfsm_chain_add_fh(error
, &nmreq
, nfsvers
, np
->n_fhp
, np
->n_fhsize
);
1343 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_SETATTR
);
1344 if (VATTR_IS_ACTIVE(vap
, va_data_size
))
1345 stateid
= 0xffffffff; /* XXX use the special stateid for now */
1348 nfsm_chain_add_32(error
, &nmreq
, stateid
);
1349 nfsm_chain_add_32(error
, &nmreq
, stateid
);
1350 nfsm_chain_add_32(error
, &nmreq
, stateid
);
1351 nfsm_chain_add_32(error
, &nmreq
, stateid
);
1352 nfsm_chain_add_fattr4(error
, &nmreq
, vap
, nmp
);
1354 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_GETATTR
);
1355 nfsm_chain_add_bitmap_masked(error
, &nmreq
, nfs_getattr_bitmap
,
1356 NFS_ATTR_BITMAP_LEN
, nmp
->nm_fsattr
.nfsa_supp_attr
);
1357 nfsm_chain_build_done(error
, &nmreq
);
1358 nfsm_assert(error
, (numops
== 0), EPROTO
);
1360 error
= nfs_request(np
, NULL
, &nmreq
, NFSPROC4_COMPOUND
, ctx
, &nmrep
, &xid
, &status
);
1362 if (!alreadylocked
&& ((lockerror
= nfs_lock(np
, NFS_NODE_LOCK_EXCLUSIVE
))))
1364 nfsm_chain_skip_tag(error
, &nmrep
);
1365 nfsm_chain_get_32(error
, &nmrep
, numops
);
1366 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_PUTFH
);
1367 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_SETATTR
);
1368 bmlen
= NFS_ATTR_BITMAP_LEN
;
1369 nfsm_chain_get_bitmap(error
, &nmrep
, bitmap
, bmlen
);
1371 nfs_vattr_set_supported(bitmap
, vap
);
1372 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_GETATTR
);
1373 nfsm_chain_loadattr(error
, &nmrep
, np
, nfsvers
, NULL
, &xid
);
1375 NATTRINVALIDATE(np
);
1377 if (!alreadylocked
&& !lockerror
)
1379 nfsm_chain_cleanup(&nmreq
);
1380 nfsm_chain_cleanup(&nmrep
);
1385 nfs4_vnop_open(struct vnop_open_args
*ap
)
1387 return nfs3_vnop_open(ap
);
1391 nfs4_vnop_close(struct vnop_close_args
*ap
)
1393 return nfs3_vnop_close(ap
);
1397 nfs4_vnop_advlock(__unused
struct vnop_advlock_args
*ap
)
1403 * Note: the NFSv4 CREATE RPC is for everything EXCEPT regular files.
1404 * Files are created using the NFSv4 OPEN RPC. So we must open the
1405 * file to create it and then close it immediately.
1409 struct vnop_create_args
/* {
1410 struct vnodeop_desc *a_desc;
1413 struct componentname *a_cnp;
1414 struct vnode_attr *a_vap;
1415 vfs_context_t a_context;
1418 vfs_context_t ctx
= ap
->a_context
;
1419 struct componentname
*cnp
= ap
->a_cnp
;
1420 struct vnode_attr
*vap
= ap
->a_vap
;
1421 vnode_t dvp
= ap
->a_dvp
;
1422 vnode_t
*vpp
= ap
->a_vpp
;
1423 struct nfsmount
*nmp
;
1424 struct nfs_vattr nvattr
, dnvattr
;
1425 int error
= 0, create_error
= EIO
, lockerror
= ENOENT
, status
;
1426 int nfsvers
, numops
;
1427 u_int64_t xid
, savedxid
= 0;
1428 nfsnode_t dnp
= VTONFS(dvp
);
1429 nfsnode_t np
= NULL
;
1430 vnode_t newvp
= NULL
;
1431 struct nfsm_chain nmreq
, nmrep
;
1432 uint32_t bitmap
[NFS_ATTR_BITMAP_LEN
], bmlen
;
1433 uint32_t seqid
, stateid
[4], rflags
, delegation
, val
;
1435 struct nfsreq
*req
= NULL
;
1436 struct nfs_dulookup dul
;
1438 static uint32_t nfs4_open_owner_hack
= 0;
1443 nfsvers
= nmp
->nm_vers
;
1445 seqid
= stateid
[0] = stateid
[1] = stateid
[2] = stateid
[3] = 0;
1448 nfs_dulookup_init(&dul
, dnp
, cnp
->cn_nameptr
, cnp
->cn_namelen
);
1450 nfsm_chain_null(&nmreq
);
1451 nfsm_chain_null(&nmrep
);
1453 // PUTFH, SAVEFH, OPEN(CREATE), GETATTR(FH), RESTOREFH, GETATTR
1455 nfsm_chain_build_alloc_init(error
, &nmreq
, 53 * NFSX_UNSIGNED
+ cnp
->cn_namelen
);
1456 nfsm_chain_add_compound_header(error
, &nmreq
, "create", numops
);
1458 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_PUTFH
);
1459 nfsm_chain_add_fh(error
, &nmreq
, nfsvers
, dnp
->n_fhp
, dnp
->n_fhsize
);
1461 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_SAVEFH
);
1463 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_OPEN
);
1464 nfsm_chain_add_32(error
, &nmreq
, seqid
);
1466 nfsm_chain_add_32(error
, &nmreq
, NFS_OPEN_SHARE_ACCESS_BOTH
);
1467 nfsm_chain_add_32(error
, &nmreq
, NFS_OPEN_SHARE_DENY_NONE
);
1468 nfsm_chain_add_64(error
, &nmreq
, nmp
->nm_clientid
); // open_owner4.clientid
1469 OSAddAtomic(1, (SInt32
*)&nfs4_open_owner_hack
);
1470 nfsm_chain_add_32(error
, &nmreq
, sizeof(nfs4_open_owner_hack
));
1471 nfsm_chain_add_opaque(error
, &nmreq
, &nfs4_open_owner_hack
, sizeof(nfs4_open_owner_hack
)); // open_owner4.owner
1473 nfsm_chain_add_32(error
, &nmreq
, NFS_OPEN_CREATE
);
1474 nfsm_chain_add_32(error
, &nmreq
, NFS_CREATE_UNCHECKED
); // XXX exclusive/guarded
1475 nfsm_chain_add_fattr4(error
, &nmreq
, vap
, nmp
);
1477 nfsm_chain_add_32(error
, &nmreq
, NFS_CLAIM_NULL
);
1478 nfsm_chain_add_string(error
, &nmreq
, cnp
->cn_nameptr
, cnp
->cn_namelen
);
1480 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_GETATTR
);
1481 NFS_COPY_ATTRIBUTES(nfs_getattr_bitmap
, bitmap
);
1482 NFS_BITMAP_SET(bitmap
, NFS_FATTR_FILEHANDLE
);
1483 nfsm_chain_add_bitmap_masked(error
, &nmreq
, bitmap
,
1484 NFS_ATTR_BITMAP_LEN
, nmp
->nm_fsattr
.nfsa_supp_attr
);
1486 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_RESTOREFH
);
1488 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_GETATTR
);
1489 nfsm_chain_add_bitmap_masked(error
, &nmreq
, nfs_getattr_bitmap
,
1490 NFS_ATTR_BITMAP_LEN
, nmp
->nm_fsattr
.nfsa_supp_attr
);
1491 nfsm_chain_build_done(error
, &nmreq
);
1492 nfsm_assert(error
, (numops
== 0), EPROTO
);
1494 if ((lockerror
= nfs_lock(dnp
, NFS_NODE_LOCK_EXCLUSIVE
)))
1498 error
= nfs_request_async(dnp
, NULL
, &nmreq
, NFSPROC4_COMPOUND
,
1499 vfs_context_thread(ctx
), vfs_context_ucred(ctx
), NULL
, &req
);
1501 nfs_dulookup_start(&dul
, dnp
, ctx
);
1502 error
= nfs_request_async_finish(req
, &nmrep
, &xid
, &status
);
1506 nfsm_chain_skip_tag(error
, &nmrep
);
1507 nfsm_chain_get_32(error
, &nmrep
, numops
);
1508 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_PUTFH
);
1509 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_SAVEFH
);
1510 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_OPEN
);
1511 nfsm_chain_get_32(error
, &nmrep
, stateid
[0]);
1512 nfsm_chain_get_32(error
, &nmrep
, stateid
[1]);
1513 nfsm_chain_get_32(error
, &nmrep
, stateid
[2]);
1514 nfsm_chain_get_32(error
, &nmrep
, stateid
[3]);
1515 nfsm_chain_check_change_info(error
, &nmrep
, dnp
);
1516 nfsm_chain_get_32(error
, &nmrep
, rflags
);
1517 bmlen
= NFS_ATTR_BITMAP_LEN
;
1518 nfsm_chain_get_bitmap(error
, &nmrep
, bitmap
, bmlen
);
1519 nfsm_chain_get_32(error
, &nmrep
, delegation
);
1521 switch (delegation
) {
1522 case NFS_OPEN_DELEGATE_NONE
:
1524 case NFS_OPEN_DELEGATE_READ
:
1525 printf("nfs4_vnop_create: read delegation?\n");
1526 nfsm_chain_adv(error
, &nmrep
, 5*NFSX_UNSIGNED
);
1528 nfsm_chain_adv(error
, &nmrep
, 3 * NFSX_UNSIGNED
);
1529 nfsm_chain_get_32(error
, &nmrep
, val
); /* string length */
1530 nfsm_chain_adv(error
, &nmrep
, nfsm_rndup(val
));
1532 case NFS_OPEN_DELEGATE_WRITE
:
1533 printf("nfs4_vnop_create: write delegation?\n");
1534 nfsm_chain_adv(error
, &nmrep
, 5*NFSX_UNSIGNED
);
1535 nfsm_chain_adv(error
, &nmrep
, 3*NFSX_UNSIGNED
);
1537 nfsm_chain_adv(error
, &nmrep
, 3 * NFSX_UNSIGNED
);
1538 nfsm_chain_get_32(error
, &nmrep
, val
); /* string length */
1539 nfsm_chain_adv(error
, &nmrep
, nfsm_rndup(val
));
1545 /* At this point if we have no error, the object was created. */
1546 /* if we don't get attributes, then we should lookitup. */
1547 create_error
= error
;
1549 nfs_vattr_set_supported(bitmap
, vap
);
1550 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_GETATTR
);
1552 NFS_CLEAR_ATTRIBUTES(nvattr
.nva_bitmap
);
1553 error
= nfs4_parsefattr(&nmrep
, NULL
, &nvattr
, &fh
, NULL
);
1555 if (!NFS_BITMAP_ISSET(nvattr
.nva_bitmap
, NFS_FATTR_FILEHANDLE
)) {
1556 printf("nfs: open/create didn't return filehandle?\n");
1560 /* directory attributes: if we don't get them, make sure to invalidate */
1561 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_RESTOREFH
);
1562 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_GETATTR
);
1563 nfsm_chain_loadattr(error
, &nmrep
, dnp
, nfsvers
, NULL
, &xid
);
1565 NATTRINVALIDATE(dnp
);
1567 if (rflags
& NFS_OPEN_RESULT_CONFIRM
) {
1568 nfsm_chain_cleanup(&nmreq
);
1569 nfsm_chain_cleanup(&nmrep
);
1570 // PUTFH, OPEN_CONFIRM, GETATTR
1572 nfsm_chain_build_alloc_init(error
, &nmreq
, 23 * NFSX_UNSIGNED
);
1573 nfsm_chain_add_compound_header(error
, &nmreq
, "create_confirm", numops
);
1575 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_PUTFH
);
1576 nfsm_chain_add_fh(error
, &nmreq
, nfsvers
, fh
.fh_data
, fh
.fh_len
);
1578 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_OPEN_CONFIRM
);
1579 nfsm_chain_add_32(error
, &nmreq
, stateid
[0]);
1580 nfsm_chain_add_32(error
, &nmreq
, stateid
[1]);
1581 nfsm_chain_add_32(error
, &nmreq
, stateid
[2]);
1582 nfsm_chain_add_32(error
, &nmreq
, stateid
[3]);
1583 nfsm_chain_add_32(error
, &nmreq
, seqid
);
1586 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_GETATTR
);
1587 nfsm_chain_add_bitmap_masked(error
, &nmreq
, nfs_getattr_bitmap
,
1588 NFS_ATTR_BITMAP_LEN
, nmp
->nm_fsattr
.nfsa_supp_attr
);
1589 nfsm_chain_build_done(error
, &nmreq
);
1590 nfsm_assert(error
, (numops
== 0), EPROTO
);
1592 error
= nfs_request(dnp
, NULL
, &nmreq
, NFSPROC4_COMPOUND
, ctx
, &nmrep
, &xid
, &status
);
1594 nfsm_chain_skip_tag(error
, &nmrep
);
1595 nfsm_chain_get_32(error
, &nmrep
, numops
);
1596 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_PUTFH
);
1597 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_OPEN_CONFIRM
);
1598 nfsm_chain_get_32(error
, &nmrep
, stateid
[0]);
1599 nfsm_chain_get_32(error
, &nmrep
, stateid
[1]);
1600 nfsm_chain_get_32(error
, &nmrep
, stateid
[2]);
1601 nfsm_chain_get_32(error
, &nmrep
, stateid
[3]);
1602 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_GETATTR
);
1604 NFS_CLEAR_ATTRIBUTES(nvattr
.nva_bitmap
);
1605 error
= nfs4_parsefattr(&nmrep
, NULL
, &nvattr
, NULL
, NULL
);
1610 nfsm_chain_cleanup(&nmreq
);
1611 nfsm_chain_cleanup(&nmrep
);
1615 nfsm_chain_build_alloc_init(error
, &nmreq
, 19 * NFSX_UNSIGNED
);
1616 nfsm_chain_add_compound_header(error
, &nmreq
, "create_close", numops
);
1618 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_PUTFH
);
1619 nfsm_chain_add_fh(error
, &nmreq
, nfsvers
, fh
.fh_data
, fh
.fh_len
);
1621 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_CLOSE
);
1622 nfsm_chain_add_32(error
, &nmreq
, seqid
);
1624 nfsm_chain_add_32(error
, &nmreq
, stateid
[0]);
1625 nfsm_chain_add_32(error
, &nmreq
, stateid
[1]);
1626 nfsm_chain_add_32(error
, &nmreq
, stateid
[2]);
1627 nfsm_chain_add_32(error
, &nmreq
, stateid
[3]);
1628 nfsm_chain_build_done(error
, &nmreq
);
1629 nfsm_assert(error
, (numops
== 0), EPROTO
);
1631 error
= nfs_request(dnp
, NULL
, &nmreq
, NFSPROC4_COMPOUND
, ctx
, &nmrep
, &xid
, &status
);
1633 nfsm_chain_skip_tag(error
, &nmrep
);
1634 nfsm_chain_get_32(error
, &nmrep
, numops
);
1635 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_PUTFH
);
1636 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_CLOSE
);
1637 nfsm_chain_get_32(error
, &nmrep
, stateid
[0]);
1638 nfsm_chain_get_32(error
, &nmrep
, stateid
[1]);
1639 nfsm_chain_get_32(error
, &nmrep
, stateid
[2]);
1640 nfsm_chain_get_32(error
, &nmrep
, stateid
[3]);
1642 printf("nfs4_vnop_create: close error %d\n", error
);
1645 nfsm_chain_cleanup(&nmreq
);
1646 nfsm_chain_cleanup(&nmrep
);
1649 if (!create_error
&& (dnp
->n_flag
& NNEGNCENTRIES
)) {
1650 dnp
->n_flag
&= ~NNEGNCENTRIES
;
1651 cache_purge_negatives(dvp
);
1653 dnp
->n_flag
|= NMODIFIED
;
1654 if (!nfs_getattr(dnp
, &dnvattr
, ctx
, 1)) {
1655 if (NFS_CHANGED_NC(nfsvers
, dnp
, &dnvattr
)) {
1656 dnp
->n_flag
&= ~NNEGNCENTRIES
;
1658 NFS_CHANGED_UPDATE_NC(nfsvers
, dnp
, &dnvattr
);
1663 if (!error
&& fh
.fh_len
) {
1664 /* create the vnode with the filehandle and attributes */
1666 error
= nfs_nget(NFSTOMP(dnp
), dnp
, cnp
, fh
.fh_data
, fh
.fh_len
, &nvattr
, &xid
, NG_MAKEENTRY
, &np
);
1671 nfs_dulookup_finish(&dul
, dnp
, ctx
);
1674 * Kludge: Map EEXIST => 0 assuming that you have a reply to a retry
1675 * if we can succeed in looking up the object.
1677 if ((create_error
== EEXIST
) || (!create_error
&& !newvp
)) {
1678 error
= nfs_lookitup(dnp
, cnp
->cn_nameptr
, cnp
->cn_namelen
, ctx
, &np
);
1681 if (vnode_vtype(newvp
) != VLNK
)
1700 * Note: the NFSv4 CREATE RPC is for everything EXCEPT regular files.
1706 struct componentname
*cnp
,
1707 struct vnode_attr
*vap
,
1712 struct nfsmount
*nmp
;
1713 struct nfs_vattr nvattr
, dnvattr
;
1714 int error
= 0, create_error
= EIO
, lockerror
= ENOENT
, status
;
1715 int nfsvers
, numops
;
1716 u_int64_t xid
, savedxid
= 0;
1717 nfsnode_t np
= NULL
;
1718 vnode_t newvp
= NULL
;
1719 struct nfsm_chain nmreq
, nmrep
;
1720 uint32_t bitmap
[NFS_ATTR_BITMAP_LEN
], bmlen
;
1724 struct nfsreq
*req
= NULL
;
1725 struct nfs_dulookup dul
;
1727 nmp
= NFSTONMP(dnp
);
1730 nfsvers
= nmp
->nm_vers
;
1732 sd
.specdata1
= sd
.specdata2
= 0;
1741 if (!VATTR_IS_ACTIVE(vap
, va_rdev
))
1743 sd
.specdata1
= major(vap
->va_rdev
);
1744 sd
.specdata2
= minor(vap
->va_rdev
);
1757 nfs_dulookup_init(&dul
, dnp
, cnp
->cn_nameptr
, cnp
->cn_namelen
);
1759 nfsm_chain_null(&nmreq
);
1760 nfsm_chain_null(&nmrep
);
1762 // PUTFH, SAVEFH, CREATE, GETATTR(FH), RESTOREFH, GETATTR
1764 nfsm_chain_build_alloc_init(error
, &nmreq
, 66 * NFSX_UNSIGNED
);
1765 nfsm_chain_add_compound_header(error
, &nmreq
, tag
, numops
);
1767 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_PUTFH
);
1768 nfsm_chain_add_fh(error
, &nmreq
, nfsvers
, dnp
->n_fhp
, dnp
->n_fhsize
);
1770 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_SAVEFH
);
1772 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_CREATE
);
1773 nfsm_chain_add_32(error
, &nmreq
, type
);
1774 if (type
== NFLNK
) {
1775 nfsm_chain_add_string(error
, &nmreq
, link
, strlen(link
));
1776 } else if ((type
== NFBLK
) || (type
== NFCHR
)) {
1777 nfsm_chain_add_32(error
, &nmreq
, sd
.specdata1
);
1778 nfsm_chain_add_32(error
, &nmreq
, sd
.specdata2
);
1780 nfsm_chain_add_string(error
, &nmreq
, cnp
->cn_nameptr
, cnp
->cn_namelen
);
1781 nfsm_chain_add_fattr4(error
, &nmreq
, vap
, nmp
);
1783 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_GETATTR
);
1784 NFS_COPY_ATTRIBUTES(nfs_getattr_bitmap
, bitmap
);
1785 NFS_BITMAP_SET(bitmap
, NFS_FATTR_FILEHANDLE
);
1786 nfsm_chain_add_bitmap_masked(error
, &nmreq
, bitmap
,
1787 NFS_ATTR_BITMAP_LEN
, nmp
->nm_fsattr
.nfsa_supp_attr
);
1789 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_RESTOREFH
);
1791 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_GETATTR
);
1792 nfsm_chain_add_bitmap_masked(error
, &nmreq
, nfs_getattr_bitmap
,
1793 NFS_ATTR_BITMAP_LEN
, nmp
->nm_fsattr
.nfsa_supp_attr
);
1794 nfsm_chain_build_done(error
, &nmreq
);
1795 nfsm_assert(error
, (numops
== 0), EPROTO
);
1797 if ((lockerror
= nfs_lock(dnp
, NFS_NODE_LOCK_EXCLUSIVE
)))
1801 error
= nfs_request_async(dnp
, NULL
, &nmreq
, NFSPROC4_COMPOUND
,
1802 vfs_context_thread(ctx
), vfs_context_ucred(ctx
), NULL
, &req
);
1804 nfs_dulookup_start(&dul
, dnp
, ctx
);
1805 error
= nfs_request_async_finish(req
, &nmrep
, &xid
, &status
);
1808 nfsm_chain_skip_tag(error
, &nmrep
);
1809 nfsm_chain_get_32(error
, &nmrep
, numops
);
1810 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_PUTFH
);
1811 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_SAVEFH
);
1813 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_CREATE
);
1814 nfsm_chain_check_change_info(error
, &nmrep
, dnp
);
1815 bmlen
= NFS_ATTR_BITMAP_LEN
;
1816 nfsm_chain_get_bitmap(error
, &nmrep
, bitmap
, bmlen
);
1817 /* At this point if we have no error, the object was created. */
1818 /* if we don't get attributes, then we should lookitup. */
1819 create_error
= error
;
1821 nfs_vattr_set_supported(bitmap
, vap
);
1822 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_GETATTR
);
1824 NFS_CLEAR_ATTRIBUTES(nvattr
.nva_bitmap
);
1825 error
= nfs4_parsefattr(&nmrep
, NULL
, &nvattr
, &fh
, NULL
);
1827 if (!NFS_BITMAP_ISSET(nvattr
.nva_bitmap
, NFS_FATTR_FILEHANDLE
)) {
1828 printf("nfs: create/%s didn't return filehandle?\n", tag
);
1832 /* directory attributes: if we don't get them, make sure to invalidate */
1833 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_RESTOREFH
);
1834 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_GETATTR
);
1836 nfsm_chain_loadattr(error
, &nmrep
, dnp
, nfsvers
, NULL
, &xid
);
1838 NATTRINVALIDATE(dnp
);
1841 nfsm_chain_cleanup(&nmreq
);
1842 nfsm_chain_cleanup(&nmrep
);
1845 if (!create_error
&& (dnp
->n_flag
& NNEGNCENTRIES
)) {
1846 dnp
->n_flag
&= ~NNEGNCENTRIES
;
1847 cache_purge_negatives(NFSTOV(dnp
));
1849 dnp
->n_flag
|= NMODIFIED
;
1850 if (!nfs_getattr(dnp
, &dnvattr
, ctx
, 1)) {
1851 if (NFS_CHANGED_NC(nfsvers
, dnp
, &dnvattr
)) {
1852 dnp
->n_flag
&= ~NNEGNCENTRIES
;
1853 cache_purge(NFSTOV(dnp
));
1854 NFS_CHANGED_UPDATE_NC(nfsvers
, dnp
, &dnvattr
);
1859 if (!error
&& fh
.fh_len
) {
1860 /* create the vnode with the filehandle and attributes */
1862 error
= nfs_nget(NFSTOMP(dnp
), dnp
, cnp
, fh
.fh_data
, fh
.fh_len
, &nvattr
, &xid
, NG_MAKEENTRY
, &np
);
1867 nfs_dulookup_finish(&dul
, dnp
, ctx
);
1870 * Kludge: Map EEXIST => 0 assuming that you have a reply to a retry
1871 * if we can succeed in looking up the object.
1873 if ((create_error
== EEXIST
) || (!create_error
&& !newvp
)) {
1874 error
= nfs_lookitup(dnp
, cnp
->cn_nameptr
, cnp
->cn_namelen
, ctx
, &np
);
1877 if (vnode_vtype(newvp
) != VLNK
)
1897 struct vnop_mknod_args
/* {
1898 struct vnodeop_desc *a_desc;
1901 struct componentname *a_cnp;
1902 struct vnode_attr *a_vap;
1903 vfs_context_t a_context;
1906 nfsnode_t np
= NULL
;
1907 struct nfsmount
*nmp
;
1910 nmp
= VTONMP(ap
->a_dvp
);
1914 if (!VATTR_IS_ACTIVE(ap
->a_vap
, va_type
))
1916 switch (ap
->a_vap
->va_type
) {
1926 error
= nfs4_create_rpc(ap
->a_context
, VTONFS(ap
->a_dvp
), ap
->a_cnp
, ap
->a_vap
,
1927 vtonfs_type(ap
->a_vap
->va_type
, nmp
->nm_vers
), NULL
, &np
);
1929 *ap
->a_vpp
= NFSTOV(np
);
1935 struct vnop_mkdir_args
/* {
1936 struct vnodeop_desc *a_desc;
1939 struct componentname *a_cnp;
1940 struct vnode_attr *a_vap;
1941 vfs_context_t a_context;
1944 nfsnode_t np
= NULL
;
1947 error
= nfs4_create_rpc(ap
->a_context
, VTONFS(ap
->a_dvp
), ap
->a_cnp
, ap
->a_vap
,
1950 *ap
->a_vpp
= NFSTOV(np
);
1956 struct vnop_symlink_args
/* {
1957 struct vnodeop_desc *a_desc;
1960 struct componentname *a_cnp;
1961 struct vnode_attr *a_vap;
1963 vfs_context_t a_context;
1966 nfsnode_t np
= NULL
;
1969 error
= nfs4_create_rpc(ap
->a_context
, VTONFS(ap
->a_dvp
), ap
->a_cnp
, ap
->a_vap
,
1970 NFLNK
, ap
->a_target
, &np
);
1972 *ap
->a_vpp
= NFSTOV(np
);
1978 struct vnop_link_args
/* {
1979 struct vnodeop_desc *a_desc;
1982 struct componentname *a_cnp;
1983 vfs_context_t a_context;
1986 vfs_context_t ctx
= ap
->a_context
;
1987 vnode_t vp
= ap
->a_vp
;
1988 vnode_t tdvp
= ap
->a_tdvp
;
1989 struct componentname
*cnp
= ap
->a_cnp
;
1990 int error
= 0, status
;
1991 struct nfsmount
*nmp
;
1992 nfsnode_t np
= VTONFS(vp
);
1993 nfsnode_t tdnp
= VTONFS(tdvp
);
1994 int nfsvers
, numops
;
1995 u_int64_t xid
, savedxid
;
1996 struct nfsm_chain nmreq
, nmrep
;
1998 if (vnode_mount(vp
) != vnode_mount(tdvp
))
2004 nfsvers
= nmp
->nm_vers
;
2007 * Push all writes to the server, so that the attribute cache
2008 * doesn't get "out of sync" with the server.
2009 * XXX There should be a better way!
2011 nfs_flush(np
, MNT_WAIT
, vfs_context_thread(ctx
), V_IGNORE_WRITEERR
);
2013 error
= nfs_lock2(tdnp
, np
, NFS_NODE_LOCK_EXCLUSIVE
);
2017 nfsm_chain_null(&nmreq
);
2018 nfsm_chain_null(&nmrep
);
2020 // PUTFH(SOURCE), SAVEFH, PUTFH(DIR), LINK, GETATTR(DIR), RESTOREFH, GETATTR
2022 nfsm_chain_build_alloc_init(error
, &nmreq
, 29 * NFSX_UNSIGNED
+ cnp
->cn_namelen
);
2023 nfsm_chain_add_compound_header(error
, &nmreq
, "link", numops
);
2025 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_PUTFH
);
2026 nfsm_chain_add_fh(error
, &nmreq
, nfsvers
, np
->n_fhp
, np
->n_fhsize
);
2028 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_SAVEFH
);
2030 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_PUTFH
);
2031 nfsm_chain_add_fh(error
, &nmreq
, nfsvers
, tdnp
->n_fhp
, tdnp
->n_fhsize
);
2033 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_LINK
);
2034 nfsm_chain_add_string(error
, &nmreq
, cnp
->cn_nameptr
, cnp
->cn_namelen
);
2036 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_GETATTR
);
2037 nfsm_chain_add_bitmap_masked(error
, &nmreq
, nfs_getattr_bitmap
,
2038 NFS_ATTR_BITMAP_LEN
, nmp
->nm_fsattr
.nfsa_supp_attr
);
2040 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_RESTOREFH
);
2042 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_GETATTR
);
2043 nfsm_chain_add_bitmap_masked(error
, &nmreq
, nfs_getattr_bitmap
,
2044 NFS_ATTR_BITMAP_LEN
, nmp
->nm_fsattr
.nfsa_supp_attr
);
2045 nfsm_chain_build_done(error
, &nmreq
);
2046 nfsm_assert(error
, (numops
== 0), EPROTO
);
2048 error
= nfs_request(tdnp
, NULL
, &nmreq
, NFSPROC4_COMPOUND
, ctx
, &nmrep
, &xid
, &status
);
2050 nfsm_chain_skip_tag(error
, &nmrep
);
2051 nfsm_chain_get_32(error
, &nmrep
, numops
);
2052 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_PUTFH
);
2053 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_SAVEFH
);
2054 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_PUTFH
);
2055 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_LINK
);
2056 nfsm_chain_check_change_info(error
, &nmrep
, tdnp
);
2057 /* directory attributes: if we don't get them, make sure to invalidate */
2058 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_GETATTR
);
2060 nfsm_chain_loadattr(error
, &nmrep
, tdnp
, nfsvers
, NULL
, &xid
);
2062 NATTRINVALIDATE(tdnp
);
2063 /* link attributes: if we don't get them, make sure to invalidate */
2064 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_RESTOREFH
);
2065 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_GETATTR
);
2067 nfsm_chain_loadattr(error
, &nmrep
, np
, nfsvers
, NULL
, &xid
);
2069 NATTRINVALIDATE(np
);
2071 nfsm_chain_cleanup(&nmreq
);
2072 nfsm_chain_cleanup(&nmrep
);
2073 tdnp
->n_flag
|= NMODIFIED
;
2074 /* Kludge: Map EEXIST => 0 assuming that it is a reply to a retry. */
2075 if (error
== EEXIST
)
2077 if (!error
&& (tdnp
->n_flag
& NNEGNCENTRIES
)) {
2078 tdnp
->n_flag
&= ~NNEGNCENTRIES
;
2079 cache_purge_negatives(tdvp
);
2081 nfs_unlock2(tdnp
, np
);
2087 struct vnop_rmdir_args
/* {
2088 struct vnodeop_desc *a_desc;
2091 struct componentname *a_cnp;
2092 vfs_context_t a_context;
2095 vfs_context_t ctx
= ap
->a_context
;
2096 vnode_t vp
= ap
->a_vp
;
2097 vnode_t dvp
= ap
->a_dvp
;
2098 struct componentname
*cnp
= ap
->a_cnp
;
2100 nfsnode_t np
= VTONFS(vp
);
2101 nfsnode_t dnp
= VTONFS(dvp
);
2102 struct nfs_vattr dnvattr
;
2103 struct nfs_dulookup dul
;
2105 if (vnode_vtype(vp
) != VDIR
)
2108 nfs_dulookup_init(&dul
, dnp
, cnp
->cn_nameptr
, cnp
->cn_namelen
);
2110 if ((error
= nfs_lock2(dnp
, np
, NFS_NODE_LOCK_EXCLUSIVE
)))
2113 nfs_dulookup_start(&dul
, dnp
, ctx
);
2115 error
= nfs4_remove_rpc(dnp
, cnp
->cn_nameptr
, cnp
->cn_namelen
,
2116 vfs_context_thread(ctx
), vfs_context_ucred(ctx
));
2119 if (!nfs_getattr(dnp
, &dnvattr
, ctx
, 1)) {
2120 if (NFS_CHANGED_NC(NFS_VER4
, dnp
, &dnvattr
)) {
2121 dnp
->n_flag
&= ~NNEGNCENTRIES
;
2123 NFS_CHANGED_UPDATE_NC(NFS_VER4
, dnp
, &dnvattr
);
2127 nfs_dulookup_finish(&dul
, dnp
, ctx
);
2128 nfs_unlock2(dnp
, np
);
2131 * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry.
2133 if (error
== ENOENT
)
2137 * remove nfsnode from hash now so we can't accidentally find it
2138 * again if another object gets created with the same filehandle
2139 * before this vnode gets reclaimed
2141 lck_mtx_lock(nfs_node_hash_mutex
);
2142 if (np
->n_hflag
& NHHASHED
) {
2143 LIST_REMOVE(np
, n_hash
);
2144 np
->n_hflag
&= ~NHHASHED
;
2145 FSDBG(266, 0, np
, np
->n_flag
, 0xb1eb1e);
2147 lck_mtx_unlock(nfs_node_hash_mutex
);