xref: /onnv-gate/usr/src/uts/common/fs/ctfs/ctfs_root.c (revision 3898:c788126f2a20)
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
5*3898Srsb  * Common Development and Distribution License (the "License").
6*3898Srsb  * 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 /*
22*3898Srsb  * 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/modctl.h>
290Sstevel@tonic-gate #include <sys/types.h>
300Sstevel@tonic-gate #include <sys/param.h>
310Sstevel@tonic-gate #include <sys/time.h>
320Sstevel@tonic-gate #include <sys/cred.h>
330Sstevel@tonic-gate #include <sys/vfs.h>
34*3898Srsb #include <sys/vfs_opreg.h>
350Sstevel@tonic-gate #include <sys/gfs.h>
360Sstevel@tonic-gate #include <sys/vnode.h>
370Sstevel@tonic-gate #include <sys/systm.h>
380Sstevel@tonic-gate #include <sys/cmn_err.h>
390Sstevel@tonic-gate #include <sys/errno.h>
400Sstevel@tonic-gate #include <sys/sysmacros.h>
410Sstevel@tonic-gate #include <sys/policy.h>
420Sstevel@tonic-gate #include <sys/mount.h>
430Sstevel@tonic-gate #include <sys/pathname.h>
440Sstevel@tonic-gate #include <sys/dirent.h>
450Sstevel@tonic-gate #include <fs/fs_subr.h>
460Sstevel@tonic-gate #include <sys/contract.h>
470Sstevel@tonic-gate #include <sys/contract_impl.h>
480Sstevel@tonic-gate #include <sys/ctfs.h>
490Sstevel@tonic-gate #include <sys/ctfs_impl.h>
500Sstevel@tonic-gate #include <sys/uio.h>
510Sstevel@tonic-gate #include <sys/file.h>
520Sstevel@tonic-gate #include <sys/atomic.h>
530Sstevel@tonic-gate #include <sys/sunddi.h>
540Sstevel@tonic-gate 
550Sstevel@tonic-gate /*
560Sstevel@tonic-gate  * ctfs, the contract filesystem.
570Sstevel@tonic-gate  *
580Sstevel@tonic-gate  * Exposes the constract subsystem to userland.  The structure of the
590Sstevel@tonic-gate  * filesytem is a public interface, but the behavior of the files is
600Sstevel@tonic-gate  * private and unstable.  Contract consumers are expected to use
610Sstevel@tonic-gate  * libcontract(3lib) to operate on ctfs file descriptors.
620Sstevel@tonic-gate  *
630Sstevel@tonic-gate  * We're trying something a little different here.  Rather than make
640Sstevel@tonic-gate  * each vnode op itself call into a vector of file type operations, we
650Sstevel@tonic-gate  * actually use different vnode types (gasp!), the implementations of
660Sstevel@tonic-gate  * which may call into routines providing common functionality.  This
670Sstevel@tonic-gate  * design should hopefully make it easier to factor and maintain the
680Sstevel@tonic-gate  * code.  For the most part, there is a separate file for each vnode
690Sstevel@tonic-gate  * type's implementation.  The exceptions to this are the ctl/stat
700Sstevel@tonic-gate  * nodes, which are very similar, and the three event endpoint types.
710Sstevel@tonic-gate  *
720Sstevel@tonic-gate  * This file contains common routines used by some or all of the vnode
730Sstevel@tonic-gate  * types, the filesystem's module linkage and VFS operations, and the
740Sstevel@tonic-gate  * implementation of the root vnode.
750Sstevel@tonic-gate  */
760Sstevel@tonic-gate 
770Sstevel@tonic-gate /*
780Sstevel@tonic-gate  * Ops vectors for all the vnode types; they have to be defined
790Sstevel@tonic-gate  * somewhere.  See gfs_make_opsvec for thoughts on how this could be
800Sstevel@tonic-gate  * done differently.
810Sstevel@tonic-gate  */
820Sstevel@tonic-gate vnodeops_t *ctfs_ops_root;
830Sstevel@tonic-gate vnodeops_t *ctfs_ops_adir;
840Sstevel@tonic-gate vnodeops_t *ctfs_ops_sym;
850Sstevel@tonic-gate vnodeops_t *ctfs_ops_tdir;
860Sstevel@tonic-gate vnodeops_t *ctfs_ops_tmpl;
870Sstevel@tonic-gate vnodeops_t *ctfs_ops_cdir;
880Sstevel@tonic-gate vnodeops_t *ctfs_ops_ctl;
890Sstevel@tonic-gate vnodeops_t *ctfs_ops_stat;
900Sstevel@tonic-gate vnodeops_t *ctfs_ops_event;
910Sstevel@tonic-gate vnodeops_t *ctfs_ops_bundle;
920Sstevel@tonic-gate vnodeops_t *ctfs_ops_latest;
930Sstevel@tonic-gate 
940Sstevel@tonic-gate static const fs_operation_def_t ctfs_vfstops[];
950Sstevel@tonic-gate static gfs_opsvec_t ctfs_opsvec[];
960Sstevel@tonic-gate 
970Sstevel@tonic-gate static int ctfs_init(int, char *);
980Sstevel@tonic-gate 
990Sstevel@tonic-gate static ino64_t ctfs_root_do_inode(vnode_t *, int);
1000Sstevel@tonic-gate 
1010Sstevel@tonic-gate 
1020Sstevel@tonic-gate /*
1030Sstevel@tonic-gate  * File system module linkage
1040Sstevel@tonic-gate  */
1050Sstevel@tonic-gate static mntopts_t ctfs_mntopts = {
1060Sstevel@tonic-gate 	0,
1070Sstevel@tonic-gate 	NULL
1080Sstevel@tonic-gate };
1090Sstevel@tonic-gate 
1100Sstevel@tonic-gate static vfsdef_t vfw = {
1110Sstevel@tonic-gate 	VFSDEF_VERSION,
1120Sstevel@tonic-gate 	"ctfs",
1130Sstevel@tonic-gate 	ctfs_init,
1140Sstevel@tonic-gate 	VSW_HASPROTO,
1150Sstevel@tonic-gate 	&ctfs_mntopts,
1160Sstevel@tonic-gate };
1170Sstevel@tonic-gate 
1180Sstevel@tonic-gate extern struct mod_ops mod_fsops;
1190Sstevel@tonic-gate 
1200Sstevel@tonic-gate static struct modlfs modlfs = {
1210Sstevel@tonic-gate 	&mod_fsops, "contract filesystem", &vfw
1220Sstevel@tonic-gate };
1230Sstevel@tonic-gate 
1240Sstevel@tonic-gate static struct modlinkage modlinkage = {
1250Sstevel@tonic-gate 	MODREV_1, (void *)&modlfs, NULL
1260Sstevel@tonic-gate };
1270Sstevel@tonic-gate 
1280Sstevel@tonic-gate int
1290Sstevel@tonic-gate _init(void)
1300Sstevel@tonic-gate {
1310Sstevel@tonic-gate 	return (mod_install(&modlinkage));
1320Sstevel@tonic-gate }
1330Sstevel@tonic-gate 
1340Sstevel@tonic-gate int
1350Sstevel@tonic-gate _info(struct modinfo *modinfop)
1360Sstevel@tonic-gate {
1370Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
1380Sstevel@tonic-gate }
1390Sstevel@tonic-gate 
1400Sstevel@tonic-gate int
1410Sstevel@tonic-gate _fini(void)
1420Sstevel@tonic-gate {
1430Sstevel@tonic-gate 	/*
1440Sstevel@tonic-gate 	 * As unloading filesystem modules isn't completely safe, we
1450Sstevel@tonic-gate 	 * don't allow it.
1460Sstevel@tonic-gate 	 */
1470Sstevel@tonic-gate 	return (EBUSY);
1480Sstevel@tonic-gate }
1490Sstevel@tonic-gate 
1500Sstevel@tonic-gate static int ctfs_fstype;
1510Sstevel@tonic-gate static major_t ctfs_major;
1520Sstevel@tonic-gate static minor_t ctfs_minor = 0;
1530Sstevel@tonic-gate 
1540Sstevel@tonic-gate /*
1550Sstevel@tonic-gate  * The ops vector vector.
1560Sstevel@tonic-gate  */
1570Sstevel@tonic-gate static const fs_operation_def_t ctfs_tops_root[];
1580Sstevel@tonic-gate extern const fs_operation_def_t ctfs_tops_tmpl[];
1590Sstevel@tonic-gate extern const fs_operation_def_t ctfs_tops_ctl[];
1600Sstevel@tonic-gate extern const fs_operation_def_t ctfs_tops_adir[];
1610Sstevel@tonic-gate extern const fs_operation_def_t ctfs_tops_cdir[];
1620Sstevel@tonic-gate extern const fs_operation_def_t ctfs_tops_tdir[];
1630Sstevel@tonic-gate extern const fs_operation_def_t ctfs_tops_latest[];
1640Sstevel@tonic-gate extern const fs_operation_def_t ctfs_tops_stat[];
1650Sstevel@tonic-gate extern const fs_operation_def_t ctfs_tops_sym[];
1660Sstevel@tonic-gate extern const fs_operation_def_t ctfs_tops_event[];
1670Sstevel@tonic-gate extern const fs_operation_def_t ctfs_tops_bundle[];
1680Sstevel@tonic-gate static gfs_opsvec_t ctfs_opsvec[] = {
1690Sstevel@tonic-gate 	{ "ctfs root directory", ctfs_tops_root, &ctfs_ops_root },
1700Sstevel@tonic-gate 	{ "ctfs all directory", ctfs_tops_adir, &ctfs_ops_adir },
1710Sstevel@tonic-gate 	{ "ctfs all symlink", ctfs_tops_sym, &ctfs_ops_sym },
1720Sstevel@tonic-gate 	{ "ctfs template directory", ctfs_tops_tdir, &ctfs_ops_tdir },
1730Sstevel@tonic-gate 	{ "ctfs template file", ctfs_tops_tmpl, &ctfs_ops_tmpl },
1740Sstevel@tonic-gate 	{ "ctfs contract directory", ctfs_tops_cdir, &ctfs_ops_cdir },
1750Sstevel@tonic-gate 	{ "ctfs ctl file", ctfs_tops_ctl, &ctfs_ops_ctl },
1760Sstevel@tonic-gate 	{ "ctfs status file", ctfs_tops_stat, &ctfs_ops_stat },
1770Sstevel@tonic-gate 	{ "ctfs events file", ctfs_tops_event, &ctfs_ops_event },
1780Sstevel@tonic-gate 	{ "ctfs bundle file", ctfs_tops_bundle, &ctfs_ops_bundle },
1790Sstevel@tonic-gate 	{ "ctfs latest file", ctfs_tops_latest, &ctfs_ops_latest },
1800Sstevel@tonic-gate 	{ NULL }
1810Sstevel@tonic-gate };
1820Sstevel@tonic-gate 
1830Sstevel@tonic-gate 
1840Sstevel@tonic-gate /*
1850Sstevel@tonic-gate  * ctfs_init - the vfsdef_t init entry point
1860Sstevel@tonic-gate  *
1870Sstevel@tonic-gate  * Sets the VFS ops, builds all the vnode ops, and allocates a device
1880Sstevel@tonic-gate  * number.
1890Sstevel@tonic-gate  */
1900Sstevel@tonic-gate /* ARGSUSED */
1910Sstevel@tonic-gate static int
1920Sstevel@tonic-gate ctfs_init(int fstype, char *name)
1930Sstevel@tonic-gate {
1940Sstevel@tonic-gate 	vfsops_t *vfsops;
1950Sstevel@tonic-gate 	int error;
1960Sstevel@tonic-gate 
1970Sstevel@tonic-gate 	ctfs_fstype = fstype;
1980Sstevel@tonic-gate 	if (error = vfs_setfsops(fstype, ctfs_vfstops, &vfsops)) {
1990Sstevel@tonic-gate 		cmn_err(CE_WARN, "ctfs_init: bad vfs ops template");
2000Sstevel@tonic-gate 		return (error);
2010Sstevel@tonic-gate 	}
2020Sstevel@tonic-gate 
2030Sstevel@tonic-gate 	if (error = gfs_make_opsvec(ctfs_opsvec)) {
2040Sstevel@tonic-gate 		(void) vfs_freevfsops(vfsops);
2050Sstevel@tonic-gate 		return (error);
2060Sstevel@tonic-gate 	}
2070Sstevel@tonic-gate 
2080Sstevel@tonic-gate 	if ((ctfs_major = getudev()) == (major_t)-1) {
2090Sstevel@tonic-gate 		cmn_err(CE_WARN, "ctfs_init: can't get unique device number");
2100Sstevel@tonic-gate 		ctfs_major = 0;
2110Sstevel@tonic-gate 	}
2120Sstevel@tonic-gate 
2130Sstevel@tonic-gate 	return (0);
2140Sstevel@tonic-gate }
2150Sstevel@tonic-gate 
2160Sstevel@tonic-gate /*
2170Sstevel@tonic-gate  * ctfs_mount - the VFS_MOUNT entry point
2180Sstevel@tonic-gate  */
2190Sstevel@tonic-gate static int
2200Sstevel@tonic-gate ctfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
2210Sstevel@tonic-gate {
2220Sstevel@tonic-gate 	ctfs_vfs_t *data;
2230Sstevel@tonic-gate 	dev_t dev;
2240Sstevel@tonic-gate 	gfs_dirent_t *dirent;
2250Sstevel@tonic-gate 	int i;
2260Sstevel@tonic-gate 
2270Sstevel@tonic-gate 	if (secpolicy_fs_mount(cr, mvp, vfsp) != 0)
2280Sstevel@tonic-gate 		return (EPERM);
2290Sstevel@tonic-gate 
2300Sstevel@tonic-gate 	if (mvp->v_type != VDIR)
2310Sstevel@tonic-gate 		return (ENOTDIR);
2320Sstevel@tonic-gate 
2330Sstevel@tonic-gate 	if ((uap->flags & MS_OVERLAY) == 0 &&
2340Sstevel@tonic-gate 	    (mvp->v_count > 1 || (mvp->v_flag & VROOT)))
2350Sstevel@tonic-gate 		return (EBUSY);
2360Sstevel@tonic-gate 
2370Sstevel@tonic-gate 	data = kmem_alloc(sizeof (ctfs_vfs_t), KM_SLEEP);
2380Sstevel@tonic-gate 
2390Sstevel@tonic-gate 	/*
2400Sstevel@tonic-gate 	 * Initialize vfs fields not initialized by VFS_INIT/domount
2410Sstevel@tonic-gate 	 */
2420Sstevel@tonic-gate 	vfsp->vfs_bsize = DEV_BSIZE;
2430Sstevel@tonic-gate 	vfsp->vfs_fstype = ctfs_fstype;
2440Sstevel@tonic-gate 	do
2450Sstevel@tonic-gate 		dev = makedevice(ctfs_major,
2460Sstevel@tonic-gate 		    atomic_add_32_nv(&ctfs_minor, 1) & L_MAXMIN32);
2470Sstevel@tonic-gate 	while (vfs_devismounted(dev));
2480Sstevel@tonic-gate 	vfs_make_fsid(&vfsp->vfs_fsid, dev, ctfs_fstype);
2490Sstevel@tonic-gate 	vfsp->vfs_data = data;
2500Sstevel@tonic-gate 	vfsp->vfs_dev = dev;
2510Sstevel@tonic-gate 
2520Sstevel@tonic-gate 	/*
2530Sstevel@tonic-gate 	 * Dynamically create gfs_dirent_t array for the root directory.
2540Sstevel@tonic-gate 	 */
2550Sstevel@tonic-gate 	dirent = kmem_zalloc((ct_ntypes + 2) * sizeof (gfs_dirent_t), KM_SLEEP);
2560Sstevel@tonic-gate 	for (i = 0; i < ct_ntypes; i++) {
2570Sstevel@tonic-gate 		dirent[i].gfse_name = (char *)ct_types[i]->ct_type_name;
2580Sstevel@tonic-gate 		dirent[i].gfse_ctor = ctfs_create_tdirnode;
2590Sstevel@tonic-gate 		dirent[i].gfse_flags = GFS_CACHE_VNODE;
2600Sstevel@tonic-gate 	}
2610Sstevel@tonic-gate 	dirent[i].gfse_name = "all";
2620Sstevel@tonic-gate 	dirent[i].gfse_ctor = ctfs_create_adirnode;
2630Sstevel@tonic-gate 	dirent[i].gfse_flags = GFS_CACHE_VNODE;
2640Sstevel@tonic-gate 	dirent[i+1].gfse_name = NULL;
2650Sstevel@tonic-gate 
2660Sstevel@tonic-gate 	/*
2670Sstevel@tonic-gate 	 * Create root vnode
2680Sstevel@tonic-gate 	 */
2690Sstevel@tonic-gate 	data->ctvfs_root = gfs_root_create(sizeof (ctfs_rootnode_t),
2700Sstevel@tonic-gate 	    vfsp, ctfs_ops_root, CTFS_INO_ROOT, dirent, ctfs_root_do_inode,
2710Sstevel@tonic-gate 	    CTFS_NAME_MAX, NULL, NULL);
2720Sstevel@tonic-gate 
2730Sstevel@tonic-gate 	kmem_free(dirent, (ct_ntypes + 2) * sizeof (gfs_dirent_t));
2740Sstevel@tonic-gate 
2750Sstevel@tonic-gate 	return (0);
2760Sstevel@tonic-gate }
2770Sstevel@tonic-gate 
2780Sstevel@tonic-gate /*
2790Sstevel@tonic-gate  * ctfs_unmount - the VFS_UNMOUNT entry point
2800Sstevel@tonic-gate  */
2810Sstevel@tonic-gate static int
2820Sstevel@tonic-gate ctfs_unmount(vfs_t *vfsp, int flag, struct cred *cr)
2830Sstevel@tonic-gate {
2840Sstevel@tonic-gate 	ctfs_vfs_t *data;
2850Sstevel@tonic-gate 
2860Sstevel@tonic-gate 	if (secpolicy_fs_unmount(cr, vfsp) != 0)
2870Sstevel@tonic-gate 		return (EPERM);
2880Sstevel@tonic-gate 
2890Sstevel@tonic-gate 	/*
2900Sstevel@tonic-gate 	 * Supporting forced unmounts would be nice to do at some
2910Sstevel@tonic-gate 	 * point.
2920Sstevel@tonic-gate 	 */
2930Sstevel@tonic-gate 	if (flag & MS_FORCE)
2940Sstevel@tonic-gate 		return (ENOTSUP);
2950Sstevel@tonic-gate 
2960Sstevel@tonic-gate 	/*
2970Sstevel@tonic-gate 	 * We should never have a reference count less than 2: one for
2980Sstevel@tonic-gate 	 * the caller, one for the root vnode.
2990Sstevel@tonic-gate 	 */
3000Sstevel@tonic-gate 	ASSERT(vfsp->vfs_count >= 2);
3010Sstevel@tonic-gate 
3020Sstevel@tonic-gate 	/*
3030Sstevel@tonic-gate 	 * If we have any active vnodes, they will (transitively) have
3040Sstevel@tonic-gate 	 * holds on the root vnode.
3050Sstevel@tonic-gate 	 */
3060Sstevel@tonic-gate 	data = vfsp->vfs_data;
3070Sstevel@tonic-gate 	if (data->ctvfs_root->v_count > 1)
3080Sstevel@tonic-gate 		return (EBUSY);
3090Sstevel@tonic-gate 
3100Sstevel@tonic-gate 	/*
3110Sstevel@tonic-gate 	 * Release the last hold on the root vnode.  It will, in turn,
3120Sstevel@tonic-gate 	 * release its hold on us.
3130Sstevel@tonic-gate 	 */
3140Sstevel@tonic-gate 	VN_RELE(data->ctvfs_root);
3150Sstevel@tonic-gate 
3160Sstevel@tonic-gate 	/*
3170Sstevel@tonic-gate 	 * Disappear.
3180Sstevel@tonic-gate 	 */
3190Sstevel@tonic-gate 	kmem_free(data, sizeof (ctfs_vfs_t));
3200Sstevel@tonic-gate 
3210Sstevel@tonic-gate 	return (0);
3220Sstevel@tonic-gate }
3230Sstevel@tonic-gate 
3240Sstevel@tonic-gate /*
3250Sstevel@tonic-gate  * ctfs_root - the VFS_ROOT entry point
3260Sstevel@tonic-gate  */
3270Sstevel@tonic-gate static int
3280Sstevel@tonic-gate ctfs_root(vfs_t *vfsp, vnode_t **vpp)
3290Sstevel@tonic-gate {
3300Sstevel@tonic-gate 	vnode_t *vp;
3310Sstevel@tonic-gate 
3320Sstevel@tonic-gate 	vp = ((ctfs_vfs_t *)vfsp->vfs_data)->ctvfs_root;
3330Sstevel@tonic-gate 	VN_HOLD(vp);
3340Sstevel@tonic-gate 	*vpp = vp;
3350Sstevel@tonic-gate 
3360Sstevel@tonic-gate 	return (0);
3370Sstevel@tonic-gate }
3380Sstevel@tonic-gate 
3390Sstevel@tonic-gate /*
3400Sstevel@tonic-gate  * ctfs_statvfs - the VFS_STATVFS entry point
3410Sstevel@tonic-gate  */
3420Sstevel@tonic-gate static int
3430Sstevel@tonic-gate ctfs_statvfs(vfs_t *vfsp, statvfs64_t *sp)
3440Sstevel@tonic-gate {
3450Sstevel@tonic-gate 	dev32_t	d32;
3460Sstevel@tonic-gate 	int	total, i;
3470Sstevel@tonic-gate 
3480Sstevel@tonic-gate 	bzero(sp, sizeof (*sp));
3490Sstevel@tonic-gate 	sp->f_bsize = DEV_BSIZE;
3500Sstevel@tonic-gate 	sp->f_frsize = DEV_BSIZE;
3510Sstevel@tonic-gate 	for (i = 0, total = 0; i < ct_ntypes; i++)
3520Sstevel@tonic-gate 		total += contract_type_count(ct_types[i]);
3530Sstevel@tonic-gate 	sp->f_files = total;
3540Sstevel@tonic-gate 	sp->f_favail = sp->f_ffree = INT_MAX - total;
3550Sstevel@tonic-gate 	(void) cmpldev(&d32, vfsp->vfs_dev);
3560Sstevel@tonic-gate 	sp->f_fsid = d32;
3570Sstevel@tonic-gate 	(void) strlcpy(sp->f_basetype, vfssw[vfsp->vfs_fstype].vsw_name,
3580Sstevel@tonic-gate 	    sizeof (sp->f_basetype));
3590Sstevel@tonic-gate 	sp->f_flag = vf_to_stf(vfsp->vfs_flag);
3600Sstevel@tonic-gate 	sp->f_namemax = CTFS_NAME_MAX;
3610Sstevel@tonic-gate 	(void) strlcpy(sp->f_fstr, "contract", sizeof (sp->f_fstr));
3620Sstevel@tonic-gate 
3630Sstevel@tonic-gate 	return (0);
3640Sstevel@tonic-gate }
3650Sstevel@tonic-gate 
3660Sstevel@tonic-gate static const fs_operation_def_t ctfs_vfstops[] = {
367*3898Srsb 	{ VFSNAME_MOUNT,	{ .vfs_mount = ctfs_mount } },
368*3898Srsb 	{ VFSNAME_UNMOUNT,	{ .vfs_unmount = ctfs_unmount } },
369*3898Srsb 	{ VFSNAME_ROOT,		{ .vfs_root = ctfs_root } },
370*3898Srsb 	{ VFSNAME_STATVFS,	{ .vfs_statvfs = ctfs_statvfs } },
3710Sstevel@tonic-gate 	{ NULL, NULL }
3720Sstevel@tonic-gate };
3730Sstevel@tonic-gate 
3740Sstevel@tonic-gate /*
3750Sstevel@tonic-gate  * ctfs_common_getattr
3760Sstevel@tonic-gate  *
3770Sstevel@tonic-gate  * Implements functionality common to all ctfs VOP_GETATTR entry
3780Sstevel@tonic-gate  * points.  It assumes vap->va_size is set.
3790Sstevel@tonic-gate  */
3800Sstevel@tonic-gate void
3810Sstevel@tonic-gate ctfs_common_getattr(vnode_t *vp, vattr_t *vap)
3820Sstevel@tonic-gate {
3830Sstevel@tonic-gate 	vap->va_uid = 0;
3840Sstevel@tonic-gate 	vap->va_gid = 0;
3850Sstevel@tonic-gate 	vap->va_rdev = 0;
3860Sstevel@tonic-gate 	vap->va_blksize = DEV_BSIZE;
3870Sstevel@tonic-gate 	vap->va_nblocks = howmany(vap->va_size, vap->va_blksize);
3880Sstevel@tonic-gate 	vap->va_seq = 0;
3890Sstevel@tonic-gate 	vap->va_fsid = vp->v_vfsp->vfs_dev;
3900Sstevel@tonic-gate 	vap->va_nodeid = gfs_file_inode(vp);
3910Sstevel@tonic-gate }
3920Sstevel@tonic-gate 
3930Sstevel@tonic-gate /*
3940Sstevel@tonic-gate  * ctfs_open - common VOP_OPEN entry point
3950Sstevel@tonic-gate  *
3960Sstevel@tonic-gate  * Used by all ctfs directories; just verifies we are using large-file
3970Sstevel@tonic-gate  * aware interfaces and we aren't trying to open the directories
3980Sstevel@tonic-gate  * writable.
3990Sstevel@tonic-gate  */
4000Sstevel@tonic-gate /* ARGSUSED */
4010Sstevel@tonic-gate int
4020Sstevel@tonic-gate ctfs_open(vnode_t **vpp, int flag, cred_t *cr)
4030Sstevel@tonic-gate {
4040Sstevel@tonic-gate 	if ((flag & (FOFFMAX | FWRITE)) != FOFFMAX)
4050Sstevel@tonic-gate 		return (EINVAL);
4060Sstevel@tonic-gate 
4070Sstevel@tonic-gate 	return (0);
4080Sstevel@tonic-gate }
4090Sstevel@tonic-gate 
4100Sstevel@tonic-gate /*
4110Sstevel@tonic-gate  * ctfs_close - common VOP_CLOSE entry point
4120Sstevel@tonic-gate  *
4130Sstevel@tonic-gate  * For all ctfs vnode types which have no close-time clean-up to do.
4140Sstevel@tonic-gate  */
4150Sstevel@tonic-gate /* ARGSUSED */
4160Sstevel@tonic-gate int
4170Sstevel@tonic-gate ctfs_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr)
4180Sstevel@tonic-gate {
4190Sstevel@tonic-gate 	return (0);
4200Sstevel@tonic-gate }
4210Sstevel@tonic-gate 
4220Sstevel@tonic-gate /*
4230Sstevel@tonic-gate  * ctfs_access_dir - common VOP_ACCESS entry point for directories
4240Sstevel@tonic-gate  */
4250Sstevel@tonic-gate /* ARGSUSED */
4260Sstevel@tonic-gate int
4270Sstevel@tonic-gate ctfs_access_dir(vnode_t *vp, int mode, int flags, cred_t *cr)
4280Sstevel@tonic-gate {
4290Sstevel@tonic-gate 	if (mode & VWRITE)
4300Sstevel@tonic-gate 		return (EACCES);
4310Sstevel@tonic-gate 
4320Sstevel@tonic-gate 	return (0);
4330Sstevel@tonic-gate }
4340Sstevel@tonic-gate 
4350Sstevel@tonic-gate /*
4360Sstevel@tonic-gate  * ctfs_access_dir - common VOP_ACCESS entry point for read-only files
4370Sstevel@tonic-gate  */
4380Sstevel@tonic-gate /* ARGSUSED */
4390Sstevel@tonic-gate int
4400Sstevel@tonic-gate ctfs_access_readonly(vnode_t *vp, int mode, int flags, cred_t *cr)
4410Sstevel@tonic-gate {
4420Sstevel@tonic-gate 	if (mode & (VWRITE | VEXEC))
4430Sstevel@tonic-gate 		return (EACCES);
4440Sstevel@tonic-gate 
4450Sstevel@tonic-gate 	return (0);
4460Sstevel@tonic-gate }
4470Sstevel@tonic-gate 
4480Sstevel@tonic-gate /*
4490Sstevel@tonic-gate  * ctfs_access_dir - common VOP_ACCESS entry point for read-write files
4500Sstevel@tonic-gate  */
4510Sstevel@tonic-gate /* ARGSUSED */
4520Sstevel@tonic-gate int
4530Sstevel@tonic-gate ctfs_access_readwrite(vnode_t *vp, int mode, int flags, cred_t *cr)
4540Sstevel@tonic-gate {
4550Sstevel@tonic-gate 	if (mode & VEXEC)
4560Sstevel@tonic-gate 		return (EACCES);
4570Sstevel@tonic-gate 
4580Sstevel@tonic-gate 	return (0);
4590Sstevel@tonic-gate }
4600Sstevel@tonic-gate 
4610Sstevel@tonic-gate /*
4620Sstevel@tonic-gate  * ctfs_root_getattr - VOP_GETATTR entry point
4630Sstevel@tonic-gate  */
4640Sstevel@tonic-gate /* ARGSUSED */
4650Sstevel@tonic-gate static int
4660Sstevel@tonic-gate ctfs_root_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
4670Sstevel@tonic-gate {
4680Sstevel@tonic-gate 	vap->va_type = VDIR;
4690Sstevel@tonic-gate 	vap->va_mode = 0555;
4700Sstevel@tonic-gate 	vap->va_nlink = 2 + ct_ntypes + 1;
4710Sstevel@tonic-gate 	vap->va_size = vap->va_nlink;
4720Sstevel@tonic-gate 	vap->va_atime.tv_sec = vp->v_vfsp->vfs_mtime;
4730Sstevel@tonic-gate 	vap->va_atime.tv_nsec = 0;
4740Sstevel@tonic-gate 	vap->va_mtime = vap->va_ctime = vap->va_atime;
4750Sstevel@tonic-gate 	ctfs_common_getattr(vp, vap);
4760Sstevel@tonic-gate 
4770Sstevel@tonic-gate 	return (0);
4780Sstevel@tonic-gate }
4790Sstevel@tonic-gate 
4800Sstevel@tonic-gate /* ARGSUSED */
4810Sstevel@tonic-gate static ino64_t
4820Sstevel@tonic-gate ctfs_root_do_inode(vnode_t *vp, int index)
4830Sstevel@tonic-gate {
4840Sstevel@tonic-gate 	return (CTFS_INO_TYPE_DIR(index));
4850Sstevel@tonic-gate }
4860Sstevel@tonic-gate 
4870Sstevel@tonic-gate static const fs_operation_def_t ctfs_tops_root[] = {
488*3898Srsb 	{ VOPNAME_OPEN,		{ .vop_open = ctfs_open } },
489*3898Srsb 	{ VOPNAME_CLOSE,	{ .vop_close = ctfs_close } },
490*3898Srsb 	{ VOPNAME_IOCTL,	{ .error = fs_inval } },
491*3898Srsb 	{ VOPNAME_GETATTR,	{ .vop_getattr = ctfs_root_getattr } },
492*3898Srsb 	{ VOPNAME_ACCESS,	{ .vop_access = ctfs_access_dir } },
493*3898Srsb 	{ VOPNAME_READDIR,	{ .vop_readdir = gfs_vop_readdir } },
494*3898Srsb 	{ VOPNAME_LOOKUP,	{ .vop_lookup = gfs_vop_lookup } },
495*3898Srsb 	{ VOPNAME_SEEK,		{ .vop_seek = fs_seek } },
496*3898Srsb 	{ VOPNAME_INACTIVE,	{ .vop_inactive = gfs_vop_inactive } },
4970Sstevel@tonic-gate 	{ NULL, NULL }
4980Sstevel@tonic-gate };
499