76#include <netinet/in.h> 77#ifdef ISO 78#include <netiso/iso.h> 79#endif 80 81#define TRUE 1 82#define FALSE 0 83 84/* 85 * Data items converted to xdr at startup, since they are constant 86 * This is kinda hokey, but may save a little time doing byte swaps 87 */ 88u_long nfs_procids[NFS_NPROCS]; 89u_long nfs_xdrneg1; 90u_long rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr, 91 rpc_mismatch, rpc_auth_unix, rpc_msgaccepted, rpc_rejectedcred, 92 rpc_auth_kerb; 93u_long nfs_vers, nfs_prog, nfs_true, nfs_false; 94 95/* And other global data */ 96static u_long nfs_xid = 0; 97enum vtype ntov_type[7] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON }; 98extern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON]; 99extern int nqnfs_piggy[NFS_NPROCS]; 100extern struct nfsrtt nfsrtt; 101extern time_t nqnfsstarttime; 102extern u_long nqnfs_prog, nqnfs_vers; 103extern int nqsrv_clockskew; 104extern int nqsrv_writeslack; 105extern int nqsrv_maxlease; 106 107#ifdef VFS_LKM 108struct getfh_args; 109extern int getfh(struct proc *, struct getfh_args *, int *); 110struct nfssvc_args; 111extern int nfssvc(struct proc *, struct nfssvc_args *, int *); 112#endif 113 114LIST_HEAD(nfsnodehashhead, nfsnode); 115 116/* 117 * Create the header for an rpc request packet 118 * The hsiz is the size of the rest of the nfs request header. 119 * (just used to decide if a cluster is a good idea) 120 */ 121struct mbuf * 122nfsm_reqh(vp, procid, hsiz, bposp) 123 struct vnode *vp; 124 u_long procid; 125 int hsiz; 126 caddr_t *bposp; 127{ 128 register struct mbuf *mb; 129 register u_long *tl; 130 register caddr_t bpos; 131 struct mbuf *mb2; 132 struct nfsmount *nmp; 133 int nqflag; 134 135 MGET(mb, M_WAIT, MT_DATA); 136 if (hsiz >= MINCLSIZE) 137 MCLGET(mb, M_WAIT); 138 mb->m_len = 0; 139 bpos = mtod(mb, caddr_t); 140 141 /* 142 * For NQNFS, add lease request. 143 */ 144 if (vp) { 145 nmp = VFSTONFS(vp->v_mount); 146 if (nmp->nm_flag & NFSMNT_NQNFS) { 147 nqflag = NQNFS_NEEDLEASE(vp, procid); 148 if (nqflag) { 149 nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 150 *tl++ = txdr_unsigned(nqflag); 151 *tl = txdr_unsigned(nmp->nm_leaseterm); 152 } else { 153 nfsm_build(tl, u_long *, NFSX_UNSIGNED); 154 *tl = 0; 155 } 156 } 157 } 158 /* Finally, return values */ 159 *bposp = bpos; 160 return (mb); 161} 162 163/* 164 * Build the RPC header and fill in the authorization info. 165 * The authorization string argument is only used when the credentials 166 * come from outside of the kernel. 167 * Returns the head of the mbuf list. 168 */ 169struct mbuf * 170nfsm_rpchead(cr, nqnfs, procid, auth_type, auth_len, auth_str, mrest, 171 mrest_len, mbp, xidp) 172 register struct ucred *cr; 173 int nqnfs; 174 int procid; 175 int auth_type; 176 int auth_len; 177 char *auth_str; 178 struct mbuf *mrest; 179 int mrest_len; 180 struct mbuf **mbp; 181 u_long *xidp; 182{ 183 register struct mbuf *mb; 184 register u_long *tl; 185 register caddr_t bpos; 186 register int i; 187 struct mbuf *mreq, *mb2; 188 int siz, grpsiz, authsiz; 189 190 authsiz = nfsm_rndup(auth_len); 191 if (auth_type == RPCAUTH_NQNFS) 192 authsiz += 2 * NFSX_UNSIGNED; 193 MGETHDR(mb, M_WAIT, MT_DATA); 194 if ((authsiz + 10*NFSX_UNSIGNED) >= MINCLSIZE) { 195 MCLGET(mb, M_WAIT); 196 } else if ((authsiz + 10*NFSX_UNSIGNED) < MHLEN) { 197 MH_ALIGN(mb, authsiz + 10*NFSX_UNSIGNED); 198 } else { 199 MH_ALIGN(mb, 8*NFSX_UNSIGNED); 200 } 201 mb->m_len = 0; 202 mreq = mb; 203 bpos = mtod(mb, caddr_t); 204 205 /* 206 * First the RPC header. 207 */ 208 nfsm_build(tl, u_long *, 8*NFSX_UNSIGNED); 209 if (++nfs_xid == 0) 210 nfs_xid++; 211 *tl++ = *xidp = txdr_unsigned(nfs_xid); 212 *tl++ = rpc_call; 213 *tl++ = rpc_vers; 214 if (nqnfs) { 215 *tl++ = txdr_unsigned(NQNFS_PROG); 216 *tl++ = txdr_unsigned(NQNFS_VER1); 217 } else { 218 *tl++ = txdr_unsigned(NFS_PROG); 219 *tl++ = txdr_unsigned(NFS_VER2); 220 } 221 *tl++ = txdr_unsigned(procid); 222 223 /* 224 * And then the authorization cred. 225 */ 226 *tl++ = txdr_unsigned(auth_type); 227 *tl = txdr_unsigned(authsiz); 228 switch (auth_type) { 229 case RPCAUTH_UNIX: 230 nfsm_build(tl, u_long *, auth_len); 231 *tl++ = 0; /* stamp ?? */ 232 *tl++ = 0; /* NULL hostname */ 233 *tl++ = txdr_unsigned(cr->cr_uid); 234 *tl++ = txdr_unsigned(cr->cr_groups[0]); 235 grpsiz = (auth_len >> 2) - 5; 236 *tl++ = txdr_unsigned(grpsiz); 237 for (i = 1; i <= grpsiz; i++) 238 *tl++ = txdr_unsigned(cr->cr_groups[i]); 239 break; 240 case RPCAUTH_NQNFS: 241 nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 242 *tl++ = txdr_unsigned(cr->cr_uid); 243 *tl = txdr_unsigned(auth_len); 244 siz = auth_len; 245 while (siz > 0) { 246 if (M_TRAILINGSPACE(mb) == 0) { 247 MGET(mb2, M_WAIT, MT_DATA); 248 if (siz >= MINCLSIZE) 249 MCLGET(mb2, M_WAIT); 250 mb->m_next = mb2; 251 mb = mb2; 252 mb->m_len = 0; 253 bpos = mtod(mb, caddr_t); 254 } 255 i = min(siz, M_TRAILINGSPACE(mb)); 256 bcopy(auth_str, bpos, i); 257 mb->m_len += i; 258 auth_str += i; 259 bpos += i; 260 siz -= i; 261 } 262 if ((siz = (nfsm_rndup(auth_len) - auth_len)) > 0) { 263 for (i = 0; i < siz; i++) 264 *bpos++ = '\0'; 265 mb->m_len += siz; 266 } 267 break; 268 }; 269 nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 270 *tl++ = txdr_unsigned(RPCAUTH_NULL); 271 *tl = 0; 272 mb->m_next = mrest; 273 mreq->m_pkthdr.len = authsiz + 10*NFSX_UNSIGNED + mrest_len; 274 mreq->m_pkthdr.rcvif = (struct ifnet *)0; 275 *mbp = mb; 276 return (mreq); 277} 278 279/* 280 * copies mbuf chain to the uio scatter/gather list 281 */ 282int 283nfsm_mbuftouio(mrep, uiop, siz, dpos) 284 struct mbuf **mrep; 285 register struct uio *uiop; 286 int siz; 287 caddr_t *dpos; 288{ 289 register char *mbufcp, *uiocp; 290 register int xfer, left, len; 291 register struct mbuf *mp; 292 long uiosiz, rem; 293 int error = 0; 294 295 mp = *mrep; 296 mbufcp = *dpos; 297 len = mtod(mp, caddr_t)+mp->m_len-mbufcp; 298 rem = nfsm_rndup(siz)-siz; 299 while (siz > 0) { 300 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) 301 return (EFBIG); 302 left = uiop->uio_iov->iov_len; 303 uiocp = uiop->uio_iov->iov_base; 304 if (left > siz) 305 left = siz; 306 uiosiz = left; 307 while (left > 0) { 308 while (len == 0) { 309 mp = mp->m_next; 310 if (mp == NULL) 311 return (EBADRPC); 312 mbufcp = mtod(mp, caddr_t); 313 len = mp->m_len; 314 } 315 xfer = (left > len) ? len : left; 316#ifdef notdef 317 /* Not Yet.. */ 318 if (uiop->uio_iov->iov_op != NULL) 319 (*(uiop->uio_iov->iov_op)) 320 (mbufcp, uiocp, xfer); 321 else 322#endif 323 if (uiop->uio_segflg == UIO_SYSSPACE) 324 bcopy(mbufcp, uiocp, xfer); 325 else 326 copyout(mbufcp, uiocp, xfer); 327 left -= xfer; 328 len -= xfer; 329 mbufcp += xfer; 330 uiocp += xfer; 331 uiop->uio_offset += xfer; 332 uiop->uio_resid -= xfer; 333 } 334 if (uiop->uio_iov->iov_len <= siz) { 335 uiop->uio_iovcnt--; 336 uiop->uio_iov++; 337 } else { 338 uiop->uio_iov->iov_base += uiosiz; 339 uiop->uio_iov->iov_len -= uiosiz; 340 } 341 siz -= uiosiz; 342 } 343 *dpos = mbufcp; 344 *mrep = mp; 345 if (rem > 0) { 346 if (len < rem) 347 error = nfs_adv(mrep, dpos, rem, len); 348 else 349 *dpos += rem; 350 } 351 return (error); 352} 353 354/* 355 * copies a uio scatter/gather list to an mbuf chain... 356 */ 357int 358nfsm_uiotombuf(uiop, mq, siz, bpos) 359 register struct uio *uiop; 360 struct mbuf **mq; 361 int siz; 362 caddr_t *bpos; 363{ 364 register char *uiocp; 365 register struct mbuf *mp, *mp2; 366 register int xfer, left, mlen; 367 int uiosiz, clflg, rem; 368 char *cp; 369 370 if (siz > MLEN) /* or should it >= MCLBYTES ?? */ 371 clflg = 1; 372 else 373 clflg = 0; 374 rem = nfsm_rndup(siz)-siz; 375 mp = mp2 = *mq; 376 while (siz > 0) { 377 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) 378 return (EINVAL); 379 left = uiop->uio_iov->iov_len; 380 uiocp = uiop->uio_iov->iov_base; 381 if (left > siz) 382 left = siz; 383 uiosiz = left; 384 while (left > 0) { 385 mlen = M_TRAILINGSPACE(mp); 386 if (mlen == 0) { 387 MGET(mp, M_WAIT, MT_DATA); 388 if (clflg) 389 MCLGET(mp, M_WAIT); 390 mp->m_len = 0; 391 mp2->m_next = mp; 392 mp2 = mp; 393 mlen = M_TRAILINGSPACE(mp); 394 } 395 xfer = (left > mlen) ? mlen : left; 396#ifdef notdef 397 /* Not Yet.. */ 398 if (uiop->uio_iov->iov_op != NULL) 399 (*(uiop->uio_iov->iov_op)) 400 (uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 401 else 402#endif 403 if (uiop->uio_segflg == UIO_SYSSPACE) 404 bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 405 else 406 copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 407 mp->m_len += xfer; 408 left -= xfer; 409 uiocp += xfer; 410 uiop->uio_offset += xfer; 411 uiop->uio_resid -= xfer; 412 } 413 if (uiop->uio_iov->iov_len <= siz) { 414 uiop->uio_iovcnt--; 415 uiop->uio_iov++; 416 } else { 417 uiop->uio_iov->iov_base += uiosiz; 418 uiop->uio_iov->iov_len -= uiosiz; 419 } 420 siz -= uiosiz; 421 } 422 if (rem > 0) { 423 if (rem > M_TRAILINGSPACE(mp)) { 424 MGET(mp, M_WAIT, MT_DATA); 425 mp->m_len = 0; 426 mp2->m_next = mp; 427 } 428 cp = mtod(mp, caddr_t)+mp->m_len; 429 for (left = 0; left < rem; left++) 430 *cp++ = '\0'; 431 mp->m_len += rem; 432 *bpos = cp; 433 } else 434 *bpos = mtod(mp, caddr_t)+mp->m_len; 435 *mq = mp; 436 return (0); 437} 438 439/* 440 * Help break down an mbuf chain by setting the first siz bytes contiguous 441 * pointed to by returned val. 442 * This is used by the macros nfsm_dissect and nfsm_dissecton for tough 443 * cases. (The macros use the vars. dpos and dpos2) 444 */ 445int 446nfsm_disct(mdp, dposp, siz, left, cp2) 447 struct mbuf **mdp; 448 caddr_t *dposp; 449 int siz; 450 int left; 451 caddr_t *cp2; 452{ 453 register struct mbuf *mp, *mp2; 454 register int siz2, xfer; 455 register caddr_t p; 456 457 mp = *mdp; 458 while (left == 0) { 459 *mdp = mp = mp->m_next; 460 if (mp == NULL) 461 return (EBADRPC); 462 left = mp->m_len; 463 *dposp = mtod(mp, caddr_t); 464 } 465 if (left >= siz) { 466 *cp2 = *dposp; 467 *dposp += siz; 468 } else if (mp->m_next == NULL) { 469 return (EBADRPC); 470 } else if (siz > MHLEN) { 471 panic("nfs S too big"); 472 } else { 473 MGET(mp2, M_WAIT, MT_DATA); 474 mp2->m_next = mp->m_next; 475 mp->m_next = mp2; 476 mp->m_len -= left; 477 mp = mp2; 478 *cp2 = p = mtod(mp, caddr_t); 479 bcopy(*dposp, p, left); /* Copy what was left */ 480 siz2 = siz-left; 481 p += left; 482 mp2 = mp->m_next; 483 /* Loop around copying up the siz2 bytes */ 484 while (siz2 > 0) { 485 if (mp2 == NULL) 486 return (EBADRPC); 487 xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2; 488 if (xfer > 0) { 489 bcopy(mtod(mp2, caddr_t), p, xfer); 490 NFSMADV(mp2, xfer); 491 mp2->m_len -= xfer; 492 p += xfer; 493 siz2 -= xfer; 494 } 495 if (siz2 > 0) 496 mp2 = mp2->m_next; 497 } 498 mp->m_len = siz; 499 *mdp = mp2; 500 *dposp = mtod(mp2, caddr_t); 501 } 502 return (0); 503} 504 505/* 506 * Advance the position in the mbuf chain. 507 */ 508int 509nfs_adv(mdp, dposp, offs, left) 510 struct mbuf **mdp; 511 caddr_t *dposp; 512 int offs; 513 int left; 514{ 515 register struct mbuf *m; 516 register int s; 517 518 m = *mdp; 519 s = left; 520 while (s < offs) { 521 offs -= s; 522 m = m->m_next; 523 if (m == NULL) 524 return (EBADRPC); 525 s = m->m_len; 526 } 527 *mdp = m; 528 *dposp = mtod(m, caddr_t)+offs; 529 return (0); 530} 531 532/* 533 * Copy a string into mbufs for the hard cases... 534 */ 535int 536nfsm_strtmbuf(mb, bpos, cp, siz) 537 struct mbuf **mb; 538 char **bpos; 539 char *cp; 540 long siz; 541{ 542 register struct mbuf *m1 = 0, *m2; 543 long left, xfer, len, tlen; 544 u_long *tl; 545 int putsize; 546 547 putsize = 1; 548 m2 = *mb; 549 left = M_TRAILINGSPACE(m2); 550 if (left > 0) { 551 tl = ((u_long *)(*bpos)); 552 *tl++ = txdr_unsigned(siz); 553 putsize = 0; 554 left -= NFSX_UNSIGNED; 555 m2->m_len += NFSX_UNSIGNED; 556 if (left > 0) { 557 bcopy(cp, (caddr_t) tl, left); 558 siz -= left; 559 cp += left; 560 m2->m_len += left; 561 left = 0; 562 } 563 } 564 /* Loop around adding mbufs */ 565 while (siz > 0) { 566 MGET(m1, M_WAIT, MT_DATA); 567 if (siz > MLEN) 568 MCLGET(m1, M_WAIT); 569 m1->m_len = NFSMSIZ(m1); 570 m2->m_next = m1; 571 m2 = m1; 572 tl = mtod(m1, u_long *); 573 tlen = 0; 574 if (putsize) { 575 *tl++ = txdr_unsigned(siz); 576 m1->m_len -= NFSX_UNSIGNED; 577 tlen = NFSX_UNSIGNED; 578 putsize = 0; 579 } 580 if (siz < m1->m_len) { 581 len = nfsm_rndup(siz); 582 xfer = siz; 583 if (xfer < len) 584 *(tl+(xfer>>2)) = 0; 585 } else { 586 xfer = len = m1->m_len; 587 } 588 bcopy(cp, (caddr_t) tl, xfer); 589 m1->m_len = len+tlen; 590 siz -= xfer; 591 cp += xfer; 592 } 593 *mb = m1; 594 *bpos = mtod(m1, caddr_t)+m1->m_len; 595 return (0); 596} 597 598/* 599 * Called once to initialize data structures... 600 */ 601int 602nfs_init() 603{ 604 register int i; 605 606 nfsrtt.pos = 0; 607 rpc_vers = txdr_unsigned(RPC_VER2); 608 rpc_call = txdr_unsigned(RPC_CALL); 609 rpc_reply = txdr_unsigned(RPC_REPLY); 610 rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED); 611 rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED); 612 rpc_mismatch = txdr_unsigned(RPC_MISMATCH); 613 rpc_autherr = txdr_unsigned(RPC_AUTHERR); 614 rpc_rejectedcred = txdr_unsigned(AUTH_REJECTCRED); 615 rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX); 616 rpc_auth_kerb = txdr_unsigned(RPCAUTH_NQNFS); 617 nfs_vers = txdr_unsigned(NFS_VER2); 618 nfs_prog = txdr_unsigned(NFS_PROG); 619 nfs_true = txdr_unsigned(TRUE); 620 nfs_false = txdr_unsigned(FALSE); 621 nfs_xdrneg1 = txdr_unsigned(-1); 622 /* Loop thru nfs procids */ 623 for (i = 0; i < NFS_NPROCS; i++) 624 nfs_procids[i] = txdr_unsigned(i); 625 /* Ensure async daemons disabled */ 626 for (i = 0; i < NFS_MAXASYNCDAEMON; i++) 627 nfs_iodwant[i] = (struct proc *)0; 628 TAILQ_INIT(&nfs_bufq); 629 nfs_nhinit(); /* Init the nfsnode table */ 630 nfsrv_init(0); /* Init server data structures */ 631 nfsrv_initcache(); /* Init the server request cache */ 632 633 /* 634 * Initialize the nqnfs server stuff. 635 */ 636 if (nqnfsstarttime == 0) { 637 nqnfsstarttime = boottime.tv_sec + nqsrv_maxlease 638 + nqsrv_clockskew + nqsrv_writeslack; 639 NQLOADNOVRAM(nqnfsstarttime); 640 nqnfs_prog = txdr_unsigned(NQNFS_PROG); 641 nqnfs_vers = txdr_unsigned(NQNFS_VER1); 642 CIRCLEQ_INIT(&nqtimerhead); 643 nqfhhashtbl = hashinit(NQLCHSZ, M_NQLEASE, &nqfhhash); 644 } 645 646 /* 647 * Initialize reply list and start timer 648 */ 649 TAILQ_INIT(&nfs_reqq); 650 nfs_timer(0); 651 652 /* 653 * Set up lease_check and lease_updatetime so that other parts 654 * of the system can call us, if we are loadable. 655 */ 656 lease_check = nfs_lease_check; 657 lease_updatetime = nfs_lease_updatetime; 658 vfsconf[MOUNT_NFS]->vfc_refcount++; /* make us non-unloadable */ 659#ifdef VFS_LKM 660 sysent[SYS_nfssvc].sy_narg = 2; 661 sysent[SYS_nfssvc].sy_call = nfssvc; 662 sysent[SYS_getfh].sy_narg = 2; 663 sysent[SYS_getfh].sy_call = getfh; 664#endif 665 666 return (0); 667} 668 669/* 670 * Attribute cache routines. 671 * nfs_loadattrcache() - loads or updates the cache contents from attributes 672 * that are on the mbuf list 673 * nfs_getattrcache() - returns valid attributes if found in cache, returns 674 * error otherwise 675 */ 676 677/* 678 * Load the attribute cache (that lives in the nfsnode entry) with 679 * the values on the mbuf list and 680 * Iff vap not NULL 681 * copy the attributes to *vaper 682 */ 683int 684nfs_loadattrcache(vpp, mdp, dposp, vaper) 685 struct vnode **vpp; 686 struct mbuf **mdp; 687 caddr_t *dposp; 688 struct vattr *vaper; 689{ 690 register struct vnode *vp = *vpp; 691 register struct vattr *vap; 692 register struct nfsv2_fattr *fp; 693 extern int (**spec_nfsv2nodeop_p)(); 694 register struct nfsnode *np; 695 register struct nfsnodehashhead *nhpp; 696 register long t1; 697 caddr_t dpos, cp2; 698 int error = 0, isnq; 699 struct mbuf *md; 700 enum vtype vtyp; 701 u_short vmode; 702 long rdev; 703 struct timespec mtime; 704 struct vnode *nvp; 705 706 md = *mdp; 707 dpos = *dposp; 708 t1 = (mtod(md, caddr_t) + md->m_len) - dpos; 709 isnq = (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS); 710 error = nfsm_disct(&md, &dpos, NFSX_FATTR(isnq), t1, &cp2); 711 if (error) 712 return (error); 713 fp = (struct nfsv2_fattr *)cp2; 714 vtyp = nfstov_type(fp->fa_type); 715 vmode = fxdr_unsigned(u_short, fp->fa_mode); 716 if (vtyp == VNON || vtyp == VREG) 717 vtyp = IFTOVT(vmode); 718 if (isnq) { 719 rdev = fxdr_unsigned(long, fp->fa_nqrdev); 720 fxdr_nqtime(&fp->fa_nqmtime, &mtime); 721 } else { 722 rdev = fxdr_unsigned(long, fp->fa_nfsrdev); 723 fxdr_nfstime(&fp->fa_nfsmtime, &mtime); 724 } 725 /* 726 * If v_type == VNON it is a new node, so fill in the v_type, 727 * n_mtime fields. Check to see if it represents a special 728 * device, and if so, check for a possible alias. Once the 729 * correct vnode has been obtained, fill in the rest of the 730 * information. 731 */ 732 np = VTONFS(vp); 733 if (vp->v_type == VNON) { 734 if (vtyp == VCHR && rdev == 0xffffffff) 735 vp->v_type = vtyp = VFIFO; 736 else 737 vp->v_type = vtyp; 738 if (vp->v_type == VFIFO) { 739 extern int (**fifo_nfsv2nodeop_p)(); 740 vp->v_op = fifo_nfsv2nodeop_p; 741 } 742 if (vp->v_type == VCHR || vp->v_type == VBLK) { 743 vp->v_op = spec_nfsv2nodeop_p; 744 nvp = checkalias(vp, (dev_t)rdev, vp->v_mount); 745 if (nvp) { 746 /* 747 * Discard unneeded vnode, but save its nfsnode. 748 */ 749 LIST_REMOVE(np, n_hash); 750 nvp->v_data = vp->v_data; 751 vp->v_data = NULL; 752 vp->v_op = spec_vnodeop_p; 753 vrele(vp); 754 vgone(vp); 755 /* 756 * Reinitialize aliased node. 757 */ 758 np->n_vnode = nvp; 759 nhpp = nfs_hash(&np->n_fh); 760 LIST_INSERT_HEAD(nhpp, np, n_hash); 761 *vpp = vp = nvp; 762 } 763 } 764 np->n_mtime = mtime.ts_sec; 765 } 766 vap = &np->n_vattr; 767 vap->va_type = vtyp; 768 vap->va_mode = (vmode & 07777); 769 vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink); 770 vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid); 771 vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid); 772 vap->va_rdev = (dev_t)rdev; 773 vap->va_mtime = mtime; 774 vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; 775 if (isnq) { 776 fxdr_hyper(&fp->fa_nqsize, &vap->va_size); 777 vap->va_blocksize = fxdr_unsigned(long, fp->fa_nqblocksize); 778 fxdr_hyper(&fp->fa_nqbytes, &vap->va_bytes); 779 vap->va_fileid = fxdr_unsigned(long, fp->fa_nqfileid); 780 fxdr_nqtime(&fp->fa_nqatime, &vap->va_atime); 781 vap->va_flags = fxdr_unsigned(u_long, fp->fa_nqflags); 782 fxdr_nqtime(&fp->fa_nqctime, &vap->va_ctime); 783 vap->va_gen = fxdr_unsigned(u_long, fp->fa_nqgen); 784 fxdr_hyper(&fp->fa_nqfilerev, &vap->va_filerev); 785 } else { 786 vap->va_size = fxdr_unsigned(u_long, fp->fa_nfssize); 787 vap->va_blocksize = fxdr_unsigned(long, fp->fa_nfsblocksize); 788 vap->va_bytes = fxdr_unsigned(long, fp->fa_nfsblocks) * NFS_FABLKSIZE; 789 vap->va_fileid = fxdr_unsigned(long, fp->fa_nfsfileid); 790 fxdr_nfstime(&fp->fa_nfsatime, &vap->va_atime); 791 vap->va_flags = 0; 792 fxdr_nfstime(&fp->fa_nfsctime, &vap->va_ctime); 793 vap->va_gen = 0; 794 vap->va_filerev = 0; 795 } 796 if (vap->va_size != np->n_size) { 797 if (vap->va_type == VREG) { 798 if (np->n_flag & NMODIFIED) { 799 if (vap->va_size < np->n_size) 800 vap->va_size = np->n_size; 801 else 802 np->n_size = vap->va_size; 803 } else 804 np->n_size = vap->va_size; 805 vnode_pager_setsize(vp, (u_long)np->n_size); 806 } else 807 np->n_size = vap->va_size; 808 } 809 np->n_attrstamp = time.tv_sec; 810 *dposp = dpos; 811 *mdp = md; 812 if (vaper != NULL) { 813 bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap)); 814#ifdef notdef 815 if ((np->n_flag & NMODIFIED) && np->n_size > vap->va_size) 816 if (np->n_size > vap->va_size) 817 vaper->va_size = np->n_size; 818#endif 819 if (np->n_flag & NCHG) { 820 if (np->n_flag & NACC) { 821 vaper->va_atime.ts_sec = np->n_atim.tv_sec; 822 vaper->va_atime.ts_nsec = 823 np->n_atim.tv_usec * 1000; 824 } 825 if (np->n_flag & NUPD) { 826 vaper->va_mtime.ts_sec = np->n_mtim.tv_sec; 827 vaper->va_mtime.ts_nsec = 828 np->n_mtim.tv_usec * 1000; 829 } 830 } 831 } 832 return (0); 833} 834 835/* 836 * Check the time stamp 837 * If the cache is valid, copy contents to *vap and return 0 838 * otherwise return an error 839 */ 840int 841nfs_getattrcache(vp, vaper) 842 register struct vnode *vp; 843 struct vattr *vaper; 844{ 845 register struct nfsnode *np = VTONFS(vp); 846 register struct vattr *vap; 847 848 if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQLOOKLEASE) { 849 if (!NQNFS_CKCACHABLE(vp, NQL_READ) || np->n_attrstamp == 0) { 850 nfsstats.attrcache_misses++; 851 return (ENOENT); 852 } 853 } else if ((time.tv_sec - np->n_attrstamp) >= NFS_ATTRTIMEO(np)) { 854 nfsstats.attrcache_misses++; 855 return (ENOENT); 856 } 857 nfsstats.attrcache_hits++; 858 vap = &np->n_vattr; 859 if (vap->va_size != np->n_size) { 860 if (vap->va_type == VREG) { 861 if (np->n_flag & NMODIFIED) { 862 if (vap->va_size < np->n_size) 863 vap->va_size = np->n_size; 864 else 865 np->n_size = vap->va_size; 866 } else 867 np->n_size = vap->va_size; 868 vnode_pager_setsize(vp, (u_long)np->n_size); 869 } else 870 np->n_size = vap->va_size; 871 } 872 bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(struct vattr)); 873#ifdef notdef 874 if ((np->n_flag & NMODIFIED) == 0) { 875 np->n_size = vaper->va_size; 876 vnode_pager_setsize(vp, (u_long)np->n_size); 877 } else if (np->n_size > vaper->va_size) 878 if (np->n_size > vaper->va_size) 879 vaper->va_size = np->n_size; 880#endif 881 if (np->n_flag & NCHG) { 882 if (np->n_flag & NACC) { 883 vaper->va_atime.ts_sec = np->n_atim.tv_sec; 884 vaper->va_atime.ts_nsec = np->n_atim.tv_usec * 1000; 885 } 886 if (np->n_flag & NUPD) { 887 vaper->va_mtime.ts_sec = np->n_mtim.tv_sec; 888 vaper->va_mtime.ts_nsec = np->n_mtim.tv_usec * 1000; 889 } 890 } 891 return (0); 892} 893 894/* 895 * Set up nameidata for a lookup() call and do it 896 */ 897int 898nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, p) 899 register struct nameidata *ndp; 900 fhandle_t *fhp; 901 int len; 902 struct nfssvc_sock *slp; 903 struct mbuf *nam; 904 struct mbuf **mdp; 905 caddr_t *dposp; 906 struct proc *p; 907{ 908 register int i, rem; 909 register struct mbuf *md; 910 register char *fromcp, *tocp; 911 struct vnode *dp; 912 int error, rdonly; 913 struct componentname *cnp = &ndp->ni_cnd; 914 915 MALLOC(cnp->cn_pnbuf, char *, len + 1, M_NAMEI, M_WAITOK); 916 /* 917 * Copy the name from the mbuf list to ndp->ni_pnbuf 918 * and set the various ndp fields appropriately. 919 */ 920 fromcp = *dposp; 921 tocp = cnp->cn_pnbuf; 922 md = *mdp; 923 rem = mtod(md, caddr_t) + md->m_len - fromcp; 924 cnp->cn_hash = 0; 925 for (i = 0; i < len; i++) { 926 while (rem == 0) { 927 md = md->m_next; 928 if (md == NULL) { 929 error = EBADRPC; 930 goto out; 931 } 932 fromcp = mtod(md, caddr_t); 933 rem = md->m_len; 934 } 935 if (*fromcp == '\0' || *fromcp == '/') { 936 error = EINVAL; 937 goto out; 938 } 939 cnp->cn_hash += (unsigned char)*fromcp; 940 *tocp++ = *fromcp++; 941 rem--; 942 } 943 *tocp = '\0'; 944 *mdp = md; 945 *dposp = fromcp; 946 len = nfsm_rndup(len)-len; 947 if (len > 0) { 948 if (rem >= len) 949 *dposp += len; 950 else { 951 error = nfs_adv(mdp, dposp, len, rem); 952 if (error) 953 goto out; 954 } 955 } 956 ndp->ni_pathlen = tocp - cnp->cn_pnbuf; 957 cnp->cn_nameptr = cnp->cn_pnbuf; 958 /* 959 * Extract and set starting directory. 960 */ 961 error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp, 962 nam, &rdonly); 963 if (error) 964 goto out; 965 if (dp->v_type != VDIR) { 966 nfsrv_vrele(dp); 967 error = ENOTDIR; 968 goto out; 969 } 970 ndp->ni_startdir = dp; 971 if (rdonly) 972 cnp->cn_flags |= (NOCROSSMOUNT | RDONLY); 973 else 974 cnp->cn_flags |= NOCROSSMOUNT; 975 /* 976 * And call lookup() to do the real work 977 */ 978 cnp->cn_proc = p; 979 error = lookup(ndp); 980 if (error) 981 goto out; 982 /* 983 * Check for encountering a symbolic link 984 */ 985 if (cnp->cn_flags & ISSYMLINK) { 986 if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1) 987 vput(ndp->ni_dvp); 988 else 989 vrele(ndp->ni_dvp); 990 vput(ndp->ni_vp); 991 ndp->ni_vp = NULL; 992 error = EINVAL; 993 goto out; 994 } 995 /* 996 * Check for saved name request 997 */ 998 if (cnp->cn_flags & (SAVENAME | SAVESTART)) { 999 cnp->cn_flags |= HASBUF; 1000 nfsrv_vmio( ndp->ni_vp); 1001 return (0); 1002 } 1003out: 1004 FREE(cnp->cn_pnbuf, M_NAMEI); 1005 return (error); 1006} 1007 1008/* 1009 * A fiddled version of m_adj() that ensures null fill to a long 1010 * boundary and only trims off the back end 1011 */ 1012void 1013nfsm_adj(mp, len, nul) 1014 struct mbuf *mp; 1015 register int len; 1016 int nul; 1017{ 1018 register struct mbuf *m; 1019 register int count, i; 1020 register char *cp; 1021 1022 /* 1023 * Trim from tail. Scan the mbuf chain, 1024 * calculating its length and finding the last mbuf. 1025 * If the adjustment only affects this mbuf, then just 1026 * adjust and return. Otherwise, rescan and truncate 1027 * after the remaining size. 1028 */ 1029 count = 0; 1030 m = mp; 1031 for (;;) { 1032 count += m->m_len; 1033 if (m->m_next == (struct mbuf *)0) 1034 break; 1035 m = m->m_next; 1036 } 1037 if (m->m_len > len) { 1038 m->m_len -= len; 1039 if (nul > 0) { 1040 cp = mtod(m, caddr_t)+m->m_len-nul; 1041 for (i = 0; i < nul; i++) 1042 *cp++ = '\0'; 1043 } 1044 return; 1045 } 1046 count -= len; 1047 if (count < 0) 1048 count = 0; 1049 /* 1050 * Correct length for chain is "count". 1051 * Find the mbuf with last data, adjust its length, 1052 * and toss data from remaining mbufs on chain. 1053 */ 1054 for (m = mp; m; m = m->m_next) { 1055 if (m->m_len >= count) { 1056 m->m_len = count; 1057 if (nul > 0) { 1058 cp = mtod(m, caddr_t)+m->m_len-nul; 1059 for (i = 0; i < nul; i++) 1060 *cp++ = '\0'; 1061 } 1062 break; 1063 } 1064 count -= m->m_len; 1065 } 1066 for (m = m->m_next;m;m = m->m_next) 1067 m->m_len = 0; 1068} 1069 1070/* 1071 * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked) 1072 * - look up fsid in mount list (if not found ret error) 1073 * - get vp and export rights by calling VFS_FHTOVP() 1074 * - if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon 1075 * - if not lockflag unlock it with VOP_UNLOCK() 1076 */ 1077int 1078nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp) 1079 fhandle_t *fhp; 1080 int lockflag; 1081 struct vnode **vpp; 1082 struct ucred *cred; 1083 struct nfssvc_sock *slp; 1084 struct mbuf *nam; 1085 int *rdonlyp; 1086{ 1087 register struct mount *mp; 1088 register struct nfsuid *uidp; 1089 register int i; 1090 struct ucred *credanon; 1091 int error, exflags; 1092 1093 *vpp = (struct vnode *)0; 1094 mp = getvfs(&fhp->fh_fsid); 1095 if (!mp) 1096 return (ESTALE); 1097 error = VFS_FHTOVP(mp, &fhp->fh_fid, nam, vpp, &exflags, &credanon); 1098 if (error) 1099 return (error); 1100 /* 1101 * Check/setup credentials. 1102 */ 1103 if (exflags & MNT_EXKERB) { 1104 for (uidp = NUIDHASH(slp, cred->cr_uid)->lh_first; uidp != 0; 1105 uidp = uidp->nu_hash.le_next) { 1106 if (uidp->nu_uid == cred->cr_uid) 1107 break; 1108 } 1109 if (uidp == 0) { 1110 vput(*vpp); 1111 return (NQNFS_AUTHERR); 1112 } 1113 cred->cr_uid = uidp->nu_cr.cr_uid; 1114 for (i = 0; i < uidp->nu_cr.cr_ngroups; i++) 1115 cred->cr_groups[i] = uidp->nu_cr.cr_groups[i]; 1116 cred->cr_ngroups = i; 1117 } else if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) { 1118 cred->cr_uid = credanon->cr_uid; 1119 for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++) 1120 cred->cr_groups[i] = credanon->cr_groups[i]; 1121 cred->cr_ngroups = i; 1122 } 1123 if (exflags & MNT_EXRDONLY) 1124 *rdonlyp = 1; 1125 else 1126 *rdonlyp = 0; 1127 if (!lockflag) 1128 VOP_UNLOCK(*vpp); 1129 nfsrv_vmio(*vpp); 1130 return (0); 1131} 1132 1133/* 1134 * This function compares two net addresses by family and returns TRUE 1135 * if they are the same host. 1136 * If there is any doubt, return FALSE. 1137 * The AF_INET family is handled as a special case so that address mbufs 1138 * don't need to be saved to store "struct in_addr", which is only 4 bytes. 1139 */ 1140int 1141netaddr_match(family, haddr, nam) 1142 int family; 1143 union nethostaddr *haddr; 1144 struct mbuf *nam; 1145{ 1146 register struct sockaddr_in *inetaddr; 1147 1148 switch (family) { 1149 case AF_INET: 1150 inetaddr = mtod(nam, struct sockaddr_in *); 1151 if (inetaddr->sin_family == AF_INET && 1152 inetaddr->sin_addr.s_addr == haddr->had_inetaddr) 1153 return (1); 1154 break; 1155#ifdef ISO 1156 case AF_ISO: 1157 { 1158 register struct sockaddr_iso *isoaddr1, *isoaddr2; 1159 1160 isoaddr1 = mtod(nam, struct sockaddr_iso *); 1161 isoaddr2 = mtod(haddr->had_nam, struct sockaddr_iso *); 1162 if (isoaddr1->siso_family == AF_ISO && 1163 isoaddr1->siso_nlen > 0 && 1164 isoaddr1->siso_nlen == isoaddr2->siso_nlen && 1165 SAME_ISOADDR(isoaddr1, isoaddr2)) 1166 return (1); 1167 break; 1168 } 1169#endif /* ISO */ 1170 default: 1171 break; 1172 }; 1173 return (0); 1174} 1175 1176int 1177nfsrv_vmio( struct vnode *vp) {
|