]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/fs/nfsclient/nfs_clrpcops.c
Add initial testcases for bin/ls
[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 nfsmout:
3093         if (nd->nd_mrep != NULL)
3094                 mbuf_freem(nd->nd_mrep);
3095         return (error);
3096 }
3097
3098 #ifndef APPLE
3099 /*
3100  * NFS V3 readdir plus RPC. Used in place of nfsrpc_readdir().
3101  * (Also used for NFS V4 when mount flag set.)
3102  * (ditto above w.r.t. multiple of DIRBLKSIZ, etc.)
3103  */
3104 APPLESTATIC int
3105 nfsrpc_readdirplus(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep,
3106     struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp,
3107     int *eofp, void *stuff)
3108 {
3109         int len, left;
3110         struct dirent *dp = NULL;
3111         u_int32_t *tl;
3112         vnode_t newvp = NULLVP;
3113         struct nfsrv_descript nfsd, *nd = &nfsd;
3114         struct nameidata nami, *ndp = &nami;
3115         struct componentname *cnp = &ndp->ni_cnd;
3116         struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
3117         struct nfsnode *dnp = VTONFS(vp), *np;
3118         struct nfsvattr nfsva;
3119         struct nfsfh *nfhp;
3120         nfsquad_t cookie, ncookie;
3121         int error = 0, tlen, more_dirs = 1, blksiz = 0, bigenough = 1;
3122         int attrflag, tryformoredirs = 1, eof = 0, gotmnton = 0;
3123         int isdotdot = 0, unlocknewvp = 0;
3124         long dotfileid, dotdotfileid = 0, fileno = 0;
3125         char *cp;
3126         nfsattrbit_t attrbits, dattrbits;
3127         size_t tresid;
3128         u_int32_t *tl2 = NULL, fakefileno = 0xffffffff, rderr;
3129         struct timespec dctime;
3130
3131         KASSERT(uiop->uio_iovcnt == 1 &&
3132             (uio_uio_resid(uiop) & (DIRBLKSIZ - 1)) == 0,
3133             ("nfs readdirplusrpc bad uio"));
3134         timespecclear(&dctime);
3135         *attrflagp = 0;
3136         if (eofp != NULL)
3137                 *eofp = 0;
3138         ndp->ni_dvp = vp;
3139         nd->nd_mrep = NULL;
3140         cookie.lval[0] = cookiep->nfsuquad[0];
3141         cookie.lval[1] = cookiep->nfsuquad[1];
3142         tresid = uio_uio_resid(uiop);
3143
3144         /*
3145          * For NFSv4, first create the "." and ".." entries.
3146          */
3147         if (NFSHASNFSV4(nmp)) {
3148                 NFSGETATTR_ATTRBIT(&dattrbits);
3149                 NFSZERO_ATTRBIT(&attrbits);
3150                 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FILEID);
3151                 if (NFSISSET_ATTRBIT(&dnp->n_vattr.na_suppattr,
3152                     NFSATTRBIT_MOUNTEDONFILEID)) {
3153                         NFSSETBIT_ATTRBIT(&attrbits,
3154                             NFSATTRBIT_MOUNTEDONFILEID);
3155                         gotmnton = 1;
3156                 } else {
3157                         /*
3158                          * Must fake it. Use the fileno, except when the
3159                          * fsid is != to that of the directory. For that
3160                          * case, generate a fake fileno that is not the same.
3161                          */
3162                         NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FSID);
3163                         gotmnton = 0;
3164                 }
3165
3166                 /*
3167                  * Joy, oh joy. For V4 we get to hand craft '.' and '..'.
3168                  */
3169                 if (uiop->uio_offset == 0) {
3170                         NFSCL_REQSTART(nd, NFSPROC_LOOKUPP, vp);
3171                         NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3172                         *tl++ = txdr_unsigned(NFSV4OP_GETFH);
3173                         *tl = txdr_unsigned(NFSV4OP_GETATTR);
3174                         (void) nfsrv_putattrbit(nd, &attrbits);
3175                         error = nfscl_request(nd, vp, p, cred, stuff);
3176                         if (error)
3177                             return (error);
3178                         dotfileid = 0;  /* Fake out the compiler. */
3179                         if ((nd->nd_flag & ND_NOMOREDATA) == 0) {
3180                             error = nfsm_loadattr(nd, &nfsva);
3181                             if (error != 0)
3182                                 goto nfsmout;
3183                             dctime = nfsva.na_ctime;
3184                             dotfileid = nfsva.na_fileid;
3185                         }
3186                         if (nd->nd_repstat == 0) {
3187                             NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
3188                             len = fxdr_unsigned(int, *(tl + 4));
3189                             if (len > 0 && len <= NFSX_V4FHMAX)
3190                                 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
3191                             else
3192                                 error = EPERM;
3193                             if (!error) {
3194                                 NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED);
3195                                 nfsva.na_mntonfileno = 0xffffffff;
3196                                 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL,
3197                                     NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
3198                                     NULL, NULL, NULL, p, cred);
3199                                 if (error) {
3200                                     dotdotfileid = dotfileid;
3201                                 } else if (gotmnton) {
3202                                     if (nfsva.na_mntonfileno != 0xffffffff)
3203                                         dotdotfileid = nfsva.na_mntonfileno;
3204                                     else
3205                                         dotdotfileid = nfsva.na_fileid;
3206                                 } else if (nfsva.na_filesid[0] ==
3207                                     dnp->n_vattr.na_filesid[0] &&
3208                                     nfsva.na_filesid[1] ==
3209                                     dnp->n_vattr.na_filesid[1]) {
3210                                     dotdotfileid = nfsva.na_fileid;
3211                                 } else {
3212                                     do {
3213                                         fakefileno--;
3214                                     } while (fakefileno ==
3215                                         nfsva.na_fileid);
3216                                     dotdotfileid = fakefileno;
3217                                 }
3218                             }
3219                         } else if (nd->nd_repstat == NFSERR_NOENT) {
3220                             /*
3221                              * Lookupp returns NFSERR_NOENT when we are
3222                              * at the root, so just use the current dir.
3223                              */
3224                             nd->nd_repstat = 0;
3225                             dotdotfileid = dotfileid;
3226                         } else {
3227                             error = nd->nd_repstat;
3228                         }
3229                         mbuf_freem(nd->nd_mrep);
3230                         if (error)
3231                             return (error);
3232                         nd->nd_mrep = NULL;
3233                         dp = (struct dirent *)uio_iov_base(uiop);
3234                         dp->d_type = DT_DIR;
3235                         dp->d_fileno = dotfileid;
3236                         dp->d_namlen = 1;
3237                         dp->d_name[0] = '.';
3238                         dp->d_name[1] = '\0';
3239                         dp->d_reclen = DIRENT_SIZE(dp) + NFSX_HYPER;
3240                         /*
3241                          * Just make these offset cookie 0.
3242                          */
3243                         tl = (u_int32_t *)&dp->d_name[4];
3244                         *tl++ = 0;
3245                         *tl = 0;
3246                         blksiz += dp->d_reclen;
3247                         uio_uio_resid_add(uiop, -(dp->d_reclen));
3248                         uiop->uio_offset += dp->d_reclen;
3249                         uio_iov_base_add(uiop, dp->d_reclen);
3250                         uio_iov_len_add(uiop, -(dp->d_reclen));
3251                         dp = (struct dirent *)uio_iov_base(uiop);
3252                         dp->d_type = DT_DIR;
3253                         dp->d_fileno = dotdotfileid;
3254                         dp->d_namlen = 2;
3255                         dp->d_name[0] = '.';
3256                         dp->d_name[1] = '.';
3257                         dp->d_name[2] = '\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                 }
3271                 NFSREADDIRPLUS_ATTRBIT(&attrbits);
3272                 if (gotmnton)
3273                         NFSSETBIT_ATTRBIT(&attrbits,
3274                             NFSATTRBIT_MOUNTEDONFILEID);
3275         }
3276
3277         /*
3278          * Loop around doing readdir rpc's of size nm_readdirsize.
3279          * The stopping criteria is EOF or buffer full.
3280          */
3281         while (more_dirs && bigenough) {
3282                 *attrflagp = 0;
3283                 NFSCL_REQSTART(nd, NFSPROC_READDIRPLUS, vp);
3284                 NFSM_BUILD(tl, u_int32_t *, 6 * NFSX_UNSIGNED);
3285                 *tl++ = cookie.lval[0];
3286                 *tl++ = cookie.lval[1];
3287                 if (cookie.qval == 0) {
3288                         *tl++ = 0;
3289                         *tl++ = 0;
3290                 } else {
3291                         NFSLOCKNODE(dnp);
3292                         *tl++ = dnp->n_cookieverf.nfsuquad[0];
3293                         *tl++ = dnp->n_cookieverf.nfsuquad[1];
3294                         NFSUNLOCKNODE(dnp);
3295                 }
3296                 *tl++ = txdr_unsigned(nmp->nm_readdirsize);
3297                 *tl = txdr_unsigned(nmp->nm_readdirsize);
3298                 if (nd->nd_flag & ND_NFSV4) {
3299                         (void) nfsrv_putattrbit(nd, &attrbits);
3300                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3301                         *tl = txdr_unsigned(NFSV4OP_GETATTR);
3302                         (void) nfsrv_putattrbit(nd, &dattrbits);
3303                 }
3304                 error = nfscl_request(nd, vp, p, cred, stuff);
3305                 if (error)
3306                         return (error);
3307                 if (nd->nd_flag & ND_NFSV3)
3308                         error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
3309                 if (nd->nd_repstat || error) {
3310                         if (!error)
3311                                 error = nd->nd_repstat;
3312                         goto nfsmout;
3313                 }
3314                 if ((nd->nd_flag & ND_NFSV3) != 0 && *attrflagp != 0)
3315                         dctime = nap->na_ctime;
3316                 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3317                 NFSLOCKNODE(dnp);
3318                 dnp->n_cookieverf.nfsuquad[0] = *tl++;
3319                 dnp->n_cookieverf.nfsuquad[1] = *tl++;
3320                 NFSUNLOCKNODE(dnp);
3321                 more_dirs = fxdr_unsigned(int, *tl);
3322                 if (!more_dirs)
3323                         tryformoredirs = 0;
3324         
3325                 /* loop thru the dir entries, doctoring them to 4bsd form */
3326                 while (more_dirs && bigenough) {
3327                         NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3328                         if (nd->nd_flag & ND_NFSV4) {
3329                                 ncookie.lval[0] = *tl++;
3330                                 ncookie.lval[1] = *tl++;
3331                         } else {
3332                                 fileno = fxdr_unsigned(long, *++tl);
3333                                 tl++;
3334                         }
3335                         len = fxdr_unsigned(int, *tl);
3336                         if (len <= 0 || len > NFS_MAXNAMLEN) {
3337                                 error = EBADRPC;
3338                                 goto nfsmout;
3339                         }
3340                         tlen = NFSM_RNDUP(len);
3341                         if (tlen == len)
3342                                 tlen += 4;  /* To ensure null termination */
3343                         left = DIRBLKSIZ - blksiz;
3344                         if ((tlen + DIRHDSIZ + NFSX_HYPER) > left) {
3345                                 dp->d_reclen += left;
3346                                 uio_iov_base_add(uiop, left);
3347                                 uio_iov_len_add(uiop, -(left));
3348                                 uio_uio_resid_add(uiop, -(left));
3349                                 uiop->uio_offset += left;
3350                                 blksiz = 0;
3351                         }
3352                         if ((tlen + DIRHDSIZ + NFSX_HYPER) > uio_uio_resid(uiop))
3353                                 bigenough = 0;
3354                         if (bigenough) {
3355                                 dp = (struct dirent *)uio_iov_base(uiop);
3356                                 dp->d_namlen = len;
3357                                 dp->d_reclen = tlen + DIRHDSIZ + NFSX_HYPER;
3358                                 dp->d_type = DT_UNKNOWN;
3359                                 blksiz += dp->d_reclen;
3360                                 if (blksiz == DIRBLKSIZ)
3361                                         blksiz = 0;
3362                                 uio_uio_resid_add(uiop, -(DIRHDSIZ));
3363                                 uiop->uio_offset += DIRHDSIZ;
3364                                 uio_iov_base_add(uiop, DIRHDSIZ);
3365                                 uio_iov_len_add(uiop, -(DIRHDSIZ));
3366                                 cnp->cn_nameptr = uio_iov_base(uiop);
3367                                 cnp->cn_namelen = len;
3368                                 NFSCNHASHZERO(cnp);
3369                                 error = nfsm_mbufuio(nd, uiop, len);
3370                                 if (error)
3371                                         goto nfsmout;
3372                                 cp = uio_iov_base(uiop);
3373                                 tlen -= len;
3374                                 *cp = '\0';
3375                                 cp += tlen;     /* points to cookie storage */
3376                                 tl2 = (u_int32_t *)cp;
3377                                 if (len == 2 && cnp->cn_nameptr[0] == '.' &&
3378                                     cnp->cn_nameptr[1] == '.')
3379                                         isdotdot = 1;
3380                                 else
3381                                         isdotdot = 0;
3382                                 uio_iov_base_add(uiop, (tlen + NFSX_HYPER));
3383                                 uio_iov_len_add(uiop, -(tlen + NFSX_HYPER));
3384                                 uio_uio_resid_add(uiop, -(tlen + NFSX_HYPER));
3385                                 uiop->uio_offset += (tlen + NFSX_HYPER);
3386                         } else {
3387                                 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
3388                                 if (error)
3389                                         goto nfsmout;
3390                         }
3391                         nfhp = NULL;
3392                         if (nd->nd_flag & ND_NFSV3) {
3393                                 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED);
3394                                 ncookie.lval[0] = *tl++;
3395                                 ncookie.lval[1] = *tl++;
3396                                 attrflag = fxdr_unsigned(int, *tl);
3397                                 if (attrflag) {
3398                                   error = nfsm_loadattr(nd, &nfsva);
3399                                   if (error)
3400                                         goto nfsmout;
3401                                 }
3402                                 NFSM_DISSECT(tl,u_int32_t *,NFSX_UNSIGNED);
3403                                 if (*tl) {
3404                                         error = nfsm_getfh(nd, &nfhp);
3405                                         if (error)
3406                                             goto nfsmout;
3407                                 }
3408                                 if (!attrflag && nfhp != NULL) {
3409                                         FREE((caddr_t)nfhp, M_NFSFH);
3410                                         nfhp = NULL;
3411                                 }
3412                         } else {
3413                                 rderr = 0;
3414                                 nfsva.na_mntonfileno = 0xffffffff;
3415                                 error = nfsv4_loadattr(nd, NULL, &nfsva, &nfhp,
3416                                     NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
3417                                     NULL, NULL, &rderr, p, cred);
3418                                 if (error)
3419                                         goto nfsmout;
3420                         }
3421
3422                         if (bigenough) {
3423                             if (nd->nd_flag & ND_NFSV4) {
3424                                 if (rderr) {
3425                                     dp->d_fileno = 0;
3426                                 } else if (gotmnton) {
3427                                     if (nfsva.na_mntonfileno != 0xffffffff)
3428                                         dp->d_fileno = nfsva.na_mntonfileno;
3429                                     else
3430                                         dp->d_fileno = nfsva.na_fileid;
3431                                 } else if (nfsva.na_filesid[0] ==
3432                                     dnp->n_vattr.na_filesid[0] &&
3433                                     nfsva.na_filesid[1] ==
3434                                     dnp->n_vattr.na_filesid[1]) {
3435                                     dp->d_fileno = nfsva.na_fileid;
3436                                 } else {
3437                                     do {
3438                                         fakefileno--;
3439                                     } while (fakefileno ==
3440                                         nfsva.na_fileid);
3441                                     dp->d_fileno = fakefileno;
3442                                 }
3443                             } else {
3444                                 dp->d_fileno = fileno;
3445                             }
3446                             *tl2++ = cookiep->nfsuquad[0] = cookie.lval[0] =
3447                                 ncookie.lval[0];
3448                             *tl2 = cookiep->nfsuquad[1] = cookie.lval[1] =
3449                                 ncookie.lval[1];
3450
3451                             if (nfhp != NULL) {
3452                                 if (NFSRV_CMPFH(nfhp->nfh_fh, nfhp->nfh_len,
3453                                     dnp->n_fhp->nfh_fh, dnp->n_fhp->nfh_len)) {
3454                                     VREF(vp);
3455                                     newvp = vp;
3456                                     unlocknewvp = 0;
3457                                     FREE((caddr_t)nfhp, M_NFSFH);
3458                                     np = dnp;
3459                                 } else if (isdotdot != 0) {
3460                                     /*
3461                                      * Skip doing a nfscl_nget() call for "..".
3462                                      * There's a race between acquiring the nfs
3463                                      * node here and lookups that look for the
3464                                      * directory being read (in the parent).
3465                                      * It would try to get a lock on ".." here,
3466                                      * owning the lock on the directory being
3467                                      * read. Lookup will hold the lock on ".."
3468                                      * and try to acquire the lock on the
3469                                      * directory being read.
3470                                      * If the directory is unlocked/relocked,
3471                                      * then there is a LOR with the buflock
3472                                      * vp is relocked.
3473                                      */
3474                                     free(nfhp, M_NFSFH);
3475                                 } else {
3476                                     error = nfscl_nget(vnode_mount(vp), vp,
3477                                       nfhp, cnp, p, &np, NULL, LK_EXCLUSIVE);
3478                                     if (!error) {
3479                                         newvp = NFSTOV(np);
3480                                         unlocknewvp = 1;
3481                                     }
3482                                 }
3483                                 nfhp = NULL;
3484                                 if (newvp != NULLVP) {
3485                                     error = nfscl_loadattrcache(&newvp,
3486                                         &nfsva, NULL, NULL, 0, 0);
3487                                     if (error) {
3488                                         if (unlocknewvp)
3489                                             vput(newvp);
3490                                         else
3491                                             vrele(newvp);
3492                                         goto nfsmout;
3493                                     }
3494                                     dp->d_type =
3495                                         vtonfs_dtype(np->n_vattr.na_type);
3496                                     ndp->ni_vp = newvp;
3497                                     NFSCNHASH(cnp, HASHINIT);
3498                                     if (cnp->cn_namelen <= NCHNAMLEN &&
3499                                         (newvp->v_type != VDIR ||
3500                                          dctime.tv_sec != 0)) {
3501                                         cache_enter_time(ndp->ni_dvp,
3502                                             ndp->ni_vp, cnp,
3503                                             &nfsva.na_ctime,
3504                                             newvp->v_type != VDIR ? NULL :
3505                                             &dctime);
3506                                     }
3507                                     if (unlocknewvp)
3508                                         vput(newvp);
3509                                     else
3510                                         vrele(newvp);
3511                                     newvp = NULLVP;
3512                                 }
3513                             }
3514                         } else if (nfhp != NULL) {
3515                             FREE((caddr_t)nfhp, M_NFSFH);
3516                         }
3517                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3518                         more_dirs = fxdr_unsigned(int, *tl);
3519                 }
3520                 /*
3521                  * If at end of rpc data, get the eof boolean
3522                  */
3523                 if (!more_dirs) {
3524                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3525                         eof = fxdr_unsigned(int, *tl);
3526                         if (tryformoredirs)
3527                                 more_dirs = !eof;
3528                         if (nd->nd_flag & ND_NFSV4) {
3529                                 error = nfscl_postop_attr(nd, nap, attrflagp,
3530                                     stuff);
3531                                 if (error)
3532                                         goto nfsmout;
3533                         }
3534                 }
3535                 mbuf_freem(nd->nd_mrep);
3536                 nd->nd_mrep = NULL;
3537         }
3538         /*
3539          * Fill last record, iff any, out to a multiple of DIRBLKSIZ
3540          * by increasing d_reclen for the last record.
3541          */
3542         if (blksiz > 0) {
3543                 left = DIRBLKSIZ - blksiz;
3544                 dp->d_reclen += left;
3545                 uio_iov_base_add(uiop, left);
3546                 uio_iov_len_add(uiop, -(left));
3547                 uio_uio_resid_add(uiop, -(left));
3548                 uiop->uio_offset += left;
3549         }
3550
3551         /*
3552          * If returning no data, assume end of file.
3553          * If not bigenough, return not end of file, since you aren't
3554          *    returning all the data
3555          * Otherwise, return the eof flag from the server.
3556          */
3557         if (eofp != NULL) {
3558                 if (tresid == uio_uio_resid(uiop))
3559                         *eofp = 1;
3560                 else if (!bigenough)
3561                         *eofp = 0;
3562                 else
3563                         *eofp = eof;
3564         }
3565
3566 nfsmout:
3567         if (nd->nd_mrep != NULL)
3568                 mbuf_freem(nd->nd_mrep);
3569         return (error);
3570 }
3571 #endif  /* !APPLE */
3572
3573 /*
3574  * Nfs commit rpc
3575  */
3576 APPLESTATIC int
3577 nfsrpc_commit(vnode_t vp, u_quad_t offset, int cnt, struct ucred *cred,
3578     NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff)
3579 {
3580         u_int32_t *tl;
3581         struct nfsrv_descript nfsd, *nd = &nfsd;
3582         nfsattrbit_t attrbits;
3583         int error;
3584         struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
3585         
3586         *attrflagp = 0;
3587         NFSCL_REQSTART(nd, NFSPROC_COMMIT, vp);
3588         NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3589         txdr_hyper(offset, tl);
3590         tl += 2;
3591         *tl = txdr_unsigned(cnt);
3592         if (nd->nd_flag & ND_NFSV4) {
3593                 /*
3594                  * And do a Getattr op.
3595                  */
3596                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3597                 *tl = txdr_unsigned(NFSV4OP_GETATTR);
3598                 NFSGETATTR_ATTRBIT(&attrbits);
3599                 (void) nfsrv_putattrbit(nd, &attrbits);
3600         }
3601         error = nfscl_request(nd, vp, p, cred, stuff);
3602         if (error)
3603                 return (error);
3604         error = nfscl_wcc_data(nd, vp, nap, attrflagp, NULL, stuff);
3605         if (!error && !nd->nd_repstat) {
3606                 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
3607                 NFSLOCKMNT(nmp);
3608                 if (NFSBCMP(nmp->nm_verf, tl, NFSX_VERF)) {
3609                         NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF);
3610                         nd->nd_repstat = NFSERR_STALEWRITEVERF;
3611                 }
3612                 NFSUNLOCKMNT(nmp);
3613                 if (nd->nd_flag & ND_NFSV4)
3614                         error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
3615         }
3616 nfsmout:
3617         if (!error && nd->nd_repstat)
3618                 error = nd->nd_repstat;
3619         mbuf_freem(nd->nd_mrep);
3620         return (error);
3621 }
3622
3623 /*
3624  * NFS byte range lock rpc.
3625  * (Mostly just calls one of the three lower level RPC routines.)
3626  */
3627 APPLESTATIC int
3628 nfsrpc_advlock(vnode_t vp, off_t size, int op, struct flock *fl,
3629     int reclaim, struct ucred *cred, NFSPROC_T *p, void *id, int flags)
3630 {
3631         struct nfscllockowner *lp;
3632         struct nfsclclient *clp;
3633         struct nfsfh *nfhp;
3634         struct nfsrv_descript nfsd, *nd = &nfsd;
3635         struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
3636         u_int64_t off, len;
3637         off_t start, end;
3638         u_int32_t clidrev = 0;
3639         int error = 0, newone = 0, expireret = 0, retrycnt, donelocally;
3640         int callcnt, dorpc;
3641
3642         /*
3643          * Convert the flock structure into a start and end and do POSIX
3644          * bounds checking.
3645          */
3646         switch (fl->l_whence) {
3647         case SEEK_SET:
3648         case SEEK_CUR:
3649                 /*
3650                  * Caller is responsible for adding any necessary offset
3651                  * when SEEK_CUR is used.
3652                  */
3653                 start = fl->l_start;
3654                 off = fl->l_start;
3655                 break;
3656         case SEEK_END:
3657                 start = size + fl->l_start;
3658                 off = size + fl->l_start;
3659                 break;
3660         default:
3661                 return (EINVAL);
3662         };
3663         if (start < 0)
3664                 return (EINVAL);
3665         if (fl->l_len != 0) {
3666                 end = start + fl->l_len - 1;
3667                 if (end < start)
3668                         return (EINVAL);
3669         }
3670
3671         len = fl->l_len;
3672         if (len == 0)
3673                 len = NFS64BITSSET;
3674         retrycnt = 0;
3675         do {
3676             nd->nd_repstat = 0;
3677             if (op == F_GETLK) {
3678                 error = nfscl_getcl(vnode_mount(vp), cred, p, 1, &clp);
3679                 if (error)
3680                         return (error);
3681                 error = nfscl_lockt(vp, clp, off, len, fl, p, id, flags);
3682                 if (!error) {
3683                         clidrev = clp->nfsc_clientidrev;
3684                         error = nfsrpc_lockt(nd, vp, clp, off, len, fl, cred,
3685                             p, id, flags);
3686                 } else if (error == -1) {
3687                         error = 0;
3688                 }
3689                 nfscl_clientrelease(clp);
3690             } else if (op == F_UNLCK && fl->l_type == F_UNLCK) {
3691                 /*
3692                  * We must loop around for all lockowner cases.
3693                  */
3694                 callcnt = 0;
3695                 error = nfscl_getcl(vnode_mount(vp), cred, p, 1, &clp);
3696                 if (error)
3697                         return (error);
3698                 do {
3699                     error = nfscl_relbytelock(vp, off, len, cred, p, callcnt,
3700                         clp, id, flags, &lp, &dorpc);
3701                     /*
3702                      * If it returns a NULL lp, we're done.
3703                      */
3704                     if (lp == NULL) {
3705                         if (callcnt == 0)
3706                             nfscl_clientrelease(clp);
3707                         else
3708                             nfscl_releasealllocks(clp, vp, p, id, flags);
3709                         return (error);
3710                     }
3711                     if (nmp->nm_clp != NULL)
3712                         clidrev = nmp->nm_clp->nfsc_clientidrev;
3713                     else
3714                         clidrev = 0;
3715                     /*
3716                      * If the server doesn't support Posix lock semantics,
3717                      * only allow locks on the entire file, since it won't
3718                      * handle overlapping byte ranges.
3719                      * There might still be a problem when a lock
3720                      * upgrade/downgrade (read<->write) occurs, since the
3721                      * server "might" expect an unlock first?
3722                      */
3723                     if (dorpc && (lp->nfsl_open->nfso_posixlock ||
3724                         (off == 0 && len == NFS64BITSSET))) {
3725                         /*
3726                          * Since the lock records will go away, we must
3727                          * wait for grace and delay here.
3728                          */
3729                         do {
3730                             error = nfsrpc_locku(nd, nmp, lp, off, len,
3731                                 NFSV4LOCKT_READ, cred, p, 0);
3732                             if ((nd->nd_repstat == NFSERR_GRACE ||
3733                                  nd->nd_repstat == NFSERR_DELAY) &&
3734                                 error == 0)
3735                                 (void) nfs_catnap(PZERO, (int)nd->nd_repstat,
3736                                     "nfs_advlock");
3737                         } while ((nd->nd_repstat == NFSERR_GRACE ||
3738                             nd->nd_repstat == NFSERR_DELAY) && error == 0);
3739                     }
3740                     callcnt++;
3741                 } while (error == 0 && nd->nd_repstat == 0);
3742                 nfscl_releasealllocks(clp, vp, p, id, flags);
3743             } else if (op == F_SETLK) {
3744                 error = nfscl_getbytelock(vp, off, len, fl->l_type, cred, p,
3745                     NULL, 0, id, flags, NULL, NULL, &lp, &newone, &donelocally);
3746                 if (error || donelocally) {
3747                         return (error);
3748                 }
3749                 if (nmp->nm_clp != NULL)
3750                         clidrev = nmp->nm_clp->nfsc_clientidrev;
3751                 else
3752                         clidrev = 0;
3753                 nfhp = VTONFS(vp)->n_fhp;
3754                 if (!lp->nfsl_open->nfso_posixlock &&
3755                     (off != 0 || len != NFS64BITSSET)) {
3756                         error = EINVAL;
3757                 } else {
3758                         error = nfsrpc_lock(nd, nmp, vp, nfhp->nfh_fh,
3759                             nfhp->nfh_len, lp, newone, reclaim, off,
3760                             len, fl->l_type, cred, p, 0);
3761                 }
3762                 if (!error)
3763                         error = nd->nd_repstat;
3764                 nfscl_lockrelease(lp, error, newone);
3765             } else {
3766                 error = EINVAL;
3767             }
3768             if (!error)
3769                 error = nd->nd_repstat;
3770             if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
3771                 error == NFSERR_STALEDONTRECOVER ||
3772                 error == NFSERR_STALECLIENTID || error == NFSERR_DELAY ||
3773                 error == NFSERR_BADSESSION) {
3774                 (void) nfs_catnap(PZERO, error, "nfs_advlock");
3775             } else if ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID)
3776                 && clidrev != 0) {
3777                 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
3778                 retrycnt++;
3779             }
3780         } while (error == NFSERR_GRACE ||
3781             error == NFSERR_STALECLIENTID || error == NFSERR_DELAY ||
3782             error == NFSERR_STALEDONTRECOVER || error == NFSERR_STALESTATEID ||
3783             error == NFSERR_BADSESSION ||
3784             ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
3785              expireret == 0 && clidrev != 0 && retrycnt < 4));
3786         if (error && retrycnt >= 4)
3787                 error = EIO;
3788         return (error);
3789 }
3790
3791 /*
3792  * The lower level routine for the LockT case.
3793  */
3794 APPLESTATIC int
3795 nfsrpc_lockt(struct nfsrv_descript *nd, vnode_t vp,
3796     struct nfsclclient *clp, u_int64_t off, u_int64_t len, struct flock *fl,
3797     struct ucred *cred, NFSPROC_T *p, void *id, int flags)
3798 {
3799         u_int32_t *tl;
3800         int error, type, size;
3801         uint8_t own[NFSV4CL_LOCKNAMELEN + NFSX_V4FHMAX];
3802         struct nfsnode *np;
3803         struct nfsmount *nmp;
3804
3805         nmp = VFSTONFS(vp->v_mount);
3806         NFSCL_REQSTART(nd, NFSPROC_LOCKT, vp);
3807         NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
3808         if (fl->l_type == F_RDLCK)
3809                 *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
3810         else
3811                 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
3812         txdr_hyper(off, tl);
3813         tl += 2;
3814         txdr_hyper(len, tl);
3815         tl += 2;
3816         *tl++ = NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[0];
3817         *tl = NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[1];
3818         nfscl_filllockowner(id, own, flags);
3819         np = VTONFS(vp);
3820         NFSBCOPY(np->n_fhp->nfh_fh, &own[NFSV4CL_LOCKNAMELEN],
3821             np->n_fhp->nfh_len);
3822         (void)nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN + np->n_fhp->nfh_len);
3823         error = nfscl_request(nd, vp, p, cred, NULL);
3824         if (error)
3825                 return (error);
3826         if (nd->nd_repstat == 0) {
3827                 fl->l_type = F_UNLCK;
3828         } else if (nd->nd_repstat == NFSERR_DENIED) {
3829                 nd->nd_repstat = 0;
3830                 fl->l_whence = SEEK_SET;
3831                 NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
3832                 fl->l_start = fxdr_hyper(tl);
3833                 tl += 2;
3834                 len = fxdr_hyper(tl);
3835                 tl += 2;
3836                 if (len == NFS64BITSSET)
3837                         fl->l_len = 0;
3838                 else
3839                         fl->l_len = len;
3840                 type = fxdr_unsigned(int, *tl++);
3841                 if (type == NFSV4LOCKT_WRITE)
3842                         fl->l_type = F_WRLCK;
3843                 else
3844                         fl->l_type = F_RDLCK;
3845                 /*
3846                  * XXX For now, I have no idea what to do with the
3847                  * conflicting lock_owner, so I'll just set the pid == 0
3848                  * and skip over the lock_owner.
3849                  */
3850                 fl->l_pid = (pid_t)0;
3851                 tl += 2;
3852                 size = fxdr_unsigned(int, *tl);
3853                 if (size < 0 || size > NFSV4_OPAQUELIMIT)
3854                         error = EBADRPC;
3855                 if (!error)
3856                         error = nfsm_advance(nd, NFSM_RNDUP(size), -1);
3857         } else if (nd->nd_repstat == NFSERR_STALECLIENTID ||
3858             nd->nd_repstat == NFSERR_BADSESSION)
3859                 nfscl_initiate_recovery(clp);
3860 nfsmout:
3861         mbuf_freem(nd->nd_mrep);
3862         return (error);
3863 }
3864
3865 /*
3866  * Lower level function that performs the LockU RPC.
3867  */
3868 static int
3869 nfsrpc_locku(struct nfsrv_descript *nd, struct nfsmount *nmp,
3870     struct nfscllockowner *lp, u_int64_t off, u_int64_t len,
3871     u_int32_t type, struct ucred *cred, NFSPROC_T *p, int syscred)
3872 {
3873         u_int32_t *tl;
3874         int error;
3875
3876         nfscl_reqstart(nd, NFSPROC_LOCKU, nmp, lp->nfsl_open->nfso_fh,
3877             lp->nfsl_open->nfso_fhlen, NULL, NULL);
3878         NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED);
3879         *tl++ = txdr_unsigned(type);
3880         *tl = txdr_unsigned(lp->nfsl_seqid);
3881         if (nfstest_outofseq &&
3882             (arc4random() % nfstest_outofseq) == 0)
3883                 *tl = txdr_unsigned(lp->nfsl_seqid + 1);
3884         tl++;
3885         if (NFSHASNFSV4N(nmp))
3886                 *tl++ = 0;
3887         else
3888                 *tl++ = lp->nfsl_stateid.seqid;
3889         *tl++ = lp->nfsl_stateid.other[0];
3890         *tl++ = lp->nfsl_stateid.other[1];
3891         *tl++ = lp->nfsl_stateid.other[2];
3892         txdr_hyper(off, tl);
3893         tl += 2;
3894         txdr_hyper(len, tl);
3895         if (syscred)
3896                 nd->nd_flag |= ND_USEGSSNAME;
3897         error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
3898             NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
3899         NFSCL_INCRSEQID(lp->nfsl_seqid, nd);
3900         if (error)
3901                 return (error);
3902         if (nd->nd_repstat == 0) {
3903                 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
3904                 lp->nfsl_stateid.seqid = *tl++;
3905                 lp->nfsl_stateid.other[0] = *tl++;
3906                 lp->nfsl_stateid.other[1] = *tl++;
3907                 lp->nfsl_stateid.other[2] = *tl;
3908         } else if (nd->nd_repstat == NFSERR_STALESTATEID ||
3909             nd->nd_repstat == NFSERR_BADSESSION)
3910                 nfscl_initiate_recovery(lp->nfsl_open->nfso_own->nfsow_clp);
3911 nfsmout:
3912         mbuf_freem(nd->nd_mrep);
3913         return (error);
3914 }
3915
3916 /*
3917  * The actual Lock RPC.
3918  */
3919 APPLESTATIC int
3920 nfsrpc_lock(struct nfsrv_descript *nd, struct nfsmount *nmp, vnode_t vp,
3921     u_int8_t *nfhp, int fhlen, struct nfscllockowner *lp, int newone,
3922     int reclaim, u_int64_t off, u_int64_t len, short type, struct ucred *cred,
3923     NFSPROC_T *p, int syscred)
3924 {
3925         u_int32_t *tl;
3926         int error, size;
3927         uint8_t own[NFSV4CL_LOCKNAMELEN + NFSX_V4FHMAX];
3928
3929         nfscl_reqstart(nd, NFSPROC_LOCK, nmp, nfhp, fhlen, NULL, NULL);
3930         NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
3931         if (type == F_RDLCK)
3932                 *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
3933         else
3934                 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
3935         *tl++ = txdr_unsigned(reclaim);
3936         txdr_hyper(off, tl);
3937         tl += 2;
3938         txdr_hyper(len, tl);
3939         tl += 2;
3940         if (newone) {
3941             *tl = newnfs_true;
3942             NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID +
3943                 2 * NFSX_UNSIGNED + NFSX_HYPER);
3944             *tl++ = txdr_unsigned(lp->nfsl_open->nfso_own->nfsow_seqid);
3945             if (NFSHASNFSV4N(nmp))
3946                 *tl++ = 0;
3947             else
3948                 *tl++ = lp->nfsl_open->nfso_stateid.seqid;
3949             *tl++ = lp->nfsl_open->nfso_stateid.other[0];
3950             *tl++ = lp->nfsl_open->nfso_stateid.other[1];
3951             *tl++ = lp->nfsl_open->nfso_stateid.other[2];
3952             *tl++ = txdr_unsigned(lp->nfsl_seqid);
3953             *tl++ = NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[0];
3954             *tl = NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[1];
3955             NFSBCOPY(lp->nfsl_owner, own, NFSV4CL_LOCKNAMELEN);
3956             NFSBCOPY(nfhp, &own[NFSV4CL_LOCKNAMELEN], fhlen);
3957             (void)nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN + fhlen);
3958         } else {
3959             *tl = newnfs_false;
3960             NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
3961             if (NFSHASNFSV4N(nmp))
3962                 *tl++ = 0;
3963             else
3964                 *tl++ = lp->nfsl_stateid.seqid;
3965             *tl++ = lp->nfsl_stateid.other[0];
3966             *tl++ = lp->nfsl_stateid.other[1];
3967             *tl++ = lp->nfsl_stateid.other[2];
3968             *tl = txdr_unsigned(lp->nfsl_seqid);
3969             if (nfstest_outofseq &&
3970                 (arc4random() % nfstest_outofseq) == 0)
3971                     *tl = txdr_unsigned(lp->nfsl_seqid + 1);
3972         }
3973         if (syscred)
3974                 nd->nd_flag |= ND_USEGSSNAME;
3975         error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, vp, p, cred,
3976             NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
3977         if (error)
3978                 return (error);
3979         if (newone)
3980             NFSCL_INCRSEQID(lp->nfsl_open->nfso_own->nfsow_seqid, nd);
3981         NFSCL_INCRSEQID(lp->nfsl_seqid, nd);
3982         if (nd->nd_repstat == 0) {
3983                 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
3984                 lp->nfsl_stateid.seqid = *tl++;
3985                 lp->nfsl_stateid.other[0] = *tl++;
3986                 lp->nfsl_stateid.other[1] = *tl++;
3987                 lp->nfsl_stateid.other[2] = *tl;
3988         } else if (nd->nd_repstat == NFSERR_DENIED) {
3989                 NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
3990                 size = fxdr_unsigned(int, *(tl + 7));
3991                 if (size < 0 || size > NFSV4_OPAQUELIMIT)
3992                         error = EBADRPC;
3993                 if (!error)
3994                         error = nfsm_advance(nd, NFSM_RNDUP(size), -1);
3995         } else if (nd->nd_repstat == NFSERR_STALESTATEID ||
3996             nd->nd_repstat == NFSERR_BADSESSION)
3997                 nfscl_initiate_recovery(lp->nfsl_open->nfso_own->nfsow_clp);
3998 nfsmout:
3999         mbuf_freem(nd->nd_mrep);
4000         return (error);
4001 }
4002
4003 /*
4004  * nfs statfs rpc
4005  * (always called with the vp for the mount point)
4006  */
4007 APPLESTATIC int
4008 nfsrpc_statfs(vnode_t vp, struct nfsstatfs *sbp, struct nfsfsinfo *fsp,
4009     struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp,
4010     void *stuff)
4011 {
4012         u_int32_t *tl = NULL;
4013         struct nfsrv_descript nfsd, *nd = &nfsd;
4014         struct nfsmount *nmp;
4015         nfsattrbit_t attrbits;
4016         int error;
4017
4018         *attrflagp = 0;
4019         nmp = VFSTONFS(vnode_mount(vp));
4020         if (NFSHASNFSV4(nmp)) {
4021                 /*
4022                  * For V4, you actually do a getattr.
4023                  */
4024                 NFSCL_REQSTART(nd, NFSPROC_GETATTR, vp);
4025                 NFSSTATFS_GETATTRBIT(&attrbits);
4026                 (void) nfsrv_putattrbit(nd, &attrbits);
4027                 nd->nd_flag |= ND_USEGSSNAME;
4028                 error = nfscl_request(nd, vp, p, cred, stuff);
4029                 if (error)
4030                         return (error);
4031                 if (nd->nd_repstat == 0) {
4032                         error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0,
4033                             NULL, NULL, sbp, fsp, NULL, 0, NULL, NULL, NULL, p,
4034                             cred);
4035                         if (!error) {
4036                                 nmp->nm_fsid[0] = nap->na_filesid[0];
4037                                 nmp->nm_fsid[1] = nap->na_filesid[1];
4038                                 NFSSETHASSETFSID(nmp);
4039                                 *attrflagp = 1;
4040                         }
4041                 } else {
4042                         error = nd->nd_repstat;
4043                 }
4044                 if (error)
4045                         goto nfsmout;
4046         } else {
4047                 NFSCL_REQSTART(nd, NFSPROC_FSSTAT, vp);
4048                 error = nfscl_request(nd, vp, p, cred, stuff);
4049                 if (error)
4050                         return (error);
4051                 if (nd->nd_flag & ND_NFSV3) {
4052                         error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
4053                         if (error)
4054                                 goto nfsmout;
4055                 }
4056                 if (nd->nd_repstat) {
4057                         error = nd->nd_repstat;
4058                         goto nfsmout;
4059                 }
4060                 NFSM_DISSECT(tl, u_int32_t *,
4061                     NFSX_STATFS(nd->nd_flag & ND_NFSV3));
4062         }
4063         if (NFSHASNFSV3(nmp)) {
4064                 sbp->sf_tbytes = fxdr_hyper(tl); tl += 2;
4065                 sbp->sf_fbytes = fxdr_hyper(tl); tl += 2;
4066                 sbp->sf_abytes = fxdr_hyper(tl); tl += 2;
4067                 sbp->sf_tfiles = fxdr_hyper(tl); tl += 2;
4068                 sbp->sf_ffiles = fxdr_hyper(tl); tl += 2;
4069                 sbp->sf_afiles = fxdr_hyper(tl); tl += 2;
4070                 sbp->sf_invarsec = fxdr_unsigned(u_int32_t, *tl);
4071         } else if (NFSHASNFSV4(nmp) == 0) {
4072                 sbp->sf_tsize = fxdr_unsigned(u_int32_t, *tl++);
4073                 sbp->sf_bsize = fxdr_unsigned(u_int32_t, *tl++);
4074                 sbp->sf_blocks = fxdr_unsigned(u_int32_t, *tl++);
4075                 sbp->sf_bfree = fxdr_unsigned(u_int32_t, *tl++);
4076                 sbp->sf_bavail = fxdr_unsigned(u_int32_t, *tl);
4077         }
4078 nfsmout:
4079         mbuf_freem(nd->nd_mrep);
4080         return (error);
4081 }
4082
4083 /*
4084  * nfs pathconf rpc
4085  */
4086 APPLESTATIC int
4087 nfsrpc_pathconf(vnode_t vp, struct nfsv3_pathconf *pc,
4088     struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp,
4089     void *stuff)
4090 {
4091         struct nfsrv_descript nfsd, *nd = &nfsd;
4092         struct nfsmount *nmp;
4093         u_int32_t *tl;
4094         nfsattrbit_t attrbits;
4095         int error;
4096
4097         *attrflagp = 0;
4098         nmp = VFSTONFS(vnode_mount(vp));
4099         if (NFSHASNFSV4(nmp)) {
4100                 /*
4101                  * For V4, you actually do a getattr.
4102                  */
4103                 NFSCL_REQSTART(nd, NFSPROC_GETATTR, vp);
4104                 NFSPATHCONF_GETATTRBIT(&attrbits);
4105                 (void) nfsrv_putattrbit(nd, &attrbits);
4106                 nd->nd_flag |= ND_USEGSSNAME;
4107                 error = nfscl_request(nd, vp, p, cred, stuff);
4108                 if (error)
4109                         return (error);
4110                 if (nd->nd_repstat == 0) {
4111                         error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0,
4112                             pc, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, p,
4113                             cred);
4114                         if (!error)
4115                                 *attrflagp = 1;
4116                 } else {
4117                         error = nd->nd_repstat;
4118                 }
4119         } else {
4120                 NFSCL_REQSTART(nd, NFSPROC_PATHCONF, vp);
4121                 error = nfscl_request(nd, vp, p, cred, stuff);
4122                 if (error)
4123                         return (error);
4124                 error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
4125                 if (nd->nd_repstat && !error)
4126                         error = nd->nd_repstat;
4127                 if (!error) {
4128                         NFSM_DISSECT(tl, u_int32_t *, NFSX_V3PATHCONF);
4129                         pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl++);
4130                         pc->pc_namemax = fxdr_unsigned(u_int32_t, *tl++);
4131                         pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl++);
4132                         pc->pc_chownrestricted =
4133                             fxdr_unsigned(u_int32_t, *tl++);
4134                         pc->pc_caseinsensitive =
4135                             fxdr_unsigned(u_int32_t, *tl++);
4136                         pc->pc_casepreserving = fxdr_unsigned(u_int32_t, *tl);
4137                 }
4138         }
4139 nfsmout:
4140         mbuf_freem(nd->nd_mrep);
4141         return (error);
4142 }
4143
4144 /*
4145  * nfs version 3 fsinfo rpc call
4146  */
4147 APPLESTATIC int
4148 nfsrpc_fsinfo(vnode_t vp, struct nfsfsinfo *fsp, struct ucred *cred,
4149     NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff)
4150 {
4151         u_int32_t *tl;
4152         struct nfsrv_descript nfsd, *nd = &nfsd;
4153         int error;
4154
4155         *attrflagp = 0;
4156         NFSCL_REQSTART(nd, NFSPROC_FSINFO, vp);
4157         error = nfscl_request(nd, vp, p, cred, stuff);
4158         if (error)
4159                 return (error);
4160         error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
4161         if (nd->nd_repstat && !error)
4162                 error = nd->nd_repstat;
4163         if (!error) {
4164                 NFSM_DISSECT(tl, u_int32_t *, NFSX_V3FSINFO);
4165                 fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *tl++);
4166                 fsp->fs_rtpref = fxdr_unsigned(u_int32_t, *tl++);
4167                 fsp->fs_rtmult = fxdr_unsigned(u_int32_t, *tl++);
4168                 fsp->fs_wtmax = fxdr_unsigned(u_int32_t, *tl++);
4169                 fsp->fs_wtpref = fxdr_unsigned(u_int32_t, *tl++);
4170                 fsp->fs_wtmult = fxdr_unsigned(u_int32_t, *tl++);
4171                 fsp->fs_dtpref = fxdr_unsigned(u_int32_t, *tl++);
4172                 fsp->fs_maxfilesize = fxdr_hyper(tl);
4173                 tl += 2;
4174                 fxdr_nfsv3time(tl, &fsp->fs_timedelta);
4175                 tl += 2;
4176                 fsp->fs_properties = fxdr_unsigned(u_int32_t, *tl);
4177         }
4178 nfsmout:
4179         mbuf_freem(nd->nd_mrep);
4180         return (error);
4181 }
4182
4183 /*
4184  * This function performs the Renew RPC.
4185  */
4186 APPLESTATIC int
4187 nfsrpc_renew(struct nfsclclient *clp, struct nfsclds *dsp, struct ucred *cred,
4188     NFSPROC_T *p)
4189 {
4190         u_int32_t *tl;
4191         struct nfsrv_descript nfsd;
4192         struct nfsrv_descript *nd = &nfsd;
4193         struct nfsmount *nmp;
4194         int error;
4195         struct nfssockreq *nrp;
4196
4197         nmp = clp->nfsc_nmp;
4198         if (nmp == NULL)
4199                 return (0);
4200         nfscl_reqstart(nd, NFSPROC_RENEW, nmp, NULL, 0, NULL,
4201             &dsp->nfsclds_sess);
4202         if (!NFSHASNFSV4N(nmp)) {
4203                 /* NFSv4.1 just uses a Sequence Op and not a Renew. */
4204                 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
4205                 *tl++ = NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[0];
4206                 *tl = NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[1];
4207         }
4208         nrp = dsp->nfsclds_sockp;
4209         if (nrp == NULL)
4210                 /* If NULL, use the MDS socket. */
4211                 nrp = &nmp->nm_sockreq;
4212         nd->nd_flag |= ND_USEGSSNAME;
4213         error = newnfs_request(nd, nmp, NULL, nrp, NULL, p, cred,
4214             NFS_PROG, NFS_VER4, NULL, 1, NULL, &dsp->nfsclds_sess);
4215         if (error)
4216                 return (error);
4217         error = nd->nd_repstat;
4218         mbuf_freem(nd->nd_mrep);
4219         return (error);
4220 }
4221
4222 /*
4223  * This function performs the Releaselockowner RPC.
4224  */
4225 APPLESTATIC int
4226 nfsrpc_rellockown(struct nfsmount *nmp, struct nfscllockowner *lp,
4227     uint8_t *fh, int fhlen, struct ucred *cred, NFSPROC_T *p)
4228 {
4229         struct nfsrv_descript nfsd, *nd = &nfsd;
4230         u_int32_t *tl;
4231         int error;
4232         uint8_t own[NFSV4CL_LOCKNAMELEN + NFSX_V4FHMAX];
4233
4234         if (NFSHASNFSV4N(nmp)) {
4235                 /* For NFSv4.1, do a FreeStateID. */
4236                 nfscl_reqstart(nd, NFSPROC_FREESTATEID, nmp, NULL, 0, NULL,
4237                     NULL);
4238                 nfsm_stateidtom(nd, &lp->nfsl_stateid, NFSSTATEID_PUTSTATEID);
4239         } else {
4240                 nfscl_reqstart(nd, NFSPROC_RELEASELCKOWN, nmp, NULL, 0, NULL,
4241                     NULL);
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                 NFSBCOPY(lp->nfsl_owner, own, NFSV4CL_LOCKNAMELEN);
4246                 NFSBCOPY(fh, &own[NFSV4CL_LOCKNAMELEN], fhlen);
4247                 (void)nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN + fhlen);
4248         }
4249         nd->nd_flag |= ND_USEGSSNAME;
4250         error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
4251             NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
4252         if (error)
4253                 return (error);
4254         error = nd->nd_repstat;
4255         mbuf_freem(nd->nd_mrep);
4256         return (error);
4257 }
4258
4259 /*
4260  * This function performs the Compound to get the mount pt FH.
4261  */
4262 APPLESTATIC int
4263 nfsrpc_getdirpath(struct nfsmount *nmp, u_char *dirpath, struct ucred *cred,
4264     NFSPROC_T *p)
4265 {
4266         u_int32_t *tl;
4267         struct nfsrv_descript nfsd;
4268         struct nfsrv_descript *nd = &nfsd;
4269         u_char *cp, *cp2;
4270         int error, cnt, len, setnil;
4271         u_int32_t *opcntp;
4272
4273         nfscl_reqstart(nd, NFSPROC_PUTROOTFH, nmp, NULL, 0, &opcntp, NULL);
4274         cp = dirpath;
4275         cnt = 0;
4276         do {
4277                 setnil = 0;
4278                 while (*cp == '/')
4279                         cp++;
4280                 cp2 = cp;
4281                 while (*cp2 != '\0' && *cp2 != '/')
4282                         cp2++;
4283                 if (*cp2 == '/') {
4284                         setnil = 1;
4285                         *cp2 = '\0';
4286                 }
4287                 if (cp2 != cp) {
4288                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
4289                         *tl = txdr_unsigned(NFSV4OP_LOOKUP);
4290                         nfsm_strtom(nd, cp, strlen(cp));
4291                         cnt++;
4292                 }
4293                 if (setnil)
4294                         *cp2++ = '/';
4295                 cp = cp2;
4296         } while (*cp != '\0');
4297         if (NFSHASNFSV4N(nmp))
4298                 /* Has a Sequence Op done by nfscl_reqstart(). */
4299                 *opcntp = txdr_unsigned(3 + cnt);
4300         else
4301                 *opcntp = txdr_unsigned(2 + cnt);
4302         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
4303         *tl = txdr_unsigned(NFSV4OP_GETFH);
4304         nd->nd_flag |= ND_USEGSSNAME;
4305         error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
4306                 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
4307         if (error)
4308                 return (error);
4309         if (nd->nd_repstat == 0) {
4310                 NFSM_DISSECT(tl, u_int32_t *, (3 + 2 * cnt) * NFSX_UNSIGNED);
4311                 tl += (2 + 2 * cnt);
4312                 if ((len = fxdr_unsigned(int, *tl)) <= 0 ||
4313                         len > NFSX_FHMAX) {
4314                         nd->nd_repstat = NFSERR_BADXDR;
4315                 } else {
4316                         nd->nd_repstat = nfsrv_mtostr(nd, nmp->nm_fh, len);
4317                         if (nd->nd_repstat == 0)
4318                                 nmp->nm_fhsize = len;
4319                 }
4320         }
4321         error = nd->nd_repstat;
4322 nfsmout:
4323         mbuf_freem(nd->nd_mrep);
4324         return (error);
4325 }
4326
4327 /*
4328  * This function performs the Delegreturn RPC.
4329  */
4330 APPLESTATIC int
4331 nfsrpc_delegreturn(struct nfscldeleg *dp, struct ucred *cred,
4332     struct nfsmount *nmp, NFSPROC_T *p, int syscred)
4333 {
4334         u_int32_t *tl;
4335         struct nfsrv_descript nfsd;
4336         struct nfsrv_descript *nd = &nfsd;
4337         int error;
4338
4339         nfscl_reqstart(nd, NFSPROC_DELEGRETURN, nmp, dp->nfsdl_fh,
4340             dp->nfsdl_fhlen, NULL, NULL);
4341         NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
4342         if (NFSHASNFSV4N(nmp))
4343                 *tl++ = 0;
4344         else
4345                 *tl++ = dp->nfsdl_stateid.seqid;
4346         *tl++ = dp->nfsdl_stateid.other[0];
4347         *tl++ = dp->nfsdl_stateid.other[1];
4348         *tl = dp->nfsdl_stateid.other[2];
4349         if (syscred)
4350                 nd->nd_flag |= ND_USEGSSNAME;
4351         error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
4352             NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
4353         if (error)
4354                 return (error);
4355         error = nd->nd_repstat;
4356         mbuf_freem(nd->nd_mrep);
4357         return (error);
4358 }
4359
4360 /*
4361  * nfs getacl call.
4362  */
4363 APPLESTATIC int
4364 nfsrpc_getacl(vnode_t vp, struct ucred *cred, NFSPROC_T *p,
4365     struct acl *aclp, void *stuff)
4366 {
4367         struct nfsrv_descript nfsd, *nd = &nfsd;
4368         int error;
4369         nfsattrbit_t attrbits;
4370         struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
4371         
4372         if (nfsrv_useacl == 0 || !NFSHASNFSV4(nmp))
4373                 return (EOPNOTSUPP);
4374         NFSCL_REQSTART(nd, NFSPROC_GETACL, vp);
4375         NFSZERO_ATTRBIT(&attrbits);
4376         NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_ACL);
4377         (void) nfsrv_putattrbit(nd, &attrbits);
4378         error = nfscl_request(nd, vp, p, cred, stuff);
4379         if (error)
4380                 return (error);
4381         if (!nd->nd_repstat)
4382                 error = nfsv4_loadattr(nd, vp, NULL, NULL, NULL, 0, NULL,
4383                     NULL, NULL, NULL, aclp, 0, NULL, NULL, NULL, p, cred);
4384         else
4385                 error = nd->nd_repstat;
4386         mbuf_freem(nd->nd_mrep);
4387         return (error);
4388 }
4389
4390 /*
4391  * nfs setacl call.
4392  */
4393 APPLESTATIC int
4394 nfsrpc_setacl(vnode_t vp, struct ucred *cred, NFSPROC_T *p,
4395     struct acl *aclp, void *stuff)
4396 {
4397         int error;
4398         struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
4399         
4400         if (nfsrv_useacl == 0 || !NFSHASNFSV4(nmp))
4401                 return (EOPNOTSUPP);
4402         error = nfsrpc_setattr(vp, NULL, aclp, cred, p, NULL, NULL, stuff);
4403         return (error);
4404 }
4405
4406 /*
4407  * nfs setacl call.
4408  */
4409 static int
4410 nfsrpc_setaclrpc(vnode_t vp, struct ucred *cred, NFSPROC_T *p,
4411     struct acl *aclp, nfsv4stateid_t *stateidp, void *stuff)
4412 {
4413         struct nfsrv_descript nfsd, *nd = &nfsd;
4414         int error;
4415         nfsattrbit_t attrbits;
4416         struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
4417         
4418         if (!NFSHASNFSV4(nmp))
4419                 return (EOPNOTSUPP);
4420         NFSCL_REQSTART(nd, NFSPROC_SETACL, vp);
4421         nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID);
4422         NFSZERO_ATTRBIT(&attrbits);
4423         NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_ACL);
4424         (void) nfsv4_fillattr(nd, vnode_mount(vp), vp, aclp, NULL, NULL, 0,
4425             &attrbits, NULL, NULL, 0, 0, 0, 0, (uint64_t)0);
4426         error = nfscl_request(nd, vp, p, cred, stuff);
4427         if (error)
4428                 return (error);
4429         /* Don't care about the pre/postop attributes */
4430         mbuf_freem(nd->nd_mrep);
4431         return (nd->nd_repstat);
4432 }
4433
4434 /*
4435  * Do the NFSv4.1 Exchange ID.
4436  */
4437 int
4438 nfsrpc_exchangeid(struct nfsmount *nmp, struct nfsclclient *clp,
4439     struct nfssockreq *nrp, uint32_t exchflags, struct nfsclds **dspp,
4440     struct ucred *cred, NFSPROC_T *p)
4441 {
4442         uint32_t *tl, v41flags;
4443         struct nfsrv_descript nfsd;
4444         struct nfsrv_descript *nd = &nfsd;
4445         struct nfsclds *dsp;
4446         struct timespec verstime;
4447         int error, len;
4448
4449         *dspp = NULL;
4450         nfscl_reqstart(nd, NFSPROC_EXCHANGEID, nmp, NULL, 0, NULL, NULL);
4451         NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
4452         *tl++ = txdr_unsigned(nfsboottime.tv_sec);      /* Client owner */
4453         *tl = txdr_unsigned(clp->nfsc_rev);
4454         (void) nfsm_strtom(nd, clp->nfsc_id, clp->nfsc_idlen);
4455
4456         NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED);
4457         *tl++ = txdr_unsigned(exchflags);
4458         *tl++ = txdr_unsigned(NFSV4EXCH_SP4NONE);
4459
4460         /* Set the implementation id4 */
4461         *tl = txdr_unsigned(1);
4462         (void) nfsm_strtom(nd, "freebsd.org", strlen("freebsd.org"));
4463         (void) nfsm_strtom(nd, version, strlen(version));
4464         NFSM_BUILD(tl, uint32_t *, NFSX_V4TIME);
4465         verstime.tv_sec = 1293840000;           /* Jan 1, 2011 */
4466         verstime.tv_nsec = 0;
4467         txdr_nfsv4time(&verstime, tl);
4468         nd->nd_flag |= ND_USEGSSNAME;
4469         error = newnfs_request(nd, nmp, NULL, nrp, NULL, p, cred,
4470             NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
4471         NFSCL_DEBUG(1, "exchangeid err=%d reps=%d\n", error,
4472             (int)nd->nd_repstat);
4473         if (error != 0)
4474                 return (error);
4475         if (nd->nd_repstat == 0) {
4476                 NFSM_DISSECT(tl, uint32_t *, 6 * NFSX_UNSIGNED + NFSX_HYPER);
4477                 len = fxdr_unsigned(int, *(tl + 7));
4478                 if (len < 0 || len > NFSV4_OPAQUELIMIT) {
4479                         error = NFSERR_BADXDR;
4480                         goto nfsmout;
4481                 }
4482                 dsp = malloc(sizeof(struct nfsclds) + len, M_NFSCLDS,
4483                     M_WAITOK | M_ZERO);
4484                 dsp->nfsclds_expire = NFSD_MONOSEC + clp->nfsc_renew;
4485                 dsp->nfsclds_servownlen = len;
4486                 dsp->nfsclds_sess.nfsess_clientid.lval[0] = *tl++;
4487                 dsp->nfsclds_sess.nfsess_clientid.lval[1] = *tl++;
4488                 dsp->nfsclds_sess.nfsess_sequenceid =
4489                     fxdr_unsigned(uint32_t, *tl++);
4490                 v41flags = fxdr_unsigned(uint32_t, *tl);
4491                 if ((v41flags & NFSV4EXCH_USEPNFSMDS) != 0 &&
4492                     NFSHASPNFSOPT(nmp)) {
4493                         NFSCL_DEBUG(1, "set PNFS\n");
4494                         NFSLOCKMNT(nmp);
4495                         nmp->nm_state |= NFSSTA_PNFS;
4496                         NFSUNLOCKMNT(nmp);
4497                         dsp->nfsclds_flags |= NFSCLDS_MDS;
4498                 }
4499                 if ((v41flags & NFSV4EXCH_USEPNFSDS) != 0)
4500                         dsp->nfsclds_flags |= NFSCLDS_DS;
4501                 if (len > 0)
4502                         nd->nd_repstat = nfsrv_mtostr(nd,
4503                             dsp->nfsclds_serverown, len);
4504                 if (nd->nd_repstat == 0) {
4505                         mtx_init(&dsp->nfsclds_mtx, "nfsds", NULL, MTX_DEF);
4506                         mtx_init(&dsp->nfsclds_sess.nfsess_mtx, "nfssession",
4507                             NULL, MTX_DEF);
4508                         nfscl_initsessionslots(&dsp->nfsclds_sess);
4509                         *dspp = dsp;
4510                 } else
4511                         free(dsp, M_NFSCLDS);
4512         }
4513         error = nd->nd_repstat;
4514 nfsmout:
4515         mbuf_freem(nd->nd_mrep);
4516         return (error);
4517 }
4518
4519 /*
4520  * Do the NFSv4.1 Create Session.
4521  */
4522 int
4523 nfsrpc_createsession(struct nfsmount *nmp, struct nfsclsession *sep,
4524     struct nfssockreq *nrp, uint32_t sequenceid, int mds, struct ucred *cred,
4525     NFSPROC_T *p)
4526 {
4527         uint32_t crflags, *tl;
4528         struct nfsrv_descript nfsd;
4529         struct nfsrv_descript *nd = &nfsd;
4530         int error, irdcnt;
4531
4532         nfscl_reqstart(nd, NFSPROC_CREATESESSION, nmp, NULL, 0, NULL, NULL);
4533         NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED);
4534         *tl++ = sep->nfsess_clientid.lval[0];
4535         *tl++ = sep->nfsess_clientid.lval[1];
4536         *tl++ = txdr_unsigned(sequenceid);
4537         crflags = (NFSMNT_RDONLY(nmp->nm_mountp) ? 0 : NFSV4CRSESS_PERSIST);
4538         if (nfscl_enablecallb != 0 && nfs_numnfscbd > 0)
4539                 crflags |= NFSV4CRSESS_CONNBACKCHAN;
4540         *tl = txdr_unsigned(crflags);
4541
4542         /* Fill in fore channel attributes. */
4543         NFSM_BUILD(tl, uint32_t *, 7 * NFSX_UNSIGNED);
4544         *tl++ = 0;                              /* Header pad size */
4545         *tl++ = txdr_unsigned(100000);          /* Max request size */
4546         *tl++ = txdr_unsigned(100000);          /* Max response size */
4547         *tl++ = txdr_unsigned(4096);            /* Max response size cached */
4548         *tl++ = txdr_unsigned(20);              /* Max operations */
4549         *tl++ = txdr_unsigned(64);              /* Max slots */
4550         *tl = 0;                                /* No rdma ird */
4551
4552         /* Fill in back channel attributes. */
4553         NFSM_BUILD(tl, uint32_t *, 7 * NFSX_UNSIGNED);
4554         *tl++ = 0;                              /* Header pad size */
4555         *tl++ = txdr_unsigned(10000);           /* Max request size */
4556         *tl++ = txdr_unsigned(10000);           /* Max response size */
4557         *tl++ = txdr_unsigned(4096);            /* Max response size cached */
4558         *tl++ = txdr_unsigned(4);               /* Max operations */
4559         *tl++ = txdr_unsigned(NFSV4_CBSLOTS);   /* Max slots */
4560         *tl = 0;                                /* No rdma ird */
4561
4562         NFSM_BUILD(tl, uint32_t *, 8 * NFSX_UNSIGNED);
4563         *tl++ = txdr_unsigned(NFS_CALLBCKPROG); /* Call back prog # */
4564
4565         /* Allow AUTH_SYS callbacks as uid, gid == 0. */
4566         *tl++ = txdr_unsigned(1);               /* Auth_sys only */
4567         *tl++ = txdr_unsigned(AUTH_SYS);        /* AUTH_SYS type */
4568         *tl++ = txdr_unsigned(nfsboottime.tv_sec); /* time stamp */
4569         *tl++ = 0;                              /* Null machine name */
4570         *tl++ = 0;                              /* Uid == 0 */
4571         *tl++ = 0;                              /* Gid == 0 */
4572         *tl = 0;                                /* No additional gids */
4573         nd->nd_flag |= ND_USEGSSNAME;
4574         error = newnfs_request(nd, nmp, NULL, nrp, NULL, p, cred, NFS_PROG,
4575             NFS_VER4, NULL, 1, NULL, NULL);
4576         if (error != 0)
4577                 return (error);
4578         if (nd->nd_repstat == 0) {
4579                 NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID +
4580                     2 * NFSX_UNSIGNED);
4581                 bcopy(tl, sep->nfsess_sessionid, NFSX_V4SESSIONID);
4582                 tl += NFSX_V4SESSIONID / NFSX_UNSIGNED;
4583                 sep->nfsess_sequenceid = fxdr_unsigned(uint32_t, *tl++);
4584                 crflags = fxdr_unsigned(uint32_t, *tl);
4585                 if ((crflags & NFSV4CRSESS_PERSIST) != 0 && mds != 0) {
4586                         NFSLOCKMNT(nmp);
4587                         nmp->nm_state |= NFSSTA_SESSPERSIST;
4588                         NFSUNLOCKMNT(nmp);
4589                 }
4590
4591                 /* Get the fore channel slot count. */
4592                 NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED);
4593                 tl += 3;                /* Skip the other counts. */            
4594                 sep->nfsess_maxcache = fxdr_unsigned(int, *tl++);
4595                 tl++;
4596                 sep->nfsess_foreslots = fxdr_unsigned(uint16_t, *tl++);
4597                 NFSCL_DEBUG(4, "fore slots=%d\n", (int)sep->nfsess_foreslots);
4598                 irdcnt = fxdr_unsigned(int, *tl);
4599                 if (irdcnt > 0)
4600                         NFSM_DISSECT(tl, uint32_t *, irdcnt * NFSX_UNSIGNED);
4601
4602                 /* and the back channel slot count. */
4603                 NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED);
4604                 tl += 5;
4605                 sep->nfsess_backslots = fxdr_unsigned(uint16_t, *tl);
4606                 NFSCL_DEBUG(4, "back slots=%d\n", (int)sep->nfsess_backslots);
4607         }
4608         error = nd->nd_repstat;
4609 nfsmout:
4610         mbuf_freem(nd->nd_mrep);
4611         return (error);
4612 }
4613
4614 /*
4615  * Do the NFSv4.1 Destroy Session.
4616  */
4617 int
4618 nfsrpc_destroysession(struct nfsmount *nmp, struct nfsclclient *clp,
4619     struct ucred *cred, NFSPROC_T *p)
4620 {
4621         uint32_t *tl;
4622         struct nfsrv_descript nfsd;
4623         struct nfsrv_descript *nd = &nfsd;
4624         int error;
4625
4626         nfscl_reqstart(nd, NFSPROC_DESTROYSESSION, nmp, NULL, 0, NULL, NULL);
4627         NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID);
4628         bcopy(NFSMNT_MDSSESSION(nmp)->nfsess_sessionid, tl, NFSX_V4SESSIONID);
4629         nd->nd_flag |= ND_USEGSSNAME;
4630         error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
4631             NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
4632         if (error != 0)
4633                 return (error);
4634         error = nd->nd_repstat;
4635         mbuf_freem(nd->nd_mrep);
4636         return (error);
4637 }
4638
4639 /*
4640  * Do the NFSv4.1 Destroy Client.
4641  */
4642 int
4643 nfsrpc_destroyclient(struct nfsmount *nmp, struct nfsclclient *clp,
4644     struct ucred *cred, NFSPROC_T *p)
4645 {
4646         uint32_t *tl;
4647         struct nfsrv_descript nfsd;
4648         struct nfsrv_descript *nd = &nfsd;
4649         int error;
4650
4651         nfscl_reqstart(nd, NFSPROC_DESTROYCLIENT, nmp, NULL, 0, NULL, NULL);
4652         NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
4653         *tl++ = NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[0];
4654         *tl = NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[1];
4655         nd->nd_flag |= ND_USEGSSNAME;
4656         error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
4657             NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
4658         if (error != 0)
4659                 return (error);
4660         error = nd->nd_repstat;
4661         mbuf_freem(nd->nd_mrep);
4662         return (error);
4663 }
4664
4665 /*
4666  * Do the NFSv4.1 LayoutGet.
4667  */
4668 int
4669 nfsrpc_layoutget(struct nfsmount *nmp, uint8_t *fhp, int fhlen, int iomode,
4670     uint64_t offset, uint64_t len, uint64_t minlen, int layoutlen,
4671     nfsv4stateid_t *stateidp, int *retonclosep, struct nfsclflayouthead *flhp,
4672     struct ucred *cred, NFSPROC_T *p, void *stuff)
4673 {
4674         uint32_t *tl;
4675         struct nfsrv_descript nfsd, *nd = &nfsd;
4676         struct nfsfh *nfhp;
4677         struct nfsclflayout *flp, *prevflp, *tflp;
4678         int cnt, error, gotiomode, fhcnt, nfhlen, i, j;
4679         uint8_t *cp;
4680         uint64_t retlen;
4681
4682         flp = NULL;
4683         gotiomode = -1;
4684         nfscl_reqstart(nd, NFSPROC_LAYOUTGET, nmp, fhp, fhlen, NULL, NULL);
4685         NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED + 3 * NFSX_HYPER +
4686             NFSX_STATEID);
4687         *tl++ = newnfs_false;           /* Don't signal availability. */
4688         *tl++ = txdr_unsigned(NFSLAYOUT_NFSV4_1_FILES);
4689         *tl++ = txdr_unsigned(iomode);
4690         txdr_hyper(offset, tl);
4691         tl += 2;
4692         txdr_hyper(len, tl);
4693         tl += 2;
4694         txdr_hyper(minlen, tl);
4695         tl += 2;
4696         *tl++ = txdr_unsigned(stateidp->seqid);
4697         NFSCL_DEBUG(4, "layget seq=%d\n", (int)stateidp->seqid);
4698         *tl++ = stateidp->other[0];
4699         *tl++ = stateidp->other[1];
4700         *tl++ = stateidp->other[2];
4701         *tl = txdr_unsigned(layoutlen);
4702         nd->nd_flag |= ND_USEGSSNAME;
4703         error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
4704             NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
4705         if (error != 0)
4706                 return (error);
4707         if (nd->nd_repstat == 0) {
4708                 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + NFSX_STATEID);
4709                 if (*tl++ != 0)
4710                         *retonclosep = 1;
4711                 else
4712                         *retonclosep = 0;
4713                 stateidp->seqid = fxdr_unsigned(uint32_t, *tl++);
4714                 NFSCL_DEBUG(4, "retoncls=%d stseq=%d\n", *retonclosep,
4715                     (int)stateidp->seqid);
4716                 stateidp->other[0] = *tl++;
4717                 stateidp->other[1] = *tl++;
4718                 stateidp->other[2] = *tl++;
4719                 cnt = fxdr_unsigned(int, *tl);
4720                 NFSCL_DEBUG(4, "layg cnt=%d\n", cnt);
4721                 if (cnt <= 0 || cnt > 10000) {
4722                         /* Don't accept more than 10000 layouts in reply. */
4723                         error = NFSERR_BADXDR;
4724                         goto nfsmout;
4725                 }
4726                 for (i = 0; i < cnt; i++) {
4727                         /* Dissect all the way to the file handle cnt. */
4728                         NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_HYPER +
4729                             6 * NFSX_UNSIGNED + NFSX_V4DEVICEID);
4730                         fhcnt = fxdr_unsigned(int, *(tl + 11 +
4731                             NFSX_V4DEVICEID / NFSX_UNSIGNED));
4732                         NFSCL_DEBUG(4, "fhcnt=%d\n", fhcnt);
4733                         if (fhcnt < 0 || fhcnt > 100) {
4734                                 /* Don't accept more than 100 file handles. */
4735                                 error = NFSERR_BADXDR;
4736                                 goto nfsmout;
4737                         }
4738                         if (fhcnt > 1)
4739                                 flp = malloc(sizeof(*flp) + (fhcnt - 1) *
4740                                     sizeof(struct nfsfh *),
4741                                     M_NFSFLAYOUT, M_WAITOK);
4742                         else
4743                                 flp = malloc(sizeof(*flp),
4744                                     M_NFSFLAYOUT, M_WAITOK);
4745                         flp->nfsfl_flags = 0;
4746                         flp->nfsfl_fhcnt = 0;
4747                         flp->nfsfl_devp = NULL;
4748                         flp->nfsfl_off = fxdr_hyper(tl); tl += 2;
4749                         retlen = fxdr_hyper(tl); tl += 2;
4750                         if (flp->nfsfl_off + retlen < flp->nfsfl_off)
4751                                 flp->nfsfl_end = UINT64_MAX - flp->nfsfl_off;
4752                         else
4753                                 flp->nfsfl_end = flp->nfsfl_off + retlen;
4754                         flp->nfsfl_iomode = fxdr_unsigned(int, *tl++);
4755                         if (gotiomode == -1)
4756                                 gotiomode = flp->nfsfl_iomode;
4757                         NFSCL_DEBUG(4, "layg reqiom=%d retiom=%d\n", iomode,
4758                             (int)flp->nfsfl_iomode);
4759                         if (fxdr_unsigned(int, *tl++) !=
4760                             NFSLAYOUT_NFSV4_1_FILES) {
4761                                 printf("NFSv4.1: got non-files layout\n");
4762                                 error = NFSERR_BADXDR;
4763                                 goto nfsmout;
4764                         }
4765                         NFSBCOPY(++tl, flp->nfsfl_dev, NFSX_V4DEVICEID);
4766                         tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED);
4767                         flp->nfsfl_util = fxdr_unsigned(uint32_t, *tl++);
4768                         NFSCL_DEBUG(4, "flutil=0x%x\n", flp->nfsfl_util);
4769                         flp->nfsfl_stripe1 = fxdr_unsigned(uint32_t, *tl++);
4770                         flp->nfsfl_patoff = fxdr_hyper(tl); tl += 2;
4771                         if (fxdr_unsigned(int, *tl) != fhcnt) {
4772                                 printf("EEK! bad fhcnt\n");
4773                                 error = NFSERR_BADXDR;
4774                                 goto nfsmout;
4775                         }
4776                         for (j = 0; j < fhcnt; j++) {
4777                                 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4778                                 nfhlen = fxdr_unsigned(int, *tl);
4779                                 if (nfhlen <= 0 || nfhlen > NFSX_V4FHMAX) {
4780                                         error = NFSERR_BADXDR;
4781                                         goto nfsmout;
4782                                 }
4783                                 nfhp = malloc(sizeof(*nfhp) + nfhlen - 1,
4784                                     M_NFSFH, M_WAITOK);
4785                                 flp->nfsfl_fh[j] = nfhp;
4786                                 flp->nfsfl_fhcnt++;
4787                                 nfhp->nfh_len = nfhlen;
4788                                 NFSM_DISSECT(cp, uint8_t *, NFSM_RNDUP(nfhlen));
4789                                 NFSBCOPY(cp, nfhp->nfh_fh, nfhlen);
4790                         }
4791                         if (flp->nfsfl_iomode == gotiomode) {
4792                                 /* Keep the list in increasing offset order. */
4793                                 tflp = LIST_FIRST(flhp);
4794                                 prevflp = NULL;
4795                                 while (tflp != NULL &&
4796                                     tflp->nfsfl_off < flp->nfsfl_off) {
4797                                         prevflp = tflp;
4798                                         tflp = LIST_NEXT(tflp, nfsfl_list);
4799                                 }
4800                                 if (prevflp == NULL)
4801                                         LIST_INSERT_HEAD(flhp, flp, nfsfl_list);
4802                                 else
4803                                         LIST_INSERT_AFTER(prevflp, flp,
4804                                             nfsfl_list);
4805                         } else {
4806                                 printf("nfscl_layoutget(): got wrong iomode\n");
4807                                 nfscl_freeflayout(flp);
4808                         }
4809                         flp = NULL;
4810                 }
4811         }
4812         if (nd->nd_repstat != 0 && error == 0)
4813                 error = nd->nd_repstat;
4814 nfsmout:
4815         if (error != 0 && flp != NULL)
4816                 nfscl_freeflayout(flp);
4817         mbuf_freem(nd->nd_mrep);
4818         return (error);
4819 }
4820
4821 /*
4822  * Do the NFSv4.1 Get Device Info.
4823  */
4824 int
4825 nfsrpc_getdeviceinfo(struct nfsmount *nmp, uint8_t *deviceid, int layouttype,
4826     uint32_t *notifybitsp, struct nfscldevinfo **ndip, struct ucred *cred,
4827     NFSPROC_T *p)
4828 {
4829         uint32_t cnt, *tl;
4830         struct nfsrv_descript nfsd;
4831         struct nfsrv_descript *nd = &nfsd;
4832         struct sockaddr_storage ss;
4833         struct nfsclds *dsp = NULL, **dspp;
4834         struct nfscldevinfo *ndi;
4835         int addrcnt, bitcnt, error, i, isudp, j, pos, safilled, stripecnt;
4836         uint8_t stripeindex;
4837
4838         *ndip = NULL;
4839         ndi = NULL;
4840         nfscl_reqstart(nd, NFSPROC_GETDEVICEINFO, nmp, NULL, 0, NULL, NULL);
4841         NFSM_BUILD(tl, uint32_t *, NFSX_V4DEVICEID + 3 * NFSX_UNSIGNED);
4842         NFSBCOPY(deviceid, tl, NFSX_V4DEVICEID);
4843         tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED);
4844         *tl++ = txdr_unsigned(layouttype);
4845         *tl++ = txdr_unsigned(100000);
4846         if (notifybitsp != NULL && *notifybitsp != 0) {
4847                 *tl = txdr_unsigned(1);         /* One word of bits. */
4848                 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
4849                 *tl = txdr_unsigned(*notifybitsp);
4850         } else
4851                 *tl = txdr_unsigned(0);
4852         nd->nd_flag |= ND_USEGSSNAME;
4853         error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
4854             NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
4855         if (error != 0)
4856                 return (error);
4857         if (nd->nd_repstat == 0) {
4858                 NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_UNSIGNED);
4859                 if (layouttype != fxdr_unsigned(int, *tl++))
4860                         printf("EEK! devinfo layout type not same!\n");
4861                 stripecnt = fxdr_unsigned(int, *++tl);
4862                 NFSCL_DEBUG(4, "stripecnt=%d\n", stripecnt);
4863                 if (stripecnt < 1 || stripecnt > 4096) {
4864                         printf("NFS devinfo stripecnt %d: out of range\n",
4865                             stripecnt);
4866                         error = NFSERR_BADXDR;
4867                         goto nfsmout;
4868                 }
4869                 NFSM_DISSECT(tl, uint32_t *, (stripecnt + 1) * NFSX_UNSIGNED);
4870                 addrcnt = fxdr_unsigned(int, *(tl + stripecnt));
4871                 NFSCL_DEBUG(4, "addrcnt=%d\n", addrcnt);
4872                 if (addrcnt < 1 || addrcnt > 128) {
4873                         printf("NFS devinfo addrcnt %d: out of range\n",
4874                             addrcnt);
4875                         error = NFSERR_BADXDR;
4876                         goto nfsmout;
4877                 }
4878
4879                 /*
4880                  * Now we know how many stripe indices and addresses, so
4881                  * we can allocate the structure the correct size.
4882                  */
4883                 i = (stripecnt * sizeof(uint8_t)) / sizeof(struct nfsclds *)
4884                     + 1;
4885                 NFSCL_DEBUG(4, "stripeindices=%d\n", i);
4886                 ndi = malloc(sizeof(*ndi) + (addrcnt + i) *
4887                     sizeof(struct nfsclds *), M_NFSDEVINFO, M_WAITOK | M_ZERO);
4888                 NFSBCOPY(deviceid, ndi->nfsdi_deviceid, NFSX_V4DEVICEID);
4889                 ndi->nfsdi_refcnt = 0;
4890                 ndi->nfsdi_stripecnt = stripecnt;
4891                 ndi->nfsdi_addrcnt = addrcnt;
4892                 /* Fill in the stripe indices. */
4893                 for (i = 0; i < stripecnt; i++) {
4894                         stripeindex = fxdr_unsigned(uint8_t, *tl++);
4895                         NFSCL_DEBUG(4, "stripeind=%d\n", stripeindex);
4896                         if (stripeindex >= addrcnt) {
4897                                 printf("NFS devinfo stripeindex %d: too big\n",
4898                                     (int)stripeindex);
4899                                 error = NFSERR_BADXDR;
4900                                 goto nfsmout;
4901                         }
4902                         nfsfldi_setstripeindex(ndi, i, stripeindex);
4903                 }
4904
4905                 /* Now, dissect the server address(es). */
4906                 safilled = 0;
4907                 for (i = 0; i < addrcnt; i++) {
4908                         NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4909                         cnt = fxdr_unsigned(uint32_t, *tl);
4910                         if (cnt == 0) {
4911                                 printf("NFS devinfo 0 len addrlist\n");
4912                                 error = NFSERR_BADXDR;
4913                                 goto nfsmout;
4914                         }
4915                         dspp = nfsfldi_addr(ndi, i);
4916                         pos = arc4random() % cnt;       /* Choose one. */
4917                         safilled = 0;
4918                         for (j = 0; j < cnt; j++) {
4919                                 error = nfsv4_getipaddr(nd, &ss, &isudp);
4920                                 if (error != 0 && error != EPERM) {
4921                                         error = NFSERR_BADXDR;
4922                                         goto nfsmout;
4923                                 }
4924                                 if (error == 0 && isudp == 0) {
4925                                         /*
4926                                          * The algorithm is:
4927                                          * - use "pos" entry if it is of the
4928                                          *   same af_family or none of them
4929                                          *   is of the same af_family
4930                                          * else
4931                                          * - use the first one of the same
4932                                          *   af_family.
4933                                          */
4934                                         if ((safilled == 0 && ss.ss_family ==
4935                                              nmp->nm_nam->sa_family) ||
4936                                             (j == pos &&
4937                                              (safilled == 0 || ss.ss_family ==
4938                                               nmp->nm_nam->sa_family)) ||
4939                                             (safilled == 1 && ss.ss_family ==
4940                                              nmp->nm_nam->sa_family)) {
4941                                                 error = nfsrpc_fillsa(nmp, &ss,
4942                                                     &dsp, p);
4943                                                 if (error == 0) {
4944                                                         *dspp = dsp;
4945                                                         if (ss.ss_family ==
4946                                                          nmp->nm_nam->sa_family)
4947                                                                 safilled = 2;
4948                                                         else
4949                                                                 safilled = 1;
4950                                                 }
4951                                         }
4952                                 }
4953                         }
4954                         if (safilled == 0)
4955                                 break;
4956                 }
4957
4958                 /* And the notify bits. */
4959                 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4960                 if (safilled != 0) {
4961                         bitcnt = fxdr_unsigned(int, *tl);
4962                         if (bitcnt > 0) {
4963                                 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4964                                 if (notifybitsp != NULL)
4965                                         *notifybitsp =
4966                                             fxdr_unsigned(uint32_t, *tl);
4967                         }
4968                         *ndip = ndi;
4969                 } else
4970                         error = EPERM;
4971         }
4972         if (nd->nd_repstat != 0)
4973                 error = nd->nd_repstat;
4974 nfsmout:
4975         if (error != 0 && ndi != NULL)
4976                 nfscl_freedevinfo(ndi);
4977         mbuf_freem(nd->nd_mrep);
4978         return (error);
4979 }
4980
4981 /*
4982  * Do the NFSv4.1 LayoutCommit.
4983  */
4984 int
4985 nfsrpc_layoutcommit(struct nfsmount *nmp, uint8_t *fh, int fhlen, int reclaim,
4986     uint64_t off, uint64_t len, uint64_t lastbyte, nfsv4stateid_t *stateidp,
4987     int layouttype, int layoutupdatecnt, uint8_t *layp, struct ucred *cred,
4988     NFSPROC_T *p, void *stuff)
4989 {
4990         uint32_t *tl;
4991         struct nfsrv_descript nfsd, *nd = &nfsd;
4992         int error, outcnt, i;
4993         uint8_t *cp;
4994
4995         nfscl_reqstart(nd, NFSPROC_LAYOUTCOMMIT, nmp, fh, fhlen, NULL, NULL);
4996         NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED + 3 * NFSX_HYPER +
4997             NFSX_STATEID);
4998         txdr_hyper(off, tl);
4999         tl += 2;
5000         txdr_hyper(len, tl);
5001         tl += 2;
5002         if (reclaim != 0)
5003                 *tl++ = newnfs_true;
5004         else
5005                 *tl++ = newnfs_false;
5006         *tl++ = txdr_unsigned(stateidp->seqid);
5007         *tl++ = stateidp->other[0];
5008         *tl++ = stateidp->other[1];
5009         *tl++ = stateidp->other[2];
5010         *tl++ = newnfs_true;
5011         if (lastbyte < off)
5012                 lastbyte = off;
5013         else if (lastbyte >= (off + len))
5014                 lastbyte = off + len - 1;
5015         txdr_hyper(lastbyte, tl);
5016         tl += 2;
5017         *tl++ = newnfs_false;
5018         *tl++ = txdr_unsigned(layouttype);
5019         *tl = txdr_unsigned(layoutupdatecnt);
5020         if (layoutupdatecnt > 0) {
5021                 KASSERT(layouttype != NFSLAYOUT_NFSV4_1_FILES,
5022                     ("Must be nil for Files Layout"));
5023                 outcnt = NFSM_RNDUP(layoutupdatecnt);
5024                 NFSM_BUILD(cp, uint8_t *, outcnt);
5025                 NFSBCOPY(layp, cp, layoutupdatecnt);
5026                 cp += layoutupdatecnt;
5027                 for (i = 0; i < (outcnt - layoutupdatecnt); i++)
5028                         *cp++ = 0x0;
5029         }
5030         nd->nd_flag |= ND_USEGSSNAME;
5031         error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
5032             NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
5033         if (error != 0)
5034                 return (error);
5035         error = nd->nd_repstat;
5036         mbuf_freem(nd->nd_mrep);
5037         return (error);
5038 }
5039
5040 /*
5041  * Do the NFSv4.1 LayoutReturn.
5042  */
5043 int
5044 nfsrpc_layoutreturn(struct nfsmount *nmp, uint8_t *fh, int fhlen, int reclaim,
5045     int layouttype, uint32_t iomode, int layoutreturn, uint64_t offset,
5046     uint64_t len, nfsv4stateid_t *stateidp, int layoutcnt, uint32_t *layp,
5047     struct ucred *cred, NFSPROC_T *p, void *stuff)
5048 {
5049         uint32_t *tl;
5050         struct nfsrv_descript nfsd, *nd = &nfsd;
5051         int error, outcnt, i;
5052         uint8_t *cp;
5053
5054         nfscl_reqstart(nd, NFSPROC_LAYOUTRETURN, nmp, fh, fhlen, NULL, NULL);
5055         NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED);
5056         if (reclaim != 0)
5057                 *tl++ = newnfs_true;
5058         else
5059                 *tl++ = newnfs_false;
5060         *tl++ = txdr_unsigned(layouttype);
5061         *tl++ = txdr_unsigned(iomode);
5062         *tl = txdr_unsigned(layoutreturn);
5063         if (layoutreturn == NFSLAYOUTRETURN_FILE) {
5064                 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_STATEID +
5065                     NFSX_UNSIGNED);
5066                 txdr_hyper(offset, tl);
5067                 tl += 2;
5068                 txdr_hyper(len, tl);
5069                 tl += 2;
5070                 NFSCL_DEBUG(4, "layoutret stseq=%d\n", (int)stateidp->seqid);
5071                 *tl++ = txdr_unsigned(stateidp->seqid);
5072                 *tl++ = stateidp->other[0];
5073                 *tl++ = stateidp->other[1];
5074                 *tl++ = stateidp->other[2];
5075                 *tl = txdr_unsigned(layoutcnt);
5076                 if (layoutcnt > 0) {
5077                         outcnt = NFSM_RNDUP(layoutcnt);
5078                         NFSM_BUILD(cp, uint8_t *, outcnt);
5079                         NFSBCOPY(layp, cp, layoutcnt);
5080                         cp += layoutcnt;
5081                         for (i = 0; i < (outcnt - layoutcnt); i++)
5082                                 *cp++ = 0x0;
5083                 }
5084         }
5085         nd->nd_flag |= ND_USEGSSNAME;
5086         error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
5087             NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
5088         if (error != 0)
5089                 return (error);
5090         if (nd->nd_repstat == 0) {
5091                 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
5092                 if (*tl != 0) {
5093                         NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID);
5094                         stateidp->seqid = fxdr_unsigned(uint32_t, *tl++);
5095                         stateidp->other[0] = *tl++;
5096                         stateidp->other[1] = *tl++;
5097                         stateidp->other[2] = *tl;
5098                 }
5099         } else
5100                 error = nd->nd_repstat;
5101 nfsmout:
5102         mbuf_freem(nd->nd_mrep);
5103         return (error);
5104 }
5105
5106 /*
5107  * Acquire a layout and devinfo, if possible. The caller must have acquired
5108  * a reference count on the nfsclclient structure before calling this.
5109  * Return the layout in lypp with a reference count on it, if successful.
5110  */
5111 static int
5112 nfsrpc_getlayout(struct nfsmount *nmp, vnode_t vp, struct nfsfh *nfhp,
5113     int iomode, uint32_t *notifybitsp, nfsv4stateid_t *stateidp, uint64_t off,
5114     struct nfscllayout **lypp, struct ucred *cred, NFSPROC_T *p)
5115 {
5116         struct nfscllayout *lyp;
5117         struct nfsclflayout *flp, *tflp;
5118         struct nfscldevinfo *dip;
5119         struct nfsclflayouthead flh;
5120         int error = 0, islocked, layoutlen, recalled, retonclose;
5121         nfsv4stateid_t stateid;
5122
5123         *lypp = NULL;
5124         /*
5125          * If lyp is returned non-NULL, there will be a refcnt (shared lock)
5126          * on it, iff flp != NULL or a lock (exclusive lock) on it iff
5127          * flp == NULL.
5128          */
5129         lyp = nfscl_getlayout(nmp->nm_clp, nfhp->nfh_fh, nfhp->nfh_len,
5130             off, &flp, &recalled);
5131         islocked = 0;
5132         if (lyp == NULL || flp == NULL) {
5133                 if (recalled != 0)
5134                         return (EIO);
5135                 LIST_INIT(&flh);
5136                 layoutlen = NFSMNT_MDSSESSION(nmp)->nfsess_maxcache -
5137                     (NFSX_STATEID + 3 * NFSX_UNSIGNED);
5138                 if (lyp == NULL) {
5139                         stateid.seqid = 0;
5140                         stateid.other[0] = stateidp->other[0];
5141                         stateid.other[1] = stateidp->other[1];
5142                         stateid.other[2] = stateidp->other[2];
5143                         error = nfsrpc_layoutget(nmp, nfhp->nfh_fh,
5144                             nfhp->nfh_len, iomode, (uint64_t)0, INT64_MAX,
5145                             (uint64_t)0, layoutlen, &stateid, &retonclose,
5146                             &flh, cred, p, NULL);
5147                 } else {
5148                         islocked = 1;
5149                         stateid.seqid = lyp->nfsly_stateid.seqid;
5150                         stateid.other[0] = lyp->nfsly_stateid.other[0];
5151                         stateid.other[1] = lyp->nfsly_stateid.other[1];
5152                         stateid.other[2] = lyp->nfsly_stateid.other[2];
5153                         error = nfsrpc_layoutget(nmp, nfhp->nfh_fh,
5154                             nfhp->nfh_len, iomode, off, INT64_MAX,
5155                             (uint64_t)0, layoutlen, &stateid, &retonclose,
5156                             &flh, cred, p, NULL);
5157                 }
5158                 if (error == 0)
5159                         LIST_FOREACH(tflp, &flh, nfsfl_list) {
5160                                 error = nfscl_adddevinfo(nmp, NULL, tflp);
5161                                 if (error != 0) {
5162                                         error = nfsrpc_getdeviceinfo(nmp,
5163                                             tflp->nfsfl_dev,
5164                                             NFSLAYOUT_NFSV4_1_FILES,
5165                                             notifybitsp, &dip, cred, p);
5166                                         if (error != 0)
5167                                                 break;
5168                                         error = nfscl_adddevinfo(nmp, dip,
5169                                             tflp);
5170                                         if (error != 0)
5171                                                 printf(
5172                                                     "getlayout: cannot add\n");
5173                                 }
5174                         }
5175                 if (error == 0) {
5176                         /*
5177                          * nfscl_layout() always returns with the nfsly_lock
5178                          * set to a refcnt (shared lock).
5179                          */
5180                         error = nfscl_layout(nmp, vp, nfhp->nfh_fh,
5181                             nfhp->nfh_len, &stateid, retonclose, &flh, &lyp,
5182                             cred, p);
5183                         if (error == 0)
5184                                 *lypp = lyp;
5185                 } else if (islocked != 0)
5186                         nfsv4_unlock(&lyp->nfsly_lock, 0);
5187         } else
5188                 *lypp = lyp;
5189         return (error);
5190 }
5191
5192 /*
5193  * Do a TCP connection plus exchange id and create session.
5194  * If successful, a "struct nfsclds" is linked into the list for the
5195  * mount point and a pointer to it is returned.
5196  */
5197 static int
5198 nfsrpc_fillsa(struct nfsmount *nmp, struct sockaddr_storage *ssp,
5199     struct nfsclds **dspp, NFSPROC_T *p)
5200 {
5201         struct sockaddr_in *msad, *sad, *ssd;
5202         struct sockaddr_in6 *msad6, *sad6, *ssd6;
5203         struct nfsclclient *clp;
5204         struct nfssockreq *nrp;
5205         struct nfsclds *dsp, *tdsp;
5206         int error;
5207         enum nfsclds_state retv;
5208         uint32_t sequenceid;
5209
5210         KASSERT(nmp->nm_sockreq.nr_cred != NULL,
5211             ("nfsrpc_fillsa: NULL nr_cred"));
5212         NFSLOCKCLSTATE();
5213         clp = nmp->nm_clp;
5214         NFSUNLOCKCLSTATE();
5215         if (clp == NULL)
5216                 return (EPERM);
5217         if (ssp->ss_family == AF_INET) {
5218                 ssd = (struct sockaddr_in *)ssp;
5219                 NFSLOCKMNT(nmp);
5220
5221                 /*
5222                  * Check to see if we already have a session for this
5223                  * address that is usable for a DS.
5224                  * Note that the MDS's address is in a different place
5225                  * than the sessions already acquired for DS's.
5226                  */
5227                 msad = (struct sockaddr_in *)nmp->nm_sockreq.nr_nam;
5228                 tdsp = TAILQ_FIRST(&nmp->nm_sess);
5229                 while (tdsp != NULL) {
5230                         if (msad != NULL && msad->sin_family == AF_INET &&
5231                             ssd->sin_addr.s_addr == msad->sin_addr.s_addr &&
5232                             ssd->sin_port == msad->sin_port &&
5233                             (tdsp->nfsclds_flags & NFSCLDS_DS) != 0) {
5234                                 *dspp = tdsp;
5235                                 NFSUNLOCKMNT(nmp);
5236                                 NFSCL_DEBUG(4, "fnd same addr\n");
5237                                 return (0);
5238                         }
5239                         tdsp = TAILQ_NEXT(tdsp, nfsclds_list);
5240                         if (tdsp != NULL && tdsp->nfsclds_sockp != NULL)
5241                                 msad = (struct sockaddr_in *)
5242                                     tdsp->nfsclds_sockp->nr_nam;
5243                         else
5244                                 msad = NULL;
5245                 }
5246                 NFSUNLOCKMNT(nmp);
5247
5248                 /* No IP address match, so look for new/trunked one. */
5249                 sad = malloc(sizeof(*sad), M_SONAME, M_WAITOK | M_ZERO);
5250                 sad->sin_len = sizeof(*sad);
5251                 sad->sin_family = AF_INET;
5252                 sad->sin_port = ssd->sin_port;
5253                 sad->sin_addr.s_addr = ssd->sin_addr.s_addr;
5254                 nrp = malloc(sizeof(*nrp), M_NFSSOCKREQ, M_WAITOK | M_ZERO);
5255                 nrp->nr_nam = (struct sockaddr *)sad;
5256         } else if (ssp->ss_family == AF_INET6) {
5257                 ssd6 = (struct sockaddr_in6 *)ssp;
5258                 NFSLOCKMNT(nmp);
5259
5260                 /*
5261                  * Check to see if we already have a session for this
5262                  * address that is usable for a DS.
5263                  * Note that the MDS's address is in a different place
5264                  * than the sessions already acquired for DS's.
5265                  */
5266                 msad6 = (struct sockaddr_in6 *)nmp->nm_sockreq.nr_nam;
5267                 tdsp = TAILQ_FIRST(&nmp->nm_sess);
5268                 while (tdsp != NULL) {
5269                         if (msad6 != NULL && msad6->sin6_family == AF_INET6 &&
5270                             IN6_ARE_ADDR_EQUAL(&ssd6->sin6_addr,
5271                             &msad6->sin6_addr) &&
5272                             ssd6->sin6_port == msad6->sin6_port &&
5273                             (tdsp->nfsclds_flags & NFSCLDS_DS) != 0) {
5274                                 *dspp = tdsp;
5275                                 NFSUNLOCKMNT(nmp);
5276                                 return (0);
5277                         }
5278                         tdsp = TAILQ_NEXT(tdsp, nfsclds_list);
5279                         if (tdsp != NULL && tdsp->nfsclds_sockp != NULL)
5280                                 msad6 = (struct sockaddr_in6 *)
5281                                     tdsp->nfsclds_sockp->nr_nam;
5282                         else
5283                                 msad6 = NULL;
5284                 }
5285                 NFSUNLOCKMNT(nmp);
5286
5287                 /* No IP address match, so look for new/trunked one. */
5288                 sad6 = malloc(sizeof(*sad6), M_SONAME, M_WAITOK | M_ZERO);
5289                 sad6->sin6_len = sizeof(*sad6);
5290                 sad6->sin6_family = AF_INET6;
5291                 sad6->sin6_port = ssd6->sin6_port;
5292                 NFSBCOPY(&ssd6->sin6_addr, &sad6->sin6_addr,
5293                     sizeof(struct in6_addr));
5294                 nrp = malloc(sizeof(*nrp), M_NFSSOCKREQ, M_WAITOK | M_ZERO);
5295                 nrp->nr_nam = (struct sockaddr *)sad6;
5296         } else
5297                 return (EPERM);
5298
5299         nrp->nr_sotype = SOCK_STREAM;
5300         mtx_init(&nrp->nr_mtx, "nfssock", NULL, MTX_DEF);
5301         nrp->nr_prog = NFS_PROG;
5302         nrp->nr_vers = NFS_VER4;
5303
5304         /*
5305          * Use the credentials that were used for the mount, which are
5306          * in nmp->nm_sockreq.nr_cred for newnfs_connect() etc.
5307          * Ref. counting the credentials with crhold() is probably not
5308          * necessary, since nm_sockreq.nr_cred won't be crfree()'d until
5309          * unmount, but I did it anyhow.
5310          */
5311         nrp->nr_cred = crhold(nmp->nm_sockreq.nr_cred);
5312         error = newnfs_connect(nmp, nrp, NULL, p, 0);
5313         NFSCL_DEBUG(3, "DS connect=%d\n", error);
5314
5315         /* Now, do the exchangeid and create session. */
5316         if (error == 0)
5317                 error = nfsrpc_exchangeid(nmp, clp, nrp, NFSV4EXCH_USEPNFSDS,
5318                     &dsp, nrp->nr_cred, p);
5319         NFSCL_DEBUG(3, "DS exchangeid=%d\n", error);
5320         if (error == 0) {
5321                 dsp->nfsclds_sockp = nrp;
5322                 NFSLOCKMNT(nmp);
5323                 retv = nfscl_getsameserver(nmp, dsp, &tdsp);
5324                 NFSCL_DEBUG(3, "getsame ret=%d\n", retv);
5325                 if (retv == NFSDSP_USETHISSESSION) {
5326                         NFSUNLOCKMNT(nmp);
5327                         /*
5328                          * If there is already a session for this server,
5329                          * use it.
5330                          */
5331                         (void)newnfs_disconnect(nrp);
5332                         nfscl_freenfsclds(dsp);
5333                         *dspp = tdsp;
5334                         return (0);
5335                 }
5336                 if (retv == NFSDSP_SEQTHISSESSION)
5337                         sequenceid = tdsp->nfsclds_sess.nfsess_sequenceid;
5338                 else
5339                         sequenceid = dsp->nfsclds_sess.nfsess_sequenceid;
5340                 NFSUNLOCKMNT(nmp);
5341                 error = nfsrpc_createsession(nmp, &dsp->nfsclds_sess,
5342                     nrp, sequenceid, 0, nrp->nr_cred, p);
5343                 NFSCL_DEBUG(3, "DS createsess=%d\n", error);
5344         } else {
5345                 NFSFREECRED(nrp->nr_cred);
5346                 NFSFREEMUTEX(&nrp->nr_mtx);
5347                 free(nrp->nr_nam, M_SONAME);
5348                 free(nrp, M_NFSSOCKREQ);
5349         }
5350         if (error == 0) {
5351                 NFSCL_DEBUG(3, "add DS session\n");
5352                 /*
5353                  * Put it at the end of the list. That way the list
5354                  * is ordered by when the entry was added. This matters
5355                  * since the one done first is the one that should be
5356                  * used for sequencid'ing any subsequent create sessions.
5357                  */
5358                 NFSLOCKMNT(nmp);
5359                 TAILQ_INSERT_TAIL(&nmp->nm_sess, dsp, nfsclds_list);
5360                 NFSUNLOCKMNT(nmp);
5361                 *dspp = dsp;
5362         } else if (dsp != NULL)
5363                 nfscl_freenfsclds(dsp);
5364         return (error);
5365 }
5366
5367 /*
5368  * Do the NFSv4.1 Reclaim Complete.
5369  */
5370 int
5371 nfsrpc_reclaimcomplete(struct nfsmount *nmp, struct ucred *cred, NFSPROC_T *p)
5372 {
5373         uint32_t *tl;
5374         struct nfsrv_descript nfsd;
5375         struct nfsrv_descript *nd = &nfsd;
5376         int error;
5377
5378         nfscl_reqstart(nd, NFSPROC_RECLAIMCOMPL, nmp, NULL, 0, NULL, NULL);
5379         NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5380         *tl = newnfs_false;
5381         nd->nd_flag |= ND_USEGSSNAME;
5382         error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
5383             NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
5384         if (error != 0)
5385                 return (error);
5386         error = nd->nd_repstat;
5387         mbuf_freem(nd->nd_mrep);
5388         return (error);
5389 }
5390
5391 /*
5392  * Initialize the slot tables for a session.
5393  */
5394 static void
5395 nfscl_initsessionslots(struct nfsclsession *sep)
5396 {
5397         int i;
5398
5399         for (i = 0; i < NFSV4_CBSLOTS; i++) {
5400                 if (sep->nfsess_cbslots[i].nfssl_reply != NULL)
5401                         m_freem(sep->nfsess_cbslots[i].nfssl_reply);
5402                 NFSBZERO(&sep->nfsess_cbslots[i], sizeof(struct nfsslot));
5403         }
5404         for (i = 0; i < 64; i++)
5405                 sep->nfsess_slotseq[i] = 0;
5406         sep->nfsess_slots = 0;
5407 }
5408
5409 /*
5410  * Called to try and do an I/O operation via an NFSv4.1 Data Server (DS).
5411  */
5412 int
5413 nfscl_doiods(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit,
5414     uint32_t rwaccess, struct ucred *cred, NFSPROC_T *p)
5415 {
5416         struct nfsnode *np = VTONFS(vp);
5417         struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
5418         struct nfscllayout *layp;
5419         struct nfscldevinfo *dip;
5420         struct nfsclflayout *rflp;
5421         nfsv4stateid_t stateid;
5422         struct ucred *newcred;
5423         uint64_t lastbyte, len, off, oresid, xfer;
5424         int eof, error, iolaymode, recalled;
5425         void *lckp;
5426
5427         if (!NFSHASPNFS(nmp) || nfscl_enablecallb == 0 || nfs_numnfscbd == 0 ||
5428             (np->n_flag & NNOLAYOUT) != 0)
5429                 return (EIO);
5430         /* Now, get a reference cnt on the clientid for this mount. */
5431         if (nfscl_getref(nmp) == 0)
5432                 return (EIO);
5433
5434         /* Find an appropriate stateid. */
5435         newcred = NFSNEWCRED(cred);
5436         error = nfscl_getstateid(vp, np->n_fhp->nfh_fh, np->n_fhp->nfh_len,
5437             rwaccess, 1, newcred, p, &stateid, &lckp);
5438         if (error != 0) {
5439                 NFSFREECRED(newcred);
5440                 nfscl_relref(nmp);
5441                 return (error);
5442         }
5443         /* Search for a layout for this file. */
5444         off = uiop->uio_offset;
5445         layp = nfscl_getlayout(nmp->nm_clp, np->n_fhp->nfh_fh,
5446             np->n_fhp->nfh_len, off, &rflp, &recalled);
5447         if (layp == NULL || rflp == NULL) {
5448                 if (recalled != 0) {
5449                         NFSFREECRED(newcred);
5450                         nfscl_relref(nmp);
5451                         return (EIO);
5452                 }
5453                 if (layp != NULL) {
5454                         nfscl_rellayout(layp, (rflp == NULL) ? 1 : 0);
5455                         layp = NULL;
5456                 }
5457                 /* Try and get a Layout, if it is supported. */
5458                 if (rwaccess == NFSV4OPEN_ACCESSWRITE ||
5459                     (np->n_flag & NWRITEOPENED) != 0)
5460                         iolaymode = NFSLAYOUTIOMODE_RW;
5461                 else
5462                         iolaymode = NFSLAYOUTIOMODE_READ;
5463                 error = nfsrpc_getlayout(nmp, vp, np->n_fhp, iolaymode,
5464                     NULL, &stateid, off, &layp, newcred, p);
5465                 if (error != 0) {
5466                         NFSLOCKNODE(np);
5467                         np->n_flag |= NNOLAYOUT;
5468                         NFSUNLOCKNODE(np);
5469                         if (lckp != NULL)
5470                                 nfscl_lockderef(lckp);
5471                         NFSFREECRED(newcred);
5472                         if (layp != NULL)
5473                                 nfscl_rellayout(layp, 0);
5474                         nfscl_relref(nmp);
5475                         return (error);
5476                 }
5477         }
5478
5479         /*
5480          * Loop around finding a layout that works for the first part of
5481          * this I/O operation, and then call the function that actually
5482          * does the RPC.
5483          */
5484         eof = 0;
5485         len = (uint64_t)uiop->uio_resid;
5486         while (len > 0 && error == 0 && eof == 0) {
5487                 off = uiop->uio_offset;
5488                 error = nfscl_findlayoutforio(layp, off, rwaccess, &rflp);
5489                 if (error == 0) {
5490                         oresid = xfer = (uint64_t)uiop->uio_resid;
5491                         if (xfer > (rflp->nfsfl_end - rflp->nfsfl_off))
5492                                 xfer = rflp->nfsfl_end - rflp->nfsfl_off;
5493                         dip = nfscl_getdevinfo(nmp->nm_clp, rflp->nfsfl_dev,
5494                             rflp->nfsfl_devp);
5495                         if (dip != NULL) {
5496                                 error = nfscl_doflayoutio(vp, uiop, iomode,
5497                                     must_commit, &eof, &stateid, rwaccess, dip,
5498                                     layp, rflp, off, xfer, newcred, p);
5499                                 nfscl_reldevinfo(dip);
5500                                 lastbyte = off + xfer - 1;
5501                                 if (error == 0) {
5502                                         NFSLOCKCLSTATE();
5503                                         if (lastbyte > layp->nfsly_lastbyte)
5504                                                 layp->nfsly_lastbyte = lastbyte;
5505                                         NFSUNLOCKCLSTATE();
5506                                 }
5507                         } else
5508                                 error = EIO;
5509                         if (error == 0)
5510                                 len -= (oresid - (uint64_t)uiop->uio_resid);
5511                 }
5512         }
5513         if (lckp != NULL)
5514                 nfscl_lockderef(lckp);
5515         NFSFREECRED(newcred);
5516         nfscl_rellayout(layp, 0);
5517         nfscl_relref(nmp);
5518         return (error);
5519 }
5520
5521 /*
5522  * Find a file layout that will handle the first bytes of the requested
5523  * range and return the information from it needed to to the I/O operation.
5524  */
5525 int
5526 nfscl_findlayoutforio(struct nfscllayout *lyp, uint64_t off, uint32_t rwaccess,
5527     struct nfsclflayout **retflpp)
5528 {
5529         struct nfsclflayout *flp, *nflp, *rflp;
5530         uint32_t rw;
5531
5532         rflp = NULL;
5533         rw = rwaccess;
5534         /* For reading, do the Read list first and then the Write list. */
5535         do {
5536                 if (rw == NFSV4OPEN_ACCESSREAD)
5537                         flp = LIST_FIRST(&lyp->nfsly_flayread);
5538                 else
5539                         flp = LIST_FIRST(&lyp->nfsly_flayrw);
5540                 while (flp != NULL) {
5541                         nflp = LIST_NEXT(flp, nfsfl_list);
5542                         if (flp->nfsfl_off > off)
5543                                 break;
5544                         if (flp->nfsfl_end > off &&
5545                             (rflp == NULL || rflp->nfsfl_end < flp->nfsfl_end))
5546                                 rflp = flp;
5547                         flp = nflp;
5548                 }
5549                 if (rw == NFSV4OPEN_ACCESSREAD)
5550                         rw = NFSV4OPEN_ACCESSWRITE;
5551                 else
5552                         rw = 0;
5553         } while (rw != 0);
5554         if (rflp != NULL) {
5555                 /* This one covers the most bytes starting at off. */
5556                 *retflpp = rflp;
5557                 return (0);
5558         }
5559         return (EIO);
5560 }
5561
5562 /*
5563  * Do I/O using an NFSv4.1 file layout.
5564  */
5565 static int
5566 nfscl_doflayoutio(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit,
5567     int *eofp, nfsv4stateid_t *stateidp, int rwflag, struct nfscldevinfo *dp,
5568     struct nfscllayout *lyp, struct nfsclflayout *flp, uint64_t off,
5569     uint64_t len, struct ucred *cred, NFSPROC_T *p)
5570 {
5571         uint64_t io_off, rel_off, stripe_unit_size, transfer, xfer;
5572         int commit_thru_mds, error = 0, stripe_index, stripe_pos;
5573         struct nfsnode *np;
5574         struct nfsfh *fhp;
5575         struct nfsclds **dspp;
5576
5577         np = VTONFS(vp);
5578         rel_off = off - flp->nfsfl_patoff;
5579         stripe_unit_size = (flp->nfsfl_util >> 6) & 0x3ffffff;
5580         stripe_pos = (rel_off / stripe_unit_size + flp->nfsfl_stripe1) %
5581             dp->nfsdi_stripecnt;
5582         transfer = stripe_unit_size - (rel_off % stripe_unit_size);
5583
5584         /* Loop around, doing I/O for each stripe unit. */
5585         while (len > 0 && error == 0) {
5586                 stripe_index = nfsfldi_stripeindex(dp, stripe_pos);
5587                 dspp = nfsfldi_addr(dp, stripe_index);
5588                 if (len > transfer)
5589                         xfer = transfer;
5590                 else
5591                         xfer = len;
5592                 if ((flp->nfsfl_util & NFSFLAYUTIL_DENSE) != 0) {
5593                         /* Dense layout. */
5594                         if (stripe_pos >= flp->nfsfl_fhcnt)
5595                                 return (EIO);
5596                         fhp = flp->nfsfl_fh[stripe_pos];
5597                         io_off = (rel_off / (stripe_unit_size *
5598                             dp->nfsdi_stripecnt)) * stripe_unit_size +
5599                             rel_off % stripe_unit_size;
5600                 } else {
5601                         /* Sparse layout. */
5602                         if (flp->nfsfl_fhcnt > 1) {
5603                                 if (stripe_index >= flp->nfsfl_fhcnt)
5604                                         return (EIO);
5605                                 fhp = flp->nfsfl_fh[stripe_index];
5606                         } else if (flp->nfsfl_fhcnt == 1)
5607                                 fhp = flp->nfsfl_fh[0];
5608                         else
5609                                 fhp = np->n_fhp;
5610                         io_off = off;
5611                 }
5612                 if ((flp->nfsfl_util & NFSFLAYUTIL_COMMIT_THRU_MDS) != 0)
5613                         commit_thru_mds = 1;
5614                 else
5615                         commit_thru_mds = 0;
5616                 if (rwflag == FREAD)
5617                         error = nfsrpc_readds(vp, uiop, stateidp, eofp, *dspp,
5618                             io_off, xfer, fhp, cred, p);
5619                 else {
5620                         error = nfsrpc_writeds(vp, uiop, iomode, must_commit,
5621                             stateidp, *dspp, io_off, xfer, fhp, commit_thru_mds,
5622                             cred, p);
5623                         if (error == 0) {
5624                                 NFSLOCKCLSTATE();
5625                                 lyp->nfsly_flags |= NFSLY_WRITTEN;
5626                                 NFSUNLOCKCLSTATE();
5627                         }
5628                 }
5629                 if (error == 0) {
5630                         transfer = stripe_unit_size;
5631                         stripe_pos = (stripe_pos + 1) % dp->nfsdi_stripecnt;
5632                         len -= xfer;
5633                         off += xfer;
5634                 }
5635         }
5636         return (error);
5637 }
5638
5639 /*
5640  * The actual read RPC done to a DS.
5641  */
5642 static int
5643 nfsrpc_readds(vnode_t vp, struct uio *uiop, nfsv4stateid_t *stateidp, int *eofp,
5644     struct nfsclds *dsp, uint64_t io_off, int len, struct nfsfh *fhp,
5645     struct ucred *cred, NFSPROC_T *p)
5646 {
5647         uint32_t *tl;
5648         int error, retlen;
5649         struct nfsrv_descript nfsd;
5650         struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
5651         struct nfsrv_descript *nd = &nfsd;
5652         struct nfssockreq *nrp;
5653
5654         nd->nd_mrep = NULL;
5655         nfscl_reqstart(nd, NFSPROC_READDS, nmp, fhp->nfh_fh, fhp->nfh_len,
5656             NULL, &dsp->nfsclds_sess);
5657         nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSEQIDZERO);
5658         NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED * 3);
5659         txdr_hyper(io_off, tl);
5660         *(tl + 2) = txdr_unsigned(len);
5661         nrp = dsp->nfsclds_sockp;
5662         if (nrp == NULL)
5663                 /* If NULL, use the MDS socket. */
5664                 nrp = &nmp->nm_sockreq;
5665         error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred,
5666             NFS_PROG, NFS_VER4, NULL, 1, NULL, &dsp->nfsclds_sess);
5667         if (error != 0)
5668                 return (error);
5669         if (nd->nd_repstat != 0) {
5670                 error = nd->nd_repstat;
5671                 goto nfsmout;
5672         }
5673         NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
5674         *eofp = fxdr_unsigned(int, *tl);
5675         NFSM_STRSIZ(retlen, len);
5676         error = nfsm_mbufuio(nd, uiop, retlen);
5677 nfsmout:
5678         if (nd->nd_mrep != NULL)
5679                 mbuf_freem(nd->nd_mrep);
5680         return (error);
5681 }
5682
5683 /*
5684  * The actual write RPC done to a DS.
5685  */
5686 static int
5687 nfsrpc_writeds(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit,
5688     nfsv4stateid_t *stateidp, struct nfsclds *dsp, uint64_t io_off, int len,
5689     struct nfsfh *fhp, int commit_thru_mds, struct ucred *cred, NFSPROC_T *p)
5690 {
5691         uint32_t *tl;
5692         struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
5693         int error, rlen, commit, committed = NFSWRITE_FILESYNC;
5694         int32_t backup;
5695         struct nfsrv_descript nfsd;
5696         struct nfsrv_descript *nd = &nfsd;
5697         struct nfssockreq *nrp;
5698
5699         KASSERT(uiop->uio_iovcnt == 1, ("nfs: writerpc iovcnt > 1"));
5700         nd->nd_mrep = NULL;
5701         nfscl_reqstart(nd, NFSPROC_WRITEDS, nmp, fhp->nfh_fh, fhp->nfh_len,
5702             NULL, &dsp->nfsclds_sess);
5703         nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSEQIDZERO);
5704         NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED);
5705         txdr_hyper(io_off, tl);
5706         tl += 2;
5707         *tl++ = txdr_unsigned(*iomode);
5708         *tl = txdr_unsigned(len);
5709         nfsm_uiombuf(nd, uiop, len);
5710         nrp = dsp->nfsclds_sockp;
5711         if (nrp == NULL)
5712                 /* If NULL, use the MDS socket. */
5713                 nrp = &nmp->nm_sockreq;
5714         error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred,
5715             NFS_PROG, NFS_VER4, NULL, 1, NULL, &dsp->nfsclds_sess);
5716         if (error != 0)
5717                 return (error);
5718         if (nd->nd_repstat != 0) {
5719                 /*
5720                  * In case the rpc gets retried, roll
5721                  * the uio fileds changed by nfsm_uiombuf()
5722                  * back.
5723                  */
5724                 uiop->uio_offset -= len;
5725                 uio_uio_resid_add(uiop, len);
5726                 uio_iov_base_add(uiop, -len);
5727                 uio_iov_len_add(uiop, len);
5728                 error = nd->nd_repstat;
5729         } else {
5730                 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + NFSX_VERF);
5731                 rlen = fxdr_unsigned(int, *tl++);
5732                 if (rlen == 0) {
5733                         error = NFSERR_IO;
5734                         goto nfsmout;
5735                 } else if (rlen < len) {
5736                         backup = len - rlen;
5737                         uio_iov_base_add(uiop, -(backup));
5738                         uio_iov_len_add(uiop, backup);
5739                         uiop->uio_offset -= backup;
5740                         uio_uio_resid_add(uiop, backup);
5741                         len = rlen;
5742                 }
5743                 commit = fxdr_unsigned(int, *tl++);
5744
5745                 /*
5746                  * Return the lowest committment level
5747                  * obtained by any of the RPCs.
5748                  */
5749                 if (committed == NFSWRITE_FILESYNC)
5750                         committed = commit;
5751                 else if (committed == NFSWRITE_DATASYNC &&
5752                     commit == NFSWRITE_UNSTABLE)
5753                         committed = commit;
5754                 if (commit_thru_mds != 0) {
5755                         NFSLOCKMNT(nmp);
5756                         if (!NFSHASWRITEVERF(nmp)) {
5757                                 NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF);
5758                                 NFSSETWRITEVERF(nmp);
5759                         } else if (NFSBCMP(tl, nmp->nm_verf, NFSX_VERF)) {
5760                                 *must_commit = 1;
5761                                 NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF);
5762                         }
5763                         NFSUNLOCKMNT(nmp);
5764                 } else {
5765                         NFSLOCKDS(dsp);
5766                         if ((dsp->nfsclds_flags & NFSCLDS_HASWRITEVERF) == 0) {
5767                                 NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF);
5768                                 dsp->nfsclds_flags |= NFSCLDS_HASWRITEVERF;
5769                         } else if (NFSBCMP(tl, dsp->nfsclds_verf, NFSX_VERF)) {
5770                                 *must_commit = 1;
5771                                 NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF);
5772                         }
5773                         NFSUNLOCKDS(dsp);
5774                 }
5775         }
5776 nfsmout:
5777         if (nd->nd_mrep != NULL)
5778                 mbuf_freem(nd->nd_mrep);
5779         *iomode = committed;
5780         if (nd->nd_repstat != 0 && error == 0)
5781                 error = nd->nd_repstat;
5782         return (error);
5783 }
5784
5785 /*
5786  * Free up the nfsclds structure.
5787  */
5788 void
5789 nfscl_freenfsclds(struct nfsclds *dsp)
5790 {
5791         int i;
5792
5793         if (dsp == NULL)
5794                 return;
5795         if (dsp->nfsclds_sockp != NULL) {
5796                 NFSFREECRED(dsp->nfsclds_sockp->nr_cred);
5797                 NFSFREEMUTEX(&dsp->nfsclds_sockp->nr_mtx);
5798                 free(dsp->nfsclds_sockp->nr_nam, M_SONAME);
5799                 free(dsp->nfsclds_sockp, M_NFSSOCKREQ);
5800         }
5801         NFSFREEMUTEX(&dsp->nfsclds_mtx);
5802         NFSFREEMUTEX(&dsp->nfsclds_sess.nfsess_mtx);
5803         for (i = 0; i < NFSV4_CBSLOTS; i++) {
5804                 if (dsp->nfsclds_sess.nfsess_cbslots[i].nfssl_reply != NULL)
5805                         m_freem(
5806                             dsp->nfsclds_sess.nfsess_cbslots[i].nfssl_reply);
5807         }
5808         free(dsp, M_NFSCLDS);
5809 }
5810
5811 static enum nfsclds_state
5812 nfscl_getsameserver(struct nfsmount *nmp, struct nfsclds *newdsp,
5813     struct nfsclds **retdspp)
5814 {
5815         struct nfsclds *dsp, *cur_dsp;
5816
5817         /*
5818          * Search the list of nfsclds structures for one with the same
5819          * server.
5820          */
5821         cur_dsp = NULL;
5822         TAILQ_FOREACH(dsp, &nmp->nm_sess, nfsclds_list) {
5823                 if (dsp->nfsclds_servownlen == newdsp->nfsclds_servownlen &&
5824                     dsp->nfsclds_servownlen != 0 &&
5825                     !NFSBCMP(dsp->nfsclds_serverown, newdsp->nfsclds_serverown,
5826                     dsp->nfsclds_servownlen)) {
5827                         NFSCL_DEBUG(4, "fnd same fdsp=%p dsp=%p flg=0x%x\n",
5828                             TAILQ_FIRST(&nmp->nm_sess), dsp,
5829                             dsp->nfsclds_flags);
5830                         /* Server major id matches. */
5831                         if ((dsp->nfsclds_flags & NFSCLDS_DS) != 0) {
5832                                 *retdspp = dsp;
5833                                 return (NFSDSP_USETHISSESSION);
5834                         }
5835
5836                         /*
5837                          * Note the first match, so it can be used for
5838                          * sequence'ing new sessions.
5839                          */
5840                         if (cur_dsp == NULL)
5841                                 cur_dsp = dsp;
5842                 }
5843         }
5844         if (cur_dsp != NULL) {
5845                 *retdspp = cur_dsp;
5846                 return (NFSDSP_SEQTHISSESSION);
5847         }
5848         return (NFSDSP_NOTFOUND);
5849 }
5850
5851 #ifdef notyet
5852 /*
5853  * NFS commit rpc to a DS.
5854  */
5855 static int
5856 nfsrpc_commitds(vnode_t vp, uint64_t offset, int cnt, struct nfsclds *dsp,
5857     struct nfsfh *fhp, struct ucred *cred, NFSPROC_T *p, void *stuff)
5858 {
5859         uint32_t *tl;
5860         struct nfsrv_descript nfsd, *nd = &nfsd;
5861         struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
5862         struct nfssockreq *nrp;
5863         int error;
5864         
5865         nfscl_reqstart(nd, NFSPROC_COMMITDS, nmp, fhp->nfh_fh, fhp->nfh_len,
5866             NULL, &dsp->nfsclds_sess);
5867         NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED);
5868         txdr_hyper(offset, tl);
5869         tl += 2;
5870         *tl = txdr_unsigned(cnt);
5871         nrp = dsp->nfsclds_sockp;
5872         if (nrp == NULL)
5873                 /* If NULL, use the MDS socket. */
5874                 nrp = &nmp->nm_sockreq;
5875         error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred,
5876             NFS_PROG, NFS_VER4, NULL, 1, NULL, &dsp->nfsclds_sess);
5877         if (error)
5878                 return (error);
5879         if (nd->nd_repstat == 0) {
5880                 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
5881                 NFSLOCKDS(dsp);
5882                 if (NFSBCMP(tl, dsp->nfsclds_verf, NFSX_VERF)) {
5883                         NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF);
5884                         error = NFSERR_STALEWRITEVERF;
5885                 }
5886                 NFSUNLOCKDS(dsp);
5887         }
5888 nfsmout:
5889         if (error == 0 && nd->nd_repstat != 0)
5890                 error = nd->nd_repstat;
5891         mbuf_freem(nd->nd_mrep);
5892         return (error);
5893 }
5894 #endif
5895