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