[BACK]Return to nfs_srvcache.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / nfs

Annotation of src/sys/nfs/nfs_srvcache.c, Revision 1.16

1.16    ! augustss    1: /*     $NetBSD: nfs_srvcache.c,v 1.15 1998/08/09 21:19:51 perry Exp $  */
1.8       cgd         2:
1.1       cgd         3: /*
1.7       mycroft     4:  * Copyright (c) 1989, 1993
                      5:  *     The Regents of the University of California.  All rights reserved.
1.1       cgd         6:  *
                      7:  * This code is derived from software contributed to Berkeley by
                      8:  * Rick Macklem at The University of Guelph.
                      9:  *
                     10:  * Redistribution and use in source and binary forms, with or without
                     11:  * modification, are permitted provided that the following conditions
                     12:  * are met:
                     13:  * 1. Redistributions of source code must retain the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer.
                     15:  * 2. Redistributions in binary form must reproduce the above copyright
                     16:  *    notice, this list of conditions and the following disclaimer in the
                     17:  *    documentation and/or other materials provided with the distribution.
                     18:  * 3. All advertising materials mentioning features or use of this software
                     19:  *    must display the following acknowledgement:
                     20:  *     This product includes software developed by the University of
                     21:  *     California, Berkeley and its contributors.
                     22:  * 4. Neither the name of the University nor the names of its contributors
                     23:  *    may be used to endorse or promote products derived from this software
                     24:  *    without specific prior written permission.
                     25:  *
                     26:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     27:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     28:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     29:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     30:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     31:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     32:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     33:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     34:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     35:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     36:  * SUCH DAMAGE.
                     37:  *
1.12      fvdl       38:  *     @(#)nfs_srvcache.c      8.3 (Berkeley) 3/30/95
1.1       cgd        39:  */
                     40:
                     41: /*
                     42:  * Reference: Chet Juszczak, "Improving the Performance and Correctness
1.7       mycroft    43:  *             of an NFS Server", in Proc. Winter 1989 USENIX Conference,
                     44:  *             pages 53-63. San Diego, February 1989.
1.1       cgd        45:  */
1.14      jonathan   46: #include "opt_iso.h"
                     47:
1.6       mycroft    48: #include <sys/param.h>
                     49: #include <sys/vnode.h>
                     50: #include <sys/mount.h>
                     51: #include <sys/kernel.h>
                     52: #include <sys/systm.h>
1.7       mycroft    53: #include <sys/proc.h>
1.6       mycroft    54: #include <sys/mbuf.h>
1.7       mycroft    55: #include <sys/malloc.h>
1.6       mycroft    56: #include <sys/socket.h>
                     57: #include <sys/socketvar.h>
1.1       cgd        58:
1.6       mycroft    59: #include <netinet/in.h>
1.7       mycroft    60: #ifdef ISO
                     61: #include <netiso/iso.h>
                     62: #endif
1.6       mycroft    63: #include <nfs/nfsm_subs.h>
1.7       mycroft    64: #include <nfs/rpcv2.h>
1.12      fvdl       65: #include <nfs/nfsproto.h>
1.7       mycroft    66: #include <nfs/nfs.h>
1.6       mycroft    67: #include <nfs/nfsrvcache.h>
1.7       mycroft    68: #include <nfs/nqnfs.h>
1.11      christos   69: #include <nfs/nfs_var.h>
1.2       glass      70:
1.12      fvdl       71: extern struct nfsstats nfsstats;
                     72: extern int nfsv2_procid[NFS_NPROCS];
1.7       mycroft    73: long numnfsrvcache, desirednfsrvcache = NFSRVCACHESIZ;
1.1       cgd        74:
1.9       mycroft    75: #define        NFSRCHASH(xid) \
                     76:        (&nfsrvhashtbl[((xid) + ((xid) >> 24)) & nfsrvhash])
                     77: LIST_HEAD(nfsrvhash, nfsrvcache) *nfsrvhashtbl;
                     78: TAILQ_HEAD(nfsrvlru, nfsrvcache) nfsrvlruhead;
                     79: u_long nfsrvhash;
1.1       cgd        80:
                     81: #define TRUE   1
                     82: #define        FALSE   0
                     83:
