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 678