1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <sys/param.h> 27 #include <sys/types.h> 28 #include <sys/systm.h> 29 #include <sys/cred.h> 30 #include <sys/proc.h> 31 #include <sys/user.h> 32 #include <sys/vfs.h> 33 #include <sys/vnode.h> 34 #include <sys/pathname.h> 35 #include <sys/uio.h> 36 #include <sys/tiuser.h> 37 #include <sys/sysmacros.h> 38 #include <sys/kmem.h> 39 #include <sys/kobj.h> 40 #include <sys/mount.h> 41 #include <sys/ioctl.h> 42 #include <sys/statvfs.h> 43 #include <sys/errno.h> 44 #include <sys/debug.h> 45 #include <sys/cmn_err.h> 46 #include <sys/utsname.h> 47 #include <sys/modctl.h> 48 #include <sys/file.h> 49 #include <sys/stat.h> 50 #include <sys/fcntl.h> 51 #include <sys/callb.h> 52 53 #include <vm/hat.h> 54 #include <vm/as.h> 55 #include <vm/page.h> 56 #include <vm/pvn.h> 57 #include <vm/seg.h> 58 #include <vm/seg_map.h> 59 #include <vm/seg_vn.h> 60 #include <vm/rm.h> 61 #include <sys/fs/cachefs_fs.h> 62 63 extern time_t time; 64 65 /* forward references */ 66 int cachefs_rl_entry_get(cachefscache_t *, uint_t, rl_entry_t **); 67 void cachefs_garbage_collect_queue(cachefscache_t *cachep); 68 static time_t cachefs_gc_front_atime(cachefscache_t *cachep); 69 static void cachefs_garbage_collect(cachefscache_t *cachep); 70 static void cachefs_packed_pending(cachefscache_t *cachep); 71 72 73 #define RL_HEAD(cachep, type) \ 74 (&(cachep->c_rlinfo.rl_items[CACHEFS_RL_INDEX(type)])) 75 76 /* 77 * This function moves an RL entry from wherever it currently is to 78 * the back of the requested list. 79 */ 80 void 81 cachefs_rlent_moveto(cachefscache_t *cachep, 82 enum cachefs_rl_type type, uint_t entno, size_t blks) 83 { 84 mutex_enter(&cachep->c_contentslock); 85 cachefs_cache_dirty(cachep, 0); 86 cachefs_rlent_moveto_nolock(cachep, type, entno, blks); 87 mutex_exit(&cachep->c_contentslock); 88 } 89 90 void 91 cachefs_rlent_moveto_nolock(cachefscache_t *cachep, 92 enum cachefs_rl_type type, uint_t entno, size_t blks) 93 { 94 rl_entry_t *rl_ent; 95 uint_t prev, next; 96 cachefs_rl_listhead_t *lhp; 97 enum cachefs_rl_type otype; 98 int error; 99 100 ASSERT(entno != 0); 101 ASSERT((cachep->c_flags & (CACHE_NOCACHE|CACHE_NOFILL)) == 0); 102 ASSERT(MUTEX_HELD(&cachep->c_contentslock)); 103 ASSERT((CACHEFS_RL_START <= type) && (type <= CACHEFS_RL_END)); 104 105 error = cachefs_rl_entry_get(cachep, entno, &rl_ent); 106 if (error) 107 return; 108 next = rl_ent->rl_fwd_idx; 109 prev = rl_ent->rl_bkwd_idx; 110 otype = rl_ent->rl_current; 111 ASSERT((CACHEFS_RL_START <= otype) && (otype <= CACHEFS_RL_END)); 112 rl_ent->rl_current = CACHEFS_RL_NONE; 113 114 if (type == CACHEFS_RL_PACKED_PENDING) { 115 /* XXX sam: is this the right place to turn this on? */ 116 cachep->c_flags |= CACHE_PACKED_PENDING; 117 } 118 119 /* remove entry from its previous list */ 120 121 lhp = RL_HEAD(cachep, otype); 122 if ((lhp->rli_back == 0) || (lhp->rli_front == 0)) 123 ASSERT((lhp->rli_back == 0) && (lhp->rli_front == 0)); 124 125 if (lhp->rli_back == entno) 126 lhp->rli_back = next; 127 if (lhp->rli_front == entno) 128 lhp->rli_front = prev; 129 if (prev != 0) { 130 error = cachefs_rl_entry_get(cachep, prev, &rl_ent); 131 if (error) 132 return; 133 rl_ent->rl_fwd_idx = next; 134 } 135 if (next != 0) { 136 error = cachefs_rl_entry_get(cachep, next, &rl_ent); 137 if (error) 138 return; 139 rl_ent->rl_bkwd_idx = prev; 140 } 141 lhp->rli_blkcnt -= blks; 142 lhp->rli_itemcnt--; 143 144 /* add entry to its new list */ 145 146 lhp = RL_HEAD(cachep, type); 147 error = cachefs_rl_entry_get(cachep, entno, &rl_ent); 148 if (error) 149 return; 150 rl_ent->rl_current = type; 151 rl_ent->rl_bkwd_idx = 0; 152 rl_ent->rl_fwd_idx = lhp->rli_back; 153 154 if (lhp->rli_back != 0) { 155 ASSERT(lhp->rli_front != 0); 156 error = cachefs_rl_entry_get(cachep, lhp->rli_back, &rl_ent); 157 if (error) 158 return; 159 rl_ent->rl_bkwd_idx = entno; 160 } else { 161 ASSERT(lhp->rli_front == 0); 162 lhp->rli_front = entno; 163 } 164 lhp->rli_back = entno; 165 lhp->rli_blkcnt += blks; 166 lhp->rli_itemcnt++; 167 } 168 169 /* 170 * This function verifies that an rl entry is of the `correct' type. 171 * it's used for debugging (only?). 172 */ 173 174 /*ARGSUSED*/ 175 void 176 cachefs_rlent_verify(cachefscache_t *cachep, 177 enum cachefs_rl_type type, uint_t entno) 178 { 179 #ifdef CFSDEBUG 180 rl_entry_t *rl_ent; 181 int error; 182 183 ASSERT((CACHEFS_RL_START <= type) && (type <= CACHEFS_RL_END)); 184 185 mutex_enter(&cachep->c_contentslock); 186 187 error = cachefs_rl_entry_get(cachep, entno, &rl_ent); 188 if (!error && rl_ent->rl_current != type) { 189 #ifdef CFSRLDEBUG 190 printf("cachefs_rldebug: type should be %x\n", type); 191 cachefs_rl_debug_show(rl_ent); 192 debug_enter("cachefs_rlent_verify"); 193 #else /* CFSRLDEBUG */ 194 cmn_err(CE_WARN, "rl entry %x type = %x should be %x\n", 195 entno, rl_ent->rl_current, type); 196 #endif /* CFSRLDEBUG */ 197 } 198 199 mutex_exit(&cachep->c_contentslock); 200 #endif /* CFSDEBUG */ 201 } 202 203 /* 204 * Returns the rl data of the front of the specified resource list. 205 * Returns 0 for success, !0 if the list is empty. 206 */ 207 int 208 cachefs_rlent_data(cachefscache_t *cachep, rl_entry_t *valp, uint_t *entnop) 209 { 210 uint_t entno; 211 rl_entry_t *rl_ent; 212 int error = 0; 213 cachefs_rl_listhead_t *lhp; 214 enum cachefs_rl_type type; 215 216 ASSERT((cachep->c_flags & CACHE_NOCACHE) == 0); 217 218 if (entnop == NULL) 219 entnop = &entno; 220 *entnop = 0; 221 222 mutex_enter(&cachep->c_contentslock); 223 224 type = valp->rl_current; 225 ASSERT((CACHEFS_RL_START <= type) && (type <= CACHEFS_RL_END)); 226 lhp = RL_HEAD(cachep, type); 227 entno = lhp->rli_front; 228 229 if (*entnop == 0) { 230 error = ENOENT; 231 } else { 232 error = cachefs_rl_entry_get(cachep, *entnop, &rl_ent); 233 if (!error) 234 *valp = *rl_ent; 235 } 236 mutex_exit(&cachep->c_contentslock); 237 return (error); 238 } 239 240 /* 241 * This function plucks a slot from the RL free list and creates an RL entry. 242 */ 243 int 244 cachefs_rl_alloc(struct cachefscache *cachep, rl_entry_t *valp, uint_t *entnop) 245 { 246 int error = 0; 247 uint_t entno; 248 rl_entry_t *rl_ent; 249 cachefs_rl_listhead_t *lhp; 250 251 ASSERT((cachep->c_flags & (CACHE_NOCACHE|CACHE_NOFILL)) == 0); 252 mutex_enter(&cachep->c_contentslock); 253 254 cachefs_cache_dirty(cachep, 0); 255 lhp = RL_HEAD(cachep, CACHEFS_RL_FREE); 256 entno = lhp->rli_front; 257 if (entno == 0) { 258 if (cachep->c_rlinfo.rl_entries >= 259 cachep->c_label.cl_maxinodes) { 260 error = ENOMEM; 261 goto out; 262 } 263 entno = ++(cachep->c_rlinfo.rl_entries); 264 lhp->rli_itemcnt++; 265 error = cachefs_rl_entry_get(cachep, entno, &rl_ent); 266 if (error) 267 goto out; 268 rl_ent->rl_current = CACHEFS_RL_NONE; 269 rl_ent->rl_fwd_idx = 0; 270 rl_ent->rl_bkwd_idx = 0; 271 } 272 273 cachefs_rlent_moveto_nolock(cachep, CACHEFS_RL_NONE, entno, 0); 274 275 error = cachefs_rl_entry_get(cachep, entno, &rl_ent); 276 if (error) 277 goto out; 278 rl_ent->rl_fsid = valp->rl_fsid; 279 rl_ent->rl_fileno = valp->rl_fileno; 280 rl_ent->rl_local = valp->rl_local; 281 rl_ent->rl_attrc = valp->rl_attrc; 282 rl_ent->rl_fsck = 0; 283 out: 284 mutex_exit(&cachep->c_contentslock); 285 if (error == 0) 286 *entnop = entno; 287 return (error); 288 } 289 290 /* 291 * Call to change a local fileno in an rl entry to a normal fileno. 292 */ 293 void 294 cachefs_rl_changefileno(cachefscache_t *cachep, uint_t entno, ino64_t fileno) 295 { 296 rl_entry_t *rl_ent; 297 int error; 298 299 mutex_enter(&cachep->c_contentslock); 300 error = cachefs_rl_entry_get(cachep, entno, &rl_ent); 301 if (!error) { 302 ASSERT(rl_ent->rl_local); 303 rl_ent->rl_local = 0; 304 rl_ent->rl_fileno = fileno; 305 } 306 mutex_exit(&cachep->c_contentslock); 307 } 308 309 /* 310 * Moves the files on the modified list for this file system to 311 * the modified fix list. 312 */ 313 void 314 cachefs_move_modified_to_mf(cachefscache_t *cachep, fscache_t *fscp) 315 { 316 rl_entry_t *list_ent; 317 uint_t curp, nextp; 318 cachefs_rl_listhead_t *lhp; 319 int error; 320 321 ASSERT(MUTEX_HELD(&cachep->c_mflock)); 322 323 mutex_enter(&cachep->c_contentslock); 324 325 lhp = RL_HEAD(cachep, CACHEFS_RL_MF); 326 ASSERT(lhp->rli_front == 0); 327 ASSERT(lhp->rli_back == 0); 328 ASSERT(lhp->rli_itemcnt == 0); 329 lhp->rli_blkcnt = 0; 330 331 cachefs_cache_dirty(cachep, 0); 332 333 /* walk the modified list */ 334 lhp = RL_HEAD(cachep, CACHEFS_RL_MODIFIED); 335 for (curp = lhp->rli_front; curp != 0; curp = nextp) { 336 /* get the next element */ 337 error = cachefs_rl_entry_get(cachep, curp, &list_ent); 338 if (error) { 339 mutex_exit(&cachep->c_contentslock); 340 return; 341 } 342 nextp = list_ent->rl_bkwd_idx; 343 344 /* skip if element is not in this file system */ 345 if (list_ent->rl_fsid != fscp->fs_cfsid) 346 continue; 347 348 /* move from modified list to mf list */ 349 cachefs_rlent_moveto_nolock(cachep, CACHEFS_RL_MF, curp, 0); 350 } 351 mutex_exit(&cachep->c_contentslock); 352 } 353 354 /* 355 * Moves the contents of the active list to the rl list. 356 * Leave modified files on the active list, so they are not 357 * garbage collected. 358 */ 359 void 360 cachefs_rl_cleanup(cachefscache_t *cachep) 361 { 362 cachefs_rl_listhead_t *lhp; 363 rl_entry_t *rlp; 364 uint_t entno, next; 365 int error; 366 367 ASSERT(MUTEX_HELD(&cachep->c_contentslock)); 368 369 /* 370 * if fsck ran, then both of these lists should be empty. the 371 * only time this isn't the case is when we've done a cachefs 372 * boot with a clean cache. then, the cache may have been 373 * clean, but files and attrfiles were left dangling. 374 * 375 * when this happens, we just fix the linked lists here. this 376 * means that the attrcache header and cnode metadata might 377 * have incorrect information about which resource lists an 378 * entity is currently on. so, we set CACHE_CHECK_RLTYPE, 379 * which says cache-wide to double-check and go with whatever 380 * is in the resource list at the time such an object is 381 * loaded into memory. 382 */ 383 384 lhp = RL_HEAD(cachep, CACHEFS_RL_ACTIVE); 385 if (lhp->rli_itemcnt > 0) { 386 cachep->c_flags |= CACHE_CHECK_RLTYPE; 387 cachefs_cache_dirty(cachep, 0); 388 } 389 for (entno = lhp->rli_front; entno != 0; entno = next) { 390 error = cachefs_rl_entry_get(cachep, entno, &rlp); 391 if (error) 392 return; 393 next = rlp->rl_bkwd_idx; 394 395 ASSERT(rlp->rl_current == CACHEFS_RL_ACTIVE); 396 cachefs_rlent_moveto_nolock(cachep, CACHEFS_RL_GC, entno, 0); 397 } 398 399 #if 0 400 lhp = RL_HEAD(cachep, CACHEFS_RL_ATTRFILE); 401 if (lhp->rli_itemcnt > 0) { 402 cachep->c_flags |= CACHE_CHECK_RLTYPE; 403 cachefs_cache_dirty(cachep, 0); 404 } 405 for (entno = lhp->rli_front; entno != 0; entno = next) { 406 error = cachefs_rl_entry_get(cachep, entno, &rlp); 407 if (error) 408 return; 409 next = rlp->rl_bkwd_idx; 410 411 ASSERT(rlp->rl_current == CACHEFS_RL_ATTRFILE); 412 cachefs_rlent_moveto_nolock(cachep, CACHEFS_RL_GC, entno, 0); 413 } 414 #endif 415 } 416 417 int 418 cachefs_allocfile(cachefscache_t *cachep) 419 { 420 int error = 0; 421 int collect = 0; 422 struct statvfs64 sb; 423 fsfilcnt64_t used; 424 425 (void) VFS_STATVFS(cachep->c_dirvp->v_vfsp, &sb); 426 used = sb.f_files - sb.f_ffree; 427 428 mutex_enter(&cachep->c_contentslock); 429 430 /* if there are no more available inodes */ 431 if ((cachep->c_usage.cu_filesused >= cachep->c_label.cl_maxinodes) || 432 ((cachep->c_usage.cu_filesused > cachep->c_label.cl_filemin) && 433 (used > cachep->c_label.cl_filetresh))) { 434 error = ENOSPC; 435 if ((cachep->c_flags & CACHE_GARBAGE_COLLECT) == 0) 436 collect = 1; 437 } 438 439 /* else if there are more available inodes */ 440 else { 441 cachefs_cache_dirty(cachep, 0); 442 cachep->c_usage.cu_filesused++; 443 if (((cachep->c_flags & CACHE_GARBAGE_COLLECT) == 0) && 444 (cachep->c_usage.cu_filesused >= 445 cachep->c_label.cl_filehiwat)) 446 collect = 1; 447 } 448 449 mutex_exit(&cachep->c_contentslock); 450 451 if (collect) 452 cachefs_garbage_collect_queue(cachep); 453 454 return (error); 455 } 456 457 void 458 cachefs_freefile(cachefscache_t *cachep) 459 { 460 mutex_enter(&cachep->c_contentslock); 461 ASSERT(cachep->c_usage.cu_filesused > 0); 462 cachefs_cache_dirty(cachep, 0); 463 cachep->c_usage.cu_filesused--; 464 mutex_exit(&cachep->c_contentslock); 465 } 466 467 /*ARGSUSED*/ 468 int 469 cachefs_allocblocks(cachefscache_t *cachep, size_t nblks, 470 enum cachefs_rl_type type) 471 { 472 int error = 0; 473 int collect = 0; 474 struct statvfs64 sb; 475 size_t used; 476 size_t blocks; 477 478 ASSERT(type != CACHEFS_RL_FREE); 479 480 (void) VFS_STATVFS(cachep->c_dirvp->v_vfsp, &sb); 481 used = ((sb.f_blocks - sb.f_bfree) * sb.f_frsize) / MAXBSIZE; 482 483 mutex_enter(&cachep->c_contentslock); 484 485 /* if there are no more available blocks */ 486 blocks = cachep->c_usage.cu_blksused + nblks; 487 if ((blocks >= cachep->c_label.cl_maxblks) || 488 ((blocks > cachep->c_label.cl_blockmin) && 489 (used > cachep->c_label.cl_blocktresh))) { 490 error = ENOSPC; 491 if ((cachep->c_flags & CACHE_GARBAGE_COLLECT) == 0) 492 collect = 1; 493 } 494 495 /* else if there are more available blocks */ 496 else { 497 cachefs_cache_dirty(cachep, 0); 498 cachep->c_usage.cu_blksused += (uint_t)nblks; 499 ASSERT((CACHEFS_RL_START <= type) && (type <= CACHEFS_RL_END)); 500 RL_HEAD(cachep, type)->rli_blkcnt += nblks; 501 502 if (((cachep->c_flags & CACHE_GARBAGE_COLLECT) == 0) && 503 (cachep->c_usage.cu_blksused >= 504 cachep->c_label.cl_blkhiwat)) 505 collect = 1; 506 } 507 508 mutex_exit(&cachep->c_contentslock); 509 510 if (collect) 511 cachefs_garbage_collect_queue(cachep); 512 513 return (error); 514 } 515 516 void 517 cachefs_freeblocks(cachefscache_t *cachep, size_t nblks, 518 enum cachefs_rl_type type) 519 { 520 mutex_enter(&cachep->c_contentslock); 521 cachefs_cache_dirty(cachep, 0); 522 cachep->c_usage.cu_blksused -= (uint_t)nblks; 523 ASSERT(cachep->c_usage.cu_blksused >= 0); 524 ASSERT((CACHEFS_RL_START <= type) && (type <= CACHEFS_RL_END)); 525 ASSERT(type != CACHEFS_RL_FREE); 526 RL_HEAD(cachep, type)->rli_blkcnt -= nblks; 527 mutex_exit(&cachep->c_contentslock); 528 } 529 530 int 531 cachefs_victim(cachefscache_t *cachep) 532 { 533 uint_t entno; 534 rl_entry_t *rl_ent; 535 int error = 0; 536 ino64_t fsid; 537 cfs_cid_t cid; 538 struct fscache *fscp; 539 struct filegrp *fgp; 540 struct cachefs_metadata md; 541 struct cnode *cp; 542 int isattrc; 543 cachefs_rl_listhead_t *lhp; 544 545 ASSERT((cachep->c_flags & (CACHE_NOCACHE|CACHE_NOFILL)) == 0); 546 fscp = NULL; 547 fgp = NULL; 548 549 /* get the file and fsid of the first item on the rl list */ 550 /* XXX call rlent_data() instead */ 551 mutex_enter(&cachep->c_contentslock); 552 lhp = RL_HEAD(cachep, CACHEFS_RL_GC); 553 entno = lhp->rli_front; 554 if (entno == 0) { 555 mutex_exit(&cachep->c_contentslock); 556 error = ENOSPC; 557 goto out; 558 } 559 error = cachefs_rl_entry_get(cachep, entno, &rl_ent); 560 if (error) { 561 mutex_exit(&cachep->c_contentslock); 562 goto out; 563 } 564 fsid = rl_ent->rl_fsid; 565 cid.cid_fileno = rl_ent->rl_fileno; 566 ASSERT(rl_ent->rl_local == 0); 567 cid.cid_flags = 0; 568 isattrc = rl_ent->rl_attrc; 569 mutex_exit(&cachep->c_contentslock); 570 571 /* get the file system cache object for this fsid */ 572 mutex_enter(&cachep->c_fslistlock); 573 fscp = fscache_list_find(cachep, fsid); 574 if (fscp == NULL) { 575 fscp = fscache_create(cachep); 576 error = fscache_activate(fscp, fsid, NULL, NULL, 0); 577 if (error) { 578 cmn_err(CE_WARN, 579 "cachefs: cache corruption, run fsck\n"); 580 fscache_destroy(fscp); 581 fscp = NULL; 582 mutex_exit(&cachep->c_fslistlock); 583 error = 0; 584 goto out; 585 } 586 fscache_list_add(cachep, fscp); 587 } 588 fscache_hold(fscp); 589 mutex_exit(&cachep->c_fslistlock); 590 591 /* get the file group object for this file */ 592 mutex_enter(&fscp->fs_fslock); 593 fgp = filegrp_list_find(fscp, &cid); 594 if (fgp == NULL) { 595 fgp = filegrp_create(fscp, &cid); 596 filegrp_list_add(fscp, fgp); 597 } 598 if (fgp->fg_flags & CFS_FG_ALLOC_ATTR) { 599 if (isattrc == 0) { 600 cmn_err(CE_WARN, 601 "cachefs: cache corruption, run fsck\n"); 602 delay(5*hz); 603 } 604 filegrp_list_remove(fscp, fgp); 605 filegrp_destroy(fgp); 606 error = 0; 607 fgp = NULL; 608 mutex_exit(&fscp->fs_fslock); 609 goto out; 610 } 611 612 /* if we are victimizing an attrcache file */ 613 if (isattrc) { 614 mutex_enter(&fgp->fg_mutex); 615 /* if the filegrp is not writable */ 616 if ((fgp->fg_flags & CFS_FG_WRITE) == 0) { 617 mutex_exit(&fgp->fg_mutex); 618 error = EROFS; 619 fgp = NULL; 620 mutex_exit(&fscp->fs_fslock); 621 goto out; 622 } 623 624 /* if the filegrp did not go active on us */ 625 if ((fgp->fg_count == 0) && (fgp->fg_header->ach_nffs == 0)) { 626 mutex_exit(&fgp->fg_mutex); 627 filegrp_list_remove(fscp, fgp); 628 fgp->fg_header->ach_count = 0; 629 filegrp_destroy(fgp); 630 } else { 631 #ifdef CFSDEBUG 632 CFS_DEBUG(CFSDEBUG_RESOURCE) 633 printf("c_victim: filegrp went active" 634 " %p %llu %d %d %lld\n", 635 (void *) fgp, 636 (u_longlong_t)fgp->fg_id.cid_fileno, 637 fgp->fg_header->ach_rlno, 638 fgp->fg_count, fgp->fg_header->ach_nffs); 639 #endif 640 ASSERT(fgp->fg_header->ach_rl_current != 641 CACHEFS_RL_GC); 642 mutex_exit(&fgp->fg_mutex); 643 } 644 fgp = NULL; 645 error = 0; 646 mutex_exit(&fscp->fs_fslock); 647 goto out; 648 } 649 ASSERT((fgp->fg_flags & CFS_FG_ALLOC_FILE) == 0); 650 filegrp_hold(fgp); 651 mutex_exit(&fscp->fs_fslock); 652 653 /* grab the cnode list lock */ 654 mutex_enter(&fgp->fg_cnodelock); 655 656 /* see if a cnode exists for this file */ 657 (void) cachefs_cnode_find(fgp, &cid, NULL, &cp, NULL, NULL); 658 if (cp) { 659 VN_HOLD(CTOV(cp)); 660 661 /* move file from rl to active list */ 662 cachefs_rlent_moveto(fscp->fs_cache, 663 CACHEFS_RL_ACTIVE, cp->c_metadata.md_rlno, 664 cp->c_metadata.md_frontblks); 665 cp->c_metadata.md_rltype = CACHEFS_RL_ACTIVE; 666 mutex_exit(&cp->c_statelock); 667 mutex_exit(&fgp->fg_cnodelock); 668 VN_RELE(CTOV(cp)); 669 error = 0; 670 goto out; 671 } 672 673 /* 674 * The cnode does not exist and since we hold the hashlock 675 * it cannot be created until we are done. 676 */ 677 678 /* see if the item is no longer on the rl list, it could happen */ 679 mutex_enter(&cachep->c_contentslock); 680 lhp = RL_HEAD(cachep, CACHEFS_RL_GC); 681 entno = lhp->rli_front; 682 if (entno == 0) { 683 mutex_exit(&cachep->c_contentslock); 684 mutex_exit(&fgp->fg_cnodelock); 685 error = ENOSPC; 686 goto out; 687 } 688 error = cachefs_rl_entry_get(cachep, entno, &rl_ent); 689 if (error) { 690 mutex_exit(&cachep->c_contentslock); 691 mutex_exit(&fgp->fg_cnodelock); 692 goto out; 693 } 694 if ((fsid != rl_ent->rl_fsid) || 695 (cid.cid_fileno != rl_ent->rl_fileno)) { 696 mutex_exit(&cachep->c_contentslock); 697 mutex_exit(&fgp->fg_cnodelock); 698 error = 0; 699 goto out; 700 } 701 mutex_exit(&cachep->c_contentslock); 702 703 /* Get the metadata from the attrcache file */ 704 ASSERT((fgp->fg_flags & CFS_FG_ALLOC_ATTR) == 0); 705 error = filegrp_read_metadata(fgp, &cid, &md); 706 ASSERT(error == 0); 707 708 /* md.md_rltype may be incorrect, but we know file isn't active. */ 709 if (error) { 710 /* XXX this should never happen, fix on panic */ 711 mutex_exit(&fgp->fg_cnodelock); 712 error = 0; 713 goto out; 714 } 715 716 /* destroy the frontfile */ 717 cachefs_removefrontfile(&md, &cid, fgp); 718 719 /* remove the victim from the gc list */ 720 cachefs_rlent_moveto(fscp->fs_cache, CACHEFS_RL_FREE, entno, 0); 721 722 /* destroy the metadata */ 723 (void) filegrp_destroy_metadata(fgp, &cid); 724 725 mutex_exit(&fgp->fg_cnodelock); 726 error = 0; 727 out: 728 if (fgp) { 729 filegrp_rele(fgp); 730 } 731 if (fscp) { 732 fscache_rele(fscp); 733 } 734 return (error); 735 } 736 737 static void 738 cachefs_garbage_collect(cachefscache_t *cachep) 739 { 740 fsfilcnt64_t filelowat, filelowatmax, maxfiles, threshfiles; 741 fsblkcnt64_t blocklowat, blocklowatmax, maxblks, threshblks; 742 int error; 743 struct cache_usage *cup = &cachep->c_usage; 744 745 ASSERT((cachep->c_flags & (CACHE_NOCACHE|CACHE_NOFILL)) == 0); 746 mutex_enter(&cachep->c_contentslock); 747 ASSERT(cachep->c_flags & CACHE_GARBAGE_COLLECT); 748 filelowat = cachep->c_label.cl_filelowat; 749 blocklowat = cachep->c_label.cl_blklowat; 750 maxblks = cachep->c_label.cl_maxblks; 751 maxfiles = cachep->c_label.cl_maxinodes; 752 threshblks = cachep->c_label.cl_blocktresh; 753 threshfiles = cachep->c_label.cl_filetresh; 754 mutex_exit(&cachep->c_contentslock); 755 756 cachep->c_gc_count++; 757 cachep->c_gc_time = time; 758 cachep->c_gc_before = cachefs_gc_front_atime(cachep); 759 760 /* 761 * since we're here, we're running out of blocks or files. 762 * file and block lowat are what determine how low we garbage 763 * collect. in order to do any good, we should drop below 764 * maxblocks, threshblocks, or the current blocks, whichever 765 * is smaller (same goes for files). however, we won't go 766 * below an arbitrary (small) minimum for each. 767 */ 768 769 /* move down for maxfiles and maxblocks */ 770 if ((filelowatmax = (maxfiles * 7) / 10) < filelowat) 771 filelowat = filelowatmax; 772 if ((blocklowatmax = (maxblks * 7) / 10) < blocklowat) 773 blocklowat = blocklowatmax; 774 775 /* move down for threshfiles and threshblocks */ 776 if ((filelowatmax = (threshfiles * 7) / 10) < filelowat) 777 filelowat = filelowatmax; 778 if ((blocklowatmax = (threshblks * 7) / 10) < blocklowat) 779 blocklowat = blocklowatmax; 780 781 /* move down for current files and blocks */ 782 if ((filelowatmax = ((fsfilcnt64_t)cup->cu_filesused * 7) / 10) < 783 filelowat) 784 filelowat = filelowatmax; 785 if ((blocklowatmax = ((fsblkcnt64_t)cup->cu_blksused * 7) / 10) < 786 blocklowat) 787 blocklowat = blocklowatmax; 788 789 /* move up for an arbitrary minimum */ 790 #define MIN_BLKLO 640 /* 640*8192 == 5MB */ 791 #define MIN_FILELO 1000 792 if (filelowat < MIN_FILELO) 793 filelowat = MIN_FILELO; 794 if (blocklowat < MIN_BLKLO) 795 blocklowat = MIN_BLKLO; 796 797 while (cup->cu_filesused > filelowat || cup->cu_blksused > blocklowat) { 798 /* if the thread is to terminate */ 799 if (cachep->c_flags & CACHE_CACHEW_THREADEXIT) 800 break; 801 802 error = cachefs_victim(cachep); 803 if (error) 804 break; 805 } 806 807 cachep->c_gc_after = cachefs_gc_front_atime(cachep); 808 CACHEFS_TIME_TO_CFS_TIME_COPY(cachep->c_gc_after, 809 cachep->c_rlinfo.rl_gctime, error); 810 } 811 812 /* 813 * traverse the packed pending list, repacking files when possible. 814 */ 815 816 static void 817 cachefs_packed_pending(cachefscache_t *cachep) 818 { 819 rl_entry_t rl; 820 int error = 0; /* not returned -- used as placeholder */ 821 fscache_t *fscp = NULL; 822 cfs_cid_t cid; 823 cnode_t *cp; 824 uint_t entno; 825 int count = 0; 826 cachefs_rl_listhead_t *lhp; 827 828 ASSERT(MUTEX_HELD(&cachep->c_contentslock)); 829 830 lhp = RL_HEAD(cachep, CACHEFS_RL_PACKED_PENDING); 831 count = lhp->rli_itemcnt; 832 833 mutex_exit(&cachep->c_contentslock); 834 835 rl.rl_current = CACHEFS_RL_PACKED_PENDING; 836 while (cachefs_rlent_data(cachep, &rl, &entno) == 0) { 837 if (count-- <= 0) { 838 #ifdef CFSDEBUG 839 CFS_DEBUG(CFSDEBUG_RESOURCE) 840 printf("cachefs_ppending: count exceeded\n"); 841 #endif /* CFSDEBUG */ 842 break; 843 } 844 if ((cachep->c_flags & 845 (CACHE_PACKED_PENDING | CACHE_CACHEW_THREADEXIT)) != 846 CACHE_PACKED_PENDING) { 847 #ifdef CFSDEBUG 848 CFS_DEBUG(CFSDEBUG_RESOURCE) 849 printf("cachefs_ppending: early exit\n"); 850 #endif /* CFSDEBUG */ 851 break; 852 } 853 if (rl.rl_current != CACHEFS_RL_PACKED_PENDING) { 854 #ifdef CFSDEBUG 855 CFS_DEBUG(CFSDEBUG_RESOURCE) 856 printf("cachefs_ppending: gone from list\n"); 857 #endif /* CFSDEBUG */ 858 break; 859 } 860 861 /* if the fscp we have does not match */ 862 if ((fscp == NULL) || (fscp->fs_cfsid != rl.rl_fsid)) { 863 if (fscp) { 864 cachefs_cd_release(fscp); 865 fscache_rele(fscp); 866 fscp = NULL; 867 } 868 869 /* get the file system cache object for this fsid */ 870 mutex_enter(&cachep->c_fslistlock); 871 fscp = fscache_list_find(cachep, rl.rl_fsid); 872 if (fscp == NULL) { 873 874 /* 875 * uh oh, the filesystem probably 876 * isn't mounted. we `move' this 877 * entry onto the same list that it's 878 * on, which really just moves it to 879 * the back of the list. we need not 880 * worry about an infinite loop, due 881 * to the counter. 882 */ 883 884 cachefs_rlent_moveto(cachep, 885 CACHEFS_RL_PACKED_PENDING, entno, 0); 886 #ifdef CFSDEBUG 887 CFS_DEBUG(CFSDEBUG_RESOURCE) 888 printf("cachefs_ppending: " 889 "fscp find failed\n"); 890 #endif /* CFSDEBUG */ 891 continue; 892 } 893 fscache_hold(fscp); 894 mutex_exit(&cachep->c_fslistlock); 895 896 /* get access to the file system */ 897 error = cachefs_cd_access(fscp, 0, 0); 898 if ((error) || 899 (fscp->fs_cdconnected != CFS_CD_CONNECTED)) { 900 #ifdef CFSDEBUG 901 CFS_DEBUG(CFSDEBUG_RESOURCE) 902 printf("cachefs: " 903 "ppending: err %d con %d\n", 904 error, fscp->fs_cdconnected); 905 #endif /* CFSDEBUG */ 906 fscache_rele(fscp); 907 fscp = NULL; 908 break; 909 } 910 } 911 912 /* get the cnode for the file */ 913 cid.cid_fileno = rl.rl_fileno; 914 cid.cid_flags = rl.rl_local ? CFS_CID_LOCAL : 0; 915 error = cachefs_cnode_make(&cid, fscp, 916 NULL, NULL, NULL, kcred, 0, &cp); 917 if (error) { 918 #ifdef CFSDEBUG 919 CFS_DEBUG(CFSDEBUG_RESOURCE) 920 printf("cachefs: " 921 "ppending: could not find %llu\n", 922 (u_longlong_t)cid.cid_fileno); 923 delay(5*hz); 924 #endif /* CFSDEBUG */ 925 break; 926 } 927 928 mutex_enter(&cp->c_statelock); 929 if (cp->c_flags & CN_STALE) { 930 /* back file went away behind our back */ 931 ASSERT(cp->c_metadata.md_rlno == 0); 932 mutex_exit(&cp->c_statelock); 933 934 #ifdef CFSDEBUG 935 CFS_DEBUG(CFSDEBUG_RESOURCE) 936 printf("cachefs: ppending: stale\n"); 937 #endif /* CFSDEBUG */ 938 939 VN_RELE(CTOV(cp)); 940 continue; 941 } 942 mutex_exit(&cp->c_statelock); 943 944 error = cachefs_pack_common(CTOV(cp), 945 (cp->c_cred) ? cp->c_cred : kcred); 946 VN_RELE(CTOV(cp)); 947 948 if (error != 0) { 949 #ifdef CFSDEBUG 950 CFS_DEBUG(CFSDEBUG_RESOURCE) 951 printf("cachefs: " 952 "ppending: pack_common: error = %d\n", 953 error); 954 #endif /* CFSDEBUG */ 955 break; 956 } 957 } 958 959 if (fscp != NULL) { 960 cachefs_cd_release(fscp); 961 fscache_rele(fscp); 962 } 963 964 mutex_enter(&cachep->c_contentslock); 965 if (lhp->rli_itemcnt == 0) 966 cachep->c_flags &= ~CACHE_PACKED_PENDING; 967 } 968 969 /* seconds; interval to do ppend list */ 970 static time_t cachefs_ppend_time = 900; 971 972 /* main routine for the cachep worker thread */ 973 void 974 cachefs_cachep_worker_thread(cachefscache_t *cachep) 975 { 976 int error; 977 struct flock64 fl; 978 callb_cpr_t cprinfo; 979 kmutex_t cpr_lock; 980 clock_t wakeup; 981 982 /* lock the lock file for exclusive write access */ 983 fl.l_type = F_WRLCK; 984 fl.l_whence = 0; 985 fl.l_start = (offset_t)0; 986 fl.l_len = (offset_t)1024; 987 fl.l_sysid = 0; 988 fl.l_pid = 0; 989 error = VOP_FRLOCK(cachep->c_lockvp, F_SETLK, &fl, FWRITE, (offset_t)0, 990 NULL, kcred, NULL); 991 if (error) { 992 cmn_err(CE_WARN, 993 "cachefs: Can't lock Cache Lock File(r); Error %d\n", 994 error); 995 } 996 997 mutex_init(&cpr_lock, NULL, MUTEX_DEFAULT, NULL); 998 CALLB_CPR_INIT(&cprinfo, &cpr_lock, callb_generic_cpr, "cfs_gct"); 999 mutex_enter(&cpr_lock); 1000 mutex_enter(&cachep->c_contentslock); 1001 1002 wakeup = (clock_t)(cachefs_ppend_time * hz); 1003 1004 /* loop while the thread is allowed to run */ 1005 while ((cachep->c_flags & CACHE_CACHEW_THREADEXIT) == 0) { 1006 /* wait for a wakeup call */ 1007 cachep->c_flags &= ~CACHE_GARBAGE_COLLECT; 1008 CALLB_CPR_SAFE_BEGIN(&cprinfo); 1009 mutex_exit(&cpr_lock); 1010 (void) cv_reltimedwait(&cachep->c_cwcv, 1011 &cachep->c_contentslock, wakeup, TR_CLOCK_TICK); 1012 mutex_enter(&cpr_lock); 1013 CALLB_CPR_SAFE_END(&cprinfo, &cpr_lock); 1014 1015 /* if the thread is to terminate */ 1016 if (cachep->c_flags & CACHE_CACHEW_THREADEXIT) 1017 break; 1018 1019 /* thread is running during nofill, but just to hold lock */ 1020 if (cachep->c_flags & CACHE_NOFILL) 1021 continue; 1022 1023 /* if garbage collection is to run */ 1024 if (cachep->c_flags & CACHE_GARBAGE_COLLECT) { 1025 mutex_exit(&cachep->c_contentslock); 1026 cachefs_garbage_collect(cachep); 1027 1028 /* 1029 * Prevent garbage collection from running more 1030 * than once every 30 seconds. This addresses 1031 * those cases which do not allow removing 1032 * an item from the rl by keeping gc from 1033 * being a spin loop. 1034 */ 1035 delay(30*hz); /* XXX sam: still do this? */ 1036 mutex_enter(&cachep->c_contentslock); 1037 } 1038 1039 if (cachep->c_flags & CACHE_PACKED_PENDING) 1040 cachefs_packed_pending(cachep); 1041 ASSERT(MUTEX_HELD(&cachep->c_contentslock)); 1042 } 1043 1044 cachep->c_flags &= ~CACHE_CACHEW_THREADRUN; 1045 cv_broadcast(&cachep->c_cwhaltcv); 1046 CALLB_CPR_EXIT(&cprinfo); 1047 mutex_exit(&cachep->c_contentslock); 1048 mutex_destroy(&cpr_lock); 1049 1050 /* unlock the lock file */ 1051 fl.l_type = F_UNLCK; 1052 fl.l_whence = 0; 1053 fl.l_start = (offset_t)0; 1054 fl.l_len = (offset_t)1024; 1055 fl.l_sysid = 0; 1056 fl.l_pid = 0; 1057 error = VOP_FRLOCK(cachep->c_lockvp, F_SETLK, &fl, FWRITE, (offset_t)0, 1058 NULL, kcred, NULL); 1059 if (error) { 1060 cmn_err(CE_WARN, "cachefs: Can't unlock lock file\n"); 1061 } 1062 1063 thread_exit(); 1064 /*NOTREACHED*/ 1065 } 1066 1067 /* queues up a request to run the garbage collection */ 1068 void 1069 cachefs_garbage_collect_queue(cachefscache_t *cachep) 1070 { 1071 cachefs_rl_listhead_t *lhp; 1072 1073 ASSERT((cachep->c_flags & (CACHE_NOCACHE|CACHE_NOFILL)) == 0); 1074 mutex_enter(&cachep->c_contentslock); 1075 1076 /* quit if there is no garbage collection thread */ 1077 if ((cachep->c_flags & CACHE_CACHEW_THREADRUN) == 0) { 1078 mutex_exit(&cachep->c_contentslock); 1079 return; 1080 } 1081 1082 /* quit if garbage collection is already in progress */ 1083 if (cachep->c_flags & CACHE_GARBAGE_COLLECT) { 1084 mutex_exit(&cachep->c_contentslock); 1085 return; 1086 } 1087 1088 /* quit if there is no garbage to collect */ 1089 lhp = RL_HEAD(cachep, CACHEFS_RL_GC); 1090 if (lhp->rli_front == 0) { 1091 mutex_exit(&cachep->c_contentslock); 1092 return; 1093 } 1094 1095 /* indicate garbage collecting is in progress */ 1096 cachep->c_flags |= CACHE_GARBAGE_COLLECT; 1097 1098 /* wake up the garbage collection thread */ 1099 cv_signal(&cachep->c_cwcv); 1100 1101 mutex_exit(&cachep->c_contentslock); 1102 } 1103 1104 #ifdef CFSRLDEBUG 1105 time_t cachefs_dbvalid = 123; /* default to non-zero junk */ 1106 struct kmem_cache *cachefs_rl_debug_cache = NULL; 1107 static int cachefs_rl_debug_maxcount = CACHEFS_RLDB_DEF_MAXCOUNT; 1108 kmutex_t cachefs_rl_debug_mutex; 1109 static int cachefs_rl_debug_inuse = 0; 1110 1111 void 1112 cachefs_rl_debug_reclaim(void *cdrarg) 1113 { 1114 extern cachefscache_t *cachefs_cachelist; 1115 cachefscache_t *cachep; 1116 int index; 1117 int error; 1118 1119 for (cachep = cachefs_cachelist; cachep != NULL; 1120 cachep = cachep->c_next) { 1121 mutex_enter(&cachep->c_contentslock); 1122 1123 for (index = 0; 1124 index <= cachep->c_rlinfo.rl_entries; 1125 index++) { 1126 rl_entry_t *rlent; 1127 1128 error = cachefs_rl_entry_get(cachep, index, &rlent); 1129 if (error) 1130 break; 1131 cachefs_rl_debug_destroy(rlent); 1132 } 1133 1134 mutex_exit(&cachep->c_contentslock); 1135 } 1136 } 1137 1138 void 1139 cachefs_rl_debug_save(rl_entry_t *rlent) 1140 { 1141 rl_debug_t *rldb, *prev, *next; 1142 int count = 0; 1143 1144 mutex_enter(&cachefs_rl_debug_mutex); 1145 if (cachefs_rl_debug_cache == NULL) 1146 cachefs_rl_debug_cache = 1147 kmem_cache_create("cachefs_rl_debug", 1148 sizeof (rl_debug_t), 0, 1149 NULL, NULL, cachefs_rl_debug_reclaim, NULL, NULL, 0); 1150 1151 rldb = kmem_cache_alloc(cachefs_rl_debug_cache, KM_SLEEP); 1152 ++cachefs_rl_debug_inuse; 1153 1154 rldb->db_hrtime = gethrtime(); 1155 1156 rldb->db_attrc = rlent->rl_attrc; 1157 rldb->db_fsck = rlent->rl_fsck; 1158 rldb->db_fsid = rlent->rl_fsid; 1159 rldb->db_fileno = rlent->rl_fileno; 1160 rldb->db_current = rlent->rl_current; 1161 1162 rldb->db_stackheight = getpcstack(rldb->db_stack, 1163 CACHEFS_RLDB_STACKSIZE); 1164 1165 if (rlent->rl_dbvalid == cachefs_dbvalid) { 1166 rldb->db_next = rlent->rl_debug; 1167 } else { 1168 rldb->db_next = NULL; 1169 rlent->rl_dbvalid = cachefs_dbvalid; 1170 } 1171 rlent->rl_debug = rldb; 1172 1173 prev = rldb; 1174 for (rldb = rldb->db_next; rldb != NULL; rldb = next) { 1175 next = rldb->db_next; 1176 if (++count >= cachefs_rl_debug_maxcount) { 1177 if (prev != NULL) 1178 prev->db_next = NULL; 1179 kmem_cache_free(cachefs_rl_debug_cache, rldb); 1180 --cachefs_rl_debug_inuse; 1181 prev = NULL; 1182 } else { 1183 prev = rldb; 1184 } 1185 } 1186 mutex_exit(&cachefs_rl_debug_mutex); 1187 } 1188 1189 void 1190 cachefs_rl_debug_show(rl_entry_t *rlent) 1191 { 1192 rl_debug_t *rldb; 1193 hrtime_t now, elapse; 1194 timestruc_t tv; 1195 char *cname = NULL; 1196 int i; 1197 1198 mutex_enter(&cachefs_rl_debug_mutex); 1199 if (rlent->rl_dbvalid != cachefs_dbvalid) { 1200 printf("cachefs_rldb: rl entry at %lx -- no info!\n", 1201 (uintptr_t)rlent); 1202 mutex_exit(&cachefs_rl_debug_mutex); 1203 return; 1204 } 1205 1206 now = gethrtime(); 1207 hrt2ts(now, &tv); 1208 1209 printf("===== cachefs_rldb start at %ld =====\n", tv.tv_sec); 1210 printf("-==== i am thread id %lx ====-\n", (uintptr_t)curthread); 1211 1212 for (rldb = rlent->rl_debug; 1213 rldb != NULL; 1214 rldb = rldb->db_next) { 1215 printf("----- cachefs_rldb record start -----\n"); 1216 elapse = now - rldb->db_hrtime; 1217 hrt2ts(elapse, &tv); 1218 printf("cachefs_rldb: ago = %lds %ldus\n", 1219 tv.tv_sec, tv.tv_nsec / 1000); 1220 1221 printf("cachefs_rldb: rl_attrc = %d\n", rldb->db_attrc); 1222 printf("cachefs_rldb: rl_fsck = %d\n", rldb->db_fsck); 1223 printf("cachefs_rldb: rl_fsid = %u\n", rldb->db_fsid); 1224 printf("cachefs_rldb: rl_fileno = %lu\n", rldb->db_fileno); 1225 1226 switch (rldb->db_current) { 1227 case CACHEFS_RL_NONE: 1228 cname = "CACHEFS_RL_NONE"; 1229 break; 1230 case CACHEFS_RL_FREE: 1231 cname = "CACHEFS_RL_FREE"; 1232 break; 1233 case CACHEFS_RL_GC: 1234 cname = "CACHEFS_RL_GC"; 1235 break; 1236 case CACHEFS_RL_ACTIVE: 1237 cname = "CACHEFS_RL_ACTIVE"; 1238 break; 1239 case CACHEFS_RL_ATTRFILE: 1240 cname = "CACHEFS_RL_ATTRFILE"; 1241 break; 1242 case CACHEFS_RL_MODIFIED: 1243 cname = "CACHEFS_RL_MODIFIED"; 1244 break; 1245 case CACHEFS_RL_PACKED: 1246 cname = "CACHEFS_RL_PACKED"; 1247 break; 1248 case CACHEFS_RL_PACKED_PENDING: 1249 cname = "CACHEFS_RL_PACKED_PENDING"; 1250 break; 1251 case CACHEFS_RL_MF: 1252 cname = "CACHEFS_MF_GC"; 1253 break; 1254 } 1255 if (cname != NULL) { 1256 printf("cachefs_rldb: state = %s\n", cname); 1257 } else { 1258 printf("cachefs_rldb: undefined state %x\n", 1259 rldb->db_current); 1260 } 1261 1262 printf("cachefs_rldb: stack trace\n"); 1263 for (i = 0; i < rldb->db_stackheight; i++) { 1264 char *sym; 1265 uint_t off; 1266 1267 sym = kobj_getsymname(rldb->db_stack[i], &off); 1268 printf("cachefs_rldb: %s+%lx\n", 1269 sym ? sym : "?", off); 1270 delay(hz/4); 1271 } 1272 1273 printf("----- cachefs_rldb record end -----\n"); 1274 } 1275 1276 mutex_exit(&cachefs_rl_debug_mutex); 1277 } 1278 1279 void 1280 cachefs_rl_debug_destroy(rl_entry_t *rlent) 1281 { 1282 rl_debug_t *rldb, *next; 1283 1284 mutex_enter(&cachefs_rl_debug_mutex); 1285 if (rlent->rl_dbvalid != cachefs_dbvalid) { 1286 rlent->rl_debug = NULL; 1287 mutex_exit(&cachefs_rl_debug_mutex); 1288 return; 1289 } 1290 1291 for (rldb = rlent->rl_debug; rldb != NULL; rldb = next) { 1292 next = rldb->db_next; 1293 kmem_cache_free(cachefs_rl_debug_cache, rldb); 1294 --cachefs_rl_debug_inuse; 1295 } 1296 1297 rlent->rl_debug = NULL; 1298 mutex_exit(&cachefs_rl_debug_mutex); 1299 } 1300 #endif /* CFSRLDEBUG */ 1301 1302 int 1303 cachefs_rl_entry_get(cachefscache_t *cachep, uint_t entno, rl_entry_t **ent) 1304 { 1305 rl_entry_t *rl_ent; 1306 uint_t whichwindow, winoffset; 1307 int error = 0; 1308 1309 ASSERT(MUTEX_HELD(&cachep->c_contentslock)); 1310 ASSERT(entno <= cachep->c_label.cl_maxinodes); /* strictly less? */ 1311 #if 0 1312 ASSERT((cachep->c_flags & CACHE_NOFILL) == 0); 1313 #endif 1314 1315 whichwindow = entno / CACHEFS_RLPMBS; 1316 winoffset = entno % CACHEFS_RLPMBS; 1317 1318 if ((cachep->c_rl_entries == NULL) || 1319 (cachep->c_rl_window != whichwindow)) { 1320 if (cachep->c_rl_entries != NULL) { 1321 error = vn_rdwr(UIO_WRITE, cachep->c_resfilevp, 1322 (caddr_t)cachep->c_rl_entries, MAXBSIZE, 1323 (offset_t)((cachep->c_rl_window + 1) * MAXBSIZE), 1324 UIO_SYSSPACE, 0, RLIM_INFINITY, kcred, NULL); 1325 if (error) 1326 return (error); 1327 } 1328 else 1329 cachep->c_rl_entries = (rl_entry_t *) 1330 cachefs_kmem_alloc(MAXBSIZE, KM_SLEEP); 1331 1332 error = vn_rdwr(UIO_READ, cachep->c_resfilevp, 1333 (caddr_t)cachep->c_rl_entries, MAXBSIZE, 1334 (offset_t)((whichwindow + 1) * MAXBSIZE), 1335 UIO_SYSSPACE, 0, RLIM_INFINITY, kcred, NULL); 1336 if (error) { 1337 cachefs_kmem_free(cachep->c_rl_entries, MAXBSIZE); 1338 cachep->c_rl_entries = NULL; 1339 return (error); 1340 } 1341 cachep->c_rl_window = whichwindow; 1342 } 1343 rl_ent = &cachep->c_rl_entries[winoffset]; 1344 1345 *ent = rl_ent; 1346 #ifdef CFSRLDEBUG 1347 cachefs_rl_debug_save(rl_ent); 1348 #endif /* CFSRLDEBUG */ 1349 1350 return (error); 1351 } 1352 1353 static time_t 1354 cachefs_gc_front_atime(cachefscache_t *cachep) 1355 { 1356 char namebuf[CFS_FRONTFILE_NAME_SIZE]; 1357 1358 rl_entry_t rl, *rl_ent; 1359 uint_t entno, fgsize; 1360 cfs_cid_t dircid, cid; 1361 struct fscache *fscp; 1362 cachefs_rl_listhead_t *lhp; 1363 int error; 1364 1365 struct vnode *dirvp, *filevp; 1366 struct vattr va; 1367 1368 int reledir = 0; 1369 int gotfile = 0; 1370 time_t rc = (time_t)0; 1371 1372 mutex_enter(&cachep->c_contentslock); 1373 lhp = RL_HEAD(cachep, CACHEFS_RL_GC); 1374 entno = lhp->rli_front; 1375 if (entno == 0) { 1376 mutex_exit(&cachep->c_contentslock); 1377 goto out; 1378 } 1379 1380 error = cachefs_rl_entry_get(cachep, entno, &rl_ent); 1381 if (error) { 1382 mutex_exit(&cachep->c_contentslock); 1383 goto out; 1384 } 1385 rl = *rl_ent; 1386 mutex_exit(&cachep->c_contentslock); 1387 cid.cid_fileno = rl.rl_fileno; 1388 ASSERT(rl.rl_local == 0); 1389 cid.cid_flags = 0; 1390 dircid.cid_flags = 0; 1391 mutex_enter(&cachep->c_fslistlock); 1392 if ((fscp = fscache_list_find(cachep, rl.rl_fsid)) == NULL) { 1393 mutex_exit(&cachep->c_fslistlock); 1394 goto out; 1395 } 1396 1397 if (rl.rl_attrc) { 1398 make_ascii_name(&cid, namebuf); 1399 dirvp = fscp->fs_fsattrdir; 1400 } else { 1401 dirvp = NULL; 1402 fgsize = fscp->fs_info.fi_fgsize; 1403 dircid.cid_fileno = ((cid.cid_fileno / fgsize) * fgsize); 1404 make_ascii_name(&dircid, namebuf); 1405 if (VOP_LOOKUP(fscp->fs_fscdirvp, namebuf, 1406 &dirvp, (struct pathname *)NULL, 0, 1407 (vnode_t *)NULL, kcred, NULL, NULL, NULL) == 0) { 1408 make_ascii_name(&cid, namebuf); 1409 reledir++; 1410 } else { 1411 mutex_exit(&cachep->c_fslistlock); 1412 goto out; 1413 } 1414 } 1415 if (dirvp && VOP_LOOKUP(dirvp, namebuf, &filevp, 1416 (struct pathname *)NULL, 0, 1417 (vnode_t *)NULL, kcred, NULL, NULL, NULL) == 0) { 1418 gotfile = 1; 1419 } 1420 if (reledir) 1421 VN_RELE(dirvp); 1422 mutex_exit(&cachep->c_fslistlock); 1423 1424 if (gotfile) { 1425 va.va_mask = AT_ATIME; 1426 if (VOP_GETATTR(filevp, &va, 0, kcred, NULL) == 0) 1427 rc = va.va_atime.tv_sec; 1428 VN_RELE(filevp); 1429 } 1430 1431 out: 1432 return (rc); 1433 }