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