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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <sys/atomic.h> 30 #include <sys/cmn_err.h> 31 #include <sys/errno.h> 32 #include <sys/mount.h> 33 #include <sys/objfs.h> 34 #include <sys/objfs_impl.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, objfs_mount }, 271 { VFSNAME_UNMOUNT, objfs_unmount }, 272 { VFSNAME_ROOT, objfs_root }, 273 { VFSNAME_STATVFS, objfs_statvfs }, 274 { NULL } 275 }; 276