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