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.53 (Berkeley) 05/20/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.tv_sec = fxdr_unsigned(long, fp->fa_atime.tv_sec); 730 vap->va_atime.tv_usec = 0; 731 vap->va_flags = fxdr_unsigned(u_long, fp->fa_atime.tv_usec); 732 vap->va_mtime = mtime; 733 vap->va_ctime.tv_sec = fxdr_unsigned(long, fp->fa_ctime.tv_sec); 734 vap->va_ctime.tv_usec = 0; 735 vap->va_gen = fxdr_unsigned(u_long, fp->fa_ctime.tv_usec); 736 #ifdef _NOQUAD 737 vap->va_size_rsv = 0; 738 vap->va_bytes_rsv = 0; 739 #endif 740 np->n_attrstamp = time.tv_sec; 741 *dposp = dpos; 742 *mdp = md; 743 if (vaper != NULL) { 744 bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap)); 745 if ((np->n_flag & NMODIFIED) && (np->n_size > vap->va_size)) 746 vaper->va_size = np->n_size; 747 if (np->n_flag & NCHG) { 748 if (np->n_flag & NACC) 749 vaper->va_atime = np->n_atim; 750 if (np->n_flag & NUPD) 751 vaper->va_mtime = np->n_mtim; 752 } 753 } 754 return (0); 755 } 756 757 /* 758 * Check the time stamp 759 * If the cache is valid, copy contents to *vap and return 0 760 * otherwise return an error 761 */ 762 nfs_getattrcache(vp, vap) 763 register struct vnode *vp; 764 struct vattr *vap; 765 { 766 register struct nfsnode *np; 767 768 np = VTONFS(vp); 769 if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) { 770 if (!NQNFS_CKCACHABLE(vp, NQL_READ) || np->n_attrstamp == 0) { 771 nfsstats.attrcache_misses++; 772 return (ENOENT); 773 } 774 } else if ((time.tv_sec - np->n_attrstamp) >= NFS_ATTRTIMEO) { 775 nfsstats.attrcache_misses++; 776 return (ENOENT); 777 } 778 nfsstats.attrcache_hits++; 779 bcopy((caddr_t)&np->n_vattr,(caddr_t)vap,sizeof(struct vattr)); 780 if ((np->n_flag & NMODIFIED) == 0) { 781 np->n_size = vap->va_size; 782 vnode_pager_setsize(vp, (u_long)np->n_size); 783 } else if (np->n_size > vap->va_size) 784 vap->va_size = np->n_size; 785 if (np->n_flag & NCHG) { 786 if (np->n_flag & NACC) 787 vap->va_atime = np->n_atim; 788 if (np->n_flag & NUPD) 789 vap->va_mtime = np->n_mtim; 790 } 791 return (0); 792 } 793 794 /* 795 * Set up nameidata for a lookup() call and do it 796 */ 797 nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, p) 798 register struct nameidata *ndp; 799 fhandle_t *fhp; 800 int len; 801 struct nfssvc_sock *slp; 802 struct mbuf *nam; 803 struct mbuf **mdp; 804 caddr_t *dposp; 805 struct proc *p; 806 { 807 register int i, rem; 808 register struct mbuf *md; 809 register char *fromcp, *tocp; 810 struct vnode *dp; 811 int error, rdonly; 812 struct componentname *cnp = &ndp->ni_cnd; 813 814 MALLOC(cnp->cn_pnbuf, char *, len + 1, M_NAMEI, M_WAITOK); 815 /* 816 * Copy the name from the mbuf list to ndp->ni_pnbuf 817 * and set the various ndp fields appropriately. 818 */ 819 fromcp = *dposp; 820 tocp = cnp->cn_pnbuf; 821 md = *mdp; 822 rem = mtod(md, caddr_t) + md->m_len - fromcp; 823 cnp->cn_hash = 0; 824 for (i = 0; i < len; i++) { 825 while (rem == 0) { 826 md = md->m_next; 827 if (md == NULL) { 828 error = EBADRPC; 829 goto out; 830 } 831 fromcp = mtod(md, caddr_t); 832 rem = md->m_len; 833 } 834 if (*fromcp == '\0' || *fromcp == '/') { 835 error = EINVAL; 836 goto out; 837 } 838 if (*fromcp & 0200) 839 if ((*fromcp&0377) == ('/'|0200) || cnp->cn_nameiop != DELETE) { 840 error = EINVAL; 841 goto out; 842 } 843 cnp->cn_hash += (unsigned char)*fromcp; 844 *tocp++ = *fromcp++; 845 rem--; 846 } 847 *tocp = '\0'; 848 *mdp = md; 849 *dposp = fromcp; 850 len = nfsm_rndup(len)-len; 851 if (len > 0) { 852 if (rem >= len) 853 *dposp += len; 854 else if (error = nfs_adv(mdp, dposp, len, rem)) 855 goto out; 856 } 857 ndp->ni_pathlen = tocp - cnp->cn_pnbuf; 858 cnp->cn_nameptr = cnp->cn_pnbuf; 859 /* 860 * Extract and set starting directory. 861 */ 862 if (error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp, 863 nam, &rdonly)) 864 goto out; 865 if (dp->v_type != VDIR) { 866 vrele(dp); 867 error = ENOTDIR; 868 goto out; 869 } 870 ndp->ni_startdir = dp; 871 if (rdonly) 872 cnp->cn_flags |= (NOCROSSMOUNT | RDONLY); 873 else 874 cnp->cn_flags |= NOCROSSMOUNT; 875 /* 876 * And call lookup() to do the real work 877 */ 878 cnp->cn_proc = p; 879 if (error = lookup(ndp)) 880 goto out; 881 /* 882 * Check for encountering a symbolic link 883 */ 884 if (cnp->cn_flags & ISSYMLINK) { 885 if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1) 886 vput(ndp->ni_dvp); 887 else 888 vrele(ndp->ni_dvp); 889 vput(ndp->ni_vp); 890 ndp->ni_vp = NULL; 891 error = EINVAL; 892 goto out; 893 } 894 /* 895 * Check for saved name request 896 */ 897 if (cnp->cn_flags & (SAVENAME | SAVESTART)) { 898 cnp->cn_flags |= HASBUF; 899 return (0); 900 } 901 out: 902 FREE(cnp->cn_pnbuf, M_NAMEI); 903 return (error); 904 } 905 906 /* 907 * A fiddled version of m_adj() that ensures null fill to a long 908 * boundary and only trims off the back end 909 */ 910 void 911 nfsm_adj(mp, len, nul) 912 struct mbuf *mp; 913 register int len; 914 int nul; 915 { 916 register struct mbuf *m; 917 register int count, i; 918 register char *cp; 919 920 /* 921 * Trim from tail. Scan the mbuf chain, 922 * calculating its length and finding the last mbuf. 923 * If the adjustment only affects this mbuf, then just 924 * adjust and return. Otherwise, rescan and truncate 925 * after the remaining size. 926 */ 927 count = 0; 928 m = mp; 929 for (;;) { 930 count += m->m_len; 931 if (m->m_next == (struct mbuf *)0) 932 break; 933 m = m->m_next; 934 } 935 if (m->m_len > len) { 936 m->m_len -= len; 937 if (nul > 0) { 938 cp = mtod(m, caddr_t)+m->m_len-nul; 939 for (i = 0; i < nul; i++) 940 *cp++ = '\0'; 941 } 942 return; 943 } 944 count -= len; 945 if (count < 0) 946 count = 0; 947 /* 948 * Correct length for chain is "count". 949 * Find the mbuf with last data, adjust its length, 950 * and toss data from remaining mbufs on chain. 951 */ 952 for (m = mp; m; m = m->m_next) { 953 if (m->m_len >= count) { 954 m->m_len = count; 955 if (nul > 0) { 956 cp = mtod(m, caddr_t)+m->m_len-nul; 957 for (i = 0; i < nul; i++) 958 *cp++ = '\0'; 959 } 960 break; 961 } 962 count -= m->m_len; 963 } 964 while (m = m->m_next) 965 m->m_len = 0; 966 } 967 968 /* 969 * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked) 970 * - look up fsid in mount list (if not found ret error) 971 * - check that it is exported 972 * - get vp by calling VFS_FHTOVP() macro 973 * - if not lockflag unlock it with VOP_UNLOCK() 974 * - if cred->cr_uid == 0 or MNT_EXPORTANON set it to neth_anon 975 */ 976 nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp) 977 fhandle_t *fhp; 978 int lockflag; 979 struct vnode **vpp; 980 struct ucred *cred; 981 struct nfssvc_sock *slp; 982 struct mbuf *nam; 983 int *rdonlyp; 984 { 985 USES_VOP_UNLOCK; 986 register struct mount *mp; 987 register struct netaddrhash *np; 988 register struct ufsmount *ump; 989 register struct nfsuid *uidp; 990 struct sockaddr *saddr; 991 int error; 992 993 *vpp = (struct vnode *)0; 994 if ((mp = getvfs(&fhp->fh_fsid)) == NULL) 995 return (ESTALE); 996 if ((mp->mnt_flag & MNT_EXPORTED) == 0) 997 return (EACCES); 998 999 /* 1000 * Get the export permission structure for this <mp, client> tuple. 1001 */ 1002 ump = VFSTOUFS(mp); 1003 if (nam) { 1004 1005 /* 1006 * First search for a network match. 1007 */ 1008 np = ump->um_netaddr[NETMASK_HASH]; 1009 while (np) { 1010 if (nfs_netaddr_match(np->neth_family, &np->neth_haddr, 1011 &np->neth_hmask, nam)) 1012 break; 1013 np = np->neth_next; 1014 } 1015 1016 /* 1017 * If not found, try for an address match. 1018 */ 1019 if (np == (struct netaddrhash *)0) { 1020 saddr = mtod(nam, struct sockaddr *); 1021 np = ump->um_netaddr[NETADDRHASH(saddr)]; 1022 while (np) { 1023 if (nfs_netaddr_match(np->neth_family, &np->neth_haddr, 1024 (struct netaddrhash *)0, nam)) 1025 break; 1026 np = np->neth_next; 1027 } 1028 } 1029 } else 1030 np = (struct netaddrhash *)0; 1031 if (np == (struct netaddrhash *)0) { 1032 1033 /* 1034 * If no address match, use the default if it exists. 1035 */ 1036 if ((mp->mnt_flag & MNT_DEFEXPORTED) == 0) 1037 return (EACCES); 1038 np = &ump->um_defexported; 1039 } 1040 1041 /* 1042 * Check/setup credentials. 1043 */ 1044 if (np->neth_exflags & MNT_EXKERB) { 1045 uidp = slp->ns_uidh[NUIDHASH(cred->cr_uid)]; 1046 while (uidp) { 1047 if (uidp->nu_uid == cred->cr_uid) 1048 break; 1049 uidp = uidp->nu_hnext; 1050 } 1051 if (uidp) { 1052 if (cred->cr_ref != 1) 1053 panic("nsrv fhtovp"); 1054 *cred = uidp->nu_cr; 1055 } else 1056 return (NQNFS_AUTHERR); 1057 } else if (cred->cr_uid == 0 || (np->neth_exflags & MNT_EXPORTANON)) 1058 *cred = np->neth_anon; 1059 if (error = VFS_FHTOVP(mp, &fhp->fh_fid, 0, vpp)) 1060 return (ESTALE); 1061 if (np->neth_exflags & MNT_EXRDONLY) 1062 *rdonlyp = 1; 1063 else 1064 *rdonlyp = 0; 1065 if (!lockflag) 1066 VOP_UNLOCK(*vpp); 1067 return (0); 1068 } 1069