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