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