xref: /netbsd/sys/fs/nfs/client/nfs_clcomsubs.c (revision 2d8a669f)
1 /*	$NetBSD: nfs_clcomsubs.c,v 1.4 2022/02/09 21:50:24 andvar Exp $	*/
2 /*-
3  * Copyright (c) 1989, 1993
4  *	The Regents of the University of California.  All rights reserved.
5  *
6  * This code is derived from software contributed to Berkeley by
7  * Rick Macklem at The University of Guelph.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  */
34 
35 #include <sys/cdefs.h>
36 /* __FBSDID("FreeBSD: head/sys/fs/nfsclient/nfs_clcomsubs.c 304026 2016-08-12 22:44:59Z rmacklem "); */
37 __RCSID("$NetBSD: nfs_clcomsubs.c,v 1.4 2022/02/09 21:50:24 andvar Exp $");
38 
39 /*
40  * These functions support the macros and help fiddle mbuf chains for
41  * the nfs op functions. They do things like create the rpc header and
42  * copy data between mbuf chains and uio lists.
43  */
44 #ifndef APPLEKEXT
45 #include <fs/nfs/common/nfsport.h>
46 
47 extern struct nfsstatsv1 nfsstatsv1;
48 extern struct nfsv4_opflag nfsv4_opflag[NFSV41_NOPS];
49 extern int ncl_mbuf_mlen;
50 extern enum vtype newnv2tov_type[8];
51 extern enum vtype nv34tov_type[8];
52 extern int	nfs_bigreply[NFSV41_NPROCS];
53 NFSCLSTATEMUTEX;
54 #endif	/* !APPLEKEXT */
55 
56 static nfsuint64 nfs_nullcookie = {{ 0, 0 }};
57 static struct {
58 	int	op;
59 	int	opcnt;
60 	const u_char *tag;
61 	int	taglen;
62 } nfsv4_opmap[NFSV41_NPROCS] = {
63 	{ 0, 1, "Null", 4 },
64 	{ NFSV4OP_GETATTR, 1, "Getattr", 7, },
65 	{ NFSV4OP_SETATTR, 2, "Setattr", 7, },
66 	{ NFSV4OP_LOOKUP, 3, "Lookup", 6, },
67 	{ NFSV4OP_ACCESS, 2, "Access", 6, },
68 	{ NFSV4OP_READLINK, 2, "Readlink", 8, },
69 	{ NFSV4OP_READ, 1, "Read", 4, },
70 	{ NFSV4OP_WRITE, 2, "Write", 5, },
71 	{ NFSV4OP_OPEN, 5, "Open", 4, },
72 	{ NFSV4OP_CREATE, 5, "Create", 6, },
73 	{ NFSV4OP_CREATE, 1, "Create", 6, },
74 	{ NFSV4OP_CREATE, 3, "Create", 6, },
75 	{ NFSV4OP_REMOVE, 1, "Remove", 6, },
76 	{ NFSV4OP_REMOVE, 1, "Remove", 6, },
77 	{ NFSV4OP_SAVEFH, 5, "Rename", 6, },
78 	{ NFSV4OP_SAVEFH, 4, "Link", 4, },
79 	{ NFSV4OP_READDIR, 2, "Readdir", 7, },
80 	{ NFSV4OP_READDIR, 2, "Readdir", 7, },
81 	{ NFSV4OP_GETATTR, 1, "Getattr", 7, },
82 	{ NFSV4OP_GETATTR, 1, "Getattr", 7, },
83 	{ NFSV4OP_GETATTR, 1, "Getattr", 7, },
84 	{ NFSV4OP_COMMIT, 2, "Commit", 6, },
85 	{ NFSV4OP_LOOKUPP, 3, "Lookupp", 7, },
86 	{ NFSV4OP_SETCLIENTID, 1, "SetClientID", 11, },
87 	{ NFSV4OP_SETCLIENTIDCFRM, 1, "SetClientIDConfirm", 18, },
88 	{ NFSV4OP_LOCK, 1, "Lock", 4, },
89 	{ NFSV4OP_LOCKU, 1, "LockU", 5, },
90 	{ NFSV4OP_OPEN, 2, "Open", 4, },
91 	{ NFSV4OP_CLOSE, 1, "Close", 5, },
92 	{ NFSV4OP_OPENCONFIRM, 1, "Openconfirm", 11, },
93 	{ NFSV4OP_LOCKT, 1, "LockT", 5, },
94 	{ NFSV4OP_OPENDOWNGRADE, 1, "Opendowngrade", 13, },
95 	{ NFSV4OP_RENEW, 1, "Renew", 5, },
96 	{ NFSV4OP_PUTROOTFH, 1, "Dirpath", 7, },
97 	{ NFSV4OP_RELEASELCKOWN, 1, "Rellckown", 9, },
98 	{ NFSV4OP_DELEGRETURN, 1, "Delegret", 8, },
99 	{ NFSV4OP_DELEGRETURN, 3, "DelegRemove", 11, },
100 	{ NFSV4OP_DELEGRETURN, 7, "DelegRename1", 12, },
101 	{ NFSV4OP_DELEGRETURN, 9, "DelegRename2", 12, },
102 	{ NFSV4OP_GETATTR, 1, "Getacl", 6, },
103 	{ NFSV4OP_SETATTR, 1, "Setacl", 6, },
104 	{ NFSV4OP_EXCHANGEID, 1, "ExchangeID", 10, },
105 	{ NFSV4OP_CREATESESSION, 1, "CreateSession", 13, },
106 	{ NFSV4OP_DESTROYSESSION, 1, "DestroySession", 14, },
107 	{ NFSV4OP_DESTROYCLIENTID, 1, "DestroyClient", 13, },
108 	{ NFSV4OP_FREESTATEID, 1, "FreeStateID", 11, },
109 	{ NFSV4OP_LAYOUTGET, 1, "LayoutGet", 9, },
110 	{ NFSV4OP_GETDEVINFO, 1, "GetDeviceInfo", 13, },
111 	{ NFSV4OP_LAYOUTCOMMIT, 1, "LayoutCommit", 12, },
112 	{ NFSV4OP_LAYOUTRETURN, 1, "LayoutReturn", 12, },
113 	{ NFSV4OP_RECLAIMCOMPL, 1, "ReclaimComplete", 15, },
114 	{ NFSV4OP_WRITE, 1, "WriteDS", 7, },
115 	{ NFSV4OP_READ, 1, "ReadDS", 6, },
116 	{ NFSV4OP_COMMIT, 1, "CommitDS", 8, },
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
126 };
127 
128 /*
129  * Start building a request. Mostly just put the first file handle in
130  * place.
131  */
132 APPLESTATIC void
nfscl_reqstart(struct nfsrv_descript * nd,int procnum,struct nfsmount * nmp,u_int8_t * nfhp,int fhlen,u_int32_t ** opcntpp,struct nfsclsession * sep)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 {
136 	struct mbuf *mb;
137 	u_int32_t *tl;
138 	int opcnt;
139 	nfsattrbit_t attrbits;
140 
141 	/*
142 	 * First, fill in some of the fields of nd.
143 	 */
144 	nd->nd_slotseq = NULL;
145 	if (NFSHASNFSV4(nmp)) {
146 		nd->nd_flag = ND_NFSV4 | ND_NFSCL;
147 		if (NFSHASNFSV4N(nmp))
148 			nd->nd_flag |= ND_NFSV41;
149 	} else if (NFSHASNFSV3(nmp))
150 		nd->nd_flag = ND_NFSV3 | ND_NFSCL;
151 	else
152 		nd->nd_flag = ND_NFSV2 | ND_NFSCL;
153 	nd->nd_procnum = procnum;
154 	nd->nd_repstat = 0;
155 
156 	/*
157 	 * Get the first mbuf for the request.
158 	 */
159 	if (nfs_bigrequest[procnum])
160 		NFSMCLGET(mb, M_WAITOK);
161 	else
162 		NFSMGET(mb);
163 	mbuf_setlen(mb, 0);
164 	nd->nd_mreq = nd->nd_mb = mb;
165 	nd->nd_bpos = NFSMTOD(mb, caddr_t);
166 
167 	/*
168 	 * And fill the first file handle into the request.
169 	 */
170 	if (nd->nd_flag & ND_NFSV4) {
171 		opcnt = nfsv4_opmap[procnum].opcnt +
172 		    nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh;
173 		if ((nd->nd_flag & ND_NFSV41) != 0) {
174 			opcnt += nfsv4_opflag[nfsv4_opmap[procnum].op].needsseq;
175 			if (procnum == NFSPROC_RENEW)
176 				/*
177 				 * For the special case of Renew, just do a
178 				 * Sequence Op.
179 				 */
180 				opcnt = 1;
181 			else if (procnum == NFSPROC_WRITEDS ||
182 			    procnum == NFSPROC_COMMITDS)
183 				/*
184 				 * For the special case of a Writeor Commit to
185 				 * a DS, the opcnt == 3, for Sequence, PutFH,
186 				 * Write/Commit.
187 				 */
188 				opcnt = 3;
189 		}
190 		/*
191 		 * What should the tag really be?
192 		 */
193 		(void) nfsm_strtom(nd, nfsv4_opmap[procnum].tag,
194 			nfsv4_opmap[procnum].taglen);
195 		NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
196 		if ((nd->nd_flag & ND_NFSV41) != 0)
197 			*tl++ = txdr_unsigned(NFSV41_MINORVERSION);
198 		else
199 			*tl++ = txdr_unsigned(NFSV4_MINORVERSION);
200 		if (opcntpp != NULL)
201 			*opcntpp = tl;
202 		*tl = txdr_unsigned(opcnt);
203 		if ((nd->nd_flag & ND_NFSV41) != 0 &&
204 		    nfsv4_opflag[nfsv4_opmap[procnum].op].needsseq > 0) {
205 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
206 			*tl = txdr_unsigned(NFSV4OP_SEQUENCE);
207 			if (sep == NULL)
208 				nfsv4_setsequence(nmp, nd,
209 				    NFSMNT_MDSSESSION(nmp),
210 				    nfs_bigreply[procnum]);
211 			else
212 				nfsv4_setsequence(nmp, nd, sep,
213 				    nfs_bigreply[procnum]);
214 		}
215 		if (nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh > 0) {
216 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
217 			*tl = txdr_unsigned(NFSV4OP_PUTFH);
218 			(void) nfsm_fhtom(nd, nfhp, fhlen, 0);
219 			if (nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh
220 			    == 2 && procnum != NFSPROC_WRITEDS &&
221 			    procnum != NFSPROC_COMMITDS) {
222 				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
223 				*tl = txdr_unsigned(NFSV4OP_GETATTR);
224 				/*
225 				 * For Lookup Ops, we want all the directory
226 				 * attributes, so we can load the name cache.
227 				 */
228 				if (procnum == NFSPROC_LOOKUP ||
229 				    procnum == NFSPROC_LOOKUPP)
230 					NFSGETATTR_ATTRBIT(&attrbits);
231 				else {
232 					NFSWCCATTR_ATTRBIT(&attrbits);
233 					nd->nd_flag |= ND_V4WCCATTR;
234 				}
235 				(void) nfsrv_putattrbit(nd, &attrbits);
236 			}
237 		}
238 		if (procnum != NFSPROC_RENEW ||
239 		    (nd->nd_flag & ND_NFSV41) == 0) {
240 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
241 			*tl = txdr_unsigned(nfsv4_opmap[procnum].op);
242 		}
243 	} else {
244 		(void) nfsm_fhtom(nd, nfhp, fhlen, 0);
245 	}
246 	if (procnum < NFSV41_NPROCS)
247 		NFSINCRGLOBAL(nfsstatsv1.rpccnt[procnum]);
248 }
249 
250 #ifndef APPLE
251 /*
252  * copies a uio scatter/gather list to an mbuf chain.
253  * NOTE: can only handle iovcnt == 1
254  */
255 APPLESTATIC void
nfsm_uiombuf(struct nfsrv_descript * nd,struct uio * uiop,int siz)256 nfsm_uiombuf(struct nfsrv_descript *nd, struct uio *uiop, int siz)
257 {
258 	char *uiocp;
259 	struct mbuf *mp, *mp2;
260 	int xfer, left, mlen;
261 	int uiosiz, clflg, rem;
262 	char *cp, *tcp;
263 
264 	KASSERT(uiop->uio_iovcnt == 1, ("nfsm_uiotombuf: iovcnt != 1"));
265 
266 	if (siz > ncl_mbuf_mlen)	/* or should it >= MCLBYTES ?? */
267 		clflg = 1;
268 	else
269 		clflg = 0;
270 	rem = NFSM_RNDUP(siz) - siz;
271 	mp = mp2 = nd->nd_mb;
272 	while (siz > 0) {
273 		left = uiop->uio_iov->iov_len;
274 		uiocp = uiop->uio_iov->iov_base;
275 		if (left > siz)
276 			left = siz;
277 		uiosiz = left;
278 		while (left > 0) {
279 			mlen = M_TRAILINGSPACE(mp);
280 			if (mlen == 0) {
281 				if (clflg)
282 					NFSMCLGET(mp, M_WAITOK);
283 				else
284 					NFSMGET(mp);
285 				mbuf_setlen(mp, 0);
286 				mbuf_setnext(mp2, mp);
287 				mp2 = mp;
288 				mlen = M_TRAILINGSPACE(mp);
289 			}
290 			xfer = (left > mlen) ? mlen : left;
291 #ifdef notdef
292 			/* Not Yet.. */
293 			if (uiop->uio_iov->iov_op != NULL)
294 				(*(uiop->uio_iov->iov_op))
295 				(uiocp, NFSMTOD(mp, caddr_t) + mbuf_len(mp),
296 				    xfer);
297 			else
298 #endif
299 			if (uiop->uio_segflg == UIO_SYSSPACE)
300 			    NFSBCOPY(uiocp, NFSMTOD(mp, caddr_t) + mbuf_len(mp),
301 				xfer);
302 			else
303 			    copyin(CAST_USER_ADDR_T(uiocp), NFSMTOD(mp, caddr_t)
304 				+ mbuf_len(mp), xfer);
305 			mbuf_setlen(mp, mbuf_len(mp) + xfer);
306 			left -= xfer;
307 			uiocp += xfer;
308 			uiop->uio_offset += xfer;
309 			uiop->uio_resid -= xfer;
310 		}
311 		tcp = (char *)uiop->uio_iov->iov_base;
312 		tcp += uiosiz;
313 		uiop->uio_iov->iov_base = (void *)tcp;
314 		uiop->uio_iov->iov_len -= uiosiz;
315 		siz -= uiosiz;
316 	}
317 	if (rem > 0) {
318 		if (rem > M_TRAILINGSPACE(mp)) {
319 			NFSMGET(mp);
320 			mbuf_setlen(mp, 0);
321 			mbuf_setnext(mp2, mp);
322 		}
323 		cp = NFSMTOD(mp, caddr_t) + mbuf_len(mp);
324 		for (left = 0; left < rem; left++)
325 			*cp++ = '\0';
326 		mbuf_setlen(mp, mbuf_len(mp) + rem);
327 		nd->nd_bpos = cp;
328 	} else
329 		nd->nd_bpos = NFSMTOD(mp, caddr_t) + mbuf_len(mp);
330 	nd->nd_mb = mp;
331 }
332 #endif	/* !APPLE */
333 
334 /*
335  * Load vnode attributes from the xdr file attributes.
336  * Returns EBADRPC if they can't be parsed, 0 otherwise.
337  */
338 APPLESTATIC int
nfsm_loadattr(struct nfsrv_descript * nd,struct nfsvattr * nap)339 nfsm_loadattr(struct nfsrv_descript *nd, struct nfsvattr *nap)
340 {
341 	struct nfs_fattr *fp;
342 	int error = 0;
343 
344 	if (nd->nd_flag & ND_NFSV4) {
345 		error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0, NULL,
346 		    NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL);
347 	} else if (nd->nd_flag & ND_NFSV3) {
348 		NFSM_DISSECT(fp, struct nfs_fattr *, NFSX_V3FATTR);
349 		nap->na_type = nfsv34tov_type(fp->fa_type);
350 		nap->na_mode = fxdr_unsigned(u_short, fp->fa_mode);
351 		nap->na_rdev = makedev(fxdr_unsigned(u_char, fp->fa3_rdev.specdata1),
352 			fxdr_unsigned(u_char, fp->fa3_rdev.specdata2));
353 		nap->na_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
354 		nap->na_uid = fxdr_unsigned(uid_t, fp->fa_uid);
355 		nap->na_gid = fxdr_unsigned(gid_t, fp->fa_gid);
356 		nap->na_size = fxdr_hyper(&fp->fa3_size);
357 		nap->na_blocksize = NFS_FABLKSIZE;
358 		nap->na_bytes = fxdr_hyper(&fp->fa3_used);
359 		nap->na_fileid = fxdr_hyper(&fp->fa3_fileid);
360 		fxdr_nfsv3time(&fp->fa3_atime, &nap->na_atime);
361 		fxdr_nfsv3time(&fp->fa3_ctime, &nap->na_ctime);
362 		fxdr_nfsv3time(&fp->fa3_mtime, &nap->na_mtime);
363 		nap->na_flags = 0;
364 		nap->na_filerev = 0;
365 	} else {
366 		NFSM_DISSECT(fp, struct nfs_fattr *, NFSX_V2FATTR);
367 		nap->na_type = nfsv2tov_type(fp->fa_type);
368 		nap->na_mode = fxdr_unsigned(u_short, fp->fa_mode);
369 		if (nap->na_type == VNON || nap->na_type == VREG)
370 			nap->na_type = IFTOVT(nap->na_mode);
371 		nap->na_rdev = fxdr_unsigned(dev_t, fp->fa2_rdev);
372 
373 		/*
374 		 * Really ugly NFSv2 kludge.
375 		 */
376 		if (nap->na_type == VCHR && nap->na_rdev == ((dev_t)-1))
377 			nap->na_type = VFIFO;
378 		nap->na_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
379 		nap->na_uid = fxdr_unsigned(uid_t, fp->fa_uid);
380 		nap->na_gid = fxdr_unsigned(gid_t, fp->fa_gid);
381 		nap->na_size = fxdr_unsigned(u_int32_t, fp->fa2_size);
382 		nap->na_blocksize = fxdr_unsigned(int32_t, fp->fa2_blocksize);
383 		nap->na_bytes =
384 		    (u_quad_t)fxdr_unsigned(int32_t, fp->fa2_blocks) *
385 		    NFS_FABLKSIZE;
386 		nap->na_fileid = fxdr_unsigned(uint64_t, fp->fa2_fileid);
387 		fxdr_nfsv2time(&fp->fa2_atime, &nap->na_atime);
388 		fxdr_nfsv2time(&fp->fa2_mtime, &nap->na_mtime);
389 		nap->na_flags = 0;
390 		nap->na_ctime.tv_sec = fxdr_unsigned(u_int32_t,
391 		    fp->fa2_ctime.nfsv2_sec);
392 		nap->na_ctime.tv_nsec = 0;
393 		nap->na_gen = fxdr_unsigned(u_int32_t,fp->fa2_ctime.nfsv2_usec);
394 		nap->na_filerev = 0;
395 	}
396 nfsmout:
397 	return (error);
398 }
399 
400 /*
401  * This function finds the directory cookie that corresponds to the
402  * logical byte offset given.
403  */
404 APPLESTATIC nfsuint64 *
nfscl_getcookie(struct nfsnode * np,off_t off,int add)405 nfscl_getcookie(struct nfsnode *np, off_t off, int add)
406 {
407 	struct nfsdmap *dp, *dp2;
408 	int pos;
409 
410 	pos = off / NFS_DIRBLKSIZ;
411 	if (pos == 0) {
412 		KASSERT(!add, ("nfs getcookie add at 0"));
413 		return (&nfs_nullcookie);
414 	}
415 	pos--;
416 	dp = LIST_FIRST(&np->n_cookies);
417 	if (!dp) {
418 		if (add) {
419 			MALLOC(dp, struct nfsdmap *, sizeof (struct nfsdmap),
420 				M_NFSDIROFF, M_WAITOK);
421 			dp->ndm_eocookie = 0;
422 			LIST_INSERT_HEAD(&np->n_cookies, dp, ndm_list);
423 		} else
424 			return (NULL);
425 	}
426 	while (pos >= NFSNUMCOOKIES) {
427 		pos -= NFSNUMCOOKIES;
428 		if (LIST_NEXT(dp, ndm_list) != NULL) {
429 			if (!add && dp->ndm_eocookie < NFSNUMCOOKIES &&
430 				pos >= dp->ndm_eocookie)
431 				return (NULL);
432 			dp = LIST_NEXT(dp, ndm_list);
433 		} else if (add) {
434 			MALLOC(dp2, struct nfsdmap *, sizeof (struct nfsdmap),
435 				M_NFSDIROFF, M_WAITOK);
436 			dp2->ndm_eocookie = 0;
437 			LIST_INSERT_AFTER(dp, dp2, ndm_list);
438 			dp = dp2;
439 		} else
440 			return (NULL);
441 	}
442 	if (pos >= dp->ndm_eocookie) {
443 		if (add)
444 			dp->ndm_eocookie = pos + 1;
445 		else
446 			return (NULL);
447 	}
448 	return (&dp->ndm_cookies[pos]);
449 }
450 
451 /*
452  * Gets a file handle out of an nfs reply sent to the client and returns
453  * the file handle and the file's attributes.
454  * For V4, it assumes that Getfh and Getattr Op's results are here.
455  */
456 APPLESTATIC int
nfscl_mtofh(struct nfsrv_descript * nd,struct nfsfh ** nfhpp,struct nfsvattr * nap,int * attrflagp)457 nfscl_mtofh(struct nfsrv_descript *nd, struct nfsfh **nfhpp,
458     struct nfsvattr *nap, int *attrflagp)
459 {
460 	u_int32_t *tl;
461 	int error = 0, flag = 1;
462 
463 	*nfhpp = NULL;
464 	*attrflagp = 0;
465 	/*
466 	 * First get the file handle and vnode.
467 	 */
468 	if (nd->nd_flag & ND_NFSV3) {
469 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
470 		flag = fxdr_unsigned(int, *tl);
471 	} else if (nd->nd_flag & ND_NFSV4) {
472 		NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
473 	}
474 	if (flag) {
475 		error = nfsm_getfh(nd, nfhpp);
476 		if (error)
477 			return (error);
478 	}
479 
480 	/*
481 	 * Now, get the attributes.
482 	 */
483 	if (nd->nd_flag & ND_NFSV4) {
484 		NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
485 	} else if (nd->nd_flag & ND_NFSV3) {
486 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
487 		if (flag) {
488 			flag = fxdr_unsigned(int, *tl);
489 		} else if (fxdr_unsigned(int, *tl)) {
490 			error = nfsm_advance(nd, NFSX_V3FATTR, -1);
491 			if (error)
492 				return (error);
493 		}
494 	}
495 	if (flag) {
496 		error = nfsm_loadattr(nd, nap);
497 		if (!error)
498 			*attrflagp = 1;
499 	}
500 nfsmout:
501 	return (error);
502 }
503 
504 /*
505  * Put a state Id in the mbuf list.
506  */
507 APPLESTATIC void
nfsm_stateidtom(struct nfsrv_descript * nd,nfsv4stateid_t * stateidp,int flag)508 nfsm_stateidtom(struct nfsrv_descript *nd, nfsv4stateid_t *stateidp, int flag)
509 {
510 	nfsv4stateid_t *st;
511 
512 	NFSM_BUILD(st, nfsv4stateid_t *, NFSX_STATEID);
513 	if (flag == NFSSTATEID_PUTALLZERO) {
514 		st->seqid = 0;
515 		st->other[0] = 0;
516 		st->other[1] = 0;
517 		st->other[2] = 0;
518 	} else if (flag == NFSSTATEID_PUTALLONE) {
519 		st->seqid = 0xffffffff;
520 		st->other[0] = 0xffffffff;
521 		st->other[1] = 0xffffffff;
522 		st->other[2] = 0xffffffff;
523 	} else if (flag == NFSSTATEID_PUTSEQIDZERO) {
524 		st->seqid = 0;
525 		st->other[0] = stateidp->other[0];
526 		st->other[1] = stateidp->other[1];
527 		st->other[2] = stateidp->other[2];
528 	} else {
529 		st->seqid = stateidp->seqid;
530 		st->other[0] = stateidp->other[0];
531 		st->other[1] = stateidp->other[1];
532 		st->other[2] = stateidp->other[2];
533 	}
534 }
535 
536 /*
537  * Initialize the owner/delegation sleep lock.
538  */
539 APPLESTATIC void
nfscl_lockinit(struct nfsv4lock * lckp)540 nfscl_lockinit(struct nfsv4lock *lckp)
541 {
542 
543 	lckp->nfslock_usecnt = 0;
544 	lckp->nfslock_lock = 0;
545 }
546 
547 /*
548  * Get an exclusive lock. (Not needed for OpenBSD4, since there is only one
549  * thread for each posix process in the kernel.)
550  */
551 APPLESTATIC void
nfscl_lockexcl(struct nfsv4lock * lckp,void * mutex)552 nfscl_lockexcl(struct nfsv4lock *lckp, void *mutex)
553 {
554 	int igotlock;
555 
556 	do {
557 		igotlock = nfsv4_lock(lckp, 1, NULL, mutex, NULL);
558 	} while (!igotlock);
559 }
560 
561 /*
562  * Release an exclusive lock.
563  */
564 APPLESTATIC void
nfscl_lockunlock(struct nfsv4lock * lckp)565 nfscl_lockunlock(struct nfsv4lock *lckp)
566 {
567 
568 	nfsv4_unlock(lckp, 0);
569 }
570 
571 /*
572  * Called to dereference a lock on a stateid (delegation or open owner).
573  */
574 APPLESTATIC void
nfscl_lockderef(struct nfsv4lock * lckp)575 nfscl_lockderef(struct nfsv4lock *lckp)
576 {
577 
578 	NFSLOCKCLSTATE();
579 	lckp->nfslock_usecnt--;
580 	if (lckp->nfslock_usecnt == 0 && (lckp->nfslock_lock & NFSV4LOCK_WANTED)) {
581 		lckp->nfslock_lock &= ~NFSV4LOCK_WANTED;
582 		wakeup((caddr_t)lckp);
583 	}
584 	NFSUNLOCKCLSTATE();
585 }
586 
587