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> 509c0af131SPoul-Henning Kamp 519ef295b7SPoul-Henning Kamp static MALLOC_DEFINE(M_DEVT, "cdev", "cdev storage"); 52698bfad7SPoul-Henning Kamp 53e606a3c6SPoul-Henning Kamp struct mtx devmtx; 54aa2f6ddcSPoul-Henning Kamp static void destroy_devl(struct cdev *dev); 559d53363bSKonstantin Belousov static int destroy_dev_sched_cbl(struct cdev *dev, 569d53363bSKonstantin Belousov void (*cb)(void *), void *arg); 57de10ffa5SKonstantin Belousov static struct cdev *make_dev_credv(int flags, 58edde8745SEd Schouten struct cdevsw *devsw, int unit, 59d26dd2d9SRobert Watson 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 = 65aeeb4202SKonstantin Belousov SLIST_HEAD_INITIALIZER(); 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 * 1802c15afd8SPoul-Henning Kamp dev_refthread(struct cdev *dev) 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); 1862c15afd8SPoul-Henning Kamp dev_lock(); 1872c15afd8SPoul-Henning Kamp csw = dev->si_devsw; 188de10ffa5SKonstantin Belousov if (csw != NULL) { 18905427aafSKonstantin Belousov cdp = cdev2priv(dev); 190de10ffa5SKonstantin Belousov if ((cdp->cdp_flags & CDP_SCHED_DTR) == 0) 1912c15afd8SPoul-Henning Kamp dev->si_threadcount++; 192de10ffa5SKonstantin Belousov else 193de10ffa5SKonstantin Belousov csw = NULL; 194de10ffa5SKonstantin Belousov } 1952c15afd8SPoul-Henning Kamp dev_unlock(); 1962c15afd8SPoul-Henning Kamp return (csw); 1972c15afd8SPoul-Henning Kamp } 1982c15afd8SPoul-Henning Kamp 1991663075cSKonstantin Belousov struct cdevsw * 2001663075cSKonstantin Belousov devvn_refthread(struct vnode *vp, struct cdev **devp) 2011663075cSKonstantin Belousov { 2021663075cSKonstantin Belousov struct cdevsw *csw; 203de10ffa5SKonstantin Belousov struct cdev_priv *cdp; 2041663075cSKonstantin Belousov 2051663075cSKonstantin Belousov mtx_assert(&devmtx, MA_NOTOWNED); 2061663075cSKonstantin Belousov csw = NULL; 2071663075cSKonstantin Belousov dev_lock(); 2081663075cSKonstantin Belousov *devp = vp->v_rdev; 2091663075cSKonstantin Belousov if (*devp != NULL) { 21005427aafSKonstantin Belousov cdp = cdev2priv(*devp); 211de10ffa5SKonstantin Belousov if ((cdp->cdp_flags & CDP_SCHED_DTR) == 0) { 2121663075cSKonstantin Belousov csw = (*devp)->si_devsw; 2131663075cSKonstantin Belousov if (csw != NULL) 2141663075cSKonstantin Belousov (*devp)->si_threadcount++; 2151663075cSKonstantin Belousov } 216de10ffa5SKonstantin Belousov } 2171663075cSKonstantin Belousov dev_unlock(); 2181663075cSKonstantin Belousov return (csw); 2191663075cSKonstantin Belousov } 2201663075cSKonstantin Belousov 2212c15afd8SPoul-Henning Kamp void 2222c15afd8SPoul-Henning Kamp dev_relthread(struct cdev *dev) 2232c15afd8SPoul-Henning Kamp { 2242c15afd8SPoul-Henning Kamp 2252c15afd8SPoul-Henning Kamp mtx_assert(&devmtx, MA_NOTOWNED); 2262c15afd8SPoul-Henning Kamp dev_lock(); 22706fe1129SKonstantin Belousov KASSERT(dev->si_threadcount > 0, 22806fe1129SKonstantin Belousov ("%s threadcount is wrong", dev->si_name)); 2292c15afd8SPoul-Henning Kamp dev->si_threadcount--; 2302c15afd8SPoul-Henning Kamp dev_unlock(); 2312c15afd8SPoul-Henning Kamp } 232cd690b60SPoul-Henning Kamp 233b2941431SPoul-Henning Kamp int 234b2941431SPoul-Henning Kamp nullop(void) 235b2941431SPoul-Henning Kamp { 236b2941431SPoul-Henning Kamp 237b2941431SPoul-Henning Kamp return (0); 238b2941431SPoul-Henning Kamp } 239b2941431SPoul-Henning Kamp 240b2941431SPoul-Henning Kamp int 241b2941431SPoul-Henning Kamp eopnotsupp(void) 242b2941431SPoul-Henning Kamp { 243b2941431SPoul-Henning Kamp 244b2941431SPoul-Henning Kamp return (EOPNOTSUPP); 245b2941431SPoul-Henning Kamp } 24602574b19SPoul-Henning Kamp 24702574b19SPoul-Henning Kamp static int 24802574b19SPoul-Henning Kamp enxio(void) 24902574b19SPoul-Henning Kamp { 25002574b19SPoul-Henning Kamp return (ENXIO); 25102574b19SPoul-Henning Kamp } 25202574b19SPoul-Henning Kamp 253b2941431SPoul-Henning Kamp static int 254b2941431SPoul-Henning Kamp enodev(void) 255b2941431SPoul-Henning Kamp { 256b2941431SPoul-Henning Kamp return (ENODEV); 257b2941431SPoul-Henning Kamp } 258b2941431SPoul-Henning Kamp 259b2941431SPoul-Henning Kamp /* Define a dead_cdevsw for use when devices leave unexpectedly. */ 260b2941431SPoul-Henning Kamp 26102574b19SPoul-Henning Kamp #define dead_open (d_open_t *)enxio 26202574b19SPoul-Henning Kamp #define dead_close (d_close_t *)enxio 26302574b19SPoul-Henning Kamp #define dead_read (d_read_t *)enxio 26402574b19SPoul-Henning Kamp #define dead_write (d_write_t *)enxio 26502574b19SPoul-Henning Kamp #define dead_ioctl (d_ioctl_t *)enxio 266b2941431SPoul-Henning Kamp #define dead_poll (d_poll_t *)enodev 267b2941431SPoul-Henning Kamp #define dead_mmap (d_mmap_t *)enodev 26802574b19SPoul-Henning Kamp 26902574b19SPoul-Henning Kamp static void 27002574b19SPoul-Henning Kamp dead_strategy(struct bio *bp) 27102574b19SPoul-Henning Kamp { 27202574b19SPoul-Henning Kamp 27302574b19SPoul-Henning Kamp biofinish(bp, NULL, ENXIO); 27402574b19SPoul-Henning Kamp } 27502574b19SPoul-Henning Kamp 2762c6b49f6SPoul-Henning Kamp #define dead_dump (dumper_t *)enxio 27702574b19SPoul-Henning Kamp #define dead_kqfilter (d_kqfilter_t *)enxio 27802574b19SPoul-Henning Kamp 27902574b19SPoul-Henning Kamp static struct cdevsw dead_cdevsw = { 280dc08ffecSPoul-Henning Kamp .d_version = D_VERSION, 281dc08ffecSPoul-Henning Kamp .d_flags = D_NEEDGIANT, /* XXX: does dead_strategy need this ? */ 2827ac40f5fSPoul-Henning Kamp .d_open = dead_open, 2837ac40f5fSPoul-Henning Kamp .d_close = dead_close, 2847ac40f5fSPoul-Henning Kamp .d_read = dead_read, 2857ac40f5fSPoul-Henning Kamp .d_write = dead_write, 2867ac40f5fSPoul-Henning Kamp .d_ioctl = dead_ioctl, 2877ac40f5fSPoul-Henning Kamp .d_poll = dead_poll, 2887ac40f5fSPoul-Henning Kamp .d_mmap = dead_mmap, 2897ac40f5fSPoul-Henning Kamp .d_strategy = dead_strategy, 2907ac40f5fSPoul-Henning Kamp .d_name = "dead", 2917ac40f5fSPoul-Henning Kamp .d_dump = dead_dump, 2927ac40f5fSPoul-Henning Kamp .d_kqfilter = dead_kqfilter 29302574b19SPoul-Henning Kamp }; 29402574b19SPoul-Henning Kamp 295b2941431SPoul-Henning Kamp /* Default methods if driver does not specify method */ 296b2941431SPoul-Henning Kamp 297b2941431SPoul-Henning Kamp #define null_open (d_open_t *)nullop 298b2941431SPoul-Henning Kamp #define null_close (d_close_t *)nullop 299b2941431SPoul-Henning Kamp #define no_read (d_read_t *)enodev 300b2941431SPoul-Henning Kamp #define no_write (d_write_t *)enodev 301b2941431SPoul-Henning Kamp #define no_ioctl (d_ioctl_t *)enodev 302b2941431SPoul-Henning Kamp #define no_mmap (d_mmap_t *)enodev 303ad3b9257SJohn-Mark Gurney #define no_kqfilter (d_kqfilter_t *)enodev 304b2941431SPoul-Henning Kamp 305b2941431SPoul-Henning Kamp static void 306b2941431SPoul-Henning Kamp no_strategy(struct bio *bp) 307b2941431SPoul-Henning Kamp { 308b2941431SPoul-Henning Kamp 309b2941431SPoul-Henning Kamp biofinish(bp, NULL, ENODEV); 310b2941431SPoul-Henning Kamp } 311b2941431SPoul-Henning Kamp 312b2941431SPoul-Henning Kamp static int 31389c9c53dSPoul-Henning Kamp no_poll(struct cdev *dev __unused, int events, struct thread *td __unused) 314b2941431SPoul-Henning Kamp { 315b2941431SPoul-Henning Kamp 316125dcf8cSKonstantin Belousov return (poll_no_poll(events)); 317b2941431SPoul-Henning Kamp } 318b2941431SPoul-Henning Kamp 319b2941431SPoul-Henning Kamp #define no_dump (dumper_t *)enodev 3204e4a7663SPoul-Henning Kamp 321516ad423SPoul-Henning Kamp static int 322516ad423SPoul-Henning Kamp giant_open(struct cdev *dev, int oflags, int devtype, struct thread *td) 323516ad423SPoul-Henning Kamp { 324aeeb4202SKonstantin Belousov struct cdevsw *dsw; 325516ad423SPoul-Henning Kamp int retval; 326516ad423SPoul-Henning Kamp 327aeeb4202SKonstantin Belousov dsw = dev_refthread(dev); 328aeeb4202SKonstantin Belousov if (dsw == NULL) 329aeeb4202SKonstantin Belousov return (ENXIO); 330516ad423SPoul-Henning Kamp mtx_lock(&Giant); 331aeeb4202SKonstantin Belousov retval = dsw->d_gianttrick->d_open(dev, oflags, devtype, td); 332516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 333aeeb4202SKonstantin Belousov dev_relthread(dev); 334516ad423SPoul-Henning Kamp return (retval); 335516ad423SPoul-Henning Kamp } 336516ad423SPoul-Henning Kamp 337516ad423SPoul-Henning Kamp static int 3389e223287SKonstantin Belousov giant_fdopen(struct cdev *dev, int oflags, struct thread *td, struct file *fp) 339516ad423SPoul-Henning Kamp { 340aeeb4202SKonstantin Belousov struct cdevsw *dsw; 341516ad423SPoul-Henning Kamp int retval; 342516ad423SPoul-Henning Kamp 343aeeb4202SKonstantin Belousov dsw = dev_refthread(dev); 344aeeb4202SKonstantin Belousov if (dsw == NULL) 345aeeb4202SKonstantin Belousov return (ENXIO); 346516ad423SPoul-Henning Kamp mtx_lock(&Giant); 347aeeb4202SKonstantin Belousov retval = dsw->d_gianttrick->d_fdopen(dev, oflags, td, fp); 348516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 349aeeb4202SKonstantin Belousov dev_relthread(dev); 350516ad423SPoul-Henning Kamp return (retval); 351516ad423SPoul-Henning Kamp } 352516ad423SPoul-Henning Kamp 353516ad423SPoul-Henning Kamp static int 354516ad423SPoul-Henning Kamp giant_close(struct cdev *dev, int fflag, int devtype, struct thread *td) 355516ad423SPoul-Henning Kamp { 356aeeb4202SKonstantin Belousov struct cdevsw *dsw; 357516ad423SPoul-Henning Kamp int retval; 358516ad423SPoul-Henning Kamp 359aeeb4202SKonstantin Belousov dsw = dev_refthread(dev); 360aeeb4202SKonstantin Belousov if (dsw == NULL) 361aeeb4202SKonstantin Belousov return (ENXIO); 362516ad423SPoul-Henning Kamp mtx_lock(&Giant); 363aeeb4202SKonstantin Belousov retval = dsw->d_gianttrick->d_close(dev, fflag, devtype, td); 364516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 365aeeb4202SKonstantin Belousov dev_relthread(dev); 366516ad423SPoul-Henning Kamp return (retval); 367516ad423SPoul-Henning Kamp } 368516ad423SPoul-Henning Kamp 369516ad423SPoul-Henning Kamp static void 370516ad423SPoul-Henning Kamp giant_strategy(struct bio *bp) 371516ad423SPoul-Henning Kamp { 372aeeb4202SKonstantin Belousov struct cdevsw *dsw; 373aeeb4202SKonstantin Belousov struct cdev *dev; 374516ad423SPoul-Henning Kamp 375aeeb4202SKonstantin Belousov dev = bp->bio_dev; 376aeeb4202SKonstantin Belousov dsw = dev_refthread(dev); 377aeeb4202SKonstantin Belousov if (dsw == NULL) { 378aeeb4202SKonstantin Belousov biofinish(bp, NULL, ENXIO); 379aeeb4202SKonstantin Belousov return; 380aeeb4202SKonstantin Belousov } 381516ad423SPoul-Henning Kamp mtx_lock(&Giant); 382aeeb4202SKonstantin Belousov dsw->d_gianttrick->d_strategy(bp); 383516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 384aeeb4202SKonstantin Belousov dev_relthread(dev); 385516ad423SPoul-Henning Kamp } 386516ad423SPoul-Henning Kamp 387516ad423SPoul-Henning Kamp static int 388516ad423SPoul-Henning Kamp giant_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct thread *td) 389516ad423SPoul-Henning Kamp { 390aeeb4202SKonstantin Belousov struct cdevsw *dsw; 391516ad423SPoul-Henning Kamp int retval; 392516ad423SPoul-Henning Kamp 393aeeb4202SKonstantin Belousov dsw = dev_refthread(dev); 394aeeb4202SKonstantin Belousov if (dsw == NULL) 395aeeb4202SKonstantin Belousov return (ENXIO); 396516ad423SPoul-Henning Kamp mtx_lock(&Giant); 39735b45029SKonstantin Belousov retval = dsw->d_gianttrick->d_ioctl(dev, cmd, data, fflag, td); 398516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 399aeeb4202SKonstantin Belousov dev_relthread(dev); 400516ad423SPoul-Henning Kamp return (retval); 401516ad423SPoul-Henning Kamp } 402516ad423SPoul-Henning Kamp 403516ad423SPoul-Henning Kamp static int 404516ad423SPoul-Henning Kamp giant_read(struct cdev *dev, struct uio *uio, int ioflag) 405516ad423SPoul-Henning Kamp { 406aeeb4202SKonstantin Belousov struct cdevsw *dsw; 407516ad423SPoul-Henning Kamp int retval; 408516ad423SPoul-Henning Kamp 409aeeb4202SKonstantin Belousov dsw = dev_refthread(dev); 410aeeb4202SKonstantin Belousov if (dsw == NULL) 411aeeb4202SKonstantin Belousov return (ENXIO); 412516ad423SPoul-Henning Kamp mtx_lock(&Giant); 41335b45029SKonstantin Belousov retval = dsw->d_gianttrick->d_read(dev, uio, ioflag); 414516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 415aeeb4202SKonstantin Belousov dev_relthread(dev); 416516ad423SPoul-Henning Kamp return (retval); 417516ad423SPoul-Henning Kamp } 418516ad423SPoul-Henning Kamp 419516ad423SPoul-Henning Kamp static int 420516ad423SPoul-Henning Kamp giant_write(struct cdev *dev, struct uio *uio, int ioflag) 421516ad423SPoul-Henning Kamp { 422aeeb4202SKonstantin Belousov struct cdevsw *dsw; 423516ad423SPoul-Henning Kamp int retval; 424516ad423SPoul-Henning Kamp 425aeeb4202SKonstantin Belousov dsw = dev_refthread(dev); 426aeeb4202SKonstantin Belousov if (dsw == NULL) 427aeeb4202SKonstantin Belousov return (ENXIO); 428516ad423SPoul-Henning Kamp mtx_lock(&Giant); 429aeeb4202SKonstantin Belousov retval = dsw->d_gianttrick->d_write(dev, uio, ioflag); 430516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 431aeeb4202SKonstantin Belousov dev_relthread(dev); 432516ad423SPoul-Henning Kamp return (retval); 433516ad423SPoul-Henning Kamp } 434516ad423SPoul-Henning Kamp 435516ad423SPoul-Henning Kamp static int 436516ad423SPoul-Henning Kamp giant_poll(struct cdev *dev, int events, struct thread *td) 437516ad423SPoul-Henning Kamp { 438aeeb4202SKonstantin Belousov struct cdevsw *dsw; 439516ad423SPoul-Henning Kamp int retval; 440516ad423SPoul-Henning Kamp 441aeeb4202SKonstantin Belousov dsw = dev_refthread(dev); 442aeeb4202SKonstantin Belousov if (dsw == NULL) 443aeeb4202SKonstantin Belousov return (ENXIO); 444516ad423SPoul-Henning Kamp mtx_lock(&Giant); 445aeeb4202SKonstantin Belousov retval = dsw->d_gianttrick->d_poll(dev, events, td); 446516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 447aeeb4202SKonstantin Belousov dev_relthread(dev); 448516ad423SPoul-Henning Kamp return (retval); 449516ad423SPoul-Henning Kamp } 450516ad423SPoul-Henning Kamp 451516ad423SPoul-Henning Kamp static int 452516ad423SPoul-Henning Kamp giant_kqfilter(struct cdev *dev, struct knote *kn) 453516ad423SPoul-Henning Kamp { 454aeeb4202SKonstantin Belousov struct cdevsw *dsw; 455516ad423SPoul-Henning Kamp int retval; 456516ad423SPoul-Henning Kamp 457aeeb4202SKonstantin Belousov dsw = dev_refthread(dev); 458aeeb4202SKonstantin Belousov if (dsw == NULL) 459aeeb4202SKonstantin Belousov return (ENXIO); 460516ad423SPoul-Henning Kamp mtx_lock(&Giant); 461aeeb4202SKonstantin Belousov retval = dsw->d_gianttrick->d_kqfilter(dev, kn); 462516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 463aeeb4202SKonstantin Belousov dev_relthread(dev); 464516ad423SPoul-Henning Kamp return (retval); 465516ad423SPoul-Henning Kamp } 466516ad423SPoul-Henning Kamp 467516ad423SPoul-Henning Kamp static int 468516ad423SPoul-Henning Kamp giant_mmap(struct cdev *dev, vm_offset_t offset, vm_paddr_t *paddr, int nprot) 469516ad423SPoul-Henning Kamp { 470aeeb4202SKonstantin Belousov struct cdevsw *dsw; 471516ad423SPoul-Henning Kamp int retval; 472516ad423SPoul-Henning Kamp 473aeeb4202SKonstantin Belousov dsw = dev_refthread(dev); 474aeeb4202SKonstantin Belousov if (dsw == NULL) 475aeeb4202SKonstantin Belousov return (ENXIO); 476516ad423SPoul-Henning Kamp mtx_lock(&Giant); 477aeeb4202SKonstantin Belousov retval = dsw->d_gianttrick->d_mmap(dev, offset, paddr, nprot); 478516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 479aeeb4202SKonstantin Belousov dev_relthread(dev); 480516ad423SPoul-Henning Kamp return (retval); 481516ad423SPoul-Henning Kamp } 482516ad423SPoul-Henning Kamp 483516ad423SPoul-Henning Kamp 48448504cc2SKonstantin Belousov static void 48548504cc2SKonstantin Belousov notify(struct cdev *dev, const char *ev) 48648504cc2SKonstantin Belousov { 48748504cc2SKonstantin Belousov static const char prefix[] = "cdev="; 48848504cc2SKonstantin Belousov char *data; 48948504cc2SKonstantin Belousov int namelen; 49048504cc2SKonstantin Belousov 49148504cc2SKonstantin Belousov if (cold) 49248504cc2SKonstantin Belousov return; 49348504cc2SKonstantin Belousov namelen = strlen(dev->si_name); 4949995e57bSAttilio Rao data = malloc(namelen + sizeof(prefix), M_TEMP, M_NOWAIT); 4959995e57bSAttilio Rao if (data == NULL) 4969995e57bSAttilio Rao return; 49748504cc2SKonstantin Belousov memcpy(data, prefix, sizeof(prefix) - 1); 49848504cc2SKonstantin Belousov memcpy(data + sizeof(prefix) - 1, dev->si_name, namelen + 1); 49948504cc2SKonstantin Belousov devctl_notify("DEVFS", "CDEV", ev, data); 50048504cc2SKonstantin Belousov free(data, M_TEMP); 50148504cc2SKonstantin Belousov } 50248504cc2SKonstantin Belousov 50348504cc2SKonstantin Belousov static void 50448504cc2SKonstantin Belousov notify_create(struct cdev *dev) 50548504cc2SKonstantin Belousov { 50648504cc2SKonstantin Belousov 50748504cc2SKonstantin Belousov notify(dev, "CREATE"); 50848504cc2SKonstantin Belousov } 50948504cc2SKonstantin Belousov 51048504cc2SKonstantin Belousov static void 51148504cc2SKonstantin Belousov notify_destroy(struct cdev *dev) 51248504cc2SKonstantin Belousov { 51348504cc2SKonstantin Belousov 51448504cc2SKonstantin Belousov notify(dev, "DESTROY"); 51548504cc2SKonstantin Belousov } 51648504cc2SKonstantin Belousov 51789c9c53dSPoul-Henning Kamp static struct cdev * 518bce79dbbSEd Schouten newdev(struct cdevsw *csw, int unit, struct cdev *si) 5193f54a085SPoul-Henning Kamp { 520027b1f71SPoul-Henning Kamp struct cdev *si2; 5213f54a085SPoul-Henning Kamp 522027b1f71SPoul-Henning Kamp mtx_assert(&devmtx, MA_OWNED); 52329d4cb24SEd Schouten if (csw->d_flags & D_NEEDMINOR) { 52429d4cb24SEd Schouten /* We may want to return an existing device */ 525ff7284eeSPoul-Henning Kamp LIST_FOREACH(si2, &csw->d_devs, si_list) { 526bce79dbbSEd Schouten if (dev2unit(si2) == unit) { 5279bc911d4SKonstantin Belousov dev_free_devlocked(si); 528027b1f71SPoul-Henning Kamp return (si2); 5293f54a085SPoul-Henning Kamp } 530027b1f71SPoul-Henning Kamp } 53129d4cb24SEd Schouten } 532bce79dbbSEd Schouten si->si_drv0 = unit; 533e606a3c6SPoul-Henning Kamp si->si_devsw = csw; 534ff7284eeSPoul-Henning Kamp LIST_INSERT_HEAD(&csw->d_devs, si, si_list); 535698bfad7SPoul-Henning Kamp return (si); 536bfbb9ce6SPoul-Henning Kamp } 537bfbb9ce6SPoul-Henning Kamp 5382a3faf2fSPoul-Henning Kamp static void 539cd690b60SPoul-Henning Kamp fini_cdevsw(struct cdevsw *devsw) 540cd690b60SPoul-Henning Kamp { 5411d45c50eSPoul-Henning Kamp struct cdevsw *gt; 542b3d82c03SPoul-Henning Kamp 5431d45c50eSPoul-Henning Kamp if (devsw->d_gianttrick != NULL) { 5441d45c50eSPoul-Henning Kamp gt = devsw->d_gianttrick; 5451d45c50eSPoul-Henning Kamp memcpy(devsw, gt, sizeof *devsw); 546aeeb4202SKonstantin Belousov cdevsw_free_devlocked(gt); 547516ad423SPoul-Henning Kamp devsw->d_gianttrick = NULL; 5481d45c50eSPoul-Henning Kamp } 549652d0472SPoul-Henning Kamp devsw->d_flags &= ~D_INIT; 550b0b03348SPoul-Henning Kamp } 551b0b03348SPoul-Henning Kamp 552b0b03348SPoul-Henning Kamp static void 553b0b03348SPoul-Henning Kamp prep_cdevsw(struct cdevsw *devsw) 554b0b03348SPoul-Henning Kamp { 555516ad423SPoul-Henning Kamp struct cdevsw *dsw2; 556b0b03348SPoul-Henning Kamp 557aeeb4202SKonstantin Belousov mtx_assert(&devmtx, MA_OWNED); 558aeeb4202SKonstantin Belousov if (devsw->d_flags & D_INIT) 559aeeb4202SKonstantin Belousov return; 560aeeb4202SKonstantin Belousov if (devsw->d_flags & D_NEEDGIANT) { 561aeeb4202SKonstantin Belousov dev_unlock(); 562516ad423SPoul-Henning Kamp dsw2 = malloc(sizeof *dsw2, M_DEVT, M_WAITOK); 563a0e78d2eSPoul-Henning Kamp dev_lock(); 564aeeb4202SKonstantin Belousov } else 565aeeb4202SKonstantin Belousov dsw2 = NULL; 566aeeb4202SKonstantin Belousov if (devsw->d_flags & D_INIT) { 567aeeb4202SKonstantin Belousov if (dsw2 != NULL) 568aeeb4202SKonstantin Belousov cdevsw_free_devlocked(dsw2); 569aeeb4202SKonstantin Belousov return; 570aeeb4202SKonstantin Belousov } 571cd690b60SPoul-Henning Kamp 572800b42bdSPoul-Henning Kamp if (devsw->d_version != D_VERSION_01) { 573cd690b60SPoul-Henning Kamp printf( 574cd690b60SPoul-Henning Kamp "WARNING: Device driver \"%s\" has wrong version %s\n", 5757d7e053cSAlfred Perlstein devsw->d_name == NULL ? "???" : devsw->d_name, 5767d7e053cSAlfred Perlstein "and is disabled. Recompile KLD module."); 577cd690b60SPoul-Henning Kamp devsw->d_open = dead_open; 578cd690b60SPoul-Henning Kamp devsw->d_close = dead_close; 579cd690b60SPoul-Henning Kamp devsw->d_read = dead_read; 580cd690b60SPoul-Henning Kamp devsw->d_write = dead_write; 581cd690b60SPoul-Henning Kamp devsw->d_ioctl = dead_ioctl; 582cd690b60SPoul-Henning Kamp devsw->d_poll = dead_poll; 583cd690b60SPoul-Henning Kamp devsw->d_mmap = dead_mmap; 584cd690b60SPoul-Henning Kamp devsw->d_strategy = dead_strategy; 585cd690b60SPoul-Henning Kamp devsw->d_dump = dead_dump; 586cd690b60SPoul-Henning Kamp devsw->d_kqfilter = dead_kqfilter; 587cd690b60SPoul-Henning Kamp } 588cd690b60SPoul-Henning Kamp 589516ad423SPoul-Henning Kamp if (devsw->d_flags & D_NEEDGIANT) { 590516ad423SPoul-Henning Kamp if (devsw->d_gianttrick == NULL) { 591516ad423SPoul-Henning Kamp memcpy(dsw2, devsw, sizeof *dsw2); 592516ad423SPoul-Henning Kamp devsw->d_gianttrick = dsw2; 593aeeb4202SKonstantin Belousov dsw2 = NULL; 594aeeb4202SKonstantin Belousov } 595516ad423SPoul-Henning Kamp } 596516ad423SPoul-Henning Kamp 597516ad423SPoul-Henning Kamp #define FIXUP(member, noop, giant) \ 598516ad423SPoul-Henning Kamp do { \ 599516ad423SPoul-Henning Kamp if (devsw->member == NULL) { \ 600516ad423SPoul-Henning Kamp devsw->member = noop; \ 601516ad423SPoul-Henning Kamp } else if (devsw->d_flags & D_NEEDGIANT) \ 602516ad423SPoul-Henning Kamp devsw->member = giant; \ 603516ad423SPoul-Henning Kamp } \ 604516ad423SPoul-Henning Kamp while (0) 605516ad423SPoul-Henning Kamp 606516ad423SPoul-Henning Kamp FIXUP(d_open, null_open, giant_open); 607516ad423SPoul-Henning Kamp FIXUP(d_fdopen, NULL, giant_fdopen); 608516ad423SPoul-Henning Kamp FIXUP(d_close, null_close, giant_close); 609516ad423SPoul-Henning Kamp FIXUP(d_read, no_read, giant_read); 610516ad423SPoul-Henning Kamp FIXUP(d_write, no_write, giant_write); 611516ad423SPoul-Henning Kamp FIXUP(d_ioctl, no_ioctl, giant_ioctl); 612516ad423SPoul-Henning Kamp FIXUP(d_poll, no_poll, giant_poll); 613516ad423SPoul-Henning Kamp FIXUP(d_mmap, no_mmap, giant_mmap); 614516ad423SPoul-Henning Kamp FIXUP(d_strategy, no_strategy, giant_strategy); 615516ad423SPoul-Henning Kamp FIXUP(d_kqfilter, no_kqfilter, giant_kqfilter); 616516ad423SPoul-Henning Kamp 617b2941431SPoul-Henning Kamp if (devsw->d_dump == NULL) devsw->d_dump = no_dump; 618cd690b60SPoul-Henning Kamp 619cd690b60SPoul-Henning Kamp LIST_INIT(&devsw->d_devs); 620cd690b60SPoul-Henning Kamp 621cd690b60SPoul-Henning Kamp devsw->d_flags |= D_INIT; 622cd690b60SPoul-Henning Kamp 623aeeb4202SKonstantin Belousov if (dsw2 != NULL) 624aeeb4202SKonstantin Belousov cdevsw_free_devlocked(dsw2); 6252a3faf2fSPoul-Henning Kamp } 62611586717SBrian Somers 627de10ffa5SKonstantin Belousov struct cdev * 628edde8745SEd Schouten make_dev_credv(int flags, struct cdevsw *devsw, int unit, 629de10ffa5SKonstantin Belousov struct ucred *cr, uid_t uid, 630d26dd2d9SRobert Watson gid_t gid, int mode, const char *fmt, va_list ap) 6312a3faf2fSPoul-Henning Kamp { 63289c9c53dSPoul-Henning Kamp struct cdev *dev; 6332a3faf2fSPoul-Henning Kamp int i; 6342a3faf2fSPoul-Henning Kamp 635e606a3c6SPoul-Henning Kamp dev = devfs_alloc(); 636027b1f71SPoul-Henning Kamp dev_lock(); 637aeeb4202SKonstantin Belousov prep_cdevsw(devsw); 638edde8745SEd Schouten dev = newdev(devsw, unit, dev); 639de10ffa5SKonstantin Belousov if (flags & MAKEDEV_REF) 640de10ffa5SKonstantin Belousov dev_refl(dev); 64198c469d4SPoul-Henning Kamp if (dev->si_flags & SI_CHEAPCLONE && 642e606a3c6SPoul-Henning Kamp dev->si_flags & SI_NAMED) { 64398c469d4SPoul-Henning Kamp /* 64498c469d4SPoul-Henning Kamp * This is allowed as it removes races and generally 64598c469d4SPoul-Henning Kamp * simplifies cloning devices. 646cd690b60SPoul-Henning Kamp * XXX: still ?? 64798c469d4SPoul-Henning Kamp */ 6489bc911d4SKonstantin Belousov dev_unlock_and_free(); 64998c469d4SPoul-Henning Kamp return (dev); 65098c469d4SPoul-Henning Kamp } 651cd690b60SPoul-Henning Kamp KASSERT(!(dev->si_flags & SI_NAMED), 652ff7284eeSPoul-Henning Kamp ("make_dev() by driver %s on pre-existing device (min=%x, name=%s)", 6536bfa9a2dSEd Schouten devsw->d_name, dev2unit(dev), devtoname(dev))); 654cd690b60SPoul-Henning Kamp 6556334a663SPoul-Henning Kamp i = vsnrprintf(dev->__si_namebuf, sizeof dev->__si_namebuf, 32, fmt, ap); 6566334a663SPoul-Henning Kamp if (i > (sizeof dev->__si_namebuf - 1)) { 6572e4db7cfSPawel Jakub Dawidek printf("WARNING: Device name truncated! (%s)\n", 6586334a663SPoul-Henning Kamp dev->__si_namebuf); 6596334a663SPoul-Henning Kamp } 6601a1b2800SPoul-Henning Kamp 6615ef2707eSPoul-Henning Kamp dev->si_flags |= SI_NAMED; 662d26dd2d9SRobert Watson if (cr != NULL) 663d26dd2d9SRobert Watson dev->si_cred = crhold(cr); 664d26dd2d9SRobert Watson else 665d26dd2d9SRobert Watson dev->si_cred = NULL; 6669477d73eSPoul-Henning Kamp dev->si_uid = uid; 6679477d73eSPoul-Henning Kamp dev->si_gid = gid; 6689477d73eSPoul-Henning Kamp dev->si_mode = mode; 6691744fcd0SJulian Elischer 6709285a87eSPoul-Henning Kamp devfs_create(dev); 67109828ba9SKonstantin Belousov clean_unrhdrl(devfs_inos); 672aeeb4202SKonstantin Belousov dev_unlock_and_free(); 67348504cc2SKonstantin Belousov 67448504cc2SKonstantin Belousov notify_create(dev); 67548504cc2SKonstantin Belousov 6763f54a085SPoul-Henning Kamp return (dev); 6773f54a085SPoul-Henning Kamp } 6783f54a085SPoul-Henning Kamp 679d26dd2d9SRobert Watson struct cdev * 680edde8745SEd Schouten make_dev(struct cdevsw *devsw, int unit, uid_t uid, gid_t gid, int mode, 681d26dd2d9SRobert Watson const char *fmt, ...) 682d26dd2d9SRobert Watson { 683d26dd2d9SRobert Watson struct cdev *dev; 684d26dd2d9SRobert Watson va_list ap; 685d26dd2d9SRobert Watson 686d26dd2d9SRobert Watson va_start(ap, fmt); 687edde8745SEd Schouten dev = make_dev_credv(0, devsw, unit, NULL, uid, gid, mode, fmt, ap); 688d26dd2d9SRobert Watson va_end(ap); 689d26dd2d9SRobert Watson return (dev); 690d26dd2d9SRobert Watson } 691d26dd2d9SRobert Watson 692d26dd2d9SRobert Watson struct cdev * 693edde8745SEd Schouten make_dev_cred(struct cdevsw *devsw, int unit, struct ucred *cr, uid_t uid, 694d26dd2d9SRobert Watson gid_t gid, int mode, const char *fmt, ...) 695d26dd2d9SRobert Watson { 696d26dd2d9SRobert Watson struct cdev *dev; 697d26dd2d9SRobert Watson va_list ap; 698d26dd2d9SRobert Watson 699d26dd2d9SRobert Watson va_start(ap, fmt); 700edde8745SEd Schouten dev = make_dev_credv(0, devsw, unit, cr, uid, gid, mode, fmt, ap); 701de10ffa5SKonstantin Belousov va_end(ap); 702de10ffa5SKonstantin Belousov 703de10ffa5SKonstantin Belousov return (dev); 704de10ffa5SKonstantin Belousov } 705de10ffa5SKonstantin Belousov 706de10ffa5SKonstantin Belousov struct cdev * 707edde8745SEd Schouten make_dev_credf(int flags, struct cdevsw *devsw, int unit, 708de10ffa5SKonstantin Belousov struct ucred *cr, uid_t uid, 709de10ffa5SKonstantin Belousov gid_t gid, int mode, const char *fmt, ...) 710de10ffa5SKonstantin Belousov { 711de10ffa5SKonstantin Belousov struct cdev *dev; 712de10ffa5SKonstantin Belousov va_list ap; 713de10ffa5SKonstantin Belousov 714de10ffa5SKonstantin Belousov va_start(ap, fmt); 715edde8745SEd Schouten dev = make_dev_credv(flags, devsw, unit, cr, uid, gid, mode, 716de10ffa5SKonstantin Belousov fmt, ap); 717d26dd2d9SRobert Watson va_end(ap); 718d26dd2d9SRobert Watson 719d26dd2d9SRobert Watson return (dev); 720d26dd2d9SRobert Watson } 721d26dd2d9SRobert Watson 722e606a3c6SPoul-Henning Kamp static void 723e606a3c6SPoul-Henning Kamp dev_dependsl(struct cdev *pdev, struct cdev *cdev) 724e606a3c6SPoul-Henning Kamp { 725e606a3c6SPoul-Henning Kamp 726e606a3c6SPoul-Henning Kamp cdev->si_parent = pdev; 727e606a3c6SPoul-Henning Kamp cdev->si_flags |= SI_CHILD; 728e606a3c6SPoul-Henning Kamp LIST_INSERT_HEAD(&pdev->si_children, cdev, si_siblings); 729e606a3c6SPoul-Henning Kamp } 730e606a3c6SPoul-Henning Kamp 731e606a3c6SPoul-Henning Kamp 7323344c5a1SPoul-Henning Kamp void 73389c9c53dSPoul-Henning Kamp dev_depends(struct cdev *pdev, struct cdev *cdev) 7343344c5a1SPoul-Henning Kamp { 7353344c5a1SPoul-Henning Kamp 736a0e78d2eSPoul-Henning Kamp dev_lock(); 737e606a3c6SPoul-Henning Kamp dev_dependsl(pdev, cdev); 738a0e78d2eSPoul-Henning Kamp dev_unlock(); 7393344c5a1SPoul-Henning Kamp } 7403344c5a1SPoul-Henning Kamp 74189c9c53dSPoul-Henning Kamp struct cdev * 74289c9c53dSPoul-Henning Kamp make_dev_alias(struct cdev *pdev, const char *fmt, ...) 7433f54a085SPoul-Henning Kamp { 74489c9c53dSPoul-Henning Kamp struct cdev *dev; 7453f54a085SPoul-Henning Kamp va_list ap; 7463f54a085SPoul-Henning Kamp int i; 7473f54a085SPoul-Henning Kamp 748ae95dc62SKonstantin Belousov KASSERT(pdev != NULL, ("NULL pdev")); 749e606a3c6SPoul-Henning Kamp dev = devfs_alloc(); 750a0e78d2eSPoul-Henning Kamp dev_lock(); 7513f54a085SPoul-Henning Kamp dev->si_flags |= SI_ALIAS; 7525ef2707eSPoul-Henning Kamp dev->si_flags |= SI_NAMED; 7533f54a085SPoul-Henning Kamp va_start(ap, fmt); 7546334a663SPoul-Henning Kamp i = vsnrprintf(dev->__si_namebuf, sizeof dev->__si_namebuf, 32, fmt, ap); 7556334a663SPoul-Henning Kamp if (i > (sizeof dev->__si_namebuf - 1)) { 7562e4db7cfSPawel Jakub Dawidek printf("WARNING: Device name truncated! (%s)\n", 7576334a663SPoul-Henning Kamp dev->__si_namebuf); 7586334a663SPoul-Henning Kamp } 7593f54a085SPoul-Henning Kamp va_end(ap); 7603f54a085SPoul-Henning Kamp 7619285a87eSPoul-Henning Kamp devfs_create(dev); 762ae95dc62SKonstantin Belousov dev_dependsl(pdev, dev); 76309828ba9SKonstantin Belousov clean_unrhdrl(devfs_inos); 764a0e78d2eSPoul-Henning Kamp dev_unlock(); 76548504cc2SKonstantin Belousov 76648504cc2SKonstantin Belousov notify_create(dev); 76748504cc2SKonstantin Belousov 7680ef1c826SPoul-Henning Kamp return (dev); 7690ef1c826SPoul-Henning Kamp } 7700ef1c826SPoul-Henning Kamp 771cd690b60SPoul-Henning Kamp static void 772aa2f6ddcSPoul-Henning Kamp destroy_devl(struct cdev *dev) 773d137acccSPoul-Henning Kamp { 774743cd76aSPoul-Henning Kamp struct cdevsw *csw; 77582f4d640SKonstantin Belousov struct cdev_privdata *p, *p1; 776743cd76aSPoul-Henning Kamp 777aa2f6ddcSPoul-Henning Kamp mtx_assert(&devmtx, MA_OWNED); 778743cd76aSPoul-Henning Kamp KASSERT(dev->si_flags & SI_NAMED, 7796bfa9a2dSEd Schouten ("WARNING: Driver mistake: destroy_dev on %d\n", dev2unit(dev))); 7805ef2707eSPoul-Henning Kamp 7819285a87eSPoul-Henning Kamp devfs_destroy(dev); 782cd690b60SPoul-Henning Kamp 783cd690b60SPoul-Henning Kamp /* Remove name marking */ 784b0b03348SPoul-Henning Kamp dev->si_flags &= ~SI_NAMED; 785b0b03348SPoul-Henning Kamp 786cd690b60SPoul-Henning Kamp /* If we are a child, remove us from the parents list */ 7873344c5a1SPoul-Henning Kamp if (dev->si_flags & SI_CHILD) { 7883344c5a1SPoul-Henning Kamp LIST_REMOVE(dev, si_siblings); 7893344c5a1SPoul-Henning Kamp dev->si_flags &= ~SI_CHILD; 7903344c5a1SPoul-Henning Kamp } 791cd690b60SPoul-Henning Kamp 792cd690b60SPoul-Henning Kamp /* Kill our children */ 7933344c5a1SPoul-Henning Kamp while (!LIST_EMPTY(&dev->si_children)) 794aa2f6ddcSPoul-Henning Kamp destroy_devl(LIST_FIRST(&dev->si_children)); 795cd690b60SPoul-Henning Kamp 796cd690b60SPoul-Henning Kamp /* Remove from clone list */ 797b0b03348SPoul-Henning Kamp if (dev->si_flags & SI_CLONELIST) { 798b0b03348SPoul-Henning Kamp LIST_REMOVE(dev, si_clone); 799b0b03348SPoul-Henning Kamp dev->si_flags &= ~SI_CLONELIST; 800b0b03348SPoul-Henning Kamp } 801cd690b60SPoul-Henning Kamp 802e0c33ad5STor Egge dev->si_refcount++; /* Avoid race with dev_rel() */ 803743cd76aSPoul-Henning Kamp csw = dev->si_devsw; 8041abf2c36SBrian Feldman dev->si_devsw = NULL; /* already NULL for SI_ALIAS */ 8051abf2c36SBrian Feldman while (csw != NULL && csw->d_purge != NULL && dev->si_threadcount) { 806743cd76aSPoul-Henning Kamp csw->d_purge(dev); 807743cd76aSPoul-Henning Kamp msleep(csw, &devmtx, PRIBIO, "devprg", hz/10); 808d595182fSPoul-Henning Kamp if (dev->si_threadcount) 809d595182fSPoul-Henning Kamp printf("Still %lu threads in %s\n", 810d595182fSPoul-Henning Kamp dev->si_threadcount, devtoname(dev)); 811743cd76aSPoul-Henning Kamp } 812e0c33ad5STor Egge while (dev->si_threadcount != 0) { 813e0c33ad5STor Egge /* Use unique dummy wait ident */ 814e0c33ad5STor Egge msleep(&csw, &devmtx, PRIBIO, "devdrn", hz / 10); 815e0c33ad5STor Egge } 816743cd76aSPoul-Henning Kamp 81782f4d640SKonstantin Belousov dev_unlock(); 81848504cc2SKonstantin Belousov notify_destroy(dev); 81982f4d640SKonstantin Belousov mtx_lock(&cdevpriv_mtx); 82005427aafSKonstantin Belousov LIST_FOREACH_SAFE(p, &cdev2priv(dev)->cdp_fdpriv, cdpd_list, p1) { 82182f4d640SKonstantin Belousov devfs_destroy_cdevpriv(p); 82282f4d640SKonstantin Belousov mtx_lock(&cdevpriv_mtx); 82382f4d640SKonstantin Belousov } 82482f4d640SKonstantin Belousov mtx_unlock(&cdevpriv_mtx); 82582f4d640SKonstantin Belousov dev_lock(); 82648504cc2SKonstantin Belousov 827743cd76aSPoul-Henning Kamp dev->si_drv1 = 0; 828743cd76aSPoul-Henning Kamp dev->si_drv2 = 0; 829743cd76aSPoul-Henning Kamp bzero(&dev->__si_u, sizeof(dev->__si_u)); 830743cd76aSPoul-Henning Kamp 831cd690b60SPoul-Henning Kamp if (!(dev->si_flags & SI_ALIAS)) { 832cd690b60SPoul-Henning Kamp /* Remove from cdevsw list */ 833cd690b60SPoul-Henning Kamp LIST_REMOVE(dev, si_list); 834cd690b60SPoul-Henning Kamp 835e606a3c6SPoul-Henning Kamp /* If cdevsw has no more struct cdev *'s, clean it */ 836de10ffa5SKonstantin Belousov if (LIST_EMPTY(&csw->d_devs)) { 837a5993c33SPoul-Henning Kamp fini_cdevsw(csw); 838de10ffa5SKonstantin Belousov wakeup(&csw->d_devs); 839de10ffa5SKonstantin Belousov } 840cd690b60SPoul-Henning Kamp } 8415ef2707eSPoul-Henning Kamp dev->si_flags &= ~SI_ALIAS; 842e0c33ad5STor Egge dev->si_refcount--; /* Avoid race with dev_rel() */ 843743cd76aSPoul-Henning Kamp 844cd690b60SPoul-Henning Kamp if (dev->si_refcount > 0) { 845cd690b60SPoul-Henning Kamp LIST_INSERT_HEAD(&dead_cdevsw.d_devs, dev, si_list); 846cd690b60SPoul-Henning Kamp } else { 8479bc911d4SKonstantin Belousov dev_free_devlocked(dev); 848d137acccSPoul-Henning Kamp } 849cd690b60SPoul-Henning Kamp } 850cd690b60SPoul-Henning Kamp 851cd690b60SPoul-Henning Kamp void 85289c9c53dSPoul-Henning Kamp destroy_dev(struct cdev *dev) 853cd690b60SPoul-Henning Kamp { 854cd690b60SPoul-Henning Kamp 855b7a813fcSKonstantin Belousov WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, "destroy_dev"); 856a0e78d2eSPoul-Henning Kamp dev_lock(); 857aa2f6ddcSPoul-Henning Kamp destroy_devl(dev); 8589bc911d4SKonstantin Belousov dev_unlock_and_free(); 859cd690b60SPoul-Henning Kamp } 860d137acccSPoul-Henning Kamp 861c32cc149SBruce Evans const char * 86289c9c53dSPoul-Henning Kamp devtoname(struct cdev *dev) 863b8e49f68SBill Fumerola { 864b8e49f68SBill Fumerola 865b8e49f68SBill Fumerola return (dev->si_name); 866b8e49f68SBill Fumerola } 867db901281SPoul-Henning Kamp 868db901281SPoul-Henning Kamp int 86901de1b13SPoul-Henning Kamp dev_stdclone(char *name, char **namep, const char *stem, int *unit) 870db901281SPoul-Henning Kamp { 871db901281SPoul-Henning Kamp int u, i; 872db901281SPoul-Henning Kamp 873db901281SPoul-Henning Kamp i = strlen(stem); 87456700d46SBrian Somers if (bcmp(stem, name, i) != 0) 87556700d46SBrian Somers return (0); 876db901281SPoul-Henning Kamp if (!isdigit(name[i])) 877db901281SPoul-Henning Kamp return (0); 878db901281SPoul-Henning Kamp u = 0; 87910786074SPoul-Henning Kamp if (name[i] == '0' && isdigit(name[i+1])) 88010786074SPoul-Henning Kamp return (0); 881db901281SPoul-Henning Kamp while (isdigit(name[i])) { 882db901281SPoul-Henning Kamp u *= 10; 883db901281SPoul-Henning Kamp u += name[i++] - '0'; 884db901281SPoul-Henning Kamp } 885dab3d85fSBrian Feldman if (u > 0xffffff) 886dab3d85fSBrian Feldman return (0); 887db901281SPoul-Henning Kamp *unit = u; 888db901281SPoul-Henning Kamp if (namep) 889db901281SPoul-Henning Kamp *namep = &name[i]; 890db901281SPoul-Henning Kamp if (name[i]) 891db901281SPoul-Henning Kamp return (2); 892db901281SPoul-Henning Kamp return (1); 893db901281SPoul-Henning Kamp } 8948d25eb2cSPoul-Henning Kamp 8958d25eb2cSPoul-Henning Kamp /* 896b0b03348SPoul-Henning Kamp * Helper functions for cloning device drivers. 897b0b03348SPoul-Henning Kamp * 898b0b03348SPoul-Henning Kamp * The objective here is to make it unnecessary for the device drivers to 899b0b03348SPoul-Henning Kamp * use rman or similar to manage their unit number space. Due to the way 900b0b03348SPoul-Henning Kamp * we do "on-demand" devices, using rman or other "private" methods 901b0b03348SPoul-Henning Kamp * will be very tricky to lock down properly once we lock down this file. 902b0b03348SPoul-Henning Kamp * 9039a98ae94SLukas Ertl * Instead we give the drivers these routines which puts the struct cdev *'s 9049a98ae94SLukas Ertl * that are to be managed on their own list, and gives the driver the ability 905b0b03348SPoul-Henning Kamp * to ask for the first free unit number or a given specified unit number. 906b0b03348SPoul-Henning Kamp * 907b0b03348SPoul-Henning Kamp * In addition these routines support paired devices (pty, nmdm and similar) 908b0b03348SPoul-Henning Kamp * by respecting a number of "flag" bits in the minor number. 909b0b03348SPoul-Henning Kamp * 910b0b03348SPoul-Henning Kamp */ 911b0b03348SPoul-Henning Kamp 912b0b03348SPoul-Henning Kamp struct clonedevs { 913b0b03348SPoul-Henning Kamp LIST_HEAD(,cdev) head; 914b0b03348SPoul-Henning Kamp }; 915b0b03348SPoul-Henning Kamp 9169397290eSPoul-Henning Kamp void 9179397290eSPoul-Henning Kamp clone_setup(struct clonedevs **cdp) 9189397290eSPoul-Henning Kamp { 9199397290eSPoul-Henning Kamp 9209397290eSPoul-Henning Kamp *cdp = malloc(sizeof **cdp, M_DEVBUF, M_WAITOK | M_ZERO); 9219397290eSPoul-Henning Kamp LIST_INIT(&(*cdp)->head); 9229397290eSPoul-Henning Kamp } 9239397290eSPoul-Henning Kamp 924b0b03348SPoul-Henning Kamp int 925217f71d8SBruce M Simpson clone_create(struct clonedevs **cdp, struct cdevsw *csw, int *up, struct cdev **dp, int extra) 926b0b03348SPoul-Henning Kamp { 927b0b03348SPoul-Henning Kamp struct clonedevs *cd; 928027b1f71SPoul-Henning Kamp struct cdev *dev, *ndev, *dl, *de; 929b0b03348SPoul-Henning Kamp int unit, low, u; 930b0b03348SPoul-Henning Kamp 9319397290eSPoul-Henning Kamp KASSERT(*cdp != NULL, 9329397290eSPoul-Henning Kamp ("clone_setup() not called in driver \"%s\"", csw->d_name)); 933b0b03348SPoul-Henning Kamp KASSERT(!(extra & CLONE_UNITMASK), 934b0b03348SPoul-Henning Kamp ("Illegal extra bits (0x%x) in clone_create", extra)); 935b0b03348SPoul-Henning Kamp KASSERT(*up <= CLONE_UNITMASK, 936b0b03348SPoul-Henning Kamp ("Too high unit (0x%x) in clone_create", *up)); 93729d4cb24SEd Schouten KASSERT(csw->d_flags & D_NEEDMINOR, 93829d4cb24SEd Schouten ("clone_create() on cdevsw without minor numbers")); 939b0b03348SPoul-Henning Kamp 940b0b03348SPoul-Henning Kamp 941b0b03348SPoul-Henning Kamp /* 942b0b03348SPoul-Henning Kamp * Search the list for a lot of things in one go: 943b0b03348SPoul-Henning Kamp * A preexisting match is returned immediately. 944b0b03348SPoul-Henning Kamp * The lowest free unit number if we are passed -1, and the place 945b0b03348SPoul-Henning Kamp * in the list where we should insert that new element. 946b0b03348SPoul-Henning Kamp * The place to insert a specified unit number, if applicable 947b0b03348SPoul-Henning Kamp * the end of the list. 948b0b03348SPoul-Henning Kamp */ 949b0b03348SPoul-Henning Kamp unit = *up; 950e606a3c6SPoul-Henning Kamp ndev = devfs_alloc(); 951027b1f71SPoul-Henning Kamp dev_lock(); 952aeeb4202SKonstantin Belousov prep_cdevsw(csw); 9538666b655SPoul-Henning Kamp low = extra; 954b0b03348SPoul-Henning Kamp de = dl = NULL; 9559397290eSPoul-Henning Kamp cd = *cdp; 956b0b03348SPoul-Henning Kamp LIST_FOREACH(dev, &cd->head, si_clone) { 957027b1f71SPoul-Henning Kamp KASSERT(dev->si_flags & SI_CLONELIST, 958027b1f71SPoul-Henning Kamp ("Dev %p(%s) should be on clonelist", dev, dev->si_name)); 959b0b03348SPoul-Henning Kamp u = dev2unit(dev); 960b0b03348SPoul-Henning Kamp if (u == (unit | extra)) { 961b0b03348SPoul-Henning Kamp *dp = dev; 962027b1f71SPoul-Henning Kamp dev_unlock(); 9639bc911d4SKonstantin Belousov devfs_free(ndev); 964b0b03348SPoul-Henning Kamp return (0); 965b0b03348SPoul-Henning Kamp } 966b0b03348SPoul-Henning Kamp if (unit == -1 && u == low) { 967b0b03348SPoul-Henning Kamp low++; 968b0b03348SPoul-Henning Kamp de = dev; 969b0b03348SPoul-Henning Kamp continue; 9707bbb3a26SPoul-Henning Kamp } else if (u < (unit | extra)) { 9717bbb3a26SPoul-Henning Kamp de = dev; 9727bbb3a26SPoul-Henning Kamp continue; 9737bbb3a26SPoul-Henning Kamp } else if (u > (unit | extra)) { 974b0b03348SPoul-Henning Kamp dl = dev; 975b0b03348SPoul-Henning Kamp break; 976b0b03348SPoul-Henning Kamp } 977b0b03348SPoul-Henning Kamp } 978b0b03348SPoul-Henning Kamp if (unit == -1) 9798666b655SPoul-Henning Kamp unit = low & CLONE_UNITMASK; 980d3ce8327SEd Schouten dev = newdev(csw, unit | extra, ndev); 981027b1f71SPoul-Henning Kamp if (dev->si_flags & SI_CLONELIST) { 982027b1f71SPoul-Henning Kamp printf("dev %p (%s) is on clonelist\n", dev, dev->si_name); 9837bbb3a26SPoul-Henning Kamp printf("unit=%d, low=%d, extra=0x%x\n", unit, low, extra); 984027b1f71SPoul-Henning Kamp LIST_FOREACH(dev, &cd->head, si_clone) { 985027b1f71SPoul-Henning Kamp printf("\t%p %s\n", dev, dev->si_name); 986027b1f71SPoul-Henning Kamp } 987027b1f71SPoul-Henning Kamp panic("foo"); 988027b1f71SPoul-Henning Kamp } 989b0b03348SPoul-Henning Kamp KASSERT(!(dev->si_flags & SI_CLONELIST), 990027b1f71SPoul-Henning Kamp ("Dev %p(%s) should not be on clonelist", dev, dev->si_name)); 991b0b03348SPoul-Henning Kamp if (dl != NULL) 992b0b03348SPoul-Henning Kamp LIST_INSERT_BEFORE(dl, dev, si_clone); 993b0b03348SPoul-Henning Kamp else if (de != NULL) 994b0b03348SPoul-Henning Kamp LIST_INSERT_AFTER(de, dev, si_clone); 995b0b03348SPoul-Henning Kamp else 996b0b03348SPoul-Henning Kamp LIST_INSERT_HEAD(&cd->head, dev, si_clone); 997b0b03348SPoul-Henning Kamp dev->si_flags |= SI_CLONELIST; 998b0b03348SPoul-Henning Kamp *up = unit; 9999bc911d4SKonstantin Belousov dev_unlock_and_free(); 1000b0b03348SPoul-Henning Kamp return (1); 1001b0b03348SPoul-Henning Kamp } 1002b0b03348SPoul-Henning Kamp 1003b0b03348SPoul-Henning Kamp /* 1004b0b03348SPoul-Henning Kamp * Kill everything still on the list. The driver should already have 100589c9c53dSPoul-Henning Kamp * disposed of any softc hung of the struct cdev *'s at this time. 1006b0b03348SPoul-Henning Kamp */ 1007b0b03348SPoul-Henning Kamp void 1008b0b03348SPoul-Henning Kamp clone_cleanup(struct clonedevs **cdp) 1009b0b03348SPoul-Henning Kamp { 1010de10ffa5SKonstantin Belousov struct cdev *dev; 1011de10ffa5SKonstantin Belousov struct cdev_priv *cp; 1012b0b03348SPoul-Henning Kamp struct clonedevs *cd; 1013b0b03348SPoul-Henning Kamp 1014b0b03348SPoul-Henning Kamp cd = *cdp; 1015b0b03348SPoul-Henning Kamp if (cd == NULL) 1016b0b03348SPoul-Henning Kamp return; 1017027b1f71SPoul-Henning Kamp dev_lock(); 1018de10ffa5SKonstantin Belousov while (!LIST_EMPTY(&cd->head)) { 1019de10ffa5SKonstantin Belousov dev = LIST_FIRST(&cd->head); 1020de10ffa5SKonstantin Belousov LIST_REMOVE(dev, si_clone); 1021027b1f71SPoul-Henning Kamp KASSERT(dev->si_flags & SI_CLONELIST, 1022027b1f71SPoul-Henning Kamp ("Dev %p(%s) should be on clonelist", dev, dev->si_name)); 1023de10ffa5SKonstantin Belousov dev->si_flags &= ~SI_CLONELIST; 102405427aafSKonstantin Belousov cp = cdev2priv(dev); 1025de10ffa5SKonstantin Belousov if (!(cp->cdp_flags & CDP_SCHED_DTR)) { 1026de10ffa5SKonstantin Belousov cp->cdp_flags |= CDP_SCHED_DTR; 1027b0b03348SPoul-Henning Kamp KASSERT(dev->si_flags & SI_NAMED, 1028d7cbfc1bSEd Schouten ("Driver has goofed in cloning underways udev %x unit %x", dev2udev(dev), dev2unit(dev))); 1029aa2f6ddcSPoul-Henning Kamp destroy_devl(dev); 1030b0b03348SPoul-Henning Kamp } 1031de10ffa5SKonstantin Belousov } 1032aeeb4202SKonstantin Belousov dev_unlock_and_free(); 1033b0b03348SPoul-Henning Kamp free(cd, M_DEVBUF); 1034b0b03348SPoul-Henning Kamp *cdp = NULL; 1035b0b03348SPoul-Henning Kamp } 1036de10ffa5SKonstantin Belousov 1037de10ffa5SKonstantin Belousov static TAILQ_HEAD(, cdev_priv) dev_ddtr = 1038de10ffa5SKonstantin Belousov TAILQ_HEAD_INITIALIZER(dev_ddtr); 1039de10ffa5SKonstantin Belousov static struct task dev_dtr_task; 1040de10ffa5SKonstantin Belousov 1041de10ffa5SKonstantin Belousov static void 1042de10ffa5SKonstantin Belousov destroy_dev_tq(void *ctx, int pending) 1043de10ffa5SKonstantin Belousov { 1044de10ffa5SKonstantin Belousov struct cdev_priv *cp; 1045de10ffa5SKonstantin Belousov struct cdev *dev; 1046de10ffa5SKonstantin Belousov void (*cb)(void *); 1047de10ffa5SKonstantin Belousov void *cb_arg; 1048de10ffa5SKonstantin Belousov 1049de10ffa5SKonstantin Belousov dev_lock(); 1050de10ffa5SKonstantin Belousov while (!TAILQ_EMPTY(&dev_ddtr)) { 1051de10ffa5SKonstantin Belousov cp = TAILQ_FIRST(&dev_ddtr); 1052de10ffa5SKonstantin Belousov dev = &cp->cdp_c; 1053de10ffa5SKonstantin Belousov KASSERT(cp->cdp_flags & CDP_SCHED_DTR, 1054de10ffa5SKonstantin Belousov ("cdev %p in dev_destroy_tq without CDP_SCHED_DTR", cp)); 1055de10ffa5SKonstantin Belousov TAILQ_REMOVE(&dev_ddtr, cp, cdp_dtr_list); 1056de10ffa5SKonstantin Belousov cb = cp->cdp_dtr_cb; 1057de10ffa5SKonstantin Belousov cb_arg = cp->cdp_dtr_cb_arg; 1058de10ffa5SKonstantin Belousov destroy_devl(dev); 1059aeeb4202SKonstantin Belousov dev_unlock_and_free(); 1060de10ffa5SKonstantin Belousov dev_rel(dev); 1061de10ffa5SKonstantin Belousov if (cb != NULL) 1062de10ffa5SKonstantin Belousov cb(cb_arg); 1063de10ffa5SKonstantin Belousov dev_lock(); 1064de10ffa5SKonstantin Belousov } 1065de10ffa5SKonstantin Belousov dev_unlock(); 1066de10ffa5SKonstantin Belousov } 1067de10ffa5SKonstantin Belousov 10689d53363bSKonstantin Belousov /* 10699d53363bSKonstantin Belousov * devmtx shall be locked on entry. devmtx will be unlocked after 10709d53363bSKonstantin Belousov * function return. 10719d53363bSKonstantin Belousov */ 10729d53363bSKonstantin Belousov static int 10739d53363bSKonstantin Belousov destroy_dev_sched_cbl(struct cdev *dev, void (*cb)(void *), void *arg) 1074de10ffa5SKonstantin Belousov { 1075de10ffa5SKonstantin Belousov struct cdev_priv *cp; 1076de10ffa5SKonstantin Belousov 10779d53363bSKonstantin Belousov mtx_assert(&devmtx, MA_OWNED); 107805427aafSKonstantin Belousov cp = cdev2priv(dev); 1079de10ffa5SKonstantin Belousov if (cp->cdp_flags & CDP_SCHED_DTR) { 1080de10ffa5SKonstantin Belousov dev_unlock(); 1081de10ffa5SKonstantin Belousov return (0); 1082de10ffa5SKonstantin Belousov } 1083de10ffa5SKonstantin Belousov dev_refl(dev); 1084de10ffa5SKonstantin Belousov cp->cdp_flags |= CDP_SCHED_DTR; 1085de10ffa5SKonstantin Belousov cp->cdp_dtr_cb = cb; 1086de10ffa5SKonstantin Belousov cp->cdp_dtr_cb_arg = arg; 1087de10ffa5SKonstantin Belousov TAILQ_INSERT_TAIL(&dev_ddtr, cp, cdp_dtr_list); 1088de10ffa5SKonstantin Belousov dev_unlock(); 1089de10ffa5SKonstantin Belousov taskqueue_enqueue(taskqueue_swi_giant, &dev_dtr_task); 1090de10ffa5SKonstantin Belousov return (1); 1091de10ffa5SKonstantin Belousov } 1092de10ffa5SKonstantin Belousov 1093de10ffa5SKonstantin Belousov int 10949d53363bSKonstantin Belousov destroy_dev_sched_cb(struct cdev *dev, void (*cb)(void *), void *arg) 10959d53363bSKonstantin Belousov { 10969d53363bSKonstantin Belousov dev_lock(); 10979d53363bSKonstantin Belousov return (destroy_dev_sched_cbl(dev, cb, arg)); 10989d53363bSKonstantin Belousov } 10999d53363bSKonstantin Belousov 11009d53363bSKonstantin Belousov int 1101de10ffa5SKonstantin Belousov destroy_dev_sched(struct cdev *dev) 1102de10ffa5SKonstantin Belousov { 1103de10ffa5SKonstantin Belousov return (destroy_dev_sched_cb(dev, NULL, NULL)); 1104de10ffa5SKonstantin Belousov } 1105de10ffa5SKonstantin Belousov 1106de10ffa5SKonstantin Belousov void 1107de10ffa5SKonstantin Belousov destroy_dev_drain(struct cdevsw *csw) 1108de10ffa5SKonstantin Belousov { 1109de10ffa5SKonstantin Belousov 1110de10ffa5SKonstantin Belousov dev_lock(); 1111de10ffa5SKonstantin Belousov while (!LIST_EMPTY(&csw->d_devs)) { 1112de10ffa5SKonstantin Belousov msleep(&csw->d_devs, &devmtx, PRIBIO, "devscd", hz/10); 1113de10ffa5SKonstantin Belousov } 1114de10ffa5SKonstantin Belousov dev_unlock(); 1115de10ffa5SKonstantin Belousov } 1116de10ffa5SKonstantin Belousov 1117de10ffa5SKonstantin Belousov void 1118de10ffa5SKonstantin Belousov drain_dev_clone_events(void) 1119de10ffa5SKonstantin Belousov { 1120de10ffa5SKonstantin Belousov 1121de10ffa5SKonstantin Belousov sx_xlock(&clone_drain_lock); 1122de10ffa5SKonstantin Belousov sx_xunlock(&clone_drain_lock); 1123de10ffa5SKonstantin Belousov } 1124de10ffa5SKonstantin Belousov 1125de10ffa5SKonstantin Belousov static void 1126de10ffa5SKonstantin Belousov devdtr_init(void *dummy __unused) 1127de10ffa5SKonstantin Belousov { 1128de10ffa5SKonstantin Belousov 1129de10ffa5SKonstantin Belousov TASK_INIT(&dev_dtr_task, 0, destroy_dev_tq, NULL); 1130de10ffa5SKonstantin Belousov } 1131de10ffa5SKonstantin Belousov 1132de10ffa5SKonstantin Belousov SYSINIT(devdtr, SI_SUB_DEVFS, SI_ORDER_SECOND, devdtr_init, NULL); 1133