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