1/* 2 * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc. 3 * All Rights Reserved. 4 * 5 * This program is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU General Public License as 7 * published by the Free Software Foundation. 8 * 9 * This program is distributed in the hope that it would be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write the Free Software Foundation, 16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 17 */ 18#include "xfs.h" 19#include "xfs_fs.h" 20#include "xfs_types.h" 21#include "xfs_bit.h" 22#include "xfs_log.h" 23#include "xfs_inum.h" 24#include "xfs_trans.h" 25#include "xfs_sb.h" 26#include "xfs_ag.h" 27#include "xfs_dir.h" 28#include "xfs_dir2.h" 29#include "xfs_dmapi.h" 30#include "xfs_mount.h" 31#include "xfs_bmap_btree.h" 32#include "xfs_alloc_btree.h" 33#include "xfs_ialloc_btree.h" 34#include "xfs_dir_sf.h" 35#include "xfs_dir2_sf.h" 36#include "xfs_attr_sf.h" 37#include "xfs_dinode.h" 38#include "xfs_inode.h" 39#include "xfs_inode_item.h" 40#include "xfs_itable.h" 41#include "xfs_btree.h" 42#include "xfs_alloc.h" 43#include "xfs_ialloc.h" 44#include "xfs_bmap.h" 45#include "xfs_attr.h" 46#include "xfs_error.h" 47#include "xfs_buf_item.h" 48#include "xfs_refcache.h" 49 50STATIC lock_t xfs_refcache_lock; 51STATIC xfs_inode_t **xfs_refcache; 52STATIC int xfs_refcache_index; 53STATIC int xfs_refcache_busy; 54STATIC int xfs_refcache_count; 55 56void 57xfs_refcache_init(void) 58{ 59 spinlock_init(&xfs_refcache_lock, "xfs_refcache"); 60} 61/* 62 * Insert the given inode into the reference cache. 63 */ 64void 65xfs_refcache_insert( 66 xfs_inode_t *ip) 67{ 68 vnode_t *vp; 69 xfs_inode_t *release_ip; 70 xfs_inode_t **refcache; 71 72 ASSERT(ismrlocked(&(ip->i_iolock), MR_UPDATE)); 73 74 /* 75 * If an unmount is busy blowing entries out of the cache, 76 * then don't bother. 77 */ 78 if (xfs_refcache_busy) { 79 return; 80 } 81 82 /* 83 * If we tuned the refcache down to zero, don't do anything. 84 */ 85 if (!xfs_refcache_size) { 86 return; 87 } 88 89 /* 90 * The inode is already in the refcache, so don't bother 91 * with it. 92 */ 93 if (ip->i_refcache != NULL) { 94 return; 95 } 96 97 vp = XFS_ITOV(ip); 98 /* ASSERT(vp->v_count > 0); */ 99 VN_HOLD(vp); 100 101 /* 102 * We allocate the reference cache on use so that we don't 103 * waste the memory on systems not being used as NFS servers. 104 */ 105 if (xfs_refcache == NULL) { 106 refcache = (xfs_inode_t **)kmem_zalloc(XFS_REFCACHE_SIZE_MAX * 107 sizeof(xfs_inode_t *), 108 KM_SLEEP); 109 } else { 110 refcache = NULL; 111 } 112 113 spin_lock(&xfs_refcache_lock); 114 115 /* 116 * If we allocated memory for the refcache above and it still 117 * needs it, then use the memory we allocated. Otherwise we'll 118 * free the memory below. 119 */ 120 if (refcache != NULL) { 121 if (xfs_refcache == NULL) { 122 xfs_refcache = refcache; 123 refcache = NULL; 124 } 125 } 126 127 /* 128 * If an unmount is busy clearing out the cache, don't add new 129 * entries to it. 130 */ 131 if (xfs_refcache_busy) { 132 spin_unlock(&xfs_refcache_lock); 133 VN_RELE(vp); 134 /* 135 * If we allocated memory for the refcache above but someone 136 * else beat us to using it, then free the memory now. 137 */ 138 if (refcache != NULL) { 139 kmem_free(refcache, 140 XFS_REFCACHE_SIZE_MAX * sizeof(xfs_inode_t *)); 141 } 142 return; 143 } 144 release_ip = xfs_refcache[xfs_refcache_index]; 145 if (release_ip != NULL) { 146 release_ip->i_refcache = NULL; 147 xfs_refcache_count--; 148 ASSERT(xfs_refcache_count >= 0); 149 } 150 xfs_refcache[xfs_refcache_index] = ip; 151 ASSERT(ip->i_refcache == NULL); 152 ip->i_refcache = &(xfs_refcache[xfs_refcache_index]); 153 xfs_refcache_count++; 154 ASSERT(xfs_refcache_count <= xfs_refcache_size); 155 xfs_refcache_index++; 156 if (xfs_refcache_index == xfs_refcache_size) { 157 xfs_refcache_index = 0; 158 } 159 spin_unlock(&xfs_refcache_lock); 160 161 /* 162 * Save the pointer to the inode to be released so that we can 163 * VN_RELE it once we've dropped our inode locks in xfs_rwunlock(). 164 * The pointer may be NULL, but that's OK. 165 */ 166 ip->i_release = release_ip; 167 168 /* 169 * If we allocated memory for the refcache above but someone 170 * else beat us to using it, then free the memory now. 171 */ 172 if (refcache != NULL) { 173 kmem_free(refcache, 174 XFS_REFCACHE_SIZE_MAX * sizeof(xfs_inode_t *)); 175 } 176} 177 178 179/* 180 * If the given inode is in the reference cache, purge its entry and 181 * release the reference on the vnode. 182 */ 183void 184xfs_refcache_purge_ip( 185 xfs_inode_t *ip) 186{ 187 vnode_t *vp; 188 int error; 189 190 /* 191 * If we're not pointing to our entry in the cache, then 192 * we must not be in the cache. 193 */ 194 if (ip->i_refcache == NULL) { 195 return; 196 } 197 198 spin_lock(&xfs_refcache_lock); 199 if (ip->i_refcache == NULL) { 200 spin_unlock(&xfs_refcache_lock); 201 return; 202 } 203 204 /* 205 * Clear both our pointer to the cache entry and its pointer 206 * back to us. 207 */ 208 ASSERT(*(ip->i_refcache) == ip); 209 *(ip->i_refcache) = NULL; 210 ip->i_refcache = NULL; 211 xfs_refcache_count--; 212 ASSERT(xfs_refcache_count >= 0); 213 spin_unlock(&xfs_refcache_lock); 214 215 vp = XFS_ITOV(ip); 216 /* ASSERT(vp->v_count > 1); */ 217 VOP_RELEASE(vp, error); 218 VN_RELE(vp); 219} 220 221 222/* 223 * This is called from the XFS unmount code to purge all entries for the 224 * given mount from the cache. It uses the refcache busy counter to 225 * make sure that new entries are not added to the cache as we purge them. 226 */ 227void 228xfs_refcache_purge_mp( 229 xfs_mount_t *mp) 230{ 231 vnode_t *vp; 232 int error, i; 233 xfs_inode_t *ip; 234 235 if (xfs_refcache == NULL) { 236 return; 237 } 238 239 spin_lock(&xfs_refcache_lock); 240 /* 241 * Bumping the busy counter keeps new entries from being added 242 * to the cache. We use a counter since multiple unmounts could 243 * be in here simultaneously. 244 */ 245 xfs_refcache_busy++; 246 247 for (i = 0; i < xfs_refcache_size; i++) { 248 ip = xfs_refcache[i]; 249 if ((ip != NULL) && (ip->i_mount == mp)) { 250 xfs_refcache[i] = NULL; 251 ip->i_refcache = NULL; 252 xfs_refcache_count--; 253 ASSERT(xfs_refcache_count >= 0); 254 spin_unlock(&xfs_refcache_lock); 255 vp = XFS_ITOV(ip); 256 VOP_RELEASE(vp, error); 257 VN_RELE(vp); 258 spin_lock(&xfs_refcache_lock); 259 } 260 } 261 262 xfs_refcache_busy--; 263 ASSERT(xfs_refcache_busy >= 0); 264 spin_unlock(&xfs_refcache_lock); 265} 266 267 268/* 269 * This is called from the XFS sync code to ensure that the refcache 270 * is emptied out over time. We purge a small number of entries with 271 * each call. 272 */ 273void 274xfs_refcache_purge_some(xfs_mount_t *mp) 275{ 276 int error, i; 277 xfs_inode_t *ip; 278 int iplist_index; 279 xfs_inode_t **iplist; 280 281 if ((xfs_refcache == NULL) || (xfs_refcache_count == 0)) { 282 return; 283 } 284 285 iplist_index = 0; 286 iplist = (xfs_inode_t **)kmem_zalloc(xfs_refcache_purge_count * 287 sizeof(xfs_inode_t *), KM_SLEEP); 288 289 spin_lock(&xfs_refcache_lock); 290 291 /* 292 * Store any inodes we find in the next several entries 293 * into the iplist array to be released after dropping 294 * the spinlock. We always start looking from the currently 295 * oldest place in the cache. We move the refcache index 296 * forward as we go so that we are sure to eventually clear 297 * out the entire cache when the system goes idle. 298 */ 299 for (i = 0; i < xfs_refcache_purge_count; i++) { 300 ip = xfs_refcache[xfs_refcache_index]; 301 if (ip != NULL) { 302 xfs_refcache[xfs_refcache_index] = NULL; 303 ip->i_refcache = NULL; 304 xfs_refcache_count--; 305 ASSERT(xfs_refcache_count >= 0); 306 iplist[iplist_index] = ip; 307 iplist_index++; 308 } 309 xfs_refcache_index++; 310 if (xfs_refcache_index == xfs_refcache_size) { 311 xfs_refcache_index = 0; 312 } 313 } 314 315 spin_unlock(&xfs_refcache_lock); 316 317 /* 318 * Now drop the inodes we collected. 319 */ 320 for (i = 0; i < iplist_index; i++) { 321 VOP_RELEASE(XFS_ITOV(iplist[i]), error); 322 VN_RELE(XFS_ITOV(iplist[i])); 323 } 324 325 kmem_free(iplist, xfs_refcache_purge_count * 326 sizeof(xfs_inode_t *)); 327} 328 329/* 330 * This is called when the refcache is dynamically resized 331 * via a sysctl. 332 * 333 * If the new size is smaller than the old size, purge all 334 * entries in slots greater than the new size, and move 335 * the index if necessary. 336 * 337 * If the refcache hasn't even been allocated yet, or the 338 * new size is larger than the old size, just set the value 339 * of xfs_refcache_size. 340 */ 341 342void 343xfs_refcache_resize(int xfs_refcache_new_size) 344{ 345 int i; 346 xfs_inode_t *ip; 347 int iplist_index = 0; 348 xfs_inode_t **iplist; 349 int error; 350 351 /* 352 * If the new size is smaller than the current size, 353 * purge entries to create smaller cache, and 354 * reposition index if necessary. 355 * Don't bother if no refcache yet. 356 */ 357 if (xfs_refcache && (xfs_refcache_new_size < xfs_refcache_size)) { 358 359 iplist = (xfs_inode_t **)kmem_zalloc(XFS_REFCACHE_SIZE_MAX * 360 sizeof(xfs_inode_t *), KM_SLEEP); 361 362 spin_lock(&xfs_refcache_lock); 363 364 for (i = xfs_refcache_new_size; i < xfs_refcache_size; i++) { 365 ip = xfs_refcache[i]; 366 if (ip != NULL) { 367 xfs_refcache[i] = NULL; 368 ip->i_refcache = NULL; 369 xfs_refcache_count--; 370 ASSERT(xfs_refcache_count >= 0); 371 iplist[iplist_index] = ip; 372 iplist_index++; 373 } 374 } 375 376 xfs_refcache_size = xfs_refcache_new_size; 377 378 /* 379 * Move index to beginning of cache if it's now past the end 380 */ 381 if (xfs_refcache_index >= xfs_refcache_new_size) 382 xfs_refcache_index = 0; 383 384 spin_unlock(&xfs_refcache_lock); 385 386 /* 387 * Now drop the inodes we collected. 388 */ 389 for (i = 0; i < iplist_index; i++) { 390 VOP_RELEASE(XFS_ITOV(iplist[i]), error); 391 VN_RELE(XFS_ITOV(iplist[i])); 392 } 393 394 kmem_free(iplist, XFS_REFCACHE_SIZE_MAX * 395 sizeof(xfs_inode_t *)); 396 } else { 397 spin_lock(&xfs_refcache_lock); 398 xfs_refcache_size = xfs_refcache_new_size; 399 spin_unlock(&xfs_refcache_lock); 400 } 401} 402 403void 404xfs_refcache_iunlock( 405 xfs_inode_t *ip, 406 uint lock_flags) 407{ 408 xfs_inode_t *release_ip; 409 int error; 410 411 release_ip = ip->i_release; 412 ip->i_release = NULL; 413 414 xfs_iunlock(ip, lock_flags); 415 416 if (release_ip != NULL) { 417 VOP_RELEASE(XFS_ITOV(release_ip), error); 418 VN_RELE(XFS_ITOV(release_ip)); 419 } 420} 421 422void 423xfs_refcache_destroy(void) 424{ 425 if (xfs_refcache) { 426 kmem_free(xfs_refcache, 427 XFS_REFCACHE_SIZE_MAX * sizeof(xfs_inode_t *)); 428 xfs_refcache = NULL; 429 } 430 spinlock_destroy(&xfs_refcache_lock); 431} 432