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