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