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