Annotation of Net2/nfs/nfs_socket.c, revision 1.1.1.2

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

unix.superglobalmegacorp.com

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