[BACK]Return to nfs_srvcache.c CVS log [TXT][DIR] Up to [local] / sys / nfs

Annotation of sys/nfs/nfs_srvcache.c, Revision 1.1.1.1

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

CVSweb