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 { 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 if (nfsv4_opflag[nfsv4_opmap[procnum].op].loopbadsess > 206 0) 207 nd->nd_flag |= ND_LOOPBADSESS; 208 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 209 *tl = txdr_unsigned(NFSV4OP_SEQUENCE); 210 if (sep == NULL) { 211 sep = nfsmnt_mdssession(nmp); 212 nfsv4_setsequence(nmp, nd, sep, 213 nfs_bigreply[procnum]); 214 } else 215 nfsv4_setsequence(nmp, nd, sep, 216 nfs_bigreply[procnum]); 217 } 218 if (nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh > 0) { 219 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 220 *tl = txdr_unsigned(NFSV4OP_PUTFH); 221 (void) nfsm_fhtom(nd, nfhp, fhlen, 0); 222 if (nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh 223 == 2 && procnum != NFSPROC_WRITEDS && 224 procnum != NFSPROC_COMMITDS) { 225 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 226 *tl = txdr_unsigned(NFSV4OP_GETATTR); 227 /* 228 * For Lookup Ops, we want all the directory 229 * attributes, so we can load the name cache. 230 */ 231 if (procnum == NFSPROC_LOOKUP || 232 procnum == NFSPROC_LOOKUPP) 233 NFSGETATTR_ATTRBIT(&attrbits); 234 else { 235 NFSWCCATTR_ATTRBIT(&attrbits); 236 nd->nd_flag |= ND_V4WCCATTR; 237 } 238 (void) nfsrv_putattrbit(nd, &attrbits); 239 } 240 } 241 if (procnum != NFSPROC_RENEW || 242 (nd->nd_flag & ND_NFSV41) == 0) { 243 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 244 *tl = txdr_unsigned(nfsv4_opmap[procnum].op); 245 } 246 } else { 247 (void) nfsm_fhtom(nd, nfhp, fhlen, 0); 248 } 249 if (procnum < NFSV41_NPROCS) 250 NFSINCRGLOBAL(nfsstatsv1.rpccnt[procnum]); 251 } 252 253 #ifndef APPLE 254 /* 255 * copies a uio scatter/gather list to an mbuf chain. 256 * NOTE: can ony handle iovcnt == 1 257 */ 258 APPLESTATIC void 259 nfsm_uiombuf(struct nfsrv_descript *nd, struct uio *uiop, int siz) 260 { 261 char *uiocp; 262 struct mbuf *mp, *mp2; 263 int xfer, left, mlen; 264 int uiosiz, clflg, rem; 265 char *cp, *tcp; 266 267 KASSERT(uiop->uio_iovcnt == 1, ("nfsm_uiotombuf: iovcnt != 1")); 268 269 if (siz > ncl_mbuf_mlen) /* or should it >= MCLBYTES ?? */ 270 clflg = 1; 271 else 272 clflg = 0; 273 rem = NFSM_RNDUP(siz) - siz; 274 mp = mp2 = nd->nd_mb; 275 while (siz > 0) { 276 left = uiop->uio_iov->iov_len; 277 uiocp = uiop->uio_iov->iov_base; 278 if (left > siz) 279 left = siz; 280 uiosiz = left; 281 while (left > 0) { 282 mlen = M_TRAILINGSPACE(mp); 283 if (mlen == 0) { 284 if (clflg) 285 NFSMCLGET(mp, M_WAITOK); 286 else 287 NFSMGET(mp); 288 mbuf_setlen(mp, 0); 289 mbuf_setnext(mp2, mp); 290 mp2 = mp; 291 mlen = M_TRAILINGSPACE(mp); 292 } 293 xfer = (left > mlen) ? mlen : left; 294 #ifdef notdef 295 /* Not Yet.. */ 296 if (uiop->uio_iov->iov_op != NULL) 297 (*(uiop->uio_iov->iov_op)) 298 (uiocp, NFSMTOD(mp, caddr_t) + mbuf_len(mp), 299 xfer); 300 else 301 #endif 302 if (uiop->uio_segflg == UIO_SYSSPACE) 303 NFSBCOPY(uiocp, NFSMTOD(mp, caddr_t) + mbuf_len(mp), 304 xfer); 305 else 306 copyin(CAST_USER_ADDR_T(uiocp), NFSMTOD(mp, caddr_t) 307 + mbuf_len(mp), xfer); 308 mbuf_setlen(mp, mbuf_len(mp) + xfer); 309 left -= xfer; 310 uiocp += xfer; 311 uiop->uio_offset += xfer; 312 uiop->uio_resid -= xfer; 313 } 314 tcp = (char *)uiop->uio_iov->iov_base; 315 tcp += uiosiz; 316 uiop->uio_iov->iov_base = (void *)tcp; 317 uiop->uio_iov->iov_len -= uiosiz; 318 siz -= uiosiz; 319 } 320 if (rem > 0) { 321 if (rem > M_TRAILINGSPACE(mp)) { 322 NFSMGET(mp); 323 mbuf_setlen(mp, 0); 324 mbuf_setnext(mp2, mp); 325 } 326 cp = NFSMTOD(mp, caddr_t) + mbuf_len(mp); 327 for (left = 0; left < rem; left++) 328 *cp++ = '\0'; 329 mbuf_setlen(mp, mbuf_len(mp) + rem); 330 nd->nd_bpos = cp; 331 } else 332 nd->nd_bpos = NFSMTOD(mp, caddr_t) + mbuf_len(mp); 333 nd->nd_mb = mp; 334 } 335 #endif /* !APPLE */ 336 337 /* 338 * Load vnode attributes from the xdr file attributes. 339 * Returns EBADRPC if they can't be parsed, 0 otherwise. 340 */ 341 APPLESTATIC int 342 nfsm_loadattr(struct nfsrv_descript *nd, struct nfsvattr *nap) 343 { 344 struct nfs_fattr *fp; 345 int error = 0; 346 347 if (nd->nd_flag & ND_NFSV4) { 348 error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0, NULL, 349 NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL); 350 } else if (nd->nd_flag & ND_NFSV3) { 351 NFSM_DISSECT(fp, struct nfs_fattr *, NFSX_V3FATTR); 352 nap->na_type = nfsv34tov_type(fp->fa_type); 353 nap->na_mode = fxdr_unsigned(u_short, fp->fa_mode); 354 nap->na_rdev = makedev(fxdr_unsigned(u_char, fp->fa3_rdev.specdata1), 355 fxdr_unsigned(u_char, fp->fa3_rdev.specdata2)); 356 nap->na_nlink = fxdr_unsigned(u_short, fp->fa_nlink); 357 nap->na_uid = fxdr_unsigned(uid_t, fp->fa_uid); 358 nap->na_gid = fxdr_unsigned(gid_t, fp->fa_gid); 359 nap->na_size = fxdr_hyper(&fp->fa3_size); 360 nap->na_blocksize = NFS_FABLKSIZE; 361 nap->na_bytes = fxdr_hyper(&fp->fa3_used); 362 nap->na_fileid = fxdr_hyper(&fp->fa3_fileid); 363 fxdr_nfsv3time(&fp->fa3_atime, &nap->na_atime); 364 fxdr_nfsv3time(&fp->fa3_ctime, &nap->na_ctime); 365 fxdr_nfsv3time(&fp->fa3_mtime, &nap->na_mtime); 366 nap->na_flags = 0; 367 nap->na_filerev = 0; 368 } else { 369 NFSM_DISSECT(fp, struct nfs_fattr *, NFSX_V2FATTR); 370 nap->na_type = nfsv2tov_type(fp->fa_type); 371 nap->na_mode = fxdr_unsigned(u_short, fp->fa_mode); 372 if (nap->na_type == VNON || nap->na_type == VREG) 373 nap->na_type = IFTOVT(nap->na_mode); 374 nap->na_rdev = fxdr_unsigned(dev_t, fp->fa2_rdev); 375 376 /* 377 * Really ugly NFSv2 kludge. 378 */ 379 if (nap->na_type == VCHR && nap->na_rdev == ((dev_t)-1)) 380 nap->na_type = VFIFO; 381 nap->na_nlink = fxdr_unsigned(u_short, fp->fa_nlink); 382 nap->na_uid = fxdr_unsigned(uid_t, fp->fa_uid); 383 nap->na_gid = fxdr_unsigned(gid_t, fp->fa_gid); 384 nap->na_size = fxdr_unsigned(u_int32_t, fp->fa2_size); 385 nap->na_blocksize = fxdr_unsigned(int32_t, fp->fa2_blocksize); 386 nap->na_bytes = 387 (u_quad_t)fxdr_unsigned(int32_t, fp->fa2_blocks) * 388 NFS_FABLKSIZE; 389 nap->na_fileid = fxdr_unsigned(uint64_t, fp->fa2_fileid); 390 fxdr_nfsv2time(&fp->fa2_atime, &nap->na_atime); 391 fxdr_nfsv2time(&fp->fa2_mtime, &nap->na_mtime); 392 nap->na_flags = 0; 393 nap->na_ctime.tv_sec = fxdr_unsigned(u_int32_t, 394 fp->fa2_ctime.nfsv2_sec); 395 nap->na_ctime.tv_nsec = 0; 396 nap->na_gen = fxdr_unsigned(u_int32_t,fp->fa2_ctime.nfsv2_usec); 397 nap->na_filerev = 0; 398 } 399 nfsmout: 400 return (error); 401 } 402 403 /* 404 * This function finds the directory cookie that corresponds to the 405 * logical byte offset given. 406 */ 407 APPLESTATIC nfsuint64 * 408 nfscl_getcookie(struct nfsnode *np, off_t off, int add) 409 { 410 struct nfsdmap *dp, *dp2; 411 int pos; 412 413 pos = off / NFS_DIRBLKSIZ; 414 if (pos == 0) { 415 KASSERT(!add, ("nfs getcookie add at 0")); 416 return (&nfs_nullcookie); 417 } 418 pos--; 419 dp = LIST_FIRST(&np->n_cookies); 420 if (!dp) { 421 if (add) { 422 MALLOC(dp, struct nfsdmap *, sizeof (struct nfsdmap), 423 M_NFSDIROFF, M_WAITOK); 424 dp->ndm_eocookie = 0; 425 LIST_INSERT_HEAD(&np->n_cookies, dp, ndm_list); 426 } else 427 return (NULL); 428 } 429 while (pos >= NFSNUMCOOKIES) { 430 pos -= NFSNUMCOOKIES; 431 if (LIST_NEXT(dp, ndm_list) != NULL) { 432 if (!add && dp->ndm_eocookie < NFSNUMCOOKIES && 433 pos >= dp->ndm_eocookie) 434 return (NULL); 435 dp = LIST_NEXT(dp, ndm_list); 436 } else if (add) { 437 MALLOC(dp2, struct nfsdmap *, sizeof (struct nfsdmap), 438 M_NFSDIROFF, M_WAITOK); 439 dp2->ndm_eocookie = 0; 440 LIST_INSERT_AFTER(dp, dp2, ndm_list); 441 dp = dp2; 442 } else 443 return (NULL); 444 } 445 if (pos >= dp->ndm_eocookie) { 446 if (add) 447 dp->ndm_eocookie = pos + 1; 448 else 449 return (NULL); 450 } 451 return (&dp->ndm_cookies[pos]); 452 } 453 454 /* 455 * Gets a file handle out of an nfs reply sent to the client and returns 456 * the file handle and the file's attributes. 457 * For V4, it assumes that Getfh and Getattr Op's results are here. 458 */ 459 APPLESTATIC int 460 nfscl_mtofh(struct nfsrv_descript *nd, struct nfsfh **nfhpp, 461 struct nfsvattr *nap, int *attrflagp) 462 { 463 u_int32_t *tl; 464 int error = 0, flag = 1; 465 466 *nfhpp = NULL; 467 *attrflagp = 0; 468 /* 469 * First get the file handle and vnode. 470 */ 471 if (nd->nd_flag & ND_NFSV3) { 472 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 473 flag = fxdr_unsigned(int, *tl); 474 } else if (nd->nd_flag & ND_NFSV4) { 475 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 476 /* If the GetFH failed, clear flag. */ 477 if (*++tl != 0) { 478 nd->nd_flag |= ND_NOMOREDATA; 479 flag = 0; 480 error = ENXIO; /* Return ENXIO so *nfhpp isn't used. */ 481 } 482 } 483 if (flag) { 484 error = nfsm_getfh(nd, nfhpp); 485 if (error) 486 return (error); 487 } 488 489 /* 490 * Now, get the attributes. 491 */ 492 if (flag != 0 && (nd->nd_flag & ND_NFSV4) != 0) { 493 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 494 if (*++tl != 0) { 495 nd->nd_flag |= ND_NOMOREDATA; 496 flag = 0; 497 } 498 } else if (nd->nd_flag & ND_NFSV3) { 499 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 500 if (flag) { 501 flag = fxdr_unsigned(int, *tl); 502 } else if (fxdr_unsigned(int, *tl)) { 503 error = nfsm_advance(nd, NFSX_V3FATTR, -1); 504 if (error) 505 return (error); 506 } 507 } 508 if (flag) { 509 error = nfsm_loadattr(nd, nap); 510 if (!error) 511 *attrflagp = 1; 512 } 513 nfsmout: 514 return (error); 515 } 516 517 /* 518 * Put a state Id in the mbuf list. 519 */ 520 APPLESTATIC void 521 nfsm_stateidtom(struct nfsrv_descript *nd, nfsv4stateid_t *stateidp, int flag) 522 { 523 nfsv4stateid_t *st; 524 525 NFSM_BUILD(st, nfsv4stateid_t *, NFSX_STATEID); 526 if (flag == NFSSTATEID_PUTALLZERO) { 527 st->seqid = 0; 528 st->other[0] = 0; 529 st->other[1] = 0; 530 st->other[2] = 0; 531 } else if (flag == NFSSTATEID_PUTALLONE) { 532 st->seqid = 0xffffffff; 533 st->other[0] = 0xffffffff; 534 st->other[1] = 0xffffffff; 535 st->other[2] = 0xffffffff; 536 } else if (flag == NFSSTATEID_PUTSEQIDZERO) { 537 st->seqid = 0; 538 st->other[0] = stateidp->other[0]; 539 st->other[1] = stateidp->other[1]; 540 st->other[2] = stateidp->other[2]; 541 } else { 542 st->seqid = stateidp->seqid; 543 st->other[0] = stateidp->other[0]; 544 st->other[1] = stateidp->other[1]; 545 st->other[2] = stateidp->other[2]; 546 } 547 } 548 549 /* 550 * Initialize the owner/delegation sleep lock. 551 */ 552 APPLESTATIC void 553 nfscl_lockinit(struct nfsv4lock *lckp) 554 { 555 556 lckp->nfslock_usecnt = 0; 557 lckp->nfslock_lock = 0; 558 } 559 560 /* 561 * Get an exclusive lock. (Not needed for OpenBSD4, since there is only one 562 * thread for each posix process in the kernel.) 563 */ 564 APPLESTATIC void 565 nfscl_lockexcl(struct nfsv4lock *lckp, void *mutex) 566 { 567 int igotlock; 568 569 do { 570 igotlock = nfsv4_lock(lckp, 1, NULL, mutex, NULL); 571 } while (!igotlock); 572 } 573 574 /* 575 * Release an exclusive lock. 576 */ 577 APPLESTATIC void 578 nfscl_lockunlock(struct nfsv4lock *lckp) 579 { 580 581 nfsv4_unlock(lckp, 0); 582 } 583 584 /* 585 * Called to derefernce a lock on a stateid (delegation or open owner). 586 */ 587 APPLESTATIC void 588 nfscl_lockderef(struct nfsv4lock *lckp) 589 { 590 591 NFSLOCKCLSTATE(); 592 lckp->nfslock_usecnt--; 593 if (lckp->nfslock_usecnt == 0 && (lckp->nfslock_lock & NFSV4LOCK_WANTED)) { 594 lckp->nfslock_lock &= ~NFSV4LOCK_WANTED; 595 wakeup((caddr_t)lckp); 596 } 597 NFSUNLOCKCLSTATE(); 598 } 599 600