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