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

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

unix.superglobalmegacorp.com

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