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