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); 58f1bb758dSKonstantin Belousov static int make_dev_credv(int flags, struct cdev **dres, struct cdevsw *devsw, 59f1bb758dSKonstantin Belousov int unit, struct ucred *cr, uid_t uid, gid_t gid, int mode, const char *fmt, 60d26dd2d9SRobert Watson va_list ap); 61f3732fd1SPoul-Henning Kamp 629bc911d4SKonstantin Belousov static struct cdev_priv_list cdevp_free_list = 639bc911d4SKonstantin Belousov TAILQ_HEAD_INITIALIZER(cdevp_free_list); 64aeeb4202SKonstantin Belousov static SLIST_HEAD(free_cdevsw, cdevsw) cdevsw_gt_post_list = 6513e403fdSAntoine Brodin SLIST_HEAD_INITIALIZER(cdevsw_gt_post_list); 669bc911d4SKonstantin Belousov 67a0e78d2eSPoul-Henning Kamp void 68a0e78d2eSPoul-Henning Kamp dev_lock(void) 69cd690b60SPoul-Henning Kamp { 708c4b6380SJohn Baldwin 71cd690b60SPoul-Henning Kamp mtx_lock(&devmtx); 72cd690b60SPoul-Henning Kamp } 73cd690b60SPoul-Henning Kamp 74aeeb4202SKonstantin Belousov /* 75aeeb4202SKonstantin Belousov * Free all the memory collected while the cdev mutex was 76aeeb4202SKonstantin Belousov * locked. Since devmtx is after the system map mutex, free() cannot 77aeeb4202SKonstantin Belousov * be called immediately and is postponed until cdev mutex can be 78aeeb4202SKonstantin Belousov * dropped. 79aeeb4202SKonstantin Belousov */ 809bc911d4SKonstantin Belousov static void 819bc911d4SKonstantin Belousov dev_unlock_and_free(void) 829bc911d4SKonstantin Belousov { 83aeeb4202SKonstantin Belousov struct cdev_priv_list cdp_free; 84aeeb4202SKonstantin Belousov struct free_cdevsw csw_free; 859bc911d4SKonstantin Belousov struct cdev_priv *cdp; 86aeeb4202SKonstantin Belousov struct cdevsw *csw; 879bc911d4SKonstantin Belousov 889bc911d4SKonstantin Belousov mtx_assert(&devmtx, MA_OWNED); 89aeeb4202SKonstantin Belousov 90aeeb4202SKonstantin Belousov /* 91aeeb4202SKonstantin Belousov * Make the local copy of the list heads while the dev_mtx is 92aeeb4202SKonstantin Belousov * held. Free it later. 93aeeb4202SKonstantin Belousov */ 94aeeb4202SKonstantin Belousov TAILQ_INIT(&cdp_free); 95aeeb4202SKonstantin Belousov TAILQ_CONCAT(&cdp_free, &cdevp_free_list, cdp_list); 96aeeb4202SKonstantin Belousov csw_free = cdevsw_gt_post_list; 97aeeb4202SKonstantin Belousov SLIST_INIT(&cdevsw_gt_post_list); 98aeeb4202SKonstantin Belousov 999bc911d4SKonstantin Belousov mtx_unlock(&devmtx); 100aeeb4202SKonstantin Belousov 101aeeb4202SKonstantin Belousov while ((cdp = TAILQ_FIRST(&cdp_free)) != NULL) { 102aeeb4202SKonstantin Belousov TAILQ_REMOVE(&cdp_free, cdp, cdp_list); 1039bc911d4SKonstantin Belousov devfs_free(&cdp->cdp_c); 1049bc911d4SKonstantin Belousov } 105aeeb4202SKonstantin Belousov while ((csw = SLIST_FIRST(&csw_free)) != NULL) { 106aeeb4202SKonstantin Belousov SLIST_REMOVE_HEAD(&csw_free, d_postfree_list); 107aeeb4202SKonstantin Belousov free(csw, M_DEVT); 108aeeb4202SKonstantin Belousov } 1099bc911d4SKonstantin Belousov } 1109bc911d4SKonstantin Belousov 1119bc911d4SKonstantin Belousov static void 1129bc911d4SKonstantin Belousov dev_free_devlocked(struct cdev *cdev) 1139bc911d4SKonstantin Belousov { 1149bc911d4SKonstantin Belousov struct cdev_priv *cdp; 1159bc911d4SKonstantin Belousov 1169bc911d4SKonstantin Belousov mtx_assert(&devmtx, MA_OWNED); 11705427aafSKonstantin Belousov cdp = cdev2priv(cdev); 1189bc911d4SKonstantin Belousov TAILQ_INSERT_HEAD(&cdevp_free_list, cdp, cdp_list); 1199bc911d4SKonstantin Belousov } 1209bc911d4SKonstantin Belousov 121aeeb4202SKonstantin Belousov static void 122aeeb4202SKonstantin Belousov cdevsw_free_devlocked(struct cdevsw *csw) 123aeeb4202SKonstantin Belousov { 124aeeb4202SKonstantin Belousov 125aeeb4202SKonstantin Belousov mtx_assert(&devmtx, MA_OWNED); 126aeeb4202SKonstantin Belousov SLIST_INSERT_HEAD(&cdevsw_gt_post_list, csw, d_postfree_list); 127aeeb4202SKonstantin Belousov } 128aeeb4202SKonstantin Belousov 129a0e78d2eSPoul-Henning Kamp void 130a0e78d2eSPoul-Henning Kamp dev_unlock(void) 131cd690b60SPoul-Henning Kamp { 1322c15afd8SPoul-Henning Kamp 133cd690b60SPoul-Henning Kamp mtx_unlock(&devmtx); 134cd690b60SPoul-Henning Kamp } 135cd690b60SPoul-Henning Kamp 136cd690b60SPoul-Henning Kamp void 1379477d73eSPoul-Henning Kamp dev_ref(struct cdev *dev) 1389477d73eSPoul-Henning Kamp { 1399477d73eSPoul-Henning Kamp 1409477d73eSPoul-Henning Kamp mtx_assert(&devmtx, MA_NOTOWNED); 1419477d73eSPoul-Henning Kamp mtx_lock(&devmtx); 1429477d73eSPoul-Henning Kamp dev->si_refcount++; 1439477d73eSPoul-Henning Kamp mtx_unlock(&devmtx); 1449477d73eSPoul-Henning Kamp } 1459477d73eSPoul-Henning Kamp 1469477d73eSPoul-Henning Kamp void 147eb151cb9SPoul-Henning Kamp dev_refl(struct cdev *dev) 148cd690b60SPoul-Henning Kamp { 1492c15afd8SPoul-Henning Kamp 1501a1457d4SPoul-Henning Kamp mtx_assert(&devmtx, MA_OWNED); 151cd690b60SPoul-Henning Kamp dev->si_refcount++; 152cd690b60SPoul-Henning Kamp } 153cd690b60SPoul-Henning Kamp 154cd690b60SPoul-Henning Kamp void 155aa2f6ddcSPoul-Henning Kamp dev_rel(struct cdev *dev) 156cd690b60SPoul-Henning Kamp { 157aa2f6ddcSPoul-Henning Kamp int flag = 0; 158a0e78d2eSPoul-Henning Kamp 159ba285125SPoul-Henning Kamp mtx_assert(&devmtx, MA_NOTOWNED); 160ba285125SPoul-Henning Kamp dev_lock(); 161cd690b60SPoul-Henning Kamp dev->si_refcount--; 162cd690b60SPoul-Henning Kamp KASSERT(dev->si_refcount >= 0, 163cd690b60SPoul-Henning Kamp ("dev_rel(%s) gave negative count", devtoname(dev))); 164e606a3c6SPoul-Henning Kamp #if 0 165aa2f6ddcSPoul-Henning Kamp if (dev->si_usecount == 0 && 166aa2f6ddcSPoul-Henning Kamp (dev->si_flags & SI_CHEAPCLONE) && (dev->si_flags & SI_NAMED)) 167e606a3c6SPoul-Henning Kamp ; 168e606a3c6SPoul-Henning Kamp else 169e606a3c6SPoul-Henning Kamp #endif 170cd690b60SPoul-Henning Kamp if (dev->si_devsw == NULL && dev->si_refcount == 0) { 171cd690b60SPoul-Henning Kamp LIST_REMOVE(dev, si_list); 172ba285125SPoul-Henning Kamp flag = 1; 173ba285125SPoul-Henning Kamp } 174ba285125SPoul-Henning Kamp dev_unlock(); 175ba285125SPoul-Henning Kamp if (flag) 176e606a3c6SPoul-Henning Kamp devfs_free(dev); 177cd690b60SPoul-Henning Kamp } 178ba285125SPoul-Henning Kamp 1792c15afd8SPoul-Henning Kamp struct cdevsw * 180*3979450bSKonstantin Belousov dev_refthread(struct cdev *dev, int *ref) 1812c15afd8SPoul-Henning Kamp { 1822c15afd8SPoul-Henning Kamp struct cdevsw *csw; 183de10ffa5SKonstantin Belousov struct cdev_priv *cdp; 1842c15afd8SPoul-Henning Kamp 1852c15afd8SPoul-Henning Kamp mtx_assert(&devmtx, MA_NOTOWNED); 186*3979450bSKonstantin Belousov if ((dev->si_flags & SI_ETERNAL) != 0) { 187*3979450bSKonstantin Belousov *ref = 0; 188*3979450bSKonstantin Belousov return (dev->si_devsw); 189*3979450bSKonstantin Belousov } 1902c15afd8SPoul-Henning Kamp dev_lock(); 1912c15afd8SPoul-Henning Kamp csw = dev->si_devsw; 192de10ffa5SKonstantin Belousov if (csw != NULL) { 19305427aafSKonstantin Belousov cdp = cdev2priv(dev); 194de10ffa5SKonstantin Belousov if ((cdp->cdp_flags & CDP_SCHED_DTR) == 0) 1952c15afd8SPoul-Henning Kamp dev->si_threadcount++; 196de10ffa5SKonstantin Belousov else 197de10ffa5SKonstantin Belousov csw = NULL; 198de10ffa5SKonstantin Belousov } 1992c15afd8SPoul-Henning Kamp dev_unlock(); 200*3979450bSKonstantin Belousov *ref = 1; 2012c15afd8SPoul-Henning Kamp return (csw); 2022c15afd8SPoul-Henning Kamp } 2032c15afd8SPoul-Henning Kamp 2041663075cSKonstantin Belousov struct cdevsw * 205*3979450bSKonstantin Belousov devvn_refthread(struct vnode *vp, struct cdev **devp, int *ref) 2061663075cSKonstantin Belousov { 2071663075cSKonstantin Belousov struct cdevsw *csw; 208de10ffa5SKonstantin Belousov struct cdev_priv *cdp; 209*3979450bSKonstantin Belousov struct cdev *dev; 2101663075cSKonstantin Belousov 2111663075cSKonstantin Belousov mtx_assert(&devmtx, MA_NOTOWNED); 212*3979450bSKonstantin Belousov if ((vp->v_vflag & VV_ETERNALDEV) != 0) { 213*3979450bSKonstantin Belousov dev = vp->v_rdev; 214*3979450bSKonstantin Belousov if (dev == NULL) 215*3979450bSKonstantin Belousov return (NULL); 216*3979450bSKonstantin Belousov KASSERT((dev->si_flags & SI_ETERNAL) != 0, 217*3979450bSKonstantin Belousov ("Not eternal cdev")); 218*3979450bSKonstantin Belousov *ref = 0; 219*3979450bSKonstantin Belousov csw = dev->si_devsw; 220*3979450bSKonstantin Belousov KASSERT(csw != NULL, ("Eternal cdev is destroyed")); 221*3979450bSKonstantin Belousov *devp = dev; 222*3979450bSKonstantin Belousov return (csw); 223*3979450bSKonstantin Belousov } 224*3979450bSKonstantin Belousov 2251663075cSKonstantin Belousov csw = NULL; 2261663075cSKonstantin Belousov dev_lock(); 227*3979450bSKonstantin Belousov dev = vp->v_rdev; 228*3979450bSKonstantin Belousov if (dev == NULL) { 229*3979450bSKonstantin Belousov dev_unlock(); 230*3979450bSKonstantin Belousov return (NULL); 2311663075cSKonstantin Belousov } 232*3979450bSKonstantin Belousov cdp = cdev2priv(dev); 233*3979450bSKonstantin Belousov if ((cdp->cdp_flags & CDP_SCHED_DTR) == 0) { 234*3979450bSKonstantin Belousov csw = dev->si_devsw; 235*3979450bSKonstantin Belousov if (csw != NULL) 236*3979450bSKonstantin Belousov dev->si_threadcount++; 237de10ffa5SKonstantin Belousov } 2381663075cSKonstantin Belousov dev_unlock(); 239*3979450bSKonstantin Belousov if (csw != NULL) { 240*3979450bSKonstantin Belousov *devp = dev; 241*3979450bSKonstantin Belousov *ref = 1; 242*3979450bSKonstantin Belousov } 2431663075cSKonstantin Belousov return (csw); 2441663075cSKonstantin Belousov } 2451663075cSKonstantin Belousov 2462c15afd8SPoul-Henning Kamp void 247*3979450bSKonstantin Belousov dev_relthread(struct cdev *dev, int ref) 2482c15afd8SPoul-Henning Kamp { 2492c15afd8SPoul-Henning Kamp 2502c15afd8SPoul-Henning Kamp mtx_assert(&devmtx, MA_NOTOWNED); 251*3979450bSKonstantin Belousov if (!ref) 252*3979450bSKonstantin Belousov return; 2532c15afd8SPoul-Henning Kamp dev_lock(); 25406fe1129SKonstantin Belousov KASSERT(dev->si_threadcount > 0, 25506fe1129SKonstantin Belousov ("%s threadcount is wrong", dev->si_name)); 2562c15afd8SPoul-Henning Kamp dev->si_threadcount--; 2572c15afd8SPoul-Henning Kamp dev_unlock(); 2582c15afd8SPoul-Henning Kamp } 259cd690b60SPoul-Henning Kamp 260b2941431SPoul-Henning Kamp int 261b2941431SPoul-Henning Kamp nullop(void) 262b2941431SPoul-Henning Kamp { 263b2941431SPoul-Henning Kamp 264b2941431SPoul-Henning Kamp return (0); 265b2941431SPoul-Henning Kamp } 266b2941431SPoul-Henning Kamp 267b2941431SPoul-Henning Kamp int 268b2941431SPoul-Henning Kamp eopnotsupp(void) 269b2941431SPoul-Henning Kamp { 270b2941431SPoul-Henning Kamp 271b2941431SPoul-Henning Kamp return (EOPNOTSUPP); 272b2941431SPoul-Henning Kamp } 27302574b19SPoul-Henning Kamp 27402574b19SPoul-Henning Kamp static int 27502574b19SPoul-Henning Kamp enxio(void) 27602574b19SPoul-Henning Kamp { 27702574b19SPoul-Henning Kamp return (ENXIO); 27802574b19SPoul-Henning Kamp } 27902574b19SPoul-Henning Kamp 280b2941431SPoul-Henning Kamp static int 281b2941431SPoul-Henning Kamp enodev(void) 282b2941431SPoul-Henning Kamp { 283b2941431SPoul-Henning Kamp return (ENODEV); 284b2941431SPoul-Henning Kamp } 285b2941431SPoul-Henning Kamp 286b2941431SPoul-Henning Kamp /* Define a dead_cdevsw for use when devices leave unexpectedly. */ 287b2941431SPoul-Henning Kamp 28802574b19SPoul-Henning Kamp #define dead_open (d_open_t *)enxio 28902574b19SPoul-Henning Kamp #define dead_close (d_close_t *)enxio 29002574b19SPoul-Henning Kamp #define dead_read (d_read_t *)enxio 29102574b19SPoul-Henning Kamp #define dead_write (d_write_t *)enxio 29202574b19SPoul-Henning Kamp #define dead_ioctl (d_ioctl_t *)enxio 293b2941431SPoul-Henning Kamp #define dead_poll (d_poll_t *)enodev 294b2941431SPoul-Henning Kamp #define dead_mmap (d_mmap_t *)enodev 29502574b19SPoul-Henning Kamp 29602574b19SPoul-Henning Kamp static void 29702574b19SPoul-Henning Kamp dead_strategy(struct bio *bp) 29802574b19SPoul-Henning Kamp { 29902574b19SPoul-Henning Kamp 30002574b19SPoul-Henning Kamp biofinish(bp, NULL, ENXIO); 30102574b19SPoul-Henning Kamp } 30202574b19SPoul-Henning Kamp 3032c6b49f6SPoul-Henning Kamp #define dead_dump (dumper_t *)enxio 30402574b19SPoul-Henning Kamp #define dead_kqfilter (d_kqfilter_t *)enxio 30564345f0bSJohn Baldwin #define dead_mmap_single (d_mmap_single_t *)enodev 30602574b19SPoul-Henning Kamp 30702574b19SPoul-Henning Kamp static struct cdevsw dead_cdevsw = { 308dc08ffecSPoul-Henning Kamp .d_version = D_VERSION, 309dc08ffecSPoul-Henning Kamp .d_flags = D_NEEDGIANT, /* XXX: does dead_strategy need this ? */ 3107ac40f5fSPoul-Henning Kamp .d_open = dead_open, 3117ac40f5fSPoul-Henning Kamp .d_close = dead_close, 3127ac40f5fSPoul-Henning Kamp .d_read = dead_read, 3137ac40f5fSPoul-Henning Kamp .d_write = dead_write, 3147ac40f5fSPoul-Henning Kamp .d_ioctl = dead_ioctl, 3157ac40f5fSPoul-Henning Kamp .d_poll = dead_poll, 3167ac40f5fSPoul-Henning Kamp .d_mmap = dead_mmap, 3177ac40f5fSPoul-Henning Kamp .d_strategy = dead_strategy, 3187ac40f5fSPoul-Henning Kamp .d_name = "dead", 3197ac40f5fSPoul-Henning Kamp .d_dump = dead_dump, 32064345f0bSJohn Baldwin .d_kqfilter = dead_kqfilter, 32164345f0bSJohn Baldwin .d_mmap_single = dead_mmap_single 32202574b19SPoul-Henning Kamp }; 32302574b19SPoul-Henning Kamp 324b2941431SPoul-Henning Kamp /* Default methods if driver does not specify method */ 325b2941431SPoul-Henning Kamp 326b2941431SPoul-Henning Kamp #define null_open (d_open_t *)nullop 327b2941431SPoul-Henning Kamp #define null_close (d_close_t *)nullop 328b2941431SPoul-Henning Kamp #define no_read (d_read_t *)enodev 329b2941431SPoul-Henning Kamp #define no_write (d_write_t *)enodev 330b2941431SPoul-Henning Kamp #define no_ioctl (d_ioctl_t *)enodev 331cfd7baceSRobert Noland #define no_mmap (d_mmap_t *)enodev 332ad3b9257SJohn-Mark Gurney #define no_kqfilter (d_kqfilter_t *)enodev 33364345f0bSJohn Baldwin #define no_mmap_single (d_mmap_single_t *)enodev 334b2941431SPoul-Henning Kamp 335b2941431SPoul-Henning Kamp static void 336b2941431SPoul-Henning Kamp no_strategy(struct bio *bp) 337b2941431SPoul-Henning Kamp { 338b2941431SPoul-Henning Kamp 339b2941431SPoul-Henning Kamp biofinish(bp, NULL, ENODEV); 340b2941431SPoul-Henning Kamp } 341b2941431SPoul-Henning Kamp 342b2941431SPoul-Henning Kamp static int 34389c9c53dSPoul-Henning Kamp no_poll(struct cdev *dev __unused, int events, struct thread *td __unused) 344b2941431SPoul-Henning Kamp { 345b2941431SPoul-Henning Kamp 346125dcf8cSKonstantin Belousov return (poll_no_poll(events)); 347b2941431SPoul-Henning Kamp } 348b2941431SPoul-Henning Kamp 349b2941431SPoul-Henning Kamp #define no_dump (dumper_t *)enodev 3504e4a7663SPoul-Henning Kamp 351516ad423SPoul-Henning Kamp static int 352516ad423SPoul-Henning Kamp giant_open(struct cdev *dev, int oflags, int devtype, struct thread *td) 353516ad423SPoul-Henning Kamp { 354aeeb4202SKonstantin Belousov struct cdevsw *dsw; 355*3979450bSKonstantin Belousov int ref, retval; 356516ad423SPoul-Henning Kamp 357*3979450bSKonstantin Belousov dsw = dev_refthread(dev, &ref); 358aeeb4202SKonstantin Belousov if (dsw == NULL) 359aeeb4202SKonstantin Belousov return (ENXIO); 360516ad423SPoul-Henning Kamp mtx_lock(&Giant); 361aeeb4202SKonstantin Belousov retval = dsw->d_gianttrick->d_open(dev, oflags, devtype, td); 362516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 363*3979450bSKonstantin Belousov dev_relthread(dev, ref); 364516ad423SPoul-Henning Kamp return (retval); 365516ad423SPoul-Henning Kamp } 366516ad423SPoul-Henning Kamp 367516ad423SPoul-Henning Kamp static int 3689e223287SKonstantin Belousov giant_fdopen(struct cdev *dev, int oflags, struct thread *td, struct file *fp) 369516ad423SPoul-Henning Kamp { 370aeeb4202SKonstantin Belousov struct cdevsw *dsw; 371*3979450bSKonstantin Belousov int ref, retval; 372516ad423SPoul-Henning Kamp 373*3979450bSKonstantin Belousov dsw = dev_refthread(dev, &ref); 374aeeb4202SKonstantin Belousov if (dsw == NULL) 375aeeb4202SKonstantin Belousov return (ENXIO); 376516ad423SPoul-Henning Kamp mtx_lock(&Giant); 377aeeb4202SKonstantin Belousov retval = dsw->d_gianttrick->d_fdopen(dev, oflags, td, fp); 378516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 379*3979450bSKonstantin Belousov dev_relthread(dev, ref); 380516ad423SPoul-Henning Kamp return (retval); 381516ad423SPoul-Henning Kamp } 382516ad423SPoul-Henning Kamp 383516ad423SPoul-Henning Kamp static int 384516ad423SPoul-Henning Kamp giant_close(struct cdev *dev, int fflag, int devtype, struct thread *td) 385516ad423SPoul-Henning Kamp { 386aeeb4202SKonstantin Belousov struct cdevsw *dsw; 387*3979450bSKonstantin Belousov int ref, retval; 388516ad423SPoul-Henning Kamp 389*3979450bSKonstantin Belousov dsw = dev_refthread(dev, &ref); 390aeeb4202SKonstantin Belousov if (dsw == NULL) 391aeeb4202SKonstantin Belousov return (ENXIO); 392516ad423SPoul-Henning Kamp mtx_lock(&Giant); 393aeeb4202SKonstantin Belousov retval = dsw->d_gianttrick->d_close(dev, fflag, devtype, td); 394516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 395*3979450bSKonstantin Belousov dev_relthread(dev, ref); 396516ad423SPoul-Henning Kamp return (retval); 397516ad423SPoul-Henning Kamp } 398516ad423SPoul-Henning Kamp 399516ad423SPoul-Henning Kamp static void 400516ad423SPoul-Henning Kamp giant_strategy(struct bio *bp) 401516ad423SPoul-Henning Kamp { 402aeeb4202SKonstantin Belousov struct cdevsw *dsw; 403aeeb4202SKonstantin Belousov struct cdev *dev; 404*3979450bSKonstantin Belousov int ref; 405516ad423SPoul-Henning Kamp 406aeeb4202SKonstantin Belousov dev = bp->bio_dev; 407*3979450bSKonstantin Belousov dsw = dev_refthread(dev, &ref); 408aeeb4202SKonstantin Belousov if (dsw == NULL) { 409aeeb4202SKonstantin Belousov biofinish(bp, NULL, ENXIO); 410aeeb4202SKonstantin Belousov return; 411aeeb4202SKonstantin Belousov } 412516ad423SPoul-Henning Kamp mtx_lock(&Giant); 413aeeb4202SKonstantin Belousov dsw->d_gianttrick->d_strategy(bp); 414516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 415*3979450bSKonstantin Belousov dev_relthread(dev, ref); 416516ad423SPoul-Henning Kamp } 417516ad423SPoul-Henning Kamp 418516ad423SPoul-Henning Kamp static int 419516ad423SPoul-Henning Kamp giant_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct thread *td) 420516ad423SPoul-Henning Kamp { 421aeeb4202SKonstantin Belousov struct cdevsw *dsw; 422*3979450bSKonstantin Belousov int ref, retval; 423516ad423SPoul-Henning Kamp 424*3979450bSKonstantin Belousov dsw = dev_refthread(dev, &ref); 425aeeb4202SKonstantin Belousov if (dsw == NULL) 426aeeb4202SKonstantin Belousov return (ENXIO); 427516ad423SPoul-Henning Kamp mtx_lock(&Giant); 42835b45029SKonstantin Belousov retval = dsw->d_gianttrick->d_ioctl(dev, cmd, data, fflag, td); 429516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 430*3979450bSKonstantin Belousov dev_relthread(dev, ref); 431516ad423SPoul-Henning Kamp return (retval); 432516ad423SPoul-Henning Kamp } 433516ad423SPoul-Henning Kamp 434516ad423SPoul-Henning Kamp static int 435516ad423SPoul-Henning Kamp giant_read(struct cdev *dev, struct uio *uio, int ioflag) 436516ad423SPoul-Henning Kamp { 437aeeb4202SKonstantin Belousov struct cdevsw *dsw; 438*3979450bSKonstantin Belousov int ref, retval; 439516ad423SPoul-Henning Kamp 440*3979450bSKonstantin Belousov dsw = dev_refthread(dev, &ref); 441aeeb4202SKonstantin Belousov if (dsw == NULL) 442aeeb4202SKonstantin Belousov return (ENXIO); 443516ad423SPoul-Henning Kamp mtx_lock(&Giant); 44435b45029SKonstantin Belousov retval = dsw->d_gianttrick->d_read(dev, uio, ioflag); 445516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 446*3979450bSKonstantin Belousov dev_relthread(dev, ref); 447516ad423SPoul-Henning Kamp return (retval); 448516ad423SPoul-Henning Kamp } 449516ad423SPoul-Henning Kamp 450516ad423SPoul-Henning Kamp static int 451516ad423SPoul-Henning Kamp giant_write(struct cdev *dev, struct uio *uio, int ioflag) 452516ad423SPoul-Henning Kamp { 453aeeb4202SKonstantin Belousov struct cdevsw *dsw; 454*3979450bSKonstantin Belousov int ref, retval; 455516ad423SPoul-Henning Kamp 456*3979450bSKonstantin Belousov dsw = dev_refthread(dev, &ref); 457aeeb4202SKonstantin Belousov if (dsw == NULL) 458aeeb4202SKonstantin Belousov return (ENXIO); 459516ad423SPoul-Henning Kamp mtx_lock(&Giant); 460aeeb4202SKonstantin Belousov retval = dsw->d_gianttrick->d_write(dev, uio, ioflag); 461516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 462*3979450bSKonstantin Belousov dev_relthread(dev, ref); 463516ad423SPoul-Henning Kamp return (retval); 464516ad423SPoul-Henning Kamp } 465516ad423SPoul-Henning Kamp 466516ad423SPoul-Henning Kamp static int 467516ad423SPoul-Henning Kamp giant_poll(struct cdev *dev, int events, struct thread *td) 468516ad423SPoul-Henning Kamp { 469aeeb4202SKonstantin Belousov struct cdevsw *dsw; 470*3979450bSKonstantin Belousov int ref, retval; 471516ad423SPoul-Henning Kamp 472*3979450bSKonstantin Belousov dsw = dev_refthread(dev, &ref); 473aeeb4202SKonstantin Belousov if (dsw == NULL) 474aeeb4202SKonstantin Belousov return (ENXIO); 475516ad423SPoul-Henning Kamp mtx_lock(&Giant); 476aeeb4202SKonstantin Belousov retval = dsw->d_gianttrick->d_poll(dev, events, td); 477516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 478*3979450bSKonstantin Belousov dev_relthread(dev, ref); 479516ad423SPoul-Henning Kamp return (retval); 480516ad423SPoul-Henning Kamp } 481516ad423SPoul-Henning Kamp 482516ad423SPoul-Henning Kamp static int 483516ad423SPoul-Henning Kamp giant_kqfilter(struct cdev *dev, struct knote *kn) 484516ad423SPoul-Henning Kamp { 485aeeb4202SKonstantin Belousov struct cdevsw *dsw; 486*3979450bSKonstantin Belousov int ref, retval; 487516ad423SPoul-Henning Kamp 488*3979450bSKonstantin Belousov dsw = dev_refthread(dev, &ref); 489aeeb4202SKonstantin Belousov if (dsw == NULL) 490aeeb4202SKonstantin Belousov return (ENXIO); 491516ad423SPoul-Henning Kamp mtx_lock(&Giant); 492aeeb4202SKonstantin Belousov retval = dsw->d_gianttrick->d_kqfilter(dev, kn); 493516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 494*3979450bSKonstantin Belousov dev_relthread(dev, ref); 495516ad423SPoul-Henning Kamp return (retval); 496516ad423SPoul-Henning Kamp } 497516ad423SPoul-Henning Kamp 498516ad423SPoul-Henning Kamp static int 499cfd7baceSRobert Noland giant_mmap(struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr, int nprot, 5002fa8c8d2SJohn Baldwin vm_memattr_t *memattr) 501516ad423SPoul-Henning Kamp { 502aeeb4202SKonstantin Belousov struct cdevsw *dsw; 503*3979450bSKonstantin Belousov int ref, retval; 504516ad423SPoul-Henning Kamp 505*3979450bSKonstantin Belousov dsw = dev_refthread(dev, &ref); 506aeeb4202SKonstantin Belousov if (dsw == NULL) 507aeeb4202SKonstantin Belousov return (ENXIO); 508516ad423SPoul-Henning Kamp mtx_lock(&Giant); 509cfd7baceSRobert Noland retval = dsw->d_gianttrick->d_mmap(dev, offset, paddr, nprot, 5102fa8c8d2SJohn Baldwin memattr); 511516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 512*3979450bSKonstantin Belousov dev_relthread(dev, ref); 513516ad423SPoul-Henning Kamp return (retval); 514516ad423SPoul-Henning Kamp } 515516ad423SPoul-Henning Kamp 51664345f0bSJohn Baldwin static int 51764345f0bSJohn Baldwin giant_mmap_single(struct cdev *dev, vm_ooffset_t *offset, vm_size_t size, 51864345f0bSJohn Baldwin vm_object_t *object, int nprot) 51964345f0bSJohn Baldwin { 52064345f0bSJohn Baldwin struct cdevsw *dsw; 521*3979450bSKonstantin Belousov int ref, retval; 52264345f0bSJohn Baldwin 523*3979450bSKonstantin Belousov dsw = dev_refthread(dev, &ref); 52464345f0bSJohn Baldwin if (dsw == NULL) 52564345f0bSJohn Baldwin return (ENXIO); 52664345f0bSJohn Baldwin mtx_lock(&Giant); 52764345f0bSJohn Baldwin retval = dsw->d_gianttrick->d_mmap_single(dev, offset, size, object, 52864345f0bSJohn Baldwin nprot); 52964345f0bSJohn Baldwin mtx_unlock(&Giant); 530*3979450bSKonstantin Belousov dev_relthread(dev, ref); 53164345f0bSJohn Baldwin return (retval); 53264345f0bSJohn Baldwin } 533516ad423SPoul-Henning Kamp 53448504cc2SKonstantin Belousov static void 535d2ba618aSKonstantin Belousov notify(struct cdev *dev, const char *ev, int flags) 53648504cc2SKonstantin Belousov { 53748504cc2SKonstantin Belousov static const char prefix[] = "cdev="; 53848504cc2SKonstantin Belousov char *data; 53976d43557SKonstantin Belousov int namelen, mflags; 54048504cc2SKonstantin Belousov 54148504cc2SKonstantin Belousov if (cold) 54248504cc2SKonstantin Belousov return; 54376d43557SKonstantin Belousov mflags = (flags & MAKEDEV_NOWAIT) ? M_NOWAIT : M_WAITOK; 54448504cc2SKonstantin Belousov namelen = strlen(dev->si_name); 54576d43557SKonstantin Belousov data = malloc(namelen + sizeof(prefix), M_TEMP, mflags); 5469995e57bSAttilio Rao if (data == NULL) 5479995e57bSAttilio Rao return; 54848504cc2SKonstantin Belousov memcpy(data, prefix, sizeof(prefix) - 1); 54948504cc2SKonstantin Belousov memcpy(data + sizeof(prefix) - 1, dev->si_name, namelen + 1); 55076d43557SKonstantin Belousov devctl_notify_f("DEVFS", "CDEV", ev, data, mflags); 55148504cc2SKonstantin Belousov free(data, M_TEMP); 55248504cc2SKonstantin Belousov } 55348504cc2SKonstantin Belousov 55448504cc2SKonstantin Belousov static void 555d2ba618aSKonstantin Belousov notify_create(struct cdev *dev, int flags) 55648504cc2SKonstantin Belousov { 55748504cc2SKonstantin Belousov 558d2ba618aSKonstantin Belousov notify(dev, "CREATE", flags); 55948504cc2SKonstantin Belousov } 56048504cc2SKonstantin Belousov 56148504cc2SKonstantin Belousov static void 56248504cc2SKonstantin Belousov notify_destroy(struct cdev *dev) 56348504cc2SKonstantin Belousov { 56448504cc2SKonstantin Belousov 565d2ba618aSKonstantin Belousov notify(dev, "DESTROY", MAKEDEV_WAITOK); 56648504cc2SKonstantin Belousov } 56748504cc2SKonstantin Belousov 56889c9c53dSPoul-Henning Kamp static struct cdev * 569bce79dbbSEd Schouten newdev(struct cdevsw *csw, int unit, struct cdev *si) 5703f54a085SPoul-Henning Kamp { 571027b1f71SPoul-Henning Kamp struct cdev *si2; 5723f54a085SPoul-Henning Kamp 573027b1f71SPoul-Henning Kamp mtx_assert(&devmtx, MA_OWNED); 57429d4cb24SEd Schouten if (csw->d_flags & D_NEEDMINOR) { 57529d4cb24SEd Schouten /* We may want to return an existing device */ 576ff7284eeSPoul-Henning Kamp LIST_FOREACH(si2, &csw->d_devs, si_list) { 577bce79dbbSEd Schouten if (dev2unit(si2) == unit) { 5789bc911d4SKonstantin Belousov dev_free_devlocked(si); 579027b1f71SPoul-Henning Kamp return (si2); 5803f54a085SPoul-Henning Kamp } 581027b1f71SPoul-Henning Kamp } 58229d4cb24SEd Schouten } 583bce79dbbSEd Schouten si->si_drv0 = unit; 584e606a3c6SPoul-Henning Kamp si->si_devsw = csw; 585ff7284eeSPoul-Henning Kamp LIST_INSERT_HEAD(&csw->d_devs, si, si_list); 586698bfad7SPoul-Henning Kamp return (si); 587bfbb9ce6SPoul-Henning Kamp } 588bfbb9ce6SPoul-Henning Kamp 5892a3faf2fSPoul-Henning Kamp static void 590cd690b60SPoul-Henning Kamp fini_cdevsw(struct cdevsw *devsw) 591cd690b60SPoul-Henning Kamp { 5921d45c50eSPoul-Henning Kamp struct cdevsw *gt; 593b3d82c03SPoul-Henning Kamp 5941d45c50eSPoul-Henning Kamp if (devsw->d_gianttrick != NULL) { 5951d45c50eSPoul-Henning Kamp gt = devsw->d_gianttrick; 5961d45c50eSPoul-Henning Kamp memcpy(devsw, gt, sizeof *devsw); 597aeeb4202SKonstantin Belousov cdevsw_free_devlocked(gt); 598516ad423SPoul-Henning Kamp devsw->d_gianttrick = NULL; 5991d45c50eSPoul-Henning Kamp } 600652d0472SPoul-Henning Kamp devsw->d_flags &= ~D_INIT; 601b0b03348SPoul-Henning Kamp } 602b0b03348SPoul-Henning Kamp 603d2ba618aSKonstantin Belousov static int 604d2ba618aSKonstantin Belousov prep_cdevsw(struct cdevsw *devsw, int flags) 605b0b03348SPoul-Henning Kamp { 606516ad423SPoul-Henning Kamp struct cdevsw *dsw2; 607b0b03348SPoul-Henning Kamp 608aeeb4202SKonstantin Belousov mtx_assert(&devmtx, MA_OWNED); 609aeeb4202SKonstantin Belousov if (devsw->d_flags & D_INIT) 610f1bb758dSKonstantin Belousov return (0); 611aeeb4202SKonstantin Belousov if (devsw->d_flags & D_NEEDGIANT) { 612aeeb4202SKonstantin Belousov dev_unlock(); 613d2ba618aSKonstantin Belousov dsw2 = malloc(sizeof *dsw2, M_DEVT, 614d2ba618aSKonstantin Belousov (flags & MAKEDEV_NOWAIT) ? M_NOWAIT : M_WAITOK); 615a0e78d2eSPoul-Henning Kamp dev_lock(); 616d2ba618aSKonstantin Belousov if (dsw2 == NULL && !(devsw->d_flags & D_INIT)) 617f1bb758dSKonstantin Belousov return (ENOMEM); 618aeeb4202SKonstantin Belousov } else 619aeeb4202SKonstantin Belousov dsw2 = NULL; 620aeeb4202SKonstantin Belousov if (devsw->d_flags & D_INIT) { 621aeeb4202SKonstantin Belousov if (dsw2 != NULL) 622aeeb4202SKonstantin Belousov cdevsw_free_devlocked(dsw2); 623f1bb758dSKonstantin Belousov return (0); 624aeeb4202SKonstantin Belousov } 625cd690b60SPoul-Henning Kamp 626cfd7baceSRobert Noland if (devsw->d_version != D_VERSION_03) { 627cd690b60SPoul-Henning Kamp printf( 628cd690b60SPoul-Henning Kamp "WARNING: Device driver \"%s\" has wrong version %s\n", 6297d7e053cSAlfred Perlstein devsw->d_name == NULL ? "???" : devsw->d_name, 6307d7e053cSAlfred Perlstein "and is disabled. Recompile KLD module."); 631cd690b60SPoul-Henning Kamp devsw->d_open = dead_open; 632cd690b60SPoul-Henning Kamp devsw->d_close = dead_close; 633cd690b60SPoul-Henning Kamp devsw->d_read = dead_read; 634cd690b60SPoul-Henning Kamp devsw->d_write = dead_write; 635cd690b60SPoul-Henning Kamp devsw->d_ioctl = dead_ioctl; 636cd690b60SPoul-Henning Kamp devsw->d_poll = dead_poll; 637cd690b60SPoul-Henning Kamp devsw->d_mmap = dead_mmap; 638cfd7baceSRobert Noland devsw->d_mmap_single = dead_mmap_single; 639cd690b60SPoul-Henning Kamp devsw->d_strategy = dead_strategy; 640cd690b60SPoul-Henning Kamp devsw->d_dump = dead_dump; 641cd690b60SPoul-Henning Kamp devsw->d_kqfilter = dead_kqfilter; 642cd690b60SPoul-Henning Kamp } 643cd690b60SPoul-Henning Kamp 644516ad423SPoul-Henning Kamp if (devsw->d_flags & D_NEEDGIANT) { 645516ad423SPoul-Henning Kamp if (devsw->d_gianttrick == NULL) { 646516ad423SPoul-Henning Kamp memcpy(dsw2, devsw, sizeof *dsw2); 647516ad423SPoul-Henning Kamp devsw->d_gianttrick = dsw2; 648aeeb4202SKonstantin Belousov dsw2 = NULL; 649aeeb4202SKonstantin Belousov } 650516ad423SPoul-Henning Kamp } 651516ad423SPoul-Henning Kamp 652516ad423SPoul-Henning Kamp #define FIXUP(member, noop, giant) \ 653516ad423SPoul-Henning Kamp do { \ 654516ad423SPoul-Henning Kamp if (devsw->member == NULL) { \ 655516ad423SPoul-Henning Kamp devsw->member = noop; \ 656516ad423SPoul-Henning Kamp } else if (devsw->d_flags & D_NEEDGIANT) \ 657516ad423SPoul-Henning Kamp devsw->member = giant; \ 658516ad423SPoul-Henning Kamp } \ 659516ad423SPoul-Henning Kamp while (0) 660516ad423SPoul-Henning Kamp 661516ad423SPoul-Henning Kamp FIXUP(d_open, null_open, giant_open); 662516ad423SPoul-Henning Kamp FIXUP(d_fdopen, NULL, giant_fdopen); 663516ad423SPoul-Henning Kamp FIXUP(d_close, null_close, giant_close); 664516ad423SPoul-Henning Kamp FIXUP(d_read, no_read, giant_read); 665516ad423SPoul-Henning Kamp FIXUP(d_write, no_write, giant_write); 666516ad423SPoul-Henning Kamp FIXUP(d_ioctl, no_ioctl, giant_ioctl); 667516ad423SPoul-Henning Kamp FIXUP(d_poll, no_poll, giant_poll); 668cfd7baceSRobert Noland FIXUP(d_mmap, no_mmap, giant_mmap); 669516ad423SPoul-Henning Kamp FIXUP(d_strategy, no_strategy, giant_strategy); 670516ad423SPoul-Henning Kamp FIXUP(d_kqfilter, no_kqfilter, giant_kqfilter); 67164345f0bSJohn Baldwin FIXUP(d_mmap_single, no_mmap_single, giant_mmap_single); 672516ad423SPoul-Henning Kamp 673b2941431SPoul-Henning Kamp if (devsw->d_dump == NULL) devsw->d_dump = no_dump; 674cd690b60SPoul-Henning Kamp 675cd690b60SPoul-Henning Kamp LIST_INIT(&devsw->d_devs); 676cd690b60SPoul-Henning Kamp 677cd690b60SPoul-Henning Kamp devsw->d_flags |= D_INIT; 678cd690b60SPoul-Henning Kamp 679aeeb4202SKonstantin Belousov if (dsw2 != NULL) 680aeeb4202SKonstantin Belousov cdevsw_free_devlocked(dsw2); 681f1bb758dSKonstantin Belousov return (0); 6822a3faf2fSPoul-Henning Kamp } 68311586717SBrian Somers 684f1bb758dSKonstantin Belousov static int 685f1bb758dSKonstantin Belousov make_dev_credv(int flags, struct cdev **dres, struct cdevsw *devsw, int unit, 686f1bb758dSKonstantin Belousov struct ucred *cr, uid_t uid, gid_t gid, int mode, const char *fmt, 687f1bb758dSKonstantin Belousov va_list ap) 6882a3faf2fSPoul-Henning Kamp { 68989c9c53dSPoul-Henning Kamp struct cdev *dev; 690f1bb758dSKonstantin Belousov int i, res; 6912a3faf2fSPoul-Henning Kamp 692f1bb758dSKonstantin Belousov KASSERT((flags & MAKEDEV_WAITOK) == 0 || (flags & MAKEDEV_NOWAIT) == 0, 693f1bb758dSKonstantin Belousov ("make_dev_credv: both WAITOK and NOWAIT specified")); 694d2ba618aSKonstantin Belousov dev = devfs_alloc(flags); 695d2ba618aSKonstantin Belousov if (dev == NULL) 696f1bb758dSKonstantin Belousov return (ENOMEM); 697027b1f71SPoul-Henning Kamp dev_lock(); 698f1bb758dSKonstantin Belousov res = prep_cdevsw(devsw, flags); 699f1bb758dSKonstantin Belousov if (res != 0) { 700d2ba618aSKonstantin Belousov dev_unlock(); 701d2ba618aSKonstantin Belousov devfs_free(dev); 702f1bb758dSKonstantin Belousov return (res); 703d2ba618aSKonstantin Belousov } 704edde8745SEd Schouten dev = newdev(devsw, unit, dev); 705de10ffa5SKonstantin Belousov if (flags & MAKEDEV_REF) 706de10ffa5SKonstantin Belousov dev_refl(dev); 707*3979450bSKonstantin Belousov if (flags & MAKEDEV_ETERNAL) 708*3979450bSKonstantin Belousov dev->si_flags |= SI_ETERNAL; 70998c469d4SPoul-Henning Kamp if (dev->si_flags & SI_CHEAPCLONE && 710e606a3c6SPoul-Henning Kamp dev->si_flags & SI_NAMED) { 71198c469d4SPoul-Henning Kamp /* 71298c469d4SPoul-Henning Kamp * This is allowed as it removes races and generally 71398c469d4SPoul-Henning Kamp * simplifies cloning devices. 714cd690b60SPoul-Henning Kamp * XXX: still ?? 71598c469d4SPoul-Henning Kamp */ 7169bc911d4SKonstantin Belousov dev_unlock_and_free(); 717f1bb758dSKonstantin Belousov *dres = dev; 718f1bb758dSKonstantin Belousov return (0); 71998c469d4SPoul-Henning Kamp } 720cd690b60SPoul-Henning Kamp KASSERT(!(dev->si_flags & SI_NAMED), 721ff7284eeSPoul-Henning Kamp ("make_dev() by driver %s on pre-existing device (min=%x, name=%s)", 7226bfa9a2dSEd Schouten devsw->d_name, dev2unit(dev), devtoname(dev))); 723cd690b60SPoul-Henning Kamp 7246334a663SPoul-Henning Kamp i = vsnrprintf(dev->__si_namebuf, sizeof dev->__si_namebuf, 32, fmt, ap); 7256334a663SPoul-Henning Kamp if (i > (sizeof dev->__si_namebuf - 1)) { 7262e4db7cfSPawel Jakub Dawidek printf("WARNING: Device name truncated! (%s)\n", 7276334a663SPoul-Henning Kamp dev->__si_namebuf); 7286334a663SPoul-Henning Kamp } 7291a1b2800SPoul-Henning Kamp 7305ef2707eSPoul-Henning Kamp dev->si_flags |= SI_NAMED; 731d26dd2d9SRobert Watson if (cr != NULL) 732d26dd2d9SRobert Watson dev->si_cred = crhold(cr); 7339477d73eSPoul-Henning Kamp dev->si_uid = uid; 7349477d73eSPoul-Henning Kamp dev->si_gid = gid; 7359477d73eSPoul-Henning Kamp dev->si_mode = mode; 7361744fcd0SJulian Elischer 7379285a87eSPoul-Henning Kamp devfs_create(dev); 73809828ba9SKonstantin Belousov clean_unrhdrl(devfs_inos); 739aeeb4202SKonstantin Belousov dev_unlock_and_free(); 74048504cc2SKonstantin Belousov 741d2ba618aSKonstantin Belousov notify_create(dev, flags); 74248504cc2SKonstantin Belousov 743f1bb758dSKonstantin Belousov *dres = dev; 744f1bb758dSKonstantin Belousov return (0); 7453f54a085SPoul-Henning Kamp } 7463f54a085SPoul-Henning Kamp 747d26dd2d9SRobert Watson struct cdev * 748edde8745SEd Schouten make_dev(struct cdevsw *devsw, int unit, uid_t uid, gid_t gid, int mode, 749d26dd2d9SRobert Watson const char *fmt, ...) 750d26dd2d9SRobert Watson { 751d26dd2d9SRobert Watson struct cdev *dev; 752d26dd2d9SRobert Watson va_list ap; 753f1bb758dSKonstantin Belousov int res; 754d26dd2d9SRobert Watson 755d26dd2d9SRobert Watson va_start(ap, fmt); 756f1bb758dSKonstantin Belousov res = make_dev_credv(0, &dev, devsw, unit, NULL, uid, gid, mode, fmt, 757f1bb758dSKonstantin Belousov ap); 758d26dd2d9SRobert Watson va_end(ap); 759f1bb758dSKonstantin Belousov KASSERT(res == 0 && dev != NULL, ("make_dev: failed make_dev_credv")); 760d26dd2d9SRobert Watson return (dev); 761d26dd2d9SRobert Watson } 762d26dd2d9SRobert Watson 763d26dd2d9SRobert Watson struct cdev * 764edde8745SEd Schouten make_dev_cred(struct cdevsw *devsw, int unit, struct ucred *cr, uid_t uid, 765d26dd2d9SRobert Watson gid_t gid, int mode, const char *fmt, ...) 766d26dd2d9SRobert Watson { 767d26dd2d9SRobert Watson struct cdev *dev; 768d26dd2d9SRobert Watson va_list ap; 769f1bb758dSKonstantin Belousov int res; 770d26dd2d9SRobert Watson 771d26dd2d9SRobert Watson va_start(ap, fmt); 772f1bb758dSKonstantin Belousov res = make_dev_credv(0, &dev, devsw, unit, cr, uid, gid, mode, fmt, ap); 773de10ffa5SKonstantin Belousov va_end(ap); 774de10ffa5SKonstantin Belousov 775f1bb758dSKonstantin Belousov KASSERT(res == 0 && dev != NULL, 776f1bb758dSKonstantin Belousov ("make_dev_cred: failed make_dev_credv")); 777de10ffa5SKonstantin Belousov return (dev); 778de10ffa5SKonstantin Belousov } 779de10ffa5SKonstantin Belousov 780de10ffa5SKonstantin Belousov struct cdev * 781f1bb758dSKonstantin Belousov make_dev_credf(int flags, struct cdevsw *devsw, int unit, struct ucred *cr, 782f1bb758dSKonstantin Belousov uid_t uid, gid_t gid, int mode, const char *fmt, ...) 783de10ffa5SKonstantin Belousov { 784de10ffa5SKonstantin Belousov struct cdev *dev; 785de10ffa5SKonstantin Belousov va_list ap; 786f1bb758dSKonstantin Belousov int res; 787de10ffa5SKonstantin Belousov 788de10ffa5SKonstantin Belousov va_start(ap, fmt); 789f1bb758dSKonstantin Belousov res = make_dev_credv(flags, &dev, devsw, unit, cr, uid, gid, mode, 790de10ffa5SKonstantin Belousov fmt, ap); 791d26dd2d9SRobert Watson va_end(ap); 792d26dd2d9SRobert Watson 793f1bb758dSKonstantin Belousov KASSERT((flags & MAKEDEV_NOWAIT) != 0 || res == 0, 794f1bb758dSKonstantin Belousov ("make_dev_credf: failed make_dev_credv")); 795f1bb758dSKonstantin Belousov return (res == 0 ? dev : NULL); 796f1bb758dSKonstantin Belousov } 797f1bb758dSKonstantin Belousov 798f1bb758dSKonstantin Belousov int 7992e983aceSEd Schouten make_dev_p(int flags, struct cdev **cdev, struct cdevsw *devsw, 800f1bb758dSKonstantin Belousov struct ucred *cr, uid_t uid, gid_t gid, int mode, const char *fmt, ...) 801f1bb758dSKonstantin Belousov { 802f1bb758dSKonstantin Belousov va_list ap; 803f1bb758dSKonstantin Belousov int res; 804f1bb758dSKonstantin Belousov 805f1bb758dSKonstantin Belousov va_start(ap, fmt); 8062e983aceSEd Schouten res = make_dev_credv(flags, cdev, devsw, 0, cr, uid, gid, mode, 807f1bb758dSKonstantin Belousov fmt, ap); 808f1bb758dSKonstantin Belousov va_end(ap); 809f1bb758dSKonstantin Belousov 810f1bb758dSKonstantin Belousov KASSERT((flags & MAKEDEV_NOWAIT) != 0 || res == 0, 8118fa17b79SJaakko Heinonen ("make_dev_p: failed make_dev_credv")); 812f1bb758dSKonstantin Belousov return (res); 813d26dd2d9SRobert Watson } 814d26dd2d9SRobert Watson 815e606a3c6SPoul-Henning Kamp static void 816e606a3c6SPoul-Henning Kamp dev_dependsl(struct cdev *pdev, struct cdev *cdev) 817e606a3c6SPoul-Henning Kamp { 818e606a3c6SPoul-Henning Kamp 819e606a3c6SPoul-Henning Kamp cdev->si_parent = pdev; 820e606a3c6SPoul-Henning Kamp cdev->si_flags |= SI_CHILD; 821e606a3c6SPoul-Henning Kamp LIST_INSERT_HEAD(&pdev->si_children, cdev, si_siblings); 822e606a3c6SPoul-Henning Kamp } 823e606a3c6SPoul-Henning Kamp 824e606a3c6SPoul-Henning Kamp 8253344c5a1SPoul-Henning Kamp void 82689c9c53dSPoul-Henning Kamp dev_depends(struct cdev *pdev, struct cdev *cdev) 8273344c5a1SPoul-Henning Kamp { 8283344c5a1SPoul-Henning Kamp 829a0e78d2eSPoul-Henning Kamp dev_lock(); 830e606a3c6SPoul-Henning Kamp dev_dependsl(pdev, cdev); 831a0e78d2eSPoul-Henning Kamp dev_unlock(); 8323344c5a1SPoul-Henning Kamp } 8333344c5a1SPoul-Henning Kamp 83489c9c53dSPoul-Henning Kamp struct cdev * 83589c9c53dSPoul-Henning Kamp make_dev_alias(struct cdev *pdev, const char *fmt, ...) 8363f54a085SPoul-Henning Kamp { 83789c9c53dSPoul-Henning Kamp struct cdev *dev; 8383f54a085SPoul-Henning Kamp va_list ap; 8393f54a085SPoul-Henning Kamp int i; 8403f54a085SPoul-Henning Kamp 841ae95dc62SKonstantin Belousov KASSERT(pdev != NULL, ("NULL pdev")); 842d2ba618aSKonstantin Belousov dev = devfs_alloc(MAKEDEV_WAITOK); 843a0e78d2eSPoul-Henning Kamp dev_lock(); 8443f54a085SPoul-Henning Kamp dev->si_flags |= SI_ALIAS; 8455ef2707eSPoul-Henning Kamp dev->si_flags |= SI_NAMED; 8463f54a085SPoul-Henning Kamp va_start(ap, fmt); 8476334a663SPoul-Henning Kamp i = vsnrprintf(dev->__si_namebuf, sizeof dev->__si_namebuf, 32, fmt, ap); 8486334a663SPoul-Henning Kamp if (i > (sizeof dev->__si_namebuf - 1)) { 8492e4db7cfSPawel Jakub Dawidek printf("WARNING: Device name truncated! (%s)\n", 8506334a663SPoul-Henning Kamp dev->__si_namebuf); 8516334a663SPoul-Henning Kamp } 8523f54a085SPoul-Henning Kamp va_end(ap); 8533f54a085SPoul-Henning Kamp 8549285a87eSPoul-Henning Kamp devfs_create(dev); 855ae95dc62SKonstantin Belousov dev_dependsl(pdev, dev); 85609828ba9SKonstantin Belousov clean_unrhdrl(devfs_inos); 857a0e78d2eSPoul-Henning Kamp dev_unlock(); 85848504cc2SKonstantin Belousov 859d2ba618aSKonstantin Belousov notify_create(dev, MAKEDEV_WAITOK); 86048504cc2SKonstantin Belousov 8610ef1c826SPoul-Henning Kamp return (dev); 8620ef1c826SPoul-Henning Kamp } 8630ef1c826SPoul-Henning Kamp 864cd690b60SPoul-Henning Kamp static void 865aa2f6ddcSPoul-Henning Kamp destroy_devl(struct cdev *dev) 866d137acccSPoul-Henning Kamp { 867743cd76aSPoul-Henning Kamp struct cdevsw *csw; 86882f4d640SKonstantin Belousov struct cdev_privdata *p, *p1; 869743cd76aSPoul-Henning Kamp 870aa2f6ddcSPoul-Henning Kamp mtx_assert(&devmtx, MA_OWNED); 871743cd76aSPoul-Henning Kamp KASSERT(dev->si_flags & SI_NAMED, 8726bfa9a2dSEd Schouten ("WARNING: Driver mistake: destroy_dev on %d\n", dev2unit(dev))); 873*3979450bSKonstantin Belousov KASSERT((dev->si_flags & SI_ETERNAL) == 0, 874*3979450bSKonstantin Belousov ("WARNING: Driver mistake: destroy_dev on eternal %d\n", 875*3979450bSKonstantin Belousov dev2unit(dev))); 8765ef2707eSPoul-Henning Kamp 8779285a87eSPoul-Henning Kamp devfs_destroy(dev); 878cd690b60SPoul-Henning Kamp 879cd690b60SPoul-Henning Kamp /* Remove name marking */ 880b0b03348SPoul-Henning Kamp dev->si_flags &= ~SI_NAMED; 881b0b03348SPoul-Henning Kamp 882cd690b60SPoul-Henning Kamp /* If we are a child, remove us from the parents list */ 8833344c5a1SPoul-Henning Kamp if (dev->si_flags & SI_CHILD) { 8843344c5a1SPoul-Henning Kamp LIST_REMOVE(dev, si_siblings); 8853344c5a1SPoul-Henning Kamp dev->si_flags &= ~SI_CHILD; 8863344c5a1SPoul-Henning Kamp } 887cd690b60SPoul-Henning Kamp 888cd690b60SPoul-Henning Kamp /* Kill our children */ 8893344c5a1SPoul-Henning Kamp while (!LIST_EMPTY(&dev->si_children)) 890aa2f6ddcSPoul-Henning Kamp destroy_devl(LIST_FIRST(&dev->si_children)); 891cd690b60SPoul-Henning Kamp 892cd690b60SPoul-Henning Kamp /* Remove from clone list */ 893b0b03348SPoul-Henning Kamp if (dev->si_flags & SI_CLONELIST) { 894b0b03348SPoul-Henning Kamp LIST_REMOVE(dev, si_clone); 895b0b03348SPoul-Henning Kamp dev->si_flags &= ~SI_CLONELIST; 896b0b03348SPoul-Henning Kamp } 897cd690b60SPoul-Henning Kamp 898e0c33ad5STor Egge dev->si_refcount++; /* Avoid race with dev_rel() */ 899743cd76aSPoul-Henning Kamp csw = dev->si_devsw; 9001abf2c36SBrian Feldman dev->si_devsw = NULL; /* already NULL for SI_ALIAS */ 9011abf2c36SBrian Feldman while (csw != NULL && csw->d_purge != NULL && dev->si_threadcount) { 902743cd76aSPoul-Henning Kamp csw->d_purge(dev); 903743cd76aSPoul-Henning Kamp msleep(csw, &devmtx, PRIBIO, "devprg", hz/10); 904d595182fSPoul-Henning Kamp if (dev->si_threadcount) 905d595182fSPoul-Henning Kamp printf("Still %lu threads in %s\n", 906d595182fSPoul-Henning Kamp dev->si_threadcount, devtoname(dev)); 907743cd76aSPoul-Henning Kamp } 908e0c33ad5STor Egge while (dev->si_threadcount != 0) { 909e0c33ad5STor Egge /* Use unique dummy wait ident */ 910e0c33ad5STor Egge msleep(&csw, &devmtx, PRIBIO, "devdrn", hz / 10); 911e0c33ad5STor Egge } 912743cd76aSPoul-Henning Kamp 91382f4d640SKonstantin Belousov dev_unlock(); 91448504cc2SKonstantin Belousov notify_destroy(dev); 91582f4d640SKonstantin Belousov mtx_lock(&cdevpriv_mtx); 91605427aafSKonstantin Belousov LIST_FOREACH_SAFE(p, &cdev2priv(dev)->cdp_fdpriv, cdpd_list, p1) { 91782f4d640SKonstantin Belousov devfs_destroy_cdevpriv(p); 91882f4d640SKonstantin Belousov mtx_lock(&cdevpriv_mtx); 91982f4d640SKonstantin Belousov } 92082f4d640SKonstantin Belousov mtx_unlock(&cdevpriv_mtx); 92182f4d640SKonstantin Belousov dev_lock(); 92248504cc2SKonstantin Belousov 923743cd76aSPoul-Henning Kamp dev->si_drv1 = 0; 924743cd76aSPoul-Henning Kamp dev->si_drv2 = 0; 925743cd76aSPoul-Henning Kamp bzero(&dev->__si_u, sizeof(dev->__si_u)); 926743cd76aSPoul-Henning Kamp 927cd690b60SPoul-Henning Kamp if (!(dev->si_flags & SI_ALIAS)) { 928cd690b60SPoul-Henning Kamp /* Remove from cdevsw list */ 929cd690b60SPoul-Henning Kamp LIST_REMOVE(dev, si_list); 930cd690b60SPoul-Henning Kamp 931e606a3c6SPoul-Henning Kamp /* If cdevsw has no more struct cdev *'s, clean it */ 932de10ffa5SKonstantin Belousov if (LIST_EMPTY(&csw->d_devs)) { 933a5993c33SPoul-Henning Kamp fini_cdevsw(csw); 934de10ffa5SKonstantin Belousov wakeup(&csw->d_devs); 935de10ffa5SKonstantin Belousov } 936cd690b60SPoul-Henning Kamp } 9375ef2707eSPoul-Henning Kamp dev->si_flags &= ~SI_ALIAS; 938e0c33ad5STor Egge dev->si_refcount--; /* Avoid race with dev_rel() */ 939743cd76aSPoul-Henning Kamp 940cd690b60SPoul-Henning Kamp if (dev->si_refcount > 0) { 941cd690b60SPoul-Henning Kamp LIST_INSERT_HEAD(&dead_cdevsw.d_devs, dev, si_list); 942cd690b60SPoul-Henning Kamp } else { 9439bc911d4SKonstantin Belousov dev_free_devlocked(dev); 944d137acccSPoul-Henning Kamp } 945cd690b60SPoul-Henning Kamp } 946cd690b60SPoul-Henning Kamp 947cd690b60SPoul-Henning Kamp void 94889c9c53dSPoul-Henning Kamp destroy_dev(struct cdev *dev) 949cd690b60SPoul-Henning Kamp { 950cd690b60SPoul-Henning Kamp 951b7a813fcSKonstantin Belousov WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, "destroy_dev"); 952a0e78d2eSPoul-Henning Kamp dev_lock(); 953aa2f6ddcSPoul-Henning Kamp destroy_devl(dev); 9549bc911d4SKonstantin Belousov dev_unlock_and_free(); 955cd690b60SPoul-Henning Kamp } 956d137acccSPoul-Henning Kamp 957c32cc149SBruce Evans const char * 95889c9c53dSPoul-Henning Kamp devtoname(struct cdev *dev) 959b8e49f68SBill Fumerola { 960b8e49f68SBill Fumerola 961b8e49f68SBill Fumerola return (dev->si_name); 962b8e49f68SBill Fumerola } 963db901281SPoul-Henning Kamp 964db901281SPoul-Henning Kamp int 96501de1b13SPoul-Henning Kamp dev_stdclone(char *name, char **namep, const char *stem, int *unit) 966db901281SPoul-Henning Kamp { 967db901281SPoul-Henning Kamp int u, i; 968db901281SPoul-Henning Kamp 969db901281SPoul-Henning Kamp i = strlen(stem); 97056700d46SBrian Somers if (bcmp(stem, name, i) != 0) 97156700d46SBrian Somers return (0); 972db901281SPoul-Henning Kamp if (!isdigit(name[i])) 973db901281SPoul-Henning Kamp return (0); 974db901281SPoul-Henning Kamp u = 0; 97510786074SPoul-Henning Kamp if (name[i] == '0' && isdigit(name[i+1])) 97610786074SPoul-Henning Kamp return (0); 977db901281SPoul-Henning Kamp while (isdigit(name[i])) { 978db901281SPoul-Henning Kamp u *= 10; 979db901281SPoul-Henning Kamp u += name[i++] - '0'; 980db901281SPoul-Henning Kamp } 981dab3d85fSBrian Feldman if (u > 0xffffff) 982dab3d85fSBrian Feldman return (0); 983db901281SPoul-Henning Kamp *unit = u; 984db901281SPoul-Henning Kamp if (namep) 985db901281SPoul-Henning Kamp *namep = &name[i]; 986db901281SPoul-Henning Kamp if (name[i]) 987db901281SPoul-Henning Kamp return (2); 988db901281SPoul-Henning Kamp return (1); 989db901281SPoul-Henning Kamp } 9908d25eb2cSPoul-Henning Kamp 9918d25eb2cSPoul-Henning Kamp /* 992b0b03348SPoul-Henning Kamp * Helper functions for cloning device drivers. 993b0b03348SPoul-Henning Kamp * 994b0b03348SPoul-Henning Kamp * The objective here is to make it unnecessary for the device drivers to 995b0b03348SPoul-Henning Kamp * use rman or similar to manage their unit number space. Due to the way 996b0b03348SPoul-Henning Kamp * we do "on-demand" devices, using rman or other "private" methods 997b0b03348SPoul-Henning Kamp * will be very tricky to lock down properly once we lock down this file. 998b0b03348SPoul-Henning Kamp * 9999a98ae94SLukas Ertl * Instead we give the drivers these routines which puts the struct cdev *'s 10009a98ae94SLukas Ertl * that are to be managed on their own list, and gives the driver the ability 1001b0b03348SPoul-Henning Kamp * to ask for the first free unit number or a given specified unit number. 1002b0b03348SPoul-Henning Kamp * 1003b0b03348SPoul-Henning Kamp * In addition these routines support paired devices (pty, nmdm and similar) 1004b0b03348SPoul-Henning Kamp * by respecting a number of "flag" bits in the minor number. 1005b0b03348SPoul-Henning Kamp * 1006b0b03348SPoul-Henning Kamp */ 1007b0b03348SPoul-Henning Kamp 1008b0b03348SPoul-Henning Kamp struct clonedevs { 1009b0b03348SPoul-Henning Kamp LIST_HEAD(,cdev) head; 1010b0b03348SPoul-Henning Kamp }; 1011b0b03348SPoul-Henning Kamp 10129397290eSPoul-Henning Kamp void 10139397290eSPoul-Henning Kamp clone_setup(struct clonedevs **cdp) 10149397290eSPoul-Henning Kamp { 10159397290eSPoul-Henning Kamp 10169397290eSPoul-Henning Kamp *cdp = malloc(sizeof **cdp, M_DEVBUF, M_WAITOK | M_ZERO); 10179397290eSPoul-Henning Kamp LIST_INIT(&(*cdp)->head); 10189397290eSPoul-Henning Kamp } 10199397290eSPoul-Henning Kamp 1020b0b03348SPoul-Henning Kamp int 1021cf141467SKonstantin Belousov clone_create(struct clonedevs **cdp, struct cdevsw *csw, int *up, 1022cf141467SKonstantin Belousov struct cdev **dp, int extra) 1023b0b03348SPoul-Henning Kamp { 1024b0b03348SPoul-Henning Kamp struct clonedevs *cd; 1025027b1f71SPoul-Henning Kamp struct cdev *dev, *ndev, *dl, *de; 1026b0b03348SPoul-Henning Kamp int unit, low, u; 1027b0b03348SPoul-Henning Kamp 10289397290eSPoul-Henning Kamp KASSERT(*cdp != NULL, 10299397290eSPoul-Henning Kamp ("clone_setup() not called in driver \"%s\"", csw->d_name)); 1030b0b03348SPoul-Henning Kamp KASSERT(!(extra & CLONE_UNITMASK), 1031b0b03348SPoul-Henning Kamp ("Illegal extra bits (0x%x) in clone_create", extra)); 1032b0b03348SPoul-Henning Kamp KASSERT(*up <= CLONE_UNITMASK, 1033b0b03348SPoul-Henning Kamp ("Too high unit (0x%x) in clone_create", *up)); 103429d4cb24SEd Schouten KASSERT(csw->d_flags & D_NEEDMINOR, 103529d4cb24SEd Schouten ("clone_create() on cdevsw without minor numbers")); 1036b0b03348SPoul-Henning Kamp 1037b0b03348SPoul-Henning Kamp 1038b0b03348SPoul-Henning Kamp /* 1039b0b03348SPoul-Henning Kamp * Search the list for a lot of things in one go: 1040b0b03348SPoul-Henning Kamp * A preexisting match is returned immediately. 1041b0b03348SPoul-Henning Kamp * The lowest free unit number if we are passed -1, and the place 1042b0b03348SPoul-Henning Kamp * in the list where we should insert that new element. 1043b0b03348SPoul-Henning Kamp * The place to insert a specified unit number, if applicable 1044b0b03348SPoul-Henning Kamp * the end of the list. 1045b0b03348SPoul-Henning Kamp */ 1046b0b03348SPoul-Henning Kamp unit = *up; 1047d2ba618aSKonstantin Belousov ndev = devfs_alloc(MAKEDEV_WAITOK); 1048027b1f71SPoul-Henning Kamp dev_lock(); 1049d2ba618aSKonstantin Belousov prep_cdevsw(csw, MAKEDEV_WAITOK); 10508666b655SPoul-Henning Kamp low = extra; 1051b0b03348SPoul-Henning Kamp de = dl = NULL; 10529397290eSPoul-Henning Kamp cd = *cdp; 1053b0b03348SPoul-Henning Kamp LIST_FOREACH(dev, &cd->head, si_clone) { 1054027b1f71SPoul-Henning Kamp KASSERT(dev->si_flags & SI_CLONELIST, 1055027b1f71SPoul-Henning Kamp ("Dev %p(%s) should be on clonelist", dev, dev->si_name)); 1056b0b03348SPoul-Henning Kamp u = dev2unit(dev); 1057b0b03348SPoul-Henning Kamp if (u == (unit | extra)) { 1058b0b03348SPoul-Henning Kamp *dp = dev; 1059027b1f71SPoul-Henning Kamp dev_unlock(); 10609bc911d4SKonstantin Belousov devfs_free(ndev); 1061b0b03348SPoul-Henning Kamp return (0); 1062b0b03348SPoul-Henning Kamp } 1063b0b03348SPoul-Henning Kamp if (unit == -1 && u == low) { 1064b0b03348SPoul-Henning Kamp low++; 1065b0b03348SPoul-Henning Kamp de = dev; 1066b0b03348SPoul-Henning Kamp continue; 10677bbb3a26SPoul-Henning Kamp } else if (u < (unit | extra)) { 10687bbb3a26SPoul-Henning Kamp de = dev; 10697bbb3a26SPoul-Henning Kamp continue; 10707bbb3a26SPoul-Henning Kamp } else if (u > (unit | extra)) { 1071b0b03348SPoul-Henning Kamp dl = dev; 1072b0b03348SPoul-Henning Kamp break; 1073b0b03348SPoul-Henning Kamp } 1074b0b03348SPoul-Henning Kamp } 1075b0b03348SPoul-Henning Kamp if (unit == -1) 10768666b655SPoul-Henning Kamp unit = low & CLONE_UNITMASK; 1077d3ce8327SEd Schouten dev = newdev(csw, unit | extra, ndev); 1078027b1f71SPoul-Henning Kamp if (dev->si_flags & SI_CLONELIST) { 1079027b1f71SPoul-Henning Kamp printf("dev %p (%s) is on clonelist\n", dev, dev->si_name); 10807bbb3a26SPoul-Henning Kamp printf("unit=%d, low=%d, extra=0x%x\n", unit, low, extra); 1081027b1f71SPoul-Henning Kamp LIST_FOREACH(dev, &cd->head, si_clone) { 1082027b1f71SPoul-Henning Kamp printf("\t%p %s\n", dev, dev->si_name); 1083027b1f71SPoul-Henning Kamp } 1084027b1f71SPoul-Henning Kamp panic("foo"); 1085027b1f71SPoul-Henning Kamp } 1086b0b03348SPoul-Henning Kamp KASSERT(!(dev->si_flags & SI_CLONELIST), 1087027b1f71SPoul-Henning Kamp ("Dev %p(%s) should not be on clonelist", dev, dev->si_name)); 1088b0b03348SPoul-Henning Kamp if (dl != NULL) 1089b0b03348SPoul-Henning Kamp LIST_INSERT_BEFORE(dl, dev, si_clone); 1090b0b03348SPoul-Henning Kamp else if (de != NULL) 1091b0b03348SPoul-Henning Kamp LIST_INSERT_AFTER(de, dev, si_clone); 1092b0b03348SPoul-Henning Kamp else 1093b0b03348SPoul-Henning Kamp LIST_INSERT_HEAD(&cd->head, dev, si_clone); 1094b0b03348SPoul-Henning Kamp dev->si_flags |= SI_CLONELIST; 1095b0b03348SPoul-Henning Kamp *up = unit; 10969bc911d4SKonstantin Belousov dev_unlock_and_free(); 1097b0b03348SPoul-Henning Kamp return (1); 1098b0b03348SPoul-Henning Kamp } 1099b0b03348SPoul-Henning Kamp 1100b0b03348SPoul-Henning Kamp /* 1101b0b03348SPoul-Henning Kamp * Kill everything still on the list. The driver should already have 110289c9c53dSPoul-Henning Kamp * disposed of any softc hung of the struct cdev *'s at this time. 1103b0b03348SPoul-Henning Kamp */ 1104b0b03348SPoul-Henning Kamp void 1105b0b03348SPoul-Henning Kamp clone_cleanup(struct clonedevs **cdp) 1106b0b03348SPoul-Henning Kamp { 1107de10ffa5SKonstantin Belousov struct cdev *dev; 1108de10ffa5SKonstantin Belousov struct cdev_priv *cp; 1109b0b03348SPoul-Henning Kamp struct clonedevs *cd; 1110b0b03348SPoul-Henning Kamp 1111b0b03348SPoul-Henning Kamp cd = *cdp; 1112b0b03348SPoul-Henning Kamp if (cd == NULL) 1113b0b03348SPoul-Henning Kamp return; 1114027b1f71SPoul-Henning Kamp dev_lock(); 1115de10ffa5SKonstantin Belousov while (!LIST_EMPTY(&cd->head)) { 1116de10ffa5SKonstantin Belousov dev = LIST_FIRST(&cd->head); 1117de10ffa5SKonstantin Belousov LIST_REMOVE(dev, si_clone); 1118027b1f71SPoul-Henning Kamp KASSERT(dev->si_flags & SI_CLONELIST, 1119027b1f71SPoul-Henning Kamp ("Dev %p(%s) should be on clonelist", dev, dev->si_name)); 1120de10ffa5SKonstantin Belousov dev->si_flags &= ~SI_CLONELIST; 112105427aafSKonstantin Belousov cp = cdev2priv(dev); 1122de10ffa5SKonstantin Belousov if (!(cp->cdp_flags & CDP_SCHED_DTR)) { 1123de10ffa5SKonstantin Belousov cp->cdp_flags |= CDP_SCHED_DTR; 1124b0b03348SPoul-Henning Kamp KASSERT(dev->si_flags & SI_NAMED, 1125d7cbfc1bSEd Schouten ("Driver has goofed in cloning underways udev %x unit %x", dev2udev(dev), dev2unit(dev))); 1126aa2f6ddcSPoul-Henning Kamp destroy_devl(dev); 1127b0b03348SPoul-Henning Kamp } 1128de10ffa5SKonstantin Belousov } 1129aeeb4202SKonstantin Belousov dev_unlock_and_free(); 1130b0b03348SPoul-Henning Kamp free(cd, M_DEVBUF); 1131b0b03348SPoul-Henning Kamp *cdp = NULL; 1132b0b03348SPoul-Henning Kamp } 1133de10ffa5SKonstantin Belousov 1134de10ffa5SKonstantin Belousov static TAILQ_HEAD(, cdev_priv) dev_ddtr = 1135de10ffa5SKonstantin Belousov TAILQ_HEAD_INITIALIZER(dev_ddtr); 1136de10ffa5SKonstantin Belousov static struct task dev_dtr_task; 1137de10ffa5SKonstantin Belousov 1138de10ffa5SKonstantin Belousov static void 1139de10ffa5SKonstantin Belousov destroy_dev_tq(void *ctx, int pending) 1140de10ffa5SKonstantin Belousov { 1141de10ffa5SKonstantin Belousov struct cdev_priv *cp; 1142de10ffa5SKonstantin Belousov struct cdev *dev; 1143de10ffa5SKonstantin Belousov void (*cb)(void *); 1144de10ffa5SKonstantin Belousov void *cb_arg; 1145de10ffa5SKonstantin Belousov 1146de10ffa5SKonstantin Belousov dev_lock(); 1147de10ffa5SKonstantin Belousov while (!TAILQ_EMPTY(&dev_ddtr)) { 1148de10ffa5SKonstantin Belousov cp = TAILQ_FIRST(&dev_ddtr); 1149de10ffa5SKonstantin Belousov dev = &cp->cdp_c; 1150de10ffa5SKonstantin Belousov KASSERT(cp->cdp_flags & CDP_SCHED_DTR, 1151de10ffa5SKonstantin Belousov ("cdev %p in dev_destroy_tq without CDP_SCHED_DTR", cp)); 1152de10ffa5SKonstantin Belousov TAILQ_REMOVE(&dev_ddtr, cp, cdp_dtr_list); 1153de10ffa5SKonstantin Belousov cb = cp->cdp_dtr_cb; 1154de10ffa5SKonstantin Belousov cb_arg = cp->cdp_dtr_cb_arg; 1155de10ffa5SKonstantin Belousov destroy_devl(dev); 1156aeeb4202SKonstantin Belousov dev_unlock_and_free(); 1157de10ffa5SKonstantin Belousov dev_rel(dev); 1158de10ffa5SKonstantin Belousov if (cb != NULL) 1159de10ffa5SKonstantin Belousov cb(cb_arg); 1160de10ffa5SKonstantin Belousov dev_lock(); 1161de10ffa5SKonstantin Belousov } 1162de10ffa5SKonstantin Belousov dev_unlock(); 1163de10ffa5SKonstantin Belousov } 1164de10ffa5SKonstantin Belousov 11659d53363bSKonstantin Belousov /* 11669d53363bSKonstantin Belousov * devmtx shall be locked on entry. devmtx will be unlocked after 11679d53363bSKonstantin Belousov * function return. 11689d53363bSKonstantin Belousov */ 11699d53363bSKonstantin Belousov static int 11709d53363bSKonstantin Belousov destroy_dev_sched_cbl(struct cdev *dev, void (*cb)(void *), void *arg) 1171de10ffa5SKonstantin Belousov { 1172de10ffa5SKonstantin Belousov struct cdev_priv *cp; 1173de10ffa5SKonstantin Belousov 11749d53363bSKonstantin Belousov mtx_assert(&devmtx, MA_OWNED); 117505427aafSKonstantin Belousov cp = cdev2priv(dev); 1176de10ffa5SKonstantin Belousov if (cp->cdp_flags & CDP_SCHED_DTR) { 1177de10ffa5SKonstantin Belousov dev_unlock(); 1178de10ffa5SKonstantin Belousov return (0); 1179de10ffa5SKonstantin Belousov } 1180de10ffa5SKonstantin Belousov dev_refl(dev); 1181de10ffa5SKonstantin Belousov cp->cdp_flags |= CDP_SCHED_DTR; 1182de10ffa5SKonstantin Belousov cp->cdp_dtr_cb = cb; 1183de10ffa5SKonstantin Belousov cp->cdp_dtr_cb_arg = arg; 1184de10ffa5SKonstantin Belousov TAILQ_INSERT_TAIL(&dev_ddtr, cp, cdp_dtr_list); 1185de10ffa5SKonstantin Belousov dev_unlock(); 1186de10ffa5SKonstantin Belousov taskqueue_enqueue(taskqueue_swi_giant, &dev_dtr_task); 1187de10ffa5SKonstantin Belousov return (1); 1188de10ffa5SKonstantin Belousov } 1189de10ffa5SKonstantin Belousov 1190de10ffa5SKonstantin Belousov int 11919d53363bSKonstantin Belousov destroy_dev_sched_cb(struct cdev *dev, void (*cb)(void *), void *arg) 11929d53363bSKonstantin Belousov { 1193cf141467SKonstantin Belousov 11949d53363bSKonstantin Belousov dev_lock(); 11959d53363bSKonstantin Belousov return (destroy_dev_sched_cbl(dev, cb, arg)); 11969d53363bSKonstantin Belousov } 11979d53363bSKonstantin Belousov 11989d53363bSKonstantin Belousov int 1199de10ffa5SKonstantin Belousov destroy_dev_sched(struct cdev *dev) 1200de10ffa5SKonstantin Belousov { 1201cf141467SKonstantin Belousov 1202de10ffa5SKonstantin Belousov return (destroy_dev_sched_cb(dev, NULL, NULL)); 1203de10ffa5SKonstantin Belousov } 1204de10ffa5SKonstantin Belousov 1205de10ffa5SKonstantin Belousov void 1206de10ffa5SKonstantin Belousov destroy_dev_drain(struct cdevsw *csw) 1207de10ffa5SKonstantin Belousov { 1208de10ffa5SKonstantin Belousov 1209de10ffa5SKonstantin Belousov dev_lock(); 1210de10ffa5SKonstantin Belousov while (!LIST_EMPTY(&csw->d_devs)) { 1211de10ffa5SKonstantin Belousov msleep(&csw->d_devs, &devmtx, PRIBIO, "devscd", hz/10); 1212de10ffa5SKonstantin Belousov } 1213de10ffa5SKonstantin Belousov dev_unlock(); 1214de10ffa5SKonstantin Belousov } 1215de10ffa5SKonstantin Belousov 1216de10ffa5SKonstantin Belousov void 1217de10ffa5SKonstantin Belousov drain_dev_clone_events(void) 1218de10ffa5SKonstantin Belousov { 1219de10ffa5SKonstantin Belousov 1220de10ffa5SKonstantin Belousov sx_xlock(&clone_drain_lock); 1221de10ffa5SKonstantin Belousov sx_xunlock(&clone_drain_lock); 1222de10ffa5SKonstantin Belousov } 1223de10ffa5SKonstantin Belousov 1224de10ffa5SKonstantin Belousov static void 1225de10ffa5SKonstantin Belousov devdtr_init(void *dummy __unused) 1226de10ffa5SKonstantin Belousov { 1227de10ffa5SKonstantin Belousov 1228de10ffa5SKonstantin Belousov TASK_INIT(&dev_dtr_task, 0, destroy_dev_tq, NULL); 1229de10ffa5SKonstantin Belousov } 1230de10ffa5SKonstantin Belousov 1231de10ffa5SKonstantin Belousov SYSINIT(devdtr, SI_SUB_DEVFS, SI_ORDER_SECOND, devdtr_init, NULL); 1232