1.7       mycroft    84: #define        NETFAMILY(rp) \
                     85:                (((rp)->rc_flag & RC_INETADDR) ? AF_INET : AF_ISO)
                     86:
                     87: /*
                     88:  * Static array that defines which nfs rpc's are nonidempotent
                     89:  */
                     90: int nonidempotent[NFS_NPROCS] = {
                     91:        FALSE,
                     92:        FALSE,
                     93:        TRUE,
                     94:        FALSE,
                     95:        FALSE,
                     96:        FALSE,
                     97:        FALSE,
                     98:        TRUE,
                     99:        TRUE,
                    100:        TRUE,
                    101:        TRUE,
                    102:        TRUE,
                    103:        TRUE,
                    104:        TRUE,
                    105:        TRUE,
1.12      fvdl      106:        TRUE,
                    107:        FALSE,
                    108:        FALSE,
                    109:        FALSE,
1.7       mycroft   110:        FALSE,
                    111:        FALSE,
                    112:        FALSE,
                    113:        FALSE,
                    114:        FALSE,
                    115:        FALSE,
                    116:        FALSE,
                    117: };
1.1       cgd       118:
                    119: /* True iff the rpc reply is an nfs status ONLY! */
1.12      fvdl      120: static int nfsv2_repstat[NFS_NPROCS] = {
1.1       cgd       121:        FALSE,
                    122:        FALSE,
                    123:        FALSE,
                    124:        FALSE,
                    125:        FALSE,
                    126:        FALSE,
                    127:        FALSE,
                    128:        FALSE,
                    129:        FALSE,
                    130:        FALSE,
                    131:        TRUE,
                    132:        TRUE,
                    133:        TRUE,
                    134:        TRUE,
                    135:        FALSE,
                    136:        TRUE,
                    137:        FALSE,
                    138:        FALSE,
                    139: };
                    140:
                    141: /*
                    142:  * Initialize the server request cache list
                    143:  */
1.11      christos  144: void
1.1       cgd       145: nfsrv_initcache()
                    146: {
1.7       mycroft   147:
1.13      chs       148:        nfsrvhashtbl = hashinit(desirednfsrvcache, M_NFSD, M_WAITOK, &nfsrvhash);
1.9       mycroft   149:        TAILQ_INIT(&nfsrvlruhead);
1.1       cgd       150: }
                    151:
                    152: /*
                    153:  * Look for the request in the cache
                    154:  * If found then
                    155:  *    return action and optionally reply
                    156:  * else
                    157:  *    insert it in the cache
                    158:  *
                    159:  * The rules are as follows:
                    160:  * - if in progress, return DROP request
                    161:  * - if completed within DELAY of the current time, return DROP it
                    162:  * - if completed a longer time ago return REPLY if the reply was cached or
                    163:  *   return DOIT
                    164:  * Update/add new request at end of lru list
                    165:  */
