xref: /titanic_41/usr/src/uts/common/fs/cachefs/cachefs_cnode.c (revision da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*da6c28aaSamw  * Common Development and Distribution License (the "License").
6*da6c28aaSamw  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*da6c28aaSamw  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate #include <sys/param.h>
307c478bd9Sstevel@tonic-gate #include <sys/types.h>
317c478bd9Sstevel@tonic-gate #include <sys/systm.h>
327c478bd9Sstevel@tonic-gate #include <sys/cred.h>
337c478bd9Sstevel@tonic-gate #include <sys/proc.h>
347c478bd9Sstevel@tonic-gate #include <sys/user.h>
357c478bd9Sstevel@tonic-gate #include <sys/vfs.h>
367c478bd9Sstevel@tonic-gate #include <sys/vnode.h>
377c478bd9Sstevel@tonic-gate #include <sys/pathname.h>
387c478bd9Sstevel@tonic-gate #include <sys/uio.h>
397c478bd9Sstevel@tonic-gate #include <sys/tiuser.h>
407c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
417c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
427c478bd9Sstevel@tonic-gate #include <sys/buf.h>
437c478bd9Sstevel@tonic-gate #include <netinet/in.h>
447c478bd9Sstevel@tonic-gate #include <rpc/types.h>
457c478bd9Sstevel@tonic-gate #include <rpc/xdr.h>
467c478bd9Sstevel@tonic-gate #include <rpc/auth.h>
477c478bd9Sstevel@tonic-gate #include <rpc/clnt.h>
487c478bd9Sstevel@tonic-gate #include <sys/mount.h>
497c478bd9Sstevel@tonic-gate #include <sys/ioctl.h>
507c478bd9Sstevel@tonic-gate #include <sys/statvfs.h>
517c478bd9Sstevel@tonic-gate #include <sys/errno.h>
527c478bd9Sstevel@tonic-gate #include <sys/debug.h>
537c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
547c478bd9Sstevel@tonic-gate #include <sys/utsname.h>
557c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
567c478bd9Sstevel@tonic-gate #include <vm/pvn.h>
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate #include <sys/fs/cachefs_fs.h>
597c478bd9Sstevel@tonic-gate 
607c478bd9Sstevel@tonic-gate /*
617c478bd9Sstevel@tonic-gate  * cachefs_max_idle is a global that is tunable.
627c478bd9Sstevel@tonic-gate  * This value decides how frequently or when the
637c478bd9Sstevel@tonic-gate  * cachefs_cnode_idleclean is run.
647c478bd9Sstevel@tonic-gate  * The default value is set to CFS_FS_MAXIDLE.
657c478bd9Sstevel@tonic-gate  * The tunable if set to X triggers a cleanup when
667c478bd9Sstevel@tonic-gate  * the number of idle cnodes reach X, and cleans up
677c478bd9Sstevel@tonic-gate  * (.25 * X) idle cnodes.
687c478bd9Sstevel@tonic-gate  */
697c478bd9Sstevel@tonic-gate int cachefs_max_idle = CFS_FS_MAXIDLE;
707c478bd9Sstevel@tonic-gate 
717c478bd9Sstevel@tonic-gate 
727c478bd9Sstevel@tonic-gate struct kmem_cache *cachefs_cnode_cache = NULL;
737c478bd9Sstevel@tonic-gate 
747c478bd9Sstevel@tonic-gate /*
757c478bd9Sstevel@tonic-gate  * Functions for cnode management.
767c478bd9Sstevel@tonic-gate  */
777c478bd9Sstevel@tonic-gate 
787c478bd9Sstevel@tonic-gate /*
797c478bd9Sstevel@tonic-gate  * Puts cnode on idle list.  Only call from an async thread or no
807c478bd9Sstevel@tonic-gate  * locks held.
817c478bd9Sstevel@tonic-gate  */
827c478bd9Sstevel@tonic-gate /*ARGSUSED1*/
837c478bd9Sstevel@tonic-gate void
cachefs_cnode_idle(struct vnode * vp,cred_t * cr)847c478bd9Sstevel@tonic-gate cachefs_cnode_idle(struct vnode *vp, cred_t *cr)
857c478bd9Sstevel@tonic-gate {
867c478bd9Sstevel@tonic-gate 	cnode_t *cp = VTOC(vp);
877c478bd9Sstevel@tonic-gate 	fscache_t *fscp = C_TO_FSCACHE(cp);
887c478bd9Sstevel@tonic-gate 	int cleanidle;
897c478bd9Sstevel@tonic-gate 	vnode_t *unldvp;
907c478bd9Sstevel@tonic-gate 	cred_t *unlcred;
917c478bd9Sstevel@tonic-gate 	char *unlname;
927c478bd9Sstevel@tonic-gate 	int error;
937c478bd9Sstevel@tonic-gate 
947c478bd9Sstevel@tonic-gate 	/*
957c478bd9Sstevel@tonic-gate 	 * The key to this routine is not to drop the vnode count
967c478bd9Sstevel@tonic-gate 	 * while on the idle list.  This prevents this routine from
977c478bd9Sstevel@tonic-gate 	 * being called again by vn_rele on an inactive cnode.
987c478bd9Sstevel@tonic-gate 	 * Nothing bad happens if an "active" cnode is put on the idle
997c478bd9Sstevel@tonic-gate 	 * list.  It eventually gets pulled off.
1007c478bd9Sstevel@tonic-gate 	 * Also this routine is only called from a thread message sent
1017c478bd9Sstevel@tonic-gate 	 * by cachefs_inactive().  It is not safe for this routine
1027c478bd9Sstevel@tonic-gate 	 * to be the "inactive" entry point because of the dnlc.
1037c478bd9Sstevel@tonic-gate 	 */
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate 	for (;;) {
1067c478bd9Sstevel@tonic-gate 		/* get access to the file system */
1077c478bd9Sstevel@tonic-gate 		error = cachefs_cd_access(fscp, 0, 1);
1087c478bd9Sstevel@tonic-gate 		ASSERT(error == 0);
1097c478bd9Sstevel@tonic-gate 
1107c478bd9Sstevel@tonic-gate 		/* get exclusive access to this cnode */
1117c478bd9Sstevel@tonic-gate 		mutex_enter(&cp->c_statelock);
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate 		/* done with this loop if not unlinking a file */
1147c478bd9Sstevel@tonic-gate 		if (cp->c_unldvp == NULL)
1157c478bd9Sstevel@tonic-gate 			break;
1167c478bd9Sstevel@tonic-gate 
1177c478bd9Sstevel@tonic-gate 		/* get unlink info out of the cnode */
1187c478bd9Sstevel@tonic-gate 		unldvp = cp->c_unldvp;
1197c478bd9Sstevel@tonic-gate 		unlcred = cp->c_unlcred;
1207c478bd9Sstevel@tonic-gate 		unlname = cp->c_unlname;
1217c478bd9Sstevel@tonic-gate 		cp->c_unldvp = NULL;
1227c478bd9Sstevel@tonic-gate 		cp->c_unlcred = NULL;
1237c478bd9Sstevel@tonic-gate 		cp->c_unlname = NULL;
1247c478bd9Sstevel@tonic-gate 		mutex_exit(&cp->c_statelock);
1257c478bd9Sstevel@tonic-gate 
1267c478bd9Sstevel@tonic-gate 		/* finish the remove operation */
1277c478bd9Sstevel@tonic-gate 		if (fscp->fs_cdconnected == CFS_CD_CONNECTED) {
1287c478bd9Sstevel@tonic-gate 			error = cachefs_remove_connected(unldvp,
1297c478bd9Sstevel@tonic-gate 			    unlname, unlcred, vp);
1307c478bd9Sstevel@tonic-gate 		} else {
1317c478bd9Sstevel@tonic-gate 			error = cachefs_remove_disconnected(unldvp,
1327c478bd9Sstevel@tonic-gate 			    unlname, unlcred, vp);
1337c478bd9Sstevel@tonic-gate 		}
1347c478bd9Sstevel@tonic-gate 
135*da6c28aaSamw 		/* reacquire cnode lock */
1367c478bd9Sstevel@tonic-gate 		mutex_enter(&cp->c_statelock);
1377c478bd9Sstevel@tonic-gate 
1387c478bd9Sstevel@tonic-gate 		/* if a timeout occurred */
1397c478bd9Sstevel@tonic-gate 		if (CFS_TIMEOUT(fscp, error)) {
1407c478bd9Sstevel@tonic-gate 			/* restore cnode state */
1417c478bd9Sstevel@tonic-gate 			if (cp->c_unldvp == NULL) {
1427c478bd9Sstevel@tonic-gate 				cp->c_unldvp = unldvp;
1437c478bd9Sstevel@tonic-gate 				cp->c_unlcred = unlcred;
1447c478bd9Sstevel@tonic-gate 				cp->c_unlname = unlname;
1457c478bd9Sstevel@tonic-gate 				if (fscp->fs_cdconnected == CFS_CD_CONNECTED) {
1467c478bd9Sstevel@tonic-gate 					mutex_exit(&cp->c_statelock);
1477c478bd9Sstevel@tonic-gate 					cachefs_cd_release(fscp);
1487c478bd9Sstevel@tonic-gate 					cachefs_cd_timedout(fscp);
1497c478bd9Sstevel@tonic-gate 					continue;
1507c478bd9Sstevel@tonic-gate 				} else {
1517c478bd9Sstevel@tonic-gate 					cp->c_flags |= CN_PENDRM;
1527c478bd9Sstevel@tonic-gate 					mutex_exit(&cp->c_statelock);
1537c478bd9Sstevel@tonic-gate 					goto out;
1547c478bd9Sstevel@tonic-gate 				}
1557c478bd9Sstevel@tonic-gate 			}
1567c478bd9Sstevel@tonic-gate 		}
1577c478bd9Sstevel@tonic-gate 		/* free up resources */
1587c478bd9Sstevel@tonic-gate 		VN_RELE(unldvp);
1597c478bd9Sstevel@tonic-gate 		cachefs_kmem_free(unlname, MAXNAMELEN);
1607c478bd9Sstevel@tonic-gate 		crfree(unlcred);
1617c478bd9Sstevel@tonic-gate 		break;
1627c478bd9Sstevel@tonic-gate 	}
1637c478bd9Sstevel@tonic-gate 
1647c478bd9Sstevel@tonic-gate 	ASSERT((cp->c_flags & CN_IDLE) == 0);
1657c478bd9Sstevel@tonic-gate 	/*
1667c478bd9Sstevel@tonic-gate 	 * If we are going to destroy this cnode,
1677c478bd9Sstevel@tonic-gate 	 * do it now instead of later.
1687c478bd9Sstevel@tonic-gate 	 */
1697c478bd9Sstevel@tonic-gate 	if (cp->c_flags & (CN_DESTROY | CN_STALE)) {
1707c478bd9Sstevel@tonic-gate 		mutex_exit(&cp->c_statelock);
1717c478bd9Sstevel@tonic-gate 		(void) cachefs_cnode_inactive(vp, cr);
1727c478bd9Sstevel@tonic-gate 		goto out;
1737c478bd9Sstevel@tonic-gate 	}
1747c478bd9Sstevel@tonic-gate 
1757c478bd9Sstevel@tonic-gate 	/*
1767c478bd9Sstevel@tonic-gate 	 * mark cnode as idle, put it on the idle list, and increment the
1777c478bd9Sstevel@tonic-gate 	 * number of idle cnodes
1787c478bd9Sstevel@tonic-gate 	 */
1797c478bd9Sstevel@tonic-gate 	cp->c_flags |= CN_IDLE;
1807c478bd9Sstevel@tonic-gate 	mutex_enter(&fscp->fs_idlelock);
1817c478bd9Sstevel@tonic-gate 	cachefs_cnode_idleadd(cp);
1827c478bd9Sstevel@tonic-gate 	if ((fscp->fs_idlecnt > cachefs_max_idle) &&
1837c478bd9Sstevel@tonic-gate 	    (fscp->fs_idleclean == 0) &&
1847c478bd9Sstevel@tonic-gate 	    (fscp->fs_cdtransition == 0)) {
1857c478bd9Sstevel@tonic-gate 		fscp->fs_idleclean = 1;
1867c478bd9Sstevel@tonic-gate 		cleanidle = 1;
1877c478bd9Sstevel@tonic-gate 	} else {
1887c478bd9Sstevel@tonic-gate 		cleanidle = 0;
1897c478bd9Sstevel@tonic-gate 	}
1907c478bd9Sstevel@tonic-gate 	mutex_exit(&fscp->fs_idlelock);
1917c478bd9Sstevel@tonic-gate 
1927c478bd9Sstevel@tonic-gate 	/* release cnode */
1937c478bd9Sstevel@tonic-gate 	mutex_exit(&cp->c_statelock);
1947c478bd9Sstevel@tonic-gate 
1957c478bd9Sstevel@tonic-gate 	/* if should reduce the number of idle cnodes */
1967c478bd9Sstevel@tonic-gate 	if (cleanidle) {
1977c478bd9Sstevel@tonic-gate 		ASSERT(fscp->fs_idlecnt > 1);
1987c478bd9Sstevel@tonic-gate 		fscache_hold(fscp);
1997c478bd9Sstevel@tonic-gate 		cachefs_cnode_idleclean(fscp, 0);
2007c478bd9Sstevel@tonic-gate 		/* XXX race with cachefs_unmount() calling destroy */
2017c478bd9Sstevel@tonic-gate 		fscache_rele(fscp);
2027c478bd9Sstevel@tonic-gate 	}
2037c478bd9Sstevel@tonic-gate 
2047c478bd9Sstevel@tonic-gate out:
2057c478bd9Sstevel@tonic-gate 	/* release hold on the file system */
2067c478bd9Sstevel@tonic-gate 	/* XXX unmount() could have called destroy after fscache_rele() */
2077c478bd9Sstevel@tonic-gate 	cachefs_cd_release(fscp);
2087c478bd9Sstevel@tonic-gate }
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate /*
2117c478bd9Sstevel@tonic-gate  * Removes cnodes from the idle list and destroys them.
2127c478bd9Sstevel@tonic-gate  */
2137c478bd9Sstevel@tonic-gate void
cachefs_cnode_idleclean(fscache_t * fscp,int unmount)2147c478bd9Sstevel@tonic-gate cachefs_cnode_idleclean(fscache_t *fscp, int unmount)
2157c478bd9Sstevel@tonic-gate {
2167c478bd9Sstevel@tonic-gate 	int remcnt;
2177c478bd9Sstevel@tonic-gate 	cnode_t *cp;
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate 	mutex_enter(&fscp->fs_idlelock);
2207c478bd9Sstevel@tonic-gate 
2217c478bd9Sstevel@tonic-gate 	/* determine number of cnodes to destroy */
2227c478bd9Sstevel@tonic-gate 	if (unmount) {
2237c478bd9Sstevel@tonic-gate 		/* destroy all plus any that go idle while in this routine */
2247c478bd9Sstevel@tonic-gate 		remcnt = fscp->fs_idlecnt * 2;
2257c478bd9Sstevel@tonic-gate 	} else {
2267c478bd9Sstevel@tonic-gate 		/* reduce to 75% of max allowed idle cnodes */
2277c478bd9Sstevel@tonic-gate 		remcnt = (fscp->fs_idlecnt - cachefs_max_idle) +
2287c478bd9Sstevel@tonic-gate 		    (cachefs_max_idle >> 2);
2297c478bd9Sstevel@tonic-gate 	}
2307c478bd9Sstevel@tonic-gate 
2317c478bd9Sstevel@tonic-gate 	for (; remcnt > 0; remcnt--) {
2327c478bd9Sstevel@tonic-gate 		/* get cnode on back of idle list and hold it */
2337c478bd9Sstevel@tonic-gate 		cp = fscp->fs_idleback;
2347c478bd9Sstevel@tonic-gate 		if (cp == NULL)
2357c478bd9Sstevel@tonic-gate 			break;
2367c478bd9Sstevel@tonic-gate 		VN_HOLD(CTOV(cp));
2377c478bd9Sstevel@tonic-gate 		mutex_exit(&fscp->fs_idlelock);
2387c478bd9Sstevel@tonic-gate 
2397c478bd9Sstevel@tonic-gate 		/* if the cnode is still on the idle list */
2407c478bd9Sstevel@tonic-gate 		mutex_enter(&cp->c_statelock);
2417c478bd9Sstevel@tonic-gate 		if (cp->c_flags & CN_IDLE) {
2427c478bd9Sstevel@tonic-gate 			cp->c_flags &= ~CN_IDLE;
2437c478bd9Sstevel@tonic-gate 
2447c478bd9Sstevel@tonic-gate 			/* remove cnode from the idle list */
2457c478bd9Sstevel@tonic-gate 			mutex_enter(&fscp->fs_idlelock);
2467c478bd9Sstevel@tonic-gate 			cachefs_cnode_idlerem(cp);
2477c478bd9Sstevel@tonic-gate 			mutex_exit(&fscp->fs_idlelock);
2487c478bd9Sstevel@tonic-gate 			mutex_exit(&cp->c_statelock);
2497c478bd9Sstevel@tonic-gate 
2507c478bd9Sstevel@tonic-gate 			/* destroy the cnode */
2517c478bd9Sstevel@tonic-gate 			VN_RELE(CTOV(cp));
2527c478bd9Sstevel@tonic-gate 			(void) cachefs_cnode_inactive(CTOV(cp), kcred);
2537c478bd9Sstevel@tonic-gate 		} else {
2547c478bd9Sstevel@tonic-gate 			/* cnode went active, just skip it */
2557c478bd9Sstevel@tonic-gate 			mutex_exit(&cp->c_statelock);
2567c478bd9Sstevel@tonic-gate 			VN_RELE(CTOV(cp));
2577c478bd9Sstevel@tonic-gate 		}
2587c478bd9Sstevel@tonic-gate 		mutex_enter(&fscp->fs_idlelock);
2597c478bd9Sstevel@tonic-gate 	}
2607c478bd9Sstevel@tonic-gate 
2617c478bd9Sstevel@tonic-gate 	fscp->fs_idleclean = 0;
2627c478bd9Sstevel@tonic-gate 	mutex_exit(&fscp->fs_idlelock);
2637c478bd9Sstevel@tonic-gate }
2647c478bd9Sstevel@tonic-gate 
2657c478bd9Sstevel@tonic-gate /*
2667c478bd9Sstevel@tonic-gate  * This routine does the real work of inactivating a cachefs vnode.
2677c478bd9Sstevel@tonic-gate  */
2687c478bd9Sstevel@tonic-gate int
cachefs_cnode_inactive(register struct vnode * vp,cred_t * cr)2697c478bd9Sstevel@tonic-gate cachefs_cnode_inactive(register struct vnode *vp, cred_t *cr)
2707c478bd9Sstevel@tonic-gate {
2717c478bd9Sstevel@tonic-gate 	cnode_t *cp;
2727c478bd9Sstevel@tonic-gate 	struct fscache *fscp;
2737c478bd9Sstevel@tonic-gate 	struct filegrp *fgp;
2747c478bd9Sstevel@tonic-gate 	cachefscache_t *cachep;
2757c478bd9Sstevel@tonic-gate 	struct cachefs_metadata *mdp;
2767c478bd9Sstevel@tonic-gate 	int meta_destroyed = 0;
2777c478bd9Sstevel@tonic-gate 
2787c478bd9Sstevel@tonic-gate 	cp = VTOC(vp);
2797c478bd9Sstevel@tonic-gate 
2807c478bd9Sstevel@tonic-gate 	fscp = C_TO_FSCACHE(cp);
2817c478bd9Sstevel@tonic-gate 	cachep = fscp->fs_cache;
2827c478bd9Sstevel@tonic-gate 	ASSERT(cachep != NULL);
2837c478bd9Sstevel@tonic-gate 	fgp = cp->c_filegrp;
2847c478bd9Sstevel@tonic-gate 
2857c478bd9Sstevel@tonic-gate 	ASSERT((cp->c_flags & CN_IDLE) == 0);
2867c478bd9Sstevel@tonic-gate 
2877c478bd9Sstevel@tonic-gate 	/* truncate the front file if necessary */
2887c478bd9Sstevel@tonic-gate 	mutex_enter(&cp->c_statelock);
2897c478bd9Sstevel@tonic-gate 	if ((cp->c_flags & CN_NOCACHE) && (cp->c_metadata.md_flags & MD_FILE) &&
2907c478bd9Sstevel@tonic-gate 	    cp->c_metadata.md_frontblks) {
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate 		ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
2937c478bd9Sstevel@tonic-gate 
2947c478bd9Sstevel@tonic-gate #ifdef CFSDEBUG
2957c478bd9Sstevel@tonic-gate 		CFS_DEBUG(CFSDEBUG_INVALIDATE)
2967c478bd9Sstevel@tonic-gate 			printf("c_cnode_inactive: invalidating %llu\n",
2977c478bd9Sstevel@tonic-gate 			    (u_longlong_t)cp->c_id.cid_fileno);
2987c478bd9Sstevel@tonic-gate #endif
2997c478bd9Sstevel@tonic-gate 		/*
3007c478bd9Sstevel@tonic-gate 		 * If the cnode is being populated, and we're not the
3017c478bd9Sstevel@tonic-gate 		 * populating thread, then block until the pop thread
3027c478bd9Sstevel@tonic-gate 		 * completes.  If we are the pop thread, then we may come in
3037c478bd9Sstevel@tonic-gate 		 * here, but not to nuke the directory cnode at a critical
3047c478bd9Sstevel@tonic-gate 		 * juncture.
3057c478bd9Sstevel@tonic-gate 		 */
3067c478bd9Sstevel@tonic-gate 		while ((cp->c_flags & CN_ASYNC_POP_WORKING) &&
3077c478bd9Sstevel@tonic-gate 		    (cp->c_popthrp != curthread))
3087c478bd9Sstevel@tonic-gate 			cv_wait(&cp->c_popcv, &cp->c_statelock);
3097c478bd9Sstevel@tonic-gate 
3107c478bd9Sstevel@tonic-gate 		cachefs_inval_object(cp);
3117c478bd9Sstevel@tonic-gate 	}
3127c478bd9Sstevel@tonic-gate 	mutex_exit(&cp->c_statelock);
3137c478bd9Sstevel@tonic-gate 
3147c478bd9Sstevel@tonic-gate 	for (;;) {
3157c478bd9Sstevel@tonic-gate 		/* see if vnode is really inactive */
3167c478bd9Sstevel@tonic-gate 		mutex_enter(&vp->v_lock);
3177c478bd9Sstevel@tonic-gate 		ASSERT(vp->v_count > 0);
3187c478bd9Sstevel@tonic-gate 		if (vp->v_count > 1) {
3197c478bd9Sstevel@tonic-gate 			/*
3207c478bd9Sstevel@tonic-gate 			 * It's impossible for us to be cnode_inactive for
3217c478bd9Sstevel@tonic-gate 			 * the root cnode _unless_ we are being called from
3227c478bd9Sstevel@tonic-gate 			 * cachefs_unmount (where inactive is called
3237c478bd9Sstevel@tonic-gate 			 * explictly).  If the count is not 1, there is
3247c478bd9Sstevel@tonic-gate 			 * still an outstanding reference to the root cnode,
3257c478bd9Sstevel@tonic-gate 			 * and we return EBUSY; this allows cachefs_unmount
3267c478bd9Sstevel@tonic-gate 			 * to fail.
3277c478bd9Sstevel@tonic-gate 			 */
3287c478bd9Sstevel@tonic-gate 			if (cp->c_flags & CN_ROOT) {
3297c478bd9Sstevel@tonic-gate 				mutex_exit(&vp->v_lock);
3307c478bd9Sstevel@tonic-gate 				return (EBUSY);
3317c478bd9Sstevel@tonic-gate 			}
3327c478bd9Sstevel@tonic-gate 			cp->c_ipending = 0;
3337c478bd9Sstevel@tonic-gate 			vp->v_count--;	/* release our hold from vn_rele */
3347c478bd9Sstevel@tonic-gate 			mutex_exit(&vp->v_lock);
3357c478bd9Sstevel@tonic-gate 			return (0);
3367c478bd9Sstevel@tonic-gate 		}
3377c478bd9Sstevel@tonic-gate 		mutex_exit(&vp->v_lock);
3387c478bd9Sstevel@tonic-gate 
3397c478bd9Sstevel@tonic-gate 		/* get rid of any pages, do not care if cannot be pushed */
3407c478bd9Sstevel@tonic-gate 		if (vn_has_cached_data(vp)) {
3417c478bd9Sstevel@tonic-gate 			ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
3427c478bd9Sstevel@tonic-gate 			(void) cachefs_putpage_common(vp, (offset_t)0, 0,
3437c478bd9Sstevel@tonic-gate 			    B_INVAL | B_FORCE, cr);
3447c478bd9Sstevel@tonic-gate 		}
3457c478bd9Sstevel@tonic-gate 
3467c478bd9Sstevel@tonic-gate 		/* if need to sync metadata, the call is a no op for NFSv4 */
3477c478bd9Sstevel@tonic-gate 		if ((cp->c_flags & (CN_UPDATED | CN_DESTROY)) == CN_UPDATED) {
3487c478bd9Sstevel@tonic-gate 			(void) cachefs_sync_metadata(cp);
3497c478bd9Sstevel@tonic-gate 			continue;
3507c478bd9Sstevel@tonic-gate 		}
3517c478bd9Sstevel@tonic-gate 		break;
3527c478bd9Sstevel@tonic-gate 	}
3537c478bd9Sstevel@tonic-gate 
3547c478bd9Sstevel@tonic-gate 	/*
3557c478bd9Sstevel@tonic-gate 	 * Lock out possible race with makecachefsnode.
3567c478bd9Sstevel@tonic-gate 	 * Makecachefsnode will fix up the rl/active list stuff to
3577c478bd9Sstevel@tonic-gate 	 * be correct when it gets to run.
3587c478bd9Sstevel@tonic-gate 	 * We have to do the rl/active stuff while the cnode is on the hash
3597c478bd9Sstevel@tonic-gate 	 * list to sync actions on the rl/active list.
3607c478bd9Sstevel@tonic-gate 	 */
3617c478bd9Sstevel@tonic-gate 	mutex_enter(&fgp->fg_cnodelock);
3627c478bd9Sstevel@tonic-gate 	mutex_enter(&cp->c_statelock);
3637c478bd9Sstevel@tonic-gate 
3647c478bd9Sstevel@tonic-gate 	/* see if vnode is still inactive */
3657c478bd9Sstevel@tonic-gate 	mutex_enter(&vp->v_lock);
3667c478bd9Sstevel@tonic-gate 	ASSERT(vp->v_count > 0);
3677c478bd9Sstevel@tonic-gate 	if (vp->v_count > 1) {
3687c478bd9Sstevel@tonic-gate 		cp->c_ipending = 0;
3697c478bd9Sstevel@tonic-gate 		vp->v_count--;
3707c478bd9Sstevel@tonic-gate 		mutex_exit(&vp->v_lock);
3717c478bd9Sstevel@tonic-gate 		mutex_exit(&cp->c_statelock);
3727c478bd9Sstevel@tonic-gate 		mutex_exit(&fgp->fg_cnodelock);
3737c478bd9Sstevel@tonic-gate #ifdef CFSDEBUG
3747c478bd9Sstevel@tonic-gate 		CFS_DEBUG(CFSDEBUG_INVALIDATE)
3757c478bd9Sstevel@tonic-gate 			printf("cachefs_cnode_inactive: %u vp %p\n",
3767c478bd9Sstevel@tonic-gate 			    vp->v_count, vp);
3777c478bd9Sstevel@tonic-gate #endif
3787c478bd9Sstevel@tonic-gate 		return (0);
3797c478bd9Sstevel@tonic-gate 	}
3807c478bd9Sstevel@tonic-gate 	mutex_exit(&vp->v_lock);
3817c478bd9Sstevel@tonic-gate 
3827c478bd9Sstevel@tonic-gate 	/* check for race with remove */
3837c478bd9Sstevel@tonic-gate 	if (cp->c_unldvp) {
3847c478bd9Sstevel@tonic-gate 		mutex_exit(&cp->c_statelock);
3857c478bd9Sstevel@tonic-gate 		mutex_exit(&fgp->fg_cnodelock);
3867c478bd9Sstevel@tonic-gate 
3877c478bd9Sstevel@tonic-gate 		/* this causes cachefs_inactive to be called again */
3887c478bd9Sstevel@tonic-gate 		VN_RELE(vp);
3897c478bd9Sstevel@tonic-gate 		return (0);
3907c478bd9Sstevel@tonic-gate 	}
3917c478bd9Sstevel@tonic-gate 
3927c478bd9Sstevel@tonic-gate 	/* if any pages left, really get rid of them */
3937c478bd9Sstevel@tonic-gate 	if (vn_has_cached_data(vp)) {
3947c478bd9Sstevel@tonic-gate 		ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
3957c478bd9Sstevel@tonic-gate 		(void) pvn_vplist_dirty(vp, 0, NULL, B_INVAL | B_TRUNC, cr);
3967c478bd9Sstevel@tonic-gate 	}
3977c478bd9Sstevel@tonic-gate 	ASSERT(vp->v_count == 1);
3987c478bd9Sstevel@tonic-gate 
3997c478bd9Sstevel@tonic-gate 	mdp = &cp->c_metadata;
4007c478bd9Sstevel@tonic-gate 
4017c478bd9Sstevel@tonic-gate 	/* if we can (and should) destroy the front file and metadata */
4027c478bd9Sstevel@tonic-gate 	if ((cp->c_flags & (CN_DESTROY | CN_STALE)) &&
4037c478bd9Sstevel@tonic-gate 	    (fgp->fg_flags & CFS_FG_WRITE) && !CFS_ISFS_BACKFS_NFSV4(fscp)) {
4047c478bd9Sstevel@tonic-gate 		if (mdp->md_rlno) {
4057c478bd9Sstevel@tonic-gate 			cachefs_removefrontfile(mdp, &cp->c_id, fgp);
4067c478bd9Sstevel@tonic-gate 			cachefs_rlent_moveto(cachep, CACHEFS_RL_FREE,
4077c478bd9Sstevel@tonic-gate 			    mdp->md_rlno, 0);
4087c478bd9Sstevel@tonic-gate 			mdp->md_rlno = 0;
4097c478bd9Sstevel@tonic-gate 			mdp->md_rltype = CACHEFS_RL_NONE;
4107c478bd9Sstevel@tonic-gate 		}
4117c478bd9Sstevel@tonic-gate 		if ((cp->c_flags & CN_ALLOC_PENDING) == 0) {
4127c478bd9Sstevel@tonic-gate 			(void) filegrp_destroy_metadata(fgp, &cp->c_id);
4137c478bd9Sstevel@tonic-gate 			meta_destroyed = 1;
4147c478bd9Sstevel@tonic-gate 		}
4157c478bd9Sstevel@tonic-gate 	}
4167c478bd9Sstevel@tonic-gate 
4177c478bd9Sstevel@tonic-gate 	/* else put the front file on the gc list */
4187c478bd9Sstevel@tonic-gate 	else if (mdp->md_rlno &&
4197c478bd9Sstevel@tonic-gate 	    (fgp->fg_flags & CFS_FG_WRITE) &&
4207c478bd9Sstevel@tonic-gate 	    (cp->c_metadata.md_rltype == CACHEFS_RL_ACTIVE)) {
4217c478bd9Sstevel@tonic-gate #ifdef CFSDEBUG
4227c478bd9Sstevel@tonic-gate 		cachefs_rlent_verify(cachep, CACHEFS_RL_ACTIVE,
4237c478bd9Sstevel@tonic-gate 		    mdp->md_rlno);
4247c478bd9Sstevel@tonic-gate #endif /* CFSDEBUG */
4257c478bd9Sstevel@tonic-gate 
4267c478bd9Sstevel@tonic-gate 		ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
4277c478bd9Sstevel@tonic-gate 		cachefs_rlent_moveto(cachep, CACHEFS_RL_GC, mdp->md_rlno,
4287c478bd9Sstevel@tonic-gate 		    mdp->md_frontblks);
4297c478bd9Sstevel@tonic-gate 		mdp->md_rltype = CACHEFS_RL_GC;
4307c478bd9Sstevel@tonic-gate 		cp->c_flags |= CN_UPDATED;
4317c478bd9Sstevel@tonic-gate 	}
4327c478bd9Sstevel@tonic-gate 
4337c478bd9Sstevel@tonic-gate 	/* if idlelist pointer(s) not null, remove from idle list */
4347c478bd9Sstevel@tonic-gate 	if ((cp->c_idlefront != NULL) || (cp->c_idleback != NULL)) {
4357c478bd9Sstevel@tonic-gate 		mutex_enter(&fscp->fs_idlelock);
4367c478bd9Sstevel@tonic-gate 		cachefs_cnode_idlerem(cp);
4377c478bd9Sstevel@tonic-gate 		mutex_exit(&fscp->fs_idlelock);
4387c478bd9Sstevel@tonic-gate 	}
4397c478bd9Sstevel@tonic-gate 
4407c478bd9Sstevel@tonic-gate 	/* remove from the filegrp list prior to releasing the cnode lock */
4417c478bd9Sstevel@tonic-gate 	cachefs_cnode_listrem(cp);
4427c478bd9Sstevel@tonic-gate 
4437c478bd9Sstevel@tonic-gate 	mutex_exit(&cp->c_statelock);
4447c478bd9Sstevel@tonic-gate 	if (! meta_destroyed)
4457c478bd9Sstevel@tonic-gate 		(void) cachefs_sync_metadata(cp);
4467c478bd9Sstevel@tonic-gate 
4477c478bd9Sstevel@tonic-gate 	mutex_exit(&fgp->fg_cnodelock);
4487c478bd9Sstevel@tonic-gate 
4497c478bd9Sstevel@tonic-gate 	if (cp->c_cred != NULL) {
4507c478bd9Sstevel@tonic-gate 		crfree(cp->c_cred);
4517c478bd9Sstevel@tonic-gate 		cp->c_cred = NULL;
4527c478bd9Sstevel@tonic-gate 	}
4537c478bd9Sstevel@tonic-gate 
4547c478bd9Sstevel@tonic-gate 	if (cp->c_frontvp)
4557c478bd9Sstevel@tonic-gate 		VN_RELE(cp->c_frontvp);
4567c478bd9Sstevel@tonic-gate 
4577c478bd9Sstevel@tonic-gate 	if (cp->c_backvp)
4587c478bd9Sstevel@tonic-gate 		VN_RELE(cp->c_backvp);
4597c478bd9Sstevel@tonic-gate 
4607c478bd9Sstevel@tonic-gate 	if (cp->c_acldirvp)
4617c478bd9Sstevel@tonic-gate 		VN_RELE(cp->c_acldirvp);
4627c478bd9Sstevel@tonic-gate 
4637c478bd9Sstevel@tonic-gate 	rw_destroy(&cp->c_rwlock);
4647c478bd9Sstevel@tonic-gate 	mutex_destroy(&cp->c_statelock);
4657c478bd9Sstevel@tonic-gate 	cv_destroy(&cp->c_popcv);
4667c478bd9Sstevel@tonic-gate 	mutex_destroy(&cp->c_iomutex);
4677c478bd9Sstevel@tonic-gate 	cv_destroy(&cp->c_iocv);
4687c478bd9Sstevel@tonic-gate 
4697c478bd9Sstevel@tonic-gate 	/* free up cnode memory */
4707c478bd9Sstevel@tonic-gate 	vn_invalid(cp->c_vnode);
4717c478bd9Sstevel@tonic-gate 	vn_free(cp->c_vnode);
4727c478bd9Sstevel@tonic-gate 	kmem_cache_free(cachefs_cnode_cache, cp);
4737c478bd9Sstevel@tonic-gate 
4747c478bd9Sstevel@tonic-gate 	filegrp_rele(fgp);
4757c478bd9Sstevel@tonic-gate 	(void) fscache_cnodecnt(fscp, -1);
4767c478bd9Sstevel@tonic-gate 	return (0);
4777c478bd9Sstevel@tonic-gate }
4787c478bd9Sstevel@tonic-gate 
4797c478bd9Sstevel@tonic-gate /*
4807c478bd9Sstevel@tonic-gate  * Add a cnode to the filegrp list.
4817c478bd9Sstevel@tonic-gate  */
4827c478bd9Sstevel@tonic-gate void
cachefs_cnode_listadd(struct cnode * cp)4837c478bd9Sstevel@tonic-gate cachefs_cnode_listadd(struct cnode *cp)
4847c478bd9Sstevel@tonic-gate {
4857c478bd9Sstevel@tonic-gate 	filegrp_t *fgp = cp->c_filegrp;
4867c478bd9Sstevel@tonic-gate 
4877c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&fgp->fg_cnodelock));
4887c478bd9Sstevel@tonic-gate 	ASSERT(cp->c_next == NULL);
4897c478bd9Sstevel@tonic-gate 
4907c478bd9Sstevel@tonic-gate 	cp->c_next = fgp->fg_cnodelist;
4917c478bd9Sstevel@tonic-gate 	fgp->fg_cnodelist = cp;
4927c478bd9Sstevel@tonic-gate }
4937c478bd9Sstevel@tonic-gate 
4947c478bd9Sstevel@tonic-gate /*
4957c478bd9Sstevel@tonic-gate  * Remove a cnode from the filegrp list.
4967c478bd9Sstevel@tonic-gate  */
4977c478bd9Sstevel@tonic-gate void
cachefs_cnode_listrem(struct cnode * cp)4987c478bd9Sstevel@tonic-gate cachefs_cnode_listrem(struct cnode *cp)
4997c478bd9Sstevel@tonic-gate {
5007c478bd9Sstevel@tonic-gate 	filegrp_t *fgp = cp->c_filegrp;
5017c478bd9Sstevel@tonic-gate 	struct cnode **headpp;
5027c478bd9Sstevel@tonic-gate 
5037c478bd9Sstevel@tonic-gate #ifdef CFSDEBUG
5047c478bd9Sstevel@tonic-gate 	int found = 0;
5057c478bd9Sstevel@tonic-gate #endif
5067c478bd9Sstevel@tonic-gate 
5077c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&fgp->fg_cnodelock));
5087c478bd9Sstevel@tonic-gate 	ASSERT(cp->c_idleback == NULL);
5097c478bd9Sstevel@tonic-gate 	ASSERT(cp->c_idlefront == NULL);
5107c478bd9Sstevel@tonic-gate 
5117c478bd9Sstevel@tonic-gate 	for (headpp = &fgp->fg_cnodelist;
5127c478bd9Sstevel@tonic-gate 		*headpp != NULL; headpp = &(*headpp)->c_next) {
5137c478bd9Sstevel@tonic-gate 		if (*headpp == cp) {
5147c478bd9Sstevel@tonic-gate 			*headpp = cp->c_next;
5157c478bd9Sstevel@tonic-gate 			cp->c_next = NULL;
5167c478bd9Sstevel@tonic-gate #ifdef CFSDEBUG
5177c478bd9Sstevel@tonic-gate 			found++;
5187c478bd9Sstevel@tonic-gate #endif
5197c478bd9Sstevel@tonic-gate 			break;
5207c478bd9Sstevel@tonic-gate 		}
5217c478bd9Sstevel@tonic-gate 	}
5227c478bd9Sstevel@tonic-gate #ifdef CFSDEBUG
5237c478bd9Sstevel@tonic-gate 	ASSERT(found);
5247c478bd9Sstevel@tonic-gate #endif
5257c478bd9Sstevel@tonic-gate }
5267c478bd9Sstevel@tonic-gate 
5277c478bd9Sstevel@tonic-gate /*
5287c478bd9Sstevel@tonic-gate  * Add a cnode to the front of the fscache idle list.
5297c478bd9Sstevel@tonic-gate  */
5307c478bd9Sstevel@tonic-gate void
cachefs_cnode_idleadd(struct cnode * cp)5317c478bd9Sstevel@tonic-gate cachefs_cnode_idleadd(struct cnode *cp)
5327c478bd9Sstevel@tonic-gate {
5337c478bd9Sstevel@tonic-gate 	fscache_t *fscp = C_TO_FSCACHE(cp);
5347c478bd9Sstevel@tonic-gate 
5357c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&cp->c_statelock));
5367c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&fscp->fs_idlelock));
5377c478bd9Sstevel@tonic-gate 
5387c478bd9Sstevel@tonic-gate 	/* put cnode on the front of the idle list */
5397c478bd9Sstevel@tonic-gate 	cp->c_idlefront = fscp->fs_idlefront;
5407c478bd9Sstevel@tonic-gate 	cp->c_idleback =  NULL;
5417c478bd9Sstevel@tonic-gate 
5427c478bd9Sstevel@tonic-gate 	if (fscp->fs_idlefront)
5437c478bd9Sstevel@tonic-gate 		fscp->fs_idlefront->c_idleback = cp;
5447c478bd9Sstevel@tonic-gate 	else {
5457c478bd9Sstevel@tonic-gate 		ASSERT(fscp->fs_idleback == NULL);
5467c478bd9Sstevel@tonic-gate 		fscp->fs_idleback = cp;
5477c478bd9Sstevel@tonic-gate 	}
5487c478bd9Sstevel@tonic-gate 	fscp->fs_idlefront = cp;
5497c478bd9Sstevel@tonic-gate 	fscp->fs_idlecnt++;
5507c478bd9Sstevel@tonic-gate }
5517c478bd9Sstevel@tonic-gate 
5527c478bd9Sstevel@tonic-gate /*
5537c478bd9Sstevel@tonic-gate  * Remove a cnode from the fscache idle list.
5547c478bd9Sstevel@tonic-gate  */
5557c478bd9Sstevel@tonic-gate void
cachefs_cnode_idlerem(struct cnode * cp)5567c478bd9Sstevel@tonic-gate cachefs_cnode_idlerem(struct cnode *cp)
5577c478bd9Sstevel@tonic-gate {
5587c478bd9Sstevel@tonic-gate 	fscache_t *fscp = C_TO_FSCACHE(cp);
5597c478bd9Sstevel@tonic-gate 
5607c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&cp->c_statelock));
5617c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&fscp->fs_idlelock));
5627c478bd9Sstevel@tonic-gate 
5637c478bd9Sstevel@tonic-gate 	if (cp->c_idlefront == NULL) {
5647c478bd9Sstevel@tonic-gate 		ASSERT(fscp->fs_idleback == cp);
5657c478bd9Sstevel@tonic-gate 		fscp->fs_idleback = cp->c_idleback;
5667c478bd9Sstevel@tonic-gate 		if (fscp->fs_idleback != NULL)
5677c478bd9Sstevel@tonic-gate 			fscp->fs_idleback->c_idlefront = NULL;
5687c478bd9Sstevel@tonic-gate 	} else {
5697c478bd9Sstevel@tonic-gate 		cp->c_idlefront->c_idleback = cp->c_idleback;
5707c478bd9Sstevel@tonic-gate 	}
5717c478bd9Sstevel@tonic-gate 
5727c478bd9Sstevel@tonic-gate 	if (cp->c_idleback == NULL) {
5737c478bd9Sstevel@tonic-gate 		ASSERT(fscp->fs_idlefront == cp);
5747c478bd9Sstevel@tonic-gate 		fscp->fs_idlefront = cp->c_idlefront;
5757c478bd9Sstevel@tonic-gate 		if (fscp->fs_idlefront != NULL)
5767c478bd9Sstevel@tonic-gate 			fscp->fs_idlefront->c_idleback = NULL;
5777c478bd9Sstevel@tonic-gate 	} else {
5787c478bd9Sstevel@tonic-gate 		cp->c_idleback->c_idlefront = cp->c_idlefront;
5797c478bd9Sstevel@tonic-gate 		cp->c_idleback = NULL;
5807c478bd9Sstevel@tonic-gate 	}
5817c478bd9Sstevel@tonic-gate 	cp->c_idlefront = NULL;
5827c478bd9Sstevel@tonic-gate 	fscp->fs_idlecnt--;
5837c478bd9Sstevel@tonic-gate 	ASSERT(fscp->fs_idlecnt >= 0);
5847c478bd9Sstevel@tonic-gate }
5857c478bd9Sstevel@tonic-gate 
5867c478bd9Sstevel@tonic-gate /*
5877c478bd9Sstevel@tonic-gate  * Search the cnode list of the input file group, looking for a cnode which
5887c478bd9Sstevel@tonic-gate  * matches the supplied file ident fileno.
5897c478bd9Sstevel@tonic-gate  *
5907c478bd9Sstevel@tonic-gate  * Returns:
5917c478bd9Sstevel@tonic-gate  *	*cpp = NULL, if no valid matching cnode is found
5927c478bd9Sstevel@tonic-gate  *	*cpp = address of cnode with matching fileno, with c_statelock held
5937c478bd9Sstevel@tonic-gate  *	return status is 0 if no cnode found, or if found & cookies match
5947c478bd9Sstevel@tonic-gate  *	return status is 1 if a cnode was found, but the cookies don't match
5957c478bd9Sstevel@tonic-gate  *
5967c478bd9Sstevel@tonic-gate  * Note:  must grab the c_statelock for each cnode, or its state could
5977c478bd9Sstevel@tonic-gate  * change while we're processing it.  Also, if a cnode is found, must return
5987c478bd9Sstevel@tonic-gate  * with c_statelock still held, so that the cnode state cannot change until
5997c478bd9Sstevel@tonic-gate  * the calling routine releases the lock.
6007c478bd9Sstevel@tonic-gate  */
6017c478bd9Sstevel@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)6027c478bd9Sstevel@tonic-gate cachefs_cnode_find(filegrp_t *fgp, cfs_cid_t *cidp, fid_t *cookiep,
6037c478bd9Sstevel@tonic-gate     struct cnode **cpp, struct vnode *backvp, vattr_t *vap)
6047c478bd9Sstevel@tonic-gate {
6057c478bd9Sstevel@tonic-gate 	struct cnode *cp;
6067c478bd9Sstevel@tonic-gate 	int badcookie = 0;
6077c478bd9Sstevel@tonic-gate 	uint32_t is_nfsv4;
6087c478bd9Sstevel@tonic-gate 
6097c478bd9Sstevel@tonic-gate #ifdef CFSDEBUG
6107c478bd9Sstevel@tonic-gate 	CFS_DEBUG(CFSDEBUG_CNODE)
6117c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "cachefs_cnode_find: fileno %llu fgp %p\n",
6127c478bd9Sstevel@tonic-gate 		    (u_longlong_t)cidp->cid_fileno, (void *)fgp);
6137c478bd9Sstevel@tonic-gate #endif
6147c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&fgp->fg_cnodelock));
6157c478bd9Sstevel@tonic-gate 
6167c478bd9Sstevel@tonic-gate 	*cpp = NULL;
6177c478bd9Sstevel@tonic-gate 	is_nfsv4 = CFS_ISFS_BACKFS_NFSV4(fgp->fg_fscp);
6187c478bd9Sstevel@tonic-gate 
6197c478bd9Sstevel@tonic-gate 	/*
6207c478bd9Sstevel@tonic-gate 	 * Cookie should be filled unless disconnected operation or
6217c478bd9Sstevel@tonic-gate 	 * backfilesystem is NFSv4
6227c478bd9Sstevel@tonic-gate 	 */
6237c478bd9Sstevel@tonic-gate 	if (cookiep == NULL && !CFS_ISFS_SNR(fgp->fg_fscp) &&
6247c478bd9Sstevel@tonic-gate 	    !CFS_ISFS_BACKFS_NFSV4(fgp->fg_fscp)) {
6257c478bd9Sstevel@tonic-gate 		goto out;
6267c478bd9Sstevel@tonic-gate 	}
6277c478bd9Sstevel@tonic-gate 
6287c478bd9Sstevel@tonic-gate 	for (cp = fgp->fg_cnodelist; cp != NULL; cp = cp->c_next) {
6297c478bd9Sstevel@tonic-gate 		mutex_enter(&cp->c_statelock);
6307c478bd9Sstevel@tonic-gate 
6317c478bd9Sstevel@tonic-gate 		if ((cidp->cid_fileno != cp->c_id.cid_fileno &&
6327c478bd9Sstevel@tonic-gate 			(is_nfsv4 == FALSE || cp->c_backvp != backvp)) ||
6337c478bd9Sstevel@tonic-gate 		    (cp->c_flags & (CN_STALE | CN_DESTROY))) {
6347c478bd9Sstevel@tonic-gate 			mutex_exit(&cp->c_statelock);
6357c478bd9Sstevel@tonic-gate 			continue;
6367c478bd9Sstevel@tonic-gate 		}
6377c478bd9Sstevel@tonic-gate 
6387c478bd9Sstevel@tonic-gate 		/*
6397c478bd9Sstevel@tonic-gate 		 * Having found a non stale, non destroy pending cnode with
6407c478bd9Sstevel@tonic-gate 		 * matching fileno, will be exiting the for loop, after
6417c478bd9Sstevel@tonic-gate 		 * determining return status
6427c478bd9Sstevel@tonic-gate 		 */
6437c478bd9Sstevel@tonic-gate 		*cpp = cp;
6447c478bd9Sstevel@tonic-gate 
6457c478bd9Sstevel@tonic-gate 		if ((cookiep != NULL) &&
6467c478bd9Sstevel@tonic-gate 		    ((cookiep->fid_len != cp->c_cookie.fid_len) ||
6477c478bd9Sstevel@tonic-gate 		    (bcmp((caddr_t)cookiep->fid_data,
6487c478bd9Sstevel@tonic-gate 		    (caddr_t)&cp->c_cookie.fid_data, cookiep->fid_len)) != 0)) {
6497c478bd9Sstevel@tonic-gate #ifdef CFSDEBUG
6507c478bd9Sstevel@tonic-gate 			CFS_DEBUG(CFSDEBUG_GENERAL) {
6517c478bd9Sstevel@tonic-gate 				cmn_err(CE_NOTE,
6527c478bd9Sstevel@tonic-gate 				    "cachefs: dup fileno %llu, cp %p\n",
6537c478bd9Sstevel@tonic-gate 				    (u_longlong_t)cidp->cid_fileno, (void *)cp);
6547c478bd9Sstevel@tonic-gate 			}
6557c478bd9Sstevel@tonic-gate #endif
6567c478bd9Sstevel@tonic-gate 			badcookie = 1;
6577c478bd9Sstevel@tonic-gate 		}
6587c478bd9Sstevel@tonic-gate 
6597c478bd9Sstevel@tonic-gate 		/*
6607c478bd9Sstevel@tonic-gate 		 * For NFSv4 since there is no fid, add a check to
6617c478bd9Sstevel@tonic-gate 		 * ensure the backvp and vap matches that in the cnode.
6627c478bd9Sstevel@tonic-gate 		 * If it doesn't then someone tried to use a stale cnode.
6637c478bd9Sstevel@tonic-gate 		 */
6647c478bd9Sstevel@tonic-gate 		if (is_nfsv4) {
6657c478bd9Sstevel@tonic-gate 			if (backvp && backvp != cp->c_backvp ||
6667c478bd9Sstevel@tonic-gate 			    vap && vap->va_type != cp->c_attr.va_type ||
6677c478bd9Sstevel@tonic-gate 			    cidp->cid_fileno != cp->c_id.cid_fileno) {
6687c478bd9Sstevel@tonic-gate 				CFS_DPRINT_BACKFS_NFSV4(C_TO_FSCACHE(cp),
6697c478bd9Sstevel@tonic-gate 				("cachefs_cnode_find (nfsv4): stale cnode "
6707c478bd9Sstevel@tonic-gate 				"cnode %p, backvp %p, new-backvp %p, vap %p "
6717c478bd9Sstevel@tonic-gate 				"fileno=%llx cp-fileno=%llx\n",
6727c478bd9Sstevel@tonic-gate 				cp, cp->c_backvp, backvp, vap,
6737c478bd9Sstevel@tonic-gate 				cidp->cid_fileno, cp->c_id.cid_fileno));
6747c478bd9Sstevel@tonic-gate 				badcookie = 1;
6757c478bd9Sstevel@tonic-gate 			}
6767c478bd9Sstevel@tonic-gate 		}
6777c478bd9Sstevel@tonic-gate 		break;
6787c478bd9Sstevel@tonic-gate 	}
6797c478bd9Sstevel@tonic-gate out:
6807c478bd9Sstevel@tonic-gate 
6817c478bd9Sstevel@tonic-gate #ifdef CFSDEBUG
6827c478bd9Sstevel@tonic-gate 	CFS_DEBUG(CFSDEBUG_CNODE)
6837c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "cachefs_cnode_find: cp %p\n", (void *)*cpp);
6847c478bd9Sstevel@tonic-gate #endif
6857c478bd9Sstevel@tonic-gate 	return (badcookie);
6867c478bd9Sstevel@tonic-gate }
6877c478bd9Sstevel@tonic-gate 
6887c478bd9Sstevel@tonic-gate /*
6897c478bd9Sstevel@tonic-gate  * We have to initialize the cnode contents. Fill in the contents from the
6907c478bd9Sstevel@tonic-gate  * cache (attrcache file), from the info passed in, whatever it takes.
6917c478bd9Sstevel@tonic-gate  */
6927c478bd9Sstevel@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)6937c478bd9Sstevel@tonic-gate cachefs_cnode_init(cfs_cid_t *cidp, cnode_t *cp, fscache_t *fscp,
6947c478bd9Sstevel@tonic-gate     filegrp_t *fgp, fid_t *cookiep, vattr_t *vap, vnode_t *backvp,
6957c478bd9Sstevel@tonic-gate     int flag, cred_t *cr)
6967c478bd9Sstevel@tonic-gate {
6977c478bd9Sstevel@tonic-gate 	int error = 0;
6987c478bd9Sstevel@tonic-gate 	int slotfound;
6997c478bd9Sstevel@tonic-gate 	vnode_t *vp;
7007c478bd9Sstevel@tonic-gate 	int null_cookie;
7017c478bd9Sstevel@tonic-gate 	cachefscache_t *cachep = fscp->fs_cache;
7027c478bd9Sstevel@tonic-gate 
7037c478bd9Sstevel@tonic-gate 	bzero(cp, sizeof (cnode_t));
7047c478bd9Sstevel@tonic-gate 	cp->c_vnode = vn_alloc(KM_SLEEP);
7057c478bd9Sstevel@tonic-gate 
7067c478bd9Sstevel@tonic-gate 	vp = CTOV(cp);
7077c478bd9Sstevel@tonic-gate 
7087c478bd9Sstevel@tonic-gate 	vp->v_data = (caddr_t)cp;
7097c478bd9Sstevel@tonic-gate 
7107c478bd9Sstevel@tonic-gate 	rw_init(&cp->c_rwlock, NULL, RW_DEFAULT, NULL);
7117c478bd9Sstevel@tonic-gate 	mutex_init(&cp->c_statelock, NULL, MUTEX_DEFAULT, NULL);
7127c478bd9Sstevel@tonic-gate 	cv_init(&cp->c_popcv, NULL, CV_DEFAULT, NULL);
7137c478bd9Sstevel@tonic-gate 	mutex_init(&cp->c_iomutex, NULL, MUTEX_DEFAULT, NULL);
7147c478bd9Sstevel@tonic-gate 	cv_init(&cp->c_iocv, NULL, CV_DEFAULT, NULL);
7157c478bd9Sstevel@tonic-gate 
7167c478bd9Sstevel@tonic-gate 	vn_setops(vp, cachefs_getvnodeops());
7177c478bd9Sstevel@tonic-gate 	cp->c_id = *cidp;
7187c478bd9Sstevel@tonic-gate 	if (backvp != NULL) {
7197c478bd9Sstevel@tonic-gate 		cp->c_backvp = backvp;
7207c478bd9Sstevel@tonic-gate 		VN_HOLD(backvp);
7217c478bd9Sstevel@tonic-gate 	}
7227c478bd9Sstevel@tonic-gate 	cp->c_flags |= flag;
7237c478bd9Sstevel@tonic-gate 	filegrp_hold(fgp);
7247c478bd9Sstevel@tonic-gate 	cp->c_filegrp = fgp;
7257c478bd9Sstevel@tonic-gate 	if (cookiep)
7267c478bd9Sstevel@tonic-gate 		cp->c_cookie = *cookiep;
7277c478bd9Sstevel@tonic-gate 	mutex_enter(&cp->c_statelock);
7287c478bd9Sstevel@tonic-gate 
7297c478bd9Sstevel@tonic-gate 	/*
7307c478bd9Sstevel@tonic-gate 	 * if nocache is set then ignore anything cached for this file,
7317c478bd9Sstevel@tonic-gate 	 * if nfsv4 flag is set, then create the cnode but don't do
7327c478bd9Sstevel@tonic-gate 	 * any caching.
7337c478bd9Sstevel@tonic-gate 	 */
7347c478bd9Sstevel@tonic-gate 	if (cp->c_flags & CN_NOCACHE || CFS_ISFS_BACKFS_NFSV4(fscp)) {
7357c478bd9Sstevel@tonic-gate 		/*
7367c478bd9Sstevel@tonic-gate 		 * this case only happens while booting without a cache
7377c478bd9Sstevel@tonic-gate 		 * or if NFSv4 is the backfilesystem
7387c478bd9Sstevel@tonic-gate 		 */
7397c478bd9Sstevel@tonic-gate 		ASSERT(!CFS_ISFS_SNR(fscp));
7407c478bd9Sstevel@tonic-gate 		ASSERT(fscp->fs_cdconnected == CFS_CD_CONNECTED);
7417c478bd9Sstevel@tonic-gate 		if (cookiep || CFS_ISFS_BACKFS_NFSV4(fscp)) {
7427c478bd9Sstevel@tonic-gate 			error = CFSOP_INIT_COBJECT(fscp, cp, vap, cr);
7437c478bd9Sstevel@tonic-gate 			if (error)
7447c478bd9Sstevel@tonic-gate 				goto out;
7457c478bd9Sstevel@tonic-gate 			cp->c_flags |= CN_UPDATED | CN_ALLOC_PENDING;
7467c478bd9Sstevel@tonic-gate 			ASSERT(cp->c_attr.va_type != 0);
7477c478bd9Sstevel@tonic-gate 			VN_SET_VFS_TYPE_DEV(vp, fscp->fs_cfsvfsp,
7487c478bd9Sstevel@tonic-gate 			    cp->c_attr.va_type, cp->c_attr.va_rdev);
7497c478bd9Sstevel@tonic-gate 			cachefs_cnode_setlocalstats(cp);
7507c478bd9Sstevel@tonic-gate 		} else
7517c478bd9Sstevel@tonic-gate 			error = ESTALE;
7527c478bd9Sstevel@tonic-gate 		goto out;
7537c478bd9Sstevel@tonic-gate 	}
7547c478bd9Sstevel@tonic-gate 
7557c478bd9Sstevel@tonic-gate 	/*
7567c478bd9Sstevel@tonic-gate 	 * see if there's a slot for this filegrp/cid fileno
7577c478bd9Sstevel@tonic-gate 	 * if not, and there's no cookie info, nothing can be done, but if
7587c478bd9Sstevel@tonic-gate 	 * there's cookie data indicate we need to create a metadata slot.
7597c478bd9Sstevel@tonic-gate 	 */
7607c478bd9Sstevel@tonic-gate 	slotfound = cachefs_cid_inuse(cp->c_filegrp, cidp);
7617c478bd9Sstevel@tonic-gate 	if (slotfound == 0) {
7627c478bd9Sstevel@tonic-gate 		if (cookiep == NULL) {
7637c478bd9Sstevel@tonic-gate 			error = ENOENT;
7647c478bd9Sstevel@tonic-gate 			goto out;
7657c478bd9Sstevel@tonic-gate 		}
7667c478bd9Sstevel@tonic-gate 		cp->c_flags |= CN_ALLOC_PENDING;
7677c478bd9Sstevel@tonic-gate 	} else {
7687c478bd9Sstevel@tonic-gate 		/*
7697c478bd9Sstevel@tonic-gate 		 * if a slot was found, then increment the slot in use count
7707c478bd9Sstevel@tonic-gate 		 * and try to read the metadata.
7717c478bd9Sstevel@tonic-gate 		 */
7727c478bd9Sstevel@tonic-gate 		cp->c_filegrp->fg_header->ach_count++;
7737c478bd9Sstevel@tonic-gate 		error = filegrp_read_metadata(cp->c_filegrp, cidp,
7747c478bd9Sstevel@tonic-gate 		    &cp->c_metadata);
7757c478bd9Sstevel@tonic-gate 	}
7767c478bd9Sstevel@tonic-gate 	/*
7777c478bd9Sstevel@tonic-gate 	 * if there wasn't a slot, or an attempt to read it results in ENOENT,
7787c478bd9Sstevel@tonic-gate 	 * then init the cache object, create the vnode, etc...
7797c478bd9Sstevel@tonic-gate 	 */
7807c478bd9Sstevel@tonic-gate 	if ((slotfound == 0) || (error == ENOENT)) {
7817c478bd9Sstevel@tonic-gate 		error = CFSOP_INIT_COBJECT(fscp, cp, vap, cr);
7827c478bd9Sstevel@tonic-gate 		if (error)
7837c478bd9Sstevel@tonic-gate 			goto out;
7847c478bd9Sstevel@tonic-gate 		ASSERT(cp->c_attr.va_type != 0);
7857c478bd9Sstevel@tonic-gate 		VN_SET_VFS_TYPE_DEV(vp, fscp->fs_cfsvfsp,
7867c478bd9Sstevel@tonic-gate 		    cp->c_attr.va_type, cp->c_attr.va_rdev);
7877c478bd9Sstevel@tonic-gate 		cp->c_metadata.md_rltype = CACHEFS_RL_NONE;
7887c478bd9Sstevel@tonic-gate 	} else if (error == 0) {
7897c478bd9Sstevel@tonic-gate 		/* slot found, no error occurred on the metadata read */
7907c478bd9Sstevel@tonic-gate 		cp->c_size = cp->c_attr.va_size;
7917c478bd9Sstevel@tonic-gate 
7927c478bd9Sstevel@tonic-gate 		if ((cachep->c_flags & CACHE_CHECK_RLTYPE) &&
7937c478bd9Sstevel@tonic-gate 		    (cp->c_metadata.md_rlno != 0) &&
7947c478bd9Sstevel@tonic-gate 		    (cp->c_metadata.md_rltype == CACHEFS_RL_ACTIVE)) {
7957c478bd9Sstevel@tonic-gate 			rl_entry_t rl, *rlp;
7967c478bd9Sstevel@tonic-gate 
7977c478bd9Sstevel@tonic-gate 			mutex_enter(&cachep->c_contentslock);
7987c478bd9Sstevel@tonic-gate 			error = cachefs_rl_entry_get(cachep,
7997c478bd9Sstevel@tonic-gate 			    cp->c_metadata.md_rlno, &rlp);
8007c478bd9Sstevel@tonic-gate 			if (error) {
8017c478bd9Sstevel@tonic-gate 				mutex_exit(&cachep->c_contentslock);
8027c478bd9Sstevel@tonic-gate 				goto out;
8037c478bd9Sstevel@tonic-gate 			}
8047c478bd9Sstevel@tonic-gate 			rl = *rlp;
8057c478bd9Sstevel@tonic-gate 			mutex_exit(&cachep->c_contentslock);
8067c478bd9Sstevel@tonic-gate 			if (cp->c_metadata.md_rltype != rl.rl_current) {
8077c478bd9Sstevel@tonic-gate 				cp->c_flags |= CN_UPDATED;
8087c478bd9Sstevel@tonic-gate 				cp->c_metadata.md_rltype = rl.rl_current;
8097c478bd9Sstevel@tonic-gate 			}
8107c478bd9Sstevel@tonic-gate 		}
8117c478bd9Sstevel@tonic-gate 
8127c478bd9Sstevel@tonic-gate 		/*
8137c478bd9Sstevel@tonic-gate 		 * If no cookie is specified, or if this is a local file,
8147c478bd9Sstevel@tonic-gate 		 * accept the one in the metadata.
8157c478bd9Sstevel@tonic-gate 		 */
8167c478bd9Sstevel@tonic-gate 		null_cookie = 0;
8177c478bd9Sstevel@tonic-gate 		if ((cookiep == NULL) || (cp->c_id.cid_flags & CFS_CID_LOCAL)) {
8187c478bd9Sstevel@tonic-gate 			cookiep = &cp->c_metadata.md_cookie;
8197c478bd9Sstevel@tonic-gate 			null_cookie = 1;
8207c478bd9Sstevel@tonic-gate 		}
8217c478bd9Sstevel@tonic-gate 
8227c478bd9Sstevel@tonic-gate 		/* if cookies do not match, reset the metadata */
8237c478bd9Sstevel@tonic-gate 		if ((cookiep->fid_len != cp->c_cookie.fid_len) ||
8247c478bd9Sstevel@tonic-gate 		    (bcmp(&cookiep->fid_data, &cp->c_cookie.fid_data,
8257c478bd9Sstevel@tonic-gate 			(size_t)cookiep->fid_len) != 0)) {
8267c478bd9Sstevel@tonic-gate 			cp->c_cookie = *cookiep;
8277c478bd9Sstevel@tonic-gate 			cp->c_flags |= CN_UPDATED;
8287c478bd9Sstevel@tonic-gate 			cp->c_metadata.md_timestamp.tv_sec = 0;
8297c478bd9Sstevel@tonic-gate 			/* clear all but the front file bit */
8307c478bd9Sstevel@tonic-gate 			cp->c_metadata.md_flags &= MD_FILE;
8317c478bd9Sstevel@tonic-gate 			error = CFSOP_INIT_COBJECT(fscp, cp, vap, cr);
8327c478bd9Sstevel@tonic-gate 			ASSERT(cp->c_attr.va_type != 0);
8337c478bd9Sstevel@tonic-gate 			VN_SET_VFS_TYPE_DEV(vp, fscp->fs_cfsvfsp,
8347c478bd9Sstevel@tonic-gate 			    cp->c_attr.va_type, cp->c_attr.va_rdev);
8357c478bd9Sstevel@tonic-gate 		}
8367c478bd9Sstevel@tonic-gate 
8377c478bd9Sstevel@tonic-gate 		/* else if the consistency type changed, fix it up */
8387c478bd9Sstevel@tonic-gate 		else if (cp->c_metadata.md_consttype != fscp->fs_consttype) {
8397c478bd9Sstevel@tonic-gate 			ASSERT(cp->c_attr.va_type != 0);
8407c478bd9Sstevel@tonic-gate 			VN_SET_VFS_TYPE_DEV(vp, fscp->fs_cfsvfsp,
8417c478bd9Sstevel@tonic-gate 			    cp->c_attr.va_type, cp->c_attr.va_rdev);
8427c478bd9Sstevel@tonic-gate 			CFSOP_CONVERT_COBJECT(fscp, cp, cr);
8437c478bd9Sstevel@tonic-gate 			if (!null_cookie) {
8447c478bd9Sstevel@tonic-gate 				error = CFSOP_CHECK_COBJECT(fscp, cp,
8457c478bd9Sstevel@tonic-gate 				    C_BACK_CHECK, cr);
8467c478bd9Sstevel@tonic-gate 			}
8477c478bd9Sstevel@tonic-gate 		}
8487c478bd9Sstevel@tonic-gate 
8497c478bd9Sstevel@tonic-gate 		/* else check the consistency of the data */
8507c478bd9Sstevel@tonic-gate 		else {
8517c478bd9Sstevel@tonic-gate 			ASSERT(cp->c_attr.va_type != 0);
8527c478bd9Sstevel@tonic-gate 			VN_SET_VFS_TYPE_DEV(vp, fscp->fs_cfsvfsp,
8537c478bd9Sstevel@tonic-gate 			    cp->c_attr.va_type, cp->c_attr.va_rdev);
8547c478bd9Sstevel@tonic-gate 			if (!null_cookie) {
8557c478bd9Sstevel@tonic-gate 				error = CFSOP_CHECK_COBJECT(fscp, cp, 0, cr);
8567c478bd9Sstevel@tonic-gate 			}
8577c478bd9Sstevel@tonic-gate 		}
8587c478bd9Sstevel@tonic-gate 	} else {
8597c478bd9Sstevel@tonic-gate 		goto out;
8607c478bd9Sstevel@tonic-gate 	}
8617c478bd9Sstevel@tonic-gate 	cachefs_cnode_setlocalstats(cp);
8627c478bd9Sstevel@tonic-gate 
8637c478bd9Sstevel@tonic-gate out:
8647c478bd9Sstevel@tonic-gate 	mutex_exit(&cp->c_statelock);
8657c478bd9Sstevel@tonic-gate 	if (error) {
8667c478bd9Sstevel@tonic-gate 		if (cp->c_frontvp)
8677c478bd9Sstevel@tonic-gate 			VN_RELE(cp->c_frontvp);
8687c478bd9Sstevel@tonic-gate 		if (cp->c_backvp)
8697c478bd9Sstevel@tonic-gate 			VN_RELE(cp->c_backvp);
8707c478bd9Sstevel@tonic-gate 		if (cp->c_acldirvp)
8717c478bd9Sstevel@tonic-gate 			VN_RELE(cp->c_acldirvp);
8727c478bd9Sstevel@tonic-gate 		filegrp_rele(fgp);
8737c478bd9Sstevel@tonic-gate 		rw_destroy(&cp->c_rwlock);
8747c478bd9Sstevel@tonic-gate 		mutex_destroy(&cp->c_statelock);
8757c478bd9Sstevel@tonic-gate 		cv_destroy(&cp->c_popcv);
8767c478bd9Sstevel@tonic-gate 		mutex_destroy(&cp->c_iomutex);
8777c478bd9Sstevel@tonic-gate 		cv_destroy(&cp->c_iocv);
8787c478bd9Sstevel@tonic-gate 	}
8797c478bd9Sstevel@tonic-gate 	return (error);
8807c478bd9Sstevel@tonic-gate }
8817c478bd9Sstevel@tonic-gate 
8827c478bd9Sstevel@tonic-gate /*
8837c478bd9Sstevel@tonic-gate  * Finds the cnode for the specified fileno and fid.
8847c478bd9Sstevel@tonic-gate  * Creates the cnode if it does not exist.
8857c478bd9Sstevel@tonic-gate  * The cnode is returned held.
8867c478bd9Sstevel@tonic-gate  */
8877c478bd9Sstevel@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)8887c478bd9Sstevel@tonic-gate cachefs_cnode_make(cfs_cid_t *cidp, fscache_t *fscp, fid_t *cookiep,
8897c478bd9Sstevel@tonic-gate 	vattr_t *vap, vnode_t *backvp, cred_t *cr, int flag, cnode_t **cpp)
8907c478bd9Sstevel@tonic-gate {
8917c478bd9Sstevel@tonic-gate 	struct cnode *cp;
8927c478bd9Sstevel@tonic-gate 	int error;
8937c478bd9Sstevel@tonic-gate 	struct filegrp *fgp;
8947c478bd9Sstevel@tonic-gate 	struct cachefs_metadata *mdp;
8957c478bd9Sstevel@tonic-gate 	fid_t cookie;
8967c478bd9Sstevel@tonic-gate 
8977c478bd9Sstevel@tonic-gate #ifdef CFSDEBUG
8987c478bd9Sstevel@tonic-gate 	CFS_DEBUG(CFSDEBUG_CNODE)
8997c478bd9Sstevel@tonic-gate 		printf("cachefs_cnode_make: ENTER fileno %llu\n",
9007c478bd9Sstevel@tonic-gate 		    (u_longlong_t)cidp->cid_fileno);
9017c478bd9Sstevel@tonic-gate #endif
9027c478bd9Sstevel@tonic-gate 
9037c478bd9Sstevel@tonic-gate 	/* get the file group that owns this file */
9047c478bd9Sstevel@tonic-gate 	mutex_enter(&fscp->fs_fslock);
9057c478bd9Sstevel@tonic-gate 	fgp = filegrp_list_find(fscp, cidp);
9067c478bd9Sstevel@tonic-gate 	if (fgp == NULL) {
9077c478bd9Sstevel@tonic-gate 		fgp = filegrp_create(fscp, cidp);
9087c478bd9Sstevel@tonic-gate 		filegrp_list_add(fscp, fgp);
9097c478bd9Sstevel@tonic-gate 	}
9107c478bd9Sstevel@tonic-gate 	filegrp_hold(fgp);
9117c478bd9Sstevel@tonic-gate 	mutex_exit(&fscp->fs_fslock);
9127c478bd9Sstevel@tonic-gate 
9137c478bd9Sstevel@tonic-gate 	/* grab the cnode list lock */
9147c478bd9Sstevel@tonic-gate 	mutex_enter(&fgp->fg_cnodelock);
9157c478bd9Sstevel@tonic-gate 
9167c478bd9Sstevel@tonic-gate 	if ((fgp->fg_flags & CFS_FG_READ) == 0)
9177c478bd9Sstevel@tonic-gate 		flag |= CN_NOCACHE;
9187c478bd9Sstevel@tonic-gate 
9197c478bd9Sstevel@tonic-gate 	error = 0;
9207c478bd9Sstevel@tonic-gate 	cp = NULL;
9217c478bd9Sstevel@tonic-gate 
9227c478bd9Sstevel@tonic-gate 	/* look for the cnode on the cnode list */
9237c478bd9Sstevel@tonic-gate 	error = cachefs_cnode_find(fgp, cidp, cookiep, &cp, backvp, vap);
9247c478bd9Sstevel@tonic-gate 
9257c478bd9Sstevel@tonic-gate 	/*
9267c478bd9Sstevel@tonic-gate 	 * If there already is a cnode with this cid but a different cookie,
9277c478bd9Sstevel@tonic-gate 	 * (or backvp) we're not going to be using the one we found.
9287c478bd9Sstevel@tonic-gate 	 */
9297c478bd9Sstevel@tonic-gate 	if (error && CFS_ISFS_BACKFS_NFSV4(fscp)) {
9307c478bd9Sstevel@tonic-gate 		ASSERT(MUTEX_HELD(&cp->c_statelock));
9317c478bd9Sstevel@tonic-gate 		cachefs_cnode_stale(cp);
9327c478bd9Sstevel@tonic-gate 		mutex_exit(&cp->c_statelock);
9337c478bd9Sstevel@tonic-gate 		cp = NULL;
9347c478bd9Sstevel@tonic-gate 		error = 0;
9357c478bd9Sstevel@tonic-gate 	} else if (error) {
9367c478bd9Sstevel@tonic-gate 		ASSERT(cp);
9377c478bd9Sstevel@tonic-gate 		ASSERT(cookiep);
9387c478bd9Sstevel@tonic-gate 
9397c478bd9Sstevel@tonic-gate 		mutex_exit(&cp->c_statelock);
9407c478bd9Sstevel@tonic-gate 
9417c478bd9Sstevel@tonic-gate 		/*
9427c478bd9Sstevel@tonic-gate 		 * If backvp is NULL then someone tried to use
9437c478bd9Sstevel@tonic-gate 		 * a stale cookie.
9447c478bd9Sstevel@tonic-gate 		 */
9457c478bd9Sstevel@tonic-gate 		if (backvp == NULL) {
9467c478bd9Sstevel@tonic-gate 			mutex_exit(&fgp->fg_cnodelock);
9477c478bd9Sstevel@tonic-gate 			error = ESTALE;
9487c478bd9Sstevel@tonic-gate 			goto out;
9497c478bd9Sstevel@tonic-gate 		}
9507c478bd9Sstevel@tonic-gate 
9517c478bd9Sstevel@tonic-gate 		/* verify the backvp */
9527c478bd9Sstevel@tonic-gate 		error = cachefs_getcookie(backvp, &cookie, NULL, cr, TRUE);
9537c478bd9Sstevel@tonic-gate 		if (error ||
9547c478bd9Sstevel@tonic-gate 		    ((cookiep->fid_len != cookie.fid_len) ||
9557c478bd9Sstevel@tonic-gate 		    (bcmp(&cookiep->fid_data, cookie.fid_data,
9567c478bd9Sstevel@tonic-gate 			(size_t)cookiep->fid_len) != 0))) {
9577c478bd9Sstevel@tonic-gate 			mutex_exit(&fgp->fg_cnodelock);
9587c478bd9Sstevel@tonic-gate 			error = ESTALE;
9597c478bd9Sstevel@tonic-gate 			goto out;
9607c478bd9Sstevel@tonic-gate 		}
9617c478bd9Sstevel@tonic-gate 
9627c478bd9Sstevel@tonic-gate 		/* make the old cnode give up its front file resources */
9637c478bd9Sstevel@tonic-gate 		VN_HOLD(CTOV(cp));
9647c478bd9Sstevel@tonic-gate 		(void) cachefs_sync_metadata(cp);
9657c478bd9Sstevel@tonic-gate 		mutex_enter(&cp->c_statelock);
9667c478bd9Sstevel@tonic-gate 		mdp = &cp->c_metadata;
9677c478bd9Sstevel@tonic-gate 		if (mdp->md_rlno) {
9687c478bd9Sstevel@tonic-gate 			/* XXX sam: should this assert be NOCACHE? */
9697c478bd9Sstevel@tonic-gate 			/* XXX sam: maybe we should handle NOFILL as no-op */
9707c478bd9Sstevel@tonic-gate 			ASSERT((fscp->fs_cache->c_flags & CACHE_NOFILL) == 0);
9717c478bd9Sstevel@tonic-gate 
9727c478bd9Sstevel@tonic-gate 			/* if modified in the cache, move to lost+found */
9737c478bd9Sstevel@tonic-gate 			if ((cp->c_attr.va_type == VREG) &&
9747c478bd9Sstevel@tonic-gate 			    (cp->c_metadata.md_rltype == CACHEFS_RL_MODIFIED)) {
9757c478bd9Sstevel@tonic-gate 				error = cachefs_cnode_lostfound(cp, NULL);
9767c478bd9Sstevel@tonic-gate 				if (error) {
9777c478bd9Sstevel@tonic-gate 					mutex_exit(&cp->c_statelock);
9787c478bd9Sstevel@tonic-gate 					VN_RELE(CTOV(cp));
9797c478bd9Sstevel@tonic-gate 					mutex_exit(&fgp->fg_cnodelock);
9807c478bd9Sstevel@tonic-gate 					error = ESTALE;
9817c478bd9Sstevel@tonic-gate 					goto out;
9827c478bd9Sstevel@tonic-gate 				}
9837c478bd9Sstevel@tonic-gate 			}
9847c478bd9Sstevel@tonic-gate 
9857c478bd9Sstevel@tonic-gate 			/* else nuke the front file */
9867c478bd9Sstevel@tonic-gate 			else {
9877c478bd9Sstevel@tonic-gate 				cachefs_cnode_stale(cp);
9887c478bd9Sstevel@tonic-gate 			}
9897c478bd9Sstevel@tonic-gate 		} else {
9907c478bd9Sstevel@tonic-gate 			cachefs_cnode_stale(cp);
9917c478bd9Sstevel@tonic-gate 		}
9927c478bd9Sstevel@tonic-gate 		mutex_exit(&cp->c_statelock);
9937c478bd9Sstevel@tonic-gate 		VN_RELE(CTOV(cp));
9947c478bd9Sstevel@tonic-gate 		cp = NULL;
9957c478bd9Sstevel@tonic-gate 		error = 0;
9967c478bd9Sstevel@tonic-gate 	}
9977c478bd9Sstevel@tonic-gate 
9987c478bd9Sstevel@tonic-gate 
9997c478bd9Sstevel@tonic-gate 	/* if the cnode does not exist */
10007c478bd9Sstevel@tonic-gate 	if (cp == NULL) {
10017c478bd9Sstevel@tonic-gate 		/* XXX should we drop all locks for this? */
10027c478bd9Sstevel@tonic-gate 		cp = kmem_cache_alloc(cachefs_cnode_cache, KM_SLEEP);
10037c478bd9Sstevel@tonic-gate 
10047c478bd9Sstevel@tonic-gate 		error = cachefs_cnode_init(cidp, cp, fscp, fgp,
10057c478bd9Sstevel@tonic-gate 		    cookiep, vap, backvp, flag, cr);
10067c478bd9Sstevel@tonic-gate 		if (error) {
10077c478bd9Sstevel@tonic-gate 			mutex_exit(&fgp->fg_cnodelock);
10087c478bd9Sstevel@tonic-gate 			vn_free(cp->c_vnode);
10097c478bd9Sstevel@tonic-gate 			kmem_cache_free(cachefs_cnode_cache, cp);
10107c478bd9Sstevel@tonic-gate 			goto out;
10117c478bd9Sstevel@tonic-gate 		}
10127c478bd9Sstevel@tonic-gate 
10137c478bd9Sstevel@tonic-gate 		if (cp->c_metadata.md_rlno &&
10147c478bd9Sstevel@tonic-gate 		    (cp->c_metadata.md_rltype == CACHEFS_RL_GC) &&
10157c478bd9Sstevel@tonic-gate 		    ((fscp->fs_cache->c_flags & CACHE_NOFILL) == 0)) {
10167c478bd9Sstevel@tonic-gate #ifdef CFSDEBUG
10177c478bd9Sstevel@tonic-gate 			cachefs_rlent_verify(fscp->fs_cache,
10187c478bd9Sstevel@tonic-gate 			    CACHEFS_RL_GC, cp->c_metadata.md_rlno);
10197c478bd9Sstevel@tonic-gate #endif /* CFSDEBUG */
10207c478bd9Sstevel@tonic-gate 			cachefs_rlent_moveto(fscp->fs_cache,
10217c478bd9Sstevel@tonic-gate 			    CACHEFS_RL_ACTIVE, cp->c_metadata.md_rlno,
10227c478bd9Sstevel@tonic-gate 			    cp->c_metadata.md_frontblks);
10237c478bd9Sstevel@tonic-gate 			cp->c_metadata.md_rltype = CACHEFS_RL_ACTIVE;
10247c478bd9Sstevel@tonic-gate 			cp->c_flags |= CN_UPDATED;
10257c478bd9Sstevel@tonic-gate 		}
10267c478bd9Sstevel@tonic-gate 
10277c478bd9Sstevel@tonic-gate 		cachefs_cnode_listadd(cp);
10287c478bd9Sstevel@tonic-gate 		vn_exists(cp->c_vnode);
10297c478bd9Sstevel@tonic-gate 		mutex_exit(&fgp->fg_cnodelock);
10307c478bd9Sstevel@tonic-gate 		(void) fscache_cnodecnt(fscp, 1);
10317c478bd9Sstevel@tonic-gate 	}
10327c478bd9Sstevel@tonic-gate 
10337c478bd9Sstevel@tonic-gate 	/* else if the cnode exists */
10347c478bd9Sstevel@tonic-gate 	else {
10357c478bd9Sstevel@tonic-gate 		VN_HOLD(CTOV(cp));
10367c478bd9Sstevel@tonic-gate 
10377c478bd9Sstevel@tonic-gate 		/* remove from idle list if on it */
10387c478bd9Sstevel@tonic-gate 		if (cp->c_flags & CN_IDLE) {
10397c478bd9Sstevel@tonic-gate 			cp->c_flags &= ~CN_IDLE;
10407c478bd9Sstevel@tonic-gate 
10417c478bd9Sstevel@tonic-gate 			mutex_enter(&fscp->fs_idlelock);
10427c478bd9Sstevel@tonic-gate 			cachefs_cnode_idlerem(cp);
10437c478bd9Sstevel@tonic-gate 			mutex_exit(&fscp->fs_idlelock);
10447c478bd9Sstevel@tonic-gate 			VN_RELE(CTOV(cp));
10457c478bd9Sstevel@tonic-gate 			cp->c_ipending = 0;
10467c478bd9Sstevel@tonic-gate 		}
10477c478bd9Sstevel@tonic-gate 		mutex_exit(&cp->c_statelock);
10487c478bd9Sstevel@tonic-gate 		mutex_exit(&fgp->fg_cnodelock);
10497c478bd9Sstevel@tonic-gate 	}
10507c478bd9Sstevel@tonic-gate 
10517c478bd9Sstevel@tonic-gate 	/*
10527c478bd9Sstevel@tonic-gate 	 * Assertion to ensure the cnode matches
10537c478bd9Sstevel@tonic-gate 	 * the backvp and attribute type information.
10547c478bd9Sstevel@tonic-gate 	 */
10557c478bd9Sstevel@tonic-gate 	ASSERT((CFS_ISFS_BACKFS_NFSV4(fscp) == 0) ||
10567c478bd9Sstevel@tonic-gate 		((cp->c_backvp == backvp) &&
10577c478bd9Sstevel@tonic-gate 		(cp->c_attr.va_type == vap->va_type)));
10587c478bd9Sstevel@tonic-gate out:
10597c478bd9Sstevel@tonic-gate 	*cpp = ((error == 0) ? cp : NULL);
10607c478bd9Sstevel@tonic-gate 	filegrp_rele(fgp);
10617c478bd9Sstevel@tonic-gate 
10627c478bd9Sstevel@tonic-gate #ifdef CFSDEBUG
10637c478bd9Sstevel@tonic-gate 	CFS_DEBUG(CFSDEBUG_CNODE)
10647c478bd9Sstevel@tonic-gate 		printf("cachefs_cnode_make: EXIT cp %p, error %d\n",
10657c478bd9Sstevel@tonic-gate 		    (void *)*cpp, error);
10667c478bd9Sstevel@tonic-gate #endif
10677c478bd9Sstevel@tonic-gate 	return (error);
10687c478bd9Sstevel@tonic-gate }
10697c478bd9Sstevel@tonic-gate 
10707c478bd9Sstevel@tonic-gate /*
10717c478bd9Sstevel@tonic-gate  * cachefs_cid_inuse()
10727c478bd9Sstevel@tonic-gate  *
10737c478bd9Sstevel@tonic-gate  * returns nonzero if a cid has any data in the cache; either a cnode
10747c478bd9Sstevel@tonic-gate  * or metadata.
10757c478bd9Sstevel@tonic-gate  */
10767c478bd9Sstevel@tonic-gate 
10777c478bd9Sstevel@tonic-gate int
cachefs_cid_inuse(filegrp_t * fgp,cfs_cid_t * cidp)10787c478bd9Sstevel@tonic-gate cachefs_cid_inuse(filegrp_t *fgp, cfs_cid_t *cidp)
10797c478bd9Sstevel@tonic-gate {
10807c478bd9Sstevel@tonic-gate 	cnode_t *cp;
10817c478bd9Sstevel@tonic-gate 	int status = 0;
10827c478bd9Sstevel@tonic-gate 
10837c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&fgp->fg_cnodelock));
10847c478bd9Sstevel@tonic-gate 
10857c478bd9Sstevel@tonic-gate 	/*
10867c478bd9Sstevel@tonic-gate 	 * Since we don't care about the cookie data, we don't care about any
10877c478bd9Sstevel@tonic-gate 	 * status that find might return.
10887c478bd9Sstevel@tonic-gate 	 */
10897c478bd9Sstevel@tonic-gate 
10907c478bd9Sstevel@tonic-gate 	cp = NULL;
10917c478bd9Sstevel@tonic-gate 	(void) cachefs_cnode_find(fgp, cidp, NULL, &cp, NULL, NULL);
10927c478bd9Sstevel@tonic-gate 	if (cp != NULL) {
10937c478bd9Sstevel@tonic-gate 		mutex_exit(&cp->c_statelock);
10947c478bd9Sstevel@tonic-gate 		status = 1;
10957c478bd9Sstevel@tonic-gate 		return (status);
10967c478bd9Sstevel@tonic-gate 	}
10977c478bd9Sstevel@tonic-gate 
10987c478bd9Sstevel@tonic-gate 	/*
10997c478bd9Sstevel@tonic-gate 	 * Don't want to use filegrp_read_metadata, since it will return
11007c478bd9Sstevel@tonic-gate 	 * ENOENT if the metadata slot exists but hasn't been written to yet.
11017c478bd9Sstevel@tonic-gate 	 * That condition still counts as the slot (metadata) being in use.
11027c478bd9Sstevel@tonic-gate 	 * Instead, as long as the filegrp attrcache has been created and
11037c478bd9Sstevel@tonic-gate 	 * there's a slot assigned for this cid, then the metadata is in use.
11047c478bd9Sstevel@tonic-gate 	 */
11057c478bd9Sstevel@tonic-gate 	if (((fgp->fg_flags & CFS_FG_ALLOC_ATTR) == 0) &&
11067c478bd9Sstevel@tonic-gate 	    (filegrp_cid_to_slot(fgp, cidp) != 0))
11077c478bd9Sstevel@tonic-gate 		status = 1;
11087c478bd9Sstevel@tonic-gate 
11097c478bd9Sstevel@tonic-gate 	return (status);
11107c478bd9Sstevel@tonic-gate }
11117c478bd9Sstevel@tonic-gate 
11127c478bd9Sstevel@tonic-gate /*
11137c478bd9Sstevel@tonic-gate  * cachefs_fileno_inuse()
11147c478bd9Sstevel@tonic-gate  *
11157c478bd9Sstevel@tonic-gate  * returns nonzero if a fileno is known to the cache, as either a
11167c478bd9Sstevel@tonic-gate  * local or a normal file.
11177c478bd9Sstevel@tonic-gate  */
11187c478bd9Sstevel@tonic-gate 
11197c478bd9Sstevel@tonic-gate int
cachefs_fileno_inuse(fscache_t * fscp,ino64_t fileno)11207c478bd9Sstevel@tonic-gate cachefs_fileno_inuse(fscache_t *fscp, ino64_t fileno)
11217c478bd9Sstevel@tonic-gate {
11227c478bd9Sstevel@tonic-gate 	cfs_cid_t cid;
11237c478bd9Sstevel@tonic-gate 	filegrp_t *fgp;
11247c478bd9Sstevel@tonic-gate 	int known = 0;
11257c478bd9Sstevel@tonic-gate 
11267c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&fscp->fs_fslock));
11277c478bd9Sstevel@tonic-gate 	cid.cid_fileno = fileno;
11287c478bd9Sstevel@tonic-gate 
11297c478bd9Sstevel@tonic-gate 	/* if there's no filegrp for this cid range, then there's no data */
11307c478bd9Sstevel@tonic-gate 	fgp = filegrp_list_find(fscp, &cid);
11317c478bd9Sstevel@tonic-gate 	if (fgp == NULL)
11327c478bd9Sstevel@tonic-gate 		return (known);
11337c478bd9Sstevel@tonic-gate 
11347c478bd9Sstevel@tonic-gate 	filegrp_hold(fgp);
11357c478bd9Sstevel@tonic-gate 	mutex_enter(&fgp->fg_cnodelock);
11367c478bd9Sstevel@tonic-gate 
11377c478bd9Sstevel@tonic-gate 	cid.cid_flags = CFS_CID_LOCAL;
11387c478bd9Sstevel@tonic-gate 	if (cachefs_cid_inuse(fgp, &cid)) {
11397c478bd9Sstevel@tonic-gate 		known = 1;
11407c478bd9Sstevel@tonic-gate 		goto out;
11417c478bd9Sstevel@tonic-gate 	}
11427c478bd9Sstevel@tonic-gate 	cid.cid_flags = 0;
11437c478bd9Sstevel@tonic-gate 	if (cachefs_cid_inuse(fgp, &cid))
11447c478bd9Sstevel@tonic-gate 		known = 1;
11457c478bd9Sstevel@tonic-gate out:
11467c478bd9Sstevel@tonic-gate 	mutex_exit(&fgp->fg_cnodelock);
11477c478bd9Sstevel@tonic-gate 	filegrp_rele(fgp);
11487c478bd9Sstevel@tonic-gate 	return (known);
11497c478bd9Sstevel@tonic-gate }
11507c478bd9Sstevel@tonic-gate 
11517c478bd9Sstevel@tonic-gate /*
11527c478bd9Sstevel@tonic-gate  * Creates a cnode from an unused inode in the cache.
11537c478bd9Sstevel@tonic-gate  * The cnode is returned held.
11547c478bd9Sstevel@tonic-gate  */
11557c478bd9Sstevel@tonic-gate int
cachefs_cnode_create(fscache_t * fscp,vattr_t * vap,int flag,cnode_t ** cpp)11567c478bd9Sstevel@tonic-gate cachefs_cnode_create(fscache_t *fscp, vattr_t *vap, int flag, cnode_t **cpp)
11577c478bd9Sstevel@tonic-gate {
11587c478bd9Sstevel@tonic-gate 	struct cnode *cp;
11597c478bd9Sstevel@tonic-gate 	int error, found;
11607c478bd9Sstevel@tonic-gate 	struct filegrp *fgp;
11617c478bd9Sstevel@tonic-gate 	cfs_cid_t cid, cid2;
11627c478bd9Sstevel@tonic-gate 
11637c478bd9Sstevel@tonic-gate 	ASSERT(CFS_ISFS_SNR(fscp));
11647c478bd9Sstevel@tonic-gate 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
11657c478bd9Sstevel@tonic-gate 
11667c478bd9Sstevel@tonic-gate 	cid.cid_flags = CFS_CID_LOCAL;
11677c478bd9Sstevel@tonic-gate 	cid2.cid_flags = 0;
11687c478bd9Sstevel@tonic-gate 
11697c478bd9Sstevel@tonic-gate 	/* find an unused local file in the cache */
11707c478bd9Sstevel@tonic-gate 	for (;;) {
11717c478bd9Sstevel@tonic-gate 		mutex_enter(&fscp->fs_fslock);
11727c478bd9Sstevel@tonic-gate 
11737c478bd9Sstevel@tonic-gate 		/* make sure we did not wrap */
11747c478bd9Sstevel@tonic-gate 		fscp->fs_info.fi_localfileno++;
11757c478bd9Sstevel@tonic-gate 		if (fscp->fs_info.fi_localfileno == 0)
11767c478bd9Sstevel@tonic-gate 			fscp->fs_info.fi_localfileno = 3;
11777c478bd9Sstevel@tonic-gate 		cid.cid_fileno = fscp->fs_info.fi_localfileno;
11787c478bd9Sstevel@tonic-gate 		fscp->fs_flags |= CFS_FS_DIRTYINFO;
11797c478bd9Sstevel@tonic-gate 
11807c478bd9Sstevel@tonic-gate 		/* avoid fileno conflict in non-local space */
11817c478bd9Sstevel@tonic-gate 		cid2.cid_fileno = cid.cid_fileno;
11827c478bd9Sstevel@tonic-gate 		fgp = filegrp_list_find(fscp, &cid2);
11837c478bd9Sstevel@tonic-gate 		if (fgp != NULL) {
11847c478bd9Sstevel@tonic-gate 			filegrp_hold(fgp);
11857c478bd9Sstevel@tonic-gate 			mutex_enter(&fgp->fg_cnodelock);
11867c478bd9Sstevel@tonic-gate 			found = cachefs_cid_inuse(fgp, &cid2);
11877c478bd9Sstevel@tonic-gate 			mutex_exit(&fgp->fg_cnodelock);
11887c478bd9Sstevel@tonic-gate 			filegrp_rele(fgp);
11897c478bd9Sstevel@tonic-gate 			if (found) {
11907c478bd9Sstevel@tonic-gate 				mutex_exit(&fscp->fs_fslock);
11917c478bd9Sstevel@tonic-gate 				continue;
11927c478bd9Sstevel@tonic-gate 			}
11937c478bd9Sstevel@tonic-gate 		}
11947c478bd9Sstevel@tonic-gate 
11957c478bd9Sstevel@tonic-gate 		/* get the file group that owns this fileno */
11967c478bd9Sstevel@tonic-gate 		fgp = filegrp_list_find(fscp, &cid);
11977c478bd9Sstevel@tonic-gate 		if (fgp == NULL) {
11987c478bd9Sstevel@tonic-gate 			fgp = filegrp_create(fscp, &cid);
11997c478bd9Sstevel@tonic-gate 			filegrp_list_add(fscp, fgp);
12007c478bd9Sstevel@tonic-gate 		}
12017c478bd9Sstevel@tonic-gate 
12027c478bd9Sstevel@tonic-gate 		/* see if there is any room left in this file group */
12037c478bd9Sstevel@tonic-gate 		mutex_enter(&fgp->fg_mutex);
12047c478bd9Sstevel@tonic-gate 		if (fgp->fg_header &&
12057c478bd9Sstevel@tonic-gate 		    (fgp->fg_header->ach_count ==
12067c478bd9Sstevel@tonic-gate 		    fscp->fs_info.fi_fgsize)) {
12077c478bd9Sstevel@tonic-gate 			/* no more room, set up for the next file group */
12087c478bd9Sstevel@tonic-gate 			fscp->fs_info.fi_localfileno = fgp->fg_id.cid_fileno +
12097c478bd9Sstevel@tonic-gate 			    fscp->fs_info.fi_fgsize;
12107c478bd9Sstevel@tonic-gate 			mutex_exit(&fgp->fg_mutex);
12117c478bd9Sstevel@tonic-gate 			mutex_exit(&fscp->fs_fslock);
12127c478bd9Sstevel@tonic-gate 			continue;
12137c478bd9Sstevel@tonic-gate 		}
12147c478bd9Sstevel@tonic-gate 		mutex_exit(&fgp->fg_mutex);
12157c478bd9Sstevel@tonic-gate 
12167c478bd9Sstevel@tonic-gate 		filegrp_hold(fgp);
12177c478bd9Sstevel@tonic-gate 		mutex_exit(&fscp->fs_fslock);
12187c478bd9Sstevel@tonic-gate 
12197c478bd9Sstevel@tonic-gate 		ASSERT((fgp->fg_flags &
12207c478bd9Sstevel@tonic-gate 		    (CFS_FG_READ | CFS_FG_WRITE)) ==
12217c478bd9Sstevel@tonic-gate 		    (CFS_FG_READ | CFS_FG_WRITE));
12227c478bd9Sstevel@tonic-gate 
12237c478bd9Sstevel@tonic-gate 		/* grab the cnode list lock */
12247c478bd9Sstevel@tonic-gate 		mutex_enter(&fgp->fg_cnodelock);
12257c478bd9Sstevel@tonic-gate 
12267c478bd9Sstevel@tonic-gate 		if ((fgp->fg_flags & CFS_FG_READ) == 0)
12277c478bd9Sstevel@tonic-gate 			flag |= CN_NOCACHE;
12287c478bd9Sstevel@tonic-gate 
12297c478bd9Sstevel@tonic-gate 		/* keep looking if a cnode or metadata exist for this fileno */
12307c478bd9Sstevel@tonic-gate 		if (cachefs_cid_inuse(fgp, &cid)) {
12317c478bd9Sstevel@tonic-gate 			mutex_exit(&fgp->fg_cnodelock);
12327c478bd9Sstevel@tonic-gate 			filegrp_rele(fgp);
12337c478bd9Sstevel@tonic-gate #ifdef CFSDEBUG
12347c478bd9Sstevel@tonic-gate 			CFS_DEBUG(CFSDEBUG_CNODE)
12357c478bd9Sstevel@tonic-gate 				cmn_err(CE_NOTE, "cachefs_cnode_create: "
12367c478bd9Sstevel@tonic-gate 				    "fileno %llu exists.\n",
12377c478bd9Sstevel@tonic-gate 				    (u_longlong_t)cid.cid_fileno);
12387c478bd9Sstevel@tonic-gate #endif
12397c478bd9Sstevel@tonic-gate 			continue;
12407c478bd9Sstevel@tonic-gate 		}
12417c478bd9Sstevel@tonic-gate 		break;
12427c478bd9Sstevel@tonic-gate 	}
12437c478bd9Sstevel@tonic-gate 
12447c478bd9Sstevel@tonic-gate 	vap->va_nodeid = cid.cid_fileno;
12457c478bd9Sstevel@tonic-gate 
12467c478bd9Sstevel@tonic-gate 	/* create space for the cnode */
12477c478bd9Sstevel@tonic-gate 	cp = kmem_cache_alloc(cachefs_cnode_cache, KM_SLEEP);
12487c478bd9Sstevel@tonic-gate 
12497c478bd9Sstevel@tonic-gate 	/* set up the cnode */
12507c478bd9Sstevel@tonic-gate 	error = cachefs_cnode_init(&cid, cp, fscp, fgp,
12517c478bd9Sstevel@tonic-gate 	    &cp->c_cookie, vap, NULL, flag, kcred);
12527c478bd9Sstevel@tonic-gate 	if (error) {
12537c478bd9Sstevel@tonic-gate 		mutex_exit(&fgp->fg_cnodelock);
12547c478bd9Sstevel@tonic-gate 		vn_free(cp->c_vnode);
12557c478bd9Sstevel@tonic-gate 		kmem_cache_free(cachefs_cnode_cache, cp);
12567c478bd9Sstevel@tonic-gate 		goto out;
12577c478bd9Sstevel@tonic-gate 	}
12587c478bd9Sstevel@tonic-gate 
12597c478bd9Sstevel@tonic-gate 	/* save copy of fileno that is returned to the user */
12607c478bd9Sstevel@tonic-gate 	cp->c_metadata.md_flags |= MD_LOCALFILENO;
12617c478bd9Sstevel@tonic-gate 	cp->c_metadata.md_localfileno = cid.cid_fileno;
12627c478bd9Sstevel@tonic-gate 	cp->c_flags |= CN_UPDATED;
12637c478bd9Sstevel@tonic-gate 
12647c478bd9Sstevel@tonic-gate 	cachefs_cnode_listadd(cp);
12657c478bd9Sstevel@tonic-gate 	mutex_exit(&fgp->fg_cnodelock);
12667c478bd9Sstevel@tonic-gate 	(void) fscache_cnodecnt(fscp, 1);
12677c478bd9Sstevel@tonic-gate 
12687c478bd9Sstevel@tonic-gate out:
12697c478bd9Sstevel@tonic-gate 	*cpp = ((error == 0) ? cp : NULL);
12707c478bd9Sstevel@tonic-gate 	filegrp_rele(fgp);
12717c478bd9Sstevel@tonic-gate 	return (error);
12727c478bd9Sstevel@tonic-gate }
12737c478bd9Sstevel@tonic-gate 
12747c478bd9Sstevel@tonic-gate /*
12757c478bd9Sstevel@tonic-gate  * Moves the cnode to its new location in the cache.
12767c478bd9Sstevel@tonic-gate  * Before calling this routine other steps must be taken
12777c478bd9Sstevel@tonic-gate  * to ensure that other file system routines that operate
12787c478bd9Sstevel@tonic-gate  * on cnodes do not run.
12797c478bd9Sstevel@tonic-gate  */
12807c478bd9Sstevel@tonic-gate void
cachefs_cnode_move(cnode_t * cp)12817c478bd9Sstevel@tonic-gate cachefs_cnode_move(cnode_t *cp)
12827c478bd9Sstevel@tonic-gate {
12837c478bd9Sstevel@tonic-gate 	fscache_t *fscp = C_TO_FSCACHE(cp);
12847c478bd9Sstevel@tonic-gate 	cfs_cid_t cid;
12857c478bd9Sstevel@tonic-gate 	filegrp_t *fgp;
12867c478bd9Sstevel@tonic-gate 	filegrp_t *ofgp = cp->c_filegrp;
12877c478bd9Sstevel@tonic-gate 	struct cachefs_metadata *mdp;
12887c478bd9Sstevel@tonic-gate 	cnode_t *xcp;
12897c478bd9Sstevel@tonic-gate 	char oname[CFS_FRONTFILE_NAME_SIZE];
12907c478bd9Sstevel@tonic-gate 	char nname[CFS_FRONTFILE_NAME_SIZE];
12917c478bd9Sstevel@tonic-gate 	int ffnuke = 0;
12927c478bd9Sstevel@tonic-gate 	int error;
12937c478bd9Sstevel@tonic-gate 
12947c478bd9Sstevel@tonic-gate 	ASSERT(CFS_ISFS_SNR(fscp));
12957c478bd9Sstevel@tonic-gate 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
12967c478bd9Sstevel@tonic-gate 	ASSERT(cp->c_id.cid_flags & CFS_CID_LOCAL);
12977c478bd9Sstevel@tonic-gate 	ASSERT(cp->c_attr.va_nodeid != 0);
12987c478bd9Sstevel@tonic-gate 
12997c478bd9Sstevel@tonic-gate 	/* construct the cid of the new file location */
13007c478bd9Sstevel@tonic-gate 	cid.cid_fileno = cp->c_attr.va_nodeid;
13017c478bd9Sstevel@tonic-gate 	cid.cid_flags = 0;
13027c478bd9Sstevel@tonic-gate 
13037c478bd9Sstevel@tonic-gate 	/* see if there already is a file occupying our slot */
13047c478bd9Sstevel@tonic-gate 	error = cachefs_cnode_make(&cid, fscp, NULL, NULL, NULL, kcred,
13057c478bd9Sstevel@tonic-gate 	    0, &xcp);
13067c478bd9Sstevel@tonic-gate 	if (error == 0) {
13077c478bd9Sstevel@tonic-gate 		mutex_enter(&xcp->c_statelock);
13087c478bd9Sstevel@tonic-gate 		cachefs_cnode_stale(xcp);
13097c478bd9Sstevel@tonic-gate 		mutex_exit(&xcp->c_statelock);
13107c478bd9Sstevel@tonic-gate 		VN_RELE(CTOV(xcp));
13117c478bd9Sstevel@tonic-gate 		xcp = NULL;
13127c478bd9Sstevel@tonic-gate 		error = 0;
13137c478bd9Sstevel@tonic-gate 	}
13147c478bd9Sstevel@tonic-gate 
13157c478bd9Sstevel@tonic-gate 	/* get the file group that this file is moving to */
13167c478bd9Sstevel@tonic-gate 	mutex_enter(&fscp->fs_fslock);
13177c478bd9Sstevel@tonic-gate 	fgp = filegrp_list_find(fscp, &cid);
13187c478bd9Sstevel@tonic-gate 	if (fgp == NULL) {
13197c478bd9Sstevel@tonic-gate 		fgp = filegrp_create(fscp, &cid);
13207c478bd9Sstevel@tonic-gate 		filegrp_list_add(fscp, fgp);
13217c478bd9Sstevel@tonic-gate 	}
13227c478bd9Sstevel@tonic-gate 	filegrp_hold(fgp);
13237c478bd9Sstevel@tonic-gate 	mutex_exit(&fscp->fs_fslock);
13247c478bd9Sstevel@tonic-gate 
13257c478bd9Sstevel@tonic-gate 	/* XXX fix to not have to create metadata to hold rl slot */
13267c478bd9Sstevel@tonic-gate 	/* get a metadata slot in the new file group */
13277c478bd9Sstevel@tonic-gate 	if (fgp->fg_flags & CFS_FG_ALLOC_ATTR) {
13287c478bd9Sstevel@tonic-gate 		(void) filegrp_allocattr(fgp);
13297c478bd9Sstevel@tonic-gate 	}
13307c478bd9Sstevel@tonic-gate 	/* XXX can fix create_metadata to call allocattr if necessary? */
13317c478bd9Sstevel@tonic-gate 	error = filegrp_create_metadata(fgp, &cp->c_metadata, &cid);
13327c478bd9Sstevel@tonic-gate 	if (error)
13337c478bd9Sstevel@tonic-gate 		ffnuke = 1;
13347c478bd9Sstevel@tonic-gate 	if ((ffnuke == 0) && filegrp_ffhold(fgp))
13357c478bd9Sstevel@tonic-gate 		ffnuke = 1;
13367c478bd9Sstevel@tonic-gate 
13377c478bd9Sstevel@tonic-gate 	/* move the front file to the new file group */
13387c478bd9Sstevel@tonic-gate 	if ((ffnuke == 0) && (cp->c_metadata.md_flags & MD_FILE)) {
13397c478bd9Sstevel@tonic-gate 		make_ascii_name(&cp->c_id, oname);
13407c478bd9Sstevel@tonic-gate 		make_ascii_name(&cid, nname);
13417c478bd9Sstevel@tonic-gate 		error = VOP_RENAME(ofgp->fg_dirvp, oname, fgp->fg_dirvp,
1342*da6c28aaSamw 			nname, kcred, NULL, 0);
13437c478bd9Sstevel@tonic-gate 		if (error) {
13447c478bd9Sstevel@tonic-gate 			ffnuke = 1;
13457c478bd9Sstevel@tonic-gate #ifdef CFSDEBUG
13467c478bd9Sstevel@tonic-gate 			if (error != ENOSPC) {
13477c478bd9Sstevel@tonic-gate 				CFS_DEBUG(CFSDEBUG_CNODE)
13487c478bd9Sstevel@tonic-gate 					printf("cachefs: cnode_move "
13497c478bd9Sstevel@tonic-gate 					    "1: error %d\n", error);
13507c478bd9Sstevel@tonic-gate 			}
13517c478bd9Sstevel@tonic-gate #endif
13527c478bd9Sstevel@tonic-gate 		}
13537c478bd9Sstevel@tonic-gate 	}
13547c478bd9Sstevel@tonic-gate 
13557c478bd9Sstevel@tonic-gate 	/* remove the file from the old file group */
13567c478bd9Sstevel@tonic-gate 	mutex_enter(&ofgp->fg_cnodelock);
13577c478bd9Sstevel@tonic-gate 	mutex_enter(&cp->c_statelock);
13587c478bd9Sstevel@tonic-gate 	if (cp->c_frontvp) {
13597c478bd9Sstevel@tonic-gate 		VN_RELE(cp->c_frontvp);
13607c478bd9Sstevel@tonic-gate 		cp->c_frontvp = NULL;
13617c478bd9Sstevel@tonic-gate 	}
13627c478bd9Sstevel@tonic-gate 	if (cp->c_acldirvp) {
13637c478bd9Sstevel@tonic-gate 		VN_RELE(cp->c_acldirvp);
13647c478bd9Sstevel@tonic-gate 		cp->c_acldirvp = NULL;
13657c478bd9Sstevel@tonic-gate 	}
13667c478bd9Sstevel@tonic-gate 	mdp = &cp->c_metadata;
13677c478bd9Sstevel@tonic-gate 	if (mdp->md_rlno) {
13687c478bd9Sstevel@tonic-gate 		if (ffnuke) {
13697c478bd9Sstevel@tonic-gate 			cachefs_removefrontfile(mdp, &cp->c_id, ofgp);
13707c478bd9Sstevel@tonic-gate 			cachefs_rlent_moveto(fscp->fs_cache,
13717c478bd9Sstevel@tonic-gate 			    CACHEFS_RL_FREE, mdp->md_rlno, 0);
13727c478bd9Sstevel@tonic-gate 			mdp->md_rlno = 0;
13737c478bd9Sstevel@tonic-gate 			mdp->md_rltype = CACHEFS_RL_NONE;
13747c478bd9Sstevel@tonic-gate 		} else {
13757c478bd9Sstevel@tonic-gate 			filegrp_ffrele(ofgp);
13767c478bd9Sstevel@tonic-gate 		}
13777c478bd9Sstevel@tonic-gate 	}
13787c478bd9Sstevel@tonic-gate 	if (ffnuke)
13797c478bd9Sstevel@tonic-gate 		mdp->md_flags &= ~MD_PACKED;
13807c478bd9Sstevel@tonic-gate 	if ((cp->c_flags & CN_ALLOC_PENDING) == 0) {
13817c478bd9Sstevel@tonic-gate 		(void) filegrp_destroy_metadata(ofgp, &cp->c_id);
13827c478bd9Sstevel@tonic-gate 		cp->c_flags |= CN_ALLOC_PENDING;
13837c478bd9Sstevel@tonic-gate 	}
13847c478bd9Sstevel@tonic-gate 	cachefs_cnode_listrem(cp);
13857c478bd9Sstevel@tonic-gate 	cp->c_filegrp = NULL;
13867c478bd9Sstevel@tonic-gate 	mutex_exit(&cp->c_statelock);
13877c478bd9Sstevel@tonic-gate 	mutex_exit(&ofgp->fg_cnodelock);
13887c478bd9Sstevel@tonic-gate 
13897c478bd9Sstevel@tonic-gate 	/* add the cnode to the new file group */
13907c478bd9Sstevel@tonic-gate 	mutex_enter(&fgp->fg_cnodelock);
13917c478bd9Sstevel@tonic-gate 	mutex_enter(&cp->c_statelock);
13927c478bd9Sstevel@tonic-gate 	cp->c_id = cid;
13937c478bd9Sstevel@tonic-gate 	cp->c_filegrp = fgp;
13947c478bd9Sstevel@tonic-gate 	cp->c_flags |= CN_UPDATED;
13957c478bd9Sstevel@tonic-gate 	mutex_exit(&cp->c_statelock);
13967c478bd9Sstevel@tonic-gate 	cachefs_cnode_listadd(cp);
13977c478bd9Sstevel@tonic-gate 	if (mdp->md_rlno)
13987c478bd9Sstevel@tonic-gate 		cachefs_rl_changefileno(fscp->fs_cache, mdp->md_rlno,
13997c478bd9Sstevel@tonic-gate 		    cp->c_id.cid_fileno);
14007c478bd9Sstevel@tonic-gate 	mutex_exit(&fgp->fg_cnodelock);
14017c478bd9Sstevel@tonic-gate 
14027c478bd9Sstevel@tonic-gate 	filegrp_rele(ofgp);
14037c478bd9Sstevel@tonic-gate }
14047c478bd9Sstevel@tonic-gate 
14057c478bd9Sstevel@tonic-gate /*
14067c478bd9Sstevel@tonic-gate  * Syncs out the specified cnode.
14077c478bd9Sstevel@tonic-gate  * Only called via cnode_traverse from fscache_sync
14087c478bd9Sstevel@tonic-gate  */
14097c478bd9Sstevel@tonic-gate void
cachefs_cnode_sync(cnode_t * cp)14107c478bd9Sstevel@tonic-gate cachefs_cnode_sync(cnode_t *cp)
14117c478bd9Sstevel@tonic-gate {
14127c478bd9Sstevel@tonic-gate 	vnode_t *vp = CTOV(cp);
14137c478bd9Sstevel@tonic-gate 	int error = 0;
14147c478bd9Sstevel@tonic-gate 	fscache_t *fscp = C_TO_FSCACHE(cp);
14157c478bd9Sstevel@tonic-gate 	int held = 0;
14167c478bd9Sstevel@tonic-gate 
14177c478bd9Sstevel@tonic-gate 	if (cp->c_flags & (CN_STALE | CN_DESTROY))
14187c478bd9Sstevel@tonic-gate 		return;
14197c478bd9Sstevel@tonic-gate 
14207c478bd9Sstevel@tonic-gate 	if (fscp->fs_backvfsp && fscp->fs_backvfsp->vfs_flag & VFS_RDONLY)
14217c478bd9Sstevel@tonic-gate 		return;
14227c478bd9Sstevel@tonic-gate 
14237c478bd9Sstevel@tonic-gate 	for (;;) {
14247c478bd9Sstevel@tonic-gate 		/* get (or renew) access to the file system */
14257c478bd9Sstevel@tonic-gate 		if (held) {
14267c478bd9Sstevel@tonic-gate 			cachefs_cd_release(fscp);
14277c478bd9Sstevel@tonic-gate 			held = 0;
14287c478bd9Sstevel@tonic-gate 		}
14297c478bd9Sstevel@tonic-gate 		/*
14307c478bd9Sstevel@tonic-gate 		 * Getting file system access for reading is really cheating.
14317c478bd9Sstevel@tonic-gate 		 * However we are getting called from sync so we do not
14327c478bd9Sstevel@tonic-gate 		 * want to hang up if the cachefsd is not running.
14337c478bd9Sstevel@tonic-gate 		 */
14347c478bd9Sstevel@tonic-gate 		error = cachefs_cd_access(fscp, 0, 0);
14357c478bd9Sstevel@tonic-gate 		if (error)
14367c478bd9Sstevel@tonic-gate 			break;
14377c478bd9Sstevel@tonic-gate 		held = 1;
14387c478bd9Sstevel@tonic-gate 
14397c478bd9Sstevel@tonic-gate 		/* if a regular file, write out the pages */
14407c478bd9Sstevel@tonic-gate 		if ((vp->v_type == VREG) && vn_has_cached_data(vp)) {
14417c478bd9Sstevel@tonic-gate 			ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
14427c478bd9Sstevel@tonic-gate 			error = cachefs_putpage_common(vp, (offset_t)0,
14437c478bd9Sstevel@tonic-gate 			    0, 0, kcred);
14447c478bd9Sstevel@tonic-gate 			if (CFS_TIMEOUT(fscp, error)) {
14457c478bd9Sstevel@tonic-gate 				if (fscp->fs_cdconnected == CFS_CD_CONNECTED) {
14467c478bd9Sstevel@tonic-gate 					cachefs_cd_release(fscp);
14477c478bd9Sstevel@tonic-gate 					held = 0;
14487c478bd9Sstevel@tonic-gate 					cachefs_cd_timedout(fscp);
14497c478bd9Sstevel@tonic-gate 					continue;
14507c478bd9Sstevel@tonic-gate 				} else {
14517c478bd9Sstevel@tonic-gate 					/* cannot push, give up */
14527c478bd9Sstevel@tonic-gate 					break;
14537c478bd9Sstevel@tonic-gate 				}
14547c478bd9Sstevel@tonic-gate 			}
14557c478bd9Sstevel@tonic-gate 
14567c478bd9Sstevel@tonic-gate 			/* clear the cnode error if putpage worked */
14577c478bd9Sstevel@tonic-gate 			if ((error == 0) && cp->c_error) {
14587c478bd9Sstevel@tonic-gate 				mutex_enter(&cp->c_statelock);
14597c478bd9Sstevel@tonic-gate 				cp->c_error = 0;
14607c478bd9Sstevel@tonic-gate 				mutex_exit(&cp->c_statelock);
14617c478bd9Sstevel@tonic-gate 			}
14627c478bd9Sstevel@tonic-gate 
14637c478bd9Sstevel@tonic-gate 			if (error)
14647c478bd9Sstevel@tonic-gate 				break;
14657c478bd9Sstevel@tonic-gate 		}
14667c478bd9Sstevel@tonic-gate 
14677c478bd9Sstevel@tonic-gate 		/* if connected, sync the backvp */
14687c478bd9Sstevel@tonic-gate 		if ((fscp->fs_cdconnected == CFS_CD_CONNECTED) &&
14697c478bd9Sstevel@tonic-gate 		    cp->c_backvp) {
14707c478bd9Sstevel@tonic-gate 			mutex_enter(&cp->c_statelock);
14717c478bd9Sstevel@tonic-gate 			if (cp->c_backvp) {
1472*da6c28aaSamw 				error = VOP_FSYNC(cp->c_backvp, FSYNC, kcred,
1473*da6c28aaSamw 				    NULL);
14747c478bd9Sstevel@tonic-gate 				if (CFS_TIMEOUT(fscp, error)) {
14757c478bd9Sstevel@tonic-gate 					mutex_exit(&cp->c_statelock);
14767c478bd9Sstevel@tonic-gate 					cachefs_cd_release(fscp);
14777c478bd9Sstevel@tonic-gate 					held = 0;
14787c478bd9Sstevel@tonic-gate 					cachefs_cd_timedout(fscp);
14797c478bd9Sstevel@tonic-gate 					continue;
14807c478bd9Sstevel@tonic-gate 				} else if (error && (error != EINTR))
14817c478bd9Sstevel@tonic-gate 					cp->c_error = error;
14827c478bd9Sstevel@tonic-gate 			}
14837c478bd9Sstevel@tonic-gate 			mutex_exit(&cp->c_statelock);
14847c478bd9Sstevel@tonic-gate 		}
14857c478bd9Sstevel@tonic-gate 
14867c478bd9Sstevel@tonic-gate 		/* sync the metadata and the front file to the front fs */
14877c478bd9Sstevel@tonic-gate 		(void) cachefs_sync_metadata(cp);
14887c478bd9Sstevel@tonic-gate 		break;
14897c478bd9Sstevel@tonic-gate 	}
14907c478bd9Sstevel@tonic-gate 
14917c478bd9Sstevel@tonic-gate 	if (held)
14927c478bd9Sstevel@tonic-gate 		cachefs_cd_release(fscp);
14937c478bd9Sstevel@tonic-gate }
14947c478bd9Sstevel@tonic-gate 
14957c478bd9Sstevel@tonic-gate /*
14967c478bd9Sstevel@tonic-gate  * Moves the specified file to the lost+found directory for the
14977c478bd9Sstevel@tonic-gate  * cached file system.
14987c478bd9Sstevel@tonic-gate  * Invalidates cached data and attributes.
14997c478bd9Sstevel@tonic-gate  * Returns 0 or an error if could not perform operation.
15007c478bd9Sstevel@tonic-gate  */
15017c478bd9Sstevel@tonic-gate int
cachefs_cnode_lostfound(cnode_t * cp,char * rname)15027c478bd9Sstevel@tonic-gate cachefs_cnode_lostfound(cnode_t *cp, char *rname)
15037c478bd9Sstevel@tonic-gate {
15047c478bd9Sstevel@tonic-gate 	int error = 0;
15057c478bd9Sstevel@tonic-gate 	fscache_t *fscp;
15067c478bd9Sstevel@tonic-gate 	cachefscache_t *cachep;
15077c478bd9Sstevel@tonic-gate 	char oname[CFS_FRONTFILE_NAME_SIZE];
15087c478bd9Sstevel@tonic-gate 	filegrp_t *fgp;
15097c478bd9Sstevel@tonic-gate 	char *namep, *strp;
15107c478bd9Sstevel@tonic-gate 	char *namebuf = NULL;
15117c478bd9Sstevel@tonic-gate 	vnode_t *nvp;
15127c478bd9Sstevel@tonic-gate 	int index;
15137c478bd9Sstevel@tonic-gate 	int len;
15147c478bd9Sstevel@tonic-gate 
15157c478bd9Sstevel@tonic-gate 	fscp = C_TO_FSCACHE(cp);
15167c478bd9Sstevel@tonic-gate 	cachep = fscp->fs_cache;
15177c478bd9Sstevel@tonic-gate 
15187c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&cp->c_statelock));
15197c478bd9Sstevel@tonic-gate 	ASSERT((cachep->c_flags & (CACHE_NOCACHE|CACHE_NOFILL)) == 0);
15207c478bd9Sstevel@tonic-gate 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
15217c478bd9Sstevel@tonic-gate 
15227c478bd9Sstevel@tonic-gate 	fgp = cp->c_filegrp;
15237c478bd9Sstevel@tonic-gate 
15247c478bd9Sstevel@tonic-gate 	/* set up the file group if necessary */
15257c478bd9Sstevel@tonic-gate 	if (fgp->fg_flags & CFS_FG_ALLOC_ATTR) {
15267c478bd9Sstevel@tonic-gate 		error = filegrp_allocattr(fgp);
15277c478bd9Sstevel@tonic-gate 		if (error)
15287c478bd9Sstevel@tonic-gate 			goto out;
15297c478bd9Sstevel@tonic-gate 	}
15307c478bd9Sstevel@tonic-gate 	ASSERT(fgp->fg_dirvp);
15317c478bd9Sstevel@tonic-gate 
15327c478bd9Sstevel@tonic-gate 	namebuf = cachefs_kmem_alloc(MAXNAMELEN * 2, KM_SLEEP);
15337c478bd9Sstevel@tonic-gate 
15347c478bd9Sstevel@tonic-gate 	if ((cp->c_attr.va_type != VREG) ||
15357c478bd9Sstevel@tonic-gate 	    (cp->c_metadata.md_rltype != CACHEFS_RL_MODIFIED) ||
15367c478bd9Sstevel@tonic-gate 	    ((cp->c_metadata.md_flags & MD_POPULATED) == 0) ||
15377c478bd9Sstevel@tonic-gate 	    ((cp->c_metadata.md_flags & MD_FILE) == 0) ||
15387c478bd9Sstevel@tonic-gate 	    (cp->c_metadata.md_rlno == 0)) {
15397c478bd9Sstevel@tonic-gate #ifdef CFSDEBUG
15407c478bd9Sstevel@tonic-gate 		CFS_DEBUG(CFSDEBUG_CNODE)
15417c478bd9Sstevel@tonic-gate 			printf("cachefs_cnode_lostfound cp %p cannot save\n",
15427c478bd9Sstevel@tonic-gate 			    (void *)cp);
15437c478bd9Sstevel@tonic-gate #endif
15447c478bd9Sstevel@tonic-gate 		error = EINVAL;
15457c478bd9Sstevel@tonic-gate 		goto out;
15467c478bd9Sstevel@tonic-gate 	}
15477c478bd9Sstevel@tonic-gate 
15487c478bd9Sstevel@tonic-gate 	/* lock out other users of the lost+found directory */
15497c478bd9Sstevel@tonic-gate 	mutex_enter(&cachep->c_contentslock);
15507c478bd9Sstevel@tonic-gate 
15517c478bd9Sstevel@tonic-gate 	/* find a name we can use in lost+found */
15527c478bd9Sstevel@tonic-gate 	if (rname)
15537c478bd9Sstevel@tonic-gate 		namep = rname;
15547c478bd9Sstevel@tonic-gate 	else
15557c478bd9Sstevel@tonic-gate 		namep = "lostfile";
15567c478bd9Sstevel@tonic-gate 	error = VOP_LOOKUP(cachep->c_lostfoundvp, namep, &nvp,
1557*da6c28aaSamw 	    NULL, 0, NULL, kcred, NULL, NULL, NULL);
15587c478bd9Sstevel@tonic-gate 	if (error == 0)
15597c478bd9Sstevel@tonic-gate 		VN_RELE(nvp);
15607c478bd9Sstevel@tonic-gate 	if (error != ENOENT) {
15617c478bd9Sstevel@tonic-gate #define		MAXTRIES 1000
15627c478bd9Sstevel@tonic-gate 		strp = namep;
15637c478bd9Sstevel@tonic-gate 		for (index = 0; index < MAXTRIES; index++) {
15647c478bd9Sstevel@tonic-gate 			(void) sprintf(namebuf, "%s.%" PRIx64, strp,
15657c478bd9Sstevel@tonic-gate 			    gethrestime_sec() * cp->c_id.cid_fileno * index);
15667c478bd9Sstevel@tonic-gate 			len = (int)strlen(namebuf) + 1;
15677c478bd9Sstevel@tonic-gate 			if (len > MAXNAMELEN)
15687c478bd9Sstevel@tonic-gate 				namep = &namebuf[len - MAXNAMELEN];
15697c478bd9Sstevel@tonic-gate 			else
15707c478bd9Sstevel@tonic-gate 				namep = namebuf;
15717c478bd9Sstevel@tonic-gate 			error = VOP_LOOKUP(cachep->c_lostfoundvp, namep, &nvp,
1572*da6c28aaSamw 			    NULL, 0, NULL, kcred, NULL, NULL, NULL);
15737c478bd9Sstevel@tonic-gate 			if (error == 0)
15747c478bd9Sstevel@tonic-gate 				VN_RELE(nvp);
15757c478bd9Sstevel@tonic-gate 			if (error == ENOENT)
15767c478bd9Sstevel@tonic-gate 				break;
15777c478bd9Sstevel@tonic-gate 		}
15787c478bd9Sstevel@tonic-gate 		if (index == MAXTRIES) {
15797c478bd9Sstevel@tonic-gate 			error = EIO;
15807c478bd9Sstevel@tonic-gate 			mutex_exit(&cachep->c_contentslock);
15817c478bd9Sstevel@tonic-gate 			goto out;
15827c478bd9Sstevel@tonic-gate 		}
15837c478bd9Sstevel@tonic-gate 	}
15847c478bd9Sstevel@tonic-gate 
15857c478bd9Sstevel@tonic-gate 	/* get the name of the front file */
15867c478bd9Sstevel@tonic-gate 	make_ascii_name(&cp->c_id, oname);
15877c478bd9Sstevel@tonic-gate 
15887c478bd9Sstevel@tonic-gate 	/* rename the file into the lost+found directory */
15897c478bd9Sstevel@tonic-gate 	error = VOP_RENAME(fgp->fg_dirvp, oname, cachep->c_lostfoundvp,
1590*da6c28aaSamw 	    namep, kcred, NULL, 0);
15917c478bd9Sstevel@tonic-gate 	if (error) {
15927c478bd9Sstevel@tonic-gate 		mutex_exit(&cachep->c_contentslock);
15937c478bd9Sstevel@tonic-gate 		goto out;
15947c478bd9Sstevel@tonic-gate 	}
15957c478bd9Sstevel@tonic-gate 	mutex_exit(&cachep->c_contentslock);
15967c478bd9Sstevel@tonic-gate 
15977c478bd9Sstevel@tonic-gate 	/* copy out the new name */
15987c478bd9Sstevel@tonic-gate 	if (rname)
15997c478bd9Sstevel@tonic-gate 		(void) strcpy(rname, namep);
16007c478bd9Sstevel@tonic-gate 
16017c478bd9Sstevel@tonic-gate out:
16027c478bd9Sstevel@tonic-gate 	/* clean up */
16037c478bd9Sstevel@tonic-gate 	cachefs_cnode_stale(cp);
16047c478bd9Sstevel@tonic-gate 
16057c478bd9Sstevel@tonic-gate 	if (namebuf)
16067c478bd9Sstevel@tonic-gate 		cachefs_kmem_free(namebuf, MAXNAMELEN * 2);
16077c478bd9Sstevel@tonic-gate 
16087c478bd9Sstevel@tonic-gate #if 0 /* XXX until we can put filesystem in read-only mode */
16097c478bd9Sstevel@tonic-gate 	if (error) {
16107c478bd9Sstevel@tonic-gate 		/* XXX put file system in read-only mode */
16117c478bd9Sstevel@tonic-gate 	}
16127c478bd9Sstevel@tonic-gate #endif
16137c478bd9Sstevel@tonic-gate 
16147c478bd9Sstevel@tonic-gate 	return (error);
16157c478bd9Sstevel@tonic-gate }
16167c478bd9Sstevel@tonic-gate 
16177c478bd9Sstevel@tonic-gate /*
16187c478bd9Sstevel@tonic-gate  * Traverses the list of cnodes on the fscache and calls the
16197c478bd9Sstevel@tonic-gate  * specified routine with the held cnode.
16207c478bd9Sstevel@tonic-gate  */
16217c478bd9Sstevel@tonic-gate void
cachefs_cnode_traverse(fscache_t * fscp,void (* routinep)(cnode_t *))16227c478bd9Sstevel@tonic-gate cachefs_cnode_traverse(fscache_t *fscp, void (*routinep)(cnode_t *))
16237c478bd9Sstevel@tonic-gate {
16247c478bd9Sstevel@tonic-gate 	filegrp_t *fgp, *ofgp;
16257c478bd9Sstevel@tonic-gate 	cnode_t *cp, *ocp;
16267c478bd9Sstevel@tonic-gate 	int index;
16277c478bd9Sstevel@tonic-gate 
16287c478bd9Sstevel@tonic-gate 	/* lock the fscache while we traverse the file groups */
16297c478bd9Sstevel@tonic-gate 	mutex_enter(&fscp->fs_fslock);
16307c478bd9Sstevel@tonic-gate 
16317c478bd9Sstevel@tonic-gate 	/* for each bucket of file groups */
16327c478bd9Sstevel@tonic-gate 	for (index = 0; index < CFS_FS_FGP_BUCKET_SIZE; index++) {
16337c478bd9Sstevel@tonic-gate 		ofgp = NULL;
16347c478bd9Sstevel@tonic-gate 
16357c478bd9Sstevel@tonic-gate 		/* for each file group in a bucket */
16367c478bd9Sstevel@tonic-gate 		for (fgp = fscp->fs_filegrp[index];
16377c478bd9Sstevel@tonic-gate 		    fgp != NULL;
16387c478bd9Sstevel@tonic-gate 		    fgp = fgp->fg_next) {
16397c478bd9Sstevel@tonic-gate 
16407c478bd9Sstevel@tonic-gate 			/* hold the file group */
16417c478bd9Sstevel@tonic-gate 			filegrp_hold(fgp);
16427c478bd9Sstevel@tonic-gate 
16437c478bd9Sstevel@tonic-gate 			/* drop fscache lock so others can use it */
16447c478bd9Sstevel@tonic-gate 			mutex_exit(&fscp->fs_fslock);
16457c478bd9Sstevel@tonic-gate 
16467c478bd9Sstevel@tonic-gate 			/* drop hold on previous file group */
16477c478bd9Sstevel@tonic-gate 			if (ofgp)
16487c478bd9Sstevel@tonic-gate 				filegrp_rele(ofgp);
16497c478bd9Sstevel@tonic-gate 			ofgp = fgp;
16507c478bd9Sstevel@tonic-gate 
16517c478bd9Sstevel@tonic-gate 			/* lock the cnode list while we traverse it */
16527c478bd9Sstevel@tonic-gate 			mutex_enter(&fgp->fg_cnodelock);
16537c478bd9Sstevel@tonic-gate 			ocp = NULL;
16547c478bd9Sstevel@tonic-gate 
16557c478bd9Sstevel@tonic-gate 			/* for each cnode in this file group */
16567c478bd9Sstevel@tonic-gate 			for (cp = fgp->fg_cnodelist;
16577c478bd9Sstevel@tonic-gate 			    cp != NULL;
16587c478bd9Sstevel@tonic-gate 			    cp = cp->c_next) {
16597c478bd9Sstevel@tonic-gate 
16607c478bd9Sstevel@tonic-gate 				/* hold the cnode */
16617c478bd9Sstevel@tonic-gate 				VN_HOLD(CTOV(cp));
16627c478bd9Sstevel@tonic-gate 
16637c478bd9Sstevel@tonic-gate 				/* drop cnode list lock so others can use it */
16647c478bd9Sstevel@tonic-gate 				mutex_exit(&fgp->fg_cnodelock);
16657c478bd9Sstevel@tonic-gate 
16667c478bd9Sstevel@tonic-gate 				/* drop hold on previous cnode */
16677c478bd9Sstevel@tonic-gate 				if (ocp) {
16687c478bd9Sstevel@tonic-gate 					VN_RELE(CTOV(ocp));
16697c478bd9Sstevel@tonic-gate 				}
16707c478bd9Sstevel@tonic-gate 				ocp = cp;
16717c478bd9Sstevel@tonic-gate 
16727c478bd9Sstevel@tonic-gate 				/*
16737c478bd9Sstevel@tonic-gate 				 * Execute routine for this cnode.
16747c478bd9Sstevel@tonic-gate 				 * At this point no locks are held.
16757c478bd9Sstevel@tonic-gate 				 */
16767c478bd9Sstevel@tonic-gate 				(routinep)(cp);
16777c478bd9Sstevel@tonic-gate 
1678*da6c28aaSamw 				/* reacquire the cnode list lock */
16797c478bd9Sstevel@tonic-gate 				mutex_enter(&fgp->fg_cnodelock);
16807c478bd9Sstevel@tonic-gate 			}
16817c478bd9Sstevel@tonic-gate 
16827c478bd9Sstevel@tonic-gate 			/* drop cnode list lock */
16837c478bd9Sstevel@tonic-gate 			mutex_exit(&fgp->fg_cnodelock);
16847c478bd9Sstevel@tonic-gate 
16857c478bd9Sstevel@tonic-gate 			/* drop hold on last cnode */
16867c478bd9Sstevel@tonic-gate 			if (ocp) {
16877c478bd9Sstevel@tonic-gate 				VN_RELE(CTOV(ocp));
16887c478bd9Sstevel@tonic-gate 			}
16897c478bd9Sstevel@tonic-gate 
1690*da6c28aaSamw 			/* reacquire the fscache lock */
16917c478bd9Sstevel@tonic-gate 			mutex_enter(&fscp->fs_fslock);
16927c478bd9Sstevel@tonic-gate 		}
16937c478bd9Sstevel@tonic-gate 
16947c478bd9Sstevel@tonic-gate 		/* drop hold on last file group */
16957c478bd9Sstevel@tonic-gate 		if (ofgp)
16967c478bd9Sstevel@tonic-gate 			filegrp_rele(ofgp);
16977c478bd9Sstevel@tonic-gate 	}
16987c478bd9Sstevel@tonic-gate 	mutex_exit(&fscp->fs_fslock);
16997c478bd9Sstevel@tonic-gate }
17007c478bd9Sstevel@tonic-gate 
17017c478bd9Sstevel@tonic-gate void
cachefs_cnode_disable_caching(struct cnode * cp)17027c478bd9Sstevel@tonic-gate cachefs_cnode_disable_caching(struct cnode *cp)
17037c478bd9Sstevel@tonic-gate {
17047c478bd9Sstevel@tonic-gate 	mutex_enter(&cp->c_statelock);
17057c478bd9Sstevel@tonic-gate 	cp->c_flags |= CN_NOCACHE;
17067c478bd9Sstevel@tonic-gate 	if (cp->c_frontvp != NULL) {
17077c478bd9Sstevel@tonic-gate 		VN_RELE(cp->c_frontvp);
17087c478bd9Sstevel@tonic-gate 		cp->c_frontvp = NULL;
17097c478bd9Sstevel@tonic-gate 	}
17107c478bd9Sstevel@tonic-gate 	mutex_exit(&cp->c_statelock);
17117c478bd9Sstevel@tonic-gate }
17127c478bd9Sstevel@tonic-gate 
17137c478bd9Sstevel@tonic-gate #define	TIMEMATCH(a, b)	((a)->tv_sec == (b)->tv_sec && \
17147c478bd9Sstevel@tonic-gate 	(a)->tv_nsec == (b)->tv_nsec)
17157c478bd9Sstevel@tonic-gate 
17167c478bd9Sstevel@tonic-gate static void
cnode_enable_caching(struct cnode * cp)17177c478bd9Sstevel@tonic-gate cnode_enable_caching(struct cnode *cp)
17187c478bd9Sstevel@tonic-gate {
17197c478bd9Sstevel@tonic-gate 	struct vnode *iovp;
17207c478bd9Sstevel@tonic-gate 	struct filegrp *fgp;
17217c478bd9Sstevel@tonic-gate 	struct cachefs_metadata md;
17227c478bd9Sstevel@tonic-gate 	cachefscache_t *cachep = C_TO_FSCACHE(cp)->fs_cache;
17237c478bd9Sstevel@tonic-gate 	int error;
17247c478bd9Sstevel@tonic-gate 
17257c478bd9Sstevel@tonic-gate 	ASSERT((cachep->c_flags & (CACHE_NOFILL | CACHE_NOCACHE)) == 0);
17267c478bd9Sstevel@tonic-gate 	ASSERT(CFS_ISFS_BACKFS_NFSV4(C_TO_FSCACHE(cp)) == 0);
17277c478bd9Sstevel@tonic-gate 
17287c478bd9Sstevel@tonic-gate 	iovp = NULL;
17297c478bd9Sstevel@tonic-gate 	if (CTOV(cp)->v_type == VREG)
17307c478bd9Sstevel@tonic-gate 		iovp = cp->c_backvp;
17317c478bd9Sstevel@tonic-gate 	if (iovp) {
17327c478bd9Sstevel@tonic-gate 		(void) VOP_PUTPAGE(iovp, (offset_t)0,
1733*da6c28aaSamw 		    (uint_t)0, B_INVAL, kcred, NULL);
17347c478bd9Sstevel@tonic-gate 	}
17357c478bd9Sstevel@tonic-gate 	mutex_enter(&cp->c_statelock);
17367c478bd9Sstevel@tonic-gate 	if (cp->c_backvp) {
17377c478bd9Sstevel@tonic-gate 		VN_RELE(cp->c_backvp);
17387c478bd9Sstevel@tonic-gate 		cp->c_backvp = NULL;
17397c478bd9Sstevel@tonic-gate 	}
17407c478bd9Sstevel@tonic-gate 	fgp = cp->c_filegrp;
17417c478bd9Sstevel@tonic-gate 	ASSERT(fgp);
17427c478bd9Sstevel@tonic-gate 	error = filegrp_read_metadata(fgp, &cp->c_id, &md);
17437c478bd9Sstevel@tonic-gate 	if (error == 0) {
17447c478bd9Sstevel@tonic-gate 		if ((cachep->c_flags & CACHE_CHECK_RLTYPE) &&
17457c478bd9Sstevel@tonic-gate 		    (md.md_rlno != 0) &&
17467c478bd9Sstevel@tonic-gate 		    (md.md_rltype == CACHEFS_RL_ACTIVE)) {
17477c478bd9Sstevel@tonic-gate 			rl_entry_t *rlp, rl;
17487c478bd9Sstevel@tonic-gate 
17497c478bd9Sstevel@tonic-gate 			mutex_enter(&cachep->c_contentslock);
17507c478bd9Sstevel@tonic-gate 			error = cachefs_rl_entry_get(cachep, md.md_rlno, &rlp);
17517c478bd9Sstevel@tonic-gate 			if (error) {
17527c478bd9Sstevel@tonic-gate 				mutex_exit(&cachep->c_contentslock);
17537c478bd9Sstevel@tonic-gate 				goto out;
17547c478bd9Sstevel@tonic-gate 			}
17557c478bd9Sstevel@tonic-gate 
17567c478bd9Sstevel@tonic-gate 			rl = *rlp;
17577c478bd9Sstevel@tonic-gate 			mutex_exit(&cachep->c_contentslock);
17587c478bd9Sstevel@tonic-gate 
17597c478bd9Sstevel@tonic-gate 			if (rl.rl_current != md.md_rltype) {
17607c478bd9Sstevel@tonic-gate 				md.md_rltype = rl.rl_current;
17617c478bd9Sstevel@tonic-gate 				cp->c_flags |= CN_UPDATED;
17627c478bd9Sstevel@tonic-gate 			}
17637c478bd9Sstevel@tonic-gate 		}
17647c478bd9Sstevel@tonic-gate 
17657c478bd9Sstevel@tonic-gate 		/*
17667c478bd9Sstevel@tonic-gate 		 * A rudimentary consistency check
17677c478bd9Sstevel@tonic-gate 		 * here.  If the cookie and mtime
17687c478bd9Sstevel@tonic-gate 		 * from the cnode match those from the
17697c478bd9Sstevel@tonic-gate 		 * cache metadata, we assume for now that
17707c478bd9Sstevel@tonic-gate 		 * the cached data is OK.
17717c478bd9Sstevel@tonic-gate 		 */
17727c478bd9Sstevel@tonic-gate 		if (bcmp(&md.md_cookie.fid_data, &cp->c_cookie.fid_data,
17737c478bd9Sstevel@tonic-gate 			(size_t)cp->c_cookie.fid_len) == 0 &&
17747c478bd9Sstevel@tonic-gate 		    TIMEMATCH(&cp->c_attr.va_mtime, &md.md_vattr.va_mtime)) {
17757c478bd9Sstevel@tonic-gate 			cp->c_metadata = md;
17767c478bd9Sstevel@tonic-gate 		} else {
17777c478bd9Sstevel@tonic-gate 			/*
17787c478bd9Sstevel@tonic-gate 			 * Here we're skeptical about the validity of
17797c478bd9Sstevel@tonic-gate 			 * the front file.
17807c478bd9Sstevel@tonic-gate 			 * We'll keep the attributes already present in
17817c478bd9Sstevel@tonic-gate 			 * the cnode, and bring along the parts of the
17827c478bd9Sstevel@tonic-gate 			 * metadata that we need to eventually nuke this
17837c478bd9Sstevel@tonic-gate 			 * bogus front file -- in inactive or getfrontfile,
17847c478bd9Sstevel@tonic-gate 			 * whichever comes first...
17857c478bd9Sstevel@tonic-gate 			 */
17867c478bd9Sstevel@tonic-gate 			if (cp->c_frontvp != NULL) {
17877c478bd9Sstevel@tonic-gate 				VN_RELE(cp->c_frontvp);
17887c478bd9Sstevel@tonic-gate 				cp->c_frontvp = NULL;
17897c478bd9Sstevel@tonic-gate 			}
17907c478bd9Sstevel@tonic-gate 			cp->c_metadata.md_flags = md.md_flags;
17917c478bd9Sstevel@tonic-gate 			cp->c_metadata.md_flags |= MD_NEEDATTRS;
17927c478bd9Sstevel@tonic-gate 			cp->c_metadata.md_rlno = md.md_rlno;
17937c478bd9Sstevel@tonic-gate 			cp->c_metadata.md_rltype = md.md_rltype;
17947c478bd9Sstevel@tonic-gate 			cp->c_metadata.md_consttype = md.md_consttype;
17957c478bd9Sstevel@tonic-gate 			cp->c_metadata.md_fid = md.md_fid;
17967c478bd9Sstevel@tonic-gate 			cp->c_metadata.md_frontblks = md.md_frontblks;
17977c478bd9Sstevel@tonic-gate 			cp->c_metadata.md_timestamp.tv_sec = 0;
17987c478bd9Sstevel@tonic-gate 			cp->c_metadata.md_timestamp.tv_nsec = 0;
17997c478bd9Sstevel@tonic-gate 			bzero(&cp->c_metadata.md_allocinfo,
18007c478bd9Sstevel@tonic-gate 			    cp->c_metadata.md_allocents *
18017c478bd9Sstevel@tonic-gate 			    sizeof (struct cachefs_allocmap));
18027c478bd9Sstevel@tonic-gate 			cp->c_metadata.md_allocents = 0;
18037c478bd9Sstevel@tonic-gate 			cp->c_metadata.md_flags &= ~MD_POPULATED;
18047c478bd9Sstevel@tonic-gate 			if ((cp->c_metadata.md_rlno != 0) &&
18057c478bd9Sstevel@tonic-gate 			    (cp->c_metadata.md_rltype == CACHEFS_RL_PACKED)) {
18067c478bd9Sstevel@tonic-gate 				cachefs_rlent_moveto(cachep,
18077c478bd9Sstevel@tonic-gate 				    CACHEFS_RL_PACKED_PENDING,
18087c478bd9Sstevel@tonic-gate 				    cp->c_metadata.md_rlno,
18097c478bd9Sstevel@tonic-gate 				    cp->c_metadata.md_frontblks);
18107c478bd9Sstevel@tonic-gate 				cp->c_metadata.md_rltype =
18117c478bd9Sstevel@tonic-gate 				    CACHEFS_RL_PACKED_PENDING;
18127c478bd9Sstevel@tonic-gate 			}
18137c478bd9Sstevel@tonic-gate 
18147c478bd9Sstevel@tonic-gate 			cp->c_flags |= CN_UPDATED;
18157c478bd9Sstevel@tonic-gate #ifdef CFSDEBUG
18167c478bd9Sstevel@tonic-gate 			CFS_DEBUG(CFSDEBUG_GENERAL) {
18177c478bd9Sstevel@tonic-gate 				printf(
18187c478bd9Sstevel@tonic-gate 				    "fileno %lld ignores cached data due "
18197c478bd9Sstevel@tonic-gate 				    "to cookie and/or mtime mismatch\n",
18207c478bd9Sstevel@tonic-gate 				    (longlong_t)cp->c_id.cid_fileno);
18217c478bd9Sstevel@tonic-gate 			}
18227c478bd9Sstevel@tonic-gate #endif
18237c478bd9Sstevel@tonic-gate 		}
18247c478bd9Sstevel@tonic-gate 		if (cp->c_metadata.md_rltype == CACHEFS_RL_GC) {
18257c478bd9Sstevel@tonic-gate 			cachefs_rlent_moveto(cachep, CACHEFS_RL_ACTIVE,
18267c478bd9Sstevel@tonic-gate 			    cp->c_metadata.md_rlno,
18277c478bd9Sstevel@tonic-gate 			    cp->c_metadata.md_frontblks);
18287c478bd9Sstevel@tonic-gate 			cp->c_metadata.md_rltype = CACHEFS_RL_ACTIVE;
18297c478bd9Sstevel@tonic-gate 			cp->c_flags |= CN_UPDATED;
18307c478bd9Sstevel@tonic-gate 		}
18317c478bd9Sstevel@tonic-gate 	}
18327c478bd9Sstevel@tonic-gate 
18337c478bd9Sstevel@tonic-gate out:
18347c478bd9Sstevel@tonic-gate 	cp->c_flags &= ~CN_NOCACHE;
18357c478bd9Sstevel@tonic-gate 	mutex_exit(&cp->c_statelock);
18367c478bd9Sstevel@tonic-gate 
18377c478bd9Sstevel@tonic-gate 	(void) cachefs_pack_common(CTOV(cp), kcred);
18387c478bd9Sstevel@tonic-gate }
18397c478bd9Sstevel@tonic-gate 
18407c478bd9Sstevel@tonic-gate void
cachefs_enable_caching(struct fscache * fscp)18417c478bd9Sstevel@tonic-gate cachefs_enable_caching(struct fscache *fscp)
18427c478bd9Sstevel@tonic-gate {
18437c478bd9Sstevel@tonic-gate 
18447c478bd9Sstevel@tonic-gate 	/*
18457c478bd9Sstevel@tonic-gate 	 * This function is only called when a remount occurs,
18467c478bd9Sstevel@tonic-gate 	 * with "nocache" and "nofill" options configured
18477c478bd9Sstevel@tonic-gate 	 * (currently these aren't supported). Since this
18487c478bd9Sstevel@tonic-gate 	 * function can write into the cache, make sure that
18497c478bd9Sstevel@tonic-gate 	 * its not in use with NFSv4.
18507c478bd9Sstevel@tonic-gate 	 */
18517c478bd9Sstevel@tonic-gate 	if (CFS_ISFS_BACKFS_NFSV4(fscp))
18527c478bd9Sstevel@tonic-gate 		return;
18537c478bd9Sstevel@tonic-gate 
18547c478bd9Sstevel@tonic-gate 	/*
18557c478bd9Sstevel@tonic-gate 	 * set up file groups so we can read them.  Note that general
18567c478bd9Sstevel@tonic-gate 	 * users (makecfsnode) will *not* start using them (i.e., all
18577c478bd9Sstevel@tonic-gate 	 * newly created cnodes will be NOCACHE)
18587c478bd9Sstevel@tonic-gate 	 * until we "enable_caching_rw" below.
18597c478bd9Sstevel@tonic-gate 	 */
18607c478bd9Sstevel@tonic-gate 	mutex_enter(&fscp->fs_fslock);
18617c478bd9Sstevel@tonic-gate 	filegrp_list_enable_caching_ro(fscp);
18627c478bd9Sstevel@tonic-gate 	mutex_exit(&fscp->fs_fslock);
18637c478bd9Sstevel@tonic-gate 
18647c478bd9Sstevel@tonic-gate 	cachefs_cnode_traverse(fscp, cnode_enable_caching);
18657c478bd9Sstevel@tonic-gate 
18667c478bd9Sstevel@tonic-gate 	/* enable general use of the filegrps */
18677c478bd9Sstevel@tonic-gate 	mutex_enter(&fscp->fs_fslock);
18687c478bd9Sstevel@tonic-gate 	filegrp_list_enable_caching_rw(fscp);
18697c478bd9Sstevel@tonic-gate 	mutex_exit(&fscp->fs_fslock);
18707c478bd9Sstevel@tonic-gate }
18717c478bd9Sstevel@tonic-gate 
18727c478bd9Sstevel@tonic-gate /*
18737c478bd9Sstevel@tonic-gate  * This function makes a cnode stale by performing the following tasks:
18747c478bd9Sstevel@tonic-gate  *	1) remove the front file
18757c478bd9Sstevel@tonic-gate  *	2) Remove any resource file entries
18767c478bd9Sstevel@tonic-gate  *	3) Remove any metadata entry from the attrcache file
18777c478bd9Sstevel@tonic-gate  * 	4) Set the stale bit in the cnode flags field
18787c478bd9Sstevel@tonic-gate  */
18797c478bd9Sstevel@tonic-gate void
cachefs_cnode_stale(cnode_t * cp)18807c478bd9Sstevel@tonic-gate cachefs_cnode_stale(cnode_t *cp)
18817c478bd9Sstevel@tonic-gate {
18827c478bd9Sstevel@tonic-gate 	fscache_t *fscp = C_TO_FSCACHE(cp);
18837c478bd9Sstevel@tonic-gate 	struct cachefs_metadata *mdp;
18847c478bd9Sstevel@tonic-gate 
18857c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&cp->c_statelock));
18867c478bd9Sstevel@tonic-gate 
18877c478bd9Sstevel@tonic-gate 	/*
18887c478bd9Sstevel@tonic-gate 	 * Remove a metadata entry if the file exists
18897c478bd9Sstevel@tonic-gate 	 */
18907c478bd9Sstevel@tonic-gate 	mdp = &cp->c_metadata;
18917c478bd9Sstevel@tonic-gate 	if (mdp->md_rlno) {
18927c478bd9Sstevel@tonic-gate 
18937c478bd9Sstevel@tonic-gate 		ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
18947c478bd9Sstevel@tonic-gate 
18957c478bd9Sstevel@tonic-gate 		/*
18967c478bd9Sstevel@tonic-gate 		 * destroy the frontfile
18977c478bd9Sstevel@tonic-gate 		 */
18987c478bd9Sstevel@tonic-gate 		cachefs_removefrontfile(mdp, &cp->c_id, cp->c_filegrp);
18997c478bd9Sstevel@tonic-gate 		/*
19007c478bd9Sstevel@tonic-gate 		 * Remove resource file entry
19017c478bd9Sstevel@tonic-gate 		 */
19027c478bd9Sstevel@tonic-gate 		cachefs_rlent_moveto(fscp->fs_cache, CACHEFS_RL_FREE,
19037c478bd9Sstevel@tonic-gate 		    mdp->md_rlno, 0);
19047c478bd9Sstevel@tonic-gate 		mdp->md_rlno = 0;
19057c478bd9Sstevel@tonic-gate 		mdp->md_rltype = CACHEFS_RL_NONE;
19067c478bd9Sstevel@tonic-gate 	}
19077c478bd9Sstevel@tonic-gate 
19087c478bd9Sstevel@tonic-gate 	/*
19097c478bd9Sstevel@tonic-gate 	 * Remove attrcache metadata
19107c478bd9Sstevel@tonic-gate 	 */
19117c478bd9Sstevel@tonic-gate 	if (CFS_ISFS_BACKFS_NFSV4(fscp) == 0)
19127c478bd9Sstevel@tonic-gate 		(void) filegrp_destroy_metadata(cp->c_filegrp, &cp->c_id);
19137c478bd9Sstevel@tonic-gate 	mdp->md_flags = 0;
19147c478bd9Sstevel@tonic-gate 
19157c478bd9Sstevel@tonic-gate 	if (cp->c_frontvp) {
19167c478bd9Sstevel@tonic-gate 		VN_RELE(cp->c_frontvp);
19177c478bd9Sstevel@tonic-gate 		cp->c_frontvp = NULL;
19187c478bd9Sstevel@tonic-gate 	}
19197c478bd9Sstevel@tonic-gate 
19207c478bd9Sstevel@tonic-gate 	/*
19217c478bd9Sstevel@tonic-gate 	 * For NFSv4 need to hang on to the backvp until vn_rele()
19227c478bd9Sstevel@tonic-gate 	 * frees this cnode.
19237c478bd9Sstevel@tonic-gate 	 */
19247c478bd9Sstevel@tonic-gate 	if (cp->c_backvp && !CFS_ISFS_BACKFS_NFSV4(fscp)) {
19257c478bd9Sstevel@tonic-gate 		VN_RELE(cp->c_backvp);
19267c478bd9Sstevel@tonic-gate 		cp->c_backvp = NULL;
19277c478bd9Sstevel@tonic-gate 	}
19287c478bd9Sstevel@tonic-gate 	if (cp->c_acldirvp) {
19297c478bd9Sstevel@tonic-gate 		VN_RELE(cp->c_acldirvp);
19307c478bd9Sstevel@tonic-gate 		cp->c_acldirvp = NULL;
19317c478bd9Sstevel@tonic-gate 	}
19327c478bd9Sstevel@tonic-gate 
19337c478bd9Sstevel@tonic-gate 	cp->c_flags |= CN_STALE | CN_ALLOC_PENDING | CN_NOCACHE;
19347c478bd9Sstevel@tonic-gate }
19357c478bd9Sstevel@tonic-gate 
19367c478bd9Sstevel@tonic-gate /*
19377c478bd9Sstevel@tonic-gate  * Sets up the local attributes in the metadata from the attributes.
19387c478bd9Sstevel@tonic-gate  */
19397c478bd9Sstevel@tonic-gate void
cachefs_cnode_setlocalstats(cnode_t * cp)19407c478bd9Sstevel@tonic-gate cachefs_cnode_setlocalstats(cnode_t *cp)
19417c478bd9Sstevel@tonic-gate {
19427c478bd9Sstevel@tonic-gate 	fscache_t *fscp = C_TO_FSCACHE(cp);
19437c478bd9Sstevel@tonic-gate 	cachefs_metadata_t *mdp = &cp->c_metadata;
19447c478bd9Sstevel@tonic-gate 
19457c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&cp->c_statelock));
19467c478bd9Sstevel@tonic-gate 
19477c478bd9Sstevel@tonic-gate 	/* allow over writing of local attributes if a remount occurred */
19487c478bd9Sstevel@tonic-gate 	if (fscp->fs_info.fi_resettimes != mdp->md_resettimes) {
19497c478bd9Sstevel@tonic-gate 		mdp->md_flags &= ~(MD_LOCALCTIME | MD_LOCALMTIME);
19507c478bd9Sstevel@tonic-gate 		mdp->md_resettimes = fscp->fs_info.fi_resettimes;
19517c478bd9Sstevel@tonic-gate 	}
19527c478bd9Sstevel@tonic-gate 	if (fscp->fs_info.fi_resetfileno != mdp->md_resetfileno) {
19537c478bd9Sstevel@tonic-gate 		mdp->md_flags &= ~MD_LOCALFILENO;
19547c478bd9Sstevel@tonic-gate 		mdp->md_resetfileno = fscp->fs_info.fi_resetfileno;
19557c478bd9Sstevel@tonic-gate 	}
19567c478bd9Sstevel@tonic-gate 
19577c478bd9Sstevel@tonic-gate 	/* overwrite old fileno and timestamps if not local versions */
19587c478bd9Sstevel@tonic-gate 	if ((mdp->md_flags & MD_LOCALFILENO) == 0)
19597c478bd9Sstevel@tonic-gate 		mdp->md_localfileno = mdp->md_vattr.va_nodeid;
19607c478bd9Sstevel@tonic-gate 	if ((mdp->md_flags & MD_LOCALCTIME) == 0)
19617c478bd9Sstevel@tonic-gate 		mdp->md_localctime = mdp->md_vattr.va_ctime;
19627c478bd9Sstevel@tonic-gate 	if ((mdp->md_flags & MD_LOCALMTIME) == 0)
19637c478bd9Sstevel@tonic-gate 		mdp->md_localmtime = mdp->md_vattr.va_mtime;
19647c478bd9Sstevel@tonic-gate 	cp->c_flags |= CN_UPDATED;
19657c478bd9Sstevel@tonic-gate }
1966