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