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