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