1 /* $OpenBSD: nfs_subs.c,v 1.32 2001/06/27 04:58:46 art Exp $ */ 2 /* $NetBSD: nfs_subs.c,v 1.27.4.3 1996/07/08 20:34:24 jtc Exp $ */ 3 4 /* 5 * Copyright (c) 1989, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * This code is derived from software contributed to Berkeley by 9 * Rick Macklem at The University of Guelph. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by the University of 22 * California, Berkeley and its contributors. 23 * 4. Neither the name of the University nor the names of its contributors 24 * may be used to endorse or promote products derived from this software 25 * without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 37 * SUCH DAMAGE. 38 * 39 * @(#)nfs_subs.c 8.8 (Berkeley) 5/22/95 40 */ 41 42 43 /* 44 * These functions support the macros and help fiddle mbuf chains for 45 * the nfs op functions. They do things like create the rpc header and 46 * copy data between mbuf chains and uio lists. 47 */ 48 #include <sys/param.h> 49 #include <sys/proc.h> 50 #include <sys/systm.h> 51 #include <sys/kernel.h> 52 #include <sys/mount.h> 53 #include <sys/vnode.h> 54 #include <sys/namei.h> 55 #include <sys/mbuf.h> 56 #include <sys/socket.h> 57 #include <sys/socketvar.h> 58 #include <sys/stat.h> 59 #include <sys/malloc.h> 60 #include <sys/time.h> 61 62 #include <vm/vm.h> 63 64 #include <nfs/rpcv2.h> 65 #include <nfs/nfsproto.h> 66 #include <nfs/nfsnode.h> 67 #include <nfs/nfs.h> 68 #include <nfs/xdr_subs.h> 69 #include <nfs/nfsm_subs.h> 70 #include <nfs/nfsmount.h> 71 #include <nfs/nfsrtt.h> 72 #include <nfs/nfs_var.h> 73 74 #include <miscfs/specfs/specdev.h> 75 76 #include <vm/vm.h> 77 78 #include <netinet/in.h> 79 #ifdef ISO 80 #include <netiso/iso.h> 81 #endif 82 83 #include <dev/rndvar.h> 84 85 #ifdef __GNUC__ 86 #define INLINE __inline 87 #else 88 #define INLINE 89 #endif 90 91 int nfs_attrtimeo __P((struct nfsnode *np)); 92 93 /* 94 * Data items converted to xdr at startup, since they are constant 95 * This is kinda hokey, but may save a little time doing byte swaps 96 */ 97 u_int32_t nfs_xdrneg1; 98 u_int32_t rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr, 99 rpc_mismatch, rpc_auth_unix, rpc_msgaccepted, 100 rpc_auth_kerb; 101 u_int32_t nfs_prog, nfs_true, nfs_false; 102 103 /* And other global data */ 104 static u_int32_t nfs_xid = 0; 105 static u_int32_t nfs_xid_touched = 0; 106 nfstype nfsv2_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFNON, 107 NFCHR, NFNON }; 108 nfstype nfsv3_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK, 109 NFFIFO, NFNON }; 110 enum vtype nv2tov_type[8] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON }; 111 enum vtype nv3tov_type[8]={ VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO }; 112 int nfs_ticks; 113 114 /* 115 * Mapping of old NFS Version 2 RPC numbers to generic numbers. 116 */ 117 int nfsv3_procid[NFS_NPROCS] = { 118 NFSPROC_NULL, 119 NFSPROC_GETATTR, 120 NFSPROC_SETATTR, 121 NFSPROC_NOOP, 122 NFSPROC_LOOKUP, 123 NFSPROC_READLINK, 124 NFSPROC_READ, 125 NFSPROC_NOOP, 126 NFSPROC_WRITE, 127 NFSPROC_CREATE, 128 NFSPROC_REMOVE, 129 NFSPROC_RENAME, 130 NFSPROC_LINK, 131 NFSPROC_SYMLINK, 132 NFSPROC_MKDIR, 133 NFSPROC_RMDIR, 134 NFSPROC_READDIR, 135 NFSPROC_FSSTAT, 136 NFSPROC_NOOP, 137 NFSPROC_NOOP, 138 NFSPROC_NOOP, 139 NFSPROC_NOOP, 140 NFSPROC_NOOP, 141 NFSPROC_NOOP, 142 NFSPROC_NOOP, 143 NFSPROC_NOOP 144 }; 145 146 /* 147 * and the reverse mapping from generic to Version 2 procedure numbers 148 */ 149 int nfsv2_procid[NFS_NPROCS] = { 150 NFSV2PROC_NULL, 151 NFSV2PROC_GETATTR, 152 NFSV2PROC_SETATTR, 153 NFSV2PROC_LOOKUP, 154 NFSV2PROC_NOOP, 155 NFSV2PROC_READLINK, 156 NFSV2PROC_READ, 157 NFSV2PROC_WRITE, 158 NFSV2PROC_CREATE, 159 NFSV2PROC_MKDIR, 160 NFSV2PROC_SYMLINK, 161 NFSV2PROC_CREATE, 162 NFSV2PROC_REMOVE, 163 NFSV2PROC_RMDIR, 164 NFSV2PROC_RENAME, 165 NFSV2PROC_LINK, 166 NFSV2PROC_READDIR, 167 NFSV2PROC_NOOP, 168 NFSV2PROC_STATFS, 169 NFSV2PROC_NOOP, 170 NFSV2PROC_NOOP, 171 NFSV2PROC_NOOP, 172 NFSV2PROC_NOOP, 173 NFSV2PROC_NOOP, 174 NFSV2PROC_NOOP, 175 NFSV2PROC_NOOP, 176 }; 177 178 /* 179 * Maps errno values to nfs error numbers. 180 * Use NFSERR_IO as the catch all for ones not specifically defined in 181 * RFC 1094. 182 */ 183 static u_char nfsrv_v2errmap[ELAST] = { 184 NFSERR_PERM, NFSERR_NOENT, NFSERR_IO, NFSERR_IO, NFSERR_IO, 185 NFSERR_NXIO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 186 NFSERR_IO, NFSERR_IO, NFSERR_ACCES, NFSERR_IO, NFSERR_IO, 187 NFSERR_IO, NFSERR_EXIST, NFSERR_IO, NFSERR_NODEV, NFSERR_NOTDIR, 188 NFSERR_ISDIR, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 189 NFSERR_IO, NFSERR_FBIG, NFSERR_NOSPC, NFSERR_IO, NFSERR_ROFS, 190 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 191 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 192 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 193 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 194 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 195 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 196 NFSERR_IO, NFSERR_IO, NFSERR_NAMETOL, NFSERR_IO, NFSERR_IO, 197 NFSERR_NOTEMPTY, NFSERR_IO, NFSERR_IO, NFSERR_DQUOT, NFSERR_STALE, 198 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 199 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 200 NFSERR_IO, 201 }; 202 203 /* 204 * Maps errno values to nfs error numbers. 205 * Although it is not obvious whether or not NFS clients really care if 206 * a returned error value is in the specified list for the procedure, the 207 * safest thing to do is filter them appropriately. For Version 2, the 208 * X/Open XNFS document is the only specification that defines error values 209 * for each RPC (The RFC simply lists all possible error values for all RPCs), 210 * so I have decided to not do this for Version 2. 211 * The first entry is the default error return and the rest are the valid 212 * errors for that RPC in increasing numeric order. 213 */ 214 static short nfsv3err_null[] = { 215 0, 216 0, 217 }; 218 219 static short nfsv3err_getattr[] = { 220 NFSERR_IO, 221 NFSERR_IO, 222 NFSERR_STALE, 223 NFSERR_BADHANDLE, 224 NFSERR_SERVERFAULT, 225 0, 226 }; 227 228 static short nfsv3err_setattr[] = { 229 NFSERR_IO, 230 NFSERR_PERM, 231 NFSERR_IO, 232 NFSERR_ACCES, 233 NFSERR_INVAL, 234 NFSERR_NOSPC, 235 NFSERR_ROFS, 236 NFSERR_DQUOT, 237 NFSERR_STALE, 238 NFSERR_BADHANDLE, 239 NFSERR_NOT_SYNC, 240 NFSERR_SERVERFAULT, 241 0, 242 }; 243 244 static short nfsv3err_lookup[] = { 245 NFSERR_IO, 246 NFSERR_NOENT, 247 NFSERR_IO, 248 NFSERR_ACCES, 249 NFSERR_NOTDIR, 250 NFSERR_NAMETOL, 251 NFSERR_STALE, 252 NFSERR_BADHANDLE, 253 NFSERR_SERVERFAULT, 254 0, 255 }; 256 257 static short nfsv3err_access[] = { 258 NFSERR_IO, 259 NFSERR_IO, 260 NFSERR_STALE, 261 NFSERR_BADHANDLE, 262 NFSERR_SERVERFAULT, 263 0, 264 }; 265 266 static short nfsv3err_readlink[] = { 267 NFSERR_IO, 268 NFSERR_IO, 269 NFSERR_ACCES, 270 NFSERR_INVAL, 271 NFSERR_STALE, 272 NFSERR_BADHANDLE, 273 NFSERR_NOTSUPP, 274 NFSERR_SERVERFAULT, 275 0, 276 }; 277 278 static short nfsv3err_read[] = { 279 NFSERR_IO, 280 NFSERR_IO, 281 NFSERR_NXIO, 282 NFSERR_ACCES, 283 NFSERR_INVAL, 284 NFSERR_STALE, 285 NFSERR_BADHANDLE, 286 NFSERR_SERVERFAULT, 287 0, 288 }; 289 290 static short nfsv3err_write[] = { 291 NFSERR_IO, 292 NFSERR_IO, 293 NFSERR_ACCES, 294 NFSERR_INVAL, 295 NFSERR_FBIG, 296 NFSERR_NOSPC, 297 NFSERR_ROFS, 298 NFSERR_DQUOT, 299 NFSERR_STALE, 300 NFSERR_BADHANDLE, 301 NFSERR_SERVERFAULT, 302 0, 303 }; 304 305 static short nfsv3err_create[] = { 306 NFSERR_IO, 307 NFSERR_IO, 308 NFSERR_ACCES, 309 NFSERR_EXIST, 310 NFSERR_NOTDIR, 311 NFSERR_NOSPC, 312 NFSERR_ROFS, 313 NFSERR_NAMETOL, 314 NFSERR_DQUOT, 315 NFSERR_STALE, 316 NFSERR_BADHANDLE, 317 NFSERR_NOTSUPP, 318 NFSERR_SERVERFAULT, 319 0, 320 }; 321 322 static short nfsv3err_mkdir[] = { 323 NFSERR_IO, 324 NFSERR_IO, 325 NFSERR_ACCES, 326 NFSERR_EXIST, 327 NFSERR_NOTDIR, 328 NFSERR_NOSPC, 329 NFSERR_ROFS, 330 NFSERR_NAMETOL, 331 NFSERR_DQUOT, 332 NFSERR_STALE, 333 NFSERR_BADHANDLE, 334 NFSERR_NOTSUPP, 335 NFSERR_SERVERFAULT, 336 0, 337 }; 338 339 static short nfsv3err_symlink[] = { 340 NFSERR_IO, 341 NFSERR_IO, 342 NFSERR_ACCES, 343 NFSERR_EXIST, 344 NFSERR_NOTDIR, 345 NFSERR_NOSPC, 346 NFSERR_ROFS, 347 NFSERR_NAMETOL, 348 NFSERR_DQUOT, 349 NFSERR_STALE, 350 NFSERR_BADHANDLE, 351 NFSERR_NOTSUPP, 352 NFSERR_SERVERFAULT, 353 0, 354 }; 355 356 static short nfsv3err_mknod[] = { 357 NFSERR_IO, 358 NFSERR_IO, 359 NFSERR_ACCES, 360 NFSERR_EXIST, 361 NFSERR_NOTDIR, 362 NFSERR_NOSPC, 363 NFSERR_ROFS, 364 NFSERR_NAMETOL, 365 NFSERR_DQUOT, 366 NFSERR_STALE, 367 NFSERR_BADHANDLE, 368 NFSERR_NOTSUPP, 369 NFSERR_SERVERFAULT, 370 NFSERR_BADTYPE, 371 0, 372 }; 373 374 static short nfsv3err_remove[] = { 375 NFSERR_IO, 376 NFSERR_NOENT, 377 NFSERR_IO, 378 NFSERR_ACCES, 379 NFSERR_NOTDIR, 380 NFSERR_ROFS, 381 NFSERR_NAMETOL, 382 NFSERR_STALE, 383 NFSERR_BADHANDLE, 384 NFSERR_SERVERFAULT, 385 0, 386 }; 387 388 static short nfsv3err_rmdir[] = { 389 NFSERR_IO, 390 NFSERR_NOENT, 391 NFSERR_IO, 392 NFSERR_ACCES, 393 NFSERR_EXIST, 394 NFSERR_NOTDIR, 395 NFSERR_INVAL, 396 NFSERR_ROFS, 397 NFSERR_NAMETOL, 398 NFSERR_NOTEMPTY, 399 NFSERR_STALE, 400 NFSERR_BADHANDLE, 401 NFSERR_NOTSUPP, 402 NFSERR_SERVERFAULT, 403 0, 404 }; 405 406 static short nfsv3err_rename[] = { 407 NFSERR_IO, 408 NFSERR_NOENT, 409 NFSERR_IO, 410 NFSERR_ACCES, 411 NFSERR_EXIST, 412 NFSERR_XDEV, 413 NFSERR_NOTDIR, 414 NFSERR_ISDIR, 415 NFSERR_INVAL, 416 NFSERR_NOSPC, 417 NFSERR_ROFS, 418 NFSERR_MLINK, 419 NFSERR_NAMETOL, 420 NFSERR_NOTEMPTY, 421 NFSERR_DQUOT, 422 NFSERR_STALE, 423 NFSERR_BADHANDLE, 424 NFSERR_NOTSUPP, 425 NFSERR_SERVERFAULT, 426 0, 427 }; 428 429 static short nfsv3err_link[] = { 430 NFSERR_IO, 431 NFSERR_IO, 432 NFSERR_ACCES, 433 NFSERR_EXIST, 434 NFSERR_XDEV, 435 NFSERR_NOTDIR, 436 NFSERR_INVAL, 437 NFSERR_NOSPC, 438 NFSERR_ROFS, 439 NFSERR_MLINK, 440 NFSERR_NAMETOL, 441 NFSERR_DQUOT, 442 NFSERR_STALE, 443 NFSERR_BADHANDLE, 444 NFSERR_NOTSUPP, 445 NFSERR_SERVERFAULT, 446 0, 447 }; 448 449 static short nfsv3err_readdir[] = { 450 NFSERR_IO, 451 NFSERR_IO, 452 NFSERR_ACCES, 453 NFSERR_NOTDIR, 454 NFSERR_STALE, 455 NFSERR_BADHANDLE, 456 NFSERR_BAD_COOKIE, 457 NFSERR_TOOSMALL, 458 NFSERR_SERVERFAULT, 459 0, 460 }; 461 462 static short nfsv3err_readdirplus[] = { 463 NFSERR_IO, 464 NFSERR_IO, 465 NFSERR_ACCES, 466 NFSERR_NOTDIR, 467 NFSERR_STALE, 468 NFSERR_BADHANDLE, 469 NFSERR_BAD_COOKIE, 470 NFSERR_NOTSUPP, 471 NFSERR_TOOSMALL, 472 NFSERR_SERVERFAULT, 473 0, 474 }; 475 476 static short nfsv3err_fsstat[] = { 477 NFSERR_IO, 478 NFSERR_IO, 479 NFSERR_STALE, 480 NFSERR_BADHANDLE, 481 NFSERR_SERVERFAULT, 482 0, 483 }; 484 485 static short nfsv3err_fsinfo[] = { 486 NFSERR_STALE, 487 NFSERR_STALE, 488 NFSERR_BADHANDLE, 489 NFSERR_SERVERFAULT, 490 0, 491 }; 492 493 static short nfsv3err_pathconf[] = { 494 NFSERR_STALE, 495 NFSERR_STALE, 496 NFSERR_BADHANDLE, 497 NFSERR_SERVERFAULT, 498 0, 499 }; 500 501 static short nfsv3err_commit[] = { 502 NFSERR_IO, 503 NFSERR_IO, 504 NFSERR_STALE, 505 NFSERR_BADHANDLE, 506 NFSERR_SERVERFAULT, 507 0, 508 }; 509 510 static short *nfsrv_v3errmap[] = { 511 nfsv3err_null, 512 nfsv3err_getattr, 513 nfsv3err_setattr, 514 nfsv3err_lookup, 515 nfsv3err_access, 516 nfsv3err_readlink, 517 nfsv3err_read, 518 nfsv3err_write, 519 nfsv3err_create, 520 nfsv3err_mkdir, 521 nfsv3err_symlink, 522 nfsv3err_mknod, 523 nfsv3err_remove, 524 nfsv3err_rmdir, 525 nfsv3err_rename, 526 nfsv3err_link, 527 nfsv3err_readdir, 528 nfsv3err_readdirplus, 529 nfsv3err_fsstat, 530 nfsv3err_fsinfo, 531 nfsv3err_pathconf, 532 nfsv3err_commit, 533 }; 534 535 extern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON]; 536 extern struct nfsrtt nfsrtt; 537 extern struct nfsstats nfsstats; 538 extern nfstype nfsv2_type[9]; 539 extern nfstype nfsv3_type[9]; 540 extern struct nfsnodehashhead *nfsnodehashtbl; 541 extern u_long nfsnodehash; 542 543 LIST_HEAD(nfsnodehashhead, nfsnode); 544 545 /* 546 * Create the header for an rpc request packet 547 * The hsiz is the size of the rest of the nfs request header. 548 * (just used to decide if a cluster is a good idea) 549 */ 550 struct mbuf * 551 nfsm_reqh(vp, procid, hsiz, bposp) 552 struct vnode *vp; 553 u_long procid; 554 int hsiz; 555 caddr_t *bposp; 556 { 557 register struct mbuf *mb; 558 register caddr_t bpos; 559 560 MGET(mb, M_WAIT, MT_DATA); 561 if (hsiz >= MINCLSIZE) 562 MCLGET(mb, M_WAIT); 563 mb->m_len = 0; 564 bpos = mtod(mb, caddr_t); 565 566 /* Finally, return values */ 567 *bposp = bpos; 568 return (mb); 569 } 570 571 /* 572 * Build the RPC header and fill in the authorization info. 573 * The authorization string argument is only used when the credentials 574 * come from outside of the kernel. 575 * Returns the head of the mbuf list. 576 */ 577 struct mbuf * 578 nfsm_rpchead(cr, nmflag, procid, auth_type, auth_len, auth_str, verf_len, 579 verf_str, mrest, mrest_len, mbp, xidp) 580 register struct ucred *cr; 581 int nmflag; 582 int procid; 583 int auth_type; 584 int auth_len; 585 char *auth_str; 586 int verf_len; 587 char *verf_str; 588 struct mbuf *mrest; 589 int mrest_len; 590 struct mbuf **mbp; 591 u_int32_t *xidp; 592 { 593 register struct mbuf *mb; 594 register u_int32_t *tl; 595 register caddr_t bpos; 596 register int i; 597 struct mbuf *mreq, *mb2; 598 int siz, grpsiz, authsiz; 599 600 authsiz = nfsm_rndup(auth_len); 601 MGETHDR(mb, M_WAIT, MT_DATA); 602 if ((authsiz + 10 * NFSX_UNSIGNED) >= MINCLSIZE) { 603 MCLGET(mb, M_WAIT); 604 } else if ((authsiz + 10 * NFSX_UNSIGNED) < MHLEN) { 605 MH_ALIGN(mb, authsiz + 10 * NFSX_UNSIGNED); 606 } else { 607 MH_ALIGN(mb, 8 * NFSX_UNSIGNED); 608 } 609 mb->m_len = 0; 610 mreq = mb; 611 bpos = mtod(mb, caddr_t); 612 613 /* 614 * First the RPC header. 615 */ 616 nfsm_build(tl, u_int32_t *, 8 * NFSX_UNSIGNED); 617 618 /* Get a new (non-zero) xid */ 619 620 if ((nfs_xid == 0) && (nfs_xid_touched == 0)) { 621 nfs_xid = arc4random(); 622 nfs_xid_touched = 1; 623 } else { 624 while ((*xidp = arc4random() % 256) == 0) 625 ; 626 nfs_xid += *xidp; 627 } 628 629 *tl++ = *xidp = txdr_unsigned(nfs_xid); 630 *tl++ = rpc_call; 631 *tl++ = rpc_vers; 632 *tl++ = txdr_unsigned(NFS_PROG); 633 if (nmflag & NFSMNT_NFSV3) 634 *tl++ = txdr_unsigned(NFS_VER3); 635 else 636 *tl++ = txdr_unsigned(NFS_VER2); 637 if (nmflag & NFSMNT_NFSV3) 638 *tl++ = txdr_unsigned(procid); 639 else 640 *tl++ = txdr_unsigned(nfsv2_procid[procid]); 641 642 /* 643 * And then the authorization cred. 644 */ 645 *tl++ = txdr_unsigned(auth_type); 646 *tl = txdr_unsigned(authsiz); 647 switch (auth_type) { 648 case RPCAUTH_UNIX: 649 nfsm_build(tl, u_int32_t *, auth_len); 650 *tl++ = 0; /* stamp ?? */ 651 *tl++ = 0; /* NULL hostname */ 652 *tl++ = txdr_unsigned(cr->cr_uid); 653 *tl++ = txdr_unsigned(cr->cr_gid); 654 grpsiz = (auth_len >> 2) - 5; 655 *tl++ = txdr_unsigned(grpsiz); 656 for (i = 0; i < grpsiz; i++) 657 *tl++ = txdr_unsigned(cr->cr_groups[i]); 658 break; 659 case RPCAUTH_KERB4: 660 siz = auth_len; 661 while (siz > 0) { 662 if (M_TRAILINGSPACE(mb) == 0) { 663 MGET(mb2, M_WAIT, MT_DATA); 664 if (siz >= MINCLSIZE) 665 MCLGET(mb2, M_WAIT); 666 mb->m_next = mb2; 667 mb = mb2; 668 mb->m_len = 0; 669 bpos = mtod(mb, caddr_t); 670 } 671 i = min(siz, M_TRAILINGSPACE(mb)); 672 bcopy(auth_str, bpos, i); 673 mb->m_len += i; 674 auth_str += i; 675 bpos += i; 676 siz -= i; 677 } 678 if ((siz = (nfsm_rndup(auth_len) - auth_len)) > 0) { 679 for (i = 0; i < siz; i++) 680 *bpos++ = '\0'; 681 mb->m_len += siz; 682 } 683 break; 684 }; 685 686 /* 687 * And the verifier... 688 */ 689 nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 690 if (verf_str) { 691 *tl++ = txdr_unsigned(RPCAUTH_KERB4); 692 *tl = txdr_unsigned(verf_len); 693 siz = verf_len; 694 while (siz > 0) { 695 if (M_TRAILINGSPACE(mb) == 0) { 696 MGET(mb2, M_WAIT, MT_DATA); 697 if (siz >= MINCLSIZE) 698 MCLGET(mb2, M_WAIT); 699 mb->m_next = mb2; 700 mb = mb2; 701 mb->m_len = 0; 702 bpos = mtod(mb, caddr_t); 703 } 704 i = min(siz, M_TRAILINGSPACE(mb)); 705 bcopy(verf_str, bpos, i); 706 mb->m_len += i; 707 verf_str += i; 708 bpos += i; 709 siz -= i; 710 } 711 if ((siz = (nfsm_rndup(verf_len) - verf_len)) > 0) { 712 for (i = 0; i < siz; i++) 713 *bpos++ = '\0'; 714 mb->m_len += siz; 715 } 716 } else { 717 *tl++ = txdr_unsigned(RPCAUTH_NULL); 718 *tl = 0; 719 } 720 mb->m_next = mrest; 721 mreq->m_pkthdr.len = authsiz + 10 * NFSX_UNSIGNED + mrest_len; 722 mreq->m_pkthdr.rcvif = (struct ifnet *)0; 723 *mbp = mb; 724 return (mreq); 725 } 726 727 /* 728 * copies mbuf chain to the uio scatter/gather list 729 */ 730 int 731 nfsm_mbuftouio(mrep, uiop, siz, dpos) 732 struct mbuf **mrep; 733 register struct uio *uiop; 734 int siz; 735 caddr_t *dpos; 736 { 737 register char *mbufcp, *uiocp; 738 register int xfer, left, len; 739 register struct mbuf *mp; 740 long uiosiz, rem; 741 int error = 0; 742 743 mp = *mrep; 744 mbufcp = *dpos; 745 len = mtod(mp, caddr_t)+mp->m_len-mbufcp; 746 rem = nfsm_rndup(siz)-siz; 747 while (siz > 0) { 748 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) 749 return (EFBIG); 750 left = uiop->uio_iov->iov_len; 751 uiocp = uiop->uio_iov->iov_base; 752 if (left > siz) 753 left = siz; 754 uiosiz = left; 755 while (left > 0) { 756 while (len == 0) { 757 mp = mp->m_next; 758 if (mp == NULL) 759 return (EBADRPC); 760 mbufcp = mtod(mp, caddr_t); 761 len = mp->m_len; 762 } 763 xfer = (left > len) ? len : left; 764 #ifdef notdef 765 /* Not Yet.. */ 766 if (uiop->uio_iov->iov_op != NULL) 767 (*(uiop->uio_iov->iov_op)) 768 (mbufcp, uiocp, xfer); 769 else 770 #endif 771 if (uiop->uio_segflg == UIO_SYSSPACE) 772 bcopy(mbufcp, uiocp, xfer); 773 else 774 copyout(mbufcp, uiocp, xfer); 775 left -= xfer; 776 len -= xfer; 777 mbufcp += xfer; 778 uiocp += xfer; 779 uiop->uio_offset += xfer; 780 uiop->uio_resid -= xfer; 781 } 782 if (uiop->uio_iov->iov_len <= siz) { 783 uiop->uio_iovcnt--; 784 uiop->uio_iov++; 785 } else { 786 uiop->uio_iov->iov_base += uiosiz; 787 uiop->uio_iov->iov_len -= uiosiz; 788 } 789 siz -= uiosiz; 790 } 791 *dpos = mbufcp; 792 *mrep = mp; 793 if (rem > 0) { 794 if (len < rem) 795 error = nfs_adv(mrep, dpos, rem, len); 796 else 797 *dpos += rem; 798 } 799 return (error); 800 } 801 802 /* 803 * copies a uio scatter/gather list to an mbuf chain. 804 * NOTE: can ony handle iovcnt == 1 805 */ 806 int 807 nfsm_uiotombuf(uiop, mq, siz, bpos) 808 register struct uio *uiop; 809 struct mbuf **mq; 810 int siz; 811 caddr_t *bpos; 812 { 813 register char *uiocp; 814 register struct mbuf *mp, *mp2; 815 register int xfer, left, mlen; 816 int uiosiz, clflg, rem; 817 char *cp; 818 819 #ifdef DIAGNOSTIC 820 if (uiop->uio_iovcnt != 1) 821 panic("nfsm_uiotombuf: iovcnt != 1"); 822 #endif 823 824 if (siz > MLEN) /* or should it >= MCLBYTES ?? */ 825 clflg = 1; 826 else 827 clflg = 0; 828 rem = nfsm_rndup(siz)-siz; 829 mp = mp2 = *mq; 830 while (siz > 0) { 831 left = uiop->uio_iov->iov_len; 832 uiocp = uiop->uio_iov->iov_base; 833 if (left > siz) 834 left = siz; 835 uiosiz = left; 836 while (left > 0) { 837 mlen = M_TRAILINGSPACE(mp); 838 if (mlen == 0) { 839 MGET(mp, M_WAIT, MT_DATA); 840 if (clflg) 841 MCLGET(mp, M_WAIT); 842 mp->m_len = 0; 843 mp2->m_next = mp; 844 mp2 = mp; 845 mlen = M_TRAILINGSPACE(mp); 846 } 847 xfer = (left > mlen) ? mlen : left; 848 #ifdef notdef 849 /* Not Yet.. */ 850 if (uiop->uio_iov->iov_op != NULL) 851 (*(uiop->uio_iov->iov_op)) 852 (uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 853 else 854 #endif 855 if (uiop->uio_segflg == UIO_SYSSPACE) 856 bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 857 else 858 copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 859 mp->m_len += xfer; 860 left -= xfer; 861 uiocp += xfer; 862 uiop->uio_offset += xfer; 863 uiop->uio_resid -= xfer; 864 } 865 uiop->uio_iov->iov_base += uiosiz; 866 uiop->uio_iov->iov_len -= uiosiz; 867 siz -= uiosiz; 868 } 869 if (rem > 0) { 870 if (rem > M_TRAILINGSPACE(mp)) { 871 MGET(mp, M_WAIT, MT_DATA); 872 mp->m_len = 0; 873 mp2->m_next = mp; 874 } 875 cp = mtod(mp, caddr_t)+mp->m_len; 876 for (left = 0; left < rem; left++) 877 *cp++ = '\0'; 878 mp->m_len += rem; 879 *bpos = cp; 880 } else 881 *bpos = mtod(mp, caddr_t)+mp->m_len; 882 *mq = mp; 883 return (0); 884 } 885 886 /* 887 * Help break down an mbuf chain by setting the first siz bytes contiguous 888 * pointed to by returned val. 889 * This is used by the macros nfsm_dissect and nfsm_dissecton for tough 890 * cases. (The macros use the vars. dpos and dpos2) 891 */ 892 int 893 nfsm_disct(mdp, dposp, siz, left, cp2) 894 struct mbuf **mdp; 895 caddr_t *dposp; 896 int siz; 897 int left; 898 caddr_t *cp2; 899 { 900 register struct mbuf *mp, *mp2; 901 register int siz2, xfer; 902 register caddr_t p; 903 904 mp = *mdp; 905 while (left == 0) { 906 *mdp = mp = mp->m_next; 907 if (mp == NULL) 908 return (EBADRPC); 909 left = mp->m_len; 910 *dposp = mtod(mp, caddr_t); 911 } 912 if (left >= siz) { 913 *cp2 = *dposp; 914 *dposp += siz; 915 } else if (mp->m_next == NULL) { 916 return (EBADRPC); 917 } else if (siz > MHLEN) { 918 panic("nfs S too big"); 919 } else { 920 MGET(mp2, M_WAIT, MT_DATA); 921 mp2->m_next = mp->m_next; 922 mp->m_next = mp2; 923 mp->m_len -= left; 924 mp = mp2; 925 *cp2 = p = mtod(mp, caddr_t); 926 bcopy(*dposp, p, left); /* Copy what was left */ 927 siz2 = siz-left; 928 p += left; 929 mp2 = mp->m_next; 930 /* Loop around copying up the siz2 bytes */ 931 while (siz2 > 0) { 932 if (mp2 == NULL) 933 return (EBADRPC); 934 xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2; 935 if (xfer > 0) { 936 bcopy(mtod(mp2, caddr_t), p, xfer); 937 NFSMADV(mp2, xfer); 938 mp2->m_len -= xfer; 939 p += xfer; 940 siz2 -= xfer; 941 } 942 if (siz2 > 0) 943 mp2 = mp2->m_next; 944 } 945 mp->m_len = siz; 946 *mdp = mp2; 947 *dposp = mtod(mp2, caddr_t); 948 } 949 return (0); 950 } 951 952 /* 953 * Advance the position in the mbuf chain. 954 */ 955 int 956 nfs_adv(mdp, dposp, offs, left) 957 struct mbuf **mdp; 958 caddr_t *dposp; 959 int offs; 960 int left; 961 { 962 register struct mbuf *m; 963 register int s; 964 965 m = *mdp; 966 s = left; 967 while (s < offs) { 968 offs -= s; 969 m = m->m_next; 970 if (m == NULL) 971 return (EBADRPC); 972 s = m->m_len; 973 } 974 *mdp = m; 975 *dposp = mtod(m, caddr_t)+offs; 976 return (0); 977 } 978 979 /* 980 * Copy a string into mbufs for the hard cases... 981 */ 982 int 983 nfsm_strtmbuf(mb, bpos, cp, siz) 984 struct mbuf **mb; 985 char **bpos; 986 char *cp; 987 long siz; 988 { 989 register struct mbuf *m1 = NULL, *m2; 990 long left, xfer, len, tlen; 991 u_int32_t *tl; 992 int putsize; 993 994 putsize = 1; 995 m2 = *mb; 996 left = M_TRAILINGSPACE(m2); 997 if (left > 0) { 998 tl = ((u_int32_t *)(*bpos)); 999 *tl++ = txdr_unsigned(siz); 1000 putsize = 0; 1001 left -= NFSX_UNSIGNED; 1002 m2->m_len += NFSX_UNSIGNED; 1003 if (left > 0) { 1004 bcopy(cp, (caddr_t) tl, left); 1005 siz -= left; 1006 cp += left; 1007 m2->m_len += left; 1008 left = 0; 1009 } 1010 } 1011 /* Loop around adding mbufs */ 1012 while (siz > 0) { 1013 MGET(m1, M_WAIT, MT_DATA); 1014 if (siz > MLEN) 1015 MCLGET(m1, M_WAIT); 1016 m1->m_len = NFSMSIZ(m1); 1017 m2->m_next = m1; 1018 m2 = m1; 1019 tl = mtod(m1, u_int32_t *); 1020 tlen = 0; 1021 if (putsize) { 1022 *tl++ = txdr_unsigned(siz); 1023 m1->m_len -= NFSX_UNSIGNED; 1024 tlen = NFSX_UNSIGNED; 1025 putsize = 0; 1026 } 1027 if (siz < m1->m_len) { 1028 len = nfsm_rndup(siz); 1029 xfer = siz; 1030 if (xfer < len) 1031 *(tl+(xfer>>2)) = 0; 1032 } else { 1033 xfer = len = m1->m_len; 1034 } 1035 bcopy(cp, (caddr_t) tl, xfer); 1036 m1->m_len = len+tlen; 1037 siz -= xfer; 1038 cp += xfer; 1039 } 1040 *mb = m1; 1041 *bpos = mtod(m1, caddr_t)+m1->m_len; 1042 return (0); 1043 } 1044 1045 /* 1046 * Called once to initialize data structures... 1047 */ 1048 void 1049 nfs_init() 1050 { 1051 static struct timeout nfs_timer_to; 1052 1053 #if !defined(alpha) && defined(DIAGNOSTIC) 1054 /* 1055 * Check to see if major data structures haven't bloated. 1056 */ 1057 if (sizeof (struct nfsnode) > NFS_NODEALLOC) { 1058 printf("struct nfsnode bloated (> %dbytes)\n", NFS_NODEALLOC); 1059 printf("Try reducing NFS_SMALLFH\n"); 1060 } 1061 if (sizeof (struct nfsmount) > NFS_MNTALLOC) { 1062 printf("struct nfsmount bloated (> %dbytes)\n", NFS_MNTALLOC); 1063 printf("Try reducing NFS_MUIDHASHSIZ\n"); 1064 } 1065 if (sizeof (struct nfssvc_sock) > NFS_SVCALLOC) { 1066 printf("struct nfssvc_sock bloated (> %dbytes)\n",NFS_SVCALLOC); 1067 printf("Try reducing NFS_UIDHASHSIZ\n"); 1068 } 1069 if (sizeof (struct nfsuid) > NFS_UIDALLOC) { 1070 printf("struct nfsuid bloated (> %dbytes)\n",NFS_UIDALLOC); 1071 printf("Try unionizing the nu_nickname and nu_flag fields\n"); 1072 } 1073 #endif 1074 1075 nfsrtt.pos = 0; 1076 rpc_vers = txdr_unsigned(RPC_VER2); 1077 rpc_call = txdr_unsigned(RPC_CALL); 1078 rpc_reply = txdr_unsigned(RPC_REPLY); 1079 rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED); 1080 rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED); 1081 rpc_mismatch = txdr_unsigned(RPC_MISMATCH); 1082 rpc_autherr = txdr_unsigned(RPC_AUTHERR); 1083 rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX); 1084 rpc_auth_kerb = txdr_unsigned(RPCAUTH_KERB4); 1085 nfs_prog = txdr_unsigned(NFS_PROG); 1086 nfs_true = txdr_unsigned(TRUE); 1087 nfs_false = txdr_unsigned(FALSE); 1088 nfs_xdrneg1 = txdr_unsigned(-1); 1089 nfs_ticks = (hz * NFS_TICKINTVL + 500) / 1000; 1090 if (nfs_ticks < 1) 1091 nfs_ticks = 1; 1092 #ifdef NFSSERVER 1093 nfsrv_init(0); /* Init server data structures */ 1094 nfsrv_initcache(); /* Init the server request cache */ 1095 #endif /* NFSSERVER */ 1096 1097 /* 1098 * Initialize reply list and start timer 1099 */ 1100 TAILQ_INIT(&nfs_reqq); 1101 1102 timeout_set(&nfs_timer_to, nfs_timer, &nfs_timer_to); 1103 nfs_timer(&nfs_timer_to); 1104 } 1105 1106 #ifdef NFSCLIENT 1107 int 1108 nfs_vfs_init(vfsp) 1109 struct vfsconf *vfsp; 1110 { 1111 register int i; 1112 1113 /* Ensure async daemons disabled */ 1114 for (i = 0; i < NFS_MAXASYNCDAEMON; i++) 1115 nfs_iodwant[i] = (struct proc *)0; 1116 TAILQ_INIT(&nfs_bufq); 1117 nfs_nhinit(); /* Init the nfsnode table */ 1118 1119 return (0); 1120 } 1121 1122 /* 1123 * Attribute cache routines. 1124 * nfs_loadattrcache() - loads or updates the cache contents from attributes 1125 * that are on the mbuf list 1126 * nfs_getattrcache() - returns valid attributes if found in cache, returns 1127 * error otherwise 1128 */ 1129 1130 /* 1131 * Load the attribute cache (that lives in the nfsnode entry) with 1132 * the values on the mbuf list and 1133 * Iff vap not NULL 1134 * copy the attributes to *vaper 1135 */ 1136 int 1137 nfs_loadattrcache(vpp, mdp, dposp, vaper) 1138 struct vnode **vpp; 1139 struct mbuf **mdp; 1140 caddr_t *dposp; 1141 struct vattr *vaper; 1142 { 1143 register struct vnode *vp = *vpp; 1144 register struct vattr *vap; 1145 register struct nfs_fattr *fp; 1146 extern int (**spec_nfsv2nodeop_p) __P((void *)); 1147 register struct nfsnode *np; 1148 register int32_t t1; 1149 caddr_t cp2; 1150 int error = 0; 1151 int32_t rdev; 1152 struct mbuf *md; 1153 enum vtype vtyp; 1154 u_short vmode; 1155 struct timespec mtime; 1156 struct vnode *nvp; 1157 int v3 = NFS_ISV3(vp); 1158 1159 md = *mdp; 1160 t1 = (mtod(md, caddr_t) + md->m_len) - *dposp; 1161 error = nfsm_disct(mdp, dposp, NFSX_FATTR(v3), t1, &cp2); 1162 if (error) 1163 return (error); 1164 fp = (struct nfs_fattr *)cp2; 1165 if (v3) { 1166 vtyp = nfsv3tov_type(fp->fa_type); 1167 vmode = fxdr_unsigned(u_short, fp->fa_mode); 1168 rdev = makedev(fxdr_unsigned(u_char, fp->fa3_rdev.specdata1), 1169 fxdr_unsigned(u_char, fp->fa3_rdev.specdata2)); 1170 fxdr_nfsv3time(&fp->fa3_mtime, &mtime); 1171 } else { 1172 vtyp = nfsv2tov_type(fp->fa_type); 1173 vmode = fxdr_unsigned(u_short, fp->fa_mode); 1174 if (vtyp == VNON || vtyp == VREG) 1175 vtyp = IFTOVT(vmode); 1176 rdev = fxdr_unsigned(int32_t, fp->fa2_rdev); 1177 fxdr_nfsv2time(&fp->fa2_mtime, &mtime); 1178 1179 /* 1180 * Really ugly NFSv2 kludge. 1181 */ 1182 if (vtyp == VCHR && rdev == 0xffffffff) 1183 vtyp = VFIFO; 1184 } 1185 1186 /* 1187 * If v_type == VNON it is a new node, so fill in the v_type, 1188 * n_mtime fields. Check to see if it represents a special 1189 * device, and if so, check for a possible alias. Once the 1190 * correct vnode has been obtained, fill in the rest of the 1191 * information. 1192 */ 1193 np = VTONFS(vp); 1194 if (vp->v_type != vtyp) { 1195 vp->v_type = vtyp; 1196 if (vp->v_type == VFIFO) { 1197 #ifndef FIFO 1198 return (EOPNOTSUPP); 1199 #else 1200 extern int (**fifo_nfsv2nodeop_p) __P((void *)); 1201 vp->v_op = fifo_nfsv2nodeop_p; 1202 #endif /* FIFO */ 1203 } 1204 if (vp->v_type == VCHR || vp->v_type == VBLK) { 1205 vp->v_op = spec_nfsv2nodeop_p; 1206 nvp = checkalias(vp, (dev_t)rdev, vp->v_mount); 1207 if (nvp) { 1208 /* 1209 * Discard unneeded vnode, but save its nfsnode. 1210 * Since the nfsnode does not have a lock, its 1211 * vnode lock has to be carried over. 1212 */ 1213 1214 nvp->v_vnlock = vp->v_vnlock; 1215 vp->v_vnlock = NULL; 1216 nvp->v_data = vp->v_data; 1217 vp->v_data = NULL; 1218 vp->v_op = spec_vnodeop_p; 1219 vrele(vp); 1220 vgone(vp); 1221 /* 1222 * Reinitialize aliased node. 1223 */ 1224 np->n_vnode = nvp; 1225 *vpp = vp = nvp; 1226 } 1227 } 1228 np->n_mtime = mtime.tv_sec; 1229 } 1230 vap = &np->n_vattr; 1231 vap->va_type = vtyp; 1232 vap->va_mode = (vmode & 07777); 1233 vap->va_rdev = (dev_t)rdev; 1234 vap->va_mtime = mtime; 1235 vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; 1236 if (v3) { 1237 vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink); 1238 vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid); 1239 vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid); 1240 vap->va_size = fxdr_hyper(&fp->fa3_size); 1241 vap->va_blocksize = NFS_FABLKSIZE; 1242 vap->va_bytes = fxdr_hyper(&fp->fa3_used); 1243 vap->va_fileid = fxdr_unsigned(int32_t, 1244 fp->fa3_fileid.nfsuquad[1]); 1245 fxdr_nfsv3time(&fp->fa3_atime, &vap->va_atime); 1246 fxdr_nfsv3time(&fp->fa3_ctime, &vap->va_ctime); 1247 vap->va_flags = 0; 1248 vap->va_filerev = 0; 1249 } else { 1250 vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink); 1251 vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid); 1252 vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid); 1253 vap->va_size = fxdr_unsigned(u_int32_t, fp->fa2_size); 1254 vap->va_blocksize = fxdr_unsigned(int32_t, fp->fa2_blocksize); 1255 vap->va_bytes = 1256 (u_quad_t)fxdr_unsigned(int32_t, fp->fa2_blocks) * 1257 NFS_FABLKSIZE; 1258 vap->va_fileid = fxdr_unsigned(int32_t, fp->fa2_fileid); 1259 fxdr_nfsv2time(&fp->fa2_atime, &vap->va_atime); 1260 vap->va_flags = 0; 1261 vap->va_ctime.tv_sec = fxdr_unsigned(u_int32_t, 1262 fp->fa2_ctime.nfsv2_sec); 1263 vap->va_ctime.tv_nsec = 0; 1264 vap->va_gen = fxdr_unsigned(u_int32_t,fp->fa2_ctime.nfsv2_usec); 1265 vap->va_filerev = 0; 1266 } 1267 if (vap->va_size != np->n_size) { 1268 if (vap->va_type == VREG) { 1269 if (np->n_flag & NMODIFIED) { 1270 if (vap->va_size < np->n_size) 1271 vap->va_size = np->n_size; 1272 else 1273 np->n_size = vap->va_size; 1274 } else 1275 np->n_size = vap->va_size; 1276 uvm_vnp_setsize(vp, np->n_size); 1277 } else 1278 np->n_size = vap->va_size; 1279 } 1280 np->n_attrstamp = time.tv_sec; 1281 if (vaper != NULL) { 1282 bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap)); 1283 if (np->n_flag & NCHG) { 1284 if (np->n_flag & NACC) 1285 vaper->va_atime = np->n_atim; 1286 if (np->n_flag & NUPD) 1287 vaper->va_mtime = np->n_mtim; 1288 } 1289 } 1290 return (0); 1291 } 1292 1293 INLINE int 1294 nfs_attrtimeo (np) 1295 struct nfsnode *np; 1296 { 1297 struct vnode *vp = np->n_vnode; 1298 struct nfsmount *nmp = VFSTONFS(vp->v_mount); 1299 int tenthage = (time.tv_sec - np->n_mtime) / 10; 1300 int minto, maxto; 1301 1302 if (vp->v_type == VDIR) { 1303 maxto = nmp->nm_acdirmax; 1304 minto = nmp->nm_acdirmin; 1305 } 1306 else { 1307 maxto = nmp->nm_acregmax; 1308 minto = nmp->nm_acregmin; 1309 } 1310 1311 if (np->n_flag & NMODIFIED || tenthage < minto) 1312 return minto; 1313 else if (tenthage < maxto) 1314 return tenthage; 1315 else 1316 return maxto; 1317 } 1318 1319 /* 1320 * Check the time stamp 1321 * If the cache is valid, copy contents to *vap and return 0 1322 * otherwise return an error 1323 */ 1324 int 1325 nfs_getattrcache(vp, vaper) 1326 register struct vnode *vp; 1327 struct vattr *vaper; 1328 { 1329 register struct nfsnode *np = VTONFS(vp); 1330 register struct vattr *vap; 1331 1332 if ((time.tv_sec - np->n_attrstamp) >= nfs_attrtimeo(np)) { 1333 nfsstats.attrcache_misses++; 1334 return (ENOENT); 1335 } 1336 nfsstats.attrcache_hits++; 1337 vap = &np->n_vattr; 1338 if (vap->va_size != np->n_size) { 1339 if (vap->va_type == VREG) { 1340 if (np->n_flag & NMODIFIED) { 1341 if (vap->va_size < np->n_size) 1342 vap->va_size = np->n_size; 1343 else 1344 np->n_size = vap->va_size; 1345 } else 1346 np->n_size = vap->va_size; 1347 uvm_vnp_setsize(vp, np->n_size); 1348 } else 1349 np->n_size = vap->va_size; 1350 } 1351 bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(struct vattr)); 1352 if (np->n_flag & NCHG) { 1353 if (np->n_flag & NACC) 1354 vaper->va_atime = np->n_atim; 1355 if (np->n_flag & NUPD) 1356 vaper->va_mtime = np->n_mtim; 1357 } 1358 return (0); 1359 } 1360 #endif /* NFSCLIENT */ 1361 1362 /* 1363 * Set up nameidata for a lookup() call and do it 1364 */ 1365 int 1366 nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, retdirp, p, kerbflag) 1367 register struct nameidata *ndp; 1368 fhandle_t *fhp; 1369 int len; 1370 struct nfssvc_sock *slp; 1371 struct mbuf *nam; 1372 struct mbuf **mdp; 1373 caddr_t *dposp; 1374 struct vnode **retdirp; 1375 struct proc *p; 1376 int kerbflag; 1377 { 1378 register int i, rem; 1379 register struct mbuf *md; 1380 register char *fromcp, *tocp; 1381 struct vnode *dp; 1382 int error, rdonly; 1383 struct componentname *cnp = &ndp->ni_cnd; 1384 1385 *retdirp = (struct vnode *)0; 1386 MALLOC(cnp->cn_pnbuf, char *, len + 1, M_NAMEI, M_WAITOK); 1387 /* 1388 * Copy the name from the mbuf list to ndp->ni_pnbuf 1389 * and set the various ndp fields appropriately. 1390 */ 1391 fromcp = *dposp; 1392 tocp = cnp->cn_pnbuf; 1393 md = *mdp; 1394 rem = mtod(md, caddr_t) + md->m_len - fromcp; 1395 cnp->cn_hash = 0; 1396 for (i = 0; i < len; i++) { 1397 while (rem == 0) { 1398 md = md->m_next; 1399 if (md == NULL) { 1400 error = EBADRPC; 1401 goto out; 1402 } 1403 fromcp = mtod(md, caddr_t); 1404 rem = md->m_len; 1405 } 1406 if (*fromcp == '\0' || *fromcp == '/') { 1407 error = EACCES; 1408 goto out; 1409 } 1410 cnp->cn_hash += (u_char)*fromcp; 1411 *tocp++ = *fromcp++; 1412 rem--; 1413 } 1414 *tocp = '\0'; 1415 *mdp = md; 1416 *dposp = fromcp; 1417 len = nfsm_rndup(len)-len; 1418 if (len > 0) { 1419 if (rem >= len) 1420 *dposp += len; 1421 else if ((error = nfs_adv(mdp, dposp, len, rem)) != 0) 1422 goto out; 1423 } 1424 ndp->ni_pathlen = tocp - cnp->cn_pnbuf; 1425 cnp->cn_nameptr = cnp->cn_pnbuf; 1426 /* 1427 * Extract and set starting directory. 1428 */ 1429 error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp, 1430 nam, &rdonly, kerbflag); 1431 if (error) 1432 goto out; 1433 if (dp->v_type != VDIR) { 1434 vrele(dp); 1435 error = ENOTDIR; 1436 goto out; 1437 } 1438 VREF(dp); 1439 *retdirp = dp; 1440 ndp->ni_startdir = dp; 1441 if (rdonly) 1442 cnp->cn_flags |= (NOCROSSMOUNT | RDONLY); 1443 else 1444 cnp->cn_flags |= NOCROSSMOUNT; 1445 /* 1446 * And call lookup() to do the real work 1447 */ 1448 cnp->cn_proc = p; 1449 error = lookup(ndp); 1450 if (error) 1451 goto out; 1452 /* 1453 * Check for encountering a symbolic link 1454 */ 1455 if (cnp->cn_flags & ISSYMLINK) { 1456 if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1) 1457 vput(ndp->ni_dvp); 1458 else 1459 vrele(ndp->ni_dvp); 1460 vput(ndp->ni_vp); 1461 ndp->ni_vp = NULL; 1462 error = EINVAL; 1463 goto out; 1464 } 1465 /* 1466 * Check for saved name request 1467 */ 1468 if (cnp->cn_flags & (SAVENAME | SAVESTART)) { 1469 cnp->cn_flags |= HASBUF; 1470 return (0); 1471 } 1472 out: 1473 FREE(cnp->cn_pnbuf, M_NAMEI); 1474 return (error); 1475 } 1476 1477 /* 1478 * A fiddled version of m_adj() that ensures null fill to a long 1479 * boundary and only trims off the back end 1480 */ 1481 void 1482 nfsm_adj(mp, len, nul) 1483 struct mbuf *mp; 1484 register int len; 1485 int nul; 1486 { 1487 register struct mbuf *m; 1488 register int count, i; 1489 register char *cp; 1490 1491 /* 1492 * Trim from tail. Scan the mbuf chain, 1493 * calculating its length and finding the last mbuf. 1494 * If the adjustment only affects this mbuf, then just 1495 * adjust and return. Otherwise, rescan and truncate 1496 * after the remaining size. 1497 */ 1498 count = 0; 1499 m = mp; 1500 for (;;) { 1501 count += m->m_len; 1502 if (m->m_next == (struct mbuf *)0) 1503 break; 1504 m = m->m_next; 1505 } 1506 if (m->m_len > len) { 1507 m->m_len -= len; 1508 if (nul > 0) { 1509 cp = mtod(m, caddr_t)+m->m_len-nul; 1510 for (i = 0; i < nul; i++) 1511 *cp++ = '\0'; 1512 } 1513 return; 1514 } 1515 count -= len; 1516 if (count < 0) 1517 count = 0; 1518 /* 1519 * Correct length for chain is "count". 1520 * Find the mbuf with last data, adjust its length, 1521 * and toss data from remaining mbufs on chain. 1522 */ 1523 for (m = mp; m; m = m->m_next) { 1524 if (m->m_len >= count) { 1525 m->m_len = count; 1526 if (nul > 0) { 1527 cp = mtod(m, caddr_t)+m->m_len-nul; 1528 for (i = 0; i < nul; i++) 1529 *cp++ = '\0'; 1530 } 1531 break; 1532 } 1533 count -= m->m_len; 1534 } 1535 for (m = m->m_next;m;m = m->m_next) 1536 m->m_len = 0; 1537 } 1538 1539 /* 1540 * Make these functions instead of macros, so that the kernel text size 1541 * doesn't get too big... 1542 */ 1543 void 1544 nfsm_srvwcc(nfsd, before_ret, before_vap, after_ret, after_vap, mbp, bposp) 1545 struct nfsrv_descript *nfsd; 1546 int before_ret; 1547 register struct vattr *before_vap; 1548 int after_ret; 1549 struct vattr *after_vap; 1550 struct mbuf **mbp; 1551 char **bposp; 1552 { 1553 register struct mbuf *mb = *mbp, *mb2; 1554 register char *bpos = *bposp; 1555 register u_int32_t *tl; 1556 1557 if (before_ret) { 1558 nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); 1559 *tl = nfs_false; 1560 } else { 1561 nfsm_build(tl, u_int32_t *, 7 * NFSX_UNSIGNED); 1562 *tl++ = nfs_true; 1563 txdr_hyper(before_vap->va_size, tl); 1564 tl += 2; 1565 txdr_nfsv3time(&(before_vap->va_mtime), tl); 1566 tl += 2; 1567 txdr_nfsv3time(&(before_vap->va_ctime), tl); 1568 } 1569 *bposp = bpos; 1570 *mbp = mb; 1571 nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp); 1572 } 1573 1574 void 1575 nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp) 1576 struct nfsrv_descript *nfsd; 1577 int after_ret; 1578 struct vattr *after_vap; 1579 struct mbuf **mbp; 1580 char **bposp; 1581 { 1582 register struct mbuf *mb = *mbp, *mb2; 1583 register char *bpos = *bposp; 1584 register u_int32_t *tl; 1585 register struct nfs_fattr *fp; 1586 1587 if (after_ret) { 1588 nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); 1589 *tl = nfs_false; 1590 } else { 1591 nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_V3FATTR); 1592 *tl++ = nfs_true; 1593 fp = (struct nfs_fattr *)tl; 1594 nfsm_srvfattr(nfsd, after_vap, fp); 1595 } 1596 *mbp = mb; 1597 *bposp = bpos; 1598 } 1599 1600 void 1601 nfsm_srvfattr(nfsd, vap, fp) 1602 register struct nfsrv_descript *nfsd; 1603 register struct vattr *vap; 1604 register struct nfs_fattr *fp; 1605 { 1606 1607 fp->fa_nlink = txdr_unsigned(vap->va_nlink); 1608 fp->fa_uid = txdr_unsigned(vap->va_uid); 1609 fp->fa_gid = txdr_unsigned(vap->va_gid); 1610 if (nfsd->nd_flag & ND_NFSV3) { 1611 fp->fa_type = vtonfsv3_type(vap->va_type); 1612 fp->fa_mode = vtonfsv3_mode(vap->va_mode); 1613 txdr_hyper(vap->va_size, &fp->fa3_size); 1614 txdr_hyper(vap->va_bytes, &fp->fa3_used); 1615 fp->fa3_rdev.specdata1 = txdr_unsigned(major(vap->va_rdev)); 1616 fp->fa3_rdev.specdata2 = txdr_unsigned(minor(vap->va_rdev)); 1617 fp->fa3_fsid.nfsuquad[0] = 0; 1618 fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid); 1619 fp->fa3_fileid.nfsuquad[0] = 0; 1620 fp->fa3_fileid.nfsuquad[1] = txdr_unsigned(vap->va_fileid); 1621 txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime); 1622 txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime); 1623 txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime); 1624 } else { 1625 fp->fa_type = vtonfsv2_type(vap->va_type); 1626 fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode); 1627 fp->fa2_size = txdr_unsigned(vap->va_size); 1628 fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize); 1629 if (vap->va_type == VFIFO) 1630 fp->fa2_rdev = 0xffffffff; 1631 else 1632 fp->fa2_rdev = txdr_unsigned(vap->va_rdev); 1633 fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE); 1634 fp->fa2_fsid = txdr_unsigned(vap->va_fsid); 1635 fp->fa2_fileid = txdr_unsigned(vap->va_fileid); 1636 txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime); 1637 txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime); 1638 txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime); 1639 } 1640 } 1641 1642 /* 1643 * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked) 1644 * - look up fsid in mount list (if not found ret error) 1645 * - get vp and export rights by calling VFS_FHTOVP() and VFS_CHECKEXP() 1646 * - if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon 1647 * - if not lockflag unlock it with VOP_UNLOCK() 1648 */ 1649 int 1650 nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp, kerbflag) 1651 fhandle_t *fhp; 1652 int lockflag; 1653 struct vnode **vpp; 1654 struct ucred *cred; 1655 struct nfssvc_sock *slp; 1656 struct mbuf *nam; 1657 int *rdonlyp; 1658 int kerbflag; 1659 { 1660 struct proc *p = curproc; /* XXX */ 1661 register struct mount *mp; 1662 register int i; 1663 struct ucred *credanon; 1664 int error, exflags; 1665 struct sockaddr_in *saddr; 1666 1667 *vpp = (struct vnode *)0; 1668 mp = vfs_getvfs(&fhp->fh_fsid); 1669 1670 if (!mp) 1671 return (ESTALE); 1672 error = VFS_CHECKEXP(mp, nam, &exflags, &credanon); 1673 if (error) 1674 return (error); 1675 error = VFS_FHTOVP(mp, &fhp->fh_fid, vpp); 1676 if (error) 1677 return (error); 1678 1679 saddr = mtod(nam, struct sockaddr_in *); 1680 if (saddr->sin_family == AF_INET && 1681 (ntohs(saddr->sin_port) >= IPPORT_RESERVED || 1682 (slp->ns_so->so_type == SOCK_STREAM && ntohs(saddr->sin_port) == 20))) { 1683 vput(*vpp); 1684 return (NFSERR_AUTHERR | AUTH_TOOWEAK); 1685 } 1686 1687 /* 1688 * Check/setup credentials. 1689 */ 1690 if (exflags & MNT_EXKERB) { 1691 if (!kerbflag) { 1692 vput(*vpp); 1693 return (NFSERR_AUTHERR | AUTH_TOOWEAK); 1694 } 1695 } else if (kerbflag) { 1696 vput(*vpp); 1697 return (NFSERR_AUTHERR | AUTH_TOOWEAK); 1698 } else if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) { 1699 cred->cr_uid = credanon->cr_uid; 1700 cred->cr_gid = credanon->cr_gid; 1701 for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++) 1702 cred->cr_groups[i] = credanon->cr_groups[i]; 1703 cred->cr_ngroups = i; 1704 } 1705 if (exflags & MNT_EXRDONLY) 1706 *rdonlyp = 1; 1707 else 1708 *rdonlyp = 0; 1709 if (!lockflag) 1710 VOP_UNLOCK(*vpp, 0, p); 1711 1712 return (0); 1713 } 1714 1715 /* 1716 * This function compares two net addresses by family and returns TRUE 1717 * if they are the same host. 1718 * If there is any doubt, return FALSE. 1719 * The AF_INET family is handled as a special case so that address mbufs 1720 * don't need to be saved to store "struct in_addr", which is only 4 bytes. 1721 */ 1722 int 1723 netaddr_match(family, haddr, nam) 1724 int family; 1725 union nethostaddr *haddr; 1726 struct mbuf *nam; 1727 { 1728 register struct sockaddr_in *inetaddr; 1729 1730 switch (family) { 1731 case AF_INET: 1732 inetaddr = mtod(nam, struct sockaddr_in *); 1733 if (inetaddr->sin_family == AF_INET && 1734 inetaddr->sin_addr.s_addr == haddr->had_inetaddr) 1735 return (1); 1736 break; 1737 #ifdef ISO 1738 case AF_ISO: 1739 { 1740 register struct sockaddr_iso *isoaddr1, *isoaddr2; 1741 1742 isoaddr1 = mtod(nam, struct sockaddr_iso *); 1743 isoaddr2 = mtod(haddr->had_nam, struct sockaddr_iso *); 1744 if (isoaddr1->siso_family == AF_ISO && 1745 isoaddr1->siso_nlen > 0 && 1746 isoaddr1->siso_nlen == isoaddr2->siso_nlen && 1747 SAME_ISOADDR(isoaddr1, isoaddr2)) 1748 return (1); 1749 break; 1750 } 1751 #endif /* ISO */ 1752 default: 1753 break; 1754 }; 1755 return (0); 1756 } 1757 1758 /* 1759 * The write verifier has changed (probably due to a server reboot), so all 1760 * B_NEEDCOMMIT blocks will have to be written again. Since they are on the 1761 * dirty block list as B_DELWRI, all this takes is clearing the B_NEEDCOMMIT 1762 * flag. Once done the new write verifier can be set for the mount point. 1763 */ 1764 void 1765 nfs_clearcommit(mp) 1766 struct mount *mp; 1767 { 1768 register struct vnode *vp, *nvp; 1769 register struct buf *bp, *nbp; 1770 int s; 1771 1772 s = splbio(); 1773 loop: 1774 for (vp = mp->mnt_vnodelist.lh_first; vp; vp = nvp) { 1775 if (vp->v_mount != mp) /* Paranoia */ 1776 goto loop; 1777 nvp = vp->v_mntvnodes.le_next; 1778 for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) { 1779 nbp = bp->b_vnbufs.le_next; 1780 if ((bp->b_flags & (B_BUSY | B_DELWRI | B_NEEDCOMMIT)) 1781 == (B_DELWRI | B_NEEDCOMMIT)) 1782 bp->b_flags &= ~B_NEEDCOMMIT; 1783 } 1784 } 1785 splx(s); 1786 } 1787 1788 /* 1789 * Map errnos to NFS error numbers. For Version 3 also filter out error 1790 * numbers not specified for the associated procedure. 1791 */ 1792 int 1793 nfsrv_errmap(nd, err) 1794 struct nfsrv_descript *nd; 1795 register int err; 1796 { 1797 register short *defaulterrp, *errp; 1798 1799 if (nd->nd_flag & ND_NFSV3) { 1800 if (nd->nd_procnum <= NFSPROC_COMMIT) { 1801 errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum]; 1802 while (*++errp) { 1803 if (*errp == err) 1804 return (err); 1805 else if (*errp > err) 1806 break; 1807 } 1808 return ((int)*defaulterrp); 1809 } else 1810 return (err & 0xffff); 1811 } 1812 if (err <= ELAST) 1813 return ((int)nfsrv_v2errmap[err - 1]); 1814 return (NFSERR_IO); 1815 } 1816 1817 /* 1818 * Sort the group list in increasing numerical order. 1819 * (Insertion sort by Chris Torek, who was grossed out by the bubble sort 1820 * that used to be here.) 1821 */ 1822 void 1823 nfsrvw_sort(list, num) 1824 register gid_t *list; 1825 register int num; 1826 { 1827 register int i, j; 1828 gid_t v; 1829 1830 /* Insertion sort. */ 1831 for (i = 1; i < num; i++) { 1832 v = list[i]; 1833 /* find correct slot for value v, moving others up */ 1834 for (j = i; --j >= 0 && v < list[j];) 1835 list[j + 1] = list[j]; 1836 list[j + 1] = v; 1837 } 1838 } 1839 1840 /* 1841 * copy credentials making sure that the result can be compared with bcmp(). 1842 */ 1843 void 1844 nfsrv_setcred(incred, outcred) 1845 register struct ucred *incred, *outcred; 1846 { 1847 register int i; 1848 1849 bzero((caddr_t)outcred, sizeof (struct ucred)); 1850 outcred->cr_ref = 1; 1851 outcred->cr_uid = incred->cr_uid; 1852 outcred->cr_gid = incred->cr_gid; 1853 outcred->cr_ngroups = incred->cr_ngroups; 1854 for (i = 0; i < incred->cr_ngroups; i++) 1855 outcred->cr_groups[i] = incred->cr_groups[i]; 1856 nfsrvw_sort(outcred->cr_groups, outcred->cr_ngroups); 1857 } 1858