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