Home | History | Annotate | Download | only in cachefs
      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/mount.h>
     40 #include <sys/ioctl.h>
     41 #include <sys/statvfs.h>
     42 #include <sys/errno.h>
     43 #include <sys/debug.h>
     44 #include <sys/cmn_err.h>
     45 #include <sys/utsname.h>
     46 #include <sys/modctl.h>
     47 #include <sys/file.h>
     48 #include <sys/stat.h>
     49 #include <sys/fcntl.h>
     50 #include <sys/fbuf.h>
     51 #include <sys/dnlc.h>
     52 #include <sys/callb.h>
     53 #include <sys/kobj.h>
     54 #include <sys/rwlock.h>
     55 
     56 #include <sys/vmsystm.h>
     57 #include <vm/hat.h>
     58 #include <vm/as.h>
     59 #include <vm/page.h>
     60 #include <vm/pvn.h>
     61 #include <vm/seg.h>
     62 #include <vm/seg_map.h>
     63 #include <vm/seg_vn.h>
     64 #include <vm/rm.h>
     65 #include <sys/fs/cachefs_fs.h>
     66 #include <sys/fs/cachefs_log.h>
     67 #include <sys/fs/cachefs_dir.h>
     68 
     69 extern struct seg *segkmap;
     70 caddr_t segmap_getmap();
     71 int segmap_release();
     72 
     73 extern struct cnode *cachefs_freeback;
     74 extern struct cnode *cachefs_freefront;
     75 extern cachefscache_t *cachefs_cachelist;
     76 
     77 #ifdef CFSDEBUG
     78 int cachefsdebug = 0;
     79 #endif
     80 
     81 int cachefs_max_threads = CFS_MAX_THREADS;
     82 ino64_t cachefs_check_fileno = 0;
     83 struct kmem_cache *cachefs_cache_kmcache = NULL;
     84 struct kmem_cache *cachefs_req_cache = NULL;
     85 
     86 static int
     87 cachefs_async_populate_reg(struct cachefs_populate_req *, cred_t *,
     88     vnode_t *, vnode_t *);
     89 
     90 /*
     91  * Cache routines
     92  */
     93 
     94 /*
     95  * ------------------------------------------------------------------
     96  *
     97  *		cachefs_cache_create
     98  *
     99  * Description:
    100  *	Creates a cachefscache_t object and initializes it to
    101  *	be NOCACHE and NOFILL mode.
    102  * Arguments:
    103  * Returns:
    104  *	Returns a pointer to the created object or NULL if
    105  *	threads could not be created.
    106  * Preconditions:
    107  */
    108 
    109 cachefscache_t *
    110 cachefs_cache_create(void)
    111 {
    112 	cachefscache_t *cachep;
    113 	struct cachefs_req *rp;
    114 
    115 	/* allocate zeroed memory for the object */
    116 	cachep = kmem_cache_alloc(cachefs_cache_kmcache, KM_SLEEP);
    117 
    118 	bzero(cachep, sizeof (*cachep));
    119 
    120 	cv_init(&cachep->c_cwcv, NULL, CV_DEFAULT, NULL);
    121 	cv_init(&cachep->c_cwhaltcv, NULL, CV_DEFAULT, NULL);
    122 	mutex_init(&cachep->c_contentslock, NULL, MUTEX_DEFAULT, NULL);
    123 	mutex_init(&cachep->c_fslistlock, NULL, MUTEX_DEFAULT, NULL);
    124 	mutex_init(&cachep->c_log_mutex, NULL, MUTEX_DEFAULT, NULL);
    125 
    126 	/* set up the work queue and get the sync thread created */
    127 	cachefs_workq_init(&cachep->c_workq);
    128 	cachep->c_workq.wq_keepone = 1;
    129 	cachep->c_workq.wq_cachep = cachep;
    130 	rp = kmem_cache_alloc(cachefs_req_cache, KM_SLEEP);
    131 	rp->cfs_cmd = CFS_NOOP;
    132 	rp->cfs_cr = kcred;
    133 	rp->cfs_req_u.cu_fs_sync.cf_cachep = cachep;
    134 	crhold(rp->cfs_cr);
    135 	cachefs_addqueue(rp, &cachep->c_workq);
    136 	cachep->c_flags |= CACHE_NOCACHE | CACHE_NOFILL | CACHE_ALLOC_PENDING;
    137 
    138 	return (cachep);
    139 }
    140 
    141 /*
    142  * ------------------------------------------------------------------
    143  *
    144  *		cachefs_cache_destroy
    145  *
    146  * Description:
    147  *	Destroys the cachefscache_t object.
    148  * Arguments:
    149  *	cachep	the cachefscache_t object to destroy
    150  * Returns:
    151  * Preconditions:
    152  *	precond(cachep)
    153  */
    154 
    155 void
    156 cachefs_cache_destroy(cachefscache_t *cachep)
    157 {
    158 	int error = 0;
    159 #ifdef CFSRLDEBUG
    160 	uint_t index;
    161 #endif /* CFSRLDEBUG */
    162 	clock_t wakeup = (60 * hz);
    163 
    164 	/* stop async threads */
    165 	while (cachep->c_workq.wq_thread_count > 0)
    166 		(void) cachefs_async_halt(&cachep->c_workq, 1);
    167 
    168 	/* kill off the cachep worker thread */
    169 	mutex_enter(&cachep->c_contentslock);
    170 	while (cachep->c_flags & CACHE_CACHEW_THREADRUN) {
    171 		cachep->c_flags |= CACHE_CACHEW_THREADEXIT;
    172 		cv_signal(&cachep->c_cwcv);
    173 		(void) cv_reltimedwait(&cachep->c_cwhaltcv,
    174 		    &cachep->c_contentslock, wakeup, TR_CLOCK_TICK);
    175 	}
    176 
    177 	if ((cachep->c_flags & CACHE_ALLOC_PENDING) == 0) {
    178 		cachep->c_usage.cu_flags &= ~CUSAGE_ACTIVE;
    179 		(void) cachefs_cache_rssync(cachep);
    180 	}
    181 	mutex_exit(&cachep->c_contentslock);
    182 
    183 	/* if there is a cache */
    184 	if ((cachep->c_flags & CACHE_NOCACHE) == 0) {
    185 		if ((cachep->c_flags & CACHE_NOFILL) == 0) {
    186 #ifdef CFSRLDEBUG
    187 			/* blow away dangling rl debugging info */
    188 			mutex_enter(&cachep->c_contentslock);
    189 			for (index = 0;
    190 			    index <= cachep->c_rlinfo.rl_entries;
    191 			    index++) {
    192 				rl_entry_t *rlent;
    193 
    194 				error = cachefs_rl_entry_get(cachep, index,
    195 				    rlent);
    196 				/*
    197 				 * Since we are destroying the cache,
    198 				 * better to ignore and proceed
    199 				 */
    200 				if (error)
    201 					break;
    202 				cachefs_rl_debug_destroy(rlent);
    203 			}
    204 			mutex_exit(&cachep->c_contentslock);
    205 #endif /* CFSRLDEBUG */
    206 
    207 			/* sync the cache */
    208 			if (!error)
    209 				cachefs_cache_sync(cachep);
    210 		} else {
    211 			/* get rid of any unused fscache objects */
    212 			mutex_enter(&cachep->c_fslistlock);
    213 			fscache_list_gc(cachep);
    214 			mutex_exit(&cachep->c_fslistlock);
    215 		}
    216 		ASSERT(cachep->c_fslist == NULL);
    217 
    218 		VN_RELE(cachep->c_resfilevp);
    219 		VN_RELE(cachep->c_dirvp);
    220 		VN_RELE(cachep->c_lockvp);
    221 		VN_RELE(cachep->c_lostfoundvp);
    222 	}
    223 
    224 	if (cachep->c_log_ctl != NULL)
    225 		cachefs_kmem_free(cachep->c_log_ctl,
    226 		    sizeof (cachefs_log_control_t));
    227 	if (cachep->c_log != NULL)
    228 		cachefs_log_destroy_cookie(cachep->c_log);
    229 
    230 	cv_destroy(&cachep->c_cwcv);
    231 	cv_destroy(&cachep->c_cwhaltcv);
    232 	mutex_destroy(&cachep->c_contentslock);
    233 	mutex_destroy(&cachep->c_fslistlock);
    234 	mutex_destroy(&cachep->c_log_mutex);
    235 
    236 	kmem_cache_free(cachefs_cache_kmcache, cachep);
    237 }
    238 
    239 /*
    240  * ------------------------------------------------------------------
    241  *
    242  *		cachefs_cache_active_ro
    243  *
    244  * Description:
    245  *	Activates the cachefscache_t object for a read-only file system.
    246  * Arguments:
    247  *	cachep	the cachefscache_t object to activate
    248  *	cdvp	the vnode of the cache directory
    249  * Returns:
    250  *	Returns 0 for success, !0 if there is a problem with the cache.
    251  * Preconditions:
    252  *	precond(cachep)
    253  *	precond(cdvp)
    254  *	precond(cachep->c_flags & CACHE_NOCACHE)
    255  */
    256 
    257 int
    258 cachefs_cache_activate_ro(cachefscache_t *cachep, vnode_t *cdvp)
    259 {
    260 	cachefs_log_control_t *lc;
    261 	vnode_t *labelvp = NULL;
    262 	vnode_t *rifvp = NULL;
    263 	vnode_t *lockvp = NULL;
    264 	vnode_t *statevp = NULL;
    265 	vnode_t *lostfoundvp = NULL;
    266 	struct vattr *attrp = NULL;
    267 	int error;
    268 
    269 	ASSERT(cachep->c_flags & CACHE_NOCACHE);
    270 	mutex_enter(&cachep->c_contentslock);
    271 
    272 	attrp = cachefs_kmem_alloc(sizeof (struct vattr), KM_SLEEP);
    273 
    274 	/* get the mode bits of the cache directory */
    275 	attrp->va_mask = AT_ALL;
    276 	error = VOP_GETATTR(cdvp, attrp, 0, kcred, NULL);
    277 	if (error)
    278 		goto out;
    279 
    280 	/* ensure the mode bits are 000 to keep out casual users */
    281 	if (attrp->va_mode & S_IAMB) {
    282 		cmn_err(CE_WARN, "cachefs: Cache Directory Mode must be 000\n");
    283 		error = EPERM;
    284 		goto out;
    285 	}
    286 
    287 	/* Get the lock file */
    288 	error = VOP_LOOKUP(cdvp, CACHEFS_LOCK_FILE, &lockvp, NULL, 0, NULL,
    289 	    kcred, NULL, NULL, NULL);
    290 	if (error) {
    291 		cmn_err(CE_WARN, "cachefs: activate_a: cache corruption"
    292 		    " run fsck.\n");
    293 		goto out;
    294 	}
    295 
    296 	/* Get the label file */
    297 	error = VOP_LOOKUP(cdvp, CACHELABEL_NAME, &labelvp, NULL, 0, NULL,
    298 	    kcred, NULL, NULL, NULL);
    299 	if (error) {
    300 		cmn_err(CE_WARN, "cachefs: activate_b: cache corruption"
    301 		    " run fsck.\n");
    302 		goto out;
    303 	}
    304 
    305 	/* read in the label */
    306 	error = vn_rdwr(UIO_READ, labelvp, (caddr_t)&cachep->c_label,
    307 	    sizeof (struct cache_label), 0LL, UIO_SYSSPACE,
    308 	    0, (rlim64_t)0, kcred, NULL);
    309 	if (error) {
    310 		cmn_err(CE_WARN, "cachefs: activate_c: cache corruption"
    311 		    " run fsck.\n");
    312 		goto out;
    313 	}
    314 
    315 	/* Verify that we can handle the version this cache was created under */
    316 	if (cachep->c_label.cl_cfsversion != CFSVERSION) {
    317 		cmn_err(CE_WARN, "cachefs: Invalid Cache Version, run fsck\n");
    318 		error = EINVAL;
    319 		goto out;
    320 	}
    321 
    322 	/* Open the resource file */
    323 	error = VOP_LOOKUP(cdvp, RESOURCE_NAME, &rifvp, NULL, 0, NULL, kcred,
    324 	    NULL, NULL, NULL);
    325 	if (error) {
    326 		cmn_err(CE_WARN, "cachefs: activate_d: cache corruption"
    327 		    " run fsck.\n");
    328 		goto out;
    329 	}
    330 
    331 	/*  Read the usage struct for this cache */
    332 	error = vn_rdwr(UIO_READ, rifvp, (caddr_t)&cachep->c_usage,
    333 	    sizeof (struct cache_usage), 0LL, UIO_SYSSPACE, 0,
    334 	    (rlim64_t)0, kcred, NULL);
    335 	if (error) {
    336 		cmn_err(CE_WARN, "cachefs: activate_e: cache corruption"
    337 		    " run fsck.\n");
    338 		goto out;
    339 	}
    340 
    341 	if (cachep->c_usage.cu_flags & CUSAGE_ACTIVE) {
    342 		cmn_err(CE_WARN, "cachefs: cache not clean.  Run fsck\n");
    343 		/* ENOSPC is what UFS uses for clean flag check */
    344 		error = ENOSPC;
    345 		goto out;
    346 	}
    347 
    348 	/*  Read the rlinfo for this cache */
    349 	error = vn_rdwr(UIO_READ, rifvp, (caddr_t)&cachep->c_rlinfo,
    350 	    sizeof (cachefs_rl_info_t), (offset_t)sizeof (struct cache_usage),
    351 	    UIO_SYSSPACE, 0, 0, kcred, NULL);
    352 	if (error) {
    353 		cmn_err(CE_WARN, "cachefs: activate_f: cache corruption"
    354 		    " run fsck.\n");
    355 		goto out;
    356 	}
    357 
    358 	/* Open the lost+found directory */
    359 	error = VOP_LOOKUP(cdvp, CACHEFS_LOSTFOUND_NAME, &lostfoundvp,
    360 	    NULL, 0, NULL, kcred, NULL, NULL, NULL);
    361 	if (error) {
    362 		cmn_err(CE_WARN, "cachefs: activate_g: cache corruption"
    363 		    " run fsck.\n");
    364 		goto out;
    365 	}
    366 
    367 	VN_HOLD(rifvp);
    368 	VN_HOLD(cdvp);
    369 	VN_HOLD(lockvp);
    370 	VN_HOLD(lostfoundvp);
    371 	cachep->c_resfilevp = rifvp;
    372 	cachep->c_dirvp = cdvp;
    373 	cachep->c_lockvp = lockvp;
    374 	cachep->c_lostfoundvp = lostfoundvp;
    375 
    376 	/* get the cachep worker thread created */
    377 	cachep->c_flags |= CACHE_CACHEW_THREADRUN;
    378 	(void) thread_create(NULL, 0, cachefs_cachep_worker_thread,
    379 	    cachep, 0, &p0, TS_RUN, minclsyspri);
    380 
    381 	/* allocate the `logging control' field */
    382 	mutex_enter(&cachep->c_log_mutex);
    383 	cachep->c_log_ctl =
    384 	    cachefs_kmem_zalloc(sizeof (cachefs_log_control_t), KM_SLEEP);
    385 	lc = (cachefs_log_control_t *)cachep->c_log_ctl;
    386 
    387 	/* if the LOG_STATUS_NAME file exists, read it in and set up logging */
    388 	error = VOP_LOOKUP(cachep->c_dirvp, LOG_STATUS_NAME, &statevp,
    389 	    NULL, 0, NULL, kcred, NULL, NULL, NULL);
    390 	if (error == 0) {
    391 		int vnrw_error;
    392 
    393 		vnrw_error = vn_rdwr(UIO_READ, statevp, (caddr_t)lc,
    394 		    sizeof (*lc), 0LL, UIO_SYSSPACE, 0, (rlim64_t)RLIM_INFINITY,
    395 		    kcred, NULL);
    396 		VN_RELE(statevp);
    397 
    398 		if (vnrw_error == 0) {
    399 			if ((cachep->c_log = cachefs_log_create_cookie(lc))
    400 			    == NULL)
    401 				cachefs_log_error(cachep, ENOMEM, 0);
    402 			else if ((lc->lc_magic != CACHEFS_LOG_MAGIC) ||
    403 			    (lc->lc_path[0] != '/') ||
    404 			    (cachefs_log_logfile_open(cachep,
    405 			    lc->lc_path) != 0))
    406 				cachefs_log_error(cachep, EINVAL, 0);
    407 		}
    408 	} else {
    409 		error = 0;
    410 	}
    411 	lc->lc_magic = CACHEFS_LOG_MAGIC;
    412 	lc->lc_cachep = (uint64_t)(uintptr_t)cachep;
    413 	mutex_exit(&cachep->c_log_mutex);
    414 
    415 out:
    416 	if (error == 0) {
    417 		cachep->c_flags &= ~(CACHE_NOCACHE | CACHE_ALLOC_PENDING);
    418 	}
    419 	if (attrp)
    420 		cachefs_kmem_free(attrp, sizeof (struct vattr));
    421 	if (labelvp != NULL)
    422 		VN_RELE(labelvp);
    423 	if (rifvp != NULL)
    424 		VN_RELE(rifvp);
    425 	if (lockvp)
    426 		VN_RELE(lockvp);
    427 	if (lostfoundvp)
    428 		VN_RELE(lostfoundvp);
    429 
    430 	mutex_exit(&cachep->c_contentslock);
    431 	return (error);
    432 }
    433 
    434 int
    435 cachefs_stop_cache(cnode_t *cp)
    436 {
    437 	fscache_t *fscp = C_TO_FSCACHE(cp);
    438 	cachefscache_t *cachep = fscp->fs_cache;
    439 	filegrp_t *fgp;
    440 	int i;
    441 	int error = 0;
    442 	clock_t wakeup = (60 * hz);
    443 
    444 	/* XXX verify lock-ordering for this function */
    445 
    446 	mutex_enter(&cachep->c_contentslock);
    447 
    448 	/*
    449 	 * no work if we're already in nocache mode.  hopefully this
    450 	 * will be the usual case.
    451 	 */
    452 
    453 	if (cachep->c_flags & CACHE_NOCACHE) {
    454 		mutex_exit(&cachep->c_contentslock);
    455 		return (0);
    456 	}
    457 
    458 	if ((cachep->c_flags & CACHE_NOFILL) == 0) {
    459 		mutex_exit(&cachep->c_contentslock);
    460 		return (EINVAL);
    461 	}
    462 
    463 	mutex_exit(&cachep->c_contentslock);
    464 
    465 	/* We are already not caching if nfsv4 */
    466 	if (CFS_ISFS_BACKFS_NFSV4(fscp)) {
    467 		return (0);
    468 	}
    469 
    470 #ifdef CFSDEBUG
    471 	mutex_enter(&cachep->c_fslistlock);
    472 	ASSERT(fscp == cachep->c_fslist);
    473 	ASSERT(fscp->fs_next == NULL);
    474 	mutex_exit(&cachep->c_fslistlock);
    475 
    476 	printf("cachefs_stop_cache: resetting CACHE_NOCACHE\n");
    477 #endif
    478 
    479 	/* XXX should i worry about disconnected during boot? */
    480 	error = cachefs_cd_access(fscp, 1, 1);
    481 	if (error)
    482 		goto out;
    483 
    484 	error = cachefs_async_halt(&fscp->fs_workq, 1);
    485 	ASSERT(error == 0);
    486 	error = cachefs_async_halt(&cachep->c_workq, 1);
    487 	ASSERT(error == 0);
    488 	/* sigh -- best to keep going if async_halt failed. */
    489 	error = 0;
    490 
    491 	/* XXX current order: cnode, fgp, fscp, cache. okay? */
    492 
    493 	cachefs_cnode_traverse(fscp, cachefs_cnode_disable_caching);
    494 
    495 	for (i = 0; i < CFS_FS_FGP_BUCKET_SIZE; i++) {
    496 		for (fgp = fscp->fs_filegrp[i]; fgp != NULL;
    497 		    fgp = fgp->fg_next) {
    498 			mutex_enter(&fgp->fg_mutex);
    499 
    500 			ASSERT((fgp->fg_flags &
    501 			    (CFS_FG_WRITE | CFS_FG_UPDATED)) == 0);
    502 			fgp->fg_flags |=
    503 			    CFS_FG_ALLOC_FILE |
    504 			    CFS_FG_ALLOC_ATTR;
    505 			fgp->fg_flags &= ~CFS_FG_READ;
    506 
    507 			if (fgp->fg_dirvp) {
    508 				fgp->fg_flags |= CFS_FG_ALLOC_FILE;
    509 				VN_RELE(fgp->fg_dirvp);
    510 				fgp->fg_dirvp = NULL;
    511 			}
    512 			if (fgp->fg_attrvp) {
    513 				fgp->fg_flags |= CFS_FG_ALLOC_ATTR;
    514 				VN_RELE(fgp->fg_attrvp);
    515 				fgp->fg_attrvp = NULL;
    516 			}
    517 
    518 			mutex_exit(&fgp->fg_mutex);
    519 		}
    520 	}
    521 
    522 	mutex_enter(&fscp->fs_fslock);
    523 	ASSERT((fscp->fs_flags & (CFS_FS_WRITE)) == 0);
    524 	fscp->fs_flags &= ~(CFS_FS_READ | CFS_FS_DIRTYINFO);
    525 
    526 	if (fscp->fs_fscdirvp) {
    527 		VN_RELE(fscp->fs_fscdirvp);
    528 		fscp->fs_fscdirvp = NULL;
    529 	}
    530 	if (fscp->fs_fsattrdir) {
    531 		VN_RELE(fscp->fs_fsattrdir);
    532 		fscp->fs_fsattrdir = NULL;
    533 	}
    534 	if (fscp->fs_infovp) {
    535 		VN_RELE(fscp->fs_infovp);
    536 		fscp->fs_infovp = NULL;
    537 	}
    538 	/* XXX dlog stuff? */
    539 
    540 	mutex_exit(&fscp->fs_fslock);
    541 
    542 	/*
    543 	 * release resources grabbed in cachefs_cache_activate_ro
    544 	 */
    545 
    546 	mutex_enter(&cachep->c_contentslock);
    547 
    548 	/* kill off the cachep worker thread */
    549 	while (cachep->c_flags & CACHE_CACHEW_THREADRUN) {
    550 		cachep->c_flags |= CACHE_CACHEW_THREADEXIT;
    551 		cv_signal(&cachep->c_cwcv);
    552 		(void) cv_reltimedwait(&cachep->c_cwhaltcv,
    553 		    &cachep->c_contentslock, wakeup, TR_CLOCK_TICK);
    554 	}
    555 
    556 	if (cachep->c_resfilevp) {
    557 		VN_RELE(cachep->c_resfilevp);
    558 		cachep->c_resfilevp = NULL;
    559 	}
    560 	if (cachep->c_dirvp) {
    561 		VN_RELE(cachep->c_dirvp);
    562 		cachep->c_dirvp = NULL;
    563 	}
    564 	if (cachep->c_lockvp) {
    565 		VN_RELE(cachep->c_lockvp);
    566 		cachep->c_lockvp = NULL;
    567 	}
    568 	if (cachep->c_lostfoundvp) {
    569 		VN_RELE(cachep->c_lostfoundvp);
    570 		cachep->c_lostfoundvp = NULL;
    571 	}
    572 
    573 	mutex_enter(&cachep->c_log_mutex);
    574 	if (cachep->c_log_ctl) {
    575 		cachefs_kmem_free(cachep->c_log_ctl,
    576 		    sizeof (cachefs_log_control_t));
    577 		cachep->c_log_ctl = NULL;
    578 	}
    579 	if (cachep->c_log) {
    580 		cachefs_log_destroy_cookie(cachep->c_log);
    581 		cachep->c_log = NULL;
    582 	}
    583 	mutex_exit(&cachep->c_log_mutex);
    584 
    585 	/* XXX do what mountroot_init does when ! foundcache */
    586 
    587 	cachep->c_flags |= CACHE_NOCACHE;
    588 	mutex_exit(&cachep->c_contentslock);
    589 
    590 	/* XXX should i release this here? */
    591 	cachefs_cd_release(fscp);
    592 
    593 out:
    594 
    595 	return (error);
    596 }
    597 
    598 /*
    599  * ------------------------------------------------------------------
    600  *
    601  *		cachefs_cache_active_rw
    602  *
    603  * Description:
    604  *	Activates the cachefscache_t object for a read-write file system.
    605  * Arguments:
    606  *	cachep	the cachefscache_t object to activate
    607  * Returns:
    608  * Preconditions:
    609  *	precond(cachep)
    610  *	precond((cachep->c_flags & CACHE_NOCACHE) == 0)
    611  *	precond(cachep->c_flags & CACHE_NOFILL)
    612  */
    613 
    614 void
    615 cachefs_cache_activate_rw(cachefscache_t *cachep)
    616 {
    617 	cachefs_rl_listhead_t *lhp;
    618 
    619 	ASSERT((cachep->c_flags & CACHE_NOCACHE) == 0);
    620 	ASSERT(cachep->c_flags & CACHE_NOFILL);
    621 
    622 	mutex_enter(&cachep->c_contentslock);
    623 	cachep->c_flags &= ~CACHE_NOFILL;
    624 
    625 	/* move the active list to the rl list */
    626 	cachefs_rl_cleanup(cachep);
    627 
    628 	lhp = &cachep->c_rlinfo.rl_items[
    629 	    CACHEFS_RL_INDEX(CACHEFS_RL_PACKED_PENDING)];
    630 	if (lhp->rli_itemcnt != 0)
    631 		cachep->c_flags |= CACHE_PACKED_PENDING;
    632 	cachefs_cache_dirty(cachep, 0);
    633 	mutex_exit(&cachep->c_contentslock);
    634 }
    635 
    636 /*
    637  * ------------------------------------------------------------------
    638  *
    639  *		cachefs_cache_dirty
    640  *
    641  * Description:
    642  *	Marks the cache as dirty (active).
    643  * Arguments:
    644  *	cachep	the cachefscache_t to mark as dirty
    645  *	lockit	1 means grab contents lock, 0 means caller grabbed it
    646  * Returns:
    647  * Preconditions:
    648  *	precond(cachep)
    649  *	precond(cache is in rw mode)
    650  */
    651 
    652 void
    653 cachefs_cache_dirty(struct cachefscache *cachep, int lockit)
    654 {
    655 	int error;
    656 
    657 	ASSERT((cachep->c_flags & (CACHE_NOCACHE | CACHE_NOFILL)) == 0);
    658 
    659 	if (lockit) {
    660 		mutex_enter(&cachep->c_contentslock);
    661 	} else {
    662 		ASSERT(MUTEX_HELD(&cachep->c_contentslock));
    663 	}
    664 	if (cachep->c_flags & CACHE_DIRTY) {
    665 		ASSERT(cachep->c_usage.cu_flags & CUSAGE_ACTIVE);
    666 	} else {
    667 		/*
    668 		 * turn on the "cache active" (dirty) flag and write it
    669 		 * synchronously to disk
    670 		 */
    671 		cachep->c_flags |= CACHE_DIRTY;
    672 		cachep->c_usage.cu_flags |= CUSAGE_ACTIVE;
    673 		if (error = vn_rdwr(UIO_WRITE, cachep->c_resfilevp,
    674 		    (caddr_t)&cachep->c_usage, sizeof (struct cache_usage),
    675 		    0LL, UIO_SYSSPACE, FSYNC, (rlim64_t)RLIM_INFINITY,
    676 		    kcred, NULL)) {
    677 			cmn_err(CE_WARN,
    678 			    "cachefs: clean flag write error: %d\n", error);
    679 		}
    680 	}
    681 
    682 	if (lockit)
    683 		mutex_exit(&cachep->c_contentslock);
    684 }
    685 
    686 /*
    687  * ------------------------------------------------------------------
    688  *
    689  *		cachefs_cache_rssync
    690  *
    691  * Description:
    692  *	Syncs out the resource file for the cachefscache_t object.
    693  * Arguments:
    694  *	cachep	the cachefscache_t object to operate on
    695  * Returns:
    696  *	Returns 0 for success, !0 on an error writing data.
    697  * Preconditions:
    698  *	precond(cachep)
    699  *	precond(cache is in rw mode)
    700  */
    701 
    702 int
    703 cachefs_cache_rssync(struct cachefscache *cachep)
    704 {
    705 	int error;
    706 
    707 	ASSERT((cachep->c_flags & (CACHE_NOCACHE | CACHE_NOFILL |
    708 	    CACHE_ALLOC_PENDING)) == 0);
    709 
    710 	if (cachep->c_rl_entries != NULL) {
    711 		error = vn_rdwr(UIO_WRITE, cachep->c_resfilevp,
    712 		    (caddr_t)cachep->c_rl_entries, MAXBSIZE,
    713 		    (offset_t)((cachep->c_rl_window + 1) * MAXBSIZE),
    714 		    UIO_SYSSPACE, FSYNC, RLIM_INFINITY, kcred, NULL);
    715 		if (error)
    716 			cmn_err(CE_WARN,
    717 			    "cachefs: Can't Write rl entries Info\n");
    718 		cachefs_kmem_free(cachep->c_rl_entries, MAXBSIZE);
    719 		cachep->c_rl_entries = NULL;
    720 	}
    721 
    722 	/* write the usage struct for this cache */
    723 	error = vn_rdwr(UIO_WRITE, cachep->c_resfilevp,
    724 	    (caddr_t)&cachep->c_usage, sizeof (struct cache_usage),
    725 	    0LL, UIO_SYSSPACE, 0, (rlim64_t)RLIM_INFINITY, kcred, NULL);
    726 	if (error) {
    727 		cmn_err(CE_WARN, "cachefs: Can't Write Cache Usage Info\n");
    728 	}
    729 
    730 	/* write the rlinfo for this cache */
    731 	error = vn_rdwr(UIO_WRITE, cachep->c_resfilevp,
    732 	    (caddr_t)&cachep->c_rlinfo, sizeof (cachefs_rl_info_t),
    733 	    (offset_t)sizeof (struct cache_usage), UIO_SYSSPACE,
    734 	    0, (rlim64_t)RLIM_INFINITY, kcred, NULL);
    735 	if (error) {
    736 		cmn_err(CE_WARN, "cachefs: Can't Write Cache RL Info\n");
    737 	}
    738 	error = VOP_FSYNC(cachep->c_resfilevp, FSYNC, kcred, NULL);
    739 	return (error);
    740 }
    741 
    742 /*
    743  * ------------------------------------------------------------------
    744  *
    745  *		cachefs_cache_sync
    746  *
    747  * Description:
    748  *	Sync a cache which includes all of its fscaches.
    749  * Arguments:
    750  *	cachep	the cachefscache_t object to sync
    751  * Returns:
    752  * Preconditions:
    753  *	precond(cachep)
    754  *	precond(cache is in rw mode)
    755  */
    756 
    757 void
    758 cachefs_cache_sync(struct cachefscache *cachep)
    759 {
    760 	struct fscache *fscp;
    761 	struct fscache **syncfsc;
    762 	int nfscs, fscidx;
    763 	int try;
    764 	int done;
    765 
    766 	if (cachep->c_flags & (CACHE_NOCACHE | CACHE_NOFILL))
    767 		return;
    768 
    769 	done = 0;
    770 	for (try = 0; (try < 2) && !done; try++) {
    771 
    772 		nfscs = 0;
    773 
    774 		/*
    775 		 * here we turn off the cache-wide DIRTY flag.  If it's still
    776 		 * off when the sync completes we can write the clean flag to
    777 		 * disk telling fsck it has no work to do.
    778 		 */
    779 #ifdef CFSCLEANFLAG
    780 		mutex_enter(&cachep->c_contentslock);
    781 		cachep->c_flags &= ~CACHE_DIRTY;
    782 		mutex_exit(&cachep->c_contentslock);
    783 #endif /* CFSCLEANFLAG */
    784 
    785 		cachefs_log_process_queue(cachep, 1);
    786 
    787 		mutex_enter(&cachep->c_fslistlock);
    788 		syncfsc = cachefs_kmem_alloc(
    789 		    cachep->c_refcnt * sizeof (struct fscache *), KM_SLEEP);
    790 		for (fscp = cachep->c_fslist; fscp; fscp = fscp->fs_next) {
    791 			fscache_hold(fscp);
    792 			ASSERT(nfscs < cachep->c_refcnt);
    793 			syncfsc[nfscs++] = fscp;
    794 		}
    795 		ASSERT(nfscs == cachep->c_refcnt);
    796 		mutex_exit(&cachep->c_fslistlock);
    797 		for (fscidx = 0; fscidx < nfscs; fscidx++) {
    798 			fscp = syncfsc[fscidx];
    799 			fscache_sync(fscp);
    800 			fscache_rele(fscp);
    801 		}
    802 
    803 		/* get rid of any unused fscache objects */
    804 		mutex_enter(&cachep->c_fslistlock);
    805 		fscache_list_gc(cachep);
    806 		mutex_exit(&cachep->c_fslistlock);
    807 
    808 		/*
    809 		 * here we check the cache-wide DIRTY flag.
    810 		 * If it's off,
    811 		 * we can write the clean flag to disk.
    812 		 */
    813 #ifdef CFSCLEANFLAG
    814 		mutex_enter(&cachep->c_contentslock);
    815 		if ((cachep->c_flags & CACHE_DIRTY) == 0) {
    816 			if (cachep->c_usage.cu_flags & CUSAGE_ACTIVE) {
    817 				cachep->c_usage.cu_flags &= ~CUSAGE_ACTIVE;
    818 				if (cachefs_cache_rssync(cachep) == 0) {
    819 					done = 1;
    820 				} else {
    821 					cachep->c_usage.cu_flags |=
    822 					    CUSAGE_ACTIVE;
    823 				}
    824 			} else {
    825 				done = 1;
    826 			}
    827 		}
    828 		mutex_exit(&cachep->c_contentslock);
    829 #else /* CFSCLEANFLAG */
    830 		mutex_enter(&cachep->c_contentslock);
    831 		(void) cachefs_cache_rssync(cachep);
    832 		mutex_exit(&cachep->c_contentslock);
    833 		done = 1;
    834 #endif /* CFSCLEANFLAG */
    835 		cachefs_kmem_free(syncfsc, nfscs * sizeof (struct fscache *));
    836 	}
    837 }
    838 
    839 /*
    840  * ------------------------------------------------------------------
    841  *
    842  *		cachefs_cache_unique
    843  *
    844  * Description:
    845  * Arguments:
    846  * Returns:
    847  *	Returns a unique number.
    848  * Preconditions:
    849  *	precond(cachep)
    850  */
    851 
    852 uint_t
    853 cachefs_cache_unique(cachefscache_t *cachep)
    854 {
    855 	uint_t unique = 0;
    856 	int error = 0;
    857 
    858 	mutex_enter(&cachep->c_contentslock);
    859 	if (cachep->c_usage.cu_flags & CUSAGE_NEED_ADJUST ||
    860 	    ++(cachep->c_unique) == 0) {
    861 		cachep->c_usage.cu_unique++;
    862 
    863 		if (cachep->c_unique == 0)
    864 			cachep->c_unique = 1;
    865 		cachep->c_flags &= ~CUSAGE_NEED_ADJUST;
    866 		error = cachefs_cache_rssync(cachep);
    867 	}
    868 	if (error == 0)
    869 		unique = (cachep->c_usage.cu_unique << 16) + cachep->c_unique;
    870 	mutex_exit(&cachep->c_contentslock);
    871 	return (unique);
    872 }
    873 
    874 /*
    875  * Called from c_getfrontfile. Shouldn't be called from anywhere else !
    876  */
    877 static int
    878 cachefs_createfrontfile(cnode_t *cp, struct filegrp *fgp)
    879 {
    880 	char name[CFS_FRONTFILE_NAME_SIZE];
    881 	struct vattr *attrp = NULL;
    882 	int error = 0;
    883 	int mode;
    884 	int alloc = 0;
    885 	int freefile = 0;
    886 	int ffrele = 0;
    887 	int rlfree = 0;
    888 	rl_entry_t rl_ent;
    889 
    890 #ifdef CFSDEBUG
    891 	CFS_DEBUG(CFSDEBUG_FRONT)
    892 		printf("c_createfrontfile: ENTER cp %p fgp %p\n",
    893 		    (void *)cp, (void *)fgp);
    894 #endif
    895 
    896 	ASSERT(cp->c_frontvp == NULL);
    897 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fgp->fg_fscp) == 0);
    898 
    899 	/* quit if we cannot write to the filegrp */
    900 	if ((fgp->fg_flags & CFS_FG_WRITE) == 0) {
    901 		error = ENOENT;
    902 		goto out;
    903 	}
    904 
    905 	/* find or create the filegrp attrcache file if necessary */
    906 	if (fgp->fg_flags & CFS_FG_ALLOC_ATTR) {
    907 		error = filegrp_allocattr(fgp);
    908 		if (error)
    909 			goto out;
    910 	}
    911 
    912 	make_ascii_name(&cp->c_id, name);
    913 
    914 	/* set up attributes for the front file we want to create */
    915 	attrp = cachefs_kmem_zalloc(sizeof (struct vattr), KM_SLEEP);
    916 	alloc++;
    917 	attrp->va_mode = S_IFREG | 0666;
    918 	mode = 0666;
    919 	attrp->va_uid = 0;
    920 	attrp->va_gid = 0;
    921 	attrp->va_type = VREG;
    922 	attrp->va_size = 0;
    923 	attrp->va_mask = AT_SIZE | AT_TYPE | AT_MODE | AT_UID | AT_GID;
    924 
    925 	/* get a file from the resource counts */
    926 	error = cachefs_allocfile(fgp->fg_fscp->fs_cache);
    927 	if (error) {
    928 		error = EINVAL;
    929 		goto out;
    930 	}
    931 	freefile++;
    932 
    933 	/* create the metadata slot if necessary */
    934 	if (cp->c_flags & CN_ALLOC_PENDING) {
    935 		error = filegrp_create_metadata(fgp, &cp->c_metadata,
    936 		    &cp->c_id);
    937 		if (error) {
    938 			error = EINVAL;
    939 			goto out;
    940 		}
    941 		cp->c_flags &= ~CN_ALLOC_PENDING;
    942 		cp->c_flags |= CN_UPDATED;
    943 	}
    944 
    945 	/* get an rl entry if necessary */
    946 	if (cp->c_metadata.md_rlno == 0) {
    947 		rl_ent.rl_fileno = cp->c_id.cid_fileno;
    948 		rl_ent.rl_local = (cp->c_id.cid_flags & CFS_CID_LOCAL) ? 1 : 0;
    949 		rl_ent.rl_fsid = fgp->fg_fscp->fs_cfsid;
    950 		rl_ent.rl_attrc = 0;
    951 		error = cachefs_rl_alloc(fgp->fg_fscp->fs_cache, &rl_ent,
    952 		    &cp->c_metadata.md_rlno);
    953 		if (error)
    954 			goto out;
    955 		cachefs_rlent_moveto(fgp->fg_fscp->fs_cache,
    956 		    CACHEFS_RL_ACTIVE, cp->c_metadata.md_rlno,
    957 		    cp->c_metadata.md_frontblks);
    958 		cp->c_metadata.md_rltype = CACHEFS_RL_ACTIVE;
    959 		rlfree++;
    960 		cp->c_flags |= CN_UPDATED; /* XXX sam: do we need this? */
    961 
    962 		/* increment number of front files */
    963 		error = filegrp_ffhold(fgp);
    964 		if (error) {
    965 			error = EINVAL;
    966 			goto out;
    967 		}
    968 		ffrele++;
    969 	}
    970 
    971 	if (cp->c_flags & CN_ASYNC_POP_WORKING) {
    972 		/* lookup the already created front file */
    973 		error = VOP_LOOKUP(fgp->fg_dirvp, name, &cp->c_frontvp,
    974 		    NULL, 0, NULL, kcred, NULL, NULL, NULL);
    975 	} else {
    976 		/* create the front file */
    977 		error = VOP_CREATE(fgp->fg_dirvp, name, attrp, EXCL, mode,
    978 		    &cp->c_frontvp, kcred, 0, NULL, NULL);
    979 	}
    980 	if (error) {
    981 #ifdef CFSDEBUG
    982 		CFS_DEBUG(CFSDEBUG_FRONT)
    983 			printf("c_createfrontfile: Can't create cached object"
    984 			    " error %u, fileno %llx\n", error,
    985 			    (u_longlong_t)cp->c_id.cid_fileno);
    986 #endif
    987 		goto out;
    988 	}
    989 
    990 	/* get a copy of the fid of the front file */
    991 	cp->c_metadata.md_fid.fid_len = MAXFIDSZ;
    992 	error = VOP_FID(cp->c_frontvp, &cp->c_metadata.md_fid, NULL);
    993 	if (error) {
    994 		/*
    995 		 * If we get back ENOSPC then the fid we passed in was too
    996 		 * small.  For now we don't do anything and map to EINVAL.
    997 		 */
    998 		if (error == ENOSPC) {
    999 			error = EINVAL;
   1000 		}
   1001 		goto out;
   1002 	}
   1003 
   1004 	dnlc_purge_vp(cp->c_frontvp);
   1005 
   1006 	cp->c_metadata.md_flags |= MD_FILE;
   1007 	cp->c_flags |= CN_UPDATED | CN_NEED_FRONT_SYNC;
   1008 
   1009 out:
   1010 	if (error) {
   1011 		if (cp->c_frontvp) {
   1012 			VN_RELE(cp->c_frontvp);
   1013 			(void) VOP_REMOVE(fgp->fg_dirvp, name, kcred, NULL, 0);
   1014 			cp->c_frontvp = NULL;
   1015 		}
   1016 		if (ffrele)
   1017 			filegrp_ffrele(fgp);
   1018 		if (freefile)
   1019 			cachefs_freefile(fgp->fg_fscp->fs_cache);
   1020 		if (rlfree) {
   1021 #ifdef CFSDEBUG
   1022 			cachefs_rlent_verify(fgp->fg_fscp->fs_cache,
   1023 			    CACHEFS_RL_ACTIVE, cp->c_metadata.md_rlno);
   1024 #endif /* CFSDEBUG */
   1025 			cachefs_rlent_moveto(fgp->fg_fscp->fs_cache,
   1026 			    CACHEFS_RL_FREE, cp->c_metadata.md_rlno, 0);
   1027 			cp->c_metadata.md_rlno = 0;
   1028 			cp->c_metadata.md_rltype = CACHEFS_RL_NONE;
   1029 		}
   1030 		cachefs_nocache(cp);
   1031 	}
   1032 	if (alloc)
   1033 		cachefs_kmem_free(attrp, sizeof (struct vattr));
   1034 #ifdef CFSDEBUG
   1035 	CFS_DEBUG(CFSDEBUG_FRONT)
   1036 		printf("c_createfrontfile: EXIT error = %d name %s\n", error,
   1037 		    name);
   1038 #endif
   1039 	return (error);
   1040 }
   1041 
   1042 /*
   1043  * Releases resources associated with the front file.
   1044  * Only call this routine if a ffhold has been done.
   1045  * Its okay to call this routine if the front file does not exist.
   1046  * Note: this routine is used even if there is no front file.
   1047  */
   1048 void
   1049 cachefs_removefrontfile(cachefs_metadata_t *mdp, cfs_cid_t *cidp,
   1050     filegrp_t *fgp)
   1051 {
   1052 	int error, enoent;
   1053 	char name[CFS_FRONTFILE_NAME_SIZE + 2];
   1054 
   1055 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fgp->fg_fscp) == 0);
   1056 
   1057 	enoent = 0;
   1058 	if (mdp->md_flags & MD_FILE) {
   1059 		if (fgp->fg_dirvp == NULL) {
   1060 			cmn_err(CE_WARN, "cachefs: remove error, run fsck\n");
   1061 			return;
   1062 		}
   1063 		make_ascii_name(cidp, name);
   1064 		error = VOP_REMOVE(fgp->fg_dirvp, name, kcred, NULL, 0);
   1065 		if (error == ENOENT)
   1066 			enoent = 1;
   1067 		if ((error) && (error != ENOENT)) {
   1068 			cmn_err(CE_WARN, "UFS remove error %s %d, run fsck\n",
   1069 			    name, error);
   1070 		}
   1071 		if (mdp->md_flags & MD_ACLDIR) {
   1072 			(void) strcat(name, ".d");
   1073 			error = VOP_RMDIR(fgp->fg_dirvp, name, fgp->fg_dirvp,
   1074 			    kcred, NULL, 0);
   1075 			if ((error) && (error != ENOENT)) {
   1076 				cmn_err(CE_WARN, "frontfs rmdir error %s %d"
   1077 				    "; run fsck\n", name, error);
   1078 			}
   1079 		}
   1080 		mdp->md_flags &= ~(MD_FILE | MD_POPULATED | MD_ACL | MD_ACLDIR);
   1081 		bzero(&mdp->md_allocinfo, mdp->md_allocents *
   1082 		    sizeof (struct cachefs_allocmap));
   1083 		cachefs_freefile(fgp->fg_fscp->fs_cache);
   1084 	}
   1085 
   1086 	/*
   1087 	 * Clear packed bit, fastsymlinks and special files
   1088 	 * do not have a front file.
   1089 	 */
   1090 	mdp->md_flags &= ~MD_PACKED;
   1091 
   1092 	/* XXX either rename routine or move this to caller */
   1093 	if (enoent == 0)
   1094 		filegrp_ffrele(fgp);
   1095 
   1096 	if (mdp->md_frontblks) {
   1097 		cachefs_freeblocks(fgp->fg_fscp->fs_cache, mdp->md_frontblks,
   1098 		    mdp->md_rltype);
   1099 		mdp->md_frontblks = 0;
   1100 	}
   1101 }
   1102 
   1103 /*
   1104  * This is the interface to the rest of CFS. This takes a cnode, and returns
   1105  * the frontvp (stuffs it in the cnode). This creates an attrcache slot and
   1106  * and frontfile if necessary.
   1107  */
   1108 
   1109 int
   1110 cachefs_getfrontfile(cnode_t *cp)
   1111 {
   1112 	struct filegrp *fgp = cp->c_filegrp;
   1113 	int error;
   1114 	struct vattr va;
   1115 
   1116 #ifdef CFSDEBUG
   1117 	CFS_DEBUG(CFSDEBUG_SUBR)
   1118 		printf("c_getfrontfile: ENTER cp %p\n", (void *)cp);
   1119 #endif
   1120 
   1121 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fgp->fg_fscp) == 0);
   1122 	ASSERT(MUTEX_HELD(&cp->c_statelock));
   1123 
   1124 	/*
   1125 	 * Now we check to see if there is a front file for this entry.
   1126 	 * If there is, we get the vnode for it and stick it in the cnode.
   1127 	 * Otherwise, we create a front file, get the vnode for it and stick
   1128 	 * it in the cnode.
   1129 	 */
   1130 	if (cp->c_flags & CN_STALE) {
   1131 		cp->c_flags |= CN_NOCACHE;
   1132 		error = ESTALE;
   1133 		goto out;
   1134 	}
   1135 
   1136 	/*
   1137 	 * If the cnode is being populated, and we're not the populating
   1138 	 * thread, then block until the pop thread completes.  If we are the
   1139 	 * pop thread, then we may come in here, but not to nuke the directory
   1140 	 * cnode at a critical juncture.  If we return from a cv_wait and the
   1141 	 * cnode is now stale, don't bother trying to get the front file.
   1142 	 */
   1143 	while ((cp->c_flags & CN_ASYNC_POP_WORKING) &&
   1144 	    (cp->c_popthrp != curthread)) {
   1145 		cv_wait(&cp->c_popcv, &cp->c_statelock);
   1146 		if (cp->c_flags & CN_STALE) {
   1147 			cp->c_flags |= CN_NOCACHE;
   1148 			error = ESTALE;
   1149 			goto out;
   1150 		}
   1151 	}
   1152 
   1153 	if ((cp->c_metadata.md_flags & MD_FILE) == 0) {
   1154 #ifdef CFSDEBUG
   1155 		if (cp->c_frontvp != NULL)
   1156 			CFS_DEBUG(CFSDEBUG_FRONT)
   1157 				printf("c_getfrontfile: !MD_FILE and frontvp "
   1158 				    "not null cp %p\n", (void *)cp);
   1159 #endif
   1160 		if (CTOV(cp)->v_type == VDIR)
   1161 			ASSERT((cp->c_metadata.md_flags & MD_POPULATED) == 0);
   1162 		error = cachefs_createfrontfile(cp, fgp);
   1163 		if (error)
   1164 			goto out;
   1165 	} else {
   1166 		/*
   1167 		 * A front file exists, all we need to do is to grab the fid,
   1168 		 * do a VFS_VGET() on the fid, stuff the vnode in the cnode,
   1169 		 * and return.
   1170 		 */
   1171 		if (fgp->fg_dirvp == NULL) {
   1172 			cmn_err(CE_WARN, "cachefs: gff0: corrupted file system"
   1173 			    " run fsck\n");
   1174 			cachefs_inval_object(cp);
   1175 			cp->c_flags |= CN_NOCACHE;
   1176 			error = ESTALE;
   1177 			goto out;
   1178 		}
   1179 		error = VFS_VGET(fgp->fg_dirvp->v_vfsp, &cp->c_frontvp,
   1180 		    &cp->c_metadata.md_fid);
   1181 		if (error || (cp->c_frontvp == NULL)) {
   1182 #ifdef CFSDEBUG
   1183 			CFS_DEBUG(CFSDEBUG_FRONT)
   1184 				printf("cachefs: "
   1185 				    "gff1: front file system error %d\n",
   1186 				    error);
   1187 #endif /* CFSDEBUG */
   1188 			cachefs_inval_object(cp);
   1189 			cp->c_flags |= CN_NOCACHE;
   1190 			error = ESTALE;
   1191 			goto out;
   1192 		}
   1193 
   1194 		/* don't need to check timestamps if need_front_sync is set */
   1195 		if (cp->c_flags & CN_NEED_FRONT_SYNC) {
   1196 			error = 0;
   1197 			goto out;
   1198 		}
   1199 
   1200 		/* don't need to check empty directories */
   1201 		if (CTOV(cp)->v_type == VDIR &&
   1202 		    ((cp->c_metadata.md_flags & MD_POPULATED) == 0)) {
   1203 			error = 0;
   1204 			goto out;
   1205 		}
   1206 
   1207 		/* get modify time of the front file */
   1208 		va.va_mask = AT_MTIME;
   1209 		error = VOP_GETATTR(cp->c_frontvp, &va, 0, kcred, NULL);
   1210 		if (error) {
   1211 			cmn_err(CE_WARN, "cachefs: gff2: front file"
   1212 			    " system error %d", error);
   1213 			cachefs_inval_object(cp);
   1214 			error = (cp->c_flags & CN_NOCACHE) ? ESTALE : 0;
   1215 			goto out;
   1216 		}
   1217 
   1218 		/* compare with modify time stored in metadata */
   1219 		if (bcmp(&va.va_mtime, &cp->c_metadata.md_timestamp,
   1220 		    sizeof (timestruc_t)) != 0) {
   1221 #ifdef CFSDEBUG
   1222 			CFS_DEBUG(CFSDEBUG_GENERAL | CFSDEBUG_INVALIDATE) {
   1223 				long sec, nsec;
   1224 				sec = cp->c_metadata.md_timestamp.tv_sec;
   1225 				nsec = cp->c_metadata.md_timestamp.tv_nsec;
   1226 				printf("c_getfrontfile: timestamps don't"
   1227 				    " match fileno %lld va %lx %lx"
   1228 				    " meta %lx %lx\n",
   1229 				    (u_longlong_t)cp->c_id.cid_fileno,
   1230 				    va.va_mtime.tv_sec,
   1231 				    va.va_mtime.tv_nsec, sec, nsec);
   1232 			}
   1233 #endif
   1234 			cachefs_inval_object(cp);
   1235 			error = (cp->c_flags & CN_NOCACHE) ? ESTALE : 0;
   1236 		}
   1237 	}
   1238 out:
   1239 #ifdef CFSDEBUG
   1240 	CFS_DEBUG(CFSDEBUG_FRONT)
   1241 		printf("c_getfrontfile: EXIT error = %d\n", error);
   1242 #endif
   1243 	return (error);
   1244 }
   1245 
   1246 void
   1247 cachefs_inval_object(cnode_t *cp)
   1248 {
   1249 	cachefscache_t *cachep = C_TO_FSCACHE(cp)->fs_cache;
   1250 	struct filegrp *fgp = cp->c_filegrp;
   1251 	int error;
   1252 
   1253 	ASSERT(CFS_ISFS_BACKFS_NFSV4(C_TO_FSCACHE(cp)) == 0);
   1254 	ASSERT(MUTEX_HELD(&cp->c_statelock));
   1255 	ASSERT((cp->c_flags & CN_ASYNC_POP_WORKING) == 0 ||
   1256 	    cp->c_popthrp == curthread);
   1257 #if 0
   1258 	CFS_DEBUG(CFSDEBUG_SUBR)
   1259 		printf("c_inval_object: ENTER cp %p\n", (void *)cp);
   1260 	if (cp->c_flags & (CN_ASYNC_POPULATE | CN_ASYNC_POP_WORKING))
   1261 		debug_enter("inval object during async pop");
   1262 #endif
   1263 	cp->c_flags |= CN_NOCACHE;
   1264 
   1265 	/* if we cannot modify the cache */
   1266 	if (C_TO_FSCACHE(cp)->fs_cache->c_flags &
   1267 	    (CACHE_NOFILL | CACHE_NOCACHE)) {
   1268 		goto out;
   1269 	}
   1270 
   1271 	/* if there is a front file */
   1272 	if (cp->c_metadata.md_flags & MD_FILE) {
   1273 		if (fgp->fg_dirvp == NULL)
   1274 			goto out;
   1275 
   1276 		/* get the front file vp if necessary */
   1277 		if (cp->c_frontvp == NULL) {
   1278 
   1279 			error = VFS_VGET(fgp->fg_dirvp->v_vfsp, &cp->c_frontvp,
   1280 			    &cp->c_metadata.md_fid);
   1281 			if (error || (cp->c_frontvp == NULL)) {
   1282 #ifdef CFSDEBUG
   1283 				CFS_DEBUG(CFSDEBUG_FRONT)
   1284 					printf("cachefs: "
   1285 					    "io: front file error %d\n", error);
   1286 #endif /* CFSDEBUG */
   1287 				goto out;
   1288 			}
   1289 		}
   1290 
   1291 		/* truncate the file to zero size */
   1292 		error = cachefs_frontfile_size(cp, 0);
   1293 		if (error)
   1294 			goto out;
   1295 		cp->c_flags &= ~CN_NOCACHE;
   1296 
   1297 		/* if a directory, v_type is zero if called from initcnode */
   1298 		if (cp->c_attr.va_type == VDIR) {
   1299 			if (cp->c_usage < CFS_DIRCACHE_COST) {
   1300 				cp->c_invals++;
   1301 				if (cp->c_invals > CFS_DIRCACHE_INVAL) {
   1302 					cp->c_invals = 0;
   1303 				}
   1304 			} else
   1305 				cp->c_invals = 0;
   1306 			cp->c_usage = 0;
   1307 		}
   1308 	} else {
   1309 		cp->c_flags &= ~CN_NOCACHE;
   1310 	}
   1311 
   1312 out:
   1313 	if ((cp->c_metadata.md_flags & MD_PACKED) &&
   1314 	    (cp->c_metadata.md_rltype != CACHEFS_RL_MODIFIED) &&
   1315 	    ((cachep->c_flags & CACHE_NOFILL) == 0)) {
   1316 		ASSERT(cp->c_metadata.md_rlno != 0);
   1317 		if (cp->c_metadata.md_rltype != CACHEFS_RL_PACKED_PENDING) {
   1318 			cachefs_rlent_moveto(cachep,
   1319 			    CACHEFS_RL_PACKED_PENDING,
   1320 			    cp->c_metadata.md_rlno,
   1321 			    cp->c_metadata.md_frontblks);
   1322 			cp->c_metadata.md_rltype = CACHEFS_RL_PACKED_PENDING;
   1323 			/* unconditionally set CN_UPDATED below */
   1324 		}
   1325 	}
   1326 
   1327 	cachefs_purgeacl(cp);
   1328 
   1329 	if (cp->c_flags & CN_ASYNC_POP_WORKING)
   1330 		cp->c_flags |= CN_NOCACHE;
   1331 	cp->c_metadata.md_flags &= ~(MD_POPULATED | MD_INVALREADDIR |
   1332 	    MD_FASTSYMLNK);
   1333 	cp->c_flags &= ~CN_NEED_FRONT_SYNC;
   1334 	cp->c_flags |= CN_UPDATED;
   1335 
   1336 	/*
   1337 	 * If the object invalidated is a directory, the dnlc should be purged
   1338 	 * to elide all references to this (directory) vnode.
   1339 	 */
   1340 	if (CTOV(cp)->v_type == VDIR)
   1341 		dnlc_purge_vp(CTOV(cp));
   1342 
   1343 #ifdef CFSDEBUG
   1344 	CFS_DEBUG(CFSDEBUG_SUBR)
   1345 		printf("c_inval_object: EXIT\n");
   1346 #endif
   1347 }
   1348 
   1349 void
   1350 make_ascii_name(cfs_cid_t *cidp, char *strp)
   1351 {
   1352 	int i = sizeof (uint_t) * 4;
   1353 	u_longlong_t index;
   1354 	ino64_t name;
   1355 
   1356 	if (cidp->cid_flags & CFS_CID_LOCAL)
   1357 		*strp++ = 'L';
   1358 	name = (ino64_t)cidp->cid_fileno;
   1359 	do {
   1360 		index = (((u_longlong_t)name) & 0xf000000000000000) >> 60;
   1361 		index &= (u_longlong_t)0xf;
   1362 		ASSERT(index < (u_longlong_t)16);
   1363 		*strp++ = "0123456789abcdef"[index];
   1364 		name <<= 4;
   1365 	} while (--i);
   1366 	*strp = '\0';
   1367 }
   1368 
   1369 void
   1370 cachefs_nocache(cnode_t *cp)
   1371 {
   1372 	fscache_t *fscp = C_TO_FSCACHE(cp);
   1373 	cachefscache_t *cachep = fscp->fs_cache;
   1374 
   1375 #ifdef CFSDEBUG
   1376 	CFS_DEBUG(CFSDEBUG_SUBR)
   1377 		printf("c_nocache: ENTER cp %p\n", (void *)cp);
   1378 #endif
   1379 
   1380 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
   1381 	ASSERT(MUTEX_HELD(&cp->c_statelock));
   1382 	if ((cp->c_flags & CN_NOCACHE) == 0) {
   1383 #ifdef CFSDEBUG
   1384 		CFS_DEBUG(CFSDEBUG_INVALIDATE)
   1385 			printf("cachefs_nocache: invalidating %llu\n",
   1386 			    (u_longlong_t)cp->c_id.cid_fileno);
   1387 #endif
   1388 		/*
   1389 		 * Here we are waiting until inactive time to do
   1390 		 * the inval_object.  In case we don't get to inactive
   1391 		 * (because of a crash, say) we set up a timestamp mismatch
   1392 		 * such that getfrontfile will blow the front file away
   1393 		 * next time we try to use it.
   1394 		 */
   1395 		cp->c_metadata.md_timestamp.tv_sec = 0;
   1396 		cp->c_metadata.md_timestamp.tv_nsec = 0;
   1397 		cp->c_metadata.md_flags &= ~(MD_POPULATED | MD_INVALREADDIR |
   1398 		    MD_FASTSYMLNK);
   1399 		cp->c_flags &= ~CN_NEED_FRONT_SYNC;
   1400 
   1401 		cachefs_purgeacl(cp);
   1402 
   1403 		/*
   1404 		 * It is possible we can nocache while disconnected.
   1405 		 * A directory could be nocached by running out of space.
   1406 		 * A regular file should only be nocached if an I/O error
   1407 		 * occurs to the front fs.
   1408 		 * We count on the item staying on the modified list
   1409 		 * so we do not loose the cid to fid mapping for directories.
   1410 		 */
   1411 
   1412 		if ((cp->c_metadata.md_flags & MD_PACKED) &&
   1413 		    (cp->c_metadata.md_rltype != CACHEFS_RL_MODIFIED) &&
   1414 		    ((cachep->c_flags & CACHE_NOFILL) == 0)) {
   1415 			ASSERT(cp->c_metadata.md_rlno != 0);
   1416 			if (cp->c_metadata.md_rltype !=
   1417 			    CACHEFS_RL_PACKED_PENDING) {
   1418 				cachefs_rlent_moveto(cachep,
   1419 				    CACHEFS_RL_PACKED_PENDING,
   1420 				    cp->c_metadata.md_rlno,
   1421 				    cp->c_metadata.md_frontblks);
   1422 				cp->c_metadata.md_rltype =
   1423 				    CACHEFS_RL_PACKED_PENDING;
   1424 				/* unconditionally set CN_UPDATED below */
   1425 			}
   1426 		}
   1427 
   1428 		if (CTOV(cp)->v_type == VDIR)
   1429 			dnlc_purge_vp(CTOV(cp));
   1430 		cp->c_flags |= (CN_NOCACHE | CN_UPDATED);
   1431 	}
   1432 
   1433 	if (CACHEFS_LOG_LOGGING(cachep, CACHEFS_LOG_NOCACHE))
   1434 		cachefs_log_nocache(cachep, 0, fscp->fs_cfsvfsp,
   1435 		    &cp->c_metadata.md_cookie, cp->c_id.cid_fileno);
   1436 
   1437 #ifdef CFSDEBUG
   1438 	CFS_DEBUG(CFSDEBUG_SUBR)
   1439 		printf("c_nocache: EXIT cp %p\n", (void *)cp);
   1440 #endif
   1441 }
   1442 
   1443 /*
   1444  * Checks to see if the page is in the disk cache, by checking the allocmap.
   1445  */
   1446 int
   1447 cachefs_check_allocmap(cnode_t *cp, u_offset_t off)
   1448 {
   1449 	int i;
   1450 	size_t dbl_size_to_look = cp->c_attr.va_size - off;
   1451 	uint_t	size_to_look;
   1452 
   1453 	if (dbl_size_to_look > (u_offset_t)PAGESIZE)
   1454 		size_to_look = (uint_t)PAGESIZE;
   1455 	else
   1456 		/*LINTED alignment okay*/
   1457 		size_to_look = (uint_t)dbl_size_to_look;
   1458 
   1459 	for (i = 0; i < cp->c_metadata.md_allocents; i++) {
   1460 		struct cachefs_allocmap *allocp =
   1461 		    cp->c_metadata.md_allocinfo + i;
   1462 
   1463 		if (off >= allocp->am_start_off) {
   1464 			if ((off + size_to_look) <=
   1465 			    (allocp->am_start_off + allocp->am_size)) {
   1466 				struct fscache *fscp = C_TO_FSCACHE(cp);
   1467 				cachefscache_t *cachep = fscp->fs_cache;
   1468 
   1469 				if (CACHEFS_LOG_LOGGING(cachep,
   1470 				    CACHEFS_LOG_CALLOC))
   1471 					cachefs_log_calloc(cachep, 0,
   1472 					    fscp->fs_cfsvfsp,
   1473 					    &cp->c_metadata.md_cookie,
   1474 					    cp->c_id.cid_fileno,
   1475 					    off, size_to_look);
   1476 			/*
   1477 			 * Found the page in the CFS disk cache.
   1478 			 */
   1479 				return (1);
   1480 			}
   1481 		} else {
   1482 			return (0);
   1483 		}
   1484 	}
   1485 	return (0);
   1486 }
   1487 
   1488 /*
   1489  * Merges adjacent allocmap entries together where possible, e.g.
   1490  *   offset=0x0,     size=0x40000
   1491  *   offset=0x40000, size=0x20000	becomes just offset=0x0, size-0x90000
   1492  *   offset=0x60000, size=0x30000
   1493  */
   1494 
   1495 
   1496 void
   1497 cachefs_coalesce_allocmap(struct cachefs_metadata *cmd)
   1498 {
   1499 	int i, reduced = 0;
   1500 	struct cachefs_allocmap *allocp, *nallocp;
   1501 
   1502 	nallocp = allocp = cmd->md_allocinfo;
   1503 	allocp++;
   1504 	for (i = 1; i < cmd->md_allocents; i++, allocp++) {
   1505 		if (nallocp->am_start_off + nallocp->am_size ==
   1506 		    allocp->am_start_off) {
   1507 			nallocp->am_size += allocp->am_size;
   1508 			reduced++;
   1509 		} else {
   1510 			nallocp++;
   1511 			nallocp->am_start_off = allocp->am_start_off;
   1512 			nallocp->am_size = allocp->am_size;
   1513 		}
   1514 	}
   1515 	cmd->md_allocents -= reduced;
   1516 }
   1517 
   1518 /*
   1519  * Updates the allocmap to reflect a new chunk of data that has been
   1520  * populated.
   1521  */
   1522 void
   1523 cachefs_update_allocmap(cnode_t *cp, u_offset_t off, size_t size)
   1524 {
   1525 	int i;
   1526 	struct cachefs_allocmap *allocp;
   1527 	struct fscache *fscp =  C_TO_FSCACHE(cp);
   1528 	cachefscache_t *cachep = fscp->fs_cache;
   1529 	u_offset_t saveoff;
   1530 	u_offset_t savesize;
   1531 	u_offset_t logoff = off;
   1532 	size_t logsize = size;
   1533 	u_offset_t endoff;
   1534 	u_offset_t tmpendoff;
   1535 
   1536 	/*
   1537 	 * We try to see if we can coalesce the current block into an existing
   1538 	 * allocation and mark it as such.
   1539 	 * If we can't do that then we make a new entry in the allocmap.
   1540 	 * when we run out of allocmaps, put the cnode in NOCACHE mode.
   1541 	 */
   1542 again:
   1543 	allocp = cp->c_metadata.md_allocinfo;
   1544 	for (i = 0; i < cp->c_metadata.md_allocents; i++, allocp++) {
   1545 
   1546 		if (off <= (allocp->am_start_off)) {
   1547 			endoff = off + size;
   1548 			if (endoff >= allocp->am_start_off) {
   1549 				tmpendoff = allocp->am_start_off +
   1550 				    allocp->am_size;
   1551 				if (endoff < tmpendoff)
   1552 					endoff = tmpendoff;
   1553 				allocp->am_size = endoff - off;
   1554 				allocp->am_start_off = off;
   1555 				cachefs_coalesce_allocmap(&cp->c_metadata);
   1556 				allocp = cp->c_metadata.md_allocinfo;
   1557 				if (allocp->am_size >= cp->c_size)
   1558 					cp->c_metadata.md_flags |= MD_POPULATED;
   1559 				return;
   1560 			} else {
   1561 				saveoff = off;
   1562 				savesize = size;
   1563 				off = allocp->am_start_off;
   1564 				size = allocp->am_size;
   1565 				allocp->am_size = savesize;
   1566 				allocp->am_start_off = saveoff;
   1567 				goto again;
   1568 			}
   1569 		} else {
   1570 			endoff = allocp->am_start_off + allocp->am_size;
   1571 			if (off < endoff) {
   1572 				tmpendoff = off + size;
   1573 				if (endoff < tmpendoff)
   1574 					endoff = tmpendoff;
   1575 				allocp->am_size = endoff - allocp->am_start_off;
   1576 				cachefs_coalesce_allocmap(&cp->c_metadata);
   1577 				allocp = cp->c_metadata.md_allocinfo;
   1578 				if (allocp->am_size >= cp->c_size)
   1579 					cp->c_metadata.md_flags |= MD_POPULATED;
   1580 				return;
   1581 			}
   1582 			if (off == (allocp->am_start_off + allocp->am_size)) {
   1583 				allocp->am_size += size;
   1584 				cachefs_coalesce_allocmap(&cp->c_metadata);
   1585 				allocp = cp->c_metadata.md_allocinfo;
   1586 				if (allocp->am_size >= cp->c_size)
   1587 					cp->c_metadata.md_flags |= MD_POPULATED;
   1588 				return;
   1589 			}
   1590 		}
   1591 	}
   1592 	if (i == C_MAX_ALLOCINFO_SLOTS) {
   1593 #ifdef CFSDEBUG
   1594 		CFS_DEBUG(CFSDEBUG_ALLOCMAP)
   1595 			printf("c_update_alloc_map: "
   1596 			    "Too many allinfo entries cp %p fileno %llu %p\n",
   1597 			    (void *)cp, (u_longlong_t)cp->c_id.cid_fileno,
   1598 			    (void *)cp->c_metadata.md_allocinfo);
   1599 #endif
   1600 		cachefs_nocache(cp);
   1601 		return;
   1602 	}
   1603 	allocp->am_start_off = off;
   1604 	allocp->am_size = (u_offset_t)size;
   1605 	if (allocp->am_size >= cp->c_size)
   1606 		cp->c_metadata.md_flags |= MD_POPULATED;
   1607 	cp->c_metadata.md_allocents++;
   1608 
   1609 	if (CACHEFS_LOG_LOGGING(cachep, CACHEFS_LOG_UALLOC))
   1610 		cachefs_log_ualloc(cachep, 0, fscp->fs_cfsvfsp,
   1611 		    &cp->c_metadata.md_cookie, cp->c_id.cid_fileno,
   1612 		    logoff, logsize);
   1613 }
   1614 
   1615 /*
   1616  * CFS population function
   1617  *
   1618  * before async population, this function used to turn on the cnode
   1619  * flags CN_UPDATED, CN_NEED_FRONT_SYNC, and CN_POPULATION_PENDING.
   1620  * now, however, it's the responsibility of the caller to do this if
   1621  * this function returns 0 (no error).
   1622  */
   1623 
   1624 int
   1625 cachefs_populate(cnode_t *cp, u_offset_t off, size_t popsize, vnode_t *frontvp,
   1626     vnode_t *backvp, u_offset_t cpsize, cred_t *cr)
   1627 {
   1628 	int error = 0;
   1629 	caddr_t addr;
   1630 	u_offset_t upto;
   1631 	uint_t size;
   1632 	u_offset_t from = off;
   1633 	cachefscache_t *cachep = C_TO_FSCACHE(cp)->fs_cache;
   1634 	ssize_t resid;
   1635 	struct fbuf *fbp;
   1636 	caddr_t buf = kmem_alloc(MAXBSIZE, KM_SLEEP);
   1637 
   1638 #ifdef CFSDEBUG
   1639 	CFS_DEBUG(CFSDEBUG_VOPS)
   1640 		printf("cachefs_populate: ENTER cp %p off %lld\n",
   1641 		    (void *)cp, off);
   1642 #endif
   1643 
   1644 	upto = MIN((off + popsize), cpsize);
   1645 
   1646 	while (from < upto) {
   1647 		u_offset_t blkoff = (from & (offset_t)MAXBMASK);
   1648 		uint_t n = from - blkoff;
   1649 
   1650 		size = upto - from;
   1651 		if (upto > (blkoff + MAXBSIZE))
   1652 			size = MAXBSIZE - n;
   1653 
   1654 		error = fbread(backvp, (offset_t)blkoff, n + size,
   1655 		    S_OTHER, &fbp);
   1656 		if (CFS_TIMEOUT(C_TO_FSCACHE(cp), error))
   1657 			goto out;
   1658 		else if (error) {
   1659 #ifdef CFSDEBUG
   1660 			CFS_DEBUG(CFSDEBUG_BACK)
   1661 				printf("cachefs_populate: fbread error %d\n",
   1662 				    error);
   1663 #endif
   1664 			goto out;
   1665 		}
   1666 
   1667 		addr = fbp->fb_addr;
   1668 		ASSERT(addr != NULL);
   1669 		ASSERT(n + size <= MAXBSIZE);
   1670 		bcopy(addr, buf, n + size);
   1671 		fbrelse(fbp, S_OTHER);
   1672 
   1673 		if (n == 0 || cachefs_check_allocmap(cp, blkoff) == 0) {
   1674 			if (error = cachefs_allocblocks(cachep, 1,
   1675 			    cp->c_metadata.md_rltype))
   1676 				goto out;
   1677 			cp->c_metadata.md_frontblks++;
   1678 		}
   1679 		resid = 0;
   1680 		error = vn_rdwr(UIO_WRITE, frontvp, buf + n, size,
   1681 		    (offset_t)from, UIO_SYSSPACE, 0,
   1682 		    (rlim64_t)RLIM64_INFINITY, cr, &resid);
   1683 		if (error) {
   1684 #ifdef CFSDEBUG
   1685 			CFS_DEBUG(CFSDEBUG_FRONT)
   1686 				printf("cachefs_populate: "
   1687 				    "Got error = %d from vn_rdwr\n", error);
   1688 #endif
   1689 			goto out;
   1690 		}
   1691 #ifdef CFSDEBUG
   1692 		if (resid)
   1693 			CFS_DEBUG(CFSDEBUG_FRONT)
   1694 				printf("cachefs_populate: non-zero resid %ld\n",
   1695 				    resid);
   1696 #endif
   1697 		from += size;
   1698 	}
   1699 	(void) cachefs_update_allocmap(cp, off, upto - off);
   1700 out:
   1701 	if (CACHEFS_LOG_LOGGING(cachep, CACHEFS_LOG_POPULATE))
   1702 		cachefs_log_populate(cachep, error,
   1703 		    C_TO_FSCACHE(cp)->fs_cfsvfsp,
   1704 		    &cp->c_metadata.md_cookie, cp->c_id.cid_fileno, off,
   1705 		    popsize);
   1706 
   1707 #ifdef CFSDEBUG
   1708 	CFS_DEBUG(CFSDEBUG_VOPS)
   1709 		printf("cachefs_populate: EXIT cp %p error %d\n",
   1710 		    (void *)cp, error);
   1711 #endif
   1712 	kmem_free(buf, MAXBSIZE);
   1713 
   1714 	return (error);
   1715 }
   1716 
   1717 /*
   1718  * due to compiler error we shifted cnode to the last argument slot.
   1719  * occurred during large files project - XXX.
   1720  */
   1721 void
   1722 cachefs_cluster_allocmap(u_offset_t off, u_offset_t *popoffp, size_t *popsizep,
   1723     size_t size, struct cnode *cp)
   1724 {
   1725 	int i;
   1726 	u_offset_t lastoff = 0;
   1727 	u_offset_t forward_diff = 0;
   1728 	u_offset_t backward_diff = 0;
   1729 
   1730 	ASSERT(size <= C_TO_FSCACHE(cp)->fs_info.fi_popsize);
   1731 
   1732 #ifdef CFSDEBUG
   1733 	CFS_DEBUG(CFSDEBUG_SUBR)
   1734 		printf("cachefs_cluster_allocmap: off %llx, size %llx, "
   1735 		    "c_size %llx\n", off, size, (longlong_t)cp->c_size);
   1736 #endif /* CFSDEBUG */
   1737 	for (i = 0; i < cp->c_metadata.md_allocents; i++) {
   1738 		struct cachefs_allocmap *allocp =
   1739 		    cp->c_metadata.md_allocinfo + i;
   1740 
   1741 		if (allocp->am_start_off > off) {
   1742 			if ((off + size) > allocp->am_start_off) {
   1743 				forward_diff = allocp->am_start_off - off;
   1744 				backward_diff = size - forward_diff;
   1745 				if (backward_diff > off)
   1746 					backward_diff = off;
   1747 				if (lastoff > (off - backward_diff))
   1748 					backward_diff = off - lastoff;
   1749 			} else {
   1750 				forward_diff = size;
   1751 			}
   1752 			*popoffp = (off - backward_diff) & (offset_t)PAGEMASK;
   1753 			*popsizep = ((off + forward_diff) - *popoffp) &
   1754 			    (offset_t)PAGEMASK;
   1755 			return;
   1756 		} else {
   1757 			lastoff = allocp->am_start_off + allocp->am_size;
   1758 		}
   1759 	}
   1760 	if ((lastoff + size) > off) {
   1761 		*popoffp = (lastoff & (offset_t)PAGEMASK);
   1762 	} else {
   1763 		*popoffp = off & (offset_t)PAGEMASK;
   1764 	}
   1765 
   1766 	/*
   1767 	 * 64bit project: popsize is the chunk size used to populate the
   1768 	 * cache (default 64K). As such, 32 bit should suffice.
   1769 	 */
   1770 	if ((*popoffp + size) > cp->c_size)
   1771 		*popsizep = (cp->c_size - *popoffp + PAGEOFFSET) &
   1772 		    (offset_t)PAGEMASK;
   1773 	else if (size < PAGESIZE)
   1774 		*popsizep = (size + PAGEOFFSET) & (offset_t)PAGEMASK;
   1775 	else
   1776 		*popsizep = size & (offset_t)PAGEMASK;
   1777 
   1778 #ifdef CFSDEBUG
   1779 	CFS_DEBUG(CFSDEBUG_SUBR)
   1780 		printf("cachefs_cluster_allocmap: popoff %llx, popsize %llx\n",
   1781 		    (u_longlong_t)(*popoffp), (u_longlong_t)(*popsizep));
   1782 #endif /* CFSDEBUG */
   1783 }
   1784 
   1785 /*
   1786  * "populate" a symlink in the cache
   1787  */
   1788 int
   1789 cachefs_stuffsymlink(cnode_t *cp, caddr_t buf, int buflen)
   1790 {
   1791 	int error = 0;
   1792 	struct fscache *fscp = C_TO_FSCACHE(cp);
   1793 	cachefscache_t *cachep = fscp->fs_cache;
   1794 	struct cachefs_metadata *mdp = &cp->c_metadata;
   1795 
   1796 	ASSERT(RW_WRITE_HELD(&cp->c_rwlock));
   1797 	ASSERT(MUTEX_HELD(&cp->c_statelock));
   1798 
   1799 	if (CFS_ISFS_BACKFS_NFSV4(fscp))
   1800 		goto out;
   1801 
   1802 	if (cp->c_flags & CN_NOCACHE)
   1803 		return (ENOENT);
   1804 
   1805 	cp->c_size = (u_offset_t)buflen;
   1806 
   1807 	/* if can create a fast sym link */
   1808 	if (buflen <= C_FSL_SIZE) {
   1809 		/* give up the front file resources */
   1810 		if (mdp->md_rlno) {
   1811 			cachefs_removefrontfile(mdp, &cp->c_id, cp->c_filegrp);
   1812 			cachefs_rlent_moveto(cachep, CACHEFS_RL_FREE,
   1813 			    mdp->md_rlno, 0);
   1814 			mdp->md_rlno = 0;
   1815 			mdp->md_rltype = CACHEFS_RL_NONE;
   1816 		}
   1817 		/* put sym link contents in allocinfo in metadata */
   1818 		bzero(mdp->md_allocinfo, C_FSL_SIZE);
   1819 		bcopy(buf, mdp->md_allocinfo, buflen);
   1820 
   1821 		mdp->md_flags |= MD_FASTSYMLNK;
   1822 		cp->c_flags &= ~CN_NEED_FRONT_SYNC;
   1823 		cp->c_flags |= CN_UPDATED;
   1824 		goto out;
   1825 	}
   1826 
   1827 	/* else create a sym link in a front file */
   1828 	if (cp->c_frontvp == NULL)
   1829 		error = cachefs_getfrontfile(cp);
   1830 	if (error)
   1831 		goto out;
   1832 
   1833 	/* truncate front file */
   1834 	error = cachefs_frontfile_size(cp, 0);
   1835 	mdp->md_flags &= ~(MD_FASTSYMLNK | MD_POPULATED);
   1836 	if (error)
   1837 		goto out;
   1838 
   1839 	/* get space for the sym link */
   1840 	error = cachefs_allocblocks(cachep, 1, cp->c_metadata.md_rltype);
   1841 	if (error)
   1842 		goto out;
   1843 
   1844 	/* write the sym link to the front file */
   1845 	error = vn_rdwr(UIO_WRITE, cp->c_frontvp, buf, buflen, 0,
   1846 	    UIO_SYSSPACE, 0, RLIM_INFINITY, kcred, NULL);
   1847 	if (error) {
   1848 		cachefs_freeblocks(cachep, 1, cp->c_metadata.md_rltype);
   1849 		goto out;
   1850 	}
   1851 
   1852 	cp->c_metadata.md_flags |= MD_POPULATED;
   1853 	cp->c_flags |= CN_NEED_FRONT_SYNC;
   1854 	cp->c_flags |= CN_UPDATED;
   1855 
   1856 out:
   1857 	if (CACHEFS_LOG_LOGGING(cachep, CACHEFS_LOG_CSYMLINK))
   1858 		cachefs_log_csymlink(cachep, error, fscp->fs_cfsvfsp,
   1859 		    &cp->c_metadata.md_cookie, cp->c_id.cid_fileno, buflen);
   1860 
   1861 	return (error);
   1862 }
   1863 
   1864 /*
   1865  * Reads the full contents of the symbolic link from the back file system.
   1866  * *bufp is set to a MAXPATHLEN buffer that must be freed when done
   1867  * *buflenp is the length of the link
   1868  */
   1869 int
   1870 cachefs_readlink_back(cnode_t *cp, cred_t *cr, caddr_t *bufp, int *buflenp)
   1871 {
   1872 	int error;
   1873 	struct uio uio;
   1874 	struct iovec iov;
   1875 	caddr_t buf;
   1876 	fscache_t *fscp = C_TO_FSCACHE(cp);
   1877 
   1878 	ASSERT(MUTEX_HELD(&cp->c_statelock));
   1879 
   1880 	*bufp = NULL;
   1881 
   1882 	/* get back vnode */
   1883 	if (cp->c_backvp == NULL) {
   1884 		error = cachefs_getbackvp(fscp, cp);
   1885 		if (error)
   1886 			return (error);
   1887 	}
   1888 
   1889 	/* set up for the readlink */
   1890 	bzero(&uio, sizeof (struct uio));
   1891 	bzero(&iov, sizeof (struct iovec));
   1892 	buf = cachefs_kmem_alloc(MAXPATHLEN, KM_SLEEP);
   1893 	iov.iov_base = buf;
   1894 	iov.iov_len = MAXPATHLEN;
   1895 	uio.uio_iov = &iov;
   1896 	uio.uio_iovcnt = 1;
   1897 	uio.uio_resid = MAXPATHLEN;
   1898 	uio.uio_segflg = UIO_SYSSPACE;
   1899 	uio.uio_loffset = 0;
   1900 	uio.uio_fmode = 0;
   1901 	uio.uio_extflg = UIO_COPY_CACHED;
   1902 	uio.uio_llimit = MAXOFFSET_T;
   1903 
   1904 	/* get the link data */
   1905 	CFS_DPRINT_BACKFS_NFSV4(fscp,
   1906 	    ("cachefs_readlink (nfsv4): cnode %p, backvp %p\n",
   1907 	    cp, cp->c_backvp));
   1908 	error = VOP_READLINK(cp->c_backvp, &uio, cr, NULL);
   1909 	if (error) {
   1910 		cachefs_kmem_free(buf, MAXPATHLEN);
   1911 	} else {
   1912 		*bufp = buf;
   1913 		/*LINTED alignment okay*/
   1914 		*buflenp = MAXPATHLEN - (int)uio.uio_resid;
   1915 	}
   1916 
   1917 	return (error);
   1918 }
   1919 
   1920 int
   1921 cachefs_getbackvp(struct fscache *fscp, struct cnode *cp)
   1922 {
   1923 	int error = 0;
   1924 	int flag;
   1925 
   1926 #ifdef CFSDEBUG
   1927 	CFS_DEBUG(CFSDEBUG_CHEAT | CFSDEBUG_BACK)
   1928 		printf("cachefs_getbackvp: ENTER fscp %p cp %p\n",
   1929 		    (void *)fscp, (void *)cp);
   1930 #endif
   1931 	ASSERT(cp != NULL);
   1932 	ASSERT(MUTEX_HELD(&cp->c_statelock));
   1933 	ASSERT(cp->c_backvp == NULL);
   1934 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
   1935 
   1936 	/*
   1937 	 * If destroy is set then the last link to a file has been
   1938 	 * removed.  Oddly enough NFS will still return a vnode
   1939 	 * for the file if the timeout has not expired.
   1940 	 * This causes headaches for cachefs_push because the
   1941 	 * vnode is really stale.
   1942 	 * So we just short circuit the problem here.
   1943 	 */
   1944 	if (cp->c_flags & CN_DESTROY)
   1945 		return (ESTALE);
   1946 
   1947 	ASSERT(fscp->fs_backvfsp);
   1948 	if (fscp->fs_backvfsp == NULL)
   1949 		return (ETIMEDOUT);
   1950 	error = VFS_VGET(fscp->fs_backvfsp, &cp->c_backvp,
   1951 	    (struct fid *)&cp->c_cookie);
   1952 	if (cp->c_backvp && cp->c_cred &&
   1953 	    ((cp->c_flags & CN_NEEDOPEN) || (cp->c_attr.va_type == VREG))) {
   1954 		/*
   1955 		 * XXX bob: really should pass in the correct flag,
   1956 		 * fortunately nobody pays attention to it
   1957 		 */
   1958 		flag = 0;
   1959 		/*
   1960 		 * If NEEDOOPEN is set, then this file was opened VOP_OPEN'd
   1961 		 * but the backvp was not.  So, for the sake of the vnode
   1962 		 * open counts used by delegation, we need to OPEN the backvp
   1963 		 * with the same flags that were used for this cnode.  That way
   1964 		 * when the file is VOP_CLOSE'd the counts won't go negative.
   1965 		 */
   1966 		if (cp->c_flags & CN_NEEDOPEN) {
   1967 			cp->c_flags &= ~CN_NEEDOPEN;
   1968 			if (cp->c_rdcnt > 0) {
   1969 				cp->c_rdcnt--;
   1970 				flag |= FREAD;
   1971 			}
   1972 			if (cp->c_wrcnt > 0) {
   1973 				cp->c_wrcnt--;
   1974 				flag |= FWRITE;
   1975 			}
   1976 		}
   1977 		error = VOP_OPEN(&cp->c_backvp, flag, cp->c_cred, NULL);
   1978 		if (error) {
   1979 			VN_RELE(cp->c_backvp);
   1980 			cp->c_backvp = NULL;
   1981 		}
   1982 	}
   1983 
   1984 #ifdef CFSDEBUG
   1985 	CFS_DEBUG(CFSDEBUG_GENERAL | CFSDEBUG_BACK) {
   1986 		if (error || cp->c_backvp == NULL) {
   1987 			printf("Stale cookie cp %p fileno %llu type %d \n",
   1988 			    (void *)cp, (u_longlong_t)cp->c_id.cid_fileno,
   1989 			    CTOV(cp)->v_type);
   1990 		}
   1991 	}
   1992 #endif
   1993 
   1994 #ifdef CFSDEBUG
   1995 	CFS_DEBUG(CFSDEBUG_CHEAT | CFSDEBUG_BACK)
   1996 		printf("cachefs_getbackvp: EXIT error = %d\n", error);
   1997 #endif
   1998 	return (error);
   1999 }
   2000 
   2001 int
   2002 cachefs_getcookie(
   2003 	vnode_t *vp,
   2004 	struct fid *cookiep,
   2005 	struct vattr *attrp,
   2006 	cred_t *cr,
   2007 	uint32_t valid_fid)
   2008 {
   2009 	int error = 0;
   2010 
   2011 #ifdef CFSDEBUG
   2012 	CFS_DEBUG(CFSDEBUG_CHEAT)
   2013 		printf("cachefs_getcookie: ENTER vp %p\n", (void *)vp);
   2014 #endif
   2015 	/*
   2016 	 * Get the FID only if the caller has indicated it is valid,
   2017 	 * otherwise, zero the cookie.
   2018 	 */
   2019 	if (valid_fid) {
   2020 		/*
   2021 		 * This assumes that the cookie is a full size fid, if we go to
   2022 		 * variable length fids we will need to change this.
   2023 		 */
   2024 		cookiep->fid_len = MAXFIDSZ;
   2025 		error = VOP_FID(vp, cookiep, NULL);
   2026 	} else {
   2027 		bzero(cookiep, sizeof (*cookiep));
   2028 	}
   2029 
   2030 	if (!error) {
   2031 		if (attrp) {
   2032 			ASSERT(attrp != NULL);
   2033 			attrp->va_mask = AT_ALL;
   2034 			error = VOP_GETATTR(vp, attrp, 0, cr, NULL);
   2035 		}
   2036 	} else {
   2037 		if (error == ENOSPC) {
   2038 			/*
   2039 			 * This is an indication that the underlying filesystem
   2040 			 * needs a bigger fid.  For now just map to EINVAL.
   2041 			 */
   2042 			error = EINVAL;
   2043 		}
   2044 	}
   2045 #ifdef CFSDEBUG
   2046 	CFS_DEBUG(CFSDEBUG_CHEAT)
   2047 		printf("cachefs_getcookie: EXIT error = %d\n", error);
   2048 #endif
   2049 	return (error);
   2050 }
   2051 
   2052 void
   2053 cachefs_workq_init(struct cachefs_workq *qp)
   2054 {
   2055 	qp->wq_head = qp->wq_tail = NULL;
   2056 	qp->wq_length =
   2057 	    qp->wq_thread_count =
   2058 	    qp->wq_max_len =
   2059 	    qp->wq_halt_request = 0;
   2060 	qp->wq_keepone = 0;
   2061 	cv_init(&qp->wq_req_cv, NULL, CV_DEFAULT, NULL);
   2062 	cv_init(&qp->wq_halt_cv, NULL, CV_DEFAULT, NULL);
   2063 	mutex_init(&qp->wq_queue_lock, NULL, MUTEX_DEFAULT, NULL);
   2064 }
   2065 
   2066 /*
   2067  * return non-zero if it's `okay' to queue more requests (policy)
   2068  */
   2069 
   2070 static int cachefs_async_max = 512;
   2071 static int cachefs_async_count = 0;
   2072 kmutex_t cachefs_async_lock;
   2073 
   2074 int
   2075 cachefs_async_okay(void)
   2076 {
   2077 	/*
   2078 	 * a value of -1 for max means to ignore freemem
   2079 	 */
   2080 
   2081 	if (cachefs_async_max == -1)
   2082 		return (1);
   2083 
   2084 	if (freemem < minfree)
   2085 		return (0);
   2086 
   2087 	/*
   2088 	 * a value of 0 for max means no arbitrary limit (only `freemen')
   2089 	 */
   2090 
   2091 	if (cachefs_async_max == 0)
   2092 		return (1);
   2093 
   2094 	ASSERT(cachefs_async_max > 0);
   2095 
   2096 	/*
   2097 	 * check the global count against the max.
   2098 	 *
   2099 	 * we don't need to grab cachefs_async_lock -- we're just
   2100 	 * looking, and a little bit of `fuzz' is okay.
   2101 	 */
   2102 
   2103 	if (cachefs_async_count >= cachefs_async_max)
   2104 		return (0);
   2105 
   2106 	return (1);
   2107 }
   2108 
   2109 void
   2110 cachefs_async_start(struct cachefs_workq *qp)
   2111 {
   2112 	struct cachefs_req *rp;
   2113 	int left;
   2114 	callb_cpr_t cprinfo;
   2115 
   2116 	CALLB_CPR_INIT(&cprinfo, &qp->wq_queue_lock, callb_generic_cpr, "cas");
   2117 	mutex_enter(&qp->wq_queue_lock);
   2118 	left = 1;
   2119 	for (;;) {
   2120 		/* if there are no pending requests */
   2121 		if ((qp->wq_head == NULL) && (qp->wq_logwork == 0)) {
   2122 			/* see if thread should exit */
   2123 			if (qp->wq_halt_request || (left == -1)) {
   2124 				if ((qp->wq_thread_count > 1) ||
   2125 				    (qp->wq_keepone == 0))
   2126 					break;
   2127 			}
   2128 
   2129 			/* wake up thread in async_halt if necessary */
   2130 			if (qp->wq_halt_request)
   2131 				cv_broadcast(&qp->wq_halt_cv);
   2132 
   2133 			CALLB_CPR_SAFE_BEGIN(&cprinfo);
   2134 			/* sleep until there is something to do */
   2135 			left = cv_reltimedwait(&qp->wq_req_cv,
   2136 			    &qp->wq_queue_lock, CFS_ASYNC_TIMEOUT,
   2137 			    TR_CLOCK_TICK);
   2138 			CALLB_CPR_SAFE_END(&cprinfo, &qp->wq_queue_lock);
   2139 			if ((qp->wq_head == NULL) && (qp->wq_logwork == 0))
   2140 				continue;
   2141 		}
   2142 		left = 1;
   2143 
   2144 		if (qp->wq_logwork) {
   2145 			qp->wq_logwork = 0;
   2146 			mutex_exit(&qp->wq_queue_lock);
   2147 			cachefs_log_process_queue(qp->wq_cachep, 1);
   2148 			mutex_enter(&qp->wq_queue_lock);
   2149 			continue;
   2150 		}
   2151 
   2152 		/* remove request from the list */
   2153 		rp = qp->wq_head;
   2154 		qp->wq_head = rp->cfs_next;
   2155 		if (rp->cfs_next == NULL)
   2156 			qp->wq_tail = NULL;
   2157 
   2158 		/* do the request */
   2159 		mutex_exit(&qp->wq_queue_lock);
   2160 		cachefs_do_req(rp);
   2161 		mutex_enter(&qp->wq_queue_lock);
   2162 
   2163 		/* decrement count of requests */
   2164 		qp->wq_length--;
   2165 		mutex_enter(&cachefs_async_lock);
   2166 		--cachefs_async_count;
   2167 		mutex_exit(&cachefs_async_lock);
   2168 	}
   2169 	ASSERT(qp->wq_head == NULL);
   2170 	qp->wq_thread_count--;
   2171 	if (qp->wq_halt_request && qp->wq_thread_count == 0)
   2172 		cv_broadcast(&qp->wq_halt_cv);
   2173 	CALLB_CPR_EXIT(&cprinfo);
   2174 	thread_exit();
   2175 	/*NOTREACHED*/
   2176 }
   2177 
   2178 /*
   2179  * attempt to halt all the async threads associated with a given workq
   2180  */
   2181 int
   2182 cachefs_async_halt(struct cachefs_workq *qp, int force)
   2183 {
   2184 	int error = 0;
   2185 
   2186 	mutex_enter(&qp->wq_queue_lock);
   2187 	if (force)
   2188 		qp->wq_keepone = 0;
   2189 
   2190 	if (qp->wq_thread_count > 0) {
   2191 		qp->wq_halt_request++;
   2192 		cv_broadcast(&qp->wq_req_cv);
   2193 		(void) cv_reltimedwait(&qp->wq_halt_cv,
   2194 		    &qp->wq_queue_lock, (60 * hz), TR_CLOCK_TICK);
   2195 		qp->wq_halt_request--;
   2196 		if (qp->wq_thread_count > 0) {
   2197 			if ((qp->wq_thread_count == 1) &&
   2198 			    (qp->wq_length == 0) && qp->wq_keepone)
   2199 				error = EAGAIN;
   2200 			else
   2201 				error = EBUSY;
   2202 		} else {
   2203 			ASSERT(qp->wq_length == 0 && qp->wq_head == NULL);
   2204 		}
   2205 	}
   2206 	mutex_exit(&qp->wq_queue_lock);
   2207 	return (error);
   2208 }
   2209 
   2210 void
   2211 cachefs_addqueue(struct cachefs_req *rp, struct cachefs_workq *qp)
   2212 {
   2213 	mutex_enter(&qp->wq_queue_lock);
   2214 	if (qp->wq_thread_count < cachefs_max_threads) {
   2215 		if (qp->wq_thread_count == 0 ||
   2216 		    (qp->wq_length >= (qp->wq_thread_count * 2))) {
   2217 			(void) thread_create(NULL, 0, cachefs_async_start,
   2218 			    qp, 0, &p0, TS_RUN, minclsyspri);
   2219 			qp->wq_thread_count++;
   2220 		}
   2221 	}
   2222 	mutex_enter(&rp->cfs_req_lock);
   2223 	if (qp->wq_tail)
   2224 		qp->wq_tail->cfs_next = rp;
   2225 	else
   2226 		qp->wq_head = rp;
   2227 	qp->wq_tail = rp;
   2228 	rp->cfs_next = NULL;
   2229 	qp->wq_length++;
   2230 	if (qp->wq_length > qp->wq_max_len)
   2231 		qp->wq_max_len = qp->wq_length;
   2232 	mutex_enter(&cachefs_async_lock);
   2233 	++cachefs_async_count;
   2234 	mutex_exit(&cachefs_async_lock);
   2235 
   2236 	cv_signal(&qp->wq_req_cv);
   2237 	mutex_exit(&rp->cfs_req_lock);
   2238 	mutex_exit(&qp->wq_queue_lock);
   2239 }
   2240 
   2241 void
   2242 cachefs_async_putpage(struct cachefs_putpage_req *prp, cred_t *cr)
   2243 {
   2244 	struct cnode *cp = VTOC(prp->cp_vp);
   2245 
   2246 	ASSERT(CFS_ISFS_BACKFS_NFSV4(C_TO_FSCACHE(cp)) == 0);
   2247 
   2248 	(void) VOP_PUTPAGE(prp->cp_vp, prp->cp_off, prp->cp_len,
   2249 	    prp->cp_flags, cr, NULL);
   2250 
   2251 	mutex_enter(&cp->c_iomutex);
   2252 	if (--cp->c_nio == 0)
   2253 		cv_broadcast(&cp->c_iocv);
   2254 	if (prp->cp_off == 0 && prp->cp_len == 0 &&
   2255 	    (cp->c_ioflags & CIO_PUTPAGES)) {
   2256 		cp->c_ioflags &= ~CIO_PUTPAGES;
   2257 	}
   2258 	mutex_exit(&cp->c_iomutex);
   2259 }
   2260 
   2261 void
   2262 cachefs_async_populate(struct cachefs_populate_req *pop, cred_t *cr)
   2263 {
   2264 	struct cnode *cp = VTOC(pop->cpop_vp);
   2265 	struct fscache *fscp = C_TO_FSCACHE(cp);
   2266 	struct filegrp *fgp = cp->c_filegrp;
   2267 	int error = 0; /* not returned -- used as a place-holder */
   2268 	vnode_t *frontvp = NULL, *backvp = NULL;
   2269 	int havelock = 0;
   2270 	vattr_t va;
   2271 
   2272 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
   2273 
   2274 	if (((cp->c_filegrp->fg_flags & CFS_FG_WRITE) == 0) ||
   2275 	    (fscp->fs_cdconnected != CFS_CD_CONNECTED)) {
   2276 		mutex_enter(&cp->c_statelock);
   2277 		cp->c_flags &= ~CN_ASYNC_POPULATE;
   2278 		mutex_exit(&cp->c_statelock);
   2279 		return; /* goto out */
   2280 	}
   2281 
   2282 	error = cachefs_cd_access(fscp, 0, 0);
   2283 	if (error) {
   2284 #ifdef CFSDEBUG
   2285 		CFS_DEBUG(CFSDEBUG_ASYNCPOP)
   2286 			printf("async_pop: cd_access: err %d con %d\n",
   2287 			    error, fscp->fs_cdconnected);
   2288 #endif /* CFSDEBUG */
   2289 		mutex_enter(&cp->c_statelock);
   2290 		cp->c_flags &= ~CN_ASYNC_POPULATE;
   2291 		mutex_exit(&cp->c_statelock);
   2292 		return; /* goto out */
   2293 	}
   2294 
   2295 	/*
   2296 	 * grab the statelock for some minimal things
   2297 	 */
   2298 
   2299 	rw_enter(&cp->c_rwlock, RW_WRITER);
   2300 	mutex_enter(&cp->c_statelock);
   2301 	havelock = 1;
   2302 
   2303 	if ((cp->c_flags & CN_ASYNC_POPULATE) == 0)
   2304 		goto out;
   2305 
   2306 	/* there can be only one */
   2307 	ASSERT((cp->c_flags & CN_ASYNC_POP_WORKING) == 0);
   2308 	cp->c_flags |= CN_ASYNC_POP_WORKING;
   2309 	cp->c_popthrp = curthread;
   2310 
   2311 	if (cp->c_metadata.md_flags & MD_POPULATED)
   2312 		goto out;
   2313 
   2314 	if (cp->c_flags & CN_NOCACHE) {
   2315 #ifdef CFSDEBUG
   2316 		CFS_DEBUG(CFSDEBUG_ASYNCPOP)
   2317 			printf("cachefs_async_populate: nocache bit on\n");
   2318 #endif /* CFSDEBUG */
   2319 		error = EINVAL;
   2320 		goto out;
   2321 	}
   2322 
   2323 	if (cp->c_frontvp == NULL) {
   2324 		if ((cp->c_metadata.md_flags & MD_FILE) == 0) {
   2325 			struct cfs_cid cid = cp->c_id;
   2326 
   2327 			mutex_exit(&cp->c_statelock);
   2328 			havelock = 0;
   2329 
   2330 			/*
   2331 			 * if frontfile doesn't exist, drop the lock
   2332 			 * to do some of the file creation stuff.
   2333 			 */
   2334 
   2335 			if (fgp->fg_flags & CFS_FG_ALLOC_ATTR) {
   2336 				error = filegrp_allocattr(fgp);
   2337 				if (error != 0)
   2338 					goto out;
   2339 			}
   2340 			if (fgp->fg_flags & CFS_FG_ALLOC_FILE) {
   2341 				mutex_enter(&fgp->fg_mutex);
   2342 				if (fgp->fg_flags & CFS_FG_ALLOC_FILE) {
   2343 					if (fgp->fg_header->ach_nffs == 0)
   2344 						error = filegrpdir_create(fgp);
   2345 					else
   2346 						error = filegrpdir_find(fgp);
   2347 					if (error != 0) {
   2348 						mutex_exit(&fgp->fg_mutex);
   2349 						goto out;
   2350 					}
   2351 				}
   2352 				mutex_exit(&fgp->fg_mutex);
   2353 			}
   2354 
   2355 			if (fgp->fg_dirvp != NULL) {
   2356 				char name[CFS_FRONTFILE_NAME_SIZE];
   2357 				struct vattr *attrp;
   2358 
   2359 				attrp = cachefs_kmem_zalloc(
   2360 				    sizeof (struct vattr), KM_SLEEP);
   2361 				attrp->va_mode = S_IFREG | 0666;
   2362 				attrp->va_uid = 0;
   2363 				attrp->va_gid = 0;
   2364 				attrp->va_type = VREG;
   2365 				attrp->va_size = 0;
   2366 				attrp->va_mask =
   2367 				    AT_SIZE | AT_TYPE | AT_MODE |
   2368 				    AT_UID | AT_GID;
   2369 
   2370 				make_ascii_name(&cid, name);
   2371 
   2372 				(void) VOP_CREATE(fgp->fg_dirvp, name, attrp,
   2373 				    EXCL, 0666, &frontvp, kcred, 0, NULL, NULL);
   2374 
   2375 				cachefs_kmem_free(attrp,
   2376 				    sizeof (struct vattr));
   2377 			}
   2378 
   2379 			mutex_enter(&cp->c_statelock);
   2380 			havelock = 1;
   2381 		}
   2382 		error = cachefs_getfrontfile(cp);
   2383 		ASSERT((error != 0) ||
   2384 		    (frontvp == NULL) ||
   2385 		    (frontvp == cp->c_frontvp));
   2386 	}
   2387 	if ((error != 0) || (cp->c_frontvp == NULL))
   2388 		goto out;
   2389 
   2390 	if (frontvp != NULL)
   2391 		VN_RELE(frontvp);
   2392 
   2393 	frontvp = cp->c_frontvp;
   2394 	VN_HOLD(frontvp);
   2395 
   2396 	if (cp->c_backvp == NULL) {
   2397 		error = cachefs_getbackvp(fscp, cp);
   2398 		if ((error != 0) || (cp->c_backvp == NULL))
   2399 			goto out;
   2400 	}
   2401 	backvp = cp->c_backvp;
   2402 	VN_HOLD(backvp);
   2403 
   2404 	switch (pop->cpop_vp->v_type) {
   2405 	case VREG:
   2406 		mutex_exit(&cp->c_statelock);
   2407 		havelock = 0;
   2408 		error = cachefs_async_populate_reg(pop, cr, backvp, frontvp);
   2409 		break;
   2410 	case VDIR:
   2411 		error = cachefs_async_populate_dir(pop, cr, backvp, frontvp);
   2412 		mutex_exit(&cp->c_statelock);
   2413 		havelock = 0;
   2414 		break;
   2415 	default:
   2416 #ifdef CFSDEBUG
   2417 		printf("cachefs_async_populate: warning: vnode type = %d\n",
   2418 		    pop->cpop_vp->v_type);
   2419 		ASSERT(0);
   2420 #endif /* CFSDEBUG */
   2421 		error = EINVAL;
   2422 		break;
   2423 	}
   2424 
   2425 	if (error != 0)
   2426 		goto out;
   2427 
   2428 	error = VOP_FSYNC(frontvp, FSYNC, cr, NULL);
   2429 	if (error != 0) {
   2430 #ifdef CFSDEBUG
   2431 		CFS_DEBUG(CFSDEBUG_ASYNCPOP)
   2432 			printf("cachefs_async_populate: fsync\n");
   2433 #endif /* CFSDEBUG */
   2434 		goto out;
   2435 	}
   2436 
   2437 	/* grab the lock and finish up */
   2438 	mutex_enter(&cp->c_statelock);
   2439 	havelock = 1;
   2440 
   2441 	/* if went nocache while lock was dropped, get out */
   2442 	if ((cp->c_flags & CN_NOCACHE) || (cp->c_frontvp == NULL)) {
   2443 		error = EINVAL;
   2444 		goto out;
   2445 	}
   2446 
   2447 	va.va_mask = AT_MTIME;
   2448 	error = VOP_GETATTR(cp->c_frontvp, &va, 0, cr, NULL);
   2449 	if (error) {
   2450 #ifdef CFSDEBUG
   2451 		CFS_DEBUG(CFSDEBUG_ASYNCPOP)
   2452 			printf("cachefs_async_populate: getattr\n");
   2453 #endif /* CFSDEBUG */
   2454 		goto out;
   2455 	}
   2456 	cp->c_metadata.md_timestamp = va.va_mtime;
   2457 	cp->c_metadata.md_flags |= MD_POPULATED;
   2458 	cp->c_metadata.md_flags &= ~MD_INVALREADDIR;
   2459 	cp->c_flags |= CN_UPDATED;
   2460 
   2461 out:
   2462 	if (! havelock)
   2463 		mutex_enter(&cp->c_statelock);
   2464 
   2465 	/* see if an error happened behind our backs */
   2466 	if ((error == 0) && (cp->c_flags & CN_NOCACHE)) {
   2467 #ifdef CFSDEBUG
   2468 		CFS_DEBUG(CFSDEBUG_ASYNCPOP)
   2469 			printf("cachefs_async_populate: "
   2470 			    "nocache behind our backs\n");
   2471 #endif /* CFSDEBUG */
   2472 		error = EINVAL;
   2473 	}
   2474 
   2475 	cp->c_flags &= ~(CN_NEED_FRONT_SYNC | CN_POPULATION_PENDING |
   2476 	    CN_ASYNC_POPULATE | CN_ASYNC_POP_WORKING);
   2477 	cp->c_popthrp = NULL;
   2478 
   2479 	if (error != 0)
   2480 		cachefs_nocache(cp);
   2481 
   2482 	/* unblock any threads waiting for populate to finish */
   2483 	cv_broadcast(&cp->c_popcv);
   2484 	mutex_exit(&cp->c_statelock);
   2485 	rw_exit(&cp->c_rwlock);
   2486 	cachefs_cd_release(fscp);
   2487 
   2488 	if (backvp != NULL) {
   2489 		VN_RELE(backvp);
   2490 	}
   2491 	if (frontvp != NULL) {
   2492 		VN_RELE(frontvp);
   2493 	}
   2494 }
   2495 
   2496 /*
   2497  * only to be called from cachefs_async_populate
   2498  */
   2499 
   2500 static int
   2501 cachefs_async_populate_reg(struct cachefs_populate_req *pop, cred_t *cr,
   2502     vnode_t *backvp, vnode_t *frontvp)
   2503 {
   2504 	struct cnode *cp = VTOC(pop->cpop_vp);
   2505 	int error = 0;
   2506 	u_offset_t popoff;
   2507 	size_t popsize;
   2508 
   2509 	cachefs_cluster_allocmap(pop->cpop_off, &popoff,
   2510 	    &popsize, pop->cpop_size, cp);
   2511 	if (popsize == 0) {
   2512 #ifdef CFSDEBUG
   2513 		CFS_DEBUG(CFSDEBUG_ASYNCPOP)
   2514 			printf("cachefs_async_populate: popsize == 0\n");
   2515 #endif /* CFSDEBUG */
   2516 		goto out;
   2517 	}
   2518 
   2519 	error = cachefs_populate(cp, popoff, popsize, frontvp, backvp,
   2520 	    cp->c_size, cr);
   2521 	if (error != 0) {
   2522 #ifdef CFSDEBUG
   2523 		CFS_DEBUG(CFSDEBUG_ASYNCPOP)
   2524 			printf("cachefs_async_populate: cachefs_populate\n");
   2525 #endif /* CFSDEBUG */
   2526 		goto out;
   2527 	}
   2528 
   2529 out:
   2530 	return (error);
   2531 }
   2532 
   2533 void
   2534 cachefs_do_req(struct cachefs_req *rp)
   2535 {
   2536 	struct cachefscache *cachep;
   2537 
   2538 	mutex_enter(&rp->cfs_req_lock);
   2539 	switch (rp->cfs_cmd) {
   2540 	case CFS_INVALID:
   2541 		panic("cachefs_do_req: CFS_INVALID operation on queue");
   2542 		/*NOTREACHED*/
   2543 	case CFS_CACHE_SYNC:
   2544 		cachep = rp->cfs_req_u.cu_fs_sync.cf_cachep;
   2545 		cachefs_cache_sync(cachep);
   2546 		break;
   2547 	case CFS_IDLE:
   2548 		cachefs_cnode_idle(rp->cfs_req_u.cu_idle.ci_vp, rp->cfs_cr);
   2549 		break;
   2550 	case CFS_PUTPAGE:
   2551 		cachefs_async_putpage(&rp->cfs_req_u.cu_putpage, rp->cfs_cr);
   2552 		VN_RELE(rp->cfs_req_u.cu_putpage.cp_vp);
   2553 		break;
   2554 	case CFS_POPULATE:
   2555 		cachefs_async_populate(&rp->cfs_req_u.cu_populate, rp->cfs_cr);
   2556 		VN_RELE(rp->cfs_req_u.cu_populate.cpop_vp);
   2557 		break;
   2558 	case CFS_NOOP:
   2559 		break;
   2560 	default:
   2561 		panic("c_do_req: Invalid CFS async operation");
   2562 	}
   2563 	crfree(rp->cfs_cr);
   2564 	rp->cfs_cmd = CFS_INVALID;
   2565 	mutex_exit(&rp->cfs_req_lock);
   2566 	kmem_cache_free(cachefs_req_cache, rp);
   2567 }
   2568 
   2569 
   2570 
   2571 
   2572 ssize_t cachefs_mem_usage = 0;
   2573 
   2574 struct km_wrap {
   2575 	size_t kw_size;
   2576 	struct km_wrap *kw_other;
   2577 };
   2578 
   2579 kmutex_t cachefs_kmem_lock;
   2580 
   2581 void *
   2582 cachefs_kmem_alloc(size_t size, int flag)
   2583 {
   2584 #ifdef DEBUG
   2585 	caddr_t mp = NULL;
   2586 	struct km_wrap *kwp;
   2587 	size_t n = (size + (2 * sizeof (struct km_wrap)) + 7) & ~7;
   2588 
   2589 	ASSERT(n >= (size + 8));
   2590 	mp = kmem_alloc(n, flag);
   2591 	if (mp == NULL) {
   2592 		return (NULL);
   2593 	}
   2594 	/*LINTED alignment okay*/
   2595 	kwp = (struct km_wrap *)mp;
   2596 	kwp->kw_size = n;
   2597 	/*LINTED alignment okay*/
   2598 	kwp->kw_other = (struct km_wrap *)(mp + n - sizeof (struct km_wrap));
   2599 	kwp = (struct km_wrap *)kwp->kw_other;
   2600 	kwp->kw_size = n;
   2601 	/*LINTED alignment okay*/
   2602 	kwp->kw_other = (struct km_wrap *)mp;
   2603 
   2604 	mutex_enter(&cachefs_kmem_lock);
   2605 	ASSERT(cachefs_mem_usage >= 0);
   2606 	cachefs_mem_usage += n;
   2607 	mutex_exit(&cachefs_kmem_lock);
   2608 
   2609 	return (mp + sizeof (struct km_wrap));
   2610 #else /* DEBUG */
   2611 	return (kmem_alloc(size, flag));
   2612 #endif /* DEBUG */
   2613 }
   2614 
   2615 void *
   2616 cachefs_kmem_zalloc(size_t size, int flag)
   2617 {
   2618 #ifdef DEBUG
   2619 	caddr_t mp = NULL;
   2620 	struct km_wrap *kwp;
   2621 	size_t n = (size + (2 * sizeof (struct km_wrap)) + 7) & ~7;
   2622 
   2623 	ASSERT(n >= (size + 8));
   2624 	mp = kmem_zalloc(n, flag);
   2625 	if (mp == NULL) {
   2626 		return (NULL);
   2627 	}
   2628 	/*LINTED alignment okay*/
   2629 	kwp = (struct km_wrap *)mp;
   2630 	kwp->kw_size = n;
   2631 	/*LINTED alignment okay*/
   2632 	kwp->kw_other = (struct km_wrap *)(mp + n - sizeof (struct km_wrap));
   2633 	kwp = (struct km_wrap *)kwp->kw_other;
   2634 	kwp->kw_size = n;
   2635 	/*LINTED alignment okay*/
   2636 	kwp->kw_other = (struct km_wrap *)mp;
   2637 
   2638 	mutex_enter(&cachefs_kmem_lock);
   2639 	ASSERT(cachefs_mem_usage >= 0);
   2640 	cachefs_mem_usage += n;
   2641 	mutex_exit(&cachefs_kmem_lock);
   2642 
   2643 	return (mp + sizeof (struct km_wrap));
   2644 #else /* DEBUG */
   2645 	return (kmem_zalloc(size, flag));
   2646 #endif /* DEBUG */
   2647 }
   2648 
   2649 void
   2650 cachefs_kmem_free(void *mp, size_t size)
   2651 {
   2652 #ifdef DEBUG
   2653 	struct km_wrap *front_kwp;
   2654 	struct km_wrap *back_kwp;
   2655 	size_t n = (size + (2 * sizeof (struct km_wrap)) + 7) & ~7;
   2656 	void *p;
   2657 
   2658 	ASSERT(n >= (size + 8));
   2659 	front_kwp = (struct km_wrap *)((uintptr_t)mp - sizeof (struct km_wrap));
   2660 	back_kwp = (struct km_wrap *)
   2661 	    ((uintptr_t)front_kwp + n - sizeof (struct km_wrap));
   2662 
   2663 	ASSERT(front_kwp->kw_other == back_kwp);
   2664 	ASSERT(front_kwp->kw_size == n);
   2665 	ASSERT(back_kwp->kw_other == front_kwp);
   2666 	ASSERT(back_kwp->kw_size == n);
   2667 
   2668 	mutex_enter(&cachefs_kmem_lock);
   2669 	cachefs_mem_usage -= n;
   2670 	ASSERT(cachefs_mem_usage >= 0);
   2671 	mutex_exit(&cachefs_kmem_lock);
   2672 
   2673 	p = front_kwp;
   2674 	front_kwp->kw_size = back_kwp->kw_size = 0;
   2675 	front_kwp->kw_other = back_kwp->kw_other = NULL;
   2676 	kmem_free(p, n);
   2677 #else /* DEBUG */
   2678 	kmem_free(mp, size);
   2679 #endif /* DEBUG */
   2680 }
   2681 
   2682 char *
   2683 cachefs_strdup(char *s)
   2684 {
   2685 	char *rc;
   2686 
   2687 	ASSERT(s != NULL);
   2688 
   2689 	rc = cachefs_kmem_alloc(strlen(s) + 1, KM_SLEEP);
   2690 	(void) strcpy(rc, s);
   2691 
   2692 	return (rc);
   2693 }
   2694 
   2695 int
   2696 cachefs_stats_kstat_snapshot(kstat_t *ksp, void *buf, int rw)
   2697 {
   2698 	struct fscache *fscp = (struct fscache *)ksp->ks_data;
   2699 	cachefscache_t *cachep = fscp->fs_cache;
   2700 	int	error = 0;
   2701 
   2702 	if (rw == KSTAT_WRITE) {
   2703 		bcopy(buf, &fscp->fs_stats, sizeof (fscp->fs_stats));
   2704 		cachep->c_gc_count = fscp->fs_stats.st_gc_count;
   2705 		CACHEFS_CFS_TIME_TO_TIME_COPY(fscp->fs_stats.st_gc_time,
   2706 		    cachep->c_gc_time);
   2707 		CACHEFS_CFS_TIME_TO_TIME_COPY(fscp->fs_stats.st_gc_before_atime,
   2708 		    cachep->c_gc_before);
   2709 		CACHEFS_CFS_TIME_TO_TIME_COPY(fscp->fs_stats.st_gc_after_atime,
   2710 		    cachep->c_gc_after);
   2711 		return (error);
   2712 	}
   2713 
   2714 	fscp->fs_stats.st_gc_count = cachep->c_gc_count;
   2715 	CACHEFS_TIME_TO_CFS_TIME_COPY(cachep->c_gc_time,
   2716 	    fscp->fs_stats.st_gc_time, error);
   2717 	CACHEFS_TIME_TO_CFS_TIME_COPY(cachep->c_gc_before,
   2718 	    fscp->fs_stats.st_gc_before_atime, error);
   2719 	CACHEFS_TIME_TO_CFS_TIME_COPY(cachep->c_gc_after,
   2720 	    fscp->fs_stats.st_gc_after_atime, error);
   2721 	bcopy(&fscp->fs_stats, buf, sizeof (fscp->fs_stats));
   2722 
   2723 	return (error);
   2724 }
   2725 
   2726 #ifdef DEBUG
   2727 cachefs_debug_info_t *
   2728 cachefs_debug_save(cachefs_debug_info_t *oldcdb, int chain,
   2729     char *message, uint_t flags, int number, void *pointer,
   2730     cachefscache_t *cachep, struct fscache *fscp, struct cnode *cp)
   2731 {
   2732 	cachefs_debug_info_t *cdb;
   2733 
   2734 	if ((chain) || (oldcdb == NULL))
   2735 		cdb = cachefs_kmem_zalloc(sizeof (*cdb), KM_SLEEP);
   2736 	else
   2737 		cdb = oldcdb;
   2738 	if (chain)
   2739 		cdb->cdb_next = oldcdb;
   2740 
   2741 	if (message != NULL) {
   2742 		if (cdb->cdb_message != NULL)
   2743 			cachefs_kmem_free(cdb->cdb_message,
   2744 			    strlen(cdb->cdb_message) + 1);
   2745 		cdb->cdb_message = cachefs_kmem_alloc(strlen(message) + 1,
   2746 		    KM_SLEEP);
   2747 		(void) strcpy(cdb->cdb_message, message);
   2748 	}
   2749 	cdb->cdb_flags = flags;
   2750 	cdb->cdb_int = number;
   2751 	cdb->cdb_pointer = pointer;
   2752 
   2753 	cdb->cdb_count++;
   2754 
   2755 	cdb->cdb_cnode = cp;
   2756 	if (cp != NULL) {
   2757 		cdb->cdb_frontvp = cp->c_frontvp;
   2758 		cdb->cdb_backvp = cp->c_backvp;
   2759 	}
   2760 	if (fscp != NULL)
   2761 		cdb->cdb_fscp = fscp;
   2762 	else if (cp != NULL)
   2763 		cdb->cdb_fscp = C_TO_FSCACHE(cp);
   2764 	if (cachep != NULL)
   2765 		cdb->cdb_cachep = cachep;
   2766 	else if (cdb->cdb_fscp != NULL)
   2767 		cdb->cdb_cachep = cdb->cdb_fscp->fs_cache;
   2768 
   2769 	cdb->cdb_thread = curthread;
   2770 	cdb->cdb_timestamp = gethrtime();
   2771 	cdb->cdb_depth = getpcstack(cdb->cdb_stack, CACHEFS_DEBUG_DEPTH);
   2772 
   2773 	return (cdb);
   2774 }
   2775 
   2776 void
   2777 cachefs_debug_show(cachefs_debug_info_t *cdb)
   2778 {
   2779 	hrtime_t now = gethrtime();
   2780 	timestruc_t ts;
   2781 	int i;
   2782 
   2783 	while (cdb != NULL) {
   2784 		hrt2ts(now - cdb->cdb_timestamp, &ts);
   2785 		printf("cdb: %p count: %d timelapse: %ld.%9ld\n",
   2786 		    (void *)cdb, cdb->cdb_count, ts.tv_sec, ts.tv_nsec);
   2787 		if (cdb->cdb_message != NULL)
   2788 			printf("message: %s", cdb->cdb_message);
   2789 		printf("flags: %x int: %d pointer: %p\n",
   2790 		    cdb->cdb_flags, cdb->cdb_int, (void *)cdb->cdb_pointer);
   2791 
   2792 		printf("cnode: %p fscp: %p cachep: %p\n",
   2793 		    (void *)cdb->cdb_cnode,
   2794 		    (void *)cdb->cdb_fscp, (void *)cdb->cdb_cachep);
   2795 		printf("frontvp: %p backvp: %p\n",
   2796 		    (void *)cdb->cdb_frontvp, (void *)cdb->cdb_backvp);
   2797 
   2798 		printf("thread: %p stack...\n", (void *)cdb->cdb_thread);
   2799 		for (i = 0; i < cdb->cdb_depth; i++) {
   2800 			ulong_t off;
   2801 			char *sym;
   2802 
   2803 			sym = kobj_getsymname(cdb->cdb_stack[i], &off);
   2804 			printf("%s+%lx\n", sym ? sym : "?", off);
   2805 		}
   2806 		delay(2*hz);
   2807 		cdb = cdb->cdb_next;
   2808 	}
   2809 	debug_enter(NULL);
   2810 }
   2811 #endif /* DEBUG */
   2812 
   2813 /*
   2814  * Changes the size of the front file.
   2815  * Returns 0 for success or error if cannot set file size.
   2816  * NOCACHE bit is ignored.
   2817  * c_size is ignored.
   2818  * statelock must be held, frontvp must be set.
   2819  * File must be populated if setting to a size other than zero.
   2820  */
   2821 int
   2822 cachefs_frontfile_size(cnode_t *cp, u_offset_t length)
   2823 {
   2824 	cachefscache_t *cachep = C_TO_FSCACHE(cp)->fs_cache;
   2825 	vattr_t va;
   2826 	size_t nblks, blkdelta;
   2827 	int error = 0;
   2828 	int alloc = 0;
   2829 	struct cachefs_allocmap *allocp;
   2830 
   2831 	ASSERT(MUTEX_HELD(&cp->c_statelock));
   2832 	ASSERT(cp->c_frontvp);
   2833 
   2834 	/* if growing the file, allocate space first, we charge for holes */
   2835 	if (length) {
   2836 		ASSERT(cp->c_metadata.md_flags & MD_POPULATED);
   2837 
   2838 		nblks = (length + MAXBSIZE - 1) / MAXBSIZE;
   2839 		if (nblks > cp->c_metadata.md_frontblks) {
   2840 			blkdelta = nblks - cp->c_metadata.md_frontblks;
   2841 			error = cachefs_allocblocks(cachep, blkdelta,
   2842 			    cp->c_metadata.md_rltype);
   2843 			if (error)
   2844 				goto out;
   2845 			alloc = 1;
   2846 		}
   2847 	}
   2848 
   2849 	/* change the size of the front file */
   2850 	va.va_mask = AT_SIZE;
   2851 	va.va_size = length;
   2852 	error = VOP_SETATTR(cp->c_frontvp, &va, 0, kcred, NULL);
   2853 	if (error)
   2854 		goto out;
   2855 
   2856 	/* zero out the alloc map */
   2857 	bzero(&cp->c_metadata.md_allocinfo,
   2858 	    cp->c_metadata.md_allocents * sizeof (struct cachefs_allocmap));
   2859 	cp->c_metadata.md_allocents = 0;
   2860 
   2861 	if (length == 0) {
   2862 		/* free up blocks */
   2863 		if (cp->c_metadata.md_frontblks) {
   2864 			cachefs_freeblocks(cachep, cp->c_metadata.md_frontblks,
   2865 			    cp->c_metadata.md_rltype);
   2866 			cp->c_metadata.md_frontblks = 0;
   2867 		}
   2868 	} else {
   2869 		/* update number of blocks if shrinking file */
   2870 		nblks = (length + MAXBSIZE - 1) / MAXBSIZE;
   2871 		if (nblks < cp->c_metadata.md_frontblks) {
   2872 			blkdelta = cp->c_metadata.md_frontblks - nblks;
   2873 			cachefs_freeblocks(cachep, blkdelta,
   2874 			    cp->c_metadata.md_rltype);
   2875 			cp->c_metadata.md_frontblks = (uint_t)nblks;
   2876 		}
   2877 
   2878 		/* fix up alloc map to reflect new size */
   2879 		allocp = cp->c_metadata.md_allocinfo;
   2880 		allocp->am_start_off = 0;
   2881 		allocp->am_size = length;
   2882 		cp->c_metadata.md_allocents = 1;
   2883 	}
   2884 	cp->c_flags |= CN_UPDATED | CN_NEED_FRONT_SYNC;
   2885 
   2886 out:
   2887 	if (error && alloc)
   2888 		cachefs_freeblocks(cachep, blkdelta, cp->c_metadata.md_rltype);
   2889 	return (error);
   2890 }
   2891 
   2892 /*ARGSUSED*/
   2893 int
   2894 cachefs_req_create(void *voidp, void *cdrarg, int kmflags)
   2895 {
   2896 	struct cachefs_req *rp = (struct cachefs_req *)voidp;
   2897 
   2898 	/*
   2899 	 * XXX don't do this!  if you need this, you can't use this
   2900 	 * constructor.
   2901 	 */
   2902 
   2903 	bzero(rp, sizeof (struct cachefs_req));
   2904 
   2905 	mutex_init(&rp->cfs_req_lock, NULL, MUTEX_DEFAULT, NULL);
   2906 	return (0);
   2907 }
   2908 
   2909 /*ARGSUSED*/
   2910 void
   2911 cachefs_req_destroy(void *voidp, void *cdrarg)
   2912 {
   2913 	struct cachefs_req *rp = (struct cachefs_req *)voidp;
   2914 
   2915 	mutex_destroy(&rp->cfs_req_lock);
   2916 }
   2917