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 * This is the /dev (hence, the sdev_ prefix) filesystem. 30 */ 31 32 #include <sys/types.h> 33 #include <sys/param.h> 34 #include <sys/sysmacros.h> 35 #include <sys/systm.h> 36 #include <sys/kmem.h> 37 #include <sys/time.h> 38 #include <sys/pathname.h> 39 #include <sys/vfs.h> 40 #include <sys/vnode.h> 41 #include <sys/file.h> 42 #include <sys/stat.h> 43 #include <sys/uio.h> 44 #include <sys/stat.h> 45 #include <sys/errno.h> 46 #include <sys/cmn_err.h> 47 #include <sys/cred.h> 48 #include <sys/statvfs.h> 49 #include <sys/policy.h> 50 #include <sys/mount.h> 51 #include <sys/debug.h> 52 #include <sys/modctl.h> 53 #include <sys/mkdev.h> 54 #include <fs/fs_subr.h> 55 #include <sys/fs/sdev_impl.h> 56 #include <sys/fs/sdev_node.h> 57 #include <sys/fs/snode.h> 58 #include <sys/fs/dv_node.h> 59 #include <sys/sunndi.h> 60 #include <sys/mntent.h> 61 62 /* 63 * /dev vfs operations. 64 */ 65 66 /* 67 * globals 68 */ 69 struct sdev_data *sdev_origins; /* mount info for origins under /dev */ 70 kmutex_t sdev_lock; /* used for mount/unmount/rename synchronization */ 71 72 /* 73 * static 74 */ 75 static major_t devmajor; /* the fictitious major we live on */ 76 static major_t devminor; /* the fictitious minor of this instance */ 77 static struct sdev_data *sdev_mntinfo = NULL; /* linked list of instances */ 78 79 /* LINTED E_STATIC_UNUSED */ /* useful for debugging */ 80 static struct vnode *sdev_stale_attrvp; /* stale root attrvp after remount */ 81 82 static int sdev_mount(struct vfs *, struct vnode *, struct mounta *, 83 struct cred *); 84 static int sdev_unmount(struct vfs *, int, struct cred *); 85 static int sdev_root(struct vfs *, struct vnode **); 86 static int sdev_statvfs(struct vfs *, struct statvfs64 *); 87 static void sdev_insert_mntinfo(struct sdev_data *); 88 static int devinit(int, char *); 89 90 static vfsdef_t sdev_vfssw = { 91 VFSDEF_VERSION, 92 "dev", /* type name string */ 93 devinit, /* init routine */ 94 VSW_CANREMOUNT, /* flags */ 95 NULL /* mount options table prototype */ 96 }; 97 98 99 /* 100 * Module linkage information 101 */ 102 static struct modlfs modlfs = { 103 &mod_fsops, "/dev filesystem %I%", &sdev_vfssw 104 }; 105 106 static struct modlinkage modlinkage = { 107 MODREV_1, (void *)&modlfs, NULL 108 }; 109 110 int 111 _init(void) 112 { 113 int e; 114 115 mutex_init(&sdev_lock, NULL, MUTEX_DEFAULT, NULL); 116 sdev_node_cache_init(); 117 sdev_devfsadm_lockinit(); 118 if ((e = mod_install(&modlinkage)) != 0) { 119 sdev_devfsadm_lockdestroy(); 120 sdev_node_cache_fini(); 121 mutex_destroy(&sdev_lock); 122 return (e); 123 } 124 return (0); 125 } 126 127 /* 128 * dev module remained loaded for the global /dev instance 129 */ 130 int 131 _fini(void) 132 { 133 return (EBUSY); 134 } 135 136 int 137 _info(struct modinfo *modinfop) 138 { 139 return (mod_info(&modlinkage, modinfop)); 140 } 141 142 /*ARGSUSED*/ 143 static int 144 devinit(int fstype, char *name) 145 { 146 static const fs_operation_def_t dev_vfsops_tbl[] = { 147 VFSNAME_MOUNT, sdev_mount, /* mount file system */ 148 VFSNAME_UNMOUNT, sdev_unmount, /* unmount file system */ 149 VFSNAME_ROOT, sdev_root, /* get root vnode */ 150 VFSNAME_STATVFS, sdev_statvfs, /* get file system statistics */ 151 NULL, NULL 152 }; 153 154 int error; 155 extern major_t getudev(void); 156 157 devtype = fstype; 158 159 error = vfs_setfsops(fstype, dev_vfsops_tbl, NULL); 160 if (error != 0) { 161 cmn_err(CE_WARN, "devinit: bad vfs ops tbl"); 162 return (error); 163 } 164 165 error = vn_make_ops("dev", sdev_vnodeops_tbl, &sdev_vnodeops); 166 if (error != 0) { 167 (void) vfs_freevfsops_by_type(fstype); 168 cmn_err(CE_WARN, "devinit: bad vnode ops tbl"); 169 return (error); 170 } 171 172 if ((devmajor = getudev()) == (major_t)-1) { 173 cmn_err(CE_WARN, "%s: can't get unique dev", sdev_vfssw.name); 174 return (1); 175 } 176 177 /* initialize negative cache */ 178 sdev_ncache_init(); 179 180 return (0); 181 } 182 183 /* 184 * Both mount point and backing store directory name are 185 * passed in from userland 186 */ 187 static int 188 sdev_mount(struct vfs *vfsp, struct vnode *mvp, struct mounta *uap, 189 struct cred *cr) 190 { 191 struct sdev_data *sdev_data; 192 struct vnode *avp; 193 struct sdev_node *dv; 194 struct sdev_mountargs *args = NULL; 195 int error = 0; 196 dev_t devdev; 197 198 /* 199 * security check 200 */ 201 if ((secpolicy_fs_mount(cr, mvp, vfsp) != 0) || 202 (secpolicy_sys_devices(cr) != 0)) 203 return (EPERM); 204 205 /* 206 * Sanity check the mount point 207 */ 208 if (mvp->v_type != VDIR) 209 return (ENOTDIR); 210 211 /* 212 * Sanity Check for overlay mount. 213 */ 214 mutex_enter(&mvp->v_lock); 215 if ((uap->flags & MS_OVERLAY) == 0 && 216 (uap->flags & MS_REMOUNT) == 0 && 217 (mvp->v_count > 1 || (mvp->v_flag & VROOT))) { 218 mutex_exit(&mvp->v_lock); 219 return (EBUSY); 220 } 221 mutex_exit(&mvp->v_lock); 222 223 args = kmem_zalloc(sizeof (*args), KM_SLEEP); 224 225 if ((uap->flags & MS_DATA) && 226 (uap->datalen != 0 && uap->dataptr != NULL)) { 227 /* copy in the arguments */ 228 if (error = sdev_copyin_mountargs(uap, args)) 229 goto cleanup; 230 } 231 232 /* 233 * Sanity check the backing store 234 */ 235 if (args->sdev_attrdir) { 236 /* user supplied an attribute store */ 237 if (error = lookupname((char *)(uintptr_t)args->sdev_attrdir, 238 UIO_USERSPACE, FOLLOW, NULLVPP, &avp)) { 239 cmn_err(CE_NOTE, "/dev fs: lookup on attribute " 240 "directory %s failed", 241 (char *)(uintptr_t)args->sdev_attrdir); 242 goto cleanup; 243 } 244 245 if (avp->v_type != VDIR) { 246 VN_RELE(avp); 247 error = ENOTDIR; 248 goto cleanup; 249 } 250 } else { 251 /* use mountp as the attribute store */ 252 avp = mvp; 253 VN_HOLD(avp); 254 } 255 256 mutex_enter(&sdev_lock); 257 258 /* 259 * handling installation 260 */ 261 if (uap->flags & MS_REMOUNT) { 262 sdev_data = (struct sdev_data *)vfsp->vfs_data; 263 ASSERT(sdev_data); 264 265 dv = sdev_data->sdev_root; 266 ASSERT(dv == dv->sdev_dotdot); 267 268 /* 269 * mark all existing sdev_nodes (except root node) stale 270 */ 271 sdev_stale(dv); 272 273 /* Reset previous mountargs */ 274 if (sdev_data->sdev_mountargs) { 275 kmem_free(sdev_data->sdev_mountargs, 276 sizeof (struct sdev_mountargs)); 277 } 278 sdev_data->sdev_mountargs = args; 279 args = NULL; /* so it won't be freed below */ 280 281 sdev_stale_attrvp = dv->sdev_attrvp; 282 dv->sdev_attrvp = avp; 283 vfsp->vfs_mtime = ddi_get_time(); 284 285 mutex_exit(&sdev_lock); 286 goto cleanup; /* we're done */ 287 } 288 289 /* 290 * Create and initialize the vfs-private data. 291 */ 292 devdev = makedevice(devmajor, devminor); 293 while (vfs_devismounted(devdev)) { 294 devminor = (devminor + 1) & MAXMIN32; 295 296 /* 297 * All the minor numbers are used up. 298 */ 299 if (devminor == 0) { 300 mutex_exit(&sdev_lock); 301 VN_RELE(avp); 302 error = ENODEV; 303 goto cleanup; 304 } 305 306 devdev = makedevice(devmajor, devminor); 307 } 308 309 dv = sdev_mkroot(vfsp, devdev, mvp, avp, cr); 310 sdev_data = kmem_zalloc(sizeof (struct sdev_data), KM_SLEEP); 311 vfsp->vfs_dev = devdev; 312 vfsp->vfs_data = (caddr_t)sdev_data; 313 vfsp->vfs_fstype = devtype; 314 vfsp->vfs_bsize = DEV_BSIZE; 315 vfsp->vfs_mtime = ddi_get_time(); 316 vfs_make_fsid(&vfsp->vfs_fsid, vfsp->vfs_dev, devtype); 317 318 ASSERT(dv == dv->sdev_dotdot); 319 320 sdev_data->sdev_vfsp = vfsp; 321 sdev_data->sdev_root = dv; 322 sdev_data->sdev_mountargs = args; 323 324 /* get acl flavor from attribute dir */ 325 if (VOP_PATHCONF(avp, _PC_ACL_ENABLED, &sdev_data->sdev_acl_flavor, 326 kcred) != 0 || sdev_data->sdev_acl_flavor == 0) 327 sdev_data->sdev_acl_flavor = _ACL_ACLENT_ENABLED; 328 329 args = NULL; /* so it won't be freed below */ 330 sdev_insert_mntinfo(sdev_data); 331 mutex_exit(&sdev_lock); 332 333 if (!SDEV_IS_GLOBAL(dv)) { 334 ASSERT(sdev_origins); 335 dv->sdev_flags &= ~SDEV_GLOBAL; 336 dv->sdev_origin = sdev_origins->sdev_root; 337 } else { 338 sdev_ncache_setup(); 339 rw_enter(&dv->sdev_contents, RW_WRITER); 340 sdev_filldir_dynamic(dv); 341 rw_exit(&dv->sdev_contents); 342 } 343 344 sdev_update_timestamps(dv->sdev_attrvp, 345 cr, AT_CTIME|AT_MTIME|AT_ATIME); 346 347 cleanup: 348 if (args) 349 kmem_free(args, sizeof (*args)); 350 return (error); 351 } 352 353 /* 354 * unmounting the non-global /dev instances, e.g. when deleting a Kevlar zone. 355 */ 356 static int 357 sdev_unmount(struct vfs *vfsp, int flag, struct cred *cr) 358 { 359 struct sdev_node *dv; 360 int error; 361 struct sdev_data *sdev_data, *prev, *next; 362 363 /* 364 * enforce the security policies 365 */ 366 if ((secpolicy_fs_unmount(cr, vfsp) != 0) || 367 (secpolicy_sys_devices(cr) != 0)) 368 return (EPERM); 369 370 if (flag & MS_FORCE) 371 return (ENOTSUP); 372 373 mutex_enter(&sdev_lock); 374 dv = VFSTOSDEVFS(vfsp)->sdev_root; 375 ASSERT(dv == dv->sdev_dotdot); 376 if (SDEVTOV(dv)->v_count > 1) { 377 mutex_exit(&sdev_lock); 378 return (EBUSY); 379 } 380 381 /* 382 * global instance remains mounted 383 */ 384 if (SDEV_IS_GLOBAL(dv)) { 385 mutex_exit(&sdev_lock); 386 return (EBUSY); 387 } 388 mutex_exit(&sdev_lock); 389 390 /* verify the v_count */ 391 if ((error = sdev_cleandir(dv, NULL, 0)) != 0) { 392 return (error); 393 } 394 ASSERT(SDEVTOV(dv)->v_count == 1); 395 396 /* release hold on root node and destroy it */ 397 SDEV_RELE(dv); 398 dv->sdev_nlink -= 2; 399 sdev_nodedestroy(dv, 0); 400 401 sdev_data = (struct sdev_data *)vfsp->vfs_data; 402 vfsp->vfs_data = (caddr_t)0; 403 404 /* 405 * XXX separate it into sdev_delete_mntinfo() if useful 406 */ 407 mutex_enter(&sdev_lock); 408 prev = sdev_data->sdev_prev; 409 next = sdev_data->sdev_next; 410 if (prev) 411 prev->sdev_next = next; 412 else 413 sdev_mntinfo = next; 414 if (next) 415 next->sdev_prev = prev; 416 mutex_exit(&sdev_lock); 417 418 if (sdev_data->sdev_mountargs) { 419 kmem_free(sdev_data->sdev_mountargs, 420 sizeof (struct sdev_mountargs)); 421 } 422 kmem_free(sdev_data, sizeof (struct sdev_data)); 423 return (0); 424 } 425 426 /* 427 * return root vnode for given vfs 428 */ 429 static int 430 sdev_root(struct vfs *vfsp, struct vnode **vpp) 431 { 432 *vpp = SDEVTOV(VFSTOSDEVFS(vfsp)->sdev_root); 433 VN_HOLD(*vpp); 434 return (0); 435 } 436 437 /* 438 * return 'generic superblock' information to userland. 439 * 440 * not much that we can usefully admit to here 441 */ 442 static int 443 sdev_statvfs(struct vfs *vfsp, struct statvfs64 *sbp) 444 { 445 dev32_t d32; 446 447 bzero(sbp, sizeof (*sbp)); 448 sbp->f_frsize = sbp->f_bsize = vfsp->vfs_bsize; 449 sbp->f_files = kmem_cache_stat(sdev_node_cache, "alloc"); 450 451 /* no illusions that free/avail files is relevant to dev */ 452 sbp->f_ffree = 0; 453 sbp->f_favail = 0; 454 455 /* no illusions that blocks are relevant to devfs */ 456 sbp->f_bfree = 0; 457 sbp->f_bavail = 0; 458 sbp->f_blocks = 0; 459 460 (void) cmpldev(&d32, vfsp->vfs_dev); 461 sbp->f_fsid = d32; 462 (void) strcpy(sbp->f_basetype, vfssw[devtype].vsw_name); 463 sbp->f_flag = vf_to_stf(vfsp->vfs_flag); 464 sbp->f_namemax = MAXNAMELEN - 1; 465 (void) strcpy(sbp->f_fstr, "dev"); 466 467 return (0); 468 } 469 470 int 471 sdev_module_register(char *mod_name, struct devname_ops *dev_ops) 472 { 473 struct devname_nsmap *map = NULL; 474 475 if (strcmp(mod_name, DEVNAME_NSCONFIG) == 0) { 476 devname_ns_ops = dev_ops; 477 return (0); 478 } 479 480 map = sdev_get_nsmap_by_module(mod_name); 481 if (map == NULL) 482 return (EFAULT); 483 484 rw_enter(&map->dir_lock, RW_WRITER); 485 map->dir_ops = dev_ops; 486 rw_exit(&map->dir_lock); 487 return (0); 488 } 489 490 static void 491 sdev_insert_mntinfo(struct sdev_data *data) 492 { 493 ASSERT(mutex_owned(&sdev_lock)); 494 data->sdev_next = sdev_mntinfo; 495 data->sdev_prev = NULL; 496 if (sdev_mntinfo) { 497 sdev_mntinfo->sdev_prev = data; 498 } else { 499 sdev_origins = data; 500 } 501 sdev_mntinfo = data; 502 } 503 504 struct sdev_data * 505 sdev_find_mntinfo(char *mntpt) 506 { 507 struct sdev_data *mntinfo; 508 509 mutex_enter(&sdev_lock); 510 mntinfo = sdev_mntinfo; 511 while (mntinfo) { 512 if (strcmp(mntpt, mntinfo->sdev_root->sdev_name) == 0) { 513 SDEVTOV(mntinfo->sdev_root)->v_count++; 514 break; 515 } 516 mntinfo = mntinfo->sdev_next; 517 } 518 mutex_exit(&sdev_lock); 519 return (mntinfo); 520 } 521 522 void 523 sdev_mntinfo_rele(struct sdev_data *mntinfo) 524 { 525 mutex_enter(&sdev_lock); 526 SDEVTOV(mntinfo->sdev_root)->v_count--; 527 mutex_exit(&sdev_lock); 528 } 529