xref: /titanic_44/usr/src/uts/common/fs/cachefs/cachefs_vfsops.c (revision c40d7343efa60b18ad1ceb316eb337caeea79046)
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 compatable */
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);
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);
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);
566 
567 	/* wake up the cache worker if ANY packed pending work */
568 	mutex_enter(&cachep->c_contentslock);
569 	if (cachep->c_flags & CACHE_PACKED_PENDING)
570 		cv_signal(&cachep->c_cwcv);
571 	mutex_exit(&cachep->c_contentslock);
572 
573 	/*
574 	 * Warn that caching is disabled with NFSv4 first time around.
575 	 */
576 	if (!cachefs_nfsv4_warnmsg && CFS_ISFS_BACKFS_NFSV4(fscp)) {
577 		cmn_err(CE_WARN,
578 			"Cachefs has detected a mount with NFSv4: caching will"
579 			" be disabled for this and other NFSv4 mounts\n");
580 		cachefs_nfsv4_warnmsg = TRUE;
581 	}
582 
583 out:
584 	/*
585 	 * make a log entry, if appropriate
586 	 */
587 
588 	if ((cachep != NULL) &&
589 	    CACHEFS_LOG_LOGGING(cachep, CACHEFS_LOG_MOUNT))
590 		cachefs_log_mount(cachep, error, vfsp, fscp,
591 		    uap->dir, UIO_USERSPACE,
592 		    (STRUCT_BUF(map) != NULL) ? cacheid : NULL);
593 
594 	/*
595 	 * Cleanup our mess
596 	 */
597 	if (cookiep != NULL)
598 		cachefs_kmem_free(cookiep, sizeof (struct fid));
599 	if (cachedirvp != NULL)
600 		VN_RELE(cachedirvp);
601 	if (backrootvp != NULL)
602 		VN_RELE(backrootvp);
603 	if (fscp)
604 		fscache_rele(fscp);
605 	if (attrp)
606 		cachefs_kmem_free(attrp, sizeof (struct vattr));
607 
608 	if (error) {
609 		if (cachep) {
610 			int xx;
611 
612 			/* lock the cachep's fslist */
613 			mutex_enter(&cachep->c_fslistlock);
614 
615 			/*
616 			 * gc isn't necessary for list_mounted(), but
617 			 * we want to do it anyway.
618 			 */
619 
620 			fscache_list_gc(cachep);
621 			xx = fscache_list_mounted(cachep);
622 
623 			mutex_exit(&cachep->c_fslistlock);
624 
625 			/* if no more references to this cachep, punt it. */
626 			if (xx == 0)
627 				cachefs_delete_cachep(cachep);
628 			mutex_exit(&cachefs_cachelock);
629 		}
630 	} else {
631 		mutex_exit(&cachefs_cachelock);
632 	}
633 
634 #ifdef CFSDEBUG
635 	CFS_DEBUG(CFSDEBUG_VFSOP)
636 		printf("cachefs_mount: EXIT\n");
637 #endif
638 	return (error);
639 }
640 
641 void
642 cachefs_kstat_mount(struct fscache *fscp,
643     char *umountpoint, char *ubackfs, char *ucachedir, char *cacheid)
644 {
645 	cachefscache_t *cachep = fscp->fs_cache;
646 	cachefs_kstat_key_t *key;
647 	char *mountpoint = NULL, *backfs = NULL, *cachedir = NULL;
648 	size_t len;
649 	kstat_t *ksp;
650 	int i, rc;
651 
652 	mountpoint = cachefs_kmem_alloc(MAXPATHLEN, KM_SLEEP);
653 	if (copyinstr(umountpoint, mountpoint, MAXPATHLEN, &len) != 0)
654 		goto out;
655 
656 	cachedir = cachefs_kmem_alloc(MAXPATHLEN, KM_SLEEP);
657 	if (copyinstr(ucachedir, cachedir, MAXPATHLEN, &len) != 0)
658 		goto out;
659 
660 	backfs = cachefs_kmem_alloc(MAXPATHLEN, KM_SLEEP);
661 	if (backfs) {
662 		if (copyinstr(ubackfs, backfs, MAXPATHLEN, &len) != 0)
663 			goto out;
664 	} else {
665 		(void) strcpy(backfs, "no back file system");
666 	}
667 
668 	ASSERT(strlen(mountpoint) < MAXPATHLEN);
669 	ASSERT(strlen(backfs) < MAXPATHLEN);
670 	ASSERT(strlen(cachedir) < MAXPATHLEN);
671 
672 	/* protect cachefs_kstat_key */
673 	mutex_enter(&cachefs_kstat_key_lock);
674 	/*
675 	 * XXXX If already there, why not go straight to it?
676 	 * We know that fscp->fs_kstat_id == i + 1
677 	 */
678 	i = fscp->fs_kstat_id - 1;
679 	if ((i >= 0) && (i < cachefs_kstat_key_n))
680 		rc = 1;
681 	else
682 		rc = i = 0;
683 	for (; i < cachefs_kstat_key_n; i++) {
684 		key = cachefs_kstat_key + i;
685 		if (strcmp((char *)(uintptr_t)key->ks_mountpoint,
686 		    mountpoint) == 0 &&
687 		    strcmp((char *)(uintptr_t)key->ks_cachedir,
688 		    cachedir) == 0 &&
689 		    strcmp((char *)(uintptr_t)key->ks_cacheid, cacheid) == 0)
690 			break;
691 		if (rc) {	/* direct key did not work - check all */
692 			i = -1;	/* will increment to zero in loop */
693 			rc = 0;
694 		}
695 	}
696 
697 	if (i >= cachefs_kstat_key_n) {
698 		key = cachefs_kmem_alloc((cachefs_kstat_key_n + 1) *
699 		    sizeof (cachefs_kstat_key_t), KM_SLEEP);
700 		if (cachefs_kstat_key != NULL) {
701 			bcopy(cachefs_kstat_key, key,
702 			    cachefs_kstat_key_n * sizeof (*key));
703 			cachefs_kmem_free(cachefs_kstat_key,
704 			    cachefs_kstat_key_n * sizeof (*key));
705 		}
706 		cachefs_kstat_key = key;
707 		key = cachefs_kstat_key + cachefs_kstat_key_n;
708 		++cachefs_kstat_key_n;
709 		rc = key->ks_id = cachefs_kstat_key_n; /* offset + 1 */
710 
711 		key->ks_mountpoint = (uint64_t)(uintptr_t)
712 		    cachefs_strdup(mountpoint);
713 		key->ks_backfs = (uint64_t)(uintptr_t)cachefs_strdup(backfs);
714 		key->ks_cachedir = (uint64_t)(uintptr_t)
715 		    cachefs_strdup(cachedir);
716 		key->ks_cacheid = (uint64_t)(uintptr_t)cachefs_strdup(cacheid);
717 	} else
718 		rc = key->ks_id;
719 
720 	mutex_enter(&fscp->fs_fslock); /* protect fscp */
721 
722 	fscp->fs_kstat_id = rc;
723 
724 	mutex_exit(&fscp->fs_fslock); /* finished with fscp */
725 	/* finished cachefs_kstat_key */
726 	mutex_exit(&cachefs_kstat_key_lock);
727 
728 	key->ks_vfsp = (uint64_t)(uintptr_t)fscp->fs_cfsvfsp;
729 	key->ks_mounted = 1;
730 
731 	/*
732 	 * we must not be holding any mutex that is a ks_lock field
733 	 * for one of the kstats when we invoke kstat_create,
734 	 * kstat_install, and friends.
735 	 */
736 	ASSERT(MUTEX_NOT_HELD(&cachefs_kstat_key_lock));
737 	/* really should be EVERY cachep's c_log_mutex */
738 	ASSERT(MUTEX_NOT_HELD(&cachep->c_log_mutex));
739 
740 	/* cachefs.#.log */
741 	ksp = kstat_create("cachefs", fscp->fs_kstat_id, "log",
742 	    "misc", KSTAT_TYPE_RAW, 1,
743 	    KSTAT_FLAG_WRITABLE | KSTAT_FLAG_VIRTUAL);
744 	if (ksp != NULL) {
745 		ksp->ks_data = cachep->c_log_ctl;
746 		ksp->ks_data_size = sizeof (cachefs_log_control_t);
747 		ksp->ks_lock = &cachep->c_log_mutex;
748 		ksp->ks_snapshot = cachefs_log_kstat_snapshot;
749 		kstat_install(ksp);
750 	}
751 	/* cachefs.#.stats */
752 	ksp = kstat_create("cachefs", fscp->fs_kstat_id, "stats",
753 	    "misc", KSTAT_TYPE_RAW, 1,
754 	    KSTAT_FLAG_WRITABLE | KSTAT_FLAG_VIRTUAL);
755 	if (ksp != NULL) {
756 		ksp->ks_data = fscp;
757 		ksp->ks_data_size = sizeof (cachefs_stats_t);
758 		ksp->ks_snapshot = cachefs_stats_kstat_snapshot;
759 		kstat_install(ksp);
760 	}
761 
762 out:
763 	if (mountpoint != NULL)
764 		cachefs_kmem_free(mountpoint, MAXPATHLEN);
765 	if (backfs != NULL)
766 		cachefs_kmem_free(backfs, MAXPATHLEN);
767 	if (cachedir != NULL)
768 		cachefs_kmem_free(cachedir, MAXPATHLEN);
769 }
770 
771 void
772 cachefs_kstat_umount(int ksid)
773 {
774 	cachefs_kstat_key_t *k = cachefs_kstat_key + (ksid - 1);
775 
776 	ASSERT(k->ks_id == ksid);
777 
778 	k->ks_mounted = 0;
779 
780 	kstat_delete_byname("cachefs", ksid, "stats");
781 	kstat_delete_byname("cachefs", ksid, "log");
782 }
783 
784 int
785 cachefs_kstat_key_update(kstat_t *ksp, int rw)
786 {
787 	cachefs_kstat_key_t *key = *((cachefs_kstat_key_t **)ksp->ks_data);
788 	cachefs_kstat_key_t *k;
789 	int i;
790 
791 	if (rw == KSTAT_WRITE)
792 		return (EIO);
793 	if (key == NULL)
794 		return (EIO);
795 
796 	ksp->ks_data_size = cachefs_kstat_key_n * sizeof (*key);
797 	for (i = 0; i < cachefs_kstat_key_n; i++) {
798 		k = key + i;
799 
800 		ksp->ks_data_size +=
801 		    strlen((char *)(uintptr_t)k->ks_mountpoint) + 1;
802 		ksp->ks_data_size +=
803 		    strlen((char *)(uintptr_t)k->ks_backfs) + 1;
804 		ksp->ks_data_size +=
805 		    strlen((char *)(uintptr_t)k->ks_cachedir) + 1;
806 		ksp->ks_data_size +=
807 		    strlen((char *)(uintptr_t)k->ks_cacheid) + 1;
808 	}
809 
810 	ksp->ks_ndata = cachefs_kstat_key_n;
811 
812 	return (0);
813 }
814 
815 int
816 cachefs_kstat_key_snapshot(kstat_t *ksp, void *buf, int rw)
817 {
818 	cachefs_kstat_key_t *key = *((cachefs_kstat_key_t **)ksp->ks_data);
819 	cachefs_kstat_key_t *k;
820 	caddr_t s;
821 	int i;
822 
823 	if (rw == KSTAT_WRITE)
824 		return (EIO);
825 
826 	if (key == NULL)
827 		return (0); /* paranoid */
828 
829 	bcopy(key, buf, cachefs_kstat_key_n * sizeof (*key));
830 	key = buf;
831 	s = (caddr_t)(key + cachefs_kstat_key_n);
832 
833 	for (i = 0; i < cachefs_kstat_key_n; i++) {
834 		k = key + i;
835 
836 		(void) strcpy(s, (char *)(uintptr_t)k->ks_mountpoint);
837 		k->ks_mountpoint = (uint64_t)(uintptr_t)(s - (uintptr_t)buf);
838 		s += strlen(s) + 1;
839 		(void) strcpy(s, (char *)(uintptr_t)k->ks_backfs);
840 		k->ks_backfs = (uint64_t)(uintptr_t)(s - (uintptr_t)buf);
841 		s += strlen(s) + 1;
842 		(void) strcpy(s, (char *)(uintptr_t)k->ks_cachedir);
843 		k->ks_cachedir = (uint64_t)(uintptr_t)(s - (uintptr_t)buf);
844 		s += strlen(s) + 1;
845 		(void) strcpy(s, (char *)(uintptr_t)k->ks_cacheid);
846 		k->ks_cacheid = (uint64_t)(uintptr_t)(s - (uintptr_t)buf);
847 		s += strlen(s) + 1;
848 	}
849 
850 	return (0);
851 }
852 
853 extern void  cachefs_inactivate();
854 
855 static int
856 cachefs_unmount(vfs_t *vfsp, int flag, cred_t *cr)
857 {
858 	fscache_t *fscp = VFS_TO_FSCACHE(vfsp);
859 	struct cachefscache *cachep = fscp->fs_cache;
860 	int error;
861 	int xx;
862 	vnode_t *nmvp;
863 	struct vattr attr;
864 
865 #ifdef CFSDEBUG
866 	CFS_DEBUG(CFSDEBUG_VFSOP)
867 		printf("cachefs_unmount: ENTER fscp %p\n", fscp);
868 #endif
869 
870 	if ((error = secpolicy_fs_unmount(cr, vfsp)) != 0)
871 		goto out;
872 
873 	/*
874 	 * forced unmount is not supported by this file system
875 	 * and thus, ENOTSUP, is being returned.
876 	 */
877 	if (flag & MS_FORCE) {
878 		error = ENOTSUP;
879 		goto out;
880 	}
881 	/* if a log file exists don't allow the unmount */
882 	if (fscp->fs_dlogfile) {
883 		error = EBUSY;
884 		goto out;
885 	}
886 
887 	/*
888 	 * wait for the cache-wide async queue to drain.  Someone
889 	 * here may be trying to sync our fscache...
890 	 */
891 	while (cachefs_async_halt(&fscp->fs_cache->c_workq, 0) == EBUSY) {
892 #ifdef CFSDEBUG
893 		CFS_DEBUG(CFSDEBUG_VFSOP)
894 			printf("unmount: waiting for cache async queue...\n");
895 #endif
896 	}
897 
898 	error = cachefs_async_halt(&fscp->fs_workq, 1);
899 	if (error) {
900 #ifdef CFSDEBUG
901 		CFS_DEBUG(CFSDEBUG_VFSOP)
902 			printf("cachefs_unmount: "
903 			    "cachefs_async_halt error %d\n", error);
904 #endif
905 		goto out;
906 	}
907 
908 	/*
909 	 * No active cnodes on this cache && rootvp refcnt == 1
910 	 */
911 	mutex_enter(&fscp->fs_fslock);
912 	xx = fscp->fs_cnodecnt - fscp->fs_idlecnt;
913 	ASSERT(xx >= 1);
914 	if (xx > 1 || fscp->fs_rootvp->v_count != 1) {
915 		mutex_exit(&fscp->fs_fslock);
916 #ifdef CFSDEBUG
917 		CFS_DEBUG(CFSDEBUG_VFSOP)
918 			printf("cachefs_unmount: busy (cnodes active %d, idle "
919 				"%d)\n", fscp->fs_cnodecnt, fscp->fs_idlecnt);
920 #endif
921 		error = EBUSY;
922 		goto out;
923 	}
924 	mutex_exit(&fscp->fs_fslock);
925 
926 	/* get rid of anything on the idle list */
927 	ASSERT(fscp->fs_idleclean == 0);
928 	cachefs_cnode_idleclean(fscp, 1);
929 	if (fscp->fs_cnodecnt > 1) {
930 #ifdef CFSDEBUG
931 		CFS_DEBUG(CFSDEBUG_VFSOP)
932 			printf("cachefs_unmount: busy (cnode count %d)\n",
933 				fscp->fs_cnodecnt);
934 #endif
935 		error = EBUSY;
936 		goto out;
937 	}
938 
939 	fscache_hold(fscp);
940 
941 	/* get rid of the root cnode */
942 	if (cachefs_cnode_inactive(fscp->fs_rootvp, cr) == EBUSY) {
943 		fscache_rele(fscp);
944 #ifdef CFSDEBUG
945 		CFS_DEBUG(CFSDEBUG_VFSOP)
946 			printf("cachefs_unmount: busy (inactive failed)\n");
947 #endif
948 		error = EBUSY;
949 		goto out;
950 	}
951 
952 	/* create the file indicating not mounted */
953 	attr.va_mode = S_IFREG | 0666;
954 	attr.va_uid = 0;
955 	attr.va_gid = 0;
956 	attr.va_type = VREG;
957 	attr.va_mask = AT_TYPE | AT_MODE | AT_UID | AT_GID;
958 	if (fscp->fs_fscdirvp != NULL)
959 		xx = VOP_CREATE(fscp->fs_fscdirvp, CACHEFS_UNMNT_FILE, &attr,
960 		    NONEXCL, 0600, &nmvp, kcred, 0);
961 	else
962 		xx = ENOENT; /* for unmounting when NOCACHE */
963 	if (xx == 0) {
964 		VN_RELE(nmvp);
965 	} else {
966 		printf("could not create %s %d\n", CACHEFS_UNMNT_FILE, xx);
967 	}
968 
969 	ASSERT(fscp->fs_cnodecnt == 0);
970 
971 	/* sync the file system just in case */
972 	fscache_sync(fscp);
973 
974 	/* lock out other unmounts and mount */
975 	mutex_enter(&cachefs_cachelock);
976 
977 	/* mark the file system as not mounted */
978 	mutex_enter(&fscp->fs_fslock);
979 	fscp->fs_flags &= ~CFS_FS_MOUNTED;
980 	fscp->fs_rootvp = NULL;
981 	if (fscp->fs_kstat_id > 0)
982 		cachefs_kstat_umount(fscp->fs_kstat_id);
983 	fscp->fs_kstat_id = 0;
984 
985 	/* drop the inum translation table */
986 	if (fscp->fs_inum_size > 0) {
987 		cachefs_kmem_free(fscp->fs_inum_trans,
988 		    fscp->fs_inum_size * sizeof (cachefs_inum_trans_t));
989 		fscp->fs_inum_size = 0;
990 		fscp->fs_inum_trans = NULL;
991 		fscp->fs_flags &= ~CFS_FS_HASHPRINT;
992 	}
993 	mutex_exit(&fscp->fs_fslock);
994 
995 	fscache_rele(fscp);
996 
997 	/* get rid of any unused fscache objects */
998 	mutex_enter(&cachep->c_fslistlock);
999 	fscache_list_gc(cachep);
1000 	mutex_exit(&cachep->c_fslistlock);
1001 
1002 	/* get the number of mounts on this cache */
1003 	mutex_enter(&cachep->c_fslistlock);
1004 	xx = fscache_list_mounted(cachep);
1005 	mutex_exit(&cachep->c_fslistlock);
1006 
1007 	if (CACHEFS_LOG_LOGGING(cachep, CACHEFS_LOG_UMOUNT))
1008 		cachefs_log_umount(cachep, 0, vfsp);
1009 
1010 	/* if no mounts left, deactivate the cache */
1011 	if (xx == 0)
1012 		cachefs_delete_cachep(cachep);
1013 
1014 	mutex_exit(&cachefs_cachelock);
1015 
1016 out:
1017 	if (error) {
1018 		if (CACHEFS_LOG_LOGGING(cachep, CACHEFS_LOG_UMOUNT))
1019 			cachefs_log_umount(cachep, error, vfsp);
1020 	}
1021 #ifdef CFSDEBUG
1022 	CFS_DEBUG(CFSDEBUG_VFSOP)
1023 		printf("cachefs_unmount: EXIT\n");
1024 #endif
1025 	return (error);
1026 }
1027 
1028 /*
1029  * remove the cache from the list of caches
1030  */
1031 
1032 static void
1033 cachefs_delete_cachep(cachefscache_t *cachep)
1034 {
1035 	struct cachefscache **cachepp;
1036 	int found = 0;
1037 
1038 	ASSERT(MUTEX_HELD(&cachefs_cachelock));
1039 
1040 	for (cachepp = &cachefs_cachelist;
1041 	    *cachepp != NULL;
1042 	    cachepp = &(*cachepp)->c_next) {
1043 		if (*cachepp == cachep) {
1044 			*cachepp = cachep->c_next;
1045 			found++;
1046 			break;
1047 		}
1048 	}
1049 	ASSERT(found);
1050 
1051 	/* shut down the cache */
1052 	cachefs_cache_destroy(cachep);
1053 }
1054 
1055 static int
1056 cachefs_root(vfs_t *vfsp, vnode_t **vpp)
1057 {
1058 	/*LINTED alignment okay*/
1059 	struct fscache *fscp = (struct fscache *)vfsp->vfs_data;
1060 
1061 	ASSERT(fscp != NULL);
1062 	ASSERT(fscp->fs_rootvp != NULL);
1063 
1064 	if (getzoneid() != GLOBAL_ZONEID)
1065 		return (EPERM);
1066 	*vpp = fscp->fs_rootvp;
1067 	VN_HOLD(*vpp);
1068 	return (0);
1069 }
1070 
1071 /*
1072  * Get file system statistics.
1073  */
1074 static int
1075 cachefs_statvfs(register vfs_t *vfsp, struct statvfs64 *sbp)
1076 {
1077 	struct fscache *fscp = VFS_TO_FSCACHE(vfsp);
1078 	struct cache_label *lp = &fscp->fs_cache->c_label;
1079 	struct cache_usage *up = &fscp->fs_cache->c_usage;
1080 	int error;
1081 
1082 	if (getzoneid() != GLOBAL_ZONEID)
1083 		return (EPERM);
1084 	error = cachefs_cd_access(fscp, 0, 0);
1085 	if (error)
1086 		return (error);
1087 
1088 	if (fscp->fs_cdconnected == CFS_CD_CONNECTED) {
1089 		/*
1090 		 * When connected return backfs stats
1091 		 */
1092 		error = VFS_STATVFS(fscp->fs_backvfsp, sbp);
1093 	} else {
1094 		/*
1095 		 * Otherwise, just return the frontfs stats
1096 		 */
1097 		ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
1098 		error = VFS_STATVFS(fscp->fs_fscdirvp->v_vfsp, sbp);
1099 		if (!error) {
1100 			dev32_t	d32;
1101 
1102 			sbp->f_frsize = MAXBSIZE;
1103 			sbp->f_blocks = lp->cl_maxblks;
1104 			sbp->f_bfree = sbp->f_bavail =
1105 			    lp->cl_maxblks - up->cu_blksused;
1106 			sbp->f_files = lp->cl_maxinodes;
1107 			sbp->f_ffree = sbp->f_favail =
1108 			    lp->cl_maxinodes - up->cu_filesused;
1109 			(void) cmpldev(&d32, vfsp->vfs_dev);
1110 			sbp->f_fsid = d32;
1111 		}
1112 	}
1113 	cachefs_cd_release(fscp);
1114 	if (error)
1115 		return (error);
1116 
1117 	/*
1118 	 * Make sure fstype is CFS.
1119 	 */
1120 	(void) strcpy(sbp->f_basetype, vfssw[vfsp->vfs_fstype].vsw_name);
1121 	bzero(sbp->f_fstr, sizeof (sbp->f_fstr));
1122 
1123 	return (0);
1124 }
1125 
1126 /*
1127  * queue a request to sync the given fscache
1128  */
1129 static void
1130 queue_sync(struct cachefscache *cachep, cred_t *cr)
1131 {
1132 	struct cachefs_req *rp;
1133 
1134 	rp = kmem_cache_alloc(cachefs_req_cache, KM_SLEEP);
1135 	rp->cfs_cmd = CFS_CACHE_SYNC;
1136 	rp->cfs_cr = cr;
1137 	rp->cfs_req_u.cu_fs_sync.cf_cachep = cachep;
1138 	crhold(rp->cfs_cr);
1139 	cachefs_addqueue(rp, &cachep->c_workq);
1140 }
1141 
1142 /*ARGSUSED*/
1143 static int
1144 cachefs_sync(vfs_t *vfsp, short flag, cred_t *cr)
1145 {
1146 	struct fscache *fscp;
1147 	struct cachefscache *cachep;
1148 
1149 	if (getzoneid() != GLOBAL_ZONEID)
1150 		return (EPERM);
1151 	if (!(flag & SYNC_ATTR)) {
1152 		/*
1153 		 * queue an async request to do the sync.
1154 		 * We always sync an entire cache (as opposed to an
1155 		 * individual fscache) so that we have an opportunity
1156 		 * to set the clean flag.
1157 		 */
1158 		if (vfsp) {
1159 			/*LINTED alignment okay*/
1160 			fscp = (struct fscache *)vfsp->vfs_data;
1161 			queue_sync(fscp->fs_cache, cr);
1162 		} else {
1163 			mutex_enter(&cachefs_cachelock);
1164 			for (cachep = cachefs_cachelist; cachep != NULL;
1165 			    cachep = cachep->c_next) {
1166 				queue_sync(cachep, cr);
1167 			}
1168 			mutex_exit(&cachefs_cachelock);
1169 		}
1170 	}
1171 	return (0);
1172 }
1173 
1174 static int
1175 cachefs_remount(struct vfs *vfsp, struct mounta *uap)
1176 {
1177 	fscache_t *fscp = VFS_TO_FSCACHE(vfsp);
1178 	cachefscache_t *cachep = fscp->fs_cache;
1179 	int error = 0;
1180 	STRUCT_DECL(cachefs_mountargs, map);
1181 	struct cachefsoptions	*cfs_options;
1182 	char			*backfs, *cacheid, *cachedir;
1183 	struct vnode *cachedirvp = NULL;
1184 	ino64_t fsid;
1185 	vnode_t *backrootvp = NULL;
1186 	struct vnode *tmpdirvp = NULL;
1187 
1188 	STRUCT_INIT(map, get_udatamodel());
1189 	error = copyin(uap->dataptr, STRUCT_BUF(map),
1190 			SIZEOF_STRUCT(cachefs_mountargs, DATAMODEL_NATIVE));
1191 	if (error)
1192 		goto out;
1193 
1194 	/*
1195 	 * get cache directory vp
1196 	 */
1197 	cachedir = (char *)STRUCT_FGETP(map, cfs_cachedir);
1198 	error = lookupname(cachedir, UIO_USERSPACE, FOLLOW,
1199 	    NULLVPP, &cachedirvp);
1200 	if (error)
1201 		goto out;
1202 	if (cachedirvp->v_type != VDIR) {
1203 		error = EINVAL;
1204 		goto out;
1205 	}
1206 
1207 	error = 0;
1208 	if (cachedirvp) {
1209 		error = VOP_LOOKUP(cachedirvp, CACHEFS_DLOG_FILE,
1210 		    &tmpdirvp, NULL, 0, NULL, kcred);
1211 	}
1212 	cfs_options = (struct cachefsoptions *)STRUCT_FADDR(map, cfs_options);
1213 	cacheid = (char *)STRUCT_FGETP(map, cfs_cacheid);
1214 /* XXX not quite right */
1215 #if 0
1216 	/*
1217 	 * If a log file exists and the cache is being mounted without
1218 	 * the snr (aka disconnectable) option, return an error.
1219 	 */
1220 	if ((error == 0) &&
1221 	    !(cfs_options->opt_flags & CFS_DISCONNECTABLE)) {
1222 		cmn_err(CE_WARN,
1223 		    "cachefs_mount: log exists and disconnectable"
1224 		    "option not specified\n");
1225 		error = EINVAL;
1226 		goto out;
1227 	}
1228 #endif
1229 	error = 0;
1230 
1231 	/*
1232 	 * If the user is using NFSv4 and there are other options
1233 	 * specified, make sure we ignore the other options.
1234 	 */
1235 	if (CFS_ISFS_BACKFS_NFSV4(fscp)) {
1236 		cfs_options->opt_flags = CFS_BACKFS_NFSV4;
1237 	}
1238 
1239 	/* XXX need mount options "nocache" and "nofill" */
1240 
1241 	/* if nocache is being turned off */
1242 	if (cachep->c_flags & CACHE_NOCACHE) {
1243 		error = cachefs_cache_activate_ro(cachep, cachedirvp);
1244 		if (error)
1245 			goto out;
1246 		cachefs_cache_activate_rw(cachep);
1247 
1248 		/* get the fsid for the fscache */
1249 		error = fscache_name_to_fsid(cachep, cacheid, &fsid);
1250 		if (error)
1251 			fsid = 0;
1252 
1253 		/* activate the fscache */
1254 		mutex_enter(&cachep->c_fslistlock);
1255 		error = fscache_enable(fscp, fsid, cacheid,
1256 			cfs_options, fscp->fs_info.fi_root);
1257 		mutex_exit(&cachep->c_fslistlock);
1258 		if (error) {
1259 			cmn_err(CE_WARN, "cachefs: cannot remount %s\n",
1260 				cacheid);
1261 			goto out;
1262 		}
1263 
1264 		/* enable the cache */
1265 		cachefs_enable_caching(fscp);
1266 		fscache_activate_rw(fscp);
1267 	}
1268 
1269 	/* else if nofill is being turn off */
1270 	else if (cachep->c_flags & CACHE_NOFILL) {
1271 		ASSERT(cachep->c_flags & CACHE_NOFILL);
1272 		cachefs_cache_activate_rw(cachep);
1273 
1274 		/* enable the cache */
1275 		cachefs_enable_caching(fscp);
1276 		fscache_activate_rw(fscp);
1277 	}
1278 
1279 	fscache_acset(fscp, STRUCT_FGET(map, cfs_acregmin),
1280 	    STRUCT_FGET(map, cfs_acregmax),
1281 	    STRUCT_FGET(map, cfs_acdirmin), STRUCT_FGET(map, cfs_acdirmax));
1282 
1283 	/* if the backfs is mounted now or we have a new backfs */
1284 	backfs = (char *)STRUCT_FGETP(map, cfs_backfs);
1285 	if (backfs && (cfs_options->opt_flags & CFS_SLIDE)) {
1286 		/* get the back file system root vp */
1287 		error = lookupname(backfs, UIO_USERSPACE, FOLLOW,
1288 			NULLVPP, &backrootvp);
1289 		if (error)
1290 			goto out;
1291 
1292 		/*
1293 		 * Make sure the thing we just looked up is a directory
1294 		 * and a root of a file system
1295 		 */
1296 		if (backrootvp->v_type != VDIR ||
1297 		    !(backrootvp->v_flag & VROOT)) {
1298 			cmn_err(CE_WARN,
1299 			    "cachefs_mount: backpath not a directory\n");
1300 			error = EINVAL;
1301 			goto out;
1302 		}
1303 
1304 		/*
1305 		 * XXX
1306 		 * Kind of dangerous to just set this but we do
1307 		 * not have locks around usage of fs_backvfsp.
1308 		 * Hope for the best for now.
1309 		 * Probably should also spin through vnodes and fix them up.
1310 		 * Krishna - fixed c_backvp to reflect the change.
1311 		 */
1312 		fscp->fs_backvfsp = backrootvp->v_vfsp;
1313 		((cnode_t *)(fscp->fs_rootvp->v_data))->c_backvp = backrootvp;
1314 
1315 		/*
1316 		 * Now the root cnode structure is an owner of
1317 		 * the opened back root vnode structure; we must
1318 		 * clear the pointer to back root vnode here as
1319 		 * we don't need it since now, and the root cnode
1320 		 * structure will control the vnode
1321 		 */
1322 		backrootvp = (vnode_t *)NULL;
1323 	}
1324 
1325 	if (fscp->fs_kstat_id > 0)
1326 		cachefs_kstat_umount(fscp->fs_kstat_id);
1327 	fscp->fs_kstat_id = 0;
1328 	cachefs_kstat_mount(fscp, uap->dir, backfs, cachedir, cacheid);
1329 
1330 	if (CACHEFS_LOG_LOGGING(cachep, CACHEFS_LOG_MOUNT))
1331 		cachefs_log_mount(cachep, error, vfsp, fscp,
1332 		    uap->dir, UIO_USERSPACE,
1333 		    (STRUCT_BUF(map) != NULL) ? cacheid : NULL);
1334 
1335 out:
1336 	if (cachedirvp)
1337 		VN_RELE(cachedirvp);
1338 	if (backrootvp)
1339 		VN_RELE(backrootvp);
1340 	return (error);
1341 }
1342