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