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