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