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