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