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.2 (Berkeley) 07/05/94 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 cnp->cn_flags &= ~MAKEENTRY; 72 return (0); 73 } 74 if (cnp->cn_namelen > NCHNAMLEN) { 75 nchstats.ncs_long++; 76 cnp->cn_flags &= ~MAKEENTRY; 77 return (0); 78 } 79 ncpp = &nchashtbl[cnp->cn_hash & nchash]; 80 for (ncp = *ncpp; ncp; ncp = ncp->nc_forw) { 81 if (ncp->nc_dvp == dvp && 82 ncp->nc_dvpid == dvp->v_id && 83 ncp->nc_nlen == cnp->cn_namelen && 84 !bcmp(ncp->nc_name, cnp->cn_nameptr, (u_int)ncp->nc_nlen)) 85 break; 86 } 87 if (ncp == NULL) { 88 nchstats.ncs_miss++; 89 return (0); 90 } 91 if (!(cnp->cn_flags & MAKEENTRY)) { 92 nchstats.ncs_badhits++; 93 } else if (ncp->nc_vp == NULL) { 94 if (cnp->cn_nameiop != CREATE) { 95 nchstats.ncs_neghits++; 96 /* 97 * Move this slot to end of LRU chain, 98 * if not already there. 99 */ 100 if (ncp->nc_nxt) { 101 /* remove from LRU chain */ 102 *ncp->nc_prev = ncp->nc_nxt; 103 ncp->nc_nxt->nc_prev = ncp->nc_prev; 104 /* and replace at end of it */ 105 ncp->nc_nxt = NULL; 106 ncp->nc_prev = nchtail; 107 *nchtail = ncp; 108 nchtail = &ncp->nc_nxt; 109 } 110 return (ENOENT); 111 } 112 } else if (ncp->nc_vpid != ncp->nc_vp->v_id) { 113 nchstats.ncs_falsehits++; 114 } else { 115 nchstats.ncs_goodhits++; 116 /* 117 * move this slot to end of LRU chain, if not already there 118 */ 119 if (ncp->nc_nxt) { 120 /* remove from LRU chain */ 121 *ncp->nc_prev = ncp->nc_nxt; 122 ncp->nc_nxt->nc_prev = ncp->nc_prev; 123 /* and replace at end of it */ 124 ncp->nc_nxt = NULL; 125 ncp->nc_prev = nchtail; 126 *nchtail = ncp; 127 nchtail = &ncp->nc_nxt; 128 } 129 *vpp = ncp->nc_vp; 130 return (-1); 131 } 132 133 /* 134 * Last component and we are renaming or deleting, 135 * the cache entry is invalid, or otherwise don't 136 * want cache entry to exist. 137 */ 138 /* remove from LRU chain */ 139 if (ncq = ncp->nc_nxt) 140 ncq->nc_prev = ncp->nc_prev; 141 else 142 nchtail = ncp->nc_prev; 143 *ncp->nc_prev = ncq; 144 /* remove from hash chain */ 145 if (ncq = ncp->nc_forw) 146 ncq->nc_back = ncp->nc_back; 147 *ncp->nc_back = ncq; 148 /* and make a dummy hash chain */ 149 ncp->nc_forw = NULL; 150 ncp->nc_back = NULL; 151 /* insert at head of LRU list (first to grab) */ 152 if (ncq = nchhead) 153 ncq->nc_prev = &ncp->nc_nxt; 154 else 155 nchtail = &ncp->nc_nxt; 156 nchhead = ncp; 157 ncp->nc_nxt = ncq; 158 ncp->nc_prev = &nchhead; 159 return (0); 160 } 161 162 /* 163 * Add an entry to the cache 164 */ 165 cache_enter(dvp, vp, cnp) 166 struct vnode *dvp; 167 struct vnode *vp; 168 struct componentname *cnp; 169 { 170 register struct namecache *ncp, *ncq, **ncpp; 171 172 #ifdef DIAGNOSTIC 173 if (cnp->cn_namelen > NCHNAMLEN) 174 panic("cache_enter: name too long"); 175 #endif 176 if (!doingcache) 177 return; 178 /* 179 * Free the cache slot at head of lru chain. 180 */ 181 if (numcache < desiredvnodes) { 182 ncp = (struct namecache *) 183 malloc((u_long)sizeof *ncp, M_CACHE, M_WAITOK); 184 bzero((char *)ncp, sizeof *ncp); 185 numcache++; 186 } else if (ncp = nchhead) { 187 /* remove from lru chain */ 188 if (ncq = ncp->nc_nxt) 189 ncq->nc_prev = ncp->nc_prev; 190 else 191 nchtail = ncp->nc_prev; 192 *ncp->nc_prev = ncq; 193 /* remove from old hash chain, if on one */ 194 if (ncp->nc_back) { 195 if (ncq = ncp->nc_forw) 196 ncq->nc_back = ncp->nc_back; 197 *ncp->nc_back = ncq; 198 ncp->nc_forw = NULL; 199 ncp->nc_back = NULL; 200 } 201 } else 202 return; 203 /* grab the vnode we just found */ 204 ncp->nc_vp = vp; 205 if (vp) 206 ncp->nc_vpid = vp->v_id; 207 else 208 ncp->nc_vpid = 0; 209 /* fill in cache info */ 210 ncp->nc_dvp = dvp; 211 ncp->nc_dvpid = dvp->v_id; 212 ncp->nc_nlen = cnp->cn_namelen; 213 bcopy(cnp->cn_nameptr, ncp->nc_name, (unsigned)ncp->nc_nlen); 214 /* link at end of lru chain */ 215 ncp->nc_nxt = NULL; 216 ncp->nc_prev = nchtail; 217 *nchtail = ncp; 218 nchtail = &ncp->nc_nxt; 219 /* and insert on hash chain */ 220 ncpp = &nchashtbl[cnp->cn_hash & nchash]; 221 if (ncq = *ncpp) 222 ncq->nc_back = &ncp->nc_forw; 223 ncp->nc_forw = ncq; 224 ncp->nc_back = ncpp; 225 *ncpp = ncp; 226 } 227 228 /* 229 * Name cache initialization, from vfs_init() when we are booting 230 */ 231 nchinit() 232 { 233 234 nchtail = &nchhead; 235 nchashtbl = hashinit(desiredvnodes, M_CACHE, &nchash); 236 } 237 238 /* 239 * Cache flush, a particular vnode; called when a vnode is renamed to 240 * hide entries that would now be invalid 241 */ 242 cache_purge(vp) 243 struct vnode *vp; 244 { 245 struct namecache *ncp, **ncpp; 246 247 vp->v_id = ++nextvnodeid; 248 if (nextvnodeid != 0) 249 return; 250 for (ncpp = &nchashtbl[nchash]; ncpp >= nchashtbl; ncpp--) { 251 for (ncp = *ncpp; ncp; ncp = ncp->nc_forw) { 252 ncp->nc_vpid = 0; 253 ncp->nc_dvpid = 0; 254 } 255 } 256 vp->v_id = ++nextvnodeid; 257 } 258 259 /* 260 * Cache flush, a whole filesystem; called when filesys is umounted to 261 * remove entries that would now be invalid 262 * 263 * The line "nxtcp = nchhead" near the end is to avoid potential problems 264 * if the cache lru chain is modified while we are dumping the 265 * inode. This makes the algorithm O(n^2), but do you think I care? 266 */ 267 cache_purgevfs(mp) 268 struct mount *mp; 269 { 270 register struct namecache *ncp, *nxtcp; 271 272 for (ncp = nchhead; ncp; ncp = nxtcp) { 273 if (ncp->nc_dvp == NULL || ncp->nc_dvp->v_mount != mp) { 274 nxtcp = ncp->nc_nxt; 275 continue; 276 } 277 /* free the resources we had */ 278 ncp->nc_vp = NULL; 279 ncp->nc_dvp = NULL; 280 /* remove from old hash chain, if on one */ 281 if (ncp->nc_back) { 282 if (nxtcp = ncp->nc_forw) 283 nxtcp->nc_back = ncp->nc_back; 284 *ncp->nc_back = nxtcp; 285 ncp->nc_forw = NULL; 286 ncp->nc_back = NULL; 287 } 288 /* delete this entry from LRU chain */ 289 if (nxtcp = ncp->nc_nxt) 290 nxtcp->nc_prev = ncp->nc_prev; 291 else 292 nchtail = ncp->nc_prev; 293 *ncp->nc_prev = nxtcp; 294 /* cause rescan of list, it may have altered */ 295 /* also put the now-free entry at head of LRU */ 296 if (nxtcp = nchhead) 297 nxtcp->nc_prev = &ncp->nc_nxt; 298 else 299 nchtail = &ncp->nc_nxt; 300 nchhead = ncp; 301 ncp->nc_nxt = nxtcp; 302 ncp->nc_prev = &nchhead; 303 } 304 } 305