1.11      christos  166: int
1.12      fvdl      167: nfsrv_getcache(nd, slp, repp)
1.16    ! augustss  168:        struct nfsrv_descript *nd;
1.12      fvdl      169:        struct nfssvc_sock *slp;
1.1       cgd       170:        struct mbuf **repp;
                    171: {
1.16    ! augustss  172:        struct nfsrvcache *rp;
1.1       cgd       173:        struct mbuf *mb;
1.7       mycroft   174:        struct sockaddr_in *saddr;
1.1       cgd       175:        caddr_t bpos;
                    176:        int ret;
                    177:
1.12      fvdl      178:        /*
                    179:         * Don't cache recent requests for reliable transport protocols.
                    180:         * (Maybe we should for the case of a reconnect, but..)
                    181:         */
                    182:        if (!nd->nd_nam2)
1.7       mycroft   183:                return (RC_DOIT);
1.1       cgd       184: loop:
1.9       mycroft   185:        for (rp = NFSRCHASH(nd->nd_retxid)->lh_first; rp != 0;
                    186:            rp = rp->rc_hash.le_next) {
1.7       mycroft   187:            if (nd->nd_retxid == rp->rc_xid && nd->nd_procnum == rp->rc_proc &&
1.12      fvdl      188:                netaddr_match(NETFAMILY(rp), &rp->rc_haddr, nd->nd_nam)) {
1.1       cgd       189:                        if ((rp->rc_flag & RC_LOCKED) != 0) {
                    190:                                rp->rc_flag |= RC_WANTED;
                    191:                                (void) tsleep((caddr_t)rp, PZERO-1, "nfsrc", 0);
                    192:                                goto loop;
                    193:                        }
                    194:                        rp->rc_flag |= RC_LOCKED;
1.7       mycroft   195:                        /* If not at end of LRU chain, move it there */
1.9       mycroft   196:                        if (rp->rc_lru.tqe_next) {
                    197:                                TAILQ_REMOVE(&nfsrvlruhead, rp, rc_lru);
                    198:                                TAILQ_INSERT_TAIL(&nfsrvlruhead, rp, rc_lru);
1.7       mycroft   199:                        }
1.1       cgd       200:                        if (rp->rc_state == RC_UNUSED)
                    201:                                panic("nfsrv cache");
1.7       mycroft   202:                        if (rp->rc_state == RC_INPROG) {
1.1       cgd       203:                                nfsstats.srvcache_inproghits++;
                    204:                                ret = RC_DROPIT;
                    205:                        } else if (rp->rc_flag & RC_REPSTATUS) {
1.7       mycroft   206:                                nfsstats.srvcache_nonidemdonehits++;
1.12      fvdl      207:                                nfs_rephead(0, nd, slp, rp->rc_status,
1.7       mycroft   208:                                   0, (u_quad_t *)0, repp, &mb, &bpos);
1.1       cgd       209:                                ret = RC_REPLY;
                    210:                        } else if (rp->rc_flag & RC_REPMBUF) {
1.7       mycroft   211:                                nfsstats.srvcache_nonidemdonehits++;
1.1       cgd       212:                                *repp = m_copym(rp->rc_reply, 0, M_COPYALL,
                    213:                                                M_WAIT);
                    214:                                ret = RC_REPLY;
                    215:                        } else {
1.7       mycroft   216:                                nfsstats.srvcache_idemdonehits++;
1.1       cgd       217:                                rp->rc_state = RC_INPROG;
                    218:                                ret = RC_DOIT;
                    219:                        }
                    220:                        rp->rc_flag &= ~RC_LOCKED;
                    221:                        if (rp->rc_flag & RC_WANTED) {
                    222:                                rp->rc_flag &= ~RC_WANTED;
                    223:                                wakeup((caddr_t)rp);
                    224:                        }
                    225:                        return (ret);
                    226:                }
                    227:        }
                    228:        nfsstats.srvcache_misses++;
1.7       mycroft   229:        if (numnfsrvcache < desirednfsrvcache) {
                    230:                rp = (struct nfsrvcache *)malloc((u_long)sizeof *rp,
                    231:                    M_NFSD, M_WAITOK);
1.15      perry     232:                memset((char *)rp, 0, sizeof *rp);
1.7       mycroft   233:                numnfsrvcache++;
                    234:                rp->rc_flag = RC_LOCKED;
                    235:        } else {
1.9       mycroft   236:                rp = nfsrvlruhead.tqh_first;
1.7       mycroft   237:                while ((rp->rc_flag & RC_LOCKED) != 0) {
                    238:                        rp->rc_flag |= RC_WANTED;
                    239:                        (void) tsleep((caddr_t)rp, PZERO-1, "nfsrc", 0);
1.9       mycroft   240:                        rp = nfsrvlruhead.tqh_first;
1.7       mycroft   241:                }
                    242:                rp->rc_flag |= RC_LOCKED;
1.9       mycroft   243:                LIST_REMOVE(rp, rc_hash);
                    244:                TAILQ_REMOVE(&nfsrvlruhead, rp, rc_lru);
1.7       mycroft   245:                if (rp->rc_flag & RC_REPMBUF)
                    246:                        m_freem(rp->rc_reply);
                    247:                if (rp->rc_flag & RC_NAM)
                    248:                        MFREE(rp->rc_nam, mb);
                    249:                rp->rc_flag &= (RC_LOCKED | RC_WANTED);
1.1       cgd       250:        }
1.9       mycroft   251:        TAILQ_INSERT_TAIL(&nfsrvlruhead, rp, rc_lru);
1.1       cgd       252:        rp->rc_state = RC_INPROG;
1.7       mycroft   253:        rp->rc_xid = nd->nd_retxid;
1.12      fvdl      254:        saddr = mtod(nd->nd_nam, struct sockaddr_in *);
1.7       mycroft   255:        switch (saddr->sin_family) {
                    256:        case AF_INET:
                    257:                rp->rc_flag |= RC_INETADDR;
                    258:                rp->rc_inetaddr = saddr->sin_addr.s_addr;
                    259:                break;
                    260:        case AF_ISO:
                    261:        default:
                    262:                rp->rc_flag |= RC_NAM;
1.12      fvdl      263:                rp->rc_nam = m_copym(nd->nd_nam, 0, M_COPYALL, M_WAIT);
1.7       mycroft   264:                break;
                    265:        };
                    266:        rp->rc_proc = nd->nd_procnum;
1.9       mycroft   267:        LIST_INSERT_HEAD(NFSRCHASH(nd->nd_retxid), rp, rc_hash);
1.7       mycroft   268:        rp->rc_flag &= ~RC_LOCKED;
                    269:        if (rp->rc_flag & RC_WANTED) {
                    270:                rp->rc_flag &= ~RC_WANTED;
                    271:                wakeup((caddr_t)rp);
                    272:        }
1.1       cgd       273:        return (RC_DOIT);
                    274: }
                    275:
                    276: /*
                    277:  * Update a request cache entry after the rpc has been done
                    278:  */
