|
|
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 is only permitted until one year after the first shipment ! 9: * of 4.4BSD by the Regents. Otherwise, redistribution and use in source and ! 10: * binary forms are permitted provided that: (1) source distributions retain ! 11: * this entire copyright notice and comment, and (2) distributions including ! 12: * binaries display the following acknowledgement: This product includes ! 13: * software developed by the University of California, Berkeley and its ! 14: * contributors'' in the documentation or other materials provided with the ! 15: * distribution and in all advertising materials mentioning features or use ! 16: * of this software. Neither the name of the University nor the names of ! 17: * its contributors may be used to endorse or promote products derived from ! 18: * this software without specific prior written permission. ! 19: * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED ! 20: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF ! 21: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 22: * ! 23: * @(#)nfs_socket.c 7.18 (Berkeley) 6/28/90 ! 24: */ ! 25: ! 26: /* ! 27: * Socket operations for use by nfs ! 28: */ ! 29: ! 30: #include "types.h" ! 31: #include "param.h" ! 32: #include "uio.h" ! 33: #include "user.h" ! 34: #include "proc.h" ! 35: #include "signal.h" ! 36: #include "mount.h" ! 37: #include "kernel.h" ! 38: #include "malloc.h" ! 39: #include "mbuf.h" ! 40: #include "vnode.h" ! 41: #include "domain.h" ! 42: #include "protosw.h" ! 43: #include "socket.h" ! 44: #include "socketvar.h" ! 45: #include "../netinet/in.h" ! 46: #include "../netinet/tcp.h" ! 47: #include "rpcv2.h" ! 48: #include "nfsv2.h" ! 49: #include "nfs.h" ! 50: #include "xdr_subs.h" ! 51: #include "nfsm_subs.h" ! 52: #include "nfsmount.h" ! 53: ! 54: #include "syslog.h" ! 55: ! 56: #define TRUE 1 ! 57: #define FALSE 0 ! 58: ! 59: /* ! 60: * External data, mostly RPC constants in XDR form ! 61: */ ! 62: extern u_long rpc_reply, rpc_msgdenied, rpc_mismatch, rpc_vers, rpc_auth_unix, ! 63: rpc_msgaccepted, rpc_call; ! 64: extern u_long nfs_prog, nfs_vers; ! 65: /* Maybe these should be bits in a u_long ?? */ ! 66: extern int nonidempotent[NFS_NPROCS]; ! 67: int nfs_sbwait(); ! 68: void nfs_disconnect(); ! 69: ! 70: int nfsrv_null(), ! 71: nfsrv_getattr(), ! 72: nfsrv_setattr(), ! 73: nfsrv_lookup(), ! 74: nfsrv_readlink(), ! 75: nfsrv_read(), ! 76: nfsrv_write(), ! 77: nfsrv_create(), ! 78: nfsrv_remove(), ! 79: nfsrv_rename(), ! 80: nfsrv_link(), ! 81: nfsrv_symlink(), ! 82: nfsrv_mkdir(), ! 83: nfsrv_rmdir(), ! 84: nfsrv_readdir(), ! 85: nfsrv_statfs(), ! 86: nfsrv_noop(); ! 87: ! 88: int (*nfsrv_procs[NFS_NPROCS])() = { ! 89: nfsrv_null, ! 90: nfsrv_getattr, ! 91: nfsrv_setattr, ! 92: nfsrv_noop, ! 93: nfsrv_lookup, ! 94: nfsrv_readlink, ! 95: nfsrv_read, ! 96: nfsrv_noop, ! 97: nfsrv_write, ! 98: nfsrv_create, ! 99: nfsrv_remove, ! 100: nfsrv_rename, ! 101: nfsrv_link, ! 102: nfsrv_symlink, ! 103: nfsrv_mkdir, ! 104: nfsrv_rmdir, ! 105: nfsrv_readdir, ! 106: nfsrv_statfs, ! 107: }; ! 108: ! 109: struct nfsreq nfsreqh; ! 110: int nfsrexmtthresh = NFS_FISHY; ! 111: int nfs_tcpnodelay = 1; ! 112: ! 113: /* ! 114: * Initialize sockets and congestion for a new NFS connection. ! 115: * We do not free the sockaddr if error. ! 116: */ ! 117: nfs_connect(nmp) ! 118: register struct nfsmount *nmp; ! 119: { ! 120: register struct socket *so; ! 121: int s, error; ! 122: struct mbuf *m; ! 123: ! 124: nmp->nm_so = (struct socket *)0; ! 125: if (error = socreate(mtod(nmp->nm_nam, struct sockaddr *)->sa_family, ! 126: &nmp->nm_so, nmp->nm_sotype, nmp->nm_soproto)) ! 127: goto bad; ! 128: so = nmp->nm_so; ! 129: nmp->nm_soflags = so->so_proto->pr_flags; ! 130: ! 131: /* ! 132: * Protocols that do not require connections may be optionally left ! 133: * unconnected for servers that reply from a port other than NFS_PORT. ! 134: */ ! 135: if (nmp->nm_flag & NFSMNT_NOCONN) { ! 136: if (nmp->nm_soflags & PR_CONNREQUIRED) { ! 137: error = ENOTCONN; ! 138: goto bad; ! 139: } ! 140: } else { ! 141: if (error = soconnect(so, nmp->nm_nam)) ! 142: goto bad; ! 143: ! 144: /* ! 145: * Wait for the connection to complete. Cribbed from the ! 146: * connect system call but with the wait at negative prio. ! 147: */ ! 148: s = splnet(); ! 149: while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) ! 150: (void) tsleep((caddr_t)&so->so_timeo, PSOCK, "nfscon", 0); ! 151: splx(s); ! 152: if (so->so_error) { ! 153: error = so->so_error; ! 154: goto bad; ! 155: } ! 156: } ! 157: if (nmp->nm_sotype == SOCK_DGRAM) { ! 158: if (nmp->nm_flag & (NFSMNT_SOFT | NFSMNT_SPONGY | NFSMNT_INT)) { ! 159: so->so_rcv.sb_timeo = (5 * hz); ! 160: so->so_snd.sb_timeo = (5 * hz); ! 161: } else { ! 162: so->so_rcv.sb_timeo = 0; ! 163: so->so_snd.sb_timeo = 0; ! 164: } ! 165: if (error = soreserve(so, nmp->nm_wsize + NFS_MAXPKTHDR, ! 166: nmp->nm_rsize + NFS_MAXPKTHDR)) ! 167: goto bad; ! 168: } else { ! 169: if (nmp->nm_flag & (NFSMNT_SOFT | NFSMNT_SPONGY | NFSMNT_INT)) { ! 170: so->so_rcv.sb_timeo = (5 * hz); ! 171: so->so_snd.sb_timeo = (5 * hz); ! 172: } else { ! 173: so->so_rcv.sb_timeo = 0; ! 174: so->so_snd.sb_timeo = 0; ! 175: } ! 176: if (so->so_proto->pr_flags & PR_CONNREQUIRED) { ! 177: MGET(m, M_WAIT, MT_SOOPTS); ! 178: *mtod(m, int *) = 1; ! 179: m->m_len = sizeof(int); ! 180: sosetopt(so, SOL_SOCKET, SO_KEEPALIVE, m); ! 181: } ! 182: if (so->so_proto->pr_domain->dom_family == AF_INET && ! 183: so->so_proto->pr_protocol == IPPROTO_TCP && ! 184: nfs_tcpnodelay) { ! 185: MGET(m, M_WAIT, MT_SOOPTS); ! 186: *mtod(m, int *) = 1; ! 187: m->m_len = sizeof(int); ! 188: sosetopt(so, IPPROTO_TCP, TCP_NODELAY, m); ! 189: } ! 190: if (error = soreserve(so, ! 191: nmp->nm_wsize + NFS_MAXPKTHDR + sizeof(u_long), ! 192: nmp->nm_rsize + NFS_MAXPKTHDR + sizeof(u_long))) ! 193: goto bad; ! 194: } ! 195: so->so_rcv.sb_flags |= SB_NOINTR; ! 196: so->so_snd.sb_flags |= SB_NOINTR; ! 197: ! 198: /* Initialize other non-zero congestion variables */ ! 199: nmp->nm_rto = NFS_TIMEO; ! 200: nmp->nm_window = 2; /* Initial send window */ ! 201: nmp->nm_ssthresh = NFS_MAXWINDOW; /* Slowstart threshold */ ! 202: nmp->nm_rttvar = nmp->nm_rto << 1; ! 203: nmp->nm_sent = 0; ! 204: nmp->nm_currexmit = 0; ! 205: return (0); ! 206: ! 207: bad: ! 208: nfs_disconnect(nmp); ! 209: return (error); ! 210: } ! 211: ! 212: /* ! 213: * Reconnect routine: ! 214: * Called when a connection is broken on a reliable protocol. ! 215: * - clean up the old socket ! 216: * - nfs_connect() again ! 217: * - set R_MUSTRESEND for all outstanding requests on mount point ! 218: * If this fails the mount point is DEAD! ! 219: * nb: Must be called with the nfs_solock() set on the mount point. ! 220: */ ! 221: nfs_reconnect(rep, nmp) ! 222: register struct nfsreq *rep; ! 223: register struct nfsmount *nmp; ! 224: { ! 225: register struct nfsreq *rp; ! 226: int error; ! 227: ! 228: if (rep->r_procp) ! 229: tprintf(rep->r_procp->p_session, ! 230: "Nfs server %s, trying reconnect\n", ! 231: nmp->nm_mountp->mnt_stat.f_mntfromname); ! 232: else ! 233: tprintf(NULL, "Nfs server %s, trying a reconnect\n", ! 234: nmp->nm_mountp->mnt_stat.f_mntfromname); ! 235: while (error = nfs_connect(nmp)) { ! 236: #ifdef lint ! 237: error = error; ! 238: #endif /* lint */ ! 239: if ((nmp->nm_flag & NFSMNT_INT) && nfs_sigintr(rep->r_procp)) ! 240: return (EINTR); ! 241: (void) tsleep((caddr_t)&lbolt, PSOCK, "nfscon", 0); ! 242: } ! 243: if (rep->r_procp) ! 244: tprintf(rep->r_procp->p_session, ! 245: "Nfs server %s, reconnected\n", ! 246: nmp->nm_mountp->mnt_stat.f_mntfromname); ! 247: else ! 248: tprintf(NULL, "Nfs server %s, reconnected\n", ! 249: nmp->nm_mountp->mnt_stat.f_mntfromname); ! 250: ! 251: /* ! 252: * Loop through outstanding request list and fix up all requests ! 253: * on old socket. ! 254: */ ! 255: rp = nfsreqh.r_next; ! 256: while (rp != &nfsreqh) { ! 257: if (rp->r_nmp == nmp) ! 258: rp->r_flags |= R_MUSTRESEND; ! 259: rp = rp->r_next; ! 260: } ! 261: return (0); ! 262: } ! 263: ! 264: /* ! 265: * NFS disconnect. Clean up and unlink. ! 266: */ ! 267: void ! 268: nfs_disconnect(nmp) ! 269: register struct nfsmount *nmp; ! 270: { ! 271: register struct socket *so; ! 272: ! 273: if (nmp->nm_so) { ! 274: so = nmp->nm_so; ! 275: nmp->nm_so = (struct socket *)0; ! 276: soshutdown(so, 2); ! 277: soclose(so); ! 278: } ! 279: } ! 280: ! 281: /* ! 282: * This is the nfs send routine. For connection based socket types, it ! 283: * must be called with an nfs_solock() on the socket. ! 284: * "rep == NULL" indicates that it has been called from a server. ! 285: */ ! 286: nfs_send(so, nam, top, rep) ! 287: register struct socket *so; ! 288: struct mbuf *nam; ! 289: register struct mbuf *top; ! 290: struct nfsreq *rep; ! 291: { ! 292: struct mbuf *sendnam; ! 293: int error, soflags; ! 294: ! 295: if (rep) { ! 296: if (rep->r_flags & R_SOFTTERM) { ! 297: m_freem(top); ! 298: return (EINTR); ! 299: } ! 300: if (rep->r_nmp->nm_so == NULL && ! 301: (error = nfs_reconnect(rep, rep->r_nmp))) ! 302: return (error); ! 303: rep->r_flags &= ~R_MUSTRESEND; ! 304: so = rep->r_nmp->nm_so; ! 305: soflags = rep->r_nmp->nm_soflags; ! 306: } else ! 307: soflags = so->so_proto->pr_flags; ! 308: if ((soflags & PR_CONNREQUIRED) || (so->so_state & SS_ISCONNECTED)) ! 309: sendnam = (struct mbuf *)0; ! 310: else ! 311: sendnam = nam; ! 312: ! 313: error = sosend(so, sendnam, (struct uio *)0, top, ! 314: (struct mbuf *)0, 0); ! 315: if (error == EWOULDBLOCK && rep) { ! 316: if (rep->r_flags & R_SOFTTERM) ! 317: error = EINTR; ! 318: else { ! 319: rep->r_flags |= R_MUSTRESEND; ! 320: error = 0; ! 321: } ! 322: } ! 323: /* ! 324: * Ignore socket errors?? ! 325: */ ! 326: if (error && error != EINTR && error != ERESTART) ! 327: error = 0; ! 328: return (error); ! 329: } ! 330: ! 331: /* ! 332: * Receive a Sun RPC Request/Reply. For SOCK_DGRAM, the work is all ! 333: * done by soreceive(), but for SOCK_STREAM we must deal with the Record ! 334: * Mark and consolidate the data into a new mbuf list. ! 335: * nb: Sometimes TCP passes the data up to soreceive() in long lists of ! 336: * small mbufs. ! 337: * For SOCK_STREAM we must be very careful to read an entire record once ! 338: * we have read any of it, even if the system call has been interrupted. ! 339: */ ! 340: nfs_receive(so, aname, mp, rep) ! 341: register struct socket *so; ! 342: struct mbuf **aname; ! 343: struct mbuf **mp; ! 344: register struct nfsreq *rep; ! 345: { ! 346: struct uio auio; ! 347: struct iovec aio; ! 348: register struct mbuf *m; ! 349: struct mbuf *m2, *m3, *mnew, **mbp; ! 350: caddr_t fcp, tcp; ! 351: u_long len; ! 352: struct mbuf **getnam; ! 353: int error, siz, mlen, soflags, rcvflg = MSG_WAITALL; ! 354: ! 355: /* ! 356: * Set up arguments for soreceive() ! 357: */ ! 358: *mp = (struct mbuf *)0; ! 359: *aname = (struct mbuf *)0; ! 360: if (rep) ! 361: soflags = rep->r_nmp->nm_soflags; ! 362: else ! 363: soflags = so->so_proto->pr_flags; ! 364: ! 365: /* ! 366: * For reliable protocols, lock against other senders/receivers ! 367: * in case a reconnect is necessary. ! 368: * For SOCK_STREAM, first get the Record Mark to find out how much ! 369: * more there is to get. ! 370: * We must lock the socket against other receivers ! 371: * until we have an entire rpc request/reply. ! 372: */ ! 373: if (soflags & PR_CONNREQUIRED) { ! 374: tryagain: ! 375: /* ! 376: * Check for fatal errors and resending request. ! 377: */ ! 378: if (rep) { ! 379: /* ! 380: * Ugh: If a reconnect attempt just happened, nm_so ! 381: * would have changed. NULL indicates a failed ! 382: * attempt that has essentially shut down this ! 383: * mount point. ! 384: */ ! 385: if (rep->r_mrep || (so = rep->r_nmp->nm_so) == NULL || ! 386: (rep->r_flags & R_SOFTTERM)) ! 387: return (EINTR); ! 388: while (rep->r_flags & R_MUSTRESEND) { ! 389: m = m_copym(rep->r_mreq, 0, M_COPYALL, M_WAIT); ! 390: nfsstats.rpcretries++; ! 391: if (error = nfs_send(so, rep->r_nmp->nm_nam, m, ! 392: rep)) ! 393: goto errout; ! 394: } ! 395: } ! 396: if ((soflags & PR_ATOMIC) == 0) { ! 397: aio.iov_base = (caddr_t) &len; ! 398: aio.iov_len = sizeof(u_long); ! 399: auio.uio_iov = &aio; ! 400: auio.uio_iovcnt = 1; ! 401: auio.uio_segflg = UIO_SYSSPACE; ! 402: auio.uio_rw = UIO_READ; ! 403: auio.uio_offset = 0; ! 404: auio.uio_resid = sizeof(u_long); ! 405: do { ! 406: error = soreceive(so, (struct mbuf **)0, &auio, ! 407: (struct mbuf **)0, (struct mbuf **)0, &rcvflg); ! 408: if (error == EWOULDBLOCK && rep) { ! 409: if (rep->r_flags & R_SOFTTERM) ! 410: return (EINTR); ! 411: if (rep->r_flags & R_MUSTRESEND) ! 412: goto tryagain; ! 413: } ! 414: } while (error == EWOULDBLOCK); ! 415: if (!error && auio.uio_resid > 0) ! 416: error = EPIPE; ! 417: if (error) ! 418: goto errout; ! 419: len = ntohl(len) & ~0x80000000; ! 420: /* ! 421: * This is SERIOUS! We are out of sync with the sender ! 422: * and forcing a disconnect/reconnect is all I can do. ! 423: */ ! 424: if (len > NFS_MAXPACKET) { ! 425: error = EFBIG; ! 426: goto errout; ! 427: } ! 428: auio.uio_resid = len; ! 429: do { ! 430: error = soreceive(so, (struct mbuf **)0, ! 431: &auio, mp, (struct mbuf **)0, &rcvflg); ! 432: } while (error == EWOULDBLOCK || error == EINTR || ! 433: error == ERESTART); ! 434: if (!error && auio.uio_resid > 0) ! 435: error = EPIPE; ! 436: } else { ! 437: auio.uio_resid = len = 1000000; /* Anything Big */ ! 438: do { ! 439: error = soreceive(so, (struct mbuf **)0, ! 440: &auio, mp, (struct mbuf **)0, &rcvflg); ! 441: if (error == EWOULDBLOCK && rep) { ! 442: if (rep->r_flags & R_SOFTTERM) ! 443: return (EINTR); ! 444: if (rep->r_flags & R_MUSTRESEND) ! 445: goto tryagain; ! 446: } ! 447: } while (error == EWOULDBLOCK); ! 448: if (!error && *mp == NULL) ! 449: error = EPIPE; ! 450: len -= auio.uio_resid; ! 451: } ! 452: errout: ! 453: if (error && rep && error != EINTR && error != ERESTART) { ! 454: m_freem(*mp); ! 455: *mp = (struct mbuf *)0; ! 456: nfs_disconnect(rep->r_nmp); ! 457: error = nfs_reconnect(rep, rep->r_nmp); ! 458: if (!error) ! 459: goto tryagain; ! 460: } ! 461: } else { ! 462: if (so->so_state & SS_ISCONNECTED) ! 463: getnam = (struct mbuf **)0; ! 464: else ! 465: getnam = aname; ! 466: auio.uio_resid = len = 1000000; ! 467: do { ! 468: error = soreceive(so, getnam, &auio, mp, ! 469: (struct mbuf **)0, &rcvflg); ! 470: if (error == EWOULDBLOCK && rep && ! 471: (rep->r_flags & R_SOFTTERM)) ! 472: return (EINTR); ! 473: } while (error == EWOULDBLOCK); ! 474: len -= auio.uio_resid; ! 475: } ! 476: if (error) { ! 477: m_freem(*mp); ! 478: *mp = (struct mbuf *)0; ! 479: } ! 480: /* ! 481: * Search for any mbufs that are not a multiple of 4 bytes long. ! 482: * These could cause pointer alignment problems, so copy them to ! 483: * well aligned mbufs. ! 484: */ ! 485: m = *mp; ! 486: mbp = mp; ! 487: while (m) { ! 488: /* ! 489: * All this for something that may never happen. ! 490: */ ! 491: if (m->m_len & 0x3) { ! 492: printf("nfs_rcv odd length!\n"); ! 493: fcp = mtod(m, caddr_t); ! 494: mnew = m2 = (struct mbuf *)0; ! 495: #ifdef lint ! 496: m3 = (struct mbuf *)0; ! 497: mlen = 0; ! 498: #endif /* lint */ ! 499: while (m) { ! 500: if (m2 == NULL || mlen == 0) { ! 501: MGET(m2, M_WAIT, MT_DATA); ! 502: if (len > MINCLSIZE) ! 503: MCLGET(m2, M_WAIT); ! 504: m2->m_len = 0; ! 505: mlen = M_TRAILINGSPACE(m2); ! 506: tcp = mtod(m2, caddr_t); ! 507: if (mnew) { ! 508: m3->m_next = m2; ! 509: m3 = m2; ! 510: } else ! 511: mnew = m3 = m2; ! 512: } ! 513: siz = (mlen > m->m_len) ? m->m_len : mlen; ! 514: bcopy(fcp, tcp, siz); ! 515: m2->m_len += siz; ! 516: mlen -= siz; ! 517: len -= siz; ! 518: tcp += siz; ! 519: m->m_len -= siz; ! 520: fcp += siz; ! 521: if (m->m_len == 0) { ! 522: do { ! 523: m = m->m_next; ! 524: } while (m && m->m_len == 0); ! 525: if (m) ! 526: fcp = mtod(m, caddr_t); ! 527: } ! 528: } ! 529: m = *mbp; ! 530: *mbp = mnew; ! 531: m_freem(m); ! 532: break; ! 533: } ! 534: len -= m->m_len; ! 535: mbp = &m->m_next; ! 536: m = m->m_next; ! 537: } ! 538: return (error); ! 539: } ! 540: ! 541: struct rpc_replyhead { ! 542: u_long r_xid; ! 543: u_long r_rep; ! 544: }; ! 545: ! 546: /* ! 547: * Implement receipt of reply on a socket. ! 548: * We must search through the list of received datagrams matching them ! 549: * with outstanding requests using the xid, until ours is found. ! 550: */ ! 551: /* ARGSUSED */ ! 552: nfs_reply(nmp, myrep) ! 553: struct nfsmount *nmp; ! 554: struct nfsreq *myrep; ! 555: { ! 556: register struct mbuf *m; ! 557: register struct nfsreq *rep; ! 558: register int error = 0; ! 559: struct rpc_replyhead replyh; ! 560: struct mbuf *mp, *nam; ! 561: char *cp; ! 562: int cnt, xfer; ! 563: ! 564: /* ! 565: * Loop around until we get our own reply ! 566: */ ! 567: for (;;) { ! 568: /* ! 569: * Lock against other receivers so that I don't get stuck in ! 570: * sbwait() after someone else has received my reply for me. ! 571: * Also necessary for connection based protocols to avoid ! 572: * race conditions during a reconnect. ! 573: */ ! 574: nfs_solock(&nmp->nm_flag); ! 575: /* Already received, bye bye */ ! 576: if (myrep->r_mrep != NULL) { ! 577: nfs_sounlock(&nmp->nm_flag); ! 578: return (0); ! 579: } ! 580: /* ! 581: * Get the next Rpc reply off the socket ! 582: */ ! 583: if (error = nfs_receive(nmp->nm_so, &nam, &mp, myrep)) { ! 584: nfs_sounlock(&nmp->nm_flag); ! 585: ! 586: /* ! 587: * Ignore routing errors on connectionless protocols?? ! 588: */ ! 589: if (NFSIGNORE_SOERROR(nmp->nm_soflags, error)) { ! 590: nmp->nm_so->so_error = 0; ! 591: continue; ! 592: } ! 593: ! 594: /* ! 595: * Otherwise cleanup and return a fatal error. ! 596: */ ! 597: if (myrep->r_flags & R_TIMING) { ! 598: myrep->r_flags &= ~R_TIMING; ! 599: nmp->nm_rtt = -1; ! 600: } ! 601: if (myrep->r_flags & R_SENT) { ! 602: myrep->r_flags &= ~R_SENT; ! 603: nmp->nm_sent--; ! 604: } ! 605: return (error); ! 606: } ! 607: ! 608: /* ! 609: * Get the xid and check that it is an rpc reply ! 610: */ ! 611: m = mp; ! 612: if (m->m_len >= 2*NFSX_UNSIGNED) ! 613: bcopy(mtod(m, caddr_t), (caddr_t)&replyh, ! 614: 2*NFSX_UNSIGNED); ! 615: else { ! 616: cnt = 2*NFSX_UNSIGNED; ! 617: cp = (caddr_t)&replyh; ! 618: while (m && cnt > 0) { ! 619: if (m->m_len > 0) { ! 620: xfer = (m->m_len >= cnt) ? cnt : ! 621: m->m_len; ! 622: bcopy(mtod(m, caddr_t), cp, xfer); ! 623: cnt -= xfer; ! 624: cp += xfer; ! 625: } ! 626: if (cnt > 0) ! 627: m = m->m_next; ! 628: } ! 629: } ! 630: if (replyh.r_rep != rpc_reply || m == NULL) { ! 631: nfsstats.rpcinvalid++; ! 632: m_freem(mp); ! 633: nfs_sounlock(&nmp->nm_flag); ! 634: continue; ! 635: } ! 636: /* ! 637: * Loop through the request list to match up the reply ! 638: * Iff no match, just drop the datagram ! 639: */ ! 640: m = mp; ! 641: rep = nfsreqh.r_next; ! 642: while (rep != &nfsreqh) { ! 643: if (rep->r_mrep == NULL && replyh.r_xid == rep->r_xid) { ! 644: /* Found it.. */ ! 645: rep->r_mrep = m; ! 646: /* ! 647: * Update timing ! 648: */ ! 649: if (rep->r_flags & R_TIMING) { ! 650: nfs_updatetimer(rep->r_nmp); ! 651: rep->r_flags &= ~R_TIMING; ! 652: rep->r_nmp->nm_rtt = -1; ! 653: } ! 654: if (rep->r_flags & R_SENT) { ! 655: rep->r_flags &= ~R_SENT; ! 656: rep->r_nmp->nm_sent--; ! 657: } ! 658: break; ! 659: } ! 660: rep = rep->r_next; ! 661: } ! 662: nfs_sounlock(&nmp->nm_flag); ! 663: if (nam) ! 664: m_freem(nam); ! 665: /* ! 666: * If not matched to a request, drop it. ! 667: * If it's mine, get out. ! 668: */ ! 669: if (rep == &nfsreqh) { ! 670: nfsstats.rpcunexpected++; ! 671: m_freem(m); ! 672: } else if (rep == myrep) ! 673: return (0); ! 674: } ! 675: } ! 676: ! 677: /* ! 678: * nfs_request - goes something like this ! 679: * - fill in request struct ! 680: * - links it into list ! 681: * - calls nfs_send() for first transmit ! 682: * - calls nfs_receive() to get reply ! 683: * - break down rpc header and return with nfs reply pointed to ! 684: * by mrep or error ! 685: * nb: always frees up mreq mbuf list ! 686: */ ! 687: nfs_request(vp, mreq, xid, procnum, procp, tryhard, mp, mrp, mdp, dposp) ! 688: struct vnode *vp; ! 689: struct mbuf *mreq; ! 690: u_long xid; ! 691: int procnum; ! 692: struct proc *procp; ! 693: int tryhard; ! 694: struct mount *mp; ! 695: struct mbuf **mrp; ! 696: struct mbuf **mdp; ! 697: caddr_t *dposp; ! 698: { ! 699: register struct mbuf *m, *mrep; ! 700: register struct nfsreq *rep; ! 701: register u_long *p; ! 702: register int len; ! 703: struct nfsmount *nmp; ! 704: struct mbuf *md; ! 705: struct nfsreq *reph; ! 706: caddr_t dpos; ! 707: char *cp2; ! 708: int t1; ! 709: int s; ! 710: int error = 0; ! 711: ! 712: nmp = VFSTONFS(mp); ! 713: m = mreq; ! 714: MALLOC(rep, struct nfsreq *, sizeof(struct nfsreq), M_NFSREQ, M_WAITOK); ! 715: rep->r_xid = xid; ! 716: rep->r_nmp = nmp; ! 717: rep->r_vp = vp; ! 718: rep->r_procp = procp; ! 719: if ((nmp->nm_flag & NFSMNT_SOFT) || ! 720: ((nmp->nm_flag & NFSMNT_SPONGY) && !tryhard)) ! 721: rep->r_retry = nmp->nm_retry; ! 722: else ! 723: rep->r_retry = NFS_MAXREXMIT + 1; /* past clip limit */ ! 724: rep->r_flags = rep->r_rexmit = 0; ! 725: /* ! 726: * Three cases: ! 727: * - non-idempotent requests on SOCK_DGRAM use NFS_MINIDEMTIMEO ! 728: * - idempotent requests on SOCK_DGRAM use 0 ! 729: * - Reliable transports, NFS_RELIABLETIMEO ! 730: * Timeouts are still done on reliable transports to ensure detection ! 731: * of excessive connection delay. ! 732: */ ! 733: if (nmp->nm_sotype != SOCK_DGRAM) ! 734: rep->r_timerinit = -NFS_RELIABLETIMEO; ! 735: else if (nonidempotent[procnum]) ! 736: rep->r_timerinit = -NFS_MINIDEMTIMEO; ! 737: else ! 738: rep->r_timerinit = 0; ! 739: rep->r_timer = rep->r_timerinit; ! 740: rep->r_mrep = NULL; ! 741: len = 0; ! 742: while (m) { ! 743: len += m->m_len; ! 744: m = m->m_next; ! 745: } ! 746: mreq->m_pkthdr.len = len; ! 747: mreq->m_pkthdr.rcvif = (struct ifnet *)0; ! 748: /* ! 749: * For non-atomic protocols, insert a Sun RPC Record Mark. ! 750: */ ! 751: if ((nmp->nm_soflags & PR_ATOMIC) == 0) { ! 752: M_PREPEND(mreq, sizeof(u_long), M_WAIT); ! 753: *mtod(mreq, u_long *) = htonl(0x80000000 | len); ! 754: } ! 755: rep->r_mreq = mreq; ! 756: ! 757: /* ! 758: * Do the client side RPC. ! 759: */ ! 760: nfsstats.rpcrequests++; ! 761: /* ! 762: * Chain request into list of outstanding requests. Be sure ! 763: * to put it LAST so timer finds oldest requests first. ! 764: */ ! 765: s = splnet(); ! 766: reph = &nfsreqh; ! 767: reph->r_prev->r_next = rep; ! 768: rep->r_prev = reph->r_prev; ! 769: reph->r_prev = rep; ! 770: rep->r_next = reph; ! 771: /* ! 772: * If backing off another request or avoiding congestion, don't ! 773: * send this one now but let timer do it. If not timing a request, ! 774: * do it now. ! 775: */ ! 776: if (nmp->nm_sent <= 0 || nmp->nm_sotype != SOCK_DGRAM || ! 777: (nmp->nm_currexmit == 0 && nmp->nm_sent < nmp->nm_window)) { ! 778: nmp->nm_sent++; ! 779: rep->r_flags |= R_SENT; ! 780: if (nmp->nm_rtt == -1) { ! 781: nmp->nm_rtt = 0; ! 782: rep->r_flags |= R_TIMING; ! 783: } ! 784: splx(s); ! 785: m = m_copym(mreq, 0, M_COPYALL, M_WAIT); ! 786: if (nmp->nm_soflags & PR_CONNREQUIRED) ! 787: nfs_solock(&nmp->nm_flag); ! 788: error = nfs_send(nmp->nm_so, nmp->nm_nam, m, rep); ! 789: if (nmp->nm_soflags & PR_CONNREQUIRED) ! 790: nfs_sounlock(&nmp->nm_flag); ! 791: if (error && NFSIGNORE_SOERROR(nmp->nm_soflags, error)) ! 792: nmp->nm_so->so_error = error = 0; ! 793: } else ! 794: splx(s); ! 795: ! 796: /* ! 797: * Wait for the reply from our send or the timer's. ! 798: */ ! 799: if (!error) ! 800: error = nfs_reply(nmp, rep); ! 801: ! 802: /* ! 803: * RPC done, unlink the request. ! 804: */ ! 805: s = splnet(); ! 806: rep->r_prev->r_next = rep->r_next; ! 807: rep->r_next->r_prev = rep->r_prev; ! 808: splx(s); ! 809: ! 810: /* ! 811: * If there was a successful reply and a tprintf msg. ! 812: * tprintf a response. ! 813: */ ! 814: if (!error && (rep->r_flags & R_TPRINTFMSG)) { ! 815: if (rep->r_procp) ! 816: tprintf(rep->r_procp->p_session, ! 817: "Nfs server %s, is alive again\n", ! 818: rep->r_nmp->nm_mountp->mnt_stat.f_mntfromname); ! 819: else ! 820: tprintf(NULL, "Nfs server %s, is alive again\n", ! 821: rep->r_nmp->nm_mountp->mnt_stat.f_mntfromname); ! 822: } ! 823: m_freem(rep->r_mreq); ! 824: mrep = md = rep->r_mrep; ! 825: FREE((caddr_t)rep, M_NFSREQ); ! 826: if (error) ! 827: return (error); ! 828: ! 829: /* ! 830: * break down the rpc header and check if ok ! 831: */ ! 832: dpos = mtod(md, caddr_t); ! 833: nfsm_disect(p, u_long *, 5*NFSX_UNSIGNED); ! 834: p += 2; ! 835: if (*p++ == rpc_msgdenied) { ! 836: if (*p == rpc_mismatch) ! 837: error = EOPNOTSUPP; ! 838: else ! 839: error = EACCES; ! 840: m_freem(mrep); ! 841: return (error); ! 842: } ! 843: /* ! 844: * skip over the auth_verf, someday we may want to cache auth_short's ! 845: * for nfs_reqhead(), but for now just dump it ! 846: */ ! 847: if (*++p != 0) { ! 848: len = nfsm_rndup(fxdr_unsigned(long, *p)); ! 849: nfsm_adv(len); ! 850: } ! 851: nfsm_disect(p, u_long *, NFSX_UNSIGNED); ! 852: /* 0 == ok */ ! 853: if (*p == 0) { ! 854: nfsm_disect(p, u_long *, NFSX_UNSIGNED); ! 855: if (*p != 0) { ! 856: error = fxdr_unsigned(int, *p); ! 857: m_freem(mrep); ! 858: return (error); ! 859: } ! 860: *mrp = mrep; ! 861: *mdp = md; ! 862: *dposp = dpos; ! 863: return (0); ! 864: } ! 865: m_freem(mrep); ! 866: return (EPROTONOSUPPORT); ! 867: nfsmout: ! 868: return (error); ! 869: } ! 870: ! 871: /* ! 872: * Get a request for the server main loop ! 873: * - receive a request via. nfs_soreceive() ! 874: * - verify it ! 875: * - fill in the cred struct. ! 876: */ ! 877: nfs_getreq(so, prog, vers, maxproc, nam, mrp, mdp, dposp, retxid, procnum, cr, ! 878: msk, mtch) ! 879: struct socket *so; ! 880: u_long prog; ! 881: u_long vers; ! 882: int maxproc; ! 883: struct mbuf **nam; ! 884: struct mbuf **mrp; ! 885: struct mbuf **mdp; ! 886: caddr_t *dposp; ! 887: u_long *retxid; ! 888: u_long *procnum; ! 889: register struct ucred *cr; ! 890: struct mbuf *msk, *mtch; ! 891: { ! 892: register int i; ! 893: register u_long *p; ! 894: register long t1; ! 895: caddr_t dpos, cp2; ! 896: int error = 0; ! 897: struct mbuf *mrep, *md; ! 898: int len; ! 899: ! 900: if (so->so_proto->pr_flags & PR_CONNREQUIRED) { ! 901: error = nfs_receive(so, nam, &mrep, (struct nfsreq *)0); ! 902: } else { ! 903: mrep = (struct mbuf *)0; ! 904: do { ! 905: if (mrep) { ! 906: m_freem(*nam); ! 907: m_freem(mrep); ! 908: } ! 909: error = nfs_receive(so, nam, &mrep, (struct nfsreq *)0); ! 910: } while (!error && nfs_badnam(*nam, msk, mtch)); ! 911: } ! 912: if (error) ! 913: return (error); ! 914: md = mrep; ! 915: dpos = mtod(mrep, caddr_t); ! 916: nfsm_disect(p, u_long *, 10*NFSX_UNSIGNED); ! 917: *retxid = *p++; ! 918: if (*p++ != rpc_call) { ! 919: m_freem(mrep); ! 920: return (ERPCMISMATCH); ! 921: } ! 922: if (*p++ != rpc_vers) { ! 923: m_freem(mrep); ! 924: return (ERPCMISMATCH); ! 925: } ! 926: if (*p++ != prog) { ! 927: m_freem(mrep); ! 928: return (EPROGUNAVAIL); ! 929: } ! 930: if (*p++ != vers) { ! 931: m_freem(mrep); ! 932: return (EPROGMISMATCH); ! 933: } ! 934: *procnum = fxdr_unsigned(u_long, *p++); ! 935: if (*procnum == NFSPROC_NULL) { ! 936: *mrp = mrep; ! 937: return (0); ! 938: } ! 939: if (*procnum > maxproc || *p++ != rpc_auth_unix) { ! 940: m_freem(mrep); ! 941: return (EPROCUNAVAIL); ! 942: } ! 943: len = fxdr_unsigned(int, *p++); ! 944: if (len < 0 || len > RPCAUTH_MAXSIZ) { ! 945: m_freem(mrep); ! 946: return (EBADRPC); ! 947: } ! 948: len = fxdr_unsigned(int, *++p); ! 949: if (len < 0 || len > NFS_MAXNAMLEN) { ! 950: m_freem(mrep); ! 951: return (EBADRPC); ! 952: } ! 953: nfsm_adv(nfsm_rndup(len)); ! 954: nfsm_disect(p, u_long *, 3*NFSX_UNSIGNED); ! 955: cr->cr_uid = fxdr_unsigned(uid_t, *p++); ! 956: cr->cr_gid = fxdr_unsigned(gid_t, *p++); ! 957: len = fxdr_unsigned(int, *p); ! 958: if (len < 0 || len > RPCAUTH_UNIXGIDS) { ! 959: m_freem(mrep); ! 960: return (EBADRPC); ! 961: } ! 962: nfsm_disect(p, u_long *, (len + 2)*NFSX_UNSIGNED); ! 963: for (i = 1; i <= len; i++) ! 964: if (i < NGROUPS) ! 965: cr->cr_groups[i] = fxdr_unsigned(gid_t, *p++); ! 966: else ! 967: p++; ! 968: cr->cr_ngroups = (len >= NGROUPS) ? NGROUPS : (len + 1); ! 969: /* ! 970: * Do we have any use for the verifier. ! 971: * According to the "Remote Procedure Call Protocol Spec." it ! 972: * should be AUTH_NULL, but some clients make it AUTH_UNIX? ! 973: * For now, just skip over it ! 974: */ ! 975: len = fxdr_unsigned(int, *++p); ! 976: if (len < 0 || len > RPCAUTH_MAXSIZ) { ! 977: m_freem(mrep); ! 978: return (EBADRPC); ! 979: } ! 980: if (len > 0) ! 981: nfsm_adv(nfsm_rndup(len)); ! 982: *mrp = mrep; ! 983: *mdp = md; ! 984: *dposp = dpos; ! 985: return (0); ! 986: nfsmout: ! 987: return (error); ! 988: } ! 989: ! 990: /* ! 991: * Generate the rpc reply header ! 992: * siz arg. is used to decide if adding a cluster is worthwhile ! 993: */ ! 994: nfs_rephead(siz, retxid, err, mrq, mbp, bposp) ! 995: int siz; ! 996: u_long retxid; ! 997: int err; ! 998: struct mbuf **mrq; ! 999: struct mbuf **mbp; ! 1000: caddr_t *bposp; ! 1001: { ! 1002: register u_long *p; ! 1003: register long t1; ! 1004: caddr_t bpos; ! 1005: struct mbuf *mreq, *mb, *mb2; ! 1006: ! 1007: NFSMGETHDR(mreq); ! 1008: mb = mreq; ! 1009: if ((siz+RPC_REPLYSIZ) > MHLEN) ! 1010: MCLGET(mreq, M_WAIT); ! 1011: p = mtod(mreq, u_long *); ! 1012: mreq->m_len = 6*NFSX_UNSIGNED; ! 1013: bpos = ((caddr_t)p)+mreq->m_len; ! 1014: *p++ = retxid; ! 1015: *p++ = rpc_reply; ! 1016: if (err == ERPCMISMATCH) { ! 1017: *p++ = rpc_msgdenied; ! 1018: *p++ = rpc_mismatch; ! 1019: *p++ = txdr_unsigned(2); ! 1020: *p = txdr_unsigned(2); ! 1021: } else { ! 1022: *p++ = rpc_msgaccepted; ! 1023: *p++ = 0; ! 1024: *p++ = 0; ! 1025: switch (err) { ! 1026: case EPROGUNAVAIL: ! 1027: *p = txdr_unsigned(RPC_PROGUNAVAIL); ! 1028: break; ! 1029: case EPROGMISMATCH: ! 1030: *p = txdr_unsigned(RPC_PROGMISMATCH); ! 1031: nfsm_build(p, u_long *, 2*NFSX_UNSIGNED); ! 1032: *p++ = txdr_unsigned(2); ! 1033: *p = txdr_unsigned(2); /* someday 3 */ ! 1034: break; ! 1035: case EPROCUNAVAIL: ! 1036: *p = txdr_unsigned(RPC_PROCUNAVAIL); ! 1037: break; ! 1038: default: ! 1039: *p = 0; ! 1040: if (err != VNOVAL) { ! 1041: nfsm_build(p, u_long *, NFSX_UNSIGNED); ! 1042: *p = txdr_unsigned(err); ! 1043: } ! 1044: break; ! 1045: }; ! 1046: } ! 1047: *mrq = mreq; ! 1048: *mbp = mb; ! 1049: *bposp = bpos; ! 1050: if (err != 0 && err != VNOVAL) ! 1051: nfsstats.srvrpc_errs++; ! 1052: return (0); ! 1053: } ! 1054: ! 1055: /* ! 1056: * Nfs timer routine ! 1057: * Scan the nfsreq list and retranmit any requests that have timed out ! 1058: * To avoid retransmission attempts on STREAM sockets (in the future) make ! 1059: * sure to set the r_retry field to 0 (implies nm_retry == 0). ! 1060: */ ! 1061: nfs_timer() ! 1062: { ! 1063: register struct nfsreq *rep; ! 1064: register struct mbuf *m; ! 1065: register struct socket *so; ! 1066: register struct nfsmount *nmp; ! 1067: int s, error; ! 1068: ! 1069: s = splnet(); ! 1070: for (rep = nfsreqh.r_next; rep != &nfsreqh; rep = rep->r_next) { ! 1071: nmp = rep->r_nmp; ! 1072: if (rep->r_mrep || (rep->r_flags & R_SOFTTERM) || ! 1073: (so = nmp->nm_so) == NULL) ! 1074: continue; ! 1075: if ((nmp->nm_flag & NFSMNT_INT) && nfs_sigintr(rep->r_procp)) { ! 1076: rep->r_flags |= R_SOFTTERM; ! 1077: continue; ! 1078: } ! 1079: if (rep->r_flags & R_TIMING) /* update rtt in mount */ ! 1080: nmp->nm_rtt++; ! 1081: /* If not timed out */ ! 1082: if (++rep->r_timer < nmp->nm_rto) ! 1083: continue; ! 1084: /* Do backoff and save new timeout in mount */ ! 1085: if (rep->r_flags & R_TIMING) { ! 1086: nfs_backofftimer(nmp); ! 1087: rep->r_flags &= ~R_TIMING; ! 1088: nmp->nm_rtt = -1; ! 1089: } ! 1090: if (rep->r_flags & R_SENT) { ! 1091: rep->r_flags &= ~R_SENT; ! 1092: nmp->nm_sent--; ! 1093: } ! 1094: ! 1095: /* ! 1096: * Check for too many retries on soft mount. ! 1097: * nb: For hard mounts, r_retry == NFS_MAXREXMIT+1 ! 1098: */ ! 1099: if (++rep->r_rexmit > NFS_MAXREXMIT) ! 1100: rep->r_rexmit = NFS_MAXREXMIT; ! 1101: ! 1102: /* ! 1103: * Check for server not responding ! 1104: */ ! 1105: if ((rep->r_flags & R_TPRINTFMSG) == 0 && ! 1106: rep->r_rexmit > NFS_FISHY) { ! 1107: if (rep->r_procp && rep->r_procp->p_session) ! 1108: tprintf(rep->r_procp->p_session, ! 1109: "Nfs server %s, not responding\n", ! 1110: nmp->nm_mountp->mnt_stat.f_mntfromname); ! 1111: else ! 1112: tprintf(NULL, ! 1113: "Nfs server %s, not responding\n", ! 1114: nmp->nm_mountp->mnt_stat.f_mntfromname); ! 1115: rep->r_flags |= R_TPRINTFMSG; ! 1116: } ! 1117: if (rep->r_rexmit >= rep->r_retry) { /* too many */ ! 1118: nfsstats.rpctimeouts++; ! 1119: rep->r_flags |= R_SOFTTERM; ! 1120: continue; ! 1121: } ! 1122: if (nmp->nm_sotype != SOCK_DGRAM) ! 1123: continue; ! 1124: ! 1125: /* ! 1126: * If there is enough space and the window allows.. ! 1127: * Resend it ! 1128: */ ! 1129: if (sbspace(&so->so_snd) >= rep->r_mreq->m_pkthdr.len && ! 1130: nmp->nm_sent < nmp->nm_window && ! 1131: (m = m_copym(rep->r_mreq, 0, M_COPYALL, M_DONTWAIT))){ ! 1132: nfsstats.rpcretries++; ! 1133: if ((nmp->nm_flag & NFSMNT_NOCONN) == 0) ! 1134: error = (*so->so_proto->pr_usrreq)(so, PRU_SEND, m, ! 1135: (caddr_t)0, (struct mbuf *)0, (struct mbuf *)0); ! 1136: else ! 1137: error = (*so->so_proto->pr_usrreq)(so, PRU_SEND, m, ! 1138: nmp->nm_nam, (struct mbuf *)0, (struct mbuf *)0); ! 1139: if (error) { ! 1140: if (NFSIGNORE_SOERROR(nmp->nm_soflags, error)) ! 1141: so->so_error = 0; ! 1142: } else { ! 1143: /* ! 1144: * We need to time the request even though we ! 1145: * are retransmitting. ! 1146: */ ! 1147: nmp->nm_rtt = 0; ! 1148: nmp->nm_sent++; ! 1149: rep->r_flags |= (R_SENT|R_TIMING); ! 1150: rep->r_timer = rep->r_timerinit; ! 1151: } ! 1152: } ! 1153: } ! 1154: splx(s); ! 1155: timeout(nfs_timer, (caddr_t)0, hz/NFS_HZ); ! 1156: } ! 1157: ! 1158: /* ! 1159: * NFS timer update and backoff. The "Jacobson/Karels/Karn" scheme is ! 1160: * used here. The timer state is held in the nfsmount structure and ! 1161: * a single request is used to clock the response. When successful ! 1162: * the rtt smoothing in nfs_updatetimer is used, when failed the backoff ! 1163: * is done by nfs_backofftimer. We also log failure messages in these ! 1164: * routines. ! 1165: * ! 1166: * Congestion variables are held in the nfshost structure which ! 1167: * is referenced by nfsmounts and shared per-server. This separation ! 1168: * makes it possible to do per-mount timing which allows varying disk ! 1169: * access times to be dealt with, while preserving a network oriented ! 1170: * congestion control scheme. ! 1171: * ! 1172: * The windowing implements the Jacobson/Karels slowstart algorithm ! 1173: * with adjusted scaling factors. We start with one request, then send ! 1174: * 4 more after each success until the ssthresh limit is reached, then ! 1175: * we increment at a rate proportional to the window. On failure, we ! 1176: * remember 3/4 the current window and clamp the send limit to 1. Note ! 1177: * ICMP source quench is not reflected in so->so_error so we ignore that ! 1178: * for now. ! 1179: * ! 1180: * NFS behaves much more like a transport protocol with these changes, ! 1181: * shedding the teenage pedal-to-the-metal tendencies of "other" ! 1182: * implementations. ! 1183: * ! 1184: * Timers and congestion avoidance by Tom Talpey, Open Software Foundation. ! 1185: */ ! 1186: ! 1187: /* ! 1188: * The TCP algorithm was not forgiving enough. Because the NFS server ! 1189: * responds only after performing lookups/diskio/etc, we have to be ! 1190: * more prepared to accept a spiky variance. The TCP algorithm is: ! 1191: * TCP_RTO(nmp) ((((nmp)->nm_srtt >> 2) + (nmp)->nm_rttvar) >> 1) ! 1192: */ ! 1193: #define NFS_RTO(nmp) (((nmp)->nm_srtt >> 3) + (nmp)->nm_rttvar) ! 1194: ! 1195: nfs_updatetimer(nmp) ! 1196: register struct nfsmount *nmp; ! 1197: { ! 1198: ! 1199: /* If retransmitted, clear and return */ ! 1200: if (nmp->nm_rexmit || nmp->nm_currexmit) { ! 1201: nmp->nm_rexmit = nmp->nm_currexmit = 0; ! 1202: return; ! 1203: } ! 1204: /* If have a measurement, do smoothing */ ! 1205: if (nmp->nm_srtt) { ! 1206: register short delta; ! 1207: delta = nmp->nm_rtt - (nmp->nm_srtt >> 3); ! 1208: if ((nmp->nm_srtt += delta) <= 0) ! 1209: nmp->nm_srtt = 1; ! 1210: if (delta < 0) ! 1211: delta = -delta; ! 1212: delta -= (nmp->nm_rttvar >> 2); ! 1213: if ((nmp->nm_rttvar += delta) <= 0) ! 1214: nmp->nm_rttvar = 1; ! 1215: /* Else initialize */ ! 1216: } else { ! 1217: nmp->nm_rttvar = nmp->nm_rtt << 1; ! 1218: if (nmp->nm_rttvar == 0) nmp->nm_rttvar = 2; ! 1219: nmp->nm_srtt = nmp->nm_rttvar << 2; ! 1220: } ! 1221: /* Compute new Retransmission TimeOut and clip */ ! 1222: nmp->nm_rto = NFS_RTO(nmp); ! 1223: if (nmp->nm_rto < NFS_MINTIMEO) ! 1224: nmp->nm_rto = NFS_MINTIMEO; ! 1225: else if (nmp->nm_rto > NFS_MAXTIMEO) ! 1226: nmp->nm_rto = NFS_MAXTIMEO; ! 1227: ! 1228: /* Update window estimate */ ! 1229: if (nmp->nm_window < nmp->nm_ssthresh) /* quickly */ ! 1230: nmp->nm_window += 4; ! 1231: else { /* slowly */ ! 1232: register long incr = ++nmp->nm_winext; ! 1233: incr = (incr * incr) / nmp->nm_window; ! 1234: if (incr > 0) { ! 1235: nmp->nm_winext = 0; ! 1236: ++nmp->nm_window; ! 1237: } ! 1238: } ! 1239: if (nmp->nm_window > NFS_MAXWINDOW) ! 1240: nmp->nm_window = NFS_MAXWINDOW; ! 1241: } ! 1242: ! 1243: nfs_backofftimer(nmp) ! 1244: register struct nfsmount *nmp; ! 1245: { ! 1246: register unsigned long newrto; ! 1247: ! 1248: /* Clip shift count */ ! 1249: if (++nmp->nm_rexmit > 8 * sizeof nmp->nm_rto) ! 1250: nmp->nm_rexmit = 8 * sizeof nmp->nm_rto; ! 1251: /* Back off RTO exponentially */ ! 1252: newrto = NFS_RTO(nmp); ! 1253: newrto <<= (nmp->nm_rexmit - 1); ! 1254: if (newrto == 0 || newrto > NFS_MAXTIMEO) ! 1255: newrto = NFS_MAXTIMEO; ! 1256: nmp->nm_rto = newrto; ! 1257: ! 1258: /* If too many retries, message, assume a bogus RTT and re-measure */ ! 1259: if (nmp->nm_currexmit < nmp->nm_rexmit) { ! 1260: nmp->nm_currexmit = nmp->nm_rexmit; ! 1261: if (nmp->nm_currexmit >= nfsrexmtthresh) { ! 1262: if (nmp->nm_currexmit == nfsrexmtthresh) { ! 1263: nmp->nm_rttvar += (nmp->nm_srtt >> 2); ! 1264: nmp->nm_srtt = 0; ! 1265: } ! 1266: } ! 1267: } ! 1268: /* Close down window but remember this point (3/4 current) for later */ ! 1269: nmp->nm_ssthresh = ((nmp->nm_window << 1) + nmp->nm_window) >> 2; ! 1270: nmp->nm_window = 1; ! 1271: nmp->nm_winext = 0; ! 1272: } ! 1273: ! 1274: /* ! 1275: * Test for a termination signal pending on procp. ! 1276: * This is used for NFSMNT_INT mounts. ! 1277: */ ! 1278: nfs_sigintr(p) ! 1279: register struct proc *p; ! 1280: { ! 1281: if (p && p->p_sig && (((p->p_sig &~ p->p_sigmask) &~ p->p_sigignore) & ! 1282: NFSINT_SIGMASK)) ! 1283: return (1); ! 1284: else ! 1285: return (0); ! 1286: } ! 1287: ! 1288: /* ! 1289: * Lock a socket against others. ! 1290: * Necessary for STREAM sockets to ensure you get an entire rpc request/reply ! 1291: * and also to avoid race conditions between the processes with nfs requests ! 1292: * in progress when a reconnect is necessary. ! 1293: */ ! 1294: nfs_solock(flagp) ! 1295: register int *flagp; ! 1296: { ! 1297: ! 1298: while (*flagp & NFSMNT_SCKLOCK) { ! 1299: *flagp |= NFSMNT_WANTSCK; ! 1300: (void) tsleep((caddr_t)flagp, PZERO-1, "nfsolck", 0); ! 1301: } ! 1302: *flagp |= NFSMNT_SCKLOCK; ! 1303: } ! 1304: ! 1305: /* ! 1306: * Unlock the stream socket for others. ! 1307: */ ! 1308: nfs_sounlock(flagp) ! 1309: register int *flagp; ! 1310: { ! 1311: ! 1312: if ((*flagp & NFSMNT_SCKLOCK) == 0) ! 1313: panic("nfs sounlock"); ! 1314: *flagp &= ~NFSMNT_SCKLOCK; ! 1315: if (*flagp & NFSMNT_WANTSCK) { ! 1316: *flagp &= ~NFSMNT_WANTSCK; ! 1317: wakeup((caddr_t)flagp); ! 1318: } ! 1319: } ! 1320: ! 1321: /* ! 1322: * This function compares two net addresses by family and returns TRUE ! 1323: * if they are the same. ! 1324: * If there is any doubt, return FALSE. ! 1325: */ ! 1326: nfs_netaddr_match(nam1, nam2) ! 1327: struct mbuf *nam1, *nam2; ! 1328: { ! 1329: register struct sockaddr *saddr1, *saddr2; ! 1330: ! 1331: saddr1 = mtod(nam1, struct sockaddr *); ! 1332: saddr2 = mtod(nam2, struct sockaddr *); ! 1333: if (saddr1->sa_family != saddr2->sa_family) ! 1334: return (0); ! 1335: ! 1336: /* ! 1337: * Must do each address family separately since unused fields ! 1338: * are undefined values and not always zeroed. ! 1339: */ ! 1340: switch (saddr1->sa_family) { ! 1341: case AF_INET: ! 1342: if (((struct sockaddr_in *)saddr1)->sin_addr.s_addr == ! 1343: ((struct sockaddr_in *)saddr2)->sin_addr.s_addr) ! 1344: return (1); ! 1345: break; ! 1346: default: ! 1347: break; ! 1348: }; ! 1349: return (0); ! 1350: } ! 1351: ! 1352: /* ! 1353: * Check the hostname fields for nfsd's mask and match fields. ! 1354: * By address family: ! 1355: * - Bitwise AND the mask with the host address field ! 1356: * - Compare for == with match ! 1357: * return TRUE if not equal ! 1358: */ ! 1359: nfs_badnam(nam, msk, mtch) ! 1360: register struct mbuf *nam, *msk, *mtch; ! 1361: { ! 1362: switch (mtod(nam, struct sockaddr *)->sa_family) { ! 1363: case AF_INET: ! 1364: return ((mtod(nam, struct sockaddr_in *)->sin_addr.s_addr & ! 1365: mtod(msk, struct sockaddr_in *)->sin_addr.s_addr) != ! 1366: mtod(mtch, struct sockaddr_in *)->sin_addr.s_addr); ! 1367: default: ! 1368: printf("nfs_badmatch, unknown sa_family\n"); ! 1369: return (0); ! 1370: }; ! 1371: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.