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
81int
82nfs4_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];
146nfsmout:
147	nfsm_chain_cleanup(&nmreq);
148	nfsm_chain_cleanup(&nmrep);
149	return (error);
150}
151
152int
153nfs4_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);
195nfsmout:
196	nfsm_chain_cleanup(&nmreq);
197	nfsm_chain_cleanup(&nmrep);
198	return (error);
199}
200
201int
202nfs4_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;
252nfsmout:
253	if (!lockerror)
254		nfs_unlock(np);
255	nfsm_chain_cleanup(&nmreq);
256	nfsm_chain_cleanup(&nmrep);
257	return (error);
258}
259
260int
261nfs4_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);
307nfsmout:
308	nfsm_chain_cleanup(&nmreq);
309	return (error);
310}
311
312int
313nfs4_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
364int
365nfs4_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);
419nfsmout:
420	nfsm_chain_cleanup(&nmreq);
421	return (error);
422}
423
424int
425nfs4_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);
481nfsmout:
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
492int
493nfs4_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);
544nfsmout:
545	nfsm_chain_cleanup(&nmreq);
546	nfsm_chain_cleanup(&nmrep);
547
548	dnp->n_flag |= NMODIFIED;
549
550	return (remove_error);
551}
552
553int
554nfs4_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);
628nfsmout:
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)))
643int
644nfs4_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);
970nfsmout:
971	nfsm_chain_cleanup(&nmreq);
972	nfsm_chain_cleanup(&nmrep);
973	return (error);
974}
975
976int
977nfs4_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);
1030nfsmout:
1031	nfsm_chain_cleanup(&nmreq);
1032	return (error);
1033}
1034
1035int
1036nfs4_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	}
1080nfsmout:
1081	nfsm_chain_cleanup(&nmrep);
1082	return (error);
1083}
1084
1085int
1086nfs4_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);
1153nfsmout:
1154	nfsm_chain_cleanup(&nmreq);
1155	nfsm_chain_cleanup(&nmrep);
1156	return (error);
1157}
1158
1159int
1160nfs4_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);
1215nfsmout:
1216	nfsm_chain_cleanup(&nmreq);
1217	nfsm_chain_cleanup(&nmrep);
1218	return (error);
1219}
1220
1221int
1222nfs4_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
1307int
1308nfs4_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);
1376nfsmout:
1377	if (!alreadylocked && !lockerror)
1378		nfs_unlock(np);
1379	nfsm_chain_cleanup(&nmreq);
1380	nfsm_chain_cleanup(&nmrep);
1381	return (error);
1382}
1383
1384int
1385nfs4_vnop_open(struct vnop_open_args *ap)
1386{
1387	return nfs3_vnop_open(ap);
1388}
1389
1390int
1391nfs4_vnop_close(struct vnop_close_args *ap)
1392{
1393	return nfs3_vnop_close(ap);
1394}
1395
1396int
1397nfs4_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 */
1407int
1408nfs4_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
1644nfsmout:
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 */
1702static int
1703nfs4_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
1840nfsmout:
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
1895int
1896nfs4_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
1933int
1934nfs4_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
1954int
1955nfs4_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
1976int
1977nfs4_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);
2070nfsmout:
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
2085int
2086nfs4_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
2152