add support for kernel profiling; add sysctl_struct; eliminate trailing blanks
[unix-history] / usr / src / sys / kern / vfs_cache.c
index bbba599..1e989e9 100644 (file)
@@ -2,27 +2,19 @@
  * Copyright (c) 1989 The Regents of the University of California.
  * All rights reserved.
  *
  * Copyright (c) 1989 The Regents of the University of California.
  * All rights reserved.
  *
- * Redistribution and use in source and binary forms are permitted
- * provided that the above copyright notice and this paragraph are
- * duplicated in all such forms and that any documentation,
- * advertising materials, and other materials related to such
- * distribution and use acknowledge that the software was developed
- * by the University of California, Berkeley.  The name of the
- * University may not be used to endorse or promote products derived
- * from this software without specific prior written permission.
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * %sccs.include.redist.c%
  *
  *
- *     @(#)vfs_cache.c 7.4 (Berkeley) %G%
+ *     @(#)vfs_cache.c 7.16 (Berkeley) %G%
  */
 
  */
 
-#include "param.h"
-#include "systm.h"
-#include "time.h"
-#include "vnode.h"
-#include "namei.h"
-#include "errno.h"
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/time.h>
+#include <sys/mount.h>
+#include <sys/vnode.h>
+#include <sys/namei.h>
+#include <sys/errno.h>
+#include <sys/malloc.h>
 
 /*
  * Name caching works as follows:
 
 /*
  * Name caching works as follows:
 /*
  * Structures associated with name cacheing.
  */
 /*
  * Structures associated with name cacheing.
  */
-#define        NCHHASH         128     /* size of hash table */
-
-#if    ((NCHHASH)&((NCHHASH)-1)) != 0
-#define        NHASH(vp, h)    ((((unsigned)(h) >> 6) + (h)) % (NCHHASH))
-#else
-#define        NHASH(vp, h)    ((((unsigned)(h) >> 6) + (h)) & ((NCHHASH)-1))
-#endif
-
-union nchash {
-       union   nchash *nch_head[2];
-       struct  namecache *nch_chain[2];
-} nchash[NCHHASH];
-#define        nch_forw        nch_chain[0]
-#define        nch_back        nch_chain[1]
-
+struct namecache **nchashtbl;
+u_long nchash;                         /* size of hash table - 1 */
+long   numcache;                       /* number of cache entries allocated */
 struct namecache *nchhead, **nchtail;  /* LRU chain pointers */
 struct nchstats nchstats;              /* cache effectiveness statistics */
 
 struct namecache *nchhead, **nchtail;  /* LRU chain pointers */
 struct nchstats nchstats;              /* cache effectiveness statistics */
 
@@ -79,52 +59,54 @@ int doingcache = 1;                 /* 1 => enable the cache */
  * the name does not exist (negative cacheing), a status of ENOENT
  * is returned. If the lookup fails, a status of zero is returned.
  */
  * the name does not exist (negative cacheing), a status of ENOENT
  * is returned. If the lookup fails, a status of zero is returned.
  */
-cache_lookup(ndp)
-       register struct nameidata *ndp;
+int
+cache_lookup(dvp, vpp, cnp)
+       struct vnode *dvp;
+       struct vnode **vpp;
+       struct componentname *cnp;
 {
 {
-       register struct vnode *dvp;
-       register struct namecache *ncp;
-       union nchash *nhp;
+       register struct namecache *ncp, *ncq, **ncpp;
 
        if (!doingcache)
                return (0);
 
        if (!doingcache)
                return (0);
-       if (ndp->ni_namelen > NCHNAMLEN) {
+       if (cnp->cn_namelen > NCHNAMLEN) {
                nchstats.ncs_long++;
                nchstats.ncs_long++;
-               ndp->ni_makeentry = 0;
+               cnp->cn_flags &= ~MAKEENTRY;
                return (0);
        }
                return (0);
        }
-       dvp = ndp->ni_dvp;
-       nhp = &nchash[NHASH(dvp, ndp->ni_hash)];
-       for (ncp = nhp->nch_forw; ncp != (struct namecache *)nhp;
-           ncp = ncp->nc_forw) {
+       ncpp = &nchashtbl[cnp->cn_hash & nchash];
+       for (ncp = *ncpp; ncp; ncp = ncp->nc_forw) {
                if (ncp->nc_dvp == dvp &&
                    ncp->nc_dvpid == dvp->v_id &&
                if (ncp->nc_dvp == dvp &&
                    ncp->nc_dvpid == dvp->v_id &&
-                   ncp->nc_nlen == ndp->ni_namelen &&
-                   !bcmp(ncp->nc_name, ndp->ni_ptr, (unsigned)ncp->nc_nlen))
+                   ncp->nc_nlen == cnp->cn_namelen &&
+                   !bcmp(ncp->nc_name, cnp->cn_nameptr, (u_int)ncp->nc_nlen))
                        break;
        }
                        break;
        }
-       if (ncp == (struct namecache *)nhp) {
+       if (ncp == NULL) {
                nchstats.ncs_miss++;
                return (0);
        }
                nchstats.ncs_miss++;
                return (0);
        }
-       if (!ndp->ni_makeentry) {
+       if (!(cnp->cn_flags & MAKEENTRY)) {
                nchstats.ncs_badhits++;
        } else if (ncp->nc_vp == NULL) {
                nchstats.ncs_badhits++;
        } else if (ncp->nc_vp == NULL) {
-               nchstats.ncs_neghits++;
-               /*
-                * move this slot to end of LRU chain, if not already there
-                */
-               if (ncp->nc_nxt) {
-                       /* remove from LRU chain */
-                       *ncp->nc_prev = ncp->nc_nxt;
-                       ncp->nc_nxt->nc_prev = ncp->nc_prev;
-                       /* and replace at end of it */
-                       ncp->nc_nxt = NULL;
-                       ncp->nc_prev = nchtail;
-                       *nchtail = ncp;
-                       nchtail = &ncp->nc_nxt;
+               if (cnp->cn_nameiop != CREATE) {
+                       nchstats.ncs_neghits++;
+                       /*
+                        * Move this slot to end of LRU chain,
+                        * if not already there.
+                        */
+                       if (ncp->nc_nxt) {
+                               /* remove from LRU chain */
+                               *ncp->nc_prev = ncp->nc_nxt;
+                               ncp->nc_nxt->nc_prev = ncp->nc_prev;
+                               /* and replace at end of it */
+                               ncp->nc_nxt = NULL;
+                               ncp->nc_prev = nchtail;
+                               *nchtail = ncp;
+                               nchtail = &ncp->nc_nxt;
+                       }
+                       return (ENOENT);
                }
                }
-               return (ENOENT);
        } else if (ncp->nc_vpid != ncp->nc_vp->v_id) {
                nchstats.ncs_falsehits++;
        } else {
        } else if (ncp->nc_vpid != ncp->nc_vp->v_id) {
                nchstats.ncs_falsehits++;
        } else {
@@ -142,7 +124,7 @@ cache_lookup(ndp)
                        *nchtail = ncp;
                        nchtail = &ncp->nc_nxt;
                }
                        *nchtail = ncp;
                        nchtail = &ncp->nc_nxt;
                }
-               ndp->ni_vp = ncp->nc_vp;
+               *vpp = ncp->nc_vp;
                return (-1);
        }
 
                return (-1);
        }
 
@@ -152,92 +134,103 @@ cache_lookup(ndp)
         * want cache entry to exist.
         */
        /* remove from LRU chain */
         * want cache entry to exist.
         */
        /* remove from LRU chain */
-       *ncp->nc_prev = ncp->nc_nxt;
-       if (ncp->nc_nxt)
-               ncp->nc_nxt->nc_prev = ncp->nc_prev;
+       if (ncq = ncp->nc_nxt)
+               ncq->nc_prev = ncp->nc_prev;
        else
                nchtail = ncp->nc_prev;
        else
                nchtail = ncp->nc_prev;
+       *ncp->nc_prev = ncq;
        /* remove from hash chain */
        /* remove from hash chain */
-       remque(ncp);
+       if (ncq = ncp->nc_forw)
+               ncq->nc_back = ncp->nc_back;
+       *ncp->nc_back = ncq;
+       /* and make a dummy hash chain */
+       ncp->nc_forw = NULL;
+       ncp->nc_back = NULL;
        /* insert at head of LRU list (first to grab) */
        /* insert at head of LRU list (first to grab) */
-       ncp->nc_nxt = nchhead;
-       ncp->nc_prev = &nchhead;
-       nchhead->nc_prev = &ncp->nc_nxt;
+       if (ncq = nchhead)
+               ncq->nc_prev = &ncp->nc_nxt;
+       else
+               nchtail = &ncp->nc_nxt;
        nchhead = ncp;
        nchhead = ncp;
-       /* and make a dummy hash chain */
-       ncp->nc_forw = ncp;
-       ncp->nc_back = ncp;
+       ncp->nc_nxt = ncq;
+       ncp->nc_prev = &nchhead;
        return (0);
 }
 
 /*
  * Add an entry to the cache
  */
        return (0);
 }
 
 /*
  * Add an entry to the cache
  */
