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 /* 29 * lxprvfsops.c: vfs operations for /lxprocfs. 30 */ 31 32 #include <sys/types.h> 33 #include <sys/param.h> 34 #include <sys/cmn_err.h> 35 #include <sys/cred.h> 36 #include <sys/debug.h> 37 #include <sys/errno.h> 38 #include <sys/proc.h> 39 #include <sys/stat.h> 40 #include <sys/statvfs.h> 41 #include <sys/sysmacros.h> 42 #include <sys/systm.h> 43 #include <sys/var.h> 44 #include <sys/vfs.h> 45 #include <sys/vfs_opreg.h> 46 #include <sys/vnode.h> 47 #include <sys/mode.h> 48 #include <sys/signal.h> 49 #include <sys/user.h> 50 #include <sys/mount.h> 51 #include <sys/bitmap.h> 52 #include <sys/kmem.h> 53 #include <sys/policy.h> 54 #include <sys/modctl.h> 55 #include <sys/sunddi.h> 56 #include <sys/sunldi.h> 57 #include <sys/lx_impl.h> 58 59 #include "lx_proc.h" 60 61 /* Module level parameters */ 62 static int lxprocfstype; 63 static dev_t lxprocdev; 64 static kmutex_t lxpr_mount_lock; 65 66 int nproc_highbit; /* highbit(v.v_nproc) */ 67 68 static int lxpr_mount(vfs_t *, vnode_t *, mounta_t *, cred_t *); 69 static int lxpr_unmount(vfs_t *, int, cred_t *); 70 static int lxpr_root(vfs_t *, vnode_t **); 71 static int lxpr_statvfs(vfs_t *, statvfs64_t *); 72 static int lxpr_init(int, char *); 73 74 static vfsdef_t vfw = { 75 VFSDEF_VERSION, 76 "lx_proc", 77 lxpr_init, 78 VSW_ZMOUNT, 79 NULL 80 }; 81 82 /* 83 * Module linkage information for the kernel. 84 */ 85 extern struct mod_ops mod_fsops; 86 87 static struct modlfs modlfs = { 88 &mod_fsops, "generic linux procfs", &vfw 89 }; 90 91 static struct modlinkage modlinkage = { 92 MODREV_1, (void *)&modlfs, NULL 93 }; 94 95 int 96 _init(void) 97 { 98 return (mod_install(&modlinkage)); 99 } 100 101 int 102 _info(struct modinfo *modinfop) 103 { 104 return (mod_info(&modlinkage, modinfop)); 105 } 106 107 int 108 _fini(void) 109 { 110 int retval; 111 112 /* 113 * attempt to unload the module 114 */ 115 if ((retval = mod_remove(&modlinkage)) != 0) 116 goto done; 117 118 /* 119 * destroy lxpr_node cache 120 */ 121 lxpr_fininodecache(); 122 123 /* 124 * clean out the vfsops and vnodeops 125 */ 126 (void) vfs_freevfsops_by_type(lxprocfstype); 127 vn_freevnodeops(lxpr_vnodeops); 128 129 mutex_destroy(&lxpr_mount_lock); 130 done: 131 return (retval); 132 } 133 134 static int 135 lxpr_init(int fstype, char *name) 136 { 137 static const fs_operation_def_t lxpr_vfsops_template[] = { 138 VFSNAME_MOUNT, { .vfs_mount = lxpr_mount }, 139 VFSNAME_UNMOUNT, { .vfs_unmount = lxpr_unmount }, 140 VFSNAME_ROOT, { .vfs_root = lxpr_root }, 141 VFSNAME_STATVFS, { .vfs_statvfs = lxpr_statvfs }, 142 NULL, NULL 143 }; 144 extern const fs_operation_def_t lxpr_vnodeops_template[]; 145 int error; 146 major_t dev; 147 148 nproc_highbit = highbit(v.v_proc); 149 lxprocfstype = fstype; 150 ASSERT(lxprocfstype != 0); 151 152 mutex_init(&lxpr_mount_lock, NULL, MUTEX_DEFAULT, NULL); 153 154 /* 155 * Associate VFS ops vector with this fstype. 156 */ 157 error = vfs_setfsops(fstype, lxpr_vfsops_template, NULL); 158 if (error != 0) { 159 cmn_err(CE_WARN, "lxpr_init: bad vfs ops template"); 160 return (error); 161 } 162 163 /* 164 * Set up vnode ops vector too. 165 */ 166 error = vn_make_ops(name, lxpr_vnodeops_template, &lxpr_vnodeops); 167 if (error != 0) { 168 (void) vfs_freevfsops_by_type(fstype); 169 cmn_err(CE_WARN, "lxpr_init: bad vnode ops template"); 170 return (error); 171 } 172 173 /* 174 * Assign a unique "device" number (used by stat(2)). 175 */ 176 if ((dev = getudev()) == (major_t)-1) { 177 cmn_err(CE_WARN, "lxpr_init: can't get unique device number"); 178 dev = 0; 179 } 180 181 /* 182 * Make the pseudo device 183 */ 184 lxprocdev = makedevice(dev, 0); 185 186 /* 187 * Initialise cache for lxpr_nodes 188 */ 189 lxpr_initnodecache(); 190 191 return (0); 192 } 193 194 static int 195 lxpr_mount(vfs_t *vfsp, vnode_t *mvp, mounta_t *uap, cred_t *cr) 196 { 197 lxpr_mnt_t *lxpr_mnt; 198 zone_t *zone = curproc->p_zone; 199 ldi_ident_t li; 200 int err; 201 202 /* 203 * must be root to mount 204 */ 205 if (secpolicy_fs_mount(cr, mvp, vfsp) != 0) 206 return (EPERM); 207 208 /* 209 * mount point must be a directory 210 */ 211 if (mvp->v_type != VDIR) 212 return (ENOTDIR); 213 214 if (zone == global_zone) { 215 zone_t *mntzone; 216 217 mntzone = zone_find_by_path(refstr_value(vfsp->vfs_mntpt)); 218 zone_rele(mntzone); 219 if (zone != mntzone) 220 return (EBUSY); 221 } 222 223 /* 224 * Having the resource be anything but "lxproc" doesn't make sense 225 */ 226 vfs_setresource(vfsp, "lxproc",0); 227 228 lxpr_mnt = kmem_alloc(sizeof (*lxpr_mnt), KM_SLEEP); 229 230 if ((err = ldi_ident_from_mod(&modlinkage, &li)) != 0) { 231 kmem_free(lxpr_mnt, sizeof (*lxpr_mnt)); 232 return (err); 233 } 234 235 lxpr_mnt->lxprm_li = li; 236 237 mutex_enter(&lxpr_mount_lock); 238 239 /* 240 * Ensure we don't allow overlaying mounts 241 */ 242 mutex_enter(&mvp->v_lock); 243 if ((uap->flags & MS_OVERLAY) == 0 && 244 (mvp->v_count > 1 || (mvp->v_flag & VROOT))) { 245 mutex_exit(&mvp->v_lock); 246 mutex_exit(&lxpr_mount_lock); 247 kmem_free(lxpr_mnt, sizeof ((*lxpr_mnt))); 248 return (EBUSY); 249 } 250 mutex_exit(&mvp->v_lock); 251 252 /* 253 * allocate the first vnode 254 */ 255 zone_hold(lxpr_mnt->lxprm_zone = zone); 256 257 /* Arbitrarily set the parent vnode to the mounted over directory */ 258 lxpr_mnt->lxprm_node = lxpr_getnode(mvp, LXPR_PROCDIR, NULL, 0); 259 260 /* Correctly set the fs for the root node */ 261 lxpr_mnt->lxprm_node->lxpr_vnode->v_vfsp = vfsp; 262 263 vfs_make_fsid(&vfsp->vfs_fsid, lxprocdev, lxprocfstype); 264 vfsp->vfs_bsize = DEV_BSIZE; 265 vfsp->vfs_fstype = lxprocfstype; 266 vfsp->vfs_data = (caddr_t)lxpr_mnt; 267 vfsp->vfs_dev = lxprocdev; 268 269 mutex_exit(&lxpr_mount_lock); 270 271 return (0); 272 } 273 274 static int 275 lxpr_unmount(vfs_t *vfsp, int flag, cred_t *cr) 276 { 277 lxpr_mnt_t *lxpr_mnt = (lxpr_mnt_t *)vfsp->vfs_data; 278 vnode_t *vp; 279 int count; 280 281 ASSERT(lxpr_mnt != NULL); 282 vp = LXPTOV(lxpr_mnt->lxprm_node); 283 284 mutex_enter(&lxpr_mount_lock); 285 286 /* 287 * must be root to unmount 288 */ 289 if (secpolicy_fs_unmount(cr, vfsp) != 0) { 290 mutex_exit(&lxpr_mount_lock); 291 return (EPERM); 292 } 293 294 /* 295 * forced unmount is not supported by this file system 296 */ 297 if (flag & MS_FORCE) { 298 mutex_exit(&lxpr_mount_lock); 299 return (ENOTSUP); 300 } 301 302 /* 303 * Ensure that no vnodes are in use on this mount point. 304 */ 305 mutex_enter(&vp->v_lock); 306 count = vp->v_count; 307 mutex_exit(&vp->v_lock); 308 if (count > 1) { 309 mutex_exit(&lxpr_mount_lock); 310 return (EBUSY); 311 } 312 313 314 /* 315 * purge the dnlc cache for vnode entries 316 * associated with this file system 317 */ 318 count = dnlc_purge_vfsp(vfsp, 0); 319 320 /* 321 * free up the lxprnode 322 */ 323 lxpr_freenode(lxpr_mnt->lxprm_node); 324 zone_rele(lxpr_mnt->lxprm_zone); 325 kmem_free(lxpr_mnt, sizeof (*lxpr_mnt)); 326 327 mutex_exit(&lxpr_mount_lock); 328 329 return (0); 330 } 331 332 static int 333 lxpr_root(vfs_t *vfsp, vnode_t **vpp) 334 { 335 lxpr_node_t *lxpnp = ((lxpr_mnt_t *)vfsp->vfs_data)->lxprm_node; 336 vnode_t *vp = LXPTOV(lxpnp); 337 338 VN_HOLD(vp); 339 *vpp = vp; 340 return (0); 341 } 342 343 static int 344 lxpr_statvfs(vfs_t *vfsp, statvfs64_t *sp) 345 { 346 int n; 347 dev32_t d32; 348 extern uint_t nproc; 349 350 n = v.v_proc - nproc; 351 352 bzero((caddr_t)sp, sizeof (*sp)); 353 sp->f_bsize = DEV_BSIZE; 354 sp->f_frsize = DEV_BSIZE; 355 sp->f_blocks = (fsblkcnt64_t)0; 356 sp->f_bfree = (fsblkcnt64_t)0; 357 sp->f_bavail = (fsblkcnt64_t)0; 358 sp->f_files = (fsfilcnt64_t)v.v_proc + 2; 359 sp->f_ffree = (fsfilcnt64_t)n; 360 sp->f_favail = (fsfilcnt64_t)n; 361 (void) cmpldev(&d32, vfsp->vfs_dev); 362 sp->f_fsid = d32; 363 /* It is guaranteed that vsw_name will fit in f_basetype */ 364 (void) strcpy(sp->f_basetype, vfssw[lxprocfstype].vsw_name); 365 sp->f_flag = vf_to_stf(vfsp->vfs_flag); 366 sp->f_namemax = 64; /* quite arbitrary */ 367 bzero(sp->f_fstr, sizeof (sp->f_fstr)); 368 369 /* We know f_fstr is 32 chars */ 370 (void) strcpy(sp->f_fstr, "/proc"); 371 (void) strcpy(&sp->f_fstr[6], "/proc"); 372 373 return (0); 374 }