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