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