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