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, rem; 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 rem = NFSM_RNDUP(siz) - siz; 367 if (clflg != 0) 368 NFSMCLGET(mp, M_WAITOK); 369 else 370 NFSMGET(mp); 371 mbuf_setlen(mp, 0); 372 firstmp = mp2 = mp; 373 while (siz > 0) { 374 left = uiop->uio_iov->iov_len; 375 uiocp = uiop->uio_iov->iov_base; 376 if (left > siz) 377 left = siz; 378 uiosiz = left; 379 while (left > 0) { 380 mlen = M_TRAILINGSPACE(mp); 381 if (mlen == 0) { 382 if (clflg) 383 NFSMCLGET(mp, M_WAITOK); 384 else 385 NFSMGET(mp); 386 mbuf_setlen(mp, 0); 387 mbuf_setnext(mp2, mp); 388 mp2 = mp; 389 mlen = M_TRAILINGSPACE(mp); 390 } 391 xfer = (left > mlen) ? mlen : left; 392 if (uiop->uio_segflg == UIO_SYSSPACE) 393 NFSBCOPY(uiocp, NFSMTOD(mp, caddr_t) + 394 mbuf_len(mp), xfer); 395 else 396 copyin(uiocp, NFSMTOD(mp, caddr_t) + 397 mbuf_len(mp), xfer); 398 mbuf_setlen(mp, mbuf_len(mp) + xfer); 399 left -= xfer; 400 uiocp += xfer; 401 uiop->uio_offset += xfer; 402 uiop->uio_resid -= xfer; 403 } 404 tcp = (char *)uiop->uio_iov->iov_base; 405 tcp += uiosiz; 406 uiop->uio_iov->iov_base = (void *)tcp; 407 uiop->uio_iov->iov_len -= uiosiz; 408 siz -= uiosiz; 409 } 410 if (cpp != NULL) 411 *cpp = NFSMTOD(mp, caddr_t) + mbuf_len(mp); 412 if (mbp != NULL) 413 *mbp = mp; 414 return (firstmp); 415 } 416 417 /* 418 * Load vnode attributes from the xdr file attributes. 419 * Returns EBADRPC if they can't be parsed, 0 otherwise. 420 */ 421 APPLESTATIC int 422 nfsm_loadattr(struct nfsrv_descript *nd, struct nfsvattr *nap) 423 { 424 struct nfs_fattr *fp; 425 int error = 0; 426 427 if (nd->nd_flag & ND_NFSV4) { 428 error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0, NULL, 429 NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL); 430 } else if (nd->nd_flag & ND_NFSV3) { 431 NFSM_DISSECT(fp, struct nfs_fattr *, NFSX_V3FATTR); 432 nap->na_type = nfsv34tov_type(fp->fa_type); 433 nap->na_mode = fxdr_unsigned(u_short, fp->fa_mode); 434 nap->na_rdev = makedev(fxdr_unsigned(u_char, fp->fa3_rdev.specdata1), 435 fxdr_unsigned(u_char, fp->fa3_rdev.specdata2)); 436 nap->na_nlink = fxdr_unsigned(uint32_t, fp->fa_nlink); 437 nap->na_uid = fxdr_unsigned(uid_t, fp->fa_uid); 438 nap->na_gid = fxdr_unsigned(gid_t, fp->fa_gid); 439 nap->na_size = fxdr_hyper(&fp->fa3_size); 440 nap->na_blocksize = NFS_FABLKSIZE; 441 nap->na_bytes = fxdr_hyper(&fp->fa3_used); 442 nap->na_fileid = fxdr_hyper(&fp->fa3_fileid); 443 fxdr_nfsv3time(&fp->fa3_atime, &nap->na_atime); 444 fxdr_nfsv3time(&fp->fa3_ctime, &nap->na_ctime); 445 fxdr_nfsv3time(&fp->fa3_mtime, &nap->na_mtime); 446 nap->na_flags = 0; 447 nap->na_filerev = 0; 448 } else { 449 NFSM_DISSECT(fp, struct nfs_fattr *, NFSX_V2FATTR); 450 nap->na_type = nfsv2tov_type(fp->fa_type); 451 nap->na_mode = fxdr_unsigned(u_short, fp->fa_mode); 452 if (nap->na_type == VNON || nap->na_type == VREG) 453 nap->na_type = IFTOVT(nap->na_mode); 454 nap->na_rdev = fxdr_unsigned(dev_t, fp->fa2_rdev); 455 456 /* 457 * Really ugly NFSv2 kludge. 458 */ 459 if (nap->na_type == VCHR && nap->na_rdev == ((dev_t)-1)) 460 nap->na_type = VFIFO; 461 nap->na_nlink = fxdr_unsigned(u_short, fp->fa_nlink); 462 nap->na_uid = fxdr_unsigned(uid_t, fp->fa_uid); 463 nap->na_gid = fxdr_unsigned(gid_t, fp->fa_gid); 464 nap->na_size = fxdr_unsigned(u_int32_t, fp->fa2_size); 465 nap->na_blocksize = fxdr_unsigned(int32_t, fp->fa2_blocksize); 466 nap->na_bytes = 467 (u_quad_t)fxdr_unsigned(int32_t, fp->fa2_blocks) * 468 NFS_FABLKSIZE; 469 nap->na_fileid = fxdr_unsigned(uint64_t, fp->fa2_fileid); 470 fxdr_nfsv2time(&fp->fa2_atime, &nap->na_atime); 471 fxdr_nfsv2time(&fp->fa2_mtime, &nap->na_mtime); 472 nap->na_flags = 0; 473 nap->na_ctime.tv_sec = fxdr_unsigned(u_int32_t, 474 fp->fa2_ctime.nfsv2_sec); 475 nap->na_ctime.tv_nsec = 0; 476 nap->na_gen = fxdr_unsigned(u_int32_t,fp->fa2_ctime.nfsv2_usec); 477 nap->na_filerev = 0; 478 } 479 nfsmout: 480 return (error); 481 } 482 483 /* 484 * This function finds the directory cookie that corresponds to the 485 * logical byte offset given. 486 */ 487 APPLESTATIC nfsuint64 * 488 nfscl_getcookie(struct nfsnode *np, off_t off, int add) 489 { 490 struct nfsdmap *dp, *dp2; 491 int pos; 492 493 pos = off / NFS_DIRBLKSIZ; 494 if (pos == 0) { 495 KASSERT(!add, ("nfs getcookie add at 0")); 496 return (&nfs_nullcookie); 497 } 498 pos--; 499 dp = LIST_FIRST(&np->n_cookies); 500 if (!dp) { 501 if (add) { 502 MALLOC(dp, struct nfsdmap *, sizeof (struct nfsdmap), 503 M_NFSDIROFF, M_WAITOK); 504 dp->ndm_eocookie = 0; 505 LIST_INSERT_HEAD(&np->n_cookies, dp, ndm_list); 506 } else 507 return (NULL); 508 } 509 while (pos >= NFSNUMCOOKIES) { 510 pos -= NFSNUMCOOKIES; 511 if (LIST_NEXT(dp, ndm_list) != NULL) { 512 if (!add && dp->ndm_eocookie < NFSNUMCOOKIES && 513 pos >= dp->ndm_eocookie) 514 return (NULL); 515 dp = LIST_NEXT(dp, ndm_list); 516 } else if (add) { 517 MALLOC(dp2, struct nfsdmap *, sizeof (struct nfsdmap), 518 M_NFSDIROFF, M_WAITOK); 519 dp2->ndm_eocookie = 0; 520 LIST_INSERT_AFTER(dp, dp2, ndm_list); 521 dp = dp2; 522 } else 523 return (NULL); 524 } 525 if (pos >= dp->ndm_eocookie) { 526 if (add) 527 dp->ndm_eocookie = pos + 1; 528 else 529 return (NULL); 530 } 531 return (&dp->ndm_cookies[pos]); 532 } 533 534 /* 535 * Gets a file handle out of an nfs reply sent to the client and returns 536 * the file handle and the file's attributes. 537 * For V4, it assumes that Getfh and Getattr Op's results are here. 538 */ 539 APPLESTATIC int 540 nfscl_mtofh(struct nfsrv_descript *nd, struct nfsfh **nfhpp, 541 struct nfsvattr *nap, int *attrflagp) 542 { 543 u_int32_t *tl; 544 int error = 0, flag = 1; 545 546 *nfhpp = NULL; 547 *attrflagp = 0; 548 /* 549 * First get the file handle and vnode. 550 */ 551 if (nd->nd_flag & ND_NFSV3) { 552 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 553 flag = fxdr_unsigned(int, *tl); 554 } else if (nd->nd_flag & ND_NFSV4) { 555 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 556 /* If the GetFH failed, clear flag. */ 557 if (*++tl != 0) { 558 nd->nd_flag |= ND_NOMOREDATA; 559 flag = 0; 560 error = ENXIO; /* Return ENXIO so *nfhpp isn't used. */ 561 } 562 } 563 if (flag) { 564 error = nfsm_getfh(nd, nfhpp); 565 if (error) 566 return (error); 567 } 568 569 /* 570 * Now, get the attributes. 571 */ 572 if (flag != 0 && (nd->nd_flag & ND_NFSV4) != 0) { 573 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 574 if (*++tl != 0) { 575 nd->nd_flag |= ND_NOMOREDATA; 576 flag = 0; 577 } 578 } else if (nd->nd_flag & ND_NFSV3) { 579 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 580 if (flag) { 581 flag = fxdr_unsigned(int, *tl); 582 } else if (fxdr_unsigned(int, *tl)) { 583 error = nfsm_advance(nd, NFSX_V3FATTR, -1); 584 if (error) 585 return (error); 586 } 587 } 588 if (flag) { 589 error = nfsm_loadattr(nd, nap); 590 if (!error) 591 *attrflagp = 1; 592 } 593 nfsmout: 594 return (error); 595 } 596 597 /* 598 * Put a state Id in the mbuf list. 599 */ 600 APPLESTATIC void 601 nfsm_stateidtom(struct nfsrv_descript *nd, nfsv4stateid_t *stateidp, int flag) 602 { 603 nfsv4stateid_t *st; 604 605 NFSM_BUILD(st, nfsv4stateid_t *, NFSX_STATEID); 606 if (flag == NFSSTATEID_PUTALLZERO) { 607 st->seqid = 0; 608 st->other[0] = 0; 609 st->other[1] = 0; 610 st->other[2] = 0; 611 } else if (flag == NFSSTATEID_PUTALLONE) { 612 st->seqid = 0xffffffff; 613 st->other[0] = 0xffffffff; 614 st->other[1] = 0xffffffff; 615 st->other[2] = 0xffffffff; 616 } else if (flag == NFSSTATEID_PUTSEQIDZERO) { 617 st->seqid = 0; 618 st->other[0] = stateidp->other[0]; 619 st->other[1] = stateidp->other[1]; 620 st->other[2] = stateidp->other[2]; 621 } else { 622 st->seqid = stateidp->seqid; 623 st->other[0] = stateidp->other[0]; 624 st->other[1] = stateidp->other[1]; 625 st->other[2] = stateidp->other[2]; 626 } 627 } 628 629 /* 630 * Initialize the owner/delegation sleep lock. 631 */ 632 APPLESTATIC void 633 nfscl_lockinit(struct nfsv4lock *lckp) 634 { 635 636 lckp->nfslock_usecnt = 0; 637 lckp->nfslock_lock = 0; 638 } 639 640 /* 641 * Get an exclusive lock. (Not needed for OpenBSD4, since there is only one 642 * thread for each posix process in the kernel.) 643 */ 644 APPLESTATIC void 645 nfscl_lockexcl(struct nfsv4lock *lckp, void *mutex) 646 { 647 int igotlock; 648 649 do { 650 igotlock = nfsv4_lock(lckp, 1, NULL, mutex, NULL); 651 } while (!igotlock); 652 } 653 654 /* 655 * Release an exclusive lock. 656 */ 657 APPLESTATIC void 658 nfscl_lockunlock(struct nfsv4lock *lckp) 659 { 660 661 nfsv4_unlock(lckp, 0); 662 } 663 664 /* 665 * Called to derefernce a lock on a stateid (delegation or open owner). 666 */ 667 APPLESTATIC void 668 nfscl_lockderef(struct nfsv4lock *lckp) 669 { 670 671 NFSLOCKCLSTATE(); 672 lckp->nfslock_usecnt--; 673 if (lckp->nfslock_usecnt == 0 && (lckp->nfslock_lock & NFSV4LOCK_WANTED)) { 674 lckp->nfslock_lock &= ~NFSV4LOCK_WANTED; 675 wakeup((caddr_t)lckp); 676 } 677 NFSUNLOCKCLSTATE(); 678 } 679 680