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