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