1.7       mycroft   279: void
1.12      fvdl      280: nfsrv_updatecache(nd, repvalid, repmbuf)
1.16    ! augustss  281:        struct nfsrv_descript *nd;
1.1       cgd       282:        int repvalid;
                    283:        struct mbuf *repmbuf;
                    284: {
1.16    ! augustss  285:        struct nfsrvcache *rp;
1.1       cgd       286:
1.12      fvdl      287:        if (!nd->nd_nam2)
1.7       mycroft   288:                return;
1.1       cgd       289: loop:
1.9       mycroft   290:        for (rp = NFSRCHASH(nd->nd_retxid)->lh_first; rp != 0;
                    291:            rp = rp->rc_hash.le_next) {
1.7       mycroft   292:            if (nd->nd_retxid == rp->rc_xid && nd->nd_procnum == rp->rc_proc &&
1.12      fvdl      293:                netaddr_match(NETFAMILY(rp), &rp->rc_haddr, nd->nd_nam)) {
1.1       cgd       294:                        if ((rp->rc_flag & RC_LOCKED) != 0) {
                    295:                                rp->rc_flag |= RC_WANTED;
                    296:                                (void) tsleep((caddr_t)rp, PZERO-1, "nfsrc", 0);
                    297:                                goto loop;
                    298:                        }
                    299:                        rp->rc_flag |= RC_LOCKED;
                    300:                        rp->rc_state = RC_DONE;
                    301:                        /*
                    302:                         * If we have a valid reply update status and save
                    303:                         * the reply for non-idempotent rpc's.
                    304:                         */
1.7       mycroft   305:                        if (repvalid && nonidempotent[nd->nd_procnum]) {
1.12      fvdl      306:                                if ((nd->nd_flag & ND_NFSV3) == 0 &&
                    307:                                  nfsv2_repstat[nfsv2_procid[nd->nd_procnum]]) {
1.7       mycroft   308:                                        rp->rc_status = nd->nd_repstat;
                    309:                                        rp->rc_flag |= RC_REPSTATUS;
                    310:                                } else {
                    311:                                        rp->rc_reply = m_copym(repmbuf,
                    312:                                                0, M_COPYALL, M_WAIT);
                    313:                                        rp->rc_flag |= RC_REPMBUF;
1.1       cgd       314:                                }
                    315:                        }
                    316:                        rp->rc_flag &= ~RC_LOCKED;
                    317:                        if (rp->rc_flag & RC_WANTED) {
                    318:                                rp->rc_flag &= ~RC_WANTED;
                    319:                                wakeup((caddr_t)rp);
                    320:                        }
                    321:                        return;
                    322:                }
                    323:        }
1.7       mycroft   324: }
                    325:
                    326: /*
                    327:  * Clean out the cache. Called when the last nfsd terminates.
                    328:  */
                    329: void
                    330: nfsrv_cleancache()
                    331: {
1.16    ! augustss  332:        struct nfsrvcache *rp, *nextrp;
1.7       mycroft   333:
1.9       mycroft   334:        for (rp = nfsrvlruhead.tqh_first; rp != 0; rp = nextrp) {
                    335:                nextrp = rp->rc_lru.tqe_next;
                    336:                LIST_REMOVE(rp, rc_hash);
                    337:                TAILQ_REMOVE(&nfsrvlruhead, rp, rc_lru);
1.7       mycroft   338:                free(rp, M_NFSD);
                    339:        }
                    340:        numnfsrvcache = 0;
1.1       cgd       341: }

CVSweb <webmaster@jp.NetBSD.org>