xref: /onnv-gate/usr/src/uts/common/fs/cachefs/cachefs_cnode.c (revision 5331:3047ad28a67b)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*5331Samw  * Common Development and Distribution License (the "License").
6*5331Samw  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*5331Samw  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
270Sstevel@tonic-gate 
280Sstevel@tonic-gate 
290Sstevel@tonic-gate #include <sys/param.h>
300Sstevel@tonic-gate #include <sys/types.h>
310Sstevel@tonic-gate #include <sys/systm.h>
320Sstevel@tonic-gate #include <sys/cred.h>
330Sstevel@tonic-gate #include <sys/proc.h>
340Sstevel@tonic-gate #include <sys/user.h>
350Sstevel@tonic-gate #include <sys/vfs.h>
360Sstevel@tonic-gate #include <sys/vnode.h>
370Sstevel@tonic-gate #include <sys/pathname.h>
380Sstevel@tonic-gate #include <sys/uio.h>
390Sstevel@tonic-gate #include <sys/tiuser.h>
400Sstevel@tonic-gate #include <sys/sysmacros.h>
410Sstevel@tonic-gate #include <sys/kmem.h>
420Sstevel@tonic-gate #include <sys/buf.h>
430Sstevel@tonic-gate #include <netinet/in.h>
440Sstevel@tonic-gate #include <rpc/types.h>
450Sstevel@tonic-gate #include <rpc/xdr.h>
460Sstevel@tonic-gate #include <rpc/auth.h>
470Sstevel@tonic-gate #include <rpc/clnt.h>
480Sstevel@tonic-gate #include <sys/mount.h>
490Sstevel@tonic-gate #include <sys/ioctl.h>
500Sstevel@tonic-gate #include <sys/statvfs.h>
510Sstevel@tonic-gate #include <sys/errno.h>
520Sstevel@tonic-gate #include <sys/debug.h>
530Sstevel@tonic-gate #include <sys/cmn_err.h>
540Sstevel@tonic-gate #include <sys/utsname.h>
550Sstevel@tonic-gate #include <sys/modctl.h>
560Sstevel@tonic-gate #include <vm/pvn.h>
570Sstevel@tonic-gate 
580Sstevel@tonic-gate #include <sys/fs/cachefs_fs.h>
590Sstevel@tonic-gate 
600Sstevel@tonic-gate /*
610Sstevel@tonic-gate  * cachefs_max_idle is a global that is tunable.
620Sstevel@tonic-gate  * This value decides how frequently or when the
630Sstevel@tonic-gate  * cachefs_cnode_idleclean is run.
640Sstevel@tonic-gate  * The default value is set to CFS_FS_MAXIDLE.
650Sstevel@tonic-gate  * The tunable if set to X triggers a cleanup when
660Sstevel@tonic-gate  * the number of idle cnodes reach X, and cleans up
670Sstevel@tonic-gate  * (.25 * X) idle cnodes.
680Sstevel@tonic-gate  */
690Sstevel@tonic-gate int cachefs_max_idle = CFS_FS_MAXIDLE;
700Sstevel@tonic-gate 
710Sstevel@tonic-gate 
720Sstevel@tonic-gate struct kmem_cache *cachefs_cnode_cache = NULL;
730Sstevel@tonic-gate 
740Sstevel@tonic-gate /*
750Sstevel@tonic-gate  * Functions for cnode management.
760Sstevel@tonic-gate  */
770Sstevel@tonic-gate 
780Sstevel@tonic-gate /*
790Sstevel@tonic-gate  * Puts cnode on idle list.  Only call from an async thread or no
800Sstevel@tonic-gate  * locks held.
810Sstevel@tonic-gate  */
820Sstevel@tonic-gate /*ARGSUSED1*/
830Sstevel@tonic-gate void
cachefs_cnode_idle(struct vnode * vp,cred_t * cr)840Sstevel@tonic-gate cachefs_cnode_idle(struct vnode *vp, cred_t *cr)
850Sstevel@tonic-gate {
860Sstevel@tonic-gate 	cnode_t *cp = VTOC(vp);
870Sstevel@tonic-gate 	fscache_t *fscp = C_TO_FSCACHE(cp);
880Sstevel@tonic-gate 	int cleanidle;
890Sstevel@tonic-gate 	vnode_t *unldvp;
900Sstevel@tonic-gate 	cred_t *unlcred;
910Sstevel@tonic-gate 	char *unlname;
920Sstevel@tonic-gate 	int error;
930Sstevel@tonic-gate 
940Sstevel@tonic-gate 	/*
950Sstevel@tonic-gate 	 * The key to this routine is not to drop the vnode count
960Sstevel@tonic-gate 	 * while on the idle list.  This prevents this routine from
970Sstevel@tonic-gate 	 * being called again by vn_rele on an inactive cnode.
980Sstevel@tonic-gate 	 * Nothing bad happens if an "active" cnode is put on the idle
990Sstevel@tonic-gate 	 * list.  It eventually gets pulled off.
1000Sstevel@tonic-gate 	 * Also this routine is only called from a thread message sent
1010Sstevel@tonic-gate 	 * by cachefs_inactive().  It is not safe for this routine
1020Sstevel@tonic-gate 	 * to be the "inactive" entry point because of the dnlc.
1030Sstevel@tonic-gate 	 */
1040Sstevel@tonic-gate 
1050Sstevel@tonic-gate 	for (;;) {
1060Sstevel@tonic-gate 		/* get access to the file system */
1070Sstevel@tonic-gate 		error = cachefs_cd_access(fscp, 0, 1);
1080Sstevel@tonic-gate 		ASSERT(error == 0);
1090Sstevel@tonic-gate 
1100Sstevel@tonic-gate 		/* get exclusive access to this cnode */
1110Sstevel@tonic-gate 		mutex_enter(&cp->c_statelock);
1120Sstevel@tonic-gate 
1130Sstevel@tonic-gate 		/* done with this loop if not unlinking a file */
1140Sstevel@tonic-gate 		if (cp->c_unldvp == NULL)
1150Sstevel@tonic-gate 			break;
1160Sstevel@tonic-gate 
1170Sstevel@tonic-gate 		/* get unlink info out of the cnode */
1180Sstevel@tonic-gate 		unldvp = cp->c_unldvp;
1190Sstevel@tonic-gate 		unlcred = cp->c_unlcred;
1200Sstevel@tonic-gate 		unlname = cp->c_unlname;
1210Sstevel@tonic-gate 		cp->c_unldvp = NULL;
1220Sstevel@tonic-gate 		cp->c_unlcred = NULL;
1230Sstevel@tonic-gate 		cp->c_unlname = NULL;
1240Sstevel@tonic-gate 		mutex_exit(&cp->c_statelock);
1250Sstevel@tonic-gate 
1260Sstevel@tonic-gate 		/* finish the remove operation */
1270Sstevel@tonic-gate 		if (fscp->fs_cdconnected == CFS_CD_CONNECTED) {
1280Sstevel@tonic-gate 			error = cachefs_remove_connected(unldvp,
1290Sstevel@tonic-gate 			    unlname, unlcred, vp);
1300Sstevel@tonic-gate 		} else {
1310Sstevel@tonic-gate 			error = cachefs_remove_disconnected(unldvp,
1320Sstevel@tonic-gate 			    unlname, unlcred, vp);
1330Sstevel@tonic-gate 		}
1340Sstevel@tonic-gate 
135*5331Samw 		/* reacquire cnode lock */
1360Sstevel@tonic-gate 		mutex_enter(&cp->c_statelock);
1370Sstevel@tonic-gate 
1380Sstevel@tonic-gate 		/* if a timeout occurred */
1390Sstevel@tonic-gate 		if (CFS_TIMEOUT(fscp, error)) {
1400Sstevel@tonic-gate 			/* restore cnode state */
1410Sstevel@tonic-gate 			if (cp->c_unldvp == NULL) {
1420Sstevel@tonic-gate 				cp->c_unldvp = unldvp;
1430Sstevel@tonic-gate 				cp->c_unlcred = unlcred;
1440Sstevel@tonic-gate 				cp->c_unlname = unlname;
1450Sstevel@tonic-gate 				if (fscp->fs_cdconnected == CFS_CD_CONNECTED) {
1460Sstevel@tonic-gate 					mutex_exit(&cp->c_statelock);
1470Sstevel@tonic-gate 					cachefs_cd_release(fscp);
1480Sstevel@tonic-gate 					cachefs_cd_timedout(fscp);
1490Sstevel@tonic-gate 					continue;
1500Sstevel@tonic-gate 				} else {
1510Sstevel@tonic-gate 					cp->c_flags |= CN_PENDRM;
1520Sstevel@tonic-gate 					mutex_exit(&cp->c_statelock);
1530Sstevel@tonic-gate 					goto out;
1540Sstevel@tonic-gate 				}
1550Sstevel@tonic-gate 			}
1560Sstevel@tonic-gate 		}
1570Sstevel@tonic-gate 		/* free up resources */
1580Sstevel@tonic-gate 		VN_RELE(unldvp);
1590Sstevel@tonic-gate 		cachefs_kmem_free(unlname, MAXNAMELEN);
1600Sstevel@tonic-gate 		crfree(unlcred);
1610Sstevel@tonic-gate 		break;
1620Sstevel@tonic-gate 	}
1630Sstevel@tonic-gate 
1640Sstevel@tonic-gate 	ASSERT((cp->c_flags & CN_IDLE) == 0);
1650Sstevel@tonic-gate 	/*
1660Sstevel@tonic-gate 	 * If we are going to destroy this cnode,
1670Sstevel@tonic-gate 	 * do it now instead of later.
1680Sstevel@tonic-gate 	 */
1690Sstevel@tonic-gate 	if (cp->c_flags & (CN_DESTROY | CN_STALE)) {
1700Sstevel@tonic-gate 		mutex_exit(&cp->c_statelock);
1710Sstevel@tonic-gate 		(void) cachefs_cnode_inactive(vp, cr);
1720Sstevel@tonic-gate 		goto out;
1730Sstevel@tonic-gate 	}
1740Sstevel@tonic-gate 
1750Sstevel@tonic-gate 	/*
1760Sstevel@tonic-gate 	 * mark cnode as idle, put it on the idle list, and increment the
1770Sstevel@tonic-gate 	 * number of idle cnodes
1780Sstevel@tonic-gate 	 */
1790Sstevel@tonic-gate 	cp->c_flags |= CN_IDLE;
1800Sstevel@tonic-gate 	mutex_enter(&fscp->fs_idlelock);
1810Sstevel@tonic-gate 	cachefs_cnode_idleadd(cp);
1820Sstevel@tonic-gate 	if ((fscp->fs_idlecnt > cachefs_max_idle) &&
1830Sstevel@tonic-gate 	    (fscp->fs_idleclean == 0) &&
1840Sstevel@tonic-gate 	    (fscp->fs_cdtransition == 0)) {
1850Sstevel@tonic-gate 		fscp->fs_idleclean = 1;
1860Sstevel@tonic-gate 		cleanidle = 1;
1870Sstevel@tonic-gate 	} else {
1880Sstevel@tonic-gate 		cleanidle = 0;
1890Sstevel@tonic-gate 	}
1900Sstevel@tonic-gate 	mutex_exit(&fscp->fs_idlelock);
1910Sstevel@tonic-gate 
1920Sstevel@tonic-gate 	/* release cnode */
1930Sstevel@tonic-gate 	mutex_exit(&cp->c_statelock);
1940Sstevel@tonic-gate 
1950Sstevel@tonic-gate 	/* if should reduce the number of idle cnodes */
1960Sstevel@tonic-gate 	if (cleanidle) {
1970Sstevel@tonic-gate 		ASSERT(fscp->fs_idlecnt > 1);
1980Sstevel@tonic-gate 		fscache_hold(fscp);
1990Sstevel@tonic-gate 		cachefs_cnode_idleclean(fscp, 0);
2000Sstevel@tonic-gate 		/* XXX race with cachefs_unmount() calling destroy */
2010Sstevel@tonic-gate 		fscache_rele(fscp);
2020Sstevel@tonic-gate 	}
2030Sstevel@tonic-gate 
2040Sstevel@tonic-gate out:
2050Sstevel@tonic-gate 	/* release hold on the file system */
2060Sstevel@tonic-gate 	/* XXX unmount() could have called destroy after fscache_rele() */
2070Sstevel@tonic-gate 	cachefs_cd_release(fscp);
2080Sstevel@tonic-gate }
2090Sstevel@tonic-gate 
2100Sstevel@tonic-gate /*
2110Sstevel@tonic-gate  * Removes cnodes from the idle list and destroys them.
2120Sstevel@tonic-gate  */
2130Sstevel@tonic-gate void
cachefs_cnode_idleclean(fscache_t * fscp,int unmount)2140Sstevel@tonic-gate cachefs_cnode_idleclean(fscache_t *fscp, int unmount)
2150Sstevel@tonic-gate {
2160Sstevel@tonic-gate 	int remcnt;
2170Sstevel@tonic-gate 	cnode_t *cp;
2180Sstevel@tonic-gate 
2190Sstevel@tonic-gate 	mutex_enter(&fscp->fs_idlelock);
2200Sstevel@tonic-gate 
2210Sstevel@tonic-gate 	/* determine number of cnodes to destroy */
2220Sstevel@tonic-gate 	if (unmount) {
2230Sstevel@tonic-gate 		/* destroy all plus any that go idle while in this routine */
2240Sstevel@tonic-gate 		remcnt = fscp->fs_idlecnt * 2;
2250Sstevel@tonic-gate 	} else {
2260Sstevel@tonic-gate 		/* reduce to 75% of max allowed idle cnodes */
2270Sstevel@tonic-gate 		remcnt = (fscp->fs_idlecnt - cachefs_max_idle) +
2280Sstevel@tonic-gate 		    (cachefs_max_idle >> 2);
2290Sstevel@tonic-gate 	}
2300Sstevel@tonic-gate 
2310Sstevel@tonic-gate 	for (; remcnt > 0; remcnt--) {
2320Sstevel@tonic-gate 		/* get cnode on back of idle list and hold it */
2330Sstevel@tonic-gate 		cp = fscp->fs_idleback;
2340Sstevel@tonic-gate 		if (cp == NULL)
2350Sstevel@tonic-gate 			break;
2360Sstevel@tonic-gate 		VN_HOLD(CTOV(cp));
2370Sstevel@tonic-gate 		mutex_exit(&fscp->fs_idlelock);
2380Sstevel@tonic-gate 
2390Sstevel@tonic-gate 		/* if the cnode is still on the idle list */
2400Sstevel@tonic-gate 		mutex_enter(&cp->c_statelock);
2410Sstevel@tonic-gate 		if (cp->c_flags & CN_IDLE) {
2420Sstevel@tonic-gate 			cp->c_flags &= ~CN_IDLE;
2430Sstevel@tonic-gate 
2440Sstevel@tonic-gate 			/* remove cnode from the idle list */
2450Sstevel@tonic-gate 			mutex_enter(&fscp->fs_idlelock);
2460Sstevel@tonic-gate 			cachefs_cnode_idlerem(cp);
2470Sstevel@tonic-gate 			mutex_exit(&fscp->fs_idlelock);
2480Sstevel@tonic-gate 			mutex_exit(&cp->c_statelock);
2490Sstevel@tonic-gate 
2500Sstevel@tonic-gate 			/* destroy the cnode */
2510Sstevel@tonic-gate 			VN_RELE(CTOV(cp));
2520Sstevel@tonic-gate 			(void) cachefs_cnode_inactive(CTOV(cp), kcred);
2530Sstevel@tonic-gate 		} else {
2540Sstevel@tonic-gate 			/* cnode went active, just skip it */
2550Sstevel@tonic-gate 			mutex_exit(&cp->c_statelock);
2560Sstevel@tonic-gate 			VN_RELE(CTOV(cp));
2570Sstevel@tonic-gate 		}
2580Sstevel@tonic-gate 		mutex_enter(&fscp->fs_idlelock);
2590Sstevel@tonic-gate 	}
2600Sstevel@tonic-gate 
2610Sstevel@tonic-gate 	fscp->fs_idleclean = 0;
2620Sstevel@tonic-gate 	mutex_exit(&fscp->fs_idlelock);
2630Sstevel@tonic-gate }
2640Sstevel@tonic-gate 
2650Sstevel@tonic-gate /*
2660Sstevel@tonic-gate  * This routine does the real work of inactivating a cachefs vnode.
2670Sstevel@tonic-gate  */
2680Sstevel@tonic-gate int
cachefs_cnode_inactive(register struct vnode * vp,cred_t * cr)2690Sstevel@tonic-gate cachefs_cnode_inactive(register struct vnode *vp, cred_t *cr)
2700Sstevel@tonic-gate {
2710Sstevel@tonic-gate 	cnode_t *cp;
2720Sstevel@tonic-gate 	struct fscache *fscp;
2730Sstevel@tonic-gate 	struct filegrp *fgp;
2740Sstevel@tonic-gate 	cachefscache_t *cachep;
2750Sstevel@tonic-gate 	struct cachefs_metadata *mdp;
2760Sstevel@tonic-gate 	int meta_destroyed = 0;
2770Sstevel@tonic-gate 
2780Sstevel@tonic-gate 	cp = VTOC(vp);
2790Sstevel@tonic-gate 
2800Sstevel@tonic-gate 	fscp = C_TO_FSCACHE(cp);
2810Sstevel@tonic-gate 	cachep = fscp->fs_cache;
2820Sstevel@tonic-gate 	ASSERT(cachep != NULL);
2830Sstevel@tonic-gate 	fgp = cp->c_filegrp;
2840Sstevel@tonic-gate 
2850Sstevel@tonic-gate 	ASSERT((cp->c_flags & CN_IDLE) == 0);
2860Sstevel@tonic-gate 
2870Sstevel@tonic-gate 	/* truncate the front file if necessary */
2880Sstevel@tonic-gate 	mutex_enter(&cp->c_statelock);
2890Sstevel@tonic-gate 	if ((cp->c_flags & CN_NOCACHE) && (cp->c_metadata.md_flags & MD_FILE) &&
2900Sstevel@tonic-gate 	    cp->c_metadata.md_frontblks) {
2910Sstevel@tonic-gate 
2920Sstevel@tonic-gate 		ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
2930Sstevel@tonic-gate 
2940Sstevel@tonic-gate #ifdef CFSDEBUG
2950Sstevel@tonic-gate 		CFS_DEBUG(CFSDEBUG_INVALIDATE)
2960Sstevel@tonic-gate 			printf("c_cnode_inactive: invalidating %llu\n",
2970Sstevel@tonic-gate 			    (u_longlong_t)cp->c_id.cid_fileno);
2980Sstevel@tonic-gate #endif
2990Sstevel@tonic-gate 		/*
3000Sstevel@tonic-gate 		 * If the cnode is being populated, and we're not the
3010Sstevel@tonic-gate 		 * populating thread, then block until the pop thread
3020Sstevel@tonic-gate 		 * completes.  If we are the pop thread, then we may come in
3030Sstevel@tonic-gate 		 * here, but not to nuke the directory cnode at a critical
3040Sstevel@tonic-gate 		 * juncture.
3050Sstevel@tonic-gate 		 */
3060Sstevel@tonic-gate 		while ((cp->c_flags & CN_ASYNC_POP_WORKING) &&
3070Sstevel@tonic-gate 		    (cp->c_popthrp != curthread))
3080Sstevel@tonic-gate 			cv_wait(&cp->c_popcv, &cp->c_statelock);
3090Sstevel@tonic-gate 
3100Sstevel@tonic-gate 		cachefs_inval_object(cp);
3110Sstevel@tonic-gate 	}
3120Sstevel@tonic-gate 	mutex_exit(&cp->c_statelock);
3130Sstevel@tonic-gate 
3140Sstevel@tonic-gate 	for (;;) {
3150Sstevel@tonic-gate 		/* see if vnode is really inactive */
3160Sstevel@tonic-gate 		mutex_enter(&vp->v_lock);
3170Sstevel@tonic-gate 		ASSERT(vp->v_count > 0);
3180Sstevel@tonic-gate 		if (vp->v_count > 1) {
3190Sstevel@tonic-gate 			/*
3200Sstevel@tonic-gate 			 * It's impossible for us to be cnode_inactive for
3210Sstevel@tonic-gate 			 * the root cnode _unless_ we are being called from
3220Sstevel@tonic-gate 			 * cachefs_unmount (where inactive is called
3230Sstevel@tonic-gate 			 * explictly).  If the count is not 1, there is
3240Sstevel@tonic-gate 			 * still an outstanding reference to the root cnode,
3250Sstevel@tonic-gate 			 * and we return EBUSY; this allows cachefs_unmount
3260Sstevel@tonic-gate 			 * to fail.
3270Sstevel@tonic-gate 			 */
3280Sstevel@tonic-gate 			if (cp->c_flags & CN_ROOT) {
3290Sstevel@tonic-gate 				mutex_exit(&vp->v_lock);
3300Sstevel@tonic-gate 				return (EBUSY);
3310Sstevel@tonic-gate 			}
3320Sstevel@tonic-gate 			cp->c_ipending = 0;
3330Sstevel@tonic-gate 			vp->v_count--;	/* release our hold from vn_rele */
3340Sstevel@tonic-gate 			mutex_exit(&vp->v_lock);
3350Sstevel@tonic-gate 			return (0);
3360Sstevel@tonic-gate 		}
3370Sstevel@tonic-gate 		mutex_exit(&vp->v_lock);
3380Sstevel@tonic-gate 
3390Sstevel@tonic-gate 		/* get rid of any pages, do not care if cannot be pushed */
3400Sstevel@tonic-gate 		if (vn_has_cached_data(vp)) {
3410Sstevel@tonic-gate 			ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
3420Sstevel@tonic-gate 			(void) cachefs_putpage_common(vp, (offset_t)0, 0,
3430Sstevel@tonic-gate 			    B_INVAL | B_FORCE, cr);
3440Sstevel@tonic-gate 		}
3450Sstevel@tonic-gate 
3460Sstevel@tonic-gate 		/* if need to sync metadata, the call is a no op for NFSv4 */
3470Sstevel@tonic-gate 		if ((cp->c_flags & (CN_UPDATED | CN_DESTROY)) == CN_UPDATED) {
3480Sstevel@tonic-gate 			(void) cachefs_sync_metadata(cp);
3490Sstevel@tonic-gate 			continue;
3500Sstevel@tonic-gate 		}
3510Sstevel@tonic-gate 		break;
3520Sstevel@tonic-gate 	}
3530Sstevel@tonic-gate 
3540Sstevel@tonic-gate 	/*
3550Sstevel@tonic-gate 	 * Lock out possible race with makecachefsnode.
3560Sstevel@tonic-gate 	 * Makecachefsnode will fix up the rl/active list stuff to
3570Sstevel@tonic-gate 	 * be correct when it gets to run.
3580Sstevel@tonic-gate 	 * We have to do the rl/active stuff while the cnode is on the hash
3590Sstevel@tonic-gate 	 * list to sync actions on the rl/active list.
3600Sstevel@tonic-gate 	 */
3610Sstevel@tonic-gate 	mutex_enter(&fgp->fg_cnodelock);
3620Sstevel@tonic-gate 	mutex_enter(&cp->c_statelock);
3630Sstevel@tonic-gate 
3640Sstevel@tonic-gate 	/* see if vnode is still inactive */
3650Sstevel@tonic-gate 	mutex_enter(&vp->v_lock);
3660Sstevel@tonic-gate 	ASSERT(vp->v_count > 0);
3670Sstevel@tonic-gate 	if (vp->v_count > 1) {
3680Sstevel@tonic-gate 		cp->c_ipending = 0;
3690Sstevel@tonic-gate 		vp->v_count--;
3700Sstevel@tonic-gate 		mutex_exit(&vp->v_lock);
3710Sstevel@tonic-gate 		mutex_exit(&cp->c_statelock);
3720Sstevel@tonic-gate 		mutex_exit(&fgp->fg_cnodelock);
3730Sstevel@tonic-gate #ifdef CFSDEBUG
3740Sstevel@tonic-gate 		CFS_DEBUG(CFSDEBUG_INVALIDATE)
3750Sstevel@tonic-gate 			printf("cachefs_cnode_inactive: %u vp %p\n",
3760Sstevel@tonic-gate 			    vp->v_count, vp);
3770Sstevel@tonic-gate #endif
3780Sstevel@tonic-gate 		return (0);
3790Sstevel@tonic-gate 	}
3800Sstevel@tonic-gate 	mutex_exit(&vp->v_lock);
3810Sstevel@tonic-gate 
3820Sstevel@tonic-gate 	/* check for race with remove */
3830Sstevel@tonic-gate 	if (cp->c_unldvp) {
3840Sstevel@tonic-gate 		mutex_exit(&cp->c_statelock);
3850Sstevel@tonic-gate 		mutex_exit(&fgp->fg_cnodelock);
3860Sstevel@tonic-gate 
3870Sstevel@tonic-gate 		/* this causes cachefs_inactive to be called again */
3880Sstevel@tonic-gate 		VN_RELE(vp);
3890Sstevel@tonic-gate 		return (0);
3900Sstevel@tonic-gate 	}
3910Sstevel@tonic-gate 
3920Sstevel@tonic-gate 	/* if any pages left, really get rid of them */
3930Sstevel@tonic-gate 	if (vn_has_cached_data(vp)) {
3940Sstevel@tonic-gate 		ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
3950Sstevel@tonic-gate 		(void) pvn_vplist_dirty(vp, 0, NULL, B_INVAL | B_TRUNC, cr);
3960Sstevel@tonic-gate 	}
3970Sstevel@tonic-gate 	ASSERT(vp->v_count == 1);
3980Sstevel@tonic-gate 
3990Sstevel@tonic-gate 	mdp = &cp->c_metadata;
4000Sstevel@tonic-gate 
4010Sstevel@tonic-gate 	/* if we can (and should) destroy the front file and metadata */
4020Sstevel@tonic-gate 	if ((cp->c_flags & (CN_DESTROY | CN_STALE)) &&
4030Sstevel@tonic-gate 	    (fgp->fg_flags & CFS_FG_WRITE) && !CFS_ISFS_BACKFS_NFSV4(fscp)) {
4040Sstevel@tonic-gate 		if (mdp->md_rlno) {
4050Sstevel@tonic-gate 			cachefs_removefrontfile(mdp, &cp->c_id, fgp);
4060Sstevel@tonic-gate 			cachefs_rlent_moveto(cachep, CACHEFS_RL_FREE,
4070Sstevel@tonic-gate 			    mdp->md_rlno, 0);
4080Sstevel@tonic-gate 			mdp->md_rlno = 0;
4090Sstevel@tonic-gate 			mdp->md_rltype = CACHEFS_RL_NONE;
4100Sstevel@tonic-gate 		}
4110Sstevel@tonic-gate 		if ((cp->c_flags & CN_ALLOC_PENDING) == 0) {
4120Sstevel@tonic-gate 			(void) filegrp_destroy_metadata(fgp, &cp->c_id);
4130Sstevel@tonic-gate 			meta_destroyed = 1;
4140Sstevel@tonic-gate 		}
4150Sstevel@tonic-gate 	}
4160Sstevel@tonic-gate 
4170Sstevel@tonic-gate 	/* else put the front file on the gc list */
4180Sstevel@tonic-gate 	else if (mdp->md_rlno &&
4190Sstevel@tonic-gate 	    (fgp->fg_flags & CFS_FG_WRITE) &&
4200Sstevel@tonic-gate 	    (cp->c_metadata.md_rltype == CACHEFS_RL_ACTIVE)) {
4210Sstevel@tonic-gate #ifdef CFSDEBUG
4220Sstevel@tonic-gate 		cachefs_rlent_verify(cachep, CACHEFS_RL_ACTIVE,
4230Sstevel@tonic-gate 		    mdp->md_rlno);
4240Sstevel@tonic-gate #endif /* CFSDEBUG */
4250Sstevel@tonic-gate 
4260Sstevel@tonic-gate 		ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
4270Sstevel@tonic-gate 		cachefs_rlent_moveto(cachep, CACHEFS_RL_GC, mdp->md_rlno,
4280Sstevel@tonic-gate 		    mdp->md_frontblks);
4290Sstevel@tonic-gate 		mdp->md_rltype = CACHEFS_RL_GC;
4300Sstevel@tonic-gate 		cp->c_flags |= CN_UPDATED;
4310Sstevel@tonic-gate 	}
4320Sstevel@tonic-gate 
4330Sstevel@tonic-gate 	/* if idlelist pointer(s) not null, remove from idle list */
4340Sstevel@tonic-gate 	if ((cp->c_idlefront != NULL) || (cp->c_idleback != NULL)) {
4350Sstevel@tonic-gate 		mutex_enter(&fscp->fs_idlelock);
4360Sstevel@tonic-gate 		cachefs_cnode_idlerem(cp);
4370Sstevel@tonic-gate 		mutex_exit(&fscp->fs_idlelock);
4380Sstevel@tonic-gate 	}
4390Sstevel@tonic-gate 
4400Sstevel@tonic-gate 	/* remove from the filegrp list prior to releasing the cnode lock */
4410Sstevel@tonic-gate 	cachefs_cnode_listrem(cp);
4420Sstevel@tonic-gate 
4430Sstevel@tonic-gate 	mutex_exit(&cp->c_statelock);
4440Sstevel@tonic-gate 	if (! meta_destroyed)
4450Sstevel@tonic-gate 		(void) cachefs_sync_metadata(cp);
4460Sstevel@tonic-gate 
4470Sstevel@tonic-gate 	mutex_exit(&fgp->fg_cnodelock);
4480Sstevel@tonic-gate 
4490Sstevel@tonic-gate 	if (cp->c_cred != NULL) {
4500Sstevel@tonic-gate 		crfree(cp->c_cred);
4510Sstevel@tonic-gate 		cp->c_cred = NULL;
4520Sstevel@tonic-gate 	}
4530Sstevel@tonic-gate 
4540Sstevel@tonic-gate 	if (cp->c_frontvp)
4550Sstevel@tonic-gate 		VN_RELE(cp->c_frontvp);
4560Sstevel@tonic-gate 
4570Sstevel@tonic-gate 	if (cp->c_backvp)
4580Sstevel@tonic-gate 		VN_RELE(cp->c_backvp);
4590Sstevel@tonic-gate 
4600Sstevel@tonic-gate 	if (cp->c_acldirvp)
4610Sstevel@tonic-gate 		VN_RELE(cp->c_acldirvp);
4620Sstevel@tonic-gate 
4630Sstevel@tonic-gate 	rw_destroy(&cp->c_rwlock);
4640Sstevel@tonic-gate 	mutex_destroy(&cp->c_statelock);
4650Sstevel@tonic-gate 	cv_destroy(&cp->c_popcv);
4660Sstevel@tonic-gate 	mutex_destroy(&cp->c_iomutex);
4670Sstevel@tonic-gate 	cv_destroy(&cp->c_iocv);
4680Sstevel@tonic-gate 
4690Sstevel@tonic-gate 	/* free up cnode memory */
4700Sstevel@tonic-gate 	vn_invalid(cp->c_vnode);
4710Sstevel@tonic-gate 	vn_free(cp->c_vnode);
4720Sstevel@tonic-gate 	kmem_cache_free(cachefs_cnode_cache, cp);
4730Sstevel@tonic-gate 
4740Sstevel@tonic-gate 	filegrp_rele(fgp);
4750Sstevel@tonic-gate 	(void) fscache_cnodecnt(fscp, -1);
4760Sstevel@tonic-gate 	return (0);
4770Sstevel@tonic-gate }
4780Sstevel@tonic-gate 
4790Sstevel@tonic-gate /*
4800Sstevel@tonic-gate  * Add a cnode to the filegrp list.
4810Sstevel@tonic-gate  */
4820Sstevel@tonic-gate void
cachefs_cnode_listadd(struct cnode * cp)4830Sstevel@tonic-gate cachefs_cnode_listadd(struct cnode *cp)
4840Sstevel@tonic-gate {
4850Sstevel@tonic-gate 	filegrp_t *fgp = cp->c_filegrp;
4860Sstevel@tonic-gate 
4870Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&fgp->fg_cnodelock));
4880Sstevel@tonic-gate 	ASSERT(cp->c_next == NULL);
4890Sstevel@tonic-gate 
4900Sstevel@tonic-gate 	cp->c_next = fgp->fg_cnodelist;
4910Sstevel@tonic-gate 	fgp->fg_cnodelist = cp;
4920Sstevel@tonic-gate }
4930Sstevel@tonic-gate 
4940Sstevel@tonic-gate /*
4950Sstevel@tonic-gate  * Remove a cnode from the filegrp list.
4960Sstevel@tonic-gate  */
4970Sstevel@tonic-gate void
cachefs_cnode_listrem(struct cnode * cp)4980Sstevel@tonic-gate cachefs_cnode_listrem(struct cnode *cp)
4990Sstevel@tonic-gate {
5000Sstevel@tonic-gate 	filegrp_t *fgp = cp->c_filegrp;
5010Sstevel@tonic-gate 	struct cnode **headpp;
5020Sstevel@tonic-gate 
5030Sstevel@tonic-gate #ifdef CFSDEBUG
5040Sstevel@tonic-gate 	int found = 0;
5050Sstevel@tonic-gate #endif
5060Sstevel@tonic-gate 
5070Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&fgp->fg_cnodelock));
5080Sstevel@tonic-gate 	ASSERT(cp->c_idleback == NULL);
5090Sstevel@tonic-gate 	ASSERT(cp->c_idlefront == NULL);
5100Sstevel@tonic-gate 
5110Sstevel@tonic-gate 	for (headpp = &fgp->fg_cnodelist;
5120Sstevel@tonic-gate 		*headpp != NULL; headpp = &(*headpp)->c_next) {
5130Sstevel@tonic-gate 		if (*headpp == cp) {
5140Sstevel@tonic-gate 			*headpp = cp->c_next;
5150Sstevel@tonic-gate 			cp->c_next = NULL;
5160Sstevel@tonic-gate #ifdef CFSDEBUG
5170Sstevel@tonic-gate 			found++;
5180Sstevel@tonic-gate #endif
5190Sstevel@tonic-gate 			break;
5200Sstevel@tonic-gate 		}
5210Sstevel@tonic-gate 	}
5220Sstevel@tonic-gate #ifdef CFSDEBUG
5230Sstevel@tonic-gate 	ASSERT(found);
5240Sstevel@tonic-gate #endif
5250Sstevel@tonic-gate }
5260Sstevel@tonic-gate 
5270Sstevel@tonic-gate /*
5280Sstevel@tonic-gate  * Add a cnode to the front of the fscache idle list.
5290Sstevel@tonic-gate  */
5300Sstevel@tonic-gate void
cachefs_cnode_idleadd(struct cnode * cp)5310Sstevel@tonic-gate cachefs_cnode_idleadd(struct cnode *cp)
5320Sstevel@tonic-gate {
5330Sstevel@tonic-gate 	fscache_t *fscp = C_TO_FSCACHE(cp);
5340Sstevel@tonic-gate 
5350Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&cp->c_statelock));
5360Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&fscp->fs_idlelock));
5370Sstevel@tonic-gate 
5380Sstevel@tonic-gate 	/* put cnode on the front of the idle list */
5390Sstevel@tonic-gate 	cp->c_idlefront = fscp->fs_idlefront;
5400Sstevel@tonic-gate 	cp->c_idleback =  NULL;
5410Sstevel@tonic-gate 
5420Sstevel@tonic-gate 	if (fscp->fs_idlefront)
5430Sstevel@tonic-gate 		fscp->fs_idlefront->c_idleback = cp;
5440Sstevel@tonic-gate 	else {
5450Sstevel@tonic-gate 		ASSERT(fscp->fs_idleback == NULL);
5460Sstevel@tonic-gate 		fscp->fs_idleback = cp;
5470Sstevel@tonic-gate 	}
5480Sstevel@tonic-gate 	fscp->fs_idlefront = cp;
5490Sstevel@tonic-gate 	fscp->fs_idlecnt++;
5500Sstevel@tonic-gate }
5510Sstevel@tonic-gate 
5520Sstevel@tonic-gate /*
5530Sstevel@tonic-gate  * Remove a cnode from the fscache idle list.
5540Sstevel@tonic-gate  */
5550Sstevel@tonic-gate void
cachefs_cnode_idlerem(struct cnode * cp)5560Sstevel@tonic-gate cachefs_cnode_idlerem(struct cnode *cp)
5570Sstevel@tonic-gate {
5580Sstevel@tonic-gate 	fscache_t *fscp = C_TO_FSCACHE(cp);
5590Sstevel@tonic-gate 
5600Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&cp->c_statelock));
5610Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&fscp->fs_idlelock));
5620Sstevel@tonic-gate 
5630Sstevel@tonic-gate 	if (cp->c_idlefront == NULL) {
5640Sstevel@tonic-gate 		ASSERT(fscp->fs_idleback == cp);
5650Sstevel@tonic-gate 		fscp->fs_idleback = cp->c_idleback;
5660Sstevel@tonic-gate 		if (fscp->fs_idleback != NULL)
5670Sstevel@tonic-gate 			fscp->fs_idleback->c_idlefront = NULL;
5680Sstevel@tonic-gate 	} else {
5690Sstevel@tonic-gate 		cp->c_idlefront->c_idleback = cp->c_idleback;
5700Sstevel@tonic-gate 	}
5710Sstevel@tonic-gate 
5720Sstevel@tonic-gate 	if (cp->c_idleback == NULL) {
5730Sstevel@tonic-gate 		ASSERT(fscp->fs_idlefront == cp);
5740Sstevel@tonic-gate 		fscp->fs_idlefront = cp->c_idlefront;
5750Sstevel@tonic-gate 		if (fscp->fs_idlefront != NULL)
5760Sstevel@tonic-gate 			fscp->fs_idlefront->c_idleback = NULL;
5770Sstevel@tonic-gate 	} else {
5780Sstevel@tonic-gate 		cp->c_idleback->c_idlefront = cp->c_idlefront;
5790Sstevel@tonic-gate 		cp->c_idleback = NULL;
5800Sstevel@tonic-gate 	}
5810Sstevel@tonic-gate 	cp->c_idlefront = NULL;
5820Sstevel@tonic-gate 	fscp->fs_idlecnt--;
5830Sstevel@tonic-gate 	ASSERT(fscp->fs_idlecnt >= 0);
5840Sstevel@tonic-gate }
5850Sstevel@tonic-gate 
5860Sstevel@tonic-gate /*
5870Sstevel@tonic-gate  * Search the cnode list of the input file group, looking for a cnode which
5880Sstevel@tonic-gate  * matches the supplied file ident fileno.
5890Sstevel@tonic-gate  *
5900Sstevel@tonic-gate  * Returns:
5910Sstevel@tonic-gate  *	*cpp = NULL, if no valid matching cnode is found
5920Sstevel@tonic-gate  *	*cpp = address of cnode with matching fileno, with c_statelock held
5930Sstevel@tonic-gate  *	return status is 0 if no cnode found, or if found & cookies match
5940Sstevel@tonic-gate  *	return status is 1 if a cnode was found, but the cookies don't match
5950Sstevel@tonic-gate  *
5960Sstevel@tonic-gate  * Note:  must grab the c_statelock for each cnode, or its state could
5970Sstevel@tonic-gate  * change while we're processing it.  Also, if a cnode is found, must return
5980Sstevel@tonic-gate  * with c_statelock still held, so that the cnode state cannot change until
5990Sstevel@tonic-gate  * the calling routine releases the lock.
6000Sstevel@tonic-gate  */
6010Sstevel@tonic-gate int
cachefs_cnode_find(filegrp_t * fgp,cfs_cid_t * cidp,fid_t * cookiep,struct cnode ** cpp,struct vnode * backvp,vattr_t * vap)6020Sstevel@tonic-gate cachefs_cnode_find(filegrp_t *fgp, cfs_cid_t *cidp, fid_t *cookiep,
6030Sstevel@tonic-gate     struct cnode **cpp, struct vnode *backvp, vattr_t *vap)
6040Sstevel@tonic-gate {
6050Sstevel@tonic-gate 	struct cnode *cp;
6060Sstevel@tonic-gate 	int badcookie = 0;
6070Sstevel@tonic-gate 	uint32_t is_nfsv4;
6080Sstevel@tonic-gate 
6090Sstevel@tonic-gate #ifdef CFSDEBUG
6100Sstevel@tonic-gate 	CFS_DEBUG(CFSDEBUG_CNODE)
6110Sstevel@tonic-gate 		cmn_err(CE_NOTE, "cachefs_cnode_find: fileno %llu fgp %p\n",
6120Sstevel@tonic-gate 		    (u_longlong_t)cidp->cid_fileno, (void *)fgp);
6130Sstevel@tonic-gate #endif
6140Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&fgp->fg_cnodelock));
6150Sstevel@tonic-gate 
6160Sstevel@tonic-gate 	*cpp = NULL;
6170Sstevel@tonic-gate 	is_nfsv4 = CFS_ISFS_BACKFS_NFSV4(fgp->fg_fscp);
6180Sstevel@tonic-gate 
6190Sstevel@tonic-gate 	/*
6200Sstevel@tonic-gate 	 * Cookie should be filled unless disconnected operation or
6210Sstevel@tonic-gate 	 * backfilesystem is NFSv4
6220Sstevel@tonic-gate 	 */
6230Sstevel@tonic-gate 	if (cookiep == NULL && !CFS_ISFS_SNR(fgp->fg_fscp) &&
6240Sstevel@tonic-gate 	    !CFS_ISFS_BACKFS_NFSV4(fgp->fg_fscp)) {
6250Sstevel@tonic-gate 		goto out;
6260Sstevel@tonic-gate 	}
6270Sstevel@tonic-gate 
6280Sstevel@tonic-gate 	for (cp = fgp->fg_cnodelist; cp != NULL; cp = cp->c_next) {
6290Sstevel@tonic-gate 		mutex_enter(&cp->c_statelock);
6300Sstevel@tonic-gate 
6310Sstevel@tonic-gate 		if ((cidp->cid_fileno != cp->c_id.cid_fileno &&
6320Sstevel@tonic-gate 			(is_nfsv4 == FALSE || cp->c_backvp != backvp)) ||
6330Sstevel@tonic-gate 		    (cp->c_flags & (CN_STALE | CN_DESTROY))) {
6340Sstevel@tonic-gate 			mutex_exit(&cp->c_statelock);
6350Sstevel@tonic-gate 			continue;
6360Sstevel@tonic-gate 		}
6370Sstevel@tonic-gate 
6380Sstevel@tonic-gate 		/*
6390Sstevel@tonic-gate 		 * Having found a non stale, non destroy pending cnode with
6400Sstevel@tonic-gate 		 * matching fileno, will be exiting the for loop, after
6410Sstevel@tonic-gate 		 * determining return status
6420Sstevel@tonic-gate 		 */
6430Sstevel@tonic-gate 		*cpp = cp;
6440Sstevel@tonic-gate 
6450Sstevel@tonic-gate 		if ((cookiep != NULL) &&
6460Sstevel@tonic-gate 		    ((cookiep->fid_len != cp->c_cookie.fid_len) ||
6470Sstevel@tonic-gate 		    (bcmp((caddr_t)cookiep->fid_data,
6480Sstevel@tonic-gate 		    (caddr_t)&cp->c_cookie.fid_data, cookiep->fid_len)) != 0)) {
6490Sstevel@tonic-gate #ifdef CFSDEBUG
6500Sstevel@tonic-gate 			CFS_DEBUG(CFSDEBUG_GENERAL) {
6510Sstevel@tonic-gate 				cmn_err(CE_NOTE,
6520Sstevel@tonic-gate 				    "cachefs: dup fileno %llu, cp %p\n",
6530Sstevel@tonic-gate 				    (u_longlong_t)cidp->cid_fileno, (void *)cp);
6540Sstevel@tonic-gate 			}
6550Sstevel@tonic-gate #endif
6560Sstevel@tonic-gate 			badcookie = 1;
6570Sstevel@tonic-gate 		}
6580Sstevel@tonic-gate 
6590Sstevel@tonic-gate 		/*
6600Sstevel@tonic-gate 		 * For NFSv4 since there is no fid, add a check to
6610Sstevel@tonic-gate 		 * ensure the backvp and vap matches that in the cnode.
6620Sstevel@tonic-gate 		 * If it doesn't then someone tried to use a stale cnode.
6630Sstevel@tonic-gate 		 */
6640Sstevel@tonic-gate 		if (is_nfsv4) {
6650Sstevel@tonic-gate 			if (backvp && backvp != cp->c_backvp ||
6660Sstevel@tonic-gate 			    vap && vap->va_type != cp->c_attr.va_type ||
6670Sstevel@tonic-gate 			    cidp->cid_fileno != cp->c_id.cid_fileno) {
6680Sstevel@tonic-gate 				CFS_DPRINT_BACKFS_NFSV4(C_TO_FSCACHE(cp),
6690Sstevel@tonic-gate 				("cachefs_cnode_find (nfsv4): stale cnode "
6700Sstevel@tonic-gate 				"cnode %p, backvp %p, new-backvp %p, vap %p "
6710Sstevel@tonic-gate 				"fileno=%llx cp-fileno=%llx\n",
6720Sstevel@tonic-gate 				cp, cp->c_backvp, backvp, vap,
6730Sstevel@tonic-gate 				cidp->cid_fileno, cp->c_id.cid_fileno));
6740Sstevel@tonic-gate 				badcookie = 1;
6750Sstevel@tonic-gate 			}
6760Sstevel@tonic-gate 		}
6770Sstevel@tonic-gate 		break;
6780Sstevel@tonic-gate 	}
6790Sstevel@tonic-gate out:
6800Sstevel@tonic-gate 
6810Sstevel@tonic-gate #ifdef CFSDEBUG
6820Sstevel@tonic-gate 	CFS_DEBUG(CFSDEBUG_CNODE)
6830Sstevel@tonic-gate 		cmn_err(CE_NOTE, "cachefs_cnode_find: cp %p\n", (void *)*cpp);
6840Sstevel@tonic-gate #endif
6850Sstevel@tonic-gate 	return (badcookie);
6860Sstevel@tonic-gate }
6870Sstevel@tonic-gate 
6880Sstevel@tonic-gate /*
6890Sstevel@tonic-gate  * We have to initialize the cnode contents. Fill in the contents from the
6900Sstevel@tonic-gate  * cache (attrcache file), from the info passed in, whatever it takes.
6910Sstevel@tonic-gate  */
6920Sstevel@tonic-gate static int
cachefs_cnode_init(cfs_cid_t * cidp,cnode_t * cp,fscache_t * fscp,filegrp_t * fgp,fid_t * cookiep,vattr_t * vap,vnode_t * backvp,int flag,cred_t * cr)6930Sstevel@tonic-gate cachefs_cnode_init(cfs_cid_t *cidp, cnode_t *cp, fscache_t *fscp,
6940Sstevel@tonic-gate     filegrp_t *fgp, fid_t *cookiep, vattr_t *vap, vnode_t *backvp,
6950Sstevel@tonic-gate     int flag, cred_t *cr)
6960Sstevel@tonic-gate {
6970Sstevel@tonic-gate 	int error = 0;
6980Sstevel@tonic-gate 	int slotfound;
6990Sstevel@tonic-gate 	vnode_t *vp;
7000Sstevel@tonic-gate 	int null_cookie;
7010Sstevel@tonic-gate 	cachefscache_t *cachep = fscp->fs_cache;
7020Sstevel@tonic-gate 
7030Sstevel@tonic-gate 	bzero(cp, sizeof (cnode_t));
7040Sstevel@tonic-gate 	cp->c_vnode = vn_alloc(KM_SLEEP);
7050Sstevel@tonic-gate 
7060Sstevel@tonic-gate 	vp = CTOV(cp);
7070Sstevel@tonic-gate 
7080Sstevel@tonic-gate 	vp->v_data = (caddr_t)cp;
7090Sstevel@tonic-gate 
7100Sstevel@tonic-gate 	rw_init(&cp->c_rwlock, NULL, RW_DEFAULT, NULL);
7110Sstevel@tonic-gate 	mutex_init(&cp->c_statelock, NULL, MUTEX_DEFAULT, NULL);
7120Sstevel@tonic-gate 	cv_init(&cp->c_popcv, NULL, CV_DEFAULT, NULL);
7130Sstevel@tonic-gate 	mutex_init(&cp->c_iomutex, NULL, MUTEX_DEFAULT, NULL);
7140Sstevel@tonic-gate 	cv_init(&cp->c_iocv, NULL, CV_DEFAULT, NULL);
7150Sstevel@tonic-gate 
7160Sstevel@tonic-gate 	vn_setops(vp, cachefs_getvnodeops());
7170Sstevel@tonic-gate 	cp->c_id = *cidp;
7180Sstevel@tonic-gate 	if (backvp != NULL) {
7190Sstevel@tonic-gate 		cp->c_backvp = backvp;
7200Sstevel@tonic-gate 		VN_HOLD(backvp);
7210Sstevel@tonic-gate 	}
7220Sstevel@tonic-gate 	cp->c_flags |= flag;
7230Sstevel@tonic-gate 	filegrp_hold(fgp);
7240Sstevel@tonic-gate 	cp->c_filegrp = fgp;
7250Sstevel@tonic-gate 	if (cookiep)
7260Sstevel@tonic-gate 		cp->c_cookie = *cookiep;
7270Sstevel@tonic-gate 	mutex_enter(&cp->c_statelock);
7280Sstevel@tonic-gate 
7290Sstevel@tonic-gate 	/*
7300Sstevel@tonic-gate 	 * if nocache is set then ignore anything cached for this file,
7310Sstevel@tonic-gate 	 * if nfsv4 flag is set, then create the cnode but don't do
7320Sstevel@tonic-gate 	 * any caching.
7330Sstevel@tonic-gate 	 */
7340Sstevel@tonic-gate 	if (cp->c_flags & CN_NOCACHE || CFS_ISFS_BACKFS_NFSV4(fscp)) {
7350Sstevel@tonic-gate 		/*
7360Sstevel@tonic-gate 		 * this case only happens while booting without a cache
7370Sstevel@tonic-gate 		 * or if NFSv4 is the backfilesystem
7380Sstevel@tonic-gate 		 */
7390Sstevel@tonic-gate 		ASSERT(!CFS_ISFS_SNR(fscp));
7400Sstevel@tonic-gate 		ASSERT(fscp->fs_cdconnected == CFS_CD_CONNECTED);
7410Sstevel@tonic-gate 		if (cookiep || CFS_ISFS_BACKFS_NFSV4(fscp)) {
7420Sstevel@tonic-gate 			error = CFSOP_INIT_COBJECT(fscp, cp, vap, cr);
7430Sstevel@tonic-gate 			if (error)
7440Sstevel@tonic-gate 				goto out;
7450Sstevel@tonic-gate 			cp->c_flags |= CN_UPDATED | CN_ALLOC_PENDING;
7460Sstevel@tonic-gate 			ASSERT(cp->c_attr.va_type != 0);
7470Sstevel@tonic-gate 			VN_SET_VFS_TYPE_DEV(vp, fscp->fs_cfsvfsp,
7480Sstevel@tonic-gate 			    cp->c_attr.va_type, cp->c_attr.va_rdev);
7490Sstevel@tonic-gate 			cachefs_cnode_setlocalstats(cp);
7500Sstevel@tonic-gate 		} else
7510Sstevel@tonic-gate 			error = ESTALE;
7520Sstevel@tonic-gate 		goto out;
7530Sstevel@tonic-gate 	}
7540Sstevel@tonic-gate 
7550Sstevel@tonic-gate 	/*
7560Sstevel@tonic-gate 	 * see if there's a slot for this filegrp/cid fileno
7570Sstevel@tonic-gate 	 * if not, and there's no cookie info, nothing can be done, but if
7580Sstevel@tonic-gate 	 * there's cookie data indicate we need to create a metadata slot.
7590Sstevel@tonic-gate 	 */
7600Sstevel@tonic-gate 	slotfound = cachefs_cid_inuse(cp->c_filegrp, cidp);
7610Sstevel@tonic-gate 	if (slotfound == 0) {
7620Sstevel@tonic-gate 		if (cookiep == NULL) {
7630Sstevel@tonic-gate 			error = ENOENT;
7640Sstevel@tonic-gate 			goto out;
7650Sstevel@tonic-gate 		}
7660Sstevel@tonic-gate 		cp->c_flags |= CN_ALLOC_PENDING;
7670Sstevel@tonic-gate 	} else {
7680Sstevel@tonic-gate 		/*
7690Sstevel@tonic-gate 		 * if a slot was found, then increment the slot in use count
7700Sstevel@tonic-gate 		 * and try to read the metadata.
7710Sstevel@tonic-gate 		 */
7720Sstevel@tonic-gate 		cp->c_filegrp->fg_header->ach_count++;
7730Sstevel@tonic-gate 		error = filegrp_read_metadata(cp->c_filegrp, cidp,
7740Sstevel@tonic-gate 		    &cp->c_metadata);
7750Sstevel@tonic-gate 	}
7760Sstevel@tonic-gate 	/*
7770Sstevel@tonic-gate 	 * if there wasn't a slot, or an attempt to read it results in ENOENT,
7780Sstevel@tonic-gate 	 * then init the cache object, create the vnode, etc...
7790Sstevel@tonic-gate 	 */
7800Sstevel@tonic-gate 	if ((slotfound == 0) || (error == ENOENT)) {
7810Sstevel@tonic-gate 		error = CFSOP_INIT_COBJECT(fscp, cp, vap, cr);
7820Sstevel@tonic-gate 		if (error)
7830Sstevel@tonic-gate 			goto out;
7840Sstevel@tonic-gate 		ASSERT(cp->c_attr.va_type != 0);
7850Sstevel@tonic-gate 		VN_SET_VFS_TYPE_DEV(vp, fscp->fs_cfsvfsp,
7860Sstevel@tonic-gate 		    cp->c_attr.va_type, cp->c_attr.va_rdev);
7870Sstevel@tonic-gate 		cp->c_metadata.md_rltype = CACHEFS_RL_NONE;
7880Sstevel@tonic-gate 	} else if (error == 0) {
7890Sstevel@tonic-gate 		/* slot found, no error occurred on the metadata read */
7900Sstevel@tonic-gate 		cp->c_size = cp->c_attr.va_size;
7910Sstevel@tonic-gate 
7920Sstevel@tonic-gate 		if ((cachep->c_flags & CACHE_CHECK_RLTYPE) &&
7930Sstevel@tonic-gate 		    (cp->c_metadata.md_rlno != 0) &&
7940Sstevel@tonic-gate 		    (cp->c_metadata.md_rltype == CACHEFS_RL_ACTIVE)) {
7950Sstevel@tonic-gate 			rl_entry_t rl, *rlp;
7960Sstevel@tonic-gate 
7970Sstevel@tonic-gate 			mutex_enter(&cachep->c_contentslock);
7980Sstevel@tonic-gate 			error = cachefs_rl_entry_get(cachep,
7990Sstevel@tonic-gate 			    cp->c_metadata.md_rlno, &rlp);
8000Sstevel@tonic-gate 			if (error) {
8010Sstevel@tonic-gate 				mutex_exit(&cachep->c_contentslock);
8020Sstevel@tonic-gate 				goto out;
8030Sstevel@tonic-gate 			}
8040Sstevel@tonic-gate 			rl = *rlp;
8050Sstevel@tonic-gate 			mutex_exit(&cachep->c_contentslock);
8060Sstevel@tonic-gate 			if (cp->c_metadata.md_rltype != rl.rl_current) {
8070Sstevel@tonic-gate 				cp->c_flags |= CN_UPDATED;
8080Sstevel@tonic-gate 				cp->c_metadata.md_rltype = rl.rl_current;
8090Sstevel@tonic-gate 			}
8100Sstevel@tonic-gate 		}
8110Sstevel@tonic-gate 
8120Sstevel@tonic-gate 		/*
8130Sstevel@tonic-gate 		 * If no cookie is specified, or if this is a local file,
8140Sstevel@tonic-gate 		 * accept the one in the metadata.
8150Sstevel@tonic-gate 		 */
8160Sstevel@tonic-gate 		null_cookie = 0;
8170Sstevel@tonic-gate 		if ((cookiep == NULL) || (cp->c_id.cid_flags & CFS_CID_LOCAL)) {
8180Sstevel@tonic-gate 			cookiep = &cp->c_metadata.md_cookie;
8190Sstevel@tonic-gate 			null_cookie = 1;
8200Sstevel@tonic-gate 		}
8210Sstevel@tonic-gate 
8220Sstevel@tonic-gate 		/* if cookies do not match, reset the metadata */
8230Sstevel@tonic-gate 		if ((cookiep->fid_len != cp->c_cookie.fid_len) ||
8240Sstevel@tonic-gate 		    (bcmp(&cookiep->fid_data, &cp->c_cookie.fid_data,
8250Sstevel@tonic-gate 			(size_t)cookiep->fid_len) != 0)) {
8260Sstevel@tonic-gate 			cp->c_cookie = *cookiep;
8270Sstevel@tonic-gate 			cp->c_flags |= CN_UPDATED;
8280Sstevel@tonic-gate 			cp->c_metadata.md_timestamp.tv_sec = 0;
8290Sstevel@tonic-gate 			/* clear all but the front file bit */
8300Sstevel@tonic-gate 			cp->c_metadata.md_flags &= MD_FILE;
8310Sstevel@tonic-gate 			error = CFSOP_INIT_COBJECT(fscp, cp, vap, cr);
8320Sstevel@tonic-gate 			ASSERT(cp->c_attr.va_type != 0);
8330Sstevel@tonic-gate 			VN_SET_VFS_TYPE_DEV(vp, fscp->fs_cfsvfsp,
8340Sstevel@tonic-gate 			    cp->c_attr.va_type, cp->c_attr.va_rdev);
8350Sstevel@tonic-gate 		}
8360Sstevel@tonic-gate 
8370Sstevel@tonic-gate 		/* else if the consistency type changed, fix it up */
8380Sstevel@tonic-gate 		else if (cp->c_metadata.md_consttype != fscp->fs_consttype) {
8390Sstevel@tonic-gate 			ASSERT(cp->c_attr.va_type != 0);
8400Sstevel@tonic-gate 			VN_SET_VFS_TYPE_DEV(vp, fscp->fs_cfsvfsp,
8410Sstevel@tonic-gate 			    cp->c_attr.va_type, cp->c_attr.va_rdev);
8420Sstevel@tonic-gate 			CFSOP_CONVERT_COBJECT(fscp, cp, cr);
8430Sstevel@tonic-gate 			if (!null_cookie) {
8440Sstevel@tonic-gate 				error = CFSOP_CHECK_COBJECT(fscp, cp,
8450Sstevel@tonic-gate 				    C_BACK_CHECK, cr);
8460Sstevel@tonic-gate 			}
8470Sstevel@tonic-gate 		}
8480Sstevel@tonic-gate 
8490Sstevel@tonic-gate 		/* else check the consistency of the data */
8500Sstevel@tonic-gate 		else {
8510Sstevel@tonic-gate 			ASSERT(cp->c_attr.va_type != 0);
8520Sstevel@tonic-gate 			VN_SET_VFS_TYPE_DEV(vp, fscp->fs_cfsvfsp,
8530Sstevel@tonic-gate 			    cp->c_attr.va_type, cp->c_attr.va_rdev);
8540Sstevel@tonic-gate 			if (!null_cookie) {
8550Sstevel@tonic-gate 				error = CFSOP_CHECK_COBJECT(fscp, cp, 0, cr);
8560Sstevel@tonic-gate 			}
8570Sstevel@tonic-gate 		}
8580Sstevel@tonic-gate 	} else {
8590Sstevel@tonic-gate 		goto out;
8600Sstevel@tonic-gate 	}
8610Sstevel@tonic-gate 	cachefs_cnode_setlocalstats(cp);
8620Sstevel@tonic-gate 
8630Sstevel@tonic-gate out:
8640Sstevel@tonic-gate 	mutex_exit(&cp->c_statelock);
8650Sstevel@tonic-gate 	if (error) {
8660Sstevel@tonic-gate 		if (cp->c_frontvp)
8670Sstevel@tonic-gate 			VN_RELE(cp->c_frontvp);
8680Sstevel@tonic-gate 		if (cp->c_backvp)
8690Sstevel@tonic-gate 			VN_RELE(cp->c_backvp);
8700Sstevel@tonic-gate 		if (cp->c_acldirvp)
8710Sstevel@tonic-gate 			VN_RELE(cp->c_acldirvp);
8720Sstevel@tonic-gate 		filegrp_rele(fgp);
8730Sstevel@tonic-gate 		rw_destroy(&cp->c_rwlock);
8740Sstevel@tonic-gate 		mutex_destroy(&cp->c_statelock);
8750Sstevel@tonic-gate 		cv_destroy(&cp->c_popcv);
8760Sstevel@tonic-gate 		mutex_destroy(&cp->c_iomutex);
8770Sstevel@tonic-gate 		cv_destroy(&cp->c_iocv);
8780Sstevel@tonic-gate 	}
8790Sstevel@tonic-gate 	return (error);
8800Sstevel@tonic-gate }
8810Sstevel@tonic-gate 
8820Sstevel@tonic-gate /*
8830Sstevel@tonic-gate  * Finds the cnode for the specified fileno and fid.
8840Sstevel@tonic-gate  * Creates the cnode if it does not exist.
8850Sstevel@tonic-gate  * The cnode is returned held.
8860Sstevel@tonic-gate  */
8870Sstevel@tonic-gate int
cachefs_cnode_make(cfs_cid_t * cidp,fscache_t * fscp,fid_t * cookiep,vattr_t * vap,vnode_t * backvp,cred_t * cr,int flag,cnode_t ** cpp)8880Sstevel@tonic-gate cachefs_cnode_make(cfs_cid_t *cidp, fscache_t *fscp, fid_t *cookiep,
8890Sstevel@tonic-gate 	vattr_t *vap, vnode_t *backvp, cred_t *cr, int flag, cnode_t **cpp)
8900Sstevel@tonic-gate {
8910Sstevel@tonic-gate 	struct cnode *cp;
8920Sstevel@tonic-gate 	int error;
8930Sstevel@tonic-gate 	struct filegrp *fgp;
8940Sstevel@tonic-gate 	struct cachefs_metadata *mdp;
8950Sstevel@tonic-gate 	fid_t cookie;
8960Sstevel@tonic-gate 
8970Sstevel@tonic-gate #ifdef CFSDEBUG
8980Sstevel@tonic-gate 	CFS_DEBUG(CFSDEBUG_CNODE)
8990Sstevel@tonic-gate 		printf("cachefs_cnode_make: ENTER fileno %llu\n",
9000Sstevel@tonic-gate 		    (u_longlong_t)cidp->cid_fileno);
9010Sstevel@tonic-gate #endif
9020Sstevel@tonic-gate 
9030Sstevel@tonic-gate 	/* get the file group that owns this file */
9040Sstevel@tonic-gate 	mutex_enter(&fscp->fs_fslock);
9050Sstevel@tonic-gate 	fgp = filegrp_list_find(fscp, cidp);
9060Sstevel@tonic-gate 	if (fgp == NULL) {
9070Sstevel@tonic-gate 		fgp = filegrp_create(fscp, cidp);
9080Sstevel@tonic-gate 		filegrp_list_add(fscp, fgp);
9090Sstevel@tonic-gate 	}
9100Sstevel@tonic-gate 	filegrp_hold(fgp);
9110Sstevel@tonic-gate 	mutex_exit(&fscp->fs_fslock);
9120Sstevel@tonic-gate 
9130Sstevel@tonic-gate 	/* grab the cnode list lock */
9140Sstevel@tonic-gate 	mutex_enter(&fgp->fg_cnodelock);
9150Sstevel@tonic-gate 
9160Sstevel@tonic-gate 	if ((fgp->fg_flags & CFS_FG_READ) == 0)
9170Sstevel@tonic-gate 		flag |= CN_NOCACHE;
9180Sstevel@tonic-gate 
9190Sstevel@tonic-gate 	error = 0;
9200Sstevel@tonic-gate 	cp = NULL;
9210Sstevel@tonic-gate 
9220Sstevel@tonic-gate 	/* look for the cnode on the cnode list */
9230Sstevel@tonic-gate 	error = cachefs_cnode_find(fgp, cidp, cookiep, &cp, backvp, vap);
9240Sstevel@tonic-gate 
9250Sstevel@tonic-gate 	/*
9260Sstevel@tonic-gate 	 * If there already is a cnode with this cid but a different cookie,
9270Sstevel@tonic-gate 	 * (or backvp) we're not going to be using the one we found.
9280Sstevel@tonic-gate 	 */
9290Sstevel@tonic-gate 	if (error && CFS_ISFS_BACKFS_NFSV4(fscp)) {
9300Sstevel@tonic-gate 		ASSERT(MUTEX_HELD(&cp->c_statelock));
9310Sstevel@tonic-gate 		cachefs_cnode_stale(cp);
9320Sstevel@tonic-gate 		mutex_exit(&cp->c_statelock);
9330Sstevel@tonic-gate 		cp = NULL;
9340Sstevel@tonic-gate 		error = 0;
9350Sstevel@tonic-gate 	} else if (error) {
9360Sstevel@tonic-gate 		ASSERT(cp);
9370Sstevel@tonic-gate 		ASSERT(cookiep);
9380Sstevel@tonic-gate 
9390Sstevel@tonic-gate 		mutex_exit(&cp->c_statelock);
9400Sstevel@tonic-gate 
9410Sstevel@tonic-gate 		/*
9420Sstevel@tonic-gate 		 * If backvp is NULL then someone tried to use
9430Sstevel@tonic-gate 		 * a stale cookie.
9440Sstevel@tonic-gate 		 */
9450Sstevel@tonic-gate 		if (backvp == NULL) {
9460Sstevel@tonic-gate 			mutex_exit(&fgp->fg_cnodelock);
9470Sstevel@tonic-gate 			error = ESTALE;
9480Sstevel@tonic-gate 			goto out;
9490Sstevel@tonic-gate 		}
9500Sstevel@tonic-gate 
9510Sstevel@tonic-gate 		/* verify the backvp */
9520Sstevel@tonic-gate 		error = cachefs_getcookie(backvp, &cookie, NULL, cr, TRUE);
9530Sstevel@tonic-gate 		if (error ||
9540Sstevel@tonic-gate 		    ((cookiep->fid_len != cookie.fid_len) ||
9550Sstevel@tonic-gate 		    (bcmp(&cookiep->fid_data, cookie.fid_data,
9560Sstevel@tonic-gate 			(size_t)cookiep->fid_len) != 0))) {
9570Sstevel@tonic-gate 			mutex_exit(&fgp->fg_cnodelock);
9580Sstevel@tonic-gate 			error = ESTALE;
9590Sstevel@tonic-gate 			goto out;
9600Sstevel@tonic-gate 		}
9610Sstevel@tonic-gate 
9620Sstevel@tonic-gate 		/* make the old cnode give up its front file resources */
9630Sstevel@tonic-gate 		VN_HOLD(CTOV(cp));
9640Sstevel@tonic-gate 		(void) cachefs_sync_metadata(cp);
9650Sstevel@tonic-gate 		mutex_enter(&cp->c_statelock);
9660Sstevel@tonic-gate 		mdp = &cp->c_metadata;
9670Sstevel@tonic-gate 		if (mdp->md_rlno) {
9680Sstevel@tonic-gate 			/* XXX sam: should this assert be NOCACHE? */
9690Sstevel@tonic-gate 			/* XXX sam: maybe we should handle NOFILL as no-op */
9700Sstevel@tonic-gate 			ASSERT((fscp->fs_cache->c_flags & CACHE_NOFILL) == 0);
9710Sstevel@tonic-gate 
9720Sstevel@tonic-gate 			/* if modified in the cache, move to lost+found */
9730Sstevel@tonic-gate 			if ((cp->c_attr.va_type == VREG) &&
9740Sstevel@tonic-gate 			    (cp->c_metadata.md_rltype == CACHEFS_RL_MODIFIED)) {
9750Sstevel@tonic-gate 				error = cachefs_cnode_lostfound(cp, NULL);
9760Sstevel@tonic-gate 				if (error) {
9770Sstevel@tonic-gate 					mutex_exit(&cp->c_statelock);
9780Sstevel@tonic-gate 					VN_RELE(CTOV(cp));
9790Sstevel@tonic-gate 					mutex_exit(&fgp->fg_cnodelock);
9800Sstevel@tonic-gate 					error = ESTALE;
9810Sstevel@tonic-gate 					goto out;
9820Sstevel@tonic-gate 				}
9830Sstevel@tonic-gate 			}
9840Sstevel@tonic-gate 
9850Sstevel@tonic-gate 			/* else nuke the front file */
9860Sstevel@tonic-gate 			else {
9870Sstevel@tonic-gate 				cachefs_cnode_stale(cp);
9880Sstevel@tonic-gate 			}
9890Sstevel@tonic-gate 		} else {
9900Sstevel@tonic-gate 			cachefs_cnode_stale(cp);
9910Sstevel@tonic-gate 		}
9920Sstevel@tonic-gate 		mutex_exit(&cp->c_statelock);
9930Sstevel@tonic-gate 		VN_RELE(CTOV(cp));
9940Sstevel@tonic-gate 		cp = NULL;
9950Sstevel@tonic-gate 		error = 0;
9960Sstevel@tonic-gate 	}
9970Sstevel@tonic-gate 
9980Sstevel@tonic-gate 
9990Sstevel@tonic-gate 	/* if the cnode does not exist */
10000Sstevel@tonic-gate 	if (cp == NULL) {
10010Sstevel@tonic-gate 		/* XXX should we drop all locks for this? */
10020Sstevel@tonic-gate 		cp = kmem_cache_alloc(cachefs_cnode_cache, KM_SLEEP);
10030Sstevel@tonic-gate 
10040Sstevel@tonic-gate 		error = cachefs_cnode_init(cidp, cp, fscp, fgp,
10050Sstevel@tonic-gate 		    cookiep, vap, backvp, flag, cr);
10060Sstevel@tonic-gate 		if (error) {
10070Sstevel@tonic-gate 			mutex_exit(&fgp->fg_cnodelock);
10080Sstevel@tonic-gate 			vn_free(cp->c_vnode);
10090Sstevel@tonic-gate 			kmem_cache_free(cachefs_cnode_cache, cp);
10100Sstevel@tonic-gate 			goto out;
10110Sstevel@tonic-gate 		}
10120Sstevel@tonic-gate 
10130Sstevel@tonic-gate 		if (cp->c_metadata.md_rlno &&
10140Sstevel@tonic-gate 		    (cp->c_metadata.md_rltype == CACHEFS_RL_GC) &&
10150Sstevel@tonic-gate 		    ((fscp->fs_cache->c_flags & CACHE_NOFILL) == 0)) {
10160Sstevel@tonic-gate #ifdef CFSDEBUG
10170Sstevel@tonic-gate 			cachefs_rlent_verify(fscp->fs_cache,
10180Sstevel@tonic-gate 			    CACHEFS_RL_GC, cp->c_metadata.md_rlno);
10190Sstevel@tonic-gate #endif /* CFSDEBUG */
10200Sstevel@tonic-gate 			cachefs_rlent_moveto(fscp->fs_cache,
10210Sstevel@tonic-gate 			    CACHEFS_RL_ACTIVE, cp->c_metadata.md_rlno,
10220Sstevel@tonic-gate 			    cp->c_metadata.md_frontblks);
10230Sstevel@tonic-gate 			cp->c_metadata.md_rltype = CACHEFS_RL_ACTIVE;
10240Sstevel@tonic-gate 			cp->c_flags |= CN_UPDATED;
10250Sstevel@tonic-gate 		}
10260Sstevel@tonic-gate 
10270Sstevel@tonic-gate 		cachefs_cnode_listadd(cp);
10280Sstevel@tonic-gate 		vn_exists(cp->c_vnode);
10290Sstevel@tonic-gate 		mutex_exit(&fgp->fg_cnodelock);
10300Sstevel@tonic-gate 		(void) fscache_cnodecnt(fscp, 1);
10310Sstevel@tonic-gate 	}
10320Sstevel@tonic-gate 
10330Sstevel@tonic-gate 	/* else if the cnode exists */
10340Sstevel@tonic-gate 	else {
10350Sstevel@tonic-gate 		VN_HOLD(CTOV(cp));
10360Sstevel@tonic-gate 
10370Sstevel@tonic-gate 		/* remove from idle list if on it */
10380Sstevel@tonic-gate 		if (cp->c_flags & CN_IDLE) {
10390Sstevel@tonic-gate 			cp->c_flags &= ~CN_IDLE;
10400Sstevel@tonic-gate 
10410Sstevel@tonic-gate 			mutex_enter(&fscp->fs_idlelock);
10420Sstevel@tonic-gate 			cachefs_cnode_idlerem(cp);
10430Sstevel@tonic-gate 			mutex_exit(&fscp->fs_idlelock);
10440Sstevel@tonic-gate 			VN_RELE(CTOV(cp));
10450Sstevel@tonic-gate 			cp->c_ipending = 0;
10460Sstevel@tonic-gate 		}
10470Sstevel@tonic-gate 		mutex_exit(&cp->c_statelock);
10480Sstevel@tonic-gate 		mutex_exit(&fgp->fg_cnodelock);
10490Sstevel@tonic-gate 	}
10500Sstevel@tonic-gate 
10510Sstevel@tonic-gate 	/*
10520Sstevel@tonic-gate 	 * Assertion to ensure the cnode matches
10530Sstevel@tonic-gate 	 * the backvp and attribute type information.
10540Sstevel@tonic-gate 	 */
10550Sstevel@tonic-gate 	ASSERT((CFS_ISFS_BACKFS_NFSV4(fscp) == 0) ||
10560Sstevel@tonic-gate 		((cp->c_backvp == backvp) &&
10570Sstevel@tonic-gate 		(cp->c_attr.va_type == vap->va_type)));
10580Sstevel@tonic-gate out:
10590Sstevel@tonic-gate 	*cpp = ((error == 0) ? cp : NULL);
10600Sstevel@tonic-gate 	filegrp_rele(fgp);
10610Sstevel@tonic-gate 
10620Sstevel@tonic-gate #ifdef CFSDEBUG
10630Sstevel@tonic-gate 	CFS_DEBUG(CFSDEBUG_CNODE)
10640Sstevel@tonic-gate 		printf("cachefs_cnode_make: EXIT cp %p, error %d\n",
10650Sstevel@tonic-gate 		    (void *)*cpp, error);
10660Sstevel@tonic-gate #endif
10670Sstevel@tonic-gate 	return (error);
10680Sstevel@tonic-gate }
10690Sstevel@tonic-gate 
10700Sstevel@tonic-gate /*
10710Sstevel@tonic-gate  * cachefs_cid_inuse()
10720Sstevel@tonic-gate  *
10730Sstevel@tonic-gate  * returns nonzero if a cid has any data in the cache; either a cnode
10740Sstevel@tonic-gate  * or metadata.
10750Sstevel@tonic-gate  */
10760Sstevel@tonic-gate 
10770Sstevel@tonic-gate int
cachefs_cid_inuse(filegrp_t * fgp,cfs_cid_t * cidp)10780Sstevel@tonic-gate cachefs_cid_inuse(filegrp_t *fgp, cfs_cid_t *cidp)
10790Sstevel@tonic-gate {
10800Sstevel@tonic-gate 	cnode_t *cp;
10810Sstevel@tonic-gate 	int status = 0;
10820Sstevel@tonic-gate 
10830Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&fgp->fg_cnodelock));
10840Sstevel@tonic-gate 
10850Sstevel@tonic-gate 	/*
10860Sstevel@tonic-gate 	 * Since we don't care about the cookie data, we don't care about any
10870Sstevel@tonic-gate 	 * status that find might return.
10880Sstevel@tonic-gate 	 */
10890Sstevel@tonic-gate 
10900Sstevel@tonic-gate 	cp = NULL;
10910Sstevel@tonic-gate 	(void) cachefs_cnode_find(fgp, cidp, NULL, &cp, NULL, NULL);
10920Sstevel@tonic-gate 	if (cp != NULL) {
10930Sstevel@tonic-gate 		mutex_exit(&cp->c_statelock);
10940Sstevel@tonic-gate 		status = 1;
10950Sstevel@tonic-gate 		return (status);
10960Sstevel@tonic-gate 	}
10970Sstevel@tonic-gate 
10980Sstevel@tonic-gate 	/*
10990Sstevel@tonic-gate 	 * Don't want to use filegrp_read_metadata, since it will return
11000Sstevel@tonic-gate 	 * ENOENT if the metadata slot exists but hasn't been written to yet.
11010Sstevel@tonic-gate 	 * That condition still counts as the slot (metadata) being in use.
11020Sstevel@tonic-gate 	 * Instead, as long as the filegrp attrcache has been created and
11030Sstevel@tonic-gate 	 * there's a slot assigned for this cid, then the metadata is in use.
11040Sstevel@tonic-gate 	 */
11050Sstevel@tonic-gate 	if (((fgp->fg_flags & CFS_FG_ALLOC_ATTR) == 0) &&
11060Sstevel@tonic-gate 	    (filegrp_cid_to_slot(fgp, cidp) != 0))
11070Sstevel@tonic-gate 		status = 1;
11080Sstevel@tonic-gate 
11090Sstevel@tonic-gate 	return (status);
11100Sstevel@tonic-gate }
11110Sstevel@tonic-gate 
11120Sstevel@tonic-gate /*
11130Sstevel@tonic-gate  * cachefs_fileno_inuse()
11140Sstevel@tonic-gate  *
11150Sstevel@tonic-gate  * returns nonzero if a fileno is known to the cache, as either a
11160Sstevel@tonic-gate  * local or a normal file.
11170Sstevel@tonic-gate  */
11180Sstevel@tonic-gate 
11190Sstevel@tonic-gate int
cachefs_fileno_inuse(fscache_t * fscp,ino64_t fileno)11200Sstevel@tonic-gate cachefs_fileno_inuse(fscache_t *fscp, ino64_t fileno)
11210Sstevel@tonic-gate {
11220Sstevel@tonic-gate 	cfs_cid_t cid;
11230Sstevel@tonic-gate 	filegrp_t *fgp;
11240Sstevel@tonic-gate 	int known = 0;
11250Sstevel@tonic-gate 
11260Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&fscp->fs_fslock));
11270Sstevel@tonic-gate 	cid.cid_fileno = fileno;
11280Sstevel@tonic-gate 
11290Sstevel@tonic-gate 	/* if there's no filegrp for this cid range, then there's no data */
11300Sstevel@tonic-gate 	fgp = filegrp_list_find(fscp, &cid);
11310Sstevel@tonic-gate 	if (fgp == NULL)
11320Sstevel@tonic-gate 		return (known);
11330Sstevel@tonic-gate 
11340Sstevel@tonic-gate 	filegrp_hold(fgp);
11350Sstevel@tonic-gate 	mutex_enter(&fgp->fg_cnodelock);
11360Sstevel@tonic-gate 
11370Sstevel@tonic-gate 	cid.cid_flags = CFS_CID_LOCAL;
11380Sstevel@tonic-gate 	if (cachefs_cid_inuse(fgp, &cid)) {
11390Sstevel@tonic-gate 		known = 1;
11400Sstevel@tonic-gate 		goto out;
11410Sstevel@tonic-gate 	}
11420Sstevel@tonic-gate 	cid.cid_flags = 0;
11430Sstevel@tonic-gate 	if (cachefs_cid_inuse(fgp, &cid))
11440Sstevel@tonic-gate 		known = 1;
11450Sstevel@tonic-gate out:
11460Sstevel@tonic-gate 	mutex_exit(&fgp->fg_cnodelock);
11470Sstevel@tonic-gate 	filegrp_rele(fgp);
11480Sstevel@tonic-gate 	return (known);
11490Sstevel@tonic-gate }
11500Sstevel@tonic-gate 
11510Sstevel@tonic-gate /*
11520Sstevel@tonic-gate  * Creates a cnode from an unused inode in the cache.
11530Sstevel@tonic-gate  * The cnode is returned held.
11540Sstevel@tonic-gate  */
11550Sstevel@tonic-gate int
cachefs_cnode_create(fscache_t * fscp,vattr_t * vap,int flag,cnode_t ** cpp)11560Sstevel@tonic-gate cachefs_cnode_create(fscache_t *fscp, vattr_t *vap, int flag, cnode_t **cpp)
11570Sstevel@tonic-gate {
11580Sstevel@tonic-gate 	struct cnode *cp;
11590Sstevel@tonic-gate 	int error, found;
11600Sstevel@tonic-gate 	struct filegrp *fgp;
11610Sstevel@tonic-gate 	cfs_cid_t cid, cid2;
11620Sstevel@tonic-gate 
11630Sstevel@tonic-gate 	ASSERT(CFS_ISFS_SNR(fscp));
11640Sstevel@tonic-gate 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
11650Sstevel@tonic-gate 
11660Sstevel@tonic-gate 	cid.cid_flags = CFS_CID_LOCAL;
11670Sstevel@tonic-gate 	cid2.cid_flags = 0;
11680Sstevel@tonic-gate 
11690Sstevel@tonic-gate 	/* find an unused local file in the cache */
11700Sstevel@tonic-gate 	for (;;) {
11710Sstevel@tonic-gate 		mutex_enter(&fscp->fs_fslock);
11720Sstevel@tonic-gate 
11730Sstevel@tonic-gate 		/* make sure we did not wrap */
11740Sstevel@tonic-gate 		fscp->fs_info.fi_localfileno++;
11750Sstevel@tonic-gate 		if (fscp->fs_info.fi_localfileno == 0)
11760Sstevel@tonic-gate 			fscp->fs_info.fi_localfileno = 3;
11770Sstevel@tonic-gate 		cid.cid_fileno = fscp->fs_info.fi_localfileno;
11780Sstevel@tonic-gate 		fscp->fs_flags |= CFS_FS_DIRTYINFO;
11790Sstevel@tonic-gate 
11800Sstevel@tonic-gate 		/* avoid fileno conflict in non-local space */
11810Sstevel@tonic-gate 		cid2.cid_fileno = cid.cid_fileno;
11820Sstevel@tonic-gate 		fgp = filegrp_list_find(fscp, &cid2);
11830Sstevel@tonic-gate 		if (fgp != NULL) {
11840Sstevel@tonic-gate 			filegrp_hold(fgp);
11850Sstevel@tonic-gate 			mutex_enter(&fgp->fg_cnodelock);
11860Sstevel@tonic-gate 			found = cachefs_cid_inuse(fgp, &cid2);
11870Sstevel@tonic-gate 			mutex_exit(&fgp->fg_cnodelock);
11880Sstevel@tonic-gate 			filegrp_rele(fgp);
11890Sstevel@tonic-gate 			if (found) {
11900Sstevel@tonic-gate 				mutex_exit(&fscp->fs_fslock);
11910Sstevel@tonic-gate 				continue;
11920Sstevel@tonic-gate 			}
11930Sstevel@tonic-gate 		}
11940Sstevel@tonic-gate 
11950Sstevel@tonic-gate 		/* get the file group that owns this fileno */
11960Sstevel@tonic-gate 		fgp = filegrp_list_find(fscp, &cid);
11970Sstevel@tonic-gate 		if (fgp == NULL) {
11980Sstevel@tonic-gate 			fgp = filegrp_create(fscp, &cid);
11990Sstevel@tonic-gate 			filegrp_list_add(fscp, fgp);
12000Sstevel@tonic-gate 		}
12010Sstevel@tonic-gate 
12020Sstevel@tonic-gate 		/* see if there is any room left in this file group */
12030Sstevel@tonic-gate 		mutex_enter(&fgp->fg_mutex);
12040Sstevel@tonic-gate 		if (fgp->fg_header &&
12050Sstevel@tonic-gate 		    (fgp->fg_header->ach_count ==
12060Sstevel@tonic-gate 		    fscp->fs_info.fi_fgsize)) {
12070Sstevel@tonic-gate 			/* no more room, set up for the next file group */
12080Sstevel@tonic-gate 			fscp->fs_info.fi_localfileno = fgp->fg_id.cid_fileno +
12090Sstevel@tonic-gate 			    fscp->fs_info.fi_fgsize;
12100Sstevel@tonic-gate 			mutex_exit(&fgp->fg_mutex);
12110Sstevel@tonic-gate 			mutex_exit(&fscp->fs_fslock);
12120Sstevel@tonic-gate 			continue;
12130Sstevel@tonic-gate 		}
12140Sstevel@tonic-gate 		mutex_exit(&fgp->fg_mutex);
12150Sstevel@tonic-gate 
12160Sstevel@tonic-gate 		filegrp_hold(fgp);
12170Sstevel@tonic-gate 		mutex_exit(&fscp->fs_fslock);
12180Sstevel@tonic-gate 
12190Sstevel@tonic-gate 		ASSERT((fgp->fg_flags &
12200Sstevel@tonic-gate 		    (CFS_FG_READ | CFS_FG_WRITE)) ==
12210Sstevel@tonic-gate 		    (CFS_FG_READ | CFS_FG_WRITE));
12220Sstevel@tonic-gate 
12230Sstevel@tonic-gate 		/* grab the cnode list lock */
12240Sstevel@tonic-gate 		mutex_enter(&fgp->fg_cnodelock);
12250Sstevel@tonic-gate 
12260Sstevel@tonic-gate 		if ((fgp->fg_flags & CFS_FG_READ) == 0)
12270Sstevel@tonic-gate 			flag |= CN_NOCACHE;
12280Sstevel@tonic-gate 
12290Sstevel@tonic-gate 		/* keep looking if a cnode or metadata exist for this fileno */
12300Sstevel@tonic-gate 		if (cachefs_cid_inuse(fgp, &cid)) {
12310Sstevel@tonic-gate 			mutex_exit(&fgp->fg_cnodelock);
12320Sstevel@tonic-gate 			filegrp_rele(fgp);
12330Sstevel@tonic-gate #ifdef CFSDEBUG
12340Sstevel@tonic-gate 			CFS_DEBUG(CFSDEBUG_CNODE)
12350Sstevel@tonic-gate 				cmn_err(CE_NOTE, "cachefs_cnode_create: "
12360Sstevel@tonic-gate 				    "fileno %llu exists.\n",
12370Sstevel@tonic-gate 				    (u_longlong_t)cid.cid_fileno);
12380Sstevel@tonic-gate #endif
12390Sstevel@tonic-gate 			continue;
12400Sstevel@tonic-gate 		}
12410Sstevel@tonic-gate 		break;
12420Sstevel@tonic-gate 	}
12430Sstevel@tonic-gate 
12440Sstevel@tonic-gate 	vap->va_nodeid = cid.cid_fileno;
12450Sstevel@tonic-gate 
12460Sstevel@tonic-gate 	/* create space for the cnode */
12470Sstevel@tonic-gate 	cp = kmem_cache_alloc(cachefs_cnode_cache, KM_SLEEP);
12480Sstevel@tonic-gate 
12490Sstevel@tonic-gate 	/* set up the cnode */
12500Sstevel@tonic-gate 	error = cachefs_cnode_init(&cid, cp, fscp, fgp,
12510Sstevel@tonic-gate 	    &cp->c_cookie, vap, NULL, flag, kcred);
12520Sstevel@tonic-gate 	if (error) {
12530Sstevel@tonic-gate 		mutex_exit(&fgp->fg_cnodelock);
12540Sstevel@tonic-gate 		vn_free(cp->c_vnode);
12550Sstevel@tonic-gate 		kmem_cache_free(cachefs_cnode_cache, cp);
12560Sstevel@tonic-gate 		goto out;
12570Sstevel@tonic-gate 	}
12580Sstevel@tonic-gate 
12590Sstevel@tonic-gate 	/* save copy of fileno that is returned to the user */
12600Sstevel@tonic-gate 	cp->c_metadata.md_flags |= MD_LOCALFILENO;
12610Sstevel@tonic-gate 	cp->c_metadata.md_localfileno = cid.cid_fileno;
12620Sstevel@tonic-gate 	cp->c_flags |= CN_UPDATED;
12630Sstevel@tonic-gate 
12640Sstevel@tonic-gate 	cachefs_cnode_listadd(cp);
12650Sstevel@tonic-gate 	mutex_exit(&fgp->fg_cnodelock);
12660Sstevel@tonic-gate 	(void) fscache_cnodecnt(fscp, 1);
12670Sstevel@tonic-gate 
12680Sstevel@tonic-gate out:
12690Sstevel@tonic-gate 	*cpp = ((error == 0) ? cp : NULL);
12700Sstevel@tonic-gate 	filegrp_rele(fgp);
12710Sstevel@tonic-gate 	return (error);
12720Sstevel@tonic-gate }
12730Sstevel@tonic-gate 
12740Sstevel@tonic-gate /*
12750Sstevel@tonic-gate  * Moves the cnode to its new location in the cache.
12760Sstevel@tonic-gate  * Before calling this routine other steps must be taken
12770Sstevel@tonic-gate  * to ensure that other file system routines that operate
12780Sstevel@tonic-gate  * on cnodes do not run.
12790Sstevel@tonic-gate  */
12800Sstevel@tonic-gate void
cachefs_cnode_move(cnode_t * cp)12810Sstevel@tonic-gate cachefs_cnode_move(cnode_t *cp)
12820Sstevel@tonic-gate {
12830Sstevel@tonic-gate 	fscache_t *fscp = C_TO_FSCACHE(cp);
12840Sstevel@tonic-gate 	cfs_cid_t cid;
12850Sstevel@tonic-gate 	filegrp_t *fgp;
12860Sstevel@tonic-gate 	filegrp_t *ofgp = cp->c_filegrp;
12870Sstevel@tonic-gate 	struct cachefs_metadata *mdp;
12880Sstevel@tonic-gate 	cnode_t *xcp;
12890Sstevel@tonic-gate 	char oname[CFS_FRONTFILE_NAME_SIZE];
12900Sstevel@tonic-gate 	char nname[CFS_FRONTFILE_NAME_SIZE];
12910Sstevel@tonic-gate 	int ffnuke = 0;
12920Sstevel@tonic-gate 	int error;
12930Sstevel@tonic-gate 
12940Sstevel@tonic-gate 	ASSERT(CFS_ISFS_SNR(fscp));
12950Sstevel@tonic-gate 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
12960Sstevel@tonic-gate 	ASSERT(cp->c_id.cid_flags & CFS_CID_LOCAL);
12970Sstevel@tonic-gate 	ASSERT(cp->c_attr.va_nodeid != 0);
12980Sstevel@tonic-gate 
12990Sstevel@tonic-gate 	/* construct the cid of the new file location */
13000Sstevel@tonic-gate 	cid.cid_fileno = cp->c_attr.va_nodeid;
13010Sstevel@tonic-gate 	cid.cid_flags = 0;
13020Sstevel@tonic-gate 
13030Sstevel@tonic-gate 	/* see if there already is a file occupying our slot */
13040Sstevel@tonic-gate 	error = cachefs_cnode_make(&cid, fscp, NULL, NULL, NULL, kcred,
13050Sstevel@tonic-gate 	    0, &xcp);
13060Sstevel@tonic-gate 	if (error == 0) {
13070Sstevel@tonic-gate 		mutex_enter(&xcp->c_statelock);
13080Sstevel@tonic-gate 		cachefs_cnode_stale(xcp);
13090Sstevel@tonic-gate 		mutex_exit(&xcp->c_statelock);
13100Sstevel@tonic-gate 		VN_RELE(CTOV(xcp));
13110Sstevel@tonic-gate 		xcp = NULL;
13120Sstevel@tonic-gate 		error = 0;
13130Sstevel@tonic-gate 	}
13140Sstevel@tonic-gate 
13150Sstevel@tonic-gate 	/* get the file group that this file is moving to */
13160Sstevel@tonic-gate 	mutex_enter(&fscp->fs_fslock);
13170Sstevel@tonic-gate 	fgp = filegrp_list_find(fscp, &cid);
13180Sstevel@tonic-gate 	if (fgp == NULL) {
13190Sstevel@tonic-gate 		fgp = filegrp_create(fscp, &cid);
13200Sstevel@tonic-gate 		filegrp_list_add(fscp, fgp);
13210Sstevel@tonic-gate 	}
13220Sstevel@tonic-gate 	filegrp_hold(fgp);
13230Sstevel@tonic-gate 	mutex_exit(&fscp->fs_fslock);
13240Sstevel@tonic-gate 
13250Sstevel@tonic-gate 	/* XXX fix to not have to create metadata to hold rl slot */
13260Sstevel@tonic-gate 	/* get a metadata slot in the new file group */
13270Sstevel@tonic-gate 	if (fgp->fg_flags & CFS_FG_ALLOC_ATTR) {
13280Sstevel@tonic-gate 		(void) filegrp_allocattr(fgp);
13290Sstevel@tonic-gate 	}
13300Sstevel@tonic-gate 	/* XXX can fix create_metadata to call allocattr if necessary? */
13310Sstevel@tonic-gate 	error = filegrp_create_metadata(fgp, &cp->c_metadata, &cid);
13320Sstevel@tonic-gate 	if (error)
13330Sstevel@tonic-gate 		ffnuke = 1;
13340Sstevel@tonic-gate 	if ((ffnuke == 0) && filegrp_ffhold(fgp))
13350Sstevel@tonic-gate 		ffnuke = 1;
13360Sstevel@tonic-gate 
13370Sstevel@tonic-gate 	/* move the front file to the new file group */
13380Sstevel@tonic-gate 	if ((ffnuke == 0) && (cp->c_metadata.md_flags & MD_FILE)) {
13390Sstevel@tonic-gate 		make_ascii_name(&cp->c_id, oname);
13400Sstevel@tonic-gate 		make_ascii_name(&cid, nname);
13410Sstevel@tonic-gate 		error = VOP_RENAME(ofgp->fg_dirvp, oname, fgp->fg_dirvp,
1342*5331Samw 			nname, kcred, NULL, 0);
13430Sstevel@tonic-gate 		if (error) {
13440Sstevel@tonic-gate 			ffnuke = 1;
13450Sstevel@tonic-gate #ifdef CFSDEBUG
13460Sstevel@tonic-gate 			if (error != ENOSPC) {
13470Sstevel@tonic-gate 				CFS_DEBUG(CFSDEBUG_CNODE)
13480Sstevel@tonic-gate 					printf("cachefs: cnode_move "
13490Sstevel@tonic-gate 					    "1: error %d\n", error);
13500Sstevel@tonic-gate 			}
13510Sstevel@tonic-gate #endif
13520Sstevel@tonic-gate 		}
13530Sstevel@tonic-gate 	}
13540Sstevel@tonic-gate 
13550Sstevel@tonic-gate 	/* remove the file from the old file group */
13560Sstevel@tonic-gate 	mutex_enter(&ofgp->fg_cnodelock);
13570Sstevel@tonic-gate 	mutex_enter(&cp->c_statelock);
13580Sstevel@tonic-gate 	if (cp->c_frontvp) {
13590Sstevel@tonic-gate 		VN_RELE(cp->c_frontvp);
13600Sstevel@tonic-gate 		cp->c_frontvp = NULL;
13610Sstevel@tonic-gate 	}
13620Sstevel@tonic-gate 	if (cp->c_acldirvp) {
13630Sstevel@tonic-gate 		VN_RELE(cp->c_acldirvp);
13640Sstevel@tonic-gate 		cp->c_acldirvp = NULL;
13650Sstevel@tonic-gate 	}
13660Sstevel@tonic-gate 	mdp = &cp->c_metadata;
13670Sstevel@tonic-gate 	if (mdp->md_rlno) {
13680Sstevel@tonic-gate 		if (ffnuke) {
13690Sstevel@tonic-gate 			cachefs_removefrontfile(mdp, &cp->c_id, ofgp);
13700Sstevel@tonic-gate 			cachefs_rlent_moveto(fscp->fs_cache,
13710Sstevel@tonic-gate 			    CACHEFS_RL_FREE, mdp->md_rlno, 0);
13720Sstevel@tonic-gate 			mdp->md_rlno = 0;
13730Sstevel@tonic-gate 			mdp->md_rltype = CACHEFS_RL_NONE;
13740Sstevel@tonic-gate 		} else {
13750Sstevel@tonic-gate 			filegrp_ffrele(ofgp);
13760Sstevel@tonic-gate 		}
13770Sstevel@tonic-gate 	}
13780Sstevel@tonic-gate 	if (ffnuke)
13790Sstevel@tonic-gate 		mdp->md_flags &= ~MD_PACKED;
13800Sstevel@tonic-gate 	if ((cp->c_flags & CN_ALLOC_PENDING) == 0) {
13810Sstevel@tonic-gate 		(void) filegrp_destroy_metadata(ofgp, &cp->c_id);
13820Sstevel@tonic-gate 		cp->c_flags |= CN_ALLOC_PENDING;
13830Sstevel@tonic-gate 	}
13840Sstevel@tonic-gate 	cachefs_cnode_listrem(cp);
13850Sstevel@tonic-gate 	cp->c_filegrp = NULL;
13860Sstevel@tonic-gate 	mutex_exit(&cp->c_statelock);
13870Sstevel@tonic-gate 	mutex_exit(&ofgp->fg_cnodelock);
13880Sstevel@tonic-gate 
13890Sstevel@tonic-gate 	/* add the cnode to the new file group */
13900Sstevel@tonic-gate 	mutex_enter(&fgp->fg_cnodelock);
13910Sstevel@tonic-gate 	mutex_enter(&cp->c_statelock);
13920Sstevel@tonic-gate 	cp->c_id = cid;
13930Sstevel@tonic-gate 	cp->c_filegrp = fgp;
13940Sstevel@tonic-gate 	cp->c_flags |= CN_UPDATED;
13950Sstevel@tonic-gate 	mutex_exit(&cp->c_statelock);
13960Sstevel@tonic-gate 	cachefs_cnode_listadd(cp);
13970Sstevel@tonic-gate 	if (mdp->md_rlno)
13980Sstevel@tonic-gate 		cachefs_rl_changefileno(fscp->fs_cache, mdp->md_rlno,
13990Sstevel@tonic-gate 		    cp->c_id.cid_fileno);
14000Sstevel@tonic-gate 	mutex_exit(&fgp->fg_cnodelock);
14010Sstevel@tonic-gate 
14020Sstevel@tonic-gate 	filegrp_rele(ofgp);
14030Sstevel@tonic-gate }
14040Sstevel@tonic-gate 
14050Sstevel@tonic-gate /*
14060Sstevel@tonic-gate  * Syncs out the specified cnode.
14070Sstevel@tonic-gate  * Only called via cnode_traverse from fscache_sync
14080Sstevel@tonic-gate  */
14090Sstevel@tonic-gate void
cachefs_cnode_sync(cnode_t * cp)14100Sstevel@tonic-gate cachefs_cnode_sync(cnode_t *cp)
14110Sstevel@tonic-gate {
14120Sstevel@tonic-gate 	vnode_t *vp = CTOV(cp);
14130Sstevel@tonic-gate 	int error = 0;
14140Sstevel@tonic-gate 	fscache_t *fscp = C_TO_FSCACHE(cp);
14150Sstevel@tonic-gate 	int held = 0;
14160Sstevel@tonic-gate 
14170Sstevel@tonic-gate 	if (cp->c_flags & (CN_STALE | CN_DESTROY))
14180Sstevel@tonic-gate 		return;
14190Sstevel@tonic-gate 
14200Sstevel@tonic-gate 	if (fscp->fs_backvfsp && fscp->fs_backvfsp->vfs_flag & VFS_RDONLY)
14210Sstevel@tonic-gate 		return;
14220Sstevel@tonic-gate 
14230Sstevel@tonic-gate 	for (;;) {
14240Sstevel@tonic-gate 		/* get (or renew) access to the file system */
14250Sstevel@tonic-gate 		if (held) {
14260Sstevel@tonic-gate 			cachefs_cd_release(fscp);
14270Sstevel@tonic-gate 			held = 0;
14280Sstevel@tonic-gate 		}
14290Sstevel@tonic-gate 		/*
14300Sstevel@tonic-gate 		 * Getting file system access for reading is really cheating.
14310Sstevel@tonic-gate 		 * However we are getting called from sync so we do not
14320Sstevel@tonic-gate 		 * want to hang up if the cachefsd is not running.
14330Sstevel@tonic-gate 		 */
14340Sstevel@tonic-gate 		error = cachefs_cd_access(fscp, 0, 0);
14350Sstevel@tonic-gate 		if (error)
14360Sstevel@tonic-gate 			break;
14370Sstevel@tonic-gate 		held = 1;
14380Sstevel@tonic-gate 
14390Sstevel@tonic-gate 		/* if a regular file, write out the pages */
14400Sstevel@tonic-gate 		if ((vp->v_type == VREG) && vn_has_cached_data(vp)) {
14410Sstevel@tonic-gate 			ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
14420Sstevel@tonic-gate 			error = cachefs_putpage_common(vp, (offset_t)0,
14430Sstevel@tonic-gate 			    0, 0, kcred);
14440Sstevel@tonic-gate 			if (CFS_TIMEOUT(fscp, error)) {
14450Sstevel@tonic-gate 				if (fscp->fs_cdconnected == CFS_CD_CONNECTED) {
14460Sstevel@tonic-gate 					cachefs_cd_release(fscp);
14470Sstevel@tonic-gate 					held = 0;
14480Sstevel@tonic-gate 					cachefs_cd_timedout(fscp);
14490Sstevel@tonic-gate 					continue;
14500Sstevel@tonic-gate 				} else {
14510Sstevel@tonic-gate 					/* cannot push, give up */
14520Sstevel@tonic-gate 					break;
14530Sstevel@tonic-gate 				}
14540Sstevel@tonic-gate 			}
14550Sstevel@tonic-gate 
14560Sstevel@tonic-gate 			/* clear the cnode error if putpage worked */
14570Sstevel@tonic-gate 			if ((error == 0) && cp->c_error) {
14580Sstevel@tonic-gate 				mutex_enter(&cp->c_statelock);
14590Sstevel@tonic-gate 				cp->c_error = 0;
14600Sstevel@tonic-gate 				mutex_exit(&cp->c_statelock);
14610Sstevel@tonic-gate 			}
14620Sstevel@tonic-gate 
14630Sstevel@tonic-gate 			if (error)
14640Sstevel@tonic-gate 				break;
14650Sstevel@tonic-gate 		}
14660Sstevel@tonic-gate 
14670Sstevel@tonic-gate 		/* if connected, sync the backvp */
14680Sstevel@tonic-gate 		if ((fscp->fs_cdconnected == CFS_CD_CONNECTED) &&
14690Sstevel@tonic-gate 		    cp->c_backvp) {
14700Sstevel@tonic-gate 			mutex_enter(&cp->c_statelock);
14710Sstevel@tonic-gate 			if (cp->c_backvp) {
1472*5331Samw 				error = VOP_FSYNC(cp->c_backvp, FSYNC, kcred,
1473*5331Samw 				    NULL);
14740Sstevel@tonic-gate 				if (CFS_TIMEOUT(fscp, error)) {
14750Sstevel@tonic-gate 					mutex_exit(&cp->c_statelock);
14760Sstevel@tonic-gate 					cachefs_cd_release(fscp);
14770Sstevel@tonic-gate 					held = 0;
14780Sstevel@tonic-gate 					cachefs_cd_timedout(fscp);
14790Sstevel@tonic-gate 					continue;
14800Sstevel@tonic-gate 				} else if (error && (error != EINTR))
14810Sstevel@tonic-gate 					cp->c_error = error;
14820Sstevel@tonic-gate 			}
14830Sstevel@tonic-gate 			mutex_exit(&cp->c_statelock);
14840Sstevel@tonic-gate 		}
14850Sstevel@tonic-gate 
14860Sstevel@tonic-gate 		/* sync the metadata and the front file to the front fs */
14870Sstevel@tonic-gate 		(void) cachefs_sync_metadata(cp);
14880Sstevel@tonic-gate 		break;
14890Sstevel@tonic-gate 	}
14900Sstevel@tonic-gate 
14910Sstevel@tonic-gate 	if (held)
14920Sstevel@tonic-gate 		cachefs_cd_release(fscp);
14930Sstevel@tonic-gate }
14940Sstevel@tonic-gate 
14950Sstevel@tonic-gate /*
14960Sstevel@tonic-gate  * Moves the specified file to the lost+found directory for the
14970Sstevel@tonic-gate  * cached file system.
14980Sstevel@tonic-gate  * Invalidates cached data and attributes.
14990Sstevel@tonic-gate  * Returns 0 or an error if could not perform operation.
15000Sstevel@tonic-gate  */
15010Sstevel@tonic-gate int
cachefs_cnode_lostfound(cnode_t * cp,char * rname)15020Sstevel@tonic-gate cachefs_cnode_lostfound(cnode_t *cp, char *rname)
15030Sstevel@tonic-gate {
15040Sstevel@tonic-gate 	int error = 0;
15050Sstevel@tonic-gate 	fscache_t *fscp;
15060Sstevel@tonic-gate 	cachefscache_t *cachep;
15070Sstevel@tonic-gate 	char oname[CFS_FRONTFILE_NAME_SIZE];
15080Sstevel@tonic-gate 	filegrp_t *fgp;
15090Sstevel@tonic-gate 	char *namep, *strp;
15100Sstevel@tonic-gate 	char *namebuf = NULL;
15110Sstevel@tonic-gate 	vnode_t *nvp;
15120Sstevel@tonic-gate 	int index;
15130Sstevel@tonic-gate 	int len;
15140Sstevel@tonic-gate 
15150Sstevel@tonic-gate 	fscp = C_TO_FSCACHE(cp);
15160Sstevel@tonic-gate 	cachep = fscp->fs_cache;
15170Sstevel@tonic-gate 
15180Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&cp->c_statelock));
15190Sstevel@tonic-gate 	ASSERT((cachep->c_flags & (CACHE_NOCACHE|CACHE_NOFILL)) == 0);
15200Sstevel@tonic-gate 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
15210Sstevel@tonic-gate 
15220Sstevel@tonic-gate 	fgp = cp->c_filegrp;
15230Sstevel@tonic-gate 
15240Sstevel@tonic-gate 	/* set up the file group if necessary */
15250Sstevel@tonic-gate 	if (fgp->fg_flags & CFS_FG_ALLOC_ATTR) {
15260Sstevel@tonic-gate 		error = filegrp_allocattr(fgp);
15270Sstevel@tonic-gate 		if (error)
15280Sstevel@tonic-gate 			goto out;
15290Sstevel@tonic-gate 	}
15300Sstevel@tonic-gate 	ASSERT(fgp->fg_dirvp);
15310Sstevel@tonic-gate 
15320Sstevel@tonic-gate 	namebuf = cachefs_kmem_alloc(MAXNAMELEN * 2, KM_SLEEP);
15330Sstevel@tonic-gate 
15340Sstevel@tonic-gate 	if ((cp->c_attr.va_type != VREG) ||
15350Sstevel@tonic-gate 	    (cp->c_metadata.md_rltype != CACHEFS_RL_MODIFIED) ||
15360Sstevel@tonic-gate 	    ((cp->c_metadata.md_flags & MD_POPULATED) == 0) ||
15370Sstevel@tonic-gate 	    ((cp->c_metadata.md_flags & MD_FILE) == 0) ||
15380Sstevel@tonic-gate 	    (cp->c_metadata.md_rlno == 0)) {
15390Sstevel@tonic-gate #ifdef CFSDEBUG
15400Sstevel@tonic-gate 		CFS_DEBUG(CFSDEBUG_CNODE)
15410Sstevel@tonic-gate 			printf("cachefs_cnode_lostfound cp %p cannot save\n",
15420Sstevel@tonic-gate 			    (void *)cp);
15430Sstevel@tonic-gate #endif
15440Sstevel@tonic-gate 		error = EINVAL;
15450Sstevel@tonic-gate 		goto out;
15460Sstevel@tonic-gate 	}
15470Sstevel@tonic-gate 
15480Sstevel@tonic-gate 	/* lock out other users of the lost+found directory */
15490Sstevel@tonic-gate 	mutex_enter(&cachep->c_contentslock);
15500Sstevel@tonic-gate 
15510Sstevel@tonic-gate 	/* find a name we can use in lost+found */
15520Sstevel@tonic-gate 	if (rname)
15530Sstevel@tonic-gate 		namep = rname;
15540Sstevel@tonic-gate 	else
15550Sstevel@tonic-gate 		namep = "lostfile";
15560Sstevel@tonic-gate 	error = VOP_LOOKUP(cachep->c_lostfoundvp, namep, &nvp,
1557*5331Samw 	    NULL, 0, NULL, kcred, NULL, NULL, NULL);
15580Sstevel@tonic-gate 	if (error == 0)
15590Sstevel@tonic-gate 		VN_RELE(nvp);
15600Sstevel@tonic-gate 	if (error != ENOENT) {
15610Sstevel@tonic-gate #define		MAXTRIES 1000
15620Sstevel@tonic-gate 		strp = namep;
15630Sstevel@tonic-gate 		for (index = 0; index < MAXTRIES; index++) {
15640Sstevel@tonic-gate 			(void) sprintf(namebuf, "%s.%" PRIx64, strp,
15650Sstevel@tonic-gate 			    gethrestime_sec() * cp->c_id.cid_fileno * index);
15660Sstevel@tonic-gate 			len = (int)strlen(namebuf) + 1;
15670Sstevel@tonic-gate 			if (len > MAXNAMELEN)
15680Sstevel@tonic-gate 				namep = &namebuf[len - MAXNAMELEN];
15690Sstevel@tonic-gate 			else
15700Sstevel@tonic-gate 				namep = namebuf;
15710Sstevel@tonic-gate 			error = VOP_LOOKUP(cachep->c_lostfoundvp, namep, &nvp,
1572*5331Samw 			    NULL, 0, NULL, kcred, NULL, NULL, NULL);
15730Sstevel@tonic-gate 			if (error == 0)
15740Sstevel@tonic-gate 				VN_RELE(nvp);
15750Sstevel@tonic-gate 			if (error == ENOENT)
15760Sstevel@tonic-gate 				break;
15770Sstevel@tonic-gate 		}
15780Sstevel@tonic-gate 		if (index == MAXTRIES) {
15790Sstevel@tonic-gate 			error = EIO;
15800Sstevel@tonic-gate 			mutex_exit(&cachep->c_contentslock);
15810Sstevel@tonic-gate 			goto out;
15820Sstevel@tonic-gate 		}
15830Sstevel@tonic-gate 	}
15840Sstevel@tonic-gate 
15850Sstevel@tonic-gate 	/* get the name of the front file */
15860Sstevel@tonic-gate 	make_ascii_name(&cp->c_id, oname);
15870Sstevel@tonic-gate 
15880Sstevel@tonic-gate 	/* rename the file into the lost+found directory */
15890Sstevel@tonic-gate 	error = VOP_RENAME(fgp->fg_dirvp, oname, cachep->c_lostfoundvp,
1590*5331Samw 	    namep, kcred, NULL, 0);
15910Sstevel@tonic-gate 	if (error) {
15920Sstevel@tonic-gate 		mutex_exit(&cachep->c_contentslock);
15930Sstevel@tonic-gate 		goto out;
15940Sstevel@tonic-gate 	}
15950Sstevel@tonic-gate 	mutex_exit(&cachep->c_contentslock);
15960Sstevel@tonic-gate 
15970Sstevel@tonic-gate 	/* copy out the new name */
15980Sstevel@tonic-gate 	if (rname)
15990Sstevel@tonic-gate 		(void) strcpy(rname, namep);
16000Sstevel@tonic-gate 
16010Sstevel@tonic-gate out:
16020Sstevel@tonic-gate 	/* clean up */
16030Sstevel@tonic-gate 	cachefs_cnode_stale(cp);
16040Sstevel@tonic-gate 
16050Sstevel@tonic-gate 	if (namebuf)
16060Sstevel@tonic-gate 		cachefs_kmem_free(namebuf, MAXNAMELEN * 2);
16070Sstevel@tonic-gate 
16080Sstevel@tonic-gate #if 0 /* XXX until we can put filesystem in read-only mode */
16090Sstevel@tonic-gate 	if (error) {
16100Sstevel@tonic-gate 		/* XXX put file system in read-only mode */
16110Sstevel@tonic-gate 	}
16120Sstevel@tonic-gate #endif
16130Sstevel@tonic-gate 
16140Sstevel@tonic-gate 	return (error);
16150Sstevel@tonic-gate }
16160Sstevel@tonic-gate 
16170Sstevel@tonic-gate /*
16180Sstevel@tonic-gate  * Traverses the list of cnodes on the fscache and calls the
16190Sstevel@tonic-gate  * specified routine with the held cnode.
16200Sstevel@tonic-gate  */
16210Sstevel@tonic-gate void
cachefs_cnode_traverse(fscache_t * fscp,void (* routinep)(cnode_t *))16220Sstevel@tonic-gate cachefs_cnode_traverse(fscache_t *fscp, void (*routinep)(cnode_t *))
16230Sstevel@tonic-gate {
16240Sstevel@tonic-gate 	filegrp_t *fgp, *ofgp;
16250Sstevel@tonic-gate 	cnode_t *cp, *ocp;
16260Sstevel@tonic-gate 	int index;
16270Sstevel@tonic-gate 
16280Sstevel@tonic-gate 	/* lock the fscache while we traverse the file groups */
16290Sstevel@tonic-gate 	mutex_enter(&fscp->fs_fslock);
16300Sstevel@tonic-gate 
16310Sstevel@tonic-gate 	/* for each bucket of file groups */
16320Sstevel@tonic-gate 	for (index = 0; index < CFS_FS_FGP_BUCKET_SIZE; index++) {
16330Sstevel@tonic-gate 		ofgp = NULL;
16340Sstevel@tonic-gate 
16350Sstevel@tonic-gate 		/* for each file group in a bucket */
16360Sstevel@tonic-gate 		for (fgp = fscp->fs_filegrp[index];
16370Sstevel@tonic-gate 		    fgp != NULL;
16380Sstevel@tonic-gate 		    fgp = fgp->fg_next) {
16390Sstevel@tonic-gate 
16400Sstevel@tonic-gate 			/* hold the file group */
16410Sstevel@tonic-gate 			filegrp_hold(fgp);
16420Sstevel@tonic-gate 
16430Sstevel@tonic-gate 			/* drop fscache lock so others can use it */
16440Sstevel@tonic-gate 			mutex_exit(&fscp->fs_fslock);
16450Sstevel@tonic-gate 
16460Sstevel@tonic-gate 			/* drop hold on previous file group */
16470Sstevel@tonic-gate 			if (ofgp)
16480Sstevel@tonic-gate 				filegrp_rele(ofgp);
16490Sstevel@tonic-gate 			ofgp = fgp;
16500Sstevel@tonic-gate 
16510Sstevel@tonic-gate 			/* lock the cnode list while we traverse it */
16520Sstevel@tonic-gate 			mutex_enter(&fgp->fg_cnodelock);
16530Sstevel@tonic-gate 			ocp = NULL;
16540Sstevel@tonic-gate 
16550Sstevel@tonic-gate 			/* for each cnode in this file group */
16560Sstevel@tonic-gate 			for (cp = fgp->fg_cnodelist;
16570Sstevel@tonic-gate 			    cp != NULL;
16580Sstevel@tonic-gate 			    cp = cp->c_next) {
16590Sstevel@tonic-gate 
16600Sstevel@tonic-gate 				/* hold the cnode */
16610Sstevel@tonic-gate 				VN_HOLD(CTOV(cp));
16620Sstevel@tonic-gate 
16630Sstevel@tonic-gate 				/* drop cnode list lock so others can use it */
16640Sstevel@tonic-gate 				mutex_exit(&fgp->fg_cnodelock);
16650Sstevel@tonic-gate 
16660Sstevel@tonic-gate 				/* drop hold on previous cnode */
16670Sstevel@tonic-gate 				if (ocp) {
16680Sstevel@tonic-gate 					VN_RELE(CTOV(ocp));
16690Sstevel@tonic-gate 				}
16700Sstevel@tonic-gate 				ocp = cp;
16710Sstevel@tonic-gate 
16720Sstevel@tonic-gate 				/*
16730Sstevel@tonic-gate 				 * Execute routine for this cnode.
16740Sstevel@tonic-gate 				 * At this point no locks are held.
16750Sstevel@tonic-gate 				 */
16760Sstevel@tonic-gate 				(routinep)(cp);
16770Sstevel@tonic-gate 
1678*5331Samw 				/* reacquire the cnode list lock */
16790Sstevel@tonic-gate 				mutex_enter(&fgp->fg_cnodelock);
16800Sstevel@tonic-gate 			}
16810Sstevel@tonic-gate 
16820Sstevel@tonic-gate 			/* drop cnode list lock */
16830Sstevel@tonic-gate 			mutex_exit(&fgp->fg_cnodelock);
16840Sstevel@tonic-gate 
16850Sstevel@tonic-gate 			/* drop hold on last cnode */
16860Sstevel@tonic-gate 			if (ocp) {
16870Sstevel@tonic-gate 				VN_RELE(CTOV(ocp));
16880Sstevel@tonic-gate 			}
16890Sstevel@tonic-gate 
1690*5331Samw 			/* reacquire the fscache lock */
16910Sstevel@tonic-gate 			mutex_enter(&fscp->fs_fslock);
16920Sstevel@tonic-gate 		}
16930Sstevel@tonic-gate 
16940Sstevel@tonic-gate 		/* drop hold on last file group */
16950Sstevel@tonic-gate 		if (ofgp)
16960Sstevel@tonic-gate 			filegrp_rele(ofgp);
16970Sstevel@tonic-gate 	}
16980Sstevel@tonic-gate 	mutex_exit(&fscp->fs_fslock);
16990Sstevel@tonic-gate }
17000Sstevel@tonic-gate 
17010Sstevel@tonic-gate void
cachefs_cnode_disable_caching(struct cnode * cp)17020Sstevel@tonic-gate cachefs_cnode_disable_caching(struct cnode *cp)
17030Sstevel@tonic-gate {
17040Sstevel@tonic-gate 	mutex_enter(&cp->c_statelock);
17050Sstevel@tonic-gate 	cp->c_flags |= CN_NOCACHE;
17060Sstevel@tonic-gate 	if (cp->c_frontvp != NULL) {
17070Sstevel@tonic-gate 		VN_RELE(cp->c_frontvp);
17080Sstevel@tonic-gate 		cp->c_frontvp = NULL;
17090Sstevel@tonic-gate 	}
17100Sstevel@tonic-gate 	mutex_exit(&cp->c_statelock);
17110Sstevel@tonic-gate }
17120Sstevel@tonic-gate 
17130Sstevel@tonic-gate #define	TIMEMATCH(a, b)	((a)->tv_sec == (b)->tv_sec && \
17140Sstevel@tonic-gate 	(a)->tv_nsec == (b)->tv_nsec)
17150Sstevel@tonic-gate 
17160Sstevel@tonic-gate static void
cnode_enable_caching(struct cnode * cp)17170Sstevel@tonic-gate cnode_enable_caching(struct cnode *cp)
17180Sstevel@tonic-gate {
17190Sstevel@tonic-gate 	struct vnode *iovp;
17200Sstevel@tonic-gate 	struct filegrp *fgp;
17210Sstevel@tonic-gate 	struct cachefs_metadata md;
17220Sstevel@tonic-gate 	cachefscache_t *cachep = C_TO_FSCACHE(cp)->fs_cache;
17230Sstevel@tonic-gate 	int error;
17240Sstevel@tonic-gate 
17250Sstevel@tonic-gate 	ASSERT((cachep->c_flags & (CACHE_NOFILL | CACHE_NOCACHE)) == 0);
17260Sstevel@tonic-gate 	ASSERT(CFS_ISFS_BACKFS_NFSV4(C_TO_FSCACHE(cp)) == 0);
17270Sstevel@tonic-gate 
17280Sstevel@tonic-gate 	iovp = NULL;
17290Sstevel@tonic-gate 	if (CTOV(cp)->v_type == VREG)
17300Sstevel@tonic-gate 		iovp = cp->c_backvp;
17310Sstevel@tonic-gate 	if (iovp) {
17320Sstevel@tonic-gate 		(void) VOP_PUTPAGE(iovp, (offset_t)0,
1733*5331Samw 		    (uint_t)0, B_INVAL, kcred, NULL);
17340Sstevel@tonic-gate 	}
17350Sstevel@tonic-gate 	mutex_enter(&cp->c_statelock);
17360Sstevel@tonic-gate 	if (cp->c_backvp) {
17370Sstevel@tonic-gate 		VN_RELE(cp->c_backvp);
17380Sstevel@tonic-gate 		cp->c_backvp = NULL;
17390Sstevel@tonic-gate 	}
17400Sstevel@tonic-gate 	fgp = cp->c_filegrp;
17410Sstevel@tonic-gate 	ASSERT(fgp);
17420Sstevel@tonic-gate 	error = filegrp_read_metadata(fgp, &cp->c_id, &md);
17430Sstevel@tonic-gate 	if (error == 0) {
17440Sstevel@tonic-gate 		if ((cachep->c_flags & CACHE_CHECK_RLTYPE) &&
17450Sstevel@tonic-gate 		    (md.md_rlno != 0) &&
17460Sstevel@tonic-gate 		    (md.md_rltype == CACHEFS_RL_ACTIVE)) {
17470Sstevel@tonic-gate 			rl_entry_t *rlp, rl;
17480Sstevel@tonic-gate 
17490Sstevel@tonic-gate 			mutex_enter(&cachep->c_contentslock);
17500Sstevel@tonic-gate 			error = cachefs_rl_entry_get(cachep, md.md_rlno, &rlp);
17510Sstevel@tonic-gate 			if (error) {
17520Sstevel@tonic-gate 				mutex_exit(&cachep->c_contentslock);
17530Sstevel@tonic-gate 				goto out;
17540Sstevel@tonic-gate 			}
17550Sstevel@tonic-gate 
17560Sstevel@tonic-gate 			rl = *rlp;
17570Sstevel@tonic-gate 			mutex_exit(&cachep->c_contentslock);
17580Sstevel@tonic-gate 
17590Sstevel@tonic-gate 			if (rl.rl_current != md.md_rltype) {
17600Sstevel@tonic-gate 				md.md_rltype = rl.rl_current;
17610Sstevel@tonic-gate 				cp->c_flags |= CN_UPDATED;
17620Sstevel@tonic-gate 			}
17630Sstevel@tonic-gate 		}
17640Sstevel@tonic-gate 
17650Sstevel@tonic-gate 		/*
17660Sstevel@tonic-gate 		 * A rudimentary consistency check
17670Sstevel@tonic-gate 		 * here.  If the cookie and mtime
17680Sstevel@tonic-gate 		 * from the cnode match those from the
17690Sstevel@tonic-gate 		 * cache metadata, we assume for now that
17700Sstevel@tonic-gate 		 * the cached data is OK.
17710Sstevel@tonic-gate 		 */
17720Sstevel@tonic-gate 		if (bcmp(&md.md_cookie.fid_data, &cp->c_cookie.fid_data,
17730Sstevel@tonic-gate 			(size_t)cp->c_cookie.fid_len) == 0 &&
17740Sstevel@tonic-gate 		    TIMEMATCH(&cp->c_attr.va_mtime, &md.md_vattr.va_mtime)) {
17750Sstevel@tonic-gate 			cp->c_metadata = md;
17760Sstevel@tonic-gate 		} else {
17770Sstevel@tonic-gate 			/*
17780Sstevel@tonic-gate 			 * Here we're skeptical about the validity of
17790Sstevel@tonic-gate 			 * the front file.
17800Sstevel@tonic-gate 			 * We'll keep the attributes already present in
17810Sstevel@tonic-gate 			 * the cnode, and bring along the parts of the
17820Sstevel@tonic-gate 			 * metadata that we need to eventually nuke this
17830Sstevel@tonic-gate 			 * bogus front file -- in inactive or getfrontfile,
17840Sstevel@tonic-gate 			 * whichever comes first...
17850Sstevel@tonic-gate 			 */
17860Sstevel@tonic-gate 			if (cp->c_frontvp != NULL) {
17870Sstevel@tonic-gate 				VN_RELE(cp->c_frontvp);
17880Sstevel@tonic-gate 				cp->c_frontvp = NULL;
17890Sstevel@tonic-gate 			}
17900Sstevel@tonic-gate 			cp->c_metadata.md_flags = md.md_flags;
17910Sstevel@tonic-gate 			cp->c_metadata.md_flags |= MD_NEEDATTRS;
17920Sstevel@tonic-gate 			cp->c_metadata.md_rlno = md.md_rlno;
17930Sstevel@tonic-gate 			cp->c_metadata.md_rltype = md.md_rltype;
17940Sstevel@tonic-gate 			cp->c_metadata.md_consttype = md.md_consttype;
17950Sstevel@tonic-gate 			cp->c_metadata.md_fid = md.md_fid;
17960Sstevel@tonic-gate 			cp->c_metadata.md_frontblks = md.md_frontblks;
17970Sstevel@tonic-gate 			cp->c_metadata.md_timestamp.tv_sec = 0;
17980Sstevel@tonic-gate 			cp->c_metadata.md_timestamp.tv_nsec = 0;
17990Sstevel@tonic-gate 			bzero(&cp->c_metadata.md_allocinfo,
18000Sstevel@tonic-gate 			    cp->c_metadata.md_allocents *
18010Sstevel@tonic-gate 			    sizeof (struct cachefs_allocmap));
18020Sstevel@tonic-gate 			cp->c_metadata.md_allocents = 0;
18030Sstevel@tonic-gate 			cp->c_metadata.md_flags &= ~MD_POPULATED;
18040Sstevel@tonic-gate 			if ((cp->c_metadata.md_rlno != 0) &&
18050Sstevel@tonic-gate 			    (cp->c_metadata.md_rltype == CACHEFS_RL_PACKED)) {
18060Sstevel@tonic-gate 				cachefs_rlent_moveto(cachep,
18070Sstevel@tonic-gate 				    CACHEFS_RL_PACKED_PENDING,
18080Sstevel@tonic-gate 				    cp->c_metadata.md_rlno,
18090Sstevel@tonic-gate 				    cp->c_metadata.md_frontblks);
18100Sstevel@tonic-gate 				cp->c_metadata.md_rltype =
18110Sstevel@tonic-gate 				    CACHEFS_RL_PACKED_PENDING;
18120Sstevel@tonic-gate 			}
18130Sstevel@tonic-gate 
18140Sstevel@tonic-gate 			cp->c_flags |= CN_UPDATED;
18150Sstevel@tonic-gate #ifdef CFSDEBUG
18160Sstevel@tonic-gate 			CFS_DEBUG(CFSDEBUG_GENERAL) {
18170Sstevel@tonic-gate 				printf(
18180Sstevel@tonic-gate 				    "fileno %lld ignores cached data due "
18190Sstevel@tonic-gate 				    "to cookie and/or mtime mismatch\n",
18200Sstevel@tonic-gate 				    (longlong_t)cp->c_id.cid_fileno);
18210Sstevel@tonic-gate 			}
18220Sstevel@tonic-gate #endif
18230Sstevel@tonic-gate 		}
18240Sstevel@tonic-gate 		if (cp->c_metadata.md_rltype == CACHEFS_RL_GC) {
18250Sstevel@tonic-gate 			cachefs_rlent_moveto(cachep, CACHEFS_RL_ACTIVE,
18260Sstevel@tonic-gate 			    cp->c_metadata.md_rlno,
18270Sstevel@tonic-gate 			    cp->c_metadata.md_frontblks);
18280Sstevel@tonic-gate 			cp->c_metadata.md_rltype = CACHEFS_RL_ACTIVE;
18290Sstevel@tonic-gate 			cp->c_flags |= CN_UPDATED;
18300Sstevel@tonic-gate 		}
18310Sstevel@tonic-gate 	}
18320Sstevel@tonic-gate 
18330Sstevel@tonic-gate out:
18340Sstevel@tonic-gate 	cp->c_flags &= ~CN_NOCACHE;
18350Sstevel@tonic-gate 	mutex_exit(&cp->c_statelock);
18360Sstevel@tonic-gate 
18370Sstevel@tonic-gate 	(void) cachefs_pack_common(CTOV(cp), kcred);
18380Sstevel@tonic-gate }
18390Sstevel@tonic-gate 
18400Sstevel@tonic-gate void
cachefs_enable_caching(struct fscache * fscp)18410Sstevel@tonic-gate cachefs_enable_caching(struct fscache *fscp)
18420Sstevel@tonic-gate {
18430Sstevel@tonic-gate 
18440Sstevel@tonic-gate 	/*
18450Sstevel@tonic-gate 	 * This function is only called when a remount occurs,
18460Sstevel@tonic-gate 	 * with "nocache" and "nofill" options configured
18470Sstevel@tonic-gate 	 * (currently these aren't supported). Since this
18480Sstevel@tonic-gate 	 * function can write into the cache, make sure that
18490Sstevel@tonic-gate 	 * its not in use with NFSv4.
18500Sstevel@tonic-gate 	 */
18510Sstevel@tonic-gate 	if (CFS_ISFS_BACKFS_NFSV4(fscp))
18520Sstevel@tonic-gate 		return;
18530Sstevel@tonic-gate 
18540Sstevel@tonic-gate 	/*
18550Sstevel@tonic-gate 	 * set up file groups so we can read them.  Note that general
18560Sstevel@tonic-gate 	 * users (makecfsnode) will *not* start using them (i.e., all
18570Sstevel@tonic-gate 	 * newly created cnodes will be NOCACHE)
18580Sstevel@tonic-gate 	 * until we "enable_caching_rw" below.
18590Sstevel@tonic-gate 	 */
18600Sstevel@tonic-gate 	mutex_enter(&fscp->fs_fslock);
18610Sstevel@tonic-gate 	filegrp_list_enable_caching_ro(fscp);
18620Sstevel@tonic-gate 	mutex_exit(&fscp->fs_fslock);
18630Sstevel@tonic-gate 
18640Sstevel@tonic-gate 	cachefs_cnode_traverse(fscp, cnode_enable_caching);
18650Sstevel@tonic-gate 
18660Sstevel@tonic-gate 	/* enable general use of the filegrps */
18670Sstevel@tonic-gate 	mutex_enter(&fscp->fs_fslock);
18680Sstevel@tonic-gate 	filegrp_list_enable_caching_rw(fscp);
18690Sstevel@tonic-gate 	mutex_exit(&fscp->fs_fslock);
18700Sstevel@tonic-gate }
18710Sstevel@tonic-gate 
18720Sstevel@tonic-gate /*
18730Sstevel@tonic-gate  * This function makes a cnode stale by performing the following tasks:
18740Sstevel@tonic-gate  *	1) remove the front file
18750Sstevel@tonic-gate  *	2) Remove any resource file entries
18760Sstevel@tonic-gate  *	3) Remove any metadata entry from the attrcache file
18770Sstevel@tonic-gate  * 	4) Set the stale bit in the cnode flags field
18780Sstevel@tonic-gate  */
18790Sstevel@tonic-gate void
cachefs_cnode_stale(cnode_t * cp)18800Sstevel@tonic-gate cachefs_cnode_stale(cnode_t *cp)
18810Sstevel@tonic-gate {
18820Sstevel@tonic-gate 	fscache_t *fscp = C_TO_FSCACHE(cp);
18830Sstevel@tonic-gate 	struct cachefs_metadata *mdp;
18840Sstevel@tonic-gate 
18850Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&cp->c_statelock));
18860Sstevel@tonic-gate 
18870Sstevel@tonic-gate 	/*
18880Sstevel@tonic-gate 	 * Remove a metadata entry if the file exists
18890Sstevel@tonic-gate 	 */
18900Sstevel@tonic-gate 	mdp = &cp->c_metadata;
18910Sstevel@tonic-gate 	if (mdp->md_rlno) {
18920Sstevel@tonic-gate 
18930Sstevel@tonic-gate 		ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
18940Sstevel@tonic-gate 
18950Sstevel@tonic-gate 		/*
18960Sstevel@tonic-gate 		 * destroy the frontfile
18970Sstevel@tonic-gate 		 */
18980Sstevel@tonic-gate 		cachefs_removefrontfile(mdp, &cp->c_id, cp->c_filegrp);
18990Sstevel@tonic-gate 		/*
19000Sstevel@tonic-gate 		 * Remove resource file entry
19010Sstevel@tonic-gate 		 */
19020Sstevel@tonic-gate 		cachefs_rlent_moveto(fscp->fs_cache, CACHEFS_RL_FREE,
19030Sstevel@tonic-gate 		    mdp->md_rlno, 0);
19040Sstevel@tonic-gate 		mdp->md_rlno = 0;
19050Sstevel@tonic-gate 		mdp->md_rltype = CACHEFS_RL_NONE;
19060Sstevel@tonic-gate 	}
19070Sstevel@tonic-gate 
19080Sstevel@tonic-gate 	/*
19090Sstevel@tonic-gate 	 * Remove attrcache metadata
19100Sstevel@tonic-gate 	 */
19110Sstevel@tonic-gate 	if (CFS_ISFS_BACKFS_NFSV4(fscp) == 0)
19120Sstevel@tonic-gate 		(void) filegrp_destroy_metadata(cp->c_filegrp, &cp->c_id);
19130Sstevel@tonic-gate 	mdp->md_flags = 0;
19140Sstevel@tonic-gate 
19150Sstevel@tonic-gate 	if (cp->c_frontvp) {
19160Sstevel@tonic-gate 		VN_RELE(cp->c_frontvp);
19170Sstevel@tonic-gate 		cp->c_frontvp = NULL;
19180Sstevel@tonic-gate 	}
19190Sstevel@tonic-gate 
19200Sstevel@tonic-gate 	/*
19210Sstevel@tonic-gate 	 * For NFSv4 need to hang on to the backvp until vn_rele()
19220Sstevel@tonic-gate 	 * frees this cnode.
19230Sstevel@tonic-gate 	 */
19240Sstevel@tonic-gate 	if (cp->c_backvp && !CFS_ISFS_BACKFS_NFSV4(fscp)) {
19250Sstevel@tonic-gate 		VN_RELE(cp->c_backvp);
19260Sstevel@tonic-gate 		cp->c_backvp = NULL;
19270Sstevel@tonic-gate 	}
19280Sstevel@tonic-gate 	if (cp->c_acldirvp) {
19290Sstevel@tonic-gate 		VN_RELE(cp->c_acldirvp);
19300Sstevel@tonic-gate 		cp->c_acldirvp = NULL;
19310Sstevel@tonic-gate 	}
19320Sstevel@tonic-gate 
19330Sstevel@tonic-gate 	cp->c_flags |= CN_STALE | CN_ALLOC_PENDING | CN_NOCACHE;
19340Sstevel@tonic-gate }
19350Sstevel@tonic-gate 
19360Sstevel@tonic-gate /*
19370Sstevel@tonic-gate  * Sets up the local attributes in the metadata from the attributes.
19380Sstevel@tonic-gate  */
19390Sstevel@tonic-gate void
cachefs_cnode_setlocalstats(cnode_t * cp)19400Sstevel@tonic-gate cachefs_cnode_setlocalstats(cnode_t *cp)
19410Sstevel@tonic-gate {
19420Sstevel@tonic-gate 	fscache_t *fscp = C_TO_FSCACHE(cp);
19430Sstevel@tonic-gate 	cachefs_metadata_t *mdp = &cp->c_metadata;
19440Sstevel@tonic-gate 
19450Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&cp->c_statelock));
19460Sstevel@tonic-gate 
19470Sstevel@tonic-gate 	/* allow over writing of local attributes if a remount occurred */
19480Sstevel@tonic-gate 	if (fscp->fs_info.fi_resettimes != mdp->md_resettimes) {
19490Sstevel@tonic-gate 		mdp->md_flags &= ~(MD_LOCALCTIME | MD_LOCALMTIME);
19500Sstevel@tonic-gate 		mdp->md_resettimes = fscp->fs_info.fi_resettimes;
19510Sstevel@tonic-gate 	}
19520Sstevel@tonic-gate 	if (fscp->fs_info.fi_resetfileno != mdp->md_resetfileno) {
19530Sstevel@tonic-gate 		mdp->md_flags &= ~MD_LOCALFILENO;
19540Sstevel@tonic-gate 		mdp->md_resetfileno = fscp->fs_info.fi_resetfileno;
19550Sstevel@tonic-gate 	}
19560Sstevel@tonic-gate 
19570Sstevel@tonic-gate 	/* overwrite old fileno and timestamps if not local versions */
19580Sstevel@tonic-gate 	if ((mdp->md_flags & MD_LOCALFILENO) == 0)
19590Sstevel@tonic-gate 		mdp->md_localfileno = mdp->md_vattr.va_nodeid;
19600Sstevel@tonic-gate 	if ((mdp->md_flags & MD_LOCALCTIME) == 0)
19610Sstevel@tonic-gate 		mdp->md_localctime = mdp->md_vattr.va_ctime;
19620Sstevel@tonic-gate 	if ((mdp->md_flags & MD_LOCALMTIME) == 0)
19630Sstevel@tonic-gate 		mdp->md_localmtime = mdp->md_vattr.va_mtime;
19640Sstevel@tonic-gate 	cp->c_flags |= CN_UPDATED;
19650Sstevel@tonic-gate }
1966