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