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