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