]> git.saurik.com Git - apple/xnu.git/blob - bsd/nfs/nfs4_vnops.c
xnu-1228.0.2.tar.gz
[apple/xnu.git] / bsd / nfs / nfs4_vnops.c
1 /*
2 * Copyright (c) 2006-2007 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
51 #include <vfs/vfs_support.h>
52
53 #include <sys/vm.h>
54
55 #include <sys/time.h>
56 #include <kern/clock.h>
57 #include <libkern/OSAtomic.h>
58
59 #include <miscfs/fifofs/fifo.h>
60 #include <miscfs/specfs/specdev.h>
61
62 #include <nfs/rpcv2.h>
63 #include <nfs/nfsproto.h>
64 #include <nfs/nfs.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>
71
72 #include <net/if.h>
73 #include <netinet/in.h>
74 #include <netinet/in_var.h>
75 #include <vm/vm_kern.h>
76
77 #include <kern/task.h>
78 #include <kern/sched_prim.h>
79
80
81 int
82 nfs4_access_rpc(nfsnode_t np, u_long *mode, vfs_context_t ctx)
83 {
84 int error = 0, status, numops, slot;
85 u_int64_t xid;
86 struct nfsm_chain nmreq, nmrep;
87 struct timeval now;
88 uint32_t access, supported = 0, missing;
89 struct nfsmount *nmp = NFSTONMP(np);
90 int nfsvers = nmp->nm_vers;
91 uid_t uid;
92
93 nfsm_chain_null(&nmreq);
94 nfsm_chain_null(&nmrep);
95
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);
99 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);
102 numops--;
103 nfsm_chain_add_32(error, &nmreq, NFS_OP_ACCESS);
104 nfsm_chain_add_32(error, &nmreq, *mode);
105 numops--;
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);
111 nfsmout_if(error);
112 error = nfs_request(np, NULL, &nmreq, NFSPROC4_COMPOUND, ctx, &nmrep, &xid, &status);
113
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);
120 nfsmout_if(error);
121 if ((missing = (*mode & ~supported))) {
122 /* missing support for something(s) we wanted */
123 if (missing & NFS_ACCESS_DELETE) {
124 /*
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.
129 */
130 access |= NFS_ACCESS_DELETE;
131 }
132 }
133 nfsm_chain_op_check(error, &nmrep, NFS_OP_GETATTR);
134 nfsm_chain_loadattr(error, &nmrep, np, nfsvers, NULL, &xid);
135 nfsmout_if(error);
136
137 uid = kauth_cred_getuid(vfs_context_ucred(ctx));
138 slot = nfs_node_mode_slot(np, uid, 1);
139 np->n_modeuid[slot] = uid;
140 microuptime(&now);
141 np->n_modestamp[slot] = now.tv_sec;
142 np->n_mode[slot] = access;
143
144 /* pass back the mode returned with this request */
145 *mode = np->n_mode[slot];
146 nfsmout:
147 nfsm_chain_cleanup(&nmreq);
148 nfsm_chain_cleanup(&nmrep);
149 return (error);
150 }
151
152 int
153 nfs4_getattr_rpc(
154 nfsnode_t np,
155 mount_t mp,
156 u_char *fhp,
157 size_t fhsize,
158 vfs_context_t ctx,
159 struct nfs_vattr *nvap,
160 u_int64_t *xidp)
161 {
162 struct nfsmount *nmp = mp ? VFSTONFS(mp) : NFSTONMP(np);
163 int error = 0, status, nfsvers, numops;
164 struct nfsm_chain nmreq, nmrep;
165
166 if (!nmp)
167 return (ENXIO);
168 nfsvers = nmp->nm_vers;
169
170 nfsm_chain_null(&nmreq);
171 nfsm_chain_null(&nmrep);
172
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);
176 numops--;
177 nfsm_chain_add_32(error, &nmreq, NFS_OP_PUTFH);
178 nfsm_chain_add_fh(error, &nmreq, nfsvers, fhp, fhsize);
179 numops--;
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);
185 nfsmout_if(error);
186 error = nfs_request(np, mp, &nmreq, NFSPROC4_COMPOUND, ctx, &nmrep, xidp, &status);
187
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);
192 nfsmout_if(error);
193 NFS_CLEAR_ATTRIBUTES(nvap->nva_bitmap);
194 error = nfs4_parsefattr(&nmrep, NULL, nvap, NULL, NULL);
195 nfsmout:
196 nfsm_chain_cleanup(&nmreq);
197 nfsm_chain_cleanup(&nmrep);
198 return (error);
199 }
200
201 int
202 nfs4_readlink_rpc(nfsnode_t np, char *buf, uint32_t *buflenp, vfs_context_t ctx)
203 {
204 struct nfsmount *nmp;
205 int error = 0, lockerror = ENOENT, status, numops;
206 uint32_t len = 0;
207 u_int64_t xid;
208 struct nfsm_chain nmreq, nmrep;
209
210 nmp = NFSTONMP(np);
211 if (!nmp)
212 return (ENXIO);
213 nfsm_chain_null(&nmreq);
214 nfsm_chain_null(&nmrep);
215
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);
219 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);
222 numops--;
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);
226 numops--;
227 nfsm_chain_add_32(error, &nmreq, NFS_OP_READLINK);
228 nfsm_chain_build_done(error, &nmreq);
229 nfsm_assert(error, (numops == 0), EPROTO);
230 nfsmout_if(error);
231 error = nfs_request(np, NULL, &nmreq, NFSPROC4_COMPOUND, ctx, &nmrep, &xid, &status);
232
233 if ((lockerror = nfs_lock(np, NFS_NODE_LOCK_EXCLUSIVE)))
234 error = lockerror;
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);
242 nfsmout_if(error);
243 if (len >= *buflenp) {
244 if (np->n_size && (np->n_size < *buflenp))
245 len = np->n_size;
246 else
247 len = *buflenp - 1;
248 }
249 nfsm_chain_get_opaque(error, &nmrep, len, buf);
250 if (!error)
251 *buflenp = len;
252 nfsmout:
253 if (!lockerror)
254 nfs_unlock(np);
255 nfsm_chain_cleanup(&nmreq);
256 nfsm_chain_cleanup(&nmrep);
257 return (error);
258 }
259
260 int
261 nfs4_read_rpc_async(
262 nfsnode_t np,
263 off_t offset,
264 size_t len,
265 thread_t thd,
266 kauth_cred_t cred,
267 struct nfsreq_cbinfo *cb,
268 struct nfsreq **reqp)
269 {
270 struct nfsmount *nmp;
271 int error = 0, nfsvers, numops;
272 struct nfsm_chain nmreq;
273
274 nmp = NFSTONMP(np);
275 if (!nmp)
276 return (ENXIO);
277 nfsvers = nmp->nm_vers;
278
279 nfsm_chain_null(&nmreq);
280
281 // PUTFH + READ + GETATTR
282 numops = 3;
283 nfsm_chain_build_alloc_init(error, &nmreq, 22 * NFSX_UNSIGNED);
284 nfsm_chain_add_compound_header(error, &nmreq, "read", numops);
285 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);
288 numops--;
289 nfsm_chain_add_32(error, &nmreq, NFS_OP_READ);
290
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);
296
297 nfsm_chain_add_64(error, &nmreq, offset);
298 nfsm_chain_add_32(error, &nmreq, len);
299 numops--;
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);
305 nfsmout_if(error);
306 error = nfs_request_async(np, NULL, &nmreq, NFSPROC4_COMPOUND, thd, cred, cb, reqp);
307 nfsmout:
308 nfsm_chain_cleanup(&nmreq);
309 return (error);
310 }
311
312 int
313 nfs4_read_rpc_async_finish(
314 nfsnode_t np,
315 struct nfsreq *req,
316 struct uio *uiop,
317 size_t *lenp,
318 int *eofp)
319 {
320 struct nfsmount *nmp;
321 int error = 0, lockerror, nfsvers, numops, status, eof = 0;
322 size_t retlen = 0;
323 u_int64_t xid;
324 struct nfsm_chain nmrep;
325
326 nmp = NFSTONMP(np);
327 if (!nmp) {
328 nfs_request_async_cancel(req);
329 return (ENXIO);
330 }
331 nfsvers = nmp->nm_vers;
332
333 nfsm_chain_null(&nmrep);
334
335 error = nfs_request_async_finish(req, &nmrep, &xid, &status);
336 if (error == EINPROGRESS) /* async request restarted */
337 return (error);
338
339 if ((lockerror = nfs_lock(np, NFS_NODE_LOCK_EXCLUSIVE)))
340 error = lockerror;
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);
347 if (!error) {
348 *lenp = MIN(retlen, *lenp);
349 error = nfsm_chain_get_uio(&nmrep, *lenp, uiop);
350 }
351 nfsm_chain_op_check(error, &nmrep, NFS_OP_GETATTR);
352 nfsm_chain_loadattr(error, &nmrep, np, nfsvers, NULL, &xid);
353 if (!lockerror)
354 nfs_unlock(np);
355 if (eofp) {
356 if (!eof && !retlen)
357 eof = 1;
358 *eofp = eof;
359 }
360 nfsm_chain_cleanup(&nmrep);
361 return (error);
362 }
363
364 int
365 nfs4_write_rpc_async(
366 nfsnode_t np,
367 struct uio *uiop,
368 size_t len,
369 thread_t thd,
370 kauth_cred_t cred,
371 int iomode,
372 struct nfsreq_cbinfo *cb,
373 struct nfsreq **reqp)
374 {
375 struct nfsmount *nmp;
376 int error = 0, nfsvers, numops;
377 off_t offset;
378 struct nfsm_chain nmreq;
379
380 nmp = NFSTONMP(np);
381 if (!nmp)
382 return (ENXIO);
383 nfsvers = nmp->nm_vers;
384
385 offset = uiop->uio_offset;
386
387 nfsm_chain_null(&nmreq);
388
389 // PUTFH + WRITE + GETATTR
390 numops = 3;
391 nfsm_chain_build_alloc_init(error, &nmreq, 25 * NFSX_UNSIGNED + len);
392 nfsm_chain_add_compound_header(error, &nmreq, "write", numops);
393 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);
396 numops--;
397 nfsm_chain_add_32(error, &nmreq, NFS_OP_WRITE);
398
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);
404
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);
408 if (!error)
409 error = nfsm_chain_add_uio(&nmreq, uiop, len);
410 numops--;
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);
416 nfsmout_if(error);
417
418 error = nfs_request_async(np, NULL, &nmreq, NFSPROC4_COMPOUND, thd, cred, cb, reqp);
419 nfsmout:
420 nfsm_chain_cleanup(&nmreq);
421 return (error);
422 }
423
424 int
425 nfs4_write_rpc_async_finish(
426 nfsnode_t np,
427 struct nfsreq *req,
428 int *iomodep,
429 size_t *rlenp,
430 uint64_t *wverfp)
431 {
432 struct nfsmount *nmp;
433 int error = 0, lockerror = ENOENT, nfsvers, numops, status;
434 int committed = NFS_WRITE_FILESYNC;
435 size_t rlen = 0;
436 u_int64_t xid, wverf;
437 mount_t mp;
438 struct nfsm_chain nmrep;
439
440 nmp = NFSTONMP(np);
441 if (!nmp) {
442 nfs_request_async_cancel(req);
443 return (ENXIO);
444 }
445 nfsvers = nmp->nm_vers;
446
447 nfsm_chain_null(&nmrep);
448
449 error = nfs_request_async_finish(req, &nmrep, &xid, &status);
450 if (error == EINPROGRESS) /* async request restarted */
451 return (error);
452 nmp = NFSTONMP(np);
453 if (!nmp)
454 error = ENXIO;
455 if (!error && (lockerror = nfs_lock(np, NFS_NODE_LOCK_EXCLUSIVE)))
456 error = lockerror;
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);
462 nfsmout_if(error);
463 *rlenp = rlen;
464 if (rlen <= 0)
465 error = NFSERR_IO;
466 nfsm_chain_get_32(error, &nmrep, committed);
467 nfsm_chain_get_64(error, &nmrep, wverf);
468 nfsmout_if(error);
469 if (wverfp)
470 *wverfp = 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;
477 }
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);
481 nfsmout:
482 if (!lockerror)
483 nfs_unlock(np);
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;
489 return (error);
490 }
491
492 int
493 nfs4_remove_rpc(
494 nfsnode_t dnp,
495 char *name,
496 int namelen,
497 thread_t thd,
498 kauth_cred_t cred)
499 {
500 int error = 0, remove_error = 0, status;
501 struct nfsmount *nmp;
502 int nfsvers, numops;
503 u_int64_t xid;
504 struct nfsm_chain nmreq, nmrep;
505
506 nmp = NFSTONMP(dnp);
507 if (!nmp)
508 return (ENXIO);
509 nfsvers = nmp->nm_vers;
510
511 nfsm_chain_null(&nmreq);
512 nfsm_chain_null(&nmrep);
513
514 // PUTFH, REMOVE, GETATTR
515 numops = 3;
516 nfsm_chain_build_alloc_init(error, &nmreq, 17 * NFSX_UNSIGNED + namelen);
517 nfsm_chain_add_compound_header(error, &nmreq, "remove", numops);
518 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);
521 numops--;
522 nfsm_chain_add_32(error, &nmreq, NFS_OP_REMOVE);
523 nfsm_chain_add_string(error, &nmreq, name, namelen);
524 numops--;
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);
530 nfsmout_if(error);
531
532 error = nfs_request2(dnp, NULL, &nmreq, NFSPROC4_COMPOUND, thd, cred, 0, &nmrep, &xid, &status);
533
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);
542 if (error)
543 NATTRINVALIDATE(dnp);
544 nfsmout:
545 nfsm_chain_cleanup(&nmreq);
546 nfsm_chain_cleanup(&nmrep);
547
548 dnp->n_flag |= NMODIFIED;
549
550 return (remove_error);
551 }
552
553 int
554 nfs4_rename_rpc(
555 nfsnode_t fdnp,
556 char *fnameptr,
557 int fnamelen,
558 nfsnode_t tdnp,
559 char *tnameptr,
560 int tnamelen,
561 vfs_context_t ctx)
562 {
563 int error = 0, status, nfsvers, numops;
564 struct nfsmount *nmp;
565 u_int64_t xid, savedxid;
566 struct nfsm_chain nmreq, nmrep;
567
568 nmp = NFSTONMP(fdnp);
569 if (!nmp)
570 return (ENXIO);
571 nfsvers = nmp->nm_vers;
572
573 nfsm_chain_null(&nmreq);
574 nfsm_chain_null(&nmrep);
575
576 // PUTFH(FROM), SAVEFH, PUTFH(TO), RENAME, GETATTR(TO), RESTOREFH, GETATTR(FROM)
577 numops = 7;
578 nfsm_chain_build_alloc_init(error, &nmreq, 30 * NFSX_UNSIGNED + fnamelen + tnamelen);
579 nfsm_chain_add_compound_header(error, &nmreq, "rename", numops);
580 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);
583 numops--;
584 nfsm_chain_add_32(error, &nmreq, NFS_OP_SAVEFH);
585 numops--;
586 nfsm_chain_add_32(error, &nmreq, NFS_OP_PUTFH);
587 nfsm_chain_add_fh(error, &nmreq, nfsvers, tdnp->n_fhp, tdnp->n_fhsize);
588 numops--;
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);
592 numops--;
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);
596 numops--;
597 nfsm_chain_add_32(error, &nmreq, NFS_OP_RESTOREFH);
598 numops--;
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);
604 nfsmout_if(error);
605
606 error = nfs_request(fdnp, NULL, &nmreq, NFSPROC4_COMPOUND, ctx, &nmrep, &xid, &status);
607
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);
618 savedxid = xid;
619 nfsm_chain_loadattr(error, &nmrep, tdnp, nfsvers, NULL, &xid);
620 if (error)
621 NATTRINVALIDATE(tdnp);
622 nfsm_chain_op_check(error, &nmrep, NFS_OP_RESTOREFH);
623 nfsm_chain_op_check(error, &nmrep, NFS_OP_GETATTR);
624 xid = savedxid;
625 nfsm_chain_loadattr(error, &nmrep, fdnp, nfsvers, NULL, &xid);
626 if (error)
627 NATTRINVALIDATE(fdnp);
628 nfsmout:
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. */
634 if (error == EEXIST)
635 error = 0;
636 return (error);
637 }
638
639 /*
640 * NFS V4 readdir RPC.
641 */
642 #define DIRHDSIZ ((int)(sizeof(struct dirent) - (MAXNAMLEN + 1)))
643 int
644 nfs4_readdir_rpc(nfsnode_t dnp, struct uio *uiop, vfs_context_t ctx)
645 {
646 size_t len, tlen, skiplen, left;
647 struct dirent *dp = NULL;
648 vnode_t newvp;
649 nfsuint64 *cookiep;
650 struct componentname cn, *cnp = &cn;
651 nfsuint64 cookie;
652 struct nfsmount *nmp;
653 nfsnode_t np;
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;
659 char *cp;
660 const char *tag;
661 uint32_t entry_attrs[NFS_ATTR_BITMAP_LEN];
662 fhandle_t fh;
663
664 #if DIAGNOSTIC
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");
669 #endif
670 nmp = NFSTONMP(dnp);
671 if (!nmp)
672 return (ENXIO);
673 nfsvers = nmp->nm_vers;
674 nmreaddirsize = nmp->nm_readdirsize;
675 nmrsize = nmp->nm_rsize;
676 rdirplus = (nmp->nm_flag & NFSMNT_RDIRPLUS) ? 1 : 0;
677
678 bzero(cnp, sizeof(*cnp));
679 newvp = NULLVP;
680
681 /*
682 * Set up attribute request for entries.
683 * For READDIRPLUS functionality, get everything.
684 * Otherwise, just get what we need for struct dirent.
685 */
686 if (rdirplus) {
687 tag = "READDIRPLUS";
688 for (i=0; i < NFS_ATTR_BITMAP_LEN; i++)
689 entry_attrs[i] =
690 nfs_getattr_bitmap[i] &
691 nmp->nm_fsattr.nfsa_supp_attr[i];
692 NFS_BITMAP_SET(entry_attrs, NFS_FATTR_FILEHANDLE);
693 } else {
694 tag = "READDIR";
695 NFS_CLEAR_ATTRIBUTES(entry_attrs);
696 NFS_BITMAP_SET(entry_attrs, NFS_FATTR_TYPE);
697 NFS_BITMAP_SET(entry_attrs, NFS_FATTR_FILEID);
698 }
699 /* XXX NFS_BITMAP_SET(entry_attrs, NFS_FATTR_MOUNTED_ON_FILEID); */
700 NFS_BITMAP_SET(entry_attrs, NFS_FATTR_RDATTR_ERROR);
701
702 if ((lockerror = nfs_lock(dnp, NFS_NODE_LOCK_SHARED)))
703 return (lockerror);
704
705 /*
706 * If there is no cookie, assume directory was stale.
707 */
708 cookiep = nfs_getcookie(dnp, uiop->uio_offset, 0);
709 if (cookiep)
710 cookie = *cookiep;
711 else {
712 nfs_unlock(dnp);
713 return (NFSERR_BAD_COOKIE);
714 }
715
716 /*
717 * The NFS client is responsible for the "." and ".."
718 * entries in the directory. So, we put them at the top.
719 */
720 if ((uiop->uio_offset == 0) &&
721 ((2*(4 + DIRHDSIZ)) <= uio_uio_resid(uiop))) {
722 /* add "." entry */
723 len = 2;
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;
728 dp->d_namlen = len;
729 dp->d_reclen = tlen + DIRHDSIZ;
730 dp->d_type = DT_DIR;
731 strlcpy(dp->d_name, ".", len);
732 blksiz += dp->d_reclen;
733 if (blksiz == DIRBLKSIZ)
734 blksiz = 0;
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));
739 /* add ".." entry */
740 len = 3;
741 tlen = nfsm_rndup(len);
742 // LP64todo - fix this!
743 dp = (struct dirent *) CAST_DOWN(caddr_t, uio_iov_base(uiop));
744 if (dnp->n_parent)
745 dp->d_fileno = VTONFS(dnp->n_parent)->n_vattr.nva_fileid;
746 else
747 dp->d_fileno = dnp->n_vattr.nva_fileid;
748 dp->d_namlen = len;
749 dp->d_reclen = tlen + DIRHDSIZ;
750 dp->d_type = DT_DIR;
751 strlcpy(dp->d_name, "..", len);
752 blksiz += dp->d_reclen;
753 if (blksiz == DIRBLKSIZ)
754 blksiz = 0;
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;
761 }
762
763 /*
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.
767 */
768 while (more_entries && bigenough) {
769 nfsm_chain_null(&nmreq);
770 nfsm_chain_null(&nmrep);
771 nfsm_assert(error, NFSTONMP(dnp), ENXIO);
772
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);
776 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);
779 numops--;
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);
783 numops--;
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);
790 else
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);
799 nfs_unlock(dnp);
800 nfsmout_if(error);
801 error = nfs_request(dnp, NULL, &nmreq, NFSPROC4_COMPOUND, ctx, &nmrep, &xid, &status);
802
803 if ((lockerror = nfs_lock(dnp, NFS_NODE_LOCK_EXCLUSIVE)))
804 error = lockerror;
805 savexid = xid;
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);
815 nfs_unlock(dnp);
816 nfsmout_if(error);
817
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);
825 nfsmout_if(error);
826 /* Note: NFS supports longer names, but struct dirent doesn't */
827 /* so we just truncate the names to fit */
828 if (len <= 0) {
829 error = EBADRPC;
830 goto nfsmout;
831 }
832 if (len > MAXNAMLEN) {
833 skiplen = len - MAXNAMLEN;
834 len = MAXNAMLEN;
835 } else {
836 skiplen = 0;
837 }
838 tlen = nfsm_rndup(len);
839 if (tlen == 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);
848 blksiz = 0;
849 }
850 if ((tlen + DIRHDSIZ) > uio_uio_resid(uiop)) {
851 bigenough = 0;
852 break;
853 }
854 // LP64todo - fix this!
855 dp = (struct dirent *) CAST_DOWN(caddr_t, uio_iov_base(uiop));
856 dp->d_fileno = 0;
857 dp->d_namlen = len;
858 dp->d_reclen = tlen + DIRHDSIZ;
859 dp->d_type = DT_UNKNOWN;
860 blksiz += dp->d_reclen;
861 if (blksiz == DIRBLKSIZ)
862 blksiz = 0;
863 uiop->uio_offset += DIRHDSIZ;
864 #if LP64KERN
865 uio_uio_resid_add(uiop, -((int64_t)DIRHDSIZ));
866 uio_iov_len_add(uiop, -((int64_t)DIRHDSIZ));
867 #else
868 uio_uio_resid_add(uiop, -((int)DIRHDSIZ));
869 uio_iov_len_add(uiop, -((int)DIRHDSIZ));
870 #endif
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);
876 if (skiplen)
877 nfsm_chain_adv(error, &nmrep,
878 nfsm_rndup(len + skiplen) - nfsm_rndup(len));
879 nfsmout_if(error);
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);
885 error = 0;
886 }
887 nfsm_chain_get_32(error, &nmrep, more_entries);
888 nfsmout_if(error);
889
890 cp = CAST_DOWN(caddr_t, uio_iov_base(uiop));
891 tlen -= len;
892 *cp = '\0';
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);
897
898 /*
899 * Skip any "." and ".." entries returned from server.
900 * (Actually, just leave it in place with d_fileno == 0.)
901 */
902 if ((cnp->cn_nameptr[0] == '.') &&
903 ((len == 1) || ((len == 2) && (cnp->cn_nameptr[1] == '.')))) {
904 /* clear the name too */
905 dp->d_namlen = 0;
906 dp->d_name[0] = '\0';
907 continue;
908 }
909
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)) {
916 cnp->cn_hash = 0;
917 error = nfs_nget(NFSTOMP(dnp), dnp, cnp,
918 fh.fh_data, fh.fh_len, &nvattr, &xid, NG_MAKEENTRY, &np);
919 if (!error) {
920 nfs_unlock(np);
921 vnode_put(NFSTOV(np));
922 }
923 }
924 nfsmout_if(error);
925 }
926 /* If at end of rpc data, get the eof boolean */
927 if (!more_entries) {
928 nfsm_chain_get_32(error, &nmrep, eof);
929 if (!error)
930 more_entries = (eof == 0);
931 }
932 if ((lockerror = nfs_lock(dnp, NFS_NODE_LOCK_SHARED)))
933 error = lockerror;
934 nfsmout_if(error);
935 nfsm_chain_cleanup(&nmrep);
936 }
937 nfs_unlock(dnp);
938 /*
939 * Fill last record, iff any, out to a multiple of DIRBLKSIZ
940 * by increasing d_reclen for the last record.
941 */
942 if (blksiz > 0) {
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);
949 }
950
951 if ((lockerror = nfs_lock(dnp, NFS_NODE_LOCK_EXCLUSIVE)))
952 error = lockerror;
953 nfsmout_if(error);
954
955 /*
956 * We are now either at the end of the directory or have filled the
957 * block.
958 */
959 if (bigenough)
960 dnp->n_direofoffset = uiop->uio_offset;
961 else {
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);
965 if (cookiep)
966 *cookiep = cookie;
967 }
968
969 nfs_unlock(dnp);
970 nfsmout:
971 nfsm_chain_cleanup(&nmreq);
972 nfsm_chain_cleanup(&nmrep);
973 return (error);
974 }
975
976 int
977 nfs4_lookup_rpc_async(
978 nfsnode_t dnp,
979 char *name,
980 int namelen,
981 vfs_context_t ctx,
982 struct nfsreq **reqp)
983 {
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;
988
989 nmp = NFSTONMP(dnp);
990 if (!nmp)
991 return (ENXIO);
992 nfsvers = nmp->nm_vers;
993
994 if ((name[0] == '.') && (name[1] == '.') && (namelen == 2))
995 isdotdot = 1;
996
997 nfsm_chain_null(&nmreq);
998
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);
1003 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);
1006 numops--;
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);
1010 numops--;
1011 if (isdotdot) {
1012 nfsm_chain_add_32(error, &nmreq, NFS_OP_LOOKUPP);
1013 } else {
1014 nfsm_chain_add_32(error, &nmreq, NFS_OP_LOOKUP);
1015 nfsm_chain_add_string(error, &nmreq, name, namelen);
1016 }
1017 if (getattrs) {
1018 numops--;
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);
1024 }
1025 nfsm_chain_build_done(error, &nmreq);
1026 nfsm_assert(error, (numops == 0), EPROTO);
1027 nfsmout_if(error);
1028 error = nfs_request_async(dnp, NULL, &nmreq, NFSPROC4_COMPOUND,
1029 vfs_context_thread(ctx), vfs_context_ucred(ctx), NULL, reqp);
1030 nfsmout:
1031 nfsm_chain_cleanup(&nmreq);
1032 return (error);
1033 }
1034
1035 int
1036 nfs4_lookup_rpc_async_finish(
1037 nfsnode_t dnp,
1038 __unused vfs_context_t ctx,
1039 struct nfsreq *req,
1040 u_int64_t *xidp,
1041 fhandle_t *fhp,
1042 struct nfs_vattr *nvap)
1043 {
1044 int error = 0, status, nfsvers, numops;
1045 uint32_t val = 0;
1046 u_int64_t xid;
1047 struct nfsmount *nmp;
1048 struct nfsm_chain nmrep;
1049
1050 nmp = NFSTONMP(dnp);
1051 nfsvers = nmp->nm_vers;
1052
1053 nfsm_chain_null(&nmrep);
1054
1055 error = nfs_request_async_finish(req, &nmrep, &xid, &status);
1056
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);
1061 if (xidp)
1062 *xidp = xid;
1063 nfsm_chain_loadattr(error, &nmrep, dnp, nfsvers, NULL, &xid);
1064
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);
1070
1071 nfsmout_if(error || !fhp || !nvap);
1072 nfsm_chain_op_check(error, &nmrep, NFS_OP_GETATTR);
1073 nfsmout_if(error);
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)) {
1077 error = EBADRPC;
1078 goto nfsmout;
1079 }
1080 nfsmout:
1081 nfsm_chain_cleanup(&nmrep);
1082 return (error);
1083 }
1084
1085 int
1086 nfs4_commit_rpc(
1087 nfsnode_t np,
1088 u_int64_t offset,
1089 u_int64_t count,
1090 kauth_cred_t cred)
1091 {
1092 struct nfsmount *nmp;
1093 int error = 0, lockerror, status, nfsvers, numops;
1094 u_int64_t xid, wverf;
1095 uint32_t count32;
1096 struct nfsm_chain nmreq, nmrep;
1097
1098 nmp = NFSTONMP(np);
1099 FSDBG(521, np, offset, count, nmp ? nmp->nm_state : 0);
1100 if (!nmp)
1101 return (ENXIO);
1102 if (!(nmp->nm_state & NFSSTA_HASWRITEVERF))
1103 return (0);
1104 nfsvers = nmp->nm_vers;
1105
1106 if (count > UINT32_MAX)
1107 count32 = 0;
1108 else
1109 count32 = count;
1110
1111 nfsm_chain_null(&nmreq);
1112 nfsm_chain_null(&nmrep);
1113
1114 // PUTFH, COMMIT, GETATTR
1115 numops = 3;
1116 nfsm_chain_build_alloc_init(error, &nmreq, 19 * NFSX_UNSIGNED);
1117 nfsm_chain_add_compound_header(error, &nmreq, "commit", numops);
1118 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);
1121 numops--;
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);
1125 numops--;
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);
1131 nfsmout_if(error);
1132 error = nfs_request2(np, NULL, &nmreq, NFSPROC4_COMPOUND,
1133 current_thread(), cred, 0, &nmrep, &xid, &status);
1134
1135 if ((lockerror = nfs_lock(np, NFS_NODE_LOCK_EXCLUSIVE)))
1136 error = lockerror;
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);
1144 if (!lockerror)
1145 nfs_unlock(np);
1146 nfsmout_if(error);
1147 lck_mtx_lock(&nmp->nm_lock);
1148 if (nmp->nm_verf != wverf) {
1149 nmp->nm_verf = wverf;
1150 error = NFSERR_STALEWRITEVERF;
1151 }
1152 lck_mtx_unlock(&nmp->nm_lock);
1153 nfsmout:
1154 nfsm_chain_cleanup(&nmreq);
1155 nfsm_chain_cleanup(&nmrep);
1156 return (error);
1157 }
1158
1159 int
1160 nfs4_pathconf_rpc(
1161 nfsnode_t np,
1162 struct nfs_fsattr *nfsap,
1163 vfs_context_t ctx)
1164 {
1165 u_int64_t xid;
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;
1171
1172 if (!nmp)
1173 return (ENXIO);
1174 nfsvers = nmp->nm_vers;
1175
1176 nfsm_chain_null(&nmreq);
1177 nfsm_chain_null(&nmrep);
1178
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);
1183 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);
1186 numops--;
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);
1199 nfsmout_if(error);
1200 error = nfs_request(np, NULL, &nmreq, NFSPROC4_COMPOUND, ctx, &nmrep, &xid, &status);
1201
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);
1206 nfsmout_if(error);
1207 NFS_CLEAR_ATTRIBUTES(nvattr.nva_bitmap);
1208 error = nfs4_parsefattr(&nmrep, nfsap, &nvattr, NULL, NULL);
1209 nfsmout_if(error);
1210 if ((lockerror = nfs_lock(np, NFS_NODE_LOCK_EXCLUSIVE)))
1211 error = lockerror;
1212 nfs_loadattrcache(np, &nvattr, &xid, 0);
1213 if (!lockerror)
1214 nfs_unlock(np);
1215 nfsmout:
1216 nfsm_chain_cleanup(&nmreq);
1217 nfsm_chain_cleanup(&nmrep);
1218 return (error);
1219 }
1220
1221 int
1222 nfs4_vnop_getattr(
1223 struct vnop_getattr_args /* {
1224 struct vnodeop_desc *a_desc;
1225 vnode_t a_vp;
1226 struct vnode_attr *a_vap;
1227 vfs_context_t a_context;
1228 } */ *ap)
1229 {
1230 struct vnode_attr *vap = ap->a_vap;
1231 struct nfs_vattr nva;
1232 int error;
1233
1234 error = nfs_getattr(VTONFS(ap->a_vp), &nva, ap->a_context, 0);
1235 if (error)
1236 return (error);
1237
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);
1242 }
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)) {
1259 uint32_t flags = 0;
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))
1263 flags |= UF_HIDDEN;
1264 VATTR_RETURN(vap, va_flags, flags);
1265 }
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);
1270 }
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);
1275 }
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);
1280 }
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);
1285 }
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);
1290 }
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);
1297
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 */
1303
1304 return (error);
1305 }
1306
1307 int
1308 nfs4_setattr_rpc(
1309 nfsnode_t np,
1310 struct vnode_attr *vap,
1311 vfs_context_t ctx,
1312 int alreadylocked)
1313 {
1314 struct nfsmount *nmp = NFSTONMP(np);
1315 int error = 0, lockerror = ENOENT, status, nfsvers, numops;
1316 u_int64_t xid;
1317 struct nfsm_chain nmreq, nmrep;
1318 uint32_t bitmap[NFS_ATTR_BITMAP_LEN], bmlen, stateid;
1319
1320 if (!nmp)
1321 return (ENXIO);
1322 nfsvers = nmp->nm_vers;
1323
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 */
1328 else
1329 return (ENOTSUP); /* return ENOTSUP for chflags(2) */
1330 }
1331
1332 nfsm_chain_null(&nmreq);
1333 nfsm_chain_null(&nmrep);
1334
1335 // PUTFH, SETATTR, GETATTR
1336 numops = 3;
1337 nfsm_chain_build_alloc_init(error, &nmreq, 40 * NFSX_UNSIGNED);
1338 nfsm_chain_add_compound_header(error, &nmreq, "setattr", numops);
1339 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);
1342 numops--;
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 */
1346 else
1347 stateid = 0;
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);
1353 numops--;
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);
1359 nfsmout_if(error);
1360 error = nfs_request(np, NULL, &nmreq, NFSPROC4_COMPOUND, ctx, &nmrep, &xid, &status);
1361
1362 if (!alreadylocked && ((lockerror = nfs_lock(np, NFS_NODE_LOCK_EXCLUSIVE))))
1363 error = lockerror;
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);
1370 nfsmout_if(error);
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);
1374 if (error)
1375 NATTRINVALIDATE(np);
1376 nfsmout:
1377 if (!alreadylocked && !lockerror)
1378 nfs_unlock(np);
1379 nfsm_chain_cleanup(&nmreq);
1380 nfsm_chain_cleanup(&nmrep);
1381 return (error);
1382 }
1383
1384 int
1385 nfs4_vnop_open(struct vnop_open_args *ap)
1386 {
1387 return nfs3_vnop_open(ap);
1388 }
1389
1390 int
1391 nfs4_vnop_close(struct vnop_close_args *ap)
1392 {
1393 return nfs3_vnop_close(ap);
1394 }
1395
1396 int
1397 nfs4_vnop_advlock(__unused struct vnop_advlock_args *ap)
1398 {
1399 return (ENOSYS);
1400 }
1401
1402 /*
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.
1406 */
1407 int
1408 nfs4_vnop_create(
1409 struct vnop_create_args /* {
1410 struct vnodeop_desc *a_desc;
1411 vnode_t a_dvp;
1412 vnode_t *a_vpp;
1413 struct componentname *a_cnp;
1414 struct vnode_attr *a_vap;
1415 vfs_context_t a_context;
1416 } */ *ap)
1417 {
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;
1434 fhandle_t fh;
1435 struct nfsreq *req = NULL;
1436 struct nfs_dulookup dul;
1437
1438 static uint32_t nfs4_open_owner_hack = 0;
1439
1440 nmp = VTONMP(dvp);
1441 if (!nmp)
1442 return (ENXIO);
1443 nfsvers = nmp->nm_vers;
1444
1445 seqid = stateid[0] = stateid[1] = stateid[2] = stateid[3] = 0;
1446 rflags = 0;
1447
1448 nfs_dulookup_init(&dul, dnp, cnp->cn_nameptr, cnp->cn_namelen);
1449
1450 nfsm_chain_null(&nmreq);
1451 nfsm_chain_null(&nmrep);
1452
1453 // PUTFH, SAVEFH, OPEN(CREATE), GETATTR(FH), RESTOREFH, GETATTR
1454 numops = 6;
1455 nfsm_chain_build_alloc_init(error, &nmreq, 53 * NFSX_UNSIGNED + cnp->cn_namelen);
1456 nfsm_chain_add_compound_header(error, &nmreq, "create", numops);
1457 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);
1460 numops--;
1461 nfsm_chain_add_32(error, &nmreq, NFS_OP_SAVEFH);
1462 numops--;
1463 nfsm_chain_add_32(error, &nmreq, NFS_OP_OPEN);
1464 nfsm_chain_add_32(error, &nmreq, seqid);
1465 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
1472 // openflag4
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);
1476 // open_claim4
1477 nfsm_chain_add_32(error, &nmreq, NFS_CLAIM_NULL);
1478 nfsm_chain_add_string(error, &nmreq, cnp->cn_nameptr, cnp->cn_namelen);
1479 numops--;
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);
1485 numops--;
1486 nfsm_chain_add_32(error, &nmreq, NFS_OP_RESTOREFH);
1487 numops--;
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);
1493 nfsmout_if(error);
1494 if ((lockerror = nfs_lock(dnp, NFS_NODE_LOCK_EXCLUSIVE)))
1495 error = lockerror;
1496 nfsmout_if(error);
1497
1498 error = nfs_request_async(dnp, NULL, &nmreq, NFSPROC4_COMPOUND,
1499 vfs_context_thread(ctx), vfs_context_ucred(ctx), NULL, &req);
1500 if (!error) {
1501 nfs_dulookup_start(&dul, dnp, ctx);
1502 error = nfs_request_async_finish(req, &nmrep, &xid, &status);
1503 }
1504 savedxid = xid;
1505
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);
1520 if (!error)
1521 switch (delegation) {
1522 case NFS_OPEN_DELEGATE_NONE:
1523 break;
1524 case NFS_OPEN_DELEGATE_READ:
1525 printf("nfs4_vnop_create: read delegation?\n");
1526 nfsm_chain_adv(error, &nmrep, 5*NFSX_UNSIGNED);
1527 // ACE:
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));
1531 break;
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);
1536 // ACE:
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));
1540 break;
1541 default:
1542 error = EBADRPC;
1543 break;
1544 }
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;
1548 nfsmout_if(error);
1549 nfs_vattr_set_supported(bitmap, vap);
1550 nfsm_chain_op_check(error, &nmrep, NFS_OP_GETATTR);
1551 nfsmout_if(error);
1552 NFS_CLEAR_ATTRIBUTES(nvattr.nva_bitmap);
1553 error = nfs4_parsefattr(&nmrep, NULL, &nvattr, &fh, NULL);
1554 nfsmout_if(error);
1555 if (!NFS_BITMAP_ISSET(nvattr.nva_bitmap, NFS_FATTR_FILEHANDLE)) {
1556 printf("nfs: open/create didn't return filehandle?\n");
1557 error = EBADRPC;
1558 goto nfsmout;
1559 }
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);
1564 if (error)
1565 NATTRINVALIDATE(dnp);
1566
1567 if (rflags & NFS_OPEN_RESULT_CONFIRM) {
1568 nfsm_chain_cleanup(&nmreq);
1569 nfsm_chain_cleanup(&nmrep);
1570 // PUTFH, OPEN_CONFIRM, GETATTR
1571 numops = 3;
1572 nfsm_chain_build_alloc_init(error, &nmreq, 23 * NFSX_UNSIGNED);
1573 nfsm_chain_add_compound_header(error, &nmreq, "create_confirm", numops);
1574 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);
1577 numops--;
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);
1584 seqid++;
1585 numops--;
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);
1591 nfsmout_if(error);
1592 error = nfs_request(dnp, NULL, &nmreq, NFSPROC4_COMPOUND, ctx, &nmrep, &xid, &status);
1593
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);
1603 nfsmout_if(error);
1604 NFS_CLEAR_ATTRIBUTES(nvattr.nva_bitmap);
1605 error = nfs4_parsefattr(&nmrep, NULL, &nvattr, NULL, NULL);
1606 nfsmout_if(error);
1607 savedxid = xid;
1608 }
1609 nfsmout_if(error);
1610 nfsm_chain_cleanup(&nmreq);
1611 nfsm_chain_cleanup(&nmrep);
1612
1613 // PUTFH, CLOSE
1614 numops = 2;
1615 nfsm_chain_build_alloc_init(error, &nmreq, 19 * NFSX_UNSIGNED);
1616 nfsm_chain_add_compound_header(error, &nmreq, "create_close", numops);
1617 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);
1620 numops--;
1621 nfsm_chain_add_32(error, &nmreq, NFS_OP_CLOSE);
1622 nfsm_chain_add_32(error, &nmreq, seqid);
1623 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);
1630 nfsmout_if(error);
1631 error = nfs_request(dnp, NULL, &nmreq, NFSPROC4_COMPOUND, ctx, &nmrep, &xid, &status);
1632
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]);
1641 if (error)
1642 printf("nfs4_vnop_create: close error %d\n", error);
1643
1644 nfsmout:
1645 nfsm_chain_cleanup(&nmreq);
1646 nfsm_chain_cleanup(&nmrep);
1647
1648 if (!lockerror) {
1649 if (!create_error && (dnp->n_flag & NNEGNCENTRIES)) {
1650 dnp->n_flag &= ~NNEGNCENTRIES;
1651 cache_purge_negatives(dvp);
1652 }
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;
1657 cache_purge(dvp);
1658 NFS_CHANGED_UPDATE_NC(nfsvers, dnp, &dnvattr);
1659 }
1660 }
1661 }
1662
1663 if (!error && fh.fh_len) {
1664 /* create the vnode with the filehandle and attributes */
1665 xid = savedxid;
1666 error = nfs_nget(NFSTOMP(dnp), dnp, cnp, fh.fh_data, fh.fh_len, &nvattr, &xid, NG_MAKEENTRY, &np);
1667 if (!error)
1668 newvp = NFSTOV(np);
1669 }
1670
1671 nfs_dulookup_finish(&dul, dnp, ctx);
1672
1673 /*
1674 * Kludge: Map EEXIST => 0 assuming that you have a reply to a retry
1675 * if we can succeed in looking up the object.
1676 */
1677 if ((create_error == EEXIST) || (!create_error && !newvp)) {
1678 error = nfs_lookitup(dnp, cnp->cn_nameptr, cnp->cn_namelen, ctx, &np);
1679 if (!error) {
1680 newvp = NFSTOV(np);
1681 if (vnode_vtype(newvp) != VLNK)
1682 error = EEXIST;
1683 }
1684 }
1685 if (!lockerror)
1686 nfs_unlock(dnp);
1687 if (error) {
1688 if (newvp) {
1689 nfs_unlock(np);
1690 vnode_put(newvp);
1691 }
1692 } else {
1693 nfs_unlock(np);
1694 *vpp = newvp;
1695 }
1696 return (error);
1697 }
1698
1699 /*
1700 * Note: the NFSv4 CREATE RPC is for everything EXCEPT regular files.
1701 */
1702 static int
1703 nfs4_create_rpc(
1704 vfs_context_t ctx,
1705 nfsnode_t dnp,
1706 struct componentname *cnp,
1707 struct vnode_attr *vap,
1708 int type,
1709 char *link,
1710 nfsnode_t *npp)
1711 {
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;
1721 const char *tag;
1722 nfs_specdata sd;
1723 fhandle_t fh;
1724 struct nfsreq *req = NULL;
1725 struct nfs_dulookup dul;
1726
1727 nmp = NFSTONMP(dnp);
1728 if (!nmp)
1729 return (ENXIO);
1730 nfsvers = nmp->nm_vers;
1731
1732 sd.specdata1 = sd.specdata2 = 0;
1733
1734 switch (type) {
1735 case NFLNK:
1736 tag = "symlink";
1737 break;
1738 case NFBLK:
1739 case NFCHR:
1740 tag = "mknod";
1741 if (!VATTR_IS_ACTIVE(vap, va_rdev))
1742 return (EINVAL);
1743 sd.specdata1 = major(vap->va_rdev);
1744 sd.specdata2 = minor(vap->va_rdev);
1745 break;
1746 case NFSOCK:
1747 case NFFIFO:
1748 tag = "mknod";
1749 break;
1750 case NFDIR:
1751 tag = "mkdir";
1752 break;
1753 default:
1754 return (EINVAL);
1755 }
1756
1757 nfs_dulookup_init(&dul, dnp, cnp->cn_nameptr, cnp->cn_namelen);
1758
1759 nfsm_chain_null(&nmreq);
1760 nfsm_chain_null(&nmrep);
1761
1762 // PUTFH, SAVEFH, CREATE, GETATTR(FH), RESTOREFH, GETATTR
1763 numops = 6;
1764 nfsm_chain_build_alloc_init(error, &nmreq, 66 * NFSX_UNSIGNED);
1765 nfsm_chain_add_compound_header(error, &nmreq, tag, numops);
1766 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);
1769 numops--;
1770 nfsm_chain_add_32(error, &nmreq, NFS_OP_SAVEFH);
1771 numops--;
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);
1779 }
1780 nfsm_chain_add_string(error, &nmreq, cnp->cn_nameptr, cnp->cn_namelen);
1781 nfsm_chain_add_fattr4(error, &nmreq, vap, nmp);
1782 numops--;
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);
1788 numops--;
1789 nfsm_chain_add_32(error, &nmreq, NFS_OP_RESTOREFH);
1790 numops--;
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);
1796 nfsmout_if(error);
1797 if ((lockerror = nfs_lock(dnp, NFS_NODE_LOCK_EXCLUSIVE)))
1798 error = lockerror;
1799 nfsmout_if(error);
1800
1801 error = nfs_request_async(dnp, NULL, &nmreq, NFSPROC4_COMPOUND,
1802 vfs_context_thread(ctx), vfs_context_ucred(ctx), NULL, &req);
1803 if (!error) {
1804 nfs_dulookup_start(&dul, dnp, ctx);
1805 error = nfs_request_async_finish(req, &nmrep, &xid, &status);
1806 }
1807
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);
1812 nfsmout_if(error);
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;
1820 nfsmout_if(error);
1821 nfs_vattr_set_supported(bitmap, vap);
1822 nfsm_chain_op_check(error, &nmrep, NFS_OP_GETATTR);
1823 nfsmout_if(error);
1824 NFS_CLEAR_ATTRIBUTES(nvattr.nva_bitmap);
1825 error = nfs4_parsefattr(&nmrep, NULL, &nvattr, &fh, NULL);
1826 nfsmout_if(error);
1827 if (!NFS_BITMAP_ISSET(nvattr.nva_bitmap, NFS_FATTR_FILEHANDLE)) {
1828 printf("nfs: create/%s didn't return filehandle?\n", tag);
1829 error = EBADRPC;
1830 goto nfsmout;
1831 }
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);
1835 savedxid = xid;
1836 nfsm_chain_loadattr(error, &nmrep, dnp, nfsvers, NULL, &xid);
1837 if (error)
1838 NATTRINVALIDATE(dnp);
1839
1840 nfsmout:
1841 nfsm_chain_cleanup(&nmreq);
1842 nfsm_chain_cleanup(&nmrep);
1843
1844 if (!lockerror) {
1845 if (!create_error && (dnp->n_flag & NNEGNCENTRIES)) {
1846 dnp->n_flag &= ~NNEGNCENTRIES;
1847 cache_purge_negatives(NFSTOV(dnp));
1848 }
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);
1855 }
1856 }
1857 }
1858
1859 if (!error && fh.fh_len) {
1860 /* create the vnode with the filehandle and attributes */
1861 xid = savedxid;
1862 error = nfs_nget(NFSTOMP(dnp), dnp, cnp, fh.fh_data, fh.fh_len, &nvattr, &xid, NG_MAKEENTRY, &np);
1863 if (!error)
1864 newvp = NFSTOV(np);
1865 }
1866
1867 nfs_dulookup_finish(&dul, dnp, ctx);
1868
1869 /*
1870 * Kludge: Map EEXIST => 0 assuming that you have a reply to a retry
1871 * if we can succeed in looking up the object.
1872 */
1873 if ((create_error == EEXIST) || (!create_error && !newvp)) {
1874 error = nfs_lookitup(dnp, cnp->cn_nameptr, cnp->cn_namelen, ctx, &np);
1875 if (!error) {
1876 newvp = NFSTOV(np);
1877 if (vnode_vtype(newvp) != VLNK)
1878 error = EEXIST;
1879 }
1880 }
1881 if (!lockerror)
1882 nfs_unlock(dnp);
1883 if (error) {
1884 if (newvp) {
1885 nfs_unlock(np);
1886 vnode_put(newvp);
1887 }
1888 } else {
1889 nfs_unlock(np);
1890 *npp = np;
1891 }
1892 return (error);
1893 }
1894
1895 int
1896 nfs4_vnop_mknod(
1897 struct vnop_mknod_args /* {
1898 struct vnodeop_desc *a_desc;
1899 vnode_t a_dvp;
1900 vnode_t *a_vpp;
1901 struct componentname *a_cnp;
1902 struct vnode_attr *a_vap;
1903 vfs_context_t a_context;
1904 } */ *ap)
1905 {
1906 nfsnode_t np = NULL;
1907 struct nfsmount *nmp;
1908 int error;
1909
1910 nmp = VTONMP(ap->a_dvp);
1911 if (!nmp)
1912 return (ENXIO);
1913
1914 if (!VATTR_IS_ACTIVE(ap->a_vap, va_type))
1915 return (EINVAL);
1916 switch (ap->a_vap->va_type) {
1917 case VBLK:
1918 case VCHR:
1919 case VFIFO:
1920 case VSOCK:
1921 break;
1922 default:
1923 return (ENOTSUP);
1924 }
1925
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);
1928 if (!error)
1929 *ap->a_vpp = NFSTOV(np);
1930 return (error);
1931 }
1932
1933 int
1934 nfs4_vnop_mkdir(
1935 struct vnop_mkdir_args /* {
1936 struct vnodeop_desc *a_desc;
1937 vnode_t a_dvp;
1938 vnode_t *a_vpp;
1939 struct componentname *a_cnp;
1940 struct vnode_attr *a_vap;
1941 vfs_context_t a_context;
1942 } */ *ap)
1943 {
1944 nfsnode_t np = NULL;
1945 int error;
1946
1947 error = nfs4_create_rpc(ap->a_context, VTONFS(ap->a_dvp), ap->a_cnp, ap->a_vap,
1948 NFDIR, NULL, &np);
1949 if (!error)
1950 *ap->a_vpp = NFSTOV(np);
1951 return (error);
1952 }
1953
1954 int
1955 nfs4_vnop_symlink(
1956 struct vnop_symlink_args /* {
1957 struct vnodeop_desc *a_desc;
1958 vnode_t a_dvp;
1959 vnode_t *a_vpp;
1960 struct componentname *a_cnp;
1961 struct vnode_attr *a_vap;
1962 char *a_target;
1963 vfs_context_t a_context;
1964 } */ *ap)
1965 {
1966 nfsnode_t np = NULL;
1967 int error;
1968
1969 error = nfs4_create_rpc(ap->a_context, VTONFS(ap->a_dvp), ap->a_cnp, ap->a_vap,
1970 NFLNK, ap->a_target, &np);
1971 if (!error)
1972 *ap->a_vpp = NFSTOV(np);
1973 return (error);
1974 }
1975
1976 int
1977 nfs4_vnop_link(
1978 struct vnop_link_args /* {
1979 struct vnodeop_desc *a_desc;
1980 vnode_t a_vp;
1981 vnode_t a_tdvp;
1982 struct componentname *a_cnp;
1983 vfs_context_t a_context;
1984 } */ *ap)
1985 {
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;
1997
1998 if (vnode_mount(vp) != vnode_mount(tdvp))
1999 return (EXDEV);
2000
2001 nmp = VTONMP(vp);
2002 if (!nmp)
2003 return (ENXIO);
2004 nfsvers = nmp->nm_vers;
2005
2006 /*
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!
2010 */
2011 nfs_flush(np, MNT_WAIT, vfs_context_thread(ctx), V_IGNORE_WRITEERR);
2012
2013 error = nfs_lock2(tdnp, np, NFS_NODE_LOCK_EXCLUSIVE);
2014 if (error)
2015 return (error);
2016
2017 nfsm_chain_null(&nmreq);
2018 nfsm_chain_null(&nmrep);
2019
2020 // PUTFH(SOURCE), SAVEFH, PUTFH(DIR), LINK, GETATTR(DIR), RESTOREFH, GETATTR
2021 numops = 7;
2022 nfsm_chain_build_alloc_init(error, &nmreq, 29 * NFSX_UNSIGNED + cnp->cn_namelen);
2023 nfsm_chain_add_compound_header(error, &nmreq, "link", numops);
2024 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);
2027 numops--;
2028 nfsm_chain_add_32(error, &nmreq, NFS_OP_SAVEFH);
2029 numops--;
2030 nfsm_chain_add_32(error, &nmreq, NFS_OP_PUTFH);
2031 nfsm_chain_add_fh(error, &nmreq, nfsvers, tdnp->n_fhp, tdnp->n_fhsize);
2032 numops--;
2033 nfsm_chain_add_32(error, &nmreq, NFS_OP_LINK);
2034 nfsm_chain_add_string(error, &nmreq, cnp->cn_nameptr, cnp->cn_namelen);
2035 numops--;
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);
2039 numops--;
2040 nfsm_chain_add_32(error, &nmreq, NFS_OP_RESTOREFH);
2041 numops--;
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);
2047 nfsmout_if(error);
2048 error = nfs_request(tdnp, NULL, &nmreq, NFSPROC4_COMPOUND, ctx, &nmrep, &xid, &status);
2049
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);
2059 savedxid = xid;
2060 nfsm_chain_loadattr(error, &nmrep, tdnp, nfsvers, NULL, &xid);
2061 if (error)
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);
2066 xid = savedxid;
2067 nfsm_chain_loadattr(error, &nmrep, np, nfsvers, NULL, &xid);
2068 if (error)
2069 NATTRINVALIDATE(np);
2070 nfsmout:
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)
2076 error = 0;
2077 if (!error && (tdnp->n_flag & NNEGNCENTRIES)) {
2078 tdnp->n_flag &= ~NNEGNCENTRIES;
2079 cache_purge_negatives(tdvp);
2080 }
2081 nfs_unlock2(tdnp, np);
2082 return (error);
2083 }
2084
2085 int
2086 nfs4_vnop_rmdir(
2087 struct vnop_rmdir_args /* {
2088 struct vnodeop_desc *a_desc;
2089 vnode_t a_dvp;
2090 vnode_t a_vp;
2091 struct componentname *a_cnp;
2092 vfs_context_t a_context;
2093 } */ *ap)
2094 {
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;
2099 int error = 0;
2100 nfsnode_t np = VTONFS(vp);
2101 nfsnode_t dnp = VTONFS(dvp);
2102 struct nfs_vattr dnvattr;
2103 struct nfs_dulookup dul;
2104
2105 if (vnode_vtype(vp) != VDIR)
2106 return (EINVAL);
2107
2108 nfs_dulookup_init(&dul, dnp, cnp->cn_nameptr, cnp->cn_namelen);
2109
2110 if ((error = nfs_lock2(dnp, np, NFS_NODE_LOCK_EXCLUSIVE)))
2111 return (error);
2112
2113 nfs_dulookup_start(&dul, dnp, ctx);
2114
2115 error = nfs4_remove_rpc(dnp, cnp->cn_nameptr, cnp->cn_namelen,
2116 vfs_context_thread(ctx), vfs_context_ucred(ctx));
2117
2118 cache_purge(vp);
2119 if (!nfs_getattr(dnp, &dnvattr, ctx, 1)) {
2120 if (NFS_CHANGED_NC(NFS_VER4, dnp, &dnvattr)) {
2121 dnp->n_flag &= ~NNEGNCENTRIES;
2122 cache_purge(dvp);
2123 NFS_CHANGED_UPDATE_NC(NFS_VER4, dnp, &dnvattr);
2124 }
2125 }
2126
2127 nfs_dulookup_finish(&dul, dnp, ctx);
2128 nfs_unlock2(dnp, np);
2129
2130 /*
2131 * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry.
2132 */
2133 if (error == ENOENT)
2134 error = 0;
2135 if (!error) {
2136 /*
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
2140 */
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);
2146 }
2147 lck_mtx_unlock(nfs_node_hash_mutex);
2148 }
2149 return (error);
2150 }
2151