1 /*	$NetBSD: nfs_clcomsubs.c,v 1.1.1.1 2013/09/30 07:18:58 dholland Exp $	*/
2 /*-
3  * Copyright (c) 1989, 1993
4  *	The Regents of the University of California.  All rights reserved.
5  *
6  * This code is derived from software contributed to Berkeley by
7  * Rick Macklem at The University of Guelph.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  */
34 
35 #include <sys/cdefs.h>
36 /* __FBSDID("FreeBSD: head/sys/fs/nfsclient/nfs_clcomsubs.c 244042 2012-12-08 22:52:39Z rmacklem "); */
37 __RCSID("$NetBSD: nfs_clcomsubs.c,v 1.1.1.1 2013/09/30 07:18:58 dholland Exp $");
38 
39 /*
40  * These functions support the macros and help fiddle mbuf chains for
41  * the nfs op functions. They do things like create the rpc header and
42  * copy data between mbuf chains and uio lists.
43  */
44 #ifndef APPLEKEXT
45 #include <fs/nfs/nfsport.h>
46 
47 extern struct nfsstats newnfsstats;
48 extern struct nfsv4_opflag nfsv4_opflag[NFSV41_NOPS];
49 extern int ncl_mbuf_mlen;
50 extern enum vtype newnv2tov_type[8];
51 extern enum vtype nv34tov_type[8];
52 extern int	nfs_bigreply[NFSV41_NPROCS];
53 NFSCLSTATEMUTEX;
54 #endif	/* !APPLEKEXT */
55 
56 static nfsuint64 nfs_nullcookie = {{ 0, 0 }};
57 static struct {
58 	int	op;
59 	int	opcnt;
60 	const u_char *tag;
61 	int	taglen;
62 } nfsv4_opmap[NFSV41_NPROCS] = {
63 	{ 0, 1, "Null", 4 },
64 	{ NFSV4OP_GETATTR, 1, "Getattr", 7, },
65 	{ NFSV4OP_SETATTR, 2, "Setattr", 7, },
66 	{ NFSV4OP_LOOKUP, 3, "Lookup", 6, },
67 	{ NFSV4OP_ACCESS, 2, "Access", 6, },
68 	{ NFSV4OP_READLINK, 2, "Readlink", 8, },
69 	{ NFSV4OP_READ, 1, "Read", 4, },
70 	{ NFSV4OP_WRITE, 2, "Write", 5, },
71 	{ NFSV4OP_OPEN, 3, "Open", 4, },
72 	{ NFSV4OP_CREATE, 3, "Create", 6, },
73 	{ NFSV4OP_CREATE, 1, "Create", 6, },
74 	{ NFSV4OP_CREATE, 3, "Create", 6, },
75 	{ NFSV4OP_REMOVE, 1, "Remove", 6, },
76 	{ NFSV4OP_REMOVE, 1, "Remove", 6, },
77 	{ NFSV4OP_SAVEFH, 5, "Rename", 6, },
78 	{ NFSV4OP_SAVEFH, 4, "Link", 4, },
79 	{ NFSV4OP_READDIR, 2, "Readdir", 7, },
80 	{ NFSV4OP_READDIR, 2, "Readdir", 7, },
81 	{ NFSV4OP_GETATTR, 1, "Getattr", 7, },
82 	{ NFSV4OP_GETATTR, 1, "Getattr", 7, },
83 	{ NFSV4OP_GETATTR, 1, "Getattr", 7, },
84 	{ NFSV4OP_COMMIT, 2, "Commit", 6, },
85 	{ NFSV4OP_LOOKUPP, 3, "Lookupp", 7, },
86 	{ NFSV4OP_SETCLIENTID, 1, "SetClientID", 11, },
87 	{ NFSV4OP_SETCLIENTIDCFRM, 1, "SetClientIDConfirm", 18, },
88 	{ NFSV4OP_LOCK, 1, "Lock", 4, },
89 	{ NFSV4OP_LOCKU, 1, "LockU", 5, },
90 	{ NFSV4OP_OPEN, 2, "Open", 4, },
91 	{ NFSV4OP_CLOSE, 1, "Close", 5, },
92 	{ NFSV4OP_OPENCONFIRM, 1, "Openconfirm", 11, },
93 	{ NFSV4OP_LOCKT, 1, "LockT", 5, },
94 	{ NFSV4OP_OPENDOWNGRADE, 1, "Opendowngrade", 13, },
95 	{ NFSV4OP_RENEW, 1, "Renew", 5, },
96 	{ NFSV4OP_PUTROOTFH, 1, "Dirpath", 7, },
97 	{ NFSV4OP_RELEASELCKOWN, 1, "Rellckown", 9, },
98 	{ NFSV4OP_DELEGRETURN, 1, "Delegret", 8, },
99 	{ NFSV4OP_DELEGRETURN, 3, "DelegRemove", 11, },
100 	{ NFSV4OP_DELEGRETURN, 7, "DelegRename1", 12, },
101 	{ NFSV4OP_DELEGRETURN, 9, "DelegRename2", 12, },
102 	{ NFSV4OP_GETATTR, 1, "Getacl", 6, },
103 	{ NFSV4OP_SETATTR, 1, "Setacl", 6, },
104 	{ NFSV4OP_EXCHANGEID, 1, "ExchangeID", 10, },
105 	{ NFSV4OP_CREATESESSION, 1, "CreateSession", 13, },
106 	{ NFSV4OP_DESTROYSESSION, 1, "DestroySession", 14, },
107 	{ NFSV4OP_DESTROYCLIENTID, 1, "DestroyClient", 13, },
108 	{ NFSV4OP_FREESTATEID, 1, "FreeStateID", 11, },
109 	{ NFSV4OP_LAYOUTGET, 1, "LayoutGet", 9, },
110 	{ NFSV4OP_GETDEVINFO, 1, "GetDeviceInfo", 13, },
111 	{ NFSV4OP_LAYOUTCOMMIT, 1, "LayoutCommit", 12, },
112 	{ NFSV4OP_LAYOUTRETURN, 1, "LayoutReturn", 12, },
113 	{ NFSV4OP_RECLAIMCOMPL, 1, "ReclaimComplete", 15, },
114 	{ NFSV4OP_WRITE, 1, "WriteDS", 7, },
115 	{ NFSV4OP_READ, 1, "ReadDS", 6, },
116 	{ NFSV4OP_COMMIT, 1, "CommitDS", 8, },
117 };
118 
119 /*
120  * NFS RPCS that have large request message size.
121  */
122 static int nfs_bigrequest[NFSV41_NPROCS] = {
123 	0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
124 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
125 	0, 0, 0, 0, 0, 0, 1, 0, 0
126 };
127 
128 /*
129  * Start building a request. Mostly just put the first file handle in
130  * place.
131  */
132 APPLESTATIC void
nfscl_reqstart(struct nfsrv_descript * nd,int procnum,struct nfsmount * nmp,u_int8_t * nfhp,int fhlen,u_int32_t ** opcntpp,struct nfsclsession * sep)133 nfscl_reqstart(struct nfsrv_descript *nd, int procnum, struct nfsmount *nmp,
134     u_int8_t *nfhp, int fhlen, u_int32_t **opcntpp, struct nfsclsession *sep)
135 {
136 	struct mbuf *mb;
137 	u_int32_t *tl;
138 	int opcnt;
139 	nfsattrbit_t attrbits;
140 
141 	/*
142 	 * First, fill in some of the fields of nd.
143 	 */
144 	nd->nd_slotseq = NULL;
145 	if (NFSHASNFSV4(nmp)) {
146 		nd->nd_flag = ND_NFSV4 | ND_NFSCL;
147 		if (NFSHASNFSV4N(nmp))
148 			nd->nd_flag |= ND_NFSV41;
149 	} else if (NFSHASNFSV3(nmp))
150 		nd->nd_flag = ND_NFSV3 | ND_NFSCL;
151 	else
152 		nd->nd_flag = ND_NFSV2 | ND_NFSCL;
153 	nd->nd_procnum = procnum;
154 	nd->nd_repstat = 0;
155 
156 	/*
157 	 * Get the first mbuf for the request.
158 	 */
159 	if (nfs_bigrequest[procnum])
160 		NFSMCLGET(mb, M_WAITOK);
161 	else
162 		NFSMGET(mb);
163 	mbuf_setlen(mb, 0);
164 	nd->nd_mreq = nd->nd_mb = mb;
165 	nd->nd_bpos = NFSMTOD(mb, caddr_t);
166 
167 	/*
168 	 * And fill the first file handle into the request.
169 	 */
170 	if (nd->nd_flag & ND_NFSV4) {
171 		opcnt = nfsv4_opmap[procnum].opcnt +
172 		    nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh;
173 		if ((nd->nd_flag & ND_NFSV41) != 0) {
174 			opcnt += nfsv4_opflag[nfsv4_opmap[procnum].op].needsseq;
175 			if (procnum == NFSPROC_RENEW)
176 				/*
177 				 * For the special case of Renew, just do a
178 				 * Sequence Op.
179 				 */
180 				opcnt = 1;
181 			else if (procnum == NFSPROC_WRITEDS ||
182 			    procnum == NFSPROC_COMMITDS)
183 				/*
184 				 * For the special case of a Writeor Commit to
185 				 * a DS, the opcnt == 3, for Sequence, PutFH,
186 				 * Write/Commit.
187 				 */
188 				opcnt = 3;
189 		}
190 		/*
191 		 * What should the tag really be?
192 		 */
193 		(void) nfsm_strtom(nd, nfsv4_opmap[procnum].tag,
194 			nfsv4_opmap[procnum].taglen);
195 		NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
196 		if ((nd->nd_flag & ND_NFSV41) != 0)
197 			*tl++ = txdr_unsigned(NFSV41_MINORVERSION);
198 		else
199 			*tl++ = txdr_unsigned(NFSV4_MINORVERSION);
200 		if (opcntpp != NULL)
201 			*opcntpp = tl;
202 		*tl = txdr_unsigned(opcnt);
203 		if ((nd->nd_flag & ND_NFSV41) != 0 &&
204 		    nfsv4_opflag[nfsv4_opmap[procnum].op].needsseq > 0) {
205 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
206 			*tl = txdr_unsigned(NFSV4OP_SEQUENCE);
207 			if (sep == NULL)
208 				nfsv4_setsequence(nd, NFSMNT_MDSSESSION(nmp),
209 				    nfs_bigreply[procnum]);
210 			else
211 				nfsv4_setsequence(nd, sep,
212 				    nfs_bigreply[procnum]);
213 		}
214 		if (nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh > 0) {
215 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
216 			*tl = txdr_unsigned(NFSV4OP_PUTFH);
217 			(void) nfsm_fhtom(nd, nfhp, fhlen, 0);
218 			if (nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh
219 			    == 2 && procnum != NFSPROC_WRITEDS &&
220 			    procnum != NFSPROC_COMMITDS) {
221 				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
222 				*tl = txdr_unsigned(NFSV4OP_GETATTR);
223 				NFSWCCATTR_ATTRBIT(&attrbits);
224 				(void) nfsrv_putattrbit(nd, &attrbits);
225 				nd->nd_flag |= ND_V4WCCATTR;
226 			}
227 		}
228 		if (procnum != NFSPROC_RENEW ||
229 		    (nd->nd_flag & ND_NFSV41) == 0) {
230 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
231 			*tl = txdr_unsigned(nfsv4_opmap[procnum].op);
232 		}
233 	} else {
234 		(void) nfsm_fhtom(nd, nfhp, fhlen, 0);
235 	}
236 	if (procnum < NFSV4_NPROCS)
237 		NFSINCRGLOBAL(newnfsstats.rpccnt[procnum]);
238 }
239 
240 #ifndef APPLE
241 /*
242  * copies a uio scatter/gather list to an mbuf chain.
243  * NOTE: can ony handle iovcnt == 1
244  */
245 APPLESTATIC void
nfsm_uiombuf(struct nfsrv_descript * nd,struct uio * uiop,int siz)246 nfsm_uiombuf(struct nfsrv_descript *nd, struct uio *uiop, int siz)
247 {
248 	char *uiocp;
249 	struct mbuf *mp, *mp2;
250 	int xfer, left, mlen;
251 	int uiosiz, clflg, rem;
252 	char *cp, *tcp;
253 
254 	KASSERT(uiop->uio_iovcnt == 1, ("nfsm_uiotombuf: iovcnt != 1"));
255 
256 	if (siz > ncl_mbuf_mlen)	/* or should it >= MCLBYTES ?? */
257 		clflg = 1;
258 	else
259 		clflg = 0;
260 	rem = NFSM_RNDUP(siz) - siz;
261 	mp = mp2 = nd->nd_mb;
262 	while (siz > 0) {
263 		left = uiop->uio_iov->iov_len;
264 		uiocp = uiop->uio_iov->iov_base;
265 		if (left > siz)
266 			left = siz;
267 		uiosiz = left;
268 		while (left > 0) {
269 			mlen = M_TRAILINGSPACE(mp);
270 			if (mlen == 0) {
271 				if (clflg)
272 					NFSMCLGET(mp, M_WAITOK);
273 				else
274 					NFSMGET(mp);
275 				mbuf_setlen(mp, 0);
276 				mbuf_setnext(mp2, mp);
277 				mp2 = mp;
278 				mlen = M_TRAILINGSPACE(mp);
279 			}
280 			xfer = (left > mlen) ? mlen : left;
281 #ifdef notdef
282 			/* Not Yet.. */
283 			if (uiop->uio_iov->iov_op != NULL)
284 				(*(uiop->uio_iov->iov_op))
285 				(uiocp, NFSMTOD(mp, caddr_t) + mbuf_len(mp),
286 				    xfer);
287 			else
288 #endif
289 			if (uiop->uio_segflg == UIO_SYSSPACE)
290 			    NFSBCOPY(uiocp, NFSMTOD(mp, caddr_t) + mbuf_len(mp),
291 				xfer);
292 			else
293 			    copyin(CAST_USER_ADDR_T(uiocp), NFSMTOD(mp, caddr_t)
294 				+ mbuf_len(mp), xfer);
295 			mbuf_setlen(mp, mbuf_len(mp) + xfer);
296 			left -= xfer;
297 			uiocp += xfer;
298 			uiop->uio_offset += xfer;
299 			uiop->uio_resid -= xfer;
300 		}
301 		tcp = (char *)uiop->uio_iov->iov_base;
302 		tcp += uiosiz;
303 		uiop->uio_iov->iov_base = (void *)tcp;
304 		uiop->uio_iov->iov_len -= uiosiz;
305 		siz -= uiosiz;
306 	}
307 	if (rem > 0) {
308 		if (rem > M_TRAILINGSPACE(mp)) {
309 			NFSMGET(mp);
310 			mbuf_setlen(mp, 0);
311 			mbuf_setnext(mp2, mp);
312 		}
313 		cp = NFSMTOD(mp, caddr_t) + mbuf_len(mp);
314 		for (left = 0; left < rem; left++)
315 			*cp++ = '\0';
316 		mbuf_setlen(mp, mbuf_len(mp) + rem);
317 		nd->nd_bpos = cp;
318 	} else
319 		nd->nd_bpos = NFSMTOD(mp, caddr_t) + mbuf_len(mp);
320 	nd->nd_mb = mp;
321 }
322 #endif	/* !APPLE */
323 
324 /*
325  * Load vnode attributes from the xdr file attributes.
326  * Returns EBADRPC if they can't be parsed, 0 otherwise.
327  */
328 APPLESTATIC int
nfsm_loadattr(struct nfsrv_descript * nd,struct nfsvattr * nap)329 nfsm_loadattr(struct nfsrv_descript *nd, struct nfsvattr *nap)
330 {
331 	struct nfs_fattr *fp;
332 	int error = 0;
333 
334 	if (nd->nd_flag & ND_NFSV4) {
335 		error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0, NULL,
336 		    NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL);
337 	} else if (nd->nd_flag & ND_NFSV3) {
338 		NFSM_DISSECT(fp, struct nfs_fattr *, NFSX_V3FATTR);
339 		nap->na_type = nfsv34tov_type(fp->fa_type);
340 		nap->na_mode = fxdr_unsigned(u_short, fp->fa_mode);
341 		nap->na_rdev = makedev(fxdr_unsigned(u_char, fp->fa3_rdev.specdata1),
342 			fxdr_unsigned(u_char, fp->fa3_rdev.specdata2));
343 		nap->na_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
344 		nap->na_uid = fxdr_unsigned(uid_t, fp->fa_uid);
345 		nap->na_gid = fxdr_unsigned(gid_t, fp->fa_gid);
346 		nap->na_size = fxdr_hyper(&fp->fa3_size);
347 		nap->na_blocksize = NFS_FABLKSIZE;
348 		nap->na_bytes = fxdr_hyper(&fp->fa3_used);
349 		nap->na_fileid = fxdr_hyper(&fp->fa3_fileid);
350 		fxdr_nfsv3time(&fp->fa3_atime, &nap->na_atime);
351 		fxdr_nfsv3time(&fp->fa3_ctime, &nap->na_ctime);
352 		fxdr_nfsv3time(&fp->fa3_mtime, &nap->na_mtime);
353 		nap->na_flags = 0;
354 		nap->na_filerev = 0;
355 	} else {
356 		NFSM_DISSECT(fp, struct nfs_fattr *, NFSX_V2FATTR);
357 		nap->na_type = nfsv2tov_type(fp->fa_type);
358 		nap->na_mode = fxdr_unsigned(u_short, fp->fa_mode);
359 		if (nap->na_type == VNON || nap->na_type == VREG)
360 			nap->na_type = IFTOVT(nap->na_mode);
361 		nap->na_rdev = fxdr_unsigned(dev_t, fp->fa2_rdev);
362 
363 		/*
364 		 * Really ugly NFSv2 kludge.
365 		 */
366 		if (nap->na_type == VCHR && nap->na_rdev == ((dev_t)-1))
367 			nap->na_type = VFIFO;
368 		nap->na_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
369 		nap->na_uid = fxdr_unsigned(uid_t, fp->fa_uid);
370 		nap->na_gid = fxdr_unsigned(gid_t, fp->fa_gid);
371 		nap->na_size = fxdr_unsigned(u_int32_t, fp->fa2_size);
372 		nap->na_blocksize = fxdr_unsigned(int32_t, fp->fa2_blocksize);
373 		nap->na_bytes =
374 		    (u_quad_t)fxdr_unsigned(int32_t, fp->fa2_blocks) *
375 		    NFS_FABLKSIZE;
376 		nap->na_fileid = fxdr_unsigned(uint64_t, fp->fa2_fileid);
377 		fxdr_nfsv2time(&fp->fa2_atime, &nap->na_atime);
378 		fxdr_nfsv2time(&fp->fa2_mtime, &nap->na_mtime);
379 		nap->na_flags = 0;
380 		nap->na_ctime.tv_sec = fxdr_unsigned(u_int32_t,
381 		    fp->fa2_ctime.nfsv2_sec);
382 		nap->na_ctime.tv_nsec = 0;
383 		nap->na_gen = fxdr_unsigned(u_int32_t,fp->fa2_ctime.nfsv2_usec);
384 		nap->na_filerev = 0;
385 	}
386 nfsmout:
387 	return (error);
388 }
389 
390 /*
391  * This function finds the directory cookie that corresponds to the
392  * logical byte offset given.
393  */
394 APPLESTATIC nfsuint64 *
nfscl_getcookie(struct nfsnode * np,off_t off,int add)395 nfscl_getcookie(struct nfsnode *np, off_t off, int add)
396 {
397 	struct nfsdmap *dp, *dp2;
398 	int pos;
399 
400 	pos = off / NFS_DIRBLKSIZ;
401 	if (pos == 0) {
402 		KASSERT(!add, ("nfs getcookie add at 0"));
403 		return (&nfs_nullcookie);
404 	}
405 	pos--;
406 	dp = LIST_FIRST(&np->n_cookies);
407 	if (!dp) {
408 		if (add) {
409 			MALLOC(dp, struct nfsdmap *, sizeof (struct nfsdmap),
410 				M_NFSDIROFF, M_WAITOK);
411 			dp->ndm_eocookie = 0;
412 			LIST_INSERT_HEAD(&np->n_cookies, dp, ndm_list);
413 		} else
414 			return (NULL);
415 	}
416 	while (pos >= NFSNUMCOOKIES) {
417 		pos -= NFSNUMCOOKIES;
418 		if (LIST_NEXT(dp, ndm_list) != NULL) {
419 			if (!add && dp->ndm_eocookie < NFSNUMCOOKIES &&
420 				pos >= dp->ndm_eocookie)
421 				return (NULL);
422 			dp = LIST_NEXT(dp, ndm_list);
423 		} else if (add) {
424 			MALLOC(dp2, struct nfsdmap *, sizeof (struct nfsdmap),
425 				M_NFSDIROFF, M_WAITOK);
426 			dp2->ndm_eocookie = 0;
427 			LIST_INSERT_AFTER(dp, dp2, ndm_list);
428 			dp = dp2;
429 		} else
430 			return (NULL);
431 	}
432 	if (pos >= dp->ndm_eocookie) {
433 		if (add)
434 			dp->ndm_eocookie = pos + 1;
435 		else
436 			return (NULL);
437 	}
438 	return (&dp->ndm_cookies[pos]);
439 }
440 
441 /*
442  * Gets a file handle out of an nfs reply sent to the client and returns
443  * the file handle and the file's attributes.
444  * For V4, it assumes that Getfh and Getattr Op's results are here.
445  */
446 APPLESTATIC int
nfscl_mtofh(struct nfsrv_descript * nd,struct nfsfh ** nfhpp,struct nfsvattr * nap,int * attrflagp)447 nfscl_mtofh(struct nfsrv_descript *nd, struct nfsfh **nfhpp,
448     struct nfsvattr *nap, int *attrflagp)
449 {
450 	u_int32_t *tl;
451 	int error = 0, flag = 1;
452 
453 	*nfhpp = NULL;
454 	*attrflagp = 0;
455 	/*
456 	 * First get the file handle and vnode.
457 	 */
458 	if (nd->nd_flag & ND_NFSV3) {
459 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
460 		flag = fxdr_unsigned(int, *tl);
461 	} else if (nd->nd_flag & ND_NFSV4) {
462 		NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
463 	}
464 	if (flag) {
465 		error = nfsm_getfh(nd, nfhpp);
466 		if (error)
467 			return (error);
468 	}
469 
470 	/*
471 	 * Now, get the attributes.
472 	 */
473 	if (nd->nd_flag & ND_NFSV4) {
474 		NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
475 	} else if (nd->nd_flag & ND_NFSV3) {
476 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
477 		if (flag) {
478 			flag = fxdr_unsigned(int, *tl);
479 		} else if (fxdr_unsigned(int, *tl)) {
480 			error = nfsm_advance(nd, NFSX_V3FATTR, -1);
481 			if (error)
482 				return (error);
483 		}
484 	}
485 	if (flag) {
486 		error = nfsm_loadattr(nd, nap);
487 		if (!error)
488 			*attrflagp = 1;
489 	}
490 nfsmout:
491 	return (error);
492 }
493 
494 /*
495  * Put a state Id in the mbuf list.
496  */
497 APPLESTATIC void
nfsm_stateidtom(struct nfsrv_descript * nd,nfsv4stateid_t * stateidp,int flag)498 nfsm_stateidtom(struct nfsrv_descript *nd, nfsv4stateid_t *stateidp, int flag)
499 {
500 	nfsv4stateid_t *st;
501 
502 	NFSM_BUILD(st, nfsv4stateid_t *, NFSX_STATEID);
503 	if (flag == NFSSTATEID_PUTALLZERO) {
504 		st->seqid = 0;
505 		st->other[0] = 0;
506 		st->other[1] = 0;
507 		st->other[2] = 0;
508 	} else if (flag == NFSSTATEID_PUTALLONE) {
509 		st->seqid = 0xffffffff;
510 		st->other[0] = 0xffffffff;
511 		st->other[1] = 0xffffffff;
512 		st->other[2] = 0xffffffff;
513 	} else if (flag == NFSSTATEID_PUTSEQIDZERO) {
514 		st->seqid = 0;
515 		st->other[0] = stateidp->other[0];
516 		st->other[1] = stateidp->other[1];
517 		st->other[2] = stateidp->other[2];
518 	} else {
519 		st->seqid = stateidp->seqid;
520 		st->other[0] = stateidp->other[0];
521 		st->other[1] = stateidp->other[1];
522 		st->other[2] = stateidp->other[2];
523 	}
524 }
525 
526 /*
527  * Initialize the owner/delegation sleep lock.
528  */
529 APPLESTATIC void
nfscl_lockinit(struct nfsv4lock * lckp)530 nfscl_lockinit(struct nfsv4lock *lckp)
531 {
532 
533 	lckp->nfslock_usecnt = 0;
534 	lckp->nfslock_lock = 0;
535 }
536 
537 /*
538  * Get an exclusive lock. (Not needed for OpenBSD4, since there is only one
539  * thread for each posix process in the kernel.)
540  */
541 APPLESTATIC void
nfscl_lockexcl(struct nfsv4lock * lckp,void * mutex)542 nfscl_lockexcl(struct nfsv4lock *lckp, void *mutex)
543 {
544 	int igotlock;
545 
546 	do {
547 		igotlock = nfsv4_lock(lckp, 1, NULL, mutex, NULL);
548 	} while (!igotlock);
549 }
550 
551 /*
552  * Release an exclusive lock.
553  */
554 APPLESTATIC void
nfscl_lockunlock(struct nfsv4lock * lckp)555 nfscl_lockunlock(struct nfsv4lock *lckp)
556 {
557 
558 	nfsv4_unlock(lckp, 0);
559 }
560 
561 /*
562  * Called to derefernce a lock on a stateid (delegation or open owner).
563  */
564 APPLESTATIC void
nfscl_lockderef(struct nfsv4lock * lckp)565 nfscl_lockderef(struct nfsv4lock *lckp)
566 {
567 
568 	NFSLOCKCLSTATE();
569 	lckp->nfslock_usecnt--;
570 	if (lckp->nfslock_usecnt == 0 && (lckp->nfslock_lock & NFSV4LOCK_WANTED)) {
571 		lckp->nfslock_lock &= ~NFSV4LOCK_WANTED;
572 		wakeup((caddr_t)lckp);
573 	}
574 	NFSUNLOCKCLSTATE();
575 }
576 
577