[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.20

1.20    ! matt        1: /*     $NetBSD: nfs_srvcache.c,v 1.19 2001/11/10 10:59:10 lukem 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.19      lukem      46:
                     47: #include <sys/cdefs.h>
1.20    ! matt       48: __KERNEL_RCSID(0, "$NetBSD: nfs_srvcache.c,v 1.19 2001/11/10 10:59:10 lukem Exp $");
1.19      lukem      49:
1.14      jonathan   50: #include "opt_iso.h"
                     51:
1.6       mycroft    52: #include <sys/param.h>
                     53: #include <sys/vnode.h>
                     54: #include <sys/mount.h>
                     55: #include <sys/kernel.h>
                     56: #include <sys/systm.h>
1.7       mycroft    57: #include <sys/proc.h>
1.6       mycroft    58: #include <sys/mbuf.h>
1.7       mycroft    59: #include <sys/malloc.h>
1.6       mycroft    60: #include <sys/socket.h>
                     61: #include <sys/socketvar.h>
1.1       cgd        62:
1.6       mycroft    63: #include <netinet/in.h>
1.7       mycroft    64: #ifdef ISO
                     65: #include <netiso/iso.h>
                     66: #endif
1.6       mycroft    67: #include <nfs/nfsm_subs.h>
1.7       mycroft    68: #include <nfs/rpcv2.h>
1.12      fvdl       69: #include <nfs/nfsproto.h>
1.7       mycroft    70: #include <nfs/nfs.h>
1.6       mycroft    71: #include <nfs/nfsrvcache.h>
1.7       mycroft    72: #include <nfs/nqnfs.h>
1.11      christos   73: #include <nfs/nfs_var.h>
1.2       glass      74:
1.12      fvdl       75: extern struct nfsstats nfsstats;
1.20    ! matt       76: extern const int nfsv2_procid[NFS_NPROCS];
1.7       mycroft    77: long numnfsrvcache, desirednfsrvcache = NFSRVCACHESIZ;
1.1       cgd        78:
1.9       mycroft    79: #define        NFSRCHASH(xid) \
                     80:        (&nfsrvhashtbl[((xid) + ((xid) >> 24)) & nfsrvhash])
                     81: LIST_HEAD(nfsrvhash, nfsrvcache) *nfsrvhashtbl;
                     82: TAILQ_HEAD(nfsrvlru, nfsrvcache) nfsrvlruhead;
                     83: u_long nfsrvhash;
1.1       cgd        84:
                     85: #define TRUE   1
                     86: #define        FALSE   0
                     87:
1.7       mycroft    88: #define        NETFAMILY(rp) \
                     89:                (((rp)->rc_flag & RC_INETADDR) ? AF_INET : AF_ISO)
                     90:
                     91: /*
                     92:  * Static array that defines which nfs rpc's are nonidempotent
                     93:  */
1.18      jdolecek   94: const int nonidempotent[NFS_NPROCS] = {
1.7       mycroft    95:        FALSE,
                     96:        FALSE,
                     97:        TRUE,
                     98:        FALSE,
                     99:        FALSE,
                    100:        FALSE,
                    101:        FALSE,
                    102:        TRUE,
                    103:        TRUE,
                    104:        TRUE,
                    105:        TRUE,
                    106:        TRUE,
                    107:        TRUE,
                    108:        TRUE,
                    109:        TRUE,
1.12      fvdl      110:        TRUE,
                    111:        FALSE,
                    112:        FALSE,
                    113:        FALSE,
1.7       mycroft   114:        FALSE,
                    115:        FALSE,
                    116:        FALSE,
                    117:        FALSE,
                    118:        FALSE,
                    119:        FALSE,
                    120:        FALSE,
                    121: };
1.1       cgd       122:
                    123: /* True iff the rpc reply is an nfs status ONLY! */
1.18      jdolecek  124: static const int nfsv2_repstat[NFS_NPROCS] = {
1.1       cgd       125:        FALSE,
                    126:        FALSE,
                    127:        FALSE,
                    128:        FALSE,
                    129:        FALSE,
                    130:        FALSE,
                    131:        FALSE,
                    132:        FALSE,
                    133:        FALSE,
                    134:        FALSE,
                    135:        TRUE,
                    136:        TRUE,
                    137:        TRUE,
                    138:        TRUE,
                    139:        FALSE,
                    140:        TRUE,
                    141:        FALSE,
                    142:        FALSE,
                    143: };
                    144:
                    145: /*
                    146:  * Initialize the server request cache list
                    147:  */
1.11      christos  148: void
1.1       cgd       149: nfsrv_initcache()
                    150: {
1.7       mycroft   151:
1.17      ad        152:        nfsrvhashtbl = hashinit(desirednfsrvcache, HASH_LIST, M_NFSD,
                    153:            M_WAITOK, &nfsrvhash);
1.9       mycroft   154:        TAILQ_INIT(&nfsrvlruhead);
1.1       cgd       155: }
                    156:
                    157: /*
                    158:  * Look for the request in the cache
                    159:  * If found then
                    160:  *    return action and optionally reply
                    161:  * else
                    162:  *    insert it in the cache
                    163:  *
                    164:  * The rules are as follows:
                    165:  * - if in progress, return DROP request
                    166:  * - if completed within DELAY of the current time, return DROP it
                    167:  * - if completed a longer time ago return REPLY if the reply was cached or
                    168:  *   return DOIT
                    169:  * Update/add new request at end of lru list
                    170:  */
1.11      christos  171: int
1.12      fvdl      172: nfsrv_getcache(nd, slp, repp)
1.16      augustss  173:        struct nfsrv_descript *nd;
1.12      fvdl      174:        struct nfssvc_sock *slp;
1.1       cgd       175:        struct mbuf **repp;
                    176: {
1.16      augustss  177:        struct nfsrvcache *rp;
1.1       cgd       178:        struct mbuf *mb;
1.7       mycroft   179:        struct sockaddr_in *saddr;
1.1       cgd       180:        caddr_t bpos;
                    181:        int ret;
                    182:
1.12      fvdl      183:        /*
                    184:         * Don't cache recent requests for reliable transport protocols.
                    185:         * (Maybe we should for the case of a reconnect, but..)
                    186:         */
                    187:        if (!nd->nd_nam2)
1.7       mycroft   188:                return (RC_DOIT);
1.1       cgd       189: loop:
1.9       mycroft   190:        for (rp = NFSRCHASH(nd->nd_retxid)->lh_first; rp != 0;
                    191:            rp = rp->rc_hash.le_next) {
1.7       mycroft   192:            if (nd->nd_retxid == rp->rc_xid && nd->nd_procnum == rp->rc_proc &&
1.12      fvdl      193:                netaddr_match(NETFAMILY(rp), &rp->rc_haddr, nd->nd_nam)) {
1.1       cgd       194:                        if ((rp->rc_flag & RC_LOCKED) != 0) {
                    195:                                rp->rc_flag |= RC_WANTED;
                    196:                                (void) tsleep((caddr_t)rp, PZERO-1, "nfsrc", 0);
                    197:                                goto loop;
                    198:                        }
                    199:                        rp->rc_flag |= RC_LOCKED;
1.7       mycroft   200:                        /* If not at end of LRU chain, move it there */
1.9       mycroft   201:                        if (rp->rc_lru.tqe_next) {
                    202:                                TAILQ_REMOVE(&nfsrvlruhead, rp, rc_lru);
                    203:                                TAILQ_INSERT_TAIL(&nfsrvlruhead, rp, rc_lru);
1.7       mycroft   204:                        }
1.1       cgd       205:                        if (rp->rc_state == RC_UNUSED)
                    206:                                panic("nfsrv cache");
1.7       mycroft   207:                        if (rp->rc_state == RC_INPROG) {
1.1       cgd       208:                                nfsstats.srvcache_inproghits++;
                    209:                                ret = RC_DROPIT;
                    210:                        } else if (rp->rc_flag & RC_REPSTATUS) {
1.7       mycroft   211:                                nfsstats.srvcache_nonidemdonehits++;
1.12      fvdl      212:                                nfs_rephead(0, nd, slp, rp->rc_status,
1.7       mycroft   213:                                   0, (u_quad_t *)0, repp, &mb, &bpos);
1.1       cgd       214:                                ret = RC_REPLY;
                    215:                        } else if (rp->rc_flag & RC_REPMBUF) {
1.7       mycroft   216:                                nfsstats.srvcache_nonidemdonehits++;
1.1       cgd       217:                                *repp = m_copym(rp->rc_reply, 0, M_COPYALL,
                    218:                                                M_WAIT);
                    219:                                ret = RC_REPLY;
                    220:                        } else {
1.7       mycroft   221:                                nfsstats.srvcache_idemdonehits++;
1.1       cgd       222:                                rp->rc_state = RC_INPROG;
                    223:                                ret = RC_DOIT;
                    224:                        }
                    225:                        rp->rc_flag &= ~RC_LOCKED;
                    226:                        if (rp->rc_flag & RC_WANTED) {
                    227:                                rp->rc_flag &= ~RC_WANTED;
                    228:                                wakeup((caddr_t)rp);
                    229:                        }
                    230:                        return (ret);
                    231:                }
                    232:        }
                    233:        nfsstats.srvcache_misses++;
1.7       mycroft   234:        if (numnfsrvcache < desirednfsrvcache) {
                    235:                rp = (struct nfsrvcache *)malloc((u_long)sizeof *rp,
                    236:                    M_NFSD, M_WAITOK);
1.15      perry     237:                memset((char *)rp, 0, sizeof *rp);
1.7       mycroft   238:                numnfsrvcache++;
                    239:                rp->rc_flag = RC_LOCKED;
                    240:        } else {
1.9       mycroft   241:                rp = nfsrvlruhead.tqh_first;
1.7       mycroft   242:                while ((rp->rc_flag & RC_LOCKED) != 0) {
                    243:                        rp->rc_flag |= RC_WANTED;
                    244:                        (void) tsleep((caddr_t)rp, PZERO-1, "nfsrc", 0);
1.9       mycroft   245:                        rp = nfsrvlruhead.tqh_first;
1.7       mycroft   246:                }
                    247:                rp->rc_flag |= RC_LOCKED;
1.9       mycroft   248:                LIST_REMOVE(rp, rc_hash);
                    249:                TAILQ_REMOVE(&nfsrvlruhead, rp, rc_lru);
1.7       mycroft   250:                if (rp->rc_flag & RC_REPMBUF)
                    251:                        m_freem(rp->rc_reply);
                    252:                if (rp->rc_flag & RC_NAM)
                    253:                        MFREE(rp->rc_nam, mb);
                    254:                rp->rc_flag &= (RC_LOCKED | RC_WANTED);
1.1       cgd       255:        }
1.9       mycroft   256:        TAILQ_INSERT_TAIL(&nfsrvlruhead, rp, rc_lru);
1.1       cgd       257:        rp->rc_state = RC_INPROG;
1.7       mycroft   258:        rp->rc_xid = nd->nd_retxid;
1.12      fvdl      259:        saddr = mtod(nd->nd_nam, struct sockaddr_in *);
1.7       mycroft   260:        switch (saddr->sin_family) {
                    261:        case AF_INET:
                    262:                rp->rc_flag |= RC_INETADDR;
                    263:                rp->rc_inetaddr = saddr->sin_addr.s_addr;
                    264:                break;
                    265:        case AF_ISO:
                    266:        default:
                    267:                rp->rc_flag |= RC_NAM;
1.12      fvdl      268:                rp->rc_nam = m_copym(nd->nd_nam, 0, M_COPYALL, M_WAIT);
1.7       mycroft   269:                break;
                    270:        };
                    271:        rp->rc_proc = nd->nd_procnum;
1.9       mycroft   272:        LIST_INSERT_HEAD(NFSRCHASH(nd->nd_retxid), rp, rc_hash);
1.7       mycroft   273:        rp->rc_flag &= ~RC_LOCKED;
                    274:        if (rp->rc_flag & RC_WANTED) {
                    275:                rp->rc_flag &= ~RC_WANTED;
                    276:                wakeup((caddr_t)rp);
                    277:        }
1.1       cgd       278:        return (RC_DOIT);
                    279: }
                    280:
                    281: /*
                    282:  * Update a request cache entry after the rpc has been done
                    283:  */
1.7       mycroft   284: void
1.12      fvdl      285: nfsrv_updatecache(nd, repvalid, repmbuf)
1.16      augustss  286:        struct nfsrv_descript *nd;
1.1       cgd       287:        int repvalid;
                    288:        struct mbuf *repmbuf;
                    289: {
1.16      augustss  290:        struct nfsrvcache *rp;
1.1       cgd       291:
1.12      fvdl      292:        if (!nd->nd_nam2)
1.7       mycroft   293:                return;
1.1       cgd       294: loop:
1.9       mycroft   295:        for (rp = NFSRCHASH(nd->nd_retxid)->lh_first; rp != 0;
                    296:            rp = rp->rc_hash.le_next) {
1.7       mycroft   297:            if (nd->nd_retxid == rp->rc_xid && nd->nd_procnum == rp->rc_proc &&
1.12      fvdl      298:                netaddr_match(NETFAMILY(rp), &rp->rc_haddr, nd->nd_nam)) {
1.1       cgd       299:                        if ((rp->rc_flag & RC_LOCKED) != 0) {
                    300:                                rp->rc_flag |= RC_WANTED;
                    301:                                (void) tsleep((caddr_t)rp, PZERO-1, "nfsrc", 0);
                    302:                                goto loop;
                    303:                        }
                    304:                        rp->rc_flag |= RC_LOCKED;
                    305:                        rp->rc_state = RC_DONE;
                    306:                        /*
                    307:                         * If we have a valid reply update status and save
                    308:                         * the reply for non-idempotent rpc's.
                    309:                         */
1.7       mycroft   310:                        if (repvalid && nonidempotent[nd->nd_procnum]) {
1.12      fvdl      311:                                if ((nd->nd_flag & ND_NFSV3) == 0 &&
                    312:                                  nfsv2_repstat[nfsv2_procid[nd->nd_procnum]]) {
1.7       mycroft   313:                                        rp->rc_status = nd->nd_repstat;
                    314:                                        rp->rc_flag |= RC_REPSTATUS;
                    315:                                } else {
                    316:                                        rp->rc_reply = m_copym(repmbuf,
                    317:                                                0, M_COPYALL, M_WAIT);
                    318:                                        rp->rc_flag |= RC_REPMBUF;
1.1       cgd       319:                                }
                    320:                        }
                    321:                        rp->rc_flag &= ~RC_LOCKED;
                    322:                        if (rp->rc_flag & RC_WANTED) {
                    323:                                rp->rc_flag &= ~RC_WANTED;
                    324:                                wakeup((caddr_t)rp);
                    325:                        }
                    326:                        return;
                    327:                }
                    328:        }
1.7       mycroft   329: }
                    330:
                    331: /*
                    332:  * Clean out the cache. Called when the last nfsd terminates.
                    333:  */
                    334: void
                    335: nfsrv_cleancache()
                    336: {
1.16      augustss  337:        struct nfsrvcache *rp, *nextrp;
1.7       mycroft   338:
1.9       mycroft   339:        for (rp = nfsrvlruhead.tqh_first; rp != 0; rp = nextrp) {
                    340:                nextrp = rp->rc_lru.tqe_next;
                    341:                LIST_REMOVE(rp, rc_hash);
                    342:                TAILQ_REMOVE(&nfsrvlruhead, rp, rc_lru);
1.7       mycroft   343:                free(rp, M_NFSD);
                    344:        }
                    345:        numnfsrvcache = 0;
1.1       cgd       346: }

CVSweb <webmaster@jp.NetBSD.org>