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