xref: /freebsd/sys/fs/nfsclient/nfs_clcomsubs.c (revision 2a243b9539a45b392a515569cab2091844cf2bdf)
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  * 3. 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 
45 extern struct nfsstatsv1 nfsstatsv1;
46 extern struct nfsv4_opflag nfsv4_opflag[NFSV41_NOPS];
47 extern int ncl_mbuf_mlen;
48 extern enum vtype newnv2tov_type[8];
49 extern enum vtype nv34tov_type[8];
50 extern int	nfs_bigreply[NFSV41_NPROCS];
51 NFSCLSTATEMUTEX;
52 #endif	/* !APPLEKEXT */
53 
54 static nfsuint64 nfs_nullcookie = {{ 0, 0 }};
55 static 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, 5, "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 	{ NFSV4OP_OPEN, 3, "OpenLayoutGet", 13, },
116 	{ NFSV4OP_OPEN, 8, "CreateLayGet", 12, },
117 };
118 
119 /*
120  * NFS RPCS that have large request message size.
121  */
122 static int nfs_bigrequest[NFSV41_NPROCS] = {
123 	0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
124 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
125 	0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0
126 };
127 
128 /*
129  * Start building a request. Mostly just put the first file handle in
130  * place.
131  */
132 APPLESTATIC void
133 nfscl_reqstart(struct nfsrv_descript *nd, int procnum, struct nfsmount *nmp,
134     u_int8_t *nfhp, int fhlen, u_int32_t **opcntpp, struct nfsclsession *sep,
135     int vers, int minorvers)
136 {
137 	struct mbuf *mb;
138 	u_int32_t *tl;
139 	int opcnt;
140 	nfsattrbit_t attrbits;
141 
142 	/*
143 	 * First, fill in some of the fields of nd.
144 	 */
145 	nd->nd_slotseq = NULL;
146 	if (vers == NFS_VER4) {
147 		nd->nd_flag = ND_NFSV4 | ND_NFSCL;
148 		if (minorvers == NFSV41_MINORVERSION)
149 			nd->nd_flag |= ND_NFSV41;
150 	} else if (vers == NFS_VER3)
151 		nd->nd_flag = ND_NFSV3 | ND_NFSCL;
152 	else {
153 		if (NFSHASNFSV4(nmp)) {
154 			nd->nd_flag = ND_NFSV4 | ND_NFSCL;
155 			if (NFSHASNFSV4N(nmp))
156 				nd->nd_flag |= ND_NFSV41;
157 		} else if (NFSHASNFSV3(nmp))
158 			nd->nd_flag = ND_NFSV3 | ND_NFSCL;
159 		else
160 			nd->nd_flag = ND_NFSV2 | ND_NFSCL;
161 	}
162 	nd->nd_procnum = procnum;
163 	nd->nd_repstat = 0;
164 
165 	/*
166 	 * Get the first mbuf for the request.
167 	 */
168 	if (nfs_bigrequest[procnum])
169 		NFSMCLGET(mb, M_WAITOK);
170 	else
171 		NFSMGET(mb);
172 	mbuf_setlen(mb, 0);
173 	nd->nd_mreq = nd->nd_mb = mb;
174 	nd->nd_bpos = NFSMTOD(mb, caddr_t);
175 
176 	/*
177 	 * And fill the first file handle into the request.
178 	 */
179 	if (nd->nd_flag & ND_NFSV4) {
180 		opcnt = nfsv4_opmap[procnum].opcnt +
181 		    nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh;
182 		if ((nd->nd_flag & ND_NFSV41) != 0) {
183 			opcnt += nfsv4_opflag[nfsv4_opmap[procnum].op].needsseq;
184 			if (procnum == NFSPROC_RENEW)
185 				/*
186 				 * For the special case of Renew, just do a
187 				 * Sequence Op.
188 				 */
189 				opcnt = 1;
190 			else if (procnum == NFSPROC_WRITEDS ||
191 			    procnum == NFSPROC_COMMITDS)
192 				/*
193 				 * For the special case of a Writeor Commit to
194 				 * a DS, the opcnt == 3, for Sequence, PutFH,
195 				 * Write/Commit.
196 				 */
197 				opcnt = 3;
198 		}
199 		/*
200 		 * What should the tag really be?
201 		 */
202 		(void) nfsm_strtom(nd, nfsv4_opmap[procnum].tag,
203 			nfsv4_opmap[procnum].taglen);
204 		NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
205 		if ((nd->nd_flag & ND_NFSV41) != 0)
206 			*tl++ = txdr_unsigned(NFSV41_MINORVERSION);
207 		else
208 			*tl++ = txdr_unsigned(NFSV4_MINORVERSION);
209 		if (opcntpp != NULL)
210 			*opcntpp = tl;
211 		*tl = txdr_unsigned(opcnt);
212 		if ((nd->nd_flag & ND_NFSV41) != 0 &&
213 		    nfsv4_opflag[nfsv4_opmap[procnum].op].needsseq > 0) {
214 			if (nfsv4_opflag[nfsv4_opmap[procnum].op].loopbadsess >
215 			    0)
216 				nd->nd_flag |= ND_LOOPBADSESS;
217 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
218 			*tl = txdr_unsigned(NFSV4OP_SEQUENCE);
219 			if (sep == NULL) {
220 				sep = nfsmnt_mdssession(nmp);
221 				nfsv4_setsequence(nmp, nd, sep,
222 				    nfs_bigreply[procnum]);
223 			} else
224 				nfsv4_setsequence(nmp, nd, sep,
225 				    nfs_bigreply[procnum]);
226 		}
227 		if (nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh > 0) {
228 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
229 			*tl = txdr_unsigned(NFSV4OP_PUTFH);
230 			(void) nfsm_fhtom(nd, nfhp, fhlen, 0);
231 			if (nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh
232 			    == 2 && procnum != NFSPROC_WRITEDS &&
233 			    procnum != NFSPROC_COMMITDS) {
234 				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
235 				*tl = txdr_unsigned(NFSV4OP_GETATTR);
236 				/*
237 				 * For Lookup Ops, we want all the directory
238 				 * attributes, so we can load the name cache.
239 				 */
240 				if (procnum == NFSPROC_LOOKUP ||
241 				    procnum == NFSPROC_LOOKUPP)
242 					NFSGETATTR_ATTRBIT(&attrbits);
243 				else {
244 					NFSWCCATTR_ATTRBIT(&attrbits);
245 					nd->nd_flag |= ND_V4WCCATTR;
246 				}
247 				(void) nfsrv_putattrbit(nd, &attrbits);
248 			}
249 		}
250 		if (procnum != NFSPROC_RENEW ||
251 		    (nd->nd_flag & ND_NFSV41) == 0) {
252 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
253 			*tl = txdr_unsigned(nfsv4_opmap[procnum].op);
254 		}
255 	} else {
256 		(void) nfsm_fhtom(nd, nfhp, fhlen, 0);
257 	}
258 	if (procnum < NFSV41_NPROCS)
259 		NFSINCRGLOBAL(nfsstatsv1.rpccnt[procnum]);
260 }
261 
262 /*
263  * copies a uio scatter/gather list to an mbuf chain.
264  * NOTE: can ony handle iovcnt == 1
265  */
266 APPLESTATIC void
267 nfsm_uiombuf(struct nfsrv_descript *nd, struct uio *uiop, int siz)
268 {
269 	char *uiocp;
270 	struct mbuf *mp, *mp2;
271 	int xfer, left, mlen;
272 	int uiosiz, clflg, rem;
273 	char *cp, *tcp;
274 
275 	KASSERT(uiop->uio_iovcnt == 1, ("nfsm_uiotombuf: iovcnt != 1"));
276 
277 	if (siz > ncl_mbuf_mlen)	/* or should it >= MCLBYTES ?? */
278 		clflg = 1;
279 	else
280 		clflg = 0;
281 	rem = NFSM_RNDUP(siz) - siz;
282 	mp = mp2 = nd->nd_mb;
283 	while (siz > 0) {
284 		left = uiop->uio_iov->iov_len;
285 		uiocp = uiop->uio_iov->iov_base;
286 		if (left > siz)
287 			left = siz;
288 		uiosiz = left;
289 		while (left > 0) {
290 			mlen = M_TRAILINGSPACE(mp);
291 			if (mlen == 0) {
292 				if (clflg)
293 					NFSMCLGET(mp, M_WAITOK);
294 				else
295 					NFSMGET(mp);
296 				mbuf_setlen(mp, 0);
297 				mbuf_setnext(mp2, mp);
298 				mp2 = mp;
299 				mlen = M_TRAILINGSPACE(mp);
300 			}
301 			xfer = (left > mlen) ? mlen : left;
302 #ifdef notdef
303 			/* Not Yet.. */
304 			if (uiop->uio_iov->iov_op != NULL)
305 				(*(uiop->uio_iov->iov_op))
306 				(uiocp, NFSMTOD(mp, caddr_t) + mbuf_len(mp),
307 				    xfer);
308 			else
309 #endif
310 			if (uiop->uio_segflg == UIO_SYSSPACE)
311 			    NFSBCOPY(uiocp, NFSMTOD(mp, caddr_t) + mbuf_len(mp),
312 				xfer);
313 			else
314 			    copyin(CAST_USER_ADDR_T(uiocp), NFSMTOD(mp, caddr_t)
315 				+ mbuf_len(mp), xfer);
316 			mbuf_setlen(mp, mbuf_len(mp) + xfer);
317 			left -= xfer;
318 			uiocp += xfer;
319 			uiop->uio_offset += xfer;
320 			uiop->uio_resid -= xfer;
321 		}
322 		tcp = (char *)uiop->uio_iov->iov_base;
323 		tcp += uiosiz;
324 		uiop->uio_iov->iov_base = (void *)tcp;
325 		uiop->uio_iov->iov_len -= uiosiz;
326 		siz -= uiosiz;
327 	}
328 	if (rem > 0) {
329 		if (rem > M_TRAILINGSPACE(mp)) {
330 			NFSMGET(mp);
331 			mbuf_setlen(mp, 0);
332 			mbuf_setnext(mp2, mp);
333 		}
334 		cp = NFSMTOD(mp, caddr_t) + mbuf_len(mp);
335 		for (left = 0; left < rem; left++)
336 			*cp++ = '\0';
337 		mbuf_setlen(mp, mbuf_len(mp) + rem);
338 		nd->nd_bpos = cp;
339 	} else
340 		nd->nd_bpos = NFSMTOD(mp, caddr_t) + mbuf_len(mp);
341 	nd->nd_mb = mp;
342 }
343 
344 /*
345  * copies a uio scatter/gather list to an mbuf chain.
346  * This version returns the mbuf list and does not use "nd".
347  * NOTE: can ony handle iovcnt == 1
348  */
349 struct mbuf *
350 nfsm_uiombuflist(struct uio *uiop, int siz, struct mbuf **mbp, char **cpp)
351 {
352 	char *uiocp;
353 	struct mbuf *mp, *mp2, *firstmp;
354 	int xfer, left, mlen;
355 	int uiosiz, clflg, rem;
356 	char *tcp;
357 
358 	KASSERT(uiop->uio_iovcnt == 1, ("nfsm_uiotombuf: iovcnt != 1"));
359 
360 	if (siz > ncl_mbuf_mlen)	/* or should it >= MCLBYTES ?? */
361 		clflg = 1;
362 	else
363 		clflg = 0;
364 	rem = NFSM_RNDUP(siz) - siz;
365 	if (clflg != 0)
366 		NFSMCLGET(mp, M_WAITOK);
367 	else
368 		NFSMGET(mp);
369 	mbuf_setlen(mp, 0);
370 	firstmp = mp2 = mp;
371 	while (siz > 0) {
372 		left = uiop->uio_iov->iov_len;
373 		uiocp = uiop->uio_iov->iov_base;
374 		if (left > siz)
375 			left = siz;
376 		uiosiz = left;
377 		while (left > 0) {
378 			mlen = M_TRAILINGSPACE(mp);
379 			if (mlen == 0) {
380 				if (clflg)
381 					NFSMCLGET(mp, M_WAITOK);
382 				else
383 					NFSMGET(mp);
384 				mbuf_setlen(mp, 0);
385 				mbuf_setnext(mp2, mp);
386 				mp2 = mp;
387 				mlen = M_TRAILINGSPACE(mp);
388 			}
389 			xfer = (left > mlen) ? mlen : left;
390 			if (uiop->uio_segflg == UIO_SYSSPACE)
391 				NFSBCOPY(uiocp, NFSMTOD(mp, caddr_t) +
392 				    mbuf_len(mp), xfer);
393 			else
394 				copyin(uiocp, NFSMTOD(mp, caddr_t) +
395 				    mbuf_len(mp), xfer);
396 			mbuf_setlen(mp, mbuf_len(mp) + xfer);
397 			left -= xfer;
398 			uiocp += xfer;
399 			uiop->uio_offset += xfer;
400 			uiop->uio_resid -= xfer;
401 		}
402 		tcp = (char *)uiop->uio_iov->iov_base;
403 		tcp += uiosiz;
404 		uiop->uio_iov->iov_base = (void *)tcp;
405 		uiop->uio_iov->iov_len -= uiosiz;
406 		siz -= uiosiz;
407 	}
408 	if (cpp != NULL)
409 		*cpp = NFSMTOD(mp, caddr_t) + mbuf_len(mp);
410 	if (mbp != NULL)
411 		*mbp = mp;
412 	return (firstmp);
413 }
414 
415 /*
416  * Load vnode attributes from the xdr file attributes.
417  * Returns EBADRPC if they can't be parsed, 0 otherwise.
418  */
419 APPLESTATIC int
420 nfsm_loadattr(struct nfsrv_descript *nd, struct nfsvattr *nap)
421 {
422 	struct nfs_fattr *fp;
423 	int error = 0;
424 
425 	if (nd->nd_flag & ND_NFSV4) {
426 		error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0, NULL,
427 		    NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL);
428 	} else if (nd->nd_flag & ND_NFSV3) {
429 		NFSM_DISSECT(fp, struct nfs_fattr *, NFSX_V3FATTR);
430 		nap->na_type = nfsv34tov_type(fp->fa_type);
431 		nap->na_mode = fxdr_unsigned(u_short, fp->fa_mode);
432 		nap->na_rdev = makedev(fxdr_unsigned(u_char, fp->fa3_rdev.specdata1),
433 			fxdr_unsigned(u_char, fp->fa3_rdev.specdata2));
434 		nap->na_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
435 		nap->na_uid = fxdr_unsigned(uid_t, fp->fa_uid);
436 		nap->na_gid = fxdr_unsigned(gid_t, fp->fa_gid);
437 		nap->na_size = fxdr_hyper(&fp->fa3_size);
438 		nap->na_blocksize = NFS_FABLKSIZE;
439 		nap->na_bytes = fxdr_hyper(&fp->fa3_used);
440 		nap->na_fileid = fxdr_hyper(&fp->fa3_fileid);
441 		fxdr_nfsv3time(&fp->fa3_atime, &nap->na_atime);
442 		fxdr_nfsv3time(&fp->fa3_ctime, &nap->na_ctime);
443 		fxdr_nfsv3time(&fp->fa3_mtime, &nap->na_mtime);
444 		nap->na_flags = 0;
445 		nap->na_filerev = 0;
446 	} else {
447 		NFSM_DISSECT(fp, struct nfs_fattr *, NFSX_V2FATTR);
448 		nap->na_type = nfsv2tov_type(fp->fa_type);
449 		nap->na_mode = fxdr_unsigned(u_short, fp->fa_mode);
450 		if (nap->na_type == VNON || nap->na_type == VREG)
451 			nap->na_type = IFTOVT(nap->na_mode);
452 		nap->na_rdev = fxdr_unsigned(dev_t, fp->fa2_rdev);
453 
454 		/*
455 		 * Really ugly NFSv2 kludge.
456 		 */
457 		if (nap->na_type == VCHR && nap->na_rdev == ((dev_t)-1))
458 			nap->na_type = VFIFO;
459 		nap->na_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
460 		nap->na_uid = fxdr_unsigned(uid_t, fp->fa_uid);
461 		nap->na_gid = fxdr_unsigned(gid_t, fp->fa_gid);
462 		nap->na_size = fxdr_unsigned(u_int32_t, fp->fa2_size);
463 		nap->na_blocksize = fxdr_unsigned(int32_t, fp->fa2_blocksize);
464 		nap->na_bytes =
465 		    (u_quad_t)fxdr_unsigned(int32_t, fp->fa2_blocks) *
466 		    NFS_FABLKSIZE;
467 		nap->na_fileid = fxdr_unsigned(uint64_t, fp->fa2_fileid);
468 		fxdr_nfsv2time(&fp->fa2_atime, &nap->na_atime);
469 		fxdr_nfsv2time(&fp->fa2_mtime, &nap->na_mtime);
470 		nap->na_flags = 0;
471 		nap->na_ctime.tv_sec = fxdr_unsigned(u_int32_t,
472 		    fp->fa2_ctime.nfsv2_sec);
473 		nap->na_ctime.tv_nsec = 0;
474 		nap->na_gen = fxdr_unsigned(u_int32_t,fp->fa2_ctime.nfsv2_usec);
475 		nap->na_filerev = 0;
476 	}
477 nfsmout:
478 	return (error);
479 }
480 
481 /*
482  * This function finds the directory cookie that corresponds to the
483  * logical byte offset given.
484  */
485 APPLESTATIC nfsuint64 *
486 nfscl_getcookie(struct nfsnode *np, off_t off, int add)
487 {
488 	struct nfsdmap *dp, *dp2;
489 	int pos;
490 
491 	pos = off / NFS_DIRBLKSIZ;
492 	if (pos == 0) {
493 		KASSERT(!add, ("nfs getcookie add at 0"));
494 		return (&nfs_nullcookie);
495 	}
496 	pos--;
497 	dp = LIST_FIRST(&np->n_cookies);
498 	if (!dp) {
499 		if (add) {
500 			MALLOC(dp, struct nfsdmap *, sizeof (struct nfsdmap),
501 				M_NFSDIROFF, M_WAITOK);
502 			dp->ndm_eocookie = 0;
503 			LIST_INSERT_HEAD(&np->n_cookies, dp, ndm_list);
504 		} else
505 			return (NULL);
506 	}
507 	while (pos >= NFSNUMCOOKIES) {
508 		pos -= NFSNUMCOOKIES;
509 		if (LIST_NEXT(dp, ndm_list) != NULL) {
510 			if (!add && dp->ndm_eocookie < NFSNUMCOOKIES &&
511 				pos >= dp->ndm_eocookie)
512 				return (NULL);
513 			dp = LIST_NEXT(dp, ndm_list);
514 		} else if (add) {
515 			MALLOC(dp2, struct nfsdmap *, sizeof (struct nfsdmap),
516 				M_NFSDIROFF, M_WAITOK);
517 			dp2->ndm_eocookie = 0;
518 			LIST_INSERT_AFTER(dp, dp2, ndm_list);
519 			dp = dp2;
520 		} else
521 			return (NULL);
522 	}
523 	if (pos >= dp->ndm_eocookie) {
524 		if (add)
525 			dp->ndm_eocookie = pos + 1;
526 		else
527 			return (NULL);
528 	}
529 	return (&dp->ndm_cookies[pos]);
530 }
531 
532 /*
533  * Gets a file handle out of an nfs reply sent to the client and returns
534  * the file handle and the file's attributes.
535  * For V4, it assumes that Getfh and Getattr Op's results are here.
536  */
537 APPLESTATIC int
538 nfscl_mtofh(struct nfsrv_descript *nd, struct nfsfh **nfhpp,
539     struct nfsvattr *nap, int *attrflagp)
540 {
541 	u_int32_t *tl;
542 	int error = 0, flag = 1;
543 
544 	*nfhpp = NULL;
545 	*attrflagp = 0;
546 	/*
547 	 * First get the file handle and vnode.
548 	 */
549 	if (nd->nd_flag & ND_NFSV3) {
550 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
551 		flag = fxdr_unsigned(int, *tl);
552 	} else if (nd->nd_flag & ND_NFSV4) {
553 		NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
554 		/* If the GetFH failed, clear flag. */
555 		if (*++tl != 0) {
556 			nd->nd_flag |= ND_NOMOREDATA;
557 			flag = 0;
558 			error = ENXIO;	/* Return ENXIO so *nfhpp isn't used. */
559 		}
560 	}
561 	if (flag) {
562 		error = nfsm_getfh(nd, nfhpp);
563 		if (error)
564 			return (error);
565 	}
566 
567 	/*
568 	 * Now, get the attributes.
569 	 */
570 	if (flag != 0 && (nd->nd_flag & ND_NFSV4) != 0) {
571 		NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
572 		if (*++tl != 0) {
573 			nd->nd_flag |= ND_NOMOREDATA;
574 			flag = 0;
575 		}
576 	} else if (nd->nd_flag & ND_NFSV3) {
577 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
578 		if (flag) {
579 			flag = fxdr_unsigned(int, *tl);
580 		} else if (fxdr_unsigned(int, *tl)) {
581 			error = nfsm_advance(nd, NFSX_V3FATTR, -1);
582 			if (error)
583 				return (error);
584 		}
585 	}
586 	if (flag) {
587 		error = nfsm_loadattr(nd, nap);
588 		if (!error)
589 			*attrflagp = 1;
590 	}
591 nfsmout:
592 	return (error);
593 }
594 
595 /*
596  * Put a state Id in the mbuf list.
597  */
598 APPLESTATIC void
599 nfsm_stateidtom(struct nfsrv_descript *nd, nfsv4stateid_t *stateidp, int flag)
600 {
601 	nfsv4stateid_t *st;
602 
603 	NFSM_BUILD(st, nfsv4stateid_t *, NFSX_STATEID);
604 	if (flag == NFSSTATEID_PUTALLZERO) {
605 		st->seqid = 0;
606 		st->other[0] = 0;
607 		st->other[1] = 0;
608 		st->other[2] = 0;
609 	} else if (flag == NFSSTATEID_PUTALLONE) {
610 		st->seqid = 0xffffffff;
611 		st->other[0] = 0xffffffff;
612 		st->other[1] = 0xffffffff;
613 		st->other[2] = 0xffffffff;
614 	} else if (flag == NFSSTATEID_PUTSEQIDZERO) {
615 		st->seqid = 0;
616 		st->other[0] = stateidp->other[0];
617 		st->other[1] = stateidp->other[1];
618 		st->other[2] = stateidp->other[2];
619 	} else {
620 		st->seqid = stateidp->seqid;
621 		st->other[0] = stateidp->other[0];
622 		st->other[1] = stateidp->other[1];
623 		st->other[2] = stateidp->other[2];
624 	}
625 }
626 
627 /*
628  * Initialize the owner/delegation sleep lock.
629  */
630 APPLESTATIC void
631 nfscl_lockinit(struct nfsv4lock *lckp)
632 {
633 
634 	lckp->nfslock_usecnt = 0;
635 	lckp->nfslock_lock = 0;
636 }
637 
638 /*
639  * Get an exclusive lock. (Not needed for OpenBSD4, since there is only one
640  * thread for each posix process in the kernel.)
641  */
642 APPLESTATIC void
643 nfscl_lockexcl(struct nfsv4lock *lckp, void *mutex)
644 {
645 	int igotlock;
646 
647 	do {
648 		igotlock = nfsv4_lock(lckp, 1, NULL, mutex, NULL);
649 	} while (!igotlock);
650 }
651 
652 /*
653  * Release an exclusive lock.
654  */
655 APPLESTATIC void
656 nfscl_lockunlock(struct nfsv4lock *lckp)
657 {
658 
659 	nfsv4_unlock(lckp, 0);
660 }
661 
662 /*
663  * Called to derefernce a lock on a stateid (delegation or open owner).
664  */
665 APPLESTATIC void
666 nfscl_lockderef(struct nfsv4lock *lckp)
667 {
668 
669 	NFSLOCKCLSTATE();
670 	lckp->nfslock_usecnt--;
671 	if (lckp->nfslock_usecnt == 0 && (lckp->nfslock_lock & NFSV4LOCK_WANTED)) {
672 		lckp->nfslock_lock &= ~NFSV4LOCK_WANTED;
673 		wakeup((caddr_t)lckp);
674 	}
675 	NFSUNLOCKCLSTATE();
676 }
677 
678