Annotation of 43BSDReno/sys/kern/vfs_cache.c, revision 1.1

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

unix.superglobalmegacorp.com

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