Annotation of Net2/kern/vfs_cache.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 1989 The Regents of the University of California.
                      3:  * All rights reserved.
                      4:  *
                      5:  * Redistribution and use in source and binary forms, with or without
                      6:  * modification, are permitted provided that the following conditions
                      7:  * are met:
                      8:  * 1. Redistributions of source code must retain the above copyright
                      9:  *    notice, this list of conditions and the following disclaimer.
                     10:  * 2. Redistributions in binary form must reproduce the above copyright
                     11:  *    notice, this list of conditions and the following disclaimer in the
                     12:  *    documentation and/or other materials provided with the distribution.
                     13:  * 3. All advertising materials mentioning features or use of this software
                     14:  *    must display the following acknowledgement:
                     15:  *     This product includes software developed by the University of
                     16:  *     California, Berkeley and its contributors.
                     17:  * 4. Neither the name of the University nor the names of its contributors
                     18:  *    may be used to endorse or promote products derived from this software
                     19:  *    without specific prior written permission.
                     20:  *
                     21:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     22:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     23:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     24:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     25:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     26:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     27:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     28:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     29:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     30:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     31:  * SUCH DAMAGE.
                     32:  *
                     33:  *     @(#)vfs_cache.c 7.8 (Berkeley) 2/28/91
                     34:  */
                     35: 
                     36: #include "param.h"
                     37: #include "systm.h"
                     38: #include "time.h"
                     39: #include "mount.h"
                     40: #include "vnode.h"
                     41: #include "namei.h"
                     42: #include "errno.h"
                     43: #include "malloc.h"
                     44: 
                     45: /*
                     46:  * Name caching works as follows:
                     47:  *
                     48:  * Names found by directory scans are retained in a cache
                     49:  * for future reference.  It is managed LRU, so frequently
                     50:  * used names will hang around.  Cache is indexed by hash value
                     51:  * obtained from (vp, name) where vp refers to the directory
                     52:  * containing name.
                     53:  *
                     54:  * For simplicity (and economy of storage), names longer than
                     55:  * a maximum length of NCHNAMLEN are not cached; they occur
                     56:  * infrequently in any case, and are almost never of interest.
                     57:  *
                     58:  * Upon reaching the last segment of a path, if the reference
                     59:  * is for DELETE, or NOCACHE is set (rewrite), and the
                     60:  * name is located in the cache, it will be dropped.
                     61:  */
                     62: 
                     63: /*
                     64:  * Structures associated with name cacheing.
                     65:  */
                     66: union nchash {
                     67:        union   nchash *nch_head[2];
                     68:        struct  namecache *nch_chain[2];
                     69: } *nchashtbl;
                     70: #define        nch_forw        nch_chain[0]
                     71: #define        nch_back        nch_chain[1]
                     72: 
                     73: u_long nchash;                         /* size of hash table - 1 */
                     74: long   numcache;                       /* number of cache entries allocated */
                     75: struct namecache *nchhead, **nchtail;  /* LRU chain pointers */
                     76: struct nchstats nchstats;              /* cache effectiveness statistics */
                     77: 
                     78: int doingcache = 1;                    /* 1 => enable the cache */
                     79: 
                     80: /*
                     81:  * Look for a the name in the cache. We don't do this
                     82:  * if the segment name is long, simply so the cache can avoid
                     83:  * holding long names (which would either waste space, or
                     84:  * add greatly to the complexity).
                     85:  *
                     86:  * Lookup is called with ni_dvp pointing to the directory to search,
                     87:  * ni_ptr pointing to the name of the entry being sought, ni_namelen
                     88:  * tells the length of the name, and ni_hash contains a hash of
                     89:  * the name. If the lookup succeeds, the vnode is returned in ni_vp
                     90:  * and a status of -1 is returned. If the lookup determines that
                     91:  * the name does not exist (negative cacheing), a status of ENOENT
                     92:  * is returned. If the lookup fails, a status of zero is returned.
                     93:  */
                     94: cache_lookup(ndp)
                     95:        register struct nameidata *ndp;
                     96: {
                     97:        register struct vnode *dvp;
                     98:        register struct namecache *ncp;
                     99:        union nchash *nhp;
                    100: 
                    101:        if (!doingcache)
                    102:                return (0);
                    103:        if (ndp->ni_namelen > NCHNAMLEN) {
                    104:                nchstats.ncs_long++;
                    105:                ndp->ni_makeentry = 0;
                    106:                return (0);
                    107:        }
                    108:        dvp = ndp->ni_dvp;
                    109:        nhp = &nchashtbl[ndp->ni_hash & nchash];
                    110:        for (ncp = nhp->nch_forw; ncp != (struct namecache *)nhp;
                    111:            ncp = ncp->nc_forw) {
                    112:                if (ncp->nc_dvp == dvp &&
                    113:                    ncp->nc_dvpid == dvp->v_id &&
                    114:                    ncp->nc_nlen == ndp->ni_namelen &&
                    115:                    !bcmp(ncp->nc_name, ndp->ni_ptr, (unsigned)ncp->nc_nlen))
                    116:                        break;
                    117:        }
                    118:        if (ncp == (struct namecache *)nhp) {
                    119:                nchstats.ncs_miss++;
                    120:                return (0);
                    121:        }
                    122:        if (!ndp->ni_makeentry) {
                    123:                nchstats.ncs_badhits++;
                    124:        } else if (ncp->nc_vp == NULL) {
                    125:                if ((ndp->ni_nameiop & OPMASK) != CREATE) {
                    126:                        nchstats.ncs_neghits++;
                    127:                        /*
                    128:                         * Move this slot to end of LRU chain,
                    129:                         * if not already there.
                    130:                         */
                    131:                        if (ncp->nc_nxt) {
                    132:                                /* remove from LRU chain */
                    133:                                *ncp->nc_prev = ncp->nc_nxt;
                    134:                                ncp->nc_nxt->nc_prev = ncp->nc_prev;
                    135:                                /* and replace at end of it */
                    136:                                ncp->nc_nxt = NULL;
                    137:                                ncp->nc_prev = nchtail;
                    138:                                *nchtail = ncp;
                    139:                                nchtail = &ncp->nc_nxt;
                    140:                        }
                    141:                        return (ENOENT);
                    142:                }
                    143:        } else if (ncp->nc_vpid != ncp->nc_vp->v_id) {
                    144:                nchstats.ncs_falsehits++;
                    145:        } else {
                    146:                nchstats.ncs_goodhits++;
                    147:                /*
                    148:                 * move this slot to end of LRU chain, if not already there
                    149:                 */
                    150:                if (ncp->nc_nxt) {
                    151:                        /* remove from LRU chain */
                    152:                        *ncp->nc_prev = ncp->nc_nxt;
                    153:                        ncp->nc_nxt->nc_prev = ncp->nc_prev;
                    154:                        /* and replace at end of it */
                    155:                        ncp->nc_nxt = NULL;
                    156:                        ncp->nc_prev = nchtail;
                    157:                        *nchtail = ncp;
                    158:                        nchtail = &ncp->nc_nxt;
                    159:                }
                    160:                ndp->ni_vp = ncp->nc_vp;
                    161:                return (-1);
                    162:        }
                    163: 
                    164:        /*
                    165:         * Last component and we are renaming or deleting,
                    166:         * the cache entry is invalid, or otherwise don't
                    167:         * want cache entry to exist.
                    168:         */
                    169:        /* remove from LRU chain */
                    170:        *ncp->nc_prev = ncp->nc_nxt;
                    171:        if (ncp->nc_nxt)
                    172:                ncp->nc_nxt->nc_prev = ncp->nc_prev;
                    173:        else
                    174:                nchtail = ncp->nc_prev;
                    175:        /* remove from hash chain */
                    176:        remque(ncp);
                    177:        /* insert at head of LRU list (first to grab) */
                    178:        ncp->nc_nxt = nchhead;
                    179:        ncp->nc_prev = &nchhead;
                    180:        nchhead->nc_prev = &ncp->nc_nxt;
                    181:        nchhead = ncp;
                    182:        /* and make a dummy hash chain */
                    183:        ncp->nc_forw = ncp;
                    184:        ncp->nc_back = ncp;
                    185:        return (0);
                    186: }
                    187: 
                    188: /*
                    189:  * Add an entry to the cache
                    190:  */
                    191: cache_enter(ndp)
                    192:        register struct nameidata *ndp;
                    193: {
                    194:        register struct namecache *ncp;
                    195:        union nchash *nhp;
                    196: 
                    197:        if (!doingcache)
                    198:                return;
                    199:        /*
                    200:         * Free the cache slot at head of lru chain.
                    201:         */
                    202:        if (numcache < desiredvnodes) {
                    203:                ncp = (struct namecache *)
                    204:                        malloc((u_long)sizeof *ncp, M_CACHE, M_WAITOK);
                    205:                bzero((char *)ncp, sizeof *ncp);
                    206:                numcache++;
                    207:        } else if (ncp = nchhead) {
                    208:                /* remove from lru chain */
                    209:                *ncp->nc_prev = ncp->nc_nxt;
                    210:                if (ncp->nc_nxt)
                    211:                        ncp->nc_nxt->nc_prev = ncp->nc_prev;
                    212:                else
                    213:                        nchtail = ncp->nc_prev;
                    214:                /* remove from old hash chain */
                    215:                remque(ncp);
                    216:        } else
                    217:                return;
                    218:        /* grab the vnode we just found */
                    219:        ncp->nc_vp = ndp->ni_vp;
                    220:        if (ndp->ni_vp)
                    221:                ncp->nc_vpid = ndp->ni_vp->v_id;
                    222:        else
                    223:                ncp->nc_vpid = 0;
                    224:        /* fill in cache info */
                    225:        ncp->nc_dvp = ndp->ni_dvp;
                    226:        ncp->nc_dvpid = ndp->ni_dvp->v_id;
                    227:        ncp->nc_nlen = ndp->ni_namelen;
                    228:        bcopy(ndp->ni_ptr, ncp->nc_name, (unsigned)ncp->nc_nlen);
                    229:        /* link at end of lru chain */
                    230:        ncp->nc_nxt = NULL;
                    231:        ncp->nc_prev = nchtail;
                    232:        *nchtail = ncp;
                    233:        nchtail = &ncp->nc_nxt;
                    234:        /* and insert on hash chain */
                    235:        nhp = &nchashtbl[ndp->ni_hash & nchash];
                    236:        insque(ncp, nhp);
                    237: }
                    238: 
                    239: /*
                    240:  * Name cache initialization, from vfs_init() when we are booting
                    241:  */
                    242: nchinit()
                    243: {
                    244:        register union nchash *nchp;
                    245:        long nchashsize;
                    246: 
                    247:        nchhead = 0;
                    248:        nchtail = &nchhead;
                    249:        nchashsize = roundup((desiredvnodes + 1) * sizeof *nchp / 2,
                    250:                NBPG * CLSIZE);
                    251:        nchashtbl = (union nchash *)malloc((u_long)nchashsize,
                    252:            M_CACHE, M_WAITOK);
                    253:        for (nchash = 1; nchash <= nchashsize / sizeof *nchp; nchash <<= 1)
                    254:                /* void */;
                    255:        nchash = (nchash >> 1) - 1;
                    256:        for (nchp = &nchashtbl[nchash]; nchp >= nchashtbl; nchp--) {
                    257:                nchp->nch_head[0] = nchp;
                    258:                nchp->nch_head[1] = nchp;
                    259:        }
                    260: }
                    261: 
                    262: /*
                    263:  * Cache flush, a particular vnode; called when a vnode is renamed to
                    264:  * hide entries that would now be invalid
                    265:  */
                    266: cache_purge(vp)
                    267:        struct vnode *vp;
                    268: {
                    269:        union nchash *nhp;
                    270:        struct namecache *ncp;
                    271: 
                    272:        vp->v_id = ++nextvnodeid;
                    273:        if (nextvnodeid != 0)
                    274:                return;
                    275:        for (nhp = &nchashtbl[nchash]; nhp >= nchashtbl; nhp--) {
                    276:                for (ncp = nhp->nch_forw; ncp != (struct namecache *)nhp;
                    277:                    ncp = ncp->nc_forw) {
                    278:                        ncp->nc_vpid = 0;
                    279:                        ncp->nc_dvpid = 0;
                    280:                }
                    281:        }
                    282:        vp->v_id = ++nextvnodeid;
                    283: }
                    284: 
                    285: /*
                    286:  * Cache flush, a whole filesystem; called when filesys is umounted to
                    287:  * remove entries that would now be invalid
                    288:  *
                    289:  * The line "nxtcp = nchhead" near the end is to avoid potential problems
                    290:  * if the cache lru chain is modified while we are dumping the
                    291:  * inode.  This makes the algorithm O(n^2), but do you think I care?
                    292:  */
                    293: cache_purgevfs(mp)
                    294:        struct mount *mp;
                    295: {
                    296:        register struct namecache *ncp, *nxtcp;
                    297: 
                    298:        for (ncp = nchhead; ncp; ncp = nxtcp) {
                    299:                nxtcp = ncp->nc_nxt;
                    300:                if (ncp->nc_dvp == NULL || ncp->nc_dvp->v_mount != mp)
                    301:                        continue;
                    302:                /* free the resources we had */
                    303:                ncp->nc_vp = NULL;
                    304:                ncp->nc_dvp = NULL;
                    305:                remque(ncp);            /* remove entry from its hash chain */
                    306:                ncp->nc_forw = ncp;     /* and make a dummy one */
                    307:                ncp->nc_back = ncp;
                    308:                /* delete this entry from LRU chain */
                    309:                *ncp->nc_prev = nxtcp;
                    310:                if (nxtcp)
                    311:                        nxtcp->nc_prev = ncp->nc_prev;
                    312:                else
                    313:                        nchtail = ncp->nc_prev;
                    314:                /* cause rescan of list, it may have altered */
                    315:                nxtcp = nchhead;
                    316:                /* put the now-free entry at head of LRU */
                    317:                ncp->nc_nxt = nxtcp;
                    318:                ncp->nc_prev = &nchhead;
                    319:                nxtcp->nc_prev = &ncp->nc_nxt;
                    320:                nchhead = ncp;
                    321:        }
                    322: }

unix.superglobalmegacorp.com

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