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