xref: /csrg-svn/sys/kern/vfs_cache.c (revision 38768)
137487Smckusick /*
237487Smckusick  * Copyright (c) 1989 The Regents of the University of California.
337487Smckusick  * All rights reserved.
437487Smckusick  *
537487Smckusick  * Redistribution and use in source and binary forms are permitted
637487Smckusick  * provided that the above copyright notice and this paragraph are
737487Smckusick  * duplicated in all such forms and that any documentation,
837487Smckusick  * advertising materials, and other materials related to such
937487Smckusick  * distribution and use acknowledge that the software was developed
1037487Smckusick  * by the University of California, Berkeley.  The name of the
1137487Smckusick  * University may not be used to endorse or promote products derived
1237487Smckusick  * from this software without specific prior written permission.
1337487Smckusick  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1437487Smckusick  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1537487Smckusick  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1637487Smckusick  *
17*38768Smckusick  *	@(#)vfs_cache.c	7.4 (Berkeley) 08/25/89
1837487Smckusick  */
1937487Smckusick 
2037487Smckusick #include "param.h"
2137487Smckusick #include "systm.h"
2237487Smckusick #include "time.h"
2337487Smckusick #include "vnode.h"
2437487Smckusick #include "namei.h"
25*38768Smckusick #include "errno.h"
2637487Smckusick 
2737487Smckusick /*
2837487Smckusick  * Name caching works as follows:
2937487Smckusick  *
3037487Smckusick  * Names found by directory scans are retained in a cache
3137487Smckusick  * for future reference.  It is managed LRU, so frequently
3237487Smckusick  * used names will hang around.  Cache is indexed by hash value
33*38768Smckusick  * obtained from (vp, name) where vp refers to the directory
34*38768Smckusick  * containing name.
3537487Smckusick  *
3637487Smckusick  * For simplicity (and economy of storage), names longer than
3737487Smckusick  * a maximum length of NCHNAMLEN are not cached; they occur
3837487Smckusick  * infrequently in any case, and are almost never of interest.
3937487Smckusick  *
4037487Smckusick  * Upon reaching the last segment of a path, if the reference
4137487Smckusick  * is for DELETE, or NOCACHE is set (rewrite), and the
4237487Smckusick  * name is located in the cache, it will be dropped.
4337487Smckusick  */
4437487Smckusick 
4537487Smckusick /*
4637487Smckusick  * Structures associated with name cacheing.
4737487Smckusick  */
4837487Smckusick #define	NCHHASH		128	/* size of hash table */
4937487Smckusick 
5037487Smckusick #if	((NCHHASH)&((NCHHASH)-1)) != 0
51*38768Smckusick #define	NHASH(vp, h)	((((unsigned)(h) >> 6) + (h)) % (NCHHASH))
5237487Smckusick #else
53*38768Smckusick #define	NHASH(vp, h)	((((unsigned)(h) >> 6) + (h)) & ((NCHHASH)-1))
5437487Smckusick #endif
5537487Smckusick 
5637487Smckusick union nchash {
5737487Smckusick 	union	nchash *nch_head[2];
5837487Smckusick 	struct	namecache *nch_chain[2];
5937487Smckusick } nchash[NCHHASH];
6037487Smckusick #define	nch_forw	nch_chain[0]
6137487Smckusick #define	nch_back	nch_chain[1]
6237487Smckusick 
6337487Smckusick struct	namecache *nchhead, **nchtail;	/* LRU chain pointers */
6437487Smckusick struct	nchstats nchstats;		/* cache effectiveness statistics */
6537487Smckusick 
66*38768Smckusick int doingcache = 1;			/* 1 => enable the cache */
67*38768Smckusick 
6837487Smckusick /*
6937487Smckusick  * Look for a the name in the cache. We don't do this
7037487Smckusick  * if the segment name is long, simply so the cache can avoid
7137487Smckusick  * holding long names (which would either waste space, or
7237487Smckusick  * add greatly to the complexity).
73*38768Smckusick  *
74*38768Smckusick  * Lookup is called with ni_dvp pointing to the directory to search,
75*38768Smckusick  * ni_ptr pointing to the name of the entry being sought, ni_namelen
76*38768Smckusick  * tells the length of the name, and ni_hash contains a hash of
77*38768Smckusick  * the name. If the lookup succeeds, the vnode is returned in ni_vp
78*38768Smckusick  * and a status of -1 is returned. If the lookup determines that
79*38768Smckusick  * the name does not exist (negative cacheing), a status of ENOENT
80*38768Smckusick  * is returned. If the lookup fails, a status of zero is returned.
8137487Smckusick  */
8237487Smckusick cache_lookup(ndp)
8337487Smckusick 	register struct nameidata *ndp;
8437487Smckusick {
85*38768Smckusick 	register struct vnode *dvp;
8637487Smckusick 	register struct namecache *ncp;
8737487Smckusick 	union nchash *nhp;
8837487Smckusick 
89*38768Smckusick 	if (!doingcache)
90*38768Smckusick 		return (0);
91*38768Smckusick 	if (ndp->ni_namelen > NCHNAMLEN) {
9237487Smckusick 		nchstats.ncs_long++;
9337487Smckusick 		ndp->ni_makeentry = 0;
9437487Smckusick 		return (0);
9537487Smckusick 	}
96*38768Smckusick 	dvp = ndp->ni_dvp;
97*38768Smckusick 	nhp = &nchash[NHASH(dvp, ndp->ni_hash)];
9837487Smckusick 	for (ncp = nhp->nch_forw; ncp != (struct namecache *)nhp;
9937487Smckusick 	    ncp = ncp->nc_forw) {
100*38768Smckusick 		if (ncp->nc_dvp == dvp &&
101*38768Smckusick 		    ncp->nc_dvpid == dvp->v_id &&
102*38768Smckusick 		    ncp->nc_nlen == ndp->ni_namelen &&
103*38768Smckusick 		    !bcmp(ncp->nc_name, ndp->ni_ptr, (unsigned)ncp->nc_nlen))
10437487Smckusick 			break;
10537487Smckusick 	}
10637487Smckusick 	if (ncp == (struct namecache *)nhp) {
10737487Smckusick 		nchstats.ncs_miss++;
10837487Smckusick 		return (0);
10937487Smckusick 	}
110*38768Smckusick 	if (!ndp->ni_makeentry) {
111*38768Smckusick 		nchstats.ncs_badhits++;
112*38768Smckusick 	} else if (ncp->nc_vp == NULL) {
113*38768Smckusick 		nchstats.ncs_neghits++;
11437487Smckusick 		/*
115*38768Smckusick 		 * move this slot to end of LRU chain, if not already there
11637487Smckusick 		 */
11737487Smckusick 		if (ncp->nc_nxt) {
11837487Smckusick 			/* remove from LRU chain */
11937487Smckusick 			*ncp->nc_prev = ncp->nc_nxt;
12037487Smckusick 			ncp->nc_nxt->nc_prev = ncp->nc_prev;
12137487Smckusick 			/* and replace at end of it */
12237487Smckusick 			ncp->nc_nxt = NULL;
12337487Smckusick 			ncp->nc_prev = nchtail;
12437487Smckusick 			*nchtail = ncp;
12537487Smckusick 			nchtail = &ncp->nc_nxt;
12637487Smckusick 		}
127*38768Smckusick 		return (ENOENT);
128*38768Smckusick 	} else if (ncp->nc_vpid != ncp->nc_vp->v_id) {
129*38768Smckusick 		nchstats.ncs_falsehits++;
130*38768Smckusick 	} else {
13137487Smckusick 		nchstats.ncs_goodhits++;
132*38768Smckusick 		/*
133*38768Smckusick 		 * move this slot to end of LRU chain, if not already there
134*38768Smckusick 		 */
135*38768Smckusick 		if (ncp->nc_nxt) {
136*38768Smckusick 			/* remove from LRU chain */
137*38768Smckusick 			*ncp->nc_prev = ncp->nc_nxt;
138*38768Smckusick 			ncp->nc_nxt->nc_prev = ncp->nc_prev;
139*38768Smckusick 			/* and replace at end of it */
140*38768Smckusick 			ncp->nc_nxt = NULL;
141*38768Smckusick 			ncp->nc_prev = nchtail;
142*38768Smckusick 			*nchtail = ncp;
143*38768Smckusick 			nchtail = &ncp->nc_nxt;
144*38768Smckusick 		}
145*38768Smckusick 		ndp->ni_vp = ncp->nc_vp;
146*38768Smckusick 		return (-1);
14737487Smckusick 	}
14837487Smckusick 
14937487Smckusick 	/*
15037487Smckusick 	 * Last component and we are renaming or deleting,
15137487Smckusick 	 * the cache entry is invalid, or otherwise don't
15237487Smckusick 	 * want cache entry to exist.
15337487Smckusick 	 */
15437487Smckusick 	/* remove from LRU chain */
15537487Smckusick 	*ncp->nc_prev = ncp->nc_nxt;
15637487Smckusick 	if (ncp->nc_nxt)
15737487Smckusick 		ncp->nc_nxt->nc_prev = ncp->nc_prev;
15837487Smckusick 	else
15937487Smckusick 		nchtail = ncp->nc_prev;
160*38768Smckusick 	/* remove from hash chain */
161*38768Smckusick 	remque(ncp);
16237487Smckusick 	/* insert at head of LRU list (first to grab) */
16337487Smckusick 	ncp->nc_nxt = nchhead;
16437487Smckusick 	ncp->nc_prev = &nchhead;
16537487Smckusick 	nchhead->nc_prev = &ncp->nc_nxt;
16637487Smckusick 	nchhead = ncp;
16737487Smckusick 	/* and make a dummy hash chain */
16837487Smckusick 	ncp->nc_forw = ncp;
16937487Smckusick 	ncp->nc_back = ncp;
17037487Smckusick 	return (0);
17137487Smckusick }
17237487Smckusick 
17337487Smckusick /*
17437487Smckusick  * Add an entry to the cache
17537487Smckusick  */
17637487Smckusick cache_enter(ndp)
17737487Smckusick 	register struct nameidata *ndp;
17837487Smckusick {
17937487Smckusick 	register struct namecache *ncp;
18037487Smckusick 	union nchash *nhp;
18137487Smckusick 
182*38768Smckusick 	if (!doingcache)
183*38768Smckusick 		return;
18437487Smckusick 	/*
18537487Smckusick 	 * Free the cache slot at head of lru chain.
18637487Smckusick 	 */
18737487Smckusick 	if (ncp = nchhead) {
18837487Smckusick 		/* remove from lru chain */
18937487Smckusick 		*ncp->nc_prev = ncp->nc_nxt;
19037487Smckusick 		if (ncp->nc_nxt)
19137487Smckusick 			ncp->nc_nxt->nc_prev = ncp->nc_prev;
19237487Smckusick 		else
19337487Smckusick 			nchtail = ncp->nc_prev;
194*38768Smckusick 		/* remove from old hash chain */
195*38768Smckusick 		remque(ncp);
19637487Smckusick 		/* grab the inode we just found */
19737487Smckusick 		ncp->nc_vp = ndp->ni_vp;
198*38768Smckusick 		if (ndp->ni_vp)
199*38768Smckusick 			ncp->nc_vpid = ndp->ni_vp->v_id;
200*38768Smckusick 		else
201*38768Smckusick 			ncp->nc_vpid = 0;
20237487Smckusick 		/* fill in cache info */
203*38768Smckusick 		ncp->nc_dvp = ndp->ni_dvp;
204*38768Smckusick 		ncp->nc_dvpid = ndp->ni_dvp->v_id;
205*38768Smckusick 		ncp->nc_nlen = ndp->ni_namelen;
206*38768Smckusick 		bcopy(ndp->ni_ptr, ncp->nc_name, (unsigned)ncp->nc_nlen);
20737487Smckusick 		/* link at end of lru chain */
20837487Smckusick 		ncp->nc_nxt = NULL;
20937487Smckusick 		ncp->nc_prev = nchtail;
21037487Smckusick 		*nchtail = ncp;
21137487Smckusick 		nchtail = &ncp->nc_nxt;
21237487Smckusick 		/* and insert on hash chain */
213*38768Smckusick 		nhp = &nchash[NHASH(ndp->ni_vp, ndp->ni_hash)];
21437487Smckusick 		insque(ncp, nhp);
21537487Smckusick 	}
21637487Smckusick }
21737487Smckusick 
21837487Smckusick /*
21937487Smckusick  * Name cache initialization, from main() when we are booting
22037487Smckusick  */
22137487Smckusick nchinit()
22237487Smckusick {
22337487Smckusick 	register union nchash *nchp;
22437487Smckusick 	register struct namecache *ncp;
22537487Smckusick 
22637487Smckusick 	nchhead = 0;
22737487Smckusick 	nchtail = &nchhead;
22837487Smckusick 	for (ncp = namecache; ncp < &namecache[nchsize]; ncp++) {
22937487Smckusick 		ncp->nc_forw = ncp;			/* hash chain */
23037487Smckusick 		ncp->nc_back = ncp;
23137487Smckusick 		ncp->nc_nxt = NULL;			/* lru chain */
23237487Smckusick 		*nchtail = ncp;
23337487Smckusick 		ncp->nc_prev = nchtail;
23437487Smckusick 		nchtail = &ncp->nc_nxt;
23537487Smckusick 		/* all else is zero already */
23637487Smckusick 	}
23737487Smckusick 	for (nchp = nchash; nchp < &nchash[NCHHASH]; 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
245*38768Smckusick  * hide entries that would now be invalid
24637487Smckusick  */
24737487Smckusick cache_purge(vp)
248*38768Smckusick 	struct vnode *vp;
24937487Smckusick {
250*38768Smckusick 	struct namecache *ncp;
25137487Smckusick 
252*38768Smckusick 	vp->v_id = ++nextvnodeid;
253*38768Smckusick 	if (nextvnodeid != 0)
254*38768Smckusick 		return;
255*38768Smckusick 	for (ncp = namecache; ncp < &namecache[nchsize]; ncp++) {
256*38768Smckusick 		ncp->nc_vpid = 0;
257*38768Smckusick 		ncp->nc_dvpid = 0;
25837487Smckusick 	}
259*38768Smckusick 	vp->v_id = ++nextvnodeid;
26037487Smckusick }
26137487Smckusick 
26237487Smckusick /*
26337487Smckusick  * Cache flush, a whole filesystem; called when filesys is umounted to
26437487Smckusick  * remove entries that would now be invalid
26537487Smckusick  *
26637487Smckusick  * The line "nxtcp = nchhead" near the end is to avoid potential problems
26737487Smckusick  * if the cache lru chain is modified while we are dumping the
26837487Smckusick  * inode.  This makes the algorithm O(n^2), but do you think I care?
26937487Smckusick  */
27037487Smckusick cache_purgevfs(mp)
27137487Smckusick 	register struct mount *mp;
27237487Smckusick {
27337487Smckusick 	register struct namecache *ncp, *nxtcp;
27437487Smckusick 
27537487Smckusick 	for (ncp = nchhead; ncp; ncp = nxtcp) {
27637487Smckusick 		nxtcp = ncp->nc_nxt;
277*38768Smckusick 		if (ncp->nc_dvp == NULL || ncp->nc_dvp->v_mount != mp)
27837487Smckusick 			continue;
27937487Smckusick 		/* free the resources we had */
28037487Smckusick 		ncp->nc_vp = NULL;
281*38768Smckusick 		ncp->nc_dvp = NULL;
28237487Smckusick 		remque(ncp);		/* remove entry from its hash chain */
28337487Smckusick 		ncp->nc_forw = ncp;	/* and make a dummy one */
28437487Smckusick 		ncp->nc_back = ncp;
28537487Smckusick 		/* delete this entry from LRU chain */
28637487Smckusick 		*ncp->nc_prev = nxtcp;
28737487Smckusick 		if (nxtcp)
28837487Smckusick 			nxtcp->nc_prev = ncp->nc_prev;
28937487Smckusick 		else
29037487Smckusick 			nchtail = ncp->nc_prev;
29137487Smckusick 		/* cause rescan of list, it may have altered */
29237487Smckusick 		nxtcp = nchhead;
29337487Smckusick 		/* put the now-free entry at head of LRU */
29437487Smckusick 		ncp->nc_nxt = nxtcp;
29537487Smckusick 		ncp->nc_prev = &nchhead;
29637487Smckusick 		nxtcp->nc_prev = &ncp->nc_nxt;
29737487Smckusick 		nchhead = ncp;
29837487Smckusick 	}
29937487Smckusick }
300