10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
53898Srsb * Common Development and Distribution License (the "License").
63898Srsb * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
223898Srsb * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
230Sstevel@tonic-gate * Use is subject to license terms.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
270Sstevel@tonic-gate
280Sstevel@tonic-gate #include <sys/param.h>
290Sstevel@tonic-gate #include <sys/types.h>
300Sstevel@tonic-gate #include <sys/systm.h>
310Sstevel@tonic-gate #include <sys/cred.h>
320Sstevel@tonic-gate #include <sys/proc.h>
330Sstevel@tonic-gate #include <sys/user.h>
340Sstevel@tonic-gate #include <sys/vfs.h>
353898Srsb #include <sys/vfs_opreg.h>
360Sstevel@tonic-gate #include <sys/vnode.h>
370Sstevel@tonic-gate #include <sys/pathname.h>
380Sstevel@tonic-gate #include <sys/uio.h>
390Sstevel@tonic-gate #include <sys/tiuser.h>
400Sstevel@tonic-gate #include <sys/sysmacros.h>
410Sstevel@tonic-gate #include <sys/kmem.h>
420Sstevel@tonic-gate #include <sys/mount.h>
430Sstevel@tonic-gate #include <sys/ioctl.h>
440Sstevel@tonic-gate #include <sys/statvfs.h>
450Sstevel@tonic-gate #include <sys/stat.h>
460Sstevel@tonic-gate #include <sys/errno.h>
470Sstevel@tonic-gate #include <sys/debug.h>
480Sstevel@tonic-gate #include <sys/cmn_err.h>
490Sstevel@tonic-gate #include <sys/utsname.h>
500Sstevel@tonic-gate #include <sys/bootconf.h>
510Sstevel@tonic-gate #include <sys/reboot.h>
520Sstevel@tonic-gate #include <sys/modctl.h>
530Sstevel@tonic-gate #include <rpc/types.h>
540Sstevel@tonic-gate
550Sstevel@tonic-gate #include <sys/fs/cachefs_fs.h>
560Sstevel@tonic-gate #include <sys/fs/cachefs_log.h>
570Sstevel@tonic-gate #include <sys/mkdev.h>
580Sstevel@tonic-gate #include <sys/dnlc.h>
590Sstevel@tonic-gate #include <sys/policy.h>
600Sstevel@tonic-gate #include "fs/fs_subr.h"
610Sstevel@tonic-gate
620Sstevel@tonic-gate extern kmutex_t cachefs_kmem_lock;
630Sstevel@tonic-gate kmutex_t cachefs_kstat_key_lock;
640Sstevel@tonic-gate
650Sstevel@tonic-gate /* forward declarations */
660Sstevel@tonic-gate static int cachefs_remount(struct vfs *, struct mounta *);
670Sstevel@tonic-gate static void cachefs_delete_cachep(cachefscache_t *);
680Sstevel@tonic-gate
690Sstevel@tonic-gate #define CFS_MAPSIZE 256
700Sstevel@tonic-gate
710Sstevel@tonic-gate kmutex_t cachefs_cachelock; /* Cache list mutex */
720Sstevel@tonic-gate cachefscache_t *cachefs_cachelist = NULL; /* Cache struct list */
730Sstevel@tonic-gate
740Sstevel@tonic-gate int cachefs_mount_retries = 3;
750Sstevel@tonic-gate kmutex_t cachefs_minor_lock; /* Lock for minor device map */
760Sstevel@tonic-gate major_t cachefs_major = 0;
770Sstevel@tonic-gate minor_t cachefs_minor = 0;
780Sstevel@tonic-gate cachefs_kstat_key_t *cachefs_kstat_key = NULL;
790Sstevel@tonic-gate int cachefs_kstat_key_n = 0;
800Sstevel@tonic-gate static uint32_t cachefs_nfsv4_warnmsg = FALSE;
810Sstevel@tonic-gate
820Sstevel@tonic-gate /*
830Sstevel@tonic-gate * cachefs vfs operations.
840Sstevel@tonic-gate */
850Sstevel@tonic-gate static int cachefs_mount(vfs_t *, vnode_t *, struct mounta *, cred_t *);
860Sstevel@tonic-gate static int cachefs_unmount(vfs_t *, int, cred_t *);
870Sstevel@tonic-gate static int cachefs_root(vfs_t *, vnode_t **);
880Sstevel@tonic-gate static int cachefs_statvfs(register vfs_t *, struct statvfs64 *);
890Sstevel@tonic-gate static int cachefs_sync(vfs_t *, short, cred_t *);
900Sstevel@tonic-gate
910Sstevel@tonic-gate /*
920Sstevel@tonic-gate * Initialize the vfs structure
930Sstevel@tonic-gate */
940Sstevel@tonic-gate int cachefsfstyp;
950Sstevel@tonic-gate int cnodesize = 0;
960Sstevel@tonic-gate
970Sstevel@tonic-gate int
cachefs_init_vfsops(int fstype)980Sstevel@tonic-gate cachefs_init_vfsops(int fstype)
990Sstevel@tonic-gate {
1000Sstevel@tonic-gate static const fs_operation_def_t cachefs_vfsops_template[] = {
1013898Srsb VFSNAME_MOUNT, { .vfs_mount = cachefs_mount },
1023898Srsb VFSNAME_UNMOUNT, { .vfs_unmount = cachefs_unmount },
1033898Srsb VFSNAME_ROOT, { .vfs_root = cachefs_root },
1043898Srsb VFSNAME_STATVFS, { .vfs_statvfs = cachefs_statvfs },
1053898Srsb VFSNAME_SYNC, { .vfs_sync = cachefs_sync },
1063898Srsb NULL, NULL
1070Sstevel@tonic-gate };
1080Sstevel@tonic-gate int error;
1090Sstevel@tonic-gate
1100Sstevel@tonic-gate error = vfs_setfsops(fstype, cachefs_vfsops_template, NULL);
1110Sstevel@tonic-gate if (error != 0)
1120Sstevel@tonic-gate return (error);
1130Sstevel@tonic-gate
1140Sstevel@tonic-gate cachefsfstyp = fstype;
1150Sstevel@tonic-gate
1160Sstevel@tonic-gate return (0);
1170Sstevel@tonic-gate }
1180Sstevel@tonic-gate
1190Sstevel@tonic-gate dev_t
cachefs_mkmntdev(void)1200Sstevel@tonic-gate cachefs_mkmntdev(void)
1210Sstevel@tonic-gate {
1220Sstevel@tonic-gate dev_t cachefs_dev;
1230Sstevel@tonic-gate
1240Sstevel@tonic-gate mutex_enter(&cachefs_minor_lock);
1250Sstevel@tonic-gate do {
1260Sstevel@tonic-gate cachefs_minor = (cachefs_minor + 1) & MAXMIN32;
1270Sstevel@tonic-gate cachefs_dev = makedevice(cachefs_major, cachefs_minor);
1280Sstevel@tonic-gate } while (vfs_devismounted(cachefs_dev));
1290Sstevel@tonic-gate mutex_exit(&cachefs_minor_lock);
1300Sstevel@tonic-gate
1310Sstevel@tonic-gate return (cachefs_dev);
1320Sstevel@tonic-gate }
1330Sstevel@tonic-gate
1340Sstevel@tonic-gate /*
1350Sstevel@tonic-gate * vfs operations
1360Sstevel@tonic-gate */
1370Sstevel@tonic-gate static int
cachefs_mount(vfs_t * vfsp,vnode_t * mvp,struct mounta * uap,cred_t * cr)1380Sstevel@tonic-gate cachefs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
1390Sstevel@tonic-gate {
1400Sstevel@tonic-gate char *data = uap->dataptr;
1410Sstevel@tonic-gate STRUCT_DECL(cachefs_mountargs, map);
1420Sstevel@tonic-gate struct cachefsoptions *cfs_options;
1430Sstevel@tonic-gate char *backfs, *cacheid, *cachedir;
1440Sstevel@tonic-gate vnode_t *cachedirvp = NULL;
1450Sstevel@tonic-gate vnode_t *backrootvp = NULL;
1460Sstevel@tonic-gate cachefscache_t *cachep = NULL;
1470Sstevel@tonic-gate fscache_t *fscp = NULL;
1480Sstevel@tonic-gate cnode_t *cp;
1490Sstevel@tonic-gate struct fid *cookiep = NULL;
1500Sstevel@tonic-gate struct vattr *attrp = NULL;
1510Sstevel@tonic-gate dev_t cachefs_dev; /* devid for this mount */
1520Sstevel@tonic-gate int error = 0;
1530Sstevel@tonic-gate int retries = cachefs_mount_retries;
1540Sstevel@tonic-gate ino64_t fsid;
1550Sstevel@tonic-gate cfs_cid_t cid;
1560Sstevel@tonic-gate char *backmntpt;
1570Sstevel@tonic-gate ino64_t backfileno;
1580Sstevel@tonic-gate struct vfs *backvfsp;
1590Sstevel@tonic-gate size_t strl;
1600Sstevel@tonic-gate char tmpstr[MAXPATHLEN];
1610Sstevel@tonic-gate vnode_t *tmpdirvp = NULL;
1620Sstevel@tonic-gate ulong_t maxfilesizebits;
1630Sstevel@tonic-gate uint32_t valid_fid;
1640Sstevel@tonic-gate
1650Sstevel@tonic-gate #ifdef CFSDEBUG
1660Sstevel@tonic-gate CFS_DEBUG(CFSDEBUG_VFSOP)
1670Sstevel@tonic-gate printf("cachefs_mount: ENTER cachefs_mntargs %p\n", data);
1680Sstevel@tonic-gate #endif
1690Sstevel@tonic-gate
1700Sstevel@tonic-gate /*
1710Sstevel@tonic-gate * Make sure we have sufficient privileges.
1720Sstevel@tonic-gate */
1730Sstevel@tonic-gate if ((error = secpolicy_fs_mount(cr, mvp, vfsp)) != 0)
1740Sstevel@tonic-gate goto out;
1750Sstevel@tonic-gate
1760Sstevel@tonic-gate /*
1770Sstevel@tonic-gate * make sure we're mounting on a directory
1780Sstevel@tonic-gate */
1790Sstevel@tonic-gate if (mvp->v_type != VDIR) {
1800Sstevel@tonic-gate error = ENOTDIR;
1810Sstevel@tonic-gate goto out;
1820Sstevel@tonic-gate }
1830Sstevel@tonic-gate
1840Sstevel@tonic-gate /*
1850Sstevel@tonic-gate * Determine the zone we're being mounted into, and make sure it's the
1860Sstevel@tonic-gate * global zone.
1870Sstevel@tonic-gate */
1880Sstevel@tonic-gate if (getzoneid() == GLOBAL_ZONEID) {
1890Sstevel@tonic-gate zone_t *mntzone;
1900Sstevel@tonic-gate
1910Sstevel@tonic-gate mntzone = zone_find_by_path(refstr_value(vfsp->vfs_mntpt));
1920Sstevel@tonic-gate ASSERT(mntzone != NULL);
1930Sstevel@tonic-gate zone_rele(mntzone);
1940Sstevel@tonic-gate if (mntzone != curproc->p_zone) {
1950Sstevel@tonic-gate error = EBUSY;
1960Sstevel@tonic-gate goto out;
1970Sstevel@tonic-gate }
1980Sstevel@tonic-gate } else {
1990Sstevel@tonic-gate error = EPERM;
2000Sstevel@tonic-gate goto out;
2010Sstevel@tonic-gate }
2020Sstevel@tonic-gate
2030Sstevel@tonic-gate if (uap->flags & MS_REMOUNT) {
2040Sstevel@tonic-gate error = cachefs_remount(vfsp, uap);
2050Sstevel@tonic-gate goto out;
2060Sstevel@tonic-gate }
2070Sstevel@tonic-gate
2080Sstevel@tonic-gate /*
2090Sstevel@tonic-gate * Assign a unique device id to the mount
2100Sstevel@tonic-gate */
2110Sstevel@tonic-gate cachefs_dev = cachefs_mkmntdev();
2120Sstevel@tonic-gate #ifdef _LP64
2130Sstevel@tonic-gate /*
2140Sstevel@tonic-gate * It's not a good idea to make fsid bigger since that'll
2150Sstevel@tonic-gate * have adverse effects on nfs filehandles. For now assume that
2160Sstevel@tonic-gate * cachefs be used on devices that fit into dev32_t's.
2170Sstevel@tonic-gate */
2180Sstevel@tonic-gate if (cachefs_dev == NODEV) {
2190Sstevel@tonic-gate error = EOVERFLOW;
2200Sstevel@tonic-gate goto out;
2210Sstevel@tonic-gate }
2220Sstevel@tonic-gate #endif
2230Sstevel@tonic-gate
2240Sstevel@tonic-gate /*
2250Sstevel@tonic-gate * Copy in the arguments
2260Sstevel@tonic-gate */
2270Sstevel@tonic-gate STRUCT_INIT(map, get_udatamodel());
2280Sstevel@tonic-gate error = copyin(data, STRUCT_BUF(map),
2290Sstevel@tonic-gate SIZEOF_STRUCT(cachefs_mountargs, DATAMODEL_NATIVE));
2300Sstevel@tonic-gate if (error) {
2310Sstevel@tonic-gate goto out;
2320Sstevel@tonic-gate }
2330Sstevel@tonic-gate
2340Sstevel@tonic-gate cfs_options = (struct cachefsoptions *)STRUCT_FADDR(map, cfs_options);
2350Sstevel@tonic-gate cacheid = (char *)STRUCT_FGETP(map, cfs_cacheid);
2360Sstevel@tonic-gate if ((cfs_options->opt_flags &
2370Sstevel@tonic-gate (CFS_WRITE_AROUND|CFS_NONSHARED|CFS_BACKFS_NFSV4)) == 0) {
2380Sstevel@tonic-gate error = EINVAL;
2390Sstevel@tonic-gate goto out;
2400Sstevel@tonic-gate }
2410Sstevel@tonic-gate if ((cfs_options->opt_popsize % MAXBSIZE) != 0) {
2420Sstevel@tonic-gate error = EINVAL;
2430Sstevel@tonic-gate goto out;
2440Sstevel@tonic-gate }
2450Sstevel@tonic-gate /*
2460Sstevel@tonic-gate * Get the cache directory vp
2470Sstevel@tonic-gate */
2480Sstevel@tonic-gate /*LINTED 32-bit pointer casting okay*/
2490Sstevel@tonic-gate cachedir = (char *)STRUCT_FGETP(map, cfs_cachedir);
2500Sstevel@tonic-gate error = lookupname(cachedir, UIO_USERSPACE, FOLLOW,
2510Sstevel@tonic-gate NULLVPP, &cachedirvp);
2520Sstevel@tonic-gate if (error)
2530Sstevel@tonic-gate goto out;
2540Sstevel@tonic-gate
2550Sstevel@tonic-gate /*
2560Sstevel@tonic-gate * Make sure the thing we just looked up is a directory
2570Sstevel@tonic-gate */
2580Sstevel@tonic-gate if (cachedirvp->v_type != VDIR) {
2590Sstevel@tonic-gate cmn_err(CE_WARN, "cachefs_mount: cachedir not a directory\n");
2600Sstevel@tonic-gate error = EINVAL;
2610Sstevel@tonic-gate goto out;
2620Sstevel@tonic-gate }
2630Sstevel@tonic-gate
2640Sstevel@tonic-gate /*
2650Sstevel@tonic-gate * Make sure the cache doesn't live in cachefs!
2660Sstevel@tonic-gate */
2670Sstevel@tonic-gate if (vn_matchops(cachedirvp, cachefs_getvnodeops())) {
2680Sstevel@tonic-gate cmn_err(CE_WARN, "cachefs_mount: cachedir in cachefs!\n");
2690Sstevel@tonic-gate error = EINVAL;
2700Sstevel@tonic-gate goto out;
2710Sstevel@tonic-gate }
2720Sstevel@tonic-gate
2730Sstevel@tonic-gate /* if the backfs is mounted */
2740Sstevel@tonic-gate /*LINTED 32-bit pointer casting okay*/
2750Sstevel@tonic-gate if ((backfs = STRUCT_FGETP(map, cfs_backfs)) != NULL) {
2760Sstevel@tonic-gate /*
2770Sstevel@tonic-gate * Get the back file system root vp
2780Sstevel@tonic-gate */
2790Sstevel@tonic-gate error = lookupname(backfs, UIO_USERSPACE, FOLLOW,
2800Sstevel@tonic-gate NULLVPP, &backrootvp);
2810Sstevel@tonic-gate if (error)
2820Sstevel@tonic-gate goto out;
2830Sstevel@tonic-gate
2840Sstevel@tonic-gate /*
2850Sstevel@tonic-gate * Make sure the thing we just looked up is a directory
2860Sstevel@tonic-gate * and a root of a file system
2870Sstevel@tonic-gate */
2880Sstevel@tonic-gate if (backrootvp->v_type != VDIR ||
2890Sstevel@tonic-gate !(backrootvp->v_flag & VROOT)) {
2900Sstevel@tonic-gate cmn_err(CE_WARN,
2910Sstevel@tonic-gate "cachefs_mount: backpath not a directory\n");
2920Sstevel@tonic-gate error = EINVAL;
2930Sstevel@tonic-gate goto out;
2940Sstevel@tonic-gate }
2950Sstevel@tonic-gate
2960Sstevel@tonic-gate /*
2970Sstevel@tonic-gate * Get the fid and attributes for the root of the
2980Sstevel@tonic-gate * backfilesystem, except if NFSv4 is in use,
2990Sstevel@tonic-gate * in which case we get the attributes only (the
3000Sstevel@tonic-gate * (VOP_FID() operation called by cachefs_get_cookie()
3010Sstevel@tonic-gate * is not supported in NFSv4).
3020Sstevel@tonic-gate */
3030Sstevel@tonic-gate cookiep = cachefs_kmem_alloc(sizeof (struct fid), KM_SLEEP);
3040Sstevel@tonic-gate attrp = cachefs_kmem_alloc(sizeof (struct vattr), KM_SLEEP);
3050Sstevel@tonic-gate
3060Sstevel@tonic-gate if ((cfs_options->opt_flags & CFS_BACKFS_NFSV4)) {
3070Sstevel@tonic-gate valid_fid = FALSE;
3080Sstevel@tonic-gate } else {
3090Sstevel@tonic-gate valid_fid = TRUE;
3100Sstevel@tonic-gate }
3110Sstevel@tonic-gate error = cachefs_getcookie(backrootvp, cookiep, attrp, cr,
3120Sstevel@tonic-gate valid_fid);
3130Sstevel@tonic-gate
3140Sstevel@tonic-gate if (error)
3150Sstevel@tonic-gate goto out;
3160Sstevel@tonic-gate
3170Sstevel@tonic-gate backmntpt = backfs;
3180Sstevel@tonic-gate backfileno = attrp->va_nodeid;
3190Sstevel@tonic-gate backvfsp = backrootvp->v_vfsp;
3200Sstevel@tonic-gate } else {
3210Sstevel@tonic-gate backmntpt = NULL;
3220Sstevel@tonic-gate backfileno = 0;
3230Sstevel@tonic-gate backvfsp = NULL;
3240Sstevel@tonic-gate }
3250Sstevel@tonic-gate
3260Sstevel@tonic-gate again:
3270Sstevel@tonic-gate
3280Sstevel@tonic-gate /*
3290Sstevel@tonic-gate * In SVR4 it's not acceptable to stack up mounts
3300Sstevel@tonic-gate * unless MS_OVERLAY specified.
3310Sstevel@tonic-gate */
3320Sstevel@tonic-gate mutex_enter(&mvp->v_lock);
3330Sstevel@tonic-gate if (((uap->flags & MS_OVERLAY) == 0) &&
3340Sstevel@tonic-gate ((mvp->v_count != 1) || (mvp->v_flag & VROOT))) {
3350Sstevel@tonic-gate mutex_exit(&mvp->v_lock);
3360Sstevel@tonic-gate error = EBUSY;
3370Sstevel@tonic-gate goto out;
3380Sstevel@tonic-gate }
3390Sstevel@tonic-gate mutex_exit(&mvp->v_lock);
3400Sstevel@tonic-gate
3410Sstevel@tonic-gate /*
3420Sstevel@tonic-gate * Lock out other mounts and unmounts until we safely have
3430Sstevel@tonic-gate * a mounted fscache object.
3440Sstevel@tonic-gate */
3450Sstevel@tonic-gate mutex_enter(&cachefs_cachelock);
3460Sstevel@tonic-gate
3470Sstevel@tonic-gate /*
3480Sstevel@tonic-gate * Find the cache structure
3490Sstevel@tonic-gate */
3500Sstevel@tonic-gate for (cachep = cachefs_cachelist; cachep != NULL;
3510Sstevel@tonic-gate cachep = cachep->c_next) {
3520Sstevel@tonic-gate if (cachep->c_dirvp == cachedirvp)
3530Sstevel@tonic-gate break;
3540Sstevel@tonic-gate }
3550Sstevel@tonic-gate
3560Sstevel@tonic-gate /* if the cache object does not exist, then create it */
3570Sstevel@tonic-gate if (cachep == NULL) {
3580Sstevel@tonic-gate cachep = cachefs_cache_create();
3590Sstevel@tonic-gate error = cachefs_cache_activate_ro(cachep, cachedirvp);
3600Sstevel@tonic-gate if (error) {
3610Sstevel@tonic-gate cachefs_cache_destroy(cachep);
3620Sstevel@tonic-gate cachep = NULL;
3630Sstevel@tonic-gate goto out;
3640Sstevel@tonic-gate }
3650Sstevel@tonic-gate if ((cfs_options->opt_flags & CFS_NOFILL) == 0)
3660Sstevel@tonic-gate cachefs_cache_activate_rw(cachep);
3670Sstevel@tonic-gate else
3680Sstevel@tonic-gate cfs_options->opt_flags &= ~CFS_NOFILL;
3690Sstevel@tonic-gate
3700Sstevel@tonic-gate cachep->c_next = cachefs_cachelist;
3710Sstevel@tonic-gate cachefs_cachelist = cachep;
3720Sstevel@tonic-gate } else if (cfs_options->opt_flags & CFS_NOFILL) {
3730Sstevel@tonic-gate cmn_err(CE_WARN,
3740Sstevel@tonic-gate "CacheFS: attempt to convert nonempty cache "
3750Sstevel@tonic-gate "to NOFILL mode");
3760Sstevel@tonic-gate error = EINVAL;
3770Sstevel@tonic-gate goto out;
3780Sstevel@tonic-gate }
3790Sstevel@tonic-gate
3800Sstevel@tonic-gate /* get the fscache id for this name */
3810Sstevel@tonic-gate error = fscache_name_to_fsid(cachep, cacheid, &fsid);
3820Sstevel@tonic-gate if (error) {
3830Sstevel@tonic-gate fsid = 0;
3840Sstevel@tonic-gate }
3850Sstevel@tonic-gate
3860Sstevel@tonic-gate /* find the fscache object for this mount point or create it */
3870Sstevel@tonic-gate mutex_enter(&cachep->c_fslistlock);
3880Sstevel@tonic-gate fscp = fscache_list_find(cachep, fsid);
3890Sstevel@tonic-gate if (fscp == NULL) {
3900Sstevel@tonic-gate fscp = fscache_create(cachep);
3910Sstevel@tonic-gate error = fscache_activate(fscp, fsid, cacheid,
3920Sstevel@tonic-gate cfs_options, backfileno);
3930Sstevel@tonic-gate if (error) {
3940Sstevel@tonic-gate fscache_destroy(fscp);
3950Sstevel@tonic-gate fscp = NULL;
3960Sstevel@tonic-gate mutex_exit(&cachep->c_fslistlock);
3970Sstevel@tonic-gate if ((error == ENOSPC) && (retries-- > 0)) {
3980Sstevel@tonic-gate mutex_exit(&cachefs_cachelock);
3990Sstevel@tonic-gate delay(6 * hz);
4000Sstevel@tonic-gate goto again;
4010Sstevel@tonic-gate }
4020Sstevel@tonic-gate goto out;
4030Sstevel@tonic-gate }
4040Sstevel@tonic-gate fscache_list_add(cachep, fscp);
4050Sstevel@tonic-gate } else {
406*5331Samw /* compare the options to make sure they are compatible */
4070Sstevel@tonic-gate error = fscache_compare_options(fscp, cfs_options);
4080Sstevel@tonic-gate if (error) {
4090Sstevel@tonic-gate cmn_err(CE_WARN,
4100Sstevel@tonic-gate "CacheFS: mount failed, options do not match.");
4110Sstevel@tonic-gate fscp = NULL;
4120Sstevel@tonic-gate mutex_exit(&cachep->c_fslistlock);
4130Sstevel@tonic-gate goto out;
4140Sstevel@tonic-gate }
4150Sstevel@tonic-gate
4160Sstevel@tonic-gate /* copy options into the fscache */
4170Sstevel@tonic-gate mutex_enter(&fscp->fs_fslock);
4180Sstevel@tonic-gate fscp->fs_info.fi_mntflags = cfs_options->opt_flags;
4190Sstevel@tonic-gate fscp->fs_info.fi_popsize = cfs_options->opt_popsize;
4200Sstevel@tonic-gate fscp->fs_info.fi_fgsize = cfs_options->opt_fgsize;
4210Sstevel@tonic-gate fscp->fs_flags |= CFS_FS_DIRTYINFO;
4220Sstevel@tonic-gate mutex_exit(&fscp->fs_fslock);
4230Sstevel@tonic-gate }
4240Sstevel@tonic-gate fscache_hold(fscp);
4250Sstevel@tonic-gate
4260Sstevel@tonic-gate error = 0;
4270Sstevel@tonic-gate if (fscp->fs_fscdirvp) {
4280Sstevel@tonic-gate error = VOP_LOOKUP(fscp->fs_fscdirvp, CACHEFS_DLOG_FILE,
429*5331Samw &tmpdirvp, NULL, 0, NULL, kcred, NULL, NULL, NULL);
4300Sstevel@tonic-gate
4310Sstevel@tonic-gate /*
4320Sstevel@tonic-gate * If a log file exists and the cache is being mounted without
4330Sstevel@tonic-gate * the snr (aka disconnectable) option, return an error.
4340Sstevel@tonic-gate */
4350Sstevel@tonic-gate if ((error == 0) &&
4360Sstevel@tonic-gate !(cfs_options->opt_flags & CFS_DISCONNECTABLE)) {
4370Sstevel@tonic-gate mutex_exit(&cachep->c_fslistlock);
4380Sstevel@tonic-gate cmn_err(CE_WARN, "cachefs: log exists and "
4390Sstevel@tonic-gate "disconnectable option not specified\n");
4400Sstevel@tonic-gate error = EINVAL;
4410Sstevel@tonic-gate goto out;
4420Sstevel@tonic-gate }
4430Sstevel@tonic-gate }
4440Sstevel@tonic-gate
4450Sstevel@tonic-gate /*
4460Sstevel@tonic-gate * Acquire the name of the mount point
4470Sstevel@tonic-gate */
4480Sstevel@tonic-gate if (fscp->fs_mntpt == NULL) {
4490Sstevel@tonic-gate /*
4500Sstevel@tonic-gate * the string length returned by copystr includes the
4510Sstevel@tonic-gate * terminating NULL character, unless a NULL string is
4520Sstevel@tonic-gate * passed in, then the string length is unchanged.
4530Sstevel@tonic-gate */
4540Sstevel@tonic-gate strl = 0;
4550Sstevel@tonic-gate tmpstr[0] = '\0';
4560Sstevel@tonic-gate (void) copyinstr(uap->dir, tmpstr, MAXPATHLEN, &strl);
4570Sstevel@tonic-gate if (strl > 1) {
4580Sstevel@tonic-gate fscp->fs_mntpt = kmem_alloc(strl, KM_SLEEP);
4590Sstevel@tonic-gate (void) strncpy(fscp->fs_mntpt, tmpstr, strl);
4600Sstevel@tonic-gate }
4610Sstevel@tonic-gate /*
4620Sstevel@tonic-gate * else fscp->fs_mntpt is unchanged(still NULL) try again
4630Sstevel@tonic-gate * next time
4640Sstevel@tonic-gate */
4650Sstevel@tonic-gate }
4660Sstevel@tonic-gate
4670Sstevel@tonic-gate /*
4680Sstevel@tonic-gate * Acquire the name of the server
4690Sstevel@tonic-gate */
4700Sstevel@tonic-gate if (fscp->fs_hostname == NULL) {
4710Sstevel@tonic-gate strl = 0;
4720Sstevel@tonic-gate tmpstr[0] = '\0';
4730Sstevel@tonic-gate /*LINTED 32-bit pointer casting okay*/
4740Sstevel@tonic-gate (void) copyinstr((char *)STRUCT_FGETP(map, cfs_hostname),
4750Sstevel@tonic-gate tmpstr, MAXPATHLEN, &strl);
4760Sstevel@tonic-gate if (strl > 1) {
4770Sstevel@tonic-gate fscp->fs_hostname = kmem_alloc(strl, KM_SLEEP);
4780Sstevel@tonic-gate (void) strncpy(fscp->fs_hostname, tmpstr, strl);
4790Sstevel@tonic-gate }
4800Sstevel@tonic-gate /*
4810Sstevel@tonic-gate * else fscp->fs_hostname remains unchanged (is still NULL)
4820Sstevel@tonic-gate */
4830Sstevel@tonic-gate }
4840Sstevel@tonic-gate
4850Sstevel@tonic-gate /*
4860Sstevel@tonic-gate * Acquire name of the back filesystem
4870Sstevel@tonic-gate */
4880Sstevel@tonic-gate if (fscp->fs_backfsname == NULL) {
4890Sstevel@tonic-gate strl = 0;
4900Sstevel@tonic-gate tmpstr[0] = '\0';
4910Sstevel@tonic-gate /*LINTED 32-bit pointer casting okay*/
4920Sstevel@tonic-gate (void) copyinstr((char *)STRUCT_FGETP(map, cfs_backfsname),
4930Sstevel@tonic-gate tmpstr, MAXPATHLEN, &strl);
4940Sstevel@tonic-gate if (strl > 1) {
4950Sstevel@tonic-gate fscp->fs_backfsname = kmem_alloc(strl, KM_SLEEP);
4960Sstevel@tonic-gate (void) strncpy(fscp->fs_backfsname, tmpstr, strl);
4970Sstevel@tonic-gate }
4980Sstevel@tonic-gate /*
4990Sstevel@tonic-gate * else fscp->fs_backfsname remains unchanged (is still NULL)
5000Sstevel@tonic-gate */
5010Sstevel@tonic-gate }
5020Sstevel@tonic-gate
5030Sstevel@tonic-gate backfileno = fscp->fs_info.fi_root;
5040Sstevel@tonic-gate mutex_exit(&cachep->c_fslistlock);
5050Sstevel@tonic-gate
5060Sstevel@tonic-gate /* see if fscache object is already mounted, it not, make it so */
5070Sstevel@tonic-gate error = fscache_mounted(fscp, vfsp, backvfsp);
5080Sstevel@tonic-gate if (error) {
5090Sstevel@tonic-gate /* fs cache was already mounted */
5100Sstevel@tonic-gate error = EBUSY;
5110Sstevel@tonic-gate goto out;
5120Sstevel@tonic-gate }
5130Sstevel@tonic-gate
5140Sstevel@tonic-gate cachefs_kstat_mount(fscp, uap->dir, backmntpt, cachedir, cacheid);
5150Sstevel@tonic-gate
5160Sstevel@tonic-gate /* set nfs style time out parameters */
5170Sstevel@tonic-gate fscache_acset(fscp, STRUCT_FGET(map, cfs_acregmin),
5180Sstevel@tonic-gate STRUCT_FGET(map, cfs_acregmax),
5190Sstevel@tonic-gate STRUCT_FGET(map, cfs_acdirmin), STRUCT_FGET(map, cfs_acdirmax));
5200Sstevel@tonic-gate
5210Sstevel@tonic-gate vfsp->vfs_dev = cachefs_dev;
5220Sstevel@tonic-gate vfsp->vfs_data = (caddr_t)fscp;
5230Sstevel@tonic-gate vfs_make_fsid(&vfsp->vfs_fsid, cachefs_dev, cachefsfstyp);
5240Sstevel@tonic-gate vfsp->vfs_fstype = cachefsfstyp;
5250Sstevel@tonic-gate if (backvfsp)
5260Sstevel@tonic-gate vfsp->vfs_bsize = backvfsp->vfs_bsize;
5270Sstevel@tonic-gate else
5280Sstevel@tonic-gate vfsp->vfs_bsize = MAXBSIZE; /* XXX */
5290Sstevel@tonic-gate
5300Sstevel@tonic-gate /* make a cnode for the root of the file system */
5310Sstevel@tonic-gate cid.cid_flags = 0;
5320Sstevel@tonic-gate cid.cid_fileno = backfileno;
5330Sstevel@tonic-gate error = cachefs_cnode_make(&cid, fscp, (valid_fid ? cookiep : NULL),
5340Sstevel@tonic-gate attrp, backrootvp, cr, CN_ROOT, &cp);
5350Sstevel@tonic-gate
5360Sstevel@tonic-gate if (error) {
5370Sstevel@tonic-gate cmn_err(CE_WARN, "cachefs_mount: can't create root cnode\n");
5380Sstevel@tonic-gate goto out;
5390Sstevel@tonic-gate }
5400Sstevel@tonic-gate
5410Sstevel@tonic-gate /* stick the root cnode in the fscache object */
5420Sstevel@tonic-gate mutex_enter(&fscp->fs_fslock);
5430Sstevel@tonic-gate fscp->fs_rootvp = CTOV(cp);
5440Sstevel@tonic-gate fscp->fs_rootvp->v_flag |= VROOT;
5450Sstevel@tonic-gate fscp->fs_rootvp->v_type |= cp->c_attr.va_type;
5460Sstevel@tonic-gate ASSERT(fscp->fs_rootvp->v_type == VDIR);
5470Sstevel@tonic-gate
5480Sstevel@tonic-gate /*
5490Sstevel@tonic-gate * Get the maxfilesize bits of the back file system.
5500Sstevel@tonic-gate */
5510Sstevel@tonic-gate
5520Sstevel@tonic-gate error = VOP_PATHCONF(backrootvp, _PC_FILESIZEBITS, &maxfilesizebits,
553*5331Samw kcred, NULL);
5540Sstevel@tonic-gate
5550Sstevel@tonic-gate if (error) {
5560Sstevel@tonic-gate cmn_err(CE_WARN,
5570Sstevel@tonic-gate "cachefs_mount: Can't get the FILESIZEBITS of the back root vnode \n");
5580Sstevel@tonic-gate goto out;
5590Sstevel@tonic-gate }
5600Sstevel@tonic-gate
5610Sstevel@tonic-gate fscp->fs_offmax = (1LL << (maxfilesizebits - 1)) - 1;
5620Sstevel@tonic-gate mutex_exit(&fscp->fs_fslock);
5630Sstevel@tonic-gate
5640Sstevel@tonic-gate /* remove the unmount file if it is there */
565*5331Samw (void) VOP_REMOVE(fscp->fs_fscdirvp, CACHEFS_UNMNT_FILE, kcred, NULL,
566*5331Samw 0);
5670Sstevel@tonic-gate
5680Sstevel@tonic-gate /* wake up the cache worker if ANY packed pending work */
5690Sstevel@tonic-gate mutex_enter(&cachep->c_contentslock);
5700Sstevel@tonic-gate if (cachep->c_flags & CACHE_PACKED_PENDING)
5710Sstevel@tonic-gate cv_signal(&cachep->c_cwcv);
5720Sstevel@tonic-gate mutex_exit(&cachep->c_contentslock);
5730Sstevel@tonic-gate
5740Sstevel@tonic-gate /*
5750Sstevel@tonic-gate * Warn that caching is disabled with NFSv4 first time around.
5760Sstevel@tonic-gate */
5770Sstevel@tonic-gate if (!cachefs_nfsv4_warnmsg && CFS_ISFS_BACKFS_NFSV4(fscp)) {
5780Sstevel@tonic-gate cmn_err(CE_WARN,
5790Sstevel@tonic-gate "Cachefs has detected a mount with NFSv4: caching will"
5800Sstevel@tonic-gate " be disabled for this and other NFSv4 mounts\n");
5810Sstevel@tonic-gate cachefs_nfsv4_warnmsg = TRUE;
5820Sstevel@tonic-gate }
5830Sstevel@tonic-gate
5840Sstevel@tonic-gate out:
5850Sstevel@tonic-gate /*
5860Sstevel@tonic-gate * make a log entry, if appropriate
5870Sstevel@tonic-gate */
5880Sstevel@tonic-gate
5890Sstevel@tonic-gate if ((cachep != NULL) &&
5900Sstevel@tonic-gate CACHEFS_LOG_LOGGING(cachep, CACHEFS_LOG_MOUNT))
5910Sstevel@tonic-gate cachefs_log_mount(cachep, error, vfsp, fscp,
5920Sstevel@tonic-gate uap->dir, UIO_USERSPACE,
5930Sstevel@tonic-gate (STRUCT_BUF(map) != NULL) ? cacheid : NULL);
5940Sstevel@tonic-gate
5950Sstevel@tonic-gate /*
5960Sstevel@tonic-gate * Cleanup our mess
5970Sstevel@tonic-gate */
5980Sstevel@tonic-gate if (cookiep != NULL)
5990Sstevel@tonic-gate cachefs_kmem_free(cookiep, sizeof (struct fid));
6000Sstevel@tonic-gate if (cachedirvp != NULL)
6010Sstevel@tonic-gate VN_RELE(cachedirvp);
6020Sstevel@tonic-gate if (backrootvp != NULL)
6030Sstevel@tonic-gate VN_RELE(backrootvp);
6040Sstevel@tonic-gate if (fscp)
6050Sstevel@tonic-gate fscache_rele(fscp);
6060Sstevel@tonic-gate if (attrp)
6070Sstevel@tonic-gate cachefs_kmem_free(attrp, sizeof (struct vattr));
6080Sstevel@tonic-gate
6090Sstevel@tonic-gate if (error) {
6100Sstevel@tonic-gate if (cachep) {
6110Sstevel@tonic-gate int xx;
6120Sstevel@tonic-gate
6130Sstevel@tonic-gate /* lock the cachep's fslist */
6140Sstevel@tonic-gate mutex_enter(&cachep->c_fslistlock);
6150Sstevel@tonic-gate
6160Sstevel@tonic-gate /*
6170Sstevel@tonic-gate * gc isn't necessary for list_mounted(), but
6180Sstevel@tonic-gate * we want to do it anyway.
6190Sstevel@tonic-gate */
6200Sstevel@tonic-gate
6210Sstevel@tonic-gate fscache_list_gc(cachep);
6220Sstevel@tonic-gate xx = fscache_list_mounted(cachep);
6230Sstevel@tonic-gate
6240Sstevel@tonic-gate mutex_exit(&cachep->c_fslistlock);
6250Sstevel@tonic-gate
6260Sstevel@tonic-gate /* if no more references to this cachep, punt it. */
6270Sstevel@tonic-gate if (xx == 0)
6280Sstevel@tonic-gate cachefs_delete_cachep(cachep);
6290Sstevel@tonic-gate mutex_exit(&cachefs_cachelock);
6300Sstevel@tonic-gate }
6310Sstevel@tonic-gate } else {
6320Sstevel@tonic-gate mutex_exit(&cachefs_cachelock);
6330Sstevel@tonic-gate }
6340Sstevel@tonic-gate
6350Sstevel@tonic-gate #ifdef CFSDEBUG
6360Sstevel@tonic-gate CFS_DEBUG(CFSDEBUG_VFSOP)
6370Sstevel@tonic-gate printf("cachefs_mount: EXIT\n");
6380Sstevel@tonic-gate #endif
6390Sstevel@tonic-gate return (error);
6400Sstevel@tonic-gate }
6410Sstevel@tonic-gate
6420Sstevel@tonic-gate void
cachefs_kstat_mount(struct fscache * fscp,char * umountpoint,char * ubackfs,char * ucachedir,char * cacheid)6430Sstevel@tonic-gate cachefs_kstat_mount(struct fscache *fscp,
6440Sstevel@tonic-gate char *umountpoint, char *ubackfs, char *ucachedir, char *cacheid)
6450Sstevel@tonic-gate {
6460Sstevel@tonic-gate cachefscache_t *cachep = fscp->fs_cache;
6470Sstevel@tonic-gate cachefs_kstat_key_t *key;
6480Sstevel@tonic-gate char *mountpoint = NULL, *backfs = NULL, *cachedir = NULL;
6490Sstevel@tonic-gate size_t len;
6500Sstevel@tonic-gate kstat_t *ksp;
6510Sstevel@tonic-gate int i, rc;
6520Sstevel@tonic-gate
6530Sstevel@tonic-gate mountpoint = cachefs_kmem_alloc(MAXPATHLEN, KM_SLEEP);
6540Sstevel@tonic-gate if (copyinstr(umountpoint, mountpoint, MAXPATHLEN, &len) != 0)
6550Sstevel@tonic-gate goto out;
6560Sstevel@tonic-gate
6570Sstevel@tonic-gate cachedir = cachefs_kmem_alloc(MAXPATHLEN, KM_SLEEP);
6580Sstevel@tonic-gate if (copyinstr(ucachedir, cachedir, MAXPATHLEN, &len) != 0)
6590Sstevel@tonic-gate goto out;
6600Sstevel@tonic-gate
6610Sstevel@tonic-gate backfs = cachefs_kmem_alloc(MAXPATHLEN, KM_SLEEP);
6620Sstevel@tonic-gate if (backfs) {
6630Sstevel@tonic-gate if (copyinstr(ubackfs, backfs, MAXPATHLEN, &len) != 0)
6640Sstevel@tonic-gate goto out;
6650Sstevel@tonic-gate } else {
6660Sstevel@tonic-gate (void) strcpy(backfs, "no back file system");
6670Sstevel@tonic-gate }
6680Sstevel@tonic-gate
6690Sstevel@tonic-gate ASSERT(strlen(mountpoint) < MAXPATHLEN);
6700Sstevel@tonic-gate ASSERT(strlen(backfs) < MAXPATHLEN);
6710Sstevel@tonic-gate ASSERT(strlen(cachedir) < MAXPATHLEN);
6720Sstevel@tonic-gate
6730Sstevel@tonic-gate /* protect cachefs_kstat_key */
6740Sstevel@tonic-gate mutex_enter(&cachefs_kstat_key_lock);
6750Sstevel@tonic-gate /*
6760Sstevel@tonic-gate * XXXX If already there, why not go straight to it?
6770Sstevel@tonic-gate * We know that fscp->fs_kstat_id == i + 1
6780Sstevel@tonic-gate */
6790Sstevel@tonic-gate i = fscp->fs_kstat_id - 1;
6800Sstevel@tonic-gate if ((i >= 0) && (i < cachefs_kstat_key_n))
6810Sstevel@tonic-gate rc = 1;
6820Sstevel@tonic-gate else
6830Sstevel@tonic-gate rc = i = 0;
6840Sstevel@tonic-gate for (; i < cachefs_kstat_key_n; i++) {
6850Sstevel@tonic-gate key = cachefs_kstat_key + i;
6860Sstevel@tonic-gate if (strcmp((char *)(uintptr_t)key->ks_mountpoint,
6870Sstevel@tonic-gate mountpoint) == 0 &&
6880Sstevel@tonic-gate strcmp((char *)(uintptr_t)key->ks_cachedir,
6890Sstevel@tonic-gate cachedir) == 0 &&
6900Sstevel@tonic-gate strcmp((char *)(uintptr_t)key->ks_cacheid, cacheid) == 0)
6910Sstevel@tonic-gate break;
6920Sstevel@tonic-gate if (rc) { /* direct key did not work - check all */
6930Sstevel@tonic-gate i = -1; /* will increment to zero in loop */
6940Sstevel@tonic-gate rc = 0;
6950Sstevel@tonic-gate }
6960Sstevel@tonic-gate }
6970Sstevel@tonic-gate
6980Sstevel@tonic-gate if (i >= cachefs_kstat_key_n) {
6990Sstevel@tonic-gate key = cachefs_kmem_alloc((cachefs_kstat_key_n + 1) *
7000Sstevel@tonic-gate sizeof (cachefs_kstat_key_t), KM_SLEEP);
7010Sstevel@tonic-gate if (cachefs_kstat_key != NULL) {
7020Sstevel@tonic-gate bcopy(cachefs_kstat_key, key,
7030Sstevel@tonic-gate cachefs_kstat_key_n * sizeof (*key));
7040Sstevel@tonic-gate cachefs_kmem_free(cachefs_kstat_key,
7050Sstevel@tonic-gate cachefs_kstat_key_n * sizeof (*key));
7060Sstevel@tonic-gate }
7070Sstevel@tonic-gate cachefs_kstat_key = key;
7080Sstevel@tonic-gate key = cachefs_kstat_key + cachefs_kstat_key_n;
7090Sstevel@tonic-gate ++cachefs_kstat_key_n;
7100Sstevel@tonic-gate rc = key->ks_id = cachefs_kstat_key_n; /* offset + 1 */
7110Sstevel@tonic-gate
7120Sstevel@tonic-gate key->ks_mountpoint = (uint64_t)(uintptr_t)
7130Sstevel@tonic-gate cachefs_strdup(mountpoint);
7140Sstevel@tonic-gate key->ks_backfs = (uint64_t)(uintptr_t)cachefs_strdup(backfs);
7150Sstevel@tonic-gate key->ks_cachedir = (uint64_t)(uintptr_t)
7160Sstevel@tonic-gate cachefs_strdup(cachedir);
7170Sstevel@tonic-gate key->ks_cacheid = (uint64_t)(uintptr_t)cachefs_strdup(cacheid);
7180Sstevel@tonic-gate } else
7190Sstevel@tonic-gate rc = key->ks_id;
7200Sstevel@tonic-gate
7210Sstevel@tonic-gate mutex_enter(&fscp->fs_fslock); /* protect fscp */
7220Sstevel@tonic-gate
7230Sstevel@tonic-gate fscp->fs_kstat_id = rc;
7240Sstevel@tonic-gate
7250Sstevel@tonic-gate mutex_exit(&fscp->fs_fslock); /* finished with fscp */
7260Sstevel@tonic-gate /* finished cachefs_kstat_key */
7270Sstevel@tonic-gate mutex_exit(&cachefs_kstat_key_lock);
7280Sstevel@tonic-gate
7290Sstevel@tonic-gate key->ks_vfsp = (uint64_t)(uintptr_t)fscp->fs_cfsvfsp;
7300Sstevel@tonic-gate key->ks_mounted = 1;
7310Sstevel@tonic-gate
7320Sstevel@tonic-gate /*
7330Sstevel@tonic-gate * we must not be holding any mutex that is a ks_lock field
7340Sstevel@tonic-gate * for one of the kstats when we invoke kstat_create,
7350Sstevel@tonic-gate * kstat_install, and friends.
7360Sstevel@tonic-gate */
7370Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&cachefs_kstat_key_lock));
7380Sstevel@tonic-gate /* really should be EVERY cachep's c_log_mutex */
7390Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&cachep->c_log_mutex));
7400Sstevel@tonic-gate
7410Sstevel@tonic-gate /* cachefs.#.log */
7420Sstevel@tonic-gate ksp = kstat_create("cachefs", fscp->fs_kstat_id, "log",
7430Sstevel@tonic-gate "misc", KSTAT_TYPE_RAW, 1,
7440Sstevel@tonic-gate KSTAT_FLAG_WRITABLE | KSTAT_FLAG_VIRTUAL);
7450Sstevel@tonic-gate if (ksp != NULL) {
7460Sstevel@tonic-gate ksp->ks_data = cachep->c_log_ctl;
7470Sstevel@tonic-gate ksp->ks_data_size = sizeof (cachefs_log_control_t);
7480Sstevel@tonic-gate ksp->ks_lock = &cachep->c_log_mutex;
7490Sstevel@tonic-gate ksp->ks_snapshot = cachefs_log_kstat_snapshot;
7500Sstevel@tonic-gate kstat_install(ksp);
7510Sstevel@tonic-gate }
7520Sstevel@tonic-gate /* cachefs.#.stats */
7530Sstevel@tonic-gate ksp = kstat_create("cachefs", fscp->fs_kstat_id, "stats",
7540Sstevel@tonic-gate "misc", KSTAT_TYPE_RAW, 1,
7550Sstevel@tonic-gate KSTAT_FLAG_WRITABLE | KSTAT_FLAG_VIRTUAL);
7560Sstevel@tonic-gate if (ksp != NULL) {
7570Sstevel@tonic-gate ksp->ks_data = fscp;
7580Sstevel@tonic-gate ksp->ks_data_size = sizeof (cachefs_stats_t);
7590Sstevel@tonic-gate ksp->ks_snapshot = cachefs_stats_kstat_snapshot;
7600Sstevel@tonic-gate kstat_install(ksp);
7610Sstevel@tonic-gate }
7620Sstevel@tonic-gate
7630Sstevel@tonic-gate out:
7640Sstevel@tonic-gate if (mountpoint != NULL)
7650Sstevel@tonic-gate cachefs_kmem_free(mountpoint, MAXPATHLEN);
7660Sstevel@tonic-gate if (backfs != NULL)
7670Sstevel@tonic-gate cachefs_kmem_free(backfs, MAXPATHLEN);
7680Sstevel@tonic-gate if (cachedir != NULL)
7690Sstevel@tonic-gate cachefs_kmem_free(cachedir, MAXPATHLEN);
7700Sstevel@tonic-gate }
7710Sstevel@tonic-gate
7720Sstevel@tonic-gate void
cachefs_kstat_umount(int ksid)7730Sstevel@tonic-gate cachefs_kstat_umount(int ksid)
7740Sstevel@tonic-gate {
7750Sstevel@tonic-gate cachefs_kstat_key_t *k = cachefs_kstat_key + (ksid - 1);
7760Sstevel@tonic-gate
7770Sstevel@tonic-gate ASSERT(k->ks_id == ksid);
7780Sstevel@tonic-gate
7790Sstevel@tonic-gate k->ks_mounted = 0;
7800Sstevel@tonic-gate
7810Sstevel@tonic-gate kstat_delete_byname("cachefs", ksid, "stats");
7820Sstevel@tonic-gate kstat_delete_byname("cachefs", ksid, "log");
7830Sstevel@tonic-gate }
7840Sstevel@tonic-gate
7850Sstevel@tonic-gate int
cachefs_kstat_key_update(kstat_t * ksp,int rw)7860Sstevel@tonic-gate cachefs_kstat_key_update(kstat_t *ksp, int rw)
7870Sstevel@tonic-gate {
7880Sstevel@tonic-gate cachefs_kstat_key_t *key = *((cachefs_kstat_key_t **)ksp->ks_data);
7890Sstevel@tonic-gate cachefs_kstat_key_t *k;
7900Sstevel@tonic-gate int i;
7910Sstevel@tonic-gate
7920Sstevel@tonic-gate if (rw == KSTAT_WRITE)
7930Sstevel@tonic-gate return (EIO);
7940Sstevel@tonic-gate if (key == NULL)
7950Sstevel@tonic-gate return (EIO);
7960Sstevel@tonic-gate
7970Sstevel@tonic-gate ksp->ks_data_size = cachefs_kstat_key_n * sizeof (*key);
7980Sstevel@tonic-gate for (i = 0; i < cachefs_kstat_key_n; i++) {
7990Sstevel@tonic-gate k = key + i;
8000Sstevel@tonic-gate
8010Sstevel@tonic-gate ksp->ks_data_size +=
8020Sstevel@tonic-gate strlen((char *)(uintptr_t)k->ks_mountpoint) + 1;
8030Sstevel@tonic-gate ksp->ks_data_size +=
8040Sstevel@tonic-gate strlen((char *)(uintptr_t)k->ks_backfs) + 1;
8050Sstevel@tonic-gate ksp->ks_data_size +=
8060Sstevel@tonic-gate strlen((char *)(uintptr_t)k->ks_cachedir) + 1;
8070Sstevel@tonic-gate ksp->ks_data_size +=
8080Sstevel@tonic-gate strlen((char *)(uintptr_t)k->ks_cacheid) + 1;
8090Sstevel@tonic-gate }
8100Sstevel@tonic-gate
8110Sstevel@tonic-gate ksp->ks_ndata = cachefs_kstat_key_n;
8120Sstevel@tonic-gate
8130Sstevel@tonic-gate return (0);
8140Sstevel@tonic-gate }
8150Sstevel@tonic-gate
8160Sstevel@tonic-gate int
cachefs_kstat_key_snapshot(kstat_t * ksp,void * buf,int rw)8170Sstevel@tonic-gate cachefs_kstat_key_snapshot(kstat_t *ksp, void *buf, int rw)
8180Sstevel@tonic-gate {
8190Sstevel@tonic-gate cachefs_kstat_key_t *key = *((cachefs_kstat_key_t **)ksp->ks_data);
8200Sstevel@tonic-gate cachefs_kstat_key_t *k;
8210Sstevel@tonic-gate caddr_t s;
8220Sstevel@tonic-gate int i;
8230Sstevel@tonic-gate
8240Sstevel@tonic-gate if (rw == KSTAT_WRITE)
8250Sstevel@tonic-gate return (EIO);
8260Sstevel@tonic-gate
8270Sstevel@tonic-gate if (key == NULL)
8280Sstevel@tonic-gate return (0); /* paranoid */
8290Sstevel@tonic-gate
8300Sstevel@tonic-gate bcopy(key, buf, cachefs_kstat_key_n * sizeof (*key));
8310Sstevel@tonic-gate key = buf;
8320Sstevel@tonic-gate s = (caddr_t)(key + cachefs_kstat_key_n);
8330Sstevel@tonic-gate
8340Sstevel@tonic-gate for (i = 0; i < cachefs_kstat_key_n; i++) {
8350Sstevel@tonic-gate k = key + i;
8360Sstevel@tonic-gate
8370Sstevel@tonic-gate (void) strcpy(s, (char *)(uintptr_t)k->ks_mountpoint);
8380Sstevel@tonic-gate k->ks_mountpoint = (uint64_t)(uintptr_t)(s - (uintptr_t)buf);
8390Sstevel@tonic-gate s += strlen(s) + 1;
8400Sstevel@tonic-gate (void) strcpy(s, (char *)(uintptr_t)k->ks_backfs);
8410Sstevel@tonic-gate k->ks_backfs = (uint64_t)(uintptr_t)(s - (uintptr_t)buf);
8420Sstevel@tonic-gate s += strlen(s) + 1;
8430Sstevel@tonic-gate (void) strcpy(s, (char *)(uintptr_t)k->ks_cachedir);
8440Sstevel@tonic-gate k->ks_cachedir = (uint64_t)(uintptr_t)(s - (uintptr_t)buf);
8450Sstevel@tonic-gate s += strlen(s) + 1;
8460Sstevel@tonic-gate (void) strcpy(s, (char *)(uintptr_t)k->ks_cacheid);
8470Sstevel@tonic-gate k->ks_cacheid = (uint64_t)(uintptr_t)(s - (uintptr_t)buf);
8480Sstevel@tonic-gate s += strlen(s) + 1;
8490Sstevel@tonic-gate }
8500Sstevel@tonic-gate
8510Sstevel@tonic-gate return (0);
8520Sstevel@tonic-gate }
8530Sstevel@tonic-gate
8540Sstevel@tonic-gate extern void cachefs_inactivate();
8550Sstevel@tonic-gate
8560Sstevel@tonic-gate static int
cachefs_unmount(vfs_t * vfsp,int flag,cred_t * cr)8570Sstevel@tonic-gate cachefs_unmount(vfs_t *vfsp, int flag, cred_t *cr)
8580Sstevel@tonic-gate {
8590Sstevel@tonic-gate fscache_t *fscp = VFS_TO_FSCACHE(vfsp);
8600Sstevel@tonic-gate struct cachefscache *cachep = fscp->fs_cache;
8610Sstevel@tonic-gate int error;
8620Sstevel@tonic-gate int xx;
8630Sstevel@tonic-gate vnode_t *nmvp;
8640Sstevel@tonic-gate struct vattr attr;
8650Sstevel@tonic-gate
8660Sstevel@tonic-gate #ifdef CFSDEBUG
8670Sstevel@tonic-gate CFS_DEBUG(CFSDEBUG_VFSOP)
8680Sstevel@tonic-gate printf("cachefs_unmount: ENTER fscp %p\n", fscp);
8690Sstevel@tonic-gate #endif
8700Sstevel@tonic-gate
8710Sstevel@tonic-gate if ((error = secpolicy_fs_unmount(cr, vfsp)) != 0)
8720Sstevel@tonic-gate goto out;
8730Sstevel@tonic-gate
8740Sstevel@tonic-gate /*
8750Sstevel@tonic-gate * forced unmount is not supported by this file system
8760Sstevel@tonic-gate * and thus, ENOTSUP, is being returned.
8770Sstevel@tonic-gate */
8780Sstevel@tonic-gate if (flag & MS_FORCE) {
8790Sstevel@tonic-gate error = ENOTSUP;
8800Sstevel@tonic-gate goto out;
8810Sstevel@tonic-gate }
8820Sstevel@tonic-gate /* if a log file exists don't allow the unmount */
8830Sstevel@tonic-gate if (fscp->fs_dlogfile) {
8840Sstevel@tonic-gate error = EBUSY;
8850Sstevel@tonic-gate goto out;
8860Sstevel@tonic-gate }
8870Sstevel@tonic-gate
8880Sstevel@tonic-gate /*
8890Sstevel@tonic-gate * wait for the cache-wide async queue to drain. Someone
8900Sstevel@tonic-gate * here may be trying to sync our fscache...
8910Sstevel@tonic-gate */
8920Sstevel@tonic-gate while (cachefs_async_halt(&fscp->fs_cache->c_workq, 0) == EBUSY) {
8930Sstevel@tonic-gate #ifdef CFSDEBUG
8940Sstevel@tonic-gate CFS_DEBUG(CFSDEBUG_VFSOP)
8950Sstevel@tonic-gate printf("unmount: waiting for cache async queue...\n");
8960Sstevel@tonic-gate #endif
8970Sstevel@tonic-gate }
8980Sstevel@tonic-gate
8990Sstevel@tonic-gate error = cachefs_async_halt(&fscp->fs_workq, 1);
9000Sstevel@tonic-gate if (error) {
9010Sstevel@tonic-gate #ifdef CFSDEBUG
9020Sstevel@tonic-gate CFS_DEBUG(CFSDEBUG_VFSOP)
9030Sstevel@tonic-gate printf("cachefs_unmount: "
9040Sstevel@tonic-gate "cachefs_async_halt error %d\n", error);
9050Sstevel@tonic-gate #endif
9060Sstevel@tonic-gate goto out;
9070Sstevel@tonic-gate }
9080Sstevel@tonic-gate
9090Sstevel@tonic-gate /*
9100Sstevel@tonic-gate * No active cnodes on this cache && rootvp refcnt == 1
9110Sstevel@tonic-gate */
9120Sstevel@tonic-gate mutex_enter(&fscp->fs_fslock);
9130Sstevel@tonic-gate xx = fscp->fs_cnodecnt - fscp->fs_idlecnt;
9140Sstevel@tonic-gate ASSERT(xx >= 1);
9150Sstevel@tonic-gate if (xx > 1 || fscp->fs_rootvp->v_count != 1) {
9160Sstevel@tonic-gate mutex_exit(&fscp->fs_fslock);
9170Sstevel@tonic-gate #ifdef CFSDEBUG
9180Sstevel@tonic-gate CFS_DEBUG(CFSDEBUG_VFSOP)
9190Sstevel@tonic-gate printf("cachefs_unmount: busy (cnodes active %d, idle "
9200Sstevel@tonic-gate "%d)\n", fscp->fs_cnodecnt, fscp->fs_idlecnt);
9210Sstevel@tonic-gate #endif
9220Sstevel@tonic-gate error = EBUSY;
9230Sstevel@tonic-gate goto out;
9240Sstevel@tonic-gate }
9250Sstevel@tonic-gate mutex_exit(&fscp->fs_fslock);
9260Sstevel@tonic-gate
9270Sstevel@tonic-gate /* get rid of anything on the idle list */
9280Sstevel@tonic-gate ASSERT(fscp->fs_idleclean == 0);
9290Sstevel@tonic-gate cachefs_cnode_idleclean(fscp, 1);
9300Sstevel@tonic-gate if (fscp->fs_cnodecnt > 1) {
9310Sstevel@tonic-gate #ifdef CFSDEBUG
9320Sstevel@tonic-gate CFS_DEBUG(CFSDEBUG_VFSOP)
9330Sstevel@tonic-gate printf("cachefs_unmount: busy (cnode count %d)\n",
9340Sstevel@tonic-gate fscp->fs_cnodecnt);
9350Sstevel@tonic-gate #endif
9360Sstevel@tonic-gate error = EBUSY;
9370Sstevel@tonic-gate goto out;
9380Sstevel@tonic-gate }
9390Sstevel@tonic-gate
9400Sstevel@tonic-gate fscache_hold(fscp);
9410Sstevel@tonic-gate
9420Sstevel@tonic-gate /* get rid of the root cnode */
9430Sstevel@tonic-gate if (cachefs_cnode_inactive(fscp->fs_rootvp, cr) == EBUSY) {
9440Sstevel@tonic-gate fscache_rele(fscp);
9450Sstevel@tonic-gate #ifdef CFSDEBUG
9460Sstevel@tonic-gate CFS_DEBUG(CFSDEBUG_VFSOP)
9470Sstevel@tonic-gate printf("cachefs_unmount: busy (inactive failed)\n");
9480Sstevel@tonic-gate #endif
9490Sstevel@tonic-gate error = EBUSY;
9500Sstevel@tonic-gate goto out;
9510Sstevel@tonic-gate }
9520Sstevel@tonic-gate
9530Sstevel@tonic-gate /* create the file indicating not mounted */
9540Sstevel@tonic-gate attr.va_mode = S_IFREG | 0666;
9550Sstevel@tonic-gate attr.va_uid = 0;
9560Sstevel@tonic-gate attr.va_gid = 0;
9570Sstevel@tonic-gate attr.va_type = VREG;
9580Sstevel@tonic-gate attr.va_mask = AT_TYPE | AT_MODE | AT_UID | AT_GID;
9590Sstevel@tonic-gate if (fscp->fs_fscdirvp != NULL)
9600Sstevel@tonic-gate xx = VOP_CREATE(fscp->fs_fscdirvp, CACHEFS_UNMNT_FILE, &attr,
961*5331Samw NONEXCL, 0600, &nmvp, kcred, 0, NULL, NULL);
9620Sstevel@tonic-gate else
9630Sstevel@tonic-gate xx = ENOENT; /* for unmounting when NOCACHE */
9640Sstevel@tonic-gate if (xx == 0) {
9650Sstevel@tonic-gate VN_RELE(nmvp);
9660Sstevel@tonic-gate } else {
9670Sstevel@tonic-gate printf("could not create %s %d\n", CACHEFS_UNMNT_FILE, xx);
9680Sstevel@tonic-gate }
9690Sstevel@tonic-gate
9700Sstevel@tonic-gate ASSERT(fscp->fs_cnodecnt == 0);
9710Sstevel@tonic-gate
9720Sstevel@tonic-gate /* sync the file system just in case */
9730Sstevel@tonic-gate fscache_sync(fscp);
9740Sstevel@tonic-gate
9750Sstevel@tonic-gate /* lock out other unmounts and mount */
9760Sstevel@tonic-gate mutex_enter(&cachefs_cachelock);
9770Sstevel@tonic-gate
9780Sstevel@tonic-gate /* mark the file system as not mounted */
9790Sstevel@tonic-gate mutex_enter(&fscp->fs_fslock);
9800Sstevel@tonic-gate fscp->fs_flags &= ~CFS_FS_MOUNTED;
9810Sstevel@tonic-gate fscp->fs_rootvp = NULL;
9820Sstevel@tonic-gate if (fscp->fs_kstat_id > 0)
9830Sstevel@tonic-gate cachefs_kstat_umount(fscp->fs_kstat_id);
9840Sstevel@tonic-gate fscp->fs_kstat_id = 0;
9850Sstevel@tonic-gate
9860Sstevel@tonic-gate /* drop the inum translation table */
9870Sstevel@tonic-gate if (fscp->fs_inum_size > 0) {
9880Sstevel@tonic-gate cachefs_kmem_free(fscp->fs_inum_trans,
9890Sstevel@tonic-gate fscp->fs_inum_size * sizeof (cachefs_inum_trans_t));
9900Sstevel@tonic-gate fscp->fs_inum_size = 0;
9910Sstevel@tonic-gate fscp->fs_inum_trans = NULL;
9920Sstevel@tonic-gate fscp->fs_flags &= ~CFS_FS_HASHPRINT;
9930Sstevel@tonic-gate }
9940Sstevel@tonic-gate mutex_exit(&fscp->fs_fslock);
9950Sstevel@tonic-gate
9960Sstevel@tonic-gate fscache_rele(fscp);
9970Sstevel@tonic-gate
9980Sstevel@tonic-gate /* get rid of any unused fscache objects */
9990Sstevel@tonic-gate mutex_enter(&cachep->c_fslistlock);
10000Sstevel@tonic-gate fscache_list_gc(cachep);
10010Sstevel@tonic-gate mutex_exit(&cachep->c_fslistlock);
10020Sstevel@tonic-gate
10030Sstevel@tonic-gate /* get the number of mounts on this cache */
10040Sstevel@tonic-gate mutex_enter(&cachep->c_fslistlock);
10050Sstevel@tonic-gate xx = fscache_list_mounted(cachep);
10060Sstevel@tonic-gate mutex_exit(&cachep->c_fslistlock);
10070Sstevel@tonic-gate
10080Sstevel@tonic-gate if (CACHEFS_LOG_LOGGING(cachep, CACHEFS_LOG_UMOUNT))
10090Sstevel@tonic-gate cachefs_log_umount(cachep, 0, vfsp);
10100Sstevel@tonic-gate
10110Sstevel@tonic-gate /* if no mounts left, deactivate the cache */
10120Sstevel@tonic-gate if (xx == 0)
10130Sstevel@tonic-gate cachefs_delete_cachep(cachep);
10140Sstevel@tonic-gate
10150Sstevel@tonic-gate mutex_exit(&cachefs_cachelock);
10160Sstevel@tonic-gate
10170Sstevel@tonic-gate out:
10180Sstevel@tonic-gate if (error) {
10190Sstevel@tonic-gate if (CACHEFS_LOG_LOGGING(cachep, CACHEFS_LOG_UMOUNT))
10200Sstevel@tonic-gate cachefs_log_umount(cachep, error, vfsp);
10210Sstevel@tonic-gate }
10220Sstevel@tonic-gate #ifdef CFSDEBUG
10230Sstevel@tonic-gate CFS_DEBUG(CFSDEBUG_VFSOP)
10240Sstevel@tonic-gate printf("cachefs_unmount: EXIT\n");
10250Sstevel@tonic-gate #endif
10260Sstevel@tonic-gate return (error);
10270Sstevel@tonic-gate }
10280Sstevel@tonic-gate
10290Sstevel@tonic-gate /*
10300Sstevel@tonic-gate * remove the cache from the list of caches
10310Sstevel@tonic-gate */
10320Sstevel@tonic-gate
10330Sstevel@tonic-gate static void
cachefs_delete_cachep(cachefscache_t * cachep)10340Sstevel@tonic-gate cachefs_delete_cachep(cachefscache_t *cachep)
10350Sstevel@tonic-gate {
10360Sstevel@tonic-gate struct cachefscache **cachepp;
10370Sstevel@tonic-gate int found = 0;
10380Sstevel@tonic-gate
10390Sstevel@tonic-gate ASSERT(MUTEX_HELD(&cachefs_cachelock));
10400Sstevel@tonic-gate
10410Sstevel@tonic-gate for (cachepp = &cachefs_cachelist;
10420Sstevel@tonic-gate *cachepp != NULL;
10430Sstevel@tonic-gate cachepp = &(*cachepp)->c_next) {
10440Sstevel@tonic-gate if (*cachepp == cachep) {
10450Sstevel@tonic-gate *cachepp = cachep->c_next;
10460Sstevel@tonic-gate found++;
10470Sstevel@tonic-gate break;
10480Sstevel@tonic-gate }
10490Sstevel@tonic-gate }
10500Sstevel@tonic-gate ASSERT(found);
10510Sstevel@tonic-gate
10520Sstevel@tonic-gate /* shut down the cache */
10530Sstevel@tonic-gate cachefs_cache_destroy(cachep);
10540Sstevel@tonic-gate }
10550Sstevel@tonic-gate
10560Sstevel@tonic-gate static int
cachefs_root(vfs_t * vfsp,vnode_t ** vpp)10570Sstevel@tonic-gate cachefs_root(vfs_t *vfsp, vnode_t **vpp)
10580Sstevel@tonic-gate {
10590Sstevel@tonic-gate /*LINTED alignment okay*/
10600Sstevel@tonic-gate struct fscache *fscp = (struct fscache *)vfsp->vfs_data;
10610Sstevel@tonic-gate
10620Sstevel@tonic-gate ASSERT(fscp != NULL);
10630Sstevel@tonic-gate ASSERT(fscp->fs_rootvp != NULL);
10640Sstevel@tonic-gate
10650Sstevel@tonic-gate if (getzoneid() != GLOBAL_ZONEID)
10660Sstevel@tonic-gate return (EPERM);
10670Sstevel@tonic-gate *vpp = fscp->fs_rootvp;
10680Sstevel@tonic-gate VN_HOLD(*vpp);
10690Sstevel@tonic-gate return (0);
10700Sstevel@tonic-gate }
10710Sstevel@tonic-gate
10720Sstevel@tonic-gate /*
10730Sstevel@tonic-gate * Get file system statistics.
10740Sstevel@tonic-gate */
10750Sstevel@tonic-gate static int
cachefs_statvfs(register vfs_t * vfsp,struct statvfs64 * sbp)10760Sstevel@tonic-gate cachefs_statvfs(register vfs_t *vfsp, struct statvfs64 *sbp)
10770Sstevel@tonic-gate {
10780Sstevel@tonic-gate struct fscache *fscp = VFS_TO_FSCACHE(vfsp);
10790Sstevel@tonic-gate struct cache_label *lp = &fscp->fs_cache->c_label;
10800Sstevel@tonic-gate struct cache_usage *up = &fscp->fs_cache->c_usage;
10810Sstevel@tonic-gate int error;
10820Sstevel@tonic-gate
10830Sstevel@tonic-gate if (getzoneid() != GLOBAL_ZONEID)
10840Sstevel@tonic-gate return (EPERM);
10850Sstevel@tonic-gate error = cachefs_cd_access(fscp, 0, 0);
10860Sstevel@tonic-gate if (error)
10870Sstevel@tonic-gate return (error);
10880Sstevel@tonic-gate
10890Sstevel@tonic-gate if (fscp->fs_cdconnected == CFS_CD_CONNECTED) {
10900Sstevel@tonic-gate /*
10910Sstevel@tonic-gate * When connected return backfs stats
10920Sstevel@tonic-gate */
10930Sstevel@tonic-gate error = VFS_STATVFS(fscp->fs_backvfsp, sbp);
10940Sstevel@tonic-gate } else {
10950Sstevel@tonic-gate /*
10960Sstevel@tonic-gate * Otherwise, just return the frontfs stats
10970Sstevel@tonic-gate */
10980Sstevel@tonic-gate ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
10990Sstevel@tonic-gate error = VFS_STATVFS(fscp->fs_fscdirvp->v_vfsp, sbp);
11000Sstevel@tonic-gate if (!error) {
11010Sstevel@tonic-gate dev32_t d32;
11020Sstevel@tonic-gate
11030Sstevel@tonic-gate sbp->f_frsize = MAXBSIZE;
11040Sstevel@tonic-gate sbp->f_blocks = lp->cl_maxblks;
11050Sstevel@tonic-gate sbp->f_bfree = sbp->f_bavail =
11060Sstevel@tonic-gate lp->cl_maxblks - up->cu_blksused;
11070Sstevel@tonic-gate sbp->f_files = lp->cl_maxinodes;
11080Sstevel@tonic-gate sbp->f_ffree = sbp->f_favail =
11090Sstevel@tonic-gate lp->cl_maxinodes - up->cu_filesused;
11100Sstevel@tonic-gate (void) cmpldev(&d32, vfsp->vfs_dev);
11110Sstevel@tonic-gate sbp->f_fsid = d32;
11120Sstevel@tonic-gate }
11130Sstevel@tonic-gate }
11140Sstevel@tonic-gate cachefs_cd_release(fscp);
11150Sstevel@tonic-gate if (error)
11160Sstevel@tonic-gate return (error);
11170Sstevel@tonic-gate
11180Sstevel@tonic-gate /*
11190Sstevel@tonic-gate * Make sure fstype is CFS.
11200Sstevel@tonic-gate */
11210Sstevel@tonic-gate (void) strcpy(sbp->f_basetype, vfssw[vfsp->vfs_fstype].vsw_name);
11220Sstevel@tonic-gate bzero(sbp->f_fstr, sizeof (sbp->f_fstr));
11230Sstevel@tonic-gate
11240Sstevel@tonic-gate return (0);
11250Sstevel@tonic-gate }
11260Sstevel@tonic-gate
11270Sstevel@tonic-gate /*
11280Sstevel@tonic-gate * queue a request to sync the given fscache
11290Sstevel@tonic-gate */
11300Sstevel@tonic-gate static void
queue_sync(struct cachefscache * cachep,cred_t * cr)11310Sstevel@tonic-gate queue_sync(struct cachefscache *cachep, cred_t *cr)
11320Sstevel@tonic-gate {
11330Sstevel@tonic-gate struct cachefs_req *rp;
11340Sstevel@tonic-gate
11350Sstevel@tonic-gate rp = kmem_cache_alloc(cachefs_req_cache, KM_SLEEP);
11360Sstevel@tonic-gate rp->cfs_cmd = CFS_CACHE_SYNC;
11370Sstevel@tonic-gate rp->cfs_cr = cr;
11380Sstevel@tonic-gate rp->cfs_req_u.cu_fs_sync.cf_cachep = cachep;
11390Sstevel@tonic-gate crhold(rp->cfs_cr);
11400Sstevel@tonic-gate cachefs_addqueue(rp, &cachep->c_workq);
11410Sstevel@tonic-gate }
11420Sstevel@tonic-gate
11430Sstevel@tonic-gate /*ARGSUSED*/
11440Sstevel@tonic-gate static int
cachefs_sync(vfs_t * vfsp,short flag,cred_t * cr)11450Sstevel@tonic-gate cachefs_sync(vfs_t *vfsp, short flag, cred_t *cr)
11460Sstevel@tonic-gate {
11470Sstevel@tonic-gate struct fscache *fscp;
11480Sstevel@tonic-gate struct cachefscache *cachep;
11490Sstevel@tonic-gate
11500Sstevel@tonic-gate if (getzoneid() != GLOBAL_ZONEID)
11510Sstevel@tonic-gate return (EPERM);
11520Sstevel@tonic-gate if (!(flag & SYNC_ATTR)) {
11530Sstevel@tonic-gate /*
11540Sstevel@tonic-gate * queue an async request to do the sync.
11550Sstevel@tonic-gate * We always sync an entire cache (as opposed to an
11560Sstevel@tonic-gate * individual fscache) so that we have an opportunity
11570Sstevel@tonic-gate * to set the clean flag.
11580Sstevel@tonic-gate */
11590Sstevel@tonic-gate if (vfsp) {
11600Sstevel@tonic-gate /*LINTED alignment okay*/
11610Sstevel@tonic-gate fscp = (struct fscache *)vfsp->vfs_data;
11620Sstevel@tonic-gate queue_sync(fscp->fs_cache, cr);
11630Sstevel@tonic-gate } else {
11640Sstevel@tonic-gate mutex_enter(&cachefs_cachelock);
11650Sstevel@tonic-gate for (cachep = cachefs_cachelist; cachep != NULL;
11660Sstevel@tonic-gate cachep = cachep->c_next) {
11670Sstevel@tonic-gate queue_sync(cachep, cr);
11680Sstevel@tonic-gate }
11690Sstevel@tonic-gate mutex_exit(&cachefs_cachelock);
11700Sstevel@tonic-gate }
11710Sstevel@tonic-gate }
11720Sstevel@tonic-gate return (0);
11730Sstevel@tonic-gate }
11740Sstevel@tonic-gate
11750Sstevel@tonic-gate static int
cachefs_remount(struct vfs * vfsp,struct mounta * uap)11760Sstevel@tonic-gate cachefs_remount(struct vfs *vfsp, struct mounta *uap)
11770Sstevel@tonic-gate {
11780Sstevel@tonic-gate fscache_t *fscp = VFS_TO_FSCACHE(vfsp);
11790Sstevel@tonic-gate cachefscache_t *cachep = fscp->fs_cache;
11800Sstevel@tonic-gate int error = 0;
11810Sstevel@tonic-gate STRUCT_DECL(cachefs_mountargs, map);
11820Sstevel@tonic-gate struct cachefsoptions *cfs_options;
11830Sstevel@tonic-gate char *backfs, *cacheid, *cachedir;
11840Sstevel@tonic-gate struct vnode *cachedirvp = NULL;
11850Sstevel@tonic-gate ino64_t fsid;
11860Sstevel@tonic-gate vnode_t *backrootvp = NULL;
11870Sstevel@tonic-gate struct vnode *tmpdirvp = NULL;
11880Sstevel@tonic-gate
11890Sstevel@tonic-gate STRUCT_INIT(map, get_udatamodel());
11900Sstevel@tonic-gate error = copyin(uap->dataptr, STRUCT_BUF(map),
11910Sstevel@tonic-gate SIZEOF_STRUCT(cachefs_mountargs, DATAMODEL_NATIVE));
11920Sstevel@tonic-gate if (error)
11930Sstevel@tonic-gate goto out;
11940Sstevel@tonic-gate
11950Sstevel@tonic-gate /*
11960Sstevel@tonic-gate * get cache directory vp
11970Sstevel@tonic-gate */
11980Sstevel@tonic-gate cachedir = (char *)STRUCT_FGETP(map, cfs_cachedir);
11990Sstevel@tonic-gate error = lookupname(cachedir, UIO_USERSPACE, FOLLOW,
12000Sstevel@tonic-gate NULLVPP, &cachedirvp);
12010Sstevel@tonic-gate if (error)
12020Sstevel@tonic-gate goto out;
12030Sstevel@tonic-gate if (cachedirvp->v_type != VDIR) {
12040Sstevel@tonic-gate error = EINVAL;
12050Sstevel@tonic-gate goto out;
12060Sstevel@tonic-gate }
12070Sstevel@tonic-gate
12080Sstevel@tonic-gate error = 0;
12090Sstevel@tonic-gate if (cachedirvp) {
12100Sstevel@tonic-gate error = VOP_LOOKUP(cachedirvp, CACHEFS_DLOG_FILE,
1211*5331Samw &tmpdirvp, NULL, 0, NULL, kcred, NULL, NULL, NULL);
12120Sstevel@tonic-gate }
12130Sstevel@tonic-gate cfs_options = (struct cachefsoptions *)STRUCT_FADDR(map, cfs_options);
12140Sstevel@tonic-gate cacheid = (char *)STRUCT_FGETP(map, cfs_cacheid);
12150Sstevel@tonic-gate /* XXX not quite right */
12160Sstevel@tonic-gate #if 0
12170Sstevel@tonic-gate /*
12180Sstevel@tonic-gate * If a log file exists and the cache is being mounted without
12190Sstevel@tonic-gate * the snr (aka disconnectable) option, return an error.
12200Sstevel@tonic-gate */
12210Sstevel@tonic-gate if ((error == 0) &&
12220Sstevel@tonic-gate !(cfs_options->opt_flags & CFS_DISCONNECTABLE)) {
12230Sstevel@tonic-gate cmn_err(CE_WARN,
12240Sstevel@tonic-gate "cachefs_mount: log exists and disconnectable"
12250Sstevel@tonic-gate "option not specified\n");
12260Sstevel@tonic-gate error = EINVAL;
12270Sstevel@tonic-gate goto out;
12280Sstevel@tonic-gate }
12290Sstevel@tonic-gate #endif
12300Sstevel@tonic-gate error = 0;
12310Sstevel@tonic-gate
12320Sstevel@tonic-gate /*
12330Sstevel@tonic-gate * If the user is using NFSv4 and there are other options
12340Sstevel@tonic-gate * specified, make sure we ignore the other options.
12350Sstevel@tonic-gate */
12360Sstevel@tonic-gate if (CFS_ISFS_BACKFS_NFSV4(fscp)) {
12370Sstevel@tonic-gate cfs_options->opt_flags = CFS_BACKFS_NFSV4;
12380Sstevel@tonic-gate }
12390Sstevel@tonic-gate
12400Sstevel@tonic-gate /* XXX need mount options "nocache" and "nofill" */
12410Sstevel@tonic-gate
12420Sstevel@tonic-gate /* if nocache is being turned off */
12430Sstevel@tonic-gate if (cachep->c_flags & CACHE_NOCACHE) {
12440Sstevel@tonic-gate error = cachefs_cache_activate_ro(cachep, cachedirvp);
12450Sstevel@tonic-gate if (error)
12460Sstevel@tonic-gate goto out;
12470Sstevel@tonic-gate cachefs_cache_activate_rw(cachep);
12480Sstevel@tonic-gate
12490Sstevel@tonic-gate /* get the fsid for the fscache */
12500Sstevel@tonic-gate error = fscache_name_to_fsid(cachep, cacheid, &fsid);
12510Sstevel@tonic-gate if (error)
12520Sstevel@tonic-gate fsid = 0;
12530Sstevel@tonic-gate
12540Sstevel@tonic-gate /* activate the fscache */
12550Sstevel@tonic-gate mutex_enter(&cachep->c_fslistlock);
12560Sstevel@tonic-gate error = fscache_enable(fscp, fsid, cacheid,
12570Sstevel@tonic-gate cfs_options, fscp->fs_info.fi_root);
12580Sstevel@tonic-gate mutex_exit(&cachep->c_fslistlock);
12590Sstevel@tonic-gate if (error) {
12600Sstevel@tonic-gate cmn_err(CE_WARN, "cachefs: cannot remount %s\n",
12610Sstevel@tonic-gate cacheid);
12620Sstevel@tonic-gate goto out;
12630Sstevel@tonic-gate }
12640Sstevel@tonic-gate
12650Sstevel@tonic-gate /* enable the cache */
12660Sstevel@tonic-gate cachefs_enable_caching(fscp);
12670Sstevel@tonic-gate fscache_activate_rw(fscp);
12680Sstevel@tonic-gate }
12690Sstevel@tonic-gate
12700Sstevel@tonic-gate /* else if nofill is being turn off */
12710Sstevel@tonic-gate else if (cachep->c_flags & CACHE_NOFILL) {
12720Sstevel@tonic-gate ASSERT(cachep->c_flags & CACHE_NOFILL);
12730Sstevel@tonic-gate cachefs_cache_activate_rw(cachep);
12740Sstevel@tonic-gate
12750Sstevel@tonic-gate /* enable the cache */
12760Sstevel@tonic-gate cachefs_enable_caching(fscp);
12770Sstevel@tonic-gate fscache_activate_rw(fscp);
12780Sstevel@tonic-gate }
12790Sstevel@tonic-gate
12800Sstevel@tonic-gate fscache_acset(fscp, STRUCT_FGET(map, cfs_acregmin),
12810Sstevel@tonic-gate STRUCT_FGET(map, cfs_acregmax),
12820Sstevel@tonic-gate STRUCT_FGET(map, cfs_acdirmin), STRUCT_FGET(map, cfs_acdirmax));
12830Sstevel@tonic-gate
12840Sstevel@tonic-gate /* if the backfs is mounted now or we have a new backfs */
12850Sstevel@tonic-gate backfs = (char *)STRUCT_FGETP(map, cfs_backfs);
12860Sstevel@tonic-gate if (backfs && (cfs_options->opt_flags & CFS_SLIDE)) {
12870Sstevel@tonic-gate /* get the back file system root vp */
12880Sstevel@tonic-gate error = lookupname(backfs, UIO_USERSPACE, FOLLOW,
12890Sstevel@tonic-gate NULLVPP, &backrootvp);
12900Sstevel@tonic-gate if (error)
12910Sstevel@tonic-gate goto out;
12920Sstevel@tonic-gate
12930Sstevel@tonic-gate /*
12940Sstevel@tonic-gate * Make sure the thing we just looked up is a directory
12950Sstevel@tonic-gate * and a root of a file system
12960Sstevel@tonic-gate */
12970Sstevel@tonic-gate if (backrootvp->v_type != VDIR ||
12980Sstevel@tonic-gate !(backrootvp->v_flag & VROOT)) {
12990Sstevel@tonic-gate cmn_err(CE_WARN,
13000Sstevel@tonic-gate "cachefs_mount: backpath not a directory\n");
13010Sstevel@tonic-gate error = EINVAL;
13020Sstevel@tonic-gate goto out;
13030Sstevel@tonic-gate }
13040Sstevel@tonic-gate
13050Sstevel@tonic-gate /*
13060Sstevel@tonic-gate * XXX
13070Sstevel@tonic-gate * Kind of dangerous to just set this but we do
13080Sstevel@tonic-gate * not have locks around usage of fs_backvfsp.
13090Sstevel@tonic-gate * Hope for the best for now.
13100Sstevel@tonic-gate * Probably should also spin through vnodes and fix them up.
13110Sstevel@tonic-gate * Krishna - fixed c_backvp to reflect the change.
13120Sstevel@tonic-gate */
13130Sstevel@tonic-gate fscp->fs_backvfsp = backrootvp->v_vfsp;
13140Sstevel@tonic-gate ((cnode_t *)(fscp->fs_rootvp->v_data))->c_backvp = backrootvp;
13150Sstevel@tonic-gate
13160Sstevel@tonic-gate /*
13170Sstevel@tonic-gate * Now the root cnode structure is an owner of
13180Sstevel@tonic-gate * the opened back root vnode structure; we must
13190Sstevel@tonic-gate * clear the pointer to back root vnode here as
13200Sstevel@tonic-gate * we don't need it since now, and the root cnode
13210Sstevel@tonic-gate * structure will control the vnode
13220Sstevel@tonic-gate */
13230Sstevel@tonic-gate backrootvp = (vnode_t *)NULL;
13240Sstevel@tonic-gate }
13250Sstevel@tonic-gate
13260Sstevel@tonic-gate if (fscp->fs_kstat_id > 0)
13270Sstevel@tonic-gate cachefs_kstat_umount(fscp->fs_kstat_id);
13280Sstevel@tonic-gate fscp->fs_kstat_id = 0;
13290Sstevel@tonic-gate cachefs_kstat_mount(fscp, uap->dir, backfs, cachedir, cacheid);
13300Sstevel@tonic-gate
13310Sstevel@tonic-gate if (CACHEFS_LOG_LOGGING(cachep, CACHEFS_LOG_MOUNT))
13320Sstevel@tonic-gate cachefs_log_mount(cachep, error, vfsp, fscp,
13330Sstevel@tonic-gate uap->dir, UIO_USERSPACE,
13340Sstevel@tonic-gate (STRUCT_BUF(map) != NULL) ? cacheid : NULL);
13350Sstevel@tonic-gate
13360Sstevel@tonic-gate out:
13370Sstevel@tonic-gate if (cachedirvp)
13380Sstevel@tonic-gate VN_RELE(cachedirvp);
13390Sstevel@tonic-gate if (backrootvp)
13400Sstevel@tonic-gate VN_RELE(backrootvp);
13410Sstevel@tonic-gate return (error);
13420Sstevel@tonic-gate }
1343