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