|
|
1.1 ! root 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: * 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 7.41 (Berkeley) 5/15/91 ! 37: */ ! 38: ! 39: /* ! 40: * These functions support the macros and help fiddle mbuf chains for ! 41: * the nfs op functions. They do things like create the rpc header and ! 42: * copy data between mbuf chains and uio lists. ! 43: */ ! 44: #include "param.h" ! 45: #include "proc.h" ! 46: #include "filedesc.h" ! 47: #include "systm.h" ! 48: #include "kernel.h" ! 49: #include "mount.h" ! 50: #include "file.h" ! 51: #include "vnode.h" ! 52: #include "namei.h" ! 53: #include "mbuf.h" ! 54: #include "map.h" ! 55: ! 56: #include "../ufs/quota.h" ! 57: #include "../ufs/inode.h" ! 58: ! 59: #include "rpcv2.h" ! 60: #include "nfsv2.h" ! 61: #include "nfsnode.h" ! 62: #include "nfs.h" ! 63: #include "nfsiom.h" ! 64: #include "xdr_subs.h" ! 65: #include "nfsm_subs.h" ! 66: #include "nfscompress.h" ! 67: ! 68: #define TRUE 1 ! 69: #define FALSE 0 ! 70: ! 71: /* ! 72: * Data items converted to xdr at startup, since they are constant ! 73: * This is kinda hokey, but may save a little time doing byte swaps ! 74: */ ! 75: u_long nfs_procids[NFS_NPROCS]; ! 76: u_long nfs_xdrneg1; ! 77: u_long rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, ! 78: rpc_mismatch, rpc_auth_unix, rpc_msgaccepted; ! 79: u_long nfs_vers, nfs_prog, nfs_true, nfs_false; ! 80: /* And other global data */ ! 81: static u_long *rpc_uidp = (u_long *)0; ! 82: static u_long nfs_xid = 1; ! 83: static char *rpc_unixauth; ! 84: extern long hostid; ! 85: enum vtype ntov_type[7] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON }; ! 86: extern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON]; ! 87: extern struct map nfsmap[NFS_MSIZ]; ! 88: extern struct nfsreq nfsreqh; ! 89: ! 90: /* Function ret types */ ! 91: static char *nfs_unixauth(); ! 92: ! 93: /* ! 94: * Maximum number of groups passed through to NFS server. ! 95: * According to RFC1057 it should be 16. ! 96: * For release 3.X systems, the maximum value is 8. ! 97: * For some other servers, the maximum value is 10. ! 98: */ ! 99: int numgrps = 8; ! 100: ! 101: /* ! 102: * Create the header for an rpc request packet ! 103: * The function nfs_unixauth() creates a unix style authorization string ! 104: * and returns a ptr to it. ! 105: * The hsiz is the size of the rest of the nfs request header. ! 106: * (just used to decide if a cluster is a good idea) ! 107: * nb: Note that the prog, vers and procid args are already in xdr byte order ! 108: */ ! 109: struct mbuf *nfsm_reqh(prog, vers, procid, cred, hsiz, bpos, mb, retxid) ! 110: u_long prog; ! 111: u_long vers; ! 112: u_long procid; ! 113: struct ucred *cred; ! 114: int hsiz; ! 115: caddr_t *bpos; ! 116: struct mbuf **mb; ! 117: u_long *retxid; ! 118: { ! 119: register struct mbuf *mreq, *m; ! 120: register u_long *tl; ! 121: struct mbuf *m1; ! 122: char *ap; ! 123: int asiz, siz; ! 124: ! 125: NFSMGETHDR(mreq); ! 126: asiz = ((((cred->cr_ngroups - 1) > numgrps) ? numgrps : ! 127: (cred->cr_ngroups - 1)) << 2); ! 128: #ifdef FILLINHOST ! 129: asiz += nfsm_rndup(hostnamelen)+(9*NFSX_UNSIGNED); ! 130: #else ! 131: asiz += 9*NFSX_UNSIGNED; ! 132: #endif ! 133: ! 134: /* If we need a lot, alloc a cluster ?? */ ! 135: if ((asiz+hsiz+RPC_SIZ) > MHLEN) ! 136: MCLGET(mreq, M_WAIT); ! 137: mreq->m_len = NFSMSIZ(mreq); ! 138: siz = mreq->m_len; ! 139: m1 = mreq; ! 140: /* ! 141: * Alloc enough mbufs ! 142: * We do it now to avoid all sleeps after the call to nfs_unixauth() ! 143: */ ! 144: while ((asiz+RPC_SIZ) > siz) { ! 145: MGET(m, M_WAIT, MT_DATA); ! 146: m1->m_next = m; ! 147: m->m_len = MLEN; ! 148: siz += MLEN; ! 149: m1 = m; ! 150: } ! 151: tl = mtod(mreq, u_long *); ! 152: *tl++ = *retxid = txdr_unsigned(++nfs_xid); ! 153: *tl++ = rpc_call; ! 154: *tl++ = rpc_vers; ! 155: *tl++ = prog; ! 156: *tl++ = vers; ! 157: *tl++ = procid; ! 158: ! 159: /* Now we can call nfs_unixauth() and copy it in */ ! 160: ap = nfs_unixauth(cred); ! 161: m = mreq; ! 162: siz = m->m_len-RPC_SIZ; ! 163: if (asiz <= siz) { ! 164: bcopy(ap, (caddr_t)tl, asiz); ! 165: m->m_len = asiz+RPC_SIZ; ! 166: } else { ! 167: bcopy(ap, (caddr_t)tl, siz); ! 168: ap += siz; ! 169: asiz -= siz; ! 170: while (asiz > 0) { ! 171: siz = (asiz > MLEN) ? MLEN : asiz; ! 172: m = m->m_next; ! 173: bcopy(ap, mtod(m, caddr_t), siz); ! 174: m->m_len = siz; ! 175: asiz -= siz; ! 176: ap += siz; ! 177: } ! 178: } ! 179: ! 180: /* Finally, return values */ ! 181: *mb = m; ! 182: *bpos = mtod(m, caddr_t)+m->m_len; ! 183: return (mreq); ! 184: } ! 185: ! 186: /* ! 187: * copies mbuf chain to the uio scatter/gather list ! 188: */ ! 189: nfsm_mbuftouio(mrep, uiop, siz, dpos) ! 190: struct mbuf **mrep; ! 191: register struct uio *uiop; ! 192: int siz; ! 193: caddr_t *dpos; ! 194: { ! 195: register char *mbufcp, *uiocp; ! 196: register int xfer, left, len; ! 197: register struct mbuf *mp; ! 198: long uiosiz, rem; ! 199: int error = 0; ! 200: ! 201: mp = *mrep; ! 202: mbufcp = *dpos; ! 203: len = mtod(mp, caddr_t)+mp->m_len-mbufcp; ! 204: rem = nfsm_rndup(siz)-siz; ! 205: while (siz > 0) { ! 206: if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) ! 207: return (EFBIG); ! 208: left = uiop->uio_iov->iov_len; ! 209: uiocp = uiop->uio_iov->iov_base; ! 210: if (left > siz) ! 211: left = siz; ! 212: uiosiz = left; ! 213: while (left > 0) { ! 214: while (len == 0) { ! 215: mp = mp->m_next; ! 216: if (mp == NULL) ! 217: return (EBADRPC); ! 218: mbufcp = mtod(mp, caddr_t); ! 219: len = mp->m_len; ! 220: } ! 221: xfer = (left > len) ? len : left; ! 222: #ifdef notdef ! 223: /* Not Yet.. */ ! 224: if (uiop->uio_iov->iov_op != NULL) ! 225: (*(uiop->uio_iov->iov_op)) ! 226: (mbufcp, uiocp, xfer); ! 227: else ! 228: #endif ! 229: if (uiop->uio_segflg == UIO_SYSSPACE) ! 230: bcopy(mbufcp, uiocp, xfer); ! 231: else ! 232: copyout(mbufcp, uiocp, xfer); ! 233: left -= xfer; ! 234: len -= xfer; ! 235: mbufcp += xfer; ! 236: uiocp += xfer; ! 237: uiop->uio_offset += xfer; ! 238: uiop->uio_resid -= xfer; ! 239: } ! 240: if (uiop->uio_iov->iov_len <= siz) { ! 241: uiop->uio_iovcnt--; ! 242: uiop->uio_iov++; ! 243: } else { ! 244: uiop->uio_iov->iov_base += uiosiz; ! 245: uiop->uio_iov->iov_len -= uiosiz; ! 246: } ! 247: siz -= uiosiz; ! 248: } ! 249: *dpos = mbufcp; ! 250: *mrep = mp; ! 251: if (rem > 0) { ! 252: if (len < rem) ! 253: error = nfs_adv(mrep, dpos, rem, len); ! 254: else ! 255: *dpos += rem; ! 256: } ! 257: return (error); ! 258: } ! 259: ! 260: /* ! 261: * copies a uio scatter/gather list to an mbuf chain... ! 262: */ ! 263: nfsm_uiotombuf(uiop, mq, siz, bpos) ! 264: register struct uio *uiop; ! 265: struct mbuf **mq; ! 266: int siz; ! 267: caddr_t *bpos; ! 268: { ! 269: register char *uiocp; ! 270: register struct mbuf *mp, *mp2; ! 271: register int xfer, left, len; ! 272: int uiosiz, clflg, rem; ! 273: char *cp; ! 274: ! 275: if (siz > MLEN) /* or should it >= MCLBYTES ?? */ ! 276: clflg = 1; ! 277: else ! 278: clflg = 0; ! 279: rem = nfsm_rndup(siz)-siz; ! 280: mp2 = *mq; ! 281: while (siz > 0) { ! 282: if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) ! 283: return (EINVAL); ! 284: left = uiop->uio_iov->iov_len; ! 285: uiocp = uiop->uio_iov->iov_base; ! 286: if (left > siz) ! 287: left = siz; ! 288: uiosiz = left; ! 289: while (left > 0) { ! 290: MGET(mp, M_WAIT, MT_DATA); ! 291: if (clflg) ! 292: MCLGET(mp, M_WAIT); ! 293: mp->m_len = NFSMSIZ(mp); ! 294: mp2->m_next = mp; ! 295: mp2 = mp; ! 296: xfer = (left > mp->m_len) ? mp->m_len : left; ! 297: #ifdef notdef ! 298: /* Not Yet.. */ ! 299: if (uiop->uio_iov->iov_op != NULL) ! 300: (*(uiop->uio_iov->iov_op)) ! 301: (uiocp, mtod(mp, caddr_t), xfer); ! 302: else ! 303: #endif ! 304: if (uiop->uio_segflg == UIO_SYSSPACE) ! 305: bcopy(uiocp, mtod(mp, caddr_t), xfer); ! 306: else ! 307: copyin(uiocp, mtod(mp, caddr_t), xfer); ! 308: len = mp->m_len; ! 309: mp->m_len = xfer; ! 310: left -= xfer; ! 311: uiocp += xfer; ! 312: uiop->uio_offset += xfer; ! 313: uiop->uio_resid -= xfer; ! 314: } ! 315: if (uiop->uio_iov->iov_len <= siz) { ! 316: uiop->uio_iovcnt--; ! 317: uiop->uio_iov++; ! 318: } else { ! 319: uiop->uio_iov->iov_base += uiosiz; ! 320: uiop->uio_iov->iov_len -= uiosiz; ! 321: } ! 322: siz -= uiosiz; ! 323: } ! 324: if (rem > 0) { ! 325: if (rem > (len-mp->m_len)) { ! 326: MGET(mp, M_WAIT, MT_DATA); ! 327: mp->m_len = 0; ! 328: mp2->m_next = mp; ! 329: } ! 330: cp = mtod(mp, caddr_t)+mp->m_len; ! 331: for (left = 0; left < rem; left++) ! 332: *cp++ = '\0'; ! 333: mp->m_len += rem; ! 334: *bpos = cp; ! 335: } else ! 336: *bpos = mtod(mp, caddr_t)+mp->m_len; ! 337: *mq = mp; ! 338: return (0); ! 339: } ! 340: ! 341: /* ! 342: * Help break down an mbuf chain by setting the first siz bytes contiguous ! 343: * pointed to by returned val. ! 344: * If Updateflg == True we can overwrite the first part of the mbuf data ! 345: * This is used by the macros nfsm_disect and nfsm_disecton for tough ! 346: * cases. (The macros use the vars. dpos and dpos2) ! 347: */ ! 348: nfsm_disct(mdp, dposp, siz, left, updateflg, cp2) ! 349: struct mbuf **mdp; ! 350: caddr_t *dposp; ! 351: int siz; ! 352: int left; ! 353: int updateflg; ! 354: caddr_t *cp2; ! 355: { ! 356: register struct mbuf *mp, *mp2; ! 357: register int siz2, xfer; ! 358: register caddr_t tl; ! 359: ! 360: mp = *mdp; ! 361: while (left == 0) { ! 362: *mdp = mp = mp->m_next; ! 363: if (mp == NULL) ! 364: return (EBADRPC); ! 365: left = mp->m_len; ! 366: *dposp = mtod(mp, caddr_t); ! 367: } ! 368: if (left >= siz) { ! 369: *cp2 = *dposp; ! 370: *dposp += siz; ! 371: } else if (mp->m_next == NULL) { ! 372: return (EBADRPC); ! 373: } else if (siz > MHLEN) { ! 374: panic("nfs S too big"); ! 375: } else { ! 376: /* Iff update, you can overwrite, else must alloc new mbuf */ ! 377: if (updateflg) { ! 378: NFSMINOFF(mp); ! 379: } else { ! 380: MGET(mp2, M_WAIT, MT_DATA); ! 381: mp2->m_next = mp->m_next; ! 382: mp->m_next = mp2; ! 383: mp->m_len -= left; ! 384: mp = mp2; ! 385: } ! 386: *cp2 = tl = mtod(mp, caddr_t); ! 387: bcopy(*dposp, tl, left); /* Copy what was left */ ! 388: siz2 = siz-left; ! 389: tl += left; ! 390: mp2 = mp->m_next; ! 391: /* Loop around copying up the siz2 bytes */ ! 392: while (siz2 > 0) { ! 393: if (mp2 == NULL) ! 394: return (EBADRPC); ! 395: xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2; ! 396: if (xfer > 0) { ! 397: bcopy(mtod(mp2, caddr_t), tl, xfer); ! 398: NFSMADV(mp2, xfer); ! 399: mp2->m_len -= xfer; ! 400: tl += xfer; ! 401: siz2 -= xfer; ! 402: } ! 403: if (siz2 > 0) ! 404: mp2 = mp2->m_next; ! 405: } ! 406: mp->m_len = siz; ! 407: *mdp = mp2; ! 408: *dposp = mtod(mp2, caddr_t); ! 409: } ! 410: return (0); ! 411: } ! 412: ! 413: /* ! 414: * Advance the position in the mbuf chain. ! 415: */ ! 416: nfs_adv(mdp, dposp, offs, left) ! 417: struct mbuf **mdp; ! 418: caddr_t *dposp; ! 419: int offs; ! 420: int left; ! 421: { ! 422: register struct mbuf *m; ! 423: register int s; ! 424: ! 425: m = *mdp; ! 426: s = left; ! 427: while (s < offs) { ! 428: offs -= s; ! 429: m = m->m_next; ! 430: if (m == NULL) ! 431: return (EBADRPC); ! 432: s = m->m_len; ! 433: } ! 434: *mdp = m; ! 435: *dposp = mtod(m, caddr_t)+offs; ! 436: return (0); ! 437: } ! 438: ! 439: /* ! 440: * Copy a string into mbufs for the hard cases... ! 441: */ ! 442: nfsm_strtmbuf(mb, bpos, cp, siz) ! 443: struct mbuf **mb; ! 444: char **bpos; ! 445: char *cp; ! 446: long siz; ! 447: { ! 448: register struct mbuf *m1, *m2; ! 449: long left, xfer, len, tlen; ! 450: u_long *tl; ! 451: int putsize; ! 452: ! 453: putsize = 1; ! 454: m2 = *mb; ! 455: left = NFSMSIZ(m2)-m2->m_len; ! 456: if (left > 0) { ! 457: tl = ((u_long *)(*bpos)); ! 458: *tl++ = txdr_unsigned(siz); ! 459: putsize = 0; ! 460: left -= NFSX_UNSIGNED; ! 461: m2->m_len += NFSX_UNSIGNED; ! 462: if (left > 0) { ! 463: bcopy(cp, (caddr_t) tl, left); ! 464: siz -= left; ! 465: cp += left; ! 466: m2->m_len += left; ! 467: left = 0; ! 468: } ! 469: } ! 470: /* Loop arround adding mbufs */ ! 471: while (siz > 0) { ! 472: MGET(m1, M_WAIT, MT_DATA); ! 473: if (siz > MLEN) ! 474: MCLGET(m1, M_WAIT); ! 475: m1->m_len = NFSMSIZ(m1); ! 476: m2->m_next = m1; ! 477: m2 = m1; ! 478: tl = mtod(m1, u_long *); ! 479: tlen = 0; ! 480: if (putsize) { ! 481: *tl++ = txdr_unsigned(siz); ! 482: m1->m_len -= NFSX_UNSIGNED; ! 483: tlen = NFSX_UNSIGNED; ! 484: putsize = 0; ! 485: } ! 486: if (siz < m1->m_len) { ! 487: len = nfsm_rndup(siz); ! 488: xfer = siz; ! 489: if (xfer < len) ! 490: *(tl+(xfer>>2)) = 0; ! 491: } else { ! 492: xfer = len = m1->m_len; ! 493: } ! 494: bcopy(cp, (caddr_t) tl, xfer); ! 495: m1->m_len = len+tlen; ! 496: siz -= xfer; ! 497: cp += xfer; ! 498: } ! 499: *mb = m1; ! 500: *bpos = mtod(m1, caddr_t)+m1->m_len; ! 501: return (0); ! 502: } ! 503: ! 504: /* ! 505: * Called once to initialize data structures... ! 506: */ ! 507: nfs_init() ! 508: { ! 509: register int i; ! 510: ! 511: rpc_vers = txdr_unsigned(RPC_VER2); ! 512: rpc_call = txdr_unsigned(RPC_CALL); ! 513: rpc_reply = txdr_unsigned(RPC_REPLY); ! 514: rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED); ! 515: rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED); ! 516: rpc_mismatch = txdr_unsigned(RPC_MISMATCH); ! 517: rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX); ! 518: nfs_vers = txdr_unsigned(NFS_VER2); ! 519: nfs_prog = txdr_unsigned(NFS_PROG); ! 520: nfs_true = txdr_unsigned(TRUE); ! 521: nfs_false = txdr_unsigned(FALSE); ! 522: /* Loop thru nfs procids */ ! 523: for (i = 0; i < NFS_NPROCS; i++) ! 524: nfs_procids[i] = txdr_unsigned(i); ! 525: /* Ensure async daemons disabled */ ! 526: for (i = 0; i < NFS_MAXASYNCDAEMON; i++) ! 527: nfs_iodwant[i] = (struct proc *)0; ! 528: nfs_xdrneg1 = txdr_unsigned(-1); ! 529: nfs_nhinit(); /* Init the nfsnode table */ ! 530: nfsrv_initcache(); /* Init the server request cache */ ! 531: rminit(nfsmap, (long)NFS_MAPREG, (long)1, "nfs mapreg", NFS_MSIZ); ! 532: ! 533: /* ! 534: * Initialize reply list and start timer ! 535: */ ! 536: nfsreqh.r_prev = nfsreqh.r_next = &nfsreqh; ! 537: nfs_timer(); ! 538: } ! 539: ! 540: /* ! 541: * Fill in the rest of the rpc_unixauth and return it ! 542: */ ! 543: static char *nfs_unixauth(cr) ! 544: register struct ucred *cr; ! 545: { ! 546: register u_long *tl; ! 547: register int i; ! 548: int ngr; ! 549: ! 550: /* Maybe someday there should be a cache of AUTH_SHORT's */ ! 551: if ((tl = rpc_uidp) == NULL) { ! 552: #ifdef FILLINHOST ! 553: i = nfsm_rndup(hostnamelen)+(25*NFSX_UNSIGNED); ! 554: #else ! 555: i = 25*NFSX_UNSIGNED; ! 556: #endif ! 557: MALLOC(tl, u_long *, i, M_TEMP, M_WAITOK); ! 558: bzero((caddr_t)tl, i); ! 559: rpc_unixauth = (caddr_t)tl; ! 560: *tl++ = txdr_unsigned(RPCAUTH_UNIX); ! 561: tl++; /* Fill in size later */ ! 562: *tl++ = hostid; ! 563: #ifdef FILLINHOST ! 564: *tl++ = txdr_unsigned(hostnamelen); ! 565: i = nfsm_rndup(hostnamelen); ! 566: bcopy(hostname, (caddr_t)tl, hostnamelen); ! 567: tl += (i>>2); ! 568: #else ! 569: *tl++ = 0; ! 570: #endif ! 571: rpc_uidp = tl; ! 572: } ! 573: *tl++ = txdr_unsigned(cr->cr_uid); ! 574: *tl++ = txdr_unsigned(cr->cr_groups[0]); ! 575: ngr = ((cr->cr_ngroups - 1) > numgrps) ? numgrps : (cr->cr_ngroups - 1); ! 576: *tl++ = txdr_unsigned(ngr); ! 577: for (i = 1; i <= ngr; i++) ! 578: *tl++ = txdr_unsigned(cr->cr_groups[i]); ! 579: /* And add the AUTH_NULL */ ! 580: *tl++ = 0; ! 581: *tl = 0; ! 582: i = (((caddr_t)tl)-rpc_unixauth)-12; ! 583: tl = (u_long *)(rpc_unixauth+4); ! 584: *tl = txdr_unsigned(i); ! 585: return (rpc_unixauth); ! 586: } ! 587: ! 588: /* ! 589: * Attribute cache routines. ! 590: * nfs_loadattrcache() - loads or updates the cache contents from attributes ! 591: * that are on the mbuf list ! 592: * nfs_getattrcache() - returns valid attributes if found in cache, returns ! 593: * error otherwise ! 594: */ ! 595: ! 596: /* ! 597: * Load the attribute cache (that lives in the nfsnode entry) with ! 598: * the values on the mbuf list and ! 599: * Iff vap not NULL ! 600: * copy the attributes to *vaper ! 601: */ ! 602: nfs_loadattrcache(vpp, mdp, dposp, vaper) ! 603: struct vnode **vpp; ! 604: struct mbuf **mdp; ! 605: caddr_t *dposp; ! 606: struct vattr *vaper; ! 607: { ! 608: register struct vnode *vp = *vpp; ! 609: register struct vattr *vap; ! 610: register struct nfsv2_fattr *fp; ! 611: extern struct vnodeops spec_nfsv2nodeops; ! 612: register struct nfsnode *np; ! 613: register long t1; ! 614: caddr_t dpos, cp2; ! 615: int error = 0; ! 616: struct mbuf *md; ! 617: enum vtype type; ! 618: u_short mode; ! 619: long rdev; ! 620: struct timeval mtime; ! 621: struct vnode *nvp; ! 622: ! 623: md = *mdp; ! 624: dpos = *dposp; ! 625: t1 = (mtod(md, caddr_t)+md->m_len)-dpos; ! 626: if (error = nfsm_disct(&md, &dpos, NFSX_FATTR, t1, TRUE, &cp2)) ! 627: return (error); ! 628: fp = (struct nfsv2_fattr *)cp2; ! 629: type = nfstov_type(fp->fa_type); ! 630: mode = fxdr_unsigned(u_short, fp->fa_mode); ! 631: if (type == VNON) ! 632: type = IFTOVT(mode); ! 633: rdev = fxdr_unsigned(long, fp->fa_rdev); ! 634: fxdr_time(&fp->fa_mtime, &mtime); ! 635: /* ! 636: * If v_type == VNON it is a new node, so fill in the v_type, ! 637: * n_mtime fields. Check to see if it represents a special ! 638: * device, and if so, check for a possible alias. Once the ! 639: * correct vnode has been obtained, fill in the rest of the ! 640: * information. ! 641: */ ! 642: np = VTONFS(vp); ! 643: if (vp->v_type == VNON) { ! 644: if (type == VCHR && rdev == 0xffffffff) ! 645: vp->v_type = type = VFIFO; ! 646: else ! 647: vp->v_type = type; ! 648: if (vp->v_type == VFIFO) { ! 649: #ifdef FIFO ! 650: extern struct vnodeops fifo_nfsv2nodeops; ! 651: vp->v_op = &fifo_nfsv2nodeops; ! 652: #else ! 653: return (EOPNOTSUPP); ! 654: #endif /* FIFO */ ! 655: } ! 656: if (vp->v_type == VCHR || vp->v_type == VBLK) { ! 657: vp->v_op = &spec_nfsv2nodeops; ! 658: if (nvp = checkalias(vp, (dev_t)rdev, vp->v_mount)) { ! 659: /* ! 660: * Reinitialize aliased node. ! 661: */ ! 662: np = VTONFS(nvp); ! 663: np->n_vnode = nvp; ! 664: np->n_flag = 0; ! 665: nfs_lock(nvp); ! 666: bcopy((caddr_t)&VTONFS(vp)->n_fh, ! 667: (caddr_t)&np->n_fh, NFSX_FH); ! 668: insque(np, nfs_hash(&np->n_fh)); ! 669: np->n_attrstamp = 0; ! 670: np->n_sillyrename = (struct sillyrename *)0; ! 671: /* ! 672: * Discard unneeded vnode and update actual one ! 673: */ ! 674: vput(vp); ! 675: *vpp = nvp; ! 676: } ! 677: } ! 678: np->n_mtime = mtime.tv_sec; ! 679: } ! 680: vap = &np->n_vattr; ! 681: vap->va_type = type; ! 682: vap->va_mode = (mode & 07777); ! 683: vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink); ! 684: vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid); ! 685: vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid); ! 686: vap->va_size = fxdr_unsigned(u_long, fp->fa_size); ! 687: if ((np->n_flag & NMODIFIED) == 0 || vap->va_size > np->n_size) { ! 688: np->n_size = vap->va_size; ! 689: vnode_pager_setsize(vp, np->n_size); ! 690: } ! 691: vap->va_size_rsv = 0; ! 692: vap->va_blocksize = fxdr_unsigned(long, fp->fa_blocksize); ! 693: vap->va_rdev = (dev_t)rdev; ! 694: vap->va_bytes = fxdr_unsigned(long, fp->fa_blocks) * NFS_FABLKSIZE; ! 695: vap->va_bytes_rsv = 0; ! 696: vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; ! 697: vap->va_fileid = fxdr_unsigned(long, fp->fa_fileid); ! 698: vap->va_atime.tv_sec = fxdr_unsigned(long, fp->fa_atime.tv_sec); ! 699: vap->va_atime.tv_usec = 0; ! 700: vap->va_flags = fxdr_unsigned(u_long, fp->fa_atime.tv_usec); ! 701: vap->va_mtime = mtime; ! 702: vap->va_ctime.tv_sec = fxdr_unsigned(long, fp->fa_ctime.tv_sec); ! 703: vap->va_ctime.tv_usec = 0; ! 704: vap->va_gen = fxdr_unsigned(u_long, fp->fa_ctime.tv_usec); ! 705: np->n_attrstamp = time.tv_sec; ! 706: *dposp = dpos; ! 707: *mdp = md; ! 708: if (vaper != NULL) { ! 709: bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap)); ! 710: if ((np->n_flag & NMODIFIED) && (np->n_size > vap->va_size)) ! 711: vaper->va_size = np->n_size; ! 712: } ! 713: return (0); ! 714: } ! 715: ! 716: /* ! 717: * Check the time stamp ! 718: * If the cache is valid, copy contents to *vap and return 0 ! 719: * otherwise return an error ! 720: */ ! 721: nfs_getattrcache(vp, vap) ! 722: register struct vnode *vp; ! 723: struct vattr *vap; ! 724: { ! 725: register struct nfsnode *np; ! 726: ! 727: np = VTONFS(vp); ! 728: if ((time.tv_sec-np->n_attrstamp) < NFS_ATTRTIMEO) { ! 729: nfsstats.attrcache_hits++; ! 730: bcopy((caddr_t)&np->n_vattr,(caddr_t)vap,sizeof(struct vattr)); ! 731: if ((np->n_flag & NMODIFIED) == 0) { ! 732: np->n_size = vap->va_size; ! 733: vnode_pager_setsize(vp, np->n_size); ! 734: } else if (np->n_size > vap->va_size) ! 735: vap->va_size = np->n_size; ! 736: return (0); ! 737: } else { ! 738: nfsstats.attrcache_misses++; ! 739: return (ENOENT); ! 740: } ! 741: } ! 742: ! 743: /* ! 744: * Set up nameidata for a namei() call and do it ! 745: */ ! 746: nfs_namei(ndp, fhp, len, mdp, dposp, p) ! 747: register struct nameidata *ndp; ! 748: fhandle_t *fhp; ! 749: int len; ! 750: struct mbuf **mdp; ! 751: caddr_t *dposp; ! 752: struct proc *p; ! 753: { ! 754: register int i, rem; ! 755: register struct mbuf *md; ! 756: register char *fromcp, *tocp; ! 757: struct vnode *dp; ! 758: int flag; ! 759: int error; ! 760: ! 761: flag = ndp->ni_nameiop & OPMASK; ! 762: MALLOC(ndp->ni_pnbuf, char *, len + 1, M_NAMEI, M_WAITOK); ! 763: /* ! 764: * Copy the name from the mbuf list to ndp->ni_pnbuf ! 765: * and set the various ndp fields appropriately. ! 766: */ ! 767: fromcp = *dposp; ! 768: tocp = ndp->ni_pnbuf; ! 769: md = *mdp; ! 770: rem = mtod(md, caddr_t) + md->m_len - fromcp; ! 771: ndp->ni_hash = 0; ! 772: for (i = 0; i < len; i++) { ! 773: while (rem == 0) { ! 774: md = md->m_next; ! 775: if (md == NULL) { ! 776: error = EBADRPC; ! 777: goto out; ! 778: } ! 779: fromcp = mtod(md, caddr_t); ! 780: rem = md->m_len; ! 781: } ! 782: if (*fromcp == '\0' || *fromcp == '/') { ! 783: error = EINVAL; ! 784: goto out; ! 785: } ! 786: if (*fromcp & 0200) ! 787: if ((*fromcp&0377) == ('/'|0200) || flag != DELETE) { ! 788: error = EINVAL; ! 789: goto out; ! 790: } ! 791: ndp->ni_hash += (unsigned char)*fromcp; ! 792: *tocp++ = *fromcp++; ! 793: rem--; ! 794: } ! 795: *tocp = '\0'; ! 796: *mdp = md; ! 797: *dposp = fromcp; ! 798: len = nfsm_rndup(len)-len; ! 799: if (len > 0) { ! 800: if (rem >= len) ! 801: *dposp += len; ! 802: else if (error = nfs_adv(mdp, dposp, len, rem)) ! 803: goto out; ! 804: } ! 805: ndp->ni_pathlen = tocp - ndp->ni_pnbuf; ! 806: ndp->ni_ptr = ndp->ni_pnbuf; ! 807: /* ! 808: * Extract and set starting directory. ! 809: */ ! 810: if (error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cred)) ! 811: goto out; ! 812: if (dp->v_type != VDIR) { ! 813: vrele(dp); ! 814: error = ENOTDIR; ! 815: goto out; ! 816: } ! 817: ndp->ni_startdir = dp; ! 818: ndp->ni_nameiop |= (NOCROSSMOUNT | REMOTE); ! 819: /* ! 820: * And call lookup() to do the real work ! 821: */ ! 822: if (error = lookup(ndp, p)) ! 823: goto out; ! 824: /* ! 825: * Check for encountering a symbolic link ! 826: */ ! 827: if (ndp->ni_more) { ! 828: if ((ndp->ni_nameiop & LOCKPARENT) && ndp->ni_pathlen == 1) ! 829: vput(ndp->ni_dvp); ! 830: else ! 831: vrele(ndp->ni_dvp); ! 832: vput(ndp->ni_vp); ! 833: ndp->ni_vp = NULL; ! 834: error = EINVAL; ! 835: goto out; ! 836: } ! 837: /* ! 838: * Check for saved name request ! 839: */ ! 840: if (ndp->ni_nameiop & (SAVENAME | SAVESTART)) { ! 841: ndp->ni_nameiop |= HASBUF; ! 842: return (0); ! 843: } ! 844: out: ! 845: FREE(ndp->ni_pnbuf, M_NAMEI); ! 846: return (error); ! 847: } ! 848: ! 849: /* ! 850: * A fiddled version of m_adj() that ensures null fill to a long ! 851: * boundary and only trims off the back end ! 852: */ ! 853: nfsm_adj(mp, len, nul) ! 854: struct mbuf *mp; ! 855: register int len; ! 856: int nul; ! 857: { ! 858: register struct mbuf *m; ! 859: register int count, i; ! 860: register char *cp; ! 861: ! 862: /* ! 863: * Trim from tail. Scan the mbuf chain, ! 864: * calculating its length and finding the last mbuf. ! 865: * If the adjustment only affects this mbuf, then just ! 866: * adjust and return. Otherwise, rescan and truncate ! 867: * after the remaining size. ! 868: */ ! 869: count = 0; ! 870: m = mp; ! 871: for (;;) { ! 872: count += m->m_len; ! 873: if (m->m_next == (struct mbuf *)0) ! 874: break; ! 875: m = m->m_next; ! 876: } ! 877: if (m->m_len > len) { ! 878: m->m_len -= len; ! 879: if (nul > 0) { ! 880: cp = mtod(m, caddr_t)+m->m_len-nul; ! 881: for (i = 0; i < nul; i++) ! 882: *cp++ = '\0'; ! 883: } ! 884: return; ! 885: } ! 886: count -= len; ! 887: if (count < 0) ! 888: count = 0; ! 889: /* ! 890: * Correct length for chain is "count". ! 891: * Find the mbuf with last data, adjust its length, ! 892: * and toss data from remaining mbufs on chain. ! 893: */ ! 894: for (m = mp; m; m = m->m_next) { ! 895: if (m->m_len >= count) { ! 896: m->m_len = count; ! 897: if (nul > 0) { ! 898: cp = mtod(m, caddr_t)+m->m_len-nul; ! 899: for (i = 0; i < nul; i++) ! 900: *cp++ = '\0'; ! 901: } ! 902: break; ! 903: } ! 904: count -= m->m_len; ! 905: } ! 906: while (m = m->m_next) ! 907: m->m_len = 0; ! 908: } ! 909: ! 910: /* ! 911: * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked) ! 912: * - look up fsid in mount list (if not found ret error) ! 913: * - check that it is exported ! 914: * - get vp by calling VFS_FHTOVP() macro ! 915: * - if not lockflag unlock it with VOP_UNLOCK() ! 916: * - if cred->cr_uid == 0 set it to m_exroot ! 917: */ ! 918: nfsrv_fhtovp(fhp, lockflag, vpp, cred) ! 919: fhandle_t *fhp; ! 920: int lockflag; ! 921: struct vnode **vpp; ! 922: struct ucred *cred; ! 923: { ! 924: register struct mount *mp; ! 925: ! 926: if ((mp = getvfs(&fhp->fh_fsid)) == NULL) ! 927: return (ESTALE); ! 928: if ((mp->mnt_flag & MNT_EXPORTED) == 0) ! 929: return (EACCES); ! 930: if (VFS_FHTOVP(mp, &fhp->fh_fid, vpp)) ! 931: return (ESTALE); ! 932: if (cred->cr_uid == 0) ! 933: cred->cr_uid = mp->mnt_exroot; ! 934: if (!lockflag) ! 935: VOP_UNLOCK(*vpp); ! 936: return (0); ! 937: } ! 938: ! 939: /* ! 940: * These two functions implement nfs rpc compression. ! 941: * The algorithm is a trivial run length encoding of '\0' bytes. The high ! 942: * order nibble of hex "e" is or'd with the number of zeroes - 2 in four ! 943: * bits. (2 - 17 zeros) Any data byte with a high order nibble of hex "e" ! 944: * is byte stuffed. ! 945: * The compressed data is padded with 0x0 bytes to an even multiple of ! 946: * 4 bytes in length to avoid any weird long pointer alignments. ! 947: * If compression/uncompression is unsuccessful, the original mbuf list ! 948: * is returned. ! 949: * The first four bytes (the XID) are left uncompressed and the fifth ! 950: * byte is set to 0x1 for request and 0x2 for reply. ! 951: * An uncompressed RPC will always have the fifth byte == 0x0. ! 952: */ ! 953: struct mbuf * ! 954: nfs_compress(m0) ! 955: struct mbuf *m0; ! 956: { ! 957: register u_char ch, nextch; ! 958: register int i, rlelast; ! 959: register u_char *ip, *op; ! 960: register int ileft, oleft, noteof; ! 961: register struct mbuf *m, *om; ! 962: struct mbuf **mp, *retm; ! 963: int olen, clget; ! 964: ! 965: i = rlelast = 0; ! 966: noteof = 1; ! 967: m = m0; ! 968: if (m->m_len < 12) ! 969: return (m0); ! 970: if (m->m_pkthdr.len >= MINCLSIZE) ! 971: clget = 1; ! 972: else ! 973: clget = 0; ! 974: ileft = m->m_len - 9; ! 975: ip = mtod(m, u_char *); ! 976: MGETHDR(om, M_WAIT, MT_DATA); ! 977: if (clget) ! 978: MCLGET(om, M_WAIT); ! 979: retm = om; ! 980: mp = &om->m_next; ! 981: olen = om->m_len = 5; ! 982: oleft = M_TRAILINGSPACE(om); ! 983: op = mtod(om, u_char *); ! 984: *((u_long *)op) = *((u_long *)ip); ! 985: ip += 7; ! 986: op += 4; ! 987: *op++ = *ip++ + 1; ! 988: nextch = *ip++; ! 989: while (noteof) { ! 990: ch = nextch; ! 991: if (ileft == 0) { ! 992: do { ! 993: m = m->m_next; ! 994: } while (m && m->m_len == 0); ! 995: if (m) { ! 996: ileft = m->m_len; ! 997: ip = mtod(m, u_char *); ! 998: } else { ! 999: noteof = 0; ! 1000: nextch = 0x1; ! 1001: goto doit; ! 1002: } ! 1003: } ! 1004: nextch = *ip++; ! 1005: ileft--; ! 1006: doit: ! 1007: if (ch == '\0') { ! 1008: if (++i == NFSC_MAX || nextch != '\0') { ! 1009: if (i < 2) { ! 1010: nfscput('\0'); ! 1011: } else { ! 1012: if (rlelast == i) { ! 1013: nfscput('\0'); ! 1014: i--; ! 1015: } ! 1016: if (NFSCRLE(i) == (nextch & 0xff)) { ! 1017: i--; ! 1018: if (i < 2) { ! 1019: nfscput('\0'); ! 1020: } else { ! 1021: nfscput(NFSCRLE(i)); ! 1022: } ! 1023: nfscput('\0'); ! 1024: rlelast = 0; ! 1025: } else { ! 1026: nfscput(NFSCRLE(i)); ! 1027: rlelast = i; ! 1028: } ! 1029: } ! 1030: i = 0; ! 1031: } ! 1032: } else { ! 1033: if ((ch & NFSCRL) == NFSCRL) { ! 1034: nfscput(ch); ! 1035: } ! 1036: nfscput(ch); ! 1037: i = rlelast = 0; ! 1038: } ! 1039: } ! 1040: if (olen < m0->m_pkthdr.len) { ! 1041: m_freem(m0); ! 1042: if (i = (olen & 0x3)) { ! 1043: i = 4 - i; ! 1044: while (i-- > 0) { ! 1045: nfscput('\0'); ! 1046: } ! 1047: } ! 1048: retm->m_pkthdr.len = olen; ! 1049: retm->m_pkthdr.rcvif = (struct ifnet *)0; ! 1050: return (retm); ! 1051: } else { ! 1052: m_freem(retm); ! 1053: return (m0); ! 1054: } ! 1055: } ! 1056: ! 1057: struct mbuf * ! 1058: nfs_uncompress(m0) ! 1059: struct mbuf *m0; ! 1060: { ! 1061: register u_char cp, nextcp, *ip, *op; ! 1062: register struct mbuf *m, *om; ! 1063: struct mbuf *retm, **mp; ! 1064: int i, j, noteof, clget, ileft, oleft, olen; ! 1065: ! 1066: m = m0; ! 1067: i = 0; ! 1068: while (m && i < MINCLSIZE) { ! 1069: i += m->m_len; ! 1070: m = m->m_next; ! 1071: } ! 1072: if (i < 6) ! 1073: return (m0); ! 1074: if (i >= MINCLSIZE) ! 1075: clget = 1; ! 1076: else ! 1077: clget = 0; ! 1078: m = m0; ! 1079: MGET(om, M_WAIT, MT_DATA); ! 1080: if (clget) ! 1081: MCLGET(om, M_WAIT); ! 1082: olen = om->m_len = 8; ! 1083: oleft = M_TRAILINGSPACE(om); ! 1084: op = mtod(om, u_char *); ! 1085: retm = om; ! 1086: mp = &om->m_next; ! 1087: if (m->m_len >= 6) { ! 1088: ileft = m->m_len - 6; ! 1089: ip = mtod(m, u_char *); ! 1090: *((u_long *)op) = *((u_long *)ip); ! 1091: bzero(op + 4, 3); ! 1092: ip += 4; ! 1093: op += 7; ! 1094: if (*ip == '\0') { ! 1095: m_freem(om); ! 1096: return (m0); ! 1097: } ! 1098: *op++ = *ip++ - 1; ! 1099: cp = *ip++; ! 1100: } else { ! 1101: ileft = m->m_len; ! 1102: ip = mtod(m, u_char *); ! 1103: nfscget(*op++); ! 1104: nfscget(*op++); ! 1105: nfscget(*op++); ! 1106: nfscget(*op++); ! 1107: bzero(op, 3); ! 1108: op += 3; ! 1109: nfscget(*op); ! 1110: if (*op == '\0') { ! 1111: m_freem(om); ! 1112: return (m0); ! 1113: } ! 1114: (*op)--; ! 1115: op++; ! 1116: nfscget(cp); ! 1117: } ! 1118: noteof = 1; ! 1119: while (noteof) { ! 1120: if ((cp & NFSCRL) == NFSCRL) { ! 1121: nfscget(nextcp); ! 1122: if (cp == nextcp) { ! 1123: nfscput(cp); ! 1124: goto readit; ! 1125: } else { ! 1126: i = (cp & 0xf) + 2; ! 1127: for (j = 0; j < i; j++) { ! 1128: nfscput('\0'); ! 1129: } ! 1130: cp = nextcp; ! 1131: } ! 1132: } else { ! 1133: nfscput(cp); ! 1134: readit: ! 1135: nfscget(cp); ! 1136: } ! 1137: } ! 1138: m_freem(m0); ! 1139: if (i = (olen & 0x3)) ! 1140: om->m_len -= i; ! 1141: return (retm); ! 1142: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.