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