]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/fs/nfsclient/nfs_clrpcops.c
Merge OpenSSL 1.0.2e.
[FreeBSD/FreeBSD.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 #include <sys/sysctl.h>
50
51 SYSCTL_DECL(_vfs_nfs);
52
53 static int      nfsignore_eexist = 0;
54 SYSCTL_INT(_vfs_nfs, OID_AUTO, ignore_eexist, CTLFLAG_RW,
55     &nfsignore_eexist, 0, "NFS ignore EEXIST replies for mkdir/symlink");
56
57 /*
58  * Global variables
59  */
60 extern int nfs_numnfscbd;
61 extern struct timeval nfsboottime;
62 extern u_int32_t newnfs_false, newnfs_true;
63 extern nfstype nfsv34_type[9];
64 extern int nfsrv_useacl;
65 extern char nfsv4_callbackaddr[INET6_ADDRSTRLEN];
66 extern int nfscl_debuglevel;
67 NFSCLSTATEMUTEX;
68 int nfstest_outofseq = 0;
69 int nfscl_assumeposixlocks = 1;
70 int nfscl_enablecallb = 0;
71 short nfsv4_cbport = NFSV4_CBPORT;
72 int nfstest_openallsetattr = 0;
73 #endif  /* !APPLEKEXT */
74
75 #define DIRHDSIZ        (sizeof (struct dirent) - (MAXNAMLEN + 1))
76
77 /*
78  * nfscl_getsameserver() can return one of three values:
79  * NFSDSP_USETHISSESSION - Use this session for the DS.
80  * NFSDSP_SEQTHISSESSION - Use the nfsclds_sequence field of this dsp for new
81  *     session.
82  * NFSDSP_NOTFOUND - No matching server was found.
83  */
84 enum nfsclds_state {
85         NFSDSP_USETHISSESSION = 0,
86         NFSDSP_SEQTHISSESSION = 1,
87         NFSDSP_NOTFOUND = 2,
88 };
89
90 static int nfsrpc_setattrrpc(vnode_t , struct vattr *, nfsv4stateid_t *,
91     struct ucred *, NFSPROC_T *, struct nfsvattr *, int *, void *);
92 static int nfsrpc_readrpc(vnode_t , struct uio *, struct ucred *,
93     nfsv4stateid_t *, NFSPROC_T *, struct nfsvattr *, int *, void *);
94 static int nfsrpc_writerpc(vnode_t , struct uio *, int *, int *,
95     struct ucred *, nfsv4stateid_t *, NFSPROC_T *, struct nfsvattr *, int *,
96     void *);
97 static int nfsrpc_createv23(vnode_t , char *, int, struct vattr *,
98     nfsquad_t, int, struct ucred *, NFSPROC_T *, struct nfsvattr *,
99     struct nfsvattr *, struct nfsfh **, int *, int *, void *);
100 static int nfsrpc_createv4(vnode_t , char *, int, struct vattr *,
101     nfsquad_t, int, struct nfsclowner *, struct nfscldeleg **, struct ucred *,
102     NFSPROC_T *, struct nfsvattr *, struct nfsvattr *, struct nfsfh **, int *,
103     int *, void *, int *);
104 static int nfsrpc_locku(struct nfsrv_descript *, struct nfsmount *,
105     struct nfscllockowner *, u_int64_t, u_int64_t,
106     u_int32_t, struct ucred *, NFSPROC_T *, int);
107 static int nfsrpc_setaclrpc(vnode_t, struct ucred *, NFSPROC_T *,
108     struct acl *, nfsv4stateid_t *, void *);
109 static int nfsrpc_getlayout(struct nfsmount *, vnode_t, struct nfsfh *, int,
110     uint32_t *, nfsv4stateid_t *, uint64_t, struct nfscllayout **,
111     struct ucred *, NFSPROC_T *);
112 static int nfsrpc_fillsa(struct nfsmount *, struct sockaddr_storage *,
113     struct nfsclds **, NFSPROC_T *);
114 static void nfscl_initsessionslots(struct nfsclsession *);
115 static int nfscl_doflayoutio(vnode_t, struct uio *, int *, int *, int *,
116     nfsv4stateid_t *, int, struct nfscldevinfo *, struct nfscllayout *,
117     struct nfsclflayout *, uint64_t, uint64_t, struct ucred *, NFSPROC_T *);
118 static int nfsrpc_readds(vnode_t, struct uio *, nfsv4stateid_t *, int *,
119     struct nfsclds *, uint64_t, int, struct nfsfh *, struct ucred *,
120     NFSPROC_T *);
121 static int nfsrpc_writeds(vnode_t, struct uio *, int *, int *,
122     nfsv4stateid_t *, struct nfsclds *, uint64_t, int,
123     struct nfsfh *, int, struct ucred *, NFSPROC_T *);
124 static enum nfsclds_state nfscl_getsameserver(struct nfsmount *,
125     struct nfsclds *, struct nfsclds **);
126 #ifdef notyet
127 static int nfsrpc_commitds(vnode_t, uint64_t, int, struct nfsclds *,
128     struct nfsfh *, struct ucred *, NFSPROC_T *, void *);
129 #endif
130
131 /*
132  * nfs null call from vfs.
133  */
134 APPLESTATIC int
135 nfsrpc_null(vnode_t vp, struct ucred *cred, NFSPROC_T *p)
136 {
137         int error;
138         struct nfsrv_descript nfsd, *nd = &nfsd;
139         
140         NFSCL_REQSTART(nd, NFSPROC_NULL, vp);
141         error = nfscl_request(nd, vp, p, cred, NULL);
142         if (nd->nd_repstat && !error)
143                 error = nd->nd_repstat;
144         mbuf_freem(nd->nd_mrep);
145         return (error);
146 }
147
148 /*
149  * nfs access rpc op.
150  * For nfs version 3 and 4, use the access rpc to check accessibility. If file
151  * modes are changed on the server, accesses might still fail later.
152  */
153 APPLESTATIC int
154 nfsrpc_access(vnode_t vp, int acmode, struct ucred *cred,
155     NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp)
156 {
157         int error;
158         u_int32_t mode, rmode;
159
160         if (acmode & VREAD)
161                 mode = NFSACCESS_READ;
162         else
163                 mode = 0;
164         if (vnode_vtype(vp) == VDIR) {
165                 if (acmode & VWRITE)
166                         mode |= (NFSACCESS_MODIFY | NFSACCESS_EXTEND |
167                                  NFSACCESS_DELETE);
168                 if (acmode & VEXEC)
169                         mode |= NFSACCESS_LOOKUP;
170         } else {
171                 if (acmode & VWRITE)
172                         mode |= (NFSACCESS_MODIFY | NFSACCESS_EXTEND);
173                 if (acmode & VEXEC)
174                         mode |= NFSACCESS_EXECUTE;
175         }
176
177         /*
178          * Now, just call nfsrpc_accessrpc() to do the actual RPC.
179          */
180         error = nfsrpc_accessrpc(vp, mode, cred, p, nap, attrflagp, &rmode,
181             NULL);
182
183         /*
184          * The NFS V3 spec does not clarify whether or not
185          * the returned access bits can be a superset of
186          * the ones requested, so...
187          */
188         if (!error && (rmode & mode) != mode)
189                 error = EACCES;
190         return (error);
191 }
192
193 /*
194  * The actual rpc, separated out for Darwin.
195  */
196 APPLESTATIC int
197 nfsrpc_accessrpc(vnode_t vp, u_int32_t mode, struct ucred *cred,
198     NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, u_int32_t *rmodep,
199     void *stuff)
200 {
201         u_int32_t *tl;
202         u_int32_t supported, rmode;
203         int error;
204         struct nfsrv_descript nfsd, *nd = &nfsd;
205         nfsattrbit_t attrbits;
206
207         *attrflagp = 0;
208         supported = mode;
209         NFSCL_REQSTART(nd, NFSPROC_ACCESS, vp);
210         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
211         *tl = txdr_unsigned(mode);
212         if (nd->nd_flag & ND_NFSV4) {
213                 /*
214                  * And do a Getattr op.
215                  */
216                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
217                 *tl = txdr_unsigned(NFSV4OP_GETATTR);
218                 NFSGETATTR_ATTRBIT(&attrbits);
219                 (void) nfsrv_putattrbit(nd, &attrbits);
220         }
221         error = nfscl_request(nd, vp, p, cred, stuff);
222         if (error)
223                 return (error);
224         if (nd->nd_flag & ND_NFSV3) {
225                 error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
226                 if (error)
227                         goto nfsmout;
228         }
229         if (!nd->nd_repstat) {
230                 if (nd->nd_flag & ND_NFSV4) {
231                         NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
232                         supported = fxdr_unsigned(u_int32_t, *tl++);
233                 } else {
234                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
235                 }
236                 rmode = fxdr_unsigned(u_int32_t, *tl);
237                 if (nd->nd_flag & ND_NFSV4)
238                         error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
239
240                 /*
241                  * It's not obvious what should be done about
242                  * unsupported access modes. For now, be paranoid
243                  * and clear the unsupported ones.
244                  */
245                 rmode &= supported;
246                 *rmodep = rmode;
247         } else
248                 error = nd->nd_repstat;
249 nfsmout:
250         mbuf_freem(nd->nd_mrep);
251         return (error);
252 }
253
254 /*
255  * nfs open rpc
256  */
257 APPLESTATIC int
258 nfsrpc_open(vnode_t vp, int amode, struct ucred *cred, NFSPROC_T *p)
259 {
260         struct nfsclopen *op;
261         struct nfscldeleg *dp;
262         struct nfsfh *nfhp;
263         struct nfsnode *np = VTONFS(vp);
264         struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
265         u_int32_t mode, clidrev;
266         int ret, newone, error, expireret = 0, retrycnt;
267
268         /*
269          * For NFSv4, Open Ops are only done on Regular Files.
270          */
271         if (vnode_vtype(vp) != VREG)
272                 return (0);
273         mode = 0;
274         if (amode & FREAD)
275                 mode |= NFSV4OPEN_ACCESSREAD;
276         if (amode & FWRITE)
277                 mode |= NFSV4OPEN_ACCESSWRITE;
278         nfhp = np->n_fhp;
279
280         retrycnt = 0;
281 #ifdef notdef
282 { char name[100]; int namel;
283 namel = (np->n_v4->n4_namelen < 100) ? np->n_v4->n4_namelen : 99;
284 bcopy(NFS4NODENAME(np->n_v4), name, namel);
285 name[namel] = '\0';
286 printf("rpcopen p=0x%x name=%s",p->p_pid,name);
287 if (nfhp->nfh_len > 0) printf(" fh=0x%x\n",nfhp->nfh_fh[12]);
288 else printf(" fhl=0\n");
289 }
290 #endif
291         do {
292             dp = NULL;
293             error = nfscl_open(vp, nfhp->nfh_fh, nfhp->nfh_len, mode, 1,
294                 cred, p, NULL, &op, &newone, &ret, 1);
295             if (error) {
296                 return (error);
297             }
298             if (nmp->nm_clp != NULL)
299                 clidrev = nmp->nm_clp->nfsc_clientidrev;
300             else
301                 clidrev = 0;
302             if (ret == NFSCLOPEN_DOOPEN) {
303                 if (np->n_v4 != NULL) {
304                         error = nfsrpc_openrpc(nmp, vp, np->n_v4->n4_data,
305                            np->n_v4->n4_fhlen, np->n_fhp->nfh_fh,
306                            np->n_fhp->nfh_len, mode, op,
307                            NFS4NODENAME(np->n_v4), np->n_v4->n4_namelen, &dp,
308                            0, 0x0, cred, p, 0, 0);
309                         if (dp != NULL) {
310 #ifdef APPLE
311                                 OSBitAndAtomic((int32_t)~NDELEGMOD, (UInt32 *)&np->n_flag);
312 #else
313                                 NFSLOCKNODE(np);
314                                 np->n_flag &= ~NDELEGMOD;
315                                 /*
316                                  * Invalidate the attribute cache, so that
317                                  * attributes that pre-date the issue of a
318                                  * delegation are not cached, since the
319                                  * cached attributes will remain valid while
320                                  * the delegation is held.
321                                  */
322                                 NFSINVALATTRCACHE(np);
323                                 NFSUNLOCKNODE(np);
324 #endif
325                                 (void) nfscl_deleg(nmp->nm_mountp,
326                                     op->nfso_own->nfsow_clp,
327                                     nfhp->nfh_fh, nfhp->nfh_len, cred, p, &dp);
328                         }
329                 } else {
330                         error = EIO;
331                 }
332                 newnfs_copyincred(cred, &op->nfso_cred);
333             } else if (ret == NFSCLOPEN_SETCRED)
334                 /*
335                  * This is a new local open on a delegation. It needs
336                  * to have credentials so that an open can be done
337                  * against the server during recovery.
338                  */
339                 newnfs_copyincred(cred, &op->nfso_cred);
340
341             /*
342              * nfso_opencnt is the count of how many VOP_OPEN()s have
343              * been done on this Open successfully and a VOP_CLOSE()
344              * is expected for each of these.
345              * If error is non-zero, don't increment it, since the Open
346              * hasn't succeeded yet.
347              */
348             if (!error)
349                 op->nfso_opencnt++;
350             nfscl_openrelease(op, error, newone);
351             if (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID ||
352                 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
353                 error == NFSERR_BADSESSION) {
354                 (void) nfs_catnap(PZERO, error, "nfs_open");
355             } else if ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID)
356                 && clidrev != 0) {
357                 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
358                 retrycnt++;
359             }
360         } while (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID ||
361             error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
362             error == NFSERR_BADSESSION ||
363             ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
364              expireret == 0 && clidrev != 0 && retrycnt < 4));
365         if (error && retrycnt >= 4)
366                 error = EIO;
367         return (error);
368 }
369
370 /*
371  * the actual open rpc
372  */
373 APPLESTATIC int
374 nfsrpc_openrpc(struct nfsmount *nmp, vnode_t vp, u_int8_t *nfhp, int fhlen,
375     u_int8_t *newfhp, int newfhlen, u_int32_t mode, struct nfsclopen *op,
376     u_int8_t *name, int namelen, struct nfscldeleg **dpp,
377     int reclaim, u_int32_t delegtype, struct ucred *cred, NFSPROC_T *p,
378     int syscred, int recursed)
379 {
380         u_int32_t *tl;
381         struct nfsrv_descript nfsd, *nd = &nfsd;
382         struct nfscldeleg *dp, *ndp = NULL;
383         struct nfsvattr nfsva;
384         u_int32_t rflags, deleg;
385         nfsattrbit_t attrbits;
386         int error, ret, acesize, limitby;
387
388         dp = *dpp;
389         *dpp = NULL;
390         nfscl_reqstart(nd, NFSPROC_OPEN, nmp, nfhp, fhlen, NULL, NULL);
391         NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
392         *tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid);
393         *tl++ = txdr_unsigned(mode & NFSV4OPEN_ACCESSBOTH);
394         *tl++ = txdr_unsigned((mode >> NFSLCK_SHIFT) & NFSV4OPEN_DENYBOTH);
395         *tl++ = NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[0];
396         *tl = NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[1];
397         (void) nfsm_strtom(nd, op->nfso_own->nfsow_owner, NFSV4CL_LOCKNAMELEN);
398         NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
399         *tl++ = txdr_unsigned(NFSV4OPEN_NOCREATE);
400         if (reclaim) {
401                 *tl = txdr_unsigned(NFSV4OPEN_CLAIMPREVIOUS);
402                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
403                 *tl = txdr_unsigned(delegtype);
404         } else {
405                 if (dp != NULL) {
406                         *tl = txdr_unsigned(NFSV4OPEN_CLAIMDELEGATECUR);
407                         NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
408                         if (NFSHASNFSV4N(nmp))
409                                 *tl++ = 0;
410                         else
411                                 *tl++ = dp->nfsdl_stateid.seqid;
412                         *tl++ = dp->nfsdl_stateid.other[0];
413                         *tl++ = dp->nfsdl_stateid.other[1];
414                         *tl = dp->nfsdl_stateid.other[2];
415                 } else {
416                         *tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL);
417                 }
418                 (void) nfsm_strtom(nd, name, namelen);
419         }
420         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
421         *tl = txdr_unsigned(NFSV4OP_GETATTR);
422         NFSZERO_ATTRBIT(&attrbits);
423         NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE);
424         NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFY);
425         (void) nfsrv_putattrbit(nd, &attrbits);
426         if (syscred)
427                 nd->nd_flag |= ND_USEGSSNAME;
428         error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, vp, p, cred,
429             NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
430         if (error)
431                 return (error);
432         NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd);
433         if (!nd->nd_repstat) {
434                 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
435                     6 * NFSX_UNSIGNED);
436                 op->nfso_stateid.seqid = *tl++;
437                 op->nfso_stateid.other[0] = *tl++;
438                 op->nfso_stateid.other[1] = *tl++;
439                 op->nfso_stateid.other[2] = *tl;
440                 rflags = fxdr_unsigned(u_int32_t, *(tl + 6));
441                 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
442                 if (error)
443                         goto nfsmout;
444                 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
445                 deleg = fxdr_unsigned(u_int32_t, *tl);
446                 if (deleg == NFSV4OPEN_DELEGATEREAD ||
447                     deleg == NFSV4OPEN_DELEGATEWRITE) {
448                         if (!(op->nfso_own->nfsow_clp->nfsc_flags &
449                               NFSCLFLAGS_FIRSTDELEG))
450                                 op->nfso_own->nfsow_clp->nfsc_flags |=
451                                   (NFSCLFLAGS_FIRSTDELEG | NFSCLFLAGS_GOTDELEG);
452                         MALLOC(ndp, struct nfscldeleg *,
453                             sizeof (struct nfscldeleg) + newfhlen,
454                             M_NFSCLDELEG, M_WAITOK);
455                         LIST_INIT(&ndp->nfsdl_owner);
456                         LIST_INIT(&ndp->nfsdl_lock);
457                         ndp->nfsdl_clp = op->nfso_own->nfsow_clp;
458                         ndp->nfsdl_fhlen = newfhlen;
459                         NFSBCOPY(newfhp, ndp->nfsdl_fh, newfhlen);
460                         newnfs_copyincred(cred, &ndp->nfsdl_cred);
461                         nfscl_lockinit(&ndp->nfsdl_rwlock);
462                         NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
463                             NFSX_UNSIGNED);
464                         ndp->nfsdl_stateid.seqid = *tl++;
465                         ndp->nfsdl_stateid.other[0] = *tl++;
466                         ndp->nfsdl_stateid.other[1] = *tl++;
467                         ndp->nfsdl_stateid.other[2] = *tl++;
468                         ret = fxdr_unsigned(int, *tl);
469                         if (deleg == NFSV4OPEN_DELEGATEWRITE) {
470                                 ndp->nfsdl_flags = NFSCLDL_WRITE;
471                                 /*
472                                  * Indicates how much the file can grow.
473                                  */
474                                 NFSM_DISSECT(tl, u_int32_t *,
475                                     3 * NFSX_UNSIGNED);
476                                 limitby = fxdr_unsigned(int, *tl++);
477                                 switch (limitby) {
478                                 case NFSV4OPEN_LIMITSIZE:
479                                         ndp->nfsdl_sizelimit = fxdr_hyper(tl);
480                                         break;
481                                 case NFSV4OPEN_LIMITBLOCKS:
482                                         ndp->nfsdl_sizelimit =
483                                             fxdr_unsigned(u_int64_t, *tl++);
484                                         ndp->nfsdl_sizelimit *=
485                                             fxdr_unsigned(u_int64_t, *tl);
486                                         break;
487                                 default:
488                                         error = NFSERR_BADXDR;
489                                         goto nfsmout;
490                                 };
491                         } else {
492                                 ndp->nfsdl_flags = NFSCLDL_READ;
493                         }
494                         if (ret)
495                                 ndp->nfsdl_flags |= NFSCLDL_RECALL;
496                         error = nfsrv_dissectace(nd, &ndp->nfsdl_ace, &ret,
497                             &acesize, p);
498                         if (error)
499                                 goto nfsmout;
500                 } else if (deleg != NFSV4OPEN_DELEGATENONE) {
501                         error = NFSERR_BADXDR;
502                         goto nfsmout;
503                 }
504                 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
505                 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL,
506                     NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
507                     NULL, NULL, NULL, p, cred);
508                 if (error)
509                         goto nfsmout;
510                 if (ndp != NULL) {
511                         ndp->nfsdl_change = nfsva.na_filerev;
512                         ndp->nfsdl_modtime = nfsva.na_mtime;
513                         ndp->nfsdl_flags |= NFSCLDL_MODTIMESET;
514                 }
515                 if (!reclaim && (rflags & NFSV4OPEN_RESULTCONFIRM)) {
516                     do {
517                         ret = nfsrpc_openconfirm(vp, newfhp, newfhlen, op,
518                             cred, p);
519                         if (ret == NFSERR_DELAY)
520                             (void) nfs_catnap(PZERO, ret, "nfs_open");
521                     } while (ret == NFSERR_DELAY);
522                     error = ret;
523                 }
524                 if ((rflags & NFSV4OPEN_LOCKTYPEPOSIX) ||
525                     nfscl_assumeposixlocks)
526                     op->nfso_posixlock = 1;
527                 else
528                     op->nfso_posixlock = 0;
529
530                 /*
531                  * If the server is handing out delegations, but we didn't
532                  * get one because an OpenConfirm was required, try the
533                  * Open again, to get a delegation. This is a harmless no-op,
534                  * from a server's point of view.
535                  */
536                 if (!reclaim && (rflags & NFSV4OPEN_RESULTCONFIRM) &&
537                     (op->nfso_own->nfsow_clp->nfsc_flags & NFSCLFLAGS_GOTDELEG)
538                     && !error && dp == NULL && ndp == NULL && !recursed) {
539                     do {
540                         ret = nfsrpc_openrpc(nmp, vp, nfhp, fhlen, newfhp,
541                             newfhlen, mode, op, name, namelen, &ndp, 0, 0x0,
542                             cred, p, syscred, 1);
543                         if (ret == NFSERR_DELAY)
544                             (void) nfs_catnap(PZERO, ret, "nfs_open2");
545                     } while (ret == NFSERR_DELAY);
546                     if (ret) {
547                         if (ndp != NULL) {
548                                 FREE((caddr_t)ndp, M_NFSCLDELEG);
549                                 ndp = NULL;
550                         }
551                         if (ret == NFSERR_STALECLIENTID ||
552                             ret == NFSERR_STALEDONTRECOVER ||
553                             ret == NFSERR_BADSESSION)
554                                 error = ret;
555                     }
556                 }
557         }
558         if (nd->nd_repstat != 0 && error == 0)
559                 error = nd->nd_repstat;
560         if (error == NFSERR_STALECLIENTID || error == NFSERR_BADSESSION)
561                 nfscl_initiate_recovery(op->nfso_own->nfsow_clp);
562 nfsmout:
563         if (!error)
564                 *dpp = ndp;
565         else if (ndp != NULL)
566                 FREE((caddr_t)ndp, M_NFSCLDELEG);
567         mbuf_freem(nd->nd_mrep);
568         return (error);
569 }
570
571 /*
572  * open downgrade rpc
573  */
574 APPLESTATIC int
575 nfsrpc_opendowngrade(vnode_t vp, u_int32_t mode, struct nfsclopen *op,
576     struct ucred *cred, NFSPROC_T *p)
577 {
578         u_int32_t *tl;
579         struct nfsrv_descript nfsd, *nd = &nfsd;
580         int error;
581
582         NFSCL_REQSTART(nd, NFSPROC_OPENDOWNGRADE, vp);
583         NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED);
584         if (NFSHASNFSV4N(VFSTONFS(vnode_mount(vp))))
585                 *tl++ = 0;
586         else
587                 *tl++ = op->nfso_stateid.seqid;
588         *tl++ = op->nfso_stateid.other[0];
589         *tl++ = op->nfso_stateid.other[1];
590         *tl++ = op->nfso_stateid.other[2];
591         *tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid);
592         *tl++ = txdr_unsigned(mode & NFSV4OPEN_ACCESSBOTH);
593         *tl = txdr_unsigned((mode >> NFSLCK_SHIFT) & NFSV4OPEN_DENYBOTH);
594         error = nfscl_request(nd, vp, p, cred, NULL);
595         if (error)
596                 return (error);
597         NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd);
598         if (!nd->nd_repstat) {
599                 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
600                 op->nfso_stateid.seqid = *tl++;
601                 op->nfso_stateid.other[0] = *tl++;
602                 op->nfso_stateid.other[1] = *tl++;
603                 op->nfso_stateid.other[2] = *tl;
604         }
605         if (nd->nd_repstat && error == 0)
606                 error = nd->nd_repstat;
607         if (error == NFSERR_STALESTATEID || error == NFSERR_BADSESSION)
608                 nfscl_initiate_recovery(op->nfso_own->nfsow_clp);
609 nfsmout:
610         mbuf_freem(nd->nd_mrep);
611         return (error);
612 }
613
614 /*
615  * V4 Close operation.
616  */
617 APPLESTATIC int
618 nfsrpc_close(vnode_t vp, int doclose, NFSPROC_T *p)
619 {
620         struct nfsclclient *clp;
621         int error;
622
623         if (vnode_vtype(vp) != VREG)
624                 return (0);
625         if (doclose)
626                 error = nfscl_doclose(vp, &clp, p);
627         else
628                 error = nfscl_getclose(vp, &clp);
629         if (error)
630                 return (error);
631
632         nfscl_clientrelease(clp);
633         return (0);
634 }
635
636 /*
637  * Close the open.
638  */
639 APPLESTATIC void
640 nfsrpc_doclose(struct nfsmount *nmp, struct nfsclopen *op, NFSPROC_T *p)
641 {
642         struct nfsrv_descript nfsd, *nd = &nfsd;
643         struct nfscllockowner *lp, *nlp;
644         struct nfscllock *lop, *nlop;
645         struct ucred *tcred;
646         u_int64_t off = 0, len = 0;
647         u_int32_t type = NFSV4LOCKT_READ;
648         int error, do_unlock, trycnt;
649
650         tcred = newnfs_getcred();
651         newnfs_copycred(&op->nfso_cred, tcred);
652         /*
653          * (Theoretically this could be done in the same
654          *  compound as the close, but having multiple
655          *  sequenced Ops in the same compound might be
656          *  too scary for some servers.)
657          */
658         if (op->nfso_posixlock) {
659                 off = 0;
660                 len = NFS64BITSSET;
661                 type = NFSV4LOCKT_READ;
662         }
663
664         /*
665          * Since this function is only called from VOP_INACTIVE(), no
666          * other thread will be manipulating this Open. As such, the
667          * lock lists are not being changed by other threads, so it should
668          * be safe to do this without locking.
669          */
670         LIST_FOREACH(lp, &op->nfso_lock, nfsl_list) {
671                 do_unlock = 1;
672                 LIST_FOREACH_SAFE(lop, &lp->nfsl_lock, nfslo_list, nlop) {
673                         if (op->nfso_posixlock == 0) {
674                                 off = lop->nfslo_first;
675                                 len = lop->nfslo_end - lop->nfslo_first;
676                                 if (lop->nfslo_type == F_WRLCK)
677                                         type = NFSV4LOCKT_WRITE;
678                                 else
679                                         type = NFSV4LOCKT_READ;
680                         }
681                         if (do_unlock) {
682                                 trycnt = 0;
683                                 do {
684                                         error = nfsrpc_locku(nd, nmp, lp, off,
685                                             len, type, tcred, p, 0);
686                                         if ((nd->nd_repstat == NFSERR_GRACE ||
687                                             nd->nd_repstat == NFSERR_DELAY) &&
688                                             error == 0)
689                                                 (void) nfs_catnap(PZERO,
690                                                     (int)nd->nd_repstat,
691                                                     "nfs_close");
692                                 } while ((nd->nd_repstat == NFSERR_GRACE ||
693                                     nd->nd_repstat == NFSERR_DELAY) &&
694                                     error == 0 && trycnt++ < 5);
695                                 if (op->nfso_posixlock)
696                                         do_unlock = 0;
697                         }
698                         nfscl_freelock(lop, 0);
699                 }
700                 /*
701                  * Do a ReleaseLockOwner.
702                  * The lock owner name nfsl_owner may be used by other opens for
703                  * other files but the lock_owner4 name that nfsrpc_rellockown()
704                  * puts on the wire has the file handle for this file appended
705                  * to it, so it can be done now.
706                  */
707                 (void)nfsrpc_rellockown(nmp, lp, lp->nfsl_open->nfso_fh,
708                     lp->nfsl_open->nfso_fhlen, tcred, p);
709         }
710
711         /*
712          * There could be other Opens for different files on the same
713          * OpenOwner, so locking is required.
714          */
715         NFSLOCKCLSTATE();
716         nfscl_lockexcl(&op->nfso_own->nfsow_rwlock, NFSCLSTATEMUTEXPTR);
717         NFSUNLOCKCLSTATE();
718         do {
719                 error = nfscl_tryclose(op, tcred, nmp, p);
720                 if (error == NFSERR_GRACE)
721                         (void) nfs_catnap(PZERO, error, "nfs_close");
722         } while (error == NFSERR_GRACE);
723         NFSLOCKCLSTATE();
724         nfscl_lockunlock(&op->nfso_own->nfsow_rwlock);
725
726         LIST_FOREACH_SAFE(lp, &op->nfso_lock, nfsl_list, nlp)
727                 nfscl_freelockowner(lp, 0);
728         nfscl_freeopen(op, 0);
729         NFSUNLOCKCLSTATE();
730         NFSFREECRED(tcred);
731 }
732
733 /*
734  * The actual Close RPC.
735  */
736 APPLESTATIC int
737 nfsrpc_closerpc(struct nfsrv_descript *nd, struct nfsmount *nmp,
738     struct nfsclopen *op, struct ucred *cred, NFSPROC_T *p,
739     int syscred)
740 {
741         u_int32_t *tl;
742         int error;
743
744         nfscl_reqstart(nd, NFSPROC_CLOSE, nmp, op->nfso_fh,
745             op->nfso_fhlen, NULL, NULL);
746         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID);
747         *tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid);
748         if (NFSHASNFSV4N(nmp))
749                 *tl++ = 0;
750         else
751                 *tl++ = op->nfso_stateid.seqid;
752         *tl++ = op->nfso_stateid.other[0];
753         *tl++ = op->nfso_stateid.other[1];
754         *tl = op->nfso_stateid.other[2];
755         if (syscred)
756                 nd->nd_flag |= ND_USEGSSNAME;
757         error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
758             NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
759         if (error)
760                 return (error);
761         NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd);
762         if (nd->nd_repstat == 0)
763                 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
764         error = nd->nd_repstat;
765         if (error == NFSERR_STALESTATEID || error == NFSERR_BADSESSION)
766                 nfscl_initiate_recovery(op->nfso_own->nfsow_clp);
767 nfsmout:
768         mbuf_freem(nd->nd_mrep);
769         return (error);
770 }
771
772 /*
773  * V4 Open Confirm RPC.
774  */
775 APPLESTATIC int
776 nfsrpc_openconfirm(vnode_t vp, u_int8_t *nfhp, int fhlen,
777     struct nfsclopen *op, struct ucred *cred, NFSPROC_T *p)
778 {
779         u_int32_t *tl;
780         struct nfsrv_descript nfsd, *nd = &nfsd;
781         struct nfsmount *nmp;
782         int error;
783
784         nmp = VFSTONFS(vnode_mount(vp));
785         if (NFSHASNFSV4N(nmp))
786                 return (0);             /* No confirmation for NFSv4.1. */
787         nfscl_reqstart(nd, NFSPROC_OPENCONFIRM, nmp, nfhp, fhlen, NULL, NULL);
788         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID);
789         *tl++ = op->nfso_stateid.seqid;
790         *tl++ = op->nfso_stateid.other[0];
791         *tl++ = op->nfso_stateid.other[1];
792         *tl++ = op->nfso_stateid.other[2];
793         *tl = txdr_unsigned(op->nfso_own->nfsow_seqid);
794         error = nfscl_request(nd, vp, p, cred, NULL);
795         if (error)
796                 return (error);
797         NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd);
798         if (!nd->nd_repstat) {
799                 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
800                 op->nfso_stateid.seqid = *tl++;
801                 op->nfso_stateid.other[0] = *tl++;
802                 op->nfso_stateid.other[1] = *tl++;
803                 op->nfso_stateid.other[2] = *tl;
804         }
805         error = nd->nd_repstat;
806         if (error == NFSERR_STALESTATEID || error == NFSERR_BADSESSION)
807                 nfscl_initiate_recovery(op->nfso_own->nfsow_clp);
808 nfsmout:
809         mbuf_freem(nd->nd_mrep);
810         return (error);
811 }
812
813 /*
814  * Do the setclientid and setclientid confirm RPCs. Called from nfs_statfs()
815  * when a mount has just occurred and when the server replies NFSERR_EXPIRED.
816  */
817 APPLESTATIC int
818 nfsrpc_setclient(struct nfsmount *nmp, struct nfsclclient *clp, int reclaim,
819     struct ucred *cred, NFSPROC_T *p)
820 {
821         u_int32_t *tl;
822         struct nfsrv_descript nfsd;
823         struct nfsrv_descript *nd = &nfsd;
824         nfsattrbit_t attrbits;
825         u_int8_t *cp = NULL, *cp2, addr[INET6_ADDRSTRLEN + 9];
826         u_short port;
827         int error, isinet6 = 0, callblen;
828         nfsquad_t confirm;
829         u_int32_t lease;
830         static u_int32_t rev = 0;
831         struct nfsclds *dsp, *ndsp, *tdsp;
832
833         if (nfsboottime.tv_sec == 0)
834                 NFSSETBOOTTIME(nfsboottime);
835         clp->nfsc_rev = rev++;
836         if (NFSHASNFSV4N(nmp)) {
837                 error = nfsrpc_exchangeid(nmp, clp, &nmp->nm_sockreq,
838                     NFSV4EXCH_USEPNFSMDS | NFSV4EXCH_USENONPNFS, &dsp, cred, p);
839                 NFSCL_DEBUG(1, "aft exch=%d\n", error);
840                 if (error == 0) {
841                         error = nfsrpc_createsession(nmp, &dsp->nfsclds_sess,
842                             &nmp->nm_sockreq,
843                             dsp->nfsclds_sess.nfsess_sequenceid, 1, cred, p);
844                         if (error == 0) {
845                                 NFSLOCKMNT(nmp);
846                                 TAILQ_FOREACH_SAFE(tdsp, &nmp->nm_sess,
847                                     nfsclds_list, ndsp)
848                                         nfscl_freenfsclds(tdsp);
849                                 TAILQ_INIT(&nmp->nm_sess);
850                                 TAILQ_INSERT_HEAD(&nmp->nm_sess, dsp,
851                                     nfsclds_list);
852                                 NFSUNLOCKMNT(nmp);
853                         } else
854                                 nfscl_freenfsclds(dsp);
855                         NFSCL_DEBUG(1, "aft createsess=%d\n", error);
856                 }
857                 if (error == 0 && reclaim == 0) {
858                         error = nfsrpc_reclaimcomplete(nmp, cred, p);
859                         NFSCL_DEBUG(1, "aft reclaimcomp=%d\n", error);
860                         if (error == NFSERR_COMPLETEALREADY ||
861                             error == NFSERR_NOTSUPP)
862                                 /* Ignore this error. */
863                                 error = 0;
864                 }
865                 return (error);
866         }
867
868         /*
869          * Allocate a single session structure for NFSv4.0, because some of
870          * the fields are used by NFSv4.0 although it doesn't do a session.
871          */
872         dsp = malloc(sizeof(struct nfsclds), M_NFSCLDS, M_WAITOK | M_ZERO);
873         mtx_init(&dsp->nfsclds_mtx, "nfsds", NULL, MTX_DEF);
874         mtx_init(&dsp->nfsclds_sess.nfsess_mtx, "nfssession", NULL, MTX_DEF);
875         NFSLOCKMNT(nmp);
876         TAILQ_INSERT_HEAD(&nmp->nm_sess, dsp, nfsclds_list);
877         NFSUNLOCKMNT(nmp);
878
879         nfscl_reqstart(nd, NFSPROC_SETCLIENTID, nmp, NULL, 0, NULL, NULL);
880         NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
881         *tl++ = txdr_unsigned(nfsboottime.tv_sec);
882         *tl = txdr_unsigned(clp->nfsc_rev);
883         (void) nfsm_strtom(nd, clp->nfsc_id, clp->nfsc_idlen);
884
885         /*
886          * set up the callback address
887          */
888         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
889         *tl = txdr_unsigned(NFS_CALLBCKPROG);
890         callblen = strlen(nfsv4_callbackaddr);
891         if (callblen == 0)
892                 cp = nfscl_getmyip(nmp, &isinet6);
893         if (nfscl_enablecallb && nfs_numnfscbd > 0 &&
894             (callblen > 0 || cp != NULL)) {
895                 port = htons(nfsv4_cbport);
896                 cp2 = (u_int8_t *)&port;
897 #ifdef INET6
898                 if ((callblen > 0 &&
899                      strchr(nfsv4_callbackaddr, ':')) || isinet6) {
900                         char ip6buf[INET6_ADDRSTRLEN], *ip6add;
901
902                         (void) nfsm_strtom(nd, "tcp6", 4);
903                         if (callblen == 0) {
904                                 ip6_sprintf(ip6buf, (struct in6_addr *)cp);
905                                 ip6add = ip6buf;
906                         } else {
907                                 ip6add = nfsv4_callbackaddr;
908                         }
909                         snprintf(addr, INET6_ADDRSTRLEN + 9, "%s.%d.%d",
910                             ip6add, cp2[0], cp2[1]);
911                 } else
912 #endif
913                 {
914                         (void) nfsm_strtom(nd, "tcp", 3);
915                         if (callblen == 0)
916                                 snprintf(addr, INET6_ADDRSTRLEN + 9,
917                                     "%d.%d.%d.%d.%d.%d", cp[0], cp[1],
918                                     cp[2], cp[3], cp2[0], cp2[1]);
919                         else
920                                 snprintf(addr, INET6_ADDRSTRLEN + 9,
921                                     "%s.%d.%d", nfsv4_callbackaddr,
922                                     cp2[0], cp2[1]);
923                 }
924                 (void) nfsm_strtom(nd, addr, strlen(addr));
925         } else {
926                 (void) nfsm_strtom(nd, "tcp", 3);
927                 (void) nfsm_strtom(nd, "0.0.0.0.0.0", 11);
928         }
929         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
930         *tl = txdr_unsigned(clp->nfsc_cbident);
931         nd->nd_flag |= ND_USEGSSNAME;
932         error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
933                 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
934         if (error)
935                 return (error);
936         if (nd->nd_repstat == 0) {
937             NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
938             NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[0] = *tl++;
939             NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[1] = *tl++;
940             confirm.lval[0] = *tl++;
941             confirm.lval[1] = *tl;
942             mbuf_freem(nd->nd_mrep);
943             nd->nd_mrep = NULL;
944
945             /*
946              * and confirm it.
947              */
948             nfscl_reqstart(nd, NFSPROC_SETCLIENTIDCFRM, nmp, NULL, 0, NULL,
949                 NULL);
950             NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
951             *tl++ = NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[0];
952             *tl++ = NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[1];
953             *tl++ = confirm.lval[0];
954             *tl = confirm.lval[1];
955             nd->nd_flag |= ND_USEGSSNAME;
956             error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p,
957                 cred, NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
958             if (error)
959                 return (error);
960             mbuf_freem(nd->nd_mrep);
961             nd->nd_mrep = NULL;
962             if (nd->nd_repstat == 0) {
963                 nfscl_reqstart(nd, NFSPROC_GETATTR, nmp, nmp->nm_fh,
964                     nmp->nm_fhsize, NULL, NULL);
965                 NFSZERO_ATTRBIT(&attrbits);
966                 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_LEASETIME);
967                 (void) nfsrv_putattrbit(nd, &attrbits);
968                 nd->nd_flag |= ND_USEGSSNAME;
969                 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p,
970                     cred, NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
971                 if (error)
972                     return (error);
973                 if (nd->nd_repstat == 0) {
974                     error = nfsv4_loadattr(nd, NULL, NULL, NULL, NULL, 0, NULL,
975                         NULL, NULL, NULL, NULL, 0, NULL, &lease, NULL, p, cred);
976                     if (error)
977                         goto nfsmout;
978                     clp->nfsc_renew = NFSCL_RENEW(lease);
979                     clp->nfsc_expire = NFSD_MONOSEC + clp->nfsc_renew;
980                     clp->nfsc_clientidrev++;
981                     if (clp->nfsc_clientidrev == 0)
982                         clp->nfsc_clientidrev++;
983                 }
984             }
985         }
986         error = nd->nd_repstat;
987 nfsmout:
988         mbuf_freem(nd->nd_mrep);
989         return (error);
990 }
991
992 /*
993  * nfs getattr call.
994  */
995 APPLESTATIC int
996 nfsrpc_getattr(vnode_t vp, struct ucred *cred, NFSPROC_T *p,
997     struct nfsvattr *nap, void *stuff)
998 {
999         struct nfsrv_descript nfsd, *nd = &nfsd;
1000         int error;
1001         nfsattrbit_t attrbits;
1002         
1003         NFSCL_REQSTART(nd, NFSPROC_GETATTR, vp);
1004         if (nd->nd_flag & ND_NFSV4) {
1005                 NFSGETATTR_ATTRBIT(&attrbits);
1006                 (void) nfsrv_putattrbit(nd, &attrbits);
1007         }
1008         error = nfscl_request(nd, vp, p, cred, stuff);
1009         if (error)
1010                 return (error);
1011         if (!nd->nd_repstat)
1012                 error = nfsm_loadattr(nd, nap);
1013         else
1014                 error = nd->nd_repstat;
1015         mbuf_freem(nd->nd_mrep);
1016         return (error);
1017 }
1018
1019 /*
1020  * nfs getattr call with non-vnode arguemnts.
1021  */
1022 APPLESTATIC int
1023 nfsrpc_getattrnovp(struct nfsmount *nmp, u_int8_t *fhp, int fhlen, int syscred,
1024     struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, u_int64_t *xidp,
1025     uint32_t *leasep)
1026 {
1027         struct nfsrv_descript nfsd, *nd = &nfsd;
1028         int error, vers = NFS_VER2;
1029         nfsattrbit_t attrbits;
1030         
1031         nfscl_reqstart(nd, NFSPROC_GETATTR, nmp, fhp, fhlen, NULL, NULL);
1032         if (nd->nd_flag & ND_NFSV4) {
1033                 vers = NFS_VER4;
1034                 NFSGETATTR_ATTRBIT(&attrbits);
1035                 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_LEASETIME);
1036                 (void) nfsrv_putattrbit(nd, &attrbits);
1037         } else if (nd->nd_flag & ND_NFSV3) {
1038                 vers = NFS_VER3;
1039         }
1040         if (syscred)
1041                 nd->nd_flag |= ND_USEGSSNAME;
1042         error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
1043             NFS_PROG, vers, NULL, 1, xidp, NULL);
1044         if (error)
1045                 return (error);
1046         if (nd->nd_repstat == 0) {
1047                 if ((nd->nd_flag & ND_NFSV4) != 0)
1048                         error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0,
1049                             NULL, NULL, NULL, NULL, NULL, 0, NULL, leasep, NULL,
1050                             NULL, NULL);
1051                 else
1052                         error = nfsm_loadattr(nd, nap);
1053         } else
1054                 error = nd->nd_repstat;
1055         mbuf_freem(nd->nd_mrep);
1056         return (error);
1057 }
1058
1059 /*
1060  * Do an nfs setattr operation.
1061  */
1062 APPLESTATIC int
1063 nfsrpc_setattr(vnode_t vp, struct vattr *vap, NFSACL_T *aclp,
1064     struct ucred *cred, NFSPROC_T *p, struct nfsvattr *rnap, int *attrflagp,
1065     void *stuff)
1066 {
1067         int error, expireret = 0, openerr, retrycnt;
1068         u_int32_t clidrev = 0, mode;
1069         struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
1070         struct nfsfh *nfhp;
1071         nfsv4stateid_t stateid;
1072         void *lckp;
1073
1074         if (nmp->nm_clp != NULL)
1075                 clidrev = nmp->nm_clp->nfsc_clientidrev;
1076         if (vap != NULL && NFSATTRISSET(u_quad_t, vap, va_size))
1077                 mode = NFSV4OPEN_ACCESSWRITE;
1078         else
1079                 mode = NFSV4OPEN_ACCESSREAD;
1080         retrycnt = 0;
1081         do {
1082                 lckp = NULL;
1083                 openerr = 1;
1084                 if (NFSHASNFSV4(nmp)) {
1085                         nfhp = VTONFS(vp)->n_fhp;
1086                         error = nfscl_getstateid(vp, nfhp->nfh_fh,
1087                             nfhp->nfh_len, mode, 0, cred, p, &stateid, &lckp);
1088                         if (error && vnode_vtype(vp) == VREG &&
1089                             (mode == NFSV4OPEN_ACCESSWRITE ||
1090                              nfstest_openallsetattr)) {
1091                                 /*
1092                                  * No Open stateid, so try and open the file
1093                                  * now.
1094                                  */
1095                                 if (mode == NFSV4OPEN_ACCESSWRITE)
1096                                         openerr = nfsrpc_open(vp, FWRITE, cred,
1097                                             p);
1098                                 else
1099                                         openerr = nfsrpc_open(vp, FREAD, cred,
1100                                             p);
1101                                 if (!openerr)
1102                                         (void) nfscl_getstateid(vp,
1103                                             nfhp->nfh_fh, nfhp->nfh_len,
1104                                             mode, 0, cred, p, &stateid, &lckp);
1105                         }
1106                 }
1107                 if (vap != NULL)
1108                         error = nfsrpc_setattrrpc(vp, vap, &stateid, cred, p,
1109                             rnap, attrflagp, stuff);
1110                 else
1111                         error = nfsrpc_setaclrpc(vp, cred, p, aclp, &stateid,
1112                             stuff);
1113                 if (error == NFSERR_STALESTATEID || error == NFSERR_BADSESSION)
1114                         nfscl_initiate_recovery(nmp->nm_clp);
1115                 if (lckp != NULL)
1116                         nfscl_lockderef(lckp);
1117                 if (!openerr)
1118                         (void) nfsrpc_close(vp, 0, p);
1119                 if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
1120                     error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
1121                     error == NFSERR_OLDSTATEID || error == NFSERR_BADSESSION) {
1122                         (void) nfs_catnap(PZERO, error, "nfs_setattr");
1123                 } else if ((error == NFSERR_EXPIRED ||
1124                     error == NFSERR_BADSTATEID) && clidrev != 0) {
1125                         expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
1126                 }
1127                 retrycnt++;
1128         } while (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
1129             error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
1130             error == NFSERR_BADSESSION ||
1131             (error == NFSERR_OLDSTATEID && retrycnt < 20) ||
1132             ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
1133              expireret == 0 && clidrev != 0 && retrycnt < 4));
1134         if (error && retrycnt >= 4)
1135                 error = EIO;
1136         return (error);
1137 }
1138
1139 static int
1140 nfsrpc_setattrrpc(vnode_t vp, struct vattr *vap,
1141     nfsv4stateid_t *stateidp, struct ucred *cred, NFSPROC_T *p,
1142     struct nfsvattr *rnap, int *attrflagp, void *stuff)
1143 {
1144         u_int32_t *tl;
1145         struct nfsrv_descript nfsd, *nd = &nfsd;
1146         int error;
1147         nfsattrbit_t attrbits;
1148
1149         *attrflagp = 0;
1150         NFSCL_REQSTART(nd, NFSPROC_SETATTR, vp);
1151         if (nd->nd_flag & ND_NFSV4)
1152                 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID);
1153         vap->va_type = vnode_vtype(vp);
1154         nfscl_fillsattr(nd, vap, vp, NFSSATTR_FULL, 0);
1155         if (nd->nd_flag & ND_NFSV3) {
1156                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1157                 *tl = newnfs_false;
1158         } else if (nd->nd_flag & ND_NFSV4) {
1159                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1160                 *tl = txdr_unsigned(NFSV4OP_GETATTR);
1161                 NFSGETATTR_ATTRBIT(&attrbits);
1162                 (void) nfsrv_putattrbit(nd, &attrbits);
1163         }
1164         error = nfscl_request(nd, vp, p, cred, stuff);
1165         if (error)
1166                 return (error);
1167         if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4))
1168                 error = nfscl_wcc_data(nd, vp, rnap, attrflagp, NULL, stuff);
1169         if ((nd->nd_flag & ND_NFSV4) && !error)
1170                 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
1171         if (!(nd->nd_flag & ND_NFSV3) && !nd->nd_repstat && !error)
1172                 error = nfscl_postop_attr(nd, rnap, attrflagp, stuff);
1173         mbuf_freem(nd->nd_mrep);
1174         if (nd->nd_repstat && !error)
1175                 error = nd->nd_repstat;
1176         return (error);
1177 }
1178
1179 /*
1180  * nfs lookup rpc
1181  */
1182 APPLESTATIC int
1183 nfsrpc_lookup(vnode_t dvp, char *name, int len, struct ucred *cred,
1184     NFSPROC_T *p, struct nfsvattr *dnap, struct nfsvattr *nap,
1185     struct nfsfh **nfhpp, int *attrflagp, int *dattrflagp, void *stuff)
1186 {
1187         u_int32_t *tl;
1188         struct nfsrv_descript nfsd, *nd = &nfsd;
1189         struct nfsmount *nmp;
1190         struct nfsnode *np;
1191         struct nfsfh *nfhp;
1192         nfsattrbit_t attrbits;
1193         int error = 0, lookupp = 0;
1194
1195         *attrflagp = 0;
1196         *dattrflagp = 0;
1197         if (vnode_vtype(dvp) != VDIR)
1198                 return (ENOTDIR);
1199         nmp = VFSTONFS(vnode_mount(dvp));
1200         if (len > NFS_MAXNAMLEN)
1201                 return (ENAMETOOLONG);
1202         if (NFSHASNFSV4(nmp) && len == 1 &&
1203                 name[0] == '.') {
1204                 /*
1205                  * Just return the current dir's fh.
1206                  */
1207                 np = VTONFS(dvp);
1208                 MALLOC(nfhp, struct nfsfh *, sizeof (struct nfsfh) +
1209                         np->n_fhp->nfh_len, M_NFSFH, M_WAITOK);
1210                 nfhp->nfh_len = np->n_fhp->nfh_len;
1211                 NFSBCOPY(np->n_fhp->nfh_fh, nfhp->nfh_fh, nfhp->nfh_len);
1212                 *nfhpp = nfhp;
1213                 return (0);
1214         }
1215         if (NFSHASNFSV4(nmp) && len == 2 &&
1216                 name[0] == '.' && name[1] == '.') {
1217                 lookupp = 1;
1218                 NFSCL_REQSTART(nd, NFSPROC_LOOKUPP, dvp);
1219         } else {
1220                 NFSCL_REQSTART(nd, NFSPROC_LOOKUP, dvp);
1221                 (void) nfsm_strtom(nd, name, len);
1222         }
1223         if (nd->nd_flag & ND_NFSV4) {
1224                 NFSGETATTR_ATTRBIT(&attrbits);
1225                 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1226                 *tl++ = txdr_unsigned(NFSV4OP_GETFH);
1227                 *tl = txdr_unsigned(NFSV4OP_GETATTR);
1228                 (void) nfsrv_putattrbit(nd, &attrbits);
1229         }
1230         error = nfscl_request(nd, dvp, p, cred, stuff);
1231         if (error)
1232                 return (error);
1233         if (nd->nd_repstat) {
1234                 /*
1235                  * When an NFSv4 Lookupp returns ENOENT, it means that
1236                  * the lookup is at the root of an fs, so return this dir.
1237                  */
1238                 if (nd->nd_repstat == NFSERR_NOENT && lookupp) {
1239                     np = VTONFS(dvp);
1240                     MALLOC(nfhp, struct nfsfh *, sizeof (struct nfsfh) +
1241                         np->n_fhp->nfh_len, M_NFSFH, M_WAITOK);
1242                     nfhp->nfh_len = np->n_fhp->nfh_len;
1243                     NFSBCOPY(np->n_fhp->nfh_fh, nfhp->nfh_fh, nfhp->nfh_len);
1244                     *nfhpp = nfhp;
1245                     mbuf_freem(nd->nd_mrep);
1246                     return (0);
1247                 }
1248                 if (nd->nd_flag & ND_NFSV3)
1249                     error = nfscl_postop_attr(nd, dnap, dattrflagp, stuff);
1250                 else if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) ==
1251                     ND_NFSV4) {
1252                         /* Load the directory attributes. */
1253                         error = nfsm_loadattr(nd, dnap);
1254                         if (error == 0)
1255                                 *dattrflagp = 1;
1256                 }
1257                 goto nfsmout;
1258         }
1259         if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4) {
1260                 /* Load the directory attributes. */
1261                 error = nfsm_loadattr(nd, dnap);
1262                 if (error != 0)
1263                         goto nfsmout;
1264                 *dattrflagp = 1;
1265                 /* Skip over the Lookup and GetFH operation status values. */
1266                 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1267         }
1268         error = nfsm_getfh(nd, nfhpp);
1269         if (error)
1270                 goto nfsmout;
1271
1272         error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
1273         if ((nd->nd_flag & ND_NFSV3) && !error)
1274                 error = nfscl_postop_attr(nd, dnap, dattrflagp, stuff);
1275 nfsmout:
1276         mbuf_freem(nd->nd_mrep);
1277         if (!error && nd->nd_repstat)
1278                 error = nd->nd_repstat;
1279         return (error);
1280 }
1281
1282 /*
1283  * Do a readlink rpc.
1284  */
1285 APPLESTATIC int
1286 nfsrpc_readlink(vnode_t vp, struct uio *uiop, struct ucred *cred,
1287     NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff)
1288 {
1289         u_int32_t *tl;
1290         struct nfsrv_descript nfsd, *nd = &nfsd;
1291         struct nfsnode *np = VTONFS(vp);
1292         nfsattrbit_t attrbits;
1293         int error, len, cangetattr = 1;
1294
1295         *attrflagp = 0;
1296         NFSCL_REQSTART(nd, NFSPROC_READLINK, vp);
1297         if (nd->nd_flag & ND_NFSV4) {
1298                 /*
1299                  * And do a Getattr op.
1300                  */
1301                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1302                 *tl = txdr_unsigned(NFSV4OP_GETATTR);
1303                 NFSGETATTR_ATTRBIT(&attrbits);
1304                 (void) nfsrv_putattrbit(nd, &attrbits);
1305         }
1306         error = nfscl_request(nd, vp, p, cred, stuff);
1307         if (error)
1308                 return (error);
1309         if (nd->nd_flag & ND_NFSV3)
1310                 error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
1311         if (!nd->nd_repstat && !error) {
1312                 NFSM_STRSIZ(len, NFS_MAXPATHLEN);
1313                 /*
1314                  * This seems weird to me, but must have been added to
1315                  * FreeBSD for some reason. The only thing I can think of
1316                  * is that there was/is some server that replies with
1317                  * more link data than it should?
1318                  */
1319                 if (len == NFS_MAXPATHLEN) {
1320                         NFSLOCKNODE(np);
1321                         if (np->n_size > 0 && np->n_size < NFS_MAXPATHLEN) {
1322                                 len = np->n_size;
1323                                 cangetattr = 0;
1324                         }
1325                         NFSUNLOCKNODE(np);
1326                 }
1327                 error = nfsm_mbufuio(nd, uiop, len);
1328                 if ((nd->nd_flag & ND_NFSV4) && !error && cangetattr)
1329                         error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
1330         }
1331         if (nd->nd_repstat && !error)
1332                 error = nd->nd_repstat;
1333 nfsmout:
1334         mbuf_freem(nd->nd_mrep);
1335         return (error);
1336 }
1337
1338 /*
1339  * Read operation.
1340  */
1341 APPLESTATIC int
1342 nfsrpc_read(vnode_t vp, struct uio *uiop, struct ucred *cred,
1343     NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff)
1344 {
1345         int error, expireret = 0, retrycnt;
1346         u_int32_t clidrev = 0;
1347         struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
1348         struct nfsnode *np = VTONFS(vp);
1349         struct ucred *newcred;
1350         struct nfsfh *nfhp = NULL;
1351         nfsv4stateid_t stateid;
1352         void *lckp;
1353
1354         if (nmp->nm_clp != NULL)
1355                 clidrev = nmp->nm_clp->nfsc_clientidrev;
1356         newcred = cred;
1357         if (NFSHASNFSV4(nmp)) {
1358                 nfhp = np->n_fhp;
1359                 newcred = NFSNEWCRED(cred);
1360         }
1361         retrycnt = 0;
1362         do {
1363                 lckp = NULL;
1364                 if (NFSHASNFSV4(nmp))
1365                         (void)nfscl_getstateid(vp, nfhp->nfh_fh, nfhp->nfh_len,
1366                             NFSV4OPEN_ACCESSREAD, 0, newcred, p, &stateid,
1367                             &lckp);
1368                 error = nfsrpc_readrpc(vp, uiop, newcred, &stateid, p, nap,
1369                     attrflagp, stuff);
1370                 if (error == NFSERR_STALESTATEID || error == NFSERR_BADSESSION)
1371                         nfscl_initiate_recovery(nmp->nm_clp);
1372                 if (lckp != NULL)
1373                         nfscl_lockderef(lckp);
1374                 if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
1375                     error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
1376                     error == NFSERR_OLDSTATEID || error == NFSERR_BADSESSION) {
1377                         (void) nfs_catnap(PZERO, error, "nfs_read");
1378                 } else if ((error == NFSERR_EXPIRED ||
1379                     error == NFSERR_BADSTATEID) && clidrev != 0) {
1380                         expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
1381                 }
1382                 retrycnt++;
1383         } while (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
1384             error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
1385             error == NFSERR_BADSESSION ||
1386             (error == NFSERR_OLDSTATEID && retrycnt < 20) ||
1387             ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
1388              expireret == 0 && clidrev != 0 && retrycnt < 4));
1389         if (error && retrycnt >= 4)
1390                 error = EIO;
1391         if (NFSHASNFSV4(nmp))
1392                 NFSFREECRED(newcred);
1393         return (error);
1394 }
1395
1396 /*
1397  * The actual read RPC.
1398  */
1399 static int
1400 nfsrpc_readrpc(vnode_t vp, struct uio *uiop, struct ucred *cred,
1401     nfsv4stateid_t *stateidp, NFSPROC_T *p, struct nfsvattr *nap,
1402     int *attrflagp, void *stuff)
1403 {
1404         u_int32_t *tl;
1405         int error = 0, len, retlen, tsiz, eof = 0;
1406         struct nfsrv_descript nfsd;
1407         struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
1408         struct nfsrv_descript *nd = &nfsd;
1409         int rsize;
1410         off_t tmp_off;
1411
1412         *attrflagp = 0;
1413         tsiz = uio_uio_resid(uiop);
1414         tmp_off = uiop->uio_offset + tsiz;
1415         NFSLOCKMNT(nmp);
1416         if (tmp_off > nmp->nm_maxfilesize || tmp_off < uiop->uio_offset) {
1417                 NFSUNLOCKMNT(nmp);
1418                 return (EFBIG);
1419         }
1420         rsize = nmp->nm_rsize;
1421         NFSUNLOCKMNT(nmp);
1422         nd->nd_mrep = NULL;
1423         while (tsiz > 0) {
1424                 *attrflagp = 0;
1425                 len = (tsiz > rsize) ? rsize : tsiz;
1426                 NFSCL_REQSTART(nd, NFSPROC_READ, vp);
1427                 if (nd->nd_flag & ND_NFSV4)
1428                         nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID);
1429                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED * 3);
1430                 if (nd->nd_flag & ND_NFSV2) {
1431                         *tl++ = txdr_unsigned(uiop->uio_offset);
1432                         *tl++ = txdr_unsigned(len);
1433                         *tl = 0;
1434                 } else {
1435                         txdr_hyper(uiop->uio_offset, tl);
1436                         *(tl + 2) = txdr_unsigned(len);
1437                 }
1438                 /*
1439                  * Since I can't do a Getattr for NFSv4 for Write, there
1440                  * doesn't seem any point in doing one here, either.
1441                  * (See the comment in nfsrpc_writerpc() for more info.)
1442                  */
1443                 error = nfscl_request(nd, vp, p, cred, stuff);
1444                 if (error)
1445                         return (error);
1446                 if (nd->nd_flag & ND_NFSV3) {
1447                         error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
1448                 } else if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV2)) {
1449                         error = nfsm_loadattr(nd, nap);
1450                         if (!error)
1451                                 *attrflagp = 1;
1452                 }
1453                 if (nd->nd_repstat || error) {
1454                         if (!error)
1455                                 error = nd->nd_repstat;
1456                         goto nfsmout;
1457                 }
1458                 if (nd->nd_flag & ND_NFSV3) {
1459                         NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1460                         eof = fxdr_unsigned(int, *(tl + 1));
1461                 } else if (nd->nd_flag & ND_NFSV4) {
1462                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1463                         eof = fxdr_unsigned(int, *tl);
1464                 }
1465                 NFSM_STRSIZ(retlen, len);
1466                 error = nfsm_mbufuio(nd, uiop, retlen);
1467                 if (error)
1468                         goto nfsmout;
1469                 mbuf_freem(nd->nd_mrep);
1470                 nd->nd_mrep = NULL;
1471                 tsiz -= retlen;
1472                 if (!(nd->nd_flag & ND_NFSV2)) {
1473                         if (eof || retlen == 0)
1474                                 tsiz = 0;
1475                 } else if (retlen < len)
1476                         tsiz = 0;
1477         }
1478         return (0);
1479 nfsmout:
1480         if (nd->nd_mrep != NULL)
1481                 mbuf_freem(nd->nd_mrep);
1482         return (error);
1483 }
1484
1485 /*
1486  * nfs write operation
1487  * When called_from_strategy != 0, it should return EIO for an error that
1488  * indicates recovery is in progress, so that the buffer will be left
1489  * dirty and be written back to the server later. If it loops around,
1490  * the recovery thread could get stuck waiting for the buffer and recovery
1491  * will then deadlock.
1492  */
1493 APPLESTATIC int
1494 nfsrpc_write(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit,
1495     struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp,
1496     void *stuff, int called_from_strategy)
1497 {
1498         int error, expireret = 0, retrycnt, nostateid;
1499         u_int32_t clidrev = 0;
1500         struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
1501         struct nfsnode *np = VTONFS(vp);
1502         struct ucred *newcred;
1503         struct nfsfh *nfhp = NULL;
1504         nfsv4stateid_t stateid;
1505         void *lckp;
1506
1507         *must_commit = 0;
1508         if (nmp->nm_clp != NULL)
1509                 clidrev = nmp->nm_clp->nfsc_clientidrev;
1510         newcred = cred;
1511         if (NFSHASNFSV4(nmp)) {
1512                 newcred = NFSNEWCRED(cred);
1513                 nfhp = np->n_fhp;
1514         }
1515         retrycnt = 0;
1516         do {
1517                 lckp = NULL;
1518                 nostateid = 0;
1519                 if (NFSHASNFSV4(nmp)) {
1520                         (void)nfscl_getstateid(vp, nfhp->nfh_fh, nfhp->nfh_len,
1521                             NFSV4OPEN_ACCESSWRITE, 0, newcred, p, &stateid,
1522                             &lckp);
1523                         if (stateid.other[0] == 0 && stateid.other[1] == 0 &&
1524                             stateid.other[2] == 0) {
1525                                 nostateid = 1;
1526                                 NFSCL_DEBUG(1, "stateid0 in write\n");
1527                         }
1528                 }
1529
1530                 /*
1531                  * If there is no stateid for NFSv4, it means this is an
1532                  * extraneous write after close. Basically a poorly
1533                  * implemented buffer cache. Just don't do the write.
1534                  */
1535                 if (nostateid)
1536                         error = 0;
1537                 else
1538                         error = nfsrpc_writerpc(vp, uiop, iomode, must_commit,
1539                             newcred, &stateid, p, nap, attrflagp, stuff);
1540                 if (error == NFSERR_STALESTATEID || error == NFSERR_BADSESSION)
1541                         nfscl_initiate_recovery(nmp->nm_clp);
1542                 if (lckp != NULL)
1543                         nfscl_lockderef(lckp);
1544                 if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
1545                     error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
1546                     error == NFSERR_OLDSTATEID || error == NFSERR_BADSESSION) {
1547                         (void) nfs_catnap(PZERO, error, "nfs_write");
1548                 } else if ((error == NFSERR_EXPIRED ||
1549                     error == NFSERR_BADSTATEID) && clidrev != 0) {
1550                         expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
1551                 }
1552                 retrycnt++;
1553         } while (error == NFSERR_GRACE || error == NFSERR_DELAY ||
1554             ((error == NFSERR_STALESTATEID || error == NFSERR_BADSESSION ||
1555               error == NFSERR_STALEDONTRECOVER) && called_from_strategy == 0) ||
1556             (error == NFSERR_OLDSTATEID && retrycnt < 20) ||
1557             ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
1558              expireret == 0 && clidrev != 0 && retrycnt < 4));
1559         if (error != 0 && (retrycnt >= 4 ||
1560             ((error == NFSERR_STALESTATEID || error == NFSERR_BADSESSION ||
1561               error == NFSERR_STALEDONTRECOVER) && called_from_strategy != 0)))
1562                 error = EIO;
1563         if (NFSHASNFSV4(nmp))
1564                 NFSFREECRED(newcred);
1565         return (error);
1566 }
1567
1568 /*
1569  * The actual write RPC.
1570  */
1571 static int
1572 nfsrpc_writerpc(vnode_t vp, struct uio *uiop, int *iomode,
1573     int *must_commit, struct ucred *cred, nfsv4stateid_t *stateidp,
1574     NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff)
1575 {
1576         u_int32_t *tl;
1577         struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
1578         struct nfsnode *np = VTONFS(vp);
1579         int error = 0, len, tsiz, rlen, commit, committed = NFSWRITE_FILESYNC;
1580         int wccflag = 0, wsize;
1581         int32_t backup;
1582         struct nfsrv_descript nfsd;
1583         struct nfsrv_descript *nd = &nfsd;
1584         nfsattrbit_t attrbits;
1585         off_t tmp_off;
1586
1587         KASSERT(uiop->uio_iovcnt == 1, ("nfs: writerpc iovcnt > 1"));
1588         *attrflagp = 0;
1589         tsiz = uio_uio_resid(uiop);
1590         tmp_off = uiop->uio_offset + tsiz;
1591         NFSLOCKMNT(nmp);
1592         if (tmp_off > nmp->nm_maxfilesize || tmp_off < uiop->uio_offset) {
1593                 NFSUNLOCKMNT(nmp);
1594                 return (EFBIG);
1595         }
1596         wsize = nmp->nm_wsize;
1597         NFSUNLOCKMNT(nmp);
1598         nd->nd_mrep = NULL;     /* NFSv2 sometimes does a write with */
1599         nd->nd_repstat = 0;     /* uio_resid == 0, so the while is not done */
1600         while (tsiz > 0) {
1601                 *attrflagp = 0;
1602                 len = (tsiz > wsize) ? wsize : tsiz;
1603                 NFSCL_REQSTART(nd, NFSPROC_WRITE, vp);
1604                 if (nd->nd_flag & ND_NFSV4) {
1605                         nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID);
1606                         NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER+2*NFSX_UNSIGNED);
1607                         txdr_hyper(uiop->uio_offset, tl);
1608                         tl += 2;
1609                         *tl++ = txdr_unsigned(*iomode);
1610                         *tl = txdr_unsigned(len);
1611                 } else if (nd->nd_flag & ND_NFSV3) {
1612                         NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER+3*NFSX_UNSIGNED);
1613                         txdr_hyper(uiop->uio_offset, tl);
1614                         tl += 2;
1615                         *tl++ = txdr_unsigned(len);
1616                         *tl++ = txdr_unsigned(*iomode);
1617                         *tl = txdr_unsigned(len);
1618                 } else {
1619                         u_int32_t x;
1620
1621                         NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1622                         /*
1623                          * Not sure why someone changed this, since the
1624                          * RFC clearly states that "beginoffset" and
1625                          * "totalcount" are ignored, but it wouldn't
1626                          * surprise me if there's a busted server out there.
1627                          */
1628                         /* Set both "begin" and "current" to non-garbage. */
1629                         x = txdr_unsigned((u_int32_t)uiop->uio_offset);
1630                         *tl++ = x;      /* "begin offset" */
1631                         *tl++ = x;      /* "current offset" */
1632                         x = txdr_unsigned(len);
1633                         *tl++ = x;      /* total to this offset */
1634                         *tl = x;        /* size of this write */
1635
1636                 }
1637                 nfsm_uiombuf(nd, uiop, len);
1638                 /*
1639                  * Although it is tempting to do a normal Getattr Op in the
1640                  * NFSv4 compound, the result can be a nearly hung client
1641                  * system if the Getattr asks for Owner and/or OwnerGroup.
1642                  * It occurs when the client can't map either the Owner or
1643                  * Owner_group name in the Getattr reply to a uid/gid. When
1644                  * there is a cache miss, the kernel does an upcall to the
1645                  * nfsuserd. Then, it can try and read the local /etc/passwd
1646                  * or /etc/group file. It can then block in getnewbuf(),
1647                  * waiting for dirty writes to be pushed to the NFS server.
1648                  * The only reason this doesn't result in a complete
1649                  * deadlock, is that the upcall times out and allows
1650                  * the write to complete. However, progress is so slow
1651                  * that it might just as well be deadlocked.
1652                  * As such, we get the rest of the attributes, but not
1653                  * Owner or Owner_group.
1654                  * nb: nfscl_loadattrcache() needs to be told that these
1655                  *     partial attributes from a write rpc are being
1656                  *     passed in, via a argument flag.
1657                  */
1658                 if (nd->nd_flag & ND_NFSV4) {
1659                         NFSWRITEGETATTR_ATTRBIT(&attrbits);
1660                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1661                         *tl = txdr_unsigned(NFSV4OP_GETATTR);
1662                         (void) nfsrv_putattrbit(nd, &attrbits);
1663                 }
1664                 error = nfscl_request(nd, vp, p, cred, stuff);
1665                 if (error)
1666                         return (error);
1667                 if (nd->nd_repstat) {
1668                         /*
1669                          * In case the rpc gets retried, roll
1670                          * the uio fileds changed by nfsm_uiombuf()
1671                          * back.
1672                          */
1673                         uiop->uio_offset -= len;
1674                         uio_uio_resid_add(uiop, len);
1675                         uio_iov_base_add(uiop, -len);
1676                         uio_iov_len_add(uiop, len);
1677                 }
1678                 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
1679                         error = nfscl_wcc_data(nd, vp, nap, attrflagp,
1680                             &wccflag, stuff);
1681                         if (error)
1682                                 goto nfsmout;
1683                 }
1684                 if (!nd->nd_repstat) {
1685                         if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
1686                                 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED
1687                                         + NFSX_VERF);
1688                                 rlen = fxdr_unsigned(int, *tl++);
1689                                 if (rlen == 0) {
1690                                         error = NFSERR_IO;
1691                                         goto nfsmout;
1692                                 } else if (rlen < len) {
1693                                         backup = len - rlen;
1694                                         uio_iov_base_add(uiop, -(backup));
1695                                         uio_iov_len_add(uiop, backup);
1696                                         uiop->uio_offset -= backup;
1697                                         uio_uio_resid_add(uiop, backup);
1698                                         len = rlen;
1699                                 }
1700                                 commit = fxdr_unsigned(int, *tl++);
1701
1702                                 /*
1703                                  * Return the lowest committment level
1704                                  * obtained by any of the RPCs.
1705                                  */
1706                                 if (committed == NFSWRITE_FILESYNC)
1707                                         committed = commit;
1708                                 else if (committed == NFSWRITE_DATASYNC &&
1709                                         commit == NFSWRITE_UNSTABLE)
1710                                         committed = commit;
1711                                 NFSLOCKMNT(nmp);
1712                                 if (!NFSHASWRITEVERF(nmp)) {
1713                                         NFSBCOPY((caddr_t)tl,
1714                                             (caddr_t)&nmp->nm_verf[0],
1715                                             NFSX_VERF);
1716                                         NFSSETWRITEVERF(nmp);
1717                                 } else if (NFSBCMP(tl, nmp->nm_verf,
1718                                     NFSX_VERF)) {
1719                                         *must_commit = 1;
1720                                         NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF);
1721                                 }
1722                                 NFSUNLOCKMNT(nmp);
1723                         }
1724                         if (nd->nd_flag & ND_NFSV4)
1725                                 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1726                         if (nd->nd_flag & (ND_NFSV2 | ND_NFSV4)) {
1727                                 error = nfsm_loadattr(nd, nap);
1728                                 if (!error)
1729                                         *attrflagp = NFS_LATTR_NOSHRINK;
1730                         }
1731                 } else {
1732                         error = nd->nd_repstat;
1733                 }
1734                 if (error)
1735                         goto nfsmout;
1736                 NFSWRITERPC_SETTIME(wccflag, np, (nd->nd_flag & ND_NFSV4));
1737                 mbuf_freem(nd->nd_mrep);
1738                 nd->nd_mrep = NULL;
1739                 tsiz -= len;
1740         }
1741 nfsmout:
1742         if (nd->nd_mrep != NULL)
1743                 mbuf_freem(nd->nd_mrep);
1744         *iomode = committed;
1745         if (nd->nd_repstat && !error)
1746                 error = nd->nd_repstat;
1747         return (error);
1748 }
1749
1750 /*
1751  * nfs mknod rpc
1752  * For NFS v2 this is a kludge. Use a create rpc but with the IFMT bits of the
1753  * mode set to specify the file type and the size field for rdev.
1754  */
1755 APPLESTATIC int
1756 nfsrpc_mknod(vnode_t dvp, char *name, int namelen, struct vattr *vap,
1757     u_int32_t rdev, enum vtype vtyp, struct ucred *cred, NFSPROC_T *p,
1758     struct nfsvattr *dnap, struct nfsvattr *nnap, struct nfsfh **nfhpp,
1759     int *attrflagp, int *dattrflagp, void *dstuff)
1760 {
1761         u_int32_t *tl;
1762         int error = 0;
1763         struct nfsrv_descript nfsd, *nd = &nfsd;
1764         nfsattrbit_t attrbits;
1765
1766         *nfhpp = NULL;
1767         *attrflagp = 0;
1768         *dattrflagp = 0;
1769         if (namelen > NFS_MAXNAMLEN)
1770                 return (ENAMETOOLONG);
1771         NFSCL_REQSTART(nd, NFSPROC_MKNOD, dvp);
1772         if (nd->nd_flag & ND_NFSV4) {
1773                 if (vtyp == VBLK || vtyp == VCHR) {
1774                         NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
1775                         *tl++ = vtonfsv34_type(vtyp);
1776                         *tl++ = txdr_unsigned(NFSMAJOR(rdev));
1777                         *tl = txdr_unsigned(NFSMINOR(rdev));
1778                 } else {
1779                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1780                         *tl = vtonfsv34_type(vtyp);
1781                 }
1782         }
1783         (void) nfsm_strtom(nd, name, namelen);
1784         if (nd->nd_flag & ND_NFSV3) {
1785                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1786                 *tl = vtonfsv34_type(vtyp);
1787         }
1788         if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4))
1789                 nfscl_fillsattr(nd, vap, dvp, 0, 0);
1790         if ((nd->nd_flag & ND_NFSV3) &&
1791             (vtyp == VCHR || vtyp == VBLK)) {
1792                 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1793                 *tl++ = txdr_unsigned(NFSMAJOR(rdev));
1794                 *tl = txdr_unsigned(NFSMINOR(rdev));
1795         }
1796         if (nd->nd_flag & ND_NFSV4) {
1797                 NFSGETATTR_ATTRBIT(&attrbits);
1798                 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1799                 *tl++ = txdr_unsigned(NFSV4OP_GETFH);
1800                 *tl = txdr_unsigned(NFSV4OP_GETATTR);
1801                 (void) nfsrv_putattrbit(nd, &attrbits);
1802         }
1803         if (nd->nd_flag & ND_NFSV2)
1804                 nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZERDEV, rdev);
1805         error = nfscl_request(nd, dvp, p, cred, dstuff);
1806         if (error)
1807                 return (error);
1808         if (nd->nd_flag & ND_NFSV4)
1809                 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
1810         if (!nd->nd_repstat) {
1811                 if (nd->nd_flag & ND_NFSV4) {
1812                         NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1813                         error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
1814                         if (error)
1815                                 goto nfsmout;
1816                 }
1817                 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp);
1818                 if (error)
1819                         goto nfsmout;
1820         }
1821         if (nd->nd_flag & ND_NFSV3)
1822                 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
1823         if (!error && nd->nd_repstat)
1824                 error = nd->nd_repstat;
1825 nfsmout:
1826         mbuf_freem(nd->nd_mrep);
1827         return (error);
1828 }
1829
1830 /*
1831  * nfs file create call
1832  * Mostly just call the approriate routine. (I separated out v4, so that
1833  * error recovery wouldn't be as difficult.)
1834  */
1835 APPLESTATIC int
1836 nfsrpc_create(vnode_t dvp, char *name, int namelen, struct vattr *vap,
1837     nfsquad_t cverf, int fmode, struct ucred *cred, NFSPROC_T *p,
1838     struct nfsvattr *dnap, struct nfsvattr *nnap, struct nfsfh **nfhpp,
1839     int *attrflagp, int *dattrflagp, void *dstuff)
1840 {
1841         int error = 0, newone, expireret = 0, retrycnt, unlocked;
1842         struct nfsclowner *owp;
1843         struct nfscldeleg *dp;
1844         struct nfsmount *nmp = VFSTONFS(vnode_mount(dvp));
1845         u_int32_t clidrev;
1846
1847         if (NFSHASNFSV4(nmp)) {
1848             retrycnt = 0;
1849             do {
1850                 dp = NULL;
1851                 error = nfscl_open(dvp, NULL, 0, (NFSV4OPEN_ACCESSWRITE |
1852                     NFSV4OPEN_ACCESSREAD), 0, cred, p, &owp, NULL, &newone,
1853                     NULL, 1);
1854                 if (error)
1855                         return (error);
1856                 if (nmp->nm_clp != NULL)
1857                         clidrev = nmp->nm_clp->nfsc_clientidrev;
1858                 else
1859                         clidrev = 0;
1860                 error = nfsrpc_createv4(dvp, name, namelen, vap, cverf, fmode,
1861                   owp, &dp, cred, p, dnap, nnap, nfhpp, attrflagp, dattrflagp,
1862                   dstuff, &unlocked);
1863                 /*
1864                  * There is no need to invalidate cached attributes here,
1865                  * since new post-delegation issue attributes are always
1866                  * returned by nfsrpc_createv4() and these will update the
1867                  * attribute cache.
1868                  */
1869                 if (dp != NULL)
1870                         (void) nfscl_deleg(nmp->nm_mountp, owp->nfsow_clp,
1871                             (*nfhpp)->nfh_fh, (*nfhpp)->nfh_len, cred, p, &dp);
1872                 nfscl_ownerrelease(owp, error, newone, unlocked);
1873                 if (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID ||
1874                     error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
1875                     error == NFSERR_BADSESSION) {
1876                         (void) nfs_catnap(PZERO, error, "nfs_open");
1877                 } else if ((error == NFSERR_EXPIRED ||
1878                     error == NFSERR_BADSTATEID) && clidrev != 0) {
1879                         expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
1880                         retrycnt++;
1881                 }
1882             } while (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID ||
1883                 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
1884                 error == NFSERR_BADSESSION ||
1885                 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
1886                  expireret == 0 && clidrev != 0 && retrycnt < 4));
1887             if (error && retrycnt >= 4)
1888                     error = EIO;
1889         } else {
1890                 error = nfsrpc_createv23(dvp, name, namelen, vap, cverf,
1891                     fmode, cred, p, dnap, nnap, nfhpp, attrflagp, dattrflagp,
1892                     dstuff);
1893         }
1894         return (error);
1895 }
1896
1897 /*
1898  * The create rpc for v2 and 3.
1899  */
1900 static int
1901 nfsrpc_createv23(vnode_t dvp, char *name, int namelen, struct vattr *vap,
1902     nfsquad_t cverf, int fmode, struct ucred *cred, NFSPROC_T *p,
1903     struct nfsvattr *dnap, struct nfsvattr *nnap, struct nfsfh **nfhpp,
1904     int *attrflagp, int *dattrflagp, void *dstuff)
1905 {
1906         u_int32_t *tl;
1907         int error = 0;
1908         struct nfsrv_descript nfsd, *nd = &nfsd;
1909
1910         *nfhpp = NULL;
1911         *attrflagp = 0;
1912         *dattrflagp = 0;
1913         if (namelen > NFS_MAXNAMLEN)
1914                 return (ENAMETOOLONG);
1915         NFSCL_REQSTART(nd, NFSPROC_CREATE, dvp);
1916         (void) nfsm_strtom(nd, name, namelen);
1917         if (nd->nd_flag & ND_NFSV3) {
1918                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1919                 if (fmode & O_EXCL) {
1920                         *tl = txdr_unsigned(NFSCREATE_EXCLUSIVE);
1921                         NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
1922                         *tl++ = cverf.lval[0];
1923                         *tl = cverf.lval[1];
1924                 } else {
1925                         *tl = txdr_unsigned(NFSCREATE_UNCHECKED);
1926                         nfscl_fillsattr(nd, vap, dvp, 0, 0);
1927                 }
1928         } else {
1929                 nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZE0, 0);
1930         }
1931         error = nfscl_request(nd, dvp, p, cred, dstuff);
1932         if (error)
1933                 return (error);
1934         if (nd->nd_repstat == 0) {
1935                 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp);
1936                 if (error)
1937                         goto nfsmout;
1938         }
1939         if (nd->nd_flag & ND_NFSV3)
1940                 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
1941         if (nd->nd_repstat != 0 && error == 0)
1942                 error = nd->nd_repstat;
1943 nfsmout:
1944         mbuf_freem(nd->nd_mrep);
1945         return (error);
1946 }
1947
1948 static int
1949 nfsrpc_createv4(vnode_t dvp, char *name, int namelen, struct vattr *vap,
1950     nfsquad_t cverf, int fmode, struct nfsclowner *owp, struct nfscldeleg **dpp,
1951     struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap,
1952     struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp,
1953     int *dattrflagp, void *dstuff, int *unlockedp)
1954 {
1955         u_int32_t *tl;
1956         int error = 0, deleg, newone, ret, acesize, limitby;
1957         struct nfsrv_descript nfsd, *nd = &nfsd;
1958         struct nfsclopen *op;
1959         struct nfscldeleg *dp = NULL;
1960         struct nfsnode *np;
1961         struct nfsfh *nfhp;
1962         nfsattrbit_t attrbits;
1963         nfsv4stateid_t stateid;
1964         u_int32_t rflags;
1965         struct nfsmount *nmp;
1966
1967         nmp = VFSTONFS(dvp->v_mount);
1968         np = VTONFS(dvp);
1969         *unlockedp = 0;
1970         *nfhpp = NULL;
1971         *dpp = NULL;
1972         *attrflagp = 0;
1973         *dattrflagp = 0;
1974         if (namelen > NFS_MAXNAMLEN)
1975                 return (ENAMETOOLONG);
1976         NFSCL_REQSTART(nd, NFSPROC_CREATE, dvp);
1977         /*
1978          * For V4, this is actually an Open op.
1979          */
1980         NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1981         *tl++ = txdr_unsigned(owp->nfsow_seqid);
1982         *tl++ = txdr_unsigned(NFSV4OPEN_ACCESSWRITE |
1983             NFSV4OPEN_ACCESSREAD);
1984         *tl++ = txdr_unsigned(NFSV4OPEN_DENYNONE);
1985         *tl++ = NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[0];
1986         *tl = NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[1];
1987         (void) nfsm_strtom(nd, owp->nfsow_owner, NFSV4CL_LOCKNAMELEN);
1988         NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1989         *tl++ = txdr_unsigned(NFSV4OPEN_CREATE);
1990         if (fmode & O_EXCL) {
1991                 if (NFSHASNFSV4N(nmp)) {
1992                         if (NFSHASSESSPERSIST(nmp)) {
1993                                 /* Use GUARDED for persistent sessions. */
1994                                 *tl = txdr_unsigned(NFSCREATE_GUARDED);
1995                                 nfscl_fillsattr(nd, vap, dvp, 0, 0);
1996                         } else {
1997                                 /* Otherwise, use EXCLUSIVE4_1. */
1998                                 *tl = txdr_unsigned(NFSCREATE_EXCLUSIVE41);
1999                                 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
2000                                 *tl++ = cverf.lval[0];
2001                                 *tl = cverf.lval[1];
2002                                 nfscl_fillsattr(nd, vap, dvp, 0, 0);
2003                         }
2004                 } else {
2005                         /* NFSv4.0 */
2006                         *tl = txdr_unsigned(NFSCREATE_EXCLUSIVE);
2007                         NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
2008                         *tl++ = cverf.lval[0];
2009                         *tl = cverf.lval[1];
2010                 }
2011         } else {
2012                 *tl = txdr_unsigned(NFSCREATE_UNCHECKED);
2013                 nfscl_fillsattr(nd, vap, dvp, 0, 0);
2014         }
2015         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2016         *tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL);
2017         (void) nfsm_strtom(nd, name, namelen);
2018         /* Get the new file's handle and attributes. */
2019         NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2020         *tl++ = txdr_unsigned(NFSV4OP_GETFH);
2021         *tl = txdr_unsigned(NFSV4OP_GETATTR);
2022         NFSGETATTR_ATTRBIT(&attrbits);
2023         (void) nfsrv_putattrbit(nd, &attrbits);
2024         /* Get the directory's post-op attributes. */
2025         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2026         *tl = txdr_unsigned(NFSV4OP_PUTFH);
2027         (void) nfsm_fhtom(nd, np->n_fhp->nfh_fh, np->n_fhp->nfh_len, 0);
2028         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2029         *tl = txdr_unsigned(NFSV4OP_GETATTR);
2030         (void) nfsrv_putattrbit(nd, &attrbits);
2031         error = nfscl_request(nd, dvp, p, cred, dstuff);
2032         if (error)
2033                 return (error);
2034         NFSCL_INCRSEQID(owp->nfsow_seqid, nd);
2035         if (nd->nd_repstat == 0) {
2036                 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
2037                     6 * NFSX_UNSIGNED);
2038                 stateid.seqid = *tl++;
2039                 stateid.other[0] = *tl++;
2040                 stateid.other[1] = *tl++;
2041                 stateid.other[2] = *tl;
2042                 rflags = fxdr_unsigned(u_int32_t, *(tl + 6));
2043                 (void) nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
2044                 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2045                 deleg = fxdr_unsigned(int, *tl);
2046                 if (deleg == NFSV4OPEN_DELEGATEREAD ||
2047                     deleg == NFSV4OPEN_DELEGATEWRITE) {
2048                         if (!(owp->nfsow_clp->nfsc_flags &
2049                               NFSCLFLAGS_FIRSTDELEG))
2050                                 owp->nfsow_clp->nfsc_flags |=
2051                                   (NFSCLFLAGS_FIRSTDELEG | NFSCLFLAGS_GOTDELEG);
2052                         MALLOC(dp, struct nfscldeleg *,
2053                             sizeof (struct nfscldeleg) + NFSX_V4FHMAX,
2054                             M_NFSCLDELEG, M_WAITOK);
2055                         LIST_INIT(&dp->nfsdl_owner);
2056                         LIST_INIT(&dp->nfsdl_lock);
2057                         dp->nfsdl_clp = owp->nfsow_clp;
2058                         newnfs_copyincred(cred, &dp->nfsdl_cred);
2059                         nfscl_lockinit(&dp->nfsdl_rwlock);
2060                         NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
2061                             NFSX_UNSIGNED);
2062                         dp->nfsdl_stateid.seqid = *tl++;
2063                         dp->nfsdl_stateid.other[0] = *tl++;
2064                         dp->nfsdl_stateid.other[1] = *tl++;
2065                         dp->nfsdl_stateid.other[2] = *tl++;
2066                         ret = fxdr_unsigned(int, *tl);
2067                         if (deleg == NFSV4OPEN_DELEGATEWRITE) {
2068                                 dp->nfsdl_flags = NFSCLDL_WRITE;
2069                                 /*
2070                                  * Indicates how much the file can grow.
2071                                  */
2072                                 NFSM_DISSECT(tl, u_int32_t *,
2073                                     3 * NFSX_UNSIGNED);
2074                                 limitby = fxdr_unsigned(int, *tl++);
2075                                 switch (limitby) {
2076                                 case NFSV4OPEN_LIMITSIZE:
2077                                         dp->nfsdl_sizelimit = fxdr_hyper(tl);
2078                                         break;
2079                                 case NFSV4OPEN_LIMITBLOCKS:
2080                                         dp->nfsdl_sizelimit =
2081                                             fxdr_unsigned(u_int64_t, *tl++);
2082                                         dp->nfsdl_sizelimit *=
2083                                             fxdr_unsigned(u_int64_t, *tl);
2084                                         break;
2085                                 default:
2086                                         error = NFSERR_BADXDR;
2087                                         goto nfsmout;
2088                                 };
2089                         } else {
2090                                 dp->nfsdl_flags = NFSCLDL_READ;
2091                         }
2092                         if (ret)
2093                                 dp->nfsdl_flags |= NFSCLDL_RECALL;
2094                         error = nfsrv_dissectace(nd, &dp->nfsdl_ace, &ret,
2095                             &acesize, p);
2096                         if (error)
2097                                 goto nfsmout;
2098                 } else if (deleg != NFSV4OPEN_DELEGATENONE) {
2099                         error = NFSERR_BADXDR;
2100                         goto nfsmout;
2101                 }
2102                 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp);
2103                 if (error)
2104                         goto nfsmout;
2105                 /* Get rid of the PutFH and Getattr status values. */
2106                 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
2107                 /* Load the directory attributes. */
2108                 error = nfsm_loadattr(nd, dnap);
2109                 if (error)
2110                         goto nfsmout;
2111                 *dattrflagp = 1;
2112                 if (dp != NULL && *attrflagp) {
2113                         dp->nfsdl_change = nnap->na_filerev;
2114                         dp->nfsdl_modtime = nnap->na_mtime;
2115                         dp->nfsdl_flags |= NFSCLDL_MODTIMESET;
2116                 }
2117                 /*
2118                  * We can now complete the Open state.
2119                  */
2120                 nfhp = *nfhpp;
2121                 if (dp != NULL) {
2122                         dp->nfsdl_fhlen = nfhp->nfh_len;
2123                         NFSBCOPY(nfhp->nfh_fh, dp->nfsdl_fh, nfhp->nfh_len);
2124                 }
2125                 /*
2126                  * Get an Open structure that will be
2127                  * attached to the OpenOwner, acquired already.
2128                  */
2129                 error = nfscl_open(dvp, nfhp->nfh_fh, nfhp->nfh_len, 
2130                     (NFSV4OPEN_ACCESSWRITE | NFSV4OPEN_ACCESSREAD), 0,
2131                     cred, p, NULL, &op, &newone, NULL, 0);
2132                 if (error)
2133                         goto nfsmout;
2134                 op->nfso_stateid = stateid;
2135                 newnfs_copyincred(cred, &op->nfso_cred);
2136                 if ((rflags & NFSV4OPEN_RESULTCONFIRM)) {
2137                     do {
2138                         ret = nfsrpc_openconfirm(dvp, nfhp->nfh_fh,
2139                             nfhp->nfh_len, op, cred, p);
2140                         if (ret == NFSERR_DELAY)
2141                             (void) nfs_catnap(PZERO, ret, "nfs_create");
2142                     } while (ret == NFSERR_DELAY);
2143                     error = ret;
2144                 }
2145
2146                 /*
2147                  * If the server is handing out delegations, but we didn't
2148                  * get one because an OpenConfirm was required, try the
2149                  * Open again, to get a delegation. This is a harmless no-op,
2150                  * from a server's point of view.
2151                  */
2152                 if ((rflags & NFSV4OPEN_RESULTCONFIRM) &&
2153                     (owp->nfsow_clp->nfsc_flags & NFSCLFLAGS_GOTDELEG) &&
2154                     !error && dp == NULL) {
2155                     do {
2156                         ret = nfsrpc_openrpc(VFSTONFS(vnode_mount(dvp)), dvp,
2157                             np->n_fhp->nfh_fh, np->n_fhp->nfh_len,
2158                             nfhp->nfh_fh, nfhp->nfh_len,
2159                             (NFSV4OPEN_ACCESSWRITE | NFSV4OPEN_ACCESSREAD), op,
2160                             name, namelen, &dp, 0, 0x0, cred, p, 0, 1);
2161                         if (ret == NFSERR_DELAY)
2162                             (void) nfs_catnap(PZERO, ret, "nfs_crt2");
2163                     } while (ret == NFSERR_DELAY);
2164                     if (ret) {
2165                         if (dp != NULL) {
2166                                 FREE((caddr_t)dp, M_NFSCLDELEG);
2167                                 dp = NULL;
2168                         }
2169                         if (ret == NFSERR_STALECLIENTID ||
2170                             ret == NFSERR_STALEDONTRECOVER ||
2171                             ret == NFSERR_BADSESSION)
2172                                 error = ret;
2173                     }
2174                 }
2175                 nfscl_openrelease(op, error, newone);
2176                 *unlockedp = 1;
2177         }
2178         if (nd->nd_repstat != 0 && error == 0)
2179                 error = nd->nd_repstat;
2180         if (error == NFSERR_STALECLIENTID || error == NFSERR_BADSESSION)
2181                 nfscl_initiate_recovery(owp->nfsow_clp);
2182 nfsmout:
2183         if (!error)
2184                 *dpp = dp;
2185         else if (dp != NULL)
2186                 FREE((caddr_t)dp, M_NFSCLDELEG);
2187         mbuf_freem(nd->nd_mrep);
2188         return (error);
2189 }
2190
2191 /*
2192  * Nfs remove rpc
2193  */
2194 APPLESTATIC int
2195 nfsrpc_remove(vnode_t dvp, char *name, int namelen, vnode_t vp,
2196     struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, int *dattrflagp,
2197     void *dstuff)
2198 {
2199         u_int32_t *tl;
2200         struct nfsrv_descript nfsd, *nd = &nfsd;
2201         struct nfsnode *np;
2202         struct nfsmount *nmp;
2203         nfsv4stateid_t dstateid;
2204         int error, ret = 0, i;
2205
2206         *dattrflagp = 0;
2207         if (namelen > NFS_MAXNAMLEN)
2208                 return (ENAMETOOLONG);
2209         nmp = VFSTONFS(vnode_mount(dvp));
2210 tryagain:
2211         if (NFSHASNFSV4(nmp) && ret == 0) {
2212                 ret = nfscl_removedeleg(vp, p, &dstateid);
2213                 if (ret == 1) {
2214                         NFSCL_REQSTART(nd, NFSPROC_RETDELEGREMOVE, vp);
2215                         NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID +
2216                             NFSX_UNSIGNED);
2217                         if (NFSHASNFSV4N(nmp))
2218                                 *tl++ = 0;
2219                         else
2220                                 *tl++ = dstateid.seqid;
2221                         *tl++ = dstateid.other[0];
2222                         *tl++ = dstateid.other[1];
2223                         *tl++ = dstateid.other[2];
2224                         *tl = txdr_unsigned(NFSV4OP_PUTFH);
2225                         np = VTONFS(dvp);
2226                         (void) nfsm_fhtom(nd, np->n_fhp->nfh_fh,
2227                             np->n_fhp->nfh_len, 0);
2228                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2229                         *tl = txdr_unsigned(NFSV4OP_REMOVE);
2230                 }
2231         } else {
2232                 ret = 0;
2233         }
2234         if (ret == 0)
2235                 NFSCL_REQSTART(nd, NFSPROC_REMOVE, dvp);
2236         (void) nfsm_strtom(nd, name, namelen);
2237         error = nfscl_request(nd, dvp, p, cred, dstuff);
2238         if (error)
2239                 return (error);
2240         if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
2241                 /* For NFSv4, parse out any Delereturn replies. */
2242                 if (ret > 0 && nd->nd_repstat != 0 &&
2243                     (nd->nd_flag & ND_NOMOREDATA)) {
2244                         /*
2245                          * If the Delegreturn failed, try again without
2246                          * it. The server will Recall, as required.
2247                          */
2248                         mbuf_freem(nd->nd_mrep);
2249                         goto tryagain;
2250                 }
2251                 for (i = 0; i < (ret * 2); i++) {
2252                         if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) ==
2253                             ND_NFSV4) {
2254                             NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2255                             if (*(tl + 1))
2256                                 nd->nd_flag |= ND_NOMOREDATA;
2257                         }
2258                 }
2259                 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
2260         }
2261         if (nd->nd_repstat && !error)
2262                 error = nd->nd_repstat;
2263 nfsmout:
2264         mbuf_freem(nd->nd_mrep);
2265         return (error);
2266 }
2267
2268 /*
2269  * Do an nfs rename rpc.
2270  */
2271 APPLESTATIC int
2272 nfsrpc_rename(vnode_t fdvp, vnode_t fvp, char *fnameptr, int fnamelen,
2273     vnode_t tdvp, vnode_t tvp, char *tnameptr, int tnamelen, struct ucred *cred,
2274     NFSPROC_T *p, struct nfsvattr *fnap, struct nfsvattr *tnap,
2275     int *fattrflagp, int *tattrflagp, void *fstuff, void *tstuff)
2276 {
2277         u_int32_t *tl;
2278         struct nfsrv_descript nfsd, *nd = &nfsd;
2279         struct nfsmount *nmp;
2280         struct nfsnode *np;
2281         nfsattrbit_t attrbits;
2282         nfsv4stateid_t fdstateid, tdstateid;
2283         int error = 0, ret = 0, gottd = 0, gotfd = 0, i;
2284         
2285         *fattrflagp = 0;
2286         *tattrflagp = 0;
2287         nmp = VFSTONFS(vnode_mount(fdvp));
2288         if (fnamelen > NFS_MAXNAMLEN || tnamelen > NFS_MAXNAMLEN)
2289                 return (ENAMETOOLONG);
2290 tryagain:
2291         if (NFSHASNFSV4(nmp) && ret == 0) {
2292                 ret = nfscl_renamedeleg(fvp, &fdstateid, &gotfd, tvp,
2293                     &tdstateid, &gottd, p);
2294                 if (gotfd && gottd) {
2295                         NFSCL_REQSTART(nd, NFSPROC_RETDELEGRENAME2, fvp);
2296                 } else if (gotfd) {
2297                         NFSCL_REQSTART(nd, NFSPROC_RETDELEGRENAME1, fvp);
2298                 } else if (gottd) {
2299                         NFSCL_REQSTART(nd, NFSPROC_RETDELEGRENAME1, tvp);
2300                 }
2301                 if (gotfd) {
2302                         NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2303                         if (NFSHASNFSV4N(nmp))
2304                                 *tl++ = 0;
2305                         else
2306                                 *tl++ = fdstateid.seqid;
2307                         *tl++ = fdstateid.other[0];
2308                         *tl++ = fdstateid.other[1];
2309                         *tl = fdstateid.other[2];
2310                         if (gottd) {
2311                                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2312                                 *tl = txdr_unsigned(NFSV4OP_PUTFH);
2313                                 np = VTONFS(tvp);
2314                                 (void) nfsm_fhtom(nd, np->n_fhp->nfh_fh,
2315                                     np->n_fhp->nfh_len, 0);
2316                                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2317                                 *tl = txdr_unsigned(NFSV4OP_DELEGRETURN);
2318                         }
2319                 }
2320                 if (gottd) {
2321                         NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2322                         if (NFSHASNFSV4N(nmp))
2323                                 *tl++ = 0;
2324                         else
2325                                 *tl++ = tdstateid.seqid;
2326                         *tl++ = tdstateid.other[0];
2327                         *tl++ = tdstateid.other[1];
2328                         *tl = tdstateid.other[2];
2329                 }
2330                 if (ret > 0) {
2331                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2332                         *tl = txdr_unsigned(NFSV4OP_PUTFH);
2333                         np = VTONFS(fdvp);
2334                         (void) nfsm_fhtom(nd, np->n_fhp->nfh_fh,
2335                             np->n_fhp->nfh_len, 0);
2336                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2337                         *tl = txdr_unsigned(NFSV4OP_SAVEFH);
2338                 }
2339         } else {
2340                 ret = 0;
2341         }
2342         if (ret == 0)
2343                 NFSCL_REQSTART(nd, NFSPROC_RENAME, fdvp);
2344         if (nd->nd_flag & ND_NFSV4) {
2345                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2346                 *tl = txdr_unsigned(NFSV4OP_GETATTR);
2347                 NFSWCCATTR_ATTRBIT(&attrbits);
2348                 (void) nfsrv_putattrbit(nd, &attrbits);
2349                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2350                 *tl = txdr_unsigned(NFSV4OP_PUTFH);
2351                 (void) nfsm_fhtom(nd, VTONFS(tdvp)->n_fhp->nfh_fh,
2352                     VTONFS(tdvp)->n_fhp->nfh_len, 0);
2353                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2354                 *tl = txdr_unsigned(NFSV4OP_GETATTR);
2355                 (void) nfsrv_putattrbit(nd, &attrbits);
2356                 nd->nd_flag |= ND_V4WCCATTR;
2357                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2358                 *tl = txdr_unsigned(NFSV4OP_RENAME);
2359         }
2360         (void) nfsm_strtom(nd, fnameptr, fnamelen);
2361         if (!(nd->nd_flag & ND_NFSV4))
2362                 (void) nfsm_fhtom(nd, VTONFS(tdvp)->n_fhp->nfh_fh,
2363                         VTONFS(tdvp)->n_fhp->nfh_len, 0);
2364         (void) nfsm_strtom(nd, tnameptr, tnamelen);
2365         error = nfscl_request(nd, fdvp, p, cred, fstuff);
2366         if (error)
2367                 return (error);
2368         if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
2369                 /* For NFSv4, parse out any Delereturn replies. */
2370                 if (ret > 0 && nd->nd_repstat != 0 &&
2371                     (nd->nd_flag & ND_NOMOREDATA)) {
2372                         /*
2373                          * If the Delegreturn failed, try again without
2374                          * it. The server will Recall, as required.
2375                          */
2376                         mbuf_freem(nd->nd_mrep);
2377                         goto tryagain;
2378                 }
2379                 for (i = 0; i < (ret * 2); i++) {
2380                         if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) ==
2381                             ND_NFSV4) {
2382                             NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2383                             if (*(tl + 1)) {
2384                                 if (i == 0 && ret > 1) {
2385                                     /*
2386                                      * If the Delegreturn failed, try again
2387                                      * without it. The server will Recall, as
2388                                      * required.
2389                                      * If ret > 1, the first iteration of this
2390                                      * loop is the second DelegReturn result.
2391                                      */
2392                                     mbuf_freem(nd->nd_mrep);
2393                                     goto tryagain;
2394                                 } else {
2395                                     nd->nd_flag |= ND_NOMOREDATA;
2396                                 }
2397                             }
2398                         }
2399                 }
2400                 /* Now, the first wcc attribute reply. */
2401                 if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4) {
2402                         NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2403                         if (*(tl + 1))
2404                                 nd->nd_flag |= ND_NOMOREDATA;
2405                 }
2406                 error = nfscl_wcc_data(nd, fdvp, fnap, fattrflagp, NULL,
2407                     fstuff);
2408                 /* and the second wcc attribute reply. */
2409                 if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4 &&
2410                     !error) {
2411                         NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2412                         if (*(tl + 1))
2413                                 nd->nd_flag |= ND_NOMOREDATA;
2414                 }
2415                 if (!error)
2416                         error = nfscl_wcc_data(nd, tdvp, tnap, tattrflagp,
2417                             NULL, tstuff);
2418         }
2419         if (nd->nd_repstat && !error)
2420                 error = nd->nd_repstat;
2421 nfsmout:
2422         mbuf_freem(nd->nd_mrep);
2423         return (error);
2424 }
2425
2426 /*
2427  * nfs hard link create rpc
2428  */
2429 APPLESTATIC int
2430 nfsrpc_link(vnode_t dvp, vnode_t vp, char *name, int namelen,
2431     struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap,
2432     struct nfsvattr *nap, int *attrflagp, int *dattrflagp, void *dstuff)
2433 {
2434         u_int32_t *tl;
2435         struct nfsrv_descript nfsd, *nd = &nfsd;
2436         nfsattrbit_t attrbits;
2437         int error = 0;
2438
2439         *attrflagp = 0;
2440         *dattrflagp = 0;
2441         if (namelen > NFS_MAXNAMLEN)
2442                 return (ENAMETOOLONG);
2443         NFSCL_REQSTART(nd, NFSPROC_LINK, vp);
2444         if (nd->nd_flag & ND_NFSV4) {
2445                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2446                 *tl = txdr_unsigned(NFSV4OP_PUTFH);
2447         }
2448         (void) nfsm_fhtom(nd, VTONFS(dvp)->n_fhp->nfh_fh,
2449                 VTONFS(dvp)->n_fhp->nfh_len, 0);
2450         if (nd->nd_flag & ND_NFSV4) {
2451                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2452                 *tl = txdr_unsigned(NFSV4OP_GETATTR);
2453                 NFSWCCATTR_ATTRBIT(&attrbits);
2454                 (void) nfsrv_putattrbit(nd, &attrbits);
2455                 nd->nd_flag |= ND_V4WCCATTR;
2456                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2457                 *tl = txdr_unsigned(NFSV4OP_LINK);
2458         }
2459         (void) nfsm_strtom(nd, name, namelen);
2460         error = nfscl_request(nd, vp, p, cred, dstuff);
2461         if (error)
2462                 return (error);
2463         if (nd->nd_flag & ND_NFSV3) {
2464                 error = nfscl_postop_attr(nd, nap, attrflagp, dstuff);
2465                 if (!error)
2466                         error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp,
2467                             NULL, dstuff);
2468         } else if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4) {
2469                 /*
2470                  * First, parse out the PutFH and Getattr result.
2471                  */
2472                 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2473                 if (!(*(tl + 1)))
2474                         NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2475                 if (*(tl + 1))
2476                         nd->nd_flag |= ND_NOMOREDATA;
2477                 /*
2478                  * Get the pre-op attributes.
2479                  */
2480                 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
2481         }
2482         if (nd->nd_repstat && !error)
2483                 error = nd->nd_repstat;
2484 nfsmout:
2485         mbuf_freem(nd->nd_mrep);
2486         return (error);
2487 }
2488
2489 /*
2490  * nfs symbolic link create rpc
2491  */
2492 APPLESTATIC int
2493 nfsrpc_symlink(vnode_t dvp, char *name, int namelen, char *target,
2494     struct vattr *vap, struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap,
2495     struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp,
2496     int *dattrflagp, void *dstuff)
2497 {
2498         u_int32_t *tl;
2499         struct nfsrv_descript nfsd, *nd = &nfsd;
2500         struct nfsmount *nmp;
2501         int slen, error = 0;
2502
2503         *nfhpp = NULL;
2504         *attrflagp = 0;
2505         *dattrflagp = 0;
2506         nmp = VFSTONFS(vnode_mount(dvp));
2507         slen = strlen(target);
2508         if (slen > NFS_MAXPATHLEN || namelen > NFS_MAXNAMLEN)
2509                 return (ENAMETOOLONG);
2510         NFSCL_REQSTART(nd, NFSPROC_SYMLINK, dvp);
2511         if (nd->nd_flag & ND_NFSV4) {
2512                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2513                 *tl = txdr_unsigned(NFLNK);
2514                 (void) nfsm_strtom(nd, target, slen);
2515         }
2516         (void) nfsm_strtom(nd, name, namelen);
2517         if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4))
2518                 nfscl_fillsattr(nd, vap, dvp, 0, 0);
2519         if (!(nd->nd_flag & ND_NFSV4))
2520                 (void) nfsm_strtom(nd, target, slen);
2521         if (nd->nd_flag & ND_NFSV2)
2522                 nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZENEG1, 0);
2523         error = nfscl_request(nd, dvp, p, cred, dstuff);
2524         if (error)
2525                 return (error);
2526         if (nd->nd_flag & ND_NFSV4)
2527                 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
2528         if ((nd->nd_flag & ND_NFSV3) && !error) {
2529                 if (!nd->nd_repstat)
2530                         error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp);
2531                 if (!error)
2532                         error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp,
2533                             NULL, dstuff);
2534         }
2535         if (nd->nd_repstat && !error)
2536                 error = nd->nd_repstat;
2537         mbuf_freem(nd->nd_mrep);
2538         /*
2539          * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
2540          * Only do this if vfs.nfs.ignore_eexist is set.
2541          * Never do this for NFSv4.1 or later minor versions, since sessions
2542          * should guarantee "exactly once" RPC semantics.
2543          */
2544         if (error == EEXIST && nfsignore_eexist != 0 && (!NFSHASNFSV4(nmp) ||
2545             nmp->nm_minorvers == 0))
2546                 error = 0;
2547         return (error);
2548 }
2549
2550 /*
2551  * nfs make dir rpc
2552  */
2553 APPLESTATIC int
2554 nfsrpc_mkdir(vnode_t dvp, char *name, int namelen, struct vattr *vap,
2555     struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap,
2556     struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp,
2557     int *dattrflagp, void *dstuff)
2558 {
2559         u_int32_t *tl;
2560         struct nfsrv_descript nfsd, *nd = &nfsd;
2561         nfsattrbit_t attrbits;
2562         int error = 0;
2563         struct nfsfh *fhp;
2564         struct nfsmount *nmp;
2565
2566         *nfhpp = NULL;
2567         *attrflagp = 0;
2568         *dattrflagp = 0;
2569         nmp = VFSTONFS(vnode_mount(dvp));
2570         fhp = VTONFS(dvp)->n_fhp;
2571         if (namelen > NFS_MAXNAMLEN)
2572                 return (ENAMETOOLONG);
2573         NFSCL_REQSTART(nd, NFSPROC_MKDIR, dvp);
2574         if (nd->nd_flag & ND_NFSV4) {
2575                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2576                 *tl = txdr_unsigned(NFDIR);
2577         }
2578         (void) nfsm_strtom(nd, name, namelen);
2579         nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZENEG1, 0);
2580         if (nd->nd_flag & ND_NFSV4) {
2581                 NFSGETATTR_ATTRBIT(&attrbits);
2582                 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2583                 *tl++ = txdr_unsigned(NFSV4OP_GETFH);
2584                 *tl = txdr_unsigned(NFSV4OP_GETATTR);
2585                 (void) nfsrv_putattrbit(nd, &attrbits);
2586                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2587                 *tl = txdr_unsigned(NFSV4OP_PUTFH);
2588                 (void) nfsm_fhtom(nd, fhp->nfh_fh, fhp->nfh_len, 0);
2589                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2590                 *tl = txdr_unsigned(NFSV4OP_GETATTR);
2591                 (void) nfsrv_putattrbit(nd, &attrbits);
2592         }
2593         error = nfscl_request(nd, dvp, p, cred, dstuff);
2594         if (error)
2595                 return (error);
2596         if (nd->nd_flag & ND_NFSV4)
2597                 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
2598         if (!nd->nd_repstat && !error) {
2599                 if (nd->nd_flag & ND_NFSV4) {
2600                         NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
2601                         error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
2602                 }
2603                 if (!error)
2604                         error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp);
2605                 if (error == 0 && (nd->nd_flag & ND_NFSV4) != 0) {
2606                         /* Get rid of the PutFH and Getattr status values. */
2607                         NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
2608                         /* Load the directory attributes. */
2609                         error = nfsm_loadattr(nd, dnap);
2610                         if (error == 0)
2611                                 *dattrflagp = 1;
2612                 }
2613         }
2614         if ((nd->nd_flag & ND_NFSV3) && !error)
2615                 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
2616         if (nd->nd_repstat && !error)
2617                 error = nd->nd_repstat;
2618 nfsmout:
2619         mbuf_freem(nd->nd_mrep);
2620         /*
2621          * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
2622          * Only do this if vfs.nfs.ignore_eexist is set.
2623          * Never do this for NFSv4.1 or later minor versions, since sessions
2624          * should guarantee "exactly once" RPC semantics.
2625          */
2626         if (error == EEXIST && nfsignore_eexist != 0 && (!NFSHASNFSV4(nmp) ||
2627             nmp->nm_minorvers == 0))
2628                 error = 0;
2629         return (error);
2630 }
2631
2632 /*
2633  * nfs remove directory call
2634  */
2635 APPLESTATIC int
2636 nfsrpc_rmdir(vnode_t dvp, char *name, int namelen, struct ucred *cred,
2637     NFSPROC_T *p, struct nfsvattr *dnap, int *dattrflagp, void *dstuff)
2638 {
2639         struct nfsrv_descript nfsd, *nd = &nfsd;
2640         int error = 0;
2641
2642         *dattrflagp = 0;
2643         if (namelen > NFS_MAXNAMLEN)
2644                 return (ENAMETOOLONG);
2645         NFSCL_REQSTART(nd, NFSPROC_RMDIR, dvp);
2646         (void) nfsm_strtom(nd, name, namelen);
2647         error = nfscl_request(nd, dvp, p, cred, dstuff);
2648         if (error)
2649                 return (error);
2650         if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4))
2651                 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
2652         if (nd->nd_repstat && !error)
2653                 error = nd->nd_repstat;
2654         mbuf_freem(nd->nd_mrep);
2655         /*
2656          * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry.
2657          */
2658         if (error == ENOENT)
2659                 error = 0;
2660         return (error);
2661 }
2662
2663 /*
2664  * Readdir rpc.
2665  * Always returns with either uio_resid unchanged, if you are at the
2666  * end of the directory, or uio_resid == 0, with all DIRBLKSIZ chunks
2667  * filled in.
2668  * I felt this would allow caching of directory blocks more easily
2669  * than returning a pertially filled block.
2670  * Directory offset cookies:
2671  * Oh my, what to do with them...
2672  * I can think of three ways to deal with them:
2673  * 1 - have the layer above these RPCs maintain a map between logical
2674  *     directory byte offsets and the NFS directory offset cookies
2675  * 2 - pass the opaque directory offset cookies up into userland
2676  *     and let the libc functions deal with them, via the system call
2677  * 3 - return them to userland in the "struct dirent", so future versions
2678  *     of libc can use them and do whatever is necessary to amke things work
2679  *     above these rpc calls, in the meantime
2680  * For now, I do #3 by "hiding" the directory offset cookies after the
2681  * d_name field in struct dirent. This is space inside d_reclen that
2682  * will be ignored by anything that doesn't know about them.
2683  * The directory offset cookies are filled in as the last 8 bytes of
2684  * each directory entry, after d_name. Someday, the userland libc
2685  * functions may be able to use these. In the meantime, it satisfies
2686  * OpenBSD's requirements for cookies being returned.
2687  * If expects the directory offset cookie for the read to be in uio_offset
2688  * and returns the one for the next entry after this directory block in
2689  * there, as well.
2690  */
2691 APPLESTATIC int
2692 nfsrpc_readdir(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep,
2693     struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp,
2694     int *eofp, void *stuff)
2695 {
2696         int len, left;
2697         struct dirent *dp = NULL;
2698         u_int32_t *tl;
2699         nfsquad_t cookie, ncookie;
2700         struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
2701         struct nfsnode *dnp = VTONFS(vp);
2702         struct nfsvattr nfsva;
2703         struct nfsrv_descript nfsd, *nd = &nfsd;
2704         int error = 0, tlen, more_dirs = 1, blksiz = 0, bigenough = 1;
2705         int reqsize, tryformoredirs = 1, readsize, eof = 0, gotmnton = 0;
2706         long dotfileid, dotdotfileid = 0;
2707         u_int32_t fakefileno = 0xffffffff, rderr;
2708         char *cp;
2709         nfsattrbit_t attrbits, dattrbits;
2710         u_int32_t *tl2 = NULL;
2711         size_t tresid;
2712
2713         KASSERT(uiop->uio_iovcnt == 1 &&
2714             (uio_uio_resid(uiop) & (DIRBLKSIZ - 1)) == 0,
2715             ("nfs readdirrpc bad uio"));
2716
2717         /*
2718          * There is no point in reading a lot more than uio_resid, however
2719          * adding one additional DIRBLKSIZ makes sense. Since uio_resid
2720          * and nm_readdirsize are both exact multiples of DIRBLKSIZ, this
2721          * will never make readsize > nm_readdirsize.
2722          */
2723         readsize = nmp->nm_readdirsize;
2724         if (readsize > uio_uio_resid(uiop))
2725                 readsize = uio_uio_resid(uiop) + DIRBLKSIZ;
2726
2727         *attrflagp = 0;
2728         if (eofp)
2729                 *eofp = 0;
2730         tresid = uio_uio_resid(uiop);
2731         cookie.lval[0] = cookiep->nfsuquad[0];
2732         cookie.lval[1] = cookiep->nfsuquad[1];
2733         nd->nd_mrep = NULL;
2734
2735         /*
2736          * For NFSv4, first create the "." and ".." entries.
2737          */
2738         if (NFSHASNFSV4(nmp)) {
2739                 reqsize = 6 * NFSX_UNSIGNED;
2740                 NFSGETATTR_ATTRBIT(&dattrbits);
2741                 NFSZERO_ATTRBIT(&attrbits);
2742                 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FILEID);
2743                 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TYPE);
2744                 if (NFSISSET_ATTRBIT(&dnp->n_vattr.na_suppattr,
2745                     NFSATTRBIT_MOUNTEDONFILEID)) {
2746                         NFSSETBIT_ATTRBIT(&attrbits,
2747                             NFSATTRBIT_MOUNTEDONFILEID);
2748                         gotmnton = 1;
2749                 } else {
2750                         /*
2751                          * Must fake it. Use the fileno, except when the
2752                          * fsid is != to that of the directory. For that
2753                          * case, generate a fake fileno that is not the same.
2754                          */
2755                         NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FSID);
2756                         gotmnton = 0;
2757                 }
2758
2759                 /*
2760                  * Joy, oh joy. For V4 we get to hand craft '.' and '..'.
2761                  */
2762                 if (uiop->uio_offset == 0) {
2763                         NFSCL_REQSTART(nd, NFSPROC_LOOKUPP, vp);
2764                         NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2765                         *tl++ = txdr_unsigned(NFSV4OP_GETFH);
2766                         *tl = txdr_unsigned(NFSV4OP_GETATTR);
2767                         (void) nfsrv_putattrbit(nd, &attrbits);
2768                         error = nfscl_request(nd, vp, p, cred, stuff);
2769                         if (error)
2770                             return (error);
2771                         dotfileid = 0;  /* Fake out the compiler. */
2772                         if ((nd->nd_flag & ND_NOMOREDATA) == 0) {
2773                             error = nfsm_loadattr(nd, &nfsva);
2774                             if (error != 0)
2775                                 goto nfsmout;
2776                             dotfileid = nfsva.na_fileid;
2777                         }
2778                         if (nd->nd_repstat == 0) {
2779                             NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
2780                             len = fxdr_unsigned(int, *(tl + 4));
2781                             if (len > 0 && len <= NFSX_V4FHMAX)
2782                                 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
2783                             else
2784                                 error = EPERM;
2785                             if (!error) {
2786                                 NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED);
2787                                 nfsva.na_mntonfileno = 0xffffffff;
2788                                 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL,
2789                                     NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
2790                                     NULL, NULL, NULL, p, cred);
2791                                 if (error) {
2792                                     dotdotfileid = dotfileid;
2793                                 } else if (gotmnton) {
2794                                     if (nfsva.na_mntonfileno != 0xffffffff)
2795                                         dotdotfileid = nfsva.na_mntonfileno;
2796                                     else
2797                                         dotdotfileid = nfsva.na_fileid;
2798                                 } else if (nfsva.na_filesid[0] ==
2799                                     dnp->n_vattr.na_filesid[0] &&
2800                                     nfsva.na_filesid[1] ==
2801                                     dnp->n_vattr.na_filesid[1]) {
2802                                     dotdotfileid = nfsva.na_fileid;
2803                                 } else {
2804                                     do {
2805                                         fakefileno--;
2806                                     } while (fakefileno ==
2807                                         nfsva.na_fileid);
2808                                     dotdotfileid = fakefileno;
2809                                 }
2810                             }
2811                         } else if (nd->nd_repstat == NFSERR_NOENT) {
2812                             /*
2813                              * Lookupp returns NFSERR_NOENT when we are
2814                              * at the root, so just use the current dir.
2815                              */
2816                             nd->nd_repstat = 0;
2817                             dotdotfileid = dotfileid;
2818                         } else {
2819                             error = nd->nd_repstat;
2820                         }
2821                         mbuf_freem(nd->nd_mrep);
2822                         if (error)
2823                             return (error);
2824                         nd->nd_mrep = NULL;
2825                         dp = (struct dirent *) CAST_DOWN(caddr_t, uio_iov_base(uiop));
2826                         dp->d_type = DT_DIR;
2827                         dp->d_fileno = dotfileid;
2828                         dp->d_namlen = 1;
2829                         dp->d_name[0] = '.';
2830                         dp->d_name[1] = '\0';
2831                         dp->d_reclen = DIRENT_SIZE(dp) + NFSX_HYPER;
2832                         /*
2833                          * Just make these offset cookie 0.
2834                          */
2835                         tl = (u_int32_t *)&dp->d_name[4];
2836                         *tl++ = 0;
2837                         *tl = 0;
2838                         blksiz += dp->d_reclen;
2839                         uio_uio_resid_add(uiop, -(dp->d_reclen));
2840                         uiop->uio_offset += dp->d_reclen;
2841                         uio_iov_base_add(uiop, dp->d_reclen);
2842                         uio_iov_len_add(uiop, -(dp->d_reclen));
2843                         dp = (struct dirent *) CAST_DOWN(caddr_t, uio_iov_base(uiop));
2844                         dp->d_type = DT_DIR;
2845                         dp->d_fileno = dotdotfileid;
2846                         dp->d_namlen = 2;
2847                         dp->d_name[0] = '.';
2848                         dp->d_name[1] = '.';
2849                         dp->d_name[2] = '\0';
2850                         dp->d_reclen = DIRENT_SIZE(dp) + NFSX_HYPER;
2851                         /*
2852                          * Just make these offset cookie 0.
2853                          */
2854                         tl = (u_int32_t *)&dp->d_name[4];
2855                         *tl++ = 0;
2856                         *tl = 0;
2857                         blksiz += dp->d_reclen;
2858                         uio_uio_resid_add(uiop, -(dp->d_reclen));
2859                         uiop->uio_offset += dp->d_reclen;
2860                         uio_iov_base_add(uiop, dp->d_reclen);
2861                         uio_iov_len_add(uiop, -(dp->d_reclen));
2862                 }
2863                 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_RDATTRERROR);
2864         } else {
2865                 reqsize = 5 * NFSX_UNSIGNED;
2866         }
2867
2868
2869         /*
2870          * Loop around doing readdir rpc's of size readsize.
2871          * The stopping criteria is EOF or buffer full.
2872          */
2873         while (more_dirs && bigenough) {
2874                 *attrflagp = 0;
2875                 NFSCL_REQSTART(nd, NFSPROC_READDIR, vp);
2876                 if (nd->nd_flag & ND_NFSV2) {
2877                         NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2878                         *tl++ = cookie.lval[1];
2879                         *tl = txdr_unsigned(readsize);
2880                 } else {
2881                         NFSM_BUILD(tl, u_int32_t *, reqsize);
2882                         *tl++ = cookie.lval[0];
2883                         *tl++ = cookie.lval[1];
2884                         if (cookie.qval == 0) {
2885                                 *tl++ = 0;
2886                                 *tl++ = 0;
2887                         } else {
2888                                 NFSLOCKNODE(dnp);
2889                                 *tl++ = dnp->n_cookieverf.nfsuquad[0];
2890                                 *tl++ = dnp->n_cookieverf.nfsuquad[1];
2891                                 NFSUNLOCKNODE(dnp);
2892                         }
2893                         if (nd->nd_flag & ND_NFSV4) {
2894                                 *tl++ = txdr_unsigned(readsize);
2895                                 *tl = txdr_unsigned(readsize);
2896                                 (void) nfsrv_putattrbit(nd, &attrbits);
2897                                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2898                                 *tl = txdr_unsigned(NFSV4OP_GETATTR);
2899                                 (void) nfsrv_putattrbit(nd, &dattrbits);
2900                         } else {
2901                                 *tl = txdr_unsigned(readsize);
2902                         }
2903                 }
2904                 error = nfscl_request(nd, vp, p, cred, stuff);
2905                 if (error)
2906                         return (error);
2907                 if (!(nd->nd_flag & ND_NFSV2)) {
2908                         if (nd->nd_flag & ND_NFSV3)
2909                                 error = nfscl_postop_attr(nd, nap, attrflagp,
2910                                     stuff);
2911                         if (!nd->nd_repstat && !error) {
2912                                 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2913                                 NFSLOCKNODE(dnp);
2914                                 dnp->n_cookieverf.nfsuquad[0] = *tl++;
2915                                 dnp->n_cookieverf.nfsuquad[1] = *tl;
2916                                 NFSUNLOCKNODE(dnp);
2917                         }
2918                 }
2919                 if (nd->nd_repstat || error) {
2920                         if (!error)
2921                                 error = nd->nd_repstat;
2922                         goto nfsmout;
2923                 }
2924                 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2925                 more_dirs = fxdr_unsigned(int, *tl);
2926                 if (!more_dirs)
2927                         tryformoredirs = 0;
2928         
2929                 /* loop thru the dir entries, doctoring them to 4bsd form */
2930                 while (more_dirs && bigenough) {
2931                         if (nd->nd_flag & ND_NFSV4) {
2932                                 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED);
2933                                 ncookie.lval[0] = *tl++;
2934                                 ncookie.lval[1] = *tl++;
2935                                 len = fxdr_unsigned(int, *tl);
2936                         } else if (nd->nd_flag & ND_NFSV3) {
2937                                 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED);
2938                                 nfsva.na_fileid = fxdr_hyper(tl);
2939                                 tl += 2;
2940                                 len = fxdr_unsigned(int, *tl);
2941                         } else {
2942                                 NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED);
2943                                 nfsva.na_fileid =
2944                                     fxdr_unsigned(long, *tl++);
2945                                 len = fxdr_unsigned(int, *tl);
2946                         }
2947                         if (len <= 0 || len > NFS_MAXNAMLEN) {
2948                                 error = EBADRPC;
2949                                 goto nfsmout;
2950                         }
2951                         tlen = NFSM_RNDUP(len);
2952                         if (tlen == len)
2953                                 tlen += 4;  /* To ensure null termination */
2954                         left = DIRBLKSIZ - blksiz;
2955                         if ((int)(tlen + DIRHDSIZ + NFSX_HYPER) > left) {
2956                                 dp->d_reclen += left;
2957                                 uio_iov_base_add(uiop, left);
2958                                 uio_iov_len_add(uiop, -(left));
2959                                 uio_uio_resid_add(uiop, -(left));
2960                                 uiop->uio_offset += left;
2961                                 blksiz = 0;
2962                         }
2963                         if ((int)(tlen + DIRHDSIZ + NFSX_HYPER) > uio_uio_resid(uiop))
2964                                 bigenough = 0;
2965                         if (bigenough) {
2966                                 dp = (struct dirent *) CAST_DOWN(caddr_t, uio_iov_base(uiop));
2967                                 dp->d_namlen = len;
2968                                 dp->d_reclen = tlen + DIRHDSIZ + NFSX_HYPER;
2969                                 dp->d_type = DT_UNKNOWN;
2970                                 blksiz += dp->d_reclen;
2971                                 if (blksiz == DIRBLKSIZ)
2972                                         blksiz = 0;
2973                                 uio_uio_resid_add(uiop, -(DIRHDSIZ));
2974                                 uiop->uio_offset += DIRHDSIZ;
2975                                 uio_iov_base_add(uiop, DIRHDSIZ);
2976                                 uio_iov_len_add(uiop, -(DIRHDSIZ));
2977                                 error = nfsm_mbufuio(nd, uiop, len);
2978                                 if (error)
2979                                         goto nfsmout;
2980                                 cp = CAST_DOWN(caddr_t, uio_iov_base(uiop));
2981                                 tlen -= len;
2982                                 *cp = '\0';     /* null terminate */
2983                                 cp += tlen;     /* points to cookie storage */
2984                                 tl2 = (u_int32_t *)cp;
2985                                 uio_iov_base_add(uiop, (tlen + NFSX_HYPER));
2986                                 uio_iov_len_add(uiop, -(tlen + NFSX_HYPER));
2987                                 uio_uio_resid_add(uiop, -(tlen + NFSX_HYPER));
2988                                 uiop->uio_offset += (tlen + NFSX_HYPER);
2989                         } else {
2990                                 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
2991                                 if (error)
2992                                         goto nfsmout;
2993                         }
2994                         if (nd->nd_flag & ND_NFSV4) {
2995                                 rderr = 0;
2996                                 nfsva.na_mntonfileno = 0xffffffff;
2997                                 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL,
2998                                     NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
2999                                     NULL, NULL, &rderr, p, cred);
3000                                 if (error)
3001                                         goto nfsmout;
3002                                 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3003                         } else if (nd->nd_flag & ND_NFSV3) {
3004                                 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED);
3005                                 ncookie.lval[0] = *tl++;
3006                                 ncookie.lval[1] = *tl++;
3007                         } else {
3008                                 NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED);
3009                                 ncookie.lval[0] = 0;
3010                                 ncookie.lval[1] = *tl++;
3011                         }
3012                         if (bigenough) {
3013                             if (nd->nd_flag & ND_NFSV4) {
3014                                 if (rderr) {
3015                                     dp->d_fileno = 0;
3016                                 } else {
3017                                     if (gotmnton) {
3018                                         if (nfsva.na_mntonfileno != 0xffffffff)
3019                                             dp->d_fileno = nfsva.na_mntonfileno;
3020                                         else
3021                                             dp->d_fileno = nfsva.na_fileid;
3022                                     } else if (nfsva.na_filesid[0] ==
3023                                         dnp->n_vattr.na_filesid[0] &&
3024                                         nfsva.na_filesid[1] ==
3025                                         dnp->n_vattr.na_filesid[1]) {
3026                                         dp->d_fileno = nfsva.na_fileid;
3027                                     } else {
3028                                         do {
3029                                             fakefileno--;
3030                                         } while (fakefileno ==
3031                                             nfsva.na_fileid);
3032                                         dp->d_fileno = fakefileno;
3033                                     }
3034                                     dp->d_type = vtonfs_dtype(nfsva.na_type);
3035                                 }
3036                             } else {
3037                                 dp->d_fileno = nfsva.na_fileid;
3038                             }
3039                             *tl2++ = cookiep->nfsuquad[0] = cookie.lval[0] =
3040                                 ncookie.lval[0];
3041                             *tl2 = cookiep->nfsuquad[1] = cookie.lval[1] =
3042                                 ncookie.lval[1];
3043                         }
3044                         more_dirs = fxdr_unsigned(int, *tl);
3045                 }
3046                 /*
3047                  * If at end of rpc data, get the eof boolean
3048                  */
3049                 if (!more_dirs) {
3050                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3051                         eof = fxdr_unsigned(int, *tl);
3052                         if (tryformoredirs)
3053                                 more_dirs = !eof;
3054                         if (nd->nd_flag & ND_NFSV4) {
3055                                 error = nfscl_postop_attr(nd, nap, attrflagp,
3056                                     stuff);
3057                                 if (error)
3058                                         goto nfsmout;
3059                         }
3060                 }
3061                 mbuf_freem(nd->nd_mrep);
3062                 nd->nd_mrep = NULL;
3063         }
3064         /*
3065          * Fill last record, iff any, out to a multiple of DIRBLKSIZ
3066          * by increasing d_reclen for the last record.
3067          */
3068         if (blksiz > 0) {
3069                 left = DIRBLKSIZ - blksiz;
3070                 dp->d_reclen += left;
3071                 uio_iov_base_add(uiop, left);
3072                 uio_iov_len_add(uiop, -(left));
3073                 uio_uio_resid_add(uiop, -(left));
3074                 uiop->uio_offset += left;
3075         }
3076
3077         /*
3078          * If returning no data, assume end of file.
3079          * If not bigenough, return not end of file, since you aren't
3080          *    returning all the data
3081          * Otherwise, return the eof flag from the server.
3082          */
3083         if (eofp) {
3084                 if (tresid == ((size_t)(uio_uio_resid(uiop))))
3085                         *eofp = 1;
3086                 else if (!bigenough)
3087                         *eofp = 0;
3088                 else
3089                         *eofp = eof;
3090         }
3091
3092         /*
3093          * Add extra empty records to any remaining DIRBLKSIZ chunks.
3094          */
3095         while (uio_uio_resid(uiop) > 0 && ((size_t)(uio_uio_resid(uiop))) != tresid) {
3096                 dp = (struct dirent *) CAST_DOWN(caddr_t, uio_iov_base(uiop));
3097                 dp->d_type = DT_UNKNOWN;
3098                 dp->d_fileno = 0;
3099                 dp->d_namlen = 0;
3100                 dp->d_name[0] = '\0';
3101                 tl = (u_int32_t *)&dp->d_name[4];
3102                 *tl++ = cookie.lval[0];
3103                 *tl = cookie.lval[1];
3104                 dp->d_reclen = DIRBLKSIZ;
3105                 uio_iov_base_add(uiop, DIRBLKSIZ);
3106                 uio_iov_len_add(uiop, -(DIRBLKSIZ));
3107                 uio_uio_resid_add(uiop, -(DIRBLKSIZ));
3108                 uiop->uio_offset += DIRBLKSIZ;
3109         }
3110
3111 nfsmout:
3112         if (nd->nd_mrep != NULL)
3113                 mbuf_freem(nd->nd_mrep);
3114         return (error);
3115 }
3116
3117 #ifndef APPLE
3118 /*
3119  * NFS V3 readdir plus RPC. Used in place of nfsrpc_readdir().
3120  * (Also used for NFS V4 when mount flag set.)
3121  * (ditto above w.r.t. multiple of DIRBLKSIZ, etc.)
3122  */
3123 APPLESTATIC int
3124 nfsrpc_readdirplus(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep,
3125     struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp,
3126     int *eofp, void *stuff)
3127 {
3128         int len, left;
3129         struct dirent *dp = NULL;
3130         u_int32_t *tl;
3131         vnode_t newvp = NULLVP;
3132         struct nfsrv_descript nfsd, *nd = &nfsd;
3133         struct nameidata nami, *ndp = &nami;
3134         struct componentname *cnp = &ndp->ni_cnd;
3135         struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
3136         struct nfsnode *dnp = VTONFS(vp), *np;
3137         struct nfsvattr nfsva;
3138         struct nfsfh *nfhp;
3139         nfsquad_t cookie, ncookie;
3140         int error = 0, tlen, more_dirs = 1, blksiz = 0, bigenough = 1;
3141         int attrflag, tryformoredirs = 1, eof = 0, gotmnton = 0;
3142         int isdotdot = 0, unlocknewvp = 0;
3143         long dotfileid, dotdotfileid = 0, fileno = 0;
3144         char *cp;
3145         nfsattrbit_t attrbits, dattrbits;
3146         size_t tresid;
3147         u_int32_t *tl2 = NULL, fakefileno = 0xffffffff, rderr;
3148         struct timespec dctime;
3149
3150         KASSERT(uiop->uio_iovcnt == 1 &&
3151             (uio_uio_resid(uiop) & (DIRBLKSIZ - 1)) == 0,
3152             ("nfs readdirplusrpc bad uio"));
3153         timespecclear(&dctime);
3154         *attrflagp = 0;
3155         if (eofp != NULL)
3156                 *eofp = 0;
3157         ndp->ni_dvp = vp;
3158         nd->nd_mrep = NULL;
3159         cookie.lval[0] = cookiep->nfsuquad[0];
3160         cookie.lval[1] = cookiep->nfsuquad[1];
3161         tresid = uio_uio_resid(uiop);
3162
3163         /*
3164          * For NFSv4, first create the "." and ".." entries.
3165          */
3166         if (NFSHASNFSV4(nmp)) {
3167                 NFSGETATTR_ATTRBIT(&dattrbits);
3168                 NFSZERO_ATTRBIT(&attrbits);
3169                 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FILEID);
3170                 if (NFSISSET_ATTRBIT(&dnp->n_vattr.na_suppattr,
3171                     NFSATTRBIT_MOUNTEDONFILEID)) {
3172                         NFSSETBIT_ATTRBIT(&attrbits,
3173                             NFSATTRBIT_MOUNTEDONFILEID);
3174                         gotmnton = 1;
3175                 } else {
3176                         /*
3177                          * Must fake it. Use the fileno, except when the
3178                          * fsid is != to that of the directory. For that
3179                          * case, generate a fake fileno that is not the same.
3180                          */
3181                         NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FSID);
3182                         gotmnton = 0;
3183                 }
3184
3185                 /*
3186                  * Joy, oh joy. For V4 we get to hand craft '.' and '..'.
3187                  */
3188                 if (uiop->uio_offset == 0) {
3189                         NFSCL_REQSTART(nd, NFSPROC_LOOKUPP, vp);
3190                         NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3191                         *tl++ = txdr_unsigned(NFSV4OP_GETFH);
3192                         *tl = txdr_unsigned(NFSV4OP_GETATTR);
3193                         (void) nfsrv_putattrbit(nd, &attrbits);
3194                         error = nfscl_request(nd, vp, p, cred, stuff);
3195                         if (error)
3196                             return (error);
3197                         dotfileid = 0;  /* Fake out the compiler. */
3198                         if ((nd->nd_flag & ND_NOMOREDATA) == 0) {
3199                             error = nfsm_loadattr(nd, &nfsva);
3200                             if (error != 0)
3201                                 goto nfsmout;
3202                             dctime = nfsva.na_ctime;
3203                             dotfileid = nfsva.na_fileid;
3204                         }
3205                         if (nd->nd_repstat == 0) {
3206                             NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
3207                             len = fxdr_unsigned(int, *(tl + 4));
3208                             if (len > 0 && len <= NFSX_V4FHMAX)
3209                                 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
3210                             else
3211                                 error = EPERM;
3212                             if (!error) {
3213                                 NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED);
3214                                 nfsva.na_mntonfileno = 0xffffffff;
3215                                 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL,
3216                                     NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
3217                                     NULL, NULL, NULL, p, cred);
3218                                 if (error) {
3219                                     dotdotfileid = dotfileid;
3220                                 } else if (gotmnton) {
3221                                     if (nfsva.na_mntonfileno != 0xffffffff)
3222                                         dotdotfileid = nfsva.na_mntonfileno;
3223                                     else
3224                                         dotdotfileid = nfsva.na_fileid;
3225                                 } else if (nfsva.na_filesid[0] ==
3226                                     dnp->n_vattr.na_filesid[0] &&
3227                                     nfsva.na_filesid[1] ==
3228                                     dnp->n_vattr.na_filesid[1]) {
3229                                     dotdotfileid = nfsva.na_fileid;
3230                                 } else {
3231                                     do {
3232                                         fakefileno--;
3233                                     } while (fakefileno ==
3234                                         nfsva.na_fileid);
3235                                     dotdotfileid = fakefileno;
3236                                 }
3237                             }
3238                         } else if (nd->nd_repstat == NFSERR_NOENT) {
3239                             /*
3240                              * Lookupp returns NFSERR_NOENT when we are
3241                              * at the root, so just use the current dir.
3242                              */
3243                             nd->nd_repstat = 0;
3244                             dotdotfileid = dotfileid;
3245                         } else {
3246                             error = nd->nd_repstat;
3247                         }
3248                         mbuf_freem(nd->nd_mrep);
3249                         if (error)
3250                             return (error);
3251                         nd->nd_mrep = NULL;
3252                         dp = (struct dirent *)uio_iov_base(uiop);
3253                         dp->d_type = DT_DIR;
3254                         dp->d_fileno = dotfileid;
3255                         dp->d_namlen = 1;
3256                         dp->d_name[0] = '.';
3257                         dp->d_name[1] = '\0';
3258                         dp->d_reclen = DIRENT_SIZE(dp) + NFSX_HYPER;
3259                         /*
3260                          * Just make these offset cookie 0.
3261                          */
3262                         tl = (u_int32_t *)&dp->d_name[4];
3263                         *tl++ = 0;
3264                         *tl = 0;
3265                         blksiz += dp->d_reclen;
3266                         uio_uio_resid_add(uiop, -(dp->d_reclen));
3267                         uiop->uio_offset += dp->d_reclen;
3268                         uio_iov_base_add(uiop, dp->d_reclen);
3269                         uio_iov_len_add(uiop, -(dp->d_reclen));
3270                         dp = (struct dirent *)uio_iov_base(uiop);
3271                         dp->d_type = DT_DIR;
3272                         dp->d_fileno = dotdotfileid;
3273                         dp->d_namlen = 2;
3274                         dp->d_name[0] = '.';
3275                         dp->d_name[1] = '.';
3276                         dp->d_name[2] = '\0';
3277                         dp->d_reclen = DIRENT_SIZE(dp) + NFSX_HYPER;
3278                         /*
3279                          * Just make these offset cookie 0.
3280                          */
3281                         tl = (u_int32_t *)&dp->d_name[4];
3282                         *tl++ = 0;
3283                         *tl = 0;
3284                         blksiz += dp->d_reclen;
3285                         uio_uio_resid_add(uiop, -(dp->d_reclen));
3286                         uiop->uio_offset += dp->d_reclen;
3287                         uio_iov_base_add(uiop, dp->d_reclen);
3288                         uio_iov_len_add(uiop, -(dp->d_reclen));
3289                 }
3290                 NFSREADDIRPLUS_ATTRBIT(&attrbits);
3291                 if (gotmnton)
3292                         NFSSETBIT_ATTRBIT(&attrbits,
3293                             NFSATTRBIT_MOUNTEDONFILEID);
3294         }
3295
3296         /*
3297          * Loop around doing readdir rpc's of size nm_readdirsize.
3298          * The stopping criteria is EOF or buffer full.
3299          */
3300         while (more_dirs && bigenough) {
3301                 *attrflagp = 0;
3302                 NFSCL_REQSTART(nd, NFSPROC_READDIRPLUS, vp);
3303                 NFSM_BUILD(tl, u_int32_t *, 6 * NFSX_UNSIGNED);
3304                 *tl++ = cookie.lval[0];
3305                 *tl++ = cookie.lval[1];
3306                 if (cookie.qval == 0) {
3307                         *tl++ = 0;
3308                         *tl++ = 0;
3309                 } else {
3310                         NFSLOCKNODE(dnp);
3311                         *tl++ = dnp->n_cookieverf.nfsuquad[0];
3312                         *tl++ = dnp->n_cookieverf.nfsuquad[1];
3313                         NFSUNLOCKNODE(dnp);
3314                 }
3315                 *tl++ = txdr_unsigned(nmp->nm_readdirsize);
3316                 *tl = txdr_unsigned(nmp->nm_readdirsize);
3317                 if (nd->nd_flag & ND_NFSV4) {
3318                         (void) nfsrv_putattrbit(nd, &attrbits);
3319                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3320                         *tl = txdr_unsigned(NFSV4OP_GETATTR);
3321                         (void) nfsrv_putattrbit(nd, &dattrbits);
3322                 }
3323                 error = nfscl_request(nd, vp, p, cred, stuff);
3324                 if (error)
3325                         return (error);
3326                 if (nd->nd_flag & ND_NFSV3)
3327                         error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
3328                 if (nd->nd_repstat || error) {
3329                         if (!error)
3330                                 error = nd->nd_repstat;
3331                         goto nfsmout;
3332                 }
3333                 if ((nd->nd_flag & ND_NFSV3) != 0 && *attrflagp != 0)
3334                         dctime = nap->na_ctime;
3335                 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3336                 NFSLOCKNODE(dnp);
3337                 dnp->n_cookieverf.nfsuquad[0] = *tl++;
3338                 dnp->n_cookieverf.nfsuquad[1] = *tl++;
3339                 NFSUNLOCKNODE(dnp);
3340                 more_dirs = fxdr_unsigned(int, *tl);
3341                 if (!more_dirs)
3342                         tryformoredirs = 0;
3343         
3344                 /* loop thru the dir entries, doctoring them to 4bsd form */
3345                 while (more_dirs && bigenough) {
3346                         NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3347                         if (nd->nd_flag & ND_NFSV4) {
3348                                 ncookie.lval[0] = *tl++;
3349                                 ncookie.lval[1] = *tl++;
3350                         } else {
3351                                 fileno = fxdr_unsigned(long, *++tl);
3352                                 tl++;
3353                         }
3354                         len = fxdr_unsigned(int, *tl);
3355                         if (len <= 0 || len > NFS_MAXNAMLEN) {
3356                                 error = EBADRPC;
3357                                 goto nfsmout;
3358                         }
3359                         tlen = NFSM_RNDUP(len);
3360                         if (tlen == len)
3361                                 tlen += 4;  /* To ensure null termination */
3362                         left = DIRBLKSIZ - blksiz;
3363                         if ((tlen + DIRHDSIZ + NFSX_HYPER) > left) {
3364                                 dp->d_reclen += left;
3365                                 uio_iov_base_add(uiop, left);
3366                                 uio_iov_len_add(uiop, -(left));
3367                                 uio_uio_resid_add(uiop, -(left));
3368                                 uiop->uio_offset += left;
3369                                 blksiz = 0;
3370                         }
3371                         if ((tlen + DIRHDSIZ + NFSX_HYPER) > uio_uio_resid(uiop))
3372                                 bigenough = 0;
3373                         if (bigenough) {
3374                                 dp = (struct dirent *)uio_iov_base(uiop);
3375                                 dp->d_namlen = len;
3376                                 dp->d_reclen = tlen + DIRHDSIZ + NFSX_HYPER;
3377                                 dp->d_type = DT_UNKNOWN;
3378                                 blksiz += dp->d_reclen;
3379                                 if (blksiz == DIRBLKSIZ)
3380                                         blksiz = 0;
3381                                 uio_uio_resid_add(uiop, -(DIRHDSIZ));
3382                                 uiop->uio_offset += DIRHDSIZ;
3383                                 uio_iov_base_add(uiop, DIRHDSIZ);
3384                                 uio_iov_len_add(uiop, -(DIRHDSIZ));
3385                                 cnp->cn_nameptr = uio_iov_base(uiop);
3386                                 cnp->cn_namelen = len;
3387                                 NFSCNHASHZERO(cnp);
3388                                 error = nfsm_mbufuio(nd, uiop, len);
3389                                 if (error)
3390                                         goto nfsmout;
3391                                 cp = uio_iov_base(uiop);
3392                                 tlen -= len;
3393                                 *cp = '\0';
3394                                 cp += tlen;     /* points to cookie storage */
3395                                 tl2 = (u_int32_t *)cp;
3396                                 if (len == 2 && cnp->cn_nameptr[0] == '.' &&
3397                                     cnp->cn_nameptr[1] == '.')
3398                                         isdotdot = 1;
3399                                 else
3400                                         isdotdot = 0;
3401                                 uio_iov_base_add(uiop, (tlen + NFSX_HYPER));
3402                                 uio_iov_len_add(uiop, -(tlen + NFSX_HYPER));
3403                                 uio_uio_resid_add(uiop, -(tlen + NFSX_HYPER));
3404                                 uiop->uio_offset += (tlen + NFSX_HYPER);
3405                         } else {
3406                                 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
3407                                 if (error)
3408                                         goto nfsmout;
3409                         }
3410                         nfhp = NULL;
3411                         if (nd->nd_flag & ND_NFSV3) {
3412                                 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED);
3413                                 ncookie.lval[0] = *tl++;
3414                                 ncookie.lval[1] = *tl++;
3415                                 attrflag = fxdr_unsigned(int, *tl);
3416                                 if (attrflag) {
3417                                   error = nfsm_loadattr(nd, &nfsva);
3418                                   if (error)
3419                                         goto nfsmout;
3420                                 }
3421                                 NFSM_DISSECT(tl,u_int32_t *,NFSX_UNSIGNED);
3422                                 if (*tl) {
3423                                         error = nfsm_getfh(nd, &nfhp);
3424                                         if (error)
3425                                             goto nfsmout;
3426                                 }
3427                                 if (!attrflag && nfhp != NULL) {
3428                                         FREE((caddr_t)nfhp, M_NFSFH);
3429                                         nfhp = NULL;
3430                                 }
3431                         } else {
3432                                 rderr = 0;
3433                                 nfsva.na_mntonfileno = 0xffffffff;
3434                                 error = nfsv4_loadattr(nd, NULL, &nfsva, &nfhp,
3435                                     NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
3436                                     NULL, NULL, &rderr, p, cred);
3437                                 if (error)
3438                                         goto nfsmout;
3439                         }
3440
3441                         if (bigenough) {
3442                             if (nd->nd_flag & ND_NFSV4) {
3443                                 if (rderr) {
3444                                     dp->d_fileno = 0;
3445                                 } else if (gotmnton) {
3446                                     if (nfsva.na_mntonfileno != 0xffffffff)
3447                                         dp->d_fileno = nfsva.na_mntonfileno;
3448                                     else
3449                                         dp->d_fileno = nfsva.na_fileid;
3450                                 } else if (nfsva.na_filesid[0] ==
3451                                     dnp->n_vattr.na_filesid[0] &&
3452                                     nfsva.na_filesid[1] ==
3453                                     dnp->n_vattr.na_filesid[1]) {
3454                                     dp->d_fileno = nfsva.na_fileid;
3455                                 } else {
3456                                     do {
3457                                         fakefileno--;
3458                                     } while (fakefileno ==
3459                                         nfsva.na_fileid);
3460                                     dp->d_fileno = fakefileno;
3461                                 }
3462                             } else {
3463                                 dp->d_fileno = fileno;
3464                             }
3465                             *tl2++ = cookiep->nfsuquad[0] = cookie.lval[0] =
3466                                 ncookie.lval[0];
3467                             *tl2 = cookiep->nfsuquad[1] = cookie.lval[1] =
3468                                 ncookie.lval[1];
3469
3470                             if (nfhp != NULL) {
3471                                 if (NFSRV_CMPFH(nfhp->nfh_fh, nfhp->nfh_len,
3472                                     dnp->n_fhp->nfh_fh, dnp->n_fhp->nfh_len)) {
3473                                     VREF(vp);
3474                                     newvp = vp;
3475                                     unlocknewvp = 0;
3476                                     FREE((caddr_t)nfhp, M_NFSFH);
3477                                     np = dnp;
3478                                 } else if (isdotdot != 0) {
3479                                     /*
3480                                      * Skip doing a nfscl_nget() call for "..".
3481                                      * There's a race between acquiring the nfs
3482                                      * node here and lookups that look for the
3483                                      * directory being read (in the parent).
3484                                      * It would try to get a lock on ".." here,
3485                                      * owning the lock on the directory being
3486                                      * read. Lookup will hold the lock on ".."
3487                                      * and try to acquire the lock on the
3488                                      * directory being read.
3489                                      * If the directory is unlocked/relocked,
3490                                      * then there is a LOR with the buflock
3491                                      * vp is relocked.
3492                                      */
3493                                     free(nfhp, M_NFSFH);
3494                                 } else {
3495                                     error = nfscl_nget(vnode_mount(vp), vp,
3496                                       nfhp, cnp, p, &np, NULL, LK_EXCLUSIVE);
3497                                     if (!error) {
3498                                         newvp = NFSTOV(np);
3499                                         unlocknewvp = 1;
3500                                     }
3501                                 }
3502                                 nfhp = NULL;
3503                                 if (newvp != NULLVP) {
3504                                     error = nfscl_loadattrcache(&newvp,
3505                                         &nfsva, NULL, NULL, 0, 0);
3506                                     if (error) {
3507                                         if (unlocknewvp)
3508                                             vput(newvp);
3509                                         else
3510                                             vrele(newvp);
3511                                         goto nfsmout;
3512                                     }
3513                                     dp->d_type =
3514                                         vtonfs_dtype(np->n_vattr.na_type);
3515                                     ndp->ni_vp = newvp;
3516                                     NFSCNHASH(cnp, HASHINIT);
3517                                     if (cnp->cn_namelen <= NCHNAMLEN &&
3518                                         (newvp->v_type != VDIR ||
3519                                          dctime.tv_sec != 0)) {
3520                                         cache_enter_time(ndp->ni_dvp,
3521                                             ndp->ni_vp, cnp,
3522                                             &nfsva.na_ctime,
3523                                             newvp->v_type != VDIR ? NULL :
3524                                             &dctime);
3525                                     }
3526                                     if (unlocknewvp)
3527                                         vput(newvp);
3528                                     else
3529                                         vrele(newvp);
3530                                     newvp = NULLVP;
3531                                 }
3532                             }
3533                         } else if (nfhp != NULL) {
3534                             FREE((caddr_t)nfhp, M_NFSFH);
3535                         }
3536                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3537                         more_dirs = fxdr_unsigned(int, *tl);
3538                 }
3539                 /*
3540                  * If at end of rpc data, get the eof boolean
3541                  */
3542                 if (!more_dirs) {
3543                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3544                         eof = fxdr_unsigned(int, *tl);
3545                         if (tryformoredirs)
3546                                 more_dirs = !eof;
3547                         if (nd->nd_flag & ND_NFSV4) {
3548                                 error = nfscl_postop_attr(nd, nap, attrflagp,
3549                                     stuff);
3550                                 if (error)
3551                                         goto nfsmout;
3552                         }
3553                 }
3554                 mbuf_freem(nd->nd_mrep);
3555                 nd->nd_mrep = NULL;
3556         }
3557         /*
3558          * Fill last record, iff any, out to a multiple of DIRBLKSIZ
3559          * by increasing d_reclen for the last record.
3560          */
3561         if (blksiz > 0) {
3562                 left = DIRBLKSIZ - blksiz;
3563                 dp->d_reclen += left;
3564                 uio_iov_base_add(uiop, left);
3565                 uio_iov_len_add(uiop, -(left));
3566                 uio_uio_resid_add(uiop, -(left));
3567                 uiop->uio_offset += left;
3568         }
3569
3570         /*
3571          * If returning no data, assume end of file.
3572          * If not bigenough, return not end of file, since you aren't
3573          *    returning all the data
3574          * Otherwise, return the eof flag from the server.
3575          */
3576         if (eofp != NULL) {
3577                 if (tresid == uio_uio_resid(uiop))
3578                         *eofp = 1;
3579                 else if (!bigenough)
3580                         *eofp = 0;
3581                 else
3582                         *eofp = eof;
3583         }
3584
3585         /*
3586          * Add extra empty records to any remaining DIRBLKSIZ chunks.
3587          */
3588         while (uio_uio_resid(uiop) > 0 && uio_uio_resid(uiop) != tresid) {
3589                 dp = (struct dirent *)uio_iov_base(uiop);
3590                 dp->d_type = DT_UNKNOWN;
3591                 dp->d_fileno = 0;
3592                 dp->d_namlen = 0;
3593                 dp->d_name[0] = '\0';
3594                 tl = (u_int32_t *)&dp->d_name[4];
3595                 *tl++ = cookie.lval[0];
3596                 *tl = cookie.lval[1];
3597                 dp->d_reclen = DIRBLKSIZ;
3598                 uio_iov_base_add(uiop, DIRBLKSIZ);
3599                 uio_iov_len_add(uiop, -(DIRBLKSIZ));
3600                 uio_uio_resid_add(uiop, -(DIRBLKSIZ));
3601                 uiop->uio_offset += DIRBLKSIZ;
3602         }
3603
3604 nfsmout:
3605         if (nd->nd_mrep != NULL)
3606                 mbuf_freem(nd->nd_mrep);
3607         return (error);
3608 }
3609 #endif  /* !APPLE */
3610
3611 /*
3612  * Nfs commit rpc
3613  */
3614 APPLESTATIC int
3615 nfsrpc_commit(vnode_t vp, u_quad_t offset, int cnt, struct ucred *cred,
3616     NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff)
3617 {
3618         u_int32_t *tl;
3619         struct nfsrv_descript nfsd, *nd = &nfsd;
3620         nfsattrbit_t attrbits;
3621         int error;
3622         struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
3623         
3624         *attrflagp = 0;
3625         NFSCL_REQSTART(nd, NFSPROC_COMMIT, vp);
3626         NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3627         txdr_hyper(offset, tl);
3628         tl += 2;
3629         *tl = txdr_unsigned(cnt);
3630         if (nd->nd_flag & ND_NFSV4) {
3631                 /*
3632                  * And do a Getattr op.
3633                  */
3634                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3635                 *tl = txdr_unsigned(NFSV4OP_GETATTR);
3636                 NFSGETATTR_ATTRBIT(&attrbits);
3637                 (void) nfsrv_putattrbit(nd, &attrbits);
3638         }
3639         error = nfscl_request(nd, vp, p, cred, stuff);
3640         if (error)
3641                 return (error);
3642         error = nfscl_wcc_data(nd, vp, nap, attrflagp, NULL, stuff);
3643         if (!error && !nd->nd_repstat) {
3644                 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
3645                 NFSLOCKMNT(nmp);
3646                 if (NFSBCMP(nmp->nm_verf, tl, NFSX_VERF)) {
3647                         NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF);
3648                         nd->nd_repstat = NFSERR_STALEWRITEVERF;
3649                 }
3650                 NFSUNLOCKMNT(nmp);
3651                 if (nd->nd_flag & ND_NFSV4)
3652                         error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
3653         }
3654 nfsmout:
3655         if (!error && nd->nd_repstat)
3656                 error = nd->nd_repstat;
3657         mbuf_freem(nd->nd_mrep);
3658         return (error);
3659 }
3660
3661 /*
3662  * NFS byte range lock rpc.
3663  * (Mostly just calls one of the three lower level RPC routines.)
3664  */
3665 APPLESTATIC int
3666 nfsrpc_advlock(vnode_t vp, off_t size, int op, struct flock *fl,
3667     int reclaim, struct ucred *cred, NFSPROC_T *p, void *id, int flags)
3668 {
3669         struct nfscllockowner *lp;
3670         struct nfsclclient *clp;
3671         struct nfsfh *nfhp;
3672         struct nfsrv_descript nfsd, *nd = &nfsd;
3673         struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
3674         u_int64_t off, len;
3675         off_t start, end;
3676         u_int32_t clidrev = 0;
3677         int error = 0, newone = 0, expireret = 0, retrycnt, donelocally;
3678         int callcnt, dorpc;
3679
3680         /*
3681          * Convert the flock structure into a start and end and do POSIX
3682          * bounds checking.
3683          */
3684         switch (fl->l_whence) {
3685         case SEEK_SET:
3686         case SEEK_CUR:
3687                 /*
3688                  * Caller is responsible for adding any necessary offset
3689                  * when SEEK_CUR is used.
3690                  */
3691                 start = fl->l_start;
3692                 off = fl->l_start;
3693                 break;
3694         case SEEK_END:
3695                 start = size + fl->l_start;
3696                 off = size + fl->l_start;
3697                 break;
3698         default:
3699                 return (EINVAL);
3700         };
3701         if (start < 0)
3702                 return (EINVAL);
3703         if (fl->l_len != 0) {
3704                 end = start + fl->l_len - 1;
3705                 if (end < start)
3706                         return (EINVAL);
3707         }
3708
3709         len = fl->l_len;
3710         if (len == 0)
3711                 len = NFS64BITSSET;
3712         retrycnt = 0;
3713         do {
3714             nd->nd_repstat = 0;
3715             if (op == F_GETLK) {
3716                 error = nfscl_getcl(vnode_mount(vp), cred, p, 1, &clp);
3717                 if (error)
3718                         return (error);
3719                 error = nfscl_lockt(vp, clp, off, len, fl, p, id, flags);
3720                 if (!error) {
3721                         clidrev = clp->nfsc_clientidrev;
3722                         error = nfsrpc_lockt(nd, vp, clp, off, len, fl, cred,
3723                             p, id, flags);
3724                 } else if (error == -1) {
3725                         error = 0;
3726                 }
3727                 nfscl_clientrelease(clp);
3728             } else if (op == F_UNLCK && fl->l_type == F_UNLCK) {
3729                 /*
3730                  * We must loop around for all lockowner cases.
3731                  */
3732                 callcnt = 0;
3733                 error = nfscl_getcl(vnode_mount(vp), cred, p, 1, &clp);
3734                 if (error)
3735                         return (error);
3736                 do {
3737                     error = nfscl_relbytelock(vp, off, len, cred, p, callcnt,
3738                         clp, id, flags, &lp, &dorpc);
3739                     /*
3740                      * If it returns a NULL lp, we're done.
3741                      */
3742                     if (lp == NULL) {
3743                         if (callcnt == 0)
3744                             nfscl_clientrelease(clp);
3745                         else
3746                             nfscl_releasealllocks(clp, vp, p, id, flags);
3747                         return (error);
3748                     }
3749                     if (nmp->nm_clp != NULL)
3750                         clidrev = nmp->nm_clp->nfsc_clientidrev;
3751                     else
3752                         clidrev = 0;
3753                     /*
3754                      * If the server doesn't support Posix lock semantics,
3755                      * only allow locks on the entire file, since it won't
3756                      * handle overlapping byte ranges.
3757                      * There might still be a problem when a lock
3758                      * upgrade/downgrade (read<->write) occurs, since the
3759                      * server "might" expect an unlock first?
3760                      */
3761                     if (dorpc && (lp->nfsl_open->nfso_posixlock ||
3762                         (off == 0 && len == NFS64BITSSET))) {
3763                         /*
3764                          * Since the lock records will go away, we must
3765                          * wait for grace and delay here.
3766                          */
3767                         do {
3768                             error = nfsrpc_locku(nd, nmp, lp, off, len,
3769                                 NFSV4LOCKT_READ, cred, p, 0);
3770                             if ((nd->nd_repstat == NFSERR_GRACE ||
3771                                  nd->nd_repstat == NFSERR_DELAY) &&
3772                                 error == 0)
3773                                 (void) nfs_catnap(PZERO, (int)nd->nd_repstat,
3774                                     "nfs_advlock");
3775                         } while ((nd->nd_repstat == NFSERR_GRACE ||
3776                             nd->nd_repstat == NFSERR_DELAY) && error == 0);
3777                     }
3778                     callcnt++;
3779                 } while (error == 0 && nd->nd_repstat == 0);
3780                 nfscl_releasealllocks(clp, vp, p, id, flags);
3781             } else if (op == F_SETLK) {
3782                 error = nfscl_getbytelock(vp, off, len, fl->l_type, cred, p,
3783                     NULL, 0, id, flags, NULL, NULL, &lp, &newone, &donelocally);
3784                 if (error || donelocally) {
3785                         return (error);
3786                 }
3787                 if (nmp->nm_clp != NULL)
3788                         clidrev = nmp->nm_clp->nfsc_clientidrev;
3789                 else
3790                         clidrev = 0;
3791                 nfhp = VTONFS(vp)->n_fhp;
3792                 if (!lp->nfsl_open->nfso_posixlock &&
3793                     (off != 0 || len != NFS64BITSSET)) {
3794                         error = EINVAL;
3795                 } else {
3796                         error = nfsrpc_lock(nd, nmp, vp, nfhp->nfh_fh,
3797                             nfhp->nfh_len, lp, newone, reclaim, off,
3798                             len, fl->l_type, cred, p, 0);
3799                 }
3800                 if (!error)
3801                         error = nd->nd_repstat;
3802                 nfscl_lockrelease(lp, error, newone);
3803             } else {
3804                 error = EINVAL;
3805             }
3806             if (!error)
3807                 error = nd->nd_repstat;
3808             if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
3809                 error == NFSERR_STALEDONTRECOVER ||
3810                 error == NFSERR_STALECLIENTID || error == NFSERR_DELAY ||
3811                 error == NFSERR_BADSESSION) {
3812                 (void) nfs_catnap(PZERO, error, "nfs_advlock");
3813             } else if ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID)
3814                 && clidrev != 0) {
3815                 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
3816                 retrycnt++;
3817             }
3818         } while (error == NFSERR_GRACE ||
3819             error == NFSERR_STALECLIENTID || error == NFSERR_DELAY ||
3820             error == NFSERR_STALEDONTRECOVER || error == NFSERR_STALESTATEID ||
3821             error == NFSERR_BADSESSION ||
3822             ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
3823              expireret == 0 && clidrev != 0 && retrycnt < 4));
3824         if (error && retrycnt >= 4)
3825                 error = EIO;
3826         return (error);
3827 }
3828
3829 /*
3830  * The lower level routine for the LockT case.
3831  */
3832 APPLESTATIC int
3833 nfsrpc_lockt(struct nfsrv_descript *nd, vnode_t vp,
3834     struct nfsclclient *clp, u_int64_t off, u_int64_t len, struct flock *fl,
3835     struct ucred *cred, NFSPROC_T *p, void *id, int flags)
3836 {
3837         u_int32_t *tl;
3838         int error, type, size;
3839         uint8_t own[NFSV4CL_LOCKNAMELEN + NFSX_V4FHMAX];
3840         struct nfsnode *np;
3841         struct nfsmount *nmp;
3842
3843         nmp = VFSTONFS(vp->v_mount);
3844         NFSCL_REQSTART(nd, NFSPROC_LOCKT, vp);
3845         NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
3846         if (fl->l_type == F_RDLCK)
3847                 *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
3848         else
3849                 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
3850         txdr_hyper(off, tl);
3851         tl += 2;
3852         txdr_hyper(len, tl);
3853         tl += 2;
3854         *tl++ = NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[0];
3855         *tl = NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[1];
3856         nfscl_filllockowner(id, own, flags);
3857         np = VTONFS(vp);
3858         NFSBCOPY(np->n_fhp->nfh_fh, &own[NFSV4CL_LOCKNAMELEN],
3859             np->n_fhp->nfh_len);
3860         (void)nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN + np->n_fhp->nfh_len);
3861         error = nfscl_request(nd, vp, p, cred, NULL);
3862         if (error)
3863                 return (error);
3864         if (nd->nd_repstat == 0) {
3865                 fl->l_type = F_UNLCK;
3866         } else if (nd->nd_repstat == NFSERR_DENIED) {
3867                 nd->nd_repstat = 0;
3868                 fl->l_whence = SEEK_SET;
3869                 NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
3870                 fl->l_start = fxdr_hyper(tl);
3871                 tl += 2;
3872                 len = fxdr_hyper(tl);
3873                 tl += 2;
3874                 if (len == NFS64BITSSET)
3875                         fl->l_len = 0;
3876                 else
3877                         fl->l_len = len;
3878                 type = fxdr_unsigned(int, *tl++);
3879                 if (type == NFSV4LOCKT_WRITE)
3880                         fl->l_type = F_WRLCK;
3881                 else
3882                         fl->l_type = F_RDLCK;
3883                 /*
3884                  * XXX For now, I have no idea what to do with the
3885                  * conflicting lock_owner, so I'll just set the pid == 0
3886                  * and skip over the lock_owner.
3887                  */
3888                 fl->l_pid = (pid_t)0;
3889                 tl += 2;
3890                 size = fxdr_unsigned(int, *tl);
3891                 if (size < 0 || size > NFSV4_OPAQUELIMIT)
3892                         error = EBADRPC;
3893                 if (!error)
3894                         error = nfsm_advance(nd, NFSM_RNDUP(size), -1);
3895         } else if (nd->nd_repstat == NFSERR_STALECLIENTID ||
3896             nd->nd_repstat == NFSERR_BADSESSION)
3897                 nfscl_initiate_recovery(clp);
3898 nfsmout:
3899         mbuf_freem(nd->nd_mrep);
3900         return (error);
3901 }
3902
3903 /*
3904  * Lower level function that performs the LockU RPC.
3905  */
3906 static int
3907 nfsrpc_locku(struct nfsrv_descript *nd, struct nfsmount *nmp,
3908     struct nfscllockowner *lp, u_int64_t off, u_int64_t len,
3909     u_int32_t type, struct ucred *cred, NFSPROC_T *p, int syscred)
3910 {
3911         u_int32_t *tl;
3912         int error;
3913
3914         nfscl_reqstart(nd, NFSPROC_LOCKU, nmp, lp->nfsl_open->nfso_fh,
3915             lp->nfsl_open->nfso_fhlen, NULL, NULL);
3916         NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED);
3917         *tl++ = txdr_unsigned(type);
3918         *tl = txdr_unsigned(lp->nfsl_seqid);
3919         if (nfstest_outofseq &&
3920             (arc4random() % nfstest_outofseq) == 0)
3921                 *tl = txdr_unsigned(lp->nfsl_seqid + 1);
3922         tl++;
3923         if (NFSHASNFSV4N(nmp))
3924                 *tl++ = 0;
3925         else
3926                 *tl++ = lp->nfsl_stateid.seqid;
3927         *tl++ = lp->nfsl_stateid.other[0];
3928         *tl++ = lp->nfsl_stateid.other[1];
3929         *tl++ = lp->nfsl_stateid.other[2];
3930         txdr_hyper(off, tl);
3931         tl += 2;
3932         txdr_hyper(len, tl);
3933         if (syscred)
3934                 nd->nd_flag |= ND_USEGSSNAME;
3935         error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
3936             NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
3937         NFSCL_INCRSEQID(lp->nfsl_seqid, nd);
3938         if (error)
3939                 return (error);
3940         if (nd->nd_repstat == 0) {
3941                 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
3942                 lp->nfsl_stateid.seqid = *tl++;
3943                 lp->nfsl_stateid.other[0] = *tl++;
3944                 lp->nfsl_stateid.other[1] = *tl++;
3945                 lp->nfsl_stateid.other[2] = *tl;
3946         } else if (nd->nd_repstat == NFSERR_STALESTATEID ||
3947             nd->nd_repstat == NFSERR_BADSESSION)
3948                 nfscl_initiate_recovery(lp->nfsl_open->nfso_own->nfsow_clp);
3949 nfsmout:
3950         mbuf_freem(nd->nd_mrep);
3951         return (error);
3952 }
3953
3954 /*
3955  * The actual Lock RPC.
3956  */
3957 APPLESTATIC int
3958 nfsrpc_lock(struct nfsrv_descript *nd, struct nfsmount *nmp, vnode_t vp,
3959     u_int8_t *nfhp, int fhlen, struct nfscllockowner *lp, int newone,
3960     int reclaim, u_int64_t off, u_int64_t len, short type, struct ucred *cred,
3961     NFSPROC_T *p, int syscred)
3962 {
3963         u_int32_t *tl;
3964         int error, size;
3965         uint8_t own[NFSV4CL_LOCKNAMELEN + NFSX_V4FHMAX];
3966
3967         nfscl_reqstart(nd, NFSPROC_LOCK, nmp, nfhp, fhlen, NULL, NULL);
3968         NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
3969         if (type == F_RDLCK)
3970                 *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
3971         else
3972                 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
3973         *tl++ = txdr_unsigned(reclaim);
3974         txdr_hyper(off, tl);
3975         tl += 2;
3976         txdr_hyper(len, tl);
3977         tl += 2;
3978         if (newone) {
3979             *tl = newnfs_true;
3980             NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID +
3981                 2 * NFSX_UNSIGNED + NFSX_HYPER);
3982             *tl++ = txdr_unsigned(lp->nfsl_open->nfso_own->nfsow_seqid);
3983             if (NFSHASNFSV4N(nmp))
3984                 *tl++ = 0;
3985             else
3986                 *tl++ = lp->nfsl_open->nfso_stateid.seqid;
3987             *tl++ = lp->nfsl_open->nfso_stateid.other[0];
3988             *tl++ = lp->nfsl_open->nfso_stateid.other[1];
3989             *tl++ = lp->nfsl_open->nfso_stateid.other[2];
3990             *tl++ = txdr_unsigned(lp->nfsl_seqid);
3991             *tl++ = NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[0];
3992             *tl = NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[1];
3993             NFSBCOPY(lp->nfsl_owner, own, NFSV4CL_LOCKNAMELEN);
3994             NFSBCOPY(nfhp, &own[NFSV4CL_LOCKNAMELEN], fhlen);
3995             (void)nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN + fhlen);
3996         } else {
3997             *tl = newnfs_false;
3998             NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
3999             if (NFSHASNFSV4N(nmp))
4000                 *tl++ = 0;
4001             else
4002                 *tl++ = lp->nfsl_stateid.seqid;
4003             *tl++ = lp->nfsl_stateid.other[0];
4004             *tl++ = lp->nfsl_stateid.other[1];
4005             *tl++ = lp->nfsl_stateid.other[2];
4006             *tl = txdr_unsigned(lp->nfsl_seqid);
4007             if (nfstest_outofseq &&
4008                 (arc4random() % nfstest_outofseq) == 0)
4009                     *tl = txdr_unsigned(lp->nfsl_seqid + 1);
4010         }
4011         if (syscred)
4012                 nd->nd_flag |= ND_USEGSSNAME;
4013         error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, vp, p, cred,
4014             NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
4015         if (error)
4016                 return (error);
4017         if (newone)
4018             NFSCL_INCRSEQID(lp->nfsl_open->nfso_own->nfsow_seqid, nd);
4019         NFSCL_INCRSEQID(lp->nfsl_seqid, nd);
4020         if (nd->nd_repstat == 0) {
4021                 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
4022                 lp->nfsl_stateid.seqid = *tl++;
4023                 lp->nfsl_stateid.other[0] = *tl++;
4024                 lp->nfsl_stateid.other[1] = *tl++;
4025                 lp->nfsl_stateid.other[2] = *tl;
4026         } else if (nd->nd_repstat == NFSERR_DENIED) {
4027                 NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
4028                 size = fxdr_unsigned(int, *(tl + 7));
4029                 if (size < 0 || size > NFSV4_OPAQUELIMIT)
4030                         error = EBADRPC;
4031                 if (!error)
4032                         error = nfsm_advance(nd, NFSM_RNDUP(size), -1);
4033         } else if (nd->nd_repstat == NFSERR_STALESTATEID ||
4034             nd->nd_repstat == NFSERR_BADSESSION)
4035                 nfscl_initiate_recovery(lp->nfsl_open->nfso_own->nfsow_clp);
4036 nfsmout:
4037         mbuf_freem(nd->nd_mrep);
4038         return (error);
4039 }
4040
4041 /*
4042  * nfs statfs rpc
4043  * (always called with the vp for the mount point)
4044  */
4045 APPLESTATIC int
4046 nfsrpc_statfs(vnode_t vp, struct nfsstatfs *sbp, struct nfsfsinfo *fsp,
4047     struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp,
4048     void *stuff)
4049 {
4050         u_int32_t *tl = NULL;
4051         struct nfsrv_descript nfsd, *nd = &nfsd;
4052         struct nfsmount *nmp;
4053         nfsattrbit_t attrbits;
4054         int error;
4055
4056         *attrflagp = 0;
4057         nmp = VFSTONFS(vnode_mount(vp));
4058         if (NFSHASNFSV4(nmp)) {
4059                 /*
4060                  * For V4, you actually do a getattr.
4061                  */
4062                 NFSCL_REQSTART(nd, NFSPROC_GETATTR, vp);
4063                 NFSSTATFS_GETATTRBIT(&attrbits);
4064                 (void) nfsrv_putattrbit(nd, &attrbits);
4065                 nd->nd_flag |= ND_USEGSSNAME;
4066                 error = nfscl_request(nd, vp, p, cred, stuff);
4067                 if (error)
4068                         return (error);
4069                 if (nd->nd_repstat == 0) {
4070                         error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0,
4071                             NULL, NULL, sbp, fsp, NULL, 0, NULL, NULL, NULL, p,
4072                             cred);
4073                         if (!error) {
4074                                 nmp->nm_fsid[0] = nap->na_filesid[0];
4075                                 nmp->nm_fsid[1] = nap->na_filesid[1];
4076                                 NFSSETHASSETFSID(nmp);
4077                                 *attrflagp = 1;
4078                         }
4079                 } else {
4080                         error = nd->nd_repstat;
4081                 }
4082                 if (error)
4083                         goto nfsmout;
4084         } else {
4085                 NFSCL_REQSTART(nd, NFSPROC_FSSTAT, vp);
4086                 error = nfscl_request(nd, vp, p, cred, stuff);
4087                 if (error)
4088                         return (error);
4089                 if (nd->nd_flag & ND_NFSV3) {
4090                         error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
4091                         if (error)
4092                                 goto nfsmout;
4093                 }
4094                 if (nd->nd_repstat) {
4095                         error = nd->nd_repstat;
4096                         goto nfsmout;
4097                 }
4098                 NFSM_DISSECT(tl, u_int32_t *,
4099                     NFSX_STATFS(nd->nd_flag & ND_NFSV3));
4100         }
4101         if (NFSHASNFSV3(nmp)) {
4102                 sbp->sf_tbytes = fxdr_hyper(tl); tl += 2;
4103                 sbp->sf_fbytes = fxdr_hyper(tl); tl += 2;
4104                 sbp->sf_abytes = fxdr_hyper(tl); tl += 2;
4105                 sbp->sf_tfiles = fxdr_hyper(tl); tl += 2;
4106                 sbp->sf_ffiles = fxdr_hyper(tl); tl += 2;
4107                 sbp->sf_afiles = fxdr_hyper(tl); tl += 2;
4108                 sbp->sf_invarsec = fxdr_unsigned(u_int32_t, *tl);
4109         } else if (NFSHASNFSV4(nmp) == 0) {
4110                 sbp->sf_tsize = fxdr_unsigned(u_int32_t, *tl++);
4111                 sbp->sf_bsize = fxdr_unsigned(u_int32_t, *tl++);
4112                 sbp->sf_blocks = fxdr_unsigned(u_int32_t, *tl++);
4113                 sbp->sf_bfree = fxdr_unsigned(u_int32_t, *tl++);
4114                 sbp->sf_bavail = fxdr_unsigned(u_int32_t, *tl);
4115         }
4116 nfsmout:
4117         mbuf_freem(nd->nd_mrep);
4118         return (error);
4119 }
4120
4121 /*
4122  * nfs pathconf rpc
4123  */
4124 APPLESTATIC int
4125 nfsrpc_pathconf(vnode_t vp, struct nfsv3_pathconf *pc,
4126     struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp,
4127     void *stuff)
4128 {
4129         struct nfsrv_descript nfsd, *nd = &nfsd;
4130         struct nfsmount *nmp;
4131         u_int32_t *tl;
4132         nfsattrbit_t attrbits;
4133         int error;
4134
4135         *attrflagp = 0;
4136         nmp = VFSTONFS(vnode_mount(vp));
4137         if (NFSHASNFSV4(nmp)) {
4138                 /*
4139                  * For V4, you actually do a getattr.
4140                  */
4141                 NFSCL_REQSTART(nd, NFSPROC_GETATTR, vp);
4142                 NFSPATHCONF_GETATTRBIT(&attrbits);
4143                 (void) nfsrv_putattrbit(nd, &attrbits);
4144                 nd->nd_flag |= ND_USEGSSNAME;
4145                 error = nfscl_request(nd, vp, p, cred, stuff);
4146                 if (error)
4147                         return (error);
4148                 if (nd->nd_repstat == 0) {
4149                         error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0,
4150                             pc, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, p,
4151                             cred);
4152                         if (!error)
4153                                 *attrflagp = 1;
4154                 } else {
4155                         error = nd->nd_repstat;
4156                 }
4157         } else {
4158                 NFSCL_REQSTART(nd, NFSPROC_PATHCONF, vp);
4159                 error = nfscl_request(nd, vp, p, cred, stuff);
4160                 if (error)
4161                         return (error);
4162                 error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
4163                 if (nd->nd_repstat && !error)
4164                         error = nd->nd_repstat;
4165                 if (!error) {
4166                         NFSM_DISSECT(tl, u_int32_t *, NFSX_V3PATHCONF);
4167                         pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl++);
4168                         pc->pc_namemax = fxdr_unsigned(u_int32_t, *tl++);
4169                         pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl++);
4170                         pc->pc_chownrestricted =
4171                             fxdr_unsigned(u_int32_t, *tl++);
4172                         pc->pc_caseinsensitive =
4173                             fxdr_unsigned(u_int32_t, *tl++);
4174                         pc->pc_casepreserving = fxdr_unsigned(u_int32_t, *tl);
4175                 }
4176         }
4177 nfsmout:
4178         mbuf_freem(nd->nd_mrep);
4179         return (error);
4180 }
4181
4182 /*
4183  * nfs version 3 fsinfo rpc call
4184  */
4185 APPLESTATIC int
4186 nfsrpc_fsinfo(vnode_t vp, struct nfsfsinfo *fsp, struct ucred *cred,
4187     NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff)
4188 {
4189         u_int32_t *tl;
4190         struct nfsrv_descript nfsd, *nd = &nfsd;
4191         int error;
4192
4193         *attrflagp = 0;
4194         NFSCL_REQSTART(nd, NFSPROC_FSINFO, vp);
4195         error = nfscl_request(nd, vp, p, cred, stuff);
4196         if (error)
4197                 return (error);
4198         error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
4199         if (nd->nd_repstat && !error)
4200                 error = nd->nd_repstat;
4201         if (!error) {
4202                 NFSM_DISSECT(tl, u_int32_t *, NFSX_V3FSINFO);
4203                 fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *tl++);
4204                 fsp->fs_rtpref = fxdr_unsigned(u_int32_t, *tl++);
4205                 fsp->fs_rtmult = fxdr_unsigned(u_int32_t, *tl++);
4206                 fsp->fs_wtmax = fxdr_unsigned(u_int32_t, *tl++);
4207                 fsp->fs_wtpref = fxdr_unsigned(u_int32_t, *tl++);
4208                 fsp->fs_wtmult = fxdr_unsigned(u_int32_t, *tl++);
4209                 fsp->fs_dtpref = fxdr_unsigned(u_int32_t, *tl++);
4210                 fsp->fs_maxfilesize = fxdr_hyper(tl);
4211                 tl += 2;
4212                 fxdr_nfsv3time(tl, &fsp->fs_timedelta);
4213                 tl += 2;
4214                 fsp->fs_properties = fxdr_unsigned(u_int32_t, *tl);
4215         }
4216 nfsmout:
4217         mbuf_freem(nd->nd_mrep);
4218         return (error);
4219 }
4220
4221 /*
4222  * This function performs the Renew RPC.
4223  */
4224 APPLESTATIC int
4225 nfsrpc_renew(struct nfsclclient *clp, struct nfsclds *dsp, struct ucred *cred,
4226     NFSPROC_T *p)
4227 {
4228         u_int32_t *tl;
4229         struct nfsrv_descript nfsd;
4230         struct nfsrv_descript *nd = &nfsd;
4231         struct nfsmount *nmp;
4232         int error;
4233         struct nfssockreq *nrp;
4234
4235         nmp = clp->nfsc_nmp;
4236         if (nmp == NULL)
4237                 return (0);
4238         nfscl_reqstart(nd, NFSPROC_RENEW, nmp, NULL, 0, NULL,
4239             &dsp->nfsclds_sess);
4240         if (!NFSHASNFSV4N(nmp)) {
4241                 /* NFSv4.1 just uses a Sequence Op and not a Renew. */
4242                 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
4243                 *tl++ = NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[0];
4244                 *tl = NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[1];
4245         }
4246         nrp = dsp->nfsclds_sockp;
4247         if (nrp == NULL)
4248                 /* If NULL, use the MDS socket. */
4249                 nrp = &nmp->nm_sockreq;
4250         nd->nd_flag |= ND_USEGSSNAME;
4251         error = newnfs_request(nd, nmp, NULL, nrp, NULL, p, cred,
4252             NFS_PROG, NFS_VER4, NULL, 1, NULL, &dsp->nfsclds_sess);
4253         if (error)
4254                 return (error);
4255         error = nd->nd_repstat;
4256         mbuf_freem(nd->nd_mrep);
4257         return (error);
4258 }
4259
4260 /*
4261  * This function performs the Releaselockowner RPC.
4262  */
4263 APPLESTATIC int
4264 nfsrpc_rellockown(struct nfsmount *nmp, struct nfscllockowner *lp,
4265     uint8_t *fh, int fhlen, struct ucred *cred, NFSPROC_T *p)
4266 {
4267         struct nfsrv_descript nfsd, *nd = &nfsd;
4268         u_int32_t *tl;
4269         int error;
4270         uint8_t own[NFSV4CL_LOCKNAMELEN + NFSX_V4FHMAX];
4271
4272         if (NFSHASNFSV4N(nmp)) {
4273                 /* For NFSv4.1, do a FreeStateID. */
4274                 nfscl_reqstart(nd, NFSPROC_FREESTATEID, nmp, NULL, 0, NULL,
4275                     NULL);
4276                 nfsm_stateidtom(nd, &lp->nfsl_stateid, NFSSTATEID_PUTSTATEID);
4277         } else {
4278                 nfscl_reqstart(nd, NFSPROC_RELEASELCKOWN, nmp, NULL, 0, NULL,
4279                     NULL);
4280                 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
4281                 *tl++ = NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[0];
4282                 *tl = NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[1];
4283                 NFSBCOPY(lp->nfsl_owner, own, NFSV4CL_LOCKNAMELEN);
4284                 NFSBCOPY(fh, &own[NFSV4CL_LOCKNAMELEN], fhlen);
4285                 (void)nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN + fhlen);
4286         }
4287         nd->nd_flag |= ND_USEGSSNAME;
4288         error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
4289             NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
4290         if (error)
4291                 return (error);
4292         error = nd->nd_repstat;
4293         mbuf_freem(nd->nd_mrep);
4294         return (error);
4295 }
4296
4297 /*
4298  * This function performs the Compound to get the mount pt FH.
4299  */
4300 APPLESTATIC int
4301 nfsrpc_getdirpath(struct nfsmount *nmp, u_char *dirpath, struct ucred *cred,
4302     NFSPROC_T *p)
4303 {
4304         u_int32_t *tl;
4305         struct nfsrv_descript nfsd;
4306         struct nfsrv_descript *nd = &nfsd;
4307         u_char *cp, *cp2;
4308         int error, cnt, len, setnil;
4309         u_int32_t *opcntp;
4310
4311         nfscl_reqstart(nd, NFSPROC_PUTROOTFH, nmp, NULL, 0, &opcntp, NULL);
4312         cp = dirpath;
4313         cnt = 0;
4314         do {
4315                 setnil = 0;
4316                 while (*cp == '/')
4317                         cp++;
4318                 cp2 = cp;
4319                 while (*cp2 != '\0' && *cp2 != '/')
4320                         cp2++;
4321                 if (*cp2 == '/') {
4322                         setnil = 1;
4323                         *cp2 = '\0';
4324                 }
4325                 if (cp2 != cp) {
4326                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
4327                         *tl = txdr_unsigned(NFSV4OP_LOOKUP);
4328                         nfsm_strtom(nd, cp, strlen(cp));
4329                         cnt++;
4330                 }
4331                 if (setnil)
4332                         *cp2++ = '/';
4333                 cp = cp2;
4334         } while (*cp != '\0');
4335         if (NFSHASNFSV4N(nmp))
4336                 /* Has a Sequence Op done by nfscl_reqstart(). */
4337                 *opcntp = txdr_unsigned(3 + cnt);
4338         else
4339                 *opcntp = txdr_unsigned(2 + cnt);
4340         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
4341         *tl = txdr_unsigned(NFSV4OP_GETFH);
4342         nd->nd_flag |= ND_USEGSSNAME;
4343         error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
4344                 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
4345         if (error)
4346                 return (error);
4347         if (nd->nd_repstat == 0) {
4348                 NFSM_DISSECT(tl, u_int32_t *, (3 + 2 * cnt) * NFSX_UNSIGNED);
4349                 tl += (2 + 2 * cnt);
4350                 if ((len = fxdr_unsigned(int, *tl)) <= 0 ||
4351                         len > NFSX_FHMAX) {
4352                         nd->nd_repstat = NFSERR_BADXDR;
4353                 } else {
4354                         nd->nd_repstat = nfsrv_mtostr(nd, nmp->nm_fh, len);
4355                         if (nd->nd_repstat == 0)
4356                                 nmp->nm_fhsize = len;
4357                 }
4358         }
4359         error = nd->nd_repstat;
4360 nfsmout:
4361         mbuf_freem(nd->nd_mrep);
4362         return (error);
4363 }
4364
4365 /*
4366  * This function performs the Delegreturn RPC.
4367  */
4368 APPLESTATIC int
4369 nfsrpc_delegreturn(struct nfscldeleg *dp, struct ucred *cred,
4370     struct nfsmount *nmp, NFSPROC_T *p, int syscred)
4371 {
4372         u_int32_t *tl;
4373         struct nfsrv_descript nfsd;
4374         struct nfsrv_descript *nd = &nfsd;
4375         int error;
4376
4377         nfscl_reqstart(nd, NFSPROC_DELEGRETURN, nmp, dp->nfsdl_fh,
4378             dp->nfsdl_fhlen, NULL, NULL);
4379         NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
4380         if (NFSHASNFSV4N(nmp))
4381                 *tl++ = 0;
4382         else
4383                 *tl++ = dp->nfsdl_stateid.seqid;
4384         *tl++ = dp->nfsdl_stateid.other[0];
4385         *tl++ = dp->nfsdl_stateid.other[1];
4386         *tl = dp->nfsdl_stateid.other[2];
4387         if (syscred)
4388                 nd->nd_flag |= ND_USEGSSNAME;
4389         error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
4390             NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
4391         if (error)
4392                 return (error);
4393         error = nd->nd_repstat;
4394         mbuf_freem(nd->nd_mrep);
4395         return (error);
4396 }
4397
4398 /*
4399  * nfs getacl call.
4400  */
4401 APPLESTATIC int
4402 nfsrpc_getacl(vnode_t vp, struct ucred *cred, NFSPROC_T *p,
4403     struct acl *aclp, void *stuff)
4404 {
4405         struct nfsrv_descript nfsd, *nd = &nfsd;
4406         int error;
4407         nfsattrbit_t attrbits;
4408         struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
4409         
4410         if (nfsrv_useacl == 0 || !NFSHASNFSV4(nmp))
4411                 return (EOPNOTSUPP);
4412         NFSCL_REQSTART(nd, NFSPROC_GETACL, vp);
4413         NFSZERO_ATTRBIT(&attrbits);
4414         NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_ACL);
4415         (void) nfsrv_putattrbit(nd, &attrbits);
4416         error = nfscl_request(nd, vp, p, cred, stuff);
4417         if (error)
4418                 return (error);
4419         if (!nd->nd_repstat)
4420                 error = nfsv4_loadattr(nd, vp, NULL, NULL, NULL, 0, NULL,
4421                     NULL, NULL, NULL, aclp, 0, NULL, NULL, NULL, p, cred);
4422         else
4423                 error = nd->nd_repstat;
4424         mbuf_freem(nd->nd_mrep);
4425         return (error);
4426 }
4427
4428 /*
4429  * nfs setacl call.
4430  */
4431 APPLESTATIC int
4432 nfsrpc_setacl(vnode_t vp, struct ucred *cred, NFSPROC_T *p,
4433     struct acl *aclp, void *stuff)
4434 {
4435         int error;
4436         struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
4437         
4438         if (nfsrv_useacl == 0 || !NFSHASNFSV4(nmp))
4439                 return (EOPNOTSUPP);
4440         error = nfsrpc_setattr(vp, NULL, aclp, cred, p, NULL, NULL, stuff);
4441         return (error);
4442 }
4443
4444 /*
4445  * nfs setacl call.
4446  */
4447 static int
4448 nfsrpc_setaclrpc(vnode_t vp, struct ucred *cred, NFSPROC_T *p,
4449     struct acl *aclp, nfsv4stateid_t *stateidp, void *stuff)
4450 {
4451         struct nfsrv_descript nfsd, *nd = &nfsd;
4452         int error;
4453         nfsattrbit_t attrbits;
4454         struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
4455         
4456         if (!NFSHASNFSV4(nmp))
4457                 return (EOPNOTSUPP);
4458         NFSCL_REQSTART(nd, NFSPROC_SETACL, vp);
4459         nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID);
4460         NFSZERO_ATTRBIT(&attrbits);
4461         NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_ACL);
4462         (void) nfsv4_fillattr(nd, vnode_mount(vp), vp, aclp, NULL, NULL, 0,
4463             &attrbits, NULL, NULL, 0, 0, 0, 0, (uint64_t)0);
4464         error = nfscl_request(nd, vp, p, cred, stuff);
4465         if (error)
4466                 return (error);
4467         /* Don't care about the pre/postop attributes */
4468         mbuf_freem(nd->nd_mrep);
4469         return (nd->nd_repstat);
4470 }
4471
4472 /*
4473  * Do the NFSv4.1 Exchange ID.
4474  */
4475 int
4476 nfsrpc_exchangeid(struct nfsmount *nmp, struct nfsclclient *clp,
4477     struct nfssockreq *nrp, uint32_t exchflags, struct nfsclds **dspp,
4478     struct ucred *cred, NFSPROC_T *p)
4479 {
4480         uint32_t *tl, v41flags;
4481         struct nfsrv_descript nfsd;
4482         struct nfsrv_descript *nd = &nfsd;
4483         struct nfsclds *dsp;
4484         struct timespec verstime;
4485         int error, len;
4486
4487         *dspp = NULL;
4488         nfscl_reqstart(nd, NFSPROC_EXCHANGEID, nmp, NULL, 0, NULL, NULL);
4489         NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
4490         *tl++ = txdr_unsigned(nfsboottime.tv_sec);      /* Client owner */
4491         *tl = txdr_unsigned(clp->nfsc_rev);
4492         (void) nfsm_strtom(nd, clp->nfsc_id, clp->nfsc_idlen);
4493
4494         NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED);
4495         *tl++ = txdr_unsigned(exchflags);
4496         *tl++ = txdr_unsigned(NFSV4EXCH_SP4NONE);
4497
4498         /* Set the implementation id4 */
4499         *tl = txdr_unsigned(1);
4500         (void) nfsm_strtom(nd, "freebsd.org", strlen("freebsd.org"));
4501         (void) nfsm_strtom(nd, version, strlen(version));
4502         NFSM_BUILD(tl, uint32_t *, NFSX_V4TIME);
4503         verstime.tv_sec = 1293840000;           /* Jan 1, 2011 */
4504         verstime.tv_nsec = 0;
4505         txdr_nfsv4time(&verstime, tl);
4506         nd->nd_flag |= ND_USEGSSNAME;
4507         error = newnfs_request(nd, nmp, NULL, nrp, NULL, p, cred,
4508             NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
4509         NFSCL_DEBUG(1, "exchangeid err=%d reps=%d\n", error,
4510             (int)nd->nd_repstat);
4511         if (error != 0)
4512                 return (error);
4513         if (nd->nd_repstat == 0) {
4514                 NFSM_DISSECT(tl, uint32_t *, 6 * NFSX_UNSIGNED + NFSX_HYPER);
4515                 len = fxdr_unsigned(int, *(tl + 7));
4516                 if (len < 0 || len > NFSV4_OPAQUELIMIT) {
4517                         error = NFSERR_BADXDR;
4518                         goto nfsmout;
4519                 }
4520                 dsp = malloc(sizeof(struct nfsclds) + len, M_NFSCLDS,
4521                     M_WAITOK | M_ZERO);
4522                 dsp->nfsclds_expire = NFSD_MONOSEC + clp->nfsc_renew;
4523                 dsp->nfsclds_servownlen = len;
4524                 dsp->nfsclds_sess.nfsess_clientid.lval[0] = *tl++;
4525                 dsp->nfsclds_sess.nfsess_clientid.lval[1] = *tl++;
4526                 dsp->nfsclds_sess.nfsess_sequenceid =
4527                     fxdr_unsigned(uint32_t, *tl++);
4528                 v41flags = fxdr_unsigned(uint32_t, *tl);
4529                 if ((v41flags & NFSV4EXCH_USEPNFSMDS) != 0 &&
4530                     NFSHASPNFSOPT(nmp)) {
4531                         NFSCL_DEBUG(1, "set PNFS\n");
4532                         NFSLOCKMNT(nmp);
4533                         nmp->nm_state |= NFSSTA_PNFS;
4534                         NFSUNLOCKMNT(nmp);
4535                         dsp->nfsclds_flags |= NFSCLDS_MDS;
4536                 }
4537                 if ((v41flags & NFSV4EXCH_USEPNFSDS) != 0)
4538                         dsp->nfsclds_flags |= NFSCLDS_DS;
4539                 if (len > 0)
4540                         nd->nd_repstat = nfsrv_mtostr(nd,
4541                             dsp->nfsclds_serverown, len);
4542                 if (nd->nd_repstat == 0) {
4543                         mtx_init(&dsp->nfsclds_mtx, "nfsds", NULL, MTX_DEF);
4544                         mtx_init(&dsp->nfsclds_sess.nfsess_mtx, "nfssession",
4545                             NULL, MTX_DEF);
4546                         nfscl_initsessionslots(&dsp->nfsclds_sess);
4547                         *dspp = dsp;
4548                 } else
4549                         free(dsp, M_NFSCLDS);
4550         }
4551         error = nd->nd_repstat;
4552 nfsmout:
4553         mbuf_freem(nd->nd_mrep);
4554         return (error);
4555 }
4556
4557 /*
4558  * Do the NFSv4.1 Create Session.
4559  */
4560 int
4561 nfsrpc_createsession(struct nfsmount *nmp, struct nfsclsession *sep,
4562     struct nfssockreq *nrp, uint32_t sequenceid, int mds, struct ucred *cred,
4563     NFSPROC_T *p)
4564 {
4565         uint32_t crflags, *tl;
4566         struct nfsrv_descript nfsd;
4567         struct nfsrv_descript *nd = &nfsd;
4568         int error, irdcnt;
4569
4570         nfscl_reqstart(nd, NFSPROC_CREATESESSION, nmp, NULL, 0, NULL, NULL);
4571         NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED);
4572         *tl++ = sep->nfsess_clientid.lval[0];
4573         *tl++ = sep->nfsess_clientid.lval[1];
4574         *tl++ = txdr_unsigned(sequenceid);
4575         crflags = (NFSMNT_RDONLY(nmp->nm_mountp) ? 0 : NFSV4CRSESS_PERSIST);
4576         if (nfscl_enablecallb != 0 && nfs_numnfscbd > 0)
4577                 crflags |= NFSV4CRSESS_CONNBACKCHAN;
4578         *tl = txdr_unsigned(crflags);
4579
4580         /* Fill in fore channel attributes. */
4581         NFSM_BUILD(tl, uint32_t *, 7 * NFSX_UNSIGNED);
4582         *tl++ = 0;                              /* Header pad size */
4583         *tl++ = txdr_unsigned(100000);          /* Max request size */
4584         *tl++ = txdr_unsigned(100000);          /* Max response size */
4585         *tl++ = txdr_unsigned(4096);            /* Max response size cached */
4586         *tl++ = txdr_unsigned(20);              /* Max operations */
4587         *tl++ = txdr_unsigned(64);              /* Max slots */
4588         *tl = 0;                                /* No rdma ird */
4589
4590         /* Fill in back channel attributes. */
4591         NFSM_BUILD(tl, uint32_t *, 7 * NFSX_UNSIGNED);
4592         *tl++ = 0;                              /* Header pad size */
4593         *tl++ = txdr_unsigned(10000);           /* Max request size */
4594         *tl++ = txdr_unsigned(10000);           /* Max response size */
4595         *tl++ = txdr_unsigned(4096);            /* Max response size cached */
4596         *tl++ = txdr_unsigned(4);               /* Max operations */
4597         *tl++ = txdr_unsigned(NFSV4_CBSLOTS);   /* Max slots */
4598         *tl = 0;                                /* No rdma ird */
4599
4600         NFSM_BUILD(tl, uint32_t *, 8 * NFSX_UNSIGNED);
4601         *tl++ = txdr_unsigned(NFS_CALLBCKPROG); /* Call back prog # */
4602
4603         /* Allow AUTH_SYS callbacks as uid, gid == 0. */
4604         *tl++ = txdr_unsigned(1);               /* Auth_sys only */
4605         *tl++ = txdr_unsigned(AUTH_SYS);        /* AUTH_SYS type */
4606         *tl++ = txdr_unsigned(nfsboottime.tv_sec); /* time stamp */
4607         *tl++ = 0;                              /* Null machine name */
4608         *tl++ = 0;                              /* Uid == 0 */
4609         *tl++ = 0;                              /* Gid == 0 */
4610         *tl = 0;                                /* No additional gids */
4611         nd->nd_flag |= ND_USEGSSNAME;
4612         error = newnfs_request(nd, nmp, NULL, nrp, NULL, p, cred, NFS_PROG,
4613             NFS_VER4, NULL, 1, NULL, NULL);
4614         if (error != 0)
4615                 return (error);
4616         if (nd->nd_repstat == 0) {
4617                 NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID +
4618                     2 * NFSX_UNSIGNED);
4619                 bcopy(tl, sep->nfsess_sessionid, NFSX_V4SESSIONID);
4620                 tl += NFSX_V4SESSIONID / NFSX_UNSIGNED;
4621                 sep->nfsess_sequenceid = fxdr_unsigned(uint32_t, *tl++);
4622                 crflags = fxdr_unsigned(uint32_t, *tl);
4623                 if ((crflags & NFSV4CRSESS_PERSIST) != 0 && mds != 0) {
4624                         NFSLOCKMNT(nmp);
4625                         nmp->nm_state |= NFSSTA_SESSPERSIST;
4626                         NFSUNLOCKMNT(nmp);
4627                 }
4628
4629                 /* Get the fore channel slot count. */
4630                 NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED);
4631                 tl += 3;                /* Skip the other counts. */            
4632                 sep->nfsess_maxcache = fxdr_unsigned(int, *tl++);
4633                 tl++;
4634                 sep->nfsess_foreslots = fxdr_unsigned(uint16_t, *tl++);
4635                 NFSCL_DEBUG(4, "fore slots=%d\n", (int)sep->nfsess_foreslots);
4636                 irdcnt = fxdr_unsigned(int, *tl);
4637                 if (irdcnt > 0)
4638                         NFSM_DISSECT(tl, uint32_t *, irdcnt * NFSX_UNSIGNED);
4639
4640                 /* and the back channel slot count. */
4641                 NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED);
4642                 tl += 5;
4643                 sep->nfsess_backslots = fxdr_unsigned(uint16_t, *tl);
4644                 NFSCL_DEBUG(4, "back slots=%d\n", (int)sep->nfsess_backslots);
4645         }
4646         error = nd->nd_repstat;
4647 nfsmout:
4648         mbuf_freem(nd->nd_mrep);
4649         return (error);
4650 }
4651
4652 /*
4653  * Do the NFSv4.1 Destroy Session.
4654  */
4655 int
4656 nfsrpc_destroysession(struct nfsmount *nmp, struct nfsclclient *clp,
4657     struct ucred *cred, NFSPROC_T *p)
4658 {
4659         uint32_t *tl;
4660         struct nfsrv_descript nfsd;
4661         struct nfsrv_descript *nd = &nfsd;
4662         int error;
4663
4664         nfscl_reqstart(nd, NFSPROC_DESTROYSESSION, nmp, NULL, 0, NULL, NULL);
4665         NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID);
4666         bcopy(NFSMNT_MDSSESSION(nmp)->nfsess_sessionid, tl, NFSX_V4SESSIONID);
4667         nd->nd_flag |= ND_USEGSSNAME;
4668         error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
4669             NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
4670         if (error != 0)
4671                 return (error);
4672         error = nd->nd_repstat;
4673         mbuf_freem(nd->nd_mrep);
4674         return (error);
4675 }
4676
4677 /*
4678  * Do the NFSv4.1 Destroy Client.
4679  */
4680 int
4681 nfsrpc_destroyclient(struct nfsmount *nmp, struct nfsclclient *clp,
4682     struct ucred *cred, NFSPROC_T *p)
4683 {
4684         uint32_t *tl;
4685         struct nfsrv_descript nfsd;
4686         struct nfsrv_descript *nd = &nfsd;
4687         int error;
4688
4689         nfscl_reqstart(nd, NFSPROC_DESTROYCLIENT, nmp, NULL, 0, NULL, NULL);
4690         NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
4691         *tl++ = NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[0];
4692         *tl = NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[1];
4693         nd->nd_flag |= ND_USEGSSNAME;
4694         error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
4695             NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
4696         if (error != 0)
4697                 return (error);
4698         error = nd->nd_repstat;
4699         mbuf_freem(nd->nd_mrep);
4700         return (error);
4701 }
4702
4703 /*
4704  * Do the NFSv4.1 LayoutGet.
4705  */
4706 int
4707 nfsrpc_layoutget(struct nfsmount *nmp, uint8_t *fhp, int fhlen, int iomode,
4708     uint64_t offset, uint64_t len, uint64_t minlen, int layoutlen,
4709     nfsv4stateid_t *stateidp, int *retonclosep, struct nfsclflayouthead *flhp,
4710     struct ucred *cred, NFSPROC_T *p, void *stuff)
4711 {
4712         uint32_t *tl;
4713         struct nfsrv_descript nfsd, *nd = &nfsd;
4714         struct nfsfh *nfhp;
4715         struct nfsclflayout *flp, *prevflp, *tflp;
4716         int cnt, error, gotiomode, fhcnt, nfhlen, i, j;
4717         uint8_t *cp;
4718         uint64_t retlen;
4719
4720         flp = NULL;
4721         gotiomode = -1;
4722         nfscl_reqstart(nd, NFSPROC_LAYOUTGET, nmp, fhp, fhlen, NULL, NULL);
4723         NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED + 3 * NFSX_HYPER +
4724             NFSX_STATEID);
4725         *tl++ = newnfs_false;           /* Don't signal availability. */
4726         *tl++ = txdr_unsigned(NFSLAYOUT_NFSV4_1_FILES);
4727         *tl++ = txdr_unsigned(iomode);
4728         txdr_hyper(offset, tl);
4729         tl += 2;
4730         txdr_hyper(len, tl);
4731         tl += 2;
4732         txdr_hyper(minlen, tl);
4733         tl += 2;
4734         *tl++ = txdr_unsigned(stateidp->seqid);
4735         NFSCL_DEBUG(4, "layget seq=%d\n", (int)stateidp->seqid);
4736         *tl++ = stateidp->other[0];
4737         *tl++ = stateidp->other[1];
4738         *tl++ = stateidp->other[2];
4739         *tl = txdr_unsigned(layoutlen);
4740         nd->nd_flag |= ND_USEGSSNAME;
4741         error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
4742             NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
4743         if (error != 0)
4744                 return (error);
4745         if (nd->nd_repstat == 0) {
4746                 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + NFSX_STATEID);
4747                 if (*tl++ != 0)
4748                         *retonclosep = 1;
4749                 else
4750                         *retonclosep = 0;
4751                 stateidp->seqid = fxdr_unsigned(uint32_t, *tl++);
4752                 NFSCL_DEBUG(4, "retoncls=%d stseq=%d\n", *retonclosep,
4753                     (int)stateidp->seqid);
4754                 stateidp->other[0] = *tl++;
4755                 stateidp->other[1] = *tl++;
4756                 stateidp->other[2] = *tl++;
4757                 cnt = fxdr_unsigned(int, *tl);
4758                 NFSCL_DEBUG(4, "layg cnt=%d\n", cnt);
4759                 if (cnt <= 0 || cnt > 10000) {
4760                         /* Don't accept more than 10000 layouts in reply. */
4761                         error = NFSERR_BADXDR;
4762                         goto nfsmout;
4763                 }
4764                 for (i = 0; i < cnt; i++) {
4765                         /* Dissect all the way to the file handle cnt. */
4766                         NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_HYPER +
4767                             6 * NFSX_UNSIGNED + NFSX_V4DEVICEID);
4768                         fhcnt = fxdr_unsigned(int, *(tl + 11 +
4769                             NFSX_V4DEVICEID / NFSX_UNSIGNED));
4770                         NFSCL_DEBUG(4, "fhcnt=%d\n", fhcnt);
4771                         if (fhcnt < 0 || fhcnt > 100) {
4772                                 /* Don't accept more than 100 file handles. */
4773                                 error = NFSERR_BADXDR;
4774                                 goto nfsmout;
4775                         }
4776                         if (fhcnt > 1)
4777                                 flp = malloc(sizeof(*flp) + (fhcnt - 1) *
4778                                     sizeof(struct nfsfh *),
4779                                     M_NFSFLAYOUT, M_WAITOK);
4780                         else
4781                                 flp = malloc(sizeof(*flp),
4782                                     M_NFSFLAYOUT, M_WAITOK);
4783                         flp->nfsfl_flags = 0;
4784                         flp->nfsfl_fhcnt = 0;
4785                         flp->nfsfl_devp = NULL;
4786                         flp->nfsfl_off = fxdr_hyper(tl); tl += 2;
4787                         retlen = fxdr_hyper(tl); tl += 2;
4788                         if (flp->nfsfl_off + retlen < flp->nfsfl_off)
4789                                 flp->nfsfl_end = UINT64_MAX - flp->nfsfl_off;
4790                         else
4791                                 flp->nfsfl_end = flp->nfsfl_off + retlen;
4792                         flp->nfsfl_iomode = fxdr_unsigned(int, *tl++);
4793                         if (gotiomode == -1)
4794                                 gotiomode = flp->nfsfl_iomode;
4795                         NFSCL_DEBUG(4, "layg reqiom=%d retiom=%d\n", iomode,
4796                             (int)flp->nfsfl_iomode);
4797                         if (fxdr_unsigned(int, *tl++) !=
4798                             NFSLAYOUT_NFSV4_1_FILES) {
4799                                 printf("NFSv4.1: got non-files layout\n");
4800                                 error = NFSERR_BADXDR;
4801                                 goto nfsmout;
4802                         }
4803                         NFSBCOPY(++tl, flp->nfsfl_dev, NFSX_V4DEVICEID);
4804                         tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED);
4805                         flp->nfsfl_util = fxdr_unsigned(uint32_t, *tl++);
4806                         NFSCL_DEBUG(4, "flutil=0x%x\n", flp->nfsfl_util);
4807                         flp->nfsfl_stripe1 = fxdr_unsigned(uint32_t, *tl++);
4808                         flp->nfsfl_patoff = fxdr_hyper(tl); tl += 2;
4809                         if (fxdr_unsigned(int, *tl) != fhcnt) {
4810                                 printf("EEK! bad fhcnt\n");
4811                                 error = NFSERR_BADXDR;
4812                                 goto nfsmout;
4813                         }
4814                         for (j = 0; j < fhcnt; j++) {
4815                                 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4816                                 nfhlen = fxdr_unsigned(int, *tl);
4817                                 if (nfhlen <= 0 || nfhlen > NFSX_V4FHMAX) {
4818                                         error = NFSERR_BADXDR;
4819                                         goto nfsmout;
4820                                 }
4821                                 nfhp = malloc(sizeof(*nfhp) + nfhlen - 1,
4822                                     M_NFSFH, M_WAITOK);
4823                                 flp->nfsfl_fh[j] = nfhp;
4824                                 flp->nfsfl_fhcnt++;
4825                                 nfhp->nfh_len = nfhlen;
4826                                 NFSM_DISSECT(cp, uint8_t *, NFSM_RNDUP(nfhlen));
4827                                 NFSBCOPY(cp, nfhp->nfh_fh, nfhlen);
4828                         }
4829                         if (flp->nfsfl_iomode == gotiomode) {
4830                                 /* Keep the list in increasing offset order. */
4831                                 tflp = LIST_FIRST(flhp);
4832                                 prevflp = NULL;
4833                                 while (tflp != NULL &&
4834                                     tflp->nfsfl_off < flp->nfsfl_off) {
4835                                         prevflp = tflp;
4836                                         tflp = LIST_NEXT(tflp, nfsfl_list);
4837                                 }
4838                                 if (prevflp == NULL)
4839                                         LIST_INSERT_HEAD(flhp, flp, nfsfl_list);
4840                                 else
4841                                         LIST_INSERT_AFTER(prevflp, flp,
4842                                             nfsfl_list);
4843                         } else {
4844                                 printf("nfscl_layoutget(): got wrong iomode\n");
4845                                 nfscl_freeflayout(flp);
4846                         }
4847                         flp = NULL;
4848                 }
4849         }
4850         if (nd->nd_repstat != 0 && error == 0)
4851                 error = nd->nd_repstat;
4852 nfsmout:
4853         if (error != 0 && flp != NULL)
4854                 nfscl_freeflayout(flp);
4855         mbuf_freem(nd->nd_mrep);
4856         return (error);
4857 }
4858
4859 /*
4860  * Do the NFSv4.1 Get Device Info.
4861  */
4862 int
4863 nfsrpc_getdeviceinfo(struct nfsmount *nmp, uint8_t *deviceid, int layouttype,
4864     uint32_t *notifybitsp, struct nfscldevinfo **ndip, struct ucred *cred,
4865     NFSPROC_T *p)
4866 {
4867         uint32_t cnt, *tl;
4868         struct nfsrv_descript nfsd;
4869         struct nfsrv_descript *nd = &nfsd;
4870         struct sockaddr_storage ss;
4871         struct nfsclds *dsp = NULL, **dspp;
4872         struct nfscldevinfo *ndi;
4873         int addrcnt, bitcnt, error, i, isudp, j, pos, safilled, stripecnt;
4874         uint8_t stripeindex;
4875
4876         *ndip = NULL;
4877         ndi = NULL;
4878         nfscl_reqstart(nd, NFSPROC_GETDEVICEINFO, nmp, NULL, 0, NULL, NULL);
4879         NFSM_BUILD(tl, uint32_t *, NFSX_V4DEVICEID + 3 * NFSX_UNSIGNED);
4880         NFSBCOPY(deviceid, tl, NFSX_V4DEVICEID);
4881         tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED);
4882         *tl++ = txdr_unsigned(layouttype);
4883         *tl++ = txdr_unsigned(100000);
4884         if (notifybitsp != NULL && *notifybitsp != 0) {
4885                 *tl = txdr_unsigned(1);         /* One word of bits. */
4886                 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
4887                 *tl = txdr_unsigned(*notifybitsp);
4888         } else
4889                 *tl = txdr_unsigned(0);
4890         nd->nd_flag |= ND_USEGSSNAME;
4891         error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
4892             NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
4893         if (error != 0)
4894                 return (error);
4895         if (nd->nd_repstat == 0) {
4896                 NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_UNSIGNED);
4897                 if (layouttype != fxdr_unsigned(int, *tl++))
4898                         printf("EEK! devinfo layout type not same!\n");
4899                 stripecnt = fxdr_unsigned(int, *++tl);
4900                 NFSCL_DEBUG(4, "stripecnt=%d\n", stripecnt);
4901                 if (stripecnt < 1 || stripecnt > 4096) {
4902                         printf("NFS devinfo stripecnt %d: out of range\n",
4903                             stripecnt);
4904                         error = NFSERR_BADXDR;
4905                         goto nfsmout;
4906                 }
4907                 NFSM_DISSECT(tl, uint32_t *, (stripecnt + 1) * NFSX_UNSIGNED);
4908                 addrcnt = fxdr_unsigned(int, *(tl + stripecnt));
4909                 NFSCL_DEBUG(4, "addrcnt=%d\n", addrcnt);
4910                 if (addrcnt < 1 || addrcnt > 128) {
4911                         printf("NFS devinfo addrcnt %d: out of range\n",
4912                             addrcnt);
4913                         error = NFSERR_BADXDR;
4914                         goto nfsmout;
4915                 }
4916
4917                 /*
4918                  * Now we know how many stripe indices and addresses, so
4919                  * we can allocate the structure the correct size.
4920                  */
4921                 i = (stripecnt * sizeof(uint8_t)) / sizeof(struct nfsclds *)
4922                     + 1;
4923                 NFSCL_DEBUG(4, "stripeindices=%d\n", i);
4924                 ndi = malloc(sizeof(*ndi) + (addrcnt + i) *
4925                     sizeof(struct nfsclds *), M_NFSDEVINFO, M_WAITOK | M_ZERO);
4926                 NFSBCOPY(deviceid, ndi->nfsdi_deviceid, NFSX_V4DEVICEID);
4927                 ndi->nfsdi_refcnt = 0;
4928                 ndi->nfsdi_stripecnt = stripecnt;
4929                 ndi->nfsdi_addrcnt = addrcnt;
4930                 /* Fill in the stripe indices. */
4931                 for (i = 0; i < stripecnt; i++) {
4932                         stripeindex = fxdr_unsigned(uint8_t, *tl++);
4933                         NFSCL_DEBUG(4, "stripeind=%d\n", stripeindex);
4934                         if (stripeindex >= addrcnt) {
4935                                 printf("NFS devinfo stripeindex %d: too big\n",
4936                                     (int)stripeindex);
4937                                 error = NFSERR_BADXDR;
4938                                 goto nfsmout;
4939                         }
4940                         nfsfldi_setstripeindex(ndi, i, stripeindex);
4941                 }
4942
4943                 /* Now, dissect the server address(es). */
4944                 safilled = 0;
4945                 for (i = 0; i < addrcnt; i++) {
4946                         NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4947                         cnt = fxdr_unsigned(uint32_t, *tl);
4948                         if (cnt == 0) {
4949                                 printf("NFS devinfo 0 len addrlist\n");
4950                                 error = NFSERR_BADXDR;
4951                                 goto nfsmout;
4952                         }
4953                         dspp = nfsfldi_addr(ndi, i);
4954                         pos = arc4random() % cnt;       /* Choose one. */
4955                         safilled = 0;
4956                         for (j = 0; j < cnt; j++) {
4957                                 error = nfsv4_getipaddr(nd, &ss, &isudp);
4958                                 if (error != 0 && error != EPERM) {
4959                                         error = NFSERR_BADXDR;
4960                                         goto nfsmout;
4961                                 }
4962                                 if (error == 0 && isudp == 0) {
4963                                         /*
4964                                          * The algorithm is:
4965                                          * - use "pos" entry if it is of the
4966                                          *   same af_family or none of them
4967                                          *   is of the same af_family
4968                                          * else
4969                                          * - use the first one of the same
4970                                          *   af_family.
4971                                          */
4972                                         if ((safilled == 0 && ss.ss_family ==
4973                                              nmp->nm_nam->sa_family) ||
4974                                             (j == pos &&
4975                                              (safilled == 0 || ss.ss_family ==
4976                                               nmp->nm_nam->sa_family)) ||
4977                                             (safilled == 1 && ss.ss_family ==
4978                                              nmp->nm_nam->sa_family)) {
4979                                                 error = nfsrpc_fillsa(nmp, &ss,
4980                                                     &dsp, p);
4981                                                 if (error == 0) {
4982                                                         *dspp = dsp;
4983                                                         if (ss.ss_family ==
4984                                                          nmp->nm_nam->sa_family)
4985                                                                 safilled = 2;
4986                                                         else
4987                                                                 safilled = 1;
4988                                                 }
4989                                         }
4990                                 }
4991                         }
4992                         if (safilled == 0)
4993                                 break;
4994                 }
4995
4996                 /* And the notify bits. */
4997                 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4998                 if (safilled != 0) {
4999                         bitcnt = fxdr_unsigned(int, *tl);
5000                         if (bitcnt > 0) {
5001                                 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
5002                                 if (notifybitsp != NULL)
5003                                         *notifybitsp =
5004                                             fxdr_unsigned(uint32_t, *tl);
5005                         }
5006                         *ndip = ndi;
5007                 } else
5008                         error = EPERM;
5009         }
5010         if (nd->nd_repstat != 0)
5011                 error = nd->nd_repstat;
5012 nfsmout:
5013         if (error != 0 && ndi != NULL)
5014                 nfscl_freedevinfo(ndi);
5015         mbuf_freem(nd->nd_mrep);
5016         return (error);
5017 }
5018
5019 /*
5020  * Do the NFSv4.1 LayoutCommit.
5021  */
5022 int
5023 nfsrpc_layoutcommit(struct nfsmount *nmp, uint8_t *fh, int fhlen, int reclaim,
5024     uint64_t off, uint64_t len, uint64_t lastbyte, nfsv4stateid_t *stateidp,
5025     int layouttype, int layoutupdatecnt, uint8_t *layp, struct ucred *cred,
5026     NFSPROC_T *p, void *stuff)
5027 {
5028         uint32_t *tl;
5029         struct nfsrv_descript nfsd, *nd = &nfsd;
5030         int error, outcnt, i;
5031         uint8_t *cp;
5032
5033         nfscl_reqstart(nd, NFSPROC_LAYOUTCOMMIT, nmp, fh, fhlen, NULL, NULL);
5034         NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED + 3 * NFSX_HYPER +
5035             NFSX_STATEID);
5036         txdr_hyper(off, tl);
5037         tl += 2;
5038         txdr_hyper(len, tl);
5039         tl += 2;
5040         if (reclaim != 0)
5041                 *tl++ = newnfs_true;
5042         else
5043                 *tl++ = newnfs_false;
5044         *tl++ = txdr_unsigned(stateidp->seqid);
5045         *tl++ = stateidp->other[0];
5046         *tl++ = stateidp->other[1];
5047         *tl++ = stateidp->other[2];
5048         *tl++ = newnfs_true;
5049         if (lastbyte < off)
5050                 lastbyte = off;
5051         else if (lastbyte >= (off + len))
5052                 lastbyte = off + len - 1;
5053         txdr_hyper(lastbyte, tl);
5054         tl += 2;
5055         *tl++ = newnfs_false;
5056         *tl++ = txdr_unsigned(layouttype);
5057         *tl = txdr_unsigned(layoutupdatecnt);
5058         if (layoutupdatecnt > 0) {
5059                 KASSERT(layouttype != NFSLAYOUT_NFSV4_1_FILES,
5060                     ("Must be nil for Files Layout"));
5061                 outcnt = NFSM_RNDUP(layoutupdatecnt);
5062                 NFSM_BUILD(cp, uint8_t *, outcnt);
5063                 NFSBCOPY(layp, cp, layoutupdatecnt);
5064                 cp += layoutupdatecnt;
5065                 for (i = 0; i < (outcnt - layoutupdatecnt); i++)
5066                         *cp++ = 0x0;
5067         }
5068         nd->nd_flag |= ND_USEGSSNAME;
5069         error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
5070             NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
5071         if (error != 0)
5072                 return (error);
5073         error = nd->nd_repstat;
5074         mbuf_freem(nd->nd_mrep);
5075         return (error);
5076 }
5077
5078 /*
5079  * Do the NFSv4.1 LayoutReturn.
5080  */
5081 int
5082 nfsrpc_layoutreturn(struct nfsmount *nmp, uint8_t *fh, int fhlen, int reclaim,
5083     int layouttype, uint32_t iomode, int layoutreturn, uint64_t offset,
5084     uint64_t len, nfsv4stateid_t *stateidp, int layoutcnt, uint32_t *layp,
5085     struct ucred *cred, NFSPROC_T *p, void *stuff)
5086 {
5087         uint32_t *tl;
5088         struct nfsrv_descript nfsd, *nd = &nfsd;
5089         int error, outcnt, i;
5090         uint8_t *cp;
5091
5092         nfscl_reqstart(nd, NFSPROC_LAYOUTRETURN, nmp, fh, fhlen, NULL, NULL);
5093         NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED);
5094         if (reclaim != 0)
5095                 *tl++ = newnfs_true;
5096         else
5097                 *tl++ = newnfs_false;
5098         *tl++ = txdr_unsigned(layouttype);
5099         *tl++ = txdr_unsigned(iomode);
5100         *tl = txdr_unsigned(layoutreturn);
5101         if (layoutreturn == NFSLAYOUTRETURN_FILE) {
5102                 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_STATEID +
5103                     NFSX_UNSIGNED);
5104                 txdr_hyper(offset, tl);
5105                 tl += 2;
5106                 txdr_hyper(len, tl);
5107                 tl += 2;
5108                 NFSCL_DEBUG(4, "layoutret stseq=%d\n", (int)stateidp->seqid);
5109                 *tl++ = txdr_unsigned(stateidp->seqid);
5110                 *tl++ = stateidp->other[0];
5111                 *tl++ = stateidp->other[1];
5112                 *tl++ = stateidp->other[2];
5113                 *tl = txdr_unsigned(layoutcnt);
5114                 if (layoutcnt > 0) {
5115                         outcnt = NFSM_RNDUP(layoutcnt);
5116                         NFSM_BUILD(cp, uint8_t *, outcnt);
5117                         NFSBCOPY(layp, cp, layoutcnt);
5118                         cp += layoutcnt;
5119                         for (i = 0; i < (outcnt - layoutcnt); i++)
5120                                 *cp++ = 0x0;
5121                 }
5122         }
5123         nd->nd_flag |= ND_USEGSSNAME;
5124         error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
5125             NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
5126         if (error != 0)
5127                 return (error);
5128         if (nd->nd_repstat == 0) {
5129                 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
5130                 if (*tl != 0) {
5131                         NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID);
5132                         stateidp->seqid = fxdr_unsigned(uint32_t, *tl++);
5133                         stateidp->other[0] = *tl++;
5134                         stateidp->other[1] = *tl++;
5135                         stateidp->other[2] = *tl;
5136                 }
5137         } else
5138                 error = nd->nd_repstat;
5139 nfsmout:
5140         mbuf_freem(nd->nd_mrep);
5141         return (error);
5142 }
5143
5144 /*
5145  * Acquire a layout and devinfo, if possible. The caller must have acquired
5146  * a reference count on the nfsclclient structure before calling this.
5147  * Return the layout in lypp with a reference count on it, if successful.
5148  */
5149 static int
5150 nfsrpc_getlayout(struct nfsmount *nmp, vnode_t vp, struct nfsfh *nfhp,
5151     int iomode, uint32_t *notifybitsp, nfsv4stateid_t *stateidp, uint64_t off,
5152     struct nfscllayout **lypp, struct ucred *cred, NFSPROC_T *p)
5153 {
5154         struct nfscllayout *lyp;
5155         struct nfsclflayout *flp, *tflp;
5156         struct nfscldevinfo *dip;
5157         struct nfsclflayouthead flh;
5158         int error = 0, islocked, layoutlen, recalled, retonclose;
5159         nfsv4stateid_t stateid;
5160
5161         *lypp = NULL;
5162         /*
5163          * If lyp is returned non-NULL, there will be a refcnt (shared lock)
5164          * on it, iff flp != NULL or a lock (exclusive lock) on it iff
5165          * flp == NULL.
5166          */
5167         lyp = nfscl_getlayout(nmp->nm_clp, nfhp->nfh_fh, nfhp->nfh_len,
5168             off, &flp, &recalled);
5169         islocked = 0;
5170         if (lyp == NULL || flp == NULL) {
5171                 if (recalled != 0)
5172                         return (EIO);
5173                 LIST_INIT(&flh);
5174                 layoutlen = NFSMNT_MDSSESSION(nmp)->nfsess_maxcache -
5175                     (NFSX_STATEID + 3 * NFSX_UNSIGNED);
5176                 if (lyp == NULL) {
5177                         stateid.seqid = 0;
5178                         stateid.other[0] = stateidp->other[0];
5179                         stateid.other[1] = stateidp->other[1];
5180                         stateid.other[2] = stateidp->other[2];
5181                         error = nfsrpc_layoutget(nmp, nfhp->nfh_fh,
5182                             nfhp->nfh_len, iomode, (uint64_t)0, INT64_MAX,
5183                             (uint64_t)0, layoutlen, &stateid, &retonclose,
5184                             &flh, cred, p, NULL);
5185                 } else {
5186                         islocked = 1;
5187                         stateid.seqid = lyp->nfsly_stateid.seqid;
5188                         stateid.other[0] = lyp->nfsly_stateid.other[0];
5189                         stateid.other[1] = lyp->nfsly_stateid.other[1];
5190                         stateid.other[2] = lyp->nfsly_stateid.other[2];
5191                         error = nfsrpc_layoutget(nmp, nfhp->nfh_fh,
5192                             nfhp->nfh_len, iomode, off, INT64_MAX,
5193                             (uint64_t)0, layoutlen, &stateid, &retonclose,
5194                             &flh, cred, p, NULL);
5195                 }
5196                 if (error == 0)
5197                         LIST_FOREACH(tflp, &flh, nfsfl_list) {
5198                                 error = nfscl_adddevinfo(nmp, NULL, tflp);
5199                                 if (error != 0) {
5200                                         error = nfsrpc_getdeviceinfo(nmp,
5201                                             tflp->nfsfl_dev,
5202                                             NFSLAYOUT_NFSV4_1_FILES,
5203                                             notifybitsp, &dip, cred, p);
5204                                         if (error != 0)
5205                                                 break;
5206                                         error = nfscl_adddevinfo(nmp, dip,
5207                                             tflp);
5208                                         if (error != 0)
5209                                                 printf(
5210                                                     "getlayout: cannot add\n");
5211                                 }
5212                         }
5213                 if (error == 0) {
5214                         /*
5215                          * nfscl_layout() always returns with the nfsly_lock
5216                          * set to a refcnt (shared lock).
5217                          */
5218                         error = nfscl_layout(nmp, vp, nfhp->nfh_fh,
5219                             nfhp->nfh_len, &stateid, retonclose, &flh, &lyp,
5220                             cred, p);
5221                         if (error == 0)
5222                                 *lypp = lyp;
5223                 } else if (islocked != 0)
5224                         nfsv4_unlock(&lyp->nfsly_lock, 0);
5225         } else
5226                 *lypp = lyp;
5227         return (error);
5228 }
5229
5230 /*
5231  * Do a TCP connection plus exchange id and create session.
5232  * If successful, a "struct nfsclds" is linked into the list for the
5233  * mount point and a pointer to it is returned.
5234  */
5235 static int
5236 nfsrpc_fillsa(struct nfsmount *nmp, struct sockaddr_storage *ssp,
5237     struct nfsclds **dspp, NFSPROC_T *p)
5238 {
5239         struct sockaddr_in *msad, *sad, *ssd;
5240         struct sockaddr_in6 *msad6, *sad6, *ssd6;
5241         struct nfsclclient *clp;
5242         struct nfssockreq *nrp;
5243         struct nfsclds *dsp, *tdsp;
5244         int error;
5245         enum nfsclds_state retv;
5246         uint32_t sequenceid;
5247
5248         KASSERT(nmp->nm_sockreq.nr_cred != NULL,
5249             ("nfsrpc_fillsa: NULL nr_cred"));
5250         NFSLOCKCLSTATE();
5251         clp = nmp->nm_clp;
5252         NFSUNLOCKCLSTATE();
5253         if (clp == NULL)
5254                 return (EPERM);
5255         if (ssp->ss_family == AF_INET) {
5256                 ssd = (struct sockaddr_in *)ssp;
5257                 NFSLOCKMNT(nmp);
5258
5259                 /*
5260                  * Check to see if we already have a session for this
5261                  * address that is usable for a DS.
5262                  * Note that the MDS's address is in a different place
5263                  * than the sessions already acquired for DS's.
5264                  */
5265                 msad = (struct sockaddr_in *)nmp->nm_sockreq.nr_nam;
5266                 tdsp = TAILQ_FIRST(&nmp->nm_sess);
5267                 while (tdsp != NULL) {
5268                         if (msad != NULL && msad->sin_family == AF_INET &&
5269                             ssd->sin_addr.s_addr == msad->sin_addr.s_addr &&
5270                             ssd->sin_port == msad->sin_port &&
5271                             (tdsp->nfsclds_flags & NFSCLDS_DS) != 0) {
5272                                 *dspp = tdsp;
5273                                 NFSUNLOCKMNT(nmp);
5274                                 NFSCL_DEBUG(4, "fnd same addr\n");
5275                                 return (0);
5276                         }
5277                         tdsp = TAILQ_NEXT(tdsp, nfsclds_list);
5278                         if (tdsp != NULL && tdsp->nfsclds_sockp != NULL)
5279                                 msad = (struct sockaddr_in *)
5280                                     tdsp->nfsclds_sockp->nr_nam;
5281                         else
5282                                 msad = NULL;
5283                 }
5284                 NFSUNLOCKMNT(nmp);
5285
5286                 /* No IP address match, so look for new/trunked one. */
5287                 sad = malloc(sizeof(*sad), M_SONAME, M_WAITOK | M_ZERO);
5288                 sad->sin_len = sizeof(*sad);
5289                 sad->sin_family = AF_INET;
5290                 sad->sin_port = ssd->sin_port;
5291                 sad->sin_addr.s_addr = ssd->sin_addr.s_addr;
5292                 nrp = malloc(sizeof(*nrp), M_NFSSOCKREQ, M_WAITOK | M_ZERO);
5293                 nrp->nr_nam = (struct sockaddr *)sad;
5294         } else if (ssp->ss_family == AF_INET6) {
5295                 ssd6 = (struct sockaddr_in6 *)ssp;
5296                 NFSLOCKMNT(nmp);
5297
5298                 /*
5299                  * Check to see if we already have a session for this
5300                  * address that is usable for a DS.
5301                  * Note that the MDS's address is in a different place
5302                  * than the sessions already acquired for DS's.
5303                  */
5304                 msad6 = (struct sockaddr_in6 *)nmp->nm_sockreq.nr_nam;
5305                 tdsp = TAILQ_FIRST(&nmp->nm_sess);
5306                 while (tdsp != NULL) {
5307                         if (msad6 != NULL && msad6->sin6_family == AF_INET6 &&
5308                             IN6_ARE_ADDR_EQUAL(&ssd6->sin6_addr,
5309                             &msad6->sin6_addr) &&
5310                             ssd6->sin6_port == msad6->sin6_port &&
5311                             (tdsp->nfsclds_flags & NFSCLDS_DS) != 0) {
5312                                 *dspp = tdsp;
5313                                 NFSUNLOCKMNT(nmp);
5314                                 return (0);
5315                         }
5316                         tdsp = TAILQ_NEXT(tdsp, nfsclds_list);
5317                         if (tdsp != NULL && tdsp->nfsclds_sockp != NULL)
5318                                 msad6 = (struct sockaddr_in6 *)
5319                                     tdsp->nfsclds_sockp->nr_nam;
5320                         else
5321                                 msad6 = NULL;
5322                 }
5323                 NFSUNLOCKMNT(nmp);
5324
5325                 /* No IP address match, so look for new/trunked one. */
5326                 sad6 = malloc(sizeof(*sad6), M_SONAME, M_WAITOK | M_ZERO);
5327                 sad6->sin6_len = sizeof(*sad6);
5328                 sad6->sin6_family = AF_INET6;
5329                 sad6->sin6_port = ssd6->sin6_port;
5330                 NFSBCOPY(&ssd6->sin6_addr, &sad6->sin6_addr,
5331                     sizeof(struct in6_addr));
5332                 nrp = malloc(sizeof(*nrp), M_NFSSOCKREQ, M_WAITOK | M_ZERO);
5333                 nrp->nr_nam = (struct sockaddr *)sad6;
5334         } else
5335                 return (EPERM);
5336
5337         nrp->nr_sotype = SOCK_STREAM;
5338         mtx_init(&nrp->nr_mtx, "nfssock", NULL, MTX_DEF);
5339         nrp->nr_prog = NFS_PROG;
5340         nrp->nr_vers = NFS_VER4;
5341
5342         /*
5343          * Use the credentials that were used for the mount, which are
5344          * in nmp->nm_sockreq.nr_cred for newnfs_connect() etc.
5345          * Ref. counting the credentials with crhold() is probably not
5346          * necessary, since nm_sockreq.nr_cred won't be crfree()'d until
5347          * unmount, but I did it anyhow.
5348          */
5349         nrp->nr_cred = crhold(nmp->nm_sockreq.nr_cred);
5350         error = newnfs_connect(nmp, nrp, NULL, p, 0);
5351         NFSCL_DEBUG(3, "DS connect=%d\n", error);
5352
5353         /* Now, do the exchangeid and create session. */
5354         if (error == 0)
5355                 error = nfsrpc_exchangeid(nmp, clp, nrp, NFSV4EXCH_USEPNFSDS,
5356                     &dsp, nrp->nr_cred, p);
5357         NFSCL_DEBUG(3, "DS exchangeid=%d\n", error);
5358         if (error == 0) {
5359                 dsp->nfsclds_sockp = nrp;
5360                 NFSLOCKMNT(nmp);
5361                 retv = nfscl_getsameserver(nmp, dsp, &tdsp);
5362                 NFSCL_DEBUG(3, "getsame ret=%d\n", retv);
5363                 if (retv == NFSDSP_USETHISSESSION) {
5364                         NFSUNLOCKMNT(nmp);
5365                         /*
5366                          * If there is already a session for this server,
5367                          * use it.
5368                          */
5369                         (void)newnfs_disconnect(nrp);
5370                         nfscl_freenfsclds(dsp);
5371                         *dspp = tdsp;
5372                         return (0);
5373                 }
5374                 if (retv == NFSDSP_SEQTHISSESSION)
5375                         sequenceid = tdsp->nfsclds_sess.nfsess_sequenceid;
5376                 else
5377                         sequenceid = dsp->nfsclds_sess.nfsess_sequenceid;
5378                 NFSUNLOCKMNT(nmp);
5379                 error = nfsrpc_createsession(nmp, &dsp->nfsclds_sess,
5380                     nrp, sequenceid, 0, nrp->nr_cred, p);
5381                 NFSCL_DEBUG(3, "DS createsess=%d\n", error);
5382         } else {
5383                 NFSFREECRED(nrp->nr_cred);
5384                 NFSFREEMUTEX(&nrp->nr_mtx);
5385                 free(nrp->nr_nam, M_SONAME);
5386                 free(nrp, M_NFSSOCKREQ);
5387         }
5388         if (error == 0) {
5389                 NFSCL_DEBUG(3, "add DS session\n");
5390                 /*
5391                  * Put it at the end of the list. That way the list
5392                  * is ordered by when the entry was added. This matters
5393                  * since the one done first is the one that should be
5394                  * used for sequencid'ing any subsequent create sessions.
5395                  */
5396                 NFSLOCKMNT(nmp);
5397                 TAILQ_INSERT_TAIL(&nmp->nm_sess, dsp, nfsclds_list);
5398                 NFSUNLOCKMNT(nmp);
5399                 *dspp = dsp;
5400         } else if (dsp != NULL)
5401                 nfscl_freenfsclds(dsp);
5402         return (error);
5403 }
5404
5405 /*
5406  * Do the NFSv4.1 Reclaim Complete.
5407  */
5408 int
5409 nfsrpc_reclaimcomplete(struct nfsmount *nmp, struct ucred *cred, NFSPROC_T *p)
5410 {
5411         uint32_t *tl;
5412         struct nfsrv_descript nfsd;
5413         struct nfsrv_descript *nd = &nfsd;
5414         int error;
5415
5416         nfscl_reqstart(nd, NFSPROC_RECLAIMCOMPL, nmp, NULL, 0, NULL, NULL);
5417         NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5418         *tl = newnfs_false;
5419         nd->nd_flag |= ND_USEGSSNAME;
5420         error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
5421             NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
5422         if (error != 0)
5423                 return (error);
5424         error = nd->nd_repstat;
5425         mbuf_freem(nd->nd_mrep);
5426         return (error);
5427 }
5428
5429 /*
5430  * Initialize the slot tables for a session.
5431  */
5432 static void
5433 nfscl_initsessionslots(struct nfsclsession *sep)
5434 {
5435         int i;
5436
5437         for (i = 0; i < NFSV4_CBSLOTS; i++) {
5438                 if (sep->nfsess_cbslots[i].nfssl_reply != NULL)
5439                         m_freem(sep->nfsess_cbslots[i].nfssl_reply);
5440                 NFSBZERO(&sep->nfsess_cbslots[i], sizeof(struct nfsslot));
5441         }
5442         for (i = 0; i < 64; i++)
5443                 sep->nfsess_slotseq[i] = 0;
5444         sep->nfsess_slots = 0;
5445 }
5446
5447 /*
5448  * Called to try and do an I/O operation via an NFSv4.1 Data Server (DS).
5449  */
5450 int
5451 nfscl_doiods(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit,
5452     uint32_t rwaccess, struct ucred *cred, NFSPROC_T *p)
5453 {
5454         struct nfsnode *np = VTONFS(vp);
5455         struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
5456         struct nfscllayout *layp;
5457         struct nfscldevinfo *dip;
5458         struct nfsclflayout *rflp;
5459         nfsv4stateid_t stateid;
5460         struct ucred *newcred;
5461         uint64_t lastbyte, len, off, oresid, xfer;
5462         int eof, error, iolaymode, recalled;
5463         void *lckp;
5464
5465         if (!NFSHASPNFS(nmp) || nfscl_enablecallb == 0 || nfs_numnfscbd == 0 ||
5466             (np->n_flag & NNOLAYOUT) != 0)
5467                 return (EIO);
5468         /* Now, get a reference cnt on the clientid for this mount. */
5469         if (nfscl_getref(nmp) == 0)
5470                 return (EIO);
5471
5472         /* Find an appropriate stateid. */
5473         newcred = NFSNEWCRED(cred);
5474         error = nfscl_getstateid(vp, np->n_fhp->nfh_fh, np->n_fhp->nfh_len,
5475             rwaccess, 1, newcred, p, &stateid, &lckp);
5476         if (error != 0) {
5477                 NFSFREECRED(newcred);
5478                 nfscl_relref(nmp);
5479                 return (error);
5480         }
5481         /* Search for a layout for this file. */
5482         off = uiop->uio_offset;
5483         layp = nfscl_getlayout(nmp->nm_clp, np->n_fhp->nfh_fh,
5484             np->n_fhp->nfh_len, off, &rflp, &recalled);
5485         if (layp == NULL || rflp == NULL) {
5486                 if (recalled != 0) {
5487                         NFSFREECRED(newcred);
5488                         nfscl_relref(nmp);
5489                         return (EIO);
5490                 }
5491                 if (layp != NULL) {
5492                         nfscl_rellayout(layp, (rflp == NULL) ? 1 : 0);
5493                         layp = NULL;
5494                 }
5495                 /* Try and get a Layout, if it is supported. */
5496                 if (rwaccess == NFSV4OPEN_ACCESSWRITE ||
5497                     (np->n_flag & NWRITEOPENED) != 0)
5498                         iolaymode = NFSLAYOUTIOMODE_RW;
5499                 else
5500                         iolaymode = NFSLAYOUTIOMODE_READ;
5501                 error = nfsrpc_getlayout(nmp, vp, np->n_fhp, iolaymode,
5502                     NULL, &stateid, off, &layp, newcred, p);
5503                 if (error != 0) {
5504                         NFSLOCKNODE(np);
5505                         np->n_flag |= NNOLAYOUT;
5506                         NFSUNLOCKNODE(np);
5507                         if (lckp != NULL)
5508                                 nfscl_lockderef(lckp);
5509                         NFSFREECRED(newcred);
5510                         if (layp != NULL)
5511                                 nfscl_rellayout(layp, 0);
5512                         nfscl_relref(nmp);
5513                         return (error);
5514                 }
5515         }
5516
5517         /*
5518          * Loop around finding a layout that works for the first part of
5519          * this I/O operation, and then call the function that actually
5520          * does the RPC.
5521          */
5522         eof = 0;
5523         len = (uint64_t)uiop->uio_resid;
5524         while (len > 0 && error == 0 && eof == 0) {
5525                 off = uiop->uio_offset;
5526                 error = nfscl_findlayoutforio(layp, off, rwaccess, &rflp);
5527                 if (error == 0) {
5528                         oresid = xfer = (uint64_t)uiop->uio_resid;
5529                         if (xfer > (rflp->nfsfl_end - rflp->nfsfl_off))
5530                                 xfer = rflp->nfsfl_end - rflp->nfsfl_off;
5531                         dip = nfscl_getdevinfo(nmp->nm_clp, rflp->nfsfl_dev,
5532                             rflp->nfsfl_devp);
5533                         if (dip != NULL) {
5534                                 error = nfscl_doflayoutio(vp, uiop, iomode,
5535                                     must_commit, &eof, &stateid, rwaccess, dip,
5536                                     layp, rflp, off, xfer, newcred, p);
5537                                 nfscl_reldevinfo(dip);
5538                                 lastbyte = off + xfer - 1;
5539                                 if (error == 0) {
5540                                         NFSLOCKCLSTATE();
5541                                         if (lastbyte > layp->nfsly_lastbyte)
5542                                                 layp->nfsly_lastbyte = lastbyte;
5543                                         NFSUNLOCKCLSTATE();
5544                                 }
5545                         } else
5546                                 error = EIO;
5547                         if (error == 0)
5548                                 len -= (oresid - (uint64_t)uiop->uio_resid);
5549                 }
5550         }
5551         if (lckp != NULL)
5552                 nfscl_lockderef(lckp);
5553         NFSFREECRED(newcred);
5554         nfscl_rellayout(layp, 0);
5555         nfscl_relref(nmp);
5556         return (error);
5557 }
5558
5559 /*
5560  * Find a file layout that will handle the first bytes of the requested
5561  * range and return the information from it needed to to the I/O operation.
5562  */
5563 int
5564 nfscl_findlayoutforio(struct nfscllayout *lyp, uint64_t off, uint32_t rwaccess,
5565     struct nfsclflayout **retflpp)
5566 {
5567         struct nfsclflayout *flp, *nflp, *rflp;
5568         uint32_t rw;
5569
5570         rflp = NULL;
5571         rw = rwaccess;
5572         /* For reading, do the Read list first and then the Write list. */
5573         do {
5574                 if (rw == NFSV4OPEN_ACCESSREAD)
5575                         flp = LIST_FIRST(&lyp->nfsly_flayread);
5576                 else
5577                         flp = LIST_FIRST(&lyp->nfsly_flayrw);
5578                 while (flp != NULL) {
5579                         nflp = LIST_NEXT(flp, nfsfl_list);
5580                         if (flp->nfsfl_off > off)
5581                                 break;
5582                         if (flp->nfsfl_end > off &&
5583                             (rflp == NULL || rflp->nfsfl_end < flp->nfsfl_end))
5584                                 rflp = flp;
5585                         flp = nflp;
5586                 }
5587                 if (rw == NFSV4OPEN_ACCESSREAD)
5588                         rw = NFSV4OPEN_ACCESSWRITE;
5589                 else
5590                         rw = 0;
5591         } while (rw != 0);
5592         if (rflp != NULL) {
5593                 /* This one covers the most bytes starting at off. */
5594                 *retflpp = rflp;
5595                 return (0);
5596         }
5597         return (EIO);
5598 }
5599
5600 /*
5601  * Do I/O using an NFSv4.1 file layout.
5602  */
5603 static int
5604 nfscl_doflayoutio(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit,
5605     int *eofp, nfsv4stateid_t *stateidp, int rwflag, struct nfscldevinfo *dp,
5606     struct nfscllayout *lyp, struct nfsclflayout *flp, uint64_t off,
5607     uint64_t len, struct ucred *cred, NFSPROC_T *p)
5608 {
5609         uint64_t io_off, rel_off, stripe_unit_size, transfer, xfer;
5610         int commit_thru_mds, error = 0, stripe_index, stripe_pos;
5611         struct nfsnode *np;
5612         struct nfsfh *fhp;
5613         struct nfsclds **dspp;
5614
5615         np = VTONFS(vp);
5616         rel_off = off - flp->nfsfl_patoff;
5617         stripe_unit_size = (flp->nfsfl_util >> 6) & 0x3ffffff;
5618         stripe_pos = (rel_off / stripe_unit_size + flp->nfsfl_stripe1) %
5619             dp->nfsdi_stripecnt;
5620         transfer = stripe_unit_size - (rel_off % stripe_unit_size);
5621
5622         /* Loop around, doing I/O for each stripe unit. */
5623         while (len > 0 && error == 0) {
5624                 stripe_index = nfsfldi_stripeindex(dp, stripe_pos);
5625                 dspp = nfsfldi_addr(dp, stripe_index);
5626                 if (len > transfer)
5627                         xfer = transfer;
5628                 else
5629                         xfer = len;
5630                 if ((flp->nfsfl_util & NFSFLAYUTIL_DENSE) != 0) {
5631                         /* Dense layout. */
5632                         if (stripe_pos >= flp->nfsfl_fhcnt)
5633                                 return (EIO);
5634                         fhp = flp->nfsfl_fh[stripe_pos];
5635                         io_off = (rel_off / (stripe_unit_size *
5636                             dp->nfsdi_stripecnt)) * stripe_unit_size +
5637                             rel_off % stripe_unit_size;
5638                 } else {
5639                         /* Sparse layout. */
5640                         if (flp->nfsfl_fhcnt > 1) {
5641                                 if (stripe_index >= flp->nfsfl_fhcnt)
5642                                         return (EIO);
5643                                 fhp = flp->nfsfl_fh[stripe_index];
5644                         } else if (flp->nfsfl_fhcnt == 1)
5645                                 fhp = flp->nfsfl_fh[0];
5646                         else
5647                                 fhp = np->n_fhp;
5648                         io_off = off;
5649                 }
5650                 if ((flp->nfsfl_util & NFSFLAYUTIL_COMMIT_THRU_MDS) != 0)
5651                         commit_thru_mds = 1;
5652                 else
5653                         commit_thru_mds = 0;
5654                 if (rwflag == FREAD)
5655                         error = nfsrpc_readds(vp, uiop, stateidp, eofp, *dspp,
5656                             io_off, xfer, fhp, cred, p);
5657                 else {
5658                         error = nfsrpc_writeds(vp, uiop, iomode, must_commit,
5659                             stateidp, *dspp, io_off, xfer, fhp, commit_thru_mds,
5660                             cred, p);
5661                         if (error == 0) {
5662                                 NFSLOCKCLSTATE();
5663                                 lyp->nfsly_flags |= NFSLY_WRITTEN;
5664                                 NFSUNLOCKCLSTATE();
5665                         }
5666                 }
5667                 if (error == 0) {
5668                         transfer = stripe_unit_size;
5669                         stripe_pos = (stripe_pos + 1) % dp->nfsdi_stripecnt;
5670                         len -= xfer;
5671                         off += xfer;
5672                 }
5673         }
5674         return (error);
5675 }
5676
5677 /*
5678  * The actual read RPC done to a DS.
5679  */
5680 static int
5681 nfsrpc_readds(vnode_t vp, struct uio *uiop, nfsv4stateid_t *stateidp, int *eofp,
5682     struct nfsclds *dsp, uint64_t io_off, int len, struct nfsfh *fhp,
5683     struct ucred *cred, NFSPROC_T *p)
5684 {
5685         uint32_t *tl;
5686         int error, retlen;
5687         struct nfsrv_descript nfsd;
5688         struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
5689         struct nfsrv_descript *nd = &nfsd;
5690         struct nfssockreq *nrp;
5691
5692         nd->nd_mrep = NULL;
5693         nfscl_reqstart(nd, NFSPROC_READDS, nmp, fhp->nfh_fh, fhp->nfh_len,
5694             NULL, &dsp->nfsclds_sess);
5695         nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSEQIDZERO);
5696         NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED * 3);
5697         txdr_hyper(io_off, tl);
5698         *(tl + 2) = txdr_unsigned(len);
5699         nrp = dsp->nfsclds_sockp;
5700         if (nrp == NULL)
5701                 /* If NULL, use the MDS socket. */
5702                 nrp = &nmp->nm_sockreq;
5703         error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred,
5704             NFS_PROG, NFS_VER4, NULL, 1, NULL, &dsp->nfsclds_sess);
5705         if (error != 0)
5706                 return (error);
5707         if (nd->nd_repstat != 0) {
5708                 error = nd->nd_repstat;
5709                 goto nfsmout;
5710         }
5711         NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
5712         *eofp = fxdr_unsigned(int, *tl);
5713         NFSM_STRSIZ(retlen, len);
5714         error = nfsm_mbufuio(nd, uiop, retlen);
5715 nfsmout:
5716         if (nd->nd_mrep != NULL)
5717                 mbuf_freem(nd->nd_mrep);
5718         return (error);
5719 }
5720
5721 /*
5722  * The actual write RPC done to a DS.
5723  */
5724 static int
5725 nfsrpc_writeds(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit,
5726     nfsv4stateid_t *stateidp, struct nfsclds *dsp, uint64_t io_off, int len,
5727     struct nfsfh *fhp, int commit_thru_mds, struct ucred *cred, NFSPROC_T *p)
5728 {
5729         uint32_t *tl;
5730         struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
5731         int error, rlen, commit, committed = NFSWRITE_FILESYNC;
5732         int32_t backup;
5733         struct nfsrv_descript nfsd;
5734         struct nfsrv_descript *nd = &nfsd;
5735         struct nfssockreq *nrp;
5736
5737         KASSERT(uiop->uio_iovcnt == 1, ("nfs: writerpc iovcnt > 1"));
5738         nd->nd_mrep = NULL;
5739         nfscl_reqstart(nd, NFSPROC_WRITEDS, nmp, fhp->nfh_fh, fhp->nfh_len,
5740             NULL, &dsp->nfsclds_sess);
5741         nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSEQIDZERO);
5742         NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED);
5743         txdr_hyper(io_off, tl);
5744         tl += 2;
5745         *tl++ = txdr_unsigned(*iomode);
5746         *tl = txdr_unsigned(len);
5747         nfsm_uiombuf(nd, uiop, len);
5748         nrp = dsp->nfsclds_sockp;
5749         if (nrp == NULL)
5750                 /* If NULL, use the MDS socket. */
5751                 nrp = &nmp->nm_sockreq;
5752         error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred,
5753             NFS_PROG, NFS_VER4, NULL, 1, NULL, &dsp->nfsclds_sess);
5754         if (error != 0)
5755                 return (error);
5756         if (nd->nd_repstat != 0) {
5757                 /*
5758                  * In case the rpc gets retried, roll
5759                  * the uio fileds changed by nfsm_uiombuf()
5760                  * back.
5761                  */
5762                 uiop->uio_offset -= len;
5763                 uio_uio_resid_add(uiop, len);
5764                 uio_iov_base_add(uiop, -len);
5765                 uio_iov_len_add(uiop, len);
5766                 error = nd->nd_repstat;
5767         } else {
5768                 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + NFSX_VERF);
5769                 rlen = fxdr_unsigned(int, *tl++);
5770                 if (rlen == 0) {
5771                         error = NFSERR_IO;
5772                         goto nfsmout;
5773                 } else if (rlen < len) {
5774                         backup = len - rlen;
5775                         uio_iov_base_add(uiop, -(backup));
5776                         uio_iov_len_add(uiop, backup);
5777                         uiop->uio_offset -= backup;
5778                         uio_uio_resid_add(uiop, backup);
5779                         len = rlen;
5780                 }
5781                 commit = fxdr_unsigned(int, *tl++);
5782
5783                 /*
5784                  * Return the lowest committment level
5785                  * obtained by any of the RPCs.
5786                  */
5787                 if (committed == NFSWRITE_FILESYNC)
5788                         committed = commit;
5789                 else if (committed == NFSWRITE_DATASYNC &&
5790                     commit == NFSWRITE_UNSTABLE)
5791                         committed = commit;
5792                 if (commit_thru_mds != 0) {
5793                         NFSLOCKMNT(nmp);
5794                         if (!NFSHASWRITEVERF(nmp)) {
5795                                 NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF);
5796                                 NFSSETWRITEVERF(nmp);
5797                         } else if (NFSBCMP(tl, nmp->nm_verf, NFSX_VERF)) {
5798                                 *must_commit = 1;
5799                                 NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF);
5800                         }
5801                         NFSUNLOCKMNT(nmp);
5802                 } else {
5803                         NFSLOCKDS(dsp);
5804                         if ((dsp->nfsclds_flags & NFSCLDS_HASWRITEVERF) == 0) {
5805                                 NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF);
5806                                 dsp->nfsclds_flags |= NFSCLDS_HASWRITEVERF;
5807                         } else if (NFSBCMP(tl, dsp->nfsclds_verf, NFSX_VERF)) {
5808                                 *must_commit = 1;
5809                                 NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF);
5810                         }
5811                         NFSUNLOCKDS(dsp);
5812                 }
5813         }
5814 nfsmout:
5815         if (nd->nd_mrep != NULL)
5816                 mbuf_freem(nd->nd_mrep);
5817         *iomode = committed;
5818         if (nd->nd_repstat != 0 && error == 0)
5819                 error = nd->nd_repstat;
5820         return (error);
5821 }
5822
5823 /*
5824  * Free up the nfsclds structure.
5825  */
5826 void
5827 nfscl_freenfsclds(struct nfsclds *dsp)
5828 {
5829         int i;
5830
5831         if (dsp == NULL)
5832                 return;
5833         if (dsp->nfsclds_sockp != NULL) {
5834                 NFSFREECRED(dsp->nfsclds_sockp->nr_cred);
5835                 NFSFREEMUTEX(&dsp->nfsclds_sockp->nr_mtx);
5836                 free(dsp->nfsclds_sockp->nr_nam, M_SONAME);
5837                 free(dsp->nfsclds_sockp, M_NFSSOCKREQ);
5838         }
5839         NFSFREEMUTEX(&dsp->nfsclds_mtx);
5840         NFSFREEMUTEX(&dsp->nfsclds_sess.nfsess_mtx);
5841         for (i = 0; i < NFSV4_CBSLOTS; i++) {
5842                 if (dsp->nfsclds_sess.nfsess_cbslots[i].nfssl_reply != NULL)
5843                         m_freem(
5844                             dsp->nfsclds_sess.nfsess_cbslots[i].nfssl_reply);
5845         }
5846         free(dsp, M_NFSCLDS);
5847 }
5848
5849 static enum nfsclds_state
5850 nfscl_getsameserver(struct nfsmount *nmp, struct nfsclds *newdsp,
5851     struct nfsclds **retdspp)
5852 {
5853         struct nfsclds *dsp, *cur_dsp;
5854
5855         /*
5856          * Search the list of nfsclds structures for one with the same
5857          * server.
5858          */
5859         cur_dsp = NULL;
5860         TAILQ_FOREACH(dsp, &nmp->nm_sess, nfsclds_list) {
5861                 if (dsp->nfsclds_servownlen == newdsp->nfsclds_servownlen &&
5862                     dsp->nfsclds_servownlen != 0 &&
5863                     !NFSBCMP(dsp->nfsclds_serverown, newdsp->nfsclds_serverown,
5864                     dsp->nfsclds_servownlen)) {
5865                         NFSCL_DEBUG(4, "fnd same fdsp=%p dsp=%p flg=0x%x\n",
5866                             TAILQ_FIRST(&nmp->nm_sess), dsp,
5867                             dsp->nfsclds_flags);
5868                         /* Server major id matches. */
5869                         if ((dsp->nfsclds_flags & NFSCLDS_DS) != 0) {
5870                                 *retdspp = dsp;
5871                                 return (NFSDSP_USETHISSESSION);
5872                         }
5873
5874                         /*
5875                          * Note the first match, so it can be used for
5876                          * sequence'ing new sessions.
5877                          */
5878                         if (cur_dsp == NULL)
5879                                 cur_dsp = dsp;
5880                 }
5881         }
5882         if (cur_dsp != NULL) {
5883                 *retdspp = cur_dsp;
5884                 return (NFSDSP_SEQTHISSESSION);
5885         }
5886         return (NFSDSP_NOTFOUND);
5887 }
5888
5889 #ifdef notyet
5890 /*
5891  * NFS commit rpc to a DS.
5892  */
5893 static int
5894 nfsrpc_commitds(vnode_t vp, uint64_t offset, int cnt, struct nfsclds *dsp,
5895     struct nfsfh *fhp, struct ucred *cred, NFSPROC_T *p, void *stuff)
5896 {
5897         uint32_t *tl;
5898         struct nfsrv_descript nfsd, *nd = &nfsd;
5899         struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
5900         struct nfssockreq *nrp;
5901         int error;
5902         
5903         nfscl_reqstart(nd, NFSPROC_COMMITDS, nmp, fhp->nfh_fh, fhp->nfh_len,
5904             NULL, &dsp->nfsclds_sess);
5905         NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED);
5906         txdr_hyper(offset, tl);
5907         tl += 2;
5908         *tl = txdr_unsigned(cnt);
5909         nrp = dsp->nfsclds_sockp;
5910         if (nrp == NULL)
5911                 /* If NULL, use the MDS socket. */
5912                 nrp = &nmp->nm_sockreq;
5913         error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred,
5914             NFS_PROG, NFS_VER4, NULL, 1, NULL, &dsp->nfsclds_sess);
5915         if (error)
5916                 return (error);
5917         if (nd->nd_repstat == 0) {
5918                 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
5919                 NFSLOCKDS(dsp);
5920                 if (NFSBCMP(tl, dsp->nfsclds_verf, NFSX_VERF)) {
5921                         NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF);
5922                         error = NFSERR_STALEWRITEVERF;
5923                 }
5924                 NFSUNLOCKDS(dsp);
5925         }
5926 nfsmout:
5927         if (error == 0 && nd->nd_repstat != 0)
5928                 error = nd->nd_repstat;
5929         mbuf_freem(nd->nd_mrep);
5930         return (error);
5931 }
5932 #endif
5933