1 /* 2 * Copyright (c) 1989, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 * 7 * @(#)vfs_cache.c 8.1 (Berkeley) 06/10/93 8 */ 9 10 #include <sys/param.h> 11 #include <sys/systm.h> 12 #include <sys/time.h> 13 #include <sys/mount.h> 14 #include <sys/vnode.h> 15 #include <sys/namei.h> 16 #include <sys/errno.h> 17 #include <sys/malloc.h> 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 25 * obtained from (vp, name) where vp refers to the directory 26 * containing name. 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 */ 40 struct namecache **nchashtbl; 41 u_long nchash; /* size of hash table - 1 */ 42 long numcache; /* number of cache entries allocated */ 43 struct namecache *nchhead, **nchtail; /* LRU chain pointers */ 44 struct nchstats nchstats; /* cache effectiveness statistics */ 45 46 int doingcache = 1; /* 1 => enable the cache */ 47 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). 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. 61 */ 62 int 63 cache_lookup(dvp, vpp, cnp) 64 struct vnode *dvp; 65 struct vnode **vpp; 66 struct componentname *cnp; 67 { 68 register struct namecache *ncp, *ncq, **ncpp; 69 70 if (!doingcache) 71 return (0); 72 if (cnp->cn_namelen > NCHNAMLEN) { 73 nchstats.ncs_long++; 74 cnp->cn_flags &= ~MAKEENTRY; 75 return (0); 76 } 77 ncpp = &nchashtbl[cnp->cn_hash & nchash]; 78 for (ncp = *ncpp; ncp; ncp = ncp->nc_forw) { 79 if (ncp->nc_dvp == dvp && 80 ncp->nc_dvpid == dvp->v_id && 81 ncp->nc_nlen == cnp->cn_namelen && 82 !bcmp(ncp->nc_name, cnp->cn_nameptr, (u_int)ncp->nc_nlen)) 83 break; 84 } 85 if (ncp == NULL) { 86 nchstats.ncs_miss++; 87 return (0); 88 } 89 if (!(cnp->cn_flags & MAKEENTRY)) { 90 nchstats.ncs_badhits++; 91 } else if (ncp->nc_vp == NULL) { 92 if (cnp->cn_nameiop != CREATE) { 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); 109 } 110 } else if (ncp->nc_vpid != ncp->nc_vp->v_id) { 111 nchstats.ncs_falsehits++; 112 } else { 113 nchstats.ncs_goodhits++; 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 } 127 *vpp = ncp->nc_vp; 128 return (-1); 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 */ 136 /* remove from LRU chain */ 137 if (ncq = ncp->nc_nxt) 138 ncq->nc_prev = ncp->nc_prev; 139 else 140 nchtail = ncp->nc_prev; 141 *ncp->nc_prev = ncq; 142 /* remove from hash chain */ 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; 149 /* insert at head of LRU list (first to grab) */ 150 if (ncq = nchhead) 151 ncq->nc_prev = &ncp->nc_nxt; 152 else 153 nchtail = &ncp->nc_nxt; 154 nchhead = ncp; 155 ncp->nc_nxt = ncq; 156 ncp->nc_prev = &nchhead; 157 return (0); 158 } 159 160 /* 161 * Add an entry to the cache 162 */ 163 cache_enter(dvp, vp, cnp) 164 struct vnode *dvp; 165 struct vnode *vp; 166 struct componentname *cnp; 167 { 168 register struct namecache *ncp, *ncq, **ncpp; 169 170 #ifdef DIAGNOSTIC 171 if (cnp->cn_namelen > NCHNAMLEN) 172 panic("cache_enter: name too long"); 173 #endif 174 if (!doingcache) 175 return; 176 /* 177 * Free the cache slot at head of lru chain. 178 */ 179 if (numcache < desiredvnodes) { 180 ncp = (struct namecache *) 181 malloc((u_long)sizeof *ncp, M_CACHE, M_WAITOK); 182 bzero((char *)ncp, sizeof *ncp); 183 numcache++; 184 } else if (ncp = nchhead) { 185 /* remove from lru chain */ 186 if (ncq = ncp->nc_nxt) 187 ncq->nc_prev = ncp->nc_prev; 188 else 189 nchtail = ncp->nc_prev; 190 *ncp->nc_prev = ncq; 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 } 199 } else 200 return; 201 /* grab the vnode we just found */ 202 ncp->nc_vp = vp; 203 if (vp) 204 ncp->nc_vpid = vp->v_id; 205 else 206 ncp->nc_vpid = 0; 207 /* fill in cache info */ 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); 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 */ 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; 224 } 225 226 /* 227 * Name cache initialization, from vfs_init() when we are booting 228 */ 229 nchinit() 230 { 231 232 nchtail = &nchhead; 233 nchashtbl = hashinit(desiredvnodes, M_CACHE, &nchash); 234 } 235 236 /* 237 * Cache flush, a particular vnode; called when a vnode is renamed to 238 * hide entries that would now be invalid 239 */ 240 cache_purge(vp) 241 struct vnode *vp; 242 { 243 struct namecache *ncp, **ncpp; 244 245 vp->v_id = ++nextvnodeid; 246 if (nextvnodeid != 0) 247 return; 248 for (ncpp = &nchashtbl[nchash]; ncpp >= nchashtbl; ncpp--) { 249 for (ncp = *ncpp; ncp; ncp = ncp->nc_forw) { 250 ncp->nc_vpid = 0; 251 ncp->nc_dvpid = 0; 252 } 253 } 254 vp->v_id = ++nextvnodeid; 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 */ 265 cache_purgevfs(mp) 266 struct mount *mp; 267 { 268 register struct namecache *ncp, *nxtcp; 269 270 for (ncp = nchhead; ncp; ncp = nxtcp) { 271 if (ncp->nc_dvp == NULL || ncp->nc_dvp->v_mount != mp) { 272 nxtcp = ncp->nc_nxt; 273 continue; 274 } 275 /* free the resources we had */ 276 ncp->nc_vp = NULL; 277 ncp->nc_dvp = NULL; 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 } 286 /* delete this entry from LRU chain */ 287 if (nxtcp = ncp->nc_nxt) 288 nxtcp->nc_prev = ncp->nc_prev; 289 else 290 nchtail = ncp->nc_prev; 291 *ncp->nc_prev = nxtcp; 292 /* cause rescan of list, it may have altered */ 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; 299 ncp->nc_nxt = nxtcp; 300 ncp->nc_prev = &nchhead; 301 } 302 } 303