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

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:  *
1.1.1.2 ! root       33:  *     from: @(#)vfs_cache.c   7.8 (Berkeley) 2/28/91
        !            34:  *     vfs_cache.c,v 1.2 1993/05/20 02:55:33 cgd Exp
1.1       root       35:  */
                     36: 
                     37: #include "param.h"
                     38: #include "systm.h"
                     39: #include "time.h"
                     40: #include "mount.h"
                     41: #include "vnode.h"
                     42: #include "namei.h"
                     43: #include "errno.h"
                     44: #include "malloc.h"
                     45: 
                     46: /*
                     47:  * Name caching works as follows:
                     48:  *
                     49:  * Names found by directory scans are retained in a cache
                     50:  * for future reference.  It is managed LRU, so frequently
                     51:  * used names will hang around.  Cache is indexed by hash value
                     52:  * obtained from (vp, name) where vp refers to the directory
                     53:  * containing name.
                     54:  *
                     55:  * For simplicity (and economy of storage), names longer than
                     56:  * a maximum length of NCHNAMLEN are not cached; they occur
                     57:  * infrequently in any case, and are almost never of interest.
                     58:  *
                     59:  * Upon reaching the last segment of a path, if the reference
                     60:  * is for DELETE, or NOCACHE is set (rewrite), and the
                     61:  * name is located in the cache, it will be dropped.
                     62:  */
                     63: 
                     64: /*
                     65:  * Structures associated with name cacheing.
                     66:  */
                     67: union nchash {
                     68:        union   nchash *nch_head[2];
                     69:        struct  namecache *nch_chain[2];
                     70: } *nchashtbl;
                     71: #define        nch_forw        nch_chain[0]
                     72: #define        nch_back        nch_chain[1]
                     73: 
                     74: u_long nchash;                         /* size of hash table - 1 */
                     75: long   numcache;                       /* number of cache entries allocated */
                     76: struct namecache *nchhead, **nchtail;  /* LRU chain pointers */
                     77: struct nchstats nchstats;              /* cache effectiveness statistics */
                     78: 
                     79: int doingcache = 1;                    /* 1 => enable the cache */
                     80: 
                     81: /*
                     82:  * Look for a the name in the cache. We don't do this
                     83:  * if the segment name is long, simply so the cache can avoid
                     84:  * holding long names (which would either waste space, or
                     85:  * add greatly to the complexity).
                     86:  *
                     87:  * Lookup is called with ni_dvp pointing to the directory to search,
                     88:  * ni_ptr pointing to the name of the entry being sought, ni_namelen
                     89:  * tells the length of the name, and ni_hash contains a hash of
                     90:  * the name. If the lookup succeeds, the vnode is returned in ni_vp
                     91:  * and a status of -1 is returned. If the lookup determines that
                     92:  * the name does not exist (negative cacheing), a status of ENOENT
                     93:  * is returned. If the lookup fails, a status of zero is returned.
                     94:  */
                     95: cache_lookup(ndp)
                     96:        register struct nameidata *ndp;
                     97: {
                     98:        register struct vnode *dvp;
                     99:        register struct namecache *ncp;
                    100:        union nchash *nhp;
                    101: 
                    102:        if (!doingcache)
                    103:                return (0);
                    104:        if (ndp->ni_namelen > NCHNAMLEN) {
                    105:                nchstats.ncs_long++;
                    106:                ndp->ni_makeentry = 0;
                    107:                return (0);
                    108:        }
                    109:        dvp = ndp->ni_dvp;
                    110:        nhp = &nchashtbl[ndp->ni_hash & nchash];
                    111:        for (ncp = nhp->nch_forw; ncp != (struct namecache *)nhp;
                    112:            ncp = ncp->nc_forw) {
                    113:                if (ncp->nc_dvp == dvp &&
                    114:                    ncp->nc_dvpid == dvp->v_id &&
                    115:                    ncp->nc_nlen == ndp->ni_namelen &&
                    116:                    !bcmp(ncp->nc_name, ndp->ni_ptr, (unsigned)ncp->nc_nlen))
                    117:                        break;
                    118:        }
                    119:        if (ncp == (struct namecache *)nhp) {
                    120:                nchstats.ncs_miss++;
                    121:                return (0);
                    122:        }
                    123:        if (!ndp->ni_makeentry) {
                    124:                nchstats.ncs_badhits++;
                    125:        } else if (ncp->nc_vp == NULL) {
                    126:                if ((ndp->ni_nameiop & OPMASK) != CREATE) {
                    127:                        nchstats.ncs_neghits++;
                    128:                        /*
                    129:                         * Move this slot to end of LRU chain,
                    130:                         * if not already there.
                    131:                         */
                    132:                        if (ncp->nc_nxt) {
                    133:                                /* remove from LRU chain */
                    134:                                *ncp->nc_prev = ncp->nc_nxt;
                    135:                                ncp->nc_nxt->nc_prev = ncp->nc_prev;
                    136:                                /* and replace at end of it */
                    137:                                ncp->nc_nxt = NULL;
                    138:                                ncp->nc_prev = nchtail;
                    139:                                *nchtail = ncp;
                    140:                                nchtail = &ncp->nc_nxt;
                    141:                        }
                    142:                        return (ENOENT);
                    143:                }
                    144:        } else if (ncp->nc_vpid != ncp->nc_vp->v_id) {
                    145:                nchstats.ncs_falsehits++;
                    146:        } else {
                    147:                nchstats.ncs_goodhits++;
                    148:                /*
                    149:                 * move this slot to end of LRU chain, if not already there
                    150:                 */
                    151:                if (ncp->nc_nxt) {
                    152:                        /* remove from LRU chain */
                    153:                        *ncp->nc_prev = ncp->nc_nxt;
                    154:                        ncp->nc_nxt->nc_prev = ncp->nc_prev;
                    155:                        /* and replace at end of it */
                    156:                        ncp->nc_nxt = NULL;
                    157:                        ncp->nc_prev = nchtail;
                    158:                        *nchtail = ncp;
                    159:                        nchtail = &ncp->nc_nxt;
                    160:                }
                    161:                ndp->ni_vp = ncp->nc_vp;
                    162:                return (-1);
                    163:        }
                    164: 
                    165:        /*
                    166:         * Last component and we are renaming or deleting,
                    167:         * the cache entry is invalid, or otherwise don't
                    168:         * want cache entry to exist.
                    169:         */
                    170:        /* remove from LRU chain */
                    171:        *ncp->nc_prev = ncp->nc_nxt;
                    172:        if (ncp->nc_nxt)
                    173:                ncp->nc_nxt->nc_prev = ncp->nc_prev;
                    174:        else
                    175:                nchtail = ncp->nc_prev;
                    176:        /* remove from hash chain */
                    177:        remque(ncp);
                    178:        /* insert at head of LRU list (first to grab) */
                    179:        ncp->nc_nxt = nchhead;
                    180:        ncp->nc_prev = &nchhead;
                    181:        nchhead->nc_prev = &ncp->nc_nxt;
                    182:        nchhead = ncp;
                    183:        /* and make a dummy hash chain */
                    184:        ncp->nc_forw = ncp;
                    185:        ncp->nc_back = ncp;
                    186:        return (0);
                    187: }
                    188: 
                    189: /*
                    190:  * Add an entry to the cache
                    191:  */
                    192: cache_enter(ndp)
                    193:        register struct nameidata *ndp;
                    194: {
                    195:        register struct namecache *ncp;
                    196:        union nchash *nhp;
                    197: 
                    198:        if (!doingcache)
                    199:                return;
                    200:        /*
                    201:         * Free the cache slot at head of lru chain.
                    202:         */
                    203:        if (numcache < desiredvnodes) {
                    204:                ncp = (struct namecache *)
                    205:                        malloc((u_long)sizeof *ncp, M_CACHE, M_WAITOK);
                    206:                bzero((char *)ncp, sizeof *ncp);
                    207:                numcache++;
                    208:        } else if (ncp = nchhead) {
                    209:                /* remove from lru chain */
                    210:                *ncp->nc_prev = ncp->nc_nxt;
                    211:                if (ncp->nc_nxt)
                    212:                        ncp->nc_nxt->nc_prev = ncp->nc_prev;
                    213:                else
                    214:                        nchtail = ncp->nc_prev;
                    215:                /* remove from old hash chain */
                    216:                remque(ncp);
                    217:        } else
                    218:                return;
                    219:        /* grab the vnode we just found */
                    220:        ncp->nc_vp = ndp->ni_vp;
                    221:        if (ndp->ni_vp)
                    222:                ncp->nc_vpid = ndp->ni_vp->v_id;
                    223:        else
                    224:                ncp->nc_vpid = 0;
                    225:        /* fill in cache info */
                    226:        ncp->nc_dvp = ndp->ni_dvp;
                    227:        ncp->nc_dvpid = ndp->ni_dvp->v_id;
                    228:        ncp->nc_nlen = ndp->ni_namelen;
                    229:        bcopy(ndp->ni_ptr, ncp->nc_name, (unsigned)ncp->nc_nlen);
                    230:        /* link at end of lru chain */
                    231:        ncp->nc_nxt = NULL;
                    232:        ncp->nc_prev = nchtail;
                    233:        *nchtail = ncp;
                    234:        nchtail = &ncp->nc_nxt;
                    235:        /* and insert on hash chain */
                    236:        nhp = &nchashtbl[ndp->ni_hash & nchash];
                    237:        insque(ncp, nhp);
                    238: }
                    239: 
                    240: /*
                    241:  * Name cache initialization, from vfs_init() when we are booting
                    242:  */
                    243: nchinit()
                    244: {
                    245:        register union nchash *nchp;
                    246:        long nchashsize;
                    247: 
                    248:        nchhead = 0;
                    249:        nchtail = &nchhead;
                    250:        nchashsize = roundup((desiredvnodes + 1) * sizeof *nchp / 2,
                    251:                NBPG * CLSIZE);
                    252:        nchashtbl = (union nchash *)malloc((u_long)nchashsize,
                    253:            M_CACHE, M_WAITOK);
                    254:        for (nchash = 1; nchash <= nchashsize / sizeof *nchp; nchash <<= 1)
                    255:                /* void */;
                    256:        nchash = (nchash >> 1) - 1;
                    257:        for (nchp = &nchashtbl[nchash]; nchp >= nchashtbl; nchp--) {
                    258:                nchp->nch_head[0] = nchp;
                    259:                nchp->nch_head[1] = nchp;
                    260:        }
                    261: }
                    262: 
                    263: /*
                    264:  * Cache flush, a particular vnode; called when a vnode is renamed to
                    265:  * hide entries that would now be invalid
                    266:  */
                    267: cache_purge(vp)
                    268:        struct vnode *vp;
                    269: {
                    270:        union nchash *nhp;
                    271:        struct namecache *ncp;
                    272: 
                    273:        vp->v_id = ++nextvnodeid;
                    274:        if (nextvnodeid != 0)
                    275:                return;
                    276:        for (nhp = &nchashtbl[nchash]; nhp >= nchashtbl; nhp--) {
                    277:                for (ncp = nhp->nch_forw; ncp != (struct namecache *)nhp;
                    278:                    ncp = ncp->nc_forw) {
                    279:                        ncp->nc_vpid = 0;
                    280:                        ncp->nc_dvpid = 0;
                    281:                }
                    282:        }
                    283:        vp->v_id = ++nextvnodeid;
                    284: }
                    285: 
                    286: /*
                    287:  * Cache flush, a whole filesystem; called when filesys is umounted to
                    288:  * remove entries that would now be invalid
                    289:  *
                    290:  * The line "nxtcp = nchhead" near the end is to avoid potential problems
                    291:  * if the cache lru chain is modified while we are dumping the
                    292:  * inode.  This makes the algorithm O(n^2), but do you think I care?
                    293:  */
                    294: cache_purgevfs(mp)
                    295:        struct mount *mp;
                    296: {
                    297:        register struct namecache *ncp, *nxtcp;
                    298: 
                    299:        for (ncp = nchhead; ncp; ncp = nxtcp) {
                    300:                nxtcp = ncp->nc_nxt;
                    301:                if (ncp->nc_dvp == NULL || ncp->nc_dvp->v_mount != mp)
                    302:                        continue;
                    303:                /* free the resources we had */
                    304:                ncp->nc_vp = NULL;
                    305:                ncp->nc_dvp = NULL;
                    306:                remque(ncp);            /* remove entry from its hash chain */
                    307:                ncp->nc_forw = ncp;     /* and make a dummy one */
                    308:                ncp->nc_back = ncp;
                    309:                /* delete this entry from LRU chain */
                    310:                *ncp->nc_prev = nxtcp;
                    311:                if (nxtcp)
                    312:                        nxtcp->nc_prev = ncp->nc_prev;
                    313:                else
                    314:                        nchtail = ncp->nc_prev;
                    315:                /* cause rescan of list, it may have altered */
                    316:                nxtcp = nchhead;
                    317:                /* put the now-free entry at head of LRU */
                    318:                ncp->nc_nxt = nxtcp;
                    319:                ncp->nc_prev = &nchhead;
                    320:                nxtcp->nc_prev = &ncp->nc_nxt;
                    321:                nchhead = ncp;
                    322:        }
                    323: }

unix.superglobalmegacorp.com

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