xref: /onnv-gate/usr/src/uts/common/fs/objfs/objfs_vfs.c (revision 12633:9f2cda0ed938)
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 /*
22*12633Sjohn.levon@sun.com  * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
230Sstevel@tonic-gate  */
240Sstevel@tonic-gate 
250Sstevel@tonic-gate #include <sys/atomic.h>
260Sstevel@tonic-gate #include <sys/cmn_err.h>
270Sstevel@tonic-gate #include <sys/errno.h>
280Sstevel@tonic-gate #include <sys/mount.h>
290Sstevel@tonic-gate #include <sys/objfs.h>
300Sstevel@tonic-gate #include <sys/objfs_impl.h>
313898Srsb #include <sys/vfs_opreg.h>
320Sstevel@tonic-gate #include <sys/policy.h>
330Sstevel@tonic-gate #include <sys/sunddi.h>
340Sstevel@tonic-gate #include <sys/sysmacros.h>
350Sstevel@tonic-gate #include <sys/systm.h>
360Sstevel@tonic-gate 
370Sstevel@tonic-gate /*
380Sstevel@tonic-gate  * Kernel object filesystem.
390Sstevel@tonic-gate  *
400Sstevel@tonic-gate  * This is a pseudo filesystem which exports information about currently loaded
410Sstevel@tonic-gate  * kernel objects.  The root directory contains one directory for each loaded
420Sstevel@tonic-gate  * object, indexed by module name.  Within each object directory is an ELF file,
430Sstevel@tonic-gate  * 'object', that contains information about the currently loaded module.
440Sstevel@tonic-gate  *
450Sstevel@tonic-gate  * This file contains functions that interact with the VFS layer.  Each
460Sstevel@tonic-gate  * filesystem element is represented by a a different node.
470Sstevel@tonic-gate  *
480Sstevel@tonic-gate  * 	/		objfs_rootnode_t	objfs_root.c
490Sstevel@tonic-gate  *	/<obj>		objfs_odirnode_t	objfs_odir.c
500Sstevel@tonic-gate  *	/<obj>/object	objfs_datanode_t	objfs_data.c
510Sstevel@tonic-gate  *
520Sstevel@tonic-gate  * In addition, some common routines are found in the 'objfs_common.c' file.
530Sstevel@tonic-gate  */
540Sstevel@tonic-gate 
550Sstevel@tonic-gate vnodeops_t *objfs_ops_root;
560Sstevel@tonic-gate vnodeops_t *objfs_ops_odir;
570Sstevel@tonic-gate vnodeops_t *objfs_ops_data;
580Sstevel@tonic-gate 
590Sstevel@tonic-gate static const fs_operation_def_t objfs_vfstops[];
600Sstevel@tonic-gate static gfs_opsvec_t objfs_opsvec[];
610Sstevel@tonic-gate 
620Sstevel@tonic-gate static int objfs_init(int, char *);
630Sstevel@tonic-gate 
640Sstevel@tonic-gate /*
650Sstevel@tonic-gate  * Module linkage
660Sstevel@tonic-gate  */
670Sstevel@tonic-gate static mntopts_t objfs_mntopts = {
680Sstevel@tonic-gate 	0,
690Sstevel@tonic-gate 	NULL
700Sstevel@tonic-gate };
710Sstevel@tonic-gate 
720Sstevel@tonic-gate static vfsdef_t vfw = {
730Sstevel@tonic-gate 	VFSDEF_VERSION,
740Sstevel@tonic-gate 	"objfs",
750Sstevel@tonic-gate 	objfs_init,
76*12633Sjohn.levon@sun.com 	VSW_HASPROTO | VSW_ZMOUNT,
770Sstevel@tonic-gate 	&objfs_mntopts,
780Sstevel@tonic-gate };
790Sstevel@tonic-gate 
800Sstevel@tonic-gate extern struct mod_ops mod_fsops;
810Sstevel@tonic-gate 
820Sstevel@tonic-gate static struct modlfs modlfs = {
830Sstevel@tonic-gate 	&mod_fsops, "kernel object filesystem", &vfw
840Sstevel@tonic-gate };
850Sstevel@tonic-gate 
860Sstevel@tonic-gate static struct modlinkage modlinkage = {
870Sstevel@tonic-gate 	MODREV_1, (void *)&modlfs, NULL
880Sstevel@tonic-gate };
890Sstevel@tonic-gate 
900Sstevel@tonic-gate int
_init(void)910Sstevel@tonic-gate _init(void)
920Sstevel@tonic-gate {
930Sstevel@tonic-gate 	return (mod_install(&modlinkage));
940Sstevel@tonic-gate }
950Sstevel@tonic-gate 
960Sstevel@tonic-gate int
_info(struct modinfo * modinfop)970Sstevel@tonic-gate _info(struct modinfo *modinfop)
980Sstevel@tonic-gate {
990Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
1000Sstevel@tonic-gate }
1010Sstevel@tonic-gate 
1020Sstevel@tonic-gate int
_fini(void)1030Sstevel@tonic-gate _fini(void)
1040Sstevel@tonic-gate {
1050Sstevel@tonic-gate 	/*
1060Sstevel@tonic-gate 	 * The object filesystem cannot be unloaded.
1070Sstevel@tonic-gate 	 */
1080Sstevel@tonic-gate 	return (EBUSY);
1090Sstevel@tonic-gate }
1100Sstevel@tonic-gate 
1110Sstevel@tonic-gate /*
1120Sstevel@tonic-gate  * Filesystem initialization.
1130Sstevel@tonic-gate  */
1140Sstevel@tonic-gate 
1150Sstevel@tonic-gate static int objfs_fstype;
1160Sstevel@tonic-gate static major_t objfs_major;
1170Sstevel@tonic-gate static minor_t objfs_minor;
1180Sstevel@tonic-gate 
1190Sstevel@tonic-gate static gfs_opsvec_t objfs_opsvec[] = {
1200Sstevel@tonic-gate 	{ "objfs root directory", objfs_tops_root, &objfs_ops_root },
1210Sstevel@tonic-gate 	{ "objfs object directory", objfs_tops_odir, &objfs_ops_odir },
1220Sstevel@tonic-gate 	{ "objfs data file", objfs_tops_data, &objfs_ops_data },
1230Sstevel@tonic-gate 	{ NULL }
1240Sstevel@tonic-gate };
1250Sstevel@tonic-gate 
1260Sstevel@tonic-gate /* ARGSUSED */
1270Sstevel@tonic-gate static int
objfs_init(int fstype,char * name)1280Sstevel@tonic-gate objfs_init(int fstype, char *name)
1290Sstevel@tonic-gate {
1300Sstevel@tonic-gate 	vfsops_t *vfsops;
1310Sstevel@tonic-gate 	int error;
1320Sstevel@tonic-gate 
1330Sstevel@tonic-gate 	objfs_fstype = fstype;
1340Sstevel@tonic-gate 	if (error = vfs_setfsops(fstype, objfs_vfstops, &vfsops)) {
1350Sstevel@tonic-gate 		cmn_err(CE_WARN, "objfs_init: bad vfs ops template");
1360Sstevel@tonic-gate 		return (error);
1370Sstevel@tonic-gate 	}
1380Sstevel@tonic-gate 
1390Sstevel@tonic-gate 	if (error = gfs_make_opsvec(objfs_opsvec)) {
1400Sstevel@tonic-gate 		(void) vfs_freevfsops(vfsops);
1410Sstevel@tonic-gate 		return (error);
1420Sstevel@tonic-gate 	}
1430Sstevel@tonic-gate 
1440Sstevel@tonic-gate 	if ((objfs_major = getudev()) == (major_t)-1) {
1450Sstevel@tonic-gate 		cmn_err(CE_WARN, "objfs_init: can't get unique device number");
1460Sstevel@tonic-gate 		objfs_major = 0;
1470Sstevel@tonic-gate 	}
1480Sstevel@tonic-gate 
1490Sstevel@tonic-gate 	objfs_data_init();
1500Sstevel@tonic-gate 
1510Sstevel@tonic-gate 	return (0);
1520Sstevel@tonic-gate }
1530Sstevel@tonic-gate 
1540Sstevel@tonic-gate /*
1550Sstevel@tonic-gate  * VFS entry points
1560Sstevel@tonic-gate  */
1570Sstevel@tonic-gate static int
objfs_mount(vfs_t * vfsp,vnode_t * mvp,struct mounta * uap,cred_t * cr)1580Sstevel@tonic-gate objfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
1590Sstevel@tonic-gate {
1600Sstevel@tonic-gate 	objfs_vfs_t *data;
1610Sstevel@tonic-gate 	dev_t dev;
1620Sstevel@tonic-gate 
1630Sstevel@tonic-gate 	if (secpolicy_fs_mount(cr, mvp, vfsp) != 0)
1640Sstevel@tonic-gate 		return (EPERM);
1650Sstevel@tonic-gate 
1660Sstevel@tonic-gate 	if (mvp->v_type != VDIR)
1670Sstevel@tonic-gate 		return (ENOTDIR);
1680Sstevel@tonic-gate 
1690Sstevel@tonic-gate 	if ((uap->flags & MS_OVERLAY) == 0 &&
1700Sstevel@tonic-gate 	    (mvp->v_count > 1 || (mvp->v_flag & VROOT)))
1710Sstevel@tonic-gate 		return (EBUSY);
1720Sstevel@tonic-gate 
1730Sstevel@tonic-gate 	data = kmem_alloc(sizeof (objfs_vfs_t), KM_SLEEP);
1740Sstevel@tonic-gate 
1750Sstevel@tonic-gate 	/*
1760Sstevel@tonic-gate 	 * Initialize vfs fields
1770Sstevel@tonic-gate 	 */
1780Sstevel@tonic-gate 	vfsp->vfs_bsize = DEV_BSIZE;
1790Sstevel@tonic-gate 	vfsp->vfs_fstype = objfs_fstype;
1800Sstevel@tonic-gate 	do {
1810Sstevel@tonic-gate 		dev = makedevice(objfs_major,
1820Sstevel@tonic-gate 		    atomic_add_32_nv(&objfs_minor, 1) & L_MAXMIN32);
1830Sstevel@tonic-gate 	} while (vfs_devismounted(dev));
1840Sstevel@tonic-gate 	vfs_make_fsid(&vfsp->vfs_fsid, dev, objfs_fstype);
1850Sstevel@tonic-gate 	vfsp->vfs_data = data;
1860Sstevel@tonic-gate 	vfsp->vfs_dev = dev;
1870Sstevel@tonic-gate 
1880Sstevel@tonic-gate 	/*
1890Sstevel@tonic-gate 	 * Create root
1900Sstevel@tonic-gate 	 */
1910Sstevel@tonic-gate 	data->objfs_vfs_root = objfs_create_root(vfsp);
1920Sstevel@tonic-gate 
1930Sstevel@tonic-gate 	return (0);
1940Sstevel@tonic-gate }
1950Sstevel@tonic-gate 
1960Sstevel@tonic-gate static int
objfs_unmount(vfs_t * vfsp,int flag,struct cred * cr)1970Sstevel@tonic-gate objfs_unmount(vfs_t *vfsp, int flag, struct cred *cr)
1980Sstevel@tonic-gate {
1990Sstevel@tonic-gate 	objfs_vfs_t *data;
2000Sstevel@tonic-gate 
2010Sstevel@tonic-gate 	if (secpolicy_fs_unmount(cr, vfsp) != 0)
2020Sstevel@tonic-gate 		return (EPERM);
2030Sstevel@tonic-gate 
2040Sstevel@tonic-gate 	/*
2050Sstevel@tonic-gate 	 * We do not currently support forced unmounts
2060Sstevel@tonic-gate 	 */
2070Sstevel@tonic-gate 	if (flag & MS_FORCE)
2080Sstevel@tonic-gate 		return (ENOTSUP);
2090Sstevel@tonic-gate 
2100Sstevel@tonic-gate 	/*
2110Sstevel@tonic-gate 	 * We should never have a reference count of less than 2: one for the
2120Sstevel@tonic-gate 	 * caller, one for the root vnode.
2130Sstevel@tonic-gate 	 */
2140Sstevel@tonic-gate 	ASSERT(vfsp->vfs_count >= 2);
2150Sstevel@tonic-gate 
2160Sstevel@tonic-gate 	/*
2170Sstevel@tonic-gate 	 * Any active vnodes will result in a hold on the root vnode
2180Sstevel@tonic-gate 	 */
2190Sstevel@tonic-gate 	data = vfsp->vfs_data;
2200Sstevel@tonic-gate 	if (data->objfs_vfs_root->v_count > 1)
2210Sstevel@tonic-gate 		return (EBUSY);
2220Sstevel@tonic-gate 
2230Sstevel@tonic-gate 	/*
2240Sstevel@tonic-gate 	 * Release the last hold on the root vnode
2250Sstevel@tonic-gate 	 */
2260Sstevel@tonic-gate 	VN_RELE(data->objfs_vfs_root);
2270Sstevel@tonic-gate 
2280Sstevel@tonic-gate 	kmem_free(data, sizeof (objfs_vfs_t));
2290Sstevel@tonic-gate 
2300Sstevel@tonic-gate 	return (0);
2310Sstevel@tonic-gate }
2320Sstevel@tonic-gate 
2330Sstevel@tonic-gate static int
objfs_root(vfs_t * vfsp,vnode_t ** vpp)2340Sstevel@tonic-gate objfs_root(vfs_t *vfsp, vnode_t **vpp)
2350Sstevel@tonic-gate {
2360Sstevel@tonic-gate 	objfs_vfs_t *data = vfsp->vfs_data;
2370Sstevel@tonic-gate 
2380Sstevel@tonic-gate 	*vpp = data->objfs_vfs_root;
2390Sstevel@tonic-gate 	VN_HOLD(*vpp);
2400Sstevel@tonic-gate 
2410Sstevel@tonic-gate 	return (0);
2420Sstevel@tonic-gate }
2430Sstevel@tonic-gate 
2440Sstevel@tonic-gate static int
objfs_statvfs(vfs_t * vfsp,statvfs64_t * sp)2450Sstevel@tonic-gate objfs_statvfs(vfs_t *vfsp, statvfs64_t *sp)
2460Sstevel@tonic-gate {
2470Sstevel@tonic-gate 	dev32_t d32;
2480Sstevel@tonic-gate 	int total = objfs_nobjs();
2490Sstevel@tonic-gate 
2500Sstevel@tonic-gate 	bzero(sp, sizeof (*sp));
2510Sstevel@tonic-gate 	sp->f_bsize = DEV_BSIZE;
2520Sstevel@tonic-gate 	sp->f_frsize = DEV_BSIZE;
2530Sstevel@tonic-gate 	sp->f_files = total;
2540Sstevel@tonic-gate 	sp->f_ffree = sp->f_favail = INT_MAX - total;
2550Sstevel@tonic-gate 	(void) cmpldev(&d32, vfsp->vfs_dev);
2560Sstevel@tonic-gate 	sp->f_fsid = d32;
2570Sstevel@tonic-gate 	(void) strlcpy(sp->f_basetype, vfssw[vfsp->vfs_fstype].vsw_name,
2580Sstevel@tonic-gate 	    sizeof (sp->f_basetype));
2590Sstevel@tonic-gate 	sp->f_flag = vf_to_stf(vfsp->vfs_flag);
2600Sstevel@tonic-gate 	sp->f_namemax = OBJFS_NAME_MAX;
2610Sstevel@tonic-gate 	(void) strlcpy(sp->f_fstr, "object", sizeof (sp->f_fstr));
2620Sstevel@tonic-gate 
2630Sstevel@tonic-gate 	return (0);
2640Sstevel@tonic-gate }
2650Sstevel@tonic-gate 
2660Sstevel@tonic-gate static const fs_operation_def_t objfs_vfstops[] = {
2673898Srsb 	{ VFSNAME_MOUNT,	{ .vfs_mount = objfs_mount } },
2683898Srsb 	{ VFSNAME_UNMOUNT,	{ .vfs_unmount = objfs_unmount } },
2693898Srsb 	{ VFSNAME_ROOT,		{ .vfs_root = objfs_root } },
2703898Srsb 	{ VFSNAME_STATVFS,	{ .vfs_statvfs = objfs_statvfs } },
2710Sstevel@tonic-gate 	{ NULL }
2720Sstevel@tonic-gate };
273