1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate /* 30*0Sstevel@tonic-gate * This is the device filesystem. 31*0Sstevel@tonic-gate * 32*0Sstevel@tonic-gate * It is a combination of a namer to drive autoconfiguration, 33*0Sstevel@tonic-gate * plus the access methods for the device drivers of the system. 34*0Sstevel@tonic-gate * 35*0Sstevel@tonic-gate * The prototype is fairly dependent on specfs for the latter part 36*0Sstevel@tonic-gate * of its implementation, though a final version would integrate the two. 37*0Sstevel@tonic-gate */ 38*0Sstevel@tonic-gate #include <sys/types.h> 39*0Sstevel@tonic-gate #include <sys/param.h> 40*0Sstevel@tonic-gate #include <sys/sysmacros.h> 41*0Sstevel@tonic-gate #include <sys/systm.h> 42*0Sstevel@tonic-gate #include <sys/kmem.h> 43*0Sstevel@tonic-gate #include <sys/time.h> 44*0Sstevel@tonic-gate #include <sys/pathname.h> 45*0Sstevel@tonic-gate #include <sys/vfs.h> 46*0Sstevel@tonic-gate #include <sys/vnode.h> 47*0Sstevel@tonic-gate #include <sys/stat.h> 48*0Sstevel@tonic-gate #include <sys/uio.h> 49*0Sstevel@tonic-gate #include <sys/stat.h> 50*0Sstevel@tonic-gate #include <sys/errno.h> 51*0Sstevel@tonic-gate #include <sys/cmn_err.h> 52*0Sstevel@tonic-gate #include <sys/cred.h> 53*0Sstevel@tonic-gate #include <sys/statvfs.h> 54*0Sstevel@tonic-gate #include <sys/mount.h> 55*0Sstevel@tonic-gate #include <sys/debug.h> 56*0Sstevel@tonic-gate #include <sys/modctl.h> 57*0Sstevel@tonic-gate #include <fs/fs_subr.h> 58*0Sstevel@tonic-gate #include <sys/fs/dv_node.h> 59*0Sstevel@tonic-gate #include <sys/fs/snode.h> 60*0Sstevel@tonic-gate #include <sys/sunndi.h> 61*0Sstevel@tonic-gate #include <sys/policy.h> 62*0Sstevel@tonic-gate 63*0Sstevel@tonic-gate /* 64*0Sstevel@tonic-gate * devfs vfs operations. 65*0Sstevel@tonic-gate */ 66*0Sstevel@tonic-gate static int devfs_mount(struct vfs *, struct vnode *, struct mounta *, 67*0Sstevel@tonic-gate struct cred *); 68*0Sstevel@tonic-gate static int devfs_unmount(struct vfs *, int, struct cred *); 69*0Sstevel@tonic-gate static int devfs_root(struct vfs *, struct vnode **); 70*0Sstevel@tonic-gate static int devfs_statvfs(struct vfs *, struct statvfs64 *); 71*0Sstevel@tonic-gate static int devfs_mountroot(struct vfs *, enum whymountroot); 72*0Sstevel@tonic-gate 73*0Sstevel@tonic-gate static int devfsinit(int, char *); 74*0Sstevel@tonic-gate 75*0Sstevel@tonic-gate static vfsdef_t devfs_vfssw = { 76*0Sstevel@tonic-gate VFSDEF_VERSION, 77*0Sstevel@tonic-gate "devfs", /* type name string */ 78*0Sstevel@tonic-gate devfsinit, /* init routine */ 79*0Sstevel@tonic-gate 0, /* flags */ 80*0Sstevel@tonic-gate NULL /* mount options table prototype */ 81*0Sstevel@tonic-gate }; 82*0Sstevel@tonic-gate 83*0Sstevel@tonic-gate static kmutex_t devfs_lock; /* protects global data */ 84*0Sstevel@tonic-gate static int devfstype; /* fstype */ 85*0Sstevel@tonic-gate static dev_t devfsdev; /* the fictious 'device' we live on */ 86*0Sstevel@tonic-gate static struct devfs_data *devfs_mntinfo; /* linked list of instances */ 87*0Sstevel@tonic-gate 88*0Sstevel@tonic-gate /* 89*0Sstevel@tonic-gate * Module linkage information 90*0Sstevel@tonic-gate */ 91*0Sstevel@tonic-gate static struct modlfs modlfs = { 92*0Sstevel@tonic-gate &mod_fsops, "devices filesystem %I%", &devfs_vfssw 93*0Sstevel@tonic-gate }; 94*0Sstevel@tonic-gate 95*0Sstevel@tonic-gate static struct modlinkage modlinkage = { 96*0Sstevel@tonic-gate MODREV_1, (void *)&modlfs, NULL 97*0Sstevel@tonic-gate }; 98*0Sstevel@tonic-gate 99*0Sstevel@tonic-gate int 100*0Sstevel@tonic-gate _init(void) 101*0Sstevel@tonic-gate { 102*0Sstevel@tonic-gate int e; 103*0Sstevel@tonic-gate 104*0Sstevel@tonic-gate mutex_init(&devfs_lock, "devfs lock", MUTEX_DEFAULT, NULL); 105*0Sstevel@tonic-gate dv_node_cache_init(); 106*0Sstevel@tonic-gate if ((e = mod_install(&modlinkage)) != 0) { 107*0Sstevel@tonic-gate dv_node_cache_fini(); 108*0Sstevel@tonic-gate mutex_destroy(&devfs_lock); 109*0Sstevel@tonic-gate return (e); 110*0Sstevel@tonic-gate } 111*0Sstevel@tonic-gate dcmn_err(("devfs loaded\n")); 112*0Sstevel@tonic-gate return (0); 113*0Sstevel@tonic-gate } 114*0Sstevel@tonic-gate 115*0Sstevel@tonic-gate int 116*0Sstevel@tonic-gate _fini(void) 117*0Sstevel@tonic-gate { 118*0Sstevel@tonic-gate return (EBUSY); 119*0Sstevel@tonic-gate } 120*0Sstevel@tonic-gate 121*0Sstevel@tonic-gate int 122*0Sstevel@tonic-gate _info(struct modinfo *modinfop) 123*0Sstevel@tonic-gate { 124*0Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 125*0Sstevel@tonic-gate } 126*0Sstevel@tonic-gate 127*0Sstevel@tonic-gate /*ARGSUSED1*/ 128*0Sstevel@tonic-gate static int 129*0Sstevel@tonic-gate devfsinit(int fstype, char *name) 130*0Sstevel@tonic-gate { 131*0Sstevel@tonic-gate static const fs_operation_def_t devfs_vfsops_template[] = { 132*0Sstevel@tonic-gate VFSNAME_MOUNT, devfs_mount, 133*0Sstevel@tonic-gate VFSNAME_UNMOUNT, devfs_unmount, 134*0Sstevel@tonic-gate VFSNAME_ROOT, devfs_root, 135*0Sstevel@tonic-gate VFSNAME_STATVFS, devfs_statvfs, 136*0Sstevel@tonic-gate VFSNAME_SYNC, (fs_generic_func_p) fs_sync, 137*0Sstevel@tonic-gate VFSNAME_MOUNTROOT, devfs_mountroot, 138*0Sstevel@tonic-gate NULL, NULL 139*0Sstevel@tonic-gate }; 140*0Sstevel@tonic-gate int error; 141*0Sstevel@tonic-gate int dev; 142*0Sstevel@tonic-gate extern major_t getudev(void); /* gack - what a function */ 143*0Sstevel@tonic-gate 144*0Sstevel@tonic-gate devfstype = fstype; 145*0Sstevel@tonic-gate /* 146*0Sstevel@tonic-gate * Associate VFS ops vector with this fstype 147*0Sstevel@tonic-gate */ 148*0Sstevel@tonic-gate error = vfs_setfsops(fstype, devfs_vfsops_template, NULL); 149*0Sstevel@tonic-gate if (error != 0) { 150*0Sstevel@tonic-gate cmn_err(CE_WARN, "devfsinit: bad vfs ops template"); 151*0Sstevel@tonic-gate return (error); 152*0Sstevel@tonic-gate } 153*0Sstevel@tonic-gate 154*0Sstevel@tonic-gate error = vn_make_ops("dev fs", dv_vnodeops_template, &dv_vnodeops); 155*0Sstevel@tonic-gate if (error != 0) { 156*0Sstevel@tonic-gate (void) vfs_freevfsops_by_type(fstype); 157*0Sstevel@tonic-gate cmn_err(CE_WARN, "devfsinit: bad vnode ops template"); 158*0Sstevel@tonic-gate return (error); 159*0Sstevel@tonic-gate } 160*0Sstevel@tonic-gate 161*0Sstevel@tonic-gate /* 162*0Sstevel@tonic-gate * Invent a dev_t (sigh). 163*0Sstevel@tonic-gate */ 164*0Sstevel@tonic-gate if ((dev = getudev()) == (major_t)-1) { 165*0Sstevel@tonic-gate cmn_err(CE_NOTE, "%s: can't get unique dev", devfs_vfssw.name); 166*0Sstevel@tonic-gate dev = 0; 167*0Sstevel@tonic-gate } 168*0Sstevel@tonic-gate devfsdev = makedevice(dev, 0); 169*0Sstevel@tonic-gate 170*0Sstevel@tonic-gate return (0); 171*0Sstevel@tonic-gate } 172*0Sstevel@tonic-gate 173*0Sstevel@tonic-gate /* 174*0Sstevel@tonic-gate * The name of the mount point and the name of the attribute 175*0Sstevel@tonic-gate * filesystem are passed down from userland for now. 176*0Sstevel@tonic-gate */ 177*0Sstevel@tonic-gate static int 178*0Sstevel@tonic-gate devfs_mount(struct vfs *vfsp, struct vnode *mvp, struct mounta *uap, 179*0Sstevel@tonic-gate struct cred *cr) 180*0Sstevel@tonic-gate { 181*0Sstevel@tonic-gate struct devfs_data *devfs_data; 182*0Sstevel@tonic-gate struct vnode *avp; 183*0Sstevel@tonic-gate struct dv_node *dv; 184*0Sstevel@tonic-gate struct vattr va; 185*0Sstevel@tonic-gate 186*0Sstevel@tonic-gate dcmn_err(("devfs_mount\n")); 187*0Sstevel@tonic-gate 188*0Sstevel@tonic-gate if (secpolicy_fs_mount(cr, mvp, vfsp) != 0) 189*0Sstevel@tonic-gate return (EPERM); 190*0Sstevel@tonic-gate 191*0Sstevel@tonic-gate /* 192*0Sstevel@tonic-gate * check that the mount point is sane 193*0Sstevel@tonic-gate */ 194*0Sstevel@tonic-gate if (mvp->v_type != VDIR) 195*0Sstevel@tonic-gate return (ENOTDIR); 196*0Sstevel@tonic-gate 197*0Sstevel@tonic-gate ASSERT(uap->flags & MS_SYSSPACE); 198*0Sstevel@tonic-gate /* 199*0Sstevel@tonic-gate * Devfs can only be mounted from kernel during boot. 200*0Sstevel@tonic-gate * avp is the existing /devices, the same as the mount point. 201*0Sstevel@tonic-gate */ 202*0Sstevel@tonic-gate avp = mvp; 203*0Sstevel@tonic-gate 204*0Sstevel@tonic-gate /* 205*0Sstevel@tonic-gate * Create and initialize the vfs-private data. 206*0Sstevel@tonic-gate * This includes a hand-crafted root vnode (we build 207*0Sstevel@tonic-gate * this here mostly so that traverse() doesn't sleep 208*0Sstevel@tonic-gate * in VFS_ROOT()). 209*0Sstevel@tonic-gate */ 210*0Sstevel@tonic-gate mutex_enter(&devfs_lock); 211*0Sstevel@tonic-gate ASSERT(devfs_mntinfo == NULL); 212*0Sstevel@tonic-gate dv = dv_mkroot(vfsp, devfsdev); 213*0Sstevel@tonic-gate dv->dv_attrvp = avp; /* attribute root vp */ 214*0Sstevel@tonic-gate 215*0Sstevel@tonic-gate ASSERT(dv == dv->dv_dotdot); 216*0Sstevel@tonic-gate 217*0Sstevel@tonic-gate devfs_data = kmem_zalloc(sizeof (struct devfs_data), KM_SLEEP); 218*0Sstevel@tonic-gate devfs_data->devfs_vfsp = vfsp; 219*0Sstevel@tonic-gate devfs_data->devfs_root = dv; 220*0Sstevel@tonic-gate 221*0Sstevel@tonic-gate vfsp->vfs_data = (caddr_t)devfs_data; 222*0Sstevel@tonic-gate vfsp->vfs_fstype = devfstype; 223*0Sstevel@tonic-gate vfsp->vfs_dev = devfsdev; 224*0Sstevel@tonic-gate vfsp->vfs_bsize = DEV_BSIZE; 225*0Sstevel@tonic-gate vfsp->vfs_mtime = ddi_get_time(); 226*0Sstevel@tonic-gate vfs_make_fsid(&vfsp->vfs_fsid, vfsp->vfs_dev, devfstype); 227*0Sstevel@tonic-gate 228*0Sstevel@tonic-gate /* We're there. */ 229*0Sstevel@tonic-gate devfs_mntinfo = devfs_data; 230*0Sstevel@tonic-gate mutex_exit(&devfs_lock); 231*0Sstevel@tonic-gate 232*0Sstevel@tonic-gate va.va_mask = AT_ATIME|AT_MTIME; 233*0Sstevel@tonic-gate gethrestime(&va.va_atime); 234*0Sstevel@tonic-gate gethrestime(&va.va_mtime); 235*0Sstevel@tonic-gate (void) VOP_SETATTR(DVTOV(dv), &va, 0, cr, NULL); 236*0Sstevel@tonic-gate return (0); 237*0Sstevel@tonic-gate } 238*0Sstevel@tonic-gate 239*0Sstevel@tonic-gate 240*0Sstevel@tonic-gate /* 241*0Sstevel@tonic-gate * We never unmount devfs in a real production system. 242*0Sstevel@tonic-gate */ 243*0Sstevel@tonic-gate /*ARGSUSED*/ 244*0Sstevel@tonic-gate static int 245*0Sstevel@tonic-gate devfs_unmount(struct vfs *vfsp, int flag, struct cred *cr) 246*0Sstevel@tonic-gate { 247*0Sstevel@tonic-gate return (EBUSY); 248*0Sstevel@tonic-gate } 249*0Sstevel@tonic-gate 250*0Sstevel@tonic-gate /* 251*0Sstevel@tonic-gate * return root vnode for given vfs 252*0Sstevel@tonic-gate */ 253*0Sstevel@tonic-gate static int 254*0Sstevel@tonic-gate devfs_root(struct vfs *vfsp, struct vnode **vpp) 255*0Sstevel@tonic-gate { 256*0Sstevel@tonic-gate dcmn_err(("devfs_root\n")); 257*0Sstevel@tonic-gate *vpp = DVTOV(VFSTODVFS(vfsp)->devfs_root); 258*0Sstevel@tonic-gate VN_HOLD(*vpp); 259*0Sstevel@tonic-gate return (0); 260*0Sstevel@tonic-gate } 261*0Sstevel@tonic-gate 262*0Sstevel@tonic-gate /* 263*0Sstevel@tonic-gate * return 'generic superblock' information to userland. 264*0Sstevel@tonic-gate * 265*0Sstevel@tonic-gate * not much that we can usefully admit to here 266*0Sstevel@tonic-gate */ 267*0Sstevel@tonic-gate static int 268*0Sstevel@tonic-gate devfs_statvfs(struct vfs *vfsp, struct statvfs64 *sbp) 269*0Sstevel@tonic-gate { 270*0Sstevel@tonic-gate extern kmem_cache_t *dv_node_cache; 271*0Sstevel@tonic-gate 272*0Sstevel@tonic-gate dev32_t d32; 273*0Sstevel@tonic-gate 274*0Sstevel@tonic-gate dcmn_err(("devfs_statvfs\n")); 275*0Sstevel@tonic-gate bzero(sbp, sizeof (*sbp)); 276*0Sstevel@tonic-gate sbp->f_frsize = sbp->f_bsize = vfsp->vfs_bsize; 277*0Sstevel@tonic-gate /* 278*0Sstevel@tonic-gate * We could compute the number of devfsnodes here .. but since 279*0Sstevel@tonic-gate * it's dynamic anyway, it's not clear how useful this is. 280*0Sstevel@tonic-gate */ 281*0Sstevel@tonic-gate sbp->f_files = kmem_cache_stat(dv_node_cache, "alloc"); 282*0Sstevel@tonic-gate 283*0Sstevel@tonic-gate /* no illusions that free/avail files is relevant to devfs */ 284*0Sstevel@tonic-gate sbp->f_ffree = 0; 285*0Sstevel@tonic-gate sbp->f_favail = 0; 286*0Sstevel@tonic-gate 287*0Sstevel@tonic-gate /* no illusions that blocks are relevant to devfs */ 288*0Sstevel@tonic-gate sbp->f_bfree = 0; 289*0Sstevel@tonic-gate sbp->f_bavail = 0; 290*0Sstevel@tonic-gate sbp->f_blocks = 0; 291*0Sstevel@tonic-gate 292*0Sstevel@tonic-gate (void) cmpldev(&d32, vfsp->vfs_dev); 293*0Sstevel@tonic-gate sbp->f_fsid = d32; 294*0Sstevel@tonic-gate (void) strcpy(sbp->f_basetype, vfssw[devfstype].vsw_name); 295*0Sstevel@tonic-gate sbp->f_flag = vf_to_stf(vfsp->vfs_flag); 296*0Sstevel@tonic-gate sbp->f_namemax = MAXNAMELEN - 1; 297*0Sstevel@tonic-gate (void) strcpy(sbp->f_fstr, "devices"); 298*0Sstevel@tonic-gate 299*0Sstevel@tonic-gate return (0); 300*0Sstevel@tonic-gate } 301*0Sstevel@tonic-gate 302*0Sstevel@tonic-gate /* 303*0Sstevel@tonic-gate * devfs always mount after root is mounted, so this should never 304*0Sstevel@tonic-gate * be invoked. 305*0Sstevel@tonic-gate */ 306*0Sstevel@tonic-gate /*ARGSUSED*/ 307*0Sstevel@tonic-gate static int 308*0Sstevel@tonic-gate devfs_mountroot(struct vfs *vfsp, enum whymountroot why) 309*0Sstevel@tonic-gate { 310*0Sstevel@tonic-gate dcmn_err(("devfs_mountroot\n")); 311*0Sstevel@tonic-gate 312*0Sstevel@tonic-gate return (EINVAL); 313*0Sstevel@tonic-gate } 314*0Sstevel@tonic-gate 315*0Sstevel@tonic-gate struct dv_node * 316*0Sstevel@tonic-gate devfs_dip_to_dvnode(dev_info_t *dip) 317*0Sstevel@tonic-gate { 318*0Sstevel@tonic-gate char *dirpath; 319*0Sstevel@tonic-gate struct vnode *dirvp; 320*0Sstevel@tonic-gate 321*0Sstevel@tonic-gate ASSERT(dip != NULL); 322*0Sstevel@tonic-gate 323*0Sstevel@tonic-gate /* no-op if devfs not mounted yet */ 324*0Sstevel@tonic-gate if (devfs_mntinfo == NULL) 325*0Sstevel@tonic-gate return (NULL); 326*0Sstevel@tonic-gate 327*0Sstevel@tonic-gate /* 328*0Sstevel@tonic-gate * The lookupname below only looks up cached dv_nodes 329*0Sstevel@tonic-gate * because devfs_clean_key is set in thread specific data. 330*0Sstevel@tonic-gate */ 331*0Sstevel@tonic-gate dirpath = kmem_alloc(MAXPATHLEN, KM_SLEEP); 332*0Sstevel@tonic-gate (void) ddi_pathname(dip, dirpath); 333*0Sstevel@tonic-gate if (devfs_lookupname(dirpath, NULLVPP, &dirvp)) { 334*0Sstevel@tonic-gate dcmn_err(("directory %s not found\n", dirpath)); 335*0Sstevel@tonic-gate kmem_free(dirpath, MAXPATHLEN); 336*0Sstevel@tonic-gate return (NULL); 337*0Sstevel@tonic-gate } 338*0Sstevel@tonic-gate 339*0Sstevel@tonic-gate kmem_free(dirpath, MAXPATHLEN); 340*0Sstevel@tonic-gate return (VTODV(dirvp)); 341*0Sstevel@tonic-gate } 342*0Sstevel@tonic-gate 343*0Sstevel@tonic-gate /* 344*0Sstevel@tonic-gate * devfs_clean() 345*0Sstevel@tonic-gate * 346*0Sstevel@tonic-gate * Destroy unreferenced dv_node's and detach devices. 347*0Sstevel@tonic-gate * Returns 0 on success, error if failed to unconfigure node. 348*0Sstevel@tonic-gate * 349*0Sstevel@tonic-gate * devfs caches unreferenced dv_node to speed by the performance 350*0Sstevel@tonic-gate * of ls, find, etc. devfs_clean() is invoked to cleanup cached 351*0Sstevel@tonic-gate * dv_nodes to reclaim memory as well as to facilitate device 352*0Sstevel@tonic-gate * removal (dv_node reference devinfo nodes, which prevents driver 353*0Sstevel@tonic-gate * detach). 354*0Sstevel@tonic-gate * 355*0Sstevel@tonic-gate * If a shell parks in a /devices directory, the dv_node will be 356*0Sstevel@tonic-gate * held, preventing the corresponding device to be detached. 357*0Sstevel@tonic-gate * This would be a denial of service against DR. To prevent this, 358*0Sstevel@tonic-gate * DR code calls devfs_clean() with the DV_CLEAN_FORCE flag. 359*0Sstevel@tonic-gate * The dv_cleandir() implementation does the right thing to ensure 360*0Sstevel@tonic-gate * successful DR. 361*0Sstevel@tonic-gate */ 362*0Sstevel@tonic-gate int 363*0Sstevel@tonic-gate devfs_clean(dev_info_t *dip, char *devnm, uint_t flags) 364*0Sstevel@tonic-gate { 365*0Sstevel@tonic-gate struct dv_node *dvp; 366*0Sstevel@tonic-gate 367*0Sstevel@tonic-gate dcmn_err(("devfs_unconfigure: dip = 0x%p, flags = 0x%x", 368*0Sstevel@tonic-gate (void *)dip, flags)); 369*0Sstevel@tonic-gate 370*0Sstevel@tonic-gate /* avoid recursion back into the device tree */ 371*0Sstevel@tonic-gate (void) tsd_set(devfs_clean_key, (void *)1); 372*0Sstevel@tonic-gate dvp = devfs_dip_to_dvnode(dip); 373*0Sstevel@tonic-gate (void) tsd_set(devfs_clean_key, NULL); 374*0Sstevel@tonic-gate if (dvp == NULL) 375*0Sstevel@tonic-gate return (0); 376*0Sstevel@tonic-gate 377*0Sstevel@tonic-gate if (dv_cleandir(dvp, devnm, flags) != 0) { 378*0Sstevel@tonic-gate VN_RELE(DVTOV(dvp)); 379*0Sstevel@tonic-gate return (EBUSY); 380*0Sstevel@tonic-gate } 381*0Sstevel@tonic-gate VN_RELE(DVTOV(dvp)); 382*0Sstevel@tonic-gate return (0); 383*0Sstevel@tonic-gate } 384*0Sstevel@tonic-gate 385*0Sstevel@tonic-gate /* 386*0Sstevel@tonic-gate * lookup a devfs relative pathname, returning held vnodes for the final 387*0Sstevel@tonic-gate * component and the containing directory (if requested). 388*0Sstevel@tonic-gate * 389*0Sstevel@tonic-gate * NOTE: We can't use lookupname because this would use the current 390*0Sstevel@tonic-gate * processes credentials (CRED) in the call lookuppnvp instead 391*0Sstevel@tonic-gate * of kcred. It also does not give you the flexibility so 392*0Sstevel@tonic-gate * specify the directory to start the resolution in (devicesdir). 393*0Sstevel@tonic-gate */ 394*0Sstevel@tonic-gate int 395*0Sstevel@tonic-gate devfs_lookupname( 396*0Sstevel@tonic-gate char *pathname, /* user pathname */ 397*0Sstevel@tonic-gate vnode_t **dirvpp, /* ret for ptr to parent dir vnode */ 398*0Sstevel@tonic-gate vnode_t **compvpp) /* ret for ptr to component vnode */ 399*0Sstevel@tonic-gate { 400*0Sstevel@tonic-gate struct pathname pn; 401*0Sstevel@tonic-gate int error; 402*0Sstevel@tonic-gate 403*0Sstevel@tonic-gate ASSERT(devicesdir); /* devfs must be initialized */ 404*0Sstevel@tonic-gate ASSERT(pathname); /* must have some path */ 405*0Sstevel@tonic-gate 406*0Sstevel@tonic-gate if (error = pn_get(pathname, UIO_SYSSPACE, &pn)) 407*0Sstevel@tonic-gate return (error); 408*0Sstevel@tonic-gate 409*0Sstevel@tonic-gate /* make the path relative to /devices. */ 410*0Sstevel@tonic-gate pn_skipslash(&pn); 411*0Sstevel@tonic-gate if (pn_pathleft(&pn) == 0) { 412*0Sstevel@tonic-gate /* all we had was "\0" or "/" (which skipslash skiped) */ 413*0Sstevel@tonic-gate if (dirvpp) 414*0Sstevel@tonic-gate *dirvpp = NULL; 415*0Sstevel@tonic-gate if (compvpp) { 416*0Sstevel@tonic-gate VN_HOLD(devicesdir); 417*0Sstevel@tonic-gate *compvpp = devicesdir; 418*0Sstevel@tonic-gate } 419*0Sstevel@tonic-gate } else { 420*0Sstevel@tonic-gate /* 421*0Sstevel@tonic-gate * Use devfs lookup to resolve pathname to the vnode for 422*0Sstevel@tonic-gate * the device via relative lookup in devfs. Extra holds for 423*0Sstevel@tonic-gate * using devicesdir as directory we are searching and for 424*0Sstevel@tonic-gate * being our root without being == rootdir. 425*0Sstevel@tonic-gate */ 426*0Sstevel@tonic-gate VN_HOLD(devicesdir); 427*0Sstevel@tonic-gate VN_HOLD(devicesdir); 428*0Sstevel@tonic-gate error = lookuppnvp(&pn, NULL, FOLLOW, dirvpp, compvpp, 429*0Sstevel@tonic-gate devicesdir, devicesdir, kcred); 430*0Sstevel@tonic-gate } 431*0Sstevel@tonic-gate pn_free(&pn); 432*0Sstevel@tonic-gate 433*0Sstevel@tonic-gate return (error); 434*0Sstevel@tonic-gate } 435*0Sstevel@tonic-gate 436*0Sstevel@tonic-gate /* 437*0Sstevel@tonic-gate * Given a devfs path (without the /devices prefix), walk 438*0Sstevel@tonic-gate * the dv_node sub-tree rooted at the path. 439*0Sstevel@tonic-gate */ 440*0Sstevel@tonic-gate int 441*0Sstevel@tonic-gate devfs_walk( 442*0Sstevel@tonic-gate char *path, 443*0Sstevel@tonic-gate void (*callback)(struct dv_node *, void *), 444*0Sstevel@tonic-gate void *arg) 445*0Sstevel@tonic-gate { 446*0Sstevel@tonic-gate char *dirpath, *devnm; 447*0Sstevel@tonic-gate struct vnode *dirvp; 448*0Sstevel@tonic-gate 449*0Sstevel@tonic-gate ASSERT(path && callback); 450*0Sstevel@tonic-gate 451*0Sstevel@tonic-gate if (*path != '/' || devfs_mntinfo == NULL) 452*0Sstevel@tonic-gate return (ENXIO); 453*0Sstevel@tonic-gate 454*0Sstevel@tonic-gate dcmn_err(("devfs_walk: path = %s", path)); 455*0Sstevel@tonic-gate 456*0Sstevel@tonic-gate dirpath = kmem_alloc(MAXPATHLEN, KM_SLEEP); 457*0Sstevel@tonic-gate 458*0Sstevel@tonic-gate (void) snprintf(dirpath, MAXPATHLEN, "/devices%s", path); 459*0Sstevel@tonic-gate 460*0Sstevel@tonic-gate devnm = strrchr(dirpath, '/'); 461*0Sstevel@tonic-gate 462*0Sstevel@tonic-gate ASSERT(devnm); 463*0Sstevel@tonic-gate 464*0Sstevel@tonic-gate *devnm++ = '\0'; 465*0Sstevel@tonic-gate 466*0Sstevel@tonic-gate if (lookupname(dirpath, UIO_SYSSPACE, 0, NULL, &dirvp)) { 467*0Sstevel@tonic-gate dcmn_err(("directory %s not found\n", dirpath)); 468*0Sstevel@tonic-gate kmem_free(dirpath, MAXPATHLEN); 469*0Sstevel@tonic-gate return (ENXIO); 470*0Sstevel@tonic-gate } 471*0Sstevel@tonic-gate 472*0Sstevel@tonic-gate /* 473*0Sstevel@tonic-gate * if path == "/", visit the root dv_node 474*0Sstevel@tonic-gate */ 475*0Sstevel@tonic-gate if (*devnm == '\0') { 476*0Sstevel@tonic-gate callback(VTODV(dirvp), arg); 477*0Sstevel@tonic-gate devnm = NULL; 478*0Sstevel@tonic-gate } 479*0Sstevel@tonic-gate 480*0Sstevel@tonic-gate dv_walk(VTODV(dirvp), devnm, callback, arg); 481*0Sstevel@tonic-gate 482*0Sstevel@tonic-gate VN_RELE(dirvp); 483*0Sstevel@tonic-gate 484*0Sstevel@tonic-gate kmem_free(dirpath, MAXPATHLEN); 485*0Sstevel@tonic-gate 486*0Sstevel@tonic-gate return (0); 487*0Sstevel@tonic-gate } 488*0Sstevel@tonic-gate 489*0Sstevel@tonic-gate int 490*0Sstevel@tonic-gate devfs_devpolicy(vnode_t *vp, devplcy_t **dpp) 491*0Sstevel@tonic-gate { 492*0Sstevel@tonic-gate struct vnode *rvp; 493*0Sstevel@tonic-gate struct dv_node *dvp; 494*0Sstevel@tonic-gate int rval = -1; 495*0Sstevel@tonic-gate 496*0Sstevel@tonic-gate /* fail if devfs not mounted yet */ 497*0Sstevel@tonic-gate if (devfs_mntinfo == NULL) 498*0Sstevel@tonic-gate return (rval); 499*0Sstevel@tonic-gate 500*0Sstevel@tonic-gate if (VOP_REALVP(vp, &rvp) == 0 && vn_matchops(rvp, dv_vnodeops)) { 501*0Sstevel@tonic-gate dvp = VTODV(rvp); 502*0Sstevel@tonic-gate rw_enter(&dvp->dv_contents, RW_READER); 503*0Sstevel@tonic-gate if (dvp->dv_priv) { 504*0Sstevel@tonic-gate dphold(dvp->dv_priv); 505*0Sstevel@tonic-gate *dpp = dvp->dv_priv; 506*0Sstevel@tonic-gate rval = 0; 507*0Sstevel@tonic-gate } 508*0Sstevel@tonic-gate rw_exit(&dvp->dv_contents); 509*0Sstevel@tonic-gate } 510*0Sstevel@tonic-gate return (rval); 511*0Sstevel@tonic-gate } 512