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