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