Home | History | Annotate | Download | only in objfs
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     27 
     28 #include <sys/atomic.h>
     29 #include <sys/cmn_err.h>
     30 #include <sys/errno.h>
     31 #include <sys/mount.h>
     32 #include <sys/objfs.h>
     33 #include <sys/objfs_impl.h>
     34 #include <sys/vfs_opreg.h>
     35 #include <sys/policy.h>
     36 #include <sys/sunddi.h>
     37 #include <sys/sysmacros.h>
     38 #include <sys/systm.h>
     39 
     40 /*
     41  * Kernel object filesystem.
     42  *
     43  * This is a pseudo filesystem which exports information about currently loaded
     44  * kernel objects.  The root directory contains one directory for each loaded
     45  * object, indexed by module name.  Within each object directory is an ELF file,
     46  * 'object', that contains information about the currently loaded module.
     47  *
     48  * This file contains functions that interact with the VFS layer.  Each
     49  * filesystem element is represented by a a different node.
     50  *
     51  * 	/		objfs_rootnode_t	objfs_root.c
     52  *	/<obj>		objfs_odirnode_t	objfs_odir.c
     53  *	/<obj>/object	objfs_datanode_t	objfs_data.c
     54  *
     55  * In addition, some common routines are found in the 'objfs_common.c' file.
     56  */
     57 
     58 vnodeops_t *objfs_ops_root;
     59 vnodeops_t *objfs_ops_odir;
     60 vnodeops_t *objfs_ops_data;
     61 
     62 static const fs_operation_def_t objfs_vfstops[];
     63 static gfs_opsvec_t objfs_opsvec[];
     64 
     65 static int objfs_init(int, char *);
     66 
     67 /*
     68  * Module linkage
     69  */
     70 static mntopts_t objfs_mntopts = {
     71 	0,
     72 	NULL
     73 };
     74 
     75 static vfsdef_t vfw = {
     76 	VFSDEF_VERSION,
     77 	"objfs",
     78 	objfs_init,
     79 	VSW_HASPROTO,
     80 	&objfs_mntopts,
     81 };
     82 
     83 extern struct mod_ops mod_fsops;
     84 
     85 static struct modlfs modlfs = {
     86 	&mod_fsops, "kernel object filesystem", &vfw
     87 };
     88 
     89 static struct modlinkage modlinkage = {
     90 	MODREV_1, (void *)&modlfs, NULL
     91 };
     92 
     93 int
     94 _init(void)
     95 {
     96 	return (mod_install(&modlinkage));
     97 }
     98 
     99 int
    100 _info(struct modinfo *modinfop)
    101 {
    102 	return (mod_info(&modlinkage, modinfop));
    103 }
    104 
    105 int
    106 _fini(void)
    107 {
    108 	/*
    109 	 * The object filesystem cannot be unloaded.
    110 	 */
    111 	return (EBUSY);
    112 }
    113 
    114 /*
    115  * Filesystem initialization.
    116  */
    117 
    118 static int objfs_fstype;
    119 static major_t objfs_major;
    120 static minor_t objfs_minor;
    121 
    122 static gfs_opsvec_t objfs_opsvec[] = {
    123 	{ "objfs root directory", objfs_tops_root, &objfs_ops_root },
    124 	{ "objfs object directory", objfs_tops_odir, &objfs_ops_odir },
    125 	{ "objfs data file", objfs_tops_data, &objfs_ops_data },
    126 	{ NULL }
    127 };
    128 
    129 /* ARGSUSED */
    130 static int
    131 objfs_init(int fstype, char *name)
    132 {
    133 	vfsops_t *vfsops;
    134 	int error;
    135 
    136 	objfs_fstype = fstype;
    137 	if (error = vfs_setfsops(fstype, objfs_vfstops, &vfsops)) {
    138 		cmn_err(CE_WARN, "objfs_init: bad vfs ops template");
    139 		return (error);
    140 	}
    141 
    142 	if (error = gfs_make_opsvec(objfs_opsvec)) {
    143 		(void) vfs_freevfsops(vfsops);
    144 		return (error);
    145 	}
    146 
    147 	if ((objfs_major = getudev()) == (major_t)-1) {
    148 		cmn_err(CE_WARN, "objfs_init: can't get unique device number");
    149 		objfs_major = 0;
    150 	}
    151 
    152 	objfs_data_init();
    153 
    154 	return (0);
    155 }
    156 
    157 /*
    158  * VFS entry points
    159  */
    160 static int
    161 objfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
    162 {
    163 	objfs_vfs_t *data;
    164 	dev_t dev;
    165 
    166 	if (secpolicy_fs_mount(cr, mvp, vfsp) != 0)
    167 		return (EPERM);
    168 
    169 	if (mvp->v_type != VDIR)
    170 		return (ENOTDIR);
    171 
    172 	if ((uap->flags & MS_OVERLAY) == 0 &&
    173 	    (mvp->v_count > 1 || (mvp->v_flag & VROOT)))
    174 		return (EBUSY);
    175 
    176 	data = kmem_alloc(sizeof (objfs_vfs_t), KM_SLEEP);
    177 
    178 	/*
    179 	 * Initialize vfs fields
    180 	 */
    181 	vfsp->vfs_bsize = DEV_BSIZE;
    182 	vfsp->vfs_fstype = objfs_fstype;
    183 	do {
    184 		dev = makedevice(objfs_major,
    185 		    atomic_add_32_nv(&objfs_minor, 1) & L_MAXMIN32);
    186 	} while (vfs_devismounted(dev));
    187 	vfs_make_fsid(&vfsp->vfs_fsid, dev, objfs_fstype);
    188 	vfsp->vfs_data = data;
    189 	vfsp->vfs_dev = dev;
    190 
    191 	/*
    192 	 * Create root
    193 	 */
    194 	data->objfs_vfs_root = objfs_create_root(vfsp);
    195 
    196 	return (0);
    197 }
    198 
    199 static int
    200 objfs_unmount(vfs_t *vfsp, int flag, struct cred *cr)
    201 {
    202 	objfs_vfs_t *data;
    203 
    204 	if (secpolicy_fs_unmount(cr, vfsp) != 0)
    205 		return (EPERM);
    206 
    207 	/*
    208 	 * We do not currently support forced unmounts
    209 	 */
    210 	if (flag & MS_FORCE)
    211 		return (ENOTSUP);
    212 
    213 	/*
    214 	 * We should never have a reference count of less than 2: one for the
    215 	 * caller, one for the root vnode.
    216 	 */
    217 	ASSERT(vfsp->vfs_count >= 2);
    218 
    219 	/*
    220 	 * Any active vnodes will result in a hold on the root vnode
    221 	 */
    222 	data = vfsp->vfs_data;
    223 	if (data->objfs_vfs_root->v_count > 1)
    224 		return (EBUSY);
    225 
    226 	/*
    227 	 * Release the last hold on the root vnode
    228 	 */
    229 	VN_RELE(data->objfs_vfs_root);
    230 
    231 	kmem_free(data, sizeof (objfs_vfs_t));
    232 
    233 	return (0);
    234 }
    235 
    236 static int
    237 objfs_root(vfs_t *vfsp, vnode_t **vpp)
    238 {
    239 	objfs_vfs_t *data = vfsp->vfs_data;
    240 
    241 	*vpp = data->objfs_vfs_root;
    242 	VN_HOLD(*vpp);
    243 
    244 	return (0);
    245 }
    246 
    247 static int
    248 objfs_statvfs(vfs_t *vfsp, statvfs64_t *sp)
    249 {
    250 	dev32_t d32;
    251 	int total = objfs_nobjs();
    252 
    253 	bzero(sp, sizeof (*sp));
    254 	sp->f_bsize = DEV_BSIZE;
    255 	sp->f_frsize = DEV_BSIZE;
    256 	sp->f_files = total;
    257 	sp->f_ffree = sp->f_favail = INT_MAX - total;
    258 	(void) cmpldev(&d32, vfsp->vfs_dev);
    259 	sp->f_fsid = d32;
    260 	(void) strlcpy(sp->f_basetype, vfssw[vfsp->vfs_fstype].vsw_name,
    261 	    sizeof (sp->f_basetype));
    262 	sp->f_flag = vf_to_stf(vfsp->vfs_flag);
    263 	sp->f_namemax = OBJFS_NAME_MAX;
    264 	(void) strlcpy(sp->f_fstr, "object", sizeof (sp->f_fstr));
    265 
    266 	return (0);
    267 }
    268 
    269 static const fs_operation_def_t objfs_vfstops[] = {
    270 	{ VFSNAME_MOUNT,	{ .vfs_mount = objfs_mount } },
    271 	{ VFSNAME_UNMOUNT,	{ .vfs_unmount = objfs_unmount } },
    272 	{ VFSNAME_ROOT,		{ .vfs_root = objfs_root } },
    273 	{ VFSNAME_STATVFS,	{ .vfs_statvfs = objfs_statvfs } },
    274 	{ NULL }
    275 };
    276