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