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