xref: /titanic_44/usr/src/uts/common/fs/cachefs/cachefs_vfsops.c (revision da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0)
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
cachefs_init_vfsops(int fstype)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
cachefs_mkmntdev(void)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
cachefs_mount(vfs_t * vfsp,vnode_t * mvp,struct mounta * uap,cred_t * cr)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
cachefs_kstat_mount(struct fscache * fscp,char * umountpoint,char * ubackfs,char * ucachedir,char * cacheid)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
cachefs_kstat_umount(int ksid)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
cachefs_kstat_key_update(kstat_t * ksp,int rw)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
cachefs_kstat_key_snapshot(kstat_t * ksp,void * buf,int rw)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
cachefs_unmount(vfs_t * vfsp,int flag,cred_t * cr)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
cachefs_delete_cachep(cachefscache_t * cachep)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
cachefs_root(vfs_t * vfsp,vnode_t ** vpp)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
cachefs_statvfs(register vfs_t * vfsp,struct statvfs64 * sbp)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
queue_sync(struct cachefscache * cachep,cred_t * cr)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
cachefs_sync(vfs_t * vfsp,short flag,cred_t * cr)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
cachefs_remount(struct vfs * vfsp,struct mounta * uap)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