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