Annotation of 43BSDReno/sys/nfs/nfs_socket.c, revision 1.1.1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.