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