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