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