1 /* $NetBSD: nfs_subs.c,v 1.148 2005/02/26 22:39:50 perry Exp $ */ 2 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 * @(#)nfs_subs.c 8.8 (Berkeley) 5/22/95 35 */ 36 37 /* 38 * Copyright 2000 Wasabi Systems, Inc. 39 * All rights reserved. 40 * 41 * Written by Frank van der Linden for Wasabi Systems, Inc. 42 * 43 * Redistribution and use in source and binary forms, with or without 44 * modification, are permitted provided that the following conditions 45 * are met: 46 * 1. Redistributions of source code must retain the above copyright 47 * notice, this list of conditions and the following disclaimer. 48 * 2. Redistributions in binary form must reproduce the above copyright 49 * notice, this list of conditions and the following disclaimer in the 50 * documentation and/or other materials provided with the distribution. 51 * 3. All advertising materials mentioning features or use of this software 52 * must display the following acknowledgement: 53 * This product includes software developed for the NetBSD Project by 54 * Wasabi Systems, Inc. 55 * 4. The name of Wasabi Systems, Inc. may not be used to endorse 56 * or promote products derived from this software without specific prior 57 * written permission. 58 * 59 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 60 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 61 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 62 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 63 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 64 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 65 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 66 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 67 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 68 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 69 * POSSIBILITY OF SUCH DAMAGE. 70 */ 71 72 #include <sys/cdefs.h> 73 __KERNEL_RCSID(0, "$NetBSD: nfs_subs.c,v 1.148 2005/02/26 22:39:50 perry Exp $"); 74 75 #include "fs_nfs.h" 76 #include "opt_nfs.h" 77 #include "opt_nfsserver.h" 78 #include "opt_iso.h" 79 #include "opt_inet.h" 80 81 /* 82 * These functions support the macros and help fiddle mbuf chains for 83 * the nfs op functions. They do things like create the rpc header and 84 * copy data between mbuf chains and uio lists. 85 */ 86 #include <sys/param.h> 87 #include <sys/proc.h> 88 #include <sys/systm.h> 89 #include <sys/kernel.h> 90 #include <sys/mount.h> 91 #include <sys/vnode.h> 92 #include <sys/namei.h> 93 #include <sys/mbuf.h> 94 #include <sys/socket.h> 95 #include <sys/stat.h> 96 #include <sys/malloc.h> 97 #include <sys/filedesc.h> 98 #include <sys/time.h> 99 #include <sys/dirent.h> 100 101 #include <uvm/uvm_extern.h> 102 103 #include <nfs/rpcv2.h> 104 #include <nfs/nfsproto.h> 105 #include <nfs/nfsnode.h> 106 #include <nfs/nfs.h> 107 #include <nfs/xdr_subs.h> 108 #include <nfs/nfsm_subs.h> 109 #include <nfs/nfsmount.h> 110 #include <nfs/nqnfs.h> 111 #include <nfs/nfsrtt.h> 112 #include <nfs/nfs_var.h> 113 114 #include <miscfs/specfs/specdev.h> 115 116 #include <netinet/in.h> 117 #ifdef ISO 118 #include <netiso/iso.h> 119 #endif 120 121 /* 122 * Data items converted to xdr at startup, since they are constant 123 * This is kinda hokey, but may save a little time doing byte swaps 124 */ 125 u_int32_t nfs_xdrneg1; 126 u_int32_t rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr, 127 rpc_mismatch, rpc_auth_unix, rpc_msgaccepted, 128 rpc_auth_kerb; 129 u_int32_t nfs_prog, nqnfs_prog, nfs_true, nfs_false; 130 131 /* And other global data */ 132 const nfstype nfsv2_type[9] = 133 { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFNON, NFCHR, NFNON }; 134 const nfstype nfsv3_type[9] = 135 { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK, NFFIFO, NFNON }; 136 const enum vtype nv2tov_type[8] = 137 { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON }; 138 const enum vtype nv3tov_type[8] = 139 { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO }; 140 int nfs_ticks; 141 int nfs_commitsize; 142 143 MALLOC_DEFINE(M_NFSDIROFF, "NFS diroff", "NFS directory cookies"); 144 145 /* NFS client/server stats. */ 146 struct nfsstats nfsstats; 147 148 /* 149 * Mapping of old NFS Version 2 RPC numbers to generic numbers. 150 */ 151 const int nfsv3_procid[NFS_NPROCS] = { 152 NFSPROC_NULL, 153 NFSPROC_GETATTR, 154 NFSPROC_SETATTR, 155 NFSPROC_NOOP, 156 NFSPROC_LOOKUP, 157 NFSPROC_READLINK, 158 NFSPROC_READ, 159 NFSPROC_NOOP, 160 NFSPROC_WRITE, 161 NFSPROC_CREATE, 162 NFSPROC_REMOVE, 163 NFSPROC_RENAME, 164 NFSPROC_LINK, 165 NFSPROC_SYMLINK, 166 NFSPROC_MKDIR, 167 NFSPROC_RMDIR, 168 NFSPROC_READDIR, 169 NFSPROC_FSSTAT, 170 NFSPROC_NOOP, 171 NFSPROC_NOOP, 172 NFSPROC_NOOP, 173 NFSPROC_NOOP, 174 NFSPROC_NOOP, 175 NFSPROC_NOOP, 176 NFSPROC_NOOP, 177 NFSPROC_NOOP 178 }; 179 180 /* 181 * and the reverse mapping from generic to Version 2 procedure numbers 182 */ 183 const int nfsv2_procid[NFS_NPROCS] = { 184 NFSV2PROC_NULL, 185 NFSV2PROC_GETATTR, 186 NFSV2PROC_SETATTR, 187 NFSV2PROC_LOOKUP, 188 NFSV2PROC_NOOP, 189 NFSV2PROC_READLINK, 190 NFSV2PROC_READ, 191 NFSV2PROC_WRITE, 192 NFSV2PROC_CREATE, 193 NFSV2PROC_MKDIR, 194 NFSV2PROC_SYMLINK, 195 NFSV2PROC_CREATE, 196 NFSV2PROC_REMOVE, 197 NFSV2PROC_RMDIR, 198 NFSV2PROC_RENAME, 199 NFSV2PROC_LINK, 200 NFSV2PROC_READDIR, 201 NFSV2PROC_NOOP, 202 NFSV2PROC_STATFS, 203 NFSV2PROC_NOOP, 204 NFSV2PROC_NOOP, 205 NFSV2PROC_NOOP, 206 NFSV2PROC_NOOP, 207 NFSV2PROC_NOOP, 208 NFSV2PROC_NOOP, 209 NFSV2PROC_NOOP, 210 }; 211 212 /* 213 * Maps errno values to nfs error numbers. 214 * Use NFSERR_IO as the catch all for ones not specifically defined in 215 * RFC 1094. 216 */ 217 static const u_char nfsrv_v2errmap[ELAST] = { 218 NFSERR_PERM, NFSERR_NOENT, NFSERR_IO, NFSERR_IO, NFSERR_IO, 219 NFSERR_NXIO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 220 NFSERR_IO, NFSERR_IO, NFSERR_ACCES, NFSERR_IO, NFSERR_IO, 221 NFSERR_IO, NFSERR_EXIST, NFSERR_IO, NFSERR_NODEV, NFSERR_NOTDIR, 222 NFSERR_ISDIR, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 223 NFSERR_IO, NFSERR_FBIG, NFSERR_NOSPC, NFSERR_IO, NFSERR_ROFS, 224 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 225 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 226 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 227 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 228 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 229 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 230 NFSERR_IO, NFSERR_IO, NFSERR_NAMETOL, NFSERR_IO, NFSERR_IO, 231 NFSERR_NOTEMPTY, NFSERR_IO, NFSERR_IO, NFSERR_DQUOT, NFSERR_STALE, 232 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 233 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 234 NFSERR_IO, NFSERR_IO, 235 }; 236 237 /* 238 * Maps errno values to nfs error numbers. 239 * Although it is not obvious whether or not NFS clients really care if 240 * a returned error value is in the specified list for the procedure, the 241 * safest thing to do is filter them appropriately. For Version 2, the 242 * X/Open XNFS document is the only specification that defines error values 243 * for each RPC (The RFC simply lists all possible error values for all RPCs), 244 * so I have decided to not do this for Version 2. 245 * The first entry is the default error return and the rest are the valid 246 * errors for that RPC in increasing numeric order. 247 */ 248 static const short nfsv3err_null[] = { 249 0, 250 0, 251 }; 252 253 static const short nfsv3err_getattr[] = { 254 NFSERR_IO, 255 NFSERR_IO, 256 NFSERR_STALE, 257 NFSERR_BADHANDLE, 258 NFSERR_SERVERFAULT, 259 0, 260 }; 261 262 static const short nfsv3err_setattr[] = { 263 NFSERR_IO, 264 NFSERR_PERM, 265 NFSERR_IO, 266 NFSERR_ACCES, 267 NFSERR_INVAL, 268 NFSERR_NOSPC, 269 NFSERR_ROFS, 270 NFSERR_DQUOT, 271 NFSERR_STALE, 272 NFSERR_BADHANDLE, 273 NFSERR_NOT_SYNC, 274 NFSERR_SERVERFAULT, 275 0, 276 }; 277 278 static const short nfsv3err_lookup[] = { 279 NFSERR_IO, 280 NFSERR_NOENT, 281 NFSERR_IO, 282 NFSERR_ACCES, 283 NFSERR_NOTDIR, 284 NFSERR_NAMETOL, 285 NFSERR_STALE, 286 NFSERR_BADHANDLE, 287 NFSERR_SERVERFAULT, 288 0, 289 }; 290 291 static const short nfsv3err_access[] = { 292 NFSERR_IO, 293 NFSERR_IO, 294 NFSERR_STALE, 295 NFSERR_BADHANDLE, 296 NFSERR_SERVERFAULT, 297 0, 298 }; 299 300 static const short nfsv3err_readlink[] = { 301 NFSERR_IO, 302 NFSERR_IO, 303 NFSERR_ACCES, 304 NFSERR_INVAL, 305 NFSERR_STALE, 306 NFSERR_BADHANDLE, 307 NFSERR_NOTSUPP, 308 NFSERR_SERVERFAULT, 309 0, 310 }; 311 312 static const short nfsv3err_read[] = { 313 NFSERR_IO, 314 NFSERR_IO, 315 NFSERR_NXIO, 316 NFSERR_ACCES, 317 NFSERR_INVAL, 318 NFSERR_STALE, 319 NFSERR_BADHANDLE, 320 NFSERR_SERVERFAULT, 321 NFSERR_JUKEBOX, 322 0, 323 }; 324 325 static const short nfsv3err_write[] = { 326 NFSERR_IO, 327 NFSERR_IO, 328 NFSERR_ACCES, 329 NFSERR_INVAL, 330 NFSERR_FBIG, 331 NFSERR_NOSPC, 332 NFSERR_ROFS, 333 NFSERR_DQUOT, 334 NFSERR_STALE, 335 NFSERR_BADHANDLE, 336 NFSERR_SERVERFAULT, 337 NFSERR_JUKEBOX, 338 0, 339 }; 340 341 static const short nfsv3err_create[] = { 342 NFSERR_IO, 343 NFSERR_IO, 344 NFSERR_ACCES, 345 NFSERR_EXIST, 346 NFSERR_NOTDIR, 347 NFSERR_NOSPC, 348 NFSERR_ROFS, 349 NFSERR_NAMETOL, 350 NFSERR_DQUOT, 351 NFSERR_STALE, 352 NFSERR_BADHANDLE, 353 NFSERR_NOTSUPP, 354 NFSERR_SERVERFAULT, 355 0, 356 }; 357 358 static const short nfsv3err_mkdir[] = { 359 NFSERR_IO, 360 NFSERR_IO, 361 NFSERR_ACCES, 362 NFSERR_EXIST, 363 NFSERR_NOTDIR, 364 NFSERR_NOSPC, 365 NFSERR_ROFS, 366 NFSERR_NAMETOL, 367 NFSERR_DQUOT, 368 NFSERR_STALE, 369 NFSERR_BADHANDLE, 370 NFSERR_NOTSUPP, 371 NFSERR_SERVERFAULT, 372 0, 373 }; 374 375 static const short nfsv3err_symlink[] = { 376 NFSERR_IO, 377 NFSERR_IO, 378 NFSERR_ACCES, 379 NFSERR_EXIST, 380 NFSERR_NOTDIR, 381 NFSERR_NOSPC, 382 NFSERR_ROFS, 383 NFSERR_NAMETOL, 384 NFSERR_DQUOT, 385 NFSERR_STALE, 386 NFSERR_BADHANDLE, 387 NFSERR_NOTSUPP, 388 NFSERR_SERVERFAULT, 389 0, 390 }; 391 392 static const short nfsv3err_mknod[] = { 393 NFSERR_IO, 394 NFSERR_IO, 395 NFSERR_ACCES, 396 NFSERR_EXIST, 397 NFSERR_NOTDIR, 398 NFSERR_NOSPC, 399 NFSERR_ROFS, 400 NFSERR_NAMETOL, 401 NFSERR_DQUOT, 402 NFSERR_STALE, 403 NFSERR_BADHANDLE, 404 NFSERR_NOTSUPP, 405 NFSERR_SERVERFAULT, 406 NFSERR_BADTYPE, 407 0, 408 }; 409 410 static const short nfsv3err_remove[] = { 411 NFSERR_IO, 412 NFSERR_NOENT, 413 NFSERR_IO, 414 NFSERR_ACCES, 415 NFSERR_NOTDIR, 416 NFSERR_ROFS, 417 NFSERR_NAMETOL, 418 NFSERR_STALE, 419 NFSERR_BADHANDLE, 420 NFSERR_SERVERFAULT, 421 0, 422 }; 423 424 static const short nfsv3err_rmdir[] = { 425 NFSERR_IO, 426 NFSERR_NOENT, 427 NFSERR_IO, 428 NFSERR_ACCES, 429 NFSERR_EXIST, 430 NFSERR_NOTDIR, 431 NFSERR_INVAL, 432 NFSERR_ROFS, 433 NFSERR_NAMETOL, 434 NFSERR_NOTEMPTY, 435 NFSERR_STALE, 436 NFSERR_BADHANDLE, 437 NFSERR_NOTSUPP, 438 NFSERR_SERVERFAULT, 439 0, 440 }; 441 442 static const short nfsv3err_rename[] = { 443 NFSERR_IO, 444 NFSERR_NOENT, 445 NFSERR_IO, 446 NFSERR_ACCES, 447 NFSERR_EXIST, 448 NFSERR_XDEV, 449 NFSERR_NOTDIR, 450 NFSERR_ISDIR, 451 NFSERR_INVAL, 452 NFSERR_NOSPC, 453 NFSERR_ROFS, 454 NFSERR_MLINK, 455 NFSERR_NAMETOL, 456 NFSERR_NOTEMPTY, 457 NFSERR_DQUOT, 458 NFSERR_STALE, 459 NFSERR_BADHANDLE, 460 NFSERR_NOTSUPP, 461 NFSERR_SERVERFAULT, 462 0, 463 }; 464 465 static const short nfsv3err_link[] = { 466 NFSERR_IO, 467 NFSERR_IO, 468 NFSERR_ACCES, 469 NFSERR_EXIST, 470 NFSERR_XDEV, 471 NFSERR_NOTDIR, 472 NFSERR_INVAL, 473 NFSERR_NOSPC, 474 NFSERR_ROFS, 475 NFSERR_MLINK, 476 NFSERR_NAMETOL, 477 NFSERR_DQUOT, 478 NFSERR_STALE, 479 NFSERR_BADHANDLE, 480 NFSERR_NOTSUPP, 481 NFSERR_SERVERFAULT, 482 0, 483 }; 484 485 static const short nfsv3err_readdir[] = { 486 NFSERR_IO, 487 NFSERR_IO, 488 NFSERR_ACCES, 489 NFSERR_NOTDIR, 490 NFSERR_STALE, 491 NFSERR_BADHANDLE, 492 NFSERR_BAD_COOKIE, 493 NFSERR_TOOSMALL, 494 NFSERR_SERVERFAULT, 495 0, 496 }; 497 498 static const short nfsv3err_readdirplus[] = { 499 NFSERR_IO, 500 NFSERR_IO, 501 NFSERR_ACCES, 502 NFSERR_NOTDIR, 503 NFSERR_STALE, 504 NFSERR_BADHANDLE, 505 NFSERR_BAD_COOKIE, 506 NFSERR_NOTSUPP, 507 NFSERR_TOOSMALL, 508 NFSERR_SERVERFAULT, 509 0, 510 }; 511 512 static const short nfsv3err_fsstat[] = { 513 NFSERR_IO, 514 NFSERR_IO, 515 NFSERR_STALE, 516 NFSERR_BADHANDLE, 517 NFSERR_SERVERFAULT, 518 0, 519 }; 520 521 static const short nfsv3err_fsinfo[] = { 522 NFSERR_STALE, 523 NFSERR_STALE, 524 NFSERR_BADHANDLE, 525 NFSERR_SERVERFAULT, 526 0, 527 }; 528 529 static const short nfsv3err_pathconf[] = { 530 NFSERR_STALE, 531 NFSERR_STALE, 532 NFSERR_BADHANDLE, 533 NFSERR_SERVERFAULT, 534 0, 535 }; 536 537 static const short nfsv3err_commit[] = { 538 NFSERR_IO, 539 NFSERR_IO, 540 NFSERR_STALE, 541 NFSERR_BADHANDLE, 542 NFSERR_SERVERFAULT, 543 0, 544 }; 545 546 static const short * const nfsrv_v3errmap[] = { 547 nfsv3err_null, 548 nfsv3err_getattr, 549 nfsv3err_setattr, 550 nfsv3err_lookup, 551 nfsv3err_access, 552 nfsv3err_readlink, 553 nfsv3err_read, 554 nfsv3err_write, 555 nfsv3err_create, 556 nfsv3err_mkdir, 557 nfsv3err_symlink, 558 nfsv3err_mknod, 559 nfsv3err_remove, 560 nfsv3err_rmdir, 561 nfsv3err_rename, 562 nfsv3err_link, 563 nfsv3err_readdir, 564 nfsv3err_readdirplus, 565 nfsv3err_fsstat, 566 nfsv3err_fsinfo, 567 nfsv3err_pathconf, 568 nfsv3err_commit, 569 }; 570 571 extern struct nfsrtt nfsrtt; 572 extern time_t nqnfsstarttime; 573 extern int nqsrv_clockskew; 574 extern int nqsrv_writeslack; 575 extern int nqsrv_maxlease; 576 extern const int nqnfs_piggy[NFS_NPROCS]; 577 extern struct nfsnodehashhead *nfsnodehashtbl; 578 extern u_long nfsnodehash; 579 580 u_long nfsdirhashmask; 581 582 int nfs_webnamei __P((struct nameidata *, struct vnode *, struct proc *)); 583 584 /* 585 * Create the header for an rpc request packet 586 * The hsiz is the size of the rest of the nfs request header. 587 * (just used to decide if a cluster is a good idea) 588 */ 589 struct mbuf * 590 nfsm_reqh(np, procid, hsiz, bposp) 591 struct nfsnode *np; 592 u_long procid; 593 int hsiz; 594 caddr_t *bposp; 595 { 596 struct mbuf *mb; 597 caddr_t bpos; 598 #ifndef NFS_V2_ONLY 599 struct nfsmount *nmp; 600 u_int32_t *tl; 601 int nqflag; 602 #endif 603 604 mb = m_get(M_WAIT, MT_DATA); 605 MCLAIM(mb, &nfs_mowner); 606 if (hsiz >= MINCLSIZE) 607 m_clget(mb, M_WAIT); 608 mb->m_len = 0; 609 bpos = mtod(mb, caddr_t); 610 611 #ifndef NFS_V2_ONLY 612 /* 613 * For NQNFS, add lease request. 614 */ 615 if (np) { 616 nmp = VFSTONFS(np->n_vnode->v_mount); 617 if (nmp->nm_flag & NFSMNT_NQNFS) { 618 nqflag = NQNFS_NEEDLEASE(np, procid); 619 if (nqflag) { 620 nfsm_build(tl, u_int32_t *, 2*NFSX_UNSIGNED); 621 *tl++ = txdr_unsigned(nqflag); 622 *tl = txdr_unsigned(nmp->nm_leaseterm); 623 } else { 624 nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); 625 *tl = 0; 626 } 627 } 628 } 629 #endif 630 /* Finally, return values */ 631 *bposp = bpos; 632 return (mb); 633 } 634 635 /* 636 * Build the RPC header and fill in the authorization info. 637 * The authorization string argument is only used when the credentials 638 * come from outside of the kernel. 639 * Returns the head of the mbuf list. 640 */ 641 struct mbuf * 642 nfsm_rpchead(cr, nmflag, procid, auth_type, auth_len, auth_str, verf_len, 643 verf_str, mrest, mrest_len, mbp, xidp) 644 struct ucred *cr; 645 int nmflag; 646 int procid; 647 int auth_type; 648 int auth_len; 649 char *auth_str; 650 int verf_len; 651 char *verf_str; 652 struct mbuf *mrest; 653 int mrest_len; 654 struct mbuf **mbp; 655 u_int32_t *xidp; 656 { 657 struct mbuf *mb; 658 u_int32_t *tl; 659 caddr_t bpos; 660 int i; 661 struct mbuf *mreq; 662 int siz, grpsiz, authsiz; 663 664 authsiz = nfsm_rndup(auth_len); 665 mb = m_gethdr(M_WAIT, MT_DATA); 666 MCLAIM(mb, &nfs_mowner); 667 if ((authsiz + 10 * NFSX_UNSIGNED) >= MINCLSIZE) { 668 m_clget(mb, M_WAIT); 669 } else if ((authsiz + 10 * NFSX_UNSIGNED) < MHLEN) { 670 MH_ALIGN(mb, authsiz + 10 * NFSX_UNSIGNED); 671 } else { 672 MH_ALIGN(mb, 8 * NFSX_UNSIGNED); 673 } 674 mb->m_len = 0; 675 mreq = mb; 676 bpos = mtod(mb, caddr_t); 677 678 /* 679 * First the RPC header. 680 */ 681 nfsm_build(tl, u_int32_t *, 8 * NFSX_UNSIGNED); 682 683 *tl++ = *xidp = nfs_getxid(); 684 *tl++ = rpc_call; 685 *tl++ = rpc_vers; 686 if (nmflag & NFSMNT_NQNFS) { 687 *tl++ = txdr_unsigned(NQNFS_PROG); 688 *tl++ = txdr_unsigned(NQNFS_VER3); 689 } else { 690 *tl++ = txdr_unsigned(NFS_PROG); 691 if (nmflag & NFSMNT_NFSV3) 692 *tl++ = txdr_unsigned(NFS_VER3); 693 else 694 *tl++ = txdr_unsigned(NFS_VER2); 695 } 696 if (nmflag & NFSMNT_NFSV3) 697 *tl++ = txdr_unsigned(procid); 698 else 699 *tl++ = txdr_unsigned(nfsv2_procid[procid]); 700 701 /* 702 * And then the authorization cred. 703 */ 704 *tl++ = txdr_unsigned(auth_type); 705 *tl = txdr_unsigned(authsiz); 706 switch (auth_type) { 707 case RPCAUTH_UNIX: 708 nfsm_build(tl, u_int32_t *, auth_len); 709 *tl++ = 0; /* stamp ?? */ 710 *tl++ = 0; /* NULL hostname */ 711 *tl++ = txdr_unsigned(cr->cr_uid); 712 *tl++ = txdr_unsigned(cr->cr_gid); 713 grpsiz = (auth_len >> 2) - 5; 714 *tl++ = txdr_unsigned(grpsiz); 715 for (i = 0; i < grpsiz; i++) 716 *tl++ = txdr_unsigned(cr->cr_groups[i]); 717 break; 718 case RPCAUTH_KERB4: 719 siz = auth_len; 720 while (siz > 0) { 721 if (M_TRAILINGSPACE(mb) == 0) { 722 struct mbuf *mb2; 723 mb2 = m_get(M_WAIT, MT_DATA); 724 MCLAIM(mb2, &nfs_mowner); 725 if (siz >= MINCLSIZE) 726 m_clget(mb2, M_WAIT); 727 mb->m_next = mb2; 728 mb = mb2; 729 mb->m_len = 0; 730 bpos = mtod(mb, caddr_t); 731 } 732 i = min(siz, M_TRAILINGSPACE(mb)); 733 memcpy(bpos, auth_str, i); 734 mb->m_len += i; 735 auth_str += i; 736 bpos += i; 737 siz -= i; 738 } 739 if ((siz = (nfsm_rndup(auth_len) - auth_len)) > 0) { 740 for (i = 0; i < siz; i++) 741 *bpos++ = '\0'; 742 mb->m_len += siz; 743 } 744 break; 745 }; 746 747 /* 748 * And the verifier... 749 */ 750 nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 751 if (verf_str) { 752 *tl++ = txdr_unsigned(RPCAUTH_KERB4); 753 *tl = txdr_unsigned(verf_len); 754 siz = verf_len; 755 while (siz > 0) { 756 if (M_TRAILINGSPACE(mb) == 0) { 757 struct mbuf *mb2; 758 mb2 = m_get(M_WAIT, MT_DATA); 759 MCLAIM(mb2, &nfs_mowner); 760 if (siz >= MINCLSIZE) 761 m_clget(mb2, M_WAIT); 762 mb->m_next = mb2; 763 mb = mb2; 764 mb->m_len = 0; 765 bpos = mtod(mb, caddr_t); 766 } 767 i = min(siz, M_TRAILINGSPACE(mb)); 768 memcpy(bpos, verf_str, i); 769 mb->m_len += i; 770 verf_str += i; 771 bpos += i; 772 siz -= i; 773 } 774 if ((siz = (nfsm_rndup(verf_len) - verf_len)) > 0) { 775 for (i = 0; i < siz; i++) 776 *bpos++ = '\0'; 777 mb->m_len += siz; 778 } 779 } else { 780 *tl++ = txdr_unsigned(RPCAUTH_NULL); 781 *tl = 0; 782 } 783 mb->m_next = mrest; 784 mreq->m_pkthdr.len = authsiz + 10 * NFSX_UNSIGNED + mrest_len; 785 mreq->m_pkthdr.rcvif = (struct ifnet *)0; 786 *mbp = mb; 787 return (mreq); 788 } 789 790 /* 791 * copies mbuf chain to the uio scatter/gather list 792 */ 793 int 794 nfsm_mbuftouio(mrep, uiop, siz, dpos) 795 struct mbuf **mrep; 796 struct uio *uiop; 797 int siz; 798 caddr_t *dpos; 799 { 800 char *mbufcp, *uiocp; 801 int xfer, left, len; 802 struct mbuf *mp; 803 long uiosiz, rem; 804 int error = 0; 805 806 mp = *mrep; 807 mbufcp = *dpos; 808 len = mtod(mp, caddr_t)+mp->m_len-mbufcp; 809 rem = nfsm_rndup(siz)-siz; 810 while (siz > 0) { 811 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) 812 return (EFBIG); 813 left = uiop->uio_iov->iov_len; 814 uiocp = uiop->uio_iov->iov_base; 815 if (left > siz) 816 left = siz; 817 uiosiz = left; 818 while (left > 0) { 819 while (len == 0) { 820 mp = mp->m_next; 821 if (mp == NULL) 822 return (EBADRPC); 823 mbufcp = mtod(mp, caddr_t); 824 len = mp->m_len; 825 } 826 xfer = (left > len) ? len : left; 827 #ifdef notdef 828 /* Not Yet.. */ 829 if (uiop->uio_iov->iov_op != NULL) 830 (*(uiop->uio_iov->iov_op)) 831 (mbufcp, uiocp, xfer); 832 else 833 #endif 834 if (uiop->uio_segflg == UIO_SYSSPACE) 835 memcpy(uiocp, mbufcp, xfer); 836 else 837 copyout(mbufcp, uiocp, xfer); 838 left -= xfer; 839 len -= xfer; 840 mbufcp += xfer; 841 uiocp += xfer; 842 uiop->uio_offset += xfer; 843 uiop->uio_resid -= xfer; 844 } 845 if (uiop->uio_iov->iov_len <= siz) { 846 uiop->uio_iovcnt--; 847 uiop->uio_iov++; 848 } else { 849 uiop->uio_iov->iov_base = 850 (caddr_t)uiop->uio_iov->iov_base + uiosiz; 851 uiop->uio_iov->iov_len -= uiosiz; 852 } 853 siz -= uiosiz; 854 } 855 *dpos = mbufcp; 856 *mrep = mp; 857 if (rem > 0) { 858 if (len < rem) 859 error = nfs_adv(mrep, dpos, rem, len); 860 else 861 *dpos += rem; 862 } 863 return (error); 864 } 865 866 /* 867 * copies a uio scatter/gather list to an mbuf chain. 868 * NOTE: can ony handle iovcnt == 1 869 */ 870 int 871 nfsm_uiotombuf(uiop, mq, siz, bpos) 872 struct uio *uiop; 873 struct mbuf **mq; 874 int siz; 875 caddr_t *bpos; 876 { 877 char *uiocp; 878 struct mbuf *mp, *mp2; 879 int xfer, left, mlen; 880 int uiosiz, clflg, rem; 881 char *cp; 882 883 #ifdef DIAGNOSTIC 884 if (uiop->uio_iovcnt != 1) 885 panic("nfsm_uiotombuf: iovcnt != 1"); 886 #endif 887 888 if (siz > MLEN) /* or should it >= MCLBYTES ?? */ 889 clflg = 1; 890 else 891 clflg = 0; 892 rem = nfsm_rndup(siz)-siz; 893 mp = mp2 = *mq; 894 while (siz > 0) { 895 left = uiop->uio_iov->iov_len; 896 uiocp = uiop->uio_iov->iov_base; 897 if (left > siz) 898 left = siz; 899 uiosiz = left; 900 while (left > 0) { 901 mlen = M_TRAILINGSPACE(mp); 902 if (mlen == 0) { 903 mp = m_get(M_WAIT, MT_DATA); 904 MCLAIM(mp, &nfs_mowner); 905 if (clflg) 906 m_clget(mp, M_WAIT); 907 mp->m_len = 0; 908 mp2->m_next = mp; 909 mp2 = mp; 910 mlen = M_TRAILINGSPACE(mp); 911 } 912 xfer = (left > mlen) ? mlen : left; 913 #ifdef notdef 914 /* Not Yet.. */ 915 if (uiop->uio_iov->iov_op != NULL) 916 (*(uiop->uio_iov->iov_op)) 917 (uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 918 else 919 #endif 920 if (uiop->uio_segflg == UIO_SYSSPACE) 921 memcpy(mtod(mp, caddr_t)+mp->m_len, uiocp, xfer); 922 else 923 copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 924 mp->m_len += xfer; 925 left -= xfer; 926 uiocp += xfer; 927 uiop->uio_offset += xfer; 928 uiop->uio_resid -= xfer; 929 } 930 uiop->uio_iov->iov_base = (caddr_t)uiop->uio_iov->iov_base + 931 uiosiz; 932 uiop->uio_iov->iov_len -= uiosiz; 933 siz -= uiosiz; 934 } 935 if (rem > 0) { 936 if (rem > M_TRAILINGSPACE(mp)) { 937 mp = m_get(M_WAIT, MT_DATA); 938 MCLAIM(mp, &nfs_mowner); 939 mp->m_len = 0; 940 mp2->m_next = mp; 941 } 942 cp = mtod(mp, caddr_t)+mp->m_len; 943 for (left = 0; left < rem; left++) 944 *cp++ = '\0'; 945 mp->m_len += rem; 946 *bpos = cp; 947 } else 948 *bpos = mtod(mp, caddr_t)+mp->m_len; 949 *mq = mp; 950 return (0); 951 } 952 953 /* 954 * Get at least "siz" bytes of correctly aligned data. 955 * When called the mbuf pointers are not necessarily correct, 956 * dsosp points to what ought to be in m_data and left contains 957 * what ought to be in m_len. 958 * This is used by the macros nfsm_dissect and nfsm_dissecton for tough 959 * cases. (The macros use the vars. dpos and dpos2) 960 */ 961 int 962 nfsm_disct(mdp, dposp, siz, left, cp2) 963 struct mbuf **mdp; 964 caddr_t *dposp; 965 int siz; 966 int left; 967 caddr_t *cp2; 968 { 969 struct mbuf *m1, *m2; 970 struct mbuf *havebuf = NULL; 971 caddr_t src = *dposp; 972 caddr_t dst; 973 int len; 974 975 #ifdef DEBUG 976 if (left < 0) 977 panic("nfsm_disct: left < 0"); 978 #endif 979 m1 = *mdp; 980 /* 981 * Skip through the mbuf chain looking for an mbuf with 982 * some data. If the first mbuf found has enough data 983 * and it is correctly aligned return it. 984 */ 985 while (left == 0) { 986 havebuf = m1; 987 *mdp = m1 = m1->m_next; 988 if (m1 == NULL) 989 return (EBADRPC); 990 src = mtod(m1, caddr_t); 991 left = m1->m_len; 992 /* 993 * If we start a new mbuf and it is big enough 994 * and correctly aligned just return it, don't 995 * do any pull up. 996 */ 997 if (left >= siz && nfsm_aligned(src)) { 998 *cp2 = src; 999 *dposp = src + siz; 1000 return (0); 1001 } 1002 } 1003 if (m1->m_flags & M_EXT) { 1004 if (havebuf) { 1005 /* If the first mbuf with data has external data 1006 * and there is a previous empty mbuf use it 1007 * to move the data into. 1008 */ 1009 m2 = m1; 1010 *mdp = m1 = havebuf; 1011 if (m1->m_flags & M_EXT) { 1012 MEXTREMOVE(m1); 1013 } 1014 } else { 1015 /* 1016 * If the first mbuf has a external data 1017 * and there is no previous empty mbuf 1018 * allocate a new mbuf and move the external 1019 * data to the new mbuf. Also make the first 1020 * mbuf look empty. 1021 */ 1022 m2 = m_get(M_WAIT, MT_DATA); 1023 m2->m_ext = m1->m_ext; 1024 m2->m_data = src; 1025 m2->m_len = left; 1026 MCLADDREFERENCE(m1, m2); 1027 MEXTREMOVE(m1); 1028 m2->m_next = m1->m_next; 1029 m1->m_next = m2; 1030 } 1031 m1->m_len = 0; 1032 if (m1->m_flags & M_PKTHDR) 1033 dst = m1->m_pktdat; 1034 else 1035 dst = m1->m_dat; 1036 m1->m_data = dst; 1037 } else { 1038 /* 1039 * If the first mbuf has no external data 1040 * move the data to the front of the mbuf. 1041 */ 1042 if (m1->m_flags & M_PKTHDR) 1043 dst = m1->m_pktdat; 1044 else 1045 dst = m1->m_dat; 1046 m1->m_data = dst; 1047 if (dst != src) 1048 memmove(dst, src, left); 1049 dst += left; 1050 m1->m_len = left; 1051 m2 = m1->m_next; 1052 } 1053 *cp2 = m1->m_data; 1054 *dposp = mtod(m1, caddr_t) + siz; 1055 /* 1056 * Loop through mbufs pulling data up into first mbuf until 1057 * the first mbuf is full or there is no more data to 1058 * pullup. 1059 */ 1060 while ((len = M_TRAILINGSPACE(m1)) != 0 && m2) { 1061 if ((len = min(len, m2->m_len)) != 0) 1062 memcpy(dst, m2->m_data, len); 1063 m1->m_len += len; 1064 dst += len; 1065 m2->m_data += len; 1066 m2->m_len -= len; 1067 m2 = m2->m_next; 1068 } 1069 if (m1->m_len < siz) 1070 return (EBADRPC); 1071 return (0); 1072 } 1073 1074 /* 1075 * Advance the position in the mbuf chain. 1076 */ 1077 int 1078 nfs_adv(mdp, dposp, offs, left) 1079 struct mbuf **mdp; 1080 caddr_t *dposp; 1081 int offs; 1082 int left; 1083 { 1084 struct mbuf *m; 1085 int s; 1086 1087 m = *mdp; 1088 s = left; 1089 while (s < offs) { 1090 offs -= s; 1091 m = m->m_next; 1092 if (m == NULL) 1093 return (EBADRPC); 1094 s = m->m_len; 1095 } 1096 *mdp = m; 1097 *dposp = mtod(m, caddr_t)+offs; 1098 return (0); 1099 } 1100 1101 /* 1102 * Copy a string into mbufs for the hard cases... 1103 */ 1104 int 1105 nfsm_strtmbuf(mb, bpos, cp, siz) 1106 struct mbuf **mb; 1107 char **bpos; 1108 const char *cp; 1109 long siz; 1110 { 1111 struct mbuf *m1 = NULL, *m2; 1112 long left, xfer, len, tlen; 1113 u_int32_t *tl; 1114 int putsize; 1115 1116 putsize = 1; 1117 m2 = *mb; 1118 left = M_TRAILINGSPACE(m2); 1119 if (left > 0) { 1120 tl = ((u_int32_t *)(*bpos)); 1121 *tl++ = txdr_unsigned(siz); 1122 putsize = 0; 1123 left -= NFSX_UNSIGNED; 1124 m2->m_len += NFSX_UNSIGNED; 1125 if (left > 0) { 1126 memcpy((caddr_t) tl, cp, left); 1127 siz -= left; 1128 cp += left; 1129 m2->m_len += left; 1130 left = 0; 1131 } 1132 } 1133 /* Loop around adding mbufs */ 1134 while (siz > 0) { 1135 m1 = m_get(M_WAIT, MT_DATA); 1136 MCLAIM(m1, &nfs_mowner); 1137 if (siz > MLEN) 1138 m_clget(m1, M_WAIT); 1139 m1->m_len = NFSMSIZ(m1); 1140 m2->m_next = m1; 1141 m2 = m1; 1142 tl = mtod(m1, u_int32_t *); 1143 tlen = 0; 1144 if (putsize) { 1145 *tl++ = txdr_unsigned(siz); 1146 m1->m_len -= NFSX_UNSIGNED; 1147 tlen = NFSX_UNSIGNED; 1148 putsize = 0; 1149 } 1150 if (siz < m1->m_len) { 1151 len = nfsm_rndup(siz); 1152 xfer = siz; 1153 if (xfer < len) 1154 *(tl+(xfer>>2)) = 0; 1155 } else { 1156 xfer = len = m1->m_len; 1157 } 1158 memcpy((caddr_t) tl, cp, xfer); 1159 m1->m_len = len+tlen; 1160 siz -= xfer; 1161 cp += xfer; 1162 } 1163 *mb = m1; 1164 *bpos = mtod(m1, caddr_t)+m1->m_len; 1165 return (0); 1166 } 1167 1168 /* 1169 * Directory caching routines. They work as follows: 1170 * - a cache is maintained per VDIR nfsnode. 1171 * - for each offset cookie that is exported to userspace, and can 1172 * thus be thrown back at us as an offset to VOP_READDIR, store 1173 * information in the cache. 1174 * - cached are: 1175 * - cookie itself 1176 * - blocknumber (essentially just a search key in the buffer cache) 1177 * - entry number in block. 1178 * - offset cookie of block in which this entry is stored 1179 * - 32 bit cookie if NFSMNT_XLATECOOKIE is used. 1180 * - entries are looked up in a hash table 1181 * - also maintained is an LRU list of entries, used to determine 1182 * which ones to delete if the cache grows too large. 1183 * - if 32 <-> 64 translation mode is requested for a filesystem, 1184 * the cache also functions as a translation table 1185 * - in the translation case, invalidating the cache does not mean 1186 * flushing it, but just marking entries as invalid, except for 1187 * the <64bit cookie, 32bitcookie> pair which is still valid, to 1188 * still be able to use the cache as a translation table. 1189 * - 32 bit cookies are uniquely created by combining the hash table 1190 * entry value, and one generation count per hash table entry, 1191 * incremented each time an entry is appended to the chain. 1192 * - the cache is invalidated each time a direcory is modified 1193 * - sanity checks are also done; if an entry in a block turns 1194 * out not to have a matching cookie, the cache is invalidated 1195 * and a new block starting from the wanted offset is fetched from 1196 * the server. 1197 * - directory entries as read from the server are extended to contain 1198 * the 64bit and, optionally, the 32bit cookies, for sanity checking 1199 * the cache and exporting them to userspace through the cookie 1200 * argument to VOP_READDIR. 1201 */ 1202 1203 u_long 1204 nfs_dirhash(off) 1205 off_t off; 1206 { 1207 int i; 1208 char *cp = (char *)&off; 1209 u_long sum = 0L; 1210 1211 for (i = 0 ; i < sizeof (off); i++) 1212 sum += *cp++; 1213 1214 return sum; 1215 } 1216 1217 #define _NFSDC_MTX(np) (&NFSTOV(np)->v_interlock) 1218 #define NFSDC_LOCK(np) simple_lock(_NFSDC_MTX(np)) 1219 #define NFSDC_UNLOCK(np) simple_unlock(_NFSDC_MTX(np)) 1220 #define NFSDC_ASSERT_LOCKED(np) LOCK_ASSERT(simple_lock_held(_NFSDC_MTX(np))) 1221 1222 void 1223 nfs_initdircache(vp) 1224 struct vnode *vp; 1225 { 1226 struct nfsnode *np = VTONFS(vp); 1227 struct nfsdirhashhead *dircache; 1228 1229 dircache = hashinit(NFS_DIRHASHSIZ, HASH_LIST, M_NFSDIROFF, 1230 M_WAITOK, &nfsdirhashmask); 1231 1232 NFSDC_LOCK(np); 1233 if (np->n_dircache == NULL) { 1234 np->n_dircachesize = 0; 1235 np->n_dircache = dircache; 1236 dircache = NULL; 1237 TAILQ_INIT(&np->n_dirchain); 1238 } 1239 NFSDC_UNLOCK(np); 1240 if (dircache) 1241 hashdone(dircache, M_NFSDIROFF); 1242 } 1243 1244 void 1245 nfs_initdirxlatecookie(vp) 1246 struct vnode *vp; 1247 { 1248 struct nfsnode *np = VTONFS(vp); 1249 unsigned *dirgens; 1250 1251 KASSERT(VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_XLATECOOKIE); 1252 1253 dirgens = malloc(NFS_DIRHASHSIZ * sizeof (unsigned), M_NFSDIROFF, 1254 M_WAITOK|M_ZERO); 1255 NFSDC_LOCK(np); 1256 if (np->n_dirgens == NULL) { 1257 np->n_dirgens = dirgens; 1258 dirgens = NULL; 1259 } 1260 NFSDC_UNLOCK(np); 1261 if (dirgens) 1262 free(dirgens, M_NFSDIROFF); 1263 } 1264 1265 static const struct nfsdircache dzero; 1266 1267 static void nfs_unlinkdircache __P((struct nfsnode *np, struct nfsdircache *)); 1268 static void nfs_putdircache_unlocked __P((struct nfsnode *, 1269 struct nfsdircache *)); 1270 1271 static void 1272 nfs_unlinkdircache(np, ndp) 1273 struct nfsnode *np; 1274 struct nfsdircache *ndp; 1275 { 1276 1277 NFSDC_ASSERT_LOCKED(np); 1278 KASSERT(ndp != &dzero); 1279 1280 if (LIST_NEXT(ndp, dc_hash) == (void *)-1) 1281 return; 1282 1283 TAILQ_REMOVE(&np->n_dirchain, ndp, dc_chain); 1284 LIST_REMOVE(ndp, dc_hash); 1285 LIST_NEXT(ndp, dc_hash) = (void *)-1; /* mark as unlinked */ 1286 1287 nfs_putdircache_unlocked(np, ndp); 1288 } 1289 1290 void 1291 nfs_putdircache(np, ndp) 1292 struct nfsnode *np; 1293 struct nfsdircache *ndp; 1294 { 1295 int ref; 1296 1297 if (ndp == &dzero) 1298 return; 1299 1300 KASSERT(ndp->dc_refcnt > 0); 1301 NFSDC_LOCK(np); 1302 ref = --ndp->dc_refcnt; 1303 NFSDC_UNLOCK(np); 1304 1305 if (ref == 0) 1306 free(ndp, M_NFSDIROFF); 1307 } 1308 1309 static void 1310 nfs_putdircache_unlocked(np, ndp) 1311 struct nfsnode *np; 1312 struct nfsdircache *ndp; 1313 { 1314 int ref; 1315 1316 NFSDC_ASSERT_LOCKED(np); 1317 1318 if (ndp == &dzero) 1319 return; 1320 1321 KASSERT(ndp->dc_refcnt > 0); 1322 ref = --ndp->dc_refcnt; 1323 if (ref == 0) 1324 free(ndp, M_NFSDIROFF); 1325 } 1326 1327 struct nfsdircache * 1328 nfs_searchdircache(vp, off, do32, hashent) 1329 struct vnode *vp; 1330 off_t off; 1331 int do32; 1332 int *hashent; 1333 { 1334 struct nfsdirhashhead *ndhp; 1335 struct nfsdircache *ndp = NULL; 1336 struct nfsnode *np = VTONFS(vp); 1337 unsigned ent; 1338 1339 /* 1340 * Zero is always a valid cookie. 1341 */ 1342 if (off == 0) 1343 /* LINTED const cast away */ 1344 return (struct nfsdircache *)&dzero; 1345 1346 if (!np->n_dircache) 1347 return NULL; 1348 1349 /* 1350 * We use a 32bit cookie as search key, directly reconstruct 1351 * the hashentry. Else use the hashfunction. 1352 */ 1353 if (do32) { 1354 ent = (u_int32_t)off >> 24; 1355 if (ent >= NFS_DIRHASHSIZ) 1356 return NULL; 1357 ndhp = &np->n_dircache[ent]; 1358 } else { 1359 ndhp = NFSDIRHASH(np, off); 1360 } 1361 1362 if (hashent) 1363 *hashent = (int)(ndhp - np->n_dircache); 1364 1365 NFSDC_LOCK(np); 1366 if (do32) { 1367 LIST_FOREACH(ndp, ndhp, dc_hash) { 1368 if (ndp->dc_cookie32 == (u_int32_t)off) { 1369 /* 1370 * An invalidated entry will become the 1371 * start of a new block fetched from 1372 * the server. 1373 */ 1374 if (ndp->dc_flags & NFSDC_INVALID) { 1375 ndp->dc_blkcookie = ndp->dc_cookie; 1376 ndp->dc_entry = 0; 1377 ndp->dc_flags &= ~NFSDC_INVALID; 1378 } 1379 break; 1380 } 1381 } 1382 } else { 1383 LIST_FOREACH(ndp, ndhp, dc_hash) { 1384 if (ndp->dc_cookie == off) 1385 break; 1386 } 1387 } 1388 if (ndp != NULL) 1389 ndp->dc_refcnt++; 1390 NFSDC_UNLOCK(np); 1391 return ndp; 1392 } 1393 1394 1395 struct nfsdircache * 1396 nfs_enterdircache(vp, off, blkoff, en, blkno) 1397 struct vnode *vp; 1398 off_t off, blkoff; 1399 int en; 1400 daddr_t blkno; 1401 { 1402 struct nfsnode *np = VTONFS(vp); 1403 struct nfsdirhashhead *ndhp; 1404 struct nfsdircache *ndp = NULL; 1405 struct nfsdircache *newndp = NULL; 1406 struct nfsmount *nmp = VFSTONFS(vp->v_mount); 1407 int hashent, gen, overwrite; 1408 1409 /* 1410 * XXX refuse entries for offset 0. amd(8) erroneously sets 1411 * cookie 0 for the '.' entry, making this necessary. This 1412 * isn't so bad, as 0 is a special case anyway. 1413 */ 1414 if (off == 0) 1415 /* LINTED const cast away */ 1416 return (struct nfsdircache *)&dzero; 1417 1418 if (!np->n_dircache) 1419 /* 1420 * XXX would like to do this in nfs_nget but vtype 1421 * isn't known at that time. 1422 */ 1423 nfs_initdircache(vp); 1424 1425 if ((nmp->nm_flag & NFSMNT_XLATECOOKIE) && !np->n_dirgens) 1426 nfs_initdirxlatecookie(vp); 1427 1428 retry: 1429 ndp = nfs_searchdircache(vp, off, 0, &hashent); 1430 1431 NFSDC_LOCK(np); 1432 if (ndp && (ndp->dc_flags & NFSDC_INVALID) == 0) { 1433 /* 1434 * Overwriting an old entry. Check if it's the same. 1435 * If so, just return. If not, remove the old entry. 1436 */ 1437 if (ndp->dc_blkcookie == blkoff && ndp->dc_entry == en) 1438 goto done; 1439 nfs_unlinkdircache(np, ndp); 1440 nfs_putdircache_unlocked(np, ndp); 1441 ndp = NULL; 1442 } 1443 1444 ndhp = &np->n_dircache[hashent]; 1445 1446 if (!ndp) { 1447 if (newndp == NULL) { 1448 NFSDC_UNLOCK(np); 1449 newndp = malloc(sizeof(*ndp), M_NFSDIROFF, M_WAITOK); 1450 newndp->dc_refcnt = 1; 1451 LIST_NEXT(newndp, dc_hash) = (void *)-1; 1452 goto retry; 1453 } 1454 ndp = newndp; 1455 newndp = NULL; 1456 overwrite = 0; 1457 if (nmp->nm_flag & NFSMNT_XLATECOOKIE) { 1458 /* 1459 * We're allocating a new entry, so bump the 1460 * generation number. 1461 */ 1462 gen = ++np->n_dirgens[hashent]; 1463 if (gen == 0) { 1464 np->n_dirgens[hashent]++; 1465 gen++; 1466 } 1467 ndp->dc_cookie32 = (hashent << 24) | (gen & 0xffffff); 1468 } 1469 } else 1470 overwrite = 1; 1471 1472 ndp->dc_cookie = off; 1473 ndp->dc_blkcookie = blkoff; 1474 ndp->dc_entry = en; 1475 ndp->dc_flags = 0; 1476 1477 if (overwrite) 1478 goto done; 1479 1480 /* 1481 * If the maximum directory cookie cache size has been reached 1482 * for this node, take one off the front. The idea is that 1483 * directories are typically read front-to-back once, so that 1484 * the oldest entries can be thrown away without much performance 1485 * loss. 1486 */ 1487 if (np->n_dircachesize == NFS_MAXDIRCACHE) { 1488 nfs_unlinkdircache(np, TAILQ_FIRST(&np->n_dirchain)); 1489 } else 1490 np->n_dircachesize++; 1491 1492 KASSERT(ndp->dc_refcnt == 1); 1493 LIST_INSERT_HEAD(ndhp, ndp, dc_hash); 1494 TAILQ_INSERT_TAIL(&np->n_dirchain, ndp, dc_chain); 1495 ndp->dc_refcnt++; 1496 done: 1497 KASSERT(ndp->dc_refcnt > 0); 1498 NFSDC_UNLOCK(np); 1499 if (newndp) 1500 nfs_putdircache(np, newndp); 1501 return ndp; 1502 } 1503 1504 void 1505 nfs_invaldircache(vp, flags) 1506 struct vnode *vp; 1507 int flags; 1508 { 1509 struct nfsnode *np = VTONFS(vp); 1510 struct nfsdircache *ndp = NULL; 1511 struct nfsmount *nmp = VFSTONFS(vp->v_mount); 1512 const boolean_t forcefree = flags & NFS_INVALDIRCACHE_FORCE; 1513 1514 #ifdef DIAGNOSTIC 1515 if (vp->v_type != VDIR) 1516 panic("nfs: invaldircache: not dir"); 1517 #endif 1518 1519 if ((flags & NFS_INVALDIRCACHE_KEEPEOF) == 0) 1520 np->n_flag &= ~NEOFVALID; 1521 1522 if (!np->n_dircache) 1523 return; 1524 1525 NFSDC_LOCK(np); 1526 if (!(nmp->nm_flag & NFSMNT_XLATECOOKIE) || forcefree) { 1527 while ((ndp = TAILQ_FIRST(&np->n_dirchain)) != NULL) { 1528 KASSERT(!forcefree || ndp->dc_refcnt == 1); 1529 nfs_unlinkdircache(np, ndp); 1530 } 1531 np->n_dircachesize = 0; 1532 if (forcefree && np->n_dirgens) { 1533 FREE(np->n_dirgens, M_NFSDIROFF); 1534 np->n_dirgens = NULL; 1535 } 1536 } else { 1537 TAILQ_FOREACH(ndp, &np->n_dirchain, dc_chain) 1538 ndp->dc_flags |= NFSDC_INVALID; 1539 } 1540 1541 NFSDC_UNLOCK(np); 1542 } 1543 1544 /* 1545 * Called once before VFS init to initialize shared and 1546 * server-specific data structures. 1547 */ 1548 void 1549 nfs_init() 1550 { 1551 nfsrtt.pos = 0; 1552 rpc_vers = txdr_unsigned(RPC_VER2); 1553 rpc_call = txdr_unsigned(RPC_CALL); 1554 rpc_reply = txdr_unsigned(RPC_REPLY); 1555 rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED); 1556 rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED); 1557 rpc_mismatch = txdr_unsigned(RPC_MISMATCH); 1558 rpc_autherr = txdr_unsigned(RPC_AUTHERR); 1559 rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX); 1560 rpc_auth_kerb = txdr_unsigned(RPCAUTH_KERB4); 1561 nfs_prog = txdr_unsigned(NFS_PROG); 1562 nqnfs_prog = txdr_unsigned(NQNFS_PROG); 1563 nfs_true = txdr_unsigned(TRUE); 1564 nfs_false = txdr_unsigned(FALSE); 1565 nfs_xdrneg1 = txdr_unsigned(-1); 1566 nfs_ticks = (hz * NFS_TICKINTVL + 500) / 1000; 1567 if (nfs_ticks < 1) 1568 nfs_ticks = 1; 1569 #ifdef NFSSERVER 1570 nfsrv_init(0); /* Init server data structures */ 1571 nfsrv_initcache(); /* Init the server request cache */ 1572 pool_init(&nfs_srvdesc_pool, sizeof(struct nfsrv_descript), 1573 0, 0, 0, "nfsrvdescpl", &pool_allocator_nointr); 1574 #endif /* NFSSERVER */ 1575 1576 #if defined(NFSSERVER) || !defined(NFS_V2_ONLY) 1577 /* 1578 * Initialize the nqnfs data structures. 1579 */ 1580 if (nqnfsstarttime == 0) { 1581 nqnfsstarttime = boottime.tv_sec + nqsrv_maxlease 1582 + nqsrv_clockskew + nqsrv_writeslack; 1583 NQLOADNOVRAM(nqnfsstarttime); 1584 CIRCLEQ_INIT(&nqtimerhead); 1585 nqfhhashtbl = hashinit(NQLCHSZ, HASH_LIST, M_NQLEASE, 1586 M_WAITOK, &nqfhhash); 1587 } 1588 #endif 1589 1590 exithook_establish(nfs_exit, NULL); 1591 1592 /* 1593 * Initialize reply list and start timer 1594 */ 1595 TAILQ_INIT(&nfs_reqq); 1596 nfs_timer(NULL); 1597 MOWNER_ATTACH(&nfs_mowner); 1598 1599 #ifdef NFS 1600 /* Initialize the kqueue structures */ 1601 nfs_kqinit(); 1602 /* Initialize the iod structures */ 1603 nfs_iodinit(); 1604 #endif 1605 } 1606 1607 #ifdef NFS 1608 /* 1609 * Called once at VFS init to initialize client-specific data structures. 1610 */ 1611 void 1612 nfs_vfs_init() 1613 { 1614 nfs_nhinit(); /* Init the nfsnode table */ 1615 nfs_commitsize = uvmexp.npages << (PAGE_SHIFT - 4); 1616 } 1617 1618 void 1619 nfs_vfs_reinit() 1620 { 1621 nfs_nhreinit(); 1622 } 1623 1624 void 1625 nfs_vfs_done() 1626 { 1627 nfs_nhdone(); 1628 } 1629 1630 /* 1631 * Attribute cache routines. 1632 * nfs_loadattrcache() - loads or updates the cache contents from attributes 1633 * that are on the mbuf list 1634 * nfs_getattrcache() - returns valid attributes if found in cache, returns 1635 * error otherwise 1636 */ 1637 1638 /* 1639 * Load the attribute cache (that lives in the nfsnode entry) with 1640 * the values on the mbuf list and 1641 * Iff vap not NULL 1642 * copy the attributes to *vaper 1643 */ 1644 int 1645 nfsm_loadattrcache(vpp, mdp, dposp, vaper, flags) 1646 struct vnode **vpp; 1647 struct mbuf **mdp; 1648 caddr_t *dposp; 1649 struct vattr *vaper; 1650 int flags; 1651 { 1652 int32_t t1; 1653 caddr_t cp2; 1654 int error = 0; 1655 struct mbuf *md; 1656 int v3 = NFS_ISV3(*vpp); 1657 1658 md = *mdp; 1659 t1 = (mtod(md, caddr_t) + md->m_len) - *dposp; 1660 error = nfsm_disct(mdp, dposp, NFSX_FATTR(v3), t1, &cp2); 1661 if (error) 1662 return (error); 1663 return nfs_loadattrcache(vpp, (struct nfs_fattr *)cp2, vaper, flags); 1664 } 1665 1666 int 1667 nfs_loadattrcache(vpp, fp, vaper, flags) 1668 struct vnode **vpp; 1669 struct nfs_fattr *fp; 1670 struct vattr *vaper; 1671 int flags; 1672 { 1673 struct vnode *vp = *vpp; 1674 struct vattr *vap; 1675 int v3 = NFS_ISV3(vp); 1676 enum vtype vtyp; 1677 u_short vmode; 1678 struct timespec mtime; 1679 struct timespec ctime; 1680 struct vnode *nvp; 1681 int32_t rdev; 1682 struct nfsnode *np; 1683 extern int (**spec_nfsv2nodeop_p) __P((void *)); 1684 uid_t uid; 1685 gid_t gid; 1686 1687 if (v3) { 1688 vtyp = nfsv3tov_type(fp->fa_type); 1689 vmode = fxdr_unsigned(u_short, fp->fa_mode); 1690 rdev = makedev(fxdr_unsigned(u_int32_t, fp->fa3_rdev.specdata1), 1691 fxdr_unsigned(u_int32_t, fp->fa3_rdev.specdata2)); 1692 fxdr_nfsv3time(&fp->fa3_mtime, &mtime); 1693 fxdr_nfsv3time(&fp->fa3_ctime, &ctime); 1694 } else { 1695 vtyp = nfsv2tov_type(fp->fa_type); 1696 vmode = fxdr_unsigned(u_short, fp->fa_mode); 1697 if (vtyp == VNON || vtyp == VREG) 1698 vtyp = IFTOVT(vmode); 1699 rdev = fxdr_unsigned(int32_t, fp->fa2_rdev); 1700 fxdr_nfsv2time(&fp->fa2_mtime, &mtime); 1701 ctime.tv_sec = fxdr_unsigned(u_int32_t, 1702 fp->fa2_ctime.nfsv2_sec); 1703 ctime.tv_nsec = 0; 1704 1705 /* 1706 * Really ugly NFSv2 kludge. 1707 */ 1708 if (vtyp == VCHR && rdev == 0xffffffff) 1709 vtyp = VFIFO; 1710 } 1711 1712 vmode &= ALLPERMS; 1713 1714 /* 1715 * If v_type == VNON it is a new node, so fill in the v_type, 1716 * n_mtime fields. Check to see if it represents a special 1717 * device, and if so, check for a possible alias. Once the 1718 * correct vnode has been obtained, fill in the rest of the 1719 * information. 1720 */ 1721 np = VTONFS(vp); 1722 if (vp->v_type == VNON) { 1723 vp->v_type = vtyp; 1724 if (vp->v_type == VFIFO) { 1725 extern int (**fifo_nfsv2nodeop_p) __P((void *)); 1726 vp->v_op = fifo_nfsv2nodeop_p; 1727 } else if (vp->v_type == VREG) { 1728 lockinit(&np->n_commitlock, PINOD, "nfsclock", 0, 0); 1729 } else if (vp->v_type == VCHR || vp->v_type == VBLK) { 1730 vp->v_op = spec_nfsv2nodeop_p; 1731 nvp = checkalias(vp, (dev_t)rdev, vp->v_mount); 1732 if (nvp) { 1733 /* 1734 * Discard unneeded vnode, but save its nfsnode. 1735 * Since the nfsnode does not have a lock, its 1736 * vnode lock has to be carried over. 1737 */ 1738 /* 1739 * XXX is the old node sure to be locked here? 1740 */ 1741 KASSERT(lockstatus(&vp->v_lock) == 1742 LK_EXCLUSIVE); 1743 nvp->v_data = vp->v_data; 1744 vp->v_data = NULL; 1745 VOP_UNLOCK(vp, 0); 1746 vp->v_op = spec_vnodeop_p; 1747 vrele(vp); 1748 vgone(vp); 1749 lockmgr(&nvp->v_lock, LK_EXCLUSIVE, 1750 &nvp->v_interlock); 1751 /* 1752 * Reinitialize aliased node. 1753 */ 1754 np->n_vnode = nvp; 1755 *vpp = vp = nvp; 1756 } 1757 } 1758 np->n_mtime = mtime; 1759 } 1760 uid = fxdr_unsigned(uid_t, fp->fa_uid); 1761 gid = fxdr_unsigned(gid_t, fp->fa_gid); 1762 vap = np->n_vattr; 1763 1764 /* 1765 * Invalidate access cache if uid, gid, mode or ctime changed. 1766 */ 1767 if (np->n_accstamp != -1 && 1768 (gid != vap->va_gid || uid != vap->va_uid || vmode != vap->va_mode 1769 || timespeccmp(&ctime, &vap->va_ctime, !=))) 1770 np->n_accstamp = -1; 1771 1772 vap->va_type = vtyp; 1773 vap->va_mode = vmode; 1774 vap->va_rdev = (dev_t)rdev; 1775 vap->va_mtime = mtime; 1776 vap->va_ctime = ctime; 1777 vap->va_fsid = vp->v_mount->mnt_stat.f_fsidx.__fsid_val[0]; 1778 switch (vtyp) { 1779 case VDIR: 1780 vap->va_blocksize = NFS_DIRFRAGSIZ; 1781 break; 1782 case VBLK: 1783 vap->va_blocksize = BLKDEV_IOSIZE; 1784 break; 1785 case VCHR: 1786 vap->va_blocksize = MAXBSIZE; 1787 break; 1788 default: 1789 vap->va_blocksize = v3 ? vp->v_mount->mnt_stat.f_iosize : 1790 fxdr_unsigned(int32_t, fp->fa2_blocksize); 1791 break; 1792 } 1793 if (v3) { 1794 vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink); 1795 vap->va_uid = uid; 1796 vap->va_gid = gid; 1797 vap->va_size = fxdr_hyper(&fp->fa3_size); 1798 vap->va_bytes = fxdr_hyper(&fp->fa3_used); 1799 vap->va_fileid = fxdr_unsigned(int32_t, 1800 fp->fa3_fileid.nfsuquad[1]); 1801 fxdr_nfsv3time(&fp->fa3_atime, &vap->va_atime); 1802 vap->va_flags = 0; 1803 vap->va_filerev = 0; 1804 } else { 1805 vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink); 1806 vap->va_uid = uid; 1807 vap->va_gid = gid; 1808 vap->va_size = fxdr_unsigned(u_int32_t, fp->fa2_size); 1809 vap->va_bytes = fxdr_unsigned(int32_t, fp->fa2_blocks) 1810 * NFS_FABLKSIZE; 1811 vap->va_fileid = fxdr_unsigned(int32_t, fp->fa2_fileid); 1812 fxdr_nfsv2time(&fp->fa2_atime, &vap->va_atime); 1813 vap->va_flags = 0; 1814 vap->va_gen = fxdr_unsigned(u_int32_t,fp->fa2_ctime.nfsv2_usec); 1815 vap->va_filerev = 0; 1816 } 1817 if (vap->va_size != np->n_size) { 1818 if ((np->n_flag & NMODIFIED) && vap->va_size < np->n_size) { 1819 vap->va_size = np->n_size; 1820 } else { 1821 np->n_size = vap->va_size; 1822 if (vap->va_type == VREG) { 1823 /* 1824 * we can't free pages if NAC_NOTRUNC because 1825 * the pages can be owned by ourselves. 1826 */ 1827 if (flags & NAC_NOTRUNC) { 1828 np->n_flag |= NTRUNCDELAYED; 1829 } else { 1830 simple_lock(&vp->v_interlock); 1831 (void)VOP_PUTPAGES(vp, 0, 1832 0, PGO_SYNCIO | PGO_CLEANIT | 1833 PGO_FREE | PGO_ALLPAGES); 1834 uvm_vnp_setsize(vp, np->n_size); 1835 } 1836 } 1837 } 1838 } 1839 np->n_attrstamp = mono_time.tv_sec; 1840 if (vaper != NULL) { 1841 memcpy((caddr_t)vaper, (caddr_t)vap, sizeof(*vap)); 1842 if (np->n_flag & NCHG) { 1843 if (np->n_flag & NACC) 1844 vaper->va_atime = np->n_atim; 1845 if (np->n_flag & NUPD) 1846 vaper->va_mtime = np->n_mtim; 1847 } 1848 } 1849 return (0); 1850 } 1851 1852 /* 1853 * Check the time stamp 1854 * If the cache is valid, copy contents to *vap and return 0 1855 * otherwise return an error 1856 */ 1857 int 1858 nfs_getattrcache(vp, vaper) 1859 struct vnode *vp; 1860 struct vattr *vaper; 1861 { 1862 struct nfsnode *np = VTONFS(vp); 1863 struct vattr *vap; 1864 1865 if (np->n_attrstamp == 0 || 1866 (mono_time.tv_sec - np->n_attrstamp) >= NFS_ATTRTIMEO(np)) { 1867 nfsstats.attrcache_misses++; 1868 return (ENOENT); 1869 } 1870 nfsstats.attrcache_hits++; 1871 vap = np->n_vattr; 1872 if (vap->va_size != np->n_size) { 1873 if (vap->va_type == VREG) { 1874 if (np->n_flag & NMODIFIED) { 1875 if (vap->va_size < np->n_size) 1876 vap->va_size = np->n_size; 1877 else 1878 np->n_size = vap->va_size; 1879 } else 1880 np->n_size = vap->va_size; 1881 uvm_vnp_setsize(vp, np->n_size); 1882 } else 1883 np->n_size = vap->va_size; 1884 } 1885 memcpy((caddr_t)vaper, (caddr_t)vap, sizeof(struct vattr)); 1886 if (np->n_flag & NCHG) { 1887 if (np->n_flag & NACC) 1888 vaper->va_atime = np->n_atim; 1889 if (np->n_flag & NUPD) 1890 vaper->va_mtime = np->n_mtim; 1891 } 1892 return (0); 1893 } 1894 1895 void 1896 nfs_delayedtruncate(vp) 1897 struct vnode *vp; 1898 { 1899 struct nfsnode *np = VTONFS(vp); 1900 1901 if (np->n_flag & NTRUNCDELAYED) { 1902 np->n_flag &= ~NTRUNCDELAYED; 1903 simple_lock(&vp->v_interlock); 1904 (void)VOP_PUTPAGES(vp, 0, 1905 0, PGO_SYNCIO | PGO_CLEANIT | PGO_FREE | PGO_ALLPAGES); 1906 uvm_vnp_setsize(vp, np->n_size); 1907 } 1908 } 1909 1910 #define NFS_WCCKLUDGE_TIMEOUT (24 * 60 * 60) /* 1 day */ 1911 #define NFS_WCCKLUDGE(nmp, now) \ 1912 (((nmp)->nm_iflag & NFSMNT_WCCKLUDGE) && \ 1913 ((now) - (nmp)->nm_wcckludgetime - NFS_WCCKLUDGE_TIMEOUT) < 0) 1914 1915 /* 1916 * nfs_check_wccdata: check inaccurate wcc_data 1917 * 1918 * => return non-zero if we shouldn't trust the wcc_data. 1919 * => NFS_WCCKLUDGE_TIMEOUT is for the case that the server is "fixed". 1920 */ 1921 1922 int 1923 nfs_check_wccdata(struct nfsnode *np, const struct timespec *ctime, 1924 struct timespec *mtime, boolean_t docheck) 1925 { 1926 int error = 0; 1927 1928 #if !defined(NFS_V2_ONLY) 1929 1930 if (docheck) { 1931 struct vnode *vp = NFSTOV(np); 1932 struct nfsmount *nmp; 1933 long now = mono_time.tv_sec; 1934 #if defined(DEBUG) 1935 const char *reason = NULL; /* XXX: gcc */ 1936 #endif 1937 1938 if (timespeccmp(&np->n_vattr->va_mtime, mtime, <=)) { 1939 #if defined(DEBUG) 1940 reason = "mtime"; 1941 #endif 1942 error = EINVAL; 1943 } 1944 1945 if (vp->v_type == VDIR && 1946 timespeccmp(&np->n_vattr->va_ctime, ctime, <=)) { 1947 #if defined(DEBUG) 1948 reason = "ctime"; 1949 #endif 1950 error = EINVAL; 1951 } 1952 1953 nmp = VFSTONFS(vp->v_mount); 1954 if (error) { 1955 1956 /* 1957 * despite of the fact that we've updated the file, 1958 * timestamps of the file were not updated as we 1959 * expected. 1960 * it means that the server has incompatible 1961 * semantics of timestamps or (more likely) 1962 * the server time is not precise enough to 1963 * track each modifications. 1964 * in that case, we disable wcc processing. 1965 * 1966 * yes, strictly speaking, we should disable all 1967 * caching. it's a compromise. 1968 */ 1969 1970 simple_lock(&nmp->nm_slock); 1971 #if defined(DEBUG) 1972 if (!NFS_WCCKLUDGE(nmp, now)) { 1973 printf("%s: inaccurate wcc data (%s) detected," 1974 " disabling wcc\n", 1975 vp->v_mount->mnt_stat.f_mntfromname, 1976 reason); 1977 } 1978 #endif 1979 nmp->nm_iflag |= NFSMNT_WCCKLUDGE; 1980 nmp->nm_wcckludgetime = now; 1981 simple_unlock(&nmp->nm_slock); 1982 } else if (NFS_WCCKLUDGE(nmp, now)) { 1983 error = EPERM; /* XXX */ 1984 } else if (nmp->nm_iflag & NFSMNT_WCCKLUDGE) { 1985 simple_lock(&nmp->nm_slock); 1986 if (nmp->nm_iflag & NFSMNT_WCCKLUDGE) { 1987 #if defined(DEBUG) 1988 printf("%s: re-enabling wcc\n", 1989 vp->v_mount->mnt_stat.f_mntfromname); 1990 #endif 1991 nmp->nm_iflag &= ~NFSMNT_WCCKLUDGE; 1992 } 1993 simple_unlock(&nmp->nm_slock); 1994 } 1995 } 1996 1997 #endif /* !defined(NFS_V2_ONLY) */ 1998 1999 return error; 2000 } 2001 2002 /* 2003 * Heuristic to see if the server XDR encodes directory cookies or not. 2004 * it is not supposed to, but a lot of servers may do this. Also, since 2005 * most/all servers will implement V2 as well, it is expected that they 2006 * may return just 32 bits worth of cookie information, so we need to 2007 * find out in which 32 bits this information is available. We do this 2008 * to avoid trouble with emulated binaries that can't handle 64 bit 2009 * directory offsets. 2010 */ 2011 2012 void 2013 nfs_cookieheuristic(vp, flagp, p, cred) 2014 struct vnode *vp; 2015 int *flagp; 2016 struct proc *p; 2017 struct ucred *cred; 2018 { 2019 struct uio auio; 2020 struct iovec aiov; 2021 caddr_t buf, cp; 2022 struct dirent *dp; 2023 off_t *cookies = NULL, *cop; 2024 int error, eof, nc, len; 2025 2026 MALLOC(buf, caddr_t, NFS_DIRFRAGSIZ, M_TEMP, M_WAITOK); 2027 2028 aiov.iov_base = buf; 2029 aiov.iov_len = NFS_DIRFRAGSIZ; 2030 auio.uio_iov = &aiov; 2031 auio.uio_iovcnt = 1; 2032 auio.uio_rw = UIO_READ; 2033 auio.uio_segflg = UIO_SYSSPACE; 2034 auio.uio_procp = NULL; 2035 auio.uio_resid = NFS_DIRFRAGSIZ; 2036 auio.uio_offset = 0; 2037 2038 error = VOP_READDIR(vp, &auio, cred, &eof, &cookies, &nc); 2039 2040 len = NFS_DIRFRAGSIZ - auio.uio_resid; 2041 if (error || len == 0) { 2042 FREE(buf, M_TEMP); 2043 if (cookies) 2044 free(cookies, M_TEMP); 2045 return; 2046 } 2047 2048 /* 2049 * Find the first valid entry and look at its offset cookie. 2050 */ 2051 2052 cp = buf; 2053 for (cop = cookies; len > 0; len -= dp->d_reclen) { 2054 dp = (struct dirent *)cp; 2055 if (dp->d_fileno != 0 && len >= dp->d_reclen) { 2056 if ((*cop >> 32) != 0 && (*cop & 0xffffffffLL) == 0) { 2057 *flagp |= NFSMNT_SWAPCOOKIE; 2058 nfs_invaldircache(vp, 0); 2059 nfs_vinvalbuf(vp, 0, cred, p, 1); 2060 } 2061 break; 2062 } 2063 cop++; 2064 cp += dp->d_reclen; 2065 } 2066 2067 FREE(buf, M_TEMP); 2068 free(cookies, M_TEMP); 2069 } 2070 #endif /* NFS */ 2071 2072 /* 2073 * Set up nameidata for a lookup() call and do it. 2074 * 2075 * If pubflag is set, this call is done for a lookup operation on the 2076 * public filehandle. In that case we allow crossing mountpoints and 2077 * absolute pathnames. However, the caller is expected to check that 2078 * the lookup result is within the public fs, and deny access if 2079 * it is not. 2080 */ 2081 int 2082 nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, retdirp, p, kerbflag, pubflag) 2083 struct nameidata *ndp; 2084 fhandle_t *fhp; 2085 uint32_t len; 2086 struct nfssvc_sock *slp; 2087 struct mbuf *nam; 2088 struct mbuf **mdp; 2089 caddr_t *dposp; 2090 struct vnode **retdirp; 2091 struct proc *p; 2092 int kerbflag, pubflag; 2093 { 2094 int i, rem; 2095 struct mbuf *md; 2096 char *fromcp, *tocp, *cp; 2097 struct iovec aiov; 2098 struct uio auio; 2099 struct vnode *dp; 2100 int error, rdonly, linklen; 2101 struct componentname *cnp = &ndp->ni_cnd; 2102 2103 *retdirp = (struct vnode *)0; 2104 2105 if ((len + 1) > MAXPATHLEN) 2106 return (ENAMETOOLONG); 2107 if (len == 0) 2108 return (EACCES); 2109 cnp->cn_pnbuf = PNBUF_GET(); 2110 2111 /* 2112 * Copy the name from the mbuf list to ndp->ni_pnbuf 2113 * and set the various ndp fields appropriately. 2114 */ 2115 fromcp = *dposp; 2116 tocp = cnp->cn_pnbuf; 2117 md = *mdp; 2118 rem = mtod(md, caddr_t) + md->m_len - fromcp; 2119 for (i = 0; i < len; i++) { 2120 while (rem == 0) { 2121 md = md->m_next; 2122 if (md == NULL) { 2123 error = EBADRPC; 2124 goto out; 2125 } 2126 fromcp = mtod(md, caddr_t); 2127 rem = md->m_len; 2128 } 2129 if (*fromcp == '\0' || (!pubflag && *fromcp == '/')) { 2130 error = EACCES; 2131 goto out; 2132 } 2133 *tocp++ = *fromcp++; 2134 rem--; 2135 } 2136 *tocp = '\0'; 2137 *mdp = md; 2138 *dposp = fromcp; 2139 len = nfsm_rndup(len)-len; 2140 if (len > 0) { 2141 if (rem >= len) 2142 *dposp += len; 2143 else if ((error = nfs_adv(mdp, dposp, len, rem)) != 0) 2144 goto out; 2145 } 2146 2147 /* 2148 * Extract and set starting directory. 2149 */ 2150 error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp, 2151 nam, &rdonly, kerbflag, pubflag); 2152 if (error) 2153 goto out; 2154 if (dp->v_type != VDIR) { 2155 vrele(dp); 2156 error = ENOTDIR; 2157 goto out; 2158 } 2159 2160 if (rdonly) 2161 cnp->cn_flags |= RDONLY; 2162 2163 *retdirp = dp; 2164 2165 if (pubflag) { 2166 /* 2167 * Oh joy. For WebNFS, handle those pesky '%' escapes, 2168 * and the 'native path' indicator. 2169 */ 2170 cp = PNBUF_GET(); 2171 fromcp = cnp->cn_pnbuf; 2172 tocp = cp; 2173 if ((unsigned char)*fromcp >= WEBNFS_SPECCHAR_START) { 2174 switch ((unsigned char)*fromcp) { 2175 case WEBNFS_NATIVE_CHAR: 2176 /* 2177 * 'Native' path for us is the same 2178 * as a path according to the NFS spec, 2179 * just skip the escape char. 2180 */ 2181 fromcp++; 2182 break; 2183 /* 2184 * More may be added in the future, range 0x80-0xff 2185 */ 2186 default: 2187 error = EIO; 2188 PNBUF_PUT(cp); 2189 goto out; 2190 } 2191 } 2192 /* 2193 * Translate the '%' escapes, URL-style. 2194 */ 2195 while (*fromcp != '\0') { 2196 if (*fromcp == WEBNFS_ESC_CHAR) { 2197 if (fromcp[1] != '\0' && fromcp[2] != '\0') { 2198 fromcp++; 2199 *tocp++ = HEXSTRTOI(fromcp); 2200 fromcp += 2; 2201 continue; 2202 } else { 2203 error = ENOENT; 2204 PNBUF_PUT(cp); 2205 goto out; 2206 } 2207 } else 2208 *tocp++ = *fromcp++; 2209 } 2210 *tocp = '\0'; 2211 PNBUF_PUT(cnp->cn_pnbuf); 2212 cnp->cn_pnbuf = cp; 2213 } 2214 2215 ndp->ni_pathlen = (tocp - cnp->cn_pnbuf) + 1; 2216 ndp->ni_segflg = UIO_SYSSPACE; 2217 ndp->ni_rootdir = rootvnode; 2218 2219 if (pubflag) { 2220 ndp->ni_loopcnt = 0; 2221 if (cnp->cn_pnbuf[0] == '/') 2222 dp = rootvnode; 2223 } else { 2224 cnp->cn_flags |= NOCROSSMOUNT; 2225 } 2226 2227 cnp->cn_proc = p; 2228 VREF(dp); 2229 2230 for (;;) { 2231 cnp->cn_nameptr = cnp->cn_pnbuf; 2232 ndp->ni_startdir = dp; 2233 /* 2234 * And call lookup() to do the real work 2235 */ 2236 error = lookup(ndp); 2237 if (error) { 2238 PNBUF_PUT(cnp->cn_pnbuf); 2239 return (error); 2240 } 2241 /* 2242 * Check for encountering a symbolic link 2243 */ 2244 if ((cnp->cn_flags & ISSYMLINK) == 0) { 2245 if (cnp->cn_flags & (SAVENAME | SAVESTART)) 2246 cnp->cn_flags |= HASBUF; 2247 else 2248 PNBUF_PUT(cnp->cn_pnbuf); 2249 return (0); 2250 } else { 2251 if ((cnp->cn_flags & LOCKPARENT) && (cnp->cn_flags & ISLASTCN)) 2252 VOP_UNLOCK(ndp->ni_dvp, 0); 2253 if (!pubflag) { 2254 error = EINVAL; 2255 break; 2256 } 2257 2258 if (ndp->ni_loopcnt++ >= MAXSYMLINKS) { 2259 error = ELOOP; 2260 break; 2261 } 2262 if (ndp->ni_vp->v_mount->mnt_flag & MNT_SYMPERM) { 2263 error = VOP_ACCESS(ndp->ni_vp, VEXEC, cnp->cn_cred, 2264 cnp->cn_proc); 2265 if (error != 0) 2266 break; 2267 } 2268 if (ndp->ni_pathlen > 1) 2269 cp = PNBUF_GET(); 2270 else 2271 cp = cnp->cn_pnbuf; 2272 aiov.iov_base = cp; 2273 aiov.iov_len = MAXPATHLEN; 2274 auio.uio_iov = &aiov; 2275 auio.uio_iovcnt = 1; 2276 auio.uio_offset = 0; 2277 auio.uio_rw = UIO_READ; 2278 auio.uio_segflg = UIO_SYSSPACE; 2279 auio.uio_procp = NULL; 2280 auio.uio_resid = MAXPATHLEN; 2281 error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred); 2282 if (error) { 2283 badlink: 2284 if (ndp->ni_pathlen > 1) 2285 PNBUF_PUT(cp); 2286 break; 2287 } 2288 linklen = MAXPATHLEN - auio.uio_resid; 2289 if (linklen == 0) { 2290 error = ENOENT; 2291 goto badlink; 2292 } 2293 if (linklen + ndp->ni_pathlen >= MAXPATHLEN) { 2294 error = ENAMETOOLONG; 2295 goto badlink; 2296 } 2297 if (ndp->ni_pathlen > 1) { 2298 memcpy(cp + linklen, ndp->ni_next, ndp->ni_pathlen); 2299 PNBUF_PUT(cnp->cn_pnbuf); 2300 cnp->cn_pnbuf = cp; 2301 } else 2302 cnp->cn_pnbuf[linklen] = '\0'; 2303 ndp->ni_pathlen += linklen; 2304 vput(ndp->ni_vp); 2305 dp = ndp->ni_dvp; 2306 /* 2307 * Check if root directory should replace current directory. 2308 */ 2309 if (cnp->cn_pnbuf[0] == '/') { 2310 vrele(dp); 2311 dp = ndp->ni_rootdir; 2312 VREF(dp); 2313 } 2314 } 2315 } 2316 vrele(ndp->ni_dvp); 2317 vput(ndp->ni_vp); 2318 ndp->ni_vp = NULL; 2319 out: 2320 PNBUF_PUT(cnp->cn_pnbuf); 2321 return (error); 2322 } 2323 2324 /* 2325 * A fiddled version of m_adj() that ensures null fill to a 32-bit 2326 * boundary and only trims off the back end 2327 * 2328 * 1. trim off 'len' bytes as m_adj(mp, -len). 2329 * 2. add zero-padding 'nul' bytes at the end of the mbuf chain. 2330 */ 2331 void 2332 nfs_zeropad(mp, len, nul) 2333 struct mbuf *mp; 2334 int len; 2335 int nul; 2336 { 2337 struct mbuf *m; 2338 int count; 2339 2340 /* 2341 * Trim from tail. Scan the mbuf chain, 2342 * calculating its length and finding the last mbuf. 2343 * If the adjustment only affects this mbuf, then just 2344 * adjust and return. Otherwise, rescan and truncate 2345 * after the remaining size. 2346 */ 2347 count = 0; 2348 m = mp; 2349 for (;;) { 2350 count += m->m_len; 2351 if (m->m_next == NULL) 2352 break; 2353 m = m->m_next; 2354 } 2355 2356 KDASSERT(count >= len); 2357 2358 if (m->m_len >= len) { 2359 m->m_len -= len; 2360 } else { 2361 count -= len; 2362 /* 2363 * Correct length for chain is "count". 2364 * Find the mbuf with last data, adjust its length, 2365 * and toss data from remaining mbufs on chain. 2366 */ 2367 for (m = mp; m; m = m->m_next) { 2368 if (m->m_len >= count) { 2369 m->m_len = count; 2370 break; 2371 } 2372 count -= m->m_len; 2373 } 2374 m_freem(m->m_next); 2375 m->m_next = NULL; 2376 } 2377 2378 KDASSERT(m->m_next == NULL); 2379 2380 /* 2381 * zero-padding. 2382 */ 2383 if (nul > 0) { 2384 char *cp; 2385 int i; 2386 2387 if (M_ROMAP(m) || M_TRAILINGSPACE(m) < nul) { 2388 struct mbuf *n; 2389 2390 KDASSERT(MLEN >= nul); 2391 n = m_get(M_WAIT, MT_DATA); 2392 MCLAIM(n, &nfs_mowner); 2393 n->m_len = nul; 2394 n->m_next = NULL; 2395 m->m_next = n; 2396 cp = mtod(n, caddr_t); 2397 } else { 2398 cp = mtod(m, caddr_t) + m->m_len; 2399 m->m_len += nul; 2400 } 2401 for (i = 0; i < nul; i++) 2402 *cp++ = '\0'; 2403 } 2404 return; 2405 } 2406 2407 /* 2408 * Make these functions instead of macros, so that the kernel text size 2409 * doesn't get too big... 2410 */ 2411 void 2412 nfsm_srvwcc(nfsd, before_ret, before_vap, after_ret, after_vap, mbp, bposp) 2413 struct nfsrv_descript *nfsd; 2414 int before_ret; 2415 struct vattr *before_vap; 2416 int after_ret; 2417 struct vattr *after_vap; 2418 struct mbuf **mbp; 2419 char **bposp; 2420 { 2421 struct mbuf *mb = *mbp; 2422 char *bpos = *bposp; 2423 u_int32_t *tl; 2424 2425 if (before_ret) { 2426 nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); 2427 *tl = nfs_false; 2428 } else { 2429 nfsm_build(tl, u_int32_t *, 7 * NFSX_UNSIGNED); 2430 *tl++ = nfs_true; 2431 txdr_hyper(before_vap->va_size, tl); 2432 tl += 2; 2433 txdr_nfsv3time(&(before_vap->va_mtime), tl); 2434 tl += 2; 2435 txdr_nfsv3time(&(before_vap->va_ctime), tl); 2436 } 2437 *bposp = bpos; 2438 *mbp = mb; 2439 nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp); 2440 } 2441 2442 void 2443 nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp) 2444 struct nfsrv_descript *nfsd; 2445 int after_ret; 2446 struct vattr *after_vap; 2447 struct mbuf **mbp; 2448 char **bposp; 2449 { 2450 struct mbuf *mb = *mbp; 2451 char *bpos = *bposp; 2452 u_int32_t *tl; 2453 struct nfs_fattr *fp; 2454 2455 if (after_ret) { 2456 nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); 2457 *tl = nfs_false; 2458 } else { 2459 nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_V3FATTR); 2460 *tl++ = nfs_true; 2461 fp = (struct nfs_fattr *)tl; 2462 nfsm_srvfattr(nfsd, after_vap, fp); 2463 } 2464 *mbp = mb; 2465 *bposp = bpos; 2466 } 2467 2468 void 2469 nfsm_srvfattr(nfsd, vap, fp) 2470 struct nfsrv_descript *nfsd; 2471 struct vattr *vap; 2472 struct nfs_fattr *fp; 2473 { 2474 2475 fp->fa_nlink = txdr_unsigned(vap->va_nlink); 2476 fp->fa_uid = txdr_unsigned(vap->va_uid); 2477 fp->fa_gid = txdr_unsigned(vap->va_gid); 2478 if (nfsd->nd_flag & ND_NFSV3) { 2479 fp->fa_type = vtonfsv3_type(vap->va_type); 2480 fp->fa_mode = vtonfsv3_mode(vap->va_mode); 2481 txdr_hyper(vap->va_size, &fp->fa3_size); 2482 txdr_hyper(vap->va_bytes, &fp->fa3_used); 2483 fp->fa3_rdev.specdata1 = txdr_unsigned(major(vap->va_rdev)); 2484 fp->fa3_rdev.specdata2 = txdr_unsigned(minor(vap->va_rdev)); 2485 fp->fa3_fsid.nfsuquad[0] = 0; 2486 fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid); 2487 fp->fa3_fileid.nfsuquad[0] = 0; 2488 fp->fa3_fileid.nfsuquad[1] = txdr_unsigned(vap->va_fileid); 2489 txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime); 2490 txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime); 2491 txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime); 2492 } else { 2493 fp->fa_type = vtonfsv2_type(vap->va_type); 2494 fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode); 2495 fp->fa2_size = txdr_unsigned(vap->va_size); 2496 fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize); 2497 if (vap->va_type == VFIFO) 2498 fp->fa2_rdev = 0xffffffff; 2499 else 2500 fp->fa2_rdev = txdr_unsigned(vap->va_rdev); 2501 fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE); 2502 fp->fa2_fsid = txdr_unsigned(vap->va_fsid); 2503 fp->fa2_fileid = txdr_unsigned(vap->va_fileid); 2504 txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime); 2505 txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime); 2506 txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime); 2507 } 2508 } 2509 2510 /* 2511 * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked) 2512 * - look up fsid in mount list (if not found ret error) 2513 * - get vp and export rights by calling VFS_FHTOVP() 2514 * - if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon 2515 * - if not lockflag unlock it with VOP_UNLOCK() 2516 */ 2517 int 2518 nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp, kerbflag, pubflag) 2519 fhandle_t *fhp; 2520 int lockflag; 2521 struct vnode **vpp; 2522 struct ucred *cred; 2523 struct nfssvc_sock *slp; 2524 struct mbuf *nam; 2525 int *rdonlyp; 2526 int kerbflag; 2527 { 2528 struct mount *mp; 2529 int i; 2530 struct ucred *credanon; 2531 int error, exflags; 2532 struct sockaddr_in *saddr; 2533 2534 *vpp = (struct vnode *)0; 2535 2536 if (nfs_ispublicfh(fhp)) { 2537 if (!pubflag || !nfs_pub.np_valid) 2538 return (ESTALE); 2539 fhp = &nfs_pub.np_handle; 2540 } 2541 2542 mp = vfs_getvfs(&fhp->fh_fsid); 2543 if (!mp) 2544 return (ESTALE); 2545 error = VFS_CHECKEXP(mp, nam, &exflags, &credanon); 2546 if (error) 2547 return (error); 2548 error = VFS_FHTOVP(mp, &fhp->fh_fid, vpp); 2549 if (error) 2550 return (error); 2551 2552 if (!(exflags & (MNT_EXNORESPORT|MNT_EXPUBLIC))) { 2553 saddr = mtod(nam, struct sockaddr_in *); 2554 if ((saddr->sin_family == AF_INET) && 2555 ntohs(saddr->sin_port) >= IPPORT_RESERVED) { 2556 vput(*vpp); 2557 return (NFSERR_AUTHERR | AUTH_TOOWEAK); 2558 } 2559 #ifdef INET6 2560 if ((saddr->sin_family == AF_INET6) && 2561 ntohs(saddr->sin_port) >= IPV6PORT_RESERVED) { 2562 vput(*vpp); 2563 return (NFSERR_AUTHERR | AUTH_TOOWEAK); 2564 } 2565 #endif 2566 } 2567 /* 2568 * Check/setup credentials. 2569 */ 2570 if (exflags & MNT_EXKERB) { 2571 if (!kerbflag) { 2572 vput(*vpp); 2573 return (NFSERR_AUTHERR | AUTH_TOOWEAK); 2574 } 2575 } else if (kerbflag) { 2576 vput(*vpp); 2577 return (NFSERR_AUTHERR | AUTH_TOOWEAK); 2578 } else if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) { 2579 cred->cr_uid = credanon->cr_uid; 2580 cred->cr_gid = credanon->cr_gid; 2581 for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++) 2582 cred->cr_groups[i] = credanon->cr_groups[i]; 2583 cred->cr_ngroups = i; 2584 } 2585 if (exflags & MNT_EXRDONLY) 2586 *rdonlyp = 1; 2587 else 2588 *rdonlyp = 0; 2589 if (!lockflag) 2590 VOP_UNLOCK(*vpp, 0); 2591 return (0); 2592 } 2593 2594 /* 2595 * WebNFS: check if a filehandle is a public filehandle. For v3, this 2596 * means a length of 0, for v2 it means all zeroes. nfsm_srvmtofh has 2597 * transformed this to all zeroes in both cases, so check for it. 2598 */ 2599 int 2600 nfs_ispublicfh(fhp) 2601 fhandle_t *fhp; 2602 { 2603 char *cp = (char *)fhp; 2604 int i; 2605 2606 for (i = 0; i < NFSX_V3FH; i++) 2607 if (*cp++ != 0) 2608 return (FALSE); 2609 return (TRUE); 2610 } 2611 2612 /* 2613 * This function compares two net addresses by family and returns TRUE 2614 * if they are the same host. 2615 * If there is any doubt, return FALSE. 2616 * The AF_INET family is handled as a special case so that address mbufs 2617 * don't need to be saved to store "struct in_addr", which is only 4 bytes. 2618 */ 2619 int 2620 netaddr_match(family, haddr, nam) 2621 int family; 2622 union nethostaddr *haddr; 2623 struct mbuf *nam; 2624 { 2625 struct sockaddr_in *inetaddr; 2626 2627 switch (family) { 2628 case AF_INET: 2629 inetaddr = mtod(nam, struct sockaddr_in *); 2630 if (inetaddr->sin_family == AF_INET && 2631 inetaddr->sin_addr.s_addr == haddr->had_inetaddr) 2632 return (1); 2633 break; 2634 #ifdef INET6 2635 case AF_INET6: 2636 { 2637 struct sockaddr_in6 *sin6_1, *sin6_2; 2638 2639 sin6_1 = mtod(nam, struct sockaddr_in6 *); 2640 sin6_2 = mtod(haddr->had_nam, struct sockaddr_in6 *); 2641 if (sin6_1->sin6_family == AF_INET6 && 2642 IN6_ARE_ADDR_EQUAL(&sin6_1->sin6_addr, &sin6_2->sin6_addr)) 2643 return 1; 2644 } 2645 #endif 2646 #ifdef ISO 2647 case AF_ISO: 2648 { 2649 struct sockaddr_iso *isoaddr1, *isoaddr2; 2650 2651 isoaddr1 = mtod(nam, struct sockaddr_iso *); 2652 isoaddr2 = mtod(haddr->had_nam, struct sockaddr_iso *); 2653 if (isoaddr1->siso_family == AF_ISO && 2654 isoaddr1->siso_nlen > 0 && 2655 isoaddr1->siso_nlen == isoaddr2->siso_nlen && 2656 SAME_ISOADDR(isoaddr1, isoaddr2)) 2657 return (1); 2658 break; 2659 } 2660 #endif /* ISO */ 2661 default: 2662 break; 2663 }; 2664 return (0); 2665 } 2666 2667 /* 2668 * The write verifier has changed (probably due to a server reboot), so all 2669 * PG_NEEDCOMMIT pages will have to be written again. Since they are marked 2670 * as dirty or are being written out just now, all this takes is clearing 2671 * the PG_NEEDCOMMIT flag. Once done the new write verifier can be set for 2672 * the mount point. 2673 */ 2674 void 2675 nfs_clearcommit(mp) 2676 struct mount *mp; 2677 { 2678 struct vnode *vp; 2679 struct nfsnode *np; 2680 struct vm_page *pg; 2681 struct nfsmount *nmp = VFSTONFS(mp); 2682 2683 lockmgr(&nmp->nm_writeverflock, LK_EXCLUSIVE, NULL); 2684 2685 LIST_FOREACH(vp, &mp->mnt_vnodelist, v_mntvnodes) { 2686 KASSERT(vp->v_mount == mp); 2687 if (vp->v_type != VREG) 2688 continue; 2689 np = VTONFS(vp); 2690 np->n_pushlo = np->n_pushhi = np->n_pushedlo = 2691 np->n_pushedhi = 0; 2692 np->n_commitflags &= 2693 ~(NFS_COMMIT_PUSH_VALID | NFS_COMMIT_PUSHED_VALID); 2694 simple_lock(&vp->v_uobj.vmobjlock); 2695 TAILQ_FOREACH(pg, &vp->v_uobj.memq, listq) { 2696 pg->flags &= ~PG_NEEDCOMMIT; 2697 } 2698 simple_unlock(&vp->v_uobj.vmobjlock); 2699 } 2700 simple_lock(&nmp->nm_slock); 2701 nmp->nm_iflag &= ~NFSMNT_STALEWRITEVERF; 2702 simple_unlock(&nmp->nm_slock); 2703 lockmgr(&nmp->nm_writeverflock, LK_RELEASE, NULL); 2704 } 2705 2706 void 2707 nfs_merge_commit_ranges(vp) 2708 struct vnode *vp; 2709 { 2710 struct nfsnode *np = VTONFS(vp); 2711 2712 KASSERT(np->n_commitflags & NFS_COMMIT_PUSH_VALID); 2713 2714 if (!(np->n_commitflags & NFS_COMMIT_PUSHED_VALID)) { 2715 np->n_pushedlo = np->n_pushlo; 2716 np->n_pushedhi = np->n_pushhi; 2717 np->n_commitflags |= NFS_COMMIT_PUSHED_VALID; 2718 } else { 2719 if (np->n_pushlo < np->n_pushedlo) 2720 np->n_pushedlo = np->n_pushlo; 2721 if (np->n_pushhi > np->n_pushedhi) 2722 np->n_pushedhi = np->n_pushhi; 2723 } 2724 2725 np->n_pushlo = np->n_pushhi = 0; 2726 np->n_commitflags &= ~NFS_COMMIT_PUSH_VALID; 2727 2728 #ifdef NFS_DEBUG_COMMIT 2729 printf("merge: committed: %u - %u\n", (unsigned)np->n_pushedlo, 2730 (unsigned)np->n_pushedhi); 2731 #endif 2732 } 2733 2734 int 2735 nfs_in_committed_range(vp, off, len) 2736 struct vnode *vp; 2737 off_t off, len; 2738 { 2739 struct nfsnode *np = VTONFS(vp); 2740 off_t lo, hi; 2741 2742 if (!(np->n_commitflags & NFS_COMMIT_PUSHED_VALID)) 2743 return 0; 2744 lo = off; 2745 hi = lo + len; 2746 2747 return (lo >= np->n_pushedlo && hi <= np->n_pushedhi); 2748 } 2749 2750 int 2751 nfs_in_tobecommitted_range(vp, off, len) 2752 struct vnode *vp; 2753 off_t off, len; 2754 { 2755 struct nfsnode *np = VTONFS(vp); 2756 off_t lo, hi; 2757 2758 if (!(np->n_commitflags & NFS_COMMIT_PUSH_VALID)) 2759 return 0; 2760 lo = off; 2761 hi = lo + len; 2762 2763 return (lo >= np->n_pushlo && hi <= np->n_pushhi); 2764 } 2765 2766 void 2767 nfs_add_committed_range(vp, off, len) 2768 struct vnode *vp; 2769 off_t off, len; 2770 { 2771 struct nfsnode *np = VTONFS(vp); 2772 off_t lo, hi; 2773 2774 lo = off; 2775 hi = lo + len; 2776 2777 if (!(np->n_commitflags & NFS_COMMIT_PUSHED_VALID)) { 2778 np->n_pushedlo = lo; 2779 np->n_pushedhi = hi; 2780 np->n_commitflags |= NFS_COMMIT_PUSHED_VALID; 2781 } else { 2782 if (hi > np->n_pushedhi) 2783 np->n_pushedhi = hi; 2784 if (lo < np->n_pushedlo) 2785 np->n_pushedlo = lo; 2786 } 2787 #ifdef NFS_DEBUG_COMMIT 2788 printf("add: committed: %u - %u\n", (unsigned)np->n_pushedlo, 2789 (unsigned)np->n_pushedhi); 2790 #endif 2791 } 2792 2793 void 2794 nfs_del_committed_range(vp, off, len) 2795 struct vnode *vp; 2796 off_t off, len; 2797 { 2798 struct nfsnode *np = VTONFS(vp); 2799 off_t lo, hi; 2800 2801 if (!(np->n_commitflags & NFS_COMMIT_PUSHED_VALID)) 2802 return; 2803 2804 lo = off; 2805 hi = lo + len; 2806 2807 if (lo > np->n_pushedhi || hi < np->n_pushedlo) 2808 return; 2809 if (lo <= np->n_pushedlo) 2810 np->n_pushedlo = hi; 2811 else if (hi >= np->n_pushedhi) 2812 np->n_pushedhi = lo; 2813 else { 2814 /* 2815 * XXX There's only one range. If the deleted range 2816 * is in the middle, pick the largest of the 2817 * contiguous ranges that it leaves. 2818 */ 2819 if ((np->n_pushedlo - lo) > (hi - np->n_pushedhi)) 2820 np->n_pushedhi = lo; 2821 else 2822 np->n_pushedlo = hi; 2823 } 2824 #ifdef NFS_DEBUG_COMMIT 2825 printf("del: committed: %u - %u\n", (unsigned)np->n_pushedlo, 2826 (unsigned)np->n_pushedhi); 2827 #endif 2828 } 2829 2830 void 2831 nfs_add_tobecommitted_range(vp, off, len) 2832 struct vnode *vp; 2833 off_t off, len; 2834 { 2835 struct nfsnode *np = VTONFS(vp); 2836 off_t lo, hi; 2837 2838 lo = off; 2839 hi = lo + len; 2840 2841 if (!(np->n_commitflags & NFS_COMMIT_PUSH_VALID)) { 2842 np->n_pushlo = lo; 2843 np->n_pushhi = hi; 2844 np->n_commitflags |= NFS_COMMIT_PUSH_VALID; 2845 } else { 2846 if (lo < np->n_pushlo) 2847 np->n_pushlo = lo; 2848 if (hi > np->n_pushhi) 2849 np->n_pushhi = hi; 2850 } 2851 #ifdef NFS_DEBUG_COMMIT 2852 printf("add: tobecommitted: %u - %u\n", (unsigned)np->n_pushlo, 2853 (unsigned)np->n_pushhi); 2854 #endif 2855 } 2856 2857 void 2858 nfs_del_tobecommitted_range(vp, off, len) 2859 struct vnode *vp; 2860 off_t off, len; 2861 { 2862 struct nfsnode *np = VTONFS(vp); 2863 off_t lo, hi; 2864 2865 if (!(np->n_commitflags & NFS_COMMIT_PUSH_VALID)) 2866 return; 2867 2868 lo = off; 2869 hi = lo + len; 2870 2871 if (lo > np->n_pushhi || hi < np->n_pushlo) 2872 return; 2873 2874 if (lo <= np->n_pushlo) 2875 np->n_pushlo = hi; 2876 else if (hi >= np->n_pushhi) 2877 np->n_pushhi = lo; 2878 else { 2879 /* 2880 * XXX There's only one range. If the deleted range 2881 * is in the middle, pick the largest of the 2882 * contiguous ranges that it leaves. 2883 */ 2884 if ((np->n_pushlo - lo) > (hi - np->n_pushhi)) 2885 np->n_pushhi = lo; 2886 else 2887 np->n_pushlo = hi; 2888 } 2889 #ifdef NFS_DEBUG_COMMIT 2890 printf("del: tobecommitted: %u - %u\n", (unsigned)np->n_pushlo, 2891 (unsigned)np->n_pushhi); 2892 #endif 2893 } 2894 2895 /* 2896 * Map errnos to NFS error numbers. For Version 3 also filter out error 2897 * numbers not specified for the associated procedure. 2898 */ 2899 int 2900 nfsrv_errmap(nd, err) 2901 struct nfsrv_descript *nd; 2902 int err; 2903 { 2904 const short *defaulterrp, *errp; 2905 2906 if (nd->nd_flag & ND_NFSV3) { 2907 if (nd->nd_procnum <= NFSPROC_COMMIT) { 2908 errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum]; 2909 while (*++errp) { 2910 if (*errp == err) 2911 return (err); 2912 else if (*errp > err) 2913 break; 2914 } 2915 return ((int)*defaulterrp); 2916 } else 2917 return (err & 0xffff); 2918 } 2919 if (err <= ELAST) 2920 return ((int)nfsrv_v2errmap[err - 1]); 2921 return (NFSERR_IO); 2922 } 2923 2924 /* 2925 * Sort the group list in increasing numerical order. 2926 * (Insertion sort by Chris Torek, who was grossed out by the bubble sort 2927 * that used to be here.) 2928 */ 2929 void 2930 nfsrvw_sort(list, num) 2931 gid_t *list; 2932 int num; 2933 { 2934 int i, j; 2935 gid_t v; 2936 2937 /* Insertion sort. */ 2938 for (i = 1; i < num; i++) { 2939 v = list[i]; 2940 /* find correct slot for value v, moving others up */ 2941 for (j = i; --j >= 0 && v < list[j];) 2942 list[j + 1] = list[j]; 2943 list[j + 1] = v; 2944 } 2945 } 2946 2947 /* 2948 * copy credentials making sure that the result can be compared with memcmp(). 2949 */ 2950 void 2951 nfsrv_setcred(incred, outcred) 2952 struct ucred *incred, *outcred; 2953 { 2954 int i; 2955 2956 memset((caddr_t)outcred, 0, sizeof (struct ucred)); 2957 outcred->cr_ref = 1; 2958 outcred->cr_uid = incred->cr_uid; 2959 outcred->cr_gid = incred->cr_gid; 2960 outcred->cr_ngroups = incred->cr_ngroups; 2961 for (i = 0; i < incred->cr_ngroups; i++) 2962 outcred->cr_groups[i] = incred->cr_groups[i]; 2963 nfsrvw_sort(outcred->cr_groups, outcred->cr_ngroups); 2964 } 2965 2966 u_int32_t 2967 nfs_getxid() 2968 { 2969 static u_int32_t base; 2970 static u_int32_t nfs_xid = 0; 2971 static struct simplelock nfs_xidlock = SIMPLELOCK_INITIALIZER; 2972 u_int32_t newxid; 2973 2974 simple_lock(&nfs_xidlock); 2975 /* 2976 * derive initial xid from system time 2977 * XXX time is invalid if root not yet mounted 2978 */ 2979 if (__predict_false(!base && (rootvp))) { 2980 struct timeval tv; 2981 2982 microtime(&tv); 2983 base = tv.tv_sec << 12; 2984 nfs_xid = base; 2985 } 2986 2987 /* 2988 * Skip zero xid if it should ever happen. 2989 */ 2990 if (__predict_false(++nfs_xid == 0)) 2991 nfs_xid++; 2992 newxid = nfs_xid; 2993 simple_unlock(&nfs_xidlock); 2994 2995 return txdr_unsigned(newxid); 2996 } 2997 2998 /* 2999 * assign a new xid for existing request. 3000 * used for NFSERR_JUKEBOX handling. 3001 */ 3002 void 3003 nfs_renewxid(struct nfsreq *req) 3004 { 3005 u_int32_t xid; 3006 int off; 3007 3008 xid = nfs_getxid(); 3009 if (req->r_nmp->nm_sotype == SOCK_STREAM) 3010 off = sizeof(u_int32_t); /* RPC record mark */ 3011 else 3012 off = 0; 3013 3014 m_copyback(req->r_mreq, off, sizeof(xid), (void *)&xid); 3015 req->r_xid = xid; 3016 } 3017