126453f35SJulian Elischer /*- 266cdbc28SPoul-Henning Kamp * Copyright (c) 1999-2002 Poul-Henning Kamp 326453f35SJulian Elischer * All rights reserved. 426453f35SJulian Elischer * 526453f35SJulian Elischer * Redistribution and use in source and binary forms, with or without 626453f35SJulian Elischer * modification, are permitted provided that the following conditions 726453f35SJulian Elischer * are met: 826453f35SJulian Elischer * 1. Redistributions of source code must retain the above copyright 926453f35SJulian Elischer * notice, this list of conditions and the following disclaimer. 1026453f35SJulian Elischer * 2. Redistributions in binary form must reproduce the above copyright 1126453f35SJulian Elischer * notice, this list of conditions and the following disclaimer in the 1226453f35SJulian Elischer * documentation and/or other materials provided with the distribution. 1326453f35SJulian Elischer * 1466cdbc28SPoul-Henning Kamp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1566cdbc28SPoul-Henning Kamp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1626453f35SJulian Elischer * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1766cdbc28SPoul-Henning Kamp * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1826453f35SJulian Elischer * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1926453f35SJulian Elischer * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2026453f35SJulian Elischer * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2126453f35SJulian Elischer * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2226453f35SJulian Elischer * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2326453f35SJulian Elischer * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2426453f35SJulian Elischer * SUCH DAMAGE. 2526453f35SJulian Elischer */ 2626453f35SJulian Elischer 27677b542eSDavid E. O'Brien #include <sys/cdefs.h> 28677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$"); 29677b542eSDavid E. O'Brien 3026453f35SJulian Elischer #include <sys/param.h> 31698bfad7SPoul-Henning Kamp #include <sys/kernel.h> 32f8a760b3SJulian Elischer #include <sys/systm.h> 3348504cc2SKonstantin Belousov #include <sys/bus.h> 3402574b19SPoul-Henning Kamp #include <sys/bio.h> 351b567820SBrian Feldman #include <sys/lock.h> 361b567820SBrian Feldman #include <sys/mutex.h> 37ecbb00a2SDoug Rabson #include <sys/module.h> 38698bfad7SPoul-Henning Kamp #include <sys/malloc.h> 3926453f35SJulian Elischer #include <sys/conf.h> 401dfcbb0cSJulian Elischer #include <sys/vnode.h> 41698bfad7SPoul-Henning Kamp #include <sys/queue.h> 42b2941431SPoul-Henning Kamp #include <sys/poll.h> 43de10ffa5SKonstantin Belousov #include <sys/sx.h> 44db901281SPoul-Henning Kamp #include <sys/ctype.h> 45d26dd2d9SRobert Watson #include <sys/ucred.h> 46de10ffa5SKonstantin Belousov #include <sys/taskqueue.h> 470ef1c826SPoul-Henning Kamp #include <machine/stdarg.h> 481dfcbb0cSJulian Elischer 499c0af131SPoul-Henning Kamp #include <fs/devfs/devfs_int.h> 5064345f0bSJohn Baldwin #include <vm/vm.h> 519c0af131SPoul-Henning Kamp 529ef295b7SPoul-Henning Kamp static MALLOC_DEFINE(M_DEVT, "cdev", "cdev storage"); 53698bfad7SPoul-Henning Kamp 54e606a3c6SPoul-Henning Kamp struct mtx devmtx; 55aa2f6ddcSPoul-Henning Kamp static void destroy_devl(struct cdev *dev); 569d53363bSKonstantin Belousov static int destroy_dev_sched_cbl(struct cdev *dev, 579d53363bSKonstantin Belousov void (*cb)(void *), void *arg); 58268e76d8SJohn Baldwin static void destroy_dev_tq(void *ctx, int pending); 59f1bb758dSKonstantin Belousov static int make_dev_credv(int flags, struct cdev **dres, struct cdevsw *devsw, 60f1bb758dSKonstantin Belousov int unit, struct ucred *cr, uid_t uid, gid_t gid, int mode, const char *fmt, 61d26dd2d9SRobert Watson va_list ap); 62f3732fd1SPoul-Henning Kamp 639bc911d4SKonstantin Belousov static struct cdev_priv_list cdevp_free_list = 649bc911d4SKonstantin Belousov TAILQ_HEAD_INITIALIZER(cdevp_free_list); 65aeeb4202SKonstantin Belousov static SLIST_HEAD(free_cdevsw, cdevsw) cdevsw_gt_post_list = 6613e403fdSAntoine Brodin SLIST_HEAD_INITIALIZER(cdevsw_gt_post_list); 679bc911d4SKonstantin Belousov 68a0e78d2eSPoul-Henning Kamp void 69a0e78d2eSPoul-Henning Kamp dev_lock(void) 70cd690b60SPoul-Henning Kamp { 718c4b6380SJohn Baldwin 72cd690b60SPoul-Henning Kamp mtx_lock(&devmtx); 73cd690b60SPoul-Henning Kamp } 74cd690b60SPoul-Henning Kamp 75aeeb4202SKonstantin Belousov /* 76aeeb4202SKonstantin Belousov * Free all the memory collected while the cdev mutex was 77aeeb4202SKonstantin Belousov * locked. Since devmtx is after the system map mutex, free() cannot 78aeeb4202SKonstantin Belousov * be called immediately and is postponed until cdev mutex can be 79aeeb4202SKonstantin Belousov * dropped. 80aeeb4202SKonstantin Belousov */ 819bc911d4SKonstantin Belousov static void 829bc911d4SKonstantin Belousov dev_unlock_and_free(void) 839bc911d4SKonstantin Belousov { 84aeeb4202SKonstantin Belousov struct cdev_priv_list cdp_free; 85aeeb4202SKonstantin Belousov struct free_cdevsw csw_free; 869bc911d4SKonstantin Belousov struct cdev_priv *cdp; 87aeeb4202SKonstantin Belousov struct cdevsw *csw; 889bc911d4SKonstantin Belousov 899bc911d4SKonstantin Belousov mtx_assert(&devmtx, MA_OWNED); 90aeeb4202SKonstantin Belousov 91aeeb4202SKonstantin Belousov /* 92aeeb4202SKonstantin Belousov * Make the local copy of the list heads while the dev_mtx is 93aeeb4202SKonstantin Belousov * held. Free it later. 94aeeb4202SKonstantin Belousov */ 95aeeb4202SKonstantin Belousov TAILQ_INIT(&cdp_free); 96aeeb4202SKonstantin Belousov TAILQ_CONCAT(&cdp_free, &cdevp_free_list, cdp_list); 97aeeb4202SKonstantin Belousov csw_free = cdevsw_gt_post_list; 98aeeb4202SKonstantin Belousov SLIST_INIT(&cdevsw_gt_post_list); 99aeeb4202SKonstantin Belousov 1009bc911d4SKonstantin Belousov mtx_unlock(&devmtx); 101aeeb4202SKonstantin Belousov 102aeeb4202SKonstantin Belousov while ((cdp = TAILQ_FIRST(&cdp_free)) != NULL) { 103aeeb4202SKonstantin Belousov TAILQ_REMOVE(&cdp_free, cdp, cdp_list); 1049bc911d4SKonstantin Belousov devfs_free(&cdp->cdp_c); 1059bc911d4SKonstantin Belousov } 106aeeb4202SKonstantin Belousov while ((csw = SLIST_FIRST(&csw_free)) != NULL) { 107aeeb4202SKonstantin Belousov SLIST_REMOVE_HEAD(&csw_free, d_postfree_list); 108aeeb4202SKonstantin Belousov free(csw, M_DEVT); 109aeeb4202SKonstantin Belousov } 1109bc911d4SKonstantin Belousov } 1119bc911d4SKonstantin Belousov 1129bc911d4SKonstantin Belousov static void 1139bc911d4SKonstantin Belousov dev_free_devlocked(struct cdev *cdev) 1149bc911d4SKonstantin Belousov { 1159bc911d4SKonstantin Belousov struct cdev_priv *cdp; 1169bc911d4SKonstantin Belousov 1179bc911d4SKonstantin Belousov mtx_assert(&devmtx, MA_OWNED); 11805427aafSKonstantin Belousov cdp = cdev2priv(cdev); 1199bc911d4SKonstantin Belousov TAILQ_INSERT_HEAD(&cdevp_free_list, cdp, cdp_list); 1209bc911d4SKonstantin Belousov } 1219bc911d4SKonstantin Belousov 122aeeb4202SKonstantin Belousov static void 123aeeb4202SKonstantin Belousov cdevsw_free_devlocked(struct cdevsw *csw) 124aeeb4202SKonstantin Belousov { 125aeeb4202SKonstantin Belousov 126aeeb4202SKonstantin Belousov mtx_assert(&devmtx, MA_OWNED); 127aeeb4202SKonstantin Belousov SLIST_INSERT_HEAD(&cdevsw_gt_post_list, csw, d_postfree_list); 128aeeb4202SKonstantin Belousov } 129aeeb4202SKonstantin Belousov 130a0e78d2eSPoul-Henning Kamp void 131a0e78d2eSPoul-Henning Kamp dev_unlock(void) 132cd690b60SPoul-Henning Kamp { 1332c15afd8SPoul-Henning Kamp 134cd690b60SPoul-Henning Kamp mtx_unlock(&devmtx); 135cd690b60SPoul-Henning Kamp } 136cd690b60SPoul-Henning Kamp 137cd690b60SPoul-Henning Kamp void 1389477d73eSPoul-Henning Kamp dev_ref(struct cdev *dev) 1399477d73eSPoul-Henning Kamp { 1409477d73eSPoul-Henning Kamp 1419477d73eSPoul-Henning Kamp mtx_assert(&devmtx, MA_NOTOWNED); 1429477d73eSPoul-Henning Kamp mtx_lock(&devmtx); 1439477d73eSPoul-Henning Kamp dev->si_refcount++; 1449477d73eSPoul-Henning Kamp mtx_unlock(&devmtx); 1459477d73eSPoul-Henning Kamp } 1469477d73eSPoul-Henning Kamp 1479477d73eSPoul-Henning Kamp void 148eb151cb9SPoul-Henning Kamp dev_refl(struct cdev *dev) 149cd690b60SPoul-Henning Kamp { 1502c15afd8SPoul-Henning Kamp 1511a1457d4SPoul-Henning Kamp mtx_assert(&devmtx, MA_OWNED); 152cd690b60SPoul-Henning Kamp dev->si_refcount++; 153cd690b60SPoul-Henning Kamp } 154cd690b60SPoul-Henning Kamp 155cd690b60SPoul-Henning Kamp void 156aa2f6ddcSPoul-Henning Kamp dev_rel(struct cdev *dev) 157cd690b60SPoul-Henning Kamp { 158aa2f6ddcSPoul-Henning Kamp int flag = 0; 159a0e78d2eSPoul-Henning Kamp 160ba285125SPoul-Henning Kamp mtx_assert(&devmtx, MA_NOTOWNED); 161ba285125SPoul-Henning Kamp dev_lock(); 162cd690b60SPoul-Henning Kamp dev->si_refcount--; 163cd690b60SPoul-Henning Kamp KASSERT(dev->si_refcount >= 0, 164cd690b60SPoul-Henning Kamp ("dev_rel(%s) gave negative count", devtoname(dev))); 165e606a3c6SPoul-Henning Kamp #if 0 166aa2f6ddcSPoul-Henning Kamp if (dev->si_usecount == 0 && 167aa2f6ddcSPoul-Henning Kamp (dev->si_flags & SI_CHEAPCLONE) && (dev->si_flags & SI_NAMED)) 168e606a3c6SPoul-Henning Kamp ; 169e606a3c6SPoul-Henning Kamp else 170e606a3c6SPoul-Henning Kamp #endif 171cd690b60SPoul-Henning Kamp if (dev->si_devsw == NULL && dev->si_refcount == 0) { 172cd690b60SPoul-Henning Kamp LIST_REMOVE(dev, si_list); 173ba285125SPoul-Henning Kamp flag = 1; 174ba285125SPoul-Henning Kamp } 175ba285125SPoul-Henning Kamp dev_unlock(); 176ba285125SPoul-Henning Kamp if (flag) 177e606a3c6SPoul-Henning Kamp devfs_free(dev); 178cd690b60SPoul-Henning Kamp } 179ba285125SPoul-Henning Kamp 1802c15afd8SPoul-Henning Kamp struct cdevsw * 1813979450bSKonstantin Belousov dev_refthread(struct cdev *dev, int *ref) 1822c15afd8SPoul-Henning Kamp { 1832c15afd8SPoul-Henning Kamp struct cdevsw *csw; 184de10ffa5SKonstantin Belousov struct cdev_priv *cdp; 1852c15afd8SPoul-Henning Kamp 1862c15afd8SPoul-Henning Kamp mtx_assert(&devmtx, MA_NOTOWNED); 1873979450bSKonstantin Belousov if ((dev->si_flags & SI_ETERNAL) != 0) { 1883979450bSKonstantin Belousov *ref = 0; 1893979450bSKonstantin Belousov return (dev->si_devsw); 1903979450bSKonstantin Belousov } 1912c15afd8SPoul-Henning Kamp dev_lock(); 1922c15afd8SPoul-Henning Kamp csw = dev->si_devsw; 193de10ffa5SKonstantin Belousov if (csw != NULL) { 19405427aafSKonstantin Belousov cdp = cdev2priv(dev); 195de10ffa5SKonstantin Belousov if ((cdp->cdp_flags & CDP_SCHED_DTR) == 0) 1969e8bd2acSAlexander Motin atomic_add_long(&dev->si_threadcount, 1); 197de10ffa5SKonstantin Belousov else 198de10ffa5SKonstantin Belousov csw = NULL; 199de10ffa5SKonstantin Belousov } 2002c15afd8SPoul-Henning Kamp dev_unlock(); 2013979450bSKonstantin Belousov *ref = 1; 2022c15afd8SPoul-Henning Kamp return (csw); 2032c15afd8SPoul-Henning Kamp } 2042c15afd8SPoul-Henning Kamp 2051663075cSKonstantin Belousov struct cdevsw * 2063979450bSKonstantin Belousov devvn_refthread(struct vnode *vp, struct cdev **devp, int *ref) 2071663075cSKonstantin Belousov { 2081663075cSKonstantin Belousov struct cdevsw *csw; 209de10ffa5SKonstantin Belousov struct cdev_priv *cdp; 2103979450bSKonstantin Belousov struct cdev *dev; 2111663075cSKonstantin Belousov 2121663075cSKonstantin Belousov mtx_assert(&devmtx, MA_NOTOWNED); 2133979450bSKonstantin Belousov if ((vp->v_vflag & VV_ETERNALDEV) != 0) { 2143979450bSKonstantin Belousov dev = vp->v_rdev; 2153979450bSKonstantin Belousov if (dev == NULL) 2163979450bSKonstantin Belousov return (NULL); 2173979450bSKonstantin Belousov KASSERT((dev->si_flags & SI_ETERNAL) != 0, 2183979450bSKonstantin Belousov ("Not eternal cdev")); 2193979450bSKonstantin Belousov *ref = 0; 2203979450bSKonstantin Belousov csw = dev->si_devsw; 2213979450bSKonstantin Belousov KASSERT(csw != NULL, ("Eternal cdev is destroyed")); 2223979450bSKonstantin Belousov *devp = dev; 2233979450bSKonstantin Belousov return (csw); 2243979450bSKonstantin Belousov } 2253979450bSKonstantin Belousov 2261663075cSKonstantin Belousov csw = NULL; 2271663075cSKonstantin Belousov dev_lock(); 2283979450bSKonstantin Belousov dev = vp->v_rdev; 2293979450bSKonstantin Belousov if (dev == NULL) { 2303979450bSKonstantin Belousov dev_unlock(); 2313979450bSKonstantin Belousov return (NULL); 2321663075cSKonstantin Belousov } 2333979450bSKonstantin Belousov cdp = cdev2priv(dev); 2343979450bSKonstantin Belousov if ((cdp->cdp_flags & CDP_SCHED_DTR) == 0) { 2353979450bSKonstantin Belousov csw = dev->si_devsw; 2363979450bSKonstantin Belousov if (csw != NULL) 2379e8bd2acSAlexander Motin atomic_add_long(&dev->si_threadcount, 1); 238de10ffa5SKonstantin Belousov } 2391663075cSKonstantin Belousov dev_unlock(); 2403979450bSKonstantin Belousov if (csw != NULL) { 2413979450bSKonstantin Belousov *devp = dev; 2423979450bSKonstantin Belousov *ref = 1; 2433979450bSKonstantin Belousov } 2441663075cSKonstantin Belousov return (csw); 2451663075cSKonstantin Belousov } 2461663075cSKonstantin Belousov 2472c15afd8SPoul-Henning Kamp void 2483979450bSKonstantin Belousov dev_relthread(struct cdev *dev, int ref) 2492c15afd8SPoul-Henning Kamp { 2502c15afd8SPoul-Henning Kamp 2512c15afd8SPoul-Henning Kamp mtx_assert(&devmtx, MA_NOTOWNED); 2523979450bSKonstantin Belousov if (!ref) 2533979450bSKonstantin Belousov return; 25406fe1129SKonstantin Belousov KASSERT(dev->si_threadcount > 0, 25506fe1129SKonstantin Belousov ("%s threadcount is wrong", dev->si_name)); 2569e8bd2acSAlexander Motin atomic_subtract_rel_long(&dev->si_threadcount, 1); 2572c15afd8SPoul-Henning Kamp } 258cd690b60SPoul-Henning Kamp 259b2941431SPoul-Henning Kamp int 260b2941431SPoul-Henning Kamp nullop(void) 261b2941431SPoul-Henning Kamp { 262b2941431SPoul-Henning Kamp 263b2941431SPoul-Henning Kamp return (0); 264b2941431SPoul-Henning Kamp } 265b2941431SPoul-Henning Kamp 266b2941431SPoul-Henning Kamp int 267b2941431SPoul-Henning Kamp eopnotsupp(void) 268b2941431SPoul-Henning Kamp { 269b2941431SPoul-Henning Kamp 270b2941431SPoul-Henning Kamp return (EOPNOTSUPP); 271b2941431SPoul-Henning Kamp } 27202574b19SPoul-Henning Kamp 27302574b19SPoul-Henning Kamp static int 27402574b19SPoul-Henning Kamp enxio(void) 27502574b19SPoul-Henning Kamp { 27602574b19SPoul-Henning Kamp return (ENXIO); 27702574b19SPoul-Henning Kamp } 27802574b19SPoul-Henning Kamp 279b2941431SPoul-Henning Kamp static int 280b2941431SPoul-Henning Kamp enodev(void) 281b2941431SPoul-Henning Kamp { 282b2941431SPoul-Henning Kamp return (ENODEV); 283b2941431SPoul-Henning Kamp } 284b2941431SPoul-Henning Kamp 285b2941431SPoul-Henning Kamp /* Define a dead_cdevsw for use when devices leave unexpectedly. */ 286b2941431SPoul-Henning Kamp 28702574b19SPoul-Henning Kamp #define dead_open (d_open_t *)enxio 28802574b19SPoul-Henning Kamp #define dead_close (d_close_t *)enxio 28902574b19SPoul-Henning Kamp #define dead_read (d_read_t *)enxio 29002574b19SPoul-Henning Kamp #define dead_write (d_write_t *)enxio 29102574b19SPoul-Henning Kamp #define dead_ioctl (d_ioctl_t *)enxio 292b2941431SPoul-Henning Kamp #define dead_poll (d_poll_t *)enodev 293b2941431SPoul-Henning Kamp #define dead_mmap (d_mmap_t *)enodev 29402574b19SPoul-Henning Kamp 29502574b19SPoul-Henning Kamp static void 29602574b19SPoul-Henning Kamp dead_strategy(struct bio *bp) 29702574b19SPoul-Henning Kamp { 29802574b19SPoul-Henning Kamp 29902574b19SPoul-Henning Kamp biofinish(bp, NULL, ENXIO); 30002574b19SPoul-Henning Kamp } 30102574b19SPoul-Henning Kamp 3022c6b49f6SPoul-Henning Kamp #define dead_dump (dumper_t *)enxio 30302574b19SPoul-Henning Kamp #define dead_kqfilter (d_kqfilter_t *)enxio 30464345f0bSJohn Baldwin #define dead_mmap_single (d_mmap_single_t *)enodev 30502574b19SPoul-Henning Kamp 30602574b19SPoul-Henning Kamp static struct cdevsw dead_cdevsw = { 307dc08ffecSPoul-Henning Kamp .d_version = D_VERSION, 3087ac40f5fSPoul-Henning Kamp .d_open = dead_open, 3097ac40f5fSPoul-Henning Kamp .d_close = dead_close, 3107ac40f5fSPoul-Henning Kamp .d_read = dead_read, 3117ac40f5fSPoul-Henning Kamp .d_write = dead_write, 3127ac40f5fSPoul-Henning Kamp .d_ioctl = dead_ioctl, 3137ac40f5fSPoul-Henning Kamp .d_poll = dead_poll, 3147ac40f5fSPoul-Henning Kamp .d_mmap = dead_mmap, 3157ac40f5fSPoul-Henning Kamp .d_strategy = dead_strategy, 3167ac40f5fSPoul-Henning Kamp .d_name = "dead", 3177ac40f5fSPoul-Henning Kamp .d_dump = dead_dump, 31864345f0bSJohn Baldwin .d_kqfilter = dead_kqfilter, 31964345f0bSJohn Baldwin .d_mmap_single = dead_mmap_single 32002574b19SPoul-Henning Kamp }; 32102574b19SPoul-Henning Kamp 322b2941431SPoul-Henning Kamp /* Default methods if driver does not specify method */ 323b2941431SPoul-Henning Kamp 324b2941431SPoul-Henning Kamp #define null_open (d_open_t *)nullop 325b2941431SPoul-Henning Kamp #define null_close (d_close_t *)nullop 326b2941431SPoul-Henning Kamp #define no_read (d_read_t *)enodev 327b2941431SPoul-Henning Kamp #define no_write (d_write_t *)enodev 328b2941431SPoul-Henning Kamp #define no_ioctl (d_ioctl_t *)enodev 329cfd7baceSRobert Noland #define no_mmap (d_mmap_t *)enodev 330ad3b9257SJohn-Mark Gurney #define no_kqfilter (d_kqfilter_t *)enodev 33164345f0bSJohn Baldwin #define no_mmap_single (d_mmap_single_t *)enodev 332b2941431SPoul-Henning Kamp 333b2941431SPoul-Henning Kamp static void 334b2941431SPoul-Henning Kamp no_strategy(struct bio *bp) 335b2941431SPoul-Henning Kamp { 336b2941431SPoul-Henning Kamp 337b2941431SPoul-Henning Kamp biofinish(bp, NULL, ENODEV); 338b2941431SPoul-Henning Kamp } 339b2941431SPoul-Henning Kamp 340b2941431SPoul-Henning Kamp static int 34189c9c53dSPoul-Henning Kamp no_poll(struct cdev *dev __unused, int events, struct thread *td __unused) 342b2941431SPoul-Henning Kamp { 343b2941431SPoul-Henning Kamp 344125dcf8cSKonstantin Belousov return (poll_no_poll(events)); 345b2941431SPoul-Henning Kamp } 346b2941431SPoul-Henning Kamp 347b2941431SPoul-Henning Kamp #define no_dump (dumper_t *)enodev 3484e4a7663SPoul-Henning Kamp 349516ad423SPoul-Henning Kamp static int 350516ad423SPoul-Henning Kamp giant_open(struct cdev *dev, int oflags, int devtype, struct thread *td) 351516ad423SPoul-Henning Kamp { 352aeeb4202SKonstantin Belousov struct cdevsw *dsw; 3533979450bSKonstantin Belousov int ref, retval; 354516ad423SPoul-Henning Kamp 3553979450bSKonstantin Belousov dsw = dev_refthread(dev, &ref); 356aeeb4202SKonstantin Belousov if (dsw == NULL) 357aeeb4202SKonstantin Belousov return (ENXIO); 358516ad423SPoul-Henning Kamp mtx_lock(&Giant); 359aeeb4202SKonstantin Belousov retval = dsw->d_gianttrick->d_open(dev, oflags, devtype, td); 360516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 3613979450bSKonstantin Belousov dev_relthread(dev, ref); 362516ad423SPoul-Henning Kamp return (retval); 363516ad423SPoul-Henning Kamp } 364516ad423SPoul-Henning Kamp 365516ad423SPoul-Henning Kamp static int 3669e223287SKonstantin Belousov giant_fdopen(struct cdev *dev, int oflags, struct thread *td, struct file *fp) 367516ad423SPoul-Henning Kamp { 368aeeb4202SKonstantin Belousov struct cdevsw *dsw; 3693979450bSKonstantin Belousov int ref, retval; 370516ad423SPoul-Henning Kamp 3713979450bSKonstantin Belousov dsw = dev_refthread(dev, &ref); 372aeeb4202SKonstantin Belousov if (dsw == NULL) 373aeeb4202SKonstantin Belousov return (ENXIO); 374516ad423SPoul-Henning Kamp mtx_lock(&Giant); 375aeeb4202SKonstantin Belousov retval = dsw->d_gianttrick->d_fdopen(dev, oflags, td, fp); 376516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 3773979450bSKonstantin Belousov dev_relthread(dev, ref); 378516ad423SPoul-Henning Kamp return (retval); 379516ad423SPoul-Henning Kamp } 380516ad423SPoul-Henning Kamp 381516ad423SPoul-Henning Kamp static int 382516ad423SPoul-Henning Kamp giant_close(struct cdev *dev, int fflag, int devtype, struct thread *td) 383516ad423SPoul-Henning Kamp { 384aeeb4202SKonstantin Belousov struct cdevsw *dsw; 3853979450bSKonstantin Belousov int ref, retval; 386516ad423SPoul-Henning Kamp 3873979450bSKonstantin Belousov dsw = dev_refthread(dev, &ref); 388aeeb4202SKonstantin Belousov if (dsw == NULL) 389aeeb4202SKonstantin Belousov return (ENXIO); 390516ad423SPoul-Henning Kamp mtx_lock(&Giant); 391aeeb4202SKonstantin Belousov retval = dsw->d_gianttrick->d_close(dev, fflag, devtype, td); 392516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 3933979450bSKonstantin Belousov dev_relthread(dev, ref); 394516ad423SPoul-Henning Kamp return (retval); 395516ad423SPoul-Henning Kamp } 396516ad423SPoul-Henning Kamp 397516ad423SPoul-Henning Kamp static void 398516ad423SPoul-Henning Kamp giant_strategy(struct bio *bp) 399516ad423SPoul-Henning Kamp { 400aeeb4202SKonstantin Belousov struct cdevsw *dsw; 401aeeb4202SKonstantin Belousov struct cdev *dev; 4023979450bSKonstantin Belousov int ref; 403516ad423SPoul-Henning Kamp 404aeeb4202SKonstantin Belousov dev = bp->bio_dev; 4053979450bSKonstantin Belousov dsw = dev_refthread(dev, &ref); 406aeeb4202SKonstantin Belousov if (dsw == NULL) { 407aeeb4202SKonstantin Belousov biofinish(bp, NULL, ENXIO); 408aeeb4202SKonstantin Belousov return; 409aeeb4202SKonstantin Belousov } 410516ad423SPoul-Henning Kamp mtx_lock(&Giant); 411aeeb4202SKonstantin Belousov dsw->d_gianttrick->d_strategy(bp); 412516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 4133979450bSKonstantin Belousov dev_relthread(dev, ref); 414516ad423SPoul-Henning Kamp } 415516ad423SPoul-Henning Kamp 416516ad423SPoul-Henning Kamp static int 417516ad423SPoul-Henning Kamp giant_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct thread *td) 418516ad423SPoul-Henning Kamp { 419aeeb4202SKonstantin Belousov struct cdevsw *dsw; 4203979450bSKonstantin Belousov int ref, retval; 421516ad423SPoul-Henning Kamp 4223979450bSKonstantin Belousov dsw = dev_refthread(dev, &ref); 423aeeb4202SKonstantin Belousov if (dsw == NULL) 424aeeb4202SKonstantin Belousov return (ENXIO); 425516ad423SPoul-Henning Kamp mtx_lock(&Giant); 42635b45029SKonstantin Belousov retval = dsw->d_gianttrick->d_ioctl(dev, cmd, data, fflag, td); 427516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 4283979450bSKonstantin Belousov dev_relthread(dev, ref); 429516ad423SPoul-Henning Kamp return (retval); 430516ad423SPoul-Henning Kamp } 431516ad423SPoul-Henning Kamp 432516ad423SPoul-Henning Kamp static int 433516ad423SPoul-Henning Kamp giant_read(struct cdev *dev, struct uio *uio, int ioflag) 434516ad423SPoul-Henning Kamp { 435aeeb4202SKonstantin Belousov struct cdevsw *dsw; 4363979450bSKonstantin Belousov int ref, retval; 437516ad423SPoul-Henning Kamp 4383979450bSKonstantin Belousov dsw = dev_refthread(dev, &ref); 439aeeb4202SKonstantin Belousov if (dsw == NULL) 440aeeb4202SKonstantin Belousov return (ENXIO); 441516ad423SPoul-Henning Kamp mtx_lock(&Giant); 44235b45029SKonstantin Belousov retval = dsw->d_gianttrick->d_read(dev, uio, ioflag); 443516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 4443979450bSKonstantin Belousov dev_relthread(dev, ref); 445516ad423SPoul-Henning Kamp return (retval); 446516ad423SPoul-Henning Kamp } 447516ad423SPoul-Henning Kamp 448516ad423SPoul-Henning Kamp static int 449516ad423SPoul-Henning Kamp giant_write(struct cdev *dev, struct uio *uio, int ioflag) 450516ad423SPoul-Henning Kamp { 451aeeb4202SKonstantin Belousov struct cdevsw *dsw; 4523979450bSKonstantin Belousov int ref, retval; 453516ad423SPoul-Henning Kamp 4543979450bSKonstantin Belousov dsw = dev_refthread(dev, &ref); 455aeeb4202SKonstantin Belousov if (dsw == NULL) 456aeeb4202SKonstantin Belousov return (ENXIO); 457516ad423SPoul-Henning Kamp mtx_lock(&Giant); 458aeeb4202SKonstantin Belousov retval = dsw->d_gianttrick->d_write(dev, uio, ioflag); 459516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 4603979450bSKonstantin Belousov dev_relthread(dev, ref); 461516ad423SPoul-Henning Kamp return (retval); 462516ad423SPoul-Henning Kamp } 463516ad423SPoul-Henning Kamp 464516ad423SPoul-Henning Kamp static int 465516ad423SPoul-Henning Kamp giant_poll(struct cdev *dev, int events, struct thread *td) 466516ad423SPoul-Henning Kamp { 467aeeb4202SKonstantin Belousov struct cdevsw *dsw; 4683979450bSKonstantin Belousov int ref, retval; 469516ad423SPoul-Henning Kamp 4703979450bSKonstantin Belousov dsw = dev_refthread(dev, &ref); 471aeeb4202SKonstantin Belousov if (dsw == NULL) 472aeeb4202SKonstantin Belousov return (ENXIO); 473516ad423SPoul-Henning Kamp mtx_lock(&Giant); 474aeeb4202SKonstantin Belousov retval = dsw->d_gianttrick->d_poll(dev, events, td); 475516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 4763979450bSKonstantin Belousov dev_relthread(dev, ref); 477516ad423SPoul-Henning Kamp return (retval); 478516ad423SPoul-Henning Kamp } 479516ad423SPoul-Henning Kamp 480516ad423SPoul-Henning Kamp static int 481516ad423SPoul-Henning Kamp giant_kqfilter(struct cdev *dev, struct knote *kn) 482516ad423SPoul-Henning Kamp { 483aeeb4202SKonstantin Belousov struct cdevsw *dsw; 4843979450bSKonstantin Belousov int ref, retval; 485516ad423SPoul-Henning Kamp 4863979450bSKonstantin Belousov dsw = dev_refthread(dev, &ref); 487aeeb4202SKonstantin Belousov if (dsw == NULL) 488aeeb4202SKonstantin Belousov return (ENXIO); 489516ad423SPoul-Henning Kamp mtx_lock(&Giant); 490aeeb4202SKonstantin Belousov retval = dsw->d_gianttrick->d_kqfilter(dev, kn); 491516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 4923979450bSKonstantin Belousov dev_relthread(dev, ref); 493516ad423SPoul-Henning Kamp return (retval); 494516ad423SPoul-Henning Kamp } 495516ad423SPoul-Henning Kamp 496516ad423SPoul-Henning Kamp static int 497cfd7baceSRobert Noland giant_mmap(struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr, int nprot, 4982fa8c8d2SJohn Baldwin vm_memattr_t *memattr) 499516ad423SPoul-Henning Kamp { 500aeeb4202SKonstantin Belousov struct cdevsw *dsw; 5013979450bSKonstantin Belousov int ref, retval; 502516ad423SPoul-Henning Kamp 5033979450bSKonstantin Belousov dsw = dev_refthread(dev, &ref); 504aeeb4202SKonstantin Belousov if (dsw == NULL) 505aeeb4202SKonstantin Belousov return (ENXIO); 506516ad423SPoul-Henning Kamp mtx_lock(&Giant); 507cfd7baceSRobert Noland retval = dsw->d_gianttrick->d_mmap(dev, offset, paddr, nprot, 5082fa8c8d2SJohn Baldwin memattr); 509516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 5103979450bSKonstantin Belousov dev_relthread(dev, ref); 511516ad423SPoul-Henning Kamp return (retval); 512516ad423SPoul-Henning Kamp } 513516ad423SPoul-Henning Kamp 51464345f0bSJohn Baldwin static int 51564345f0bSJohn Baldwin giant_mmap_single(struct cdev *dev, vm_ooffset_t *offset, vm_size_t size, 51664345f0bSJohn Baldwin vm_object_t *object, int nprot) 51764345f0bSJohn Baldwin { 51864345f0bSJohn Baldwin struct cdevsw *dsw; 5193979450bSKonstantin Belousov int ref, retval; 52064345f0bSJohn Baldwin 5213979450bSKonstantin Belousov dsw = dev_refthread(dev, &ref); 52264345f0bSJohn Baldwin if (dsw == NULL) 52364345f0bSJohn Baldwin return (ENXIO); 52464345f0bSJohn Baldwin mtx_lock(&Giant); 52564345f0bSJohn Baldwin retval = dsw->d_gianttrick->d_mmap_single(dev, offset, size, object, 52664345f0bSJohn Baldwin nprot); 52764345f0bSJohn Baldwin mtx_unlock(&Giant); 5283979450bSKonstantin Belousov dev_relthread(dev, ref); 52964345f0bSJohn Baldwin return (retval); 53064345f0bSJohn Baldwin } 531516ad423SPoul-Henning Kamp 53248504cc2SKonstantin Belousov static void 533d2ba618aSKonstantin Belousov notify(struct cdev *dev, const char *ev, int flags) 53448504cc2SKonstantin Belousov { 53548504cc2SKonstantin Belousov static const char prefix[] = "cdev="; 53648504cc2SKonstantin Belousov char *data; 53776d43557SKonstantin Belousov int namelen, mflags; 53848504cc2SKonstantin Belousov 53948504cc2SKonstantin Belousov if (cold) 54048504cc2SKonstantin Belousov return; 54176d43557SKonstantin Belousov mflags = (flags & MAKEDEV_NOWAIT) ? M_NOWAIT : M_WAITOK; 54248504cc2SKonstantin Belousov namelen = strlen(dev->si_name); 54376d43557SKonstantin Belousov data = malloc(namelen + sizeof(prefix), M_TEMP, mflags); 5449995e57bSAttilio Rao if (data == NULL) 5459995e57bSAttilio Rao return; 54648504cc2SKonstantin Belousov memcpy(data, prefix, sizeof(prefix) - 1); 54748504cc2SKonstantin Belousov memcpy(data + sizeof(prefix) - 1, dev->si_name, namelen + 1); 54876d43557SKonstantin Belousov devctl_notify_f("DEVFS", "CDEV", ev, data, mflags); 54948504cc2SKonstantin Belousov free(data, M_TEMP); 55048504cc2SKonstantin Belousov } 55148504cc2SKonstantin Belousov 55248504cc2SKonstantin Belousov static void 553d2ba618aSKonstantin Belousov notify_create(struct cdev *dev, int flags) 55448504cc2SKonstantin Belousov { 55548504cc2SKonstantin Belousov 556d2ba618aSKonstantin Belousov notify(dev, "CREATE", flags); 55748504cc2SKonstantin Belousov } 55848504cc2SKonstantin Belousov 55948504cc2SKonstantin Belousov static void 56048504cc2SKonstantin Belousov notify_destroy(struct cdev *dev) 56148504cc2SKonstantin Belousov { 56248504cc2SKonstantin Belousov 563d2ba618aSKonstantin Belousov notify(dev, "DESTROY", MAKEDEV_WAITOK); 56448504cc2SKonstantin Belousov } 56548504cc2SKonstantin Belousov 56689c9c53dSPoul-Henning Kamp static struct cdev * 567bce79dbbSEd Schouten newdev(struct cdevsw *csw, int unit, struct cdev *si) 5683f54a085SPoul-Henning Kamp { 569027b1f71SPoul-Henning Kamp struct cdev *si2; 5703f54a085SPoul-Henning Kamp 571027b1f71SPoul-Henning Kamp mtx_assert(&devmtx, MA_OWNED); 57229d4cb24SEd Schouten if (csw->d_flags & D_NEEDMINOR) { 57329d4cb24SEd Schouten /* We may want to return an existing device */ 574ff7284eeSPoul-Henning Kamp LIST_FOREACH(si2, &csw->d_devs, si_list) { 575bce79dbbSEd Schouten if (dev2unit(si2) == unit) { 5769bc911d4SKonstantin Belousov dev_free_devlocked(si); 577027b1f71SPoul-Henning Kamp return (si2); 5783f54a085SPoul-Henning Kamp } 579027b1f71SPoul-Henning Kamp } 58029d4cb24SEd Schouten } 581bce79dbbSEd Schouten si->si_drv0 = unit; 582e606a3c6SPoul-Henning Kamp si->si_devsw = csw; 583ff7284eeSPoul-Henning Kamp LIST_INSERT_HEAD(&csw->d_devs, si, si_list); 584698bfad7SPoul-Henning Kamp return (si); 585bfbb9ce6SPoul-Henning Kamp } 586bfbb9ce6SPoul-Henning Kamp 5872a3faf2fSPoul-Henning Kamp static void 588cd690b60SPoul-Henning Kamp fini_cdevsw(struct cdevsw *devsw) 589cd690b60SPoul-Henning Kamp { 5901d45c50eSPoul-Henning Kamp struct cdevsw *gt; 591b3d82c03SPoul-Henning Kamp 5921d45c50eSPoul-Henning Kamp if (devsw->d_gianttrick != NULL) { 5931d45c50eSPoul-Henning Kamp gt = devsw->d_gianttrick; 5941d45c50eSPoul-Henning Kamp memcpy(devsw, gt, sizeof *devsw); 595aeeb4202SKonstantin Belousov cdevsw_free_devlocked(gt); 596516ad423SPoul-Henning Kamp devsw->d_gianttrick = NULL; 5971d45c50eSPoul-Henning Kamp } 598652d0472SPoul-Henning Kamp devsw->d_flags &= ~D_INIT; 599b0b03348SPoul-Henning Kamp } 600b0b03348SPoul-Henning Kamp 601d2ba618aSKonstantin Belousov static int 602d2ba618aSKonstantin Belousov prep_cdevsw(struct cdevsw *devsw, int flags) 603b0b03348SPoul-Henning Kamp { 604516ad423SPoul-Henning Kamp struct cdevsw *dsw2; 605b0b03348SPoul-Henning Kamp 606aeeb4202SKonstantin Belousov mtx_assert(&devmtx, MA_OWNED); 607aeeb4202SKonstantin Belousov if (devsw->d_flags & D_INIT) 608f1bb758dSKonstantin Belousov return (0); 609aeeb4202SKonstantin Belousov if (devsw->d_flags & D_NEEDGIANT) { 610aeeb4202SKonstantin Belousov dev_unlock(); 611d2ba618aSKonstantin Belousov dsw2 = malloc(sizeof *dsw2, M_DEVT, 612d2ba618aSKonstantin Belousov (flags & MAKEDEV_NOWAIT) ? M_NOWAIT : M_WAITOK); 613a0e78d2eSPoul-Henning Kamp dev_lock(); 614d2ba618aSKonstantin Belousov if (dsw2 == NULL && !(devsw->d_flags & D_INIT)) 615f1bb758dSKonstantin Belousov return (ENOMEM); 616aeeb4202SKonstantin Belousov } else 617aeeb4202SKonstantin Belousov dsw2 = NULL; 618aeeb4202SKonstantin Belousov if (devsw->d_flags & D_INIT) { 619aeeb4202SKonstantin Belousov if (dsw2 != NULL) 620aeeb4202SKonstantin Belousov cdevsw_free_devlocked(dsw2); 621f1bb758dSKonstantin Belousov return (0); 622aeeb4202SKonstantin Belousov } 623cd690b60SPoul-Henning Kamp 624cfd7baceSRobert Noland if (devsw->d_version != D_VERSION_03) { 625cd690b60SPoul-Henning Kamp printf( 626cd690b60SPoul-Henning Kamp "WARNING: Device driver \"%s\" has wrong version %s\n", 6277d7e053cSAlfred Perlstein devsw->d_name == NULL ? "???" : devsw->d_name, 6287d7e053cSAlfred Perlstein "and is disabled. Recompile KLD module."); 629cd690b60SPoul-Henning Kamp devsw->d_open = dead_open; 630cd690b60SPoul-Henning Kamp devsw->d_close = dead_close; 631cd690b60SPoul-Henning Kamp devsw->d_read = dead_read; 632cd690b60SPoul-Henning Kamp devsw->d_write = dead_write; 633cd690b60SPoul-Henning Kamp devsw->d_ioctl = dead_ioctl; 634cd690b60SPoul-Henning Kamp devsw->d_poll = dead_poll; 635cd690b60SPoul-Henning Kamp devsw->d_mmap = dead_mmap; 636cfd7baceSRobert Noland devsw->d_mmap_single = dead_mmap_single; 637cd690b60SPoul-Henning Kamp devsw->d_strategy = dead_strategy; 638cd690b60SPoul-Henning Kamp devsw->d_dump = dead_dump; 639cd690b60SPoul-Henning Kamp devsw->d_kqfilter = dead_kqfilter; 640cd690b60SPoul-Henning Kamp } 641cd690b60SPoul-Henning Kamp 642516ad423SPoul-Henning Kamp if (devsw->d_flags & D_NEEDGIANT) { 643516ad423SPoul-Henning Kamp if (devsw->d_gianttrick == NULL) { 644516ad423SPoul-Henning Kamp memcpy(dsw2, devsw, sizeof *dsw2); 645516ad423SPoul-Henning Kamp devsw->d_gianttrick = dsw2; 646aeeb4202SKonstantin Belousov dsw2 = NULL; 647aeeb4202SKonstantin Belousov } 648516ad423SPoul-Henning Kamp } 649516ad423SPoul-Henning Kamp 650516ad423SPoul-Henning Kamp #define FIXUP(member, noop, giant) \ 651516ad423SPoul-Henning Kamp do { \ 652516ad423SPoul-Henning Kamp if (devsw->member == NULL) { \ 653516ad423SPoul-Henning Kamp devsw->member = noop; \ 654516ad423SPoul-Henning Kamp } else if (devsw->d_flags & D_NEEDGIANT) \ 655516ad423SPoul-Henning Kamp devsw->member = giant; \ 656516ad423SPoul-Henning Kamp } \ 657516ad423SPoul-Henning Kamp while (0) 658516ad423SPoul-Henning Kamp 659516ad423SPoul-Henning Kamp FIXUP(d_open, null_open, giant_open); 660516ad423SPoul-Henning Kamp FIXUP(d_fdopen, NULL, giant_fdopen); 661516ad423SPoul-Henning Kamp FIXUP(d_close, null_close, giant_close); 662516ad423SPoul-Henning Kamp FIXUP(d_read, no_read, giant_read); 663516ad423SPoul-Henning Kamp FIXUP(d_write, no_write, giant_write); 664516ad423SPoul-Henning Kamp FIXUP(d_ioctl, no_ioctl, giant_ioctl); 665516ad423SPoul-Henning Kamp FIXUP(d_poll, no_poll, giant_poll); 666cfd7baceSRobert Noland FIXUP(d_mmap, no_mmap, giant_mmap); 667516ad423SPoul-Henning Kamp FIXUP(d_strategy, no_strategy, giant_strategy); 668516ad423SPoul-Henning Kamp FIXUP(d_kqfilter, no_kqfilter, giant_kqfilter); 66964345f0bSJohn Baldwin FIXUP(d_mmap_single, no_mmap_single, giant_mmap_single); 670516ad423SPoul-Henning Kamp 671b2941431SPoul-Henning Kamp if (devsw->d_dump == NULL) devsw->d_dump = no_dump; 672cd690b60SPoul-Henning Kamp 673cd690b60SPoul-Henning Kamp LIST_INIT(&devsw->d_devs); 674cd690b60SPoul-Henning Kamp 675cd690b60SPoul-Henning Kamp devsw->d_flags |= D_INIT; 676cd690b60SPoul-Henning Kamp 677aeeb4202SKonstantin Belousov if (dsw2 != NULL) 678aeeb4202SKonstantin Belousov cdevsw_free_devlocked(dsw2); 679f1bb758dSKonstantin Belousov return (0); 6802a3faf2fSPoul-Henning Kamp } 68111586717SBrian Somers 682f1bb758dSKonstantin Belousov static int 68368f7a013SJaakko Heinonen prep_devname(struct cdev *dev, const char *fmt, va_list ap) 68468f7a013SJaakko Heinonen { 68568f7a013SJaakko Heinonen int len; 68668f7a013SJaakko Heinonen char *from, *q, *s, *to; 68768f7a013SJaakko Heinonen 68868f7a013SJaakko Heinonen mtx_assert(&devmtx, MA_OWNED); 68968f7a013SJaakko Heinonen 690852b05c5SEd Schouten len = vsnrprintf(dev->si_name, sizeof(dev->si_name), 32, fmt, ap); 6918fac9b7bSEd Schouten if (len > sizeof(dev->si_name) - 1) 69268f7a013SJaakko Heinonen return (ENAMETOOLONG); 69368f7a013SJaakko Heinonen 69468f7a013SJaakko Heinonen /* Strip leading slashes. */ 6958fac9b7bSEd Schouten for (from = dev->si_name; *from == '/'; from++) 69668f7a013SJaakko Heinonen ; 69768f7a013SJaakko Heinonen 6988fac9b7bSEd Schouten for (to = dev->si_name; *from != '\0'; from++, to++) { 699b1e1f725SJaakko Heinonen /* 700b1e1f725SJaakko Heinonen * Spaces and double quotation marks cause 701b1e1f725SJaakko Heinonen * problems for the devctl(4) protocol. 702b1e1f725SJaakko Heinonen * Reject names containing those characters. 703b1e1f725SJaakko Heinonen */ 704b1e1f725SJaakko Heinonen if (isspace(*from) || *from == '"') 705b1e1f725SJaakko Heinonen return (EINVAL); 70668f7a013SJaakko Heinonen /* Treat multiple sequential slashes as single. */ 70768f7a013SJaakko Heinonen while (from[0] == '/' && from[1] == '/') 70868f7a013SJaakko Heinonen from++; 70968f7a013SJaakko Heinonen /* Trailing slash is considered invalid. */ 71068f7a013SJaakko Heinonen if (from[0] == '/' && from[1] == '\0') 71168f7a013SJaakko Heinonen return (EINVAL); 71268f7a013SJaakko Heinonen *to = *from; 71368f7a013SJaakko Heinonen } 71468f7a013SJaakko Heinonen *to = '\0'; 71568f7a013SJaakko Heinonen 7168fac9b7bSEd Schouten if (dev->si_name[0] == '\0') 71768f7a013SJaakko Heinonen return (EINVAL); 71868f7a013SJaakko Heinonen 71968f7a013SJaakko Heinonen /* Disallow "." and ".." components. */ 7208fac9b7bSEd Schouten for (s = dev->si_name;;) { 72168f7a013SJaakko Heinonen for (q = s; *q != '/' && *q != '\0'; q++) 72268f7a013SJaakko Heinonen ; 72368f7a013SJaakko Heinonen if (q - s == 1 && s[0] == '.') 72468f7a013SJaakko Heinonen return (EINVAL); 72568f7a013SJaakko Heinonen if (q - s == 2 && s[0] == '.' && s[1] == '.') 72668f7a013SJaakko Heinonen return (EINVAL); 72768f7a013SJaakko Heinonen if (*q != '/') 72868f7a013SJaakko Heinonen break; 72968f7a013SJaakko Heinonen s = q + 1; 73068f7a013SJaakko Heinonen } 73168f7a013SJaakko Heinonen 7328fac9b7bSEd Schouten if (devfs_dev_exists(dev->si_name) != 0) 73368f7a013SJaakko Heinonen return (EEXIST); 73468f7a013SJaakko Heinonen 73568f7a013SJaakko Heinonen return (0); 73668f7a013SJaakko Heinonen } 73768f7a013SJaakko Heinonen 73868f7a013SJaakko Heinonen static int 739f1bb758dSKonstantin Belousov make_dev_credv(int flags, struct cdev **dres, struct cdevsw *devsw, int unit, 740f1bb758dSKonstantin Belousov struct ucred *cr, uid_t uid, gid_t gid, int mode, const char *fmt, 741f1bb758dSKonstantin Belousov va_list ap) 7422a3faf2fSPoul-Henning Kamp { 74368f7a013SJaakko Heinonen struct cdev *dev, *dev_new; 74468f7a013SJaakko Heinonen int res; 7452a3faf2fSPoul-Henning Kamp 746f1bb758dSKonstantin Belousov KASSERT((flags & MAKEDEV_WAITOK) == 0 || (flags & MAKEDEV_NOWAIT) == 0, 747f1bb758dSKonstantin Belousov ("make_dev_credv: both WAITOK and NOWAIT specified")); 74868f7a013SJaakko Heinonen dev_new = devfs_alloc(flags); 74968f7a013SJaakko Heinonen if (dev_new == NULL) 750f1bb758dSKonstantin Belousov return (ENOMEM); 751027b1f71SPoul-Henning Kamp dev_lock(); 752f1bb758dSKonstantin Belousov res = prep_cdevsw(devsw, flags); 753f1bb758dSKonstantin Belousov if (res != 0) { 754d2ba618aSKonstantin Belousov dev_unlock(); 75568f7a013SJaakko Heinonen devfs_free(dev_new); 756f1bb758dSKonstantin Belousov return (res); 757d2ba618aSKonstantin Belousov } 75868f7a013SJaakko Heinonen dev = newdev(devsw, unit, dev_new); 759ff91cc99SJaakko Heinonen if ((dev->si_flags & SI_NAMED) == 0) { 76068f7a013SJaakko Heinonen res = prep_devname(dev, fmt, ap); 76168f7a013SJaakko Heinonen if (res != 0) { 76268f7a013SJaakko Heinonen if ((flags & MAKEDEV_CHECKNAME) == 0) { 76368f7a013SJaakko Heinonen panic( 76468f7a013SJaakko Heinonen "make_dev_credv: bad si_name (error=%d, si_name=%s)", 76568f7a013SJaakko Heinonen res, dev->si_name); 76668f7a013SJaakko Heinonen } 76768f7a013SJaakko Heinonen if (dev == dev_new) { 76868f7a013SJaakko Heinonen LIST_REMOVE(dev, si_list); 76968f7a013SJaakko Heinonen dev_unlock(); 77068f7a013SJaakko Heinonen devfs_free(dev); 771889dffbaSKonstantin Belousov } else 772889dffbaSKonstantin Belousov dev_unlock(); 77368f7a013SJaakko Heinonen return (res); 77468f7a013SJaakko Heinonen } 775ff91cc99SJaakko Heinonen } 776de10ffa5SKonstantin Belousov if (flags & MAKEDEV_REF) 777de10ffa5SKonstantin Belousov dev_refl(dev); 7783979450bSKonstantin Belousov if (flags & MAKEDEV_ETERNAL) 7793979450bSKonstantin Belousov dev->si_flags |= SI_ETERNAL; 78098c469d4SPoul-Henning Kamp if (dev->si_flags & SI_CHEAPCLONE && 781e606a3c6SPoul-Henning Kamp dev->si_flags & SI_NAMED) { 78298c469d4SPoul-Henning Kamp /* 78398c469d4SPoul-Henning Kamp * This is allowed as it removes races and generally 78498c469d4SPoul-Henning Kamp * simplifies cloning devices. 785cd690b60SPoul-Henning Kamp * XXX: still ?? 78698c469d4SPoul-Henning Kamp */ 7879bc911d4SKonstantin Belousov dev_unlock_and_free(); 788f1bb758dSKonstantin Belousov *dres = dev; 789f1bb758dSKonstantin Belousov return (0); 79098c469d4SPoul-Henning Kamp } 791cd690b60SPoul-Henning Kamp KASSERT(!(dev->si_flags & SI_NAMED), 792ff7284eeSPoul-Henning Kamp ("make_dev() by driver %s on pre-existing device (min=%x, name=%s)", 7936bfa9a2dSEd Schouten devsw->d_name, dev2unit(dev), devtoname(dev))); 7945ef2707eSPoul-Henning Kamp dev->si_flags |= SI_NAMED; 795d26dd2d9SRobert Watson if (cr != NULL) 796d26dd2d9SRobert Watson dev->si_cred = crhold(cr); 7979477d73eSPoul-Henning Kamp dev->si_uid = uid; 7989477d73eSPoul-Henning Kamp dev->si_gid = gid; 7999477d73eSPoul-Henning Kamp dev->si_mode = mode; 8001744fcd0SJulian Elischer 8019285a87eSPoul-Henning Kamp devfs_create(dev); 80209828ba9SKonstantin Belousov clean_unrhdrl(devfs_inos); 803aeeb4202SKonstantin Belousov dev_unlock_and_free(); 80448504cc2SKonstantin Belousov 805d2ba618aSKonstantin Belousov notify_create(dev, flags); 80648504cc2SKonstantin Belousov 807f1bb758dSKonstantin Belousov *dres = dev; 808f1bb758dSKonstantin Belousov return (0); 8093f54a085SPoul-Henning Kamp } 8103f54a085SPoul-Henning Kamp 811d26dd2d9SRobert Watson struct cdev * 812edde8745SEd Schouten make_dev(struct cdevsw *devsw, int unit, uid_t uid, gid_t gid, int mode, 813d26dd2d9SRobert Watson const char *fmt, ...) 814d26dd2d9SRobert Watson { 815d26dd2d9SRobert Watson struct cdev *dev; 816d26dd2d9SRobert Watson va_list ap; 817f1bb758dSKonstantin Belousov int res; 818d26dd2d9SRobert Watson 819d26dd2d9SRobert Watson va_start(ap, fmt); 820f1bb758dSKonstantin Belousov res = make_dev_credv(0, &dev, devsw, unit, NULL, uid, gid, mode, fmt, 821f1bb758dSKonstantin Belousov ap); 822d26dd2d9SRobert Watson va_end(ap); 82368f7a013SJaakko Heinonen KASSERT(res == 0 && dev != NULL, 82468f7a013SJaakko Heinonen ("make_dev: failed make_dev_credv (error=%d)", res)); 825d26dd2d9SRobert Watson return (dev); 826d26dd2d9SRobert Watson } 827d26dd2d9SRobert Watson 828d26dd2d9SRobert Watson struct cdev * 829edde8745SEd Schouten make_dev_cred(struct cdevsw *devsw, int unit, struct ucred *cr, uid_t uid, 830d26dd2d9SRobert Watson gid_t gid, int mode, const char *fmt, ...) 831d26dd2d9SRobert Watson { 832d26dd2d9SRobert Watson struct cdev *dev; 833d26dd2d9SRobert Watson va_list ap; 834f1bb758dSKonstantin Belousov int res; 835d26dd2d9SRobert Watson 836d26dd2d9SRobert Watson va_start(ap, fmt); 837f1bb758dSKonstantin Belousov res = make_dev_credv(0, &dev, devsw, unit, cr, uid, gid, mode, fmt, ap); 838de10ffa5SKonstantin Belousov va_end(ap); 839de10ffa5SKonstantin Belousov 840f1bb758dSKonstantin Belousov KASSERT(res == 0 && dev != NULL, 84168f7a013SJaakko Heinonen ("make_dev_cred: failed make_dev_credv (error=%d)", res)); 842de10ffa5SKonstantin Belousov return (dev); 843de10ffa5SKonstantin Belousov } 844de10ffa5SKonstantin Belousov 845de10ffa5SKonstantin Belousov struct cdev * 846f1bb758dSKonstantin Belousov make_dev_credf(int flags, struct cdevsw *devsw, int unit, struct ucred *cr, 847f1bb758dSKonstantin Belousov uid_t uid, gid_t gid, int mode, const char *fmt, ...) 848de10ffa5SKonstantin Belousov { 849de10ffa5SKonstantin Belousov struct cdev *dev; 850de10ffa5SKonstantin Belousov va_list ap; 851f1bb758dSKonstantin Belousov int res; 852de10ffa5SKonstantin Belousov 853de10ffa5SKonstantin Belousov va_start(ap, fmt); 854f1bb758dSKonstantin Belousov res = make_dev_credv(flags, &dev, devsw, unit, cr, uid, gid, mode, 855de10ffa5SKonstantin Belousov fmt, ap); 856d26dd2d9SRobert Watson va_end(ap); 857d26dd2d9SRobert Watson 85868f7a013SJaakko Heinonen KASSERT(((flags & MAKEDEV_NOWAIT) != 0 && res == ENOMEM) || 85968f7a013SJaakko Heinonen ((flags & MAKEDEV_CHECKNAME) != 0 && res != ENOMEM) || res == 0, 86068f7a013SJaakko Heinonen ("make_dev_credf: failed make_dev_credv (error=%d)", res)); 861f1bb758dSKonstantin Belousov return (res == 0 ? dev : NULL); 862f1bb758dSKonstantin Belousov } 863f1bb758dSKonstantin Belousov 864f1bb758dSKonstantin Belousov int 8652e983aceSEd Schouten make_dev_p(int flags, struct cdev **cdev, struct cdevsw *devsw, 866f1bb758dSKonstantin Belousov struct ucred *cr, uid_t uid, gid_t gid, int mode, const char *fmt, ...) 867f1bb758dSKonstantin Belousov { 868f1bb758dSKonstantin Belousov va_list ap; 869f1bb758dSKonstantin Belousov int res; 870f1bb758dSKonstantin Belousov 871f1bb758dSKonstantin Belousov va_start(ap, fmt); 8722e983aceSEd Schouten res = make_dev_credv(flags, cdev, devsw, 0, cr, uid, gid, mode, 873f1bb758dSKonstantin Belousov fmt, ap); 874f1bb758dSKonstantin Belousov va_end(ap); 875f1bb758dSKonstantin Belousov 87668f7a013SJaakko Heinonen KASSERT(((flags & MAKEDEV_NOWAIT) != 0 && res == ENOMEM) || 87768f7a013SJaakko Heinonen ((flags & MAKEDEV_CHECKNAME) != 0 && res != ENOMEM) || res == 0, 87868f7a013SJaakko Heinonen ("make_dev_p: failed make_dev_credv (error=%d)", res)); 879f1bb758dSKonstantin Belousov return (res); 880d26dd2d9SRobert Watson } 881d26dd2d9SRobert Watson 882e606a3c6SPoul-Henning Kamp static void 883e606a3c6SPoul-Henning Kamp dev_dependsl(struct cdev *pdev, struct cdev *cdev) 884e606a3c6SPoul-Henning Kamp { 885e606a3c6SPoul-Henning Kamp 886e606a3c6SPoul-Henning Kamp cdev->si_parent = pdev; 887e606a3c6SPoul-Henning Kamp cdev->si_flags |= SI_CHILD; 888e606a3c6SPoul-Henning Kamp LIST_INSERT_HEAD(&pdev->si_children, cdev, si_siblings); 889e606a3c6SPoul-Henning Kamp } 890e606a3c6SPoul-Henning Kamp 891e606a3c6SPoul-Henning Kamp 8923344c5a1SPoul-Henning Kamp void 89389c9c53dSPoul-Henning Kamp dev_depends(struct cdev *pdev, struct cdev *cdev) 8943344c5a1SPoul-Henning Kamp { 8953344c5a1SPoul-Henning Kamp 896a0e78d2eSPoul-Henning Kamp dev_lock(); 897e606a3c6SPoul-Henning Kamp dev_dependsl(pdev, cdev); 898a0e78d2eSPoul-Henning Kamp dev_unlock(); 8993344c5a1SPoul-Henning Kamp } 9003344c5a1SPoul-Henning Kamp 901b50a7799SAndrey V. Elsukov static int 902b50a7799SAndrey V. Elsukov make_dev_alias_v(int flags, struct cdev **cdev, struct cdev *pdev, 903b50a7799SAndrey V. Elsukov const char *fmt, va_list ap) 9043f54a085SPoul-Henning Kamp { 90589c9c53dSPoul-Henning Kamp struct cdev *dev; 90668f7a013SJaakko Heinonen int error; 9073f54a085SPoul-Henning Kamp 908b50a7799SAndrey V. Elsukov KASSERT(pdev != NULL, ("make_dev_alias_v: pdev is NULL")); 909b50a7799SAndrey V. Elsukov KASSERT((flags & MAKEDEV_WAITOK) == 0 || (flags & MAKEDEV_NOWAIT) == 0, 910b50a7799SAndrey V. Elsukov ("make_dev_alias_v: both WAITOK and NOWAIT specified")); 911b50a7799SAndrey V. Elsukov KASSERT((flags & ~(MAKEDEV_WAITOK | MAKEDEV_NOWAIT | 912b50a7799SAndrey V. Elsukov MAKEDEV_CHECKNAME)) == 0, 913b50a7799SAndrey V. Elsukov ("make_dev_alias_v: invalid flags specified (flags=%02x)", flags)); 914b50a7799SAndrey V. Elsukov 915b50a7799SAndrey V. Elsukov dev = devfs_alloc(flags); 916b50a7799SAndrey V. Elsukov if (dev == NULL) 917b50a7799SAndrey V. Elsukov return (ENOMEM); 918a0e78d2eSPoul-Henning Kamp dev_lock(); 9193f54a085SPoul-Henning Kamp dev->si_flags |= SI_ALIAS; 92068f7a013SJaakko Heinonen error = prep_devname(dev, fmt, ap); 92168f7a013SJaakko Heinonen if (error != 0) { 922b50a7799SAndrey V. Elsukov if ((flags & MAKEDEV_CHECKNAME) == 0) { 923b50a7799SAndrey V. Elsukov panic("make_dev_alias_v: bad si_name " 924b50a7799SAndrey V. Elsukov "(error=%d, si_name=%s)", error, dev->si_name); 925b50a7799SAndrey V. Elsukov } 926b50a7799SAndrey V. Elsukov dev_unlock(); 927b50a7799SAndrey V. Elsukov devfs_free(dev); 928b50a7799SAndrey V. Elsukov return (error); 92968f7a013SJaakko Heinonen } 93068f7a013SJaakko Heinonen dev->si_flags |= SI_NAMED; 9319285a87eSPoul-Henning Kamp devfs_create(dev); 932ae95dc62SKonstantin Belousov dev_dependsl(pdev, dev); 93309828ba9SKonstantin Belousov clean_unrhdrl(devfs_inos); 934a0e78d2eSPoul-Henning Kamp dev_unlock(); 93548504cc2SKonstantin Belousov 936b50a7799SAndrey V. Elsukov notify_create(dev, flags); 937b50a7799SAndrey V. Elsukov *cdev = dev; 93848504cc2SKonstantin Belousov 939b50a7799SAndrey V. Elsukov return (0); 940b50a7799SAndrey V. Elsukov } 941b50a7799SAndrey V. Elsukov 942b50a7799SAndrey V. Elsukov struct cdev * 943b50a7799SAndrey V. Elsukov make_dev_alias(struct cdev *pdev, const char *fmt, ...) 944b50a7799SAndrey V. Elsukov { 945b50a7799SAndrey V. Elsukov struct cdev *dev; 946b50a7799SAndrey V. Elsukov va_list ap; 947b50a7799SAndrey V. Elsukov int res; 948b50a7799SAndrey V. Elsukov 949b50a7799SAndrey V. Elsukov va_start(ap, fmt); 950b50a7799SAndrey V. Elsukov res = make_dev_alias_v(MAKEDEV_WAITOK, &dev, pdev, fmt, ap); 951b50a7799SAndrey V. Elsukov va_end(ap); 952b50a7799SAndrey V. Elsukov 953b50a7799SAndrey V. Elsukov KASSERT(res == 0 && dev != NULL, 954b50a7799SAndrey V. Elsukov ("make_dev_alias: failed make_dev_alias_v (error=%d)", res)); 9550ef1c826SPoul-Henning Kamp return (dev); 9560ef1c826SPoul-Henning Kamp } 9570ef1c826SPoul-Henning Kamp 958b50a7799SAndrey V. Elsukov int 959b50a7799SAndrey V. Elsukov make_dev_alias_p(int flags, struct cdev **cdev, struct cdev *pdev, 960b50a7799SAndrey V. Elsukov const char *fmt, ...) 961b50a7799SAndrey V. Elsukov { 962b50a7799SAndrey V. Elsukov va_list ap; 963b50a7799SAndrey V. Elsukov int res; 964b50a7799SAndrey V. Elsukov 965b50a7799SAndrey V. Elsukov va_start(ap, fmt); 966b50a7799SAndrey V. Elsukov res = make_dev_alias_v(flags, cdev, pdev, fmt, ap); 967b50a7799SAndrey V. Elsukov va_end(ap); 968b50a7799SAndrey V. Elsukov return (res); 969b50a7799SAndrey V. Elsukov } 970b50a7799SAndrey V. Elsukov 971aa76615dSJustin T. Gibbs int 972aa76615dSJustin T. Gibbs make_dev_physpath_alias(int flags, struct cdev **cdev, struct cdev *pdev, 973aa76615dSJustin T. Gibbs struct cdev *old_alias, const char *physpath) 974aa76615dSJustin T. Gibbs { 975aa76615dSJustin T. Gibbs char *devfspath; 976aa76615dSJustin T. Gibbs int physpath_len; 977aa76615dSJustin T. Gibbs int max_parentpath_len; 978aa76615dSJustin T. Gibbs int parentpath_len; 979aa76615dSJustin T. Gibbs int devfspathbuf_len; 980aa76615dSJustin T. Gibbs int mflags; 981aa76615dSJustin T. Gibbs int ret; 982aa76615dSJustin T. Gibbs 983aa76615dSJustin T. Gibbs *cdev = NULL; 984aa76615dSJustin T. Gibbs devfspath = NULL; 985aa76615dSJustin T. Gibbs physpath_len = strlen(physpath); 986aa76615dSJustin T. Gibbs ret = EINVAL; 987aa76615dSJustin T. Gibbs if (physpath_len == 0) 988aa76615dSJustin T. Gibbs goto out; 989aa76615dSJustin T. Gibbs 990aa76615dSJustin T. Gibbs if (strncmp("id1,", physpath, 4) == 0) { 991aa76615dSJustin T. Gibbs physpath += 4; 992aa76615dSJustin T. Gibbs physpath_len -= 4; 993aa76615dSJustin T. Gibbs if (physpath_len == 0) 994aa76615dSJustin T. Gibbs goto out; 995aa76615dSJustin T. Gibbs } 996aa76615dSJustin T. Gibbs 997aa76615dSJustin T. Gibbs max_parentpath_len = SPECNAMELEN - physpath_len - /*/*/1; 998aa76615dSJustin T. Gibbs parentpath_len = strlen(pdev->si_name); 999aa76615dSJustin T. Gibbs if (max_parentpath_len < parentpath_len) { 100020654f4eSAlexander Motin if (bootverbose) 100120654f4eSAlexander Motin printf("WARNING: Unable to alias %s " 1002aa76615dSJustin T. Gibbs "to %s/%s - path too long\n", 1003aa76615dSJustin T. Gibbs pdev->si_name, physpath, pdev->si_name); 1004aa76615dSJustin T. Gibbs ret = ENAMETOOLONG; 1005aa76615dSJustin T. Gibbs goto out; 1006aa76615dSJustin T. Gibbs } 1007aa76615dSJustin T. Gibbs 1008aa76615dSJustin T. Gibbs mflags = (flags & MAKEDEV_NOWAIT) ? M_NOWAIT : M_WAITOK; 1009aa76615dSJustin T. Gibbs devfspathbuf_len = physpath_len + /*/*/1 + parentpath_len + /*NUL*/1; 1010aa76615dSJustin T. Gibbs devfspath = malloc(devfspathbuf_len, M_DEVBUF, mflags); 1011aa76615dSJustin T. Gibbs if (devfspath == NULL) { 1012aa76615dSJustin T. Gibbs ret = ENOMEM; 1013aa76615dSJustin T. Gibbs goto out; 1014aa76615dSJustin T. Gibbs } 1015aa76615dSJustin T. Gibbs 1016aa76615dSJustin T. Gibbs sprintf(devfspath, "%s/%s", physpath, pdev->si_name); 10174d651f4eSKonstantin Belousov if (old_alias != NULL && strcmp(old_alias->si_name, devfspath) == 0) { 1018aa76615dSJustin T. Gibbs /* Retain the existing alias. */ 1019aa76615dSJustin T. Gibbs *cdev = old_alias; 1020aa76615dSJustin T. Gibbs old_alias = NULL; 1021aa76615dSJustin T. Gibbs ret = 0; 1022aa76615dSJustin T. Gibbs } else { 1023f403cfb1SKonstantin Belousov ret = make_dev_alias_p(flags, cdev, pdev, "%s", devfspath); 1024aa76615dSJustin T. Gibbs } 1025aa76615dSJustin T. Gibbs out: 1026aa76615dSJustin T. Gibbs if (old_alias != NULL) 1027aa76615dSJustin T. Gibbs destroy_dev(old_alias); 1028aa76615dSJustin T. Gibbs if (devfspath != NULL) 1029aa76615dSJustin T. Gibbs free(devfspath, M_DEVBUF); 1030aa76615dSJustin T. Gibbs return (ret); 1031aa76615dSJustin T. Gibbs } 1032aa76615dSJustin T. Gibbs 1033cd690b60SPoul-Henning Kamp static void 1034aa2f6ddcSPoul-Henning Kamp destroy_devl(struct cdev *dev) 1035d137acccSPoul-Henning Kamp { 1036743cd76aSPoul-Henning Kamp struct cdevsw *csw; 10370bad52e1SHans Petter Selasky struct cdev_privdata *p; 1038743cd76aSPoul-Henning Kamp 1039aa2f6ddcSPoul-Henning Kamp mtx_assert(&devmtx, MA_OWNED); 1040743cd76aSPoul-Henning Kamp KASSERT(dev->si_flags & SI_NAMED, 10416bfa9a2dSEd Schouten ("WARNING: Driver mistake: destroy_dev on %d\n", dev2unit(dev))); 10423979450bSKonstantin Belousov KASSERT((dev->si_flags & SI_ETERNAL) == 0, 10433979450bSKonstantin Belousov ("WARNING: Driver mistake: destroy_dev on eternal %d\n", 10443979450bSKonstantin Belousov dev2unit(dev))); 10455ef2707eSPoul-Henning Kamp 10469285a87eSPoul-Henning Kamp devfs_destroy(dev); 1047cd690b60SPoul-Henning Kamp 1048cd690b60SPoul-Henning Kamp /* Remove name marking */ 1049b0b03348SPoul-Henning Kamp dev->si_flags &= ~SI_NAMED; 1050b0b03348SPoul-Henning Kamp 1051dbe66680SKonstantin Belousov dev->si_refcount++; /* Avoid race with dev_rel() */ 1052dbe66680SKonstantin Belousov 1053cd690b60SPoul-Henning Kamp /* If we are a child, remove us from the parents list */ 10543344c5a1SPoul-Henning Kamp if (dev->si_flags & SI_CHILD) { 10553344c5a1SPoul-Henning Kamp LIST_REMOVE(dev, si_siblings); 10563344c5a1SPoul-Henning Kamp dev->si_flags &= ~SI_CHILD; 10573344c5a1SPoul-Henning Kamp } 1058cd690b60SPoul-Henning Kamp 1059cd690b60SPoul-Henning Kamp /* Kill our children */ 10603344c5a1SPoul-Henning Kamp while (!LIST_EMPTY(&dev->si_children)) 1061aa2f6ddcSPoul-Henning Kamp destroy_devl(LIST_FIRST(&dev->si_children)); 1062cd690b60SPoul-Henning Kamp 1063cd690b60SPoul-Henning Kamp /* Remove from clone list */ 1064b0b03348SPoul-Henning Kamp if (dev->si_flags & SI_CLONELIST) { 1065b0b03348SPoul-Henning Kamp LIST_REMOVE(dev, si_clone); 1066b0b03348SPoul-Henning Kamp dev->si_flags &= ~SI_CLONELIST; 1067b0b03348SPoul-Henning Kamp } 1068cd690b60SPoul-Henning Kamp 1069743cd76aSPoul-Henning Kamp csw = dev->si_devsw; 10701abf2c36SBrian Feldman dev->si_devsw = NULL; /* already NULL for SI_ALIAS */ 10711abf2c36SBrian Feldman while (csw != NULL && csw->d_purge != NULL && dev->si_threadcount) { 1072743cd76aSPoul-Henning Kamp csw->d_purge(dev); 1073743cd76aSPoul-Henning Kamp msleep(csw, &devmtx, PRIBIO, "devprg", hz/10); 1074d595182fSPoul-Henning Kamp if (dev->si_threadcount) 1075d595182fSPoul-Henning Kamp printf("Still %lu threads in %s\n", 1076d595182fSPoul-Henning Kamp dev->si_threadcount, devtoname(dev)); 1077743cd76aSPoul-Henning Kamp } 1078e0c33ad5STor Egge while (dev->si_threadcount != 0) { 1079e0c33ad5STor Egge /* Use unique dummy wait ident */ 1080e0c33ad5STor Egge msleep(&csw, &devmtx, PRIBIO, "devdrn", hz / 10); 1081e0c33ad5STor Egge } 1082743cd76aSPoul-Henning Kamp 108382f4d640SKonstantin Belousov dev_unlock(); 108448504cc2SKonstantin Belousov notify_destroy(dev); 108582f4d640SKonstantin Belousov mtx_lock(&cdevpriv_mtx); 10860bad52e1SHans Petter Selasky while ((p = LIST_FIRST(&cdev2priv(dev)->cdp_fdpriv)) != NULL) { 108782f4d640SKonstantin Belousov devfs_destroy_cdevpriv(p); 108882f4d640SKonstantin Belousov mtx_lock(&cdevpriv_mtx); 108982f4d640SKonstantin Belousov } 109082f4d640SKonstantin Belousov mtx_unlock(&cdevpriv_mtx); 109182f4d640SKonstantin Belousov dev_lock(); 109248504cc2SKonstantin Belousov 1093743cd76aSPoul-Henning Kamp dev->si_drv1 = 0; 1094743cd76aSPoul-Henning Kamp dev->si_drv2 = 0; 1095743cd76aSPoul-Henning Kamp bzero(&dev->__si_u, sizeof(dev->__si_u)); 1096743cd76aSPoul-Henning Kamp 1097cd690b60SPoul-Henning Kamp if (!(dev->si_flags & SI_ALIAS)) { 1098cd690b60SPoul-Henning Kamp /* Remove from cdevsw list */ 1099cd690b60SPoul-Henning Kamp LIST_REMOVE(dev, si_list); 1100cd690b60SPoul-Henning Kamp 1101e606a3c6SPoul-Henning Kamp /* If cdevsw has no more struct cdev *'s, clean it */ 1102de10ffa5SKonstantin Belousov if (LIST_EMPTY(&csw->d_devs)) { 1103a5993c33SPoul-Henning Kamp fini_cdevsw(csw); 1104de10ffa5SKonstantin Belousov wakeup(&csw->d_devs); 1105de10ffa5SKonstantin Belousov } 1106cd690b60SPoul-Henning Kamp } 11075ef2707eSPoul-Henning Kamp dev->si_flags &= ~SI_ALIAS; 1108e0c33ad5STor Egge dev->si_refcount--; /* Avoid race with dev_rel() */ 1109743cd76aSPoul-Henning Kamp 1110cd690b60SPoul-Henning Kamp if (dev->si_refcount > 0) { 1111cd690b60SPoul-Henning Kamp LIST_INSERT_HEAD(&dead_cdevsw.d_devs, dev, si_list); 1112cd690b60SPoul-Henning Kamp } else { 11139bc911d4SKonstantin Belousov dev_free_devlocked(dev); 1114d137acccSPoul-Henning Kamp } 1115cd690b60SPoul-Henning Kamp } 1116cd690b60SPoul-Henning Kamp 1117*07dbde67SHans Petter Selasky static void 1118*07dbde67SHans Petter Selasky delist_dev_locked(struct cdev *dev) 1119*07dbde67SHans Petter Selasky { 1120*07dbde67SHans Petter Selasky struct cdev *child; 1121*07dbde67SHans Petter Selasky devfs_destroy(dev); 1122*07dbde67SHans Petter Selasky LIST_FOREACH(child, &dev->si_children, si_siblings) 1123*07dbde67SHans Petter Selasky delist_dev_locked(child); 1124*07dbde67SHans Petter Selasky } 1125*07dbde67SHans Petter Selasky 1126*07dbde67SHans Petter Selasky void 1127*07dbde67SHans Petter Selasky delist_dev(struct cdev *dev) 1128*07dbde67SHans Petter Selasky { 1129*07dbde67SHans Petter Selasky dev_lock(); 1130*07dbde67SHans Petter Selasky delist_dev_locked(dev); 1131*07dbde67SHans Petter Selasky dev_unlock(); 1132*07dbde67SHans Petter Selasky } 1133*07dbde67SHans Petter Selasky 1134cd690b60SPoul-Henning Kamp void 113589c9c53dSPoul-Henning Kamp destroy_dev(struct cdev *dev) 1136cd690b60SPoul-Henning Kamp { 1137cd690b60SPoul-Henning Kamp 1138b7a813fcSKonstantin Belousov WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, "destroy_dev"); 1139a0e78d2eSPoul-Henning Kamp dev_lock(); 1140aa2f6ddcSPoul-Henning Kamp destroy_devl(dev); 11419bc911d4SKonstantin Belousov dev_unlock_and_free(); 1142cd690b60SPoul-Henning Kamp } 1143d137acccSPoul-Henning Kamp 1144c32cc149SBruce Evans const char * 114589c9c53dSPoul-Henning Kamp devtoname(struct cdev *dev) 1146b8e49f68SBill Fumerola { 1147b8e49f68SBill Fumerola 1148b8e49f68SBill Fumerola return (dev->si_name); 1149b8e49f68SBill Fumerola } 1150db901281SPoul-Henning Kamp 1151db901281SPoul-Henning Kamp int 115201de1b13SPoul-Henning Kamp dev_stdclone(char *name, char **namep, const char *stem, int *unit) 1153db901281SPoul-Henning Kamp { 1154db901281SPoul-Henning Kamp int u, i; 1155db901281SPoul-Henning Kamp 1156db901281SPoul-Henning Kamp i = strlen(stem); 115756700d46SBrian Somers if (bcmp(stem, name, i) != 0) 115856700d46SBrian Somers return (0); 1159db901281SPoul-Henning Kamp if (!isdigit(name[i])) 1160db901281SPoul-Henning Kamp return (0); 1161db901281SPoul-Henning Kamp u = 0; 116210786074SPoul-Henning Kamp if (name[i] == '0' && isdigit(name[i+1])) 116310786074SPoul-Henning Kamp return (0); 1164db901281SPoul-Henning Kamp while (isdigit(name[i])) { 1165db901281SPoul-Henning Kamp u *= 10; 1166db901281SPoul-Henning Kamp u += name[i++] - '0'; 1167db901281SPoul-Henning Kamp } 1168dab3d85fSBrian Feldman if (u > 0xffffff) 1169dab3d85fSBrian Feldman return (0); 1170db901281SPoul-Henning Kamp *unit = u; 1171db901281SPoul-Henning Kamp if (namep) 1172db901281SPoul-Henning Kamp *namep = &name[i]; 1173db901281SPoul-Henning Kamp if (name[i]) 1174db901281SPoul-Henning Kamp return (2); 1175db901281SPoul-Henning Kamp return (1); 1176db901281SPoul-Henning Kamp } 11778d25eb2cSPoul-Henning Kamp 11788d25eb2cSPoul-Henning Kamp /* 1179b0b03348SPoul-Henning Kamp * Helper functions for cloning device drivers. 1180b0b03348SPoul-Henning Kamp * 1181b0b03348SPoul-Henning Kamp * The objective here is to make it unnecessary for the device drivers to 1182b0b03348SPoul-Henning Kamp * use rman or similar to manage their unit number space. Due to the way 1183b0b03348SPoul-Henning Kamp * we do "on-demand" devices, using rman or other "private" methods 1184b0b03348SPoul-Henning Kamp * will be very tricky to lock down properly once we lock down this file. 1185b0b03348SPoul-Henning Kamp * 11869a98ae94SLukas Ertl * Instead we give the drivers these routines which puts the struct cdev *'s 11879a98ae94SLukas Ertl * that are to be managed on their own list, and gives the driver the ability 1188b0b03348SPoul-Henning Kamp * to ask for the first free unit number or a given specified unit number. 1189b0b03348SPoul-Henning Kamp * 1190b0b03348SPoul-Henning Kamp * In addition these routines support paired devices (pty, nmdm and similar) 1191b0b03348SPoul-Henning Kamp * by respecting a number of "flag" bits in the minor number. 1192b0b03348SPoul-Henning Kamp * 1193b0b03348SPoul-Henning Kamp */ 1194b0b03348SPoul-Henning Kamp 1195b0b03348SPoul-Henning Kamp struct clonedevs { 1196b0b03348SPoul-Henning Kamp LIST_HEAD(,cdev) head; 1197b0b03348SPoul-Henning Kamp }; 1198b0b03348SPoul-Henning Kamp 11999397290eSPoul-Henning Kamp void 12009397290eSPoul-Henning Kamp clone_setup(struct clonedevs **cdp) 12019397290eSPoul-Henning Kamp { 12029397290eSPoul-Henning Kamp 12039397290eSPoul-Henning Kamp *cdp = malloc(sizeof **cdp, M_DEVBUF, M_WAITOK | M_ZERO); 12049397290eSPoul-Henning Kamp LIST_INIT(&(*cdp)->head); 12059397290eSPoul-Henning Kamp } 12069397290eSPoul-Henning Kamp 1207b0b03348SPoul-Henning Kamp int 1208cf141467SKonstantin Belousov clone_create(struct clonedevs **cdp, struct cdevsw *csw, int *up, 1209cf141467SKonstantin Belousov struct cdev **dp, int extra) 1210b0b03348SPoul-Henning Kamp { 1211b0b03348SPoul-Henning Kamp struct clonedevs *cd; 1212027b1f71SPoul-Henning Kamp struct cdev *dev, *ndev, *dl, *de; 1213b0b03348SPoul-Henning Kamp int unit, low, u; 1214b0b03348SPoul-Henning Kamp 12159397290eSPoul-Henning Kamp KASSERT(*cdp != NULL, 12169397290eSPoul-Henning Kamp ("clone_setup() not called in driver \"%s\"", csw->d_name)); 1217b0b03348SPoul-Henning Kamp KASSERT(!(extra & CLONE_UNITMASK), 1218b0b03348SPoul-Henning Kamp ("Illegal extra bits (0x%x) in clone_create", extra)); 1219b0b03348SPoul-Henning Kamp KASSERT(*up <= CLONE_UNITMASK, 1220b0b03348SPoul-Henning Kamp ("Too high unit (0x%x) in clone_create", *up)); 122129d4cb24SEd Schouten KASSERT(csw->d_flags & D_NEEDMINOR, 122229d4cb24SEd Schouten ("clone_create() on cdevsw without minor numbers")); 1223b0b03348SPoul-Henning Kamp 1224b0b03348SPoul-Henning Kamp 1225b0b03348SPoul-Henning Kamp /* 1226b0b03348SPoul-Henning Kamp * Search the list for a lot of things in one go: 1227b0b03348SPoul-Henning Kamp * A preexisting match is returned immediately. 1228b0b03348SPoul-Henning Kamp * The lowest free unit number if we are passed -1, and the place 1229b0b03348SPoul-Henning Kamp * in the list where we should insert that new element. 1230b0b03348SPoul-Henning Kamp * The place to insert a specified unit number, if applicable 1231b0b03348SPoul-Henning Kamp * the end of the list. 1232b0b03348SPoul-Henning Kamp */ 1233b0b03348SPoul-Henning Kamp unit = *up; 1234d2ba618aSKonstantin Belousov ndev = devfs_alloc(MAKEDEV_WAITOK); 1235027b1f71SPoul-Henning Kamp dev_lock(); 1236d2ba618aSKonstantin Belousov prep_cdevsw(csw, MAKEDEV_WAITOK); 12378666b655SPoul-Henning Kamp low = extra; 1238b0b03348SPoul-Henning Kamp de = dl = NULL; 12399397290eSPoul-Henning Kamp cd = *cdp; 1240b0b03348SPoul-Henning Kamp LIST_FOREACH(dev, &cd->head, si_clone) { 1241027b1f71SPoul-Henning Kamp KASSERT(dev->si_flags & SI_CLONELIST, 1242027b1f71SPoul-Henning Kamp ("Dev %p(%s) should be on clonelist", dev, dev->si_name)); 1243b0b03348SPoul-Henning Kamp u = dev2unit(dev); 1244b0b03348SPoul-Henning Kamp if (u == (unit | extra)) { 1245b0b03348SPoul-Henning Kamp *dp = dev; 1246027b1f71SPoul-Henning Kamp dev_unlock(); 12479bc911d4SKonstantin Belousov devfs_free(ndev); 1248b0b03348SPoul-Henning Kamp return (0); 1249b0b03348SPoul-Henning Kamp } 1250b0b03348SPoul-Henning Kamp if (unit == -1 && u == low) { 1251b0b03348SPoul-Henning Kamp low++; 1252b0b03348SPoul-Henning Kamp de = dev; 1253b0b03348SPoul-Henning Kamp continue; 12547bbb3a26SPoul-Henning Kamp } else if (u < (unit | extra)) { 12557bbb3a26SPoul-Henning Kamp de = dev; 12567bbb3a26SPoul-Henning Kamp continue; 12577bbb3a26SPoul-Henning Kamp } else if (u > (unit | extra)) { 1258b0b03348SPoul-Henning Kamp dl = dev; 1259b0b03348SPoul-Henning Kamp break; 1260b0b03348SPoul-Henning Kamp } 1261b0b03348SPoul-Henning Kamp } 1262b0b03348SPoul-Henning Kamp if (unit == -1) 12638666b655SPoul-Henning Kamp unit = low & CLONE_UNITMASK; 1264d3ce8327SEd Schouten dev = newdev(csw, unit | extra, ndev); 1265027b1f71SPoul-Henning Kamp if (dev->si_flags & SI_CLONELIST) { 1266027b1f71SPoul-Henning Kamp printf("dev %p (%s) is on clonelist\n", dev, dev->si_name); 12677bbb3a26SPoul-Henning Kamp printf("unit=%d, low=%d, extra=0x%x\n", unit, low, extra); 1268027b1f71SPoul-Henning Kamp LIST_FOREACH(dev, &cd->head, si_clone) { 1269027b1f71SPoul-Henning Kamp printf("\t%p %s\n", dev, dev->si_name); 1270027b1f71SPoul-Henning Kamp } 1271027b1f71SPoul-Henning Kamp panic("foo"); 1272027b1f71SPoul-Henning Kamp } 1273b0b03348SPoul-Henning Kamp KASSERT(!(dev->si_flags & SI_CLONELIST), 1274027b1f71SPoul-Henning Kamp ("Dev %p(%s) should not be on clonelist", dev, dev->si_name)); 1275b0b03348SPoul-Henning Kamp if (dl != NULL) 1276b0b03348SPoul-Henning Kamp LIST_INSERT_BEFORE(dl, dev, si_clone); 1277b0b03348SPoul-Henning Kamp else if (de != NULL) 1278b0b03348SPoul-Henning Kamp LIST_INSERT_AFTER(de, dev, si_clone); 1279b0b03348SPoul-Henning Kamp else 1280b0b03348SPoul-Henning Kamp LIST_INSERT_HEAD(&cd->head, dev, si_clone); 1281b0b03348SPoul-Henning Kamp dev->si_flags |= SI_CLONELIST; 1282b0b03348SPoul-Henning Kamp *up = unit; 12839bc911d4SKonstantin Belousov dev_unlock_and_free(); 1284b0b03348SPoul-Henning Kamp return (1); 1285b0b03348SPoul-Henning Kamp } 1286b0b03348SPoul-Henning Kamp 1287b0b03348SPoul-Henning Kamp /* 1288b0b03348SPoul-Henning Kamp * Kill everything still on the list. The driver should already have 128989c9c53dSPoul-Henning Kamp * disposed of any softc hung of the struct cdev *'s at this time. 1290b0b03348SPoul-Henning Kamp */ 1291b0b03348SPoul-Henning Kamp void 1292b0b03348SPoul-Henning Kamp clone_cleanup(struct clonedevs **cdp) 1293b0b03348SPoul-Henning Kamp { 1294de10ffa5SKonstantin Belousov struct cdev *dev; 1295de10ffa5SKonstantin Belousov struct cdev_priv *cp; 1296b0b03348SPoul-Henning Kamp struct clonedevs *cd; 1297b0b03348SPoul-Henning Kamp 1298b0b03348SPoul-Henning Kamp cd = *cdp; 1299b0b03348SPoul-Henning Kamp if (cd == NULL) 1300b0b03348SPoul-Henning Kamp return; 1301027b1f71SPoul-Henning Kamp dev_lock(); 1302de10ffa5SKonstantin Belousov while (!LIST_EMPTY(&cd->head)) { 1303de10ffa5SKonstantin Belousov dev = LIST_FIRST(&cd->head); 1304de10ffa5SKonstantin Belousov LIST_REMOVE(dev, si_clone); 1305027b1f71SPoul-Henning Kamp KASSERT(dev->si_flags & SI_CLONELIST, 1306027b1f71SPoul-Henning Kamp ("Dev %p(%s) should be on clonelist", dev, dev->si_name)); 1307de10ffa5SKonstantin Belousov dev->si_flags &= ~SI_CLONELIST; 130805427aafSKonstantin Belousov cp = cdev2priv(dev); 1309de10ffa5SKonstantin Belousov if (!(cp->cdp_flags & CDP_SCHED_DTR)) { 1310de10ffa5SKonstantin Belousov cp->cdp_flags |= CDP_SCHED_DTR; 1311b0b03348SPoul-Henning Kamp KASSERT(dev->si_flags & SI_NAMED, 1312dde58752SGleb Kurtsou ("Driver has goofed in cloning underways udev %jx unit %x", 1313dde58752SGleb Kurtsou (uintmax_t)dev2udev(dev), dev2unit(dev))); 1314aa2f6ddcSPoul-Henning Kamp destroy_devl(dev); 1315b0b03348SPoul-Henning Kamp } 1316de10ffa5SKonstantin Belousov } 1317aeeb4202SKonstantin Belousov dev_unlock_and_free(); 1318b0b03348SPoul-Henning Kamp free(cd, M_DEVBUF); 1319b0b03348SPoul-Henning Kamp *cdp = NULL; 1320b0b03348SPoul-Henning Kamp } 1321de10ffa5SKonstantin Belousov 1322de10ffa5SKonstantin Belousov static TAILQ_HEAD(, cdev_priv) dev_ddtr = 1323de10ffa5SKonstantin Belousov TAILQ_HEAD_INITIALIZER(dev_ddtr); 1324268e76d8SJohn Baldwin static struct task dev_dtr_task = TASK_INITIALIZER(0, destroy_dev_tq, NULL); 1325de10ffa5SKonstantin Belousov 1326de10ffa5SKonstantin Belousov static void 1327de10ffa5SKonstantin Belousov destroy_dev_tq(void *ctx, int pending) 1328de10ffa5SKonstantin Belousov { 1329de10ffa5SKonstantin Belousov struct cdev_priv *cp; 1330de10ffa5SKonstantin Belousov struct cdev *dev; 1331de10ffa5SKonstantin Belousov void (*cb)(void *); 1332de10ffa5SKonstantin Belousov void *cb_arg; 1333de10ffa5SKonstantin Belousov 1334de10ffa5SKonstantin Belousov dev_lock(); 1335de10ffa5SKonstantin Belousov while (!TAILQ_EMPTY(&dev_ddtr)) { 1336de10ffa5SKonstantin Belousov cp = TAILQ_FIRST(&dev_ddtr); 1337de10ffa5SKonstantin Belousov dev = &cp->cdp_c; 1338de10ffa5SKonstantin Belousov KASSERT(cp->cdp_flags & CDP_SCHED_DTR, 1339de10ffa5SKonstantin Belousov ("cdev %p in dev_destroy_tq without CDP_SCHED_DTR", cp)); 1340de10ffa5SKonstantin Belousov TAILQ_REMOVE(&dev_ddtr, cp, cdp_dtr_list); 1341de10ffa5SKonstantin Belousov cb = cp->cdp_dtr_cb; 1342de10ffa5SKonstantin Belousov cb_arg = cp->cdp_dtr_cb_arg; 1343de10ffa5SKonstantin Belousov destroy_devl(dev); 1344aeeb4202SKonstantin Belousov dev_unlock_and_free(); 1345de10ffa5SKonstantin Belousov dev_rel(dev); 1346de10ffa5SKonstantin Belousov if (cb != NULL) 1347de10ffa5SKonstantin Belousov cb(cb_arg); 1348de10ffa5SKonstantin Belousov dev_lock(); 1349de10ffa5SKonstantin Belousov } 1350de10ffa5SKonstantin Belousov dev_unlock(); 1351de10ffa5SKonstantin Belousov } 1352de10ffa5SKonstantin Belousov 13539d53363bSKonstantin Belousov /* 13549d53363bSKonstantin Belousov * devmtx shall be locked on entry. devmtx will be unlocked after 13559d53363bSKonstantin Belousov * function return. 13569d53363bSKonstantin Belousov */ 13579d53363bSKonstantin Belousov static int 13589d53363bSKonstantin Belousov destroy_dev_sched_cbl(struct cdev *dev, void (*cb)(void *), void *arg) 1359de10ffa5SKonstantin Belousov { 1360de10ffa5SKonstantin Belousov struct cdev_priv *cp; 1361de10ffa5SKonstantin Belousov 13629d53363bSKonstantin Belousov mtx_assert(&devmtx, MA_OWNED); 136305427aafSKonstantin Belousov cp = cdev2priv(dev); 1364de10ffa5SKonstantin Belousov if (cp->cdp_flags & CDP_SCHED_DTR) { 1365de10ffa5SKonstantin Belousov dev_unlock(); 1366de10ffa5SKonstantin Belousov return (0); 1367de10ffa5SKonstantin Belousov } 1368de10ffa5SKonstantin Belousov dev_refl(dev); 1369de10ffa5SKonstantin Belousov cp->cdp_flags |= CDP_SCHED_DTR; 1370de10ffa5SKonstantin Belousov cp->cdp_dtr_cb = cb; 1371de10ffa5SKonstantin Belousov cp->cdp_dtr_cb_arg = arg; 1372de10ffa5SKonstantin Belousov TAILQ_INSERT_TAIL(&dev_ddtr, cp, cdp_dtr_list); 1373de10ffa5SKonstantin Belousov dev_unlock(); 1374de10ffa5SKonstantin Belousov taskqueue_enqueue(taskqueue_swi_giant, &dev_dtr_task); 1375de10ffa5SKonstantin Belousov return (1); 1376de10ffa5SKonstantin Belousov } 1377de10ffa5SKonstantin Belousov 1378de10ffa5SKonstantin Belousov int 13799d53363bSKonstantin Belousov destroy_dev_sched_cb(struct cdev *dev, void (*cb)(void *), void *arg) 13809d53363bSKonstantin Belousov { 1381cf141467SKonstantin Belousov 13829d53363bSKonstantin Belousov dev_lock(); 13839d53363bSKonstantin Belousov return (destroy_dev_sched_cbl(dev, cb, arg)); 13849d53363bSKonstantin Belousov } 13859d53363bSKonstantin Belousov 13869d53363bSKonstantin Belousov int 1387de10ffa5SKonstantin Belousov destroy_dev_sched(struct cdev *dev) 1388de10ffa5SKonstantin Belousov { 1389cf141467SKonstantin Belousov 1390de10ffa5SKonstantin Belousov return (destroy_dev_sched_cb(dev, NULL, NULL)); 1391de10ffa5SKonstantin Belousov } 1392de10ffa5SKonstantin Belousov 1393de10ffa5SKonstantin Belousov void 1394de10ffa5SKonstantin Belousov destroy_dev_drain(struct cdevsw *csw) 1395de10ffa5SKonstantin Belousov { 1396de10ffa5SKonstantin Belousov 1397de10ffa5SKonstantin Belousov dev_lock(); 1398de10ffa5SKonstantin Belousov while (!LIST_EMPTY(&csw->d_devs)) { 1399de10ffa5SKonstantin Belousov msleep(&csw->d_devs, &devmtx, PRIBIO, "devscd", hz/10); 1400de10ffa5SKonstantin Belousov } 1401de10ffa5SKonstantin Belousov dev_unlock(); 1402de10ffa5SKonstantin Belousov } 1403de10ffa5SKonstantin Belousov 1404de10ffa5SKonstantin Belousov void 1405de10ffa5SKonstantin Belousov drain_dev_clone_events(void) 1406de10ffa5SKonstantin Belousov { 1407de10ffa5SKonstantin Belousov 1408de10ffa5SKonstantin Belousov sx_xlock(&clone_drain_lock); 1409de10ffa5SKonstantin Belousov sx_xunlock(&clone_drain_lock); 1410de10ffa5SKonstantin Belousov } 1411de10ffa5SKonstantin Belousov 14126c5e633cSKonstantin Belousov #include "opt_ddb.h" 14136c5e633cSKonstantin Belousov #ifdef DDB 14146c5e633cSKonstantin Belousov #include <sys/kernel.h> 14156c5e633cSKonstantin Belousov 14166c5e633cSKonstantin Belousov #include <ddb/ddb.h> 14176c5e633cSKonstantin Belousov 14186c5e633cSKonstantin Belousov DB_SHOW_COMMAND(cdev, db_show_cdev) 14196c5e633cSKonstantin Belousov { 14206c5e633cSKonstantin Belousov struct cdev_priv *cdp; 14216c5e633cSKonstantin Belousov struct cdev *dev; 14226c5e633cSKonstantin Belousov u_int flags; 14236c5e633cSKonstantin Belousov char buf[512]; 14246c5e633cSKonstantin Belousov 14256c5e633cSKonstantin Belousov if (!have_addr) { 14266c5e633cSKonstantin Belousov TAILQ_FOREACH(cdp, &cdevp_list, cdp_list) { 14276c5e633cSKonstantin Belousov dev = &cdp->cdp_c; 14286c5e633cSKonstantin Belousov db_printf("%s %p\n", dev->si_name, dev); 14296c5e633cSKonstantin Belousov if (db_pager_quit) 14306c5e633cSKonstantin Belousov break; 14316c5e633cSKonstantin Belousov } 14326c5e633cSKonstantin Belousov return; 14336c5e633cSKonstantin Belousov } 14346c5e633cSKonstantin Belousov 14356c5e633cSKonstantin Belousov dev = (struct cdev *)addr; 14366c5e633cSKonstantin Belousov cdp = cdev2priv(dev); 14376c5e633cSKonstantin Belousov db_printf("dev %s ref %d use %ld thr %ld inuse %u fdpriv %p\n", 14386c5e633cSKonstantin Belousov dev->si_name, dev->si_refcount, dev->si_usecount, 14396c5e633cSKonstantin Belousov dev->si_threadcount, cdp->cdp_inuse, cdp->cdp_fdpriv.lh_first); 14406c5e633cSKonstantin Belousov db_printf("devsw %p si_drv0 %d si_drv1 %p si_drv2 %p\n", 14416c5e633cSKonstantin Belousov dev->si_devsw, dev->si_drv0, dev->si_drv1, dev->si_drv2); 14426c5e633cSKonstantin Belousov flags = dev->si_flags; 14436c5e633cSKonstantin Belousov #define SI_FLAG(flag) do { \ 14446c5e633cSKonstantin Belousov if (flags & (flag)) { \ 14456c5e633cSKonstantin Belousov if (buf[0] != '\0') \ 14466c5e633cSKonstantin Belousov strlcat(buf, ", ", sizeof(buf)); \ 14476c5e633cSKonstantin Belousov strlcat(buf, (#flag) + 3, sizeof(buf)); \ 14486c5e633cSKonstantin Belousov flags &= ~(flag); \ 14496c5e633cSKonstantin Belousov } \ 14506c5e633cSKonstantin Belousov } while (0) 14516c5e633cSKonstantin Belousov buf[0] = '\0'; 14526c5e633cSKonstantin Belousov SI_FLAG(SI_ETERNAL); 14536c5e633cSKonstantin Belousov SI_FLAG(SI_ALIAS); 14546c5e633cSKonstantin Belousov SI_FLAG(SI_NAMED); 14556c5e633cSKonstantin Belousov SI_FLAG(SI_CHEAPCLONE); 14566c5e633cSKonstantin Belousov SI_FLAG(SI_CHILD); 14576c5e633cSKonstantin Belousov SI_FLAG(SI_DUMPDEV); 14586c5e633cSKonstantin Belousov SI_FLAG(SI_CLONELIST); 14596c5e633cSKonstantin Belousov db_printf("si_flags %s\n", buf); 14606c5e633cSKonstantin Belousov 14616c5e633cSKonstantin Belousov flags = cdp->cdp_flags; 14626c5e633cSKonstantin Belousov #define CDP_FLAG(flag) do { \ 14636c5e633cSKonstantin Belousov if (flags & (flag)) { \ 14646c5e633cSKonstantin Belousov if (buf[0] != '\0') \ 14656c5e633cSKonstantin Belousov strlcat(buf, ", ", sizeof(buf)); \ 14666c5e633cSKonstantin Belousov strlcat(buf, (#flag) + 4, sizeof(buf)); \ 14676c5e633cSKonstantin Belousov flags &= ~(flag); \ 14686c5e633cSKonstantin Belousov } \ 14696c5e633cSKonstantin Belousov } while (0) 14706c5e633cSKonstantin Belousov buf[0] = '\0'; 14716c5e633cSKonstantin Belousov CDP_FLAG(CDP_ACTIVE); 14726c5e633cSKonstantin Belousov CDP_FLAG(CDP_SCHED_DTR); 14736c5e633cSKonstantin Belousov db_printf("cdp_flags %s\n", buf); 14746c5e633cSKonstantin Belousov } 14756c5e633cSKonstantin Belousov #endif 1476