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