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