/** * cdev_open: - open a character special device node * @inode: the character device inode * @file: the user file pointer * * cdev_open() is only used to open a stream from a character device node in an external * filesystem. This is never called for direct opens of a specfs device node (for direct opens see * spec_dev_open() in strspecfs.c). It is also not used for direct opens of fifos, pipes or * sockets. Those devices provide their own file operations to the main operating system. The * character device number from the inode is used to determine the shadow special file system * (internal) inode and chain the open call. * * This is the separation point where we convert the external device number to an internal device * number. The external device number is contained in inode->i_rdev. * * @inode is the inode in the external filesystem. * * @file->f_op is the external file operations (character device, fifo) and must be replaced with * our file operations. * * @file->f_dentry is the external filesystem dentry for the device node. * @file->f_vfsmnt is the external filesystem vfsmnt for the device node. * @file exists on the file->f_dentry->d_inode->i_sb->s_files list. * * What we should be doing here is get a fresh new dentry. Find our inode from the device number, * add it to the dentry. Set the dentry->d_sb to the specfs super block, set dentry->d_parent = * dget(file->f_dentry->d_parent), but do not add the dentry to the child list on the parent * directory, nor do we hash the dentry. Next we do a dentry open on the on the dentry and a file * pointer swap on return. * * Instead of farting around with dentries and such, just lookup the inode in the specfs replace * the file->f_ops and chain the open with the specfs inode passed to the new open procedure. For * FIFOs we pass the external filesystem inode instead. */ STATIC int cdev_open(struct inode *inode, struct file *file) { int err; struct cdevsw *cdev; struct devnode *cmin; major_t major; minor_t minor; modID_t modid; dev_t dev; int sflag; #if defined HAVE_KFUNC_TO_KDEV_T minor = MINOR(kdev_t_to_nr(inode->i_rdev)); major = MAJOR(kdev_t_to_nr(inode->i_rdev)); #else minor = MINOR(inode->i_rdev); major = MAJOR(inode->i_rdev); #endif if (!(cdev = sdev_get(major))) { return (-ENXIO); } minor = cdev_minor(cdev, major, minor); major = cdev->d_major; modid = cdev->d_modid; dev = makedevice(modid, minor); sflag = DRVOPEN; if (cdev->d_flag & D_CLONE) sflag = CLONEOPEN; else if ((cmin = cmin_get(cdev, minor)) && cmin->n_flag & D_CLONE) sflag = CLONEOPEN; err = spec_open(file, cdev, dev, sflag); sdev_put(cdev); return (err); }
/* * clone_open: - open a clone device node * @inode: the external filesystem inode * @file: the external filesystem file pointer * * clone_open() is only used to open a clone device from a character device node in an external * filesystem. This is never called for direct opens of a specfs device node (for direct opens see * spec_dev_open() in strspecfs.c). The character device number from the inode is used to * determine the shadow special filesystem (internal) inode and chain the open call. * * This is the separation point where we convert the external device number to an internal device * number. The external device number is contained in inode->i_rdev. */ STATIC int clone_open(struct inode *inode, struct file *file) { int err; struct cdevsw *cdev; major_t major; minor_t minor; modID_t modid, instance; #if defined HAVE_KFUNC_TO_KDEV_T minor = MINOR(kdev_t_to_nr(inode->i_rdev)); major = MAJOR(kdev_t_to_nr(inode->i_rdev)); #else minor = MINOR(inode->i_rdev); major = MAJOR(inode->i_rdev); #endif minor = cdev_minor(&clone_cdev, major, minor); major = clone_cdev.d_major; modid = clone_cdev.d_modid; err = -ENXIO; if (!(cdev = sdev_get(minor))) { goto exit; } instance = cdev->d_modid; err = spec_open(file, cdev, makedevice(modid, instance), CLONEOPEN); sdev_put(cdev); exit: return (err); }
/*ARGSUSED1*/ static int ds1287_open(dev_t *devp, int flags, int otyp, cred_t *credp) { struct ds1287 *softsp; int clone; if (otyp != OTYP_CHR) return (EINVAL); if ((softsp = ddi_get_soft_state(ds1287_state, instance)) == NULL) return (ENXIO); mutex_enter(&softsp->ds1287_mutex); for (clone = 1; clone < DS1287_MAX_CLONE; clone++) if (!softsp->clones[clone]) break; if (clone == DS1287_MAX_CLONE) { cmn_err(CE_WARN, "ds1287_open: No more allocation left " "to clone a minor."); mutex_exit(&softsp->ds1287_mutex); return (ENXIO); } *devp = makedevice(getmajor(*devp), (instance << 8) + clone); softsp->clones[clone] = 1; mutex_exit(&softsp->ds1287_mutex); return (0); }
/* * Get the ZFS volume name out of the given path */ int get_zfsvolname(char *volname, int len, char *path) { struct stat64 stbuf; struct extmnttab ent; FILE *mntfp; int rv; *volname = '\0'; if (stat64(path, &stbuf) != 0) { return (-1); } if ((mntfp = fopen(MNTTAB, "r")) == NULL) { return (-1); } while ((rv = getextmntent(mntfp, &ent, 0)) == 0) { if (makedevice(ent.mnt_major, ent.mnt_minor) == stbuf.st_dev) break; } if (rv == 0 && strcmp(ent.mnt_fstype, MNTTYPE_ZFS) == 0) (void) strlcpy(volname, ent.mnt_special, len); else rv = -1; (void) fclose(mntfp); return (rv); }
/* ARGSUSED */ static int log_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *cr) { log_t *lp; minor_t minor; if (sflag & (MODOPEN | CLONEOPEN)) return (ENXIO); switch (minor = getminor(*devp)) { case LOG_CONSMIN: /* clone open of /dev/conslog */ if (flag & FREAD) return (EINVAL); /* write-only device */ if (q->q_ptr) return (0); break; case LOG_LOGMIN: /* clone open of /dev/log */ break; default: return (ENXIO); } lp = log_alloc(minor); if (lp == NULL) return (ENXIO); *devp = makedevice(getmajor(*devp), lp->log_minor); q->q_ptr = lp; WR(q)->q_ptr = lp; lp->log_inuse = 1; qprocson(q); return (0); }
/*ARGSUSED*/ static int smb_open(dev_t *dp, int flag, int otyp, cred_t *cred) { minor_t c; if (ksmbios == NULL) return (ENXIO); /* * Locate and reserve a clone structure. We skip clone 0 as that is * the real minor number, and we assign a new minor to each clone. */ for (c = 1; c < smb_nclones; c++) { if (casptr(&smb_clones[c].c_hdl, NULL, ksmbios) == NULL) break; } if (c >= smb_nclones) return (EAGAIN); smb_clones[c].c_eplen = P2ROUNDUP(sizeof (smbios_entry_t), 16); smb_clones[c].c_stlen = smbios_buflen(smb_clones[c].c_hdl); *dp = makedevice(getemajor(*dp), c); (void) ddi_prop_update_int(*dp, smb_devi, "size", smb_clones[c].c_eplen + smb_clones[c].c_stlen); return (0); }
/*ARGSUSED*/ static int ipmi_open(dev_t *devp, int flag, int otyp, cred_t *cred) { minor_t minor; ipmi_device_t *dev; if (ipmi_attached == B_FALSE) return (ENXIO); if (ipmi_found == B_FALSE) return (ENODEV); /* exclusive opens are not supported */ if (flag & FEXCL) return (ENOTSUP); if ((minor = (minor_t)id_alloc_nosleep(minor_ids)) == 0) return (ENODEV); /* Initialize the per file descriptor data. */ dev = kmem_zalloc(sizeof (ipmi_device_t), KM_SLEEP); dev->ipmi_pollhead = kmem_zalloc(sizeof (pollhead_t), KM_SLEEP); TAILQ_INIT(&dev->ipmi_completed_requests); dev->ipmi_address = IPMI_BMC_SLAVE_ADDR; dev->ipmi_lun = IPMI_BMC_SMS_LUN; *devp = makedevice(getmajor(*devp), minor); dev->ipmi_dev = *devp; list_insert_head(&dev_list, dev); return (0); }
/* There are two minors 0 is the /dev/sad/admin driver and 1 is the /dev/sad/user driver. Permission for access to the /dev/sad/admin minor is performed by filesystem permission on the character device and a check on open. */ static streamscall int sad_open(queue_t *q, dev_t *devp, int oflag, int sflag, cred_t *crp) { major_t major = getmajor(*devp); minor_t minor = getminor(*devp); if (q->q_ptr) return (0); /* already open */ switch (sflag) { case CLONEOPEN: minor = 1; if (sads[minor].assigned != 0) break; case DRVOPEN: if (minor != 0 && minor != 1) break; #ifdef HAVE_KMEMB_STRUCT_CRED_UID_VAL if (minor == 0 && crp->cr_uid.val != 0 && crp->cr_ruid.val != 0) return (-EACCES); #else if (minor == 0 && crp->cr_uid != 0 && crp->cr_ruid != 0) return (-EACCES); #endif *devp = makedevice(major, minor); sads[minor].assigned |= 1; q->q_ptr = WR(q)->q_ptr = &sads[minor]; qprocson(q); return (0); } return (-ENXIO); }
/*ARGSUSED*/ static int devvt_create_rvp(struct sdev_node *ddv, char *nm, void **arg, cred_t *cred, void *whatever, char *whichever) { minor_t min; major_t maj; struct vattr *vap = (struct vattr *)arg; if ((maj = vt_wc_attached()) == (major_t)-1) return (SDEV_VTOR_INVALID); if (strcmp(nm, DEVVT_ACTIVE_NAME) == 0) { (void) vt_getactive((char *)*arg, MAXPATHLEN); return (0); } if (strcmp(nm, DEVVT_CONSUSER_NAME) == 0) { (void) vt_getconsuser((char *)*arg, MAXPATHLEN); return (0); } if (devvt_str2minor(nm, &min) != 0) return (-1); if (vt_minor_valid(min) == B_FALSE) return (-1); *vap = devvt_vattr; vap->va_rdev = makedevice(maj, min); return (0); }
static int audio_stropen(queue_t *rq, dev_t *devp, int oflag, int sflag, cred_t *credp) { int rv; audio_client_t *c; if (sflag != 0) { /* no direct clone or module opens */ return (ENXIO); } /* * Make sure its a STREAMS personality - only legacy Sun API uses * STREAMS. */ switch (AUDIO_MN_TYPE_MASK & getminor(*devp)) { case AUDIO_MINOR_DEVAUDIO: case AUDIO_MINOR_DEVAUDIOCTL: break; default: return (ENOSTR); } if ((c = auimpl_client_create(*devp)) == NULL) { audio_dev_warn(NULL, "client create failed"); return (ENXIO); } rq->q_ptr = WR(rq)->q_ptr = c; c->c_omode = oflag; c->c_pid = ddi_get_pid(); c->c_cred = credp; c->c_rq = rq; c->c_wq = WR(rq); /* * Call client/personality specific open handler. Note that * we "insist" that there is an open. The personality layer * will initialize/allocate any engines required. * * Hmm... do we need to pass in the cred? */ if ((rv = c->c_open(c, oflag)) != 0) { audio_dev_warn(c->c_dev, "open failed (rv %d)", rv); auimpl_client_destroy(c); return (rv); } /* we do device cloning! */ *devp = makedevice(c->c_major, c->c_minor); qprocson(rq); /* now we can receive upcalls */ auimpl_client_activate(c); atomic_inc_uint(&c->c_dev->d_serial); return (0); }
/* * This opens and closes the appropriate device with minor number - * hopefully, it will cause the driver to attach and register a controller * with us */ static vnode_t * rsmops_device_open(const char *major_name, const minor_t minor_num) { major_t maj; vnode_t *vp; int ret; if (minor_num == (minor_t)-1) { return (NULL); } maj = ddi_name_to_major((char *)major_name); if (maj == (major_t)-1) { return (NULL); } vp = makespecvp(makedevice(maj, minor_num), VCHR); ret = VOP_OPEN(&vp, FREAD|FWRITE, CRED(), NULL); if (ret == 0) { return (vp); } else { VN_RELE(vp); return (NULL); } }
static streamscall int zap_qopen(queue_t *q, dev_t *devp, int oflags, int sflag, cred_t *crp) { major_t cmajor = getmajor(*devp); minor_t cminor = getminor(*devp); struct zt_chan *chan; int err; if (q->q_ptr != NULL) return (0); /* already open */ if (sflag == DRVOPEN && cmajor == CMAJOR_0) { if (cminor == 0) { /* explicit open of control device */ } else if (cminor == 253) { /* special timining device */ } else if (cminor == 254) { } else if (cminor == 255) { } else if (cminor < ZT_MAX_CHANNELS) { chan = &chans[cminor]; } else goto enxio; } else if (sflag == CLONEOPEN && cmajor == CMAJOR_0) { if ((cminor == 255 && !(chan = zt_alloc_pseudo())) || cminor != 255) goto enxio; } else goto enxio; *devp = makedevice(cmajor, chan->channo); if ((err = zt_specchan_open(NULL, qstream(q)->sd_file, chan->channo, 1))) return (err < 0 ? -err : err); q->q_ptr = WR(q)->q_ptr = (void *) chan; return (0); enxio: return (ENXIO); }
/* * ctfs_mount - the VFS_MOUNT entry point */ static int ctfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr) { ctfs_vfs_t *data; dev_t dev; gfs_dirent_t *dirent; int i; if (secpolicy_fs_mount(cr, mvp, vfsp) != 0) return (EPERM); if (mvp->v_type != VDIR) return (ENOTDIR); if ((uap->flags & MS_OVERLAY) == 0 && (mvp->v_count > 1 || (mvp->v_flag & VROOT))) return (EBUSY); data = kmem_alloc(sizeof (ctfs_vfs_t), KM_SLEEP); /* * Initialize vfs fields not initialized by VFS_INIT/domount */ vfsp->vfs_bsize = DEV_BSIZE; vfsp->vfs_fstype = ctfs_fstype; do dev = makedevice(ctfs_major, atomic_add_32_nv(&ctfs_minor, 1) & L_MAXMIN32); while (vfs_devismounted(dev)); vfs_make_fsid(&vfsp->vfs_fsid, dev, ctfs_fstype); vfsp->vfs_data = data; vfsp->vfs_dev = dev; /* * Dynamically create gfs_dirent_t array for the root directory. */ dirent = kmem_zalloc((ct_ntypes + 2) * sizeof (gfs_dirent_t), KM_SLEEP); for (i = 0; i < ct_ntypes; i++) { dirent[i].gfse_name = (char *)ct_types[i]->ct_type_name; dirent[i].gfse_ctor = ctfs_create_tdirnode; dirent[i].gfse_flags = GFS_CACHE_VNODE; } dirent[i].gfse_name = "all"; dirent[i].gfse_ctor = ctfs_create_adirnode; dirent[i].gfse_flags = GFS_CACHE_VNODE; dirent[i+1].gfse_name = NULL; /* * Create root vnode */ data->ctvfs_root = gfs_root_create(sizeof (ctfs_rootnode_t), vfsp, ctfs_ops_root, CTFS_INO_ROOT, dirent, ctfs_root_do_inode, CTFS_NAME_MAX, NULL, NULL); kmem_free(dirent, (ct_ntypes + 2) * sizeof (gfs_dirent_t)); return (0); }
static void devvt_create_snode(struct sdev_node *ddv, char *nm, struct cred *cred, int type) { int error; struct sdev_node *sdv = NULL; struct vattr vattr; struct vattr *vap = &vattr; major_t maj; minor_t min; ASSERT(RW_WRITE_HELD(&ddv->sdev_contents)); if ((maj = vt_wc_attached()) == (major_t)-1) return; if (strcmp(nm, DEVVT_ACTIVE_NAME) != 0 && strcmp(nm, DEVVT_CONSUSER_NAME) != 0 && devvt_str2minor(nm, &min) != 0) return; error = sdev_mknode(ddv, nm, &sdv, NULL, NULL, NULL, cred, SDEV_INIT); if (error || !sdv) { return; } mutex_enter(&sdv->sdev_lookup_lock); SDEV_BLOCK_OTHERS(sdv, SDEV_LOOKUP); mutex_exit(&sdv->sdev_lookup_lock); if (type & SDEV_VATTR) { *vap = devvt_vattr; vap->va_rdev = makedevice(maj, min); error = sdev_mknode(ddv, nm, &sdv, vap, NULL, NULL, cred, SDEV_READY); } else if (type & SDEV_VLINK) { char *link = kmem_zalloc(MAXPATHLEN, KM_SLEEP); (void) vt_getactive(link, MAXPATHLEN); *vap = sdev_vattr_lnk; vap->va_size = strlen(link); error = sdev_mknode(ddv, nm, &sdv, vap, NULL, (void *)link, cred, SDEV_READY); kmem_free(link, MAXPATHLEN); } if (error != 0) { SDEV_RELE(sdv); return; } mutex_enter(&sdv->sdev_lookup_lock); SDEV_UNBLOCK_OTHERS(sdv, SDEV_LOOKUP); mutex_exit(&sdv->sdev_lookup_lock); }
static int m3ua_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *crp) { m3ua_t *m3ua, **m3p = &m3ua_devices; int cmajor = getmajor(*devp); int cminor = getmajor(*devp); trace(); if (q->q_ptr != NULL) return (0); if (sflag == MODOPEN || WR(q)->q_next) return EIO; if (!cminor) { if (!m3ua_ctrlq) m3ua_ctrlq = q; else sflag = CLONEOPEN; } if (sflag == CLONEOPEN) cminor = 1; for (; cminor <= NMINORS && *m3p; m3p = &(*m3p)->next) { int dminor = getminor((*m3p)->devnum); if (cminor < dminor) break; if (cminor == dminor) { if (sflag == CLONEOPEN) { cminor++; continue; } return EIO; } } if (cminor > M3UA_MINOR) return ENXIO; *devp = makedevice(cmajor, cminor); if (!(m3ua = kmalloc(sizeof(*m3ua), GFP_KERNEL))) return ENOMEM; bzero(m3ua, sizeof(*m3ua)); q->q_ptr = WR(q)->q_ptr; m3ua->rq = RD(q); m3ua->wq = WR(q); m3ua->state = FIXME; m3ua->devnum = *devp; return (0); }
static void zvol_size_changed(zvol_state_t *zv, dev_t dev) { dev = makedevice(getmajor(dev), zv->zv_minor); VERIFY(ddi_prop_update_int64(dev, zfs_dip, "Size", zv->zv_volsize) == DDI_SUCCESS); VERIFY(ddi_prop_update_int64(dev, zfs_dip, "Nblocks", lbtodb(zv->zv_volsize)) == DDI_SUCCESS); }
/*ARGSUSED1*/ static int kcpc_open(dev_t *dev, int flags, int otyp, cred_t *cr) { processorid_t cpuid; int error; ASSERT(pcbe_ops != NULL); if ((error = secpolicy_cpc_cpu(cr)) != 0) return (error); if (getminor(*dev) != KCPC_MINOR_SHARED) return (ENXIO); if ((cpuid = curthread->t_bind_cpu) == PBIND_NONE) return (EINVAL); if (cpuid > max_cpuid) return (EINVAL); rw_enter(&kcpc_cpuctx_lock, RW_WRITER); if (++kcpc_cpuctx == 1) { ASSERT(kcpc_cpumap == NULL); /* * Bail out if DTrace is already using the counters. */ if (dtrace_cpc_in_use) { kcpc_cpuctx--; rw_exit(&kcpc_cpuctx_lock); return (EAGAIN); } kcpc_cpumap = kmem_zalloc(BT_SIZEOFMAP(max_cpuid + 1), KM_SLEEP); /* * When this device is open for processor-based contexts, * no further lwp-based contexts can be created. * * Since this is the first open, ensure that all existing * contexts are invalidated. */ kcpc_invalidate_all(); } else if (BT_TEST(kcpc_cpumap, cpuid)) { kcpc_cpuctx--; rw_exit(&kcpc_cpuctx_lock); return (EAGAIN); } else if (kcpc_hw_cpu_hook(cpuid, kcpc_cpumap) != 0) { kcpc_cpuctx--; rw_exit(&kcpc_cpuctx_lock); return (EACCES); } BT_SET(kcpc_cpumap, cpuid); rw_exit(&kcpc_cpuctx_lock); *dev = makedevice(getmajor(*dev), (minor_t)cpuid); return (0); }
/** * User context entry points * * @remarks fFlags are the flags passed to open() or to ldi_open_by_name. In * the latter case the FKLYR flag is added to indicate that the caller * is a kernel component rather than user land. */ static int vgdrvSolarisOpen(dev_t *pDev, int fFlags, int fType, cred_t *pCred) { int rc; PVBOXGUESTSESSION pSession = NULL; LogFlow(("vgdrvSolarisOpen:\n")); /* * Verify we are being opened as a character device. */ if (fType != OTYP_CHR) return EINVAL; vboxguest_state_t *pState = NULL; unsigned iOpenInstance; for (iOpenInstance = 0; iOpenInstance < 4096; iOpenInstance++) { if ( !ddi_get_soft_state(g_pvgdrvSolarisState, iOpenInstance) /* faster */ && ddi_soft_state_zalloc(g_pvgdrvSolarisState, iOpenInstance) == DDI_SUCCESS) { pState = ddi_get_soft_state(g_pvgdrvSolarisState, iOpenInstance); break; } } if (!pState) { Log(("vgdrvSolarisOpen: too many open instances.")); return ENXIO; } /* * Create a new session. */ if (!(fFlags & FKLYR)) rc = VGDrvCommonCreateUserSession(&g_DevExt, &pSession); else rc = VGDrvCommonCreateKernelSession(&g_DevExt, &pSession); if (RT_SUCCESS(rc)) { if (!(fFlags & FKLYR)) pState->pvProcRef = proc_ref(); else pState->pvProcRef = NULL; pState->pSession = pSession; *pDev = makedevice(getmajor(*pDev), iOpenInstance); Log(("vgdrvSolarisOpen: pSession=%p pState=%p pid=%d\n", pSession, pState, (int)RTProcSelf())); return 0; } /* Failed, clean up. */ ddi_soft_state_free(g_pvgdrvSolarisState, iOpenInstance); LogRel((DEVICE_NAME "::Open: VGDrvCommonCreateUserSession failed. rc=%d\n", rc)); return EFAULT; }
/*ARGSUSED*/ static int devpts_create_rvp(struct sdev_node *ddv, char *nm, void **arg, cred_t *cred, void *whatever, char *whichever) { minor_t min; major_t maj; uid_t uid; gid_t gid; timestruc_t now; struct vattr *vap = (struct vattr *)arg; if (devpts_strtol(nm, &min) != 0) { sdcmn_err7(("devpts_create_rvp: not a valid minor: %s\n", nm)); return (-1); } /* * Check if pts driver is attached and if it is * get the major number. */ maj = ptms_slave_attached(); if (maj == (major_t)-1) { sdcmn_err7(("devpts_create_rvp: slave not attached\n")); return (-1); } /* * Only allow creation of ptys allocated to our zone */ if (!ptms_minor_valid(min, &uid, &gid)) { sdcmn_err7(("devpts_create_rvp: %s not valid pty" "or not valid in this zone\n", nm)); return (-1); } /* * This is a valid pty (at least at this point in time). * Create the node by setting the attribute. The rest * is taken care of by devname_lookup_func(). */ *vap = devpts_vattr; vap->va_rdev = makedevice(maj, min); ASSERT(uid >= 0); ASSERT(gid >= 0); vap->va_uid = uid; vap->va_gid = gid; gethrestime(&now); vap->va_atime = now; vap->va_mtime = now; vap->va_ctime = now; return (0); }
/* ARGSUSED3 */ int ip_helper_stream_setup(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp, boolean_t isv6) { major_t maj; ip_helper_minfo_t *ip_minfop; ASSERT((flag & ~(FKLYR)) == IP_HELPER_STR); ASSERT(RD(q) == q); ip_minfop = kmem_alloc(sizeof (ip_helper_minfo_t), KM_SLEEP); ASSERT(ip_minfop != NULL); ip_minfop->ip_minfo_dev = 0; ip_minfop->ip_minfo_arena = NULL; /* * Clone the device, allocate minor device number */ if (ip_minor_arena_la != NULL) ip_minfop->ip_minfo_dev = inet_minor_alloc(ip_minor_arena_la); if (ip_minfop->ip_minfo_dev == 0) { /* * numbers in the large arena are exhausted * Try small arena. * Or this is a 32 bit system, 32 bit systems do not have * ip_minor_arena_la */ ip_minfop->ip_minfo_dev = inet_minor_alloc(ip_minor_arena_sa); if (ip_minfop->ip_minfo_dev == 0) { return (EBUSY); } ip_minfop->ip_minfo_arena = ip_minor_arena_sa; } else { ip_minfop->ip_minfo_arena = ip_minor_arena_la; } ASSERT(ip_minfop->ip_minfo_dev != 0); ASSERT(ip_minfop->ip_minfo_arena != NULL); RD(q)->q_ptr = WR(q)->q_ptr = ip_minfop; maj = getemajor(*devp); *devp = makedevice(maj, (ulong_t)(ip_minfop->ip_minfo_dev)); q->q_qinfo = &ip_helper_stream_rinit; WR(q)->q_qinfo = &ip_helper_stream_winit; qprocson(q); return (0); }
/* ARGSUSED */ static int evtchndrv_open(dev_t *devp, int flag, int otyp, cred_t *credp) { struct evtsoftdata *ep; minor_t minor = getminor(*devp); if (otyp == OTYP_BLK) return (ENXIO); /* * only allow open on minor = 0 - the clone device */ if (minor != 0) return (ENXIO); /* * find a free slot and grab it */ mutex_enter(&evtchndrv_clone_tab_mutex); for (minor = 1; minor < evtchndrv_nclones; minor++) { if (evtchndrv_clone_tab[minor] == 0) { evtchndrv_clone_tab[minor] = 1; break; } } mutex_exit(&evtchndrv_clone_tab_mutex); if (minor == evtchndrv_nclones) return (EAGAIN); /* Allocate softstate structure */ if (ddi_soft_state_zalloc(evtchndrv_statep, EVTCHNDRV_MINOR2INST(minor)) != DDI_SUCCESS) { mutex_enter(&evtchndrv_clone_tab_mutex); evtchndrv_clone_tab[minor] = 0; mutex_exit(&evtchndrv_clone_tab_mutex); return (EAGAIN); } ep = EVTCHNDRV_INST2SOFTS(EVTCHNDRV_MINOR2INST(minor)); /* ... and init it */ ep->dip = evtchndrv_dip; cv_init(&ep->evtchn_wait, NULL, CV_DEFAULT, NULL); mutex_init(&ep->evtchn_lock, NULL, MUTEX_DEFAULT, NULL); ep->ring = kmem_alloc(PAGESIZE, KM_SLEEP); /* clone driver */ *devp = makedevice(getmajor(*devp), minor); return (0); }
int streamscall ip2xinet_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp) { mblk_t *bp; minor_t minor; struct stroptions *sop; /* already open */ if (sflag != CLONEOPEN) return ENXIO; spin_lock(&ip2xinet_lock); /* Can only open one time */ if (ip2xinet_numopen) { spin_unlock(&ip2xinet_lock); return ENXIO; } else ip2xinet_numopen = 1; if (q->q_count != 0) printk("ip2x level:q_count is %lu", (ulong) q->q_count); /* Set up the flow control parameters and send them up to the stream head. */ minor = getminor(*devp); if ((bp = allocb(sizeof(struct stroptions), BPRI_LO)) == NULL) { spin_unlock(&ip2xinet_lock); printk("%s: allocb failed", __FUNCTION__); return ENOMEM; } ip2xinet_status.myminor = minor; ip2xinet_status.ip2x_dlstate = DL_UNATTACHED; /* These are dummy to keep track of the fact the device is open */ q->q_ptr = (char *) &ip2xinet_numopen; WR(q)->q_ptr = (char *) &ip2xinet_numopen; spin_unlock(&ip2xinet_lock); bp->b_datap->db_type = M_SETOPTS; bp->b_wptr += sizeof(struct stroptions); sop = (struct stroptions *) bp->b_rptr; sop->so_flags = SO_HIWAT | SO_LOWAT; sop->so_hiwat = ip2xinet_minfo.mi_hiwat; sop->so_lowat = ip2xinet_minfo.mi_lowat; putnext(q, bp); *devp = makedevice(getmajor(*devp), 0); return 0; }
/* ARGSUSED */ static int ksyms_open(dev_t *devp, int flag, int otyp, struct cred *cred) { minor_t clone; size_t size = 0; size_t realsize; char *addr; void *hptr = NULL; ksyms_buflist_hdr_t hdr; bzero(&hdr, sizeof (struct ksyms_buflist_hdr)); list_create(&hdr.blist, PAGESIZE, offsetof(ksyms_buflist_t, buflist_node)); if (getminor(*devp) != 0) return (ENXIO); for (;;) { realsize = ksyms_snapshot(ksyms_bcopy, hptr, size); if (realsize <= size) break; size = realsize; size = ksyms_buflist_alloc(&hdr, size); if (size == 0) return (ENOMEM); hptr = (void *)&hdr; } addr = ksyms_mapin(&hdr, realsize); ksyms_buflist_free(&hdr); if (addr == NULL) return (EOVERFLOW); /* * Reserve a clone entry. Note that we don't use clone 0 * since that's the "real" minor number. */ for (clone = 1; clone < nksyms_clones; clone++) { if (atomic_cas_ptr(&ksyms_clones[clone].ksyms_base, 0, addr) == 0) { ksyms_clones[clone].ksyms_size = realsize; *devp = makedevice(getemajor(*devp), clone); (void) ddi_prop_update_int(*devp, ksyms_devi, "size", realsize); modunload_disable(); return (0); } } cmn_err(CE_NOTE, "ksyms: too many open references"); (void) as_unmap(curproc->p_as, addr, roundup(realsize, PAGESIZE)); return (ENXIO); }
static int zfs_create_unique_device(dev_t *dev) { major_t new_major; do { ASSERT3U(zfs_minor, <=, MAXMIN32); minor_t start = zfs_minor; do { mutex_enter(&zfs_dev_mtx); if (zfs_minor >= MAXMIN32) { /* * If we're still using the real major * keep out of /dev/zfs and /dev/zvol minor * number space. If we're using a getudev()'ed * major number, we can use all of its minors. */ if (zfs_major == ddi_name_to_major(ZFS_DRIVER)) zfs_minor = ZFS_MIN_MINOR; else zfs_minor = 0; } else { zfs_minor++; } *dev = makedevice(zfs_major, zfs_minor); mutex_exit(&zfs_dev_mtx); } while (vfs_devismounted(*dev) && zfs_minor != start); if (zfs_minor == start) { /* * We are using all ~262,000 minor numbers for the * current major number. Create a new major number. */ if ((new_major = getudev()) == (major_t)-1) { cmn_err(CE_WARN, "zfs_mount: Can't get unique major " "device number."); return (-1); } mutex_enter(&zfs_dev_mtx); zfs_major = new_major; zfs_minor = 0; mutex_exit(&zfs_dev_mtx); } else { break; } /* CONSTANTCONDITION */ } while (1); return (0); }
static void zvol_size_changed(uint64_t volsize, major_t maj, minor_t min) { dev_t dev = makedevice(maj, min); VERIFY(ddi_prop_update_int64(dev, zfs_dip, "Size", volsize) == DDI_SUCCESS); VERIFY(ddi_prop_update_int64(dev, zfs_dip, "Nblocks", lbtodb(volsize)) == DDI_SUCCESS); /* Notify specfs to invalidate the cached size */ spec_size_invalidate(dev, VBLK); spec_size_invalidate(dev, VCHR); }
/* ARGSUSED */ static int sadopen( queue_t *qp, /* pointer to read queue */ dev_t *devp, /* major/minor device of stream */ int flag, /* file open flags */ int sflag, /* stream open flags */ cred_t *credp) /* user credentials */ { int i; if (sflag) /* no longer called from clone driver */ return (EINVAL); /* * Both USRMIN and ADMMIN are clone interfaces. */ for (i = 0; i < sadcnt; i++) if (saddev[i].sa_qp == NULL) break; if (i >= sadcnt) /* no such device */ return (ENXIO); switch (getminor(*devp)) { case USRMIN: /* mere mortal */ saddev[i].sa_flags = 0; break; case ADMMIN: /* privileged user */ saddev[i].sa_flags = SADPRIV; break; default: return (EINVAL); } saddev[i].sa_qp = qp; qp->q_ptr = (caddr_t)&saddev[i]; WR(qp)->q_ptr = (caddr_t)&saddev[i]; /* * NOTE: should the ADMMIN or USRMIN minors change * then so should the offset of 2 below * Both USRMIN and ADMMIN are clone interfaces and * therefore their minor numbers (0 and 1) are reserved. */ *devp = makedevice(getemajor(*devp), i + 2); qprocson(qp); return (0); }
/* ARGSUSED */ static int cryptoadm_open(dev_t *devp, int flag, int otyp, cred_t *credp) { if (otyp != OTYP_CHR || cryptoadm_dip == NULL) return (ENXIO); /* exclusive opens are not supported */ if (flag & FEXCL) return (ENOTSUP); *devp = makedevice(getmajor(*devp), 0); kcf_sched_start(); return (0); }
static int VBoxUSBMonSolarisOpen(dev_t *pDev, int fFlag, int fType, cred_t *pCred) { vboxusbmon_state_t *pState = NULL; unsigned iOpenInstance; LogFunc((DEVICE_NAME ": VBoxUSBMonSolarisOpen\n")); /* * Verify we are being opened as a character device. */ if (fType != OTYP_CHR) return EINVAL; /* * Verify that we're called after attach. */ if (!g_pDip) { LogRel((DEVICE_NAME ": VBoxUSBMonSolarisOpen: Invalid state for opening\n")); return ENXIO; } for (iOpenInstance = 0; iOpenInstance < 4096; iOpenInstance++) { if ( !ddi_get_soft_state(g_pVBoxUSBMonSolarisState, iOpenInstance) /* faster */ && ddi_soft_state_zalloc(g_pVBoxUSBMonSolarisState, iOpenInstance) == DDI_SUCCESS) { pState = ddi_get_soft_state(g_pVBoxUSBMonSolarisState, iOpenInstance); break; } } if (!pState) { LogRel((DEVICE_NAME ": VBoxUSBMonSolarisOpen: Too many open instances")); return ENXIO; } pState->Process = RTProcSelf(); *pDev = makedevice(getmajor(*pDev), iOpenInstance); NOREF(fFlag); NOREF(pCred); return 0; }
/*ARGSUSED*/ static int opromopen(dev_t *devp, int flag, int otyp, cred_t *credp) { int m; struct oprom_state *st = oprom_state; if (getminor(*devp) != 0) return (ENXIO); mutex_enter(&oprom_lock); for (m = 0; m < MAX_OPENS; m++) if (st->already_open) st++; else { st->already_open = 1; /* * It's ours. */ st->current_id = (pnode_t)0; ASSERT(st->snapshot == NULL && st->size == 0); ASSERT(st->ioc_state == IOC_IDLE); break; } mutex_exit(&oprom_lock); if (m == MAX_OPENS) { /* * "Thank you for calling, but all our lines are * busy at the moment.." * * We could get sophisticated here, and go into a * sleep-retry loop .. but hey, I just can't see * that many processes sitting in this driver. * * (And if it does become possible, then we should * change the interface so that the 'state' is held * external to the driver) */ return (EAGAIN); } *devp = makedevice(getmajor(*devp), (minor_t)m); return (0); }
/*ARGSUSED*/ static int nsmb_open(dev_t *dev, int flags, int otyp, cred_t *cr) { smb_dev_t *sdp; minor_t m; mutex_enter(&dev_lck); for (m = last_minor + 1; m != last_minor; m++) { if (m > NSMB_MAX_MINOR) m = NSMB_MIN_MINOR; if (ddi_get_soft_state(statep, m) == NULL) { last_minor = m; goto found; } } /* No available minor units. */ mutex_exit(&dev_lck); return (ENXIO); found: /* NB: dev_lck still held */ if (ddi_soft_state_zalloc(statep, m) == DDI_FAILURE) { mutex_exit(&dev_lck); return (ENXIO); } if ((sdp = ddi_get_soft_state(statep, m)) == NULL) { mutex_exit(&dev_lck); return (ENXIO); } *dev = makedevice(nsmb_major, m); mutex_exit(&dev_lck); sdp->sd_cred = cr; sdp->sd_smbfid = -1; sdp->sd_flags |= NSMBFL_OPEN; sdp->zoneid = crgetzoneid(cr); return (0); }