xref: /freebsd/sys/fs/nfsclient/nfs_clrpcops.c (revision 7cd2dcf07629713e5a3d60472cfe4701b705a167)
1 /*-
2  * Copyright (c) 1989, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Rick Macklem at The University of Guelph.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 4. Neither the name of the University nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  *
32  */
33 
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
36 
37 /*
38  * Rpc op calls, generally called from the vnode op calls or through the
39  * buffer cache, for NFS v2, 3 and 4.
40  * These do not normally make any changes to vnode arguments or use
41  * structures that might change between the VFS variants. The returned
42  * arguments are all at the end, after the NFSPROC_T *p one.
43  */
44 
45 #ifndef APPLEKEXT
46 #include "opt_inet6.h"
47 
48 #include <fs/nfs/nfsport.h>
49 
50 /*
51  * Global variables
52  */
53 extern int nfs_numnfscbd;
54 extern struct timeval nfsboottime;
55 extern u_int32_t newnfs_false, newnfs_true;
56 extern nfstype nfsv34_type[9];
57 extern int nfsrv_useacl;
58 extern char nfsv4_callbackaddr[INET6_ADDRSTRLEN];
59 extern int nfscl_debuglevel;
60 NFSCLSTATEMUTEX;
61 int nfstest_outofseq = 0;
62 int nfscl_assumeposixlocks = 1;
63 int nfscl_enablecallb = 0;
64 short nfsv4_cbport = NFSV4_CBPORT;
65 int nfstest_openallsetattr = 0;
66 #endif	/* !APPLEKEXT */
67 
68 #define	DIRHDSIZ	(sizeof (struct dirent) - (MAXNAMLEN + 1))
69 
70 static int nfsrpc_setattrrpc(vnode_t , struct vattr *, nfsv4stateid_t *,
71     struct ucred *, NFSPROC_T *, struct nfsvattr *, int *, void *);
72 static int nfsrpc_readrpc(vnode_t , struct uio *, struct ucred *,
73     nfsv4stateid_t *, NFSPROC_T *, struct nfsvattr *, int *, void *);
74 static int nfsrpc_writerpc(vnode_t , struct uio *, int *, int *,
75     struct ucred *, nfsv4stateid_t *, NFSPROC_T *, struct nfsvattr *, int *,
76     void *);
77 static int nfsrpc_createv23(vnode_t , char *, int, struct vattr *,
78     nfsquad_t, int, struct ucred *, NFSPROC_T *, struct nfsvattr *,
79     struct nfsvattr *, struct nfsfh **, int *, int *, void *);
80 static int nfsrpc_createv4(vnode_t , char *, int, struct vattr *,
81     nfsquad_t, int, struct nfsclowner *, struct nfscldeleg **, struct ucred *,
82     NFSPROC_T *, struct nfsvattr *, struct nfsvattr *, struct nfsfh **, int *,
83     int *, void *, int *);
84 static int nfsrpc_locku(struct nfsrv_descript *, struct nfsmount *,
85     struct nfscllockowner *, u_int64_t, u_int64_t,
86     u_int32_t, struct ucred *, NFSPROC_T *, int);
87 static int nfsrpc_setaclrpc(vnode_t, struct ucred *, NFSPROC_T *,
88     struct acl *, nfsv4stateid_t *, void *);
89 
90 /*
91  * nfs null call from vfs.
92  */
93 APPLESTATIC int
94 nfsrpc_null(vnode_t vp, struct ucred *cred, NFSPROC_T *p)
95 {
96 	int error;
97 	struct nfsrv_descript nfsd, *nd = &nfsd;
98 
99 	NFSCL_REQSTART(nd, NFSPROC_NULL, vp);
100 	error = nfscl_request(nd, vp, p, cred, NULL);
101 	if (nd->nd_repstat && !error)
102 		error = nd->nd_repstat;
103 	mbuf_freem(nd->nd_mrep);
104 	return (error);
105 }
106 
107 /*
108  * nfs access rpc op.
109  * For nfs version 3 and 4, use the access rpc to check accessibility. If file
110  * modes are changed on the server, accesses might still fail later.
111  */
112 APPLESTATIC int
113 nfsrpc_access(vnode_t vp, int acmode, struct ucred *cred,
114     NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp)
115 {
116 	int error;
117 	u_int32_t mode, rmode;
118 
119 	if (acmode & VREAD)
120 		mode = NFSACCESS_READ;
121 	else
122 		mode = 0;
123 	if (vnode_vtype(vp) == VDIR) {
124 		if (acmode & VWRITE)
125 			mode |= (NFSACCESS_MODIFY | NFSACCESS_EXTEND |
126 				 NFSACCESS_DELETE);
127 		if (acmode & VEXEC)
128 			mode |= NFSACCESS_LOOKUP;
129 	} else {
130 		if (acmode & VWRITE)
131 			mode |= (NFSACCESS_MODIFY | NFSACCESS_EXTEND);
132 		if (acmode & VEXEC)
133 			mode |= NFSACCESS_EXECUTE;
134 	}
135 
136 	/*
137 	 * Now, just call nfsrpc_accessrpc() to do the actual RPC.
138 	 */
139 	error = nfsrpc_accessrpc(vp, mode, cred, p, nap, attrflagp, &rmode,
140 	    NULL);
141 
142 	/*
143 	 * The NFS V3 spec does not clarify whether or not
144 	 * the returned access bits can be a superset of
145 	 * the ones requested, so...
146 	 */
147 	if (!error && (rmode & mode) != mode)
148 		error = EACCES;
149 	return (error);
150 }
151 
152 /*
153  * The actual rpc, separated out for Darwin.
154  */
155 APPLESTATIC int
156 nfsrpc_accessrpc(vnode_t vp, u_int32_t mode, struct ucred *cred,
157     NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, u_int32_t *rmodep,
158     void *stuff)
159 {
160 	u_int32_t *tl;
161 	u_int32_t supported, rmode;
162 	int error;
163 	struct nfsrv_descript nfsd, *nd = &nfsd;
164 	nfsattrbit_t attrbits;
165 
166 	*attrflagp = 0;
167 	supported = mode;
168 	NFSCL_REQSTART(nd, NFSPROC_ACCESS, vp);
169 	NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
170 	*tl = txdr_unsigned(mode);
171 	if (nd->nd_flag & ND_NFSV4) {
172 		/*
173 		 * And do a Getattr op.
174 		 */
175 		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
176 		*tl = txdr_unsigned(NFSV4OP_GETATTR);
177 		NFSGETATTR_ATTRBIT(&attrbits);
178 		(void) nfsrv_putattrbit(nd, &attrbits);
179 	}
180 	error = nfscl_request(nd, vp, p, cred, stuff);
181 	if (error)
182 		return (error);
183 	if (nd->nd_flag & ND_NFSV3) {
184 		error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
185 		if (error)
186 			goto nfsmout;
187 	}
188 	if (!nd->nd_repstat) {
189 		if (nd->nd_flag & ND_NFSV4) {
190 			NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
191 			supported = fxdr_unsigned(u_int32_t, *tl++);
192 		} else {
193 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
194 		}
195 		rmode = fxdr_unsigned(u_int32_t, *tl);
196 		if (nd->nd_flag & ND_NFSV4)
197 			error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
198 
199 		/*
200 		 * It's not obvious what should be done about
201 		 * unsupported access modes. For now, be paranoid
202 		 * and clear the unsupported ones.
203 		 */
204 		rmode &= supported;
205 		*rmodep = rmode;
206 	} else
207 		error = nd->nd_repstat;
208 nfsmout:
209 	mbuf_freem(nd->nd_mrep);
210 	return (error);
211 }
212 
213 /*
214  * nfs open rpc
215  */
216 APPLESTATIC int
217 nfsrpc_open(vnode_t vp, int amode, struct ucred *cred, NFSPROC_T *p)
218 {
219 	struct nfsclopen *op;
220 	struct nfscldeleg *dp;
221 	struct nfsfh *nfhp;
222 	struct nfsnode *np = VTONFS(vp);
223 	struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
224 	u_int32_t mode, clidrev;
225 	int ret, newone, error, expireret = 0, retrycnt;
226 
227 	/*
228 	 * For NFSv4, Open Ops are only done on Regular Files.
229 	 */
230 	if (vnode_vtype(vp) != VREG)
231 		return (0);
232 	mode = 0;
233 	if (amode & FREAD)
234 		mode |= NFSV4OPEN_ACCESSREAD;
235 	if (amode & FWRITE)
236 		mode |= NFSV4OPEN_ACCESSWRITE;
237 	nfhp = np->n_fhp;
238 
239 	retrycnt = 0;
240 #ifdef notdef
241 { char name[100]; int namel;
242 namel = (np->n_v4->n4_namelen < 100) ? np->n_v4->n4_namelen : 99;
243 bcopy(NFS4NODENAME(np->n_v4), name, namel);
244 name[namel] = '\0';
245 printf("rpcopen p=0x%x name=%s",p->p_pid,name);
246 if (nfhp->nfh_len > 0) printf(" fh=0x%x\n",nfhp->nfh_fh[12]);
247 else printf(" fhl=0\n");
248 }
249 #endif
250 	do {
251 	    dp = NULL;
252 	    error = nfscl_open(vp, nfhp->nfh_fh, nfhp->nfh_len, mode, 1,
253 		cred, p, NULL, &op, &newone, &ret, 1);
254 	    if (error) {
255 		return (error);
256 	    }
257 	    if (nmp->nm_clp != NULL)
258 		clidrev = nmp->nm_clp->nfsc_clientidrev;
259 	    else
260 		clidrev = 0;
261 	    if (ret == NFSCLOPEN_DOOPEN) {
262 		if (np->n_v4 != NULL) {
263 			error = nfsrpc_openrpc(nmp, vp, np->n_v4->n4_data,
264 			   np->n_v4->n4_fhlen, np->n_fhp->nfh_fh,
265 			   np->n_fhp->nfh_len, mode, op,
266 			   NFS4NODENAME(np->n_v4), np->n_v4->n4_namelen, &dp,
267 			   0, 0x0, cred, p, 0, 0);
268 			if (dp != NULL) {
269 #ifdef APPLE
270 				OSBitAndAtomic((int32_t)~NDELEGMOD, (UInt32 *)&np->n_flag);
271 #else
272 				NFSLOCKNODE(np);
273 				np->n_flag &= ~NDELEGMOD;
274 				/*
275 				 * Invalidate the attribute cache, so that
276 				 * attributes that pre-date the issue of a
277 				 * delegation are not cached, since the
278 				 * cached attributes will remain valid while
279 				 * the delegation is held.
280 				 */
281 				NFSINVALATTRCACHE(np);
282 				NFSUNLOCKNODE(np);
283 #endif
284 				(void) nfscl_deleg(nmp->nm_mountp,
285 				    op->nfso_own->nfsow_clp,
286 				    nfhp->nfh_fh, nfhp->nfh_len, cred, p, &dp);
287 			}
288 		} else {
289 			error = EIO;
290 		}
291 		newnfs_copyincred(cred, &op->nfso_cred);
292 	    } else if (ret == NFSCLOPEN_SETCRED)
293 		/*
294 		 * This is a new local open on a delegation. It needs
295 		 * to have credentials so that an open can be done
296 		 * against the server during recovery.
297 		 */
298 		newnfs_copyincred(cred, &op->nfso_cred);
299 
300 	    /*
301 	     * nfso_opencnt is the count of how many VOP_OPEN()s have
302 	     * been done on this Open successfully and a VOP_CLOSE()
303 	     * is expected for each of these.
304 	     * If error is non-zero, don't increment it, since the Open
305 	     * hasn't succeeded yet.
306 	     */
307 	    if (!error)
308 		op->nfso_opencnt++;
309 	    nfscl_openrelease(op, error, newone);
310 	    if (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID ||
311 		error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY) {
312 		(void) nfs_catnap(PZERO, error, "nfs_open");
313 	    } else if ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID)
314 		&& clidrev != 0) {
315 		expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
316 		retrycnt++;
317 	    }
318 	} while (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID ||
319 	    error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
320 	    ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
321 	     expireret == 0 && clidrev != 0 && retrycnt < 4));
322 	if (error && retrycnt >= 4)
323 		error = EIO;
324 	return (error);
325 }
326 
327 /*
328  * the actual open rpc
329  */
330 APPLESTATIC int
331 nfsrpc_openrpc(struct nfsmount *nmp, vnode_t vp, u_int8_t *nfhp, int fhlen,
332     u_int8_t *newfhp, int newfhlen, u_int32_t mode, struct nfsclopen *op,
333     u_int8_t *name, int namelen, struct nfscldeleg **dpp,
334     int reclaim, u_int32_t delegtype, struct ucred *cred, NFSPROC_T *p,
335     int syscred, int recursed)
336 {
337 	u_int32_t *tl;
338 	struct nfsrv_descript nfsd, *nd = &nfsd;
339 	struct nfscldeleg *dp, *ndp = NULL;
340 	struct nfsvattr nfsva;
341 	u_int32_t rflags, deleg;
342 	nfsattrbit_t attrbits;
343 	int error, ret, acesize, limitby;
344 
345 	dp = *dpp;
346 	*dpp = NULL;
347 	nfscl_reqstart(nd, NFSPROC_OPEN, nmp, nfhp, fhlen, NULL);
348 	NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
349 	*tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid);
350 	*tl++ = txdr_unsigned(mode & NFSV4OPEN_ACCESSBOTH);
351 	*tl++ = txdr_unsigned((mode >> NFSLCK_SHIFT) & NFSV4OPEN_DENYBOTH);
352 	*tl++ = op->nfso_own->nfsow_clp->nfsc_clientid.lval[0];
353 	*tl = op->nfso_own->nfsow_clp->nfsc_clientid.lval[1];
354 	(void) nfsm_strtom(nd, op->nfso_own->nfsow_owner, NFSV4CL_LOCKNAMELEN);
355 	NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
356 	*tl++ = txdr_unsigned(NFSV4OPEN_NOCREATE);
357 	if (reclaim) {
358 		*tl = txdr_unsigned(NFSV4OPEN_CLAIMPREVIOUS);
359 		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
360 		*tl = txdr_unsigned(delegtype);
361 	} else {
362 		if (dp != NULL) {
363 			*tl = txdr_unsigned(NFSV4OPEN_CLAIMDELEGATECUR);
364 			NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
365 			*tl++ = dp->nfsdl_stateid.seqid;
366 			*tl++ = dp->nfsdl_stateid.other[0];
367 			*tl++ = dp->nfsdl_stateid.other[1];
368 			*tl = dp->nfsdl_stateid.other[2];
369 		} else {
370 			*tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL);
371 		}
372 		(void) nfsm_strtom(nd, name, namelen);
373 	}
374 	NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
375 	*tl = txdr_unsigned(NFSV4OP_GETATTR);
376 	NFSZERO_ATTRBIT(&attrbits);
377 	NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE);
378 	NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFY);
379 	(void) nfsrv_putattrbit(nd, &attrbits);
380 	if (syscred)
381 		nd->nd_flag |= ND_USEGSSNAME;
382 	error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, vp, p, cred,
383 	    NFS_PROG, NFS_VER4, NULL, 1, NULL);
384 	if (error)
385 		return (error);
386 	NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd);
387 	if (!nd->nd_repstat) {
388 		NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
389 		    6 * NFSX_UNSIGNED);
390 		op->nfso_stateid.seqid = *tl++;
391 		op->nfso_stateid.other[0] = *tl++;
392 		op->nfso_stateid.other[1] = *tl++;
393 		op->nfso_stateid.other[2] = *tl;
394 		rflags = fxdr_unsigned(u_int32_t, *(tl + 6));
395 		error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
396 		if (error)
397 			goto nfsmout;
398 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
399 		deleg = fxdr_unsigned(u_int32_t, *tl);
400 		if (deleg == NFSV4OPEN_DELEGATEREAD ||
401 		    deleg == NFSV4OPEN_DELEGATEWRITE) {
402 			if (!(op->nfso_own->nfsow_clp->nfsc_flags &
403 			      NFSCLFLAGS_FIRSTDELEG))
404 				op->nfso_own->nfsow_clp->nfsc_flags |=
405 				  (NFSCLFLAGS_FIRSTDELEG | NFSCLFLAGS_GOTDELEG);
406 			MALLOC(ndp, struct nfscldeleg *,
407 			    sizeof (struct nfscldeleg) + newfhlen,
408 			    M_NFSCLDELEG, M_WAITOK);
409 			LIST_INIT(&ndp->nfsdl_owner);
410 			LIST_INIT(&ndp->nfsdl_lock);
411 			ndp->nfsdl_clp = op->nfso_own->nfsow_clp;
412 			ndp->nfsdl_fhlen = newfhlen;
413 			NFSBCOPY(newfhp, ndp->nfsdl_fh, newfhlen);
414 			newnfs_copyincred(cred, &ndp->nfsdl_cred);
415 			nfscl_lockinit(&ndp->nfsdl_rwlock);
416 			NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
417 			    NFSX_UNSIGNED);
418 			ndp->nfsdl_stateid.seqid = *tl++;
419 			ndp->nfsdl_stateid.other[0] = *tl++;
420 			ndp->nfsdl_stateid.other[1] = *tl++;
421 			ndp->nfsdl_stateid.other[2] = *tl++;
422 			ret = fxdr_unsigned(int, *tl);
423 			if (deleg == NFSV4OPEN_DELEGATEWRITE) {
424 				ndp->nfsdl_flags = NFSCLDL_WRITE;
425 				/*
426 				 * Indicates how much the file can grow.
427 				 */
428 				NFSM_DISSECT(tl, u_int32_t *,
429 				    3 * NFSX_UNSIGNED);
430 				limitby = fxdr_unsigned(int, *tl++);
431 				switch (limitby) {
432 				case NFSV4OPEN_LIMITSIZE:
433 					ndp->nfsdl_sizelimit = fxdr_hyper(tl);
434 					break;
435 				case NFSV4OPEN_LIMITBLOCKS:
436 					ndp->nfsdl_sizelimit =
437 					    fxdr_unsigned(u_int64_t, *tl++);
438 					ndp->nfsdl_sizelimit *=
439 					    fxdr_unsigned(u_int64_t, *tl);
440 					break;
441 				default:
442 					error = NFSERR_BADXDR;
443 					goto nfsmout;
444 				};
445 			} else {
446 				ndp->nfsdl_flags = NFSCLDL_READ;
447 			}
448 			if (ret)
449 				ndp->nfsdl_flags |= NFSCLDL_RECALL;
450 			error = nfsrv_dissectace(nd, &ndp->nfsdl_ace, &ret,
451 			    &acesize, p);
452 			if (error)
453 				goto nfsmout;
454 		} else if (deleg != NFSV4OPEN_DELEGATENONE) {
455 			error = NFSERR_BADXDR;
456 			goto nfsmout;
457 		}
458 		NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
459 		error = nfsv4_loadattr(nd, NULL, &nfsva, NULL,
460 		    NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
461 		    NULL, NULL, NULL, p, cred);
462 		if (error)
463 			goto nfsmout;
464 		if (ndp != NULL) {
465 			ndp->nfsdl_change = nfsva.na_filerev;
466 			ndp->nfsdl_modtime = nfsva.na_mtime;
467 			ndp->nfsdl_flags |= NFSCLDL_MODTIMESET;
468 		}
469 		if (!reclaim && (rflags & NFSV4OPEN_RESULTCONFIRM)) {
470 		    do {
471 			ret = nfsrpc_openconfirm(vp, newfhp, newfhlen, op,
472 			    cred, p);
473 			if (ret == NFSERR_DELAY)
474 			    (void) nfs_catnap(PZERO, ret, "nfs_open");
475 		    } while (ret == NFSERR_DELAY);
476 		    error = ret;
477 		}
478 		if ((rflags & NFSV4OPEN_LOCKTYPEPOSIX) ||
479 		    nfscl_assumeposixlocks)
480 		    op->nfso_posixlock = 1;
481 		else
482 		    op->nfso_posixlock = 0;
483 
484 		/*
485 		 * If the server is handing out delegations, but we didn't
486 		 * get one because an OpenConfirm was required, try the
487 		 * Open again, to get a delegation. This is a harmless no-op,
488 		 * from a server's point of view.
489 		 */
490 		if (!reclaim && (rflags & NFSV4OPEN_RESULTCONFIRM) &&
491 		    (op->nfso_own->nfsow_clp->nfsc_flags & NFSCLFLAGS_GOTDELEG)
492 		    && !error && dp == NULL && ndp == NULL && !recursed) {
493 		    do {
494 			ret = nfsrpc_openrpc(nmp, vp, nfhp, fhlen, newfhp,
495 			    newfhlen, mode, op, name, namelen, &ndp, 0, 0x0,
496 			    cred, p, syscred, 1);
497 			if (ret == NFSERR_DELAY)
498 			    (void) nfs_catnap(PZERO, ret, "nfs_open2");
499 		    } while (ret == NFSERR_DELAY);
500 		    if (ret) {
501 			if (ndp != NULL)
502 				FREE((caddr_t)ndp, M_NFSCLDELEG);
503 			if (ret == NFSERR_STALECLIENTID ||
504 			    ret == NFSERR_STALEDONTRECOVER)
505 				error = ret;
506 		    }
507 		}
508 	}
509 	if (nd->nd_repstat != 0 && error == 0)
510 		error = nd->nd_repstat;
511 	if (error == NFSERR_STALECLIENTID)
512 		nfscl_initiate_recovery(op->nfso_own->nfsow_clp);
513 nfsmout:
514 	if (!error)
515 		*dpp = ndp;
516 	else if (ndp != NULL)
517 		FREE((caddr_t)ndp, M_NFSCLDELEG);
518 	mbuf_freem(nd->nd_mrep);
519 	return (error);
520 }
521 
522 /*
523  * open downgrade rpc
524  */
525 APPLESTATIC int
526 nfsrpc_opendowngrade(vnode_t vp, u_int32_t mode, struct nfsclopen *op,
527     struct ucred *cred, NFSPROC_T *p)
528 {
529 	u_int32_t *tl;
530 	struct nfsrv_descript nfsd, *nd = &nfsd;
531 	int error;
532 
533 	NFSCL_REQSTART(nd, NFSPROC_OPENDOWNGRADE, vp);
534 	NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED);
535 	*tl++ = op->nfso_stateid.seqid;
536 	*tl++ = op->nfso_stateid.other[0];
537 	*tl++ = op->nfso_stateid.other[1];
538 	*tl++ = op->nfso_stateid.other[2];
539 	*tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid);
540 	*tl++ = txdr_unsigned(mode & NFSV4OPEN_ACCESSBOTH);
541 	*tl = txdr_unsigned((mode >> NFSLCK_SHIFT) & NFSV4OPEN_DENYBOTH);
542 	error = nfscl_request(nd, vp, p, cred, NULL);
543 	if (error)
544 		return (error);
545 	NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd);
546 	if (!nd->nd_repstat) {
547 		NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
548 		op->nfso_stateid.seqid = *tl++;
549 		op->nfso_stateid.other[0] = *tl++;
550 		op->nfso_stateid.other[1] = *tl++;
551 		op->nfso_stateid.other[2] = *tl;
552 	}
553 	if (nd->nd_repstat && error == 0)
554 		error = nd->nd_repstat;
555 	if (error == NFSERR_STALESTATEID)
556 		nfscl_initiate_recovery(op->nfso_own->nfsow_clp);
557 nfsmout:
558 	mbuf_freem(nd->nd_mrep);
559 	return (error);
560 }
561 
562 /*
563  * V4 Close operation.
564  */
565 APPLESTATIC int
566 nfsrpc_close(vnode_t vp, int doclose, NFSPROC_T *p)
567 {
568 	struct nfsclclient *clp;
569 	int error;
570 
571 	if (vnode_vtype(vp) != VREG)
572 		return (0);
573 	if (doclose)
574 		error = nfscl_doclose(vp, &clp, p);
575 	else
576 		error = nfscl_getclose(vp, &clp);
577 	if (error)
578 		return (error);
579 
580 	nfscl_clientrelease(clp);
581 	return (0);
582 }
583 
584 /*
585  * Close the open.
586  */
587 APPLESTATIC void
588 nfsrpc_doclose(struct nfsmount *nmp, struct nfsclopen *op, NFSPROC_T *p)
589 {
590 	struct nfsrv_descript nfsd, *nd = &nfsd;
591 	struct nfscllockowner *lp, *nlp;
592 	struct nfscllock *lop, *nlop;
593 	struct ucred *tcred;
594 	u_int64_t off = 0, len = 0;
595 	u_int32_t type = NFSV4LOCKT_READ;
596 	int error, do_unlock, trycnt;
597 
598 	tcred = newnfs_getcred();
599 	newnfs_copycred(&op->nfso_cred, tcred);
600 	/*
601 	 * (Theoretically this could be done in the same
602 	 *  compound as the close, but having multiple
603 	 *  sequenced Ops in the same compound might be
604 	 *  too scary for some servers.)
605 	 */
606 	if (op->nfso_posixlock) {
607 		off = 0;
608 		len = NFS64BITSSET;
609 		type = NFSV4LOCKT_READ;
610 	}
611 
612 	/*
613 	 * Since this function is only called from VOP_INACTIVE(), no
614 	 * other thread will be manipulating this Open. As such, the
615 	 * lock lists are not being changed by other threads, so it should
616 	 * be safe to do this without locking.
617 	 */
618 	LIST_FOREACH(lp, &op->nfso_lock, nfsl_list) {
619 		do_unlock = 1;
620 		LIST_FOREACH_SAFE(lop, &lp->nfsl_lock, nfslo_list, nlop) {
621 			if (op->nfso_posixlock == 0) {
622 				off = lop->nfslo_first;
623 				len = lop->nfslo_end - lop->nfslo_first;
624 				if (lop->nfslo_type == F_WRLCK)
625 					type = NFSV4LOCKT_WRITE;
626 				else
627 					type = NFSV4LOCKT_READ;
628 			}
629 			if (do_unlock) {
630 				trycnt = 0;
631 				do {
632 					error = nfsrpc_locku(nd, nmp, lp, off,
633 					    len, type, tcred, p, 0);
634 					if ((nd->nd_repstat == NFSERR_GRACE ||
635 					    nd->nd_repstat == NFSERR_DELAY) &&
636 					    error == 0)
637 						(void) nfs_catnap(PZERO,
638 						    (int)nd->nd_repstat,
639 						    "nfs_close");
640 				} while ((nd->nd_repstat == NFSERR_GRACE ||
641 				    nd->nd_repstat == NFSERR_DELAY) &&
642 				    error == 0 && trycnt++ < 5);
643 				if (op->nfso_posixlock)
644 					do_unlock = 0;
645 			}
646 			nfscl_freelock(lop, 0);
647 		}
648 		/*
649 		 * Do a ReleaseLockOwner.
650 		 * The lock owner name nfsl_owner may be used by other opens for
651 		 * other files but the lock_owner4 name that nfsrpc_rellockown()
652 		 * puts on the wire has the file handle for this file appended
653 		 * to it, so it can be done now.
654 		 */
655 		(void)nfsrpc_rellockown(nmp, lp, lp->nfsl_open->nfso_fh,
656 		    lp->nfsl_open->nfso_fhlen, tcred, p);
657 	}
658 
659 	/*
660 	 * There could be other Opens for different files on the same
661 	 * OpenOwner, so locking is required.
662 	 */
663 	NFSLOCKCLSTATE();
664 	nfscl_lockexcl(&op->nfso_own->nfsow_rwlock, NFSCLSTATEMUTEXPTR);
665 	NFSUNLOCKCLSTATE();
666 	do {
667 		error = nfscl_tryclose(op, tcred, nmp, p);
668 		if (error == NFSERR_GRACE)
669 			(void) nfs_catnap(PZERO, error, "nfs_close");
670 	} while (error == NFSERR_GRACE);
671 	NFSLOCKCLSTATE();
672 	nfscl_lockunlock(&op->nfso_own->nfsow_rwlock);
673 
674 	LIST_FOREACH_SAFE(lp, &op->nfso_lock, nfsl_list, nlp)
675 		nfscl_freelockowner(lp, 0);
676 	nfscl_freeopen(op, 0);
677 	NFSUNLOCKCLSTATE();
678 	NFSFREECRED(tcred);
679 }
680 
681 /*
682  * The actual Close RPC.
683  */
684 APPLESTATIC int
685 nfsrpc_closerpc(struct nfsrv_descript *nd, struct nfsmount *nmp,
686     struct nfsclopen *op, struct ucred *cred, NFSPROC_T *p,
687     int syscred)
688 {
689 	u_int32_t *tl;
690 	int error;
691 
692 	nfscl_reqstart(nd, NFSPROC_CLOSE, nmp, op->nfso_fh,
693 	    op->nfso_fhlen, NULL);
694 	NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID);
695 	*tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid);
696 	*tl++ = op->nfso_stateid.seqid;
697 	*tl++ = op->nfso_stateid.other[0];
698 	*tl++ = op->nfso_stateid.other[1];
699 	*tl = op->nfso_stateid.other[2];
700 	if (syscred)
701 		nd->nd_flag |= ND_USEGSSNAME;
702 	error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
703 	    NFS_PROG, NFS_VER4, NULL, 1, NULL);
704 	if (error)
705 		return (error);
706 	NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd);
707 	if (nd->nd_repstat == 0)
708 		NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
709 	error = nd->nd_repstat;
710 	if (error == NFSERR_STALESTATEID)
711 		nfscl_initiate_recovery(op->nfso_own->nfsow_clp);
712 nfsmout:
713 	mbuf_freem(nd->nd_mrep);
714 	return (error);
715 }
716 
717 /*
718  * V4 Open Confirm RPC.
719  */
720 APPLESTATIC int
721 nfsrpc_openconfirm(vnode_t vp, u_int8_t *nfhp, int fhlen,
722     struct nfsclopen *op, struct ucred *cred, NFSPROC_T *p)
723 {
724 	u_int32_t *tl;
725 	struct nfsrv_descript nfsd, *nd = &nfsd;
726 	int error;
727 
728 	nfscl_reqstart(nd, NFSPROC_OPENCONFIRM, VFSTONFS(vnode_mount(vp)),
729 	    nfhp, fhlen, NULL);
730 	NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID);
731 	*tl++ = op->nfso_stateid.seqid;
732 	*tl++ = op->nfso_stateid.other[0];
733 	*tl++ = op->nfso_stateid.other[1];
734 	*tl++ = op->nfso_stateid.other[2];
735 	*tl = txdr_unsigned(op->nfso_own->nfsow_seqid);
736 	error = nfscl_request(nd, vp, p, cred, NULL);
737 	if (error)
738 		return (error);
739 	NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd);
740 	if (!nd->nd_repstat) {
741 		NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
742 		op->nfso_stateid.seqid = *tl++;
743 		op->nfso_stateid.other[0] = *tl++;
744 		op->nfso_stateid.other[1] = *tl++;
745 		op->nfso_stateid.other[2] = *tl;
746 	}
747 	error = nd->nd_repstat;
748 	if (error == NFSERR_STALESTATEID)
749 		nfscl_initiate_recovery(op->nfso_own->nfsow_clp);
750 nfsmout:
751 	mbuf_freem(nd->nd_mrep);
752 	return (error);
753 }
754 
755 /*
756  * Do the setclientid and setclientid confirm RPCs. Called from nfs_statfs()
757  * when a mount has just occurred and when the server replies NFSERR_EXPIRED.
758  */
759 APPLESTATIC int
760 nfsrpc_setclient(struct nfsmount *nmp, struct nfsclclient *clp,
761     struct ucred *cred, NFSPROC_T *p)
762 {
763 	u_int32_t *tl;
764 	struct nfsrv_descript nfsd;
765 	struct nfsrv_descript *nd = &nfsd;
766 	nfsattrbit_t attrbits;
767 	u_int8_t *cp = NULL, *cp2, addr[INET6_ADDRSTRLEN + 9];
768 	u_short port;
769 	int error, isinet6 = 0, callblen;
770 	nfsquad_t confirm;
771 	u_int32_t lease;
772 	static u_int32_t rev = 0;
773 
774 	if (nfsboottime.tv_sec == 0)
775 		NFSSETBOOTTIME(nfsboottime);
776 	nfscl_reqstart(nd, NFSPROC_SETCLIENTID, nmp, NULL, 0, NULL);
777 	NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
778 	*tl++ = txdr_unsigned(nfsboottime.tv_sec);
779 	*tl = txdr_unsigned(rev++);
780 	(void) nfsm_strtom(nd, clp->nfsc_id, clp->nfsc_idlen);
781 
782 	/*
783 	 * set up the callback address
784 	 */
785 	NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
786 	*tl = txdr_unsigned(NFS_CALLBCKPROG);
787 	callblen = strlen(nfsv4_callbackaddr);
788 	if (callblen == 0)
789 		cp = nfscl_getmyip(nmp, &isinet6);
790 	if (nfscl_enablecallb && nfs_numnfscbd > 0 &&
791 	    (callblen > 0 || cp != NULL)) {
792 		port = htons(nfsv4_cbport);
793 		cp2 = (u_int8_t *)&port;
794 #ifdef INET6
795 		if ((callblen > 0 &&
796 		     strchr(nfsv4_callbackaddr, ':')) || isinet6) {
797 			char ip6buf[INET6_ADDRSTRLEN], *ip6add;
798 
799 			(void) nfsm_strtom(nd, "tcp6", 4);
800 			if (callblen == 0) {
801 				ip6_sprintf(ip6buf, (struct in6_addr *)cp);
802 				ip6add = ip6buf;
803 			} else {
804 				ip6add = nfsv4_callbackaddr;
805 			}
806 			snprintf(addr, INET6_ADDRSTRLEN + 9, "%s.%d.%d",
807 			    ip6add, cp2[0], cp2[1]);
808 		} else
809 #endif
810 		{
811 			(void) nfsm_strtom(nd, "tcp", 3);
812 			if (callblen == 0)
813 				snprintf(addr, INET6_ADDRSTRLEN + 9,
814 				    "%d.%d.%d.%d.%d.%d", cp[0], cp[1],
815 				    cp[2], cp[3], cp2[0], cp2[1]);
816 			else
817 				snprintf(addr, INET6_ADDRSTRLEN + 9,
818 				    "%s.%d.%d", nfsv4_callbackaddr,
819 				    cp2[0], cp2[1]);
820 		}
821 		(void) nfsm_strtom(nd, addr, strlen(addr));
822 	} else {
823 		(void) nfsm_strtom(nd, "tcp", 3);
824 		(void) nfsm_strtom(nd, "0.0.0.0.0.0", 11);
825 	}
826 	NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
827 	*tl = txdr_unsigned(clp->nfsc_cbident);
828 	nd->nd_flag |= ND_USEGSSNAME;
829 	error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
830 		NFS_PROG, NFS_VER4, NULL, 1, NULL);
831 	if (error)
832 		return (error);
833 	if (nd->nd_repstat == 0) {
834 	    NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
835 	    clp->nfsc_clientid.lval[0] = *tl++;
836 	    clp->nfsc_clientid.lval[1] = *tl++;
837 	    confirm.lval[0] = *tl++;
838 	    confirm.lval[1] = *tl;
839 	    mbuf_freem(nd->nd_mrep);
840 	    nd->nd_mrep = NULL;
841 
842 	    /*
843 	     * and confirm it.
844 	     */
845 	    nfscl_reqstart(nd, NFSPROC_SETCLIENTIDCFRM, nmp, NULL, 0, NULL);
846 	    NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
847 	    *tl++ = clp->nfsc_clientid.lval[0];
848 	    *tl++ = clp->nfsc_clientid.lval[1];
849 	    *tl++ = confirm.lval[0];
850 	    *tl = confirm.lval[1];
851 	    nd->nd_flag |= ND_USEGSSNAME;
852 	    error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p,
853 		cred, NFS_PROG, NFS_VER4, NULL, 1, NULL);
854 	    if (error)
855 		return (error);
856 	    mbuf_freem(nd->nd_mrep);
857 	    nd->nd_mrep = NULL;
858 	    if (nd->nd_repstat == 0) {
859 		nfscl_reqstart(nd, NFSPROC_GETATTR, nmp, nmp->nm_fh,
860 		    nmp->nm_fhsize, NULL);
861 		NFSZERO_ATTRBIT(&attrbits);
862 		NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_LEASETIME);
863 		(void) nfsrv_putattrbit(nd, &attrbits);
864 		nd->nd_flag |= ND_USEGSSNAME;
865 		error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p,
866 		    cred, NFS_PROG, NFS_VER4, NULL, 1, NULL);
867 		if (error)
868 		    return (error);
869 		if (nd->nd_repstat == 0) {
870 		    error = nfsv4_loadattr(nd, NULL, NULL, NULL, NULL, 0, NULL,
871 			NULL, NULL, NULL, NULL, 0, NULL, &lease, NULL, p, cred);
872 		    if (error)
873 			goto nfsmout;
874 		    clp->nfsc_renew = NFSCL_RENEW(lease);
875 		    clp->nfsc_expire = NFSD_MONOSEC + clp->nfsc_renew;
876 		    clp->nfsc_clientidrev++;
877 		    if (clp->nfsc_clientidrev == 0)
878 			clp->nfsc_clientidrev++;
879 		}
880 	    }
881 	}
882 	error = nd->nd_repstat;
883 nfsmout:
884 	mbuf_freem(nd->nd_mrep);
885 	return (error);
886 }
887 
888 /*
889  * nfs getattr call.
890  */
891 APPLESTATIC int
892 nfsrpc_getattr(vnode_t vp, struct ucred *cred, NFSPROC_T *p,
893     struct nfsvattr *nap, void *stuff)
894 {
895 	struct nfsrv_descript nfsd, *nd = &nfsd;
896 	int error;
897 	nfsattrbit_t attrbits;
898 
899 	NFSCL_REQSTART(nd, NFSPROC_GETATTR, vp);
900 	if (nd->nd_flag & ND_NFSV4) {
901 		NFSGETATTR_ATTRBIT(&attrbits);
902 		(void) nfsrv_putattrbit(nd, &attrbits);
903 	}
904 	error = nfscl_request(nd, vp, p, cred, stuff);
905 	if (error)
906 		return (error);
907 	if (!nd->nd_repstat)
908 		error = nfsm_loadattr(nd, nap);
909 	else
910 		error = nd->nd_repstat;
911 	mbuf_freem(nd->nd_mrep);
912 	return (error);
913 }
914 
915 /*
916  * nfs getattr call with non-vnode arguemnts.
917  */
918 APPLESTATIC int
919 nfsrpc_getattrnovp(struct nfsmount *nmp, u_int8_t *fhp, int fhlen, int syscred,
920     struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, u_int64_t *xidp)
921 {
922 	struct nfsrv_descript nfsd, *nd = &nfsd;
923 	int error, vers = NFS_VER2;
924 	nfsattrbit_t attrbits;
925 
926 	nfscl_reqstart(nd, NFSPROC_GETATTR, nmp, fhp, fhlen, NULL);
927 	if (nd->nd_flag & ND_NFSV4) {
928 		vers = NFS_VER4;
929 		NFSGETATTR_ATTRBIT(&attrbits);
930 		(void) nfsrv_putattrbit(nd, &attrbits);
931 	} else if (nd->nd_flag & ND_NFSV3) {
932 		vers = NFS_VER3;
933 	}
934 	if (syscred)
935 		nd->nd_flag |= ND_USEGSSNAME;
936 	error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
937 	    NFS_PROG, vers, NULL, 1, xidp);
938 	if (error)
939 		return (error);
940 	if (!nd->nd_repstat)
941 		error = nfsm_loadattr(nd, nap);
942 	else
943 		error = nd->nd_repstat;
944 	mbuf_freem(nd->nd_mrep);
945 	return (error);
946 }
947 
948 /*
949  * Do an nfs setattr operation.
950  */
951 APPLESTATIC int
952 nfsrpc_setattr(vnode_t vp, struct vattr *vap, NFSACL_T *aclp,
953     struct ucred *cred, NFSPROC_T *p, struct nfsvattr *rnap, int *attrflagp,
954     void *stuff)
955 {
956 	int error, expireret = 0, openerr, retrycnt;
957 	u_int32_t clidrev = 0, mode;
958 	struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
959 	struct nfsfh *nfhp;
960 	nfsv4stateid_t stateid;
961 	void *lckp;
962 
963 	if (nmp->nm_clp != NULL)
964 		clidrev = nmp->nm_clp->nfsc_clientidrev;
965 	if (vap != NULL && NFSATTRISSET(u_quad_t, vap, va_size))
966 		mode = NFSV4OPEN_ACCESSWRITE;
967 	else
968 		mode = NFSV4OPEN_ACCESSREAD;
969 	retrycnt = 0;
970 	do {
971 		lckp = NULL;
972 		openerr = 1;
973 		if (NFSHASNFSV4(nmp)) {
974 			nfhp = VTONFS(vp)->n_fhp;
975 			error = nfscl_getstateid(vp, nfhp->nfh_fh,
976 			    nfhp->nfh_len, mode, cred, p, &stateid, &lckp);
977 			if (error && vnode_vtype(vp) == VREG &&
978 			    (mode == NFSV4OPEN_ACCESSWRITE ||
979 			     nfstest_openallsetattr)) {
980 				/*
981 				 * No Open stateid, so try and open the file
982 				 * now.
983 				 */
984 				if (mode == NFSV4OPEN_ACCESSWRITE)
985 					openerr = nfsrpc_open(vp, FWRITE, cred,
986 					    p);
987 				else
988 					openerr = nfsrpc_open(vp, FREAD, cred,
989 					    p);
990 				if (!openerr)
991 					(void) nfscl_getstateid(vp,
992 					    nfhp->nfh_fh, nfhp->nfh_len,
993 					    mode, cred, p, &stateid, &lckp);
994 			}
995 		}
996 		if (vap != NULL)
997 			error = nfsrpc_setattrrpc(vp, vap, &stateid, cred, p,
998 			    rnap, attrflagp, stuff);
999 		else
1000 			error = nfsrpc_setaclrpc(vp, cred, p, aclp, &stateid,
1001 			    stuff);
1002 		if (error == NFSERR_STALESTATEID)
1003 			nfscl_initiate_recovery(nmp->nm_clp);
1004 		if (lckp != NULL)
1005 			nfscl_lockderef(lckp);
1006 		if (!openerr)
1007 			(void) nfsrpc_close(vp, 0, p);
1008 		if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
1009 		    error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
1010 		    error == NFSERR_OLDSTATEID) {
1011 			(void) nfs_catnap(PZERO, error, "nfs_setattr");
1012 		} else if ((error == NFSERR_EXPIRED ||
1013 		    error == NFSERR_BADSTATEID) && clidrev != 0) {
1014 			expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
1015 		}
1016 		retrycnt++;
1017 	} while (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
1018 	    error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
1019 	    (error == NFSERR_OLDSTATEID && retrycnt < 20) ||
1020 	    ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
1021 	     expireret == 0 && clidrev != 0 && retrycnt < 4));
1022 	if (error && retrycnt >= 4)
1023 		error = EIO;
1024 	return (error);
1025 }
1026 
1027 static int
1028 nfsrpc_setattrrpc(vnode_t vp, struct vattr *vap,
1029     nfsv4stateid_t *stateidp, struct ucred *cred, NFSPROC_T *p,
1030     struct nfsvattr *rnap, int *attrflagp, void *stuff)
1031 {
1032 	u_int32_t *tl;
1033 	struct nfsrv_descript nfsd, *nd = &nfsd;
1034 	int error;
1035 	nfsattrbit_t attrbits;
1036 
1037 	*attrflagp = 0;
1038 	NFSCL_REQSTART(nd, NFSPROC_SETATTR, vp);
1039 	if (nd->nd_flag & ND_NFSV4)
1040 		nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID);
1041 	vap->va_type = vnode_vtype(vp);
1042 	nfscl_fillsattr(nd, vap, vp, NFSSATTR_FULL, 0);
1043 	if (nd->nd_flag & ND_NFSV3) {
1044 		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1045 		*tl = newnfs_false;
1046 	} else if (nd->nd_flag & ND_NFSV4) {
1047 		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1048 		*tl = txdr_unsigned(NFSV4OP_GETATTR);
1049 		NFSGETATTR_ATTRBIT(&attrbits);
1050 		(void) nfsrv_putattrbit(nd, &attrbits);
1051 	}
1052 	error = nfscl_request(nd, vp, p, cred, stuff);
1053 	if (error)
1054 		return (error);
1055 	if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4))
1056 		error = nfscl_wcc_data(nd, vp, rnap, attrflagp, NULL, stuff);
1057 	if ((nd->nd_flag & ND_NFSV4) && !error)
1058 		error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
1059 	if (!(nd->nd_flag & ND_NFSV3) && !nd->nd_repstat && !error)
1060 		error = nfscl_postop_attr(nd, rnap, attrflagp, stuff);
1061 	mbuf_freem(nd->nd_mrep);
1062 	if (nd->nd_repstat && !error)
1063 		error = nd->nd_repstat;
1064 	return (error);
1065 }
1066 
1067 /*
1068  * nfs lookup rpc
1069  */
1070 APPLESTATIC int
1071 nfsrpc_lookup(vnode_t dvp, char *name, int len, struct ucred *cred,
1072     NFSPROC_T *p, struct nfsvattr *dnap, struct nfsvattr *nap,
1073     struct nfsfh **nfhpp, int *attrflagp, int *dattrflagp, void *stuff)
1074 {
1075 	u_int32_t *tl;
1076 	struct nfsrv_descript nfsd, *nd = &nfsd;
1077 	struct nfsmount *nmp;
1078 	struct nfsnode *np;
1079 	struct nfsfh *nfhp;
1080 	nfsattrbit_t attrbits;
1081 	int error = 0, lookupp = 0;
1082 
1083 	*attrflagp = 0;
1084 	*dattrflagp = 0;
1085 	if (vnode_vtype(dvp) != VDIR)
1086 		return (ENOTDIR);
1087 	nmp = VFSTONFS(vnode_mount(dvp));
1088 	if (len > NFS_MAXNAMLEN)
1089 		return (ENAMETOOLONG);
1090 	if (NFSHASNFSV4(nmp) && len == 1 &&
1091 		name[0] == '.') {
1092 		/*
1093 		 * Just return the current dir's fh.
1094 		 */
1095 		np = VTONFS(dvp);
1096 		MALLOC(nfhp, struct nfsfh *, sizeof (struct nfsfh) +
1097 			np->n_fhp->nfh_len, M_NFSFH, M_WAITOK);
1098 		nfhp->nfh_len = np->n_fhp->nfh_len;
1099 		NFSBCOPY(np->n_fhp->nfh_fh, nfhp->nfh_fh, nfhp->nfh_len);
1100 		*nfhpp = nfhp;
1101 		return (0);
1102 	}
1103 	if (NFSHASNFSV4(nmp) && len == 2 &&
1104 		name[0] == '.' && name[1] == '.') {
1105 		lookupp = 1;
1106 		NFSCL_REQSTART(nd, NFSPROC_LOOKUPP, dvp);
1107 	} else {
1108 		NFSCL_REQSTART(nd, NFSPROC_LOOKUP, dvp);
1109 		(void) nfsm_strtom(nd, name, len);
1110 	}
1111 	if (nd->nd_flag & ND_NFSV4) {
1112 		NFSGETATTR_ATTRBIT(&attrbits);
1113 		NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1114 		*tl++ = txdr_unsigned(NFSV4OP_GETFH);
1115 		*tl = txdr_unsigned(NFSV4OP_GETATTR);
1116 		(void) nfsrv_putattrbit(nd, &attrbits);
1117 	}
1118 	error = nfscl_request(nd, dvp, p, cred, stuff);
1119 	if (error)
1120 		return (error);
1121 	if (nd->nd_repstat) {
1122 		/*
1123 		 * When an NFSv4 Lookupp returns ENOENT, it means that
1124 		 * the lookup is at the root of an fs, so return this dir.
1125 		 */
1126 		if (nd->nd_repstat == NFSERR_NOENT && lookupp) {
1127 		    np = VTONFS(dvp);
1128 		    MALLOC(nfhp, struct nfsfh *, sizeof (struct nfsfh) +
1129 			np->n_fhp->nfh_len, M_NFSFH, M_WAITOK);
1130 		    nfhp->nfh_len = np->n_fhp->nfh_len;
1131 		    NFSBCOPY(np->n_fhp->nfh_fh, nfhp->nfh_fh, nfhp->nfh_len);
1132 		    *nfhpp = nfhp;
1133 		    mbuf_freem(nd->nd_mrep);
1134 		    return (0);
1135 		}
1136 		if (nd->nd_flag & ND_NFSV3)
1137 		    error = nfscl_postop_attr(nd, dnap, dattrflagp, stuff);
1138 		goto nfsmout;
1139 	}
1140 	if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4) {
1141 		NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1142 		if (*(tl + 1)) {
1143 			nd->nd_flag |= ND_NOMOREDATA;
1144 			goto nfsmout;
1145 		}
1146 	}
1147 	error = nfsm_getfh(nd, nfhpp);
1148 	if (error)
1149 		goto nfsmout;
1150 
1151 	error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
1152 	if ((nd->nd_flag & ND_NFSV3) && !error)
1153 		error = nfscl_postop_attr(nd, dnap, dattrflagp, stuff);
1154 nfsmout:
1155 	mbuf_freem(nd->nd_mrep);
1156 	if (!error && nd->nd_repstat)
1157 		error = nd->nd_repstat;
1158 	return (error);
1159 }
1160 
1161 /*
1162  * Do a readlink rpc.
1163  */
1164 APPLESTATIC int
1165 nfsrpc_readlink(vnode_t vp, struct uio *uiop, struct ucred *cred,
1166     NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff)
1167 {
1168 	u_int32_t *tl;
1169 	struct nfsrv_descript nfsd, *nd = &nfsd;
1170 	struct nfsnode *np = VTONFS(vp);
1171 	nfsattrbit_t attrbits;
1172 	int error, len, cangetattr = 1;
1173 
1174 	*attrflagp = 0;
1175 	NFSCL_REQSTART(nd, NFSPROC_READLINK, vp);
1176 	if (nd->nd_flag & ND_NFSV4) {
1177 		/*
1178 		 * And do a Getattr op.
1179 		 */
1180 		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1181 		*tl = txdr_unsigned(NFSV4OP_GETATTR);
1182 		NFSGETATTR_ATTRBIT(&attrbits);
1183 		(void) nfsrv_putattrbit(nd, &attrbits);
1184 	}
1185 	error = nfscl_request(nd, vp, p, cred, stuff);
1186 	if (error)
1187 		return (error);
1188 	if (nd->nd_flag & ND_NFSV3)
1189 		error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
1190 	if (!nd->nd_repstat && !error) {
1191 		NFSM_STRSIZ(len, NFS_MAXPATHLEN);
1192 		/*
1193 		 * This seems weird to me, but must have been added to
1194 		 * FreeBSD for some reason. The only thing I can think of
1195 		 * is that there was/is some server that replies with
1196 		 * more link data than it should?
1197 		 */
1198 		if (len == NFS_MAXPATHLEN) {
1199 			NFSLOCKNODE(np);
1200 			if (np->n_size > 0 && np->n_size < NFS_MAXPATHLEN) {
1201 				len = np->n_size;
1202 				cangetattr = 0;
1203 			}
1204 			NFSUNLOCKNODE(np);
1205 		}
1206 		error = nfsm_mbufuio(nd, uiop, len);
1207 		if ((nd->nd_flag & ND_NFSV4) && !error && cangetattr)
1208 			error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
1209 	}
1210 	if (nd->nd_repstat && !error)
1211 		error = nd->nd_repstat;
1212 nfsmout:
1213 	mbuf_freem(nd->nd_mrep);
1214 	return (error);
1215 }
1216 
1217 /*
1218  * Read operation.
1219  */
1220 APPLESTATIC int
1221 nfsrpc_read(vnode_t vp, struct uio *uiop, struct ucred *cred,
1222     NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff)
1223 {
1224 	int error, expireret = 0, retrycnt;
1225 	u_int32_t clidrev = 0;
1226 	struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
1227 	struct nfsnode *np = VTONFS(vp);
1228 	struct ucred *newcred;
1229 	struct nfsfh *nfhp = NULL;
1230 	nfsv4stateid_t stateid;
1231 	void *lckp;
1232 
1233 	if (nmp->nm_clp != NULL)
1234 		clidrev = nmp->nm_clp->nfsc_clientidrev;
1235 	newcred = cred;
1236 	if (NFSHASNFSV4(nmp)) {
1237 		nfhp = np->n_fhp;
1238 		newcred = NFSNEWCRED(cred);
1239 	}
1240 	retrycnt = 0;
1241 	do {
1242 		lckp = NULL;
1243 		if (NFSHASNFSV4(nmp))
1244 			(void)nfscl_getstateid(vp, nfhp->nfh_fh, nfhp->nfh_len,
1245 			    NFSV4OPEN_ACCESSREAD, newcred, p, &stateid, &lckp);
1246 		error = nfsrpc_readrpc(vp, uiop, newcred, &stateid, p, nap,
1247 		    attrflagp, stuff);
1248 		if (error == NFSERR_STALESTATEID)
1249 			nfscl_initiate_recovery(nmp->nm_clp);
1250 		if (lckp != NULL)
1251 			nfscl_lockderef(lckp);
1252 		if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
1253 		    error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
1254 		    error == NFSERR_OLDSTATEID) {
1255 			(void) nfs_catnap(PZERO, error, "nfs_read");
1256 		} else if ((error == NFSERR_EXPIRED ||
1257 		    error == NFSERR_BADSTATEID) && clidrev != 0) {
1258 			expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
1259 		}
1260 		retrycnt++;
1261 	} while (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
1262 	    error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
1263 	    (error == NFSERR_OLDSTATEID && retrycnt < 20) ||
1264 	    ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
1265 	     expireret == 0 && clidrev != 0 && retrycnt < 4));
1266 	if (error && retrycnt >= 4)
1267 		error = EIO;
1268 	if (NFSHASNFSV4(nmp))
1269 		NFSFREECRED(newcred);
1270 	return (error);
1271 }
1272 
1273 /*
1274  * The actual read RPC.
1275  */
1276 static int
1277 nfsrpc_readrpc(vnode_t vp, struct uio *uiop, struct ucred *cred,
1278     nfsv4stateid_t *stateidp, NFSPROC_T *p, struct nfsvattr *nap,
1279     int *attrflagp, void *stuff)
1280 {
1281 	u_int32_t *tl;
1282 	int error = 0, len, retlen, tsiz, eof = 0;
1283 	struct nfsrv_descript nfsd;
1284 	struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
1285 	struct nfsrv_descript *nd = &nfsd;
1286 	int rsize;
1287 	off_t tmp_off;
1288 
1289 	*attrflagp = 0;
1290 	tsiz = uio_uio_resid(uiop);
1291 	tmp_off = uiop->uio_offset + tsiz;
1292 	NFSLOCKMNT(nmp);
1293 	if (tmp_off > nmp->nm_maxfilesize || tmp_off < uiop->uio_offset) {
1294 		NFSUNLOCKMNT(nmp);
1295 		return (EFBIG);
1296 	}
1297 	rsize = nmp->nm_rsize;
1298 	NFSUNLOCKMNT(nmp);
1299 	nd->nd_mrep = NULL;
1300 	while (tsiz > 0) {
1301 		*attrflagp = 0;
1302 		len = (tsiz > rsize) ? rsize : tsiz;
1303 		NFSCL_REQSTART(nd, NFSPROC_READ, vp);
1304 		if (nd->nd_flag & ND_NFSV4)
1305 			nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID);
1306 		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED * 3);
1307 		if (nd->nd_flag & ND_NFSV2) {
1308 			*tl++ = txdr_unsigned(uiop->uio_offset);
1309 			*tl++ = txdr_unsigned(len);
1310 			*tl = 0;
1311 		} else {
1312 			txdr_hyper(uiop->uio_offset, tl);
1313 			*(tl + 2) = txdr_unsigned(len);
1314 		}
1315 		/*
1316 		 * Since I can't do a Getattr for NFSv4 for Write, there
1317 		 * doesn't seem any point in doing one here, either.
1318 		 * (See the comment in nfsrpc_writerpc() for more info.)
1319 		 */
1320 		error = nfscl_request(nd, vp, p, cred, stuff);
1321 		if (error)
1322 			return (error);
1323 		if (nd->nd_flag & ND_NFSV3) {
1324 			error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
1325 		} else if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV2)) {
1326 			error = nfsm_loadattr(nd, nap);
1327 			if (!error)
1328 				*attrflagp = 1;
1329 		}
1330 		if (nd->nd_repstat || error) {
1331 			if (!error)
1332 				error = nd->nd_repstat;
1333 			goto nfsmout;
1334 		}
1335 		if (nd->nd_flag & ND_NFSV3) {
1336 			NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1337 			eof = fxdr_unsigned(int, *(tl + 1));
1338 		} else if (nd->nd_flag & ND_NFSV4) {
1339 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1340 			eof = fxdr_unsigned(int, *tl);
1341 		}
1342 		NFSM_STRSIZ(retlen, rsize);
1343 		error = nfsm_mbufuio(nd, uiop, retlen);
1344 		if (error)
1345 			goto nfsmout;
1346 		mbuf_freem(nd->nd_mrep);
1347 		nd->nd_mrep = NULL;
1348 		tsiz -= retlen;
1349 		if (!(nd->nd_flag & ND_NFSV2)) {
1350 			if (eof || retlen == 0)
1351 				tsiz = 0;
1352 		} else if (retlen < len)
1353 			tsiz = 0;
1354 	}
1355 	return (0);
1356 nfsmout:
1357 	if (nd->nd_mrep != NULL)
1358 		mbuf_freem(nd->nd_mrep);
1359 	return (error);
1360 }
1361 
1362 /*
1363  * nfs write operation
1364  * When called_from_strategy != 0, it should return EIO for an error that
1365  * indicates recovery is in progress, so that the buffer will be left
1366  * dirty and be written back to the server later. If it loops around,
1367  * the recovery thread could get stuck waiting for the buffer and recovery
1368  * will then deadlock.
1369  */
1370 APPLESTATIC int
1371 nfsrpc_write(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit,
1372     struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp,
1373     void *stuff, int called_from_strategy)
1374 {
1375 	int error, expireret = 0, retrycnt, nostateid;
1376 	u_int32_t clidrev = 0;
1377 	struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
1378 	struct nfsnode *np = VTONFS(vp);
1379 	struct ucred *newcred;
1380 	struct nfsfh *nfhp = NULL;
1381 	nfsv4stateid_t stateid;
1382 	void *lckp;
1383 
1384 	*must_commit = 0;
1385 	if (nmp->nm_clp != NULL)
1386 		clidrev = nmp->nm_clp->nfsc_clientidrev;
1387 	newcred = cred;
1388 	if (NFSHASNFSV4(nmp)) {
1389 		newcred = NFSNEWCRED(cred);
1390 		nfhp = np->n_fhp;
1391 	}
1392 	retrycnt = 0;
1393 	do {
1394 		lckp = NULL;
1395 		nostateid = 0;
1396 		if (NFSHASNFSV4(nmp)) {
1397 			(void)nfscl_getstateid(vp, nfhp->nfh_fh, nfhp->nfh_len,
1398 			    NFSV4OPEN_ACCESSWRITE, newcred, p, &stateid, &lckp);
1399 			if (stateid.other[0] == 0 && stateid.other[1] == 0 &&
1400 			    stateid.other[2] == 0) {
1401 				nostateid = 1;
1402 				NFSCL_DEBUG(1, "stateid0 in write\n");
1403 			}
1404 		}
1405 
1406 		/*
1407 		 * If there is no stateid for NFSv4, it means this is an
1408 		 * extraneous write after close. Basically a poorly
1409 		 * implemented buffer cache. Just don't do the write.
1410 		 */
1411 		if (nostateid)
1412 			error = 0;
1413 		else
1414 			error = nfsrpc_writerpc(vp, uiop, iomode, must_commit,
1415 			    newcred, &stateid, p, nap, attrflagp, stuff);
1416 		if (error == NFSERR_STALESTATEID)
1417 			nfscl_initiate_recovery(nmp->nm_clp);
1418 		if (lckp != NULL)
1419 			nfscl_lockderef(lckp);
1420 		if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
1421 		    error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
1422 		    error == NFSERR_OLDSTATEID) {
1423 			(void) nfs_catnap(PZERO, error, "nfs_write");
1424 		} else if ((error == NFSERR_EXPIRED ||
1425 		    error == NFSERR_BADSTATEID) && clidrev != 0) {
1426 			expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
1427 		}
1428 		retrycnt++;
1429 	} while (error == NFSERR_GRACE || error == NFSERR_DELAY ||
1430 	    ((error == NFSERR_STALESTATEID ||
1431 	      error == NFSERR_STALEDONTRECOVER) && called_from_strategy == 0) ||
1432 	    (error == NFSERR_OLDSTATEID && retrycnt < 20) ||
1433 	    ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
1434 	     expireret == 0 && clidrev != 0 && retrycnt < 4));
1435 	if (error != 0 && (retrycnt >= 4 ||
1436 	    ((error == NFSERR_STALESTATEID ||
1437 	      error == NFSERR_STALEDONTRECOVER) && called_from_strategy != 0)))
1438 		error = EIO;
1439 	if (NFSHASNFSV4(nmp))
1440 		NFSFREECRED(newcred);
1441 	return (error);
1442 }
1443 
1444 /*
1445  * The actual write RPC.
1446  */
1447 static int
1448 nfsrpc_writerpc(vnode_t vp, struct uio *uiop, int *iomode,
1449     int *must_commit, struct ucred *cred, nfsv4stateid_t *stateidp,
1450     NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff)
1451 {
1452 	u_int32_t *tl;
1453 	struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
1454 	struct nfsnode *np = VTONFS(vp);
1455 	int error = 0, len, tsiz, rlen, commit, committed = NFSWRITE_FILESYNC;
1456 	int wccflag = 0, wsize;
1457 	int32_t backup;
1458 	struct nfsrv_descript nfsd;
1459 	struct nfsrv_descript *nd = &nfsd;
1460 	nfsattrbit_t attrbits;
1461 	off_t tmp_off;
1462 
1463 	KASSERT(uiop->uio_iovcnt == 1, ("nfs: writerpc iovcnt > 1"));
1464 	*attrflagp = 0;
1465 	tsiz = uio_uio_resid(uiop);
1466 	tmp_off = uiop->uio_offset + tsiz;
1467 	NFSLOCKMNT(nmp);
1468 	if (tmp_off > nmp->nm_maxfilesize || tmp_off < uiop->uio_offset) {
1469 		NFSUNLOCKMNT(nmp);
1470 		return (EFBIG);
1471 	}
1472 	wsize = nmp->nm_wsize;
1473 	NFSUNLOCKMNT(nmp);
1474 	nd->nd_mrep = NULL;	/* NFSv2 sometimes does a write with */
1475 	nd->nd_repstat = 0;	/* uio_resid == 0, so the while is not done */
1476 	while (tsiz > 0) {
1477 		*attrflagp = 0;
1478 		len = (tsiz > wsize) ? wsize : tsiz;
1479 		NFSCL_REQSTART(nd, NFSPROC_WRITE, vp);
1480 		if (nd->nd_flag & ND_NFSV4) {
1481 			nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID);
1482 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER+2*NFSX_UNSIGNED);
1483 			txdr_hyper(uiop->uio_offset, tl);
1484 			tl += 2;
1485 			*tl++ = txdr_unsigned(*iomode);
1486 			*tl = txdr_unsigned(len);
1487 		} else if (nd->nd_flag & ND_NFSV3) {
1488 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER+3*NFSX_UNSIGNED);
1489 			txdr_hyper(uiop->uio_offset, tl);
1490 			tl += 2;
1491 			*tl++ = txdr_unsigned(len);
1492 			*tl++ = txdr_unsigned(*iomode);
1493 			*tl = txdr_unsigned(len);
1494 		} else {
1495 			u_int32_t x;
1496 
1497 			NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1498 			/*
1499 			 * Not sure why someone changed this, since the
1500 			 * RFC clearly states that "beginoffset" and
1501 			 * "totalcount" are ignored, but it wouldn't
1502 			 * surprise me if there's a busted server out there.
1503 			 */
1504 			/* Set both "begin" and "current" to non-garbage. */
1505 			x = txdr_unsigned((u_int32_t)uiop->uio_offset);
1506 			*tl++ = x;      /* "begin offset" */
1507 			*tl++ = x;      /* "current offset" */
1508 			x = txdr_unsigned(len);
1509 			*tl++ = x;      /* total to this offset */
1510 			*tl = x;        /* size of this write */
1511 
1512 		}
1513 		nfsm_uiombuf(nd, uiop, len);
1514 		/*
1515 		 * Although it is tempting to do a normal Getattr Op in the
1516 		 * NFSv4 compound, the result can be a nearly hung client
1517 		 * system if the Getattr asks for Owner and/or OwnerGroup.
1518 		 * It occurs when the client can't map either the Owner or
1519 		 * Owner_group name in the Getattr reply to a uid/gid. When
1520 		 * there is a cache miss, the kernel does an upcall to the
1521 		 * nfsuserd. Then, it can try and read the local /etc/passwd
1522 		 * or /etc/group file. It can then block in getnewbuf(),
1523 		 * waiting for dirty writes to be pushed to the NFS server.
1524 		 * The only reason this doesn't result in a complete
1525 		 * deadlock, is that the upcall times out and allows
1526 		 * the write to complete. However, progress is so slow
1527 		 * that it might just as well be deadlocked.
1528 		 * As such, we get the rest of the attributes, but not
1529 		 * Owner or Owner_group.
1530 		 * nb: nfscl_loadattrcache() needs to be told that these
1531 		 *     partial attributes from a write rpc are being
1532 		 *     passed in, via a argument flag.
1533 		 */
1534 		if (nd->nd_flag & ND_NFSV4) {
1535 			NFSWRITEGETATTR_ATTRBIT(&attrbits);
1536 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1537 			*tl = txdr_unsigned(NFSV4OP_GETATTR);
1538 			(void) nfsrv_putattrbit(nd, &attrbits);
1539 		}
1540 		error = nfscl_request(nd, vp, p, cred, stuff);
1541 		if (error)
1542 			return (error);
1543 		if (nd->nd_repstat) {
1544 			/*
1545 			 * In case the rpc gets retried, roll
1546 			 * the uio fileds changed by nfsm_uiombuf()
1547 			 * back.
1548 			 */
1549 			uiop->uio_offset -= len;
1550 			uio_uio_resid_add(uiop, len);
1551 			uio_iov_base_add(uiop, -len);
1552 			uio_iov_len_add(uiop, len);
1553 		}
1554 		if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
1555 			error = nfscl_wcc_data(nd, vp, nap, attrflagp,
1556 			    &wccflag, stuff);
1557 			if (error)
1558 				goto nfsmout;
1559 		}
1560 		if (!nd->nd_repstat) {
1561 			if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
1562 				NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED
1563 					+ NFSX_VERF);
1564 				rlen = fxdr_unsigned(int, *tl++);
1565 				if (rlen == 0) {
1566 					error = NFSERR_IO;
1567 					goto nfsmout;
1568 				} else if (rlen < len) {
1569 					backup = len - rlen;
1570 					uio_iov_base_add(uiop, -(backup));
1571 					uio_iov_len_add(uiop, backup);
1572 					uiop->uio_offset -= backup;
1573 					uio_uio_resid_add(uiop, backup);
1574 					len = rlen;
1575 				}
1576 				commit = fxdr_unsigned(int, *tl++);
1577 
1578 				/*
1579 				 * Return the lowest committment level
1580 				 * obtained by any of the RPCs.
1581 				 */
1582 				if (committed == NFSWRITE_FILESYNC)
1583 					committed = commit;
1584 				else if (committed == NFSWRITE_DATASYNC &&
1585 					commit == NFSWRITE_UNSTABLE)
1586 					committed = commit;
1587 				NFSLOCKMNT(nmp);
1588 				if (!NFSHASWRITEVERF(nmp)) {
1589 					NFSBCOPY((caddr_t)tl,
1590 					    (caddr_t)&nmp->nm_verf[0],
1591 					    NFSX_VERF);
1592 					NFSSETWRITEVERF(nmp);
1593 	    			} else if (NFSBCMP(tl, nmp->nm_verf,
1594 				    NFSX_VERF)) {
1595 					*must_commit = 1;
1596 					NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF);
1597 				}
1598 				NFSUNLOCKMNT(nmp);
1599 			}
1600 			if (nd->nd_flag & ND_NFSV4)
1601 				NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1602 			if (nd->nd_flag & (ND_NFSV2 | ND_NFSV4)) {
1603 				error = nfsm_loadattr(nd, nap);
1604 				if (!error)
1605 					*attrflagp = NFS_LATTR_NOSHRINK;
1606 			}
1607 		} else {
1608 			error = nd->nd_repstat;
1609 		}
1610 		if (error)
1611 			goto nfsmout;
1612 		NFSWRITERPC_SETTIME(wccflag, np, (nd->nd_flag & ND_NFSV4));
1613 		mbuf_freem(nd->nd_mrep);
1614 		nd->nd_mrep = NULL;
1615 		tsiz -= len;
1616 	}
1617 nfsmout:
1618 	if (nd->nd_mrep != NULL)
1619 		mbuf_freem(nd->nd_mrep);
1620 	*iomode = committed;
1621 	if (nd->nd_repstat && !error)
1622 		error = nd->nd_repstat;
1623 	return (error);
1624 }
1625 
1626 /*
1627  * nfs mknod rpc
1628  * For NFS v2 this is a kludge. Use a create rpc but with the IFMT bits of the
1629  * mode set to specify the file type and the size field for rdev.
1630  */
1631 APPLESTATIC int
1632 nfsrpc_mknod(vnode_t dvp, char *name, int namelen, struct vattr *vap,
1633     u_int32_t rdev, enum vtype vtyp, struct ucred *cred, NFSPROC_T *p,
1634     struct nfsvattr *dnap, struct nfsvattr *nnap, struct nfsfh **nfhpp,
1635     int *attrflagp, int *dattrflagp, void *dstuff)
1636 {
1637 	u_int32_t *tl;
1638 	int error = 0;
1639 	struct nfsrv_descript nfsd, *nd = &nfsd;
1640 	nfsattrbit_t attrbits;
1641 
1642 	*nfhpp = NULL;
1643 	*attrflagp = 0;
1644 	*dattrflagp = 0;
1645 	if (namelen > NFS_MAXNAMLEN)
1646 		return (ENAMETOOLONG);
1647 	NFSCL_REQSTART(nd, NFSPROC_MKNOD, dvp);
1648 	if (nd->nd_flag & ND_NFSV4) {
1649 		if (vtyp == VBLK || vtyp == VCHR) {
1650 			NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
1651 			*tl++ = vtonfsv34_type(vtyp);
1652 			*tl++ = txdr_unsigned(NFSMAJOR(rdev));
1653 			*tl = txdr_unsigned(NFSMINOR(rdev));
1654 		} else {
1655 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1656 			*tl = vtonfsv34_type(vtyp);
1657 		}
1658 	}
1659 	(void) nfsm_strtom(nd, name, namelen);
1660 	if (nd->nd_flag & ND_NFSV3) {
1661 		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1662 		*tl = vtonfsv34_type(vtyp);
1663 	}
1664 	if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4))
1665 		nfscl_fillsattr(nd, vap, dvp, 0, 0);
1666 	if ((nd->nd_flag & ND_NFSV3) &&
1667 	    (vtyp == VCHR || vtyp == VBLK)) {
1668 		NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1669 		*tl++ = txdr_unsigned(NFSMAJOR(rdev));
1670 		*tl = txdr_unsigned(NFSMINOR(rdev));
1671 	}
1672 	if (nd->nd_flag & ND_NFSV4) {
1673 		NFSGETATTR_ATTRBIT(&attrbits);
1674 		NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1675 		*tl++ = txdr_unsigned(NFSV4OP_GETFH);
1676 		*tl = txdr_unsigned(NFSV4OP_GETATTR);
1677 		(void) nfsrv_putattrbit(nd, &attrbits);
1678 	}
1679 	if (nd->nd_flag & ND_NFSV2)
1680 		nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZERDEV, rdev);
1681 	error = nfscl_request(nd, dvp, p, cred, dstuff);
1682 	if (error)
1683 		return (error);
1684 	if (nd->nd_flag & ND_NFSV4)
1685 		error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
1686 	if (!nd->nd_repstat) {
1687 		if (nd->nd_flag & ND_NFSV4) {
1688 			NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1689 			error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
1690 			if (error)
1691 				goto nfsmout;
1692 		}
1693 		error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp);
1694 		if (error)
1695 			goto nfsmout;
1696 	}
1697 	if (nd->nd_flag & ND_NFSV3)
1698 		error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
1699 	if (!error && nd->nd_repstat)
1700 		error = nd->nd_repstat;
1701 nfsmout:
1702 	mbuf_freem(nd->nd_mrep);
1703 	return (error);
1704 }
1705 
1706 /*
1707  * nfs file create call
1708  * Mostly just call the approriate routine. (I separated out v4, so that
1709  * error recovery wouldn't be as difficult.)
1710  */
1711 APPLESTATIC int
1712 nfsrpc_create(vnode_t dvp, char *name, int namelen, struct vattr *vap,
1713     nfsquad_t cverf, int fmode, struct ucred *cred, NFSPROC_T *p,
1714     struct nfsvattr *dnap, struct nfsvattr *nnap, struct nfsfh **nfhpp,
1715     int *attrflagp, int *dattrflagp, void *dstuff)
1716 {
1717 	int error = 0, newone, expireret = 0, retrycnt, unlocked;
1718 	struct nfsclowner *owp;
1719 	struct nfscldeleg *dp;
1720 	struct nfsmount *nmp = VFSTONFS(vnode_mount(dvp));
1721 	u_int32_t clidrev;
1722 
1723 	if (NFSHASNFSV4(nmp)) {
1724 	    retrycnt = 0;
1725 	    do {
1726 		dp = NULL;
1727 		error = nfscl_open(dvp, NULL, 0, (NFSV4OPEN_ACCESSWRITE |
1728 		    NFSV4OPEN_ACCESSREAD), 0, cred, p, &owp, NULL, &newone,
1729 		    NULL, 1);
1730 		if (error)
1731 			return (error);
1732 		if (nmp->nm_clp != NULL)
1733 			clidrev = nmp->nm_clp->nfsc_clientidrev;
1734 		else
1735 			clidrev = 0;
1736 		error = nfsrpc_createv4(dvp, name, namelen, vap, cverf, fmode,
1737 		  owp, &dp, cred, p, dnap, nnap, nfhpp, attrflagp, dattrflagp,
1738 		  dstuff, &unlocked);
1739 		/*
1740 		 * There is no need to invalidate cached attributes here,
1741 		 * since new post-delegation issue attributes are always
1742 		 * returned by nfsrpc_createv4() and these will update the
1743 		 * attribute cache.
1744 		 */
1745 		if (dp != NULL)
1746 			(void) nfscl_deleg(nmp->nm_mountp, owp->nfsow_clp,
1747 			    (*nfhpp)->nfh_fh, (*nfhpp)->nfh_len, cred, p, &dp);
1748 		nfscl_ownerrelease(owp, error, newone, unlocked);
1749 		if (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID ||
1750 		    error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY) {
1751 			(void) nfs_catnap(PZERO, error, "nfs_open");
1752 		} else if ((error == NFSERR_EXPIRED ||
1753 		    error == NFSERR_BADSTATEID) && clidrev != 0) {
1754 			expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
1755 			retrycnt++;
1756 		}
1757 	    } while (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID ||
1758 		error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
1759 		((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
1760 		 expireret == 0 && clidrev != 0 && retrycnt < 4));
1761 	    if (error && retrycnt >= 4)
1762 		    error = EIO;
1763 	} else {
1764 		error = nfsrpc_createv23(dvp, name, namelen, vap, cverf,
1765 		    fmode, cred, p, dnap, nnap, nfhpp, attrflagp, dattrflagp,
1766 		    dstuff);
1767 	}
1768 	return (error);
1769 }
1770 
1771 /*
1772  * The create rpc for v2 and 3.
1773  */
1774 static int
1775 nfsrpc_createv23(vnode_t dvp, char *name, int namelen, struct vattr *vap,
1776     nfsquad_t cverf, int fmode, struct ucred *cred, NFSPROC_T *p,
1777     struct nfsvattr *dnap, struct nfsvattr *nnap, struct nfsfh **nfhpp,
1778     int *attrflagp, int *dattrflagp, void *dstuff)
1779 {
1780 	u_int32_t *tl;
1781 	int error = 0;
1782 	struct nfsrv_descript nfsd, *nd = &nfsd;
1783 
1784 	*nfhpp = NULL;
1785 	*attrflagp = 0;
1786 	*dattrflagp = 0;
1787 	if (namelen > NFS_MAXNAMLEN)
1788 		return (ENAMETOOLONG);
1789 	NFSCL_REQSTART(nd, NFSPROC_CREATE, dvp);
1790 	(void) nfsm_strtom(nd, name, namelen);
1791 	if (nd->nd_flag & ND_NFSV3) {
1792 		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1793 		if (fmode & O_EXCL) {
1794 			*tl = txdr_unsigned(NFSCREATE_EXCLUSIVE);
1795 			NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
1796 			*tl++ = cverf.lval[0];
1797 			*tl = cverf.lval[1];
1798 		} else {
1799 			*tl = txdr_unsigned(NFSCREATE_UNCHECKED);
1800 			nfscl_fillsattr(nd, vap, dvp, 0, 0);
1801 		}
1802 	} else {
1803 		nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZE0, 0);
1804 	}
1805 	error = nfscl_request(nd, dvp, p, cred, dstuff);
1806 	if (error)
1807 		return (error);
1808 	if (nd->nd_repstat == 0) {
1809 		error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp);
1810 		if (error)
1811 			goto nfsmout;
1812 	}
1813 	if (nd->nd_flag & ND_NFSV3)
1814 		error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
1815 	if (nd->nd_repstat != 0 && error == 0)
1816 		error = nd->nd_repstat;
1817 nfsmout:
1818 	mbuf_freem(nd->nd_mrep);
1819 	return (error);
1820 }
1821 
1822 static int
1823 nfsrpc_createv4(vnode_t dvp, char *name, int namelen, struct vattr *vap,
1824     nfsquad_t cverf, int fmode, struct nfsclowner *owp, struct nfscldeleg **dpp,
1825     struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap,
1826     struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp,
1827     int *dattrflagp, void *dstuff, int *unlockedp)
1828 {
1829 	u_int32_t *tl;
1830 	int error = 0, deleg, newone, ret, acesize, limitby;
1831 	struct nfsrv_descript nfsd, *nd = &nfsd;
1832 	struct nfsclopen *op;
1833 	struct nfscldeleg *dp = NULL;
1834 	struct nfsnode *np;
1835 	struct nfsfh *nfhp;
1836 	nfsattrbit_t attrbits;
1837 	nfsv4stateid_t stateid;
1838 	u_int32_t rflags;
1839 
1840 	*unlockedp = 0;
1841 	*nfhpp = NULL;
1842 	*dpp = NULL;
1843 	*attrflagp = 0;
1844 	*dattrflagp = 0;
1845 	if (namelen > NFS_MAXNAMLEN)
1846 		return (ENAMETOOLONG);
1847 	NFSCL_REQSTART(nd, NFSPROC_CREATE, dvp);
1848 	/*
1849 	 * For V4, this is actually an Open op.
1850 	 */
1851 	NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1852 	*tl++ = txdr_unsigned(owp->nfsow_seqid);
1853 	*tl++ = txdr_unsigned(NFSV4OPEN_ACCESSWRITE |
1854 	    NFSV4OPEN_ACCESSREAD);
1855 	*tl++ = txdr_unsigned(NFSV4OPEN_DENYNONE);
1856 	*tl++ = owp->nfsow_clp->nfsc_clientid.lval[0];
1857 	*tl = owp->nfsow_clp->nfsc_clientid.lval[1];
1858 	(void) nfsm_strtom(nd, owp->nfsow_owner, NFSV4CL_LOCKNAMELEN);
1859 	NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1860 	*tl++ = txdr_unsigned(NFSV4OPEN_CREATE);
1861 	if (fmode & O_EXCL) {
1862 		*tl = txdr_unsigned(NFSCREATE_EXCLUSIVE);
1863 		NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
1864 		*tl++ = cverf.lval[0];
1865 		*tl = cverf.lval[1];
1866 	} else {
1867 		*tl = txdr_unsigned(NFSCREATE_UNCHECKED);
1868 		nfscl_fillsattr(nd, vap, dvp, 0, 0);
1869 	}
1870 	NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1871 	*tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL);
1872 	(void) nfsm_strtom(nd, name, namelen);
1873 	NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1874 	*tl++ = txdr_unsigned(NFSV4OP_GETFH);
1875 	*tl = txdr_unsigned(NFSV4OP_GETATTR);
1876 	NFSGETATTR_ATTRBIT(&attrbits);
1877 	(void) nfsrv_putattrbit(nd, &attrbits);
1878 	error = nfscl_request(nd, dvp, p, cred, dstuff);
1879 	if (error)
1880 		return (error);
1881 	error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
1882 	if (error)
1883 		goto nfsmout;
1884 	NFSCL_INCRSEQID(owp->nfsow_seqid, nd);
1885 	if (nd->nd_repstat == 0) {
1886 		NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
1887 		    6 * NFSX_UNSIGNED);
1888 		stateid.seqid = *tl++;
1889 		stateid.other[0] = *tl++;
1890 		stateid.other[1] = *tl++;
1891 		stateid.other[2] = *tl;
1892 		rflags = fxdr_unsigned(u_int32_t, *(tl + 6));
1893 		(void) nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
1894 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1895 		deleg = fxdr_unsigned(int, *tl);
1896 		if (deleg == NFSV4OPEN_DELEGATEREAD ||
1897 		    deleg == NFSV4OPEN_DELEGATEWRITE) {
1898 			if (!(owp->nfsow_clp->nfsc_flags &
1899 			      NFSCLFLAGS_FIRSTDELEG))
1900 				owp->nfsow_clp->nfsc_flags |=
1901 				  (NFSCLFLAGS_FIRSTDELEG | NFSCLFLAGS_GOTDELEG);
1902 			MALLOC(dp, struct nfscldeleg *,
1903 			    sizeof (struct nfscldeleg) + NFSX_V4FHMAX,
1904 			    M_NFSCLDELEG, M_WAITOK);
1905 			LIST_INIT(&dp->nfsdl_owner);
1906 			LIST_INIT(&dp->nfsdl_lock);
1907 			dp->nfsdl_clp = owp->nfsow_clp;
1908 			newnfs_copyincred(cred, &dp->nfsdl_cred);
1909 			nfscl_lockinit(&dp->nfsdl_rwlock);
1910 			NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
1911 			    NFSX_UNSIGNED);
1912 			dp->nfsdl_stateid.seqid = *tl++;
1913 			dp->nfsdl_stateid.other[0] = *tl++;
1914 			dp->nfsdl_stateid.other[1] = *tl++;
1915 			dp->nfsdl_stateid.other[2] = *tl++;
1916 			ret = fxdr_unsigned(int, *tl);
1917 			if (deleg == NFSV4OPEN_DELEGATEWRITE) {
1918 				dp->nfsdl_flags = NFSCLDL_WRITE;
1919 				/*
1920 				 * Indicates how much the file can grow.
1921 				 */
1922 				NFSM_DISSECT(tl, u_int32_t *,
1923 				    3 * NFSX_UNSIGNED);
1924 				limitby = fxdr_unsigned(int, *tl++);
1925 				switch (limitby) {
1926 				case NFSV4OPEN_LIMITSIZE:
1927 					dp->nfsdl_sizelimit = fxdr_hyper(tl);
1928 					break;
1929 				case NFSV4OPEN_LIMITBLOCKS:
1930 					dp->nfsdl_sizelimit =
1931 					    fxdr_unsigned(u_int64_t, *tl++);
1932 					dp->nfsdl_sizelimit *=
1933 					    fxdr_unsigned(u_int64_t, *tl);
1934 					break;
1935 				default:
1936 					error = NFSERR_BADXDR;
1937 					goto nfsmout;
1938 				};
1939 			} else {
1940 				dp->nfsdl_flags = NFSCLDL_READ;
1941 			}
1942 			if (ret)
1943 				dp->nfsdl_flags |= NFSCLDL_RECALL;
1944 			error = nfsrv_dissectace(nd, &dp->nfsdl_ace, &ret,
1945 			    &acesize, p);
1946 			if (error)
1947 				goto nfsmout;
1948 		} else if (deleg != NFSV4OPEN_DELEGATENONE) {
1949 			error = NFSERR_BADXDR;
1950 			goto nfsmout;
1951 		}
1952 		error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp);
1953 		if (error)
1954 			goto nfsmout;
1955 		if (dp != NULL && *attrflagp) {
1956 			dp->nfsdl_change = nnap->na_filerev;
1957 			dp->nfsdl_modtime = nnap->na_mtime;
1958 			dp->nfsdl_flags |= NFSCLDL_MODTIMESET;
1959 		}
1960 		/*
1961 		 * We can now complete the Open state.
1962 		 */
1963 		nfhp = *nfhpp;
1964 		if (dp != NULL) {
1965 			dp->nfsdl_fhlen = nfhp->nfh_len;
1966 			NFSBCOPY(nfhp->nfh_fh, dp->nfsdl_fh, nfhp->nfh_len);
1967 		}
1968 		/*
1969 		 * Get an Open structure that will be
1970 		 * attached to the OpenOwner, acquired already.
1971 		 */
1972 		error = nfscl_open(dvp, nfhp->nfh_fh, nfhp->nfh_len,
1973 		    (NFSV4OPEN_ACCESSWRITE | NFSV4OPEN_ACCESSREAD), 0,
1974 		    cred, p, NULL, &op, &newone, NULL, 0);
1975 		if (error)
1976 			goto nfsmout;
1977 		op->nfso_stateid = stateid;
1978 		newnfs_copyincred(cred, &op->nfso_cred);
1979 		if ((rflags & NFSV4OPEN_RESULTCONFIRM)) {
1980 		    do {
1981 			ret = nfsrpc_openconfirm(dvp, nfhp->nfh_fh,
1982 			    nfhp->nfh_len, op, cred, p);
1983 			if (ret == NFSERR_DELAY)
1984 			    (void) nfs_catnap(PZERO, ret, "nfs_create");
1985 		    } while (ret == NFSERR_DELAY);
1986 		    error = ret;
1987 		}
1988 
1989 		/*
1990 		 * If the server is handing out delegations, but we didn't
1991 		 * get one because an OpenConfirm was required, try the
1992 		 * Open again, to get a delegation. This is a harmless no-op,
1993 		 * from a server's point of view.
1994 		 */
1995 		if ((rflags & NFSV4OPEN_RESULTCONFIRM) &&
1996 		    (owp->nfsow_clp->nfsc_flags & NFSCLFLAGS_GOTDELEG) &&
1997 		    !error && dp == NULL) {
1998 		    np = VTONFS(dvp);
1999 		    do {
2000 			ret = nfsrpc_openrpc(VFSTONFS(vnode_mount(dvp)), dvp,
2001 			    np->n_fhp->nfh_fh, np->n_fhp->nfh_len,
2002 			    nfhp->nfh_fh, nfhp->nfh_len,
2003 			    (NFSV4OPEN_ACCESSWRITE | NFSV4OPEN_ACCESSREAD), op,
2004 			    name, namelen, &dp, 0, 0x0, cred, p, 0, 1);
2005 			if (ret == NFSERR_DELAY)
2006 			    (void) nfs_catnap(PZERO, ret, "nfs_crt2");
2007 		    } while (ret == NFSERR_DELAY);
2008 		    if (ret) {
2009 			if (dp != NULL)
2010 				FREE((caddr_t)dp, M_NFSCLDELEG);
2011 			if (ret == NFSERR_STALECLIENTID ||
2012 			    ret == NFSERR_STALEDONTRECOVER)
2013 				error = ret;
2014 		    }
2015 		}
2016 		nfscl_openrelease(op, error, newone);
2017 		*unlockedp = 1;
2018 	}
2019 	if (nd->nd_repstat != 0 && error == 0)
2020 		error = nd->nd_repstat;
2021 	if (error == NFSERR_STALECLIENTID)
2022 		nfscl_initiate_recovery(owp->nfsow_clp);
2023 nfsmout:
2024 	if (!error)
2025 		*dpp = dp;
2026 	else if (dp != NULL)
2027 		FREE((caddr_t)dp, M_NFSCLDELEG);
2028 	mbuf_freem(nd->nd_mrep);
2029 	return (error);
2030 }
2031 
2032 /*
2033  * Nfs remove rpc
2034  */
2035 APPLESTATIC int
2036 nfsrpc_remove(vnode_t dvp, char *name, int namelen, vnode_t vp,
2037     struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, int *dattrflagp,
2038     void *dstuff)
2039 {
2040 	u_int32_t *tl;
2041 	struct nfsrv_descript nfsd, *nd = &nfsd;
2042 	struct nfsnode *np;
2043 	struct nfsmount *nmp;
2044 	nfsv4stateid_t dstateid;
2045 	int error, ret = 0, i;
2046 
2047 	*dattrflagp = 0;
2048 	if (namelen > NFS_MAXNAMLEN)
2049 		return (ENAMETOOLONG);
2050 	nmp = VFSTONFS(vnode_mount(dvp));
2051 tryagain:
2052 	if (NFSHASNFSV4(nmp) && ret == 0) {
2053 		ret = nfscl_removedeleg(vp, p, &dstateid);
2054 		if (ret == 1) {
2055 			NFSCL_REQSTART(nd, NFSPROC_RETDELEGREMOVE, vp);
2056 			NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID +
2057 			    NFSX_UNSIGNED);
2058 			*tl++ = dstateid.seqid;
2059 			*tl++ = dstateid.other[0];
2060 			*tl++ = dstateid.other[1];
2061 			*tl++ = dstateid.other[2];
2062 			*tl = txdr_unsigned(NFSV4OP_PUTFH);
2063 			np = VTONFS(dvp);
2064 			(void) nfsm_fhtom(nd, np->n_fhp->nfh_fh,
2065 			    np->n_fhp->nfh_len, 0);
2066 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2067 			*tl = txdr_unsigned(NFSV4OP_REMOVE);
2068 		}
2069 	} else {
2070 		ret = 0;
2071 	}
2072 	if (ret == 0)
2073 		NFSCL_REQSTART(nd, NFSPROC_REMOVE, dvp);
2074 	(void) nfsm_strtom(nd, name, namelen);
2075 	error = nfscl_request(nd, dvp, p, cred, dstuff);
2076 	if (error)
2077 		return (error);
2078 	if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
2079 		/* For NFSv4, parse out any Delereturn replies. */
2080 		if (ret > 0 && nd->nd_repstat != 0 &&
2081 		    (nd->nd_flag & ND_NOMOREDATA)) {
2082 			/*
2083 			 * If the Delegreturn failed, try again without
2084 			 * it. The server will Recall, as required.
2085 			 */
2086 			mbuf_freem(nd->nd_mrep);
2087 			goto tryagain;
2088 		}
2089 		for (i = 0; i < (ret * 2); i++) {
2090 			if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) ==
2091 			    ND_NFSV4) {
2092 			    NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2093 			    if (*(tl + 1))
2094 				nd->nd_flag |= ND_NOMOREDATA;
2095 			}
2096 		}
2097 		error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
2098 	}
2099 	if (nd->nd_repstat && !error)
2100 		error = nd->nd_repstat;
2101 nfsmout:
2102 	mbuf_freem(nd->nd_mrep);
2103 	return (error);
2104 }
2105 
2106 /*
2107  * Do an nfs rename rpc.
2108  */
2109 APPLESTATIC int
2110 nfsrpc_rename(vnode_t fdvp, vnode_t fvp, char *fnameptr, int fnamelen,
2111     vnode_t tdvp, vnode_t tvp, char *tnameptr, int tnamelen, struct ucred *cred,
2112     NFSPROC_T *p, struct nfsvattr *fnap, struct nfsvattr *tnap,
2113     int *fattrflagp, int *tattrflagp, void *fstuff, void *tstuff)
2114 {
2115 	u_int32_t *tl;
2116 	struct nfsrv_descript nfsd, *nd = &nfsd;
2117 	struct nfsmount *nmp;
2118 	struct nfsnode *np;
2119 	nfsattrbit_t attrbits;
2120 	nfsv4stateid_t fdstateid, tdstateid;
2121 	int error = 0, ret = 0, gottd = 0, gotfd = 0, i;
2122 
2123 	*fattrflagp = 0;
2124 	*tattrflagp = 0;
2125 	nmp = VFSTONFS(vnode_mount(fdvp));
2126 	if (fnamelen > NFS_MAXNAMLEN || tnamelen > NFS_MAXNAMLEN)
2127 		return (ENAMETOOLONG);
2128 tryagain:
2129 	if (NFSHASNFSV4(nmp) && ret == 0) {
2130 		ret = nfscl_renamedeleg(fvp, &fdstateid, &gotfd, tvp,
2131 		    &tdstateid, &gottd, p);
2132 		if (gotfd && gottd) {
2133 			NFSCL_REQSTART(nd, NFSPROC_RETDELEGRENAME2, fvp);
2134 		} else if (gotfd) {
2135 			NFSCL_REQSTART(nd, NFSPROC_RETDELEGRENAME1, fvp);
2136 		} else if (gottd) {
2137 			NFSCL_REQSTART(nd, NFSPROC_RETDELEGRENAME1, tvp);
2138 		}
2139 		if (gotfd) {
2140 			NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2141 			*tl++ = fdstateid.seqid;
2142 			*tl++ = fdstateid.other[0];
2143 			*tl++ = fdstateid.other[1];
2144 			*tl = fdstateid.other[2];
2145 			if (gottd) {
2146 				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2147 				*tl = txdr_unsigned(NFSV4OP_PUTFH);
2148 				np = VTONFS(tvp);
2149 				(void) nfsm_fhtom(nd, np->n_fhp->nfh_fh,
2150 				    np->n_fhp->nfh_len, 0);
2151 				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2152 				*tl = txdr_unsigned(NFSV4OP_DELEGRETURN);
2153 			}
2154 		}
2155 		if (gottd) {
2156 			NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2157 			*tl++ = tdstateid.seqid;
2158 			*tl++ = tdstateid.other[0];
2159 			*tl++ = tdstateid.other[1];
2160 			*tl = tdstateid.other[2];
2161 		}
2162 		if (ret > 0) {
2163 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2164 			*tl = txdr_unsigned(NFSV4OP_PUTFH);
2165 			np = VTONFS(fdvp);
2166 			(void) nfsm_fhtom(nd, np->n_fhp->nfh_fh,
2167 			    np->n_fhp->nfh_len, 0);
2168 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2169 			*tl = txdr_unsigned(NFSV4OP_SAVEFH);
2170 		}
2171 	} else {
2172 		ret = 0;
2173 	}
2174 	if (ret == 0)
2175 		NFSCL_REQSTART(nd, NFSPROC_RENAME, fdvp);
2176 	if (nd->nd_flag & ND_NFSV4) {
2177 		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2178 		*tl = txdr_unsigned(NFSV4OP_GETATTR);
2179 		NFSWCCATTR_ATTRBIT(&attrbits);
2180 		(void) nfsrv_putattrbit(nd, &attrbits);
2181 		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2182 		*tl = txdr_unsigned(NFSV4OP_PUTFH);
2183 		(void) nfsm_fhtom(nd, VTONFS(tdvp)->n_fhp->nfh_fh,
2184 		    VTONFS(tdvp)->n_fhp->nfh_len, 0);
2185 		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2186 		*tl = txdr_unsigned(NFSV4OP_GETATTR);
2187 		(void) nfsrv_putattrbit(nd, &attrbits);
2188 		nd->nd_flag |= ND_V4WCCATTR;
2189 		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2190 		*tl = txdr_unsigned(NFSV4OP_RENAME);
2191 	}
2192 	(void) nfsm_strtom(nd, fnameptr, fnamelen);
2193 	if (!(nd->nd_flag & ND_NFSV4))
2194 		(void) nfsm_fhtom(nd, VTONFS(tdvp)->n_fhp->nfh_fh,
2195 			VTONFS(tdvp)->n_fhp->nfh_len, 0);
2196 	(void) nfsm_strtom(nd, tnameptr, tnamelen);
2197 	error = nfscl_request(nd, fdvp, p, cred, fstuff);
2198 	if (error)
2199 		return (error);
2200 	if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
2201 		/* For NFSv4, parse out any Delereturn replies. */
2202 		if (ret > 0 && nd->nd_repstat != 0 &&
2203 		    (nd->nd_flag & ND_NOMOREDATA)) {
2204 			/*
2205 			 * If the Delegreturn failed, try again without
2206 			 * it. The server will Recall, as required.
2207 			 */
2208 			mbuf_freem(nd->nd_mrep);
2209 			goto tryagain;
2210 		}
2211 		for (i = 0; i < (ret * 2); i++) {
2212 			if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) ==
2213 			    ND_NFSV4) {
2214 			    NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2215 			    if (*(tl + 1)) {
2216 				if (i == 0 && ret > 1) {
2217 				    /*
2218 				     * If the Delegreturn failed, try again
2219 				     * without it. The server will Recall, as
2220 				     * required.
2221 				     * If ret > 1, the first iteration of this
2222 				     * loop is the second DelegReturn result.
2223 				     */
2224 				    mbuf_freem(nd->nd_mrep);
2225 				    goto tryagain;
2226 				} else {
2227 				    nd->nd_flag |= ND_NOMOREDATA;
2228 				}
2229 			    }
2230 			}
2231 		}
2232 		/* Now, the first wcc attribute reply. */
2233 		if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4) {
2234 			NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2235 			if (*(tl + 1))
2236 				nd->nd_flag |= ND_NOMOREDATA;
2237 		}
2238 		error = nfscl_wcc_data(nd, fdvp, fnap, fattrflagp, NULL,
2239 		    fstuff);
2240 		/* and the second wcc attribute reply. */
2241 		if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4 &&
2242 		    !error) {
2243 			NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2244 			if (*(tl + 1))
2245 				nd->nd_flag |= ND_NOMOREDATA;
2246 		}
2247 		if (!error)
2248 			error = nfscl_wcc_data(nd, tdvp, tnap, tattrflagp,
2249 			    NULL, tstuff);
2250 	}
2251 	if (nd->nd_repstat && !error)
2252 		error = nd->nd_repstat;
2253 nfsmout:
2254 	mbuf_freem(nd->nd_mrep);
2255 	return (error);
2256 }
2257 
2258 /*
2259  * nfs hard link create rpc
2260  */
2261 APPLESTATIC int
2262 nfsrpc_link(vnode_t dvp, vnode_t vp, char *name, int namelen,
2263     struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap,
2264     struct nfsvattr *nap, int *attrflagp, int *dattrflagp, void *dstuff)
2265 {
2266 	u_int32_t *tl;
2267 	struct nfsrv_descript nfsd, *nd = &nfsd;
2268 	nfsattrbit_t attrbits;
2269 	int error = 0;
2270 
2271 	*attrflagp = 0;
2272 	*dattrflagp = 0;
2273 	if (namelen > NFS_MAXNAMLEN)
2274 		return (ENAMETOOLONG);
2275 	NFSCL_REQSTART(nd, NFSPROC_LINK, vp);
2276 	if (nd->nd_flag & ND_NFSV4) {
2277 		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2278 		*tl = txdr_unsigned(NFSV4OP_PUTFH);
2279 	}
2280 	(void) nfsm_fhtom(nd, VTONFS(dvp)->n_fhp->nfh_fh,
2281 		VTONFS(dvp)->n_fhp->nfh_len, 0);
2282 	if (nd->nd_flag & ND_NFSV4) {
2283 		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2284 		*tl = txdr_unsigned(NFSV4OP_GETATTR);
2285 		NFSWCCATTR_ATTRBIT(&attrbits);
2286 		(void) nfsrv_putattrbit(nd, &attrbits);
2287 		nd->nd_flag |= ND_V4WCCATTR;
2288 		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2289 		*tl = txdr_unsigned(NFSV4OP_LINK);
2290 	}
2291 	(void) nfsm_strtom(nd, name, namelen);
2292 	error = nfscl_request(nd, vp, p, cred, dstuff);
2293 	if (error)
2294 		return (error);
2295 	if (nd->nd_flag & ND_NFSV3) {
2296 		error = nfscl_postop_attr(nd, nap, attrflagp, dstuff);
2297 		if (!error)
2298 			error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp,
2299 			    NULL, dstuff);
2300 	} else if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4) {
2301 		/*
2302 		 * First, parse out the PutFH and Getattr result.
2303 		 */
2304 		NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2305 		if (!(*(tl + 1)))
2306 			NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2307 		if (*(tl + 1))
2308 			nd->nd_flag |= ND_NOMOREDATA;
2309 		/*
2310 		 * Get the pre-op attributes.
2311 		 */
2312 		error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
2313 	}
2314 	if (nd->nd_repstat && !error)
2315 		error = nd->nd_repstat;
2316 nfsmout:
2317 	mbuf_freem(nd->nd_mrep);
2318 	return (error);
2319 }
2320 
2321 /*
2322  * nfs symbolic link create rpc
2323  */
2324 APPLESTATIC int
2325 nfsrpc_symlink(vnode_t dvp, char *name, int namelen, char *target,
2326     struct vattr *vap, struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap,
2327     struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp,
2328     int *dattrflagp, void *dstuff)
2329 {
2330 	u_int32_t *tl;
2331 	struct nfsrv_descript nfsd, *nd = &nfsd;
2332 	struct nfsmount *nmp;
2333 	int slen, error = 0;
2334 
2335 	*nfhpp = NULL;
2336 	*attrflagp = 0;
2337 	*dattrflagp = 0;
2338 	nmp = VFSTONFS(vnode_mount(dvp));
2339 	slen = strlen(target);
2340 	if (slen > NFS_MAXPATHLEN || namelen > NFS_MAXNAMLEN)
2341 		return (ENAMETOOLONG);
2342 	NFSCL_REQSTART(nd, NFSPROC_SYMLINK, dvp);
2343 	if (nd->nd_flag & ND_NFSV4) {
2344 		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2345 		*tl = txdr_unsigned(NFLNK);
2346 		(void) nfsm_strtom(nd, target, slen);
2347 	}
2348 	(void) nfsm_strtom(nd, name, namelen);
2349 	if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4))
2350 		nfscl_fillsattr(nd, vap, dvp, 0, 0);
2351 	if (!(nd->nd_flag & ND_NFSV4))
2352 		(void) nfsm_strtom(nd, target, slen);
2353 	if (nd->nd_flag & ND_NFSV2)
2354 		nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZENEG1, 0);
2355 	error = nfscl_request(nd, dvp, p, cred, dstuff);
2356 	if (error)
2357 		return (error);
2358 	if (nd->nd_flag & ND_NFSV4)
2359 		error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
2360 	if ((nd->nd_flag & ND_NFSV3) && !error) {
2361 		if (!nd->nd_repstat)
2362 			error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp);
2363 		if (!error)
2364 			error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp,
2365 			    NULL, dstuff);
2366 	}
2367 	if (nd->nd_repstat && !error)
2368 		error = nd->nd_repstat;
2369 	mbuf_freem(nd->nd_mrep);
2370 	/*
2371 	 * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
2372 	 */
2373 	if (error == EEXIST)
2374 		error = 0;
2375 	return (error);
2376 }
2377 
2378 /*
2379  * nfs make dir rpc
2380  */
2381 APPLESTATIC int
2382 nfsrpc_mkdir(vnode_t dvp, char *name, int namelen, struct vattr *vap,
2383     struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap,
2384     struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp,
2385     int *dattrflagp, void *dstuff)
2386 {
2387 	u_int32_t *tl;
2388 	struct nfsrv_descript nfsd, *nd = &nfsd;
2389 	nfsattrbit_t attrbits;
2390 	int error = 0;
2391 
2392 	*nfhpp = NULL;
2393 	*attrflagp = 0;
2394 	*dattrflagp = 0;
2395 	if (namelen > NFS_MAXNAMLEN)
2396 		return (ENAMETOOLONG);
2397 	NFSCL_REQSTART(nd, NFSPROC_MKDIR, dvp);
2398 	if (nd->nd_flag & ND_NFSV4) {
2399 		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2400 		*tl = txdr_unsigned(NFDIR);
2401 	}
2402 	(void) nfsm_strtom(nd, name, namelen);
2403 	nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZENEG1, 0);
2404 	if (nd->nd_flag & ND_NFSV4) {
2405 		NFSGETATTR_ATTRBIT(&attrbits);
2406 		NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2407 		*tl++ = txdr_unsigned(NFSV4OP_GETFH);
2408 		*tl = txdr_unsigned(NFSV4OP_GETATTR);
2409 		(void) nfsrv_putattrbit(nd, &attrbits);
2410 	}
2411 	error = nfscl_request(nd, dvp, p, cred, dstuff);
2412 	if (error)
2413 		return (error);
2414 	if (nd->nd_flag & ND_NFSV4)
2415 		error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
2416 	if (!nd->nd_repstat && !error) {
2417 		if (nd->nd_flag & ND_NFSV4) {
2418 			NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
2419 			error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
2420 		}
2421 		if (!error)
2422 			error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp);
2423 	}
2424 	if ((nd->nd_flag & ND_NFSV3) && !error)
2425 		error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
2426 	if (nd->nd_repstat && !error)
2427 		error = nd->nd_repstat;
2428 nfsmout:
2429 	mbuf_freem(nd->nd_mrep);
2430 	/*
2431 	 * Kludge: Map EEXIST => 0 assuming that you have a reply to a retry.
2432 	 */
2433 	if (error == EEXIST)
2434 		error = 0;
2435 	return (error);
2436 }
2437 
2438 /*
2439  * nfs remove directory call
2440  */
2441 APPLESTATIC int
2442 nfsrpc_rmdir(vnode_t dvp, char *name, int namelen, struct ucred *cred,
2443     NFSPROC_T *p, struct nfsvattr *dnap, int *dattrflagp, void *dstuff)
2444 {
2445 	struct nfsrv_descript nfsd, *nd = &nfsd;
2446 	int error = 0;
2447 
2448 	*dattrflagp = 0;
2449 	if (namelen > NFS_MAXNAMLEN)
2450 		return (ENAMETOOLONG);
2451 	NFSCL_REQSTART(nd, NFSPROC_RMDIR, dvp);
2452 	(void) nfsm_strtom(nd, name, namelen);
2453 	error = nfscl_request(nd, dvp, p, cred, dstuff);
2454 	if (error)
2455 		return (error);
2456 	if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4))
2457 		error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
2458 	if (nd->nd_repstat && !error)
2459 		error = nd->nd_repstat;
2460 	mbuf_freem(nd->nd_mrep);
2461 	/*
2462 	 * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry.
2463 	 */
2464 	if (error == ENOENT)
2465 		error = 0;
2466 	return (error);
2467 }
2468 
2469 /*
2470  * Readdir rpc.
2471  * Always returns with either uio_resid unchanged, if you are at the
2472  * end of the directory, or uio_resid == 0, with all DIRBLKSIZ chunks
2473  * filled in.
2474  * I felt this would allow caching of directory blocks more easily
2475  * than returning a pertially filled block.
2476  * Directory offset cookies:
2477  * Oh my, what to do with them...
2478  * I can think of three ways to deal with them:
2479  * 1 - have the layer above these RPCs maintain a map between logical
2480  *     directory byte offsets and the NFS directory offset cookies
2481  * 2 - pass the opaque directory offset cookies up into userland
2482  *     and let the libc functions deal with them, via the system call
2483  * 3 - return them to userland in the "struct dirent", so future versions
2484  *     of libc can use them and do whatever is necessary to amke things work
2485  *     above these rpc calls, in the meantime
2486  * For now, I do #3 by "hiding" the directory offset cookies after the
2487  * d_name field in struct dirent. This is space inside d_reclen that
2488  * will be ignored by anything that doesn't know about them.
2489  * The directory offset cookies are filled in as the last 8 bytes of
2490  * each directory entry, after d_name. Someday, the userland libc
2491  * functions may be able to use these. In the meantime, it satisfies
2492  * OpenBSD's requirements for cookies being returned.
2493  * If expects the directory offset cookie for the read to be in uio_offset
2494  * and returns the one for the next entry after this directory block in
2495  * there, as well.
2496  */
2497 APPLESTATIC int
2498 nfsrpc_readdir(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep,
2499     struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp,
2500     int *eofp, void *stuff)
2501 {
2502 	int len, left;
2503 	struct dirent *dp = NULL;
2504 	u_int32_t *tl;
2505 	nfsquad_t cookie, ncookie;
2506 	struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
2507 	struct nfsnode *dnp = VTONFS(vp);
2508 	struct nfsvattr nfsva;
2509 	struct nfsrv_descript nfsd, *nd = &nfsd;
2510 	int error = 0, tlen, more_dirs = 1, blksiz = 0, bigenough = 1;
2511 	int reqsize, tryformoredirs = 1, readsize, eof = 0, gotmnton = 0;
2512 	long dotfileid, dotdotfileid = 0;
2513 	u_int32_t fakefileno = 0xffffffff, rderr;
2514 	char *cp;
2515 	nfsattrbit_t attrbits, dattrbits;
2516 	u_int32_t *tl2 = NULL;
2517 	size_t tresid;
2518 
2519 	KASSERT(uiop->uio_iovcnt == 1 &&
2520 	    (uio_uio_resid(uiop) & (DIRBLKSIZ - 1)) == 0,
2521 	    ("nfs readdirrpc bad uio"));
2522 
2523 	/*
2524 	 * There is no point in reading a lot more than uio_resid, however
2525 	 * adding one additional DIRBLKSIZ makes sense. Since uio_resid
2526 	 * and nm_readdirsize are both exact multiples of DIRBLKSIZ, this
2527 	 * will never make readsize > nm_readdirsize.
2528 	 */
2529 	readsize = nmp->nm_readdirsize;
2530 	if (readsize > uio_uio_resid(uiop))
2531 		readsize = uio_uio_resid(uiop) + DIRBLKSIZ;
2532 
2533 	*attrflagp = 0;
2534 	if (eofp)
2535 		*eofp = 0;
2536 	tresid = uio_uio_resid(uiop);
2537 	cookie.lval[0] = cookiep->nfsuquad[0];
2538 	cookie.lval[1] = cookiep->nfsuquad[1];
2539 	nd->nd_mrep = NULL;
2540 
2541 	/*
2542 	 * For NFSv4, first create the "." and ".." entries.
2543 	 */
2544 	if (NFSHASNFSV4(nmp)) {
2545 		reqsize = 6 * NFSX_UNSIGNED;
2546 		NFSGETATTR_ATTRBIT(&dattrbits);
2547 		NFSZERO_ATTRBIT(&attrbits);
2548 		NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FILEID);
2549 		NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TYPE);
2550 		if (NFSISSET_ATTRBIT(&dnp->n_vattr.na_suppattr,
2551 		    NFSATTRBIT_MOUNTEDONFILEID)) {
2552 			NFSSETBIT_ATTRBIT(&attrbits,
2553 			    NFSATTRBIT_MOUNTEDONFILEID);
2554 			gotmnton = 1;
2555 		} else {
2556 			/*
2557 			 * Must fake it. Use the fileno, except when the
2558 			 * fsid is != to that of the directory. For that
2559 			 * case, generate a fake fileno that is not the same.
2560 			 */
2561 			NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FSID);
2562 			gotmnton = 0;
2563 		}
2564 
2565 		/*
2566 		 * Joy, oh joy. For V4 we get to hand craft '.' and '..'.
2567 		 */
2568 		if (uiop->uio_offset == 0) {
2569 #if defined(__FreeBSD_version) && __FreeBSD_version >= 800000
2570 			error = VOP_GETATTR(vp, &nfsva.na_vattr, cred);
2571 #else
2572 			error = VOP_GETATTR(vp, &nfsva.na_vattr, cred, p);
2573 #endif
2574 			if (error)
2575 			    return (error);
2576 			dotfileid = nfsva.na_fileid;
2577 			NFSCL_REQSTART(nd, NFSPROC_LOOKUPP, vp);
2578 			NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2579 			*tl++ = txdr_unsigned(NFSV4OP_GETFH);
2580 			*tl = txdr_unsigned(NFSV4OP_GETATTR);
2581 			(void) nfsrv_putattrbit(nd, &attrbits);
2582 			error = nfscl_request(nd, vp, p, cred, stuff);
2583 			if (error)
2584 			    return (error);
2585 			if (nd->nd_repstat == 0) {
2586 			    NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED);
2587 			    len = fxdr_unsigned(int, *(tl + 2));
2588 			    if (len > 0 && len <= NFSX_V4FHMAX)
2589 				error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
2590 			    else
2591 				error = EPERM;
2592 			    if (!error) {
2593 				NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED);
2594 				nfsva.na_mntonfileno = 0xffffffff;
2595 				error = nfsv4_loadattr(nd, NULL, &nfsva, NULL,
2596 				    NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
2597 				    NULL, NULL, NULL, p, cred);
2598 				if (error) {
2599 				    dotdotfileid = dotfileid;
2600 				} else if (gotmnton) {
2601 				    if (nfsva.na_mntonfileno != 0xffffffff)
2602 					dotdotfileid = nfsva.na_mntonfileno;
2603 				    else
2604 					dotdotfileid = nfsva.na_fileid;
2605 				} else if (nfsva.na_filesid[0] ==
2606 				    dnp->n_vattr.na_filesid[0] &&
2607 				    nfsva.na_filesid[1] ==
2608 				    dnp->n_vattr.na_filesid[1]) {
2609 				    dotdotfileid = nfsva.na_fileid;
2610 				} else {
2611 				    do {
2612 					fakefileno--;
2613 				    } while (fakefileno ==
2614 					nfsva.na_fileid);
2615 				    dotdotfileid = fakefileno;
2616 				}
2617 			    }
2618 			} else if (nd->nd_repstat == NFSERR_NOENT) {
2619 			    /*
2620 			     * Lookupp returns NFSERR_NOENT when we are
2621 			     * at the root, so just use the current dir.
2622 			     */
2623 			    nd->nd_repstat = 0;
2624 			    dotdotfileid = dotfileid;
2625 			} else {
2626 			    error = nd->nd_repstat;
2627 			}
2628 			mbuf_freem(nd->nd_mrep);
2629 			if (error)
2630 			    return (error);
2631 			nd->nd_mrep = NULL;
2632 			dp = (struct dirent *) CAST_DOWN(caddr_t, uio_iov_base(uiop));
2633 			dp->d_type = DT_DIR;
2634 			dp->d_fileno = dotfileid;
2635 			dp->d_namlen = 1;
2636 			dp->d_name[0] = '.';
2637 			dp->d_name[1] = '\0';
2638 			dp->d_reclen = DIRENT_SIZE(dp) + NFSX_HYPER;
2639 			/*
2640 			 * Just make these offset cookie 0.
2641 			 */
2642 			tl = (u_int32_t *)&dp->d_name[4];
2643 			*tl++ = 0;
2644 			*tl = 0;
2645 			blksiz += dp->d_reclen;
2646 			uio_uio_resid_add(uiop, -(dp->d_reclen));
2647 			uiop->uio_offset += dp->d_reclen;
2648 			uio_iov_base_add(uiop, dp->d_reclen);
2649 			uio_iov_len_add(uiop, -(dp->d_reclen));
2650 			dp = (struct dirent *) CAST_DOWN(caddr_t, uio_iov_base(uiop));
2651 			dp->d_type = DT_DIR;
2652 			dp->d_fileno = dotdotfileid;
2653 			dp->d_namlen = 2;
2654 			dp->d_name[0] = '.';
2655 			dp->d_name[1] = '.';
2656 			dp->d_name[2] = '\0';
2657 			dp->d_reclen = DIRENT_SIZE(dp) + NFSX_HYPER;
2658 			/*
2659 			 * Just make these offset cookie 0.
2660 			 */
2661 			tl = (u_int32_t *)&dp->d_name[4];
2662 			*tl++ = 0;
2663 			*tl = 0;
2664 			blksiz += dp->d_reclen;
2665 			uio_uio_resid_add(uiop, -(dp->d_reclen));
2666 			uiop->uio_offset += dp->d_reclen;
2667 			uio_iov_base_add(uiop, dp->d_reclen);
2668 			uio_iov_len_add(uiop, -(dp->d_reclen));
2669 		}
2670 		NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_RDATTRERROR);
2671 	} else {
2672 		reqsize = 5 * NFSX_UNSIGNED;
2673 	}
2674 
2675 
2676 	/*
2677 	 * Loop around doing readdir rpc's of size readsize.
2678 	 * The stopping criteria is EOF or buffer full.
2679 	 */
2680 	while (more_dirs && bigenough) {
2681 		*attrflagp = 0;
2682 		NFSCL_REQSTART(nd, NFSPROC_READDIR, vp);
2683 		if (nd->nd_flag & ND_NFSV2) {
2684 			NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2685 			*tl++ = cookie.lval[1];
2686 			*tl = txdr_unsigned(readsize);
2687 		} else {
2688 			NFSM_BUILD(tl, u_int32_t *, reqsize);
2689 			*tl++ = cookie.lval[0];
2690 			*tl++ = cookie.lval[1];
2691 			if (cookie.qval == 0) {
2692 				*tl++ = 0;
2693 				*tl++ = 0;
2694 			} else {
2695 				NFSLOCKNODE(dnp);
2696 				*tl++ = dnp->n_cookieverf.nfsuquad[0];
2697 				*tl++ = dnp->n_cookieverf.nfsuquad[1];
2698 				NFSUNLOCKNODE(dnp);
2699 			}
2700 			if (nd->nd_flag & ND_NFSV4) {
2701 				*tl++ = txdr_unsigned(readsize);
2702 				*tl = txdr_unsigned(readsize);
2703 				(void) nfsrv_putattrbit(nd, &attrbits);
2704 				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2705 				*tl = txdr_unsigned(NFSV4OP_GETATTR);
2706 				(void) nfsrv_putattrbit(nd, &dattrbits);
2707 			} else {
2708 				*tl = txdr_unsigned(readsize);
2709 			}
2710 		}
2711 		error = nfscl_request(nd, vp, p, cred, stuff);
2712 		if (error)
2713 			return (error);
2714 		if (!(nd->nd_flag & ND_NFSV2)) {
2715 			if (nd->nd_flag & ND_NFSV3)
2716 				error = nfscl_postop_attr(nd, nap, attrflagp,
2717 				    stuff);
2718 			if (!nd->nd_repstat && !error) {
2719 				NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2720 				NFSLOCKNODE(dnp);
2721 				dnp->n_cookieverf.nfsuquad[0] = *tl++;
2722 				dnp->n_cookieverf.nfsuquad[1] = *tl;
2723 				NFSUNLOCKNODE(dnp);
2724 			}
2725 		}
2726 		if (nd->nd_repstat || error) {
2727 			if (!error)
2728 				error = nd->nd_repstat;
2729 			goto nfsmout;
2730 		}
2731 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2732 		more_dirs = fxdr_unsigned(int, *tl);
2733 		if (!more_dirs)
2734 			tryformoredirs = 0;
2735 
2736 		/* loop thru the dir entries, doctoring them to 4bsd form */
2737 		while (more_dirs && bigenough) {
2738 			if (nd->nd_flag & ND_NFSV4) {
2739 				NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED);
2740 				ncookie.lval[0] = *tl++;
2741 				ncookie.lval[1] = *tl++;
2742 				len = fxdr_unsigned(int, *tl);
2743 			} else if (nd->nd_flag & ND_NFSV3) {
2744 				NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED);
2745 				nfsva.na_fileid = fxdr_hyper(tl);
2746 				tl += 2;
2747 				len = fxdr_unsigned(int, *tl);
2748 			} else {
2749 				NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED);
2750 				nfsva.na_fileid =
2751 				    fxdr_unsigned(long, *tl++);
2752 				len = fxdr_unsigned(int, *tl);
2753 			}
2754 			if (len <= 0 || len > NFS_MAXNAMLEN) {
2755 				error = EBADRPC;
2756 				goto nfsmout;
2757 			}
2758 			tlen = NFSM_RNDUP(len);
2759 			if (tlen == len)
2760 				tlen += 4;  /* To ensure null termination */
2761 			left = DIRBLKSIZ - blksiz;
2762 			if ((int)(tlen + DIRHDSIZ + NFSX_HYPER) > left) {
2763 				dp->d_reclen += left;
2764 				uio_iov_base_add(uiop, left);
2765 				uio_iov_len_add(uiop, -(left));
2766 				uio_uio_resid_add(uiop, -(left));
2767 				uiop->uio_offset += left;
2768 				blksiz = 0;
2769 			}
2770 			if ((int)(tlen + DIRHDSIZ + NFSX_HYPER) > uio_uio_resid(uiop))
2771 				bigenough = 0;
2772 			if (bigenough) {
2773 				dp = (struct dirent *) CAST_DOWN(caddr_t, uio_iov_base(uiop));
2774 				dp->d_namlen = len;
2775 				dp->d_reclen = tlen + DIRHDSIZ + NFSX_HYPER;
2776 				dp->d_type = DT_UNKNOWN;
2777 				blksiz += dp->d_reclen;
2778 				if (blksiz == DIRBLKSIZ)
2779 					blksiz = 0;
2780 				uio_uio_resid_add(uiop, -(DIRHDSIZ));
2781 				uiop->uio_offset += DIRHDSIZ;
2782 				uio_iov_base_add(uiop, DIRHDSIZ);
2783 				uio_iov_len_add(uiop, -(DIRHDSIZ));
2784 				error = nfsm_mbufuio(nd, uiop, len);
2785 				if (error)
2786 					goto nfsmout;
2787 				cp = CAST_DOWN(caddr_t, uio_iov_base(uiop));
2788 				tlen -= len;
2789 				*cp = '\0';	/* null terminate */
2790 				cp += tlen;	/* points to cookie storage */
2791 				tl2 = (u_int32_t *)cp;
2792 				uio_iov_base_add(uiop, (tlen + NFSX_HYPER));
2793 				uio_iov_len_add(uiop, -(tlen + NFSX_HYPER));
2794 				uio_uio_resid_add(uiop, -(tlen + NFSX_HYPER));
2795 				uiop->uio_offset += (tlen + NFSX_HYPER);
2796 			} else {
2797 				error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
2798 				if (error)
2799 					goto nfsmout;
2800 			}
2801 			if (nd->nd_flag & ND_NFSV4) {
2802 				rderr = 0;
2803 				nfsva.na_mntonfileno = 0xffffffff;
2804 				error = nfsv4_loadattr(nd, NULL, &nfsva, NULL,
2805 				    NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
2806 				    NULL, NULL, &rderr, p, cred);
2807 				if (error)
2808 					goto nfsmout;
2809 				NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2810 			} else if (nd->nd_flag & ND_NFSV3) {
2811 				NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED);
2812 				ncookie.lval[0] = *tl++;
2813 				ncookie.lval[1] = *tl++;
2814 			} else {
2815 				NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED);
2816 				ncookie.lval[0] = 0;
2817 				ncookie.lval[1] = *tl++;
2818 			}
2819 			if (bigenough) {
2820 			    if (nd->nd_flag & ND_NFSV4) {
2821 				if (rderr) {
2822 				    dp->d_fileno = 0;
2823 				} else {
2824 				    if (gotmnton) {
2825 					if (nfsva.na_mntonfileno != 0xffffffff)
2826 					    dp->d_fileno = nfsva.na_mntonfileno;
2827 					else
2828 					    dp->d_fileno = nfsva.na_fileid;
2829 				    } else if (nfsva.na_filesid[0] ==
2830 					dnp->n_vattr.na_filesid[0] &&
2831 					nfsva.na_filesid[1] ==
2832 					dnp->n_vattr.na_filesid[1]) {
2833 					dp->d_fileno = nfsva.na_fileid;
2834 				    } else {
2835 					do {
2836 					    fakefileno--;
2837 					} while (fakefileno ==
2838 					    nfsva.na_fileid);
2839 					dp->d_fileno = fakefileno;
2840 				    }
2841 				    dp->d_type = vtonfs_dtype(nfsva.na_type);
2842 				}
2843 			    } else {
2844 				dp->d_fileno = nfsva.na_fileid;
2845 			    }
2846 			    *tl2++ = cookiep->nfsuquad[0] = cookie.lval[0] =
2847 				ncookie.lval[0];
2848 			    *tl2 = cookiep->nfsuquad[1] = cookie.lval[1] =
2849 				ncookie.lval[1];
2850 			}
2851 			more_dirs = fxdr_unsigned(int, *tl);
2852 		}
2853 		/*
2854 		 * If at end of rpc data, get the eof boolean
2855 		 */
2856 		if (!more_dirs) {
2857 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2858 			eof = fxdr_unsigned(int, *tl);
2859 			if (tryformoredirs)
2860 				more_dirs = !eof;
2861 			if (nd->nd_flag & ND_NFSV4) {
2862 				error = nfscl_postop_attr(nd, nap, attrflagp,
2863 				    stuff);
2864 				if (error)
2865 					goto nfsmout;
2866 			}
2867 		}
2868 		mbuf_freem(nd->nd_mrep);
2869 		nd->nd_mrep = NULL;
2870 	}
2871 	/*
2872 	 * Fill last record, iff any, out to a multiple of DIRBLKSIZ
2873 	 * by increasing d_reclen for the last record.
2874 	 */
2875 	if (blksiz > 0) {
2876 		left = DIRBLKSIZ - blksiz;
2877 		dp->d_reclen += left;
2878 		uio_iov_base_add(uiop, left);
2879 		uio_iov_len_add(uiop, -(left));
2880 		uio_uio_resid_add(uiop, -(left));
2881 		uiop->uio_offset += left;
2882 	}
2883 
2884 	/*
2885 	 * If returning no data, assume end of file.
2886 	 * If not bigenough, return not end of file, since you aren't
2887 	 *    returning all the data
2888 	 * Otherwise, return the eof flag from the server.
2889 	 */
2890 	if (eofp) {
2891 		if (tresid == ((size_t)(uio_uio_resid(uiop))))
2892 			*eofp = 1;
2893 		else if (!bigenough)
2894 			*eofp = 0;
2895 		else
2896 			*eofp = eof;
2897 	}
2898 
2899 	/*
2900 	 * Add extra empty records to any remaining DIRBLKSIZ chunks.
2901 	 */
2902 	while (uio_uio_resid(uiop) > 0 && ((size_t)(uio_uio_resid(uiop))) != tresid) {
2903 		dp = (struct dirent *) CAST_DOWN(caddr_t, uio_iov_base(uiop));
2904 		dp->d_type = DT_UNKNOWN;
2905 		dp->d_fileno = 0;
2906 		dp->d_namlen = 0;
2907 		dp->d_name[0] = '\0';
2908 		tl = (u_int32_t *)&dp->d_name[4];
2909 		*tl++ = cookie.lval[0];
2910 		*tl = cookie.lval[1];
2911 		dp->d_reclen = DIRBLKSIZ;
2912 		uio_iov_base_add(uiop, DIRBLKSIZ);
2913 		uio_iov_len_add(uiop, -(DIRBLKSIZ));
2914 		uio_uio_resid_add(uiop, -(DIRBLKSIZ));
2915 		uiop->uio_offset += DIRBLKSIZ;
2916 	}
2917 
2918 nfsmout:
2919 	if (nd->nd_mrep != NULL)
2920 		mbuf_freem(nd->nd_mrep);
2921 	return (error);
2922 }
2923 
2924 #ifndef APPLE
2925 /*
2926  * NFS V3 readdir plus RPC. Used in place of nfsrpc_readdir().
2927  * (Also used for NFS V4 when mount flag set.)
2928  * (ditto above w.r.t. multiple of DIRBLKSIZ, etc.)
2929  */
2930 APPLESTATIC int
2931 nfsrpc_readdirplus(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep,
2932     struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp,
2933     int *eofp, void *stuff)
2934 {
2935 	int len, left;
2936 	struct dirent *dp = NULL;
2937 	u_int32_t *tl;
2938 	vnode_t newvp = NULLVP;
2939 	struct nfsrv_descript nfsd, *nd = &nfsd;
2940 	struct nameidata nami, *ndp = &nami;
2941 	struct componentname *cnp = &ndp->ni_cnd;
2942 	struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
2943 	struct nfsnode *dnp = VTONFS(vp), *np;
2944 	struct nfsvattr nfsva;
2945 	struct nfsfh *nfhp;
2946 	nfsquad_t cookie, ncookie;
2947 	int error = 0, tlen, more_dirs = 1, blksiz = 0, bigenough = 1;
2948 	int attrflag, tryformoredirs = 1, eof = 0, gotmnton = 0;
2949 	int isdotdot = 0, unlocknewvp = 0;
2950 	long dotfileid, dotdotfileid = 0, fileno = 0;
2951 	char *cp;
2952 	nfsattrbit_t attrbits, dattrbits;
2953 	size_t tresid;
2954 	u_int32_t *tl2 = NULL, fakefileno = 0xffffffff, rderr;
2955 	struct timespec dctime;
2956 
2957 	KASSERT(uiop->uio_iovcnt == 1 &&
2958 	    (uio_uio_resid(uiop) & (DIRBLKSIZ - 1)) == 0,
2959 	    ("nfs readdirplusrpc bad uio"));
2960 	timespecclear(&dctime);
2961 	*attrflagp = 0;
2962 	if (eofp != NULL)
2963 		*eofp = 0;
2964 	ndp->ni_dvp = vp;
2965 	nd->nd_mrep = NULL;
2966 	cookie.lval[0] = cookiep->nfsuquad[0];
2967 	cookie.lval[1] = cookiep->nfsuquad[1];
2968 	tresid = uio_uio_resid(uiop);
2969 
2970 	/*
2971 	 * For NFSv4, first create the "." and ".." entries.
2972 	 */
2973 	if (NFSHASNFSV4(nmp)) {
2974 		NFSGETATTR_ATTRBIT(&dattrbits);
2975 		NFSZERO_ATTRBIT(&attrbits);
2976 		NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FILEID);
2977 		if (NFSISSET_ATTRBIT(&dnp->n_vattr.na_suppattr,
2978 		    NFSATTRBIT_MOUNTEDONFILEID)) {
2979 			NFSSETBIT_ATTRBIT(&attrbits,
2980 			    NFSATTRBIT_MOUNTEDONFILEID);
2981 			gotmnton = 1;
2982 		} else {
2983 			/*
2984 			 * Must fake it. Use the fileno, except when the
2985 			 * fsid is != to that of the directory. For that
2986 			 * case, generate a fake fileno that is not the same.
2987 			 */
2988 			NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FSID);
2989 			gotmnton = 0;
2990 		}
2991 
2992 		/*
2993 		 * Joy, oh joy. For V4 we get to hand craft '.' and '..'.
2994 		 */
2995 		if (uiop->uio_offset == 0) {
2996 #if defined(__FreeBSD_version) && __FreeBSD_version >= 800000
2997 			error = VOP_GETATTR(vp, &nfsva.na_vattr, cred);
2998 #else
2999 			error = VOP_GETATTR(vp, &nfsva.na_vattr, cred, p);
3000 #endif
3001 			if (error)
3002 			    return (error);
3003 			dctime = nfsva.na_ctime;
3004 			dotfileid = nfsva.na_fileid;
3005 			NFSCL_REQSTART(nd, NFSPROC_LOOKUPP, vp);
3006 			NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3007 			*tl++ = txdr_unsigned(NFSV4OP_GETFH);
3008 			*tl = txdr_unsigned(NFSV4OP_GETATTR);
3009 			(void) nfsrv_putattrbit(nd, &attrbits);
3010 			error = nfscl_request(nd, vp, p, cred, stuff);
3011 			if (error)
3012 			    return (error);
3013 			if (nd->nd_repstat == 0) {
3014 			    NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED);
3015 			    len = fxdr_unsigned(int, *(tl + 2));
3016 			    if (len > 0 && len <= NFSX_V4FHMAX)
3017 				error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
3018 			    else
3019 				error = EPERM;
3020 			    if (!error) {
3021 				NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED);
3022 				nfsva.na_mntonfileno = 0xffffffff;
3023 				error = nfsv4_loadattr(nd, NULL, &nfsva, NULL,
3024 				    NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
3025 				    NULL, NULL, NULL, p, cred);
3026 				if (error) {
3027 				    dotdotfileid = dotfileid;
3028 				} else if (gotmnton) {
3029 				    if (nfsva.na_mntonfileno != 0xffffffff)
3030 					dotdotfileid = nfsva.na_mntonfileno;
3031 				    else
3032 					dotdotfileid = nfsva.na_fileid;
3033 				} else if (nfsva.na_filesid[0] ==
3034 				    dnp->n_vattr.na_filesid[0] &&
3035 				    nfsva.na_filesid[1] ==
3036 				    dnp->n_vattr.na_filesid[1]) {
3037 				    dotdotfileid = nfsva.na_fileid;
3038 				} else {
3039 				    do {
3040 					fakefileno--;
3041 				    } while (fakefileno ==
3042 					nfsva.na_fileid);
3043 				    dotdotfileid = fakefileno;
3044 				}
3045 			    }
3046 			} else if (nd->nd_repstat == NFSERR_NOENT) {
3047 			    /*
3048 			     * Lookupp returns NFSERR_NOENT when we are
3049 			     * at the root, so just use the current dir.
3050 			     */
3051 			    nd->nd_repstat = 0;
3052 			    dotdotfileid = dotfileid;
3053 			} else {
3054 			    error = nd->nd_repstat;
3055 			}
3056 			mbuf_freem(nd->nd_mrep);
3057 			if (error)
3058 			    return (error);
3059 			nd->nd_mrep = NULL;
3060 			dp = (struct dirent *)uio_iov_base(uiop);
3061 			dp->d_type = DT_DIR;
3062 			dp->d_fileno = dotfileid;
3063 			dp->d_namlen = 1;
3064 			dp->d_name[0] = '.';
3065 			dp->d_name[1] = '\0';
3066 			dp->d_reclen = DIRENT_SIZE(dp) + NFSX_HYPER;
3067 			/*
3068 			 * Just make these offset cookie 0.
3069 			 */
3070 			tl = (u_int32_t *)&dp->d_name[4];
3071 			*tl++ = 0;
3072 			*tl = 0;
3073 			blksiz += dp->d_reclen;
3074 			uio_uio_resid_add(uiop, -(dp->d_reclen));
3075 			uiop->uio_offset += dp->d_reclen;
3076 			uio_iov_base_add(uiop, dp->d_reclen);
3077 			uio_iov_len_add(uiop, -(dp->d_reclen));
3078 			dp = (struct dirent *)uio_iov_base(uiop);
3079 			dp->d_type = DT_DIR;
3080 			dp->d_fileno = dotdotfileid;
3081 			dp->d_namlen = 2;
3082 			dp->d_name[0] = '.';
3083 			dp->d_name[1] = '.';
3084 			dp->d_name[2] = '\0';
3085 			dp->d_reclen = DIRENT_SIZE(dp) + NFSX_HYPER;
3086 			/*
3087 			 * Just make these offset cookie 0.
3088 			 */
3089 			tl = (u_int32_t *)&dp->d_name[4];
3090 			*tl++ = 0;
3091 			*tl = 0;
3092 			blksiz += dp->d_reclen;
3093 			uio_uio_resid_add(uiop, -(dp->d_reclen));
3094 			uiop->uio_offset += dp->d_reclen;
3095 			uio_iov_base_add(uiop, dp->d_reclen);
3096 			uio_iov_len_add(uiop, -(dp->d_reclen));
3097 		}
3098 		NFSREADDIRPLUS_ATTRBIT(&attrbits);
3099 		if (gotmnton)
3100 			NFSSETBIT_ATTRBIT(&attrbits,
3101 			    NFSATTRBIT_MOUNTEDONFILEID);
3102 	}
3103 
3104 	/*
3105 	 * Loop around doing readdir rpc's of size nm_readdirsize.
3106 	 * The stopping criteria is EOF or buffer full.
3107 	 */
3108 	while (more_dirs && bigenough) {
3109 		*attrflagp = 0;
3110 		NFSCL_REQSTART(nd, NFSPROC_READDIRPLUS, vp);
3111  		NFSM_BUILD(tl, u_int32_t *, 6 * NFSX_UNSIGNED);
3112 		*tl++ = cookie.lval[0];
3113 		*tl++ = cookie.lval[1];
3114 		if (cookie.qval == 0) {
3115 			*tl++ = 0;
3116 			*tl++ = 0;
3117 		} else {
3118 			NFSLOCKNODE(dnp);
3119 			*tl++ = dnp->n_cookieverf.nfsuquad[0];
3120 			*tl++ = dnp->n_cookieverf.nfsuquad[1];
3121 			NFSUNLOCKNODE(dnp);
3122 		}
3123 		*tl++ = txdr_unsigned(nmp->nm_readdirsize);
3124 		*tl = txdr_unsigned(nmp->nm_readdirsize);
3125 		if (nd->nd_flag & ND_NFSV4) {
3126 			(void) nfsrv_putattrbit(nd, &attrbits);
3127 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3128 			*tl = txdr_unsigned(NFSV4OP_GETATTR);
3129 			(void) nfsrv_putattrbit(nd, &dattrbits);
3130 		}
3131 		error = nfscl_request(nd, vp, p, cred, stuff);
3132 		if (error)
3133 			return (error);
3134 		if (nd->nd_flag & ND_NFSV3)
3135 			error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
3136 		if (nd->nd_repstat || error) {
3137 			if (!error)
3138 				error = nd->nd_repstat;
3139 			goto nfsmout;
3140 		}
3141 		if ((nd->nd_flag & ND_NFSV3) != 0 && *attrflagp != 0)
3142 			dctime = nap->na_ctime;
3143 		NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3144 		NFSLOCKNODE(dnp);
3145 		dnp->n_cookieverf.nfsuquad[0] = *tl++;
3146 		dnp->n_cookieverf.nfsuquad[1] = *tl++;
3147 		NFSUNLOCKNODE(dnp);
3148 		more_dirs = fxdr_unsigned(int, *tl);
3149 		if (!more_dirs)
3150 			tryformoredirs = 0;
3151 
3152 		/* loop thru the dir entries, doctoring them to 4bsd form */
3153 		while (more_dirs && bigenough) {
3154 			NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3155 			if (nd->nd_flag & ND_NFSV4) {
3156 				ncookie.lval[0] = *tl++;
3157 				ncookie.lval[1] = *tl++;
3158 			} else {
3159 				fileno = fxdr_unsigned(long, *++tl);
3160 				tl++;
3161 			}
3162 			len = fxdr_unsigned(int, *tl);
3163 			if (len <= 0 || len > NFS_MAXNAMLEN) {
3164 				error = EBADRPC;
3165 				goto nfsmout;
3166 			}
3167 			tlen = NFSM_RNDUP(len);
3168 			if (tlen == len)
3169 				tlen += 4;  /* To ensure null termination */
3170 			left = DIRBLKSIZ - blksiz;
3171 			if ((tlen + DIRHDSIZ + NFSX_HYPER) > left) {
3172 				dp->d_reclen += left;
3173 				uio_iov_base_add(uiop, left);
3174 				uio_iov_len_add(uiop, -(left));
3175 				uio_uio_resid_add(uiop, -(left));
3176 				uiop->uio_offset += left;
3177 				blksiz = 0;
3178 			}
3179 			if ((tlen + DIRHDSIZ + NFSX_HYPER) > uio_uio_resid(uiop))
3180 				bigenough = 0;
3181 			if (bigenough) {
3182 				dp = (struct dirent *)uio_iov_base(uiop);
3183 				dp->d_namlen = len;
3184 				dp->d_reclen = tlen + DIRHDSIZ + NFSX_HYPER;
3185 				dp->d_type = DT_UNKNOWN;
3186 				blksiz += dp->d_reclen;
3187 				if (blksiz == DIRBLKSIZ)
3188 					blksiz = 0;
3189 				uio_uio_resid_add(uiop, -(DIRHDSIZ));
3190 				uiop->uio_offset += DIRHDSIZ;
3191 				uio_iov_base_add(uiop, DIRHDSIZ);
3192 				uio_iov_len_add(uiop, -(DIRHDSIZ));
3193 				cnp->cn_nameptr = uio_iov_base(uiop);
3194 				cnp->cn_namelen = len;
3195 				NFSCNHASHZERO(cnp);
3196 				error = nfsm_mbufuio(nd, uiop, len);
3197 				if (error)
3198 					goto nfsmout;
3199 				cp = uio_iov_base(uiop);
3200 				tlen -= len;
3201 				*cp = '\0';
3202 				cp += tlen;	/* points to cookie storage */
3203 				tl2 = (u_int32_t *)cp;
3204 				if (len == 2 && cnp->cn_nameptr[0] == '.' &&
3205 				    cnp->cn_nameptr[1] == '.')
3206 					isdotdot = 1;
3207 				else
3208 					isdotdot = 0;
3209 				uio_iov_base_add(uiop, (tlen + NFSX_HYPER));
3210 				uio_iov_len_add(uiop, -(tlen + NFSX_HYPER));
3211 				uio_uio_resid_add(uiop, -(tlen + NFSX_HYPER));
3212 				uiop->uio_offset += (tlen + NFSX_HYPER);
3213 			} else {
3214 				error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
3215 				if (error)
3216 					goto nfsmout;
3217 			}
3218 			nfhp = NULL;
3219 			if (nd->nd_flag & ND_NFSV3) {
3220 				NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED);
3221 				ncookie.lval[0] = *tl++;
3222 				ncookie.lval[1] = *tl++;
3223 				attrflag = fxdr_unsigned(int, *tl);
3224 				if (attrflag) {
3225 				  error = nfsm_loadattr(nd, &nfsva);
3226 				  if (error)
3227 					goto nfsmout;
3228 				}
3229 				NFSM_DISSECT(tl,u_int32_t *,NFSX_UNSIGNED);
3230 				if (*tl) {
3231 					error = nfsm_getfh(nd, &nfhp);
3232 					if (error)
3233 					    goto nfsmout;
3234 				}
3235 				if (!attrflag && nfhp != NULL) {
3236 					FREE((caddr_t)nfhp, M_NFSFH);
3237 					nfhp = NULL;
3238 				}
3239 			} else {
3240 				rderr = 0;
3241 				nfsva.na_mntonfileno = 0xffffffff;
3242 				error = nfsv4_loadattr(nd, NULL, &nfsva, &nfhp,
3243 				    NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
3244 				    NULL, NULL, &rderr, p, cred);
3245 				if (error)
3246 					goto nfsmout;
3247 			}
3248 
3249 			if (bigenough) {
3250 			    if (nd->nd_flag & ND_NFSV4) {
3251 				if (rderr) {
3252 				    dp->d_fileno = 0;
3253 				} else if (gotmnton) {
3254 				    if (nfsva.na_mntonfileno != 0xffffffff)
3255 					dp->d_fileno = nfsva.na_mntonfileno;
3256 				    else
3257 					dp->d_fileno = nfsva.na_fileid;
3258 				} else if (nfsva.na_filesid[0] ==
3259 				    dnp->n_vattr.na_filesid[0] &&
3260 				    nfsva.na_filesid[1] ==
3261 				    dnp->n_vattr.na_filesid[1]) {
3262 				    dp->d_fileno = nfsva.na_fileid;
3263 				} else {
3264 				    do {
3265 					fakefileno--;
3266 				    } while (fakefileno ==
3267 					nfsva.na_fileid);
3268 				    dp->d_fileno = fakefileno;
3269 				}
3270 			    } else {
3271 				dp->d_fileno = fileno;
3272 			    }
3273 			    *tl2++ = cookiep->nfsuquad[0] = cookie.lval[0] =
3274 				ncookie.lval[0];
3275 			    *tl2 = cookiep->nfsuquad[1] = cookie.lval[1] =
3276 				ncookie.lval[1];
3277 
3278 			    if (nfhp != NULL) {
3279 				if (NFSRV_CMPFH(nfhp->nfh_fh, nfhp->nfh_len,
3280 				    dnp->n_fhp->nfh_fh, dnp->n_fhp->nfh_len)) {
3281 				    VREF(vp);
3282 				    newvp = vp;
3283 				    unlocknewvp = 0;
3284 				    FREE((caddr_t)nfhp, M_NFSFH);
3285 				    np = dnp;
3286 				} else if (isdotdot != 0) {
3287 				    /*
3288 				     * Skip doing a nfscl_nget() call for "..".
3289 				     * There's a race between acquiring the nfs
3290 				     * node here and lookups that look for the
3291 				     * directory being read (in the parent).
3292 				     * It would try to get a lock on ".." here,
3293 				     * owning the lock on the directory being
3294 				     * read. Lookup will hold the lock on ".."
3295 				     * and try to acquire the lock on the
3296 				     * directory being read.
3297 				     * If the directory is unlocked/relocked,
3298 				     * then there is a LOR with the buflock
3299 				     * vp is relocked.
3300 				     */
3301 				    free(nfhp, M_NFSFH);
3302 				} else {
3303 				    error = nfscl_nget(vnode_mount(vp), vp,
3304 				      nfhp, cnp, p, &np, NULL, LK_EXCLUSIVE);
3305 				    if (!error) {
3306 					newvp = NFSTOV(np);
3307 					unlocknewvp = 1;
3308 				    }
3309 				}
3310 				nfhp = NULL;
3311 				if (newvp != NULLVP) {
3312 				    error = nfscl_loadattrcache(&newvp,
3313 					&nfsva, NULL, NULL, 0, 0);
3314 				    if (error) {
3315 					if (unlocknewvp)
3316 					    vput(newvp);
3317 					else
3318 					    vrele(newvp);
3319 					goto nfsmout;
3320 				    }
3321 				    dp->d_type =
3322 					vtonfs_dtype(np->n_vattr.na_type);
3323 				    ndp->ni_vp = newvp;
3324 				    NFSCNHASH(cnp, HASHINIT);
3325 				    if (cnp->cn_namelen <= NCHNAMLEN &&
3326 					(newvp->v_type != VDIR ||
3327 					 dctime.tv_sec != 0)) {
3328 					cache_enter_time(ndp->ni_dvp,
3329 					    ndp->ni_vp, cnp,
3330 					    &nfsva.na_ctime,
3331 					    newvp->v_type != VDIR ? NULL :
3332 					    &dctime);
3333 				    }
3334 				    if (unlocknewvp)
3335 					vput(newvp);
3336 				    else
3337 					vrele(newvp);
3338 				    newvp = NULLVP;
3339 				}
3340 			    }
3341 			} else if (nfhp != NULL) {
3342 			    FREE((caddr_t)nfhp, M_NFSFH);
3343 			}
3344 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3345 			more_dirs = fxdr_unsigned(int, *tl);
3346 		}
3347 		/*
3348 		 * If at end of rpc data, get the eof boolean
3349 		 */
3350 		if (!more_dirs) {
3351 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3352 			eof = fxdr_unsigned(int, *tl);
3353 			if (tryformoredirs)
3354 				more_dirs = !eof;
3355 			if (nd->nd_flag & ND_NFSV4) {
3356 				error = nfscl_postop_attr(nd, nap, attrflagp,
3357 				    stuff);
3358 				if (error)
3359 					goto nfsmout;
3360 			}
3361 		}
3362 		mbuf_freem(nd->nd_mrep);
3363 		nd->nd_mrep = NULL;
3364 	}
3365 	/*
3366 	 * Fill last record, iff any, out to a multiple of DIRBLKSIZ
3367 	 * by increasing d_reclen for the last record.
3368 	 */
3369 	if (blksiz > 0) {
3370 		left = DIRBLKSIZ - blksiz;
3371 		dp->d_reclen += left;
3372 		uio_iov_base_add(uiop, left);
3373 		uio_iov_len_add(uiop, -(left));
3374 		uio_uio_resid_add(uiop, -(left));
3375 		uiop->uio_offset += left;
3376 	}
3377 
3378 	/*
3379 	 * If returning no data, assume end of file.
3380 	 * If not bigenough, return not end of file, since you aren't
3381 	 *    returning all the data
3382 	 * Otherwise, return the eof flag from the server.
3383 	 */
3384 	if (eofp != NULL) {
3385 		if (tresid == uio_uio_resid(uiop))
3386 			*eofp = 1;
3387 		else if (!bigenough)
3388 			*eofp = 0;
3389 		else
3390 			*eofp = eof;
3391 	}
3392 
3393 	/*
3394 	 * Add extra empty records to any remaining DIRBLKSIZ chunks.
3395 	 */
3396 	while (uio_uio_resid(uiop) > 0 && uio_uio_resid(uiop) != tresid) {
3397 		dp = (struct dirent *)uio_iov_base(uiop);
3398 		dp->d_type = DT_UNKNOWN;
3399 		dp->d_fileno = 0;
3400 		dp->d_namlen = 0;
3401 		dp->d_name[0] = '\0';
3402 		tl = (u_int32_t *)&dp->d_name[4];
3403 		*tl++ = cookie.lval[0];
3404 		*tl = cookie.lval[1];
3405 		dp->d_reclen = DIRBLKSIZ;
3406 		uio_iov_base_add(uiop, DIRBLKSIZ);
3407 		uio_iov_len_add(uiop, -(DIRBLKSIZ));
3408 		uio_uio_resid_add(uiop, -(DIRBLKSIZ));
3409 		uiop->uio_offset += DIRBLKSIZ;
3410 	}
3411 
3412 nfsmout:
3413 	if (nd->nd_mrep != NULL)
3414 		mbuf_freem(nd->nd_mrep);
3415 	return (error);
3416 }
3417 #endif	/* !APPLE */
3418 
3419 /*
3420  * Nfs commit rpc
3421  */
3422 APPLESTATIC int
3423 nfsrpc_commit(vnode_t vp, u_quad_t offset, int cnt, struct ucred *cred,
3424     NFSPROC_T *p, u_char *verfp, struct nfsvattr *nap, int *attrflagp,
3425     void *stuff)
3426 {
3427 	u_int32_t *tl;
3428 	struct nfsrv_descript nfsd, *nd = &nfsd;
3429 	nfsattrbit_t attrbits;
3430 	int error;
3431 
3432 	*attrflagp = 0;
3433 	NFSCL_REQSTART(nd, NFSPROC_COMMIT, vp);
3434 	NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3435 	txdr_hyper(offset, tl);
3436 	tl += 2;
3437 	*tl = txdr_unsigned(cnt);
3438 	if (nd->nd_flag & ND_NFSV4) {
3439 		/*
3440 		 * And do a Getattr op.
3441 		 */
3442 		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3443 		*tl = txdr_unsigned(NFSV4OP_GETATTR);
3444 		NFSGETATTR_ATTRBIT(&attrbits);
3445 		(void) nfsrv_putattrbit(nd, &attrbits);
3446 	}
3447 	error = nfscl_request(nd, vp, p, cred, stuff);
3448 	if (error)
3449 		return (error);
3450 	error = nfscl_wcc_data(nd, vp, nap, attrflagp, NULL, stuff);
3451 	if (!error && !nd->nd_repstat) {
3452 		NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
3453 		NFSBCOPY((caddr_t)tl, verfp, NFSX_VERF);
3454 		if (nd->nd_flag & ND_NFSV4)
3455 			error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
3456 	}
3457 nfsmout:
3458 	if (!error && nd->nd_repstat)
3459 		error = nd->nd_repstat;
3460 	mbuf_freem(nd->nd_mrep);
3461 	return (error);
3462 }
3463 
3464 /*
3465  * NFS byte range lock rpc.
3466  * (Mostly just calls one of the three lower level RPC routines.)
3467  */
3468 APPLESTATIC int
3469 nfsrpc_advlock(vnode_t vp, off_t size, int op, struct flock *fl,
3470     int reclaim, struct ucred *cred, NFSPROC_T *p, void *id, int flags)
3471 {
3472 	struct nfscllockowner *lp;
3473 	struct nfsclclient *clp;
3474 	struct nfsfh *nfhp;
3475 	struct nfsrv_descript nfsd, *nd = &nfsd;
3476 	struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
3477 	u_int64_t off, len;
3478 	off_t start, end;
3479 	u_int32_t clidrev = 0;
3480 	int error = 0, newone = 0, expireret = 0, retrycnt, donelocally;
3481 	int callcnt, dorpc;
3482 
3483 	/*
3484 	 * Convert the flock structure into a start and end and do POSIX
3485 	 * bounds checking.
3486 	 */
3487 	switch (fl->l_whence) {
3488 	case SEEK_SET:
3489 	case SEEK_CUR:
3490 		/*
3491 		 * Caller is responsible for adding any necessary offset
3492 		 * when SEEK_CUR is used.
3493 		 */
3494 		start = fl->l_start;
3495 		off = fl->l_start;
3496 		break;
3497 	case SEEK_END:
3498 		start = size + fl->l_start;
3499 		off = size + fl->l_start;
3500 		break;
3501 	default:
3502 		return (EINVAL);
3503 	};
3504 	if (start < 0)
3505 		return (EINVAL);
3506 	if (fl->l_len != 0) {
3507 		end = start + fl->l_len - 1;
3508 		if (end < start)
3509 			return (EINVAL);
3510 	}
3511 
3512 	len = fl->l_len;
3513 	if (len == 0)
3514 		len = NFS64BITSSET;
3515 	retrycnt = 0;
3516 	do {
3517 	    nd->nd_repstat = 0;
3518 	    if (op == F_GETLK) {
3519 		error = nfscl_getcl(vp, cred, p, &clp);
3520 		if (error)
3521 			return (error);
3522 		error = nfscl_lockt(vp, clp, off, len, fl, p, id, flags);
3523 		if (!error) {
3524 			clidrev = clp->nfsc_clientidrev;
3525 			error = nfsrpc_lockt(nd, vp, clp, off, len, fl, cred,
3526 			    p, id, flags);
3527 		} else if (error == -1) {
3528 			error = 0;
3529 		}
3530 		nfscl_clientrelease(clp);
3531 	    } else if (op == F_UNLCK && fl->l_type == F_UNLCK) {
3532 		/*
3533 		 * We must loop around for all lockowner cases.
3534 		 */
3535 		callcnt = 0;
3536 		error = nfscl_getcl(vp, cred, p, &clp);
3537 		if (error)
3538 			return (error);
3539 		do {
3540 		    error = nfscl_relbytelock(vp, off, len, cred, p, callcnt,
3541 			clp, id, flags, &lp, &dorpc);
3542 		    /*
3543 		     * If it returns a NULL lp, we're done.
3544 		     */
3545 		    if (lp == NULL) {
3546 			if (callcnt == 0)
3547 			    nfscl_clientrelease(clp);
3548 			else
3549 			    nfscl_releasealllocks(clp, vp, p, id, flags);
3550 			return (error);
3551 		    }
3552 		    if (nmp->nm_clp != NULL)
3553 			clidrev = nmp->nm_clp->nfsc_clientidrev;
3554 		    else
3555 			clidrev = 0;
3556 		    /*
3557 		     * If the server doesn't support Posix lock semantics,
3558 		     * only allow locks on the entire file, since it won't
3559 		     * handle overlapping byte ranges.
3560 		     * There might still be a problem when a lock
3561 		     * upgrade/downgrade (read<->write) occurs, since the
3562 		     * server "might" expect an unlock first?
3563 		     */
3564 		    if (dorpc && (lp->nfsl_open->nfso_posixlock ||
3565 			(off == 0 && len == NFS64BITSSET))) {
3566 			/*
3567 			 * Since the lock records will go away, we must
3568 			 * wait for grace and delay here.
3569 			 */
3570 			do {
3571 			    error = nfsrpc_locku(nd, nmp, lp, off, len,
3572 				NFSV4LOCKT_READ, cred, p, 0);
3573 			    if ((nd->nd_repstat == NFSERR_GRACE ||
3574 				 nd->nd_repstat == NFSERR_DELAY) &&
3575 				error == 0)
3576 				(void) nfs_catnap(PZERO, (int)nd->nd_repstat,
3577 				    "nfs_advlock");
3578 			} while ((nd->nd_repstat == NFSERR_GRACE ||
3579 			    nd->nd_repstat == NFSERR_DELAY) && error == 0);
3580 		    }
3581 		    callcnt++;
3582 		} while (error == 0 && nd->nd_repstat == 0);
3583 		nfscl_releasealllocks(clp, vp, p, id, flags);
3584 	    } else if (op == F_SETLK) {
3585 		error = nfscl_getbytelock(vp, off, len, fl->l_type, cred, p,
3586 		    NULL, 0, id, flags, NULL, NULL, &lp, &newone, &donelocally);
3587 		if (error || donelocally) {
3588 			return (error);
3589 		}
3590 		if (nmp->nm_clp != NULL)
3591 			clidrev = nmp->nm_clp->nfsc_clientidrev;
3592 		else
3593 			clidrev = 0;
3594 		nfhp = VTONFS(vp)->n_fhp;
3595 		if (!lp->nfsl_open->nfso_posixlock &&
3596 		    (off != 0 || len != NFS64BITSSET)) {
3597 			error = EINVAL;
3598 		} else {
3599 			error = nfsrpc_lock(nd, nmp, vp, nfhp->nfh_fh,
3600 			    nfhp->nfh_len, lp, newone, reclaim, off,
3601 			    len, fl->l_type, cred, p, 0);
3602 		}
3603 		if (!error)
3604 			error = nd->nd_repstat;
3605 		nfscl_lockrelease(lp, error, newone);
3606 	    } else {
3607 		error = EINVAL;
3608 	    }
3609 	    if (!error)
3610 	        error = nd->nd_repstat;
3611 	    if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
3612 		error == NFSERR_STALEDONTRECOVER ||
3613 		error == NFSERR_STALECLIENTID || error == NFSERR_DELAY) {
3614 		(void) nfs_catnap(PZERO, error, "nfs_advlock");
3615 	    } else if ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID)
3616 		&& clidrev != 0) {
3617 		expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
3618 		retrycnt++;
3619 	    }
3620 	} while (error == NFSERR_GRACE ||
3621 	    error == NFSERR_STALECLIENTID || error == NFSERR_DELAY ||
3622 	    error == NFSERR_STALEDONTRECOVER || error == NFSERR_STALESTATEID ||
3623 	    ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
3624 	     expireret == 0 && clidrev != 0 && retrycnt < 4));
3625 	if (error && retrycnt >= 4)
3626 		error = EIO;
3627 	return (error);
3628 }
3629 
3630 /*
3631  * The lower level routine for the LockT case.
3632  */
3633 APPLESTATIC int
3634 nfsrpc_lockt(struct nfsrv_descript *nd, vnode_t vp,
3635     struct nfsclclient *clp, u_int64_t off, u_int64_t len, struct flock *fl,
3636     struct ucred *cred, NFSPROC_T *p, void *id, int flags)
3637 {
3638 	u_int32_t *tl;
3639 	int error, type, size;
3640 	uint8_t own[NFSV4CL_LOCKNAMELEN + NFSX_V4FHMAX];
3641 	struct nfsnode *np;
3642 
3643 	NFSCL_REQSTART(nd, NFSPROC_LOCKT, vp);
3644 	NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
3645 	if (fl->l_type == F_RDLCK)
3646 		*tl++ = txdr_unsigned(NFSV4LOCKT_READ);
3647 	else
3648 		*tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
3649 	txdr_hyper(off, tl);
3650 	tl += 2;
3651 	txdr_hyper(len, tl);
3652 	tl += 2;
3653 	*tl++ = clp->nfsc_clientid.lval[0];
3654 	*tl = clp->nfsc_clientid.lval[1];
3655 	nfscl_filllockowner(id, own, flags);
3656 	np = VTONFS(vp);
3657 	NFSBCOPY(np->n_fhp->nfh_fh, &own[NFSV4CL_LOCKNAMELEN],
3658 	    np->n_fhp->nfh_len);
3659 	(void)nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN + np->n_fhp->nfh_len);
3660 	error = nfscl_request(nd, vp, p, cred, NULL);
3661 	if (error)
3662 		return (error);
3663 	if (nd->nd_repstat == 0) {
3664 		fl->l_type = F_UNLCK;
3665 	} else if (nd->nd_repstat == NFSERR_DENIED) {
3666 		nd->nd_repstat = 0;
3667 		fl->l_whence = SEEK_SET;
3668 		NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
3669 		fl->l_start = fxdr_hyper(tl);
3670 		tl += 2;
3671 		len = fxdr_hyper(tl);
3672 		tl += 2;
3673 		if (len == NFS64BITSSET)
3674 			fl->l_len = 0;
3675 		else
3676 			fl->l_len = len;
3677 		type = fxdr_unsigned(int, *tl++);
3678 		if (type == NFSV4LOCKT_WRITE)
3679 			fl->l_type = F_WRLCK;
3680 		else
3681 			fl->l_type = F_RDLCK;
3682 		/*
3683 		 * XXX For now, I have no idea what to do with the
3684 		 * conflicting lock_owner, so I'll just set the pid == 0
3685 		 * and skip over the lock_owner.
3686 		 */
3687 		fl->l_pid = (pid_t)0;
3688 		tl += 2;
3689 		size = fxdr_unsigned(int, *tl);
3690 		if (size < 0 || size > NFSV4_OPAQUELIMIT)
3691 			error = EBADRPC;
3692 		if (!error)
3693 			error = nfsm_advance(nd, NFSM_RNDUP(size), -1);
3694 	} else if (nd->nd_repstat == NFSERR_STALECLIENTID)
3695 		nfscl_initiate_recovery(clp);
3696 nfsmout:
3697 	mbuf_freem(nd->nd_mrep);
3698 	return (error);
3699 }
3700 
3701 /*
3702  * Lower level function that performs the LockU RPC.
3703  */
3704 static int
3705 nfsrpc_locku(struct nfsrv_descript *nd, struct nfsmount *nmp,
3706     struct nfscllockowner *lp, u_int64_t off, u_int64_t len,
3707     u_int32_t type, struct ucred *cred, NFSPROC_T *p, int syscred)
3708 {
3709 	u_int32_t *tl;
3710 	int error;
3711 
3712 	nfscl_reqstart(nd, NFSPROC_LOCKU, nmp, lp->nfsl_open->nfso_fh,
3713 	    lp->nfsl_open->nfso_fhlen, NULL);
3714 	NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED);
3715 	*tl++ = txdr_unsigned(type);
3716 	*tl = txdr_unsigned(lp->nfsl_seqid);
3717 	if (nfstest_outofseq &&
3718 	    (arc4random() % nfstest_outofseq) == 0)
3719 		*tl = txdr_unsigned(lp->nfsl_seqid + 1);
3720 	tl++;
3721 	*tl++ = lp->nfsl_stateid.seqid;
3722 	*tl++ = lp->nfsl_stateid.other[0];
3723 	*tl++ = lp->nfsl_stateid.other[1];
3724 	*tl++ = lp->nfsl_stateid.other[2];
3725 	txdr_hyper(off, tl);
3726 	tl += 2;
3727 	txdr_hyper(len, tl);
3728 	if (syscred)
3729 		nd->nd_flag |= ND_USEGSSNAME;
3730 	error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
3731 	    NFS_PROG, NFS_VER4, NULL, 1, NULL);
3732 	NFSCL_INCRSEQID(lp->nfsl_seqid, nd);
3733 	if (error)
3734 		return (error);
3735 	if (nd->nd_repstat == 0) {
3736 		NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
3737 		lp->nfsl_stateid.seqid = *tl++;
3738 		lp->nfsl_stateid.other[0] = *tl++;
3739 		lp->nfsl_stateid.other[1] = *tl++;
3740 		lp->nfsl_stateid.other[2] = *tl;
3741 	} else if (nd->nd_repstat == NFSERR_STALESTATEID)
3742 		nfscl_initiate_recovery(lp->nfsl_open->nfso_own->nfsow_clp);
3743 nfsmout:
3744 	mbuf_freem(nd->nd_mrep);
3745 	return (error);
3746 }
3747 
3748 /*
3749  * The actual Lock RPC.
3750  */
3751 APPLESTATIC int
3752 nfsrpc_lock(struct nfsrv_descript *nd, struct nfsmount *nmp, vnode_t vp,
3753     u_int8_t *nfhp, int fhlen, struct nfscllockowner *lp, int newone,
3754     int reclaim, u_int64_t off, u_int64_t len, short type, struct ucred *cred,
3755     NFSPROC_T *p, int syscred)
3756 {
3757 	u_int32_t *tl;
3758 	int error, size;
3759 	uint8_t own[NFSV4CL_LOCKNAMELEN + NFSX_V4FHMAX];
3760 
3761 	nfscl_reqstart(nd, NFSPROC_LOCK, nmp, nfhp, fhlen, NULL);
3762 	NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
3763 	if (type == F_RDLCK)
3764 		*tl++ = txdr_unsigned(NFSV4LOCKT_READ);
3765 	else
3766 		*tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
3767 	*tl++ = txdr_unsigned(reclaim);
3768 	txdr_hyper(off, tl);
3769 	tl += 2;
3770 	txdr_hyper(len, tl);
3771 	tl += 2;
3772 	if (newone) {
3773 	    *tl = newnfs_true;
3774 	    NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID +
3775 		2 * NFSX_UNSIGNED + NFSX_HYPER);
3776 	    *tl++ = txdr_unsigned(lp->nfsl_open->nfso_own->nfsow_seqid);
3777 	    *tl++ = lp->nfsl_open->nfso_stateid.seqid;
3778 	    *tl++ = lp->nfsl_open->nfso_stateid.other[0];
3779 	    *tl++ = lp->nfsl_open->nfso_stateid.other[1];
3780 	    *tl++ = lp->nfsl_open->nfso_stateid.other[2];
3781 	    *tl++ = txdr_unsigned(lp->nfsl_seqid);
3782 	    *tl++ = lp->nfsl_open->nfso_own->nfsow_clp->nfsc_clientid.lval[0];
3783 	    *tl = lp->nfsl_open->nfso_own->nfsow_clp->nfsc_clientid.lval[1];
3784 	    NFSBCOPY(lp->nfsl_owner, own, NFSV4CL_LOCKNAMELEN);
3785 	    NFSBCOPY(nfhp, &own[NFSV4CL_LOCKNAMELEN], fhlen);
3786 	    (void)nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN + fhlen);
3787 	} else {
3788 	    *tl = newnfs_false;
3789 	    NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
3790 	    *tl++ = lp->nfsl_stateid.seqid;
3791 	    *tl++ = lp->nfsl_stateid.other[0];
3792 	    *tl++ = lp->nfsl_stateid.other[1];
3793 	    *tl++ = lp->nfsl_stateid.other[2];
3794 	    *tl = txdr_unsigned(lp->nfsl_seqid);
3795 	    if (nfstest_outofseq &&
3796 		(arc4random() % nfstest_outofseq) == 0)
3797 		    *tl = txdr_unsigned(lp->nfsl_seqid + 1);
3798 	}
3799 	if (syscred)
3800 		nd->nd_flag |= ND_USEGSSNAME;
3801 	error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, vp, p, cred,
3802 	    NFS_PROG, NFS_VER4, NULL, 1, NULL);
3803 	if (error)
3804 		return (error);
3805 	if (newone)
3806 	    NFSCL_INCRSEQID(lp->nfsl_open->nfso_own->nfsow_seqid, nd);
3807 	NFSCL_INCRSEQID(lp->nfsl_seqid, nd);
3808 	if (nd->nd_repstat == 0) {
3809 		NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
3810 		lp->nfsl_stateid.seqid = *tl++;
3811 		lp->nfsl_stateid.other[0] = *tl++;
3812 		lp->nfsl_stateid.other[1] = *tl++;
3813 		lp->nfsl_stateid.other[2] = *tl;
3814 	} else if (nd->nd_repstat == NFSERR_DENIED) {
3815 		NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
3816 		size = fxdr_unsigned(int, *(tl + 7));
3817 		if (size < 0 || size > NFSV4_OPAQUELIMIT)
3818 			error = EBADRPC;
3819 		if (!error)
3820 			error = nfsm_advance(nd, NFSM_RNDUP(size), -1);
3821 	} else if (nd->nd_repstat == NFSERR_STALESTATEID)
3822 		nfscl_initiate_recovery(lp->nfsl_open->nfso_own->nfsow_clp);
3823 nfsmout:
3824 	mbuf_freem(nd->nd_mrep);
3825 	return (error);
3826 }
3827 
3828 /*
3829  * nfs statfs rpc
3830  * (always called with the vp for the mount point)
3831  */
3832 APPLESTATIC int
3833 nfsrpc_statfs(vnode_t vp, struct nfsstatfs *sbp, struct nfsfsinfo *fsp,
3834     struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp,
3835     void *stuff)
3836 {
3837 	u_int32_t *tl = NULL;
3838 	struct nfsrv_descript nfsd, *nd = &nfsd;
3839 	struct nfsmount *nmp;
3840 	nfsattrbit_t attrbits;
3841 	int error;
3842 
3843 	*attrflagp = 0;
3844 	nmp = VFSTONFS(vnode_mount(vp));
3845 	if (NFSHASNFSV4(nmp)) {
3846 		/*
3847 		 * For V4, you actually do a getattr.
3848 		 */
3849 		NFSCL_REQSTART(nd, NFSPROC_GETATTR, vp);
3850 		NFSSTATFS_GETATTRBIT(&attrbits);
3851 		(void) nfsrv_putattrbit(nd, &attrbits);
3852 		nd->nd_flag |= ND_USEGSSNAME;
3853 		error = nfscl_request(nd, vp, p, cred, stuff);
3854 		if (error)
3855 			return (error);
3856 		if (nd->nd_repstat == 0) {
3857 			error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0,
3858 			    NULL, NULL, sbp, fsp, NULL, 0, NULL, NULL, NULL, p,
3859 			    cred);
3860 			if (!error) {
3861 				nmp->nm_fsid[0] = nap->na_filesid[0];
3862 				nmp->nm_fsid[1] = nap->na_filesid[1];
3863 				NFSSETHASSETFSID(nmp);
3864 				*attrflagp = 1;
3865 			}
3866 		} else {
3867 			error = nd->nd_repstat;
3868 		}
3869 		if (error)
3870 			goto nfsmout;
3871 	} else {
3872 		NFSCL_REQSTART(nd, NFSPROC_FSSTAT, vp);
3873 		error = nfscl_request(nd, vp, p, cred, stuff);
3874 		if (error)
3875 			return (error);
3876 		if (nd->nd_flag & ND_NFSV3) {
3877 			error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
3878 			if (error)
3879 				goto nfsmout;
3880 		}
3881 		if (nd->nd_repstat) {
3882 			error = nd->nd_repstat;
3883 			goto nfsmout;
3884 		}
3885 		NFSM_DISSECT(tl, u_int32_t *,
3886 		    NFSX_STATFS(nd->nd_flag & ND_NFSV3));
3887 	}
3888 	if (NFSHASNFSV3(nmp)) {
3889 		sbp->sf_tbytes = fxdr_hyper(tl); tl += 2;
3890 		sbp->sf_fbytes = fxdr_hyper(tl); tl += 2;
3891 		sbp->sf_abytes = fxdr_hyper(tl); tl += 2;
3892 		sbp->sf_tfiles = fxdr_hyper(tl); tl += 2;
3893 		sbp->sf_ffiles = fxdr_hyper(tl); tl += 2;
3894 		sbp->sf_afiles = fxdr_hyper(tl); tl += 2;
3895 		sbp->sf_invarsec = fxdr_unsigned(u_int32_t, *tl);
3896 	} else if (NFSHASNFSV4(nmp) == 0) {
3897 		sbp->sf_tsize = fxdr_unsigned(u_int32_t, *tl++);
3898 		sbp->sf_bsize = fxdr_unsigned(u_int32_t, *tl++);
3899 		sbp->sf_blocks = fxdr_unsigned(u_int32_t, *tl++);
3900 		sbp->sf_bfree = fxdr_unsigned(u_int32_t, *tl++);
3901 		sbp->sf_bavail = fxdr_unsigned(u_int32_t, *tl);
3902 	}
3903 nfsmout:
3904 	mbuf_freem(nd->nd_mrep);
3905 	return (error);
3906 }
3907 
3908 /*
3909  * nfs pathconf rpc
3910  */
3911 APPLESTATIC int
3912 nfsrpc_pathconf(vnode_t vp, struct nfsv3_pathconf *pc,
3913     struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp,
3914     void *stuff)
3915 {
3916 	struct nfsrv_descript nfsd, *nd = &nfsd;
3917 	struct nfsmount *nmp;
3918 	u_int32_t *tl;
3919 	nfsattrbit_t attrbits;
3920 	int error;
3921 
3922 	*attrflagp = 0;
3923 	nmp = VFSTONFS(vnode_mount(vp));
3924 	if (NFSHASNFSV4(nmp)) {
3925 		/*
3926 		 * For V4, you actually do a getattr.
3927 		 */
3928 		NFSCL_REQSTART(nd, NFSPROC_GETATTR, vp);
3929 		NFSPATHCONF_GETATTRBIT(&attrbits);
3930 		(void) nfsrv_putattrbit(nd, &attrbits);
3931 		nd->nd_flag |= ND_USEGSSNAME;
3932 		error = nfscl_request(nd, vp, p, cred, stuff);
3933 		if (error)
3934 			return (error);
3935 		if (nd->nd_repstat == 0) {
3936 			error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0,
3937 			    pc, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, p,
3938 			    cred);
3939 			if (!error)
3940 				*attrflagp = 1;
3941 		} else {
3942 			error = nd->nd_repstat;
3943 		}
3944 	} else {
3945 		NFSCL_REQSTART(nd, NFSPROC_PATHCONF, vp);
3946 		error = nfscl_request(nd, vp, p, cred, stuff);
3947 		if (error)
3948 			return (error);
3949 		error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
3950 		if (nd->nd_repstat && !error)
3951 			error = nd->nd_repstat;
3952 		if (!error) {
3953 			NFSM_DISSECT(tl, u_int32_t *, NFSX_V3PATHCONF);
3954 			pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl++);
3955 			pc->pc_namemax = fxdr_unsigned(u_int32_t, *tl++);
3956 			pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl++);
3957 			pc->pc_chownrestricted =
3958 			    fxdr_unsigned(u_int32_t, *tl++);
3959 			pc->pc_caseinsensitive =
3960 			    fxdr_unsigned(u_int32_t, *tl++);
3961 			pc->pc_casepreserving = fxdr_unsigned(u_int32_t, *tl);
3962 		}
3963 	}
3964 nfsmout:
3965 	mbuf_freem(nd->nd_mrep);
3966 	return (error);
3967 }
3968 
3969 /*
3970  * nfs version 3 fsinfo rpc call
3971  */
3972 APPLESTATIC int
3973 nfsrpc_fsinfo(vnode_t vp, struct nfsfsinfo *fsp, struct ucred *cred,
3974     NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff)
3975 {
3976 	u_int32_t *tl;
3977 	struct nfsrv_descript nfsd, *nd = &nfsd;
3978 	int error;
3979 
3980 	*attrflagp = 0;
3981 	NFSCL_REQSTART(nd, NFSPROC_FSINFO, vp);
3982 	error = nfscl_request(nd, vp, p, cred, stuff);
3983 	if (error)
3984 		return (error);
3985 	error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
3986 	if (nd->nd_repstat && !error)
3987 		error = nd->nd_repstat;
3988 	if (!error) {
3989 		NFSM_DISSECT(tl, u_int32_t *, NFSX_V3FSINFO);
3990 		fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *tl++);
3991 		fsp->fs_rtpref = fxdr_unsigned(u_int32_t, *tl++);
3992 		fsp->fs_rtmult = fxdr_unsigned(u_int32_t, *tl++);
3993 		fsp->fs_wtmax = fxdr_unsigned(u_int32_t, *tl++);
3994 		fsp->fs_wtpref = fxdr_unsigned(u_int32_t, *tl++);
3995 		fsp->fs_wtmult = fxdr_unsigned(u_int32_t, *tl++);
3996 		fsp->fs_dtpref = fxdr_unsigned(u_int32_t, *tl++);
3997 		fsp->fs_maxfilesize = fxdr_hyper(tl);
3998 		tl += 2;
3999 		fxdr_nfsv3time(tl, &fsp->fs_timedelta);
4000 		tl += 2;
4001 		fsp->fs_properties = fxdr_unsigned(u_int32_t, *tl);
4002 	}
4003 nfsmout:
4004 	mbuf_freem(nd->nd_mrep);
4005 	return (error);
4006 }
4007 
4008 /*
4009  * This function performs the Renew RPC.
4010  */
4011 APPLESTATIC int
4012 nfsrpc_renew(struct nfsclclient *clp, struct ucred *cred, NFSPROC_T *p)
4013 {
4014 	u_int32_t *tl;
4015 	struct nfsrv_descript nfsd;
4016 	struct nfsrv_descript *nd = &nfsd;
4017 	struct nfsmount *nmp;
4018 	int error;
4019 
4020 	nmp = clp->nfsc_nmp;
4021 	if (nmp == NULL)
4022 		return (0);
4023 	nfscl_reqstart(nd, NFSPROC_RENEW, nmp, NULL, 0, NULL);
4024 	NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
4025 	*tl++ = clp->nfsc_clientid.lval[0];
4026 	*tl = clp->nfsc_clientid.lval[1];
4027 	nd->nd_flag |= ND_USEGSSNAME;
4028 	error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
4029 		NFS_PROG, NFS_VER4, NULL, 1, NULL);
4030 	if (error)
4031 		return (error);
4032 	error = nd->nd_repstat;
4033 	mbuf_freem(nd->nd_mrep);
4034 	return (error);
4035 }
4036 
4037 /*
4038  * This function performs the Releaselockowner RPC.
4039  */
4040 APPLESTATIC int
4041 nfsrpc_rellockown(struct nfsmount *nmp, struct nfscllockowner *lp,
4042     uint8_t *fh, int fhlen, struct ucred *cred, NFSPROC_T *p)
4043 {
4044 	struct nfsrv_descript nfsd, *nd = &nfsd;
4045 	u_int32_t *tl;
4046 	int error;
4047 	uint8_t own[NFSV4CL_LOCKNAMELEN + NFSX_V4FHMAX];
4048 
4049 	nfscl_reqstart(nd, NFSPROC_RELEASELCKOWN, nmp, NULL, 0, NULL);
4050 	NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
4051 	*tl++ = nmp->nm_clp->nfsc_clientid.lval[0];
4052 	*tl = nmp->nm_clp->nfsc_clientid.lval[1];
4053 	NFSBCOPY(lp->nfsl_owner, own, NFSV4CL_LOCKNAMELEN);
4054 	NFSBCOPY(fh, &own[NFSV4CL_LOCKNAMELEN], fhlen);
4055 	(void)nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN + fhlen);
4056 	nd->nd_flag |= ND_USEGSSNAME;
4057 	error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
4058 	    NFS_PROG, NFS_VER4, NULL, 1, NULL);
4059 	if (error)
4060 		return (error);
4061 	error = nd->nd_repstat;
4062 	mbuf_freem(nd->nd_mrep);
4063 	return (error);
4064 }
4065 
4066 /*
4067  * This function performs the Compound to get the mount pt FH.
4068  */
4069 APPLESTATIC int
4070 nfsrpc_getdirpath(struct nfsmount *nmp, u_char *dirpath, struct ucred *cred,
4071     NFSPROC_T *p)
4072 {
4073 	u_int32_t *tl;
4074 	struct nfsrv_descript nfsd;
4075 	struct nfsrv_descript *nd = &nfsd;
4076 	u_char *cp, *cp2;
4077 	int error, cnt, len, setnil;
4078 	u_int32_t *opcntp;
4079 
4080 	nfscl_reqstart(nd, NFSPROC_PUTROOTFH, nmp, NULL, 0, &opcntp);
4081 	cp = dirpath;
4082 	cnt = 0;
4083 	do {
4084 		setnil = 0;
4085 		while (*cp == '/')
4086 			cp++;
4087 		cp2 = cp;
4088 		while (*cp2 != '\0' && *cp2 != '/')
4089 			cp2++;
4090 		if (*cp2 == '/') {
4091 			setnil = 1;
4092 			*cp2 = '\0';
4093 		}
4094 		if (cp2 != cp) {
4095 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
4096 			*tl = txdr_unsigned(NFSV4OP_LOOKUP);
4097 			nfsm_strtom(nd, cp, strlen(cp));
4098 			cnt++;
4099 		}
4100 		if (setnil)
4101 			*cp2++ = '/';
4102 		cp = cp2;
4103 	} while (*cp != '\0');
4104 	*opcntp = txdr_unsigned(2 + cnt);
4105 	NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
4106 	*tl = txdr_unsigned(NFSV4OP_GETFH);
4107 	nd->nd_flag |= ND_USEGSSNAME;
4108 	error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
4109 		NFS_PROG, NFS_VER4, NULL, 1, NULL);
4110 	if (error)
4111 		return (error);
4112 	if (nd->nd_repstat == 0) {
4113 		NFSM_DISSECT(tl, u_int32_t *, (3 + 2 * cnt) * NFSX_UNSIGNED);
4114 		tl += (2 + 2 * cnt);
4115 		if ((len = fxdr_unsigned(int, *tl)) <= 0 ||
4116 			len > NFSX_FHMAX) {
4117 			nd->nd_repstat = NFSERR_BADXDR;
4118 		} else {
4119 			nd->nd_repstat = nfsrv_mtostr(nd, nmp->nm_fh, len);
4120 			if (nd->nd_repstat == 0)
4121 				nmp->nm_fhsize = len;
4122 		}
4123 	}
4124 	error = nd->nd_repstat;
4125 nfsmout:
4126 	mbuf_freem(nd->nd_mrep);
4127 	return (error);
4128 }
4129 
4130 /*
4131  * This function performs the Delegreturn RPC.
4132  */
4133 APPLESTATIC int
4134 nfsrpc_delegreturn(struct nfscldeleg *dp, struct ucred *cred,
4135     struct nfsmount *nmp, NFSPROC_T *p, int syscred)
4136 {
4137 	u_int32_t *tl;
4138 	struct nfsrv_descript nfsd;
4139 	struct nfsrv_descript *nd = &nfsd;
4140 	int error;
4141 
4142 	nfscl_reqstart(nd, NFSPROC_DELEGRETURN, nmp, dp->nfsdl_fh,
4143 	    dp->nfsdl_fhlen, NULL);
4144 	NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
4145 	*tl++ = dp->nfsdl_stateid.seqid;
4146 	*tl++ = dp->nfsdl_stateid.other[0];
4147 	*tl++ = dp->nfsdl_stateid.other[1];
4148 	*tl = dp->nfsdl_stateid.other[2];
4149 	if (syscred)
4150 		nd->nd_flag |= ND_USEGSSNAME;
4151 	error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
4152 	    NFS_PROG, NFS_VER4, NULL, 1, NULL);
4153 	if (error)
4154 		return (error);
4155 	error = nd->nd_repstat;
4156 	mbuf_freem(nd->nd_mrep);
4157 	return (error);
4158 }
4159 
4160 /*
4161  * nfs getacl call.
4162  */
4163 APPLESTATIC int
4164 nfsrpc_getacl(vnode_t vp, struct ucred *cred, NFSPROC_T *p,
4165     struct acl *aclp, void *stuff)
4166 {
4167 	struct nfsrv_descript nfsd, *nd = &nfsd;
4168 	int error;
4169 	nfsattrbit_t attrbits;
4170 	struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
4171 
4172 	if (nfsrv_useacl == 0 || !NFSHASNFSV4(nmp))
4173 		return (EOPNOTSUPP);
4174 	NFSCL_REQSTART(nd, NFSPROC_GETACL, vp);
4175 	NFSZERO_ATTRBIT(&attrbits);
4176 	NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_ACL);
4177 	(void) nfsrv_putattrbit(nd, &attrbits);
4178 	error = nfscl_request(nd, vp, p, cred, stuff);
4179 	if (error)
4180 		return (error);
4181 	if (!nd->nd_repstat)
4182 		error = nfsv4_loadattr(nd, vp, NULL, NULL, NULL, 0, NULL,
4183 		    NULL, NULL, NULL, aclp, 0, NULL, NULL, NULL, p, cred);
4184 	else
4185 		error = nd->nd_repstat;
4186 	mbuf_freem(nd->nd_mrep);
4187 	return (error);
4188 }
4189 
4190 /*
4191  * nfs setacl call.
4192  */
4193 APPLESTATIC int
4194 nfsrpc_setacl(vnode_t vp, struct ucred *cred, NFSPROC_T *p,
4195     struct acl *aclp, void *stuff)
4196 {
4197 	int error;
4198 	struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
4199 
4200 	if (nfsrv_useacl == 0 || !NFSHASNFSV4(nmp))
4201 		return (EOPNOTSUPP);
4202 	error = nfsrpc_setattr(vp, NULL, aclp, cred, p, NULL, NULL, stuff);
4203 	return (error);
4204 }
4205 
4206 /*
4207  * nfs setacl call.
4208  */
4209 static int
4210 nfsrpc_setaclrpc(vnode_t vp, struct ucred *cred, NFSPROC_T *p,
4211     struct acl *aclp, nfsv4stateid_t *stateidp, void *stuff)
4212 {
4213 	struct nfsrv_descript nfsd, *nd = &nfsd;
4214 	int error;
4215 	nfsattrbit_t attrbits;
4216 	struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
4217 
4218 	if (!NFSHASNFSV4(nmp))
4219 		return (EOPNOTSUPP);
4220 	NFSCL_REQSTART(nd, NFSPROC_SETACL, vp);
4221 	nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID);
4222 	NFSZERO_ATTRBIT(&attrbits);
4223 	NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_ACL);
4224 	(void) nfsv4_fillattr(nd, vnode_mount(vp), vp, aclp, NULL, NULL, 0,
4225 	    &attrbits, NULL, NULL, 0, 0, 0, 0, (uint64_t)0);
4226 	error = nfscl_request(nd, vp, p, cred, stuff);
4227 	if (error)
4228 		return (error);
4229 	/* Don't care about the pre/postop attributes */
4230 	mbuf_freem(nd->nd_mrep);
4231 	return (nd->nd_repstat);
4232 }
4233