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