Pass flags to vinvalbuf so it can optionally keep indirect blocks.
[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 *
3d73154e 7 * @(#)vfs_cache.c 7.15 (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 */
12e9ded3 40struct namecache **nchashtbl;
1dfa72b1
KM
41u_long nchash; /* size of hash table - 1 */
42long numcache; /* number of cache entries allocated */
6f7b6c68
KM
43struct namecache *nchhead, **nchtail; /* LRU chain pointers */
44struct nchstats nchstats; /* cache effectiveness statistics */
45
ea5eb849
KM
46int doingcache = 1; /* 1 => enable the cache */
47
6f7b6c68
KM
48/*
49 * Look for a the name in the cache. We don't do this
50 * if the segment name is long, simply so the cache can avoid
51 * holding long names (which would either waste space, or
52 * add greatly to the complexity).
ea5eb849
KM
53 *
54 * Lookup is called with ni_dvp pointing to the directory to search,
55 * ni_ptr pointing to the name of the entry being sought, ni_namelen
56 * tells the length of the name, and ni_hash contains a hash of
57 * the name. If the lookup succeeds, the vnode is returned in ni_vp
58 * and a status of -1 is returned. If the lookup determines that
59 * the name does not exist (negative cacheing), a status of ENOENT
60 * is returned. If the lookup fails, a status of zero is returned.
6f7b6c68 61 */
cfef4373 62int
f7c1c550 63cache_lookup(dvp, vpp, cnp)
cfef4373
JH
64 struct vnode *dvp;
65 struct vnode **vpp;
66 struct componentname *cnp;
6f7b6c68 67{
12e9ded3 68 register struct namecache *ncp, *ncq, **ncpp;
6f7b6c68 69
ea5eb849
KM
70 if (!doingcache)
71 return (0);
cfef4373 72 if (cnp->cn_namelen > NCHNAMLEN) {
6f7b6c68 73 nchstats.ncs_long++;
cfef4373 74 cnp->cn_flags &= ~MAKEENTRY;
6f7b6c68
KM
75 return (0);
76 }
12e9ded3
KM
77 ncpp = &nchashtbl[cnp->cn_hash & nchash];
78 for (ncp = *ncpp; ncp; ncp = ncp->nc_forw) {
ea5eb849
KM
79 if (ncp->nc_dvp == dvp &&
80 ncp->nc_dvpid == dvp->v_id &&
cfef4373 81 ncp->nc_nlen == cnp->cn_namelen &&
12e9ded3 82 !bcmp(ncp->nc_name, cnp->cn_nameptr, (u_int)ncp->nc_nlen))
6f7b6c68
KM
83 break;
84 }
12e9ded3 85 if (ncp == NULL) {
6f7b6c68 86 nchstats.ncs_miss++;
6f7b6c68
KM
87 return (0);
88 }
cfef4373 89 if (!(cnp->cn_flags & MAKEENTRY)) {
ea5eb849
KM
90 nchstats.ncs_badhits++;
91 } else if (ncp->nc_vp == NULL) {
f7c1c550 92 if (cnp->cn_nameiop != CREATE) {
e828c39a
KM
93 nchstats.ncs_neghits++;
94 /*
95 * Move this slot to end of LRU chain,
96 * if not already there.
97 */
98 if (ncp->nc_nxt) {
99 /* remove from LRU chain */
100 *ncp->nc_prev = ncp->nc_nxt;
101 ncp->nc_nxt->nc_prev = ncp->nc_prev;
102 /* and replace at end of it */
103 ncp->nc_nxt = NULL;
104 ncp->nc_prev = nchtail;
105 *nchtail = ncp;
106 nchtail = &ncp->nc_nxt;
107 }
108 return (ENOENT);
6f7b6c68 109 }
ea5eb849
KM
110 } else if (ncp->nc_vpid != ncp->nc_vp->v_id) {
111 nchstats.ncs_falsehits++;
112 } else {
6f7b6c68 113 nchstats.ncs_goodhits++;
ea5eb849
KM
114 /*
115 * move this slot to end of LRU chain, if not already there
116 */
117 if (ncp->nc_nxt) {
118 /* remove from LRU chain */
119 *ncp->nc_prev = ncp->nc_nxt;
120 ncp->nc_nxt->nc_prev = ncp->nc_prev;
121 /* and replace at end of it */
122 ncp->nc_nxt = NULL;
123 ncp->nc_prev = nchtail;
124 *nchtail = ncp;
125 nchtail = &ncp->nc_nxt;
126 }
cfef4373 127 *vpp = ncp->nc_vp;
ea5eb849 128 return (-1);
6f7b6c68
KM
129 }
130
131 /*
132 * Last component and we are renaming or deleting,
133 * the cache entry is invalid, or otherwise don't
134 * want cache entry to exist.
135 */
6f7b6c68 136 /* remove from LRU chain */
12e9ded3
KM
137 if (ncq = ncp->nc_nxt)
138 ncq->nc_prev = ncp->nc_prev;
6f7b6c68
KM
139 else
140 nchtail = ncp->nc_prev;
12e9ded3 141 *ncp->nc_prev = ncq;
ea5eb849 142 /* remove from hash chain */
12e9ded3
KM
143 if (ncq = ncp->nc_forw)
144 ncq->nc_back = ncp->nc_back;
145 *ncp->nc_back = ncq;
146 /* and make a dummy hash chain */
147 ncp->nc_forw = NULL;
148 ncp->nc_back = NULL;
6f7b6c68 149 /* insert at head of LRU list (first to grab) */
3d73154e
KM
150 if (ncq = nchhead)
151 ncq->nc_prev = &ncp->nc_nxt;
152 else
153 nchtail = &ncp->nc_nxt;
6f7b6c68 154 nchhead = ncp;
3d73154e
KM
155 ncp->nc_nxt = ncq;
156 ncp->nc_prev = &nchhead;
6f7b6c68
KM
157 return (0);
158}
159
160/*
161 * Add an entry to the cache
162 */
f7c1c550 163cache_enter(dvp, vp, cnp)
cfef4373
JH
164 struct vnode *dvp;
165 struct vnode *vp;
166 struct componentname *cnp;
6f7b6c68 167{
12e9ded3 168 register struct namecache *ncp, *ncq, **ncpp;
6f7b6c68 169
7f213083
KM
170#ifdef DIAGNOSTIC
171 if (cnp->cn_namelen > NCHNAMLEN)
172 panic("cache_enter: name too long");
173#endif
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 185 /* remove from lru chain */
12e9ded3
KM
186 if (ncq = ncp->nc_nxt)
187 ncq->nc_prev = ncp->nc_prev;
6f7b6c68
KM
188 else
189 nchtail = ncp->nc_prev;
12e9ded3 190 *ncp->nc_prev = ncq;
40d2c81e
KM
191 /* remove from old hash chain, if on one */
192 if (ncp->nc_back) {
193 if (ncq = ncp->nc_forw)
194 ncq->nc_back = ncp->nc_back;
195 *ncp->nc_back = ncq;
196 ncp->nc_forw = NULL;
197 ncp->nc_back = NULL;
198 }
1dfa72b1
KM
199 } else
200 return;
201 /* grab the vnode we just found */
cfef4373
JH
202 ncp->nc_vp = vp;
203 if (vp)
204 ncp->nc_vpid = vp->v_id;
1dfa72b1
KM
205 else
206 ncp->nc_vpid = 0;
207 /* fill in cache info */
cfef4373
JH
208 ncp->nc_dvp = dvp;
209 ncp->nc_dvpid = dvp->v_id;
210 ncp->nc_nlen = cnp->cn_namelen;
211 bcopy(cnp->cn_nameptr, ncp->nc_name, (unsigned)ncp->nc_nlen);
1dfa72b1
KM
212 /* link at end of lru chain */
213 ncp->nc_nxt = NULL;
214 ncp->nc_prev = nchtail;
215 *nchtail = ncp;
216 nchtail = &ncp->nc_nxt;
217 /* and insert on hash chain */
12e9ded3
KM
218 ncpp = &nchashtbl[cnp->cn_hash & nchash];
219 if (ncq = *ncpp)
220 ncq->nc_back = &ncp->nc_forw;
221 ncp->nc_forw = ncq;
222 ncp->nc_back = ncpp;
223 *ncpp = ncp;
6f7b6c68
KM
224}
225
226/*
1dfa72b1 227 * Name cache initialization, from vfs_init() when we are booting
6f7b6c68
KM
228 */
229nchinit()
230{
6f7b6c68 231
6f7b6c68 232 nchtail = &nchhead;
12e9ded3 233 nchashtbl = hashinit(desiredvnodes, M_CACHE, &nchash);
6f7b6c68
KM
234}
235
236/*
237 * Cache flush, a particular vnode; called when a vnode is renamed to
ea5eb849 238 * hide entries that would now be invalid
6f7b6c68
KM
239 */
240cache_purge(vp)
ea5eb849 241 struct vnode *vp;
6f7b6c68 242{
12e9ded3 243 struct namecache *ncp, **ncpp;
6f7b6c68 244
ea5eb849
KM
245 vp->v_id = ++nextvnodeid;
246 if (nextvnodeid != 0)
247 return;
12e9ded3
KM
248 for (ncpp = &nchashtbl[nchash]; ncpp >= nchashtbl; ncpp--) {
249 for (ncp = *ncpp; ncp; ncp = ncp->nc_forw) {
1dfa72b1
KM
250 ncp->nc_vpid = 0;
251 ncp->nc_dvpid = 0;
252 }
6f7b6c68 253 }
ea5eb849 254 vp->v_id = ++nextvnodeid;
6f7b6c68
KM
255}
256
257/*
258 * Cache flush, a whole filesystem; called when filesys is umounted to
259 * remove entries that would now be invalid
260 *
261 * The line "nxtcp = nchhead" near the end is to avoid potential problems
262 * if the cache lru chain is modified while we are dumping the
263 * inode. This makes the algorithm O(n^2), but do you think I care?
264 */
265cache_purgevfs(mp)
aacc1bff 266 struct mount *mp;
6f7b6c68
KM
267{
268 register struct namecache *ncp, *nxtcp;
269
270 for (ncp = nchhead; ncp; ncp = nxtcp) {
12e9ded3
KM
271 if (ncp->nc_dvp == NULL || ncp->nc_dvp->v_mount != mp) {
272 nxtcp = ncp->nc_nxt;
6f7b6c68 273 continue;
12e9ded3 274 }
6f7b6c68
KM
275 /* free the resources we had */
276 ncp->nc_vp = NULL;
ea5eb849 277 ncp->nc_dvp = NULL;
40d2c81e
KM
278 /* remove from old hash chain, if on one */
279 if (ncp->nc_back) {
280 if (nxtcp = ncp->nc_forw)
281 nxtcp->nc_back = ncp->nc_back;
282 *ncp->nc_back = nxtcp;
283 ncp->nc_forw = NULL;
284 ncp->nc_back = NULL;
285 }
6f7b6c68 286 /* delete this entry from LRU chain */
12e9ded3 287 if (nxtcp = ncp->nc_nxt)
6f7b6c68
KM
288 nxtcp->nc_prev = ncp->nc_prev;
289 else
290 nchtail = ncp->nc_prev;
12e9ded3 291 *ncp->nc_prev = nxtcp;
6f7b6c68 292 /* cause rescan of list, it may have altered */
3d73154e
KM
293 /* also put the now-free entry at head of LRU */
294 if (nxtcp = nchhead)
295 nxtcp->nc_prev = &ncp->nc_nxt;
296 else
297 nchtail = &ncp->nc_nxt;
298 nchhead = ncp;
6f7b6c68
KM
299 ncp->nc_nxt = nxtcp;
300 ncp->nc_prev = &nchhead;
6f7b6c68
KM
301 }
302}