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