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 
     26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     27 
     28 #include <sys/param.h>
     29 #include <sys/types.h>
     30 #include <sys/systm.h>
     31 #include <sys/cred.h>
     32 #include <sys/proc.h>
     33 #include <sys/user.h>
     34 #include <sys/vfs.h>
     35 #include <sys/vfs_opreg.h>
     36 #include <sys/vnode.h>
     37 #include <sys/pathname.h>
     38 #include <sys/uio.h>
     39 #include <sys/tiuser.h>
     40 #include <sys/sysmacros.h>
     41 #include <sys/kmem.h>
     42 #include <sys/mount.h>
     43 #include <sys/ioctl.h>
     44 #include <sys/statvfs.h>
     45 #include <sys/stat.h>
     46 #include <sys/errno.h>
     47 #include <sys/debug.h>
     48 #include <sys/cmn_err.h>
     49 #include <sys/utsname.h>
     50 #include <sys/bootconf.h>
     51 #include <sys/reboot.h>
     52 #include <sys/modctl.h>
     53 #include <rpc/types.h>
     54 
     55 #include <sys/fs/cachefs_fs.h>
     56 #include <sys/fs/cachefs_log.h>
     57 #include <sys/mkdev.h>
     58 #include <sys/dnlc.h>
     59 #include <sys/policy.h>
     60 #include "fs/fs_subr.h"
     61 
     62 extern kmutex_t cachefs_kmem_lock;
     63 kmutex_t cachefs_kstat_key_lock;
     64 
     65 /* forward declarations */
     66 static int cachefs_remount(struct vfs *, struct mounta *);
     67 static void cachefs_delete_cachep(cachefscache_t *);
     68 
     69 #define	CFS_MAPSIZE	256
     70 
     71 kmutex_t cachefs_cachelock;			/* Cache list mutex */
     72 cachefscache_t *cachefs_cachelist = NULL;		/* Cache struct list */
     73 
     74 int cachefs_mount_retries = 3;
     75 kmutex_t cachefs_minor_lock;		/* Lock for minor device map */
     76 major_t cachefs_major = 0;
     77 minor_t cachefs_minor = 0;
     78 cachefs_kstat_key_t *cachefs_kstat_key = NULL;
     79 int cachefs_kstat_key_n = 0;
     80 static uint32_t cachefs_nfsv4_warnmsg = FALSE;
     81 
     82 /*
     83  * cachefs vfs operations.
     84  */
     85 static	int cachefs_mount(vfs_t *, vnode_t *, struct mounta *, cred_t *);
     86 static	int cachefs_unmount(vfs_t *, int, cred_t *);
     87 static	int cachefs_root(vfs_t *, vnode_t **);
     88 static	int cachefs_statvfs(register vfs_t *, struct statvfs64 *);
     89 static	int cachefs_sync(vfs_t *, short, cred_t *);
     90 
     91 /*
     92  * Initialize the vfs structure
     93  */
     94 int cachefsfstyp;
     95 int cnodesize = 0;
     96 
     97 int
     98 cachefs_init_vfsops(int fstype)
     99 {
    100 	static const fs_operation_def_t cachefs_vfsops_template[] = {
    101 		VFSNAME_MOUNT,		{ .vfs_mount = cachefs_mount },
    102 		VFSNAME_UNMOUNT,	{ .vfs_unmount = cachefs_unmount },
    103 		VFSNAME_ROOT,		{ .vfs_root = cachefs_root },
    104 		VFSNAME_STATVFS,	{ .vfs_statvfs = cachefs_statvfs },
    105 		VFSNAME_SYNC,		{ .vfs_sync = cachefs_sync },
    106 		NULL,			NULL
    107 	};
    108 	int error;
    109 
    110 	error = vfs_setfsops(fstype, cachefs_vfsops_template, NULL);
    111 	if (error != 0)
    112 		return (error);
    113 
    114 	cachefsfstyp = fstype;
    115 
    116 	return (0);
    117 }
    118 
    119 dev_t
    120 cachefs_mkmntdev(void)
    121 {
    122 	dev_t cachefs_dev;
    123 
    124 	mutex_enter(&cachefs_minor_lock);
    125 	do {
    126 		cachefs_minor = (cachefs_minor + 1) & MAXMIN32;
    127 		cachefs_dev = makedevice(cachefs_major, cachefs_minor);
    128 	} while (vfs_devismounted(cachefs_dev));
    129 	mutex_exit(&cachefs_minor_lock);
    130 
    131 	return (cachefs_dev);
    132 }
    133 
    134 /*
    135  * vfs operations
    136  */
    137 static int
    138 cachefs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
    139 {
    140 	char *data = uap->dataptr;
    141 	STRUCT_DECL(cachefs_mountargs, map);
    142 	struct cachefsoptions	*cfs_options;
    143 	char			*backfs, *cacheid, *cachedir;
    144 	vnode_t *cachedirvp = NULL;
    145 	vnode_t *backrootvp = NULL;
    146 	cachefscache_t *cachep = NULL;
    147 	fscache_t *fscp = NULL;
    148 	cnode_t *cp;
    149 	struct fid *cookiep = NULL;
    150 	struct vattr *attrp = NULL;
    151 	dev_t cachefs_dev;			/* devid for this mount */
    152 	int error = 0;
    153 	int retries = cachefs_mount_retries;
    154 	ino64_t fsid;
    155 	cfs_cid_t cid;
    156 	char *backmntpt;
    157 	ino64_t backfileno;
    158 	struct vfs *backvfsp;
    159 	size_t strl;
    160 	char tmpstr[MAXPATHLEN];
    161 	vnode_t *tmpdirvp = NULL;
    162 	ulong_t maxfilesizebits;
    163 	uint32_t valid_fid;
    164 
    165 #ifdef CFSDEBUG
    166 	CFS_DEBUG(CFSDEBUG_VFSOP)
    167 		printf("cachefs_mount: ENTER cachefs_mntargs %p\n", data);
    168 #endif
    169 
    170 	/*
    171 	 * Make sure we have sufficient privileges.
    172 	 */
    173 	if ((error = secpolicy_fs_mount(cr, mvp, vfsp)) != 0)
    174 		goto out;
    175 
    176 	/*
    177 	 * make sure we're mounting on a directory
    178 	 */
    179 	if (mvp->v_type != VDIR) {
    180 		error = ENOTDIR;
    181 		goto out;
    182 	}
    183 
    184 	/*
    185 	 * Determine the zone we're being mounted into, and make sure it's the
    186 	 * global zone.
    187 	 */
    188 	if (getzoneid() == GLOBAL_ZONEID) {
    189 		zone_t *mntzone;
    190 
    191 		mntzone = zone_find_by_path(refstr_value(vfsp->vfs_mntpt));
    192 		ASSERT(mntzone != NULL);
    193 		zone_rele(mntzone);
    194 		if (mntzone != curproc->p_zone) {
    195 			error = EBUSY;
    196 			goto out;
    197 		}
    198 	} else {
    199 		error = EPERM;
    200 		goto out;
    201 	}
    202 
    203 	if (uap->flags & MS_REMOUNT) {
    204 		error = cachefs_remount(vfsp, uap);
    205 		goto out;
    206 	}
    207 
    208 	/*
    209 	 * Assign a unique device id to the mount
    210 	 */
    211 	cachefs_dev = cachefs_mkmntdev();
    212 #ifdef _LP64
    213 	/*
    214 	 * It's not a good idea to make fsid bigger since that'll
    215 	 * have adverse effects on nfs filehandles.  For now assume that
    216 	 * cachefs be used on devices that fit into dev32_t's.
    217 	 */
    218 	if (cachefs_dev == NODEV) {
    219 		error = EOVERFLOW;
    220 		goto out;
    221 	}
    222 #endif
    223 
    224 	/*
    225 	 * Copy in the arguments
    226 	 */
    227 	STRUCT_INIT(map, get_udatamodel());
    228 	error = copyin(data, STRUCT_BUF(map),
    229 			SIZEOF_STRUCT(cachefs_mountargs, DATAMODEL_NATIVE));
    230 	if (error) {
    231 		goto out;
    232 	}
    233 
    234 	cfs_options = (struct cachefsoptions *)STRUCT_FADDR(map, cfs_options);
    235 	cacheid = (char *)STRUCT_FGETP(map, cfs_cacheid);
    236 	if ((cfs_options->opt_flags &
    237 	    (CFS_WRITE_AROUND|CFS_NONSHARED|CFS_BACKFS_NFSV4)) == 0) {
    238 		error = EINVAL;
    239 		goto out;
    240 	}
    241 	if ((cfs_options->opt_popsize % MAXBSIZE) != 0) {
    242 		error = EINVAL;
    243 		goto out;
    244 	}
    245 	/*
    246 	 * Get the cache directory vp
    247 	 */
    248 	/*LINTED 32-bit pointer casting okay*/
    249 	cachedir = (char *)STRUCT_FGETP(map, cfs_cachedir);
    250 	error = lookupname(cachedir, UIO_USERSPACE, FOLLOW,
    251 			NULLVPP, &cachedirvp);
    252 	if (error)
    253 		goto out;
    254 
    255 	/*
    256 	 * Make sure the thing we just looked up is a directory
    257 	 */
    258 	if (cachedirvp->v_type != VDIR) {
    259 		cmn_err(CE_WARN, "cachefs_mount: cachedir not a directory\n");
    260 		error = EINVAL;
    261 		goto out;
    262 	}
    263 
    264 	/*
    265 	 * Make sure the cache doesn't live in cachefs!
    266 	 */
    267 	if (vn_matchops(cachedirvp, cachefs_getvnodeops())) {
    268 		cmn_err(CE_WARN, "cachefs_mount: cachedir in cachefs!\n");
    269 		error = EINVAL;
    270 		goto out;
    271 	}
    272 
    273 	/* if the backfs is mounted */
    274 	/*LINTED 32-bit pointer casting okay*/
    275 	if ((backfs = STRUCT_FGETP(map, cfs_backfs)) != NULL) {
    276 		/*
    277 		 * Get the back file system root vp
    278 		 */
    279 		error = lookupname(backfs, UIO_USERSPACE, FOLLOW,
    280 			NULLVPP, &backrootvp);
    281 		if (error)
    282 			goto out;
    283 
    284 		/*
    285 		 * Make sure the thing we just looked up is a directory
    286 		 * and a root of a file system
    287 		 */
    288 		if (backrootvp->v_type != VDIR ||
    289 		    !(backrootvp->v_flag & VROOT)) {
    290 			cmn_err(CE_WARN,
    291 			    "cachefs_mount: backpath not a directory\n");
    292 			error = EINVAL;
    293 			goto out;
    294 		}
    295 
    296 		/*
    297 		 * Get the fid and attributes for the root of the
    298 		 * backfilesystem, except if NFSv4 is in use,
    299 		 * in which case we get the attributes only (the
    300 		 * (VOP_FID() operation called by cachefs_get_cookie()
    301 		 * is not supported in NFSv4).
    302 		 */
    303 		cookiep = cachefs_kmem_alloc(sizeof (struct fid), KM_SLEEP);
    304 		attrp = cachefs_kmem_alloc(sizeof (struct vattr), KM_SLEEP);
    305 
    306 		if ((cfs_options->opt_flags & CFS_BACKFS_NFSV4)) {
    307 			valid_fid = FALSE;
    308 		} else {
    309 			valid_fid = TRUE;
    310 		}
    311 		error = cachefs_getcookie(backrootvp, cookiep, attrp, cr,
    312 						valid_fid);
    313 
    314 		if (error)
    315 			goto out;
    316 
    317 		backmntpt = backfs;
    318 		backfileno = attrp->va_nodeid;
    319 		backvfsp = backrootvp->v_vfsp;
    320 	} else {
    321 		backmntpt = NULL;
    322 		backfileno = 0;
    323 		backvfsp = NULL;
    324 	}
    325 
    326 again:
    327 
    328 	/*
    329 	 * In SVR4 it's not acceptable to stack up mounts
    330 	 * unless MS_OVERLAY specified.
    331 	 */
    332 	mutex_enter(&mvp->v_lock);
    333 	if (((uap->flags & MS_OVERLAY) == 0) &&
    334 	    ((mvp->v_count != 1) || (mvp->v_flag & VROOT))) {
    335 		mutex_exit(&mvp->v_lock);
    336 		error = EBUSY;
    337 		goto out;
    338 	}
    339 	mutex_exit(&mvp->v_lock);
    340 
    341 	/*
    342 	 * Lock out other mounts and unmounts until we safely have
    343 	 * a mounted fscache object.
    344 	 */
    345 	mutex_enter(&cachefs_cachelock);
    346 
    347 	/*
    348 	 * Find the cache structure
    349 	 */
    350 	for (cachep = cachefs_cachelist; cachep != NULL;
    351 		cachep = cachep->c_next) {
    352 		if (cachep->c_dirvp == cachedirvp)
    353 			break;
    354 	}
    355 
    356 	/* if the cache object does not exist, then create it */
    357 	if (cachep == NULL) {
    358 		cachep = cachefs_cache_create();
    359 		error = cachefs_cache_activate_ro(cachep, cachedirvp);
    360 		if (error) {
    361 			cachefs_cache_destroy(cachep);
    362 			cachep = NULL;
    363 			goto out;
    364 		}
    365 		if ((cfs_options->opt_flags & CFS_NOFILL) == 0)
    366 			cachefs_cache_activate_rw(cachep);
    367 		else
    368 			cfs_options->opt_flags &= ~CFS_NOFILL;
    369 
    370 		cachep->c_next = cachefs_cachelist;
    371 		cachefs_cachelist = cachep;
    372 	} else if (cfs_options->opt_flags & CFS_NOFILL) {
    373 		cmn_err(CE_WARN,
    374 		    "CacheFS: attempt to convert nonempty cache "
    375 		    "to NOFILL mode");
    376 		error = EINVAL;
    377 		goto out;
    378 	}
    379 
    380 	/* get the fscache id for this name */
    381 	error = fscache_name_to_fsid(cachep, cacheid, &fsid);
    382 	if (error) {
    383 		fsid = 0;
    384 	}
    385 
    386 	/* find the fscache object for this mount point or create it */
    387 	mutex_enter(&cachep->c_fslistlock);
    388 	fscp = fscache_list_find(cachep, fsid);
    389 	if (fscp == NULL) {
    390 		fscp = fscache_create(cachep);
    391 		error = fscache_activate(fscp, fsid, cacheid,
    392 			cfs_options, backfileno);
    393 		if (error) {
    394 			fscache_destroy(fscp);
    395 			fscp = NULL;
    396 			mutex_exit(&cachep->c_fslistlock);
    397 			if ((error == ENOSPC) && (retries-- > 0)) {
    398 				mutex_exit(&cachefs_cachelock);
    399 				delay(6 * hz);
    400 				goto again;
    401 			}
    402 			goto out;
    403 		}
    404 		fscache_list_add(cachep, fscp);
    405 	} else {
    406 		/* compare the options to make sure they are compatible */
    407 		error = fscache_compare_options(fscp, cfs_options);
    408 		if (error) {
    409 			cmn_err(CE_WARN,
    410 				"CacheFS: mount failed, options do not match.");
    411 			fscp = NULL;
    412 			mutex_exit(&cachep->c_fslistlock);
    413 			goto out;
    414 		}
    415 
    416 		/* copy options into the fscache */
    417 		mutex_enter(&fscp->fs_fslock);
    418 		fscp->fs_info.fi_mntflags = cfs_options->opt_flags;
    419 		fscp->fs_info.fi_popsize = cfs_options->opt_popsize;
    420 		fscp->fs_info.fi_fgsize = cfs_options->opt_fgsize;
    421 		fscp->fs_flags |= CFS_FS_DIRTYINFO;
    422 		mutex_exit(&fscp->fs_fslock);
    423 	}
    424 	fscache_hold(fscp);
    425 
    426 	error = 0;
    427 	if (fscp->fs_fscdirvp) {
    428 		error = VOP_LOOKUP(fscp->fs_fscdirvp, CACHEFS_DLOG_FILE,
    429 		    &tmpdirvp, NULL, 0, NULL, kcred, NULL, NULL, NULL);
    430 
    431 		/*
    432 		 * If a log file exists and the cache is being mounted without
    433 		 * the snr (aka disconnectable) option, return an error.
    434 		 */
    435 		if ((error == 0) &&
    436 		    !(cfs_options->opt_flags & CFS_DISCONNECTABLE)) {
    437 			mutex_exit(&cachep->c_fslistlock);
    438 			cmn_err(CE_WARN, "cachefs: log exists and "
    439 			    "disconnectable option not specified\n");
    440 			error = EINVAL;
    441 			goto out;
    442 		}
    443 	}
    444 
    445 	/*
    446 	 * Acquire the name of the mount point
    447 	 */
    448 	if (fscp->fs_mntpt == NULL) {
    449 		/*
    450 		 * the string length returned by copystr includes the
    451 		 * terminating NULL character, unless a NULL string is
    452 		 * passed in, then the string length is unchanged.
    453 		 */
    454 		strl = 0;
    455 		tmpstr[0] = '\0';
    456 		(void) copyinstr(uap->dir, tmpstr, MAXPATHLEN, &strl);
    457 		if (strl > 1) {
    458 			fscp->fs_mntpt = kmem_alloc(strl, KM_SLEEP);
    459 			(void) strncpy(fscp->fs_mntpt, tmpstr, strl);
    460 		}
    461 		/*
    462 		 * else fscp->fs_mntpt is unchanged(still NULL) try again
    463 		 * next time
    464 		 */
    465 	}
    466 
    467 	/*
    468 	 * Acquire the name of the server
    469 	 */
    470 	if (fscp->fs_hostname == NULL) {
    471 		strl = 0;
    472 		tmpstr[0] = '\0';
    473 		/*LINTED 32-bit pointer casting okay*/
    474 		(void) copyinstr((char *)STRUCT_FGETP(map, cfs_hostname),
    475 				tmpstr, MAXPATHLEN, &strl);
    476 		if (strl > 1) {
    477 			fscp->fs_hostname = kmem_alloc(strl, KM_SLEEP);
    478 			(void) strncpy(fscp->fs_hostname, tmpstr, strl);
    479 		}
    480 		/*
    481 		 * else fscp->fs_hostname remains unchanged (is still NULL)
    482 		 */
    483 	}
    484 
    485 	/*
    486 	 * Acquire name of the back filesystem
    487 	 */
    488 	if (fscp->fs_backfsname == NULL) {
    489 		strl = 0;
    490 		tmpstr[0] = '\0';
    491 		/*LINTED 32-bit pointer casting okay*/
    492 		(void) copyinstr((char *)STRUCT_FGETP(map, cfs_backfsname),
    493 				tmpstr, MAXPATHLEN, &strl);
    494 		if (strl > 1) {
    495 			fscp->fs_backfsname = kmem_alloc(strl, KM_SLEEP);
    496 			(void) strncpy(fscp->fs_backfsname, tmpstr, strl);
    497 		}
    498 		/*
    499 		 * else fscp->fs_backfsname remains unchanged (is still NULL)
    500 		 */
    501 	}
    502 
    503 	backfileno = fscp->fs_info.fi_root;
    504 	mutex_exit(&cachep->c_fslistlock);
    505 
    506 	/* see if fscache object is already mounted, it not, make it so */
    507 	error = fscache_mounted(fscp, vfsp, backvfsp);
    508 	if (error) {
    509 		/* fs cache was already mounted */
    510 		error = EBUSY;
    511 		goto out;
    512 	}
    513 
    514 	cachefs_kstat_mount(fscp, uap->dir, backmntpt, cachedir, cacheid);
    515 
    516 	/* set nfs style time out parameters */
    517 	fscache_acset(fscp, STRUCT_FGET(map, cfs_acregmin),
    518 	    STRUCT_FGET(map, cfs_acregmax),
    519 	    STRUCT_FGET(map, cfs_acdirmin), STRUCT_FGET(map, cfs_acdirmax));
    520 
    521 	vfsp->vfs_dev = cachefs_dev;
    522 	vfsp->vfs_data = (caddr_t)fscp;
    523 	vfs_make_fsid(&vfsp->vfs_fsid, cachefs_dev, cachefsfstyp);
    524 	vfsp->vfs_fstype = cachefsfstyp;
    525 	if (backvfsp)
    526 		vfsp->vfs_bsize = backvfsp->vfs_bsize;
    527 	else
    528 		vfsp->vfs_bsize = MAXBSIZE;	/* XXX */
    529 
    530 	/* make a cnode for the root of the file system */
    531 	cid.cid_flags = 0;
    532 	cid.cid_fileno = backfileno;
    533 	error = cachefs_cnode_make(&cid, fscp, (valid_fid ? cookiep : NULL),
    534 				attrp, backrootvp, cr, CN_ROOT, &cp);
    535 
    536 	if (error) {
    537 		cmn_err(CE_WARN, "cachefs_mount: can't create root cnode\n");
    538 		goto out;
    539 	}
    540 
    541 	/* stick the root cnode in the fscache object */
    542 	mutex_enter(&fscp->fs_fslock);
    543 	fscp->fs_rootvp = CTOV(cp);
    544 	fscp->fs_rootvp->v_flag |= VROOT;
    545 	fscp->fs_rootvp->v_type |= cp->c_attr.va_type;
    546 	ASSERT(fscp->fs_rootvp->v_type == VDIR);
    547 
    548 	/*
    549 	 * Get the maxfilesize bits of the back file system.
    550 	 */
    551 
    552 	error = VOP_PATHCONF(backrootvp, _PC_FILESIZEBITS, &maxfilesizebits,
    553 		    kcred, NULL);
    554 
    555 	if (error) {
    556 		cmn_err(CE_WARN,
    557 	"cachefs_mount: Can't get the FILESIZEBITS of the back root vnode \n");
    558 		goto out;
    559 	}
    560 
    561 	fscp->fs_offmax = (1LL << (maxfilesizebits - 1)) - 1;
    562 	mutex_exit(&fscp->fs_fslock);
    563 
    564 	/* remove the unmount file if it is there */
    565 	(void) VOP_REMOVE(fscp->fs_fscdirvp, CACHEFS_UNMNT_FILE, kcred, NULL,
    566 	    0);
    567 
    568 	/* wake up the cache worker if ANY packed pending work */
    569 	mutex_enter(&cachep->c_contentslock);
    570 	if (cachep->c_flags & CACHE_PACKED_PENDING)
    571 		cv_signal(&cachep->c_cwcv);
    572 	mutex_exit(&cachep->c_contentslock);
    573 
    574 	/*
    575 	 * Warn that caching is disabled with NFSv4 first time around.
    576 	 */
    577 	if (!cachefs_nfsv4_warnmsg && CFS_ISFS_BACKFS_NFSV4(fscp)) {
    578 		cmn_err(CE_WARN,
    579 			"Cachefs has detected a mount with NFSv4: caching will"
    580 			" be disabled for this and other NFSv4 mounts\n");
    581 		cachefs_nfsv4_warnmsg = TRUE;
    582 	}
    583 
    584 out:
    585 	/*
    586 	 * make a log entry, if appropriate
    587 	 */
    588 
    589 	if ((cachep != NULL) &&
    590 	    CACHEFS_LOG_LOGGING(cachep, CACHEFS_LOG_MOUNT))
    591 		cachefs_log_mount(cachep, error, vfsp, fscp,
    592 		    uap->dir, UIO_USERSPACE,
    593 		    (STRUCT_BUF(map) != NULL) ? cacheid : NULL);
    594 
    595 	/*
    596 	 * Cleanup our mess
    597 	 */
    598 	if (cookiep != NULL)
    599 		cachefs_kmem_free(cookiep, sizeof (struct fid));
    600 	if (cachedirvp != NULL)
    601 		VN_RELE(cachedirvp);
    602 	if (backrootvp != NULL)
    603 		VN_RELE(backrootvp);
    604 	if (fscp)
    605 		fscache_rele(fscp);
    606 	if (attrp)
    607 		cachefs_kmem_free(attrp, sizeof (struct vattr));
    608 
    609 	if (error) {
    610 		if (cachep) {
    611 			int xx;
    612 
    613 			/* lock the cachep's fslist */
    614 			mutex_enter(&cachep->c_fslistlock);
    615 
    616 			/*
    617 			 * gc isn't necessary for list_mounted(), but
    618 			 * we want to do it anyway.
    619 			 */
    620 
    621 			fscache_list_gc(cachep);
    622 			xx = fscache_list_mounted(cachep);
    623 
    624 			mutex_exit(&cachep->c_fslistlock);
    625 
    626 			/* if no more references to this cachep, punt it. */
    627 			if (xx == 0)
    628 				cachefs_delete_cachep(cachep);
    629 			mutex_exit(&cachefs_cachelock);
    630 		}
    631 	} else {
    632 		mutex_exit(&cachefs_cachelock);
    633 	}
    634 
    635 #ifdef CFSDEBUG
    636 	CFS_DEBUG(CFSDEBUG_VFSOP)
    637 		printf("cachefs_mount: EXIT\n");
    638 #endif
    639 	return (error);
    640 }
    641 
    642 void
    643 cachefs_kstat_mount(struct fscache *fscp,
    644     char *umountpoint, char *ubackfs, char *ucachedir, char *cacheid)
    645 {
    646 	cachefscache_t *cachep = fscp->fs_cache;
    647 	cachefs_kstat_key_t *key;
    648 	char *mountpoint = NULL, *backfs = NULL, *cachedir = NULL;
    649 	size_t len;
    650 	kstat_t *ksp;
    651 	int i, rc;
    652 
    653 	mountpoint = cachefs_kmem_alloc(MAXPATHLEN, KM_SLEEP);
    654 	if (copyinstr(umountpoint, mountpoint, MAXPATHLEN, &len) != 0)
    655 		goto out;
    656 
    657 	cachedir = cachefs_kmem_alloc(MAXPATHLEN, KM_SLEEP);
    658 	if (copyinstr(ucachedir, cachedir, MAXPATHLEN, &len) != 0)
    659 		goto out;
    660 
    661 	backfs = cachefs_kmem_alloc(MAXPATHLEN, KM_SLEEP);
    662 	if (backfs) {
    663 		if (copyinstr(ubackfs, backfs, MAXPATHLEN, &len) != 0)
    664 			goto out;
    665 	} else {
    666 		(void) strcpy(backfs, "no back file system");
    667 	}
    668 
    669 	ASSERT(strlen(mountpoint) < MAXPATHLEN);
    670 	ASSERT(strlen(backfs) < MAXPATHLEN);
    671 	ASSERT(strlen(cachedir) < MAXPATHLEN);
    672 
    673 	/* protect cachefs_kstat_key */
    674 	mutex_enter(&cachefs_kstat_key_lock);
    675 	/*
    676 	 * XXXX If already there, why not go straight to it?
    677 	 * We know that fscp->fs_kstat_id == i + 1
    678 	 */
    679 	i = fscp->fs_kstat_id - 1;
    680 	if ((i >= 0) && (i < cachefs_kstat_key_n))
    681 		rc = 1;
    682 	else
    683 		rc = i = 0;
    684 	for (; i < cachefs_kstat_key_n; i++) {
    685 		key = cachefs_kstat_key + i;
    686 		if (strcmp((char *)(uintptr_t)key->ks_mountpoint,
    687 		    mountpoint) == 0 &&
    688 		    strcmp((char *)(uintptr_t)key->ks_cachedir,
    689 		    cachedir) == 0 &&
    690 		    strcmp((char *)(uintptr_t)key->ks_cacheid, cacheid) == 0)
    691 			break;
    692 		if (rc) {	/* direct key did not work - check all */
    693 			i = -1;	/* will increment to zero in loop */
    694 			rc = 0;
    695 		}
    696 	}
    697 
    698 	if (i >= cachefs_kstat_key_n) {
    699 		key = cachefs_kmem_alloc((cachefs_kstat_key_n + 1) *
    700 		    sizeof (cachefs_kstat_key_t), KM_SLEEP);
    701 		if (cachefs_kstat_key != NULL) {
    702 			bcopy(cachefs_kstat_key, key,
    703 			    cachefs_kstat_key_n * sizeof (*key));
    704 			cachefs_kmem_free(cachefs_kstat_key,
    705 			    cachefs_kstat_key_n * sizeof (*key));
    706 		}
    707 		cachefs_kstat_key = key;
    708 		key = cachefs_kstat_key + cachefs_kstat_key_n;
    709 		++cachefs_kstat_key_n;
    710 		rc = key->ks_id = cachefs_kstat_key_n; /* offset + 1 */
    711 
    712 		key->ks_mountpoint = (uint64_t)(uintptr_t)
    713 		    cachefs_strdup(mountpoint);
    714 		key->ks_backfs = (uint64_t)(uintptr_t)cachefs_strdup(backfs);
    715 		key->ks_cachedir = (uint64_t)(uintptr_t)
    716 		    cachefs_strdup(cachedir);
    717 		key->ks_cacheid = (uint64_t)(uintptr_t)cachefs_strdup(cacheid);
    718 	} else
    719 		rc = key->ks_id;
    720 
    721 	mutex_enter(&fscp->fs_fslock); /* protect fscp */
    722 
    723 	fscp->fs_kstat_id = rc;
    724 
    725 	mutex_exit(&fscp->fs_fslock); /* finished with fscp */
    726 	/* finished cachefs_kstat_key */
    727 	mutex_exit(&cachefs_kstat_key_lock);
    728 
    729 	key->ks_vfsp = (uint64_t)(uintptr_t)fscp->fs_cfsvfsp;
    730 	key->ks_mounted = 1;
    731 
    732 	/*
    733 	 * we must not be holding any mutex that is a ks_lock field
    734 	 * for one of the kstats when we invoke kstat_create,
    735 	 * kstat_install, and friends.
    736 	 */
    737 	ASSERT(MUTEX_NOT_HELD(&cachefs_kstat_key_lock));
    738 	/* really should be EVERY cachep's c_log_mutex */
    739 	ASSERT(MUTEX_NOT_HELD(&cachep->c_log_mutex));
    740 
    741 	/* cachefs.#.log */
    742 	ksp = kstat_create("cachefs", fscp->fs_kstat_id, "log",
    743 	    "misc", KSTAT_TYPE_RAW, 1,
    744 	    KSTAT_FLAG_WRITABLE | KSTAT_FLAG_VIRTUAL);
    745 	if (ksp != NULL) {
    746 		ksp->ks_data = cachep->c_log_ctl;
    747 		ksp->ks_data_size = sizeof (cachefs_log_control_t);
    748 		ksp->ks_lock = &cachep->c_log_mutex;
    749 		ksp->ks_snapshot = cachefs_log_kstat_snapshot;
    750 		kstat_install(ksp);
    751 	}
    752 	/* cachefs.#.stats */
    753 	ksp = kstat_create("cachefs", fscp->fs_kstat_id, "stats",
    754 	    "misc", KSTAT_TYPE_RAW, 1,
    755 	    KSTAT_FLAG_WRITABLE | KSTAT_FLAG_VIRTUAL);
    756 	if (ksp != NULL) {
    757 		ksp->ks_data = fscp;
    758 		ksp->ks_data_size = sizeof (cachefs_stats_t);
    759 		ksp->ks_snapshot = cachefs_stats_kstat_snapshot;
    760 		kstat_install(ksp);
    761 	}
    762 
    763 out:
    764 	if (mountpoint != NULL)
    765 		cachefs_kmem_free(mountpoint, MAXPATHLEN);
    766 	if (backfs != NULL)
    767 		cachefs_kmem_free(backfs, MAXPATHLEN);
    768 	if (cachedir != NULL)
    769 		cachefs_kmem_free(cachedir, MAXPATHLEN);
    770 }
    771 
    772 void
    773 cachefs_kstat_umount(int ksid)
    774 {
    775 	cachefs_kstat_key_t *k = cachefs_kstat_key + (ksid - 1);
    776 
    777 	ASSERT(k->ks_id == ksid);
    778 
    779 	k->ks_mounted = 0;
    780 
    781 	kstat_delete_byname("cachefs", ksid, "stats");
    782 	kstat_delete_byname("cachefs", ksid, "log");
    783 }
    784 
    785 int
    786 cachefs_kstat_key_update(kstat_t *ksp, int rw)
    787 {
    788 	cachefs_kstat_key_t *key = *((cachefs_kstat_key_t **)ksp->ks_data);
    789 	cachefs_kstat_key_t *k;
    790 	int i;
    791 
    792 	if (rw == KSTAT_WRITE)
    793 		return (EIO);
    794 	if (key == NULL)
    795 		return (EIO);
    796 
    797 	ksp->ks_data_size = cachefs_kstat_key_n * sizeof (*key);
    798 	for (i = 0; i < cachefs_kstat_key_n; i++) {
    799 		k = key + i;
    800 
    801 		ksp->ks_data_size +=
    802 		    strlen((char *)(uintptr_t)k->ks_mountpoint) + 1;
    803 		ksp->ks_data_size +=
    804 		    strlen((char *)(uintptr_t)k->ks_backfs) + 1;
    805 		ksp->ks_data_size +=
    806 		    strlen((char *)(uintptr_t)k->ks_cachedir) + 1;
    807 		ksp->ks_data_size +=
    808 		    strlen((char *)(uintptr_t)k->ks_cacheid) + 1;
    809 	}
    810 
    811 	ksp->ks_ndata = cachefs_kstat_key_n;
    812 
    813 	return (0);
    814 }
    815 
    816 int
    817 cachefs_kstat_key_snapshot(kstat_t *ksp, void *buf, int rw)
    818 {
    819 	cachefs_kstat_key_t *key = *((cachefs_kstat_key_t **)ksp->ks_data);
    820 	cachefs_kstat_key_t *k;
    821 	caddr_t s;
    822 	int i;
    823 
    824 	if (rw == KSTAT_WRITE)
    825 		return (EIO);
    826 
    827 	if (key == NULL)
    828 		return (0); /* paranoid */
    829 
    830 	bcopy(key, buf, cachefs_kstat_key_n * sizeof (*key));
    831 	key = buf;
    832 	s = (caddr_t)(key + cachefs_kstat_key_n);
    833 
    834 	for (i = 0; i < cachefs_kstat_key_n; i++) {
    835 		k = key + i;
    836 
    837 		(void) strcpy(s, (char *)(uintptr_t)k->ks_mountpoint);
    838 		k->ks_mountpoint = (uint64_t)(uintptr_t)(s - (uintptr_t)buf);
    839 		s += strlen(s) + 1;
    840 		(void) strcpy(s, (char *)(uintptr_t)k->ks_backfs);
    841 		k->ks_backfs = (uint64_t)(uintptr_t)(s - (uintptr_t)buf);
    842 		s += strlen(s) + 1;
    843 		(void) strcpy(s, (char *)(uintptr_t)k->ks_cachedir);
    844 		k->ks_cachedir = (uint64_t)(uintptr_t)(s - (uintptr_t)buf);
    845 		s += strlen(s) + 1;
    846 		(void) strcpy(s, (char *)(uintptr_t)k->ks_cacheid);
    847 		k->ks_cacheid = (uint64_t)(uintptr_t)(s - (uintptr_t)buf);
    848 		s += strlen(s) + 1;
    849 	}
    850 
    851 	return (0);
    852 }
    853 
    854 extern void  cachefs_inactivate();
    855 
    856 static int
    857 cachefs_unmount(vfs_t *vfsp, int flag, cred_t *cr)
    858 {
    859 	fscache_t *fscp = VFS_TO_FSCACHE(vfsp);
    860 	struct cachefscache *cachep = fscp->fs_cache;
    861 	int error;
    862 	int xx;
    863 	vnode_t *nmvp;
    864 	struct vattr attr;
    865 
    866 #ifdef CFSDEBUG
    867 	CFS_DEBUG(CFSDEBUG_VFSOP)
    868 		printf("cachefs_unmount: ENTER fscp %p\n", fscp);
    869 #endif
    870 
    871 	if ((error = secpolicy_fs_unmount(cr, vfsp)) != 0)
    872 		goto out;
    873 
    874 	/*
    875 	 * forced unmount is not supported by this file system
    876 	 * and thus, ENOTSUP, is being returned.
    877 	 */
    878 	if (flag & MS_FORCE) {
    879 		error = ENOTSUP;
    880 		goto out;
    881 	}
    882 	/* if a log file exists don't allow the unmount */
    883 	if (fscp->fs_dlogfile) {
    884 		error = EBUSY;
    885 		goto out;
    886 	}
    887 
    888 	/*
    889 	 * wait for the cache-wide async queue to drain.  Someone
    890 	 * here may be trying to sync our fscache...
    891 	 */
    892 	while (cachefs_async_halt(&fscp->fs_cache->c_workq, 0) == EBUSY) {
    893 #ifdef CFSDEBUG
    894 		CFS_DEBUG(CFSDEBUG_VFSOP)
    895 			printf("unmount: waiting for cache async queue...\n");
    896 #endif
    897 	}
    898 
    899 	error = cachefs_async_halt(&fscp->fs_workq, 1);
    900 	if (error) {
    901 #ifdef CFSDEBUG
    902 		CFS_DEBUG(CFSDEBUG_VFSOP)
    903 			printf("cachefs_unmount: "
    904 			    "cachefs_async_halt error %d\n", error);
    905 #endif
    906 		goto out;
    907 	}
    908 
    909 	/*
    910 	 * No active cnodes on this cache && rootvp refcnt == 1
    911 	 */
    912 	mutex_enter(&fscp->fs_fslock);
    913 	xx = fscp->fs_cnodecnt - fscp->fs_idlecnt;
    914 	ASSERT(xx >= 1);
    915 	if (xx > 1 || fscp->fs_rootvp->v_count != 1) {
    916 		mutex_exit(&fscp->fs_fslock);
    917 #ifdef CFSDEBUG
    918 		CFS_DEBUG(CFSDEBUG_VFSOP)
    919 			printf("cachefs_unmount: busy (cnodes active %d, idle "
    920 				"%d)\n", fscp->fs_cnodecnt, fscp->fs_idlecnt);
    921 #endif
    922 		error = EBUSY;
    923 		goto out;
    924 	}
    925 	mutex_exit(&fscp->fs_fslock);
    926 
    927 	/* get rid of anything on the idle list */
    928 	ASSERT(fscp->fs_idleclean == 0);
    929 	cachefs_cnode_idleclean(fscp, 1);
    930 	if (fscp->fs_cnodecnt > 1) {
    931 #ifdef CFSDEBUG
    932 		CFS_DEBUG(CFSDEBUG_VFSOP)
    933 			printf("cachefs_unmount: busy (cnode count %d)\n",
    934 				fscp->fs_cnodecnt);
    935 #endif
    936 		error = EBUSY;
    937 		goto out;
    938 	}
    939 
    940 	fscache_hold(fscp);
    941 
    942 	/* get rid of the root cnode */
    943 	if (cachefs_cnode_inactive(fscp->fs_rootvp, cr) == EBUSY) {
    944 		fscache_rele(fscp);
    945 #ifdef CFSDEBUG
    946 		CFS_DEBUG(CFSDEBUG_VFSOP)
    947 			printf("cachefs_unmount: busy (inactive failed)\n");
    948 #endif
    949 		error = EBUSY;
    950 		goto out;
    951 	}
    952 
    953 	/* create the file indicating not mounted */
    954 	attr.va_mode = S_IFREG | 0666;
    955 	attr.va_uid = 0;
    956 	attr.va_gid = 0;
    957 	attr.va_type = VREG;
    958 	attr.va_mask = AT_TYPE | AT_MODE | AT_UID | AT_GID;
    959 	if (fscp->fs_fscdirvp != NULL)
    960 		xx = VOP_CREATE(fscp->fs_fscdirvp, CACHEFS_UNMNT_FILE, &attr,
    961 		    NONEXCL, 0600, &nmvp, kcred, 0, NULL, NULL);
    962 	else
    963 		xx = ENOENT; /* for unmounting when NOCACHE */
    964 	if (xx == 0) {
    965 		VN_RELE(nmvp);
    966 	} else {
    967 		printf("could not create %s %d\n", CACHEFS_UNMNT_FILE, xx);
    968 	}
    969 
    970 	ASSERT(fscp->fs_cnodecnt == 0);
    971 
    972 	/* sync the file system just in case */
    973 	fscache_sync(fscp);
    974 
    975 	/* lock out other unmounts and mount */
    976 	mutex_enter(&cachefs_cachelock);
    977 
    978 	/* mark the file system as not mounted */
    979 	mutex_enter(&fscp->fs_fslock);
    980 	fscp->fs_flags &= ~CFS_FS_MOUNTED;
    981 	fscp->fs_rootvp = NULL;
    982 	if (fscp->fs_kstat_id > 0)
    983 		cachefs_kstat_umount(fscp->fs_kstat_id);
    984 	fscp->fs_kstat_id = 0;
    985 
    986 	/* drop the inum translation table */
    987 	if (fscp->fs_inum_size > 0) {
    988 		cachefs_kmem_free(fscp->fs_inum_trans,
    989 		    fscp->fs_inum_size * sizeof (cachefs_inum_trans_t));
    990 		fscp->fs_inum_size = 0;
    991 		fscp->fs_inum_trans = NULL;
    992 		fscp->fs_flags &= ~CFS_FS_HASHPRINT;
    993 	}
    994 	mutex_exit(&fscp->fs_fslock);
    995 
    996 	fscache_rele(fscp);
    997 
    998 	/* get rid of any unused fscache objects */
    999 	mutex_enter(&cachep->c_fslistlock);
   1000 	fscache_list_gc(cachep);
   1001 	mutex_exit(&cachep->c_fslistlock);
   1002 
   1003 	/* get the number of mounts on this cache */
   1004 	mutex_enter(&cachep->c_fslistlock);
   1005 	xx = fscache_list_mounted(cachep);
   1006 	mutex_exit(&cachep->c_fslistlock);
   1007 
   1008 	if (CACHEFS_LOG_LOGGING(cachep, CACHEFS_LOG_UMOUNT))
   1009 		cachefs_log_umount(cachep, 0, vfsp);
   1010 
   1011 	/* if no mounts left, deactivate the cache */
   1012 	if (xx == 0)
   1013 		cachefs_delete_cachep(cachep);
   1014 
   1015 	mutex_exit(&cachefs_cachelock);
   1016 
   1017 out:
   1018 	if (error) {
   1019 		if (CACHEFS_LOG_LOGGING(cachep, CACHEFS_LOG_UMOUNT))
   1020 			cachefs_log_umount(cachep, error, vfsp);
   1021 	}
   1022 #ifdef CFSDEBUG
   1023 	CFS_DEBUG(CFSDEBUG_VFSOP)
   1024 		printf("cachefs_unmount: EXIT\n");
   1025 #endif
   1026 	return (error);
   1027 }
   1028 
   1029 /*
   1030  * remove the cache from the list of caches
   1031  */
   1032 
   1033 static void
   1034 cachefs_delete_cachep(cachefscache_t *cachep)
   1035 {
   1036 	struct cachefscache **cachepp;
   1037 	int found = 0;
   1038 
   1039 	ASSERT(MUTEX_HELD(&cachefs_cachelock));
   1040 
   1041 	for (cachepp = &cachefs_cachelist;
   1042 	    *cachepp != NULL;
   1043 	    cachepp = &(*cachepp)->c_next) {
   1044 		if (*cachepp == cachep) {
   1045 			*cachepp = cachep->c_next;
   1046 			found++;
   1047 			break;
   1048 		}
   1049 	}
   1050 	ASSERT(found);
   1051 
   1052 	/* shut down the cache */
   1053 	cachefs_cache_destroy(cachep);
   1054 }
   1055 
   1056 static int
   1057 cachefs_root(vfs_t *vfsp, vnode_t **vpp)
   1058 {
   1059 	/*LINTED alignment okay*/
   1060 	struct fscache *fscp = (struct fscache *)vfsp->vfs_data;
   1061 
   1062 	ASSERT(fscp != NULL);
   1063 	ASSERT(fscp->fs_rootvp != NULL);
   1064 
   1065 	if (getzoneid() != GLOBAL_ZONEID)
   1066 		return (EPERM);
   1067 	*vpp = fscp->fs_rootvp;
   1068 	VN_HOLD(*vpp);
   1069 	return (0);
   1070 }
   1071 
   1072 /*
   1073  * Get file system statistics.
   1074  */
   1075 static int
   1076 cachefs_statvfs(register vfs_t *vfsp, struct statvfs64 *sbp)
   1077 {
   1078 	struct fscache *fscp = VFS_TO_FSCACHE(vfsp);
   1079 	struct cache_label *lp = &fscp->fs_cache->c_label;
   1080 	struct cache_usage *up = &fscp->fs_cache->c_usage;
   1081 	int error;
   1082 
   1083 	if (getzoneid() != GLOBAL_ZONEID)
   1084 		return (EPERM);
   1085 	error = cachefs_cd_access(fscp, 0, 0);
   1086 	if (error)
   1087 		return (error);
   1088 
   1089 	if (fscp->fs_cdconnected == CFS_CD_CONNECTED) {
   1090 		/*
   1091 		 * When connected return backfs stats
   1092 		 */
   1093 		error = VFS_STATVFS(fscp->fs_backvfsp, sbp);
   1094 	} else {
   1095 		/*
   1096 		 * Otherwise, just return the frontfs stats
   1097 		 */
   1098 		ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
   1099 		error = VFS_STATVFS(fscp->fs_fscdirvp->v_vfsp, sbp);
   1100 		if (!error) {
   1101 			dev32_t	d32;
   1102 
   1103 			sbp->f_frsize = MAXBSIZE;
   1104 			sbp->f_blocks = lp->cl_maxblks;
   1105 			sbp->f_bfree = sbp->f_bavail =
   1106 			    lp->cl_maxblks - up->cu_blksused;
   1107 			sbp->f_files = lp->cl_maxinodes;
   1108 			sbp->f_ffree = sbp->f_favail =
   1109 			    lp->cl_maxinodes - up->cu_filesused;
   1110 			(void) cmpldev(&d32, vfsp->vfs_dev);
   1111 			sbp->f_fsid = d32;
   1112 		}
   1113 	}
   1114 	cachefs_cd_release(fscp);
   1115 	if (error)
   1116 		return (error);
   1117 
   1118 	/*
   1119 	 * Make sure fstype is CFS.
   1120 	 */
   1121 	(void) strcpy(sbp->f_basetype, vfssw[vfsp->vfs_fstype].vsw_name);
   1122 	bzero(sbp->f_fstr, sizeof (sbp->f_fstr));
   1123 
   1124 	return (0);
   1125 }
   1126 
   1127 /*
   1128  * queue a request to sync the given fscache
   1129  */
   1130 static void
   1131 queue_sync(struct cachefscache *cachep, cred_t *cr)
   1132 {
   1133 	struct cachefs_req *rp;
   1134 
   1135 	rp = kmem_cache_alloc(cachefs_req_cache, KM_SLEEP);
   1136 	rp->cfs_cmd = CFS_CACHE_SYNC;
   1137 	rp->cfs_cr = cr;
   1138 	rp->cfs_req_u.cu_fs_sync.cf_cachep = cachep;
   1139 	crhold(rp->cfs_cr);
   1140 	cachefs_addqueue(rp, &cachep->c_workq);
   1141 }
   1142 
   1143 /*ARGSUSED*/
   1144 static int
   1145 cachefs_sync(vfs_t *vfsp, short flag, cred_t *cr)
   1146 {
   1147 	struct fscache *fscp;
   1148 	struct cachefscache *cachep;
   1149 
   1150 	if (getzoneid() != GLOBAL_ZONEID)
   1151 		return (EPERM);
   1152 	if (!(flag & SYNC_ATTR)) {
   1153 		/*
   1154 		 * queue an async request to do the sync.
   1155 		 * We always sync an entire cache (as opposed to an
   1156 		 * individual fscache) so that we have an opportunity
   1157 		 * to set the clean flag.
   1158 		 */
   1159 		if (vfsp) {
   1160 			/*LINTED alignment okay*/
   1161 			fscp = (struct fscache *)vfsp->vfs_data;
   1162 			queue_sync(fscp->fs_cache, cr);
   1163 		} else {
   1164 			mutex_enter(&cachefs_cachelock);
   1165 			for (cachep = cachefs_cachelist; cachep != NULL;
   1166 			    cachep = cachep->c_next) {
   1167 				queue_sync(cachep, cr);
   1168 			}
   1169 			mutex_exit(&cachefs_cachelock);
   1170 		}
   1171 	}
   1172 	return (0);
   1173 }
   1174 
   1175 static int
   1176 cachefs_remount(struct vfs *vfsp, struct mounta *uap)
   1177 {
   1178 	fscache_t *fscp = VFS_TO_FSCACHE(vfsp);
   1179 	cachefscache_t *cachep = fscp->fs_cache;
   1180 	int error = 0;
   1181 	STRUCT_DECL(cachefs_mountargs, map);
   1182 	struct cachefsoptions	*cfs_options;
   1183 	char			*backfs, *cacheid, *cachedir;
   1184 	struct vnode *cachedirvp = NULL;
   1185 	ino64_t fsid;
   1186 	vnode_t *backrootvp = NULL;
   1187 	struct vnode *tmpdirvp = NULL;
   1188 
   1189 	STRUCT_INIT(map, get_udatamodel());
   1190 	error = copyin(uap->dataptr, STRUCT_BUF(map),
   1191 			SIZEOF_STRUCT(cachefs_mountargs, DATAMODEL_NATIVE));
   1192 	if (error)
   1193 		goto out;
   1194 
   1195 	/*
   1196 	 * get cache directory vp
   1197 	 */
   1198 	cachedir = (char *)STRUCT_FGETP(map, cfs_cachedir);
   1199 	error = lookupname(cachedir, UIO_USERSPACE, FOLLOW,
   1200 	    NULLVPP, &cachedirvp);
   1201 	if (error)
   1202 		goto out;
   1203 	if (cachedirvp->v_type != VDIR) {
   1204 		error = EINVAL;
   1205 		goto out;
   1206 	}
   1207 
   1208 	error = 0;
   1209 	if (cachedirvp) {
   1210 		error = VOP_LOOKUP(cachedirvp, CACHEFS_DLOG_FILE,
   1211 		    &tmpdirvp, NULL, 0, NULL, kcred, NULL, NULL, NULL);
   1212 	}
   1213 	cfs_options = (struct cachefsoptions *)STRUCT_FADDR(map, cfs_options);
   1214 	cacheid = (char *)STRUCT_FGETP(map, cfs_cacheid);
   1215 /* XXX not quite right */
   1216 #if 0
   1217 	/*
   1218 	 * If a log file exists and the cache is being mounted without
   1219 	 * the snr (aka disconnectable) option, return an error.
   1220 	 */
   1221 	if ((error == 0) &&
   1222 	    !(cfs_options->opt_flags & CFS_DISCONNECTABLE)) {
   1223 		cmn_err(CE_WARN,
   1224 		    "cachefs_mount: log exists and disconnectable"
   1225 		    "option not specified\n");
   1226 		error = EINVAL;
   1227 		goto out;
   1228 	}
   1229 #endif
   1230 	error = 0;
   1231 
   1232 	/*
   1233 	 * If the user is using NFSv4 and there are other options
   1234 	 * specified, make sure we ignore the other options.
   1235 	 */
   1236 	if (CFS_ISFS_BACKFS_NFSV4(fscp)) {
   1237 		cfs_options->opt_flags = CFS_BACKFS_NFSV4;
   1238 	}
   1239 
   1240 	/* XXX need mount options "nocache" and "nofill" */
   1241 
   1242 	/* if nocache is being turned off */
   1243 	if (cachep->c_flags & CACHE_NOCACHE) {
   1244 		error = cachefs_cache_activate_ro(cachep, cachedirvp);
   1245 		if (error)
   1246 			goto out;
   1247 		cachefs_cache_activate_rw(cachep);
   1248 
   1249 		/* get the fsid for the fscache */
   1250 		error = fscache_name_to_fsid(cachep, cacheid, &fsid);
   1251 		if (error)
   1252 			fsid = 0;
   1253 
   1254 		/* activate the fscache */
   1255 		mutex_enter(&cachep->c_fslistlock);
   1256 		error = fscache_enable(fscp, fsid, cacheid,
   1257 			cfs_options, fscp->fs_info.fi_root);
   1258 		mutex_exit(&cachep->c_fslistlock);
   1259 		if (error) {
   1260 			cmn_err(CE_WARN, "cachefs: cannot remount %s\n",
   1261 				cacheid);
   1262 			goto out;
   1263 		}
   1264 
   1265 		/* enable the cache */
   1266 		cachefs_enable_caching(fscp);
   1267 		fscache_activate_rw(fscp);
   1268 	}
   1269 
   1270 	/* else if nofill is being turn off */
   1271 	else if (cachep->c_flags & CACHE_NOFILL) {
   1272 		ASSERT(cachep->c_flags & CACHE_NOFILL);
   1273 		cachefs_cache_activate_rw(cachep);
   1274 
   1275 		/* enable the cache */
   1276 		cachefs_enable_caching(fscp);
   1277 		fscache_activate_rw(fscp);
   1278 	}
   1279 
   1280 	fscache_acset(fscp, STRUCT_FGET(map, cfs_acregmin),
   1281 	    STRUCT_FGET(map, cfs_acregmax),
   1282 	    STRUCT_FGET(map, cfs_acdirmin), STRUCT_FGET(map, cfs_acdirmax));
   1283 
   1284 	/* if the backfs is mounted now or we have a new backfs */
   1285 	backfs = (char *)STRUCT_FGETP(map, cfs_backfs);
   1286 	if (backfs && (cfs_options->opt_flags & CFS_SLIDE)) {
   1287 		/* get the back file system root vp */
   1288 		error = lookupname(backfs, UIO_USERSPACE, FOLLOW,
   1289 			NULLVPP, &backrootvp);
   1290 		if (error)
   1291 			goto out;
   1292 
   1293 		/*
   1294 		 * Make sure the thing we just looked up is a directory
   1295 		 * and a root of a file system
   1296 		 */
   1297 		if (backrootvp->v_type != VDIR ||
   1298 		    !(backrootvp->v_flag & VROOT)) {
   1299 			cmn_err(CE_WARN,
   1300 			    "cachefs_mount: backpath not a directory\n");
   1301 			error = EINVAL;
   1302 			goto out;
   1303 		}
   1304 
   1305 		/*
   1306 		 * XXX
   1307 		 * Kind of dangerous to just set this but we do
   1308 		 * not have locks around usage of fs_backvfsp.
   1309 		 * Hope for the best for now.
   1310 		 * Probably should also spin through vnodes and fix them up.
   1311 		 * Krishna - fixed c_backvp to reflect the change.
   1312 		 */
   1313 		fscp->fs_backvfsp = backrootvp->v_vfsp;
   1314 		((cnode_t *)(fscp->fs_rootvp->v_data))->c_backvp = backrootvp;
   1315 
   1316 		/*
   1317 		 * Now the root cnode structure is an owner of
   1318 		 * the opened back root vnode structure; we must
   1319 		 * clear the pointer to back root vnode here as
   1320 		 * we don't need it since now, and the root cnode
   1321 		 * structure will control the vnode
   1322 		 */
   1323 		backrootvp = (vnode_t *)NULL;
   1324 	}
   1325 
   1326 	if (fscp->fs_kstat_id > 0)
   1327 		cachefs_kstat_umount(fscp->fs_kstat_id);
   1328 	fscp->fs_kstat_id = 0;
   1329 	cachefs_kstat_mount(fscp, uap->dir, backfs, cachedir, cacheid);
   1330 
   1331 	if (CACHEFS_LOG_LOGGING(cachep, CACHEFS_LOG_MOUNT))
   1332 		cachefs_log_mount(cachep, error, vfsp, fscp,
   1333 		    uap->dir, UIO_USERSPACE,
   1334 		    (STRUCT_BUF(map) != NULL) ? cacheid : NULL);
   1335 
   1336 out:
   1337 	if (cachedirvp)
   1338 		VN_RELE(cachedirvp);
   1339 	if (backrootvp)
   1340 		VN_RELE(backrootvp);
   1341 	return (error);
   1342 }
   1343