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