xref: /csrg-svn/sys/kern/vfs_cache.c (revision 67732)
137487Smckusick /*
263180Sbostic  * Copyright (c) 1989, 1993
363180Sbostic  *	The Regents of the University of California.  All rights reserved.
437487Smckusick  *
544455Sbostic  * %sccs.include.redist.c%
637487Smckusick  *
7*67732Smckusick  *	@(#)vfs_cache.c	8.3 (Berkeley) 08/22/94
837487Smckusick  */
937487Smckusick 
1056517Sbostic #include <sys/param.h>
1156517Sbostic #include <sys/systm.h>
1256517Sbostic #include <sys/time.h>
1356517Sbostic #include <sys/mount.h>
1456517Sbostic #include <sys/vnode.h>
1556517Sbostic #include <sys/namei.h>
1656517Sbostic #include <sys/errno.h>
1756517Sbostic #include <sys/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  */
40*67732Smckusick LIST_HEAD(nchashhead, namecache) *nchashtbl;
4140881Smckusick u_long	nchash;				/* size of hash table - 1 */
4240881Smckusick long	numcache;			/* number of cache entries allocated */
43*67732Smckusick TAILQ_HEAD(, namecache) nclruhead;		/* LRU chain */
4437487Smckusick struct	nchstats nchstats;		/* cache effectiveness statistics */
4537487Smckusick 
4638768Smckusick int doingcache = 1;			/* 1 => enable the cache */
4738768Smckusick 
4837487Smckusick /*
4937487Smckusick  * Look for a the name in the cache. We don't do this
5037487Smckusick  * if the segment name is long, simply so the cache can avoid
5137487Smckusick  * holding long names (which would either waste space, or
5237487Smckusick  * add greatly to the complexity).
5338768Smckusick  *
5438768Smckusick  * Lookup is called with ni_dvp pointing to the directory to search,
5538768Smckusick  * ni_ptr pointing to the name of the entry being sought, ni_namelen
5638768Smckusick  * tells the length of the name, and ni_hash contains a hash of
5738768Smckusick  * the name. If the lookup succeeds, the vnode is returned in ni_vp
5838768Smckusick  * and a status of -1 is returned. If the lookup determines that
5938768Smckusick  * the name does not exist (negative cacheing), a status of ENOENT
6038768Smckusick  * is returned. If the lookup fails, a status of zero is returned.
6137487Smckusick  */
6252231Sheideman int
6352306Sheideman cache_lookup(dvp, vpp, cnp)
6452231Sheideman 	struct vnode *dvp;
6552231Sheideman 	struct vnode **vpp;
6652231Sheideman 	struct componentname *cnp;
6737487Smckusick {
68*67732Smckusick 	register struct namecache *ncp;
69*67732Smckusick 	register struct nchashhead *ncpp;
7037487Smckusick 
7167490Smckusick 	if (!doingcache) {
7267490Smckusick 		cnp->cn_flags &= ~MAKEENTRY;
7338768Smckusick 		return (0);
7467490Smckusick 	}
7552231Sheideman 	if (cnp->cn_namelen > NCHNAMLEN) {
7637487Smckusick 		nchstats.ncs_long++;
7752231Sheideman 		cnp->cn_flags &= ~MAKEENTRY;
7837487Smckusick 		return (0);
7937487Smckusick 	}
8055544Smckusick 	ncpp = &nchashtbl[cnp->cn_hash & nchash];
81*67732Smckusick 	for (ncp = ncpp->lh_first; ncp != 0; ncp = ncp->nc_hash.le_next) {
8238768Smckusick 		if (ncp->nc_dvp == dvp &&
8338768Smckusick 		    ncp->nc_dvpid == dvp->v_id &&
8452231Sheideman 		    ncp->nc_nlen == cnp->cn_namelen &&
8555544Smckusick 		    !bcmp(ncp->nc_name, cnp->cn_nameptr, (u_int)ncp->nc_nlen))
8637487Smckusick 			break;
8737487Smckusick 	}
88*67732Smckusick 	if (ncp == 0) {
8937487Smckusick 		nchstats.ncs_miss++;
9037487Smckusick 		return (0);
9137487Smckusick 	}
92*67732Smckusick 	if ((cnp->cn_flags & MAKEENTRY) == 0) {
9338768Smckusick 		nchstats.ncs_badhits++;
9438768Smckusick 	} else if (ncp->nc_vp == NULL) {
9552306Sheideman 		if (cnp->cn_nameiop != CREATE) {
9646747Smckusick 			nchstats.ncs_neghits++;
9746747Smckusick 			/*
9846747Smckusick 			 * Move this slot to end of LRU chain,
9946747Smckusick 			 * if not already there.
10046747Smckusick 			 */
101*67732Smckusick 			if (ncp->nc_lru.tqe_next != 0) {
102*67732Smckusick 				TAILQ_REMOVE(&nclruhead, ncp, nc_lru);
103*67732Smckusick 				TAILQ_INSERT_TAIL(&nclruhead, ncp, nc_lru);
10446747Smckusick 			}
10546747Smckusick 			return (ENOENT);
10637487Smckusick 		}
10738768Smckusick 	} else if (ncp->nc_vpid != ncp->nc_vp->v_id) {
10838768Smckusick 		nchstats.ncs_falsehits++;
10938768Smckusick 	} else {
11037487Smckusick 		nchstats.ncs_goodhits++;
11138768Smckusick 		/*
11238768Smckusick 		 * move this slot to end of LRU chain, if not already there
11338768Smckusick 		 */
114*67732Smckusick 		if (ncp->nc_lru.tqe_next != 0) {
115*67732Smckusick 			TAILQ_REMOVE(&nclruhead, ncp, nc_lru);
116*67732Smckusick 			TAILQ_INSERT_TAIL(&nclruhead, ncp, nc_lru);
11738768Smckusick 		}
11852231Sheideman 		*vpp = ncp->nc_vp;
11938768Smckusick 		return (-1);
12037487Smckusick 	}
12137487Smckusick 
12237487Smckusick 	/*
12337487Smckusick 	 * Last component and we are renaming or deleting,
12437487Smckusick 	 * the cache entry is invalid, or otherwise don't
12537487Smckusick 	 * want cache entry to exist.
12637487Smckusick 	 */
127*67732Smckusick 	TAILQ_REMOVE(&nclruhead, ncp, nc_lru);
128*67732Smckusick 	LIST_REMOVE(ncp, nc_hash);
129*67732Smckusick 	ncp->nc_hash.le_prev = 0;
130*67732Smckusick 	TAILQ_INSERT_HEAD(&nclruhead, ncp, nc_lru);
13137487Smckusick 	return (0);
13237487Smckusick }
13337487Smckusick 
13437487Smckusick /*
13537487Smckusick  * Add an entry to the cache
13637487Smckusick  */
13752306Sheideman cache_enter(dvp, vp, cnp)
13852231Sheideman 	struct vnode *dvp;
13952231Sheideman 	struct vnode *vp;
14052231Sheideman 	struct componentname *cnp;
14137487Smckusick {
142*67732Smckusick 	register struct namecache *ncp;
143*67732Smckusick 	register struct nchashhead *ncpp;
14437487Smckusick 
14555185Smckusick #ifdef DIAGNOSTIC
14655185Smckusick 	if (cnp->cn_namelen > NCHNAMLEN)
14755185Smckusick 		panic("cache_enter: name too long");
14855185Smckusick #endif
14938768Smckusick 	if (!doingcache)
15038768Smckusick 		return;
15137487Smckusick 	/*
15237487Smckusick 	 * Free the cache slot at head of lru chain.
15337487Smckusick 	 */
15440881Smckusick 	if (numcache < desiredvnodes) {
15540881Smckusick 		ncp = (struct namecache *)
15645117Smckusick 			malloc((u_long)sizeof *ncp, M_CACHE, M_WAITOK);
15740881Smckusick 		bzero((char *)ncp, sizeof *ncp);
15840881Smckusick 		numcache++;
159*67732Smckusick 	} else if (ncp = nclruhead.tqh_first) {
160*67732Smckusick 		TAILQ_REMOVE(&nclruhead, ncp, nc_lru);
161*67732Smckusick 		if (ncp->nc_hash.le_prev != 0) {
162*67732Smckusick 			LIST_REMOVE(ncp, nc_hash);
163*67732Smckusick 			ncp->nc_hash.le_prev = 0;
16455699Smckusick 		}
16540881Smckusick 	} else
16640881Smckusick 		return;
16740881Smckusick 	/* grab the vnode we just found */
16852231Sheideman 	ncp->nc_vp = vp;
16952231Sheideman 	if (vp)
17052231Sheideman 		ncp->nc_vpid = vp->v_id;
17140881Smckusick 	else
17240881Smckusick 		ncp->nc_vpid = 0;
17340881Smckusick 	/* fill in cache info */
17452231Sheideman 	ncp->nc_dvp = dvp;
17552231Sheideman 	ncp->nc_dvpid = dvp->v_id;
17652231Sheideman 	ncp->nc_nlen = cnp->cn_namelen;
17752231Sheideman 	bcopy(cnp->cn_nameptr, ncp->nc_name, (unsigned)ncp->nc_nlen);
178*67732Smckusick 	TAILQ_INSERT_TAIL(&nclruhead, ncp, nc_lru);
17955544Smckusick 	ncpp = &nchashtbl[cnp->cn_hash & nchash];
180*67732Smckusick 	LIST_INSERT_HEAD(ncpp, ncp, nc_hash);
18137487Smckusick }
18237487Smckusick 
18337487Smckusick /*
18440881Smckusick  * Name cache initialization, from vfs_init() when we are booting
18537487Smckusick  */
18637487Smckusick nchinit()
18737487Smckusick {
18837487Smckusick 
189*67732Smckusick 	TAILQ_INIT(&nclruhead);
19055544Smckusick 	nchashtbl = hashinit(desiredvnodes, M_CACHE, &nchash);
19137487Smckusick }
19237487Smckusick 
19337487Smckusick /*
19437487Smckusick  * Cache flush, a particular vnode; called when a vnode is renamed to
19538768Smckusick  * hide entries that would now be invalid
19637487Smckusick  */
19737487Smckusick cache_purge(vp)
19838768Smckusick 	struct vnode *vp;
19937487Smckusick {
200*67732Smckusick 	struct namecache *ncp;
201*67732Smckusick 	struct nchashhead *ncpp;
20237487Smckusick 
20338768Smckusick 	vp->v_id = ++nextvnodeid;
20438768Smckusick 	if (nextvnodeid != 0)
20538768Smckusick 		return;
20655544Smckusick 	for (ncpp = &nchashtbl[nchash]; ncpp >= nchashtbl; ncpp--) {
207*67732Smckusick 		for (ncp = ncpp->lh_first; ncp != 0; ncp = ncp->nc_hash.le_next) {
20840881Smckusick 			ncp->nc_vpid = 0;
20940881Smckusick 			ncp->nc_dvpid = 0;
21040881Smckusick 		}
21137487Smckusick 	}
21238768Smckusick 	vp->v_id = ++nextvnodeid;
21337487Smckusick }
21437487Smckusick 
21537487Smckusick /*
21637487Smckusick  * Cache flush, a whole filesystem; called when filesys is umounted to
21737487Smckusick  * remove entries that would now be invalid
21837487Smckusick  *
21937487Smckusick  * The line "nxtcp = nchhead" near the end is to avoid potential problems
22037487Smckusick  * if the cache lru chain is modified while we are dumping the
22137487Smckusick  * inode.  This makes the algorithm O(n^2), but do you think I care?
22237487Smckusick  */
22337487Smckusick cache_purgevfs(mp)
22445117Smckusick 	struct mount *mp;
22537487Smckusick {
22637487Smckusick 	register struct namecache *ncp, *nxtcp;
22737487Smckusick 
228*67732Smckusick 	for (ncp = nclruhead.tqh_first; ncp != 0; ncp = nxtcp) {
22955544Smckusick 		if (ncp->nc_dvp == NULL || ncp->nc_dvp->v_mount != mp) {
230*67732Smckusick 			nxtcp = ncp->nc_lru.tqe_next;
23137487Smckusick 			continue;
23255544Smckusick 		}
23337487Smckusick 		/* free the resources we had */
23437487Smckusick 		ncp->nc_vp = NULL;
23538768Smckusick 		ncp->nc_dvp = NULL;
236*67732Smckusick 		TAILQ_REMOVE(&nclruhead, ncp, nc_lru);
237*67732Smckusick 		if (ncp->nc_hash.le_prev != 0) {
238*67732Smckusick 			LIST_REMOVE(ncp, nc_hash);
239*67732Smckusick 			ncp->nc_hash.le_prev = 0;
24055699Smckusick 		}
24137487Smckusick 		/* cause rescan of list, it may have altered */
242*67732Smckusick 		nxtcp = nclruhead.tqh_first;
243*67732Smckusick 		TAILQ_INSERT_HEAD(&nclruhead, ncp, nc_lru);
24437487Smckusick 	}
24537487Smckusick }
246