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