xref: /csrg-svn/sys/kern/vfs_cache.c (revision 55185)
137487Smckusick /*
237487Smckusick  * Copyright (c) 1989 The Regents of the University of California.
337487Smckusick  * All rights reserved.
437487Smckusick  *
544455Sbostic  * %sccs.include.redist.c%
637487Smckusick  *
7*55185Smckusick  *	@(#)vfs_cache.c	7.12 (Berkeley) 07/13/92
837487Smckusick  */
937487Smckusick 
1037487Smckusick #include "param.h"
1137487Smckusick #include "systm.h"
1237487Smckusick #include "time.h"
1345117Smckusick #include "mount.h"
1437487Smckusick #include "vnode.h"
1537487Smckusick #include "namei.h"
1638768Smckusick #include "errno.h"
1740881Smckusick #include "malloc.h"
1837487Smckusick 
1937487Smckusick /*
2037487Smckusick  * Name caching works as follows:
2137487Smckusick  *
2237487Smckusick  * Names found by directory scans are retained in a cache
2337487Smckusick  * for future reference.  It is managed LRU, so frequently
2437487Smckusick  * used names will hang around.  Cache is indexed by hash value
2538768Smckusick  * obtained from (vp, name) where vp refers to the directory
2638768Smckusick  * containing name.
2737487Smckusick  *
2837487Smckusick  * For simplicity (and economy of storage), names longer than
2937487Smckusick  * a maximum length of NCHNAMLEN are not cached; they occur
3037487Smckusick  * infrequently in any case, and are almost never of interest.
3137487Smckusick  *
3237487Smckusick  * Upon reaching the last segment of a path, if the reference
3337487Smckusick  * is for DELETE, or NOCACHE is set (rewrite), and the
3437487Smckusick  * name is located in the cache, it will be dropped.
3537487Smckusick  */
3637487Smckusick 
3737487Smckusick /*
3837487Smckusick  * Structures associated with name cacheing.
3937487Smckusick  */
4037487Smckusick union nchash {
4137487Smckusick 	union	nchash *nch_head[2];
4237487Smckusick 	struct	namecache *nch_chain[2];
4340881Smckusick } *nchashtbl;
4437487Smckusick #define	nch_forw	nch_chain[0]
4537487Smckusick #define	nch_back	nch_chain[1]
4637487Smckusick 
4740881Smckusick u_long	nchash;				/* size of hash table - 1 */
4840881Smckusick long	numcache;			/* number of cache entries allocated */
4937487Smckusick struct	namecache *nchhead, **nchtail;	/* LRU chain pointers */
5037487Smckusick struct	nchstats nchstats;		/* cache effectiveness statistics */
5137487Smckusick 
5238768Smckusick int doingcache = 1;			/* 1 => enable the cache */
5338768Smckusick 
5437487Smckusick /*
5537487Smckusick  * Look for a the name in the cache. We don't do this
5637487Smckusick  * if the segment name is long, simply so the cache can avoid
5737487Smckusick  * holding long names (which would either waste space, or
5837487Smckusick  * add greatly to the complexity).
5938768Smckusick  *
6038768Smckusick  * Lookup is called with ni_dvp pointing to the directory to search,
6138768Smckusick  * ni_ptr pointing to the name of the entry being sought, ni_namelen
6238768Smckusick  * tells the length of the name, and ni_hash contains a hash of
6338768Smckusick  * the name. If the lookup succeeds, the vnode is returned in ni_vp
6438768Smckusick  * and a status of -1 is returned. If the lookup determines that
6538768Smckusick  * the name does not exist (negative cacheing), a status of ENOENT
6638768Smckusick  * is returned. If the lookup fails, a status of zero is returned.
6737487Smckusick  */
6852231Sheideman int
6952306Sheideman cache_lookup(dvp, vpp, cnp)
7052231Sheideman 	struct vnode *dvp;
7152231Sheideman 	struct vnode **vpp;
7252231Sheideman 	struct componentname *cnp;
7337487Smckusick {
7437487Smckusick 	register struct namecache *ncp;
7537487Smckusick 	union nchash *nhp;
7637487Smckusick 
7738768Smckusick 	if (!doingcache)
7838768Smckusick 		return (0);
7952231Sheideman 	if (cnp->cn_namelen > NCHNAMLEN) {
8037487Smckusick 		nchstats.ncs_long++;
8152231Sheideman 		cnp->cn_flags &= ~MAKEENTRY;
8237487Smckusick 		return (0);
8337487Smckusick 	}
8452231Sheideman 	nhp = &nchashtbl[cnp->cn_hash & nchash];
8537487Smckusick 	for (ncp = nhp->nch_forw; ncp != (struct namecache *)nhp;
8637487Smckusick 	    ncp = ncp->nc_forw) {
8738768Smckusick 		if (ncp->nc_dvp == dvp &&
8838768Smckusick 		    ncp->nc_dvpid == dvp->v_id &&
8952231Sheideman 		    ncp->nc_nlen == cnp->cn_namelen &&
9052231Sheideman 		    !bcmp(ncp->nc_name, cnp->cn_nameptr, (unsigned)ncp->nc_nlen))
9137487Smckusick 			break;
9237487Smckusick 	}
9337487Smckusick 	if (ncp == (struct namecache *)nhp) {
9437487Smckusick 		nchstats.ncs_miss++;
9537487Smckusick 		return (0);
9637487Smckusick 	}
9752231Sheideman 	if (!(cnp->cn_flags & MAKEENTRY)) {
9838768Smckusick 		nchstats.ncs_badhits++;
9938768Smckusick 	} else if (ncp->nc_vp == NULL) {
10052306Sheideman 		if (cnp->cn_nameiop != CREATE) {
10146747Smckusick 			nchstats.ncs_neghits++;
10246747Smckusick 			/*
10346747Smckusick 			 * Move this slot to end of LRU chain,
10446747Smckusick 			 * if not already there.
10546747Smckusick 			 */
10646747Smckusick 			if (ncp->nc_nxt) {
10746747Smckusick 				/* remove from LRU chain */
10846747Smckusick 				*ncp->nc_prev = ncp->nc_nxt;
10946747Smckusick 				ncp->nc_nxt->nc_prev = ncp->nc_prev;
11046747Smckusick 				/* and replace at end of it */
11146747Smckusick 				ncp->nc_nxt = NULL;
11246747Smckusick 				ncp->nc_prev = nchtail;
11346747Smckusick 				*nchtail = ncp;
11446747Smckusick 				nchtail = &ncp->nc_nxt;
11546747Smckusick 			}
11646747Smckusick 			return (ENOENT);
11737487Smckusick 		}
11838768Smckusick 	} else if (ncp->nc_vpid != ncp->nc_vp->v_id) {
11938768Smckusick 		nchstats.ncs_falsehits++;
12038768Smckusick 	} else {
12137487Smckusick 		nchstats.ncs_goodhits++;
12238768Smckusick 		/*
12338768Smckusick 		 * move this slot to end of LRU chain, if not already there
12438768Smckusick 		 */
12538768Smckusick 		if (ncp->nc_nxt) {
12638768Smckusick 			/* remove from LRU chain */
12738768Smckusick 			*ncp->nc_prev = ncp->nc_nxt;
12838768Smckusick 			ncp->nc_nxt->nc_prev = ncp->nc_prev;
12938768Smckusick 			/* and replace at end of it */
13038768Smckusick 			ncp->nc_nxt = NULL;
13138768Smckusick 			ncp->nc_prev = nchtail;
13238768Smckusick 			*nchtail = ncp;
13338768Smckusick 			nchtail = &ncp->nc_nxt;
13438768Smckusick 		}
13552231Sheideman 		*vpp = ncp->nc_vp;
13638768Smckusick 		return (-1);
13737487Smckusick 	}
13837487Smckusick 
13937487Smckusick 	/*
14037487Smckusick 	 * Last component and we are renaming or deleting,
14137487Smckusick 	 * the cache entry is invalid, or otherwise don't
14237487Smckusick 	 * want cache entry to exist.
14337487Smckusick 	 */
14437487Smckusick 	/* remove from LRU chain */
14537487Smckusick 	*ncp->nc_prev = ncp->nc_nxt;
14637487Smckusick 	if (ncp->nc_nxt)
14737487Smckusick 		ncp->nc_nxt->nc_prev = ncp->nc_prev;
14837487Smckusick 	else
14937487Smckusick 		nchtail = ncp->nc_prev;
15038768Smckusick 	/* remove from hash chain */
15138768Smckusick 	remque(ncp);
15237487Smckusick 	/* insert at head of LRU list (first to grab) */
15337487Smckusick 	ncp->nc_nxt = nchhead;
15437487Smckusick 	ncp->nc_prev = &nchhead;
15537487Smckusick 	nchhead->nc_prev = &ncp->nc_nxt;
15637487Smckusick 	nchhead = ncp;
15737487Smckusick 	/* and make a dummy hash chain */
15837487Smckusick 	ncp->nc_forw = ncp;
15937487Smckusick 	ncp->nc_back = ncp;
16037487Smckusick 	return (0);
16137487Smckusick }
16237487Smckusick 
16337487Smckusick /*
16437487Smckusick  * Add an entry to the cache
16537487Smckusick  */
16652306Sheideman cache_enter(dvp, vp, cnp)
16752231Sheideman 	struct vnode *dvp;
16852231Sheideman 	struct vnode *vp;
16952231Sheideman 	struct componentname *cnp;
17037487Smckusick {
17137487Smckusick 	register struct namecache *ncp;
17237487Smckusick 	union nchash *nhp;
17337487Smckusick 
174*55185Smckusick #ifdef DIAGNOSTIC
175*55185Smckusick 	if (cnp->cn_namelen > NCHNAMLEN)
176*55185Smckusick 		panic("cache_enter: name too long");
177*55185Smckusick #endif
17838768Smckusick 	if (!doingcache)
17938768Smckusick 		return;
18037487Smckusick 	/*
18137487Smckusick 	 * Free the cache slot at head of lru chain.
18237487Smckusick 	 */
18340881Smckusick 	if (numcache < desiredvnodes) {
18440881Smckusick 		ncp = (struct namecache *)
18545117Smckusick 			malloc((u_long)sizeof *ncp, M_CACHE, M_WAITOK);
18640881Smckusick 		bzero((char *)ncp, sizeof *ncp);
18740881Smckusick 		numcache++;
18840881Smckusick 	} else if (ncp = nchhead) {
18937487Smckusick 		/* remove from lru chain */
19037487Smckusick 		*ncp->nc_prev = ncp->nc_nxt;
19137487Smckusick 		if (ncp->nc_nxt)
19237487Smckusick 			ncp->nc_nxt->nc_prev = ncp->nc_prev;
19337487Smckusick 		else
19437487Smckusick 			nchtail = ncp->nc_prev;
19538768Smckusick 		/* remove from old hash chain */
19638768Smckusick 		remque(ncp);
19740881Smckusick 	} else
19840881Smckusick 		return;
19940881Smckusick 	/* grab the vnode we just found */
20052231Sheideman 	ncp->nc_vp = vp;
20152231Sheideman 	if (vp)
20252231Sheideman 		ncp->nc_vpid = vp->v_id;
20340881Smckusick 	else
20440881Smckusick 		ncp->nc_vpid = 0;
20540881Smckusick 	/* fill in cache info */
20652231Sheideman 	ncp->nc_dvp = dvp;
20752231Sheideman 	ncp->nc_dvpid = dvp->v_id;
20852231Sheideman 	ncp->nc_nlen = cnp->cn_namelen;
20952231Sheideman 	bcopy(cnp->cn_nameptr, ncp->nc_name, (unsigned)ncp->nc_nlen);
21040881Smckusick 	/* link at end of lru chain */
21140881Smckusick 	ncp->nc_nxt = NULL;
21240881Smckusick 	ncp->nc_prev = nchtail;
21340881Smckusick 	*nchtail = ncp;
21440881Smckusick 	nchtail = &ncp->nc_nxt;
21540881Smckusick 	/* and insert on hash chain */
21652231Sheideman 	nhp = &nchashtbl[cnp->cn_hash & nchash];
21740881Smckusick 	insque(ncp, nhp);
21837487Smckusick }
21937487Smckusick 
22037487Smckusick /*
22140881Smckusick  * Name cache initialization, from vfs_init() when we are booting
22237487Smckusick  */
22337487Smckusick nchinit()
22437487Smckusick {
22537487Smckusick 	register union nchash *nchp;
22640881Smckusick 	long nchashsize;
22737487Smckusick 
22837487Smckusick 	nchhead = 0;
22937487Smckusick 	nchtail = &nchhead;
23040881Smckusick 	nchashsize = roundup((desiredvnodes + 1) * sizeof *nchp / 2,
23140881Smckusick 		NBPG * CLSIZE);
23245117Smckusick 	nchashtbl = (union nchash *)malloc((u_long)nchashsize,
23345117Smckusick 	    M_CACHE, M_WAITOK);
23440881Smckusick 	for (nchash = 1; nchash <= nchashsize / sizeof *nchp; nchash <<= 1)
23552945Storek 		continue;
23640881Smckusick 	nchash = (nchash >> 1) - 1;
23740881Smckusick 	for (nchp = &nchashtbl[nchash]; nchp >= nchashtbl; nchp--) {
23837487Smckusick 		nchp->nch_head[0] = nchp;
23937487Smckusick 		nchp->nch_head[1] = nchp;
24037487Smckusick 	}
24137487Smckusick }
24237487Smckusick 
24337487Smckusick /*
24437487Smckusick  * Cache flush, a particular vnode; called when a vnode is renamed to
24538768Smckusick  * hide entries that would now be invalid
24637487Smckusick  */
24737487Smckusick cache_purge(vp)
24838768Smckusick 	struct vnode *vp;
24937487Smckusick {
25040881Smckusick 	union nchash *nhp;
25138768Smckusick 	struct namecache *ncp;
25237487Smckusick 
25338768Smckusick 	vp->v_id = ++nextvnodeid;
25438768Smckusick 	if (nextvnodeid != 0)
25538768Smckusick 		return;
25640881Smckusick 	for (nhp = &nchashtbl[nchash]; nhp >= nchashtbl; nhp--) {
25740881Smckusick 		for (ncp = nhp->nch_forw; ncp != (struct namecache *)nhp;
25840881Smckusick 		    ncp = ncp->nc_forw) {
25940881Smckusick 			ncp->nc_vpid = 0;
26040881Smckusick 			ncp->nc_dvpid = 0;
26140881Smckusick 		}
26237487Smckusick 	}
26338768Smckusick 	vp->v_id = ++nextvnodeid;
26437487Smckusick }
26537487Smckusick 
26637487Smckusick /*
26737487Smckusick  * Cache flush, a whole filesystem; called when filesys is umounted to
26837487Smckusick  * remove entries that would now be invalid
26937487Smckusick  *
27037487Smckusick  * The line "nxtcp = nchhead" near the end is to avoid potential problems
27137487Smckusick  * if the cache lru chain is modified while we are dumping the
27237487Smckusick  * inode.  This makes the algorithm O(n^2), but do you think I care?
27337487Smckusick  */
27437487Smckusick cache_purgevfs(mp)
27545117Smckusick 	struct mount *mp;
27637487Smckusick {
27737487Smckusick 	register struct namecache *ncp, *nxtcp;
27837487Smckusick 
27937487Smckusick 	for (ncp = nchhead; ncp; ncp = nxtcp) {
28037487Smckusick 		nxtcp = ncp->nc_nxt;
28138768Smckusick 		if (ncp->nc_dvp == NULL || ncp->nc_dvp->v_mount != mp)
28237487Smckusick 			continue;
28337487Smckusick 		/* free the resources we had */
28437487Smckusick 		ncp->nc_vp = NULL;
28538768Smckusick 		ncp->nc_dvp = NULL;
28637487Smckusick 		remque(ncp);		/* remove entry from its hash chain */
28737487Smckusick 		ncp->nc_forw = ncp;	/* and make a dummy one */
28837487Smckusick 		ncp->nc_back = ncp;
28937487Smckusick 		/* delete this entry from LRU chain */
29037487Smckusick 		*ncp->nc_prev = nxtcp;
29137487Smckusick 		if (nxtcp)
29237487Smckusick 			nxtcp->nc_prev = ncp->nc_prev;
29337487Smckusick 		else
29437487Smckusick 			nchtail = ncp->nc_prev;
29537487Smckusick 		/* cause rescan of list, it may have altered */
29637487Smckusick 		nxtcp = nchhead;
29737487Smckusick 		/* put the now-free entry at head of LRU */
29837487Smckusick 		ncp->nc_nxt = nxtcp;
29937487Smckusick 		ncp->nc_prev = &nchhead;
30037487Smckusick 		nxtcp->nc_prev = &ncp->nc_nxt;
30137487Smckusick 		nchhead = ncp;
30237487Smckusick 	}
30337487Smckusick }
304