xref: /illumos-gate/usr/src/uts/common/fs/ctfs/ctfs_root.c (revision d0b12b66)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5aa59c4cbSrsb  * Common Development and Distribution License (the "License").
6aa59c4cbSrsb  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
220fbb751dSJohn Levon  * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
237c478bd9Sstevel@tonic-gate  */
247c478bd9Sstevel@tonic-gate 
257c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
267c478bd9Sstevel@tonic-gate #include <sys/types.h>
277c478bd9Sstevel@tonic-gate #include <sys/param.h>
287c478bd9Sstevel@tonic-gate #include <sys/time.h>
297c478bd9Sstevel@tonic-gate #include <sys/cred.h>
307c478bd9Sstevel@tonic-gate #include <sys/vfs.h>
31aa59c4cbSrsb #include <sys/vfs_opreg.h>
327c478bd9Sstevel@tonic-gate #include <sys/gfs.h>
337c478bd9Sstevel@tonic-gate #include <sys/vnode.h>
347c478bd9Sstevel@tonic-gate #include <sys/systm.h>
357c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
367c478bd9Sstevel@tonic-gate #include <sys/errno.h>
377c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
387c478bd9Sstevel@tonic-gate #include <sys/policy.h>
397c478bd9Sstevel@tonic-gate #include <sys/mount.h>
407c478bd9Sstevel@tonic-gate #include <sys/pathname.h>
417c478bd9Sstevel@tonic-gate #include <sys/dirent.h>
427c478bd9Sstevel@tonic-gate #include <fs/fs_subr.h>
437c478bd9Sstevel@tonic-gate #include <sys/contract.h>
447c478bd9Sstevel@tonic-gate #include <sys/contract_impl.h>
457c478bd9Sstevel@tonic-gate #include <sys/ctfs.h>
467c478bd9Sstevel@tonic-gate #include <sys/ctfs_impl.h>
477c478bd9Sstevel@tonic-gate #include <sys/uio.h>
487c478bd9Sstevel@tonic-gate #include <sys/file.h>
497c478bd9Sstevel@tonic-gate #include <sys/atomic.h>
507c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate /*
537c478bd9Sstevel@tonic-gate  * ctfs, the contract filesystem.
547c478bd9Sstevel@tonic-gate  *
55da6c28aaSamw  * Exposes the construct subsystem to userland.  The structure of the
56*d0b12b66SToomas Soome  * filesystem is a public interface, but the behavior of the files is
577c478bd9Sstevel@tonic-gate  * private and unstable.  Contract consumers are expected to use
587c478bd9Sstevel@tonic-gate  * libcontract(3lib) to operate on ctfs file descriptors.
597c478bd9Sstevel@tonic-gate  *
607c478bd9Sstevel@tonic-gate  * We're trying something a little different here.  Rather than make
617c478bd9Sstevel@tonic-gate  * each vnode op itself call into a vector of file type operations, we
627c478bd9Sstevel@tonic-gate  * actually use different vnode types (gasp!), the implementations of
637c478bd9Sstevel@tonic-gate  * which may call into routines providing common functionality.  This
647c478bd9Sstevel@tonic-gate  * design should hopefully make it easier to factor and maintain the
657c478bd9Sstevel@tonic-gate  * code.  For the most part, there is a separate file for each vnode
667c478bd9Sstevel@tonic-gate  * type's implementation.  The exceptions to this are the ctl/stat
677c478bd9Sstevel@tonic-gate  * nodes, which are very similar, and the three event endpoint types.
687c478bd9Sstevel@tonic-gate  *
697c478bd9Sstevel@tonic-gate  * This file contains common routines used by some or all of the vnode
707c478bd9Sstevel@tonic-gate  * types, the filesystem's module linkage and VFS operations, and the
717c478bd9Sstevel@tonic-gate  * implementation of the root vnode.
727c478bd9Sstevel@tonic-gate  */
737c478bd9Sstevel@tonic-gate 
747c478bd9Sstevel@tonic-gate /*
757c478bd9Sstevel@tonic-gate  * Ops vectors for all the vnode types; they have to be defined
767c478bd9Sstevel@tonic-gate  * somewhere.  See gfs_make_opsvec for thoughts on how this could be
777c478bd9Sstevel@tonic-gate  * done differently.
787c478bd9Sstevel@tonic-gate  */
797c478bd9Sstevel@tonic-gate vnodeops_t *ctfs_ops_root;
807c478bd9Sstevel@tonic-gate vnodeops_t *ctfs_ops_adir;
817c478bd9Sstevel@tonic-gate vnodeops_t *ctfs_ops_sym;
827c478bd9Sstevel@tonic-gate vnodeops_t *ctfs_ops_tdir;
837c478bd9Sstevel@tonic-gate vnodeops_t *ctfs_ops_tmpl;
847c478bd9Sstevel@tonic-gate vnodeops_t *ctfs_ops_cdir;
857c478bd9Sstevel@tonic-gate vnodeops_t *ctfs_ops_ctl;
867c478bd9Sstevel@tonic-gate vnodeops_t *ctfs_ops_stat;
877c478bd9Sstevel@tonic-gate vnodeops_t *ctfs_ops_event;
887c478bd9Sstevel@tonic-gate vnodeops_t *ctfs_ops_bundle;
897c478bd9Sstevel@tonic-gate vnodeops_t *ctfs_ops_latest;
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate static const fs_operation_def_t ctfs_vfstops[];
927c478bd9Sstevel@tonic-gate static gfs_opsvec_t ctfs_opsvec[];
937c478bd9Sstevel@tonic-gate 
947c478bd9Sstevel@tonic-gate static int ctfs_init(int, char *);
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate static ino64_t ctfs_root_do_inode(vnode_t *, int);
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate 
997c478bd9Sstevel@tonic-gate /*
1007c478bd9Sstevel@tonic-gate  * File system module linkage
1017c478bd9Sstevel@tonic-gate  */
1027c478bd9Sstevel@tonic-gate static mntopts_t ctfs_mntopts = {
1037c478bd9Sstevel@tonic-gate 	0,
1047c478bd9Sstevel@tonic-gate 	NULL
1057c478bd9Sstevel@tonic-gate };
1067c478bd9Sstevel@tonic-gate 
1077c478bd9Sstevel@tonic-gate static vfsdef_t vfw = {
1087c478bd9Sstevel@tonic-gate 	VFSDEF_VERSION,
1097c478bd9Sstevel@tonic-gate 	"ctfs",
1107c478bd9Sstevel@tonic-gate 	ctfs_init,
1110fbb751dSJohn Levon 	VSW_HASPROTO|VSW_ZMOUNT,
1127c478bd9Sstevel@tonic-gate 	&ctfs_mntopts,
1137c478bd9Sstevel@tonic-gate };
1147c478bd9Sstevel@tonic-gate 
1157c478bd9Sstevel@tonic-gate extern struct mod_ops mod_fsops;
1167c478bd9Sstevel@tonic-gate 
1177c478bd9Sstevel@tonic-gate static struct modlfs modlfs = {
1187c478bd9Sstevel@tonic-gate 	&mod_fsops, "contract filesystem", &vfw
1197c478bd9Sstevel@tonic-gate };
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
1227c478bd9Sstevel@tonic-gate 	MODREV_1, (void *)&modlfs, NULL
1237c478bd9Sstevel@tonic-gate };
1247c478bd9Sstevel@tonic-gate 
1257c478bd9Sstevel@tonic-gate int
_init(void)1267c478bd9Sstevel@tonic-gate _init(void)
1277c478bd9Sstevel@tonic-gate {
1287c478bd9Sstevel@tonic-gate 	return (mod_install(&modlinkage));
1297c478bd9Sstevel@tonic-gate }
1307c478bd9Sstevel@tonic-gate 
1317c478bd9Sstevel@tonic-gate int
_info(struct modinfo * modinfop)1327c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
1337c478bd9Sstevel@tonic-gate {
1347c478bd9Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
1357c478bd9Sstevel@tonic-gate }
1367c478bd9Sstevel@tonic-gate 
1377c478bd9Sstevel@tonic-gate int
_fini(void)1387c478bd9Sstevel@tonic-gate _fini(void)
1397c478bd9Sstevel@tonic-gate {
1407c478bd9Sstevel@tonic-gate 	/*
1417c478bd9Sstevel@tonic-gate 	 * As unloading filesystem modules isn't completely safe, we
1427c478bd9Sstevel@tonic-gate 	 * don't allow it.
1437c478bd9Sstevel@tonic-gate 	 */
1447c478bd9Sstevel@tonic-gate 	return (EBUSY);
1457c478bd9Sstevel@tonic-gate }
1467c478bd9Sstevel@tonic-gate 
1477c478bd9Sstevel@tonic-gate static int ctfs_fstype;
1487c478bd9Sstevel@tonic-gate static major_t ctfs_major;
1497c478bd9Sstevel@tonic-gate static minor_t ctfs_minor = 0;
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate /*
1527c478bd9Sstevel@tonic-gate  * The ops vector vector.
1537c478bd9Sstevel@tonic-gate  */
1547c478bd9Sstevel@tonic-gate static const fs_operation_def_t ctfs_tops_root[];
1557c478bd9Sstevel@tonic-gate extern const fs_operation_def_t ctfs_tops_tmpl[];
1567c478bd9Sstevel@tonic-gate extern const fs_operation_def_t ctfs_tops_ctl[];
1577c478bd9Sstevel@tonic-gate extern const fs_operation_def_t ctfs_tops_adir[];
1587c478bd9Sstevel@tonic-gate extern const fs_operation_def_t ctfs_tops_cdir[];
1597c478bd9Sstevel@tonic-gate extern const fs_operation_def_t ctfs_tops_tdir[];
1607c478bd9Sstevel@tonic-gate extern const fs_operation_def_t ctfs_tops_latest[];
1617c478bd9Sstevel@tonic-gate extern const fs_operation_def_t ctfs_tops_stat[];
1627c478bd9Sstevel@tonic-gate extern const fs_operation_def_t ctfs_tops_sym[];
1637c478bd9Sstevel@tonic-gate extern const fs_operation_def_t ctfs_tops_event[];
1647c478bd9Sstevel@tonic-gate extern const fs_operation_def_t ctfs_tops_bundle[];
1657c478bd9Sstevel@tonic-gate static gfs_opsvec_t ctfs_opsvec[] = {
1667c478bd9Sstevel@tonic-gate 	{ "ctfs root directory", ctfs_tops_root, &ctfs_ops_root },
1677c478bd9Sstevel@tonic-gate 	{ "ctfs all directory", ctfs_tops_adir, &ctfs_ops_adir },
1687c478bd9Sstevel@tonic-gate 	{ "ctfs all symlink", ctfs_tops_sym, &ctfs_ops_sym },
1697c478bd9Sstevel@tonic-gate 	{ "ctfs template directory", ctfs_tops_tdir, &ctfs_ops_tdir },
1707c478bd9Sstevel@tonic-gate 	{ "ctfs template file", ctfs_tops_tmpl, &ctfs_ops_tmpl },
1717c478bd9Sstevel@tonic-gate 	{ "ctfs contract directory", ctfs_tops_cdir, &ctfs_ops_cdir },
1727c478bd9Sstevel@tonic-gate 	{ "ctfs ctl file", ctfs_tops_ctl, &ctfs_ops_ctl },
1737c478bd9Sstevel@tonic-gate 	{ "ctfs status file", ctfs_tops_stat, &ctfs_ops_stat },
1747c478bd9Sstevel@tonic-gate 	{ "ctfs events file", ctfs_tops_event, &ctfs_ops_event },
1757c478bd9Sstevel@tonic-gate 	{ "ctfs bundle file", ctfs_tops_bundle, &ctfs_ops_bundle },
1767c478bd9Sstevel@tonic-gate 	{ "ctfs latest file", ctfs_tops_latest, &ctfs_ops_latest },
1777c478bd9Sstevel@tonic-gate 	{ NULL }
1787c478bd9Sstevel@tonic-gate };
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate /*
1827c478bd9Sstevel@tonic-gate  * ctfs_init - the vfsdef_t init entry point
1837c478bd9Sstevel@tonic-gate  *
1847c478bd9Sstevel@tonic-gate  * Sets the VFS ops, builds all the vnode ops, and allocates a device
1857c478bd9Sstevel@tonic-gate  * number.
1867c478bd9Sstevel@tonic-gate  */
1877c478bd9Sstevel@tonic-gate /* ARGSUSED */
1887c478bd9Sstevel@tonic-gate static int
ctfs_init(int fstype,char * name)1897c478bd9Sstevel@tonic-gate ctfs_init(int fstype, char *name)
1907c478bd9Sstevel@tonic-gate {
1917c478bd9Sstevel@tonic-gate 	vfsops_t *vfsops;
1927c478bd9Sstevel@tonic-gate 	int error;
1937c478bd9Sstevel@tonic-gate 
1947c478bd9Sstevel@tonic-gate 	ctfs_fstype = fstype;
1957c478bd9Sstevel@tonic-gate 	if (error = vfs_setfsops(fstype, ctfs_vfstops, &vfsops)) {
1967c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "ctfs_init: bad vfs ops template");
1977c478bd9Sstevel@tonic-gate 		return (error);
1987c478bd9Sstevel@tonic-gate 	}
1997c478bd9Sstevel@tonic-gate 
2007c478bd9Sstevel@tonic-gate 	if (error = gfs_make_opsvec(ctfs_opsvec)) {
2017c478bd9Sstevel@tonic-gate 		(void) vfs_freevfsops(vfsops);
2027c478bd9Sstevel@tonic-gate 		return (error);
2037c478bd9Sstevel@tonic-gate 	}
2047c478bd9Sstevel@tonic-gate 
2057c478bd9Sstevel@tonic-gate 	if ((ctfs_major = getudev()) == (major_t)-1) {
2067c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "ctfs_init: can't get unique device number");
2077c478bd9Sstevel@tonic-gate 		ctfs_major = 0;
2087c478bd9Sstevel@tonic-gate 	}
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate 	return (0);
2117c478bd9Sstevel@tonic-gate }
2127c478bd9Sstevel@tonic-gate 
2137c478bd9Sstevel@tonic-gate /*
2147c478bd9Sstevel@tonic-gate  * ctfs_mount - the VFS_MOUNT entry point
2157c478bd9Sstevel@tonic-gate  */
2167c478bd9Sstevel@tonic-gate static int
ctfs_mount(vfs_t * vfsp,vnode_t * mvp,struct mounta * uap,cred_t * cr)2177c478bd9Sstevel@tonic-gate ctfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
2187c478bd9Sstevel@tonic-gate {
2197c478bd9Sstevel@tonic-gate 	ctfs_vfs_t *data;
2207c478bd9Sstevel@tonic-gate 	dev_t dev;
2217c478bd9Sstevel@tonic-gate 	gfs_dirent_t *dirent;
2227c478bd9Sstevel@tonic-gate 	int i;
2237c478bd9Sstevel@tonic-gate 
2247c478bd9Sstevel@tonic-gate 	if (secpolicy_fs_mount(cr, mvp, vfsp) != 0)
2257c478bd9Sstevel@tonic-gate 		return (EPERM);
2267c478bd9Sstevel@tonic-gate 
2277c478bd9Sstevel@tonic-gate 	if (mvp->v_type != VDIR)
2287c478bd9Sstevel@tonic-gate 		return (ENOTDIR);
2297c478bd9Sstevel@tonic-gate 
2307c478bd9Sstevel@tonic-gate 	if ((uap->flags & MS_OVERLAY) == 0 &&
2317c478bd9Sstevel@tonic-gate 	    (mvp->v_count > 1 || (mvp->v_flag & VROOT)))
2327c478bd9Sstevel@tonic-gate 		return (EBUSY);
2337c478bd9Sstevel@tonic-gate 
2347c478bd9Sstevel@tonic-gate 	data = kmem_alloc(sizeof (ctfs_vfs_t), KM_SLEEP);
2357c478bd9Sstevel@tonic-gate 
2367c478bd9Sstevel@tonic-gate 	/*
2377c478bd9Sstevel@tonic-gate 	 * Initialize vfs fields not initialized by VFS_INIT/domount
2387c478bd9Sstevel@tonic-gate 	 */
2397c478bd9Sstevel@tonic-gate 	vfsp->vfs_bsize = DEV_BSIZE;
2407c478bd9Sstevel@tonic-gate 	vfsp->vfs_fstype = ctfs_fstype;
2410fbb751dSJohn Levon 	do {
2427c478bd9Sstevel@tonic-gate 		dev = makedevice(ctfs_major,
2431a5e258fSJosef 'Jeff' Sipek 		    atomic_inc_32_nv(&ctfs_minor) & L_MAXMIN32);
2440fbb751dSJohn Levon 	} while (vfs_devismounted(dev));
2457c478bd9Sstevel@tonic-gate 	vfs_make_fsid(&vfsp->vfs_fsid, dev, ctfs_fstype);
2467c478bd9Sstevel@tonic-gate 	vfsp->vfs_data = data;
2477c478bd9Sstevel@tonic-gate 	vfsp->vfs_dev = dev;
2487c478bd9Sstevel@tonic-gate 
2497c478bd9Sstevel@tonic-gate 	/*
2507c478bd9Sstevel@tonic-gate 	 * Dynamically create gfs_dirent_t array for the root directory.
2517c478bd9Sstevel@tonic-gate 	 */
2527c478bd9Sstevel@tonic-gate 	dirent = kmem_zalloc((ct_ntypes + 2) * sizeof (gfs_dirent_t), KM_SLEEP);
2537c478bd9Sstevel@tonic-gate 	for (i = 0; i < ct_ntypes; i++) {
2547c478bd9Sstevel@tonic-gate 		dirent[i].gfse_name = (char *)ct_types[i]->ct_type_name;
2557c478bd9Sstevel@tonic-gate 		dirent[i].gfse_ctor = ctfs_create_tdirnode;
2567c478bd9Sstevel@tonic-gate 		dirent[i].gfse_flags = GFS_CACHE_VNODE;
2577c478bd9Sstevel@tonic-gate 	}
2587c478bd9Sstevel@tonic-gate 	dirent[i].gfse_name = "all";
2597c478bd9Sstevel@tonic-gate 	dirent[i].gfse_ctor = ctfs_create_adirnode;
2607c478bd9Sstevel@tonic-gate 	dirent[i].gfse_flags = GFS_CACHE_VNODE;
2617c478bd9Sstevel@tonic-gate 	dirent[i+1].gfse_name = NULL;
2627c478bd9Sstevel@tonic-gate 
2637c478bd9Sstevel@tonic-gate 	/*
2647c478bd9Sstevel@tonic-gate 	 * Create root vnode
2657c478bd9Sstevel@tonic-gate 	 */
2667c478bd9Sstevel@tonic-gate 	data->ctvfs_root = gfs_root_create(sizeof (ctfs_rootnode_t),
2677c478bd9Sstevel@tonic-gate 	    vfsp, ctfs_ops_root, CTFS_INO_ROOT, dirent, ctfs_root_do_inode,
2687c478bd9Sstevel@tonic-gate 	    CTFS_NAME_MAX, NULL, NULL);
2697c478bd9Sstevel@tonic-gate 
2707c478bd9Sstevel@tonic-gate 	kmem_free(dirent, (ct_ntypes + 2) * sizeof (gfs_dirent_t));
2717c478bd9Sstevel@tonic-gate 
2727c478bd9Sstevel@tonic-gate 	return (0);
2737c478bd9Sstevel@tonic-gate }
2747c478bd9Sstevel@tonic-gate 
2757c478bd9Sstevel@tonic-gate /*
2767c478bd9Sstevel@tonic-gate  * ctfs_unmount - the VFS_UNMOUNT entry point
2777c478bd9Sstevel@tonic-gate  */
2787c478bd9Sstevel@tonic-gate static int
ctfs_unmount(vfs_t * vfsp,int flag,struct cred * cr)2797c478bd9Sstevel@tonic-gate ctfs_unmount(vfs_t *vfsp, int flag, struct cred *cr)
2807c478bd9Sstevel@tonic-gate {
2817c478bd9Sstevel@tonic-gate 	ctfs_vfs_t *data;
2827c478bd9Sstevel@tonic-gate 
2837c478bd9Sstevel@tonic-gate 	if (secpolicy_fs_unmount(cr, vfsp) != 0)
2847c478bd9Sstevel@tonic-gate 		return (EPERM);
2857c478bd9Sstevel@tonic-gate 
2867c478bd9Sstevel@tonic-gate 	/*
2877c478bd9Sstevel@tonic-gate 	 * Supporting forced unmounts would be nice to do at some
2887c478bd9Sstevel@tonic-gate 	 * point.
2897c478bd9Sstevel@tonic-gate 	 */
2907c478bd9Sstevel@tonic-gate 	if (flag & MS_FORCE)
2917c478bd9Sstevel@tonic-gate 		return (ENOTSUP);
2927c478bd9Sstevel@tonic-gate 
2937c478bd9Sstevel@tonic-gate 	/*
2947c478bd9Sstevel@tonic-gate 	 * We should never have a reference count less than 2: one for
2957c478bd9Sstevel@tonic-gate 	 * the caller, one for the root vnode.
2967c478bd9Sstevel@tonic-gate 	 */
2977c478bd9Sstevel@tonic-gate 	ASSERT(vfsp->vfs_count >= 2);
2987c478bd9Sstevel@tonic-gate 
2997c478bd9Sstevel@tonic-gate 	/*
3007c478bd9Sstevel@tonic-gate 	 * If we have any active vnodes, they will (transitively) have
3017c478bd9Sstevel@tonic-gate 	 * holds on the root vnode.
3027c478bd9Sstevel@tonic-gate 	 */
3037c478bd9Sstevel@tonic-gate 	data = vfsp->vfs_data;
3047c478bd9Sstevel@tonic-gate 	if (data->ctvfs_root->v_count > 1)
3057c478bd9Sstevel@tonic-gate 		return (EBUSY);
3067c478bd9Sstevel@tonic-gate 
3077c478bd9Sstevel@tonic-gate 	/*
3087c478bd9Sstevel@tonic-gate 	 * Release the last hold on the root vnode.  It will, in turn,
3097c478bd9Sstevel@tonic-gate 	 * release its hold on us.
3107c478bd9Sstevel@tonic-gate 	 */
3117c478bd9Sstevel@tonic-gate 	VN_RELE(data->ctvfs_root);
3127c478bd9Sstevel@tonic-gate 
3137c478bd9Sstevel@tonic-gate 	/*
3147c478bd9Sstevel@tonic-gate 	 * Disappear.
3157c478bd9Sstevel@tonic-gate 	 */
3167c478bd9Sstevel@tonic-gate 	kmem_free(data, sizeof (ctfs_vfs_t));
3177c478bd9Sstevel@tonic-gate 
3187c478bd9Sstevel@tonic-gate 	return (0);
3197c478bd9Sstevel@tonic-gate }
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate /*
3227c478bd9Sstevel@tonic-gate  * ctfs_root - the VFS_ROOT entry point
3237c478bd9Sstevel@tonic-gate  */
3247c478bd9Sstevel@tonic-gate static int
ctfs_root(vfs_t * vfsp,vnode_t ** vpp)3257c478bd9Sstevel@tonic-gate ctfs_root(vfs_t *vfsp, vnode_t **vpp)
3267c478bd9Sstevel@tonic-gate {
3277c478bd9Sstevel@tonic-gate 	vnode_t *vp;
3287c478bd9Sstevel@tonic-gate 
3297c478bd9Sstevel@tonic-gate 	vp = ((ctfs_vfs_t *)vfsp->vfs_data)->ctvfs_root;
3307c478bd9Sstevel@tonic-gate 	VN_HOLD(vp);
3317c478bd9Sstevel@tonic-gate 	*vpp = vp;
3327c478bd9Sstevel@tonic-gate 
3337c478bd9Sstevel@tonic-gate 	return (0);
3347c478bd9Sstevel@tonic-gate }
3357c478bd9Sstevel@tonic-gate 
3367c478bd9Sstevel@tonic-gate /*
3377c478bd9Sstevel@tonic-gate  * ctfs_statvfs - the VFS_STATVFS entry point
3387c478bd9Sstevel@tonic-gate  */
3397c478bd9Sstevel@tonic-gate static int
ctfs_statvfs(vfs_t * vfsp,statvfs64_t * sp)3407c478bd9Sstevel@tonic-gate ctfs_statvfs(vfs_t *vfsp, statvfs64_t *sp)
3417c478bd9Sstevel@tonic-gate {
3427c478bd9Sstevel@tonic-gate 	dev32_t	d32;
3437c478bd9Sstevel@tonic-gate 	int	total, i;
3447c478bd9Sstevel@tonic-gate 
3457c478bd9Sstevel@tonic-gate 	bzero(sp, sizeof (*sp));
3467c478bd9Sstevel@tonic-gate 	sp->f_bsize = DEV_BSIZE;
3477c478bd9Sstevel@tonic-gate 	sp->f_frsize = DEV_BSIZE;
3487c478bd9Sstevel@tonic-gate 	for (i = 0, total = 0; i < ct_ntypes; i++)
3497c478bd9Sstevel@tonic-gate 		total += contract_type_count(ct_types[i]);
3507c478bd9Sstevel@tonic-gate 	sp->f_files = total;
3517c478bd9Sstevel@tonic-gate 	sp->f_favail = sp->f_ffree = INT_MAX - total;
3527c478bd9Sstevel@tonic-gate 	(void) cmpldev(&d32, vfsp->vfs_dev);
3537c478bd9Sstevel@tonic-gate 	sp->f_fsid = d32;
3547c478bd9Sstevel@tonic-gate 	(void) strlcpy(sp->f_basetype, vfssw[vfsp->vfs_fstype].vsw_name,
3557c478bd9Sstevel@tonic-gate 	    sizeof (sp->f_basetype));
3567c478bd9Sstevel@tonic-gate 	sp->f_flag = vf_to_stf(vfsp->vfs_flag);
3577c478bd9Sstevel@tonic-gate 	sp->f_namemax = CTFS_NAME_MAX;
3587c478bd9Sstevel@tonic-gate 	(void) strlcpy(sp->f_fstr, "contract", sizeof (sp->f_fstr));
3597c478bd9Sstevel@tonic-gate 
3607c478bd9Sstevel@tonic-gate 	return (0);
3617c478bd9Sstevel@tonic-gate }
3627c478bd9Sstevel@tonic-gate 
3637c478bd9Sstevel@tonic-gate static const fs_operation_def_t ctfs_vfstops[] = {
364aa59c4cbSrsb 	{ VFSNAME_MOUNT,	{ .vfs_mount = ctfs_mount } },
365aa59c4cbSrsb 	{ VFSNAME_UNMOUNT,	{ .vfs_unmount = ctfs_unmount } },
366aa59c4cbSrsb 	{ VFSNAME_ROOT,		{ .vfs_root = ctfs_root } },
367aa59c4cbSrsb 	{ VFSNAME_STATVFS,	{ .vfs_statvfs = ctfs_statvfs } },
3687c478bd9Sstevel@tonic-gate 	{ NULL, NULL }
3697c478bd9Sstevel@tonic-gate };
3707c478bd9Sstevel@tonic-gate 
3717c478bd9Sstevel@tonic-gate /*
3727c478bd9Sstevel@tonic-gate  * ctfs_common_getattr
3737c478bd9Sstevel@tonic-gate  *
3747c478bd9Sstevel@tonic-gate  * Implements functionality common to all ctfs VOP_GETATTR entry
3757c478bd9Sstevel@tonic-gate  * points.  It assumes vap->va_size is set.
3767c478bd9Sstevel@tonic-gate  */
3777c478bd9Sstevel@tonic-gate void
ctfs_common_getattr(vnode_t * vp,vattr_t * vap)3787c478bd9Sstevel@tonic-gate ctfs_common_getattr(vnode_t *vp, vattr_t *vap)
3797c478bd9Sstevel@tonic-gate {
3807c478bd9Sstevel@tonic-gate 	vap->va_uid = 0;
3817c478bd9Sstevel@tonic-gate 	vap->va_gid = 0;
3827c478bd9Sstevel@tonic-gate 	vap->va_rdev = 0;
3837c478bd9Sstevel@tonic-gate 	vap->va_blksize = DEV_BSIZE;
3847c478bd9Sstevel@tonic-gate 	vap->va_nblocks = howmany(vap->va_size, vap->va_blksize);
3857c478bd9Sstevel@tonic-gate 	vap->va_seq = 0;
3867c478bd9Sstevel@tonic-gate 	vap->va_fsid = vp->v_vfsp->vfs_dev;
3877c478bd9Sstevel@tonic-gate 	vap->va_nodeid = gfs_file_inode(vp);
3887c478bd9Sstevel@tonic-gate }
3897c478bd9Sstevel@tonic-gate 
3907c478bd9Sstevel@tonic-gate /*
3917c478bd9Sstevel@tonic-gate  * ctfs_open - common VOP_OPEN entry point
3927c478bd9Sstevel@tonic-gate  *
3937c478bd9Sstevel@tonic-gate  * Used by all ctfs directories; just verifies we are using large-file
3947c478bd9Sstevel@tonic-gate  * aware interfaces and we aren't trying to open the directories
3957c478bd9Sstevel@tonic-gate  * writable.
3967c478bd9Sstevel@tonic-gate  */
3977c478bd9Sstevel@tonic-gate /* ARGSUSED */
3987c478bd9Sstevel@tonic-gate int
ctfs_open(vnode_t ** vpp,int flag,cred_t * cr,caller_context_t * ct)399da6c28aaSamw ctfs_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
4007c478bd9Sstevel@tonic-gate {
4017c478bd9Sstevel@tonic-gate 	if ((flag & (FOFFMAX | FWRITE)) != FOFFMAX)
4027c478bd9Sstevel@tonic-gate 		return (EINVAL);
4037c478bd9Sstevel@tonic-gate 
4047c478bd9Sstevel@tonic-gate 	return (0);
4057c478bd9Sstevel@tonic-gate }
4067c478bd9Sstevel@tonic-gate 
4077c478bd9Sstevel@tonic-gate /*
4087c478bd9Sstevel@tonic-gate  * ctfs_close - common VOP_CLOSE entry point
4097c478bd9Sstevel@tonic-gate  *
4107c478bd9Sstevel@tonic-gate  * For all ctfs vnode types which have no close-time clean-up to do.
4117c478bd9Sstevel@tonic-gate  */
4127c478bd9Sstevel@tonic-gate /* ARGSUSED */
4137c478bd9Sstevel@tonic-gate int
ctfs_close(vnode_t * vp,int flag,int count,offset_t offset,cred_t * cr,caller_context_t * ct)414da6c28aaSamw ctfs_close(
415da6c28aaSamw 	vnode_t *vp,
416da6c28aaSamw 	int flag,
417da6c28aaSamw 	int count,
418da6c28aaSamw 	offset_t offset,
419da6c28aaSamw 	cred_t *cr,
420da6c28aaSamw 	caller_context_t *ct)
4217c478bd9Sstevel@tonic-gate {
4227c478bd9Sstevel@tonic-gate 	return (0);
4237c478bd9Sstevel@tonic-gate }
4247c478bd9Sstevel@tonic-gate 
4257c478bd9Sstevel@tonic-gate /*
4267c478bd9Sstevel@tonic-gate  * ctfs_access_dir - common VOP_ACCESS entry point for directories
4277c478bd9Sstevel@tonic-gate  */
4287c478bd9Sstevel@tonic-gate /* ARGSUSED */
4297c478bd9Sstevel@tonic-gate int
ctfs_access_dir(vnode_t * vp,int mode,int flags,cred_t * cr,caller_context_t * ct)430da6c28aaSamw ctfs_access_dir(
431da6c28aaSamw 	vnode_t *vp,
432da6c28aaSamw 	int mode,
433da6c28aaSamw 	int flags,
434da6c28aaSamw 	cred_t *cr,
435da6c28aaSamw 	caller_context_t *ct)
4367c478bd9Sstevel@tonic-gate {
4377c478bd9Sstevel@tonic-gate 	if (mode & VWRITE)
4387c478bd9Sstevel@tonic-gate 		return (EACCES);
4397c478bd9Sstevel@tonic-gate 
4407c478bd9Sstevel@tonic-gate 	return (0);
4417c478bd9Sstevel@tonic-gate }
4427c478bd9Sstevel@tonic-gate 
4437c478bd9Sstevel@tonic-gate /*
4447c478bd9Sstevel@tonic-gate  * ctfs_access_dir - common VOP_ACCESS entry point for read-only files
4457c478bd9Sstevel@tonic-gate  */
4467c478bd9Sstevel@tonic-gate /* ARGSUSED */
4477c478bd9Sstevel@tonic-gate int
ctfs_access_readonly(vnode_t * vp,int mode,int flags,cred_t * cr,caller_context_t * ct)448da6c28aaSamw ctfs_access_readonly(
449da6c28aaSamw 	vnode_t *vp,
450da6c28aaSamw 	int mode,
451da6c28aaSamw 	int flags,
452da6c28aaSamw 	cred_t *cr,
453da6c28aaSamw 	caller_context_t *ct)
4547c478bd9Sstevel@tonic-gate {
4557c478bd9Sstevel@tonic-gate 	if (mode & (VWRITE | VEXEC))
4567c478bd9Sstevel@tonic-gate 		return (EACCES);
4577c478bd9Sstevel@tonic-gate 
4587c478bd9Sstevel@tonic-gate 	return (0);
4597c478bd9Sstevel@tonic-gate }
4607c478bd9Sstevel@tonic-gate 
4617c478bd9Sstevel@tonic-gate /*
4627c478bd9Sstevel@tonic-gate  * ctfs_access_dir - common VOP_ACCESS entry point for read-write files
4637c478bd9Sstevel@tonic-gate  */
4647c478bd9Sstevel@tonic-gate /* ARGSUSED */
4657c478bd9Sstevel@tonic-gate int
ctfs_access_readwrite(vnode_t * vp,int mode,int flags,cred_t * cr,caller_context_t * ct)466da6c28aaSamw ctfs_access_readwrite(
467da6c28aaSamw 	vnode_t *vp,
468da6c28aaSamw 	int mode,
469da6c28aaSamw 	int flags,
470da6c28aaSamw 	cred_t *cr,
471da6c28aaSamw 	caller_context_t *ct)
4727c478bd9Sstevel@tonic-gate {
4737c478bd9Sstevel@tonic-gate 	if (mode & VEXEC)
4747c478bd9Sstevel@tonic-gate 		return (EACCES);
4757c478bd9Sstevel@tonic-gate 
4767c478bd9Sstevel@tonic-gate 	return (0);
4777c478bd9Sstevel@tonic-gate }
4787c478bd9Sstevel@tonic-gate 
4797c478bd9Sstevel@tonic-gate /*
4807c478bd9Sstevel@tonic-gate  * ctfs_root_getattr - VOP_GETATTR entry point
4817c478bd9Sstevel@tonic-gate  */
4827c478bd9Sstevel@tonic-gate /* ARGSUSED */
4837c478bd9Sstevel@tonic-gate static int
ctfs_root_getattr(vnode_t * vp,vattr_t * vap,int flags,cred_t * cr,caller_context_t * ct)484da6c28aaSamw ctfs_root_getattr(
485da6c28aaSamw 	vnode_t *vp,
486da6c28aaSamw 	vattr_t *vap,
487da6c28aaSamw 	int flags,
488da6c28aaSamw 	cred_t *cr,
489da6c28aaSamw 	caller_context_t *ct)
4907c478bd9Sstevel@tonic-gate {
4917c478bd9Sstevel@tonic-gate 	vap->va_type = VDIR;
4927c478bd9Sstevel@tonic-gate 	vap->va_mode = 0555;
4937c478bd9Sstevel@tonic-gate 	vap->va_nlink = 2 + ct_ntypes + 1;
4947c478bd9Sstevel@tonic-gate 	vap->va_size = vap->va_nlink;
4957c478bd9Sstevel@tonic-gate 	vap->va_atime.tv_sec = vp->v_vfsp->vfs_mtime;
4967c478bd9Sstevel@tonic-gate 	vap->va_atime.tv_nsec = 0;
4977c478bd9Sstevel@tonic-gate 	vap->va_mtime = vap->va_ctime = vap->va_atime;
4987c478bd9Sstevel@tonic-gate 	ctfs_common_getattr(vp, vap);
4997c478bd9Sstevel@tonic-gate 
5007c478bd9Sstevel@tonic-gate 	return (0);
5017c478bd9Sstevel@tonic-gate }
5027c478bd9Sstevel@tonic-gate 
5037c478bd9Sstevel@tonic-gate /* ARGSUSED */
5047c478bd9Sstevel@tonic-gate static ino64_t
ctfs_root_do_inode(vnode_t * vp,int index)5057c478bd9Sstevel@tonic-gate ctfs_root_do_inode(vnode_t *vp, int index)
5067c478bd9Sstevel@tonic-gate {
5077c478bd9Sstevel@tonic-gate 	return (CTFS_INO_TYPE_DIR(index));
5087c478bd9Sstevel@tonic-gate }
5097c478bd9Sstevel@tonic-gate 
5107c478bd9Sstevel@tonic-gate static const fs_operation_def_t ctfs_tops_root[] = {
511aa59c4cbSrsb 	{ VOPNAME_OPEN,		{ .vop_open = ctfs_open } },
512aa59c4cbSrsb 	{ VOPNAME_CLOSE,	{ .vop_close = ctfs_close } },
513aa59c4cbSrsb 	{ VOPNAME_IOCTL,	{ .error = fs_inval } },
514aa59c4cbSrsb 	{ VOPNAME_GETATTR,	{ .vop_getattr = ctfs_root_getattr } },
515aa59c4cbSrsb 	{ VOPNAME_ACCESS,	{ .vop_access = ctfs_access_dir } },
516aa59c4cbSrsb 	{ VOPNAME_READDIR,	{ .vop_readdir = gfs_vop_readdir } },
517aa59c4cbSrsb 	{ VOPNAME_LOOKUP,	{ .vop_lookup = gfs_vop_lookup } },
518aa59c4cbSrsb 	{ VOPNAME_SEEK,		{ .vop_seek = fs_seek } },
519aa59c4cbSrsb 	{ VOPNAME_INACTIVE,	{ .vop_inactive = gfs_vop_inactive } },
5207c478bd9Sstevel@tonic-gate 	{ NULL, NULL }
5217c478bd9Sstevel@tonic-gate };
522