-cache_enter(ndp)
-       register struct nameidata *ndp;
+cache_enter(dvp, vp, cnp)
+       struct vnode *dvp;
+       struct vnode *vp;
+       struct componentname *cnp;
 {
 {
-       register struct namecache *ncp;
-       union nchash *nhp;
+       register struct namecache *ncp, *ncq, **ncpp;
 
 
+#ifdef DIAGNOSTIC
+       if (cnp->cn_namelen > NCHNAMLEN)
+               panic("cache_enter: name too long");
+#endif
        if (!doingcache)
                return;
        /*
         * Free the cache slot at head of lru chain.
         */
        if (!doingcache)
                return;
        /*
         * Free the cache slot at head of lru chain.
         */
-       if (ncp = nchhead) {
+       if (numcache < desiredvnodes) {
+               ncp = (struct namecache *)
+                       malloc((u_long)sizeof *ncp, M_CACHE, M_WAITOK);
+               bzero((char *)ncp, sizeof *ncp);
+               numcache++;
+       } else if (ncp = nchhead) {
                /* remove from lru chain */
                /* remove from lru chain */
-               *ncp->nc_prev = ncp->nc_nxt;
-               if (ncp->nc_nxt)
-                       ncp->nc_nxt->nc_prev = ncp->nc_prev;
+               if (ncq = ncp->nc_nxt)
+                       ncq->nc_prev = ncp->nc_prev;
                else
                        nchtail = ncp->nc_prev;
                else
                        nchtail = ncp->nc_prev;
-               /* remove from old hash chain */
-               remque(ncp);
-               /* grab the inode we just found */
-               ncp->nc_vp = ndp->ni_vp;
-               if (ndp->ni_vp)
-                       ncp->nc_vpid = ndp->ni_vp->v_id;
-               else
-                       ncp->nc_vpid = 0;
-               /* fill in cache info */
-               ncp->nc_dvp = ndp->ni_dvp;
-               ncp->nc_dvpid = ndp->ni_dvp->v_id;
-               ncp->nc_nlen = ndp->ni_namelen;
-               bcopy(ndp->ni_ptr, ncp->nc_name, (unsigned)ncp->nc_nlen);
-               /* link at end of lru chain */
-               ncp->nc_nxt = NULL;
-               ncp->nc_prev = nchtail;
-               *nchtail = ncp;
-               nchtail = &ncp->nc_nxt;
-               /* and insert on hash chain */
-               nhp = &nchash[NHASH(ndp->ni_vp, ndp->ni_hash)];
-               insque(ncp, nhp);
-       }
+               *ncp->nc_prev = ncq;
+               /* remove from old hash chain, if on one */
+               if (ncp->nc_back) {
+                       if (ncq = ncp->nc_forw)
+                               ncq->nc_back = ncp->nc_back;
+                       *ncp->nc_back = ncq;
+                       ncp->nc_forw = NULL;
+                       ncp->nc_back = NULL;
+               }
+       } else
+               return;
+       /* grab the vnode we just found */
+       ncp->nc_vp = vp;
+       if (vp)
+               ncp->nc_vpid = vp->v_id;
+       else
+               ncp->nc_vpid = 0;
+       /* fill in cache info */
+       ncp->nc_dvp = dvp;
+       ncp->nc_dvpid = dvp->v_id;
+       ncp->nc_nlen = cnp->cn_namelen;
+       bcopy(cnp->cn_nameptr, ncp->nc_name, (unsigned)ncp->nc_nlen);
+       /* link at end of lru chain */
+       ncp->nc_nxt = NULL;
+       ncp->nc_prev = nchtail;
+       *nchtail = ncp;
+       nchtail = &ncp->nc_nxt;
+       /* and insert on hash chain */
+       ncpp = &nchashtbl[cnp->cn_hash & nchash];
+       if (ncq = *ncpp)
+               ncq->nc_back = &ncp->nc_forw;
+       ncp->nc_forw = ncq;
+       ncp->nc_back = ncpp;
+       *ncpp = ncp;
 }
 
 /*
 }
 
 /*
- * Name cache initialization, from main() when we are booting
+ * Name cache initialization, from vfs_init() when we are booting
  */
 nchinit()
 {
  */
 nchinit()
 {
-       register union nchash *nchp;
-       register struct namecache *ncp;
 
 
-       nchhead = 0;
        nchtail = &nchhead;
        nchtail = &nchhead;
-       for (ncp = namecache; ncp < &namecache[nchsize]; ncp++) {
-               ncp->nc_forw = ncp;                     /* hash chain */
-               ncp->nc_back = ncp;
-               ncp->nc_nxt = NULL;                     /* lru chain */
-               *nchtail = ncp;
-               ncp->nc_prev = nchtail;
-               nchtail = &ncp->nc_nxt;
-               /* all else is zero already */
-       }
-       for (nchp = nchash; nchp < &nchash[NCHHASH]; nchp++) {
-               nchp->nch_head[0] = nchp;
-               nchp->nch_head[1] = nchp;
-       }
+       nchashtbl = hashinit(desiredvnodes, M_CACHE, &nchash);
 }
 
 /*
 }
 
 /*
@@ -247,14 +240,16 @@ nchinit()
 cache_purge(vp)
        struct vnode *vp;
 {
 cache_purge(vp)
        struct vnode *vp;
 {
-       struct namecache *ncp;
+       struct namecache *ncp, **ncpp;
 
        vp->v_id = ++nextvnodeid;
        if (nextvnodeid != 0)
                return;
 
        vp->v_id = ++nextvnodeid;
        if (nextvnodeid != 0)
                return;
-       for (ncp = namecache; ncp < &namecache[nchsize]; ncp++) {
-               ncp->nc_vpid = 0;
-               ncp->nc_dvpid = 0;
+       for (ncpp = &nchashtbl[nchash]; ncpp >= nchashtbl; ncpp--) {
+               for (ncp = *ncpp; ncp; ncp = ncp->nc_forw) {
+                       ncp->nc_vpid = 0;
+                       ncp->nc_dvpid = 0;
+               }
        }
        vp->v_id = ++nextvnodeid;
 }
        }
        vp->v_id = ++nextvnodeid;
 }
@@ -268,32 +263,40 @@ cache_purge(vp)
  * inode.  This makes the algorithm O(n^2), but do you think I care?
  */
 cache_purgevfs(mp)
  * inode.  This makes the algorithm O(n^2), but do you think I care?
  */
 cache_purgevfs(mp)
-       register struct mount *mp;
+       struct mount *mp;
 {
        register struct namecache *ncp, *nxtcp;
 
        for (ncp = nchhead; ncp; ncp = nxtcp) {
 {
        register struct namecache *ncp, *nxtcp;
 
        for (ncp = nchhead; ncp; ncp = nxtcp) {
-               nxtcp = ncp->nc_nxt;
-               if (ncp->nc_dvp == NULL || ncp->nc_dvp->v_mount != mp)
+               if (ncp->nc_dvp == NULL || ncp->nc_dvp->v_mount != mp) {
+                       nxtcp = ncp->nc_nxt;
                        continue;
                        continue;
+               }
                /* free the resources we had */
                ncp->nc_vp = NULL;
                ncp->nc_dvp = NULL;
                /* free the resources we had */
                ncp->nc_vp = NULL;
                ncp->nc_dvp = NULL;
-               remque(ncp);            /* remove entry from its hash chain */
-               ncp->nc_forw = ncp;     /* and make a dummy one */
-               ncp->nc_back = ncp;
+               /* remove from old hash chain, if on one */
+               if (ncp->nc_back) {
+                       if (nxtcp = ncp->nc_forw)
+                               nxtcp->nc_back = ncp->nc_back;
+                       *ncp->nc_back = nxtcp;
+                       ncp->nc_forw = NULL;
+                       ncp->nc_back = NULL;
+               }
                /* delete this entry from LRU chain */
                /* delete this entry from LRU chain */
-               *ncp->nc_prev = nxtcp;
-               if (nxtcp)
+               if (nxtcp = ncp->nc_nxt)
                        nxtcp->nc_prev = ncp->nc_prev;
                else
                        nchtail = ncp->nc_prev;
                        nxtcp->nc_prev = ncp->nc_prev;
                else
                        nchtail = ncp->nc_prev;
+               *ncp->nc_prev = nxtcp;
                /* cause rescan of list, it may have altered */
                /* cause rescan of list, it may have altered */
-               nxtcp = nchhead;
-               /* put the now-free entry at head of LRU */
+               /* also put the now-free entry at head of LRU */
+               if (nxtcp = nchhead)
+                       nxtcp->nc_prev = &ncp->nc_nxt;
+               else
+                       nchtail = &ncp->nc_nxt;
+               nchhead = ncp;
                ncp->nc_nxt = nxtcp;
                ncp->nc_prev = &nchhead;
                ncp->nc_nxt = nxtcp;
                ncp->nc_prev = &nchhead;
-               nxtcp->nc_prev = &ncp->nc_nxt;
-               nchhead = ncp;
        }
 }
        }
 }