nfs_clcomsubs.c revision 244042
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: head/sys/fs/nfsclient/nfs_clcomsubs.c 244042 2012-12-08 22:52:39Z 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, },
69191783Srmacklem	{ NFSV4OP_OPEN, 3, "Open", 4, },
70191783Srmacklem	{ NFSV4OP_CREATE, 3, "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)
206244042Srmacklem				nfsv4_setsequence(nd, NFSMNT_MDSSESSION(nmp),
207244042Srmacklem				    nfs_bigreply[procnum]);
208244042Srmacklem			else
209244042Srmacklem				nfsv4_setsequence(nd, sep,
210244042Srmacklem				    nfs_bigreply[procnum]);
211244042Srmacklem		}
212191783Srmacklem		if (nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh > 0) {
213244042Srmacklem			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
214191783Srmacklem			*tl = txdr_unsigned(NFSV4OP_PUTFH);
215191783Srmacklem			(void) nfsm_fhtom(nd, nfhp, fhlen, 0);
216244042Srmacklem			if (nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh
217244042Srmacklem			    == 2 && procnum != NFSPROC_WRITEDS &&
218244042Srmacklem			    procnum != NFSPROC_COMMITDS) {
219191783Srmacklem				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
220191783Srmacklem				*tl = txdr_unsigned(NFSV4OP_GETATTR);
221191783Srmacklem				NFSWCCATTR_ATTRBIT(&attrbits);
222191783Srmacklem				(void) nfsrv_putattrbit(nd, &attrbits);
223191783Srmacklem				nd->nd_flag |= ND_V4WCCATTR;
224191783Srmacklem			}
225244042Srmacklem		}
226244042Srmacklem		if (procnum != NFSPROC_RENEW ||
227244042Srmacklem		    (nd->nd_flag & ND_NFSV41) == 0) {
228191783Srmacklem			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
229244042Srmacklem			*tl = txdr_unsigned(nfsv4_opmap[procnum].op);
230191783Srmacklem		}
231191783Srmacklem	} else {
232191783Srmacklem		(void) nfsm_fhtom(nd, nfhp, fhlen, 0);
233191783Srmacklem	}
234244042Srmacklem	if (procnum < NFSV4_NPROCS)
235244042Srmacklem		NFSINCRGLOBAL(newnfsstats.rpccnt[procnum]);
236191783Srmacklem}
237191783Srmacklem
238191783Srmacklem#ifndef APPLE
239191783Srmacklem/*
240191783Srmacklem * copies a uio scatter/gather list to an mbuf chain.
241191783Srmacklem * NOTE: can ony handle iovcnt == 1
242191783Srmacklem */
243191783SrmacklemAPPLESTATIC void
244191783Srmacklemnfsm_uiombuf(struct nfsrv_descript *nd, struct uio *uiop, int siz)
245191783Srmacklem{
246191783Srmacklem	char *uiocp;
247191783Srmacklem	struct mbuf *mp, *mp2;
248191783Srmacklem	int xfer, left, mlen;
249191783Srmacklem	int uiosiz, clflg, rem;
250191783Srmacklem	char *cp, *tcp;
251191783Srmacklem
252209120Skib	KASSERT(uiop->uio_iovcnt == 1, ("nfsm_uiotombuf: iovcnt != 1"));
253191783Srmacklem
254191783Srmacklem	if (siz > ncl_mbuf_mlen)	/* or should it >= MCLBYTES ?? */
255191783Srmacklem		clflg = 1;
256191783Srmacklem	else
257191783Srmacklem		clflg = 0;
258191783Srmacklem	rem = NFSM_RNDUP(siz) - siz;
259191783Srmacklem	mp = mp2 = nd->nd_mb;
260191783Srmacklem	while (siz > 0) {
261191783Srmacklem		left = uiop->uio_iov->iov_len;
262191783Srmacklem		uiocp = uiop->uio_iov->iov_base;
263191783Srmacklem		if (left > siz)
264191783Srmacklem			left = siz;
265191783Srmacklem		uiosiz = left;
266191783Srmacklem		while (left > 0) {
267191783Srmacklem			mlen = M_TRAILINGSPACE(mp);
268191783Srmacklem			if (mlen == 0) {
269191783Srmacklem				if (clflg)
270243882Sglebius					NFSMCLGET(mp, M_WAITOK);
271191783Srmacklem				else
272191783Srmacklem					NFSMGET(mp);
273191783Srmacklem				mbuf_setlen(mp, 0);
274191783Srmacklem				mbuf_setnext(mp2, mp);
275191783Srmacklem				mp2 = mp;
276191783Srmacklem				mlen = M_TRAILINGSPACE(mp);
277191783Srmacklem			}
278191783Srmacklem			xfer = (left > mlen) ? mlen : left;
279191783Srmacklem#ifdef notdef
280191783Srmacklem			/* Not Yet.. */
281191783Srmacklem			if (uiop->uio_iov->iov_op != NULL)
282191783Srmacklem				(*(uiop->uio_iov->iov_op))
283191783Srmacklem				(uiocp, NFSMTOD(mp, caddr_t) + mbuf_len(mp),
284191783Srmacklem				    xfer);
285191783Srmacklem			else
286191783Srmacklem#endif
287191783Srmacklem			if (uiop->uio_segflg == UIO_SYSSPACE)
288191783Srmacklem			    NFSBCOPY(uiocp, NFSMTOD(mp, caddr_t) + mbuf_len(mp),
289191783Srmacklem				xfer);
290191783Srmacklem			else
291191783Srmacklem			    copyin(CAST_USER_ADDR_T(uiocp), NFSMTOD(mp, caddr_t)
292191783Srmacklem				+ mbuf_len(mp), xfer);
293191783Srmacklem			mbuf_setlen(mp, mbuf_len(mp) + xfer);
294191783Srmacklem			left -= xfer;
295191783Srmacklem			uiocp += xfer;
296191783Srmacklem			uiop->uio_offset += xfer;
297191783Srmacklem			uiop->uio_resid -= xfer;
298191783Srmacklem		}
299191783Srmacklem		tcp = (char *)uiop->uio_iov->iov_base;
300191783Srmacklem		tcp += uiosiz;
301191783Srmacklem		uiop->uio_iov->iov_base = (void *)tcp;
302191783Srmacklem		uiop->uio_iov->iov_len -= uiosiz;
303191783Srmacklem		siz -= uiosiz;
304191783Srmacklem	}
305191783Srmacklem	if (rem > 0) {
306191783Srmacklem		if (rem > M_TRAILINGSPACE(mp)) {
307191783Srmacklem			NFSMGET(mp);
308191783Srmacklem			mbuf_setlen(mp, 0);
309191783Srmacklem			mbuf_setnext(mp2, mp);
310191783Srmacklem		}
311191783Srmacklem		cp = NFSMTOD(mp, caddr_t) + mbuf_len(mp);
312191783Srmacklem		for (left = 0; left < rem; left++)
313191783Srmacklem			*cp++ = '\0';
314191783Srmacklem		mbuf_setlen(mp, mbuf_len(mp) + rem);
315191783Srmacklem		nd->nd_bpos = cp;
316191783Srmacklem	} else
317191783Srmacklem		nd->nd_bpos = NFSMTOD(mp, caddr_t) + mbuf_len(mp);
318191783Srmacklem	nd->nd_mb = mp;
319191783Srmacklem}
320191783Srmacklem#endif	/* !APPLE */
321191783Srmacklem
322191783Srmacklem/*
323191783Srmacklem * Load vnode attributes from the xdr file attributes.
324191783Srmacklem * Returns EBADRPC if they can't be parsed, 0 otherwise.
325191783Srmacklem */
326191783SrmacklemAPPLESTATIC int
327191783Srmacklemnfsm_loadattr(struct nfsrv_descript *nd, struct nfsvattr *nap)
328191783Srmacklem{
329191783Srmacklem	struct nfs_fattr *fp;
330191783Srmacklem	int error = 0;
331191783Srmacklem
332191783Srmacklem	if (nd->nd_flag & ND_NFSV4) {
333191783Srmacklem		error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0, NULL,
334191783Srmacklem		    NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL);
335191783Srmacklem	} else if (nd->nd_flag & ND_NFSV3) {
336191783Srmacklem		NFSM_DISSECT(fp, struct nfs_fattr *, NFSX_V3FATTR);
337191783Srmacklem		nap->na_type = nfsv34tov_type(fp->fa_type);
338191783Srmacklem		nap->na_mode = fxdr_unsigned(u_short, fp->fa_mode);
339191783Srmacklem		nap->na_rdev = makedev(fxdr_unsigned(u_char, fp->fa3_rdev.specdata1),
340191783Srmacklem			fxdr_unsigned(u_char, fp->fa3_rdev.specdata2));
341191783Srmacklem		nap->na_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
342191783Srmacklem		nap->na_uid = fxdr_unsigned(uid_t, fp->fa_uid);
343191783Srmacklem		nap->na_gid = fxdr_unsigned(gid_t, fp->fa_gid);
344191783Srmacklem		nap->na_size = fxdr_hyper(&fp->fa3_size);
345191783Srmacklem		nap->na_blocksize = NFS_FABLKSIZE;
346191783Srmacklem		nap->na_bytes = fxdr_hyper(&fp->fa3_used);
347220152Szack		nap->na_fileid = fxdr_hyper(&fp->fa3_fileid);
348191783Srmacklem		fxdr_nfsv3time(&fp->fa3_atime, &nap->na_atime);
349191783Srmacklem		fxdr_nfsv3time(&fp->fa3_ctime, &nap->na_ctime);
350191783Srmacklem		fxdr_nfsv3time(&fp->fa3_mtime, &nap->na_mtime);
351191783Srmacklem		nap->na_flags = 0;
352191783Srmacklem		nap->na_filerev = 0;
353191783Srmacklem	} else {
354191783Srmacklem		NFSM_DISSECT(fp, struct nfs_fattr *, NFSX_V2FATTR);
355191783Srmacklem		nap->na_type = nfsv2tov_type(fp->fa_type);
356191783Srmacklem		nap->na_mode = fxdr_unsigned(u_short, fp->fa_mode);
357191783Srmacklem		if (nap->na_type == VNON || nap->na_type == VREG)
358191783Srmacklem			nap->na_type = IFTOVT(nap->na_mode);
359191783Srmacklem		nap->na_rdev = fxdr_unsigned(dev_t, fp->fa2_rdev);
360191783Srmacklem
361191783Srmacklem		/*
362191783Srmacklem		 * Really ugly NFSv2 kludge.
363191783Srmacklem		 */
364191783Srmacklem		if (nap->na_type == VCHR && nap->na_rdev == ((dev_t)-1))
365191783Srmacklem			nap->na_type = VFIFO;
366191783Srmacklem		nap->na_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
367191783Srmacklem		nap->na_uid = fxdr_unsigned(uid_t, fp->fa_uid);
368191783Srmacklem		nap->na_gid = fxdr_unsigned(gid_t, fp->fa_gid);
369191783Srmacklem		nap->na_size = fxdr_unsigned(u_int32_t, fp->fa2_size);
370191783Srmacklem		nap->na_blocksize = fxdr_unsigned(int32_t, fp->fa2_blocksize);
371191783Srmacklem		nap->na_bytes =
372191783Srmacklem		    (u_quad_t)fxdr_unsigned(int32_t, fp->fa2_blocks) *
373191783Srmacklem		    NFS_FABLKSIZE;
374220152Szack		nap->na_fileid = fxdr_unsigned(uint64_t, fp->fa2_fileid);
375191783Srmacklem		fxdr_nfsv2time(&fp->fa2_atime, &nap->na_atime);
376191783Srmacklem		fxdr_nfsv2time(&fp->fa2_mtime, &nap->na_mtime);
377191783Srmacklem		nap->na_flags = 0;
378191783Srmacklem		nap->na_ctime.tv_sec = fxdr_unsigned(u_int32_t,
379191783Srmacklem		    fp->fa2_ctime.nfsv2_sec);
380191783Srmacklem		nap->na_ctime.tv_nsec = 0;
381191783Srmacklem		nap->na_gen = fxdr_unsigned(u_int32_t,fp->fa2_ctime.nfsv2_usec);
382191783Srmacklem		nap->na_filerev = 0;
383191783Srmacklem	}
384191783Srmacklemnfsmout:
385191783Srmacklem	return (error);
386191783Srmacklem}
387191783Srmacklem
388191783Srmacklem/*
389191783Srmacklem * This function finds the directory cookie that corresponds to the
390191783Srmacklem * logical byte offset given.
391191783Srmacklem */
392191783SrmacklemAPPLESTATIC nfsuint64 *
393191783Srmacklemnfscl_getcookie(struct nfsnode *np, off_t off, int add)
394191783Srmacklem{
395191783Srmacklem	struct nfsdmap *dp, *dp2;
396191783Srmacklem	int pos;
397191783Srmacklem
398191783Srmacklem	pos = off / NFS_DIRBLKSIZ;
399191783Srmacklem	if (pos == 0) {
400209120Skib		KASSERT(!add, ("nfs getcookie add at 0"));
401191783Srmacklem		return (&nfs_nullcookie);
402191783Srmacklem	}
403191783Srmacklem	pos--;
404191783Srmacklem	dp = LIST_FIRST(&np->n_cookies);
405191783Srmacklem	if (!dp) {
406191783Srmacklem		if (add) {
407191783Srmacklem			MALLOC(dp, struct nfsdmap *, sizeof (struct nfsdmap),
408191783Srmacklem				M_NFSDIROFF, M_WAITOK);
409191783Srmacklem			dp->ndm_eocookie = 0;
410191783Srmacklem			LIST_INSERT_HEAD(&np->n_cookies, dp, ndm_list);
411191783Srmacklem		} else
412191783Srmacklem			return (NULL);
413191783Srmacklem	}
414191783Srmacklem	while (pos >= NFSNUMCOOKIES) {
415191783Srmacklem		pos -= NFSNUMCOOKIES;
416191783Srmacklem		if (LIST_NEXT(dp, ndm_list) != NULL) {
417191783Srmacklem			if (!add && dp->ndm_eocookie < NFSNUMCOOKIES &&
418191783Srmacklem				pos >= dp->ndm_eocookie)
419191783Srmacklem				return (NULL);
420191783Srmacklem			dp = LIST_NEXT(dp, ndm_list);
421191783Srmacklem		} else if (add) {
422191783Srmacklem			MALLOC(dp2, struct nfsdmap *, sizeof (struct nfsdmap),
423191783Srmacklem				M_NFSDIROFF, M_WAITOK);
424191783Srmacklem			dp2->ndm_eocookie = 0;
425191783Srmacklem			LIST_INSERT_AFTER(dp, dp2, ndm_list);
426191783Srmacklem			dp = dp2;
427191783Srmacklem		} else
428191783Srmacklem			return (NULL);
429191783Srmacklem	}
430191783Srmacklem	if (pos >= dp->ndm_eocookie) {
431191783Srmacklem		if (add)
432191783Srmacklem			dp->ndm_eocookie = pos + 1;
433191783Srmacklem		else
434191783Srmacklem			return (NULL);
435191783Srmacklem	}
436191783Srmacklem	return (&dp->ndm_cookies[pos]);
437191783Srmacklem}
438191783Srmacklem
439191783Srmacklem/*
440191783Srmacklem * Gets a file handle out of an nfs reply sent to the client and returns
441191783Srmacklem * the file handle and the file's attributes.
442191783Srmacklem * For V4, it assumes that Getfh and Getattr Op's results are here.
443191783Srmacklem */
444191783SrmacklemAPPLESTATIC int
445191783Srmacklemnfscl_mtofh(struct nfsrv_descript *nd, struct nfsfh **nfhpp,
446191783Srmacklem    struct nfsvattr *nap, int *attrflagp)
447191783Srmacklem{
448191783Srmacklem	u_int32_t *tl;
449191783Srmacklem	int error = 0, flag = 1;
450191783Srmacklem
451191783Srmacklem	*nfhpp = NULL;
452191783Srmacklem	*attrflagp = 0;
453191783Srmacklem	/*
454191783Srmacklem	 * First get the file handle and vnode.
455191783Srmacklem	 */
456191783Srmacklem	if (nd->nd_flag & ND_NFSV3) {
457191783Srmacklem		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
458191783Srmacklem		flag = fxdr_unsigned(int, *tl);
459191783Srmacklem	} else if (nd->nd_flag & ND_NFSV4) {
460191783Srmacklem		NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
461191783Srmacklem	}
462191783Srmacklem	if (flag) {
463191783Srmacklem		error = nfsm_getfh(nd, nfhpp);
464191783Srmacklem		if (error)
465191783Srmacklem			return (error);
466191783Srmacklem	}
467191783Srmacklem
468191783Srmacklem	/*
469191783Srmacklem	 * Now, get the attributes.
470191783Srmacklem	 */
471191783Srmacklem	if (nd->nd_flag & ND_NFSV4) {
472191783Srmacklem		NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
473191783Srmacklem	} else if (nd->nd_flag & ND_NFSV3) {
474191783Srmacklem		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
475191783Srmacklem		if (flag) {
476191783Srmacklem			flag = fxdr_unsigned(int, *tl);
477191783Srmacklem		} else if (fxdr_unsigned(int, *tl)) {
478191783Srmacklem			error = nfsm_advance(nd, NFSX_V3FATTR, -1);
479191783Srmacklem			if (error)
480191783Srmacklem				return (error);
481191783Srmacklem		}
482191783Srmacklem	}
483191783Srmacklem	if (flag) {
484191783Srmacklem		error = nfsm_loadattr(nd, nap);
485191783Srmacklem		if (!error)
486191783Srmacklem			*attrflagp = 1;
487191783Srmacklem	}
488191783Srmacklemnfsmout:
489191783Srmacklem	return (error);
490191783Srmacklem}
491191783Srmacklem
492191783Srmacklem/*
493191783Srmacklem * Put a state Id in the mbuf list.
494191783Srmacklem */
495191783SrmacklemAPPLESTATIC void
496191783Srmacklemnfsm_stateidtom(struct nfsrv_descript *nd, nfsv4stateid_t *stateidp, int flag)
497191783Srmacklem{
498191783Srmacklem	nfsv4stateid_t *st;
499191783Srmacklem
500191783Srmacklem	NFSM_BUILD(st, nfsv4stateid_t *, NFSX_STATEID);
501191783Srmacklem	if (flag == NFSSTATEID_PUTALLZERO) {
502191783Srmacklem		st->seqid = 0;
503191783Srmacklem		st->other[0] = 0;
504191783Srmacklem		st->other[1] = 0;
505191783Srmacklem		st->other[2] = 0;
506191783Srmacklem	} else if (flag == NFSSTATEID_PUTALLONE) {
507191783Srmacklem		st->seqid = 0xffffffff;
508191783Srmacklem		st->other[0] = 0xffffffff;
509191783Srmacklem		st->other[1] = 0xffffffff;
510191783Srmacklem		st->other[2] = 0xffffffff;
511244042Srmacklem	} else if (flag == NFSSTATEID_PUTSEQIDZERO) {
512244042Srmacklem		st->seqid = 0;
513244042Srmacklem		st->other[0] = stateidp->other[0];
514244042Srmacklem		st->other[1] = stateidp->other[1];
515244042Srmacklem		st->other[2] = stateidp->other[2];
516191783Srmacklem	} else {
517191783Srmacklem		st->seqid = stateidp->seqid;
518191783Srmacklem		st->other[0] = stateidp->other[0];
519191783Srmacklem		st->other[1] = stateidp->other[1];
520191783Srmacklem		st->other[2] = stateidp->other[2];
521191783Srmacklem	}
522191783Srmacklem}
523191783Srmacklem
524191783Srmacklem/*
525191783Srmacklem * Initialize the owner/delegation sleep lock.
526191783Srmacklem */
527191783SrmacklemAPPLESTATIC void
528191783Srmacklemnfscl_lockinit(struct nfsv4lock *lckp)
529191783Srmacklem{
530191783Srmacklem
531191783Srmacklem	lckp->nfslock_usecnt = 0;
532191783Srmacklem	lckp->nfslock_lock = 0;
533191783Srmacklem}
534191783Srmacklem
535191783Srmacklem/*
536191783Srmacklem * Get an exclusive lock. (Not needed for OpenBSD4, since there is only one
537191783Srmacklem * thread for each posix process in the kernel.)
538191783Srmacklem */
539191783SrmacklemAPPLESTATIC void
540191783Srmacklemnfscl_lockexcl(struct nfsv4lock *lckp, void *mutex)
541191783Srmacklem{
542191783Srmacklem	int igotlock;
543191783Srmacklem
544191783Srmacklem	do {
545222389Srmacklem		igotlock = nfsv4_lock(lckp, 1, NULL, mutex, NULL);
546191783Srmacklem	} while (!igotlock);
547191783Srmacklem}
548191783Srmacklem
549191783Srmacklem/*
550191783Srmacklem * Release an exclusive lock.
551191783Srmacklem */
552191783SrmacklemAPPLESTATIC void
553191783Srmacklemnfscl_lockunlock(struct nfsv4lock *lckp)
554191783Srmacklem{
555191783Srmacklem
556191783Srmacklem	nfsv4_unlock(lckp, 0);
557191783Srmacklem}
558191783Srmacklem
559191783Srmacklem/*
560191783Srmacklem * Called to derefernce a lock on a stateid (delegation or open owner).
561191783Srmacklem */
562191783SrmacklemAPPLESTATIC void
563191783Srmacklemnfscl_lockderef(struct nfsv4lock *lckp)
564191783Srmacklem{
565191783Srmacklem
566191783Srmacklem	NFSLOCKCLSTATE();
567191783Srmacklem	lckp->nfslock_usecnt--;
568191783Srmacklem	if (lckp->nfslock_usecnt == 0 && (lckp->nfslock_lock & NFSV4LOCK_WANTED)) {
569191783Srmacklem		lckp->nfslock_lock &= ~NFSV4LOCK_WANTED;
570191783Srmacklem		wakeup((caddr_t)lckp);
571191783Srmacklem	}
572191783Srmacklem	NFSUNLOCKCLSTATE();
573191783Srmacklem}
574191783Srmacklem
575