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 }