1191783Srmacklem/*-
2191783Srmacklem * Copyright (c) 1989, 1993
3191783Srmacklem *	The Regents of the University of California.  All rights reserved.
4191783Srmacklem *
5191783Srmacklem * This code is derived from software contributed to Berkeley by
6191783Srmacklem * Rick Macklem at The University of Guelph.
7191783Srmacklem *
8191783Srmacklem * Redistribution and use in source and binary forms, with or without
9191783Srmacklem * modification, are permitted provided that the following conditions
10191783Srmacklem * are met:
11191783Srmacklem * 1. Redistributions of source code must retain the above copyright
12191783Srmacklem *    notice, this list of conditions and the following disclaimer.
13191783Srmacklem * 2. Redistributions in binary form must reproduce the above copyright
14191783Srmacklem *    notice, this list of conditions and the following disclaimer in the
15191783Srmacklem *    documentation and/or other materials provided with the distribution.
16191783Srmacklem * 4. Neither the name of the University nor the names of its contributors
17191783Srmacklem *    may be used to endorse or promote products derived from this software
18191783Srmacklem *    without specific prior written permission.
19191783Srmacklem *
20191783Srmacklem * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21191783Srmacklem * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22191783Srmacklem * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23191783Srmacklem * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24191783Srmacklem * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25191783Srmacklem * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26191783Srmacklem * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27191783Srmacklem * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28191783Srmacklem * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29191783Srmacklem * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30191783Srmacklem * SUCH DAMAGE.
31191783Srmacklem *
32191783Srmacklem */
33191783Srmacklem
34191783Srmacklem#include <sys/cdefs.h>
35191783Srmacklem__FBSDID("$FreeBSD: releng/10.2/sys/fs/nfsclient/nfs_clcomsubs.c 265469 2014-05-06 21:54:52Z rmacklem $");
36191783Srmacklem
37191783Srmacklem/*
38191783Srmacklem * These functions support the macros and help fiddle mbuf chains for
39191783Srmacklem * the nfs op functions. They do things like create the rpc header and
40191783Srmacklem * copy data between mbuf chains and uio lists.
41191783Srmacklem */
42191783Srmacklem#ifndef APPLEKEXT
43191783Srmacklem#include <fs/nfs/nfsport.h>
44191783Srmacklem
45191783Srmacklemextern struct nfsstats newnfsstats;
46244042Srmacklemextern struct nfsv4_opflag nfsv4_opflag[NFSV41_NOPS];
47191783Srmacklemextern int ncl_mbuf_mlen;
48191783Srmacklemextern enum vtype newnv2tov_type[8];
49191783Srmacklemextern enum vtype nv34tov_type[8];
50244042Srmacklemextern int	nfs_bigreply[NFSV41_NPROCS];
51191783SrmacklemNFSCLSTATEMUTEX;
52191783Srmacklem#endif	/* !APPLEKEXT */
53191783Srmacklem
54191783Srmacklemstatic nfsuint64 nfs_nullcookie = {{ 0, 0 }};
55191783Srmacklemstatic struct {
56191783Srmacklem	int	op;
57191783Srmacklem	int	opcnt;
58191783Srmacklem	const u_char *tag;
59191783Srmacklem	int	taglen;
60244042Srmacklem} nfsv4_opmap[NFSV41_NPROCS] = {
61191783Srmacklem	{ 0, 1, "Null", 4 },
62191783Srmacklem	{ NFSV4OP_GETATTR, 1, "Getattr", 7, },
63191783Srmacklem	{ NFSV4OP_SETATTR, 2, "Setattr", 7, },
64191783Srmacklem	{ NFSV4OP_LOOKUP, 3, "Lookup", 6, },
65191783Srmacklem	{ NFSV4OP_ACCESS, 2, "Access", 6, },
66191783Srmacklem	{ NFSV4OP_READLINK, 2, "Readlink", 8, },
67191783Srmacklem	{ NFSV4OP_READ, 1, "Read", 4, },
68191783Srmacklem	{ NFSV4OP_WRITE, 2, "Write", 5, },
69265466Srmacklem	{ NFSV4OP_OPEN, 5, "Open", 4, },
70265469Srmacklem	{ NFSV4OP_CREATE, 5, "Create", 6, },
71191783Srmacklem	{ NFSV4OP_CREATE, 1, "Create", 6, },
72191783Srmacklem	{ NFSV4OP_CREATE, 3, "Create", 6, },
73191783Srmacklem	{ NFSV4OP_REMOVE, 1, "Remove", 6, },
74191783Srmacklem	{ NFSV4OP_REMOVE, 1, "Remove", 6, },
75191783Srmacklem	{ NFSV4OP_SAVEFH, 5, "Rename", 6, },
76191783Srmacklem	{ NFSV4OP_SAVEFH, 4, "Link", 4, },
77191783Srmacklem	{ NFSV4OP_READDIR, 2, "Readdir", 7, },
78191783Srmacklem	{ NFSV4OP_READDIR, 2, "Readdir", 7, },
79191783Srmacklem	{ NFSV4OP_GETATTR, 1, "Getattr", 7, },
80191783Srmacklem	{ NFSV4OP_GETATTR, 1, "Getattr", 7, },
81191783Srmacklem	{ NFSV4OP_GETATTR, 1, "Getattr", 7, },
82191783Srmacklem	{ NFSV4OP_COMMIT, 2, "Commit", 6, },
83191783Srmacklem	{ NFSV4OP_LOOKUPP, 3, "Lookupp", 7, },
84191783Srmacklem	{ NFSV4OP_SETCLIENTID, 1, "SetClientID", 11, },
85191783Srmacklem	{ NFSV4OP_SETCLIENTIDCFRM, 1, "SetClientIDConfirm", 18, },
86191783Srmacklem	{ NFSV4OP_LOCK, 1, "Lock", 4, },
87191783Srmacklem	{ NFSV4OP_LOCKU, 1, "LockU", 5, },
88191783Srmacklem	{ NFSV4OP_OPEN, 2, "Open", 4, },
89191783Srmacklem	{ NFSV4OP_CLOSE, 1, "Close", 5, },
90191783Srmacklem	{ NFSV4OP_OPENCONFIRM, 1, "Openconfirm", 11, },
91191783Srmacklem	{ NFSV4OP_LOCKT, 1, "LockT", 5, },
92191783Srmacklem	{ NFSV4OP_OPENDOWNGRADE, 1, "Opendowngrade", 13, },
93191783Srmacklem	{ NFSV4OP_RENEW, 1, "Renew", 5, },
94191783Srmacklem	{ NFSV4OP_PUTROOTFH, 1, "Dirpath", 7, },
95191783Srmacklem	{ NFSV4OP_RELEASELCKOWN, 1, "Rellckown", 9, },
96191783Srmacklem	{ NFSV4OP_DELEGRETURN, 1, "Delegret", 8, },
97191783Srmacklem	{ NFSV4OP_DELEGRETURN, 3, "DelegRemove", 11, },
98191783Srmacklem	{ NFSV4OP_DELEGRETURN, 7, "DelegRename1", 12, },
99191783Srmacklem	{ NFSV4OP_DELEGRETURN, 9, "DelegRename2", 12, },
100191783Srmacklem	{ NFSV4OP_GETATTR, 1, "Getacl", 6, },
101191783Srmacklem	{ NFSV4OP_SETATTR, 1, "Setacl", 6, },
102244042Srmacklem	{ NFSV4OP_EXCHANGEID, 1, "ExchangeID", 10, },
103244042Srmacklem	{ NFSV4OP_CREATESESSION, 1, "CreateSession", 13, },
104244042Srmacklem	{ NFSV4OP_DESTROYSESSION, 1, "DestroySession", 14, },
105244042Srmacklem	{ NFSV4OP_DESTROYCLIENTID, 1, "DestroyClient", 13, },
106244042Srmacklem	{ NFSV4OP_FREESTATEID, 1, "FreeStateID", 11, },
107244042Srmacklem	{ NFSV4OP_LAYOUTGET, 1, "LayoutGet", 9, },
108244042Srmacklem	{ NFSV4OP_GETDEVINFO, 1, "GetDeviceInfo", 13, },
109244042Srmacklem	{ NFSV4OP_LAYOUTCOMMIT, 1, "LayoutCommit", 12, },
110244042Srmacklem	{ NFSV4OP_LAYOUTRETURN, 1, "LayoutReturn", 12, },
111244042Srmacklem	{ NFSV4OP_RECLAIMCOMPL, 1, "ReclaimComplete", 15, },
112244042Srmacklem	{ NFSV4OP_WRITE, 1, "WriteDS", 7, },
113244042Srmacklem	{ NFSV4OP_READ, 1, "ReadDS", 6, },
114244042Srmacklem	{ NFSV4OP_COMMIT, 1, "CommitDS", 8, },
115191783Srmacklem};
116191783Srmacklem
117191783Srmacklem/*
118191783Srmacklem * NFS RPCS that have large request message size.
119191783Srmacklem */
120244042Srmacklemstatic int nfs_bigrequest[NFSV41_NPROCS] = {
121191783Srmacklem	0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
122244042Srmacklem	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
123244042Srmacklem	0, 0, 0, 0, 0, 0, 1, 0, 0
124191783Srmacklem};
125191783Srmacklem
126191783Srmacklem/*
127191783Srmacklem * Start building a request. Mostly just put the first file handle in
128191783Srmacklem * place.
129191783Srmacklem */
130191783SrmacklemAPPLESTATIC void
131191783Srmacklemnfscl_reqstart(struct nfsrv_descript *nd, int procnum, struct nfsmount *nmp,
132244042Srmacklem    u_int8_t *nfhp, int fhlen, u_int32_t **opcntpp, struct nfsclsession *sep)
133191783Srmacklem{
134191783Srmacklem	struct mbuf *mb;
135191783Srmacklem	u_int32_t *tl;
136191783Srmacklem	int opcnt;
137191783Srmacklem	nfsattrbit_t attrbits;
138191783Srmacklem
139191783Srmacklem	/*
140191783Srmacklem	 * First, fill in some of the fields of nd.
141191783Srmacklem	 */
142244042Srmacklem	nd->nd_slotseq = NULL;
143244042Srmacklem	if (NFSHASNFSV4(nmp)) {
144240720Srmacklem		nd->nd_flag = ND_NFSV4 | ND_NFSCL;
145244042Srmacklem		if (NFSHASNFSV4N(nmp))
146244042Srmacklem			nd->nd_flag |= ND_NFSV41;
147244042Srmacklem	} else if (NFSHASNFSV3(nmp))
148240720Srmacklem		nd->nd_flag = ND_NFSV3 | ND_NFSCL;
149191783Srmacklem	else
150240720Srmacklem		nd->nd_flag = ND_NFSV2 | ND_NFSCL;
151191783Srmacklem	nd->nd_procnum = procnum;
152191783Srmacklem	nd->nd_repstat = 0;
153191783Srmacklem
154191783Srmacklem	/*
155191783Srmacklem	 * Get the first mbuf for the request.
156191783Srmacklem	 */
157191783Srmacklem	if (nfs_bigrequest[procnum])
158243882Sglebius		NFSMCLGET(mb, M_WAITOK);
159191783Srmacklem	else
160191783Srmacklem		NFSMGET(mb);
161191783Srmacklem	mbuf_setlen(mb, 0);
162191783Srmacklem	nd->nd_mreq = nd->nd_mb = mb;
163191783Srmacklem	nd->nd_bpos = NFSMTOD(mb, caddr_t);
164191783Srmacklem
165191783Srmacklem	/*
166191783Srmacklem	 * And fill the first file handle into the request.
167191783Srmacklem	 */
168191783Srmacklem	if (nd->nd_flag & ND_NFSV4) {
169191783Srmacklem		opcnt = nfsv4_opmap[procnum].opcnt +
170191783Srmacklem		    nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh;
171244042Srmacklem		if ((nd->nd_flag & ND_NFSV41) != 0) {
172244042Srmacklem			opcnt += nfsv4_opflag[nfsv4_opmap[procnum].op].needsseq;
173244042Srmacklem			if (procnum == NFSPROC_RENEW)
174244042Srmacklem				/*
175244042Srmacklem				 * For the special case of Renew, just do a
176244042Srmacklem				 * Sequence Op.
177244042Srmacklem				 */
178244042Srmacklem				opcnt = 1;
179244042Srmacklem			else if (procnum == NFSPROC_WRITEDS ||
180244042Srmacklem			    procnum == NFSPROC_COMMITDS)
181244042Srmacklem				/*
182244042Srmacklem				 * For the special case of a Writeor Commit to
183244042Srmacklem				 * a DS, the opcnt == 3, for Sequence, PutFH,
184244042Srmacklem				 * Write/Commit.
185244042Srmacklem				 */
186244042Srmacklem				opcnt = 3;
187244042Srmacklem		}
188191783Srmacklem		/*
189191783Srmacklem		 * What should the tag really be?
190191783Srmacklem		 */
191191783Srmacklem		(void) nfsm_strtom(nd, nfsv4_opmap[procnum].tag,
192191783Srmacklem			nfsv4_opmap[procnum].taglen);
193244042Srmacklem		NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
194244042Srmacklem		if ((nd->nd_flag & ND_NFSV41) != 0)
195244042Srmacklem			*tl++ = txdr_unsigned(NFSV41_MINORVERSION);
196244042Srmacklem		else
197244042Srmacklem			*tl++ = txdr_unsigned(NFSV4_MINORVERSION);
198191783Srmacklem		if (opcntpp != NULL)
199191783Srmacklem			*opcntpp = tl;
200244042Srmacklem		*tl = txdr_unsigned(opcnt);
201244042Srmacklem		if ((nd->nd_flag & ND_NFSV41) != 0 &&
202244042Srmacklem		    nfsv4_opflag[nfsv4_opmap[procnum].op].needsseq > 0) {
203244042Srmacklem			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
204244042Srmacklem			*tl = txdr_unsigned(NFSV4OP_SEQUENCE);
205244042Srmacklem			if (sep == NULL)
206259238Srmacklem				nfsv4_setsequence(nmp, nd,
207259238Srmacklem				    NFSMNT_MDSSESSION(nmp),
208244042Srmacklem				    nfs_bigreply[procnum]);
209244042Srmacklem			else
210259238Srmacklem				nfsv4_setsequence(nmp, nd, sep,
211244042Srmacklem				    nfs_bigreply[procnum]);
212244042Srmacklem		}
213191783Srmacklem		if (nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh > 0) {
214244042Srmacklem			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
215191783Srmacklem			*tl = txdr_unsigned(NFSV4OP_PUTFH);
216191783Srmacklem			(void) nfsm_fhtom(nd, nfhp, fhlen, 0);
217244042Srmacklem			if (nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh
218244042Srmacklem			    == 2 && procnum != NFSPROC_WRITEDS &&
219244042Srmacklem			    procnum != NFSPROC_COMMITDS) {
220191783Srmacklem				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
221191783Srmacklem				*tl = txdr_unsigned(NFSV4OP_GETATTR);
222265434Srmacklem				/*
223265434Srmacklem				 * For Lookup Ops, we want all the directory
224265434Srmacklem				 * attributes, so we can load the name cache.
225265434Srmacklem				 */
226265434Srmacklem				if (procnum == NFSPROC_LOOKUP ||
227265434Srmacklem				    procnum == NFSPROC_LOOKUPP)
228265434Srmacklem					NFSGETATTR_ATTRBIT(&attrbits);
229265434Srmacklem				else {
230265434Srmacklem					NFSWCCATTR_ATTRBIT(&attrbits);
231265434Srmacklem					nd->nd_flag |= ND_V4WCCATTR;
232265434Srmacklem				}
233191783Srmacklem				(void) nfsrv_putattrbit(nd, &attrbits);
234191783Srmacklem			}
235244042Srmacklem		}
236244042Srmacklem		if (procnum != NFSPROC_RENEW ||
237244042Srmacklem		    (nd->nd_flag & ND_NFSV41) == 0) {
238191783Srmacklem			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
239244042Srmacklem			*tl = txdr_unsigned(nfsv4_opmap[procnum].op);
240191783Srmacklem		}
241191783Srmacklem	} else {
242191783Srmacklem		(void) nfsm_fhtom(nd, nfhp, fhlen, 0);
243191783Srmacklem	}
244244042Srmacklem	if (procnum < NFSV4_NPROCS)
245244042Srmacklem		NFSINCRGLOBAL(newnfsstats.rpccnt[procnum]);
246191783Srmacklem}
247191783Srmacklem
248191783Srmacklem#ifndef APPLE
249191783Srmacklem/*
250191783Srmacklem * copies a uio scatter/gather list to an mbuf chain.
251191783Srmacklem * NOTE: can ony handle iovcnt == 1
252191783Srmacklem */
253191783SrmacklemAPPLESTATIC void
254191783Srmacklemnfsm_uiombuf(struct nfsrv_descript *nd, struct uio *uiop, int siz)
255191783Srmacklem{
256191783Srmacklem	char *uiocp;
257191783Srmacklem	struct mbuf *mp, *mp2;
258191783Srmacklem	int xfer, left, mlen;
259191783Srmacklem	int uiosiz, clflg, rem;
260191783Srmacklem	char *cp, *tcp;
261191783Srmacklem
262209120Skib	KASSERT(uiop->uio_iovcnt == 1, ("nfsm_uiotombuf: iovcnt != 1"));
263191783Srmacklem
264191783Srmacklem	if (siz > ncl_mbuf_mlen)	/* or should it >= MCLBYTES ?? */
265191783Srmacklem		clflg = 1;
266191783Srmacklem	else
267191783Srmacklem		clflg = 0;
268191783Srmacklem	rem = NFSM_RNDUP(siz) - siz;
269191783Srmacklem	mp = mp2 = nd->nd_mb;
270191783Srmacklem	while (siz > 0) {
271191783Srmacklem		left = uiop->uio_iov->iov_len;
272191783Srmacklem		uiocp = uiop->uio_iov->iov_base;
273191783Srmacklem		if (left > siz)
274191783Srmacklem			left = siz;
275191783Srmacklem		uiosiz = left;
276191783Srmacklem		while (left > 0) {
277191783Srmacklem			mlen = M_TRAILINGSPACE(mp);
278191783Srmacklem			if (mlen == 0) {
279191783Srmacklem				if (clflg)
280243882Sglebius					NFSMCLGET(mp, M_WAITOK);
281191783Srmacklem				else
282191783Srmacklem					NFSMGET(mp);
283191783Srmacklem				mbuf_setlen(mp, 0);
284191783Srmacklem				mbuf_setnext(mp2, mp);
285191783Srmacklem				mp2 = mp;
286191783Srmacklem				mlen = M_TRAILINGSPACE(mp);
287191783Srmacklem			}
288191783Srmacklem			xfer = (left > mlen) ? mlen : left;
289191783Srmacklem#ifdef notdef
290191783Srmacklem			/* Not Yet.. */
291191783Srmacklem			if (uiop->uio_iov->iov_op != NULL)
292191783Srmacklem				(*(uiop->uio_iov->iov_op))
293191783Srmacklem				(uiocp, NFSMTOD(mp, caddr_t) + mbuf_len(mp),
294191783Srmacklem				    xfer);
295191783Srmacklem			else
296191783Srmacklem#endif
297191783Srmacklem			if (uiop->uio_segflg == UIO_SYSSPACE)
298191783Srmacklem			    NFSBCOPY(uiocp, NFSMTOD(mp, caddr_t) + mbuf_len(mp),
299191783Srmacklem				xfer);
300191783Srmacklem			else
301191783Srmacklem			    copyin(CAST_USER_ADDR_T(uiocp), NFSMTOD(mp, caddr_t)
302191783Srmacklem				+ mbuf_len(mp), xfer);
303191783Srmacklem			mbuf_setlen(mp, mbuf_len(mp) + xfer);
304191783Srmacklem			left -= xfer;
305191783Srmacklem			uiocp += xfer;
306191783Srmacklem			uiop->uio_offset += xfer;
307191783Srmacklem			uiop->uio_resid -= xfer;
308191783Srmacklem		}
309191783Srmacklem		tcp = (char *)uiop->uio_iov->iov_base;
310191783Srmacklem		tcp += uiosiz;
311191783Srmacklem		uiop->uio_iov->iov_base = (void *)tcp;
312191783Srmacklem		uiop->uio_iov->iov_len -= uiosiz;
313191783Srmacklem		siz -= uiosiz;
314191783Srmacklem	}
315191783Srmacklem	if (rem > 0) {
316191783Srmacklem		if (rem > M_TRAILINGSPACE(mp)) {
317191783Srmacklem			NFSMGET(mp);
318191783Srmacklem			mbuf_setlen(mp, 0);
319191783Srmacklem			mbuf_setnext(mp2, mp);
320191783Srmacklem		}
321191783Srmacklem		cp = NFSMTOD(mp, caddr_t) + mbuf_len(mp);
322191783Srmacklem		for (left = 0; left < rem; left++)
323191783Srmacklem			*cp++ = '\0';
324191783Srmacklem		mbuf_setlen(mp, mbuf_len(mp) + rem);
325191783Srmacklem		nd->nd_bpos = cp;
326191783Srmacklem	} else
327191783Srmacklem		nd->nd_bpos = NFSMTOD(mp, caddr_t) + mbuf_len(mp);
328191783Srmacklem	nd->nd_mb = mp;
329191783Srmacklem}
330191783Srmacklem#endif	/* !APPLE */
331191783Srmacklem
332191783Srmacklem/*
333191783Srmacklem * Load vnode attributes from the xdr file attributes.
334191783Srmacklem * Returns EBADRPC if they can't be parsed, 0 otherwise.
335191783Srmacklem */
336191783SrmacklemAPPLESTATIC int
337191783Srmacklemnfsm_loadattr(struct nfsrv_descript *nd, struct nfsvattr *nap)
338191783Srmacklem{
339191783Srmacklem	struct nfs_fattr *fp;
340191783Srmacklem	int error = 0;
341191783Srmacklem
342191783Srmacklem	if (nd->nd_flag & ND_NFSV4) {
343191783Srmacklem		error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0, NULL,
344191783Srmacklem		    NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL);
345191783Srmacklem	} else if (nd->nd_flag & ND_NFSV3) {
346191783Srmacklem		NFSM_DISSECT(fp, struct nfs_fattr *, NFSX_V3FATTR);
347191783Srmacklem		nap->na_type = nfsv34tov_type(fp->fa_type);
348191783Srmacklem		nap->na_mode = fxdr_unsigned(u_short, fp->fa_mode);
349191783Srmacklem		nap->na_rdev = makedev(fxdr_unsigned(u_char, fp->fa3_rdev.specdata1),
350191783Srmacklem			fxdr_unsigned(u_char, fp->fa3_rdev.specdata2));
351191783Srmacklem		nap->na_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
352191783Srmacklem		nap->na_uid = fxdr_unsigned(uid_t, fp->fa_uid);
353191783Srmacklem		nap->na_gid = fxdr_unsigned(gid_t, fp->fa_gid);
354191783Srmacklem		nap->na_size = fxdr_hyper(&fp->fa3_size);
355191783Srmacklem		nap->na_blocksize = NFS_FABLKSIZE;
356191783Srmacklem		nap->na_bytes = fxdr_hyper(&fp->fa3_used);
357220152Szack		nap->na_fileid = fxdr_hyper(&fp->fa3_fileid);
358191783Srmacklem		fxdr_nfsv3time(&fp->fa3_atime, &nap->na_atime);
359191783Srmacklem		fxdr_nfsv3time(&fp->fa3_ctime, &nap->na_ctime);
360191783Srmacklem		fxdr_nfsv3time(&fp->fa3_mtime, &nap->na_mtime);
361191783Srmacklem		nap->na_flags = 0;
362191783Srmacklem		nap->na_filerev = 0;
363191783Srmacklem	} else {
364191783Srmacklem		NFSM_DISSECT(fp, struct nfs_fattr *, NFSX_V2FATTR);
365191783Srmacklem		nap->na_type = nfsv2tov_type(fp->fa_type);
366191783Srmacklem		nap->na_mode = fxdr_unsigned(u_short, fp->fa_mode);
367191783Srmacklem		if (nap->na_type == VNON || nap->na_type == VREG)
368191783Srmacklem			nap->na_type = IFTOVT(nap->na_mode);
369191783Srmacklem		nap->na_rdev = fxdr_unsigned(dev_t, fp->fa2_rdev);
370191783Srmacklem
371191783Srmacklem		/*
372191783Srmacklem		 * Really ugly NFSv2 kludge.
373191783Srmacklem		 */
374191783Srmacklem		if (nap->na_type == VCHR && nap->na_rdev == ((dev_t)-1))
375191783Srmacklem			nap->na_type = VFIFO;
376191783Srmacklem		nap->na_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
377191783Srmacklem		nap->na_uid = fxdr_unsigned(uid_t, fp->fa_uid);
378191783Srmacklem		nap->na_gid = fxdr_unsigned(gid_t, fp->fa_gid);
379191783Srmacklem		nap->na_size = fxdr_unsigned(u_int32_t, fp->fa2_size);
380191783Srmacklem		nap->na_blocksize = fxdr_unsigned(int32_t, fp->fa2_blocksize);
381191783Srmacklem		nap->na_bytes =
382191783Srmacklem		    (u_quad_t)fxdr_unsigned(int32_t, fp->fa2_blocks) *
383191783Srmacklem		    NFS_FABLKSIZE;
384220152Szack		nap->na_fileid = fxdr_unsigned(uint64_t, fp->fa2_fileid);
385191783Srmacklem		fxdr_nfsv2time(&fp->fa2_atime, &nap->na_atime);
386191783Srmacklem		fxdr_nfsv2time(&fp->fa2_mtime, &nap->na_mtime);
387191783Srmacklem		nap->na_flags = 0;
388191783Srmacklem		nap->na_ctime.tv_sec = fxdr_unsigned(u_int32_t,
389191783Srmacklem		    fp->fa2_ctime.nfsv2_sec);
390191783Srmacklem		nap->na_ctime.tv_nsec = 0;
391191783Srmacklem		nap->na_gen = fxdr_unsigned(u_int32_t,fp->fa2_ctime.nfsv2_usec);
392191783Srmacklem		nap->na_filerev = 0;
393191783Srmacklem	}
394191783Srmacklemnfsmout:
395191783Srmacklem	return (error);
396191783Srmacklem}
397191783Srmacklem
398191783Srmacklem/*
399191783Srmacklem * This function finds the directory cookie that corresponds to the
400191783Srmacklem * logical byte offset given.
401191783Srmacklem */
402191783SrmacklemAPPLESTATIC nfsuint64 *
403191783Srmacklemnfscl_getcookie(struct nfsnode *np, off_t off, int add)
404191783Srmacklem{
405191783Srmacklem	struct nfsdmap *dp, *dp2;
406191783Srmacklem	int pos;
407191783Srmacklem
408191783Srmacklem	pos = off / NFS_DIRBLKSIZ;
409191783Srmacklem	if (pos == 0) {
410209120Skib		KASSERT(!add, ("nfs getcookie add at 0"));
411191783Srmacklem		return (&nfs_nullcookie);
412191783Srmacklem	}
413191783Srmacklem	pos--;
414191783Srmacklem	dp = LIST_FIRST(&np->n_cookies);
415191783Srmacklem	if (!dp) {
416191783Srmacklem		if (add) {
417191783Srmacklem			MALLOC(dp, struct nfsdmap *, sizeof (struct nfsdmap),
418191783Srmacklem				M_NFSDIROFF, M_WAITOK);
419191783Srmacklem			dp->ndm_eocookie = 0;
420191783Srmacklem			LIST_INSERT_HEAD(&np->n_cookies, dp, ndm_list);
421191783Srmacklem		} else
422191783Srmacklem			return (NULL);
423191783Srmacklem	}
424191783Srmacklem	while (pos >= NFSNUMCOOKIES) {
425191783Srmacklem		pos -= NFSNUMCOOKIES;
426191783Srmacklem		if (LIST_NEXT(dp, ndm_list) != NULL) {
427191783Srmacklem			if (!add && dp->ndm_eocookie < NFSNUMCOOKIES &&
428191783Srmacklem				pos >= dp->ndm_eocookie)
429191783Srmacklem				return (NULL);
430191783Srmacklem			dp = LIST_NEXT(dp, ndm_list);
431191783Srmacklem		} else if (add) {
432191783Srmacklem			MALLOC(dp2, struct nfsdmap *, sizeof (struct nfsdmap),
433191783Srmacklem				M_NFSDIROFF, M_WAITOK);
434191783Srmacklem			dp2->ndm_eocookie = 0;
435191783Srmacklem			LIST_INSERT_AFTER(dp, dp2, ndm_list);
436191783Srmacklem			dp = dp2;
437191783Srmacklem		} else
438191783Srmacklem			return (NULL);
439191783Srmacklem	}
440191783Srmacklem	if (pos >= dp->ndm_eocookie) {
441191783Srmacklem		if (add)
442191783Srmacklem			dp->ndm_eocookie = pos + 1;
443191783Srmacklem		else
444191783Srmacklem			return (NULL);
445191783Srmacklem	}
446191783Srmacklem	return (&dp->ndm_cookies[pos]);
447191783Srmacklem}
448191783Srmacklem
449191783Srmacklem/*
450191783Srmacklem * Gets a file handle out of an nfs reply sent to the client and returns
451191783Srmacklem * the file handle and the file's attributes.
452191783Srmacklem * For V4, it assumes that Getfh and Getattr Op's results are here.
453191783Srmacklem */
454191783SrmacklemAPPLESTATIC int
455191783Srmacklemnfscl_mtofh(struct nfsrv_descript *nd, struct nfsfh **nfhpp,
456191783Srmacklem    struct nfsvattr *nap, int *attrflagp)
457191783Srmacklem{
458191783Srmacklem	u_int32_t *tl;
459191783Srmacklem	int error = 0, flag = 1;
460191783Srmacklem
461191783Srmacklem	*nfhpp = NULL;
462191783Srmacklem	*attrflagp = 0;
463191783Srmacklem	/*
464191783Srmacklem	 * First get the file handle and vnode.
465191783Srmacklem	 */
466191783Srmacklem	if (nd->nd_flag & ND_NFSV3) {
467191783Srmacklem		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
468191783Srmacklem		flag = fxdr_unsigned(int, *tl);
469191783Srmacklem	} else if (nd->nd_flag & ND_NFSV4) {
470191783Srmacklem		NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
471191783Srmacklem	}
472191783Srmacklem	if (flag) {
473191783Srmacklem		error = nfsm_getfh(nd, nfhpp);
474191783Srmacklem		if (error)
475191783Srmacklem			return (error);
476191783Srmacklem	}
477191783Srmacklem
478191783Srmacklem	/*
479191783Srmacklem	 * Now, get the attributes.
480191783Srmacklem	 */
481191783Srmacklem	if (nd->nd_flag & ND_NFSV4) {
482191783Srmacklem		NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
483191783Srmacklem	} else if (nd->nd_flag & ND_NFSV3) {
484191783Srmacklem		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
485191783Srmacklem		if (flag) {
486191783Srmacklem			flag = fxdr_unsigned(int, *tl);
487191783Srmacklem		} else if (fxdr_unsigned(int, *tl)) {
488191783Srmacklem			error = nfsm_advance(nd, NFSX_V3FATTR, -1);
489191783Srmacklem			if (error)
490191783Srmacklem				return (error);
491191783Srmacklem		}
492191783Srmacklem	}
493191783Srmacklem	if (flag) {
494191783Srmacklem		error = nfsm_loadattr(nd, nap);
495191783Srmacklem		if (!error)
496191783Srmacklem			*attrflagp = 1;
497191783Srmacklem	}
498191783Srmacklemnfsmout:
499191783Srmacklem	return (error);
500191783Srmacklem}
501191783Srmacklem
502191783Srmacklem/*
503191783Srmacklem * Put a state Id in the mbuf list.
504191783Srmacklem */
505191783SrmacklemAPPLESTATIC void
506191783Srmacklemnfsm_stateidtom(struct nfsrv_descript *nd, nfsv4stateid_t *stateidp, int flag)
507191783Srmacklem{
508191783Srmacklem	nfsv4stateid_t *st;
509191783Srmacklem
510191783Srmacklem	NFSM_BUILD(st, nfsv4stateid_t *, NFSX_STATEID);
511191783Srmacklem	if (flag == NFSSTATEID_PUTALLZERO) {
512191783Srmacklem		st->seqid = 0;
513191783Srmacklem		st->other[0] = 0;
514191783Srmacklem		st->other[1] = 0;
515191783Srmacklem		st->other[2] = 0;
516191783Srmacklem	} else if (flag == NFSSTATEID_PUTALLONE) {
517191783Srmacklem		st->seqid = 0xffffffff;
518191783Srmacklem		st->other[0] = 0xffffffff;
519191783Srmacklem		st->other[1] = 0xffffffff;
520191783Srmacklem		st->other[2] = 0xffffffff;
521244042Srmacklem	} else if (flag == NFSSTATEID_PUTSEQIDZERO) {
522244042Srmacklem		st->seqid = 0;
523244042Srmacklem		st->other[0] = stateidp->other[0];
524244042Srmacklem		st->other[1] = stateidp->other[1];
525244042Srmacklem		st->other[2] = stateidp->other[2];
526191783Srmacklem	} else {
527191783Srmacklem		st->seqid = stateidp->seqid;
528191783Srmacklem		st->other[0] = stateidp->other[0];
529191783Srmacklem		st->other[1] = stateidp->other[1];
530191783Srmacklem		st->other[2] = stateidp->other[2];
531191783Srmacklem	}
532191783Srmacklem}
533191783Srmacklem
534191783Srmacklem/*
535191783Srmacklem * Initialize the owner/delegation sleep lock.
536191783Srmacklem */
537191783SrmacklemAPPLESTATIC void
538191783Srmacklemnfscl_lockinit(struct nfsv4lock *lckp)
539191783Srmacklem{
540191783Srmacklem
541191783Srmacklem	lckp->nfslock_usecnt = 0;
542191783Srmacklem	lckp->nfslock_lock = 0;
543191783Srmacklem}
544191783Srmacklem
545191783Srmacklem/*
546191783Srmacklem * Get an exclusive lock. (Not needed for OpenBSD4, since there is only one
547191783Srmacklem * thread for each posix process in the kernel.)
548191783Srmacklem */
549191783SrmacklemAPPLESTATIC void
550191783Srmacklemnfscl_lockexcl(struct nfsv4lock *lckp, void *mutex)
551191783Srmacklem{
552191783Srmacklem	int igotlock;
553191783Srmacklem
554191783Srmacklem	do {
555222389Srmacklem		igotlock = nfsv4_lock(lckp, 1, NULL, mutex, NULL);
556191783Srmacklem	} while (!igotlock);
557191783Srmacklem}
558191783Srmacklem
559191783Srmacklem/*
560191783Srmacklem * Release an exclusive lock.
561191783Srmacklem */
562191783SrmacklemAPPLESTATIC void
563191783Srmacklemnfscl_lockunlock(struct nfsv4lock *lckp)
564191783Srmacklem{
565191783Srmacklem
566191783Srmacklem	nfsv4_unlock(lckp, 0);
567191783Srmacklem}
568191783Srmacklem
569191783Srmacklem/*
570191783Srmacklem * Called to derefernce a lock on a stateid (delegation or open owner).
571191783Srmacklem */
572191783SrmacklemAPPLESTATIC void
573191783Srmacklemnfscl_lockderef(struct nfsv4lock *lckp)
574191783Srmacklem{
575191783Srmacklem
576191783Srmacklem	NFSLOCKCLSTATE();
577191783Srmacklem	lckp->nfslock_usecnt--;
578191783Srmacklem	if (lckp->nfslock_usecnt == 0 && (lckp->nfslock_lock & NFSV4LOCK_WANTED)) {
579191783Srmacklem		lckp->nfslock_lock &= ~NFSV4LOCK_WANTED;
580191783Srmacklem		wakeup((caddr_t)lckp);
581191783Srmacklem	}
582191783Srmacklem	NFSUNLOCKCLSTATE();
583191783Srmacklem}
584191783Srmacklem
585