Home | History | Annotate | Download | only in cachefs
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     26 
     27 #include <sys/param.h>
     28 #include <sys/types.h>
     29 #include <sys/systm.h>
     30 #include <sys/file.h>
     31 #include <sys/cred.h>
     32 #include <sys/proc.h>
     33 #include <sys/user.h>
     34 #include <sys/vfs.h>
     35 #include <sys/vnode.h>
     36 #include <sys/pathname.h>
     37 #include <sys/uio.h>
     38 #include <sys/tiuser.h>
     39 #include <sys/sysmacros.h>
     40 #include <sys/kmem.h>
     41 #include <sys/mount.h>
     42 #include <sys/ioctl.h>
     43 #include <sys/statvfs.h>
     44 #include <sys/errno.h>
     45 #include <sys/debug.h>
     46 #include <sys/cmn_err.h>
     47 #include <sys/utsname.h>
     48 #include <sys/modctl.h>
     49 #include <sys/stat.h>
     50 #include <sys/fcntl.h>
     51 #include <sys/fbuf.h>
     52 #include <rpc/types.h>
     53 
     54 #include <vm/hat.h>
     55 #include <vm/as.h>
     56 #include <vm/page.h>
     57 #include <vm/pvn.h>
     58 #include <vm/seg.h>
     59 #include <vm/seg_map.h>
     60 #include <vm/seg_vn.h>
     61 #include <vm/rm.h>
     62 #include <sys/fs/cachefs_fs.h>
     63 #include <sys/fs/cachefs_dlog.h>
     64 #include <sys/fs/cachefs_ioctl.h>
     65 
     66 /* external references */
     67 extern struct cachefsops nopcfsops, strictcfsops, codcfsops;
     68 
     69 /* forward references */
     70 int fscdir_create(cachefscache_t *cachep, char *namep, fscache_t *fscp);
     71 int fscdir_find(cachefscache_t *cachep, ino64_t fsid, fscache_t *fscp);
     72 static int fscache_info_sync(fscache_t *fscp);
     73 
     74 struct kmem_cache *cachefs_fscache_cache = NULL;
     75 
     76 /*
     77  * ------------------------------------------------------------------
     78  *
     79  *		fscache_create
     80  *
     81  * Description:
     82  *	Creates a fscache object.
     83  * Arguments:
     84  *	cachep		cache to create fscache object for
     85  * Returns:
     86  *	Returns a fscache object.
     87  * Preconditions:
     88  *	precond(cachep)
     89  */
     90 
     91 fscache_t *
     92 fscache_create(cachefscache_t *cachep)
     93 {
     94 	fscache_t *fscp;
     95 
     96 	/* create and initialize the fscache object */
     97 	fscp = kmem_cache_alloc(cachefs_fscache_cache, KM_SLEEP);
     98 
     99 	bzero(fscp, sizeof (*fscp));
    100 
    101 	mutex_init(&fscp->fs_fslock, NULL, MUTEX_DEFAULT, NULL);
    102 	mutex_init(&fscp->fs_idlelock, NULL, MUTEX_DEFAULT, NULL);
    103 	mutex_init(&fscp->fs_dlock, NULL, MUTEX_DEFAULT, NULL);
    104 	mutex_init(&fscp->fs_cdlock, NULL, MUTEX_DEFAULT, NULL);
    105 	cv_init(&fscp->fs_cdwaitcv, NULL, CV_DEFAULT, NULL);
    106 
    107 	fscp->fs_cache = cachep;
    108 	fscp->fs_info.fi_mntflags = CFS_WRITE_AROUND;
    109 	fscp->fs_info.fi_popsize = DEF_POP_SIZE;
    110 	fscp->fs_info.fi_fgsize = DEF_FILEGRP_SIZE;
    111 	fscp->fs_cfsops = &nopcfsops;
    112 	fscp->fs_consttype = CFS_FS_CONST_NOCONST;
    113 	fscp->fs_acregmin = 30;
    114 	fscp->fs_acregmax = 30;
    115 	fscp->fs_acdirmin = 30;
    116 	fscp->fs_acdirmax = 30;
    117 	fscp->fs_cdconnected = CFS_CD_CONNECTED;
    118 	fscp->fs_mntpt = NULL;
    119 	fscp->fs_hostname = NULL;
    120 	fscp->fs_backfsname = NULL;
    121 	cachefs_workq_init(&fscp->fs_workq);
    122 	return (fscp);
    123 }
    124 
    125 /*
    126  * ------------------------------------------------------------------
    127  *
    128  *		fscache_destroy
    129  *
    130  * Description:
    131  *	Destroys the fscache object.
    132  * Arguments:
    133  *	fscp	the fscache object to destroy
    134  * Returns:
    135  * Preconditions:
    136  *	precond(fscp)
    137  *	precond(fs_ref == 0)
    138  */
    139 
    140 void
    141 fscache_destroy(fscache_t *fscp)
    142 {
    143 	size_t strl;
    144 
    145 	ASSERT(fscp->fs_ref == 0);
    146 
    147 	(void) fscache_info_sync(fscp);
    148 
    149 	if (fscp->fs_mntpt) {
    150 		strl = strlen(fscp->fs_mntpt);
    151 		if (strl != 0)
    152 			kmem_free(fscp->fs_mntpt, strl + 1);
    153 	}
    154 	if (fscp->fs_hostname) {
    155 		strl = strlen(fscp->fs_hostname);
    156 		if (strl != 0)
    157 			kmem_free(fscp->fs_hostname, strl + 1);
    158 	}
    159 	if (fscp->fs_backfsname) {
    160 		strl = strlen(fscp->fs_backfsname);
    161 		if (strl != 0)
    162 			kmem_free(fscp->fs_backfsname, strl + 1);
    163 	}
    164 
    165 	/* drop the inum translation table */
    166 	if (fscp->fs_inum_size > 0)
    167 		cachefs_kmem_free(fscp->fs_inum_trans,
    168 		    fscp->fs_inum_size * sizeof (cachefs_inum_trans_t));
    169 
    170 	/* drop references to the fscache directory */
    171 	if (fscp->fs_fscdirvp)
    172 		VN_RELE(fscp->fs_fscdirvp);
    173 	if (fscp->fs_fsattrdir)
    174 		VN_RELE(fscp->fs_fsattrdir);
    175 	if (fscp->fs_infovp)
    176 		VN_RELE(fscp->fs_infovp);
    177 
    178 	/* drop logging references */
    179 	cachefs_dlog_teardown(fscp);
    180 
    181 	mutex_destroy(&fscp->fs_fslock);
    182 	mutex_destroy(&fscp->fs_idlelock);
    183 	mutex_destroy(&fscp->fs_dlock);
    184 	mutex_destroy(&fscp->fs_cdlock);
    185 	cv_destroy(&fscp->fs_cdwaitcv);
    186 
    187 	kmem_cache_free(cachefs_fscache_cache, fscp);
    188 }
    189 
    190 /*
    191  * ------------------------------------------------------------------
    192  *
    193  *		fscache_setup
    194  *
    195  * Description:
    196  *	Activates a fscache by associating the fscache object
    197  *	with on disk data.
    198  *	If the fscache directory of the specified fsid exists then
    199  *	it will be used.
    200  *	Otherwise a new fscache directory will be created using namep
    201  *	and optp with fsid being ignored.  However if namep or optp
    202  *	are not NULL or the cache is in NOFILL then this routine fails.
    203  * Arguments:
    204  *	fscp	the fscache object to activate
    205  *	fsid	unique identifier for the cache
    206  *	namep	name of the cache
    207  *	optp	options for the cache
    208  * Returns:
    209  *	Returns 0 for success, !0 on failure.
    210  * Preconditions:
    211  *	precond(fscp)
    212  *	precond(the cache must not be in NOCACHE mode)
    213  *	precond(the cache must not alread by active)
    214  */
    215 
    216 static int
    217 fscache_setup(fscache_t *fscp, ino64_t fsid, char *namep,
    218     struct cachefsoptions *optp, ino64_t backfileno, int setflags)
    219 {
    220 	int error;
    221 	cachefscache_t *cachep = fscp->fs_cache;
    222 
    223 	ASSERT((cachep->c_flags & CACHE_NOCACHE) == 0);
    224 
    225 	/* see if the fscache directory already exists */
    226 	error =	fscdir_find(cachep, fsid, fscp);
    227 	if (error) {
    228 		/* return error if cannot create the directory */
    229 		if ((namep == NULL) || (optp == NULL) ||
    230 		    (cachep->c_flags & CACHE_NOFILL)) {
    231 			return (error);
    232 		}
    233 		if (backfileno == 0)
    234 			return (EAGAIN);
    235 
    236 		/* remember the root back fileno for disconnected mounts */
    237 		fscp->fs_info.fi_root = backfileno;
    238 
    239 		/* copy options into the fscache */
    240 		fscp->fs_info.fi_mntflags = optp->opt_flags;
    241 		fscp->fs_info.fi_popsize = optp->opt_popsize;
    242 		fscp->fs_info.fi_fgsize = optp->opt_fgsize;
    243 		fscp->fs_flags |= CFS_FS_DIRTYINFO;
    244 
    245 		/* create the directory */
    246 		error = fscdir_create(cachep, namep, fscp);
    247 		if (error) {
    248 			if (error == ENOSPC)
    249 				cmn_err(CE_WARN,
    250 				    "CacheFS: not enough space to create %s",
    251 				    namep);
    252 			else
    253 				cmn_err(CE_WARN,
    254 				    "CacheFS: error %d creating %s",
    255 				    error, namep);
    256 			return (error);
    257 		}
    258 	} else if (optp) {
    259 		/* compare the options to make sure they are compatible */
    260 		error = fscache_compare_options(fscp, optp);
    261 		if (error) {
    262 			cmn_err(CE_WARN,
    263 				"CacheFS: mount failed, options do not match.");
    264 			return (error);
    265 		}
    266 
    267 		/* copy options into the fscache */
    268 		fscp->fs_info.fi_mntflags = optp->opt_flags;
    269 		fscp->fs_info.fi_popsize = optp->opt_popsize;
    270 		fscp->fs_info.fi_fgsize = optp->opt_fgsize;
    271 		fscp->fs_flags |= CFS_FS_DIRTYINFO;
    272 
    273 		/*
    274 		 * The fileid of the root of the filesystem can change
    275 		 * in NFSv4, so make sure we update the fi_root
    276 		 * with the new filenumber.
    277 		 */
    278 		if (CFS_ISFS_BACKFS_NFSV4(fscp) &&
    279 		    fscp->fs_info.fi_root != backfileno) {
    280 			fscp->fs_info.fi_root = backfileno;
    281 		}
    282 	}
    283 
    284 	if (setflags) {
    285 		mutex_enter(&fscp->fs_fslock);
    286 		fscp->fs_flags |= CFS_FS_READ;
    287 		if ((cachep->c_flags & CACHE_NOFILL) == 0)
    288 			fscp->fs_flags |= CFS_FS_WRITE;
    289 		mutex_exit(&fscp->fs_fslock);
    290 	}
    291 
    292 	return (0);
    293 }
    294 
    295 /*
    296  * ------------------------------------------------------------------
    297  *
    298  *		fscache_activate
    299  *
    300  * Description:
    301  *	A wrapper routine for fscache_setup, telling it to setup the
    302  *	fscache for general use.
    303  *
    304  */
    305 int
    306 fscache_activate(fscache_t *fscp, ino64_t fsid, char *namep,
    307     struct cachefsoptions *optp, ino64_t backfileno)
    308 {
    309 	return (fscache_setup(fscp, fsid, namep, optp, backfileno, 1));
    310 }
    311 
    312 /*
    313  * ------------------------------------------------------------------
    314  *
    315  *		fscache_enable
    316  *
    317  * Description:
    318  *	A wrapper routine for fscache_setup, telling it to create a
    319  *	fscache that can be used during remount.  In this case the
    320  *	fscache flags that allow general use are not yet turned on.
    321  *	A later call to fscache_activate_rw will set the flags.
    322  *
    323  */
    324 int
    325 fscache_enable(fscache_t *fscp, ino64_t fsid, char *namep,
    326     struct cachefsoptions *optp, ino64_t backfileno)
    327 {
    328 	return (fscache_setup(fscp, fsid, namep, optp, backfileno, 0));
    329 }
    330 
    331 /*
    332  * ------------------------------------------------------------------
    333  *
    334  *		fscache_activate_rw
    335  *
    336  * Description:
    337  *	Makes the fscache both readable and writable.
    338  * Arguments:
    339  *	fscp		fscache object
    340  * Returns:
    341  * Preconditions:
    342  *	precond(fscp)
    343  */
    344 
    345 void
    346 fscache_activate_rw(fscache_t *fscp)
    347 {
    348 	mutex_enter(&fscp->fs_fslock);
    349 	fscp->fs_flags |= (CFS_FS_WRITE|CFS_FS_READ);
    350 	mutex_exit(&fscp->fs_fslock);
    351 }
    352 
    353 /*
    354  * ------------------------------------------------------------------
    355  *
    356  *		fscache_hold
    357  *
    358  * Description:
    359  *	Increments the reference count on the fscache object
    360  * Arguments:
    361  *	fscp		fscache object to incriment reference count on
    362  * Returns:
    363  * Preconditions:
    364  *	precond(fscp)
    365  */
    366 
    367 void
    368 fscache_hold(fscache_t *fscp)
    369 {
    370 	mutex_enter(&fscp->fs_fslock);
    371 	fscp->fs_ref++;
    372 	ASSERT(fscp->fs_ref > 0);
    373 	mutex_exit(&fscp->fs_fslock);
    374 }
    375 
    376 /*
    377  * ------------------------------------------------------------------
    378  *
    379  *		fscache_rele
    380  *
    381  * Description:
    382  *	Decriments the reference count on the fscache object
    383  * Arguments:
    384  *	fscp		fscache object to decriment reference count on
    385  * Returns:
    386  * Preconditions:
    387  *	precond(fscp)
    388  */
    389 
    390 void
    391 fscache_rele(fscache_t *fscp)
    392 {
    393 	mutex_enter(&fscp->fs_fslock);
    394 	ASSERT(fscp->fs_ref > 0);
    395 	fscp->fs_ref--;
    396 	mutex_exit(&fscp->fs_fslock);
    397 }
    398 
    399 /*
    400  * ------------------------------------------------------------------
    401  *
    402  *		fscache_cnodecnt
    403  *
    404  * Description:
    405  *	Changes the count of number of cnodes on this fscache
    406  *	by the specified amount.
    407  * Arguments:
    408  *	fscp		fscache object to to modify count on
    409  *	cnt		amount to adjust by
    410  * Returns:
    411  *	Returns new count of number of cnodes.
    412  * Preconditions:
    413  *	precond(fscp)
    414  */
    415 
    416 int
    417 fscache_cnodecnt(fscache_t *fscp, int cnt)
    418 {
    419 	int xx;
    420 
    421 	mutex_enter(&fscp->fs_fslock);
    422 	fscp->fs_cnodecnt += cnt;
    423 	ASSERT(fscp->fs_cnodecnt >= 0);
    424 	xx = fscp->fs_cnodecnt;
    425 	mutex_exit(&fscp->fs_fslock);
    426 	return (xx);
    427 }
    428 
    429 /*
    430  * ------------------------------------------------------------------
    431  *
    432  *		fscache_mounted
    433  *
    434  * Description:
    435  *	Called to indicate the the fscache is mounted.
    436  * Arguments:
    437  *	fscp		fscache object
    438  *	cfsvfsp		cachefs vfsp
    439  *	backvfsp	vfsp of back file system
    440  * Returns:
    441  *	Returns 0 for success, -1 if the cache is already mounted.
    442  * Preconditions:
    443  *	precond(fscp)
    444  */
    445 
    446 int
    447 fscache_mounted(fscache_t *fscp, struct vfs *cfsvfsp, struct vfs *backvfsp)
    448 {
    449 	int error = 0;
    450 
    451 	mutex_enter(&fscp->fs_fslock);
    452 	if (fscp->fs_flags & CFS_FS_MOUNTED) {
    453 		error = -1;
    454 		goto out;
    455 	}
    456 
    457 	fscp->fs_backvfsp = backvfsp;
    458 	fscp->fs_cfsvfsp = cfsvfsp;
    459 	gethrestime(&fscp->fs_cod_time);
    460 	fscp->fs_flags |= CFS_FS_MOUNTED;
    461 
    462 	if (CFS_ISFS_SNR(fscp)) {
    463 		/*
    464 		 * If there is a dlog file present, then we assume the cache
    465 		 * was left in disconnected mode.
    466 		 * Also if the back file system was not mounted we also
    467 		 * start off in disconnected mode.
    468 		 */
    469 		error = cachefs_dlog_setup(fscp, 0);
    470 		if (!error || (backvfsp == NULL)) {
    471 			mutex_enter(&fscp->fs_cdlock);
    472 			fscp->fs_cdconnected = CFS_CD_DISCONNECTED;
    473 			fscp->fs_cdtransition = 0;
    474 			cv_broadcast(&fscp->fs_cdwaitcv);
    475 			mutex_exit(&fscp->fs_cdlock);
    476 		}
    477 
    478 		/* invalidate any local fileno mappings */
    479 		fscp->fs_info.fi_resetfileno++;
    480 		fscp->fs_flags |= CFS_FS_DIRTYINFO;
    481 
    482 		/* if connected, invalidate any local time mappings */
    483 		if (backvfsp)
    484 			fscp->fs_info.fi_resettimes++;
    485 	}
    486 
    487 		error = 0;
    488 
    489 	/* set up the consistency mode */
    490 	if (fscp->fs_info.fi_mntflags & CFS_NOCONST_MODE) {
    491 		fscp->fs_cfsops = &nopcfsops;
    492 		fscp->fs_consttype = CFS_FS_CONST_NOCONST;
    493 	} else if (fscp->fs_info.fi_mntflags & CFS_CODCONST_MODE) {
    494 		fscp->fs_cfsops = &codcfsops;
    495 		fscp->fs_consttype = CFS_FS_CONST_CODCONST;
    496 	} else {
    497 		fscp->fs_cfsops = &strictcfsops;
    498 		fscp->fs_consttype = CFS_FS_CONST_STRICT;
    499 	}
    500 
    501 out:
    502 	mutex_exit(&fscp->fs_fslock);
    503 	(void) fscache_info_sync(fscp);
    504 	return (error);
    505 }
    506 
    507 /*
    508  * Compares fscache state with new mount options
    509  * to make sure compatible.
    510  * Returns ESRCH if not compatible or 0 for success.
    511  */
    512 int
    513 fscache_compare_options(fscache_t *fscp, struct cachefsoptions *optp)
    514 {
    515 	if ((fscp->fs_info.fi_popsize == optp->opt_popsize) &&
    516 	    (fscp->fs_info.fi_fgsize == optp->opt_fgsize)) {
    517 		return (0);
    518 	} else {
    519 		return (ESRCH);
    520 	}
    521 }
    522 
    523 /*
    524  * ------------------------------------------------------------------
    525  *
    526  *		fscache_sync
    527  *
    528  * Description:
    529  *	Syncs any data for this fscache to the front file system.
    530  * Arguments:
    531  *	fscp	fscache to sync
    532  * Returns:
    533  * Preconditions:
    534  *	precond(fscp)
    535  */
    536 
    537 void
    538 fscache_sync(struct fscache *fscp)
    539 {
    540 	struct filegrp *fgp;
    541 	int xx;
    542 
    543 	(void) fscache_info_sync(fscp);
    544 
    545 	/* sync the cnodes */
    546 	cachefs_cnode_traverse(fscp, cachefs_cnode_sync);
    547 
    548 	mutex_enter(&fscp->fs_fslock);
    549 
    550 	/* sync the attrcache files */
    551 	for (xx = 0; xx < CFS_FS_FGP_BUCKET_SIZE; xx++) {
    552 		for (fgp = fscp->fs_filegrp[xx]; fgp != NULL;
    553 			fgp = fgp->fg_next) {
    554 			(void) filegrp_sync(fgp);
    555 		}
    556 	}
    557 
    558 	/* garbage collect any unused file groups */
    559 	filegrp_list_gc(fscp);
    560 
    561 	mutex_exit(&fscp->fs_fslock);
    562 }
    563 
    564 /*
    565  * ------------------------------------------------------------------
    566  *
    567  *		fscache_acset
    568  *
    569  * Description:
    570  *	Sets the ac timeout values for the fscache.
    571  * Arguments:
    572  *	fscp	fscache object
    573  * Returns:
    574  * Preconditions:
    575  *	precond(fscp)
    576  */
    577 
    578 void
    579 fscache_acset(fscache_t *fscp,
    580 	uint_t acregmin, uint_t acregmax, uint_t acdirmin, uint_t acdirmax)
    581 {
    582 	mutex_enter(&fscp->fs_fslock);
    583 	if (acregmin > acregmax)
    584 		acregmin = acregmax;
    585 	if (acdirmin > acdirmax)
    586 		acdirmin = acdirmax;
    587 	if (acregmin != 0)
    588 		fscp->fs_acregmin = acregmin;
    589 	if (acregmax != 0)
    590 		fscp->fs_acregmax = acregmax;
    591 	if (acdirmin != 0)
    592 		fscp->fs_acdirmin = acdirmin;
    593 	if (acdirmax != 0)
    594 		fscp->fs_acdirmax = acdirmax;
    595 	mutex_exit(&fscp->fs_fslock);
    596 }
    597 
    598 /*
    599  * ------------------------------------------------------------------
    600  *
    601  *		fscache_list_find
    602  *
    603  * Description:
    604  *	Finds the desired fscache structure on a cache's
    605  *	file system list.
    606  * Arguments:
    607  *	cachep	holds the list of fscache objects to search
    608  *	fsid	the numeric identifier of the fscache
    609  * Returns:
    610  *	Returns an fscache object on success or NULL on failure.
    611  * Preconditions:
    612  *	precond(cachep)
    613  *	precond(the fslistlock must be held)
    614  */
    615 
    616 fscache_t *
    617 fscache_list_find(cachefscache_t *cachep, ino64_t fsid)
    618 {
    619 	fscache_t *fscp = cachep->c_fslist;
    620 
    621 	ASSERT(MUTEX_HELD(&cachep->c_fslistlock));
    622 
    623 	while (fscp != NULL) {
    624 		if (fscp->fs_cfsid == fsid) {
    625 			ASSERT(fscp->fs_cache == cachep);
    626 			break;
    627 		}
    628 		fscp = fscp->fs_next;
    629 	}
    630 
    631 	return (fscp);
    632 }
    633 
    634 /*
    635  * ------------------------------------------------------------------
    636  *
    637  *		fscache_list_add
    638  *
    639  * Description:
    640  *	Adds the specified fscache object to the list on
    641  *	the specified cachep.
    642  * Arguments:
    643  *	cachep	holds the list of fscache objects
    644  *	fscp	fscache object to add to list
    645  * Returns:
    646  * Preconditions:
    647  *	precond(cachep)
    648  *	precond(fscp)
    649  *	precond(fscp cannot already be on a list)
    650  *	precond(the fslistlock must be held)
    651  */
    652 
    653 void
    654 fscache_list_add(cachefscache_t *cachep, fscache_t *fscp)
    655 {
    656 	ASSERT(MUTEX_HELD(&cachep->c_fslistlock));
    657 
    658 	fscp->fs_next = cachep->c_fslist;
    659 	cachep->c_fslist = fscp;
    660 	cachep->c_refcnt++;
    661 }
    662 
    663 /*
    664  * ------------------------------------------------------------------
    665  *
    666  *		fscache_list_remove
    667  *
    668  * Description:
    669  *	Removes the specified fscache object from the list
    670  *	on the specified cachep.
    671  * Arguments:
    672  *	cachep	holds the list of fscache objects
    673  *	fscp	fscache object to remove from list
    674  * Returns:
    675  * Preconditions:
    676  *	precond(cachep)
    677  *	precond(fscp)
    678  *	precond(the fslistlock must be held)
    679  */
    680 
    681 void
    682 fscache_list_remove(cachefscache_t *cachep, fscache_t *fscp)
    683 {
    684 	struct fscache **pfscp = &cachep->c_fslist;
    685 
    686 	ASSERT(MUTEX_HELD(&cachep->c_fslistlock));
    687 
    688 	while (*pfscp != NULL) {
    689 		if (fscp == *pfscp) {
    690 			*pfscp = fscp->fs_next;
    691 			cachep->c_refcnt--;
    692 			break;
    693 		}
    694 		pfscp = &(*pfscp)->fs_next;
    695 	}
    696 }
    697 
    698 /*
    699  * ------------------------------------------------------------------
    700  *
    701  *		fscache_list_gc
    702  *
    703  * Description:
    704  *	Traverses the list of fscache objects on the cachep
    705  *	list and destroys any that are not mounted and
    706  *	that are not referenced.
    707  * Arguments:
    708  *	cachep	holds the list of fscache objects
    709  * Returns:
    710  * Preconditions:
    711  *	precond(cachep)
    712  *	precond(the fslistlock must be held)
    713  */
    714 
    715 void
    716 fscache_list_gc(cachefscache_t *cachep)
    717 {
    718 	struct fscache *next, *fscp;
    719 
    720 	ASSERT(MUTEX_HELD(&cachep->c_fslistlock));
    721 
    722 	for (fscp = cachep->c_fslist; fscp != NULL; fscp = next) {
    723 		next = fscp->fs_next;
    724 		mutex_enter(&fscp->fs_fslock);
    725 		if (((fscp->fs_flags & CFS_FS_MOUNTED) == 0) &&
    726 		    (fscp->fs_ref == 0)) {
    727 			mutex_exit(&fscp->fs_fslock);
    728 			fscache_list_remove(cachep, fscp);
    729 			fscache_destroy(fscp);
    730 		} else {
    731 			mutex_exit(&fscp->fs_fslock);
    732 		}
    733 	}
    734 }
    735 
    736 /*
    737  * ------------------------------------------------------------------
    738  *
    739  *		fscache_list_mounted
    740  *
    741  * Description:
    742  *	Returns the number of fscache objects that are mounted.
    743  * Arguments:
    744  *	cachep	holds the list of fscache objects
    745  * Returns:
    746  * Preconditions:
    747  *	precond(cachep)
    748  *	precond(the fslistlock must be held)
    749  */
    750 
    751 int
    752 fscache_list_mounted(cachefscache_t *cachep)
    753 {
    754 	struct fscache *fscp;
    755 	int count;
    756 
    757 	ASSERT(MUTEX_HELD(&cachep->c_fslistlock));
    758 
    759 	count = 0;
    760 	for (fscp = cachep->c_fslist; fscp != NULL; fscp = fscp->fs_next) {
    761 		mutex_enter(&fscp->fs_fslock);
    762 		if (fscp->fs_flags & CFS_FS_MOUNTED)
    763 			count++;
    764 		mutex_exit(&fscp->fs_fslock);
    765 	}
    766 
    767 	return (count);
    768 }
    769 
    770 /*
    771  * Creates the fs cache directory.
    772  * The directory name is the ascii version of the fsid.
    773  * Also makes a symlink to the directory using the specified name.
    774  */
    775 int
    776 fscdir_create(cachefscache_t *cachep, char *namep, fscache_t *fscp)
    777 {
    778 	int error;
    779 	vnode_t *fscdirvp = NULL;
    780 	vnode_t *infovp = NULL;
    781 	vnode_t *attrvp = NULL;
    782 	struct vattr *attrp = (struct vattr *)NULL;
    783 	char name[CFS_FRONTFILE_NAME_SIZE];
    784 	int files;
    785 	int blocks = 0;
    786 	cfs_cid_t cid;
    787 	ino64_t fsid;
    788 
    789 	ASSERT(MUTEX_HELD(&cachep->c_fslistlock));
    790 	ASSERT(fscp->fs_infovp == NULL);
    791 	ASSERT(fscp->fs_fscdirvp == NULL);
    792 	ASSERT(fscp->fs_fsattrdir == NULL);
    793 
    794 	/* directory, symlink and options file + attrcache dir */
    795 	files = 0;
    796 	while (files < 4) {
    797 		error = cachefs_allocfile(cachep);
    798 		if (error)
    799 			goto out;
    800 		files++;
    801 	}
    802 	error = cachefs_allocblocks(cachep, 4, CACHEFS_RL_NONE);
    803 	if (error)
    804 		goto out;
    805 	blocks = 4;
    806 
    807 	attrp = cachefs_kmem_alloc(sizeof (struct vattr), KM_SLEEP);
    808 	attrp->va_mode = S_IFDIR | 0777;
    809 	attrp->va_uid = 0;
    810 	attrp->va_gid = 0;
    811 	attrp->va_type = VDIR;
    812 	attrp->va_mask = AT_TYPE | AT_MODE | AT_UID | AT_GID;
    813 	error = VOP_MKDIR(cachep->c_dirvp, namep, attrp, &fscdirvp, kcred,
    814 	    NULL, 0, NULL);
    815 	if (error) {
    816 		cmn_err(CE_WARN, "Can't create fs cache directory");
    817 		goto out;
    818 	}
    819 
    820 	/*
    821 	 * Created the directory. Get the fileno. That'll be the cachefs_fsid.
    822 	 */
    823 	attrp->va_mask = AT_NODEID;
    824 	error = VOP_GETATTR(fscdirvp, attrp, 0, kcred, NULL);
    825 	if (error) {
    826 		goto out;
    827 	}
    828 	fsid = attrp->va_nodeid;
    829 	attrp->va_mode = S_IFREG | 0666;
    830 	attrp->va_uid = 0;
    831 	attrp->va_gid = 0;
    832 	attrp->va_type = VREG;
    833 	attrp->va_mask = AT_TYPE | AT_MODE | AT_UID | AT_GID;
    834 	error = VOP_CREATE(fscdirvp, CACHEFS_FSINFO, attrp, EXCL,
    835 			0600, &infovp, kcred, 0, NULL, NULL);
    836 	if (error) {
    837 		cmn_err(CE_WARN, "Can't create fs option file");
    838 		goto out;
    839 	}
    840 	attrp->va_size = MAXBSIZE;
    841 	attrp->va_mask = AT_SIZE;
    842 	error = VOP_SETATTR(infovp, attrp, 0, kcred, NULL);
    843 	if (error) {
    844 		cmn_err(CE_WARN, "Can't set size of fsinfo file");
    845 		goto out;
    846 	}
    847 
    848 	/* write out the info file */
    849 	fscp->fs_flags |= CFS_FS_DIRTYINFO;
    850 	error = fscache_info_sync(fscp);
    851 	if (error)
    852 		goto out;
    853 
    854 	/*
    855 	 * Install the symlink from cachefs_fsid -> directory.
    856 	 */
    857 	cid.cid_flags = 0;
    858 	cid.cid_fileno = fsid;
    859 	make_ascii_name(&cid, name);
    860 	error = VOP_RENAME(cachep->c_dirvp, namep, cachep->c_dirvp,
    861 		name, kcred, NULL, 0);
    862 	if (error) {
    863 		cmn_err(CE_WARN, "Can't rename cache directory");
    864 		goto out;
    865 	}
    866 	attrp->va_mask = AT_MODE | AT_TYPE;
    867 	attrp->va_mode = 0777;
    868 	attrp->va_type = VLNK;
    869 	error = VOP_SYMLINK(cachep->c_dirvp, namep, attrp, name, kcred, NULL,
    870 	    0);
    871 	if (error) {
    872 		cmn_err(CE_WARN, "Can't create cache directory symlink");
    873 		goto out;
    874 	}
    875 
    876 	/*
    877 	 * Finally, make the attrcache directory
    878 	 */
    879 	attrp->va_mode = S_IFDIR | 0777;
    880 	attrp->va_uid = 0;
    881 	attrp->va_gid = 0;
    882 	attrp->va_type = VDIR;
    883 	attrp->va_mask = AT_TYPE | AT_MODE | AT_UID | AT_GID;
    884 	error = VOP_MKDIR(fscdirvp, ATTRCACHE_NAME, attrp, &attrvp, kcred, NULL,
    885 	    0, NULL);
    886 	if (error) {
    887 		cmn_err(CE_WARN, "Can't create attrcache dir for fscache");
    888 		goto out;
    889 	}
    890 
    891 	mutex_enter(&fscp->fs_fslock);
    892 	fscp->fs_cfsid = fsid;
    893 	fscp->fs_fscdirvp = fscdirvp;
    894 	fscp->fs_fsattrdir = attrvp;
    895 	fscp->fs_infovp = infovp;
    896 	mutex_exit(&fscp->fs_fslock);
    897 
    898 out:
    899 
    900 	if (error) {
    901 		while (files-- > 0)
    902 			cachefs_freefile(cachep);
    903 		if (fscdirvp)
    904 			VN_RELE(fscdirvp);
    905 		if (blocks)
    906 			cachefs_freeblocks(cachep, blocks, CACHEFS_RL_NONE);
    907 		if (attrvp)
    908 			VN_RELE(attrvp);
    909 		if (infovp)
    910 			VN_RELE(infovp);
    911 	}
    912 	if (attrp)
    913 		cachefs_kmem_free(attrp, sizeof (struct vattr));
    914 	return (error);
    915 }
    916 
    917 /*
    918  * Tries to find the fscache directory indicated by fsid.
    919  */
    920 int
    921 fscdir_find(cachefscache_t *cachep, ino64_t fsid, fscache_t *fscp)
    922 {
    923 	int error;
    924 	vnode_t *infovp = NULL;
    925 	vnode_t *fscdirvp = NULL;
    926 	vnode_t *attrvp = NULL;
    927 	char dirname[CFS_FRONTFILE_NAME_SIZE];
    928 	cfs_cid_t cid;
    929 	cachefs_fsinfo_t fsinfo;
    930 	caddr_t addr;
    931 
    932 	ASSERT(MUTEX_HELD(&cachep->c_fslistlock));
    933 	ASSERT(fscp->fs_infovp == NULL);
    934 	ASSERT(fscp->fs_fscdirvp == NULL);
    935 	ASSERT(fscp->fs_fsattrdir == NULL);
    936 
    937 	/* convert the fsid value to the name of the directory */
    938 	cid.cid_flags = 0;
    939 	cid.cid_fileno = fsid;
    940 	make_ascii_name(&cid, dirname);
    941 
    942 	/* try to find the directory */
    943 	error = VOP_LOOKUP(cachep->c_dirvp, dirname, &fscdirvp, NULL,
    944 			0, NULL, kcred, NULL, NULL, NULL);
    945 	if (error)
    946 		goto out;
    947 
    948 	/* this better be a directory or we are hosed */
    949 	if (fscdirvp->v_type != VDIR) {
    950 		cmn_err(CE_WARN, "cachefs: fscdir_find_a: cache corruption"
    951 			" run fsck, %s", dirname);
    952 		error = ENOTDIR;
    953 		goto out;
    954 	}
    955 
    956 	/* try to find the info file */
    957 	error = VOP_LOOKUP(fscdirvp, CACHEFS_FSINFO, &infovp,
    958 	    NULL, 0, NULL, kcred, NULL, NULL, NULL);
    959 	if (error) {
    960 		cmn_err(CE_WARN, "cachefs: fscdir_find_b: cache corruption"
    961 			" run fsck, %s", dirname);
    962 		goto out;
    963 	}
    964 
    965 	/* read in info struct */
    966 	addr = segmap_getmapflt(segkmap, infovp, (offset_t)0,
    967 				MAXBSIZE, 1, S_READ);
    968 
    969 	/*LINTED alignment okay*/
    970 	fsinfo = *(cachefs_fsinfo_t *)addr;
    971 	error =  segmap_release(segkmap, addr, 0);
    972 	if (error) {
    973 		cmn_err(CE_WARN, "cachefs: fscdir_find_c: cache corruption"
    974 			" run fsck, %s", dirname);
    975 		goto out;
    976 	}
    977 
    978 	/* try to find the attrcache directory */
    979 	error = VOP_LOOKUP(fscdirvp, ATTRCACHE_NAME,
    980 	    &attrvp, NULL, 0, NULL, kcred, NULL, NULL, NULL);
    981 	if (error) {
    982 		cmn_err(CE_WARN, "cachefs: fscdir_find_d: cache corruption"
    983 			" run fsck, %s", dirname);
    984 		goto out;
    985 	}
    986 
    987 	mutex_enter(&fscp->fs_fslock);
    988 	fscp->fs_info = fsinfo;
    989 	fscp->fs_cfsid = fsid;
    990 	fscp->fs_fscdirvp = fscdirvp;
    991 	fscp->fs_fsattrdir = attrvp;
    992 	fscp->fs_infovp = infovp;
    993 	mutex_exit(&fscp->fs_fslock);
    994 
    995 out:
    996 	if (error) {
    997 		if (infovp)
    998 			VN_RELE(infovp);
    999 		if (fscdirvp)
   1000 			VN_RELE(fscdirvp);
   1001 	}
   1002 	return (error);
   1003 }
   1004 
   1005 /*
   1006  * fscache_info_sync
   1007  * Writes out the fs_info data if necessary.
   1008  */
   1009 static int
   1010 fscache_info_sync(fscache_t *fscp)
   1011 {
   1012 	caddr_t addr;
   1013 	int error = 0;
   1014 
   1015 	mutex_enter(&fscp->fs_fslock);
   1016 
   1017 	if (fscp->fs_cache->c_flags & CACHE_NOFILL) {
   1018 		error = EROFS;
   1019 		goto out;
   1020 	}
   1021 
   1022 	/* if the data is dirty and we have the file vnode */
   1023 	if ((fscp->fs_flags & CFS_FS_DIRTYINFO) && fscp->fs_infovp) {
   1024 		addr = segmap_getmapflt(segkmap, fscp->fs_infovp, 0,
   1025 					MAXBSIZE, 1, S_WRITE);
   1026 
   1027 		/*LINTED alignment okay*/
   1028 		*(cachefs_fsinfo_t *)addr = fscp->fs_info;
   1029 		error = segmap_release(segkmap, addr, SM_WRITE);
   1030 
   1031 		if (error) {
   1032 			cmn_err(CE_WARN,
   1033 			    "cachefs: Can not write to info file.");
   1034 		} else {
   1035 			fscp->fs_flags &= ~CFS_FS_DIRTYINFO;
   1036 		}
   1037 	}
   1038 
   1039 out:
   1040 
   1041 	mutex_exit(&fscp->fs_fslock);
   1042 
   1043 	return (error);
   1044 }
   1045 
   1046 /*
   1047  * ------------------------------------------------------------------
   1048  *
   1049  *		fscache_name_to_fsid
   1050  *
   1051  * Description:
   1052  *	Takes the name of a cache and determines it corresponding
   1053  *	fsid.
   1054  * Arguments:
   1055  *	cachep	cache object to find name of fs cache in
   1056  *	namep	the name of the fs cache
   1057  *	fsidp	set to the fsid if found
   1058  * Returns:
   1059  *	Returns 0 on success, !0 on error.
   1060  * Preconditions:
   1061  *	precond(cachep)
   1062  *	precond(namep)
   1063  *	precond(fsidp)
   1064  */
   1065 
   1066 int
   1067 fscache_name_to_fsid(cachefscache_t *cachep, char *namep, ino64_t *fsidp)
   1068 {
   1069 	int error;
   1070 	char dirname[CFS_FRONTFILE_NAME_SIZE];
   1071 	vnode_t *linkvp = NULL;
   1072 	struct uio uio;
   1073 	struct iovec iov;
   1074 	ino64_t nodeid;
   1075 	char *pd;
   1076 	int xx;
   1077 	int c;
   1078 
   1079 	/* get the vnode of the name */
   1080 	error = VOP_LOOKUP(cachep->c_dirvp, namep, &linkvp, NULL, 0, NULL,
   1081 		kcred, NULL, NULL, NULL);
   1082 	if (error)
   1083 		goto out;
   1084 
   1085 	/* the vnode had better be a link */
   1086 	if (linkvp->v_type != VLNK) {
   1087 		error = EINVAL;
   1088 		goto out;
   1089 	}
   1090 
   1091 	/* read the contents of the link */
   1092 	iov.iov_len = CFS_FRONTFILE_NAME_SIZE;
   1093 	iov.iov_base = dirname;
   1094 	uio.uio_iov = &iov;
   1095 	uio.uio_iovcnt = 1;
   1096 	uio.uio_resid = iov.iov_len;
   1097 	uio.uio_segflg = UIO_SYSSPACE;
   1098 	uio.uio_loffset = 0;
   1099 	uio.uio_fmode = 0;
   1100 	uio.uio_extflg = UIO_COPY_CACHED;
   1101 	error = VOP_READLINK(linkvp, &uio, kcred, NULL);
   1102 	if (error) {
   1103 		cmn_err(CE_WARN, "cachefs: Can't read filesystem cache link");
   1104 		goto out;
   1105 	}
   1106 
   1107 	/* convert the contents of the link to a ino64_t */
   1108 	nodeid = 0;
   1109 	pd = dirname;
   1110 	for (xx = 0; xx < (CFS_FRONTFILE_NAME_SIZE - 2); xx++) {
   1111 		nodeid <<= 4;
   1112 		c = *pd++;
   1113 		if (c <= '9')
   1114 			c -= '0';
   1115 		else if (c <= 'F')
   1116 			c = c - 'A' + 10;
   1117 		else
   1118 			c = c - 'a' + 10;
   1119 		nodeid += c;
   1120 	}
   1121 	*fsidp = nodeid;
   1122 out:
   1123 	if (linkvp)
   1124 		VN_RELE(linkvp);
   1125 
   1126 	return (error);
   1127 }
   1128 
   1129 
   1130 /*
   1131  * Suspends the thread until access to the cache is granted.
   1132  * If !SOFT then
   1133  *	waitconnected == 1 means wait until connected
   1134  *	waitconnected == 0 means wait until connected or disconnected
   1135  * else then
   1136  *	wait until connected or disconnected
   1137  * writing is set to 1 if writing, 0 if reading
   1138  * Returns 0, EINTR, or ETIMEDOUT.
   1139  */
   1140 int
   1141 cachefs_cd_access(fscache_t *fscp, int waitconnected, int writing)
   1142 {
   1143 	int nosig;
   1144 	int error = 0;
   1145 	cachefscache_t *cachep;
   1146 	int waithappens = 0;
   1147 	pid_t pid;
   1148 
   1149 	mutex_enter(&fscp->fs_cdlock);
   1150 
   1151 #ifdef CFS_CD_DEBUG
   1152 	ASSERT((curthread->t_flag & T_CD_HELD) == 0);
   1153 #endif
   1154 
   1155 	for (;;) {
   1156 		/* if we have to wait */
   1157 		if (waithappens ||
   1158 		    (waitconnected &&
   1159 		    (fscp->fs_cdconnected != CFS_CD_CONNECTED))) {
   1160 
   1161 			/* do not make soft mounts wait until connected */
   1162 			if ((waithappens == 0) && CFS_ISFS_SOFT(fscp)) {
   1163 				error = ETIMEDOUT;
   1164 				break;
   1165 			}
   1166 
   1167 			/* wait for a wakeup or a signal */
   1168 			nosig = cv_wait_sig(&fscp->fs_cdwaitcv,
   1169 			    &fscp->fs_cdlock);
   1170 
   1171 			/* if we got a signal */
   1172 			if (nosig == 0) {
   1173 				error = EINTR;
   1174 				break;
   1175 			}
   1176 
   1177 			if (waitconnected &&
   1178 			    (fscp->fs_cdconnected == CFS_CD_CONNECTED))
   1179 				waitconnected = 0;
   1180 
   1181 			/* try again to get access */
   1182 			waithappens = 0;
   1183 			continue;
   1184 		}
   1185 
   1186 		/* if transitioning modes */
   1187 		if (fscp->fs_cdtransition) {
   1188 			waithappens = 1;
   1189 			continue;
   1190 		}
   1191 
   1192 		/* if rolling the log */
   1193 		if (fscp->fs_cdconnected == CFS_CD_RECONNECTING) {
   1194 			pid = ttoproc(curthread)->p_pid;
   1195 			cachep = fscp->fs_cache;
   1196 
   1197 			/* if writing or not the cachefsd */
   1198 			if (writing ||
   1199 			    ((fscp->fs_cddaemonid != pid) &&
   1200 			    (cachep->c_rootdaemonid != pid))) {
   1201 				waithappens = 1;
   1202 				continue;
   1203 			}
   1204 		}
   1205 
   1206 		/* if the daemon is not running */
   1207 		if (fscp->fs_cddaemonid == 0) {
   1208 			/* if writing and not connected */
   1209 			if (writing &&
   1210 			    (fscp->fs_cdconnected != CFS_CD_CONNECTED)) {
   1211 				waithappens = 1;
   1212 				continue;
   1213 			}
   1214 		}
   1215 
   1216 		/*
   1217 		 * Verify don't set wait for NFSv4 (doesn't support
   1218 		 * disconnected behavior).
   1219 		 */
   1220 		ASSERT(!CFS_ISFS_BACKFS_NFSV4(fscp) ||
   1221 				(waithappens == 0 && waitconnected == 0));
   1222 
   1223 		ASSERT(fscp->fs_cdrefcnt >= 0);
   1224 		fscp->fs_cdrefcnt++;
   1225 #ifdef CFS_CD_DEBUG
   1226 		curthread->t_flag |= T_CD_HELD;
   1227 #endif
   1228 		break;
   1229 	}
   1230 	mutex_exit(&fscp->fs_cdlock);
   1231 
   1232 	return (error);
   1233 }
   1234 
   1235 /*
   1236  * Call to check if can have access after a cache miss has occurred.
   1237  * Only read access is allowed, do not call this routine if want
   1238  * to write.
   1239  * Returns 1 if yes, 0 if no.
   1240  */
   1241 int
   1242 cachefs_cd_access_miss(fscache_t *fscp)
   1243 {
   1244 	cachefscache_t *cachep;
   1245 	pid_t pid;
   1246 
   1247 #ifdef CFS_CD_DEBUG
   1248 	ASSERT(curthread->t_flag & T_CD_HELD);
   1249 #endif
   1250 
   1251 	/* should not get called if connected */
   1252 	ASSERT(fscp->fs_cdconnected != CFS_CD_CONNECTED);
   1253 
   1254 	/* if no back file system, then no */
   1255 	if (fscp->fs_backvfsp == NULL)
   1256 		return (0);
   1257 
   1258 	/* if daemon is not running, then yes */
   1259 	if (fscp->fs_cddaemonid == 0) {
   1260 		return (1);
   1261 	}
   1262 
   1263 	pid = ttoproc(curthread)->p_pid;
   1264 	cachep = fscp->fs_cache;
   1265 
   1266 	/* if daemon is running, only daemon is allowed to have access */
   1267 	if ((fscp->fs_cddaemonid != pid) &&
   1268 	    (cachep->c_rootdaemonid != pid)) {
   1269 		return (0);
   1270 	}
   1271 
   1272 	return (1);
   1273 }
   1274 
   1275 /*
   1276  * Releases an access to the file system.
   1277  */
   1278 void
   1279 cachefs_cd_release(fscache_t *fscp)
   1280 {
   1281 	mutex_enter(&fscp->fs_cdlock);
   1282 
   1283 #ifdef CFS_CD_DEBUG
   1284 	ASSERT(curthread->t_flag & T_CD_HELD);
   1285 	curthread->t_flag &= ~T_CD_HELD;
   1286 #endif
   1287 	/* decriment hold on file system */
   1288 	fscp->fs_cdrefcnt--;
   1289 	ASSERT(fscp->fs_cdrefcnt >= 0);
   1290 
   1291 	/* Verify no connected state transitions for NFSv4 */
   1292 	ASSERT(!CFS_ISFS_BACKFS_NFSV4(fscp) || fscp->fs_cdtransition == 0);
   1293 
   1294 	/* wake up cachefsd */
   1295 	if ((fscp->fs_cdrefcnt == 0) && fscp->fs_cdtransition)
   1296 		cv_broadcast(&fscp->fs_cdwaitcv);
   1297 
   1298 	mutex_exit(&fscp->fs_cdlock);
   1299 }
   1300 
   1301 /*
   1302  * Called when a network timeout error has occurred.
   1303  * If connected, switches state to disconnected.
   1304  */
   1305 void
   1306 cachefs_cd_timedout(fscache_t *fscp)
   1307 {
   1308 	int state;
   1309 
   1310 	/* nothing to do if not snr or not connected */
   1311 	if (!CFS_ISFS_SNR(fscp) || (fscp->fs_cdconnected != CFS_CD_CONNECTED))
   1312 		return;
   1313 
   1314 #ifdef CFS_CD_DEBUG
   1315 	ASSERT((curthread->t_flag & T_CD_HELD) == 0);
   1316 #endif
   1317 
   1318 	/* Verify no state changes done for NFSv4 */
   1319 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
   1320 
   1321 	state = CFS_FS_DISCONNECTED;
   1322 	(void) cachefs_io_stateset(fscp->fs_rootvp, &state, NULL);
   1323 }
   1324