nfs_clcomsubs.c revision 259238
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 259238 2013-12-11 23:28:31Z 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, 3, "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				NFSWCCATTR_ATTRBIT(&attrbits);
223				(void) nfsrv_putattrbit(nd, &attrbits);
224				nd->nd_flag |= ND_V4WCCATTR;
225			}
226		}
227		if (procnum != NFSPROC_RENEW ||
228		    (nd->nd_flag & ND_NFSV41) == 0) {
229			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
230			*tl = txdr_unsigned(nfsv4_opmap[procnum].op);
231		}
232	} else {
233		(void) nfsm_fhtom(nd, nfhp, fhlen, 0);
234	}
235	if (procnum < NFSV4_NPROCS)
236		NFSINCRGLOBAL(newnfsstats.rpccnt[procnum]);
237}
238
239#ifndef APPLE
240/*
241 * copies a uio scatter/gather list to an mbuf chain.
242 * NOTE: can ony handle iovcnt == 1
243 */
244APPLESTATIC void
245nfsm_uiombuf(struct nfsrv_descript *nd, struct uio *uiop, int siz)
246{
247	char *uiocp;
248	struct mbuf *mp, *mp2;
249	int xfer, left, mlen;
250	int uiosiz, clflg, rem;
251	char *cp, *tcp;
252
253	KASSERT(uiop->uio_iovcnt == 1, ("nfsm_uiotombuf: iovcnt != 1"));
254
255	if (siz > ncl_mbuf_mlen)	/* or should it >= MCLBYTES ?? */
256		clflg = 1;
257	else
258		clflg = 0;
259	rem = NFSM_RNDUP(siz) - siz;
260	mp = mp2 = nd->nd_mb;
261	while (siz > 0) {
262		left = uiop->uio_iov->iov_len;
263		uiocp = uiop->uio_iov->iov_base;
264		if (left > siz)
265			left = siz;
266		uiosiz = left;
267		while (left > 0) {
268			mlen = M_TRAILINGSPACE(mp);
269			if (mlen == 0) {
270				if (clflg)
271					NFSMCLGET(mp, M_WAITOK);
272				else
273					NFSMGET(mp);
274				mbuf_setlen(mp, 0);
275				mbuf_setnext(mp2, mp);
276				mp2 = mp;
277				mlen = M_TRAILINGSPACE(mp);
278			}
279			xfer = (left > mlen) ? mlen : left;
280#ifdef notdef
281			/* Not Yet.. */
282			if (uiop->uio_iov->iov_op != NULL)
283				(*(uiop->uio_iov->iov_op))
284				(uiocp, NFSMTOD(mp, caddr_t) + mbuf_len(mp),
285				    xfer);
286			else
287#endif
288			if (uiop->uio_segflg == UIO_SYSSPACE)
289			    NFSBCOPY(uiocp, NFSMTOD(mp, caddr_t) + mbuf_len(mp),
290				xfer);
291			else
292			    copyin(CAST_USER_ADDR_T(uiocp), NFSMTOD(mp, caddr_t)
293				+ mbuf_len(mp), xfer);
294			mbuf_setlen(mp, mbuf_len(mp) + xfer);
295			left -= xfer;
296			uiocp += xfer;
297			uiop->uio_offset += xfer;
298			uiop->uio_resid -= xfer;
299		}
300		tcp = (char *)uiop->uio_iov->iov_base;
301		tcp += uiosiz;
302		uiop->uio_iov->iov_base = (void *)tcp;
303		uiop->uio_iov->iov_len -= uiosiz;
304		siz -= uiosiz;
305	}
306	if (rem > 0) {
307		if (rem > M_TRAILINGSPACE(mp)) {
308			NFSMGET(mp);
309			mbuf_setlen(mp, 0);
310			mbuf_setnext(mp2, mp);
311		}
312		cp = NFSMTOD(mp, caddr_t) + mbuf_len(mp);
313		for (left = 0; left < rem; left++)
314			*cp++ = '\0';
315		mbuf_setlen(mp, mbuf_len(mp) + rem);
316		nd->nd_bpos = cp;
317	} else
318		nd->nd_bpos = NFSMTOD(mp, caddr_t) + mbuf_len(mp);
319	nd->nd_mb = mp;
320}
321#endif	/* !APPLE */
322
323/*
324 * Load vnode attributes from the xdr file attributes.
325 * Returns EBADRPC if they can't be parsed, 0 otherwise.
326 */
327APPLESTATIC int
328nfsm_loadattr(struct nfsrv_descript *nd, struct nfsvattr *nap)
329{
330	struct nfs_fattr *fp;
331	int error = 0;
332
333	if (nd->nd_flag & ND_NFSV4) {
334		error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0, NULL,
335		    NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL);
336	} else if (nd->nd_flag & ND_NFSV3) {
337		NFSM_DISSECT(fp, struct nfs_fattr *, NFSX_V3FATTR);
338		nap->na_type = nfsv34tov_type(fp->fa_type);
339		nap->na_mode = fxdr_unsigned(u_short, fp->fa_mode);
340		nap->na_rdev = makedev(fxdr_unsigned(u_char, fp->fa3_rdev.specdata1),
341			fxdr_unsigned(u_char, fp->fa3_rdev.specdata2));
342		nap->na_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
343		nap->na_uid = fxdr_unsigned(uid_t, fp->fa_uid);
344		nap->na_gid = fxdr_unsigned(gid_t, fp->fa_gid);
345		nap->na_size = fxdr_hyper(&fp->fa3_size);
346		nap->na_blocksize = NFS_FABLKSIZE;
347		nap->na_bytes = fxdr_hyper(&fp->fa3_used);
348		nap->na_fileid = fxdr_hyper(&fp->fa3_fileid);
349		fxdr_nfsv3time(&fp->fa3_atime, &nap->na_atime);
350		fxdr_nfsv3time(&fp->fa3_ctime, &nap->na_ctime);
351		fxdr_nfsv3time(&fp->fa3_mtime, &nap->na_mtime);
352		nap->na_flags = 0;
353		nap->na_filerev = 0;
354	} else {
355		NFSM_DISSECT(fp, struct nfs_fattr *, NFSX_V2FATTR);
356		nap->na_type = nfsv2tov_type(fp->fa_type);
357		nap->na_mode = fxdr_unsigned(u_short, fp->fa_mode);
358		if (nap->na_type == VNON || nap->na_type == VREG)
359			nap->na_type = IFTOVT(nap->na_mode);
360		nap->na_rdev = fxdr_unsigned(dev_t, fp->fa2_rdev);
361
362		/*
363		 * Really ugly NFSv2 kludge.
364		 */
365		if (nap->na_type == VCHR && nap->na_rdev == ((dev_t)-1))
366			nap->na_type = VFIFO;
367		nap->na_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
368		nap->na_uid = fxdr_unsigned(uid_t, fp->fa_uid);
369		nap->na_gid = fxdr_unsigned(gid_t, fp->fa_gid);
370		nap->na_size = fxdr_unsigned(u_int32_t, fp->fa2_size);
371		nap->na_blocksize = fxdr_unsigned(int32_t, fp->fa2_blocksize);
372		nap->na_bytes =
373		    (u_quad_t)fxdr_unsigned(int32_t, fp->fa2_blocks) *
374		    NFS_FABLKSIZE;
375		nap->na_fileid = fxdr_unsigned(uint64_t, fp->fa2_fileid);
376		fxdr_nfsv2time(&fp->fa2_atime, &nap->na_atime);
377		fxdr_nfsv2time(&fp->fa2_mtime, &nap->na_mtime);
378		nap->na_flags = 0;
379		nap->na_ctime.tv_sec = fxdr_unsigned(u_int32_t,
380		    fp->fa2_ctime.nfsv2_sec);
381		nap->na_ctime.tv_nsec = 0;
382		nap->na_gen = fxdr_unsigned(u_int32_t,fp->fa2_ctime.nfsv2_usec);
383		nap->na_filerev = 0;
384	}
385nfsmout:
386	return (error);
387}
388
389/*
390 * This function finds the directory cookie that corresponds to the
391 * logical byte offset given.
392 */
393APPLESTATIC nfsuint64 *
394nfscl_getcookie(struct nfsnode *np, off_t off, int add)
395{
396	struct nfsdmap *dp, *dp2;
397	int pos;
398
399	pos = off / NFS_DIRBLKSIZ;
400	if (pos == 0) {
401		KASSERT(!add, ("nfs getcookie add at 0"));
402		return (&nfs_nullcookie);
403	}
404	pos--;
405	dp = LIST_FIRST(&np->n_cookies);
406	if (!dp) {
407		if (add) {
408			MALLOC(dp, struct nfsdmap *, sizeof (struct nfsdmap),
409				M_NFSDIROFF, M_WAITOK);
410			dp->ndm_eocookie = 0;
411			LIST_INSERT_HEAD(&np->n_cookies, dp, ndm_list);
412		} else
413			return (NULL);
414	}
415	while (pos >= NFSNUMCOOKIES) {
416		pos -= NFSNUMCOOKIES;
417		if (LIST_NEXT(dp, ndm_list) != NULL) {
418			if (!add && dp->ndm_eocookie < NFSNUMCOOKIES &&
419				pos >= dp->ndm_eocookie)
420				return (NULL);
421			dp = LIST_NEXT(dp, ndm_list);
422		} else if (add) {
423			MALLOC(dp2, struct nfsdmap *, sizeof (struct nfsdmap),
424				M_NFSDIROFF, M_WAITOK);
425			dp2->ndm_eocookie = 0;
426			LIST_INSERT_AFTER(dp, dp2, ndm_list);
427			dp = dp2;
428		} else
429			return (NULL);
430	}
431	if (pos >= dp->ndm_eocookie) {
432		if (add)
433			dp->ndm_eocookie = pos + 1;
434		else
435			return (NULL);
436	}
437	return (&dp->ndm_cookies[pos]);
438}
439
440/*
441 * Gets a file handle out of an nfs reply sent to the client and returns
442 * the file handle and the file's attributes.
443 * For V4, it assumes that Getfh and Getattr Op's results are here.
444 */
445APPLESTATIC int
446nfscl_mtofh(struct nfsrv_descript *nd, struct nfsfh **nfhpp,
447    struct nfsvattr *nap, int *attrflagp)
448{
449	u_int32_t *tl;
450	int error = 0, flag = 1;
451
452	*nfhpp = NULL;
453	*attrflagp = 0;
454	/*
455	 * First get the file handle and vnode.
456	 */
457	if (nd->nd_flag & ND_NFSV3) {
458		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
459		flag = fxdr_unsigned(int, *tl);
460	} else if (nd->nd_flag & ND_NFSV4) {
461		NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
462	}
463	if (flag) {
464		error = nfsm_getfh(nd, nfhpp);
465		if (error)
466			return (error);
467	}
468
469	/*
470	 * Now, get the attributes.
471	 */
472	if (nd->nd_flag & ND_NFSV4) {
473		NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
474	} else if (nd->nd_flag & ND_NFSV3) {
475		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
476		if (flag) {
477			flag = fxdr_unsigned(int, *tl);
478		} else if (fxdr_unsigned(int, *tl)) {
479			error = nfsm_advance(nd, NFSX_V3FATTR, -1);
480			if (error)
481				return (error);
482		}
483	}
484	if (flag) {
485		error = nfsm_loadattr(nd, nap);
486		if (!error)
487			*attrflagp = 1;
488	}
489nfsmout:
490	return (error);
491}
492
493/*
494 * Put a state Id in the mbuf list.
495 */
496APPLESTATIC void
497nfsm_stateidtom(struct nfsrv_descript *nd, nfsv4stateid_t *stateidp, int flag)
498{
499	nfsv4stateid_t *st;
500
501	NFSM_BUILD(st, nfsv4stateid_t *, NFSX_STATEID);
502	if (flag == NFSSTATEID_PUTALLZERO) {
503		st->seqid = 0;
504		st->other[0] = 0;
505		st->other[1] = 0;
506		st->other[2] = 0;
507	} else if (flag == NFSSTATEID_PUTALLONE) {
508		st->seqid = 0xffffffff;
509		st->other[0] = 0xffffffff;
510		st->other[1] = 0xffffffff;
511		st->other[2] = 0xffffffff;
512	} else if (flag == NFSSTATEID_PUTSEQIDZERO) {
513		st->seqid = 0;
514		st->other[0] = stateidp->other[0];
515		st->other[1] = stateidp->other[1];
516		st->other[2] = stateidp->other[2];
517	} else {
518		st->seqid = stateidp->seqid;
519		st->other[0] = stateidp->other[0];
520		st->other[1] = stateidp->other[1];
521		st->other[2] = stateidp->other[2];
522	}
523}
524
525/*
526 * Initialize the owner/delegation sleep lock.
527 */
528APPLESTATIC void
529nfscl_lockinit(struct nfsv4lock *lckp)
530{
531
532	lckp->nfslock_usecnt = 0;
533	lckp->nfslock_lock = 0;
534}
535
536/*
537 * Get an exclusive lock. (Not needed for OpenBSD4, since there is only one
538 * thread for each posix process in the kernel.)
539 */
540APPLESTATIC void
541nfscl_lockexcl(struct nfsv4lock *lckp, void *mutex)
542{
543	int igotlock;
544
545	do {
546		igotlock = nfsv4_lock(lckp, 1, NULL, mutex, NULL);
547	} while (!igotlock);
548}
549
550/*
551 * Release an exclusive lock.
552 */
553APPLESTATIC void
554nfscl_lockunlock(struct nfsv4lock *lckp)
555{
556
557	nfsv4_unlock(lckp, 0);
558}
559
560/*
561 * Called to derefernce a lock on a stateid (delegation or open owner).
562 */
563APPLESTATIC void
564nfscl_lockderef(struct nfsv4lock *lckp)
565{
566
567	NFSLOCKCLSTATE();
568	lckp->nfslock_usecnt--;
569	if (lckp->nfslock_usecnt == 0 && (lckp->nfslock_lock & NFSV4LOCK_WANTED)) {
570		lckp->nfslock_lock &= ~NFSV4LOCK_WANTED;
571		wakeup((caddr_t)lckp);
572	}
573	NFSUNLOCKCLSTATE();
574}
575
576