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); 58de10ffa5SKonstantin Belousov static struct cdev *make_dev_credv(int flags, 59edde8745SEd Schouten struct cdevsw *devsw, int unit, 60d26dd2d9SRobert Watson struct ucred *cr, uid_t uid, gid_t gid, int mode, const char *fmt, 61d26dd2d9SRobert Watson va_list ap); 62f3732fd1SPoul-Henning Kamp 639bc911d4SKonstantin Belousov static struct cdev_priv_list cdevp_free_list = 649bc911d4SKonstantin Belousov TAILQ_HEAD_INITIALIZER(cdevp_free_list); 65aeeb4202SKonstantin Belousov static SLIST_HEAD(free_cdevsw, cdevsw) cdevsw_gt_post_list = 6613e403fdSAntoine Brodin SLIST_HEAD_INITIALIZER(cdevsw_gt_post_list); 679bc911d4SKonstantin Belousov 68a0e78d2eSPoul-Henning Kamp void 69a0e78d2eSPoul-Henning Kamp dev_lock(void) 70cd690b60SPoul-Henning Kamp { 718c4b6380SJohn Baldwin 72cd690b60SPoul-Henning Kamp mtx_lock(&devmtx); 73cd690b60SPoul-Henning Kamp } 74cd690b60SPoul-Henning Kamp 75aeeb4202SKonstantin Belousov /* 76aeeb4202SKonstantin Belousov * Free all the memory collected while the cdev mutex was 77aeeb4202SKonstantin Belousov * locked. Since devmtx is after the system map mutex, free() cannot 78aeeb4202SKonstantin Belousov * be called immediately and is postponed until cdev mutex can be 79aeeb4202SKonstantin Belousov * dropped. 80aeeb4202SKonstantin Belousov */ 819bc911d4SKonstantin Belousov static void 829bc911d4SKonstantin Belousov dev_unlock_and_free(void) 839bc911d4SKonstantin Belousov { 84aeeb4202SKonstantin Belousov struct cdev_priv_list cdp_free; 85aeeb4202SKonstantin Belousov struct free_cdevsw csw_free; 869bc911d4SKonstantin Belousov struct cdev_priv *cdp; 87aeeb4202SKonstantin Belousov struct cdevsw *csw; 889bc911d4SKonstantin Belousov 899bc911d4SKonstantin Belousov mtx_assert(&devmtx, MA_OWNED); 90aeeb4202SKonstantin Belousov 91aeeb4202SKonstantin Belousov /* 92aeeb4202SKonstantin Belousov * Make the local copy of the list heads while the dev_mtx is 93aeeb4202SKonstantin Belousov * held. Free it later. 94aeeb4202SKonstantin Belousov */ 95aeeb4202SKonstantin Belousov TAILQ_INIT(&cdp_free); 96aeeb4202SKonstantin Belousov TAILQ_CONCAT(&cdp_free, &cdevp_free_list, cdp_list); 97aeeb4202SKonstantin Belousov csw_free = cdevsw_gt_post_list; 98aeeb4202SKonstantin Belousov SLIST_INIT(&cdevsw_gt_post_list); 99aeeb4202SKonstantin Belousov 1009bc911d4SKonstantin Belousov mtx_unlock(&devmtx); 101aeeb4202SKonstantin Belousov 102aeeb4202SKonstantin Belousov while ((cdp = TAILQ_FIRST(&cdp_free)) != NULL) { 103aeeb4202SKonstantin Belousov TAILQ_REMOVE(&cdp_free, cdp, cdp_list); 1049bc911d4SKonstantin Belousov devfs_free(&cdp->cdp_c); 1059bc911d4SKonstantin Belousov } 106aeeb4202SKonstantin Belousov while ((csw = SLIST_FIRST(&csw_free)) != NULL) { 107aeeb4202SKonstantin Belousov SLIST_REMOVE_HEAD(&csw_free, d_postfree_list); 108aeeb4202SKonstantin Belousov free(csw, M_DEVT); 109aeeb4202SKonstantin Belousov } 1109bc911d4SKonstantin Belousov } 1119bc911d4SKonstantin Belousov 1129bc911d4SKonstantin Belousov static void 1139bc911d4SKonstantin Belousov dev_free_devlocked(struct cdev *cdev) 1149bc911d4SKonstantin Belousov { 1159bc911d4SKonstantin Belousov struct cdev_priv *cdp; 1169bc911d4SKonstantin Belousov 1179bc911d4SKonstantin Belousov mtx_assert(&devmtx, MA_OWNED); 11805427aafSKonstantin Belousov cdp = cdev2priv(cdev); 1199bc911d4SKonstantin Belousov TAILQ_INSERT_HEAD(&cdevp_free_list, cdp, cdp_list); 1209bc911d4SKonstantin Belousov } 1219bc911d4SKonstantin Belousov 122aeeb4202SKonstantin Belousov static void 123aeeb4202SKonstantin Belousov cdevsw_free_devlocked(struct cdevsw *csw) 124aeeb4202SKonstantin Belousov { 125aeeb4202SKonstantin Belousov 126aeeb4202SKonstantin Belousov mtx_assert(&devmtx, MA_OWNED); 127aeeb4202SKonstantin Belousov SLIST_INSERT_HEAD(&cdevsw_gt_post_list, csw, d_postfree_list); 128aeeb4202SKonstantin Belousov } 129aeeb4202SKonstantin Belousov 130a0e78d2eSPoul-Henning Kamp void 131a0e78d2eSPoul-Henning Kamp dev_unlock(void) 132cd690b60SPoul-Henning Kamp { 1332c15afd8SPoul-Henning Kamp 134cd690b60SPoul-Henning Kamp mtx_unlock(&devmtx); 135cd690b60SPoul-Henning Kamp } 136cd690b60SPoul-Henning Kamp 137cd690b60SPoul-Henning Kamp void 1389477d73eSPoul-Henning Kamp dev_ref(struct cdev *dev) 1399477d73eSPoul-Henning Kamp { 1409477d73eSPoul-Henning Kamp 1419477d73eSPoul-Henning Kamp mtx_assert(&devmtx, MA_NOTOWNED); 1429477d73eSPoul-Henning Kamp mtx_lock(&devmtx); 1439477d73eSPoul-Henning Kamp dev->si_refcount++; 1449477d73eSPoul-Henning Kamp mtx_unlock(&devmtx); 1459477d73eSPoul-Henning Kamp } 1469477d73eSPoul-Henning Kamp 1479477d73eSPoul-Henning Kamp void 148eb151cb9SPoul-Henning Kamp dev_refl(struct cdev *dev) 149cd690b60SPoul-Henning Kamp { 1502c15afd8SPoul-Henning Kamp 1511a1457d4SPoul-Henning Kamp mtx_assert(&devmtx, MA_OWNED); 152cd690b60SPoul-Henning Kamp dev->si_refcount++; 153cd690b60SPoul-Henning Kamp } 154cd690b60SPoul-Henning Kamp 155cd690b60SPoul-Henning Kamp void 156aa2f6ddcSPoul-Henning Kamp dev_rel(struct cdev *dev) 157cd690b60SPoul-Henning Kamp { 158aa2f6ddcSPoul-Henning Kamp int flag = 0; 159a0e78d2eSPoul-Henning Kamp 160ba285125SPoul-Henning Kamp mtx_assert(&devmtx, MA_NOTOWNED); 161ba285125SPoul-Henning Kamp dev_lock(); 162cd690b60SPoul-Henning Kamp dev->si_refcount--; 163cd690b60SPoul-Henning Kamp KASSERT(dev->si_refcount >= 0, 164cd690b60SPoul-Henning Kamp ("dev_rel(%s) gave negative count", devtoname(dev))); 165e606a3c6SPoul-Henning Kamp #if 0 166aa2f6ddcSPoul-Henning Kamp if (dev->si_usecount == 0 && 167aa2f6ddcSPoul-Henning Kamp (dev->si_flags & SI_CHEAPCLONE) && (dev->si_flags & SI_NAMED)) 168e606a3c6SPoul-Henning Kamp ; 169e606a3c6SPoul-Henning Kamp else 170e606a3c6SPoul-Henning Kamp #endif 171cd690b60SPoul-Henning Kamp if (dev->si_devsw == NULL && dev->si_refcount == 0) { 172cd690b60SPoul-Henning Kamp LIST_REMOVE(dev, si_list); 173ba285125SPoul-Henning Kamp flag = 1; 174ba285125SPoul-Henning Kamp } 175ba285125SPoul-Henning Kamp dev_unlock(); 176ba285125SPoul-Henning Kamp if (flag) 177e606a3c6SPoul-Henning Kamp devfs_free(dev); 178cd690b60SPoul-Henning Kamp } 179ba285125SPoul-Henning Kamp 1802c15afd8SPoul-Henning Kamp struct cdevsw * 1812c15afd8SPoul-Henning Kamp dev_refthread(struct cdev *dev) 1822c15afd8SPoul-Henning Kamp { 1832c15afd8SPoul-Henning Kamp struct cdevsw *csw; 184de10ffa5SKonstantin Belousov struct cdev_priv *cdp; 1852c15afd8SPoul-Henning Kamp 1862c15afd8SPoul-Henning Kamp mtx_assert(&devmtx, MA_NOTOWNED); 1872c15afd8SPoul-Henning Kamp dev_lock(); 1882c15afd8SPoul-Henning Kamp csw = dev->si_devsw; 189de10ffa5SKonstantin Belousov if (csw != NULL) { 19005427aafSKonstantin Belousov cdp = cdev2priv(dev); 191de10ffa5SKonstantin Belousov if ((cdp->cdp_flags & CDP_SCHED_DTR) == 0) 1922c15afd8SPoul-Henning Kamp dev->si_threadcount++; 193de10ffa5SKonstantin Belousov else 194de10ffa5SKonstantin Belousov csw = NULL; 195de10ffa5SKonstantin Belousov } 1962c15afd8SPoul-Henning Kamp dev_unlock(); 1972c15afd8SPoul-Henning Kamp return (csw); 1982c15afd8SPoul-Henning Kamp } 1992c15afd8SPoul-Henning Kamp 2001663075cSKonstantin Belousov struct cdevsw * 2011663075cSKonstantin Belousov devvn_refthread(struct vnode *vp, struct cdev **devp) 2021663075cSKonstantin Belousov { 2031663075cSKonstantin Belousov struct cdevsw *csw; 204de10ffa5SKonstantin Belousov struct cdev_priv *cdp; 2051663075cSKonstantin Belousov 2061663075cSKonstantin Belousov mtx_assert(&devmtx, MA_NOTOWNED); 2071663075cSKonstantin Belousov csw = NULL; 2081663075cSKonstantin Belousov dev_lock(); 2091663075cSKonstantin Belousov *devp = vp->v_rdev; 2101663075cSKonstantin Belousov if (*devp != NULL) { 21105427aafSKonstantin Belousov cdp = cdev2priv(*devp); 212de10ffa5SKonstantin Belousov if ((cdp->cdp_flags & CDP_SCHED_DTR) == 0) { 2131663075cSKonstantin Belousov csw = (*devp)->si_devsw; 2141663075cSKonstantin Belousov if (csw != NULL) 2151663075cSKonstantin Belousov (*devp)->si_threadcount++; 2161663075cSKonstantin Belousov } 217de10ffa5SKonstantin Belousov } 2181663075cSKonstantin Belousov dev_unlock(); 2191663075cSKonstantin Belousov return (csw); 2201663075cSKonstantin Belousov } 2211663075cSKonstantin Belousov 2222c15afd8SPoul-Henning Kamp void 2232c15afd8SPoul-Henning Kamp dev_relthread(struct cdev *dev) 2242c15afd8SPoul-Henning Kamp { 2252c15afd8SPoul-Henning Kamp 2262c15afd8SPoul-Henning Kamp mtx_assert(&devmtx, MA_NOTOWNED); 2272c15afd8SPoul-Henning Kamp dev_lock(); 22806fe1129SKonstantin Belousov KASSERT(dev->si_threadcount > 0, 22906fe1129SKonstantin Belousov ("%s threadcount is wrong", dev->si_name)); 2302c15afd8SPoul-Henning Kamp dev->si_threadcount--; 2312c15afd8SPoul-Henning Kamp dev_unlock(); 2322c15afd8SPoul-Henning Kamp } 233cd690b60SPoul-Henning Kamp 234b2941431SPoul-Henning Kamp int 235b2941431SPoul-Henning Kamp nullop(void) 236b2941431SPoul-Henning Kamp { 237b2941431SPoul-Henning Kamp 238b2941431SPoul-Henning Kamp return (0); 239b2941431SPoul-Henning Kamp } 240b2941431SPoul-Henning Kamp 241b2941431SPoul-Henning Kamp int 242b2941431SPoul-Henning Kamp eopnotsupp(void) 243b2941431SPoul-Henning Kamp { 244b2941431SPoul-Henning Kamp 245b2941431SPoul-Henning Kamp return (EOPNOTSUPP); 246b2941431SPoul-Henning Kamp } 24702574b19SPoul-Henning Kamp 24802574b19SPoul-Henning Kamp static int 24902574b19SPoul-Henning Kamp enxio(void) 25002574b19SPoul-Henning Kamp { 25102574b19SPoul-Henning Kamp return (ENXIO); 25202574b19SPoul-Henning Kamp } 25302574b19SPoul-Henning Kamp 254b2941431SPoul-Henning Kamp static int 255b2941431SPoul-Henning Kamp enodev(void) 256b2941431SPoul-Henning Kamp { 257b2941431SPoul-Henning Kamp return (ENODEV); 258b2941431SPoul-Henning Kamp } 259b2941431SPoul-Henning Kamp 260b2941431SPoul-Henning Kamp /* Define a dead_cdevsw for use when devices leave unexpectedly. */ 261b2941431SPoul-Henning Kamp 26202574b19SPoul-Henning Kamp #define dead_open (d_open_t *)enxio 26302574b19SPoul-Henning Kamp #define dead_close (d_close_t *)enxio 26402574b19SPoul-Henning Kamp #define dead_read (d_read_t *)enxio 26502574b19SPoul-Henning Kamp #define dead_write (d_write_t *)enxio 26602574b19SPoul-Henning Kamp #define dead_ioctl (d_ioctl_t *)enxio 267b2941431SPoul-Henning Kamp #define dead_poll (d_poll_t *)enodev 268b2941431SPoul-Henning Kamp #define dead_mmap (d_mmap_t *)enodev 26902574b19SPoul-Henning Kamp 27002574b19SPoul-Henning Kamp static void 27102574b19SPoul-Henning Kamp dead_strategy(struct bio *bp) 27202574b19SPoul-Henning Kamp { 27302574b19SPoul-Henning Kamp 27402574b19SPoul-Henning Kamp biofinish(bp, NULL, ENXIO); 27502574b19SPoul-Henning Kamp } 27602574b19SPoul-Henning Kamp 2772c6b49f6SPoul-Henning Kamp #define dead_dump (dumper_t *)enxio 27802574b19SPoul-Henning Kamp #define dead_kqfilter (d_kqfilter_t *)enxio 27964345f0bSJohn Baldwin #define dead_mmap_single (d_mmap_single_t *)enodev 28002574b19SPoul-Henning Kamp 28102574b19SPoul-Henning Kamp static struct cdevsw dead_cdevsw = { 282dc08ffecSPoul-Henning Kamp .d_version = D_VERSION, 283dc08ffecSPoul-Henning Kamp .d_flags = D_NEEDGIANT, /* XXX: does dead_strategy need this ? */ 2847ac40f5fSPoul-Henning Kamp .d_open = dead_open, 2857ac40f5fSPoul-Henning Kamp .d_close = dead_close, 2867ac40f5fSPoul-Henning Kamp .d_read = dead_read, 2877ac40f5fSPoul-Henning Kamp .d_write = dead_write, 2887ac40f5fSPoul-Henning Kamp .d_ioctl = dead_ioctl, 2897ac40f5fSPoul-Henning Kamp .d_poll = dead_poll, 2907ac40f5fSPoul-Henning Kamp .d_mmap = dead_mmap, 2917ac40f5fSPoul-Henning Kamp .d_strategy = dead_strategy, 2927ac40f5fSPoul-Henning Kamp .d_name = "dead", 2937ac40f5fSPoul-Henning Kamp .d_dump = dead_dump, 29464345f0bSJohn Baldwin .d_kqfilter = dead_kqfilter, 29564345f0bSJohn Baldwin .d_mmap_single = dead_mmap_single 29602574b19SPoul-Henning Kamp }; 29702574b19SPoul-Henning Kamp 298b2941431SPoul-Henning Kamp /* Default methods if driver does not specify method */ 299b2941431SPoul-Henning Kamp 300b2941431SPoul-Henning Kamp #define null_open (d_open_t *)nullop 301b2941431SPoul-Henning Kamp #define null_close (d_close_t *)nullop 302b2941431SPoul-Henning Kamp #define no_read (d_read_t *)enodev 303b2941431SPoul-Henning Kamp #define no_write (d_write_t *)enodev 304b2941431SPoul-Henning Kamp #define no_ioctl (d_ioctl_t *)enodev 305cfd7baceSRobert Noland #define no_mmap (d_mmap_t *)enodev 306ad3b9257SJohn-Mark Gurney #define no_kqfilter (d_kqfilter_t *)enodev 30764345f0bSJohn Baldwin #define no_mmap_single (d_mmap_single_t *)enodev 308b2941431SPoul-Henning Kamp 309b2941431SPoul-Henning Kamp static void 310b2941431SPoul-Henning Kamp no_strategy(struct bio *bp) 311b2941431SPoul-Henning Kamp { 312b2941431SPoul-Henning Kamp 313b2941431SPoul-Henning Kamp biofinish(bp, NULL, ENODEV); 314b2941431SPoul-Henning Kamp } 315b2941431SPoul-Henning Kamp 316b2941431SPoul-Henning Kamp static int 31789c9c53dSPoul-Henning Kamp no_poll(struct cdev *dev __unused, int events, struct thread *td __unused) 318b2941431SPoul-Henning Kamp { 319b2941431SPoul-Henning Kamp 320125dcf8cSKonstantin Belousov return (poll_no_poll(events)); 321b2941431SPoul-Henning Kamp } 322b2941431SPoul-Henning Kamp 323b2941431SPoul-Henning Kamp #define no_dump (dumper_t *)enodev 3244e4a7663SPoul-Henning Kamp 325516ad423SPoul-Henning Kamp static int 326516ad423SPoul-Henning Kamp giant_open(struct cdev *dev, int oflags, int devtype, struct thread *td) 327516ad423SPoul-Henning Kamp { 328aeeb4202SKonstantin Belousov struct cdevsw *dsw; 329516ad423SPoul-Henning Kamp int retval; 330516ad423SPoul-Henning Kamp 331aeeb4202SKonstantin Belousov dsw = dev_refthread(dev); 332aeeb4202SKonstantin Belousov if (dsw == NULL) 333aeeb4202SKonstantin Belousov return (ENXIO); 334516ad423SPoul-Henning Kamp mtx_lock(&Giant); 335aeeb4202SKonstantin Belousov retval = dsw->d_gianttrick->d_open(dev, oflags, devtype, td); 336516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 337aeeb4202SKonstantin Belousov dev_relthread(dev); 338516ad423SPoul-Henning Kamp return (retval); 339516ad423SPoul-Henning Kamp } 340516ad423SPoul-Henning Kamp 341516ad423SPoul-Henning Kamp static int 3429e223287SKonstantin Belousov giant_fdopen(struct cdev *dev, int oflags, struct thread *td, struct file *fp) 343516ad423SPoul-Henning Kamp { 344aeeb4202SKonstantin Belousov struct cdevsw *dsw; 345516ad423SPoul-Henning Kamp int retval; 346516ad423SPoul-Henning Kamp 347aeeb4202SKonstantin Belousov dsw = dev_refthread(dev); 348aeeb4202SKonstantin Belousov if (dsw == NULL) 349aeeb4202SKonstantin Belousov return (ENXIO); 350516ad423SPoul-Henning Kamp mtx_lock(&Giant); 351aeeb4202SKonstantin Belousov retval = dsw->d_gianttrick->d_fdopen(dev, oflags, td, fp); 352516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 353aeeb4202SKonstantin Belousov dev_relthread(dev); 354516ad423SPoul-Henning Kamp return (retval); 355516ad423SPoul-Henning Kamp } 356516ad423SPoul-Henning Kamp 357516ad423SPoul-Henning Kamp static int 358516ad423SPoul-Henning Kamp giant_close(struct cdev *dev, int fflag, int devtype, struct thread *td) 359516ad423SPoul-Henning Kamp { 360aeeb4202SKonstantin Belousov struct cdevsw *dsw; 361516ad423SPoul-Henning Kamp int retval; 362516ad423SPoul-Henning Kamp 363aeeb4202SKonstantin Belousov dsw = dev_refthread(dev); 364aeeb4202SKonstantin Belousov if (dsw == NULL) 365aeeb4202SKonstantin Belousov return (ENXIO); 366516ad423SPoul-Henning Kamp mtx_lock(&Giant); 367aeeb4202SKonstantin Belousov retval = dsw->d_gianttrick->d_close(dev, fflag, devtype, td); 368516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 369aeeb4202SKonstantin Belousov dev_relthread(dev); 370516ad423SPoul-Henning Kamp return (retval); 371516ad423SPoul-Henning Kamp } 372516ad423SPoul-Henning Kamp 373516ad423SPoul-Henning Kamp static void 374516ad423SPoul-Henning Kamp giant_strategy(struct bio *bp) 375516ad423SPoul-Henning Kamp { 376aeeb4202SKonstantin Belousov struct cdevsw *dsw; 377aeeb4202SKonstantin Belousov struct cdev *dev; 378516ad423SPoul-Henning Kamp 379aeeb4202SKonstantin Belousov dev = bp->bio_dev; 380aeeb4202SKonstantin Belousov dsw = dev_refthread(dev); 381aeeb4202SKonstantin Belousov if (dsw == NULL) { 382aeeb4202SKonstantin Belousov biofinish(bp, NULL, ENXIO); 383aeeb4202SKonstantin Belousov return; 384aeeb4202SKonstantin Belousov } 385516ad423SPoul-Henning Kamp mtx_lock(&Giant); 386aeeb4202SKonstantin Belousov dsw->d_gianttrick->d_strategy(bp); 387516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 388aeeb4202SKonstantin Belousov dev_relthread(dev); 389516ad423SPoul-Henning Kamp } 390516ad423SPoul-Henning Kamp 391516ad423SPoul-Henning Kamp static int 392516ad423SPoul-Henning Kamp giant_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct thread *td) 393516ad423SPoul-Henning Kamp { 394aeeb4202SKonstantin Belousov struct cdevsw *dsw; 395516ad423SPoul-Henning Kamp int retval; 396516ad423SPoul-Henning Kamp 397aeeb4202SKonstantin Belousov dsw = dev_refthread(dev); 398aeeb4202SKonstantin Belousov if (dsw == NULL) 399aeeb4202SKonstantin Belousov return (ENXIO); 400516ad423SPoul-Henning Kamp mtx_lock(&Giant); 40135b45029SKonstantin Belousov retval = dsw->d_gianttrick->d_ioctl(dev, cmd, data, fflag, td); 402516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 403aeeb4202SKonstantin Belousov dev_relthread(dev); 404516ad423SPoul-Henning Kamp return (retval); 405516ad423SPoul-Henning Kamp } 406516ad423SPoul-Henning Kamp 407516ad423SPoul-Henning Kamp static int 408516ad423SPoul-Henning Kamp giant_read(struct cdev *dev, struct uio *uio, int ioflag) 409516ad423SPoul-Henning Kamp { 410aeeb4202SKonstantin Belousov struct cdevsw *dsw; 411516ad423SPoul-Henning Kamp int retval; 412516ad423SPoul-Henning Kamp 413aeeb4202SKonstantin Belousov dsw = dev_refthread(dev); 414aeeb4202SKonstantin Belousov if (dsw == NULL) 415aeeb4202SKonstantin Belousov return (ENXIO); 416516ad423SPoul-Henning Kamp mtx_lock(&Giant); 41735b45029SKonstantin Belousov retval = dsw->d_gianttrick->d_read(dev, uio, ioflag); 418516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 419aeeb4202SKonstantin Belousov dev_relthread(dev); 420516ad423SPoul-Henning Kamp return (retval); 421516ad423SPoul-Henning Kamp } 422516ad423SPoul-Henning Kamp 423516ad423SPoul-Henning Kamp static int 424516ad423SPoul-Henning Kamp giant_write(struct cdev *dev, struct uio *uio, int ioflag) 425516ad423SPoul-Henning Kamp { 426aeeb4202SKonstantin Belousov struct cdevsw *dsw; 427516ad423SPoul-Henning Kamp int retval; 428516ad423SPoul-Henning Kamp 429aeeb4202SKonstantin Belousov dsw = dev_refthread(dev); 430aeeb4202SKonstantin Belousov if (dsw == NULL) 431aeeb4202SKonstantin Belousov return (ENXIO); 432516ad423SPoul-Henning Kamp mtx_lock(&Giant); 433aeeb4202SKonstantin Belousov retval = dsw->d_gianttrick->d_write(dev, uio, ioflag); 434516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 435aeeb4202SKonstantin Belousov dev_relthread(dev); 436516ad423SPoul-Henning Kamp return (retval); 437516ad423SPoul-Henning Kamp } 438516ad423SPoul-Henning Kamp 439516ad423SPoul-Henning Kamp static int 440516ad423SPoul-Henning Kamp giant_poll(struct cdev *dev, int events, struct thread *td) 441516ad423SPoul-Henning Kamp { 442aeeb4202SKonstantin Belousov struct cdevsw *dsw; 443516ad423SPoul-Henning Kamp int retval; 444516ad423SPoul-Henning Kamp 445aeeb4202SKonstantin Belousov dsw = dev_refthread(dev); 446aeeb4202SKonstantin Belousov if (dsw == NULL) 447aeeb4202SKonstantin Belousov return (ENXIO); 448516ad423SPoul-Henning Kamp mtx_lock(&Giant); 449aeeb4202SKonstantin Belousov retval = dsw->d_gianttrick->d_poll(dev, events, td); 450516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 451aeeb4202SKonstantin Belousov dev_relthread(dev); 452516ad423SPoul-Henning Kamp return (retval); 453516ad423SPoul-Henning Kamp } 454516ad423SPoul-Henning Kamp 455516ad423SPoul-Henning Kamp static int 456516ad423SPoul-Henning Kamp giant_kqfilter(struct cdev *dev, struct knote *kn) 457516ad423SPoul-Henning Kamp { 458aeeb4202SKonstantin Belousov struct cdevsw *dsw; 459516ad423SPoul-Henning Kamp int retval; 460516ad423SPoul-Henning Kamp 461aeeb4202SKonstantin Belousov dsw = dev_refthread(dev); 462aeeb4202SKonstantin Belousov if (dsw == NULL) 463aeeb4202SKonstantin Belousov return (ENXIO); 464516ad423SPoul-Henning Kamp mtx_lock(&Giant); 465aeeb4202SKonstantin Belousov retval = dsw->d_gianttrick->d_kqfilter(dev, kn); 466516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 467aeeb4202SKonstantin Belousov dev_relthread(dev); 468516ad423SPoul-Henning Kamp return (retval); 469516ad423SPoul-Henning Kamp } 470516ad423SPoul-Henning Kamp 471516ad423SPoul-Henning Kamp static int 472cfd7baceSRobert Noland giant_mmap(struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr, int nprot, 4732fa8c8d2SJohn Baldwin vm_memattr_t *memattr) 474516ad423SPoul-Henning Kamp { 475aeeb4202SKonstantin Belousov struct cdevsw *dsw; 476516ad423SPoul-Henning Kamp int retval; 477516ad423SPoul-Henning Kamp 478aeeb4202SKonstantin Belousov dsw = dev_refthread(dev); 479aeeb4202SKonstantin Belousov if (dsw == NULL) 480aeeb4202SKonstantin Belousov return (ENXIO); 481516ad423SPoul-Henning Kamp mtx_lock(&Giant); 482cfd7baceSRobert Noland retval = dsw->d_gianttrick->d_mmap(dev, offset, paddr, nprot, 4832fa8c8d2SJohn Baldwin memattr); 484516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 485aeeb4202SKonstantin Belousov dev_relthread(dev); 486516ad423SPoul-Henning Kamp return (retval); 487516ad423SPoul-Henning Kamp } 488516ad423SPoul-Henning Kamp 48964345f0bSJohn Baldwin static int 49064345f0bSJohn Baldwin giant_mmap_single(struct cdev *dev, vm_ooffset_t *offset, vm_size_t size, 49164345f0bSJohn Baldwin vm_object_t *object, int nprot) 49264345f0bSJohn Baldwin { 49364345f0bSJohn Baldwin struct cdevsw *dsw; 49464345f0bSJohn Baldwin int retval; 49564345f0bSJohn Baldwin 49664345f0bSJohn Baldwin dsw = dev_refthread(dev); 49764345f0bSJohn Baldwin if (dsw == NULL) 49864345f0bSJohn Baldwin return (ENXIO); 49964345f0bSJohn Baldwin mtx_lock(&Giant); 50064345f0bSJohn Baldwin retval = dsw->d_gianttrick->d_mmap_single(dev, offset, size, object, 50164345f0bSJohn Baldwin nprot); 50264345f0bSJohn Baldwin mtx_unlock(&Giant); 50364345f0bSJohn Baldwin dev_relthread(dev); 50464345f0bSJohn Baldwin return (retval); 50564345f0bSJohn Baldwin } 506516ad423SPoul-Henning Kamp 50748504cc2SKonstantin Belousov static void 508*d2ba618aSKonstantin Belousov notify(struct cdev *dev, const char *ev, int flags) 50948504cc2SKonstantin Belousov { 51048504cc2SKonstantin Belousov static const char prefix[] = "cdev="; 51148504cc2SKonstantin Belousov char *data; 51248504cc2SKonstantin Belousov int namelen; 51348504cc2SKonstantin Belousov 51448504cc2SKonstantin Belousov if (cold) 51548504cc2SKonstantin Belousov return; 51648504cc2SKonstantin Belousov namelen = strlen(dev->si_name); 517*d2ba618aSKonstantin Belousov data = malloc(namelen + sizeof(prefix), M_TEMP, 518*d2ba618aSKonstantin Belousov (flags & MAKEDEV_NOWAIT) ? M_NOWAIT : M_WAITOK); 5199995e57bSAttilio Rao if (data == NULL) 5209995e57bSAttilio Rao return; 52148504cc2SKonstantin Belousov memcpy(data, prefix, sizeof(prefix) - 1); 52248504cc2SKonstantin Belousov memcpy(data + sizeof(prefix) - 1, dev->si_name, namelen + 1); 52348504cc2SKonstantin Belousov devctl_notify("DEVFS", "CDEV", ev, data); 52448504cc2SKonstantin Belousov free(data, M_TEMP); 52548504cc2SKonstantin Belousov } 52648504cc2SKonstantin Belousov 52748504cc2SKonstantin Belousov static void 528*d2ba618aSKonstantin Belousov notify_create(struct cdev *dev, int flags) 52948504cc2SKonstantin Belousov { 53048504cc2SKonstantin Belousov 531*d2ba618aSKonstantin Belousov notify(dev, "CREATE", flags); 53248504cc2SKonstantin Belousov } 53348504cc2SKonstantin Belousov 53448504cc2SKonstantin Belousov static void 53548504cc2SKonstantin Belousov notify_destroy(struct cdev *dev) 53648504cc2SKonstantin Belousov { 53748504cc2SKonstantin Belousov 538*d2ba618aSKonstantin Belousov notify(dev, "DESTROY", MAKEDEV_WAITOK); 53948504cc2SKonstantin Belousov } 54048504cc2SKonstantin Belousov 54189c9c53dSPoul-Henning Kamp static struct cdev * 542bce79dbbSEd Schouten newdev(struct cdevsw *csw, int unit, struct cdev *si) 5433f54a085SPoul-Henning Kamp { 544027b1f71SPoul-Henning Kamp struct cdev *si2; 5453f54a085SPoul-Henning Kamp 546027b1f71SPoul-Henning Kamp mtx_assert(&devmtx, MA_OWNED); 54729d4cb24SEd Schouten if (csw->d_flags & D_NEEDMINOR) { 54829d4cb24SEd Schouten /* We may want to return an existing device */ 549ff7284eeSPoul-Henning Kamp LIST_FOREACH(si2, &csw->d_devs, si_list) { 550bce79dbbSEd Schouten if (dev2unit(si2) == unit) { 5519bc911d4SKonstantin Belousov dev_free_devlocked(si); 552027b1f71SPoul-Henning Kamp return (si2); 5533f54a085SPoul-Henning Kamp } 554027b1f71SPoul-Henning Kamp } 55529d4cb24SEd Schouten } 556bce79dbbSEd Schouten si->si_drv0 = unit; 557e606a3c6SPoul-Henning Kamp si->si_devsw = csw; 558ff7284eeSPoul-Henning Kamp LIST_INSERT_HEAD(&csw->d_devs, si, si_list); 559698bfad7SPoul-Henning Kamp return (si); 560bfbb9ce6SPoul-Henning Kamp } 561bfbb9ce6SPoul-Henning Kamp 5622a3faf2fSPoul-Henning Kamp static void 563cd690b60SPoul-Henning Kamp fini_cdevsw(struct cdevsw *devsw) 564cd690b60SPoul-Henning Kamp { 5651d45c50eSPoul-Henning Kamp struct cdevsw *gt; 566b3d82c03SPoul-Henning Kamp 5671d45c50eSPoul-Henning Kamp if (devsw->d_gianttrick != NULL) { 5681d45c50eSPoul-Henning Kamp gt = devsw->d_gianttrick; 5691d45c50eSPoul-Henning Kamp memcpy(devsw, gt, sizeof *devsw); 570aeeb4202SKonstantin Belousov cdevsw_free_devlocked(gt); 571516ad423SPoul-Henning Kamp devsw->d_gianttrick = NULL; 5721d45c50eSPoul-Henning Kamp } 573652d0472SPoul-Henning Kamp devsw->d_flags &= ~D_INIT; 574b0b03348SPoul-Henning Kamp } 575b0b03348SPoul-Henning Kamp 576*d2ba618aSKonstantin Belousov static int 577*d2ba618aSKonstantin Belousov prep_cdevsw(struct cdevsw *devsw, int flags) 578b0b03348SPoul-Henning Kamp { 579516ad423SPoul-Henning Kamp struct cdevsw *dsw2; 580b0b03348SPoul-Henning Kamp 581aeeb4202SKonstantin Belousov mtx_assert(&devmtx, MA_OWNED); 582aeeb4202SKonstantin Belousov if (devsw->d_flags & D_INIT) 583*d2ba618aSKonstantin Belousov return (1); 584aeeb4202SKonstantin Belousov if (devsw->d_flags & D_NEEDGIANT) { 585aeeb4202SKonstantin Belousov dev_unlock(); 586*d2ba618aSKonstantin Belousov dsw2 = malloc(sizeof *dsw2, M_DEVT, 587*d2ba618aSKonstantin Belousov (flags & MAKEDEV_NOWAIT) ? M_NOWAIT : M_WAITOK); 588a0e78d2eSPoul-Henning Kamp dev_lock(); 589*d2ba618aSKonstantin Belousov if (dsw2 == NULL && !(devsw->d_flags & D_INIT)) 590*d2ba618aSKonstantin Belousov return (0); 591aeeb4202SKonstantin Belousov } else 592aeeb4202SKonstantin Belousov dsw2 = NULL; 593aeeb4202SKonstantin Belousov if (devsw->d_flags & D_INIT) { 594aeeb4202SKonstantin Belousov if (dsw2 != NULL) 595aeeb4202SKonstantin Belousov cdevsw_free_devlocked(dsw2); 596*d2ba618aSKonstantin Belousov return (1); 597aeeb4202SKonstantin Belousov } 598cd690b60SPoul-Henning Kamp 599cfd7baceSRobert Noland if (devsw->d_version != D_VERSION_03) { 600cd690b60SPoul-Henning Kamp printf( 601cd690b60SPoul-Henning Kamp "WARNING: Device driver \"%s\" has wrong version %s\n", 6027d7e053cSAlfred Perlstein devsw->d_name == NULL ? "???" : devsw->d_name, 6037d7e053cSAlfred Perlstein "and is disabled. Recompile KLD module."); 604cd690b60SPoul-Henning Kamp devsw->d_open = dead_open; 605cd690b60SPoul-Henning Kamp devsw->d_close = dead_close; 606cd690b60SPoul-Henning Kamp devsw->d_read = dead_read; 607cd690b60SPoul-Henning Kamp devsw->d_write = dead_write; 608cd690b60SPoul-Henning Kamp devsw->d_ioctl = dead_ioctl; 609cd690b60SPoul-Henning Kamp devsw->d_poll = dead_poll; 610cd690b60SPoul-Henning Kamp devsw->d_mmap = dead_mmap; 611cfd7baceSRobert Noland devsw->d_mmap_single = dead_mmap_single; 612cd690b60SPoul-Henning Kamp devsw->d_strategy = dead_strategy; 613cd690b60SPoul-Henning Kamp devsw->d_dump = dead_dump; 614cd690b60SPoul-Henning Kamp devsw->d_kqfilter = dead_kqfilter; 615cd690b60SPoul-Henning Kamp } 616cd690b60SPoul-Henning Kamp 617516ad423SPoul-Henning Kamp if (devsw->d_flags & D_NEEDGIANT) { 618516ad423SPoul-Henning Kamp if (devsw->d_gianttrick == NULL) { 619516ad423SPoul-Henning Kamp memcpy(dsw2, devsw, sizeof *dsw2); 620516ad423SPoul-Henning Kamp devsw->d_gianttrick = dsw2; 621aeeb4202SKonstantin Belousov dsw2 = NULL; 622aeeb4202SKonstantin Belousov } 623516ad423SPoul-Henning Kamp } 624516ad423SPoul-Henning Kamp 625516ad423SPoul-Henning Kamp #define FIXUP(member, noop, giant) \ 626516ad423SPoul-Henning Kamp do { \ 627516ad423SPoul-Henning Kamp if (devsw->member == NULL) { \ 628516ad423SPoul-Henning Kamp devsw->member = noop; \ 629516ad423SPoul-Henning Kamp } else if (devsw->d_flags & D_NEEDGIANT) \ 630516ad423SPoul-Henning Kamp devsw->member = giant; \ 631516ad423SPoul-Henning Kamp } \ 632516ad423SPoul-Henning Kamp while (0) 633516ad423SPoul-Henning Kamp 634516ad423SPoul-Henning Kamp FIXUP(d_open, null_open, giant_open); 635516ad423SPoul-Henning Kamp FIXUP(d_fdopen, NULL, giant_fdopen); 636516ad423SPoul-Henning Kamp FIXUP(d_close, null_close, giant_close); 637516ad423SPoul-Henning Kamp FIXUP(d_read, no_read, giant_read); 638516ad423SPoul-Henning Kamp FIXUP(d_write, no_write, giant_write); 639516ad423SPoul-Henning Kamp FIXUP(d_ioctl, no_ioctl, giant_ioctl); 640516ad423SPoul-Henning Kamp FIXUP(d_poll, no_poll, giant_poll); 641cfd7baceSRobert Noland FIXUP(d_mmap, no_mmap, giant_mmap); 642516ad423SPoul-Henning Kamp FIXUP(d_strategy, no_strategy, giant_strategy); 643516ad423SPoul-Henning Kamp FIXUP(d_kqfilter, no_kqfilter, giant_kqfilter); 64464345f0bSJohn Baldwin FIXUP(d_mmap_single, no_mmap_single, giant_mmap_single); 645516ad423SPoul-Henning Kamp 646b2941431SPoul-Henning Kamp if (devsw->d_dump == NULL) devsw->d_dump = no_dump; 647cd690b60SPoul-Henning Kamp 648cd690b60SPoul-Henning Kamp LIST_INIT(&devsw->d_devs); 649cd690b60SPoul-Henning Kamp 650cd690b60SPoul-Henning Kamp devsw->d_flags |= D_INIT; 651cd690b60SPoul-Henning Kamp 652aeeb4202SKonstantin Belousov if (dsw2 != NULL) 653aeeb4202SKonstantin Belousov cdevsw_free_devlocked(dsw2); 654*d2ba618aSKonstantin Belousov return (1); 6552a3faf2fSPoul-Henning Kamp } 65611586717SBrian Somers 657cf141467SKonstantin Belousov static struct cdev * 658edde8745SEd Schouten make_dev_credv(int flags, struct cdevsw *devsw, int unit, 659de10ffa5SKonstantin Belousov struct ucred *cr, uid_t uid, 660d26dd2d9SRobert Watson gid_t gid, int mode, const char *fmt, va_list ap) 6612a3faf2fSPoul-Henning Kamp { 66289c9c53dSPoul-Henning Kamp struct cdev *dev; 6632a3faf2fSPoul-Henning Kamp int i; 6642a3faf2fSPoul-Henning Kamp 665*d2ba618aSKonstantin Belousov dev = devfs_alloc(flags); 666*d2ba618aSKonstantin Belousov if (dev == NULL) 667*d2ba618aSKonstantin Belousov return (NULL); 668027b1f71SPoul-Henning Kamp dev_lock(); 669*d2ba618aSKonstantin Belousov if (!prep_cdevsw(devsw, flags)) { 670*d2ba618aSKonstantin Belousov dev_unlock(); 671*d2ba618aSKonstantin Belousov devfs_free(dev); 672*d2ba618aSKonstantin Belousov return (NULL); 673*d2ba618aSKonstantin Belousov } 674edde8745SEd Schouten dev = newdev(devsw, unit, dev); 675de10ffa5SKonstantin Belousov if (flags & MAKEDEV_REF) 676de10ffa5SKonstantin Belousov dev_refl(dev); 67798c469d4SPoul-Henning Kamp if (dev->si_flags & SI_CHEAPCLONE && 678e606a3c6SPoul-Henning Kamp dev->si_flags & SI_NAMED) { 67998c469d4SPoul-Henning Kamp /* 68098c469d4SPoul-Henning Kamp * This is allowed as it removes races and generally 68198c469d4SPoul-Henning Kamp * simplifies cloning devices. 682cd690b60SPoul-Henning Kamp * XXX: still ?? 68398c469d4SPoul-Henning Kamp */ 6849bc911d4SKonstantin Belousov dev_unlock_and_free(); 68598c469d4SPoul-Henning Kamp return (dev); 68698c469d4SPoul-Henning Kamp } 687cd690b60SPoul-Henning Kamp KASSERT(!(dev->si_flags & SI_NAMED), 688ff7284eeSPoul-Henning Kamp ("make_dev() by driver %s on pre-existing device (min=%x, name=%s)", 6896bfa9a2dSEd Schouten devsw->d_name, dev2unit(dev), devtoname(dev))); 690cd690b60SPoul-Henning Kamp 6916334a663SPoul-Henning Kamp i = vsnrprintf(dev->__si_namebuf, sizeof dev->__si_namebuf, 32, fmt, ap); 6926334a663SPoul-Henning Kamp if (i > (sizeof dev->__si_namebuf - 1)) { 6932e4db7cfSPawel Jakub Dawidek printf("WARNING: Device name truncated! (%s)\n", 6946334a663SPoul-Henning Kamp dev->__si_namebuf); 6956334a663SPoul-Henning Kamp } 6961a1b2800SPoul-Henning Kamp 6975ef2707eSPoul-Henning Kamp dev->si_flags |= SI_NAMED; 698d26dd2d9SRobert Watson if (cr != NULL) 699d26dd2d9SRobert Watson dev->si_cred = crhold(cr); 7009477d73eSPoul-Henning Kamp dev->si_uid = uid; 7019477d73eSPoul-Henning Kamp dev->si_gid = gid; 7029477d73eSPoul-Henning Kamp dev->si_mode = mode; 7031744fcd0SJulian Elischer 7049285a87eSPoul-Henning Kamp devfs_create(dev); 70509828ba9SKonstantin Belousov clean_unrhdrl(devfs_inos); 706aeeb4202SKonstantin Belousov dev_unlock_and_free(); 70748504cc2SKonstantin Belousov 708*d2ba618aSKonstantin Belousov notify_create(dev, flags); 70948504cc2SKonstantin Belousov 7103f54a085SPoul-Henning Kamp return (dev); 7113f54a085SPoul-Henning Kamp } 7123f54a085SPoul-Henning Kamp 713d26dd2d9SRobert Watson struct cdev * 714edde8745SEd Schouten make_dev(struct cdevsw *devsw, int unit, uid_t uid, gid_t gid, int mode, 715d26dd2d9SRobert Watson const char *fmt, ...) 716d26dd2d9SRobert Watson { 717d26dd2d9SRobert Watson struct cdev *dev; 718d26dd2d9SRobert Watson va_list ap; 719d26dd2d9SRobert Watson 720d26dd2d9SRobert Watson va_start(ap, fmt); 721edde8745SEd Schouten dev = make_dev_credv(0, devsw, unit, NULL, uid, gid, mode, fmt, ap); 722d26dd2d9SRobert Watson va_end(ap); 723d26dd2d9SRobert Watson return (dev); 724d26dd2d9SRobert Watson } 725d26dd2d9SRobert Watson 726d26dd2d9SRobert Watson struct cdev * 727edde8745SEd Schouten make_dev_cred(struct cdevsw *devsw, int unit, struct ucred *cr, uid_t uid, 728d26dd2d9SRobert Watson gid_t gid, int mode, const char *fmt, ...) 729d26dd2d9SRobert Watson { 730d26dd2d9SRobert Watson struct cdev *dev; 731d26dd2d9SRobert Watson va_list ap; 732d26dd2d9SRobert Watson 733d26dd2d9SRobert Watson va_start(ap, fmt); 734edde8745SEd Schouten dev = make_dev_credv(0, devsw, unit, cr, uid, gid, mode, fmt, ap); 735de10ffa5SKonstantin Belousov va_end(ap); 736de10ffa5SKonstantin Belousov 737de10ffa5SKonstantin Belousov return (dev); 738de10ffa5SKonstantin Belousov } 739de10ffa5SKonstantin Belousov 740de10ffa5SKonstantin Belousov struct cdev * 741edde8745SEd Schouten make_dev_credf(int flags, struct cdevsw *devsw, int unit, 742de10ffa5SKonstantin Belousov struct ucred *cr, uid_t uid, 743de10ffa5SKonstantin Belousov gid_t gid, int mode, const char *fmt, ...) 744de10ffa5SKonstantin Belousov { 745de10ffa5SKonstantin Belousov struct cdev *dev; 746de10ffa5SKonstantin Belousov va_list ap; 747de10ffa5SKonstantin Belousov 748de10ffa5SKonstantin Belousov va_start(ap, fmt); 749edde8745SEd Schouten dev = make_dev_credv(flags, devsw, unit, cr, uid, gid, mode, 750de10ffa5SKonstantin Belousov fmt, ap); 751d26dd2d9SRobert Watson va_end(ap); 752d26dd2d9SRobert Watson 753d26dd2d9SRobert Watson return (dev); 754d26dd2d9SRobert Watson } 755d26dd2d9SRobert Watson 756e606a3c6SPoul-Henning Kamp static void 757e606a3c6SPoul-Henning Kamp dev_dependsl(struct cdev *pdev, struct cdev *cdev) 758e606a3c6SPoul-Henning Kamp { 759e606a3c6SPoul-Henning Kamp 760e606a3c6SPoul-Henning Kamp cdev->si_parent = pdev; 761e606a3c6SPoul-Henning Kamp cdev->si_flags |= SI_CHILD; 762e606a3c6SPoul-Henning Kamp LIST_INSERT_HEAD(&pdev->si_children, cdev, si_siblings); 763e606a3c6SPoul-Henning Kamp } 764e606a3c6SPoul-Henning Kamp 765e606a3c6SPoul-Henning Kamp 7663344c5a1SPoul-Henning Kamp void 76789c9c53dSPoul-Henning Kamp dev_depends(struct cdev *pdev, struct cdev *cdev) 7683344c5a1SPoul-Henning Kamp { 7693344c5a1SPoul-Henning Kamp 770a0e78d2eSPoul-Henning Kamp dev_lock(); 771e606a3c6SPoul-Henning Kamp dev_dependsl(pdev, cdev); 772a0e78d2eSPoul-Henning Kamp dev_unlock(); 7733344c5a1SPoul-Henning Kamp } 7743344c5a1SPoul-Henning Kamp 77589c9c53dSPoul-Henning Kamp struct cdev * 77689c9c53dSPoul-Henning Kamp make_dev_alias(struct cdev *pdev, const char *fmt, ...) 7773f54a085SPoul-Henning Kamp { 77889c9c53dSPoul-Henning Kamp struct cdev *dev; 7793f54a085SPoul-Henning Kamp va_list ap; 7803f54a085SPoul-Henning Kamp int i; 7813f54a085SPoul-Henning Kamp 782ae95dc62SKonstantin Belousov KASSERT(pdev != NULL, ("NULL pdev")); 783*d2ba618aSKonstantin Belousov dev = devfs_alloc(MAKEDEV_WAITOK); 784a0e78d2eSPoul-Henning Kamp dev_lock(); 7853f54a085SPoul-Henning Kamp dev->si_flags |= SI_ALIAS; 7865ef2707eSPoul-Henning Kamp dev->si_flags |= SI_NAMED; 7873f54a085SPoul-Henning Kamp va_start(ap, fmt); 7886334a663SPoul-Henning Kamp i = vsnrprintf(dev->__si_namebuf, sizeof dev->__si_namebuf, 32, fmt, ap); 7896334a663SPoul-Henning Kamp if (i > (sizeof dev->__si_namebuf - 1)) { 7902e4db7cfSPawel Jakub Dawidek printf("WARNING: Device name truncated! (%s)\n", 7916334a663SPoul-Henning Kamp dev->__si_namebuf); 7926334a663SPoul-Henning Kamp } 7933f54a085SPoul-Henning Kamp va_end(ap); 7943f54a085SPoul-Henning Kamp 7959285a87eSPoul-Henning Kamp devfs_create(dev); 796ae95dc62SKonstantin Belousov dev_dependsl(pdev, dev); 79709828ba9SKonstantin Belousov clean_unrhdrl(devfs_inos); 798a0e78d2eSPoul-Henning Kamp dev_unlock(); 79948504cc2SKonstantin Belousov 800*d2ba618aSKonstantin Belousov notify_create(dev, MAKEDEV_WAITOK); 80148504cc2SKonstantin Belousov 8020ef1c826SPoul-Henning Kamp return (dev); 8030ef1c826SPoul-Henning Kamp } 8040ef1c826SPoul-Henning Kamp 805cd690b60SPoul-Henning Kamp static void 806aa2f6ddcSPoul-Henning Kamp destroy_devl(struct cdev *dev) 807d137acccSPoul-Henning Kamp { 808743cd76aSPoul-Henning Kamp struct cdevsw *csw; 80982f4d640SKonstantin Belousov struct cdev_privdata *p, *p1; 810743cd76aSPoul-Henning Kamp 811aa2f6ddcSPoul-Henning Kamp mtx_assert(&devmtx, MA_OWNED); 812743cd76aSPoul-Henning Kamp KASSERT(dev->si_flags & SI_NAMED, 8136bfa9a2dSEd Schouten ("WARNING: Driver mistake: destroy_dev on %d\n", dev2unit(dev))); 8145ef2707eSPoul-Henning Kamp 8159285a87eSPoul-Henning Kamp devfs_destroy(dev); 816cd690b60SPoul-Henning Kamp 817cd690b60SPoul-Henning Kamp /* Remove name marking */ 818b0b03348SPoul-Henning Kamp dev->si_flags &= ~SI_NAMED; 819b0b03348SPoul-Henning Kamp 820cd690b60SPoul-Henning Kamp /* If we are a child, remove us from the parents list */ 8213344c5a1SPoul-Henning Kamp if (dev->si_flags & SI_CHILD) { 8223344c5a1SPoul-Henning Kamp LIST_REMOVE(dev, si_siblings); 8233344c5a1SPoul-Henning Kamp dev->si_flags &= ~SI_CHILD; 8243344c5a1SPoul-Henning Kamp } 825cd690b60SPoul-Henning Kamp 826cd690b60SPoul-Henning Kamp /* Kill our children */ 8273344c5a1SPoul-Henning Kamp while (!LIST_EMPTY(&dev->si_children)) 828aa2f6ddcSPoul-Henning Kamp destroy_devl(LIST_FIRST(&dev->si_children)); 829cd690b60SPoul-Henning Kamp 830cd690b60SPoul-Henning Kamp /* Remove from clone list */ 831b0b03348SPoul-Henning Kamp if (dev->si_flags & SI_CLONELIST) { 832b0b03348SPoul-Henning Kamp LIST_REMOVE(dev, si_clone); 833b0b03348SPoul-Henning Kamp dev->si_flags &= ~SI_CLONELIST; 834b0b03348SPoul-Henning Kamp } 835cd690b60SPoul-Henning Kamp 836e0c33ad5STor Egge dev->si_refcount++; /* Avoid race with dev_rel() */ 837743cd76aSPoul-Henning Kamp csw = dev->si_devsw; 8381abf2c36SBrian Feldman dev->si_devsw = NULL; /* already NULL for SI_ALIAS */ 8391abf2c36SBrian Feldman while (csw != NULL && csw->d_purge != NULL && dev->si_threadcount) { 840743cd76aSPoul-Henning Kamp csw->d_purge(dev); 841743cd76aSPoul-Henning Kamp msleep(csw, &devmtx, PRIBIO, "devprg", hz/10); 842d595182fSPoul-Henning Kamp if (dev->si_threadcount) 843d595182fSPoul-Henning Kamp printf("Still %lu threads in %s\n", 844d595182fSPoul-Henning Kamp dev->si_threadcount, devtoname(dev)); 845743cd76aSPoul-Henning Kamp } 846e0c33ad5STor Egge while (dev->si_threadcount != 0) { 847e0c33ad5STor Egge /* Use unique dummy wait ident */ 848e0c33ad5STor Egge msleep(&csw, &devmtx, PRIBIO, "devdrn", hz / 10); 849e0c33ad5STor Egge } 850743cd76aSPoul-Henning Kamp 85182f4d640SKonstantin Belousov dev_unlock(); 85248504cc2SKonstantin Belousov notify_destroy(dev); 85382f4d640SKonstantin Belousov mtx_lock(&cdevpriv_mtx); 85405427aafSKonstantin Belousov LIST_FOREACH_SAFE(p, &cdev2priv(dev)->cdp_fdpriv, cdpd_list, p1) { 85582f4d640SKonstantin Belousov devfs_destroy_cdevpriv(p); 85682f4d640SKonstantin Belousov mtx_lock(&cdevpriv_mtx); 85782f4d640SKonstantin Belousov } 85882f4d640SKonstantin Belousov mtx_unlock(&cdevpriv_mtx); 85982f4d640SKonstantin Belousov dev_lock(); 86048504cc2SKonstantin Belousov 861743cd76aSPoul-Henning Kamp dev->si_drv1 = 0; 862743cd76aSPoul-Henning Kamp dev->si_drv2 = 0; 863743cd76aSPoul-Henning Kamp bzero(&dev->__si_u, sizeof(dev->__si_u)); 864743cd76aSPoul-Henning Kamp 865cd690b60SPoul-Henning Kamp if (!(dev->si_flags & SI_ALIAS)) { 866cd690b60SPoul-Henning Kamp /* Remove from cdevsw list */ 867cd690b60SPoul-Henning Kamp LIST_REMOVE(dev, si_list); 868cd690b60SPoul-Henning Kamp 869e606a3c6SPoul-Henning Kamp /* If cdevsw has no more struct cdev *'s, clean it */ 870de10ffa5SKonstantin Belousov if (LIST_EMPTY(&csw->d_devs)) { 871a5993c33SPoul-Henning Kamp fini_cdevsw(csw); 872de10ffa5SKonstantin Belousov wakeup(&csw->d_devs); 873de10ffa5SKonstantin Belousov } 874cd690b60SPoul-Henning Kamp } 8755ef2707eSPoul-Henning Kamp dev->si_flags &= ~SI_ALIAS; 876e0c33ad5STor Egge dev->si_refcount--; /* Avoid race with dev_rel() */ 877743cd76aSPoul-Henning Kamp 878cd690b60SPoul-Henning Kamp if (dev->si_refcount > 0) { 879cd690b60SPoul-Henning Kamp LIST_INSERT_HEAD(&dead_cdevsw.d_devs, dev, si_list); 880cd690b60SPoul-Henning Kamp } else { 8819bc911d4SKonstantin Belousov dev_free_devlocked(dev); 882d137acccSPoul-Henning Kamp } 883cd690b60SPoul-Henning Kamp } 884cd690b60SPoul-Henning Kamp 885cd690b60SPoul-Henning Kamp void 88689c9c53dSPoul-Henning Kamp destroy_dev(struct cdev *dev) 887cd690b60SPoul-Henning Kamp { 888cd690b60SPoul-Henning Kamp 889b7a813fcSKonstantin Belousov WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, "destroy_dev"); 890a0e78d2eSPoul-Henning Kamp dev_lock(); 891aa2f6ddcSPoul-Henning Kamp destroy_devl(dev); 8929bc911d4SKonstantin Belousov dev_unlock_and_free(); 893cd690b60SPoul-Henning Kamp } 894d137acccSPoul-Henning Kamp 895c32cc149SBruce Evans const char * 89689c9c53dSPoul-Henning Kamp devtoname(struct cdev *dev) 897b8e49f68SBill Fumerola { 898b8e49f68SBill Fumerola 899b8e49f68SBill Fumerola return (dev->si_name); 900b8e49f68SBill Fumerola } 901db901281SPoul-Henning Kamp 902db901281SPoul-Henning Kamp int 90301de1b13SPoul-Henning Kamp dev_stdclone(char *name, char **namep, const char *stem, int *unit) 904db901281SPoul-Henning Kamp { 905db901281SPoul-Henning Kamp int u, i; 906db901281SPoul-Henning Kamp 907db901281SPoul-Henning Kamp i = strlen(stem); 90856700d46SBrian Somers if (bcmp(stem, name, i) != 0) 90956700d46SBrian Somers return (0); 910db901281SPoul-Henning Kamp if (!isdigit(name[i])) 911db901281SPoul-Henning Kamp return (0); 912db901281SPoul-Henning Kamp u = 0; 91310786074SPoul-Henning Kamp if (name[i] == '0' && isdigit(name[i+1])) 91410786074SPoul-Henning Kamp return (0); 915db901281SPoul-Henning Kamp while (isdigit(name[i])) { 916db901281SPoul-Henning Kamp u *= 10; 917db901281SPoul-Henning Kamp u += name[i++] - '0'; 918db901281SPoul-Henning Kamp } 919dab3d85fSBrian Feldman if (u > 0xffffff) 920dab3d85fSBrian Feldman return (0); 921db901281SPoul-Henning Kamp *unit = u; 922db901281SPoul-Henning Kamp if (namep) 923db901281SPoul-Henning Kamp *namep = &name[i]; 924db901281SPoul-Henning Kamp if (name[i]) 925db901281SPoul-Henning Kamp return (2); 926db901281SPoul-Henning Kamp return (1); 927db901281SPoul-Henning Kamp } 9288d25eb2cSPoul-Henning Kamp 9298d25eb2cSPoul-Henning Kamp /* 930b0b03348SPoul-Henning Kamp * Helper functions for cloning device drivers. 931b0b03348SPoul-Henning Kamp * 932b0b03348SPoul-Henning Kamp * The objective here is to make it unnecessary for the device drivers to 933b0b03348SPoul-Henning Kamp * use rman or similar to manage their unit number space. Due to the way 934b0b03348SPoul-Henning Kamp * we do "on-demand" devices, using rman or other "private" methods 935b0b03348SPoul-Henning Kamp * will be very tricky to lock down properly once we lock down this file. 936b0b03348SPoul-Henning Kamp * 9379a98ae94SLukas Ertl * Instead we give the drivers these routines which puts the struct cdev *'s 9389a98ae94SLukas Ertl * that are to be managed on their own list, and gives the driver the ability 939b0b03348SPoul-Henning Kamp * to ask for the first free unit number or a given specified unit number. 940b0b03348SPoul-Henning Kamp * 941b0b03348SPoul-Henning Kamp * In addition these routines support paired devices (pty, nmdm and similar) 942b0b03348SPoul-Henning Kamp * by respecting a number of "flag" bits in the minor number. 943b0b03348SPoul-Henning Kamp * 944b0b03348SPoul-Henning Kamp */ 945b0b03348SPoul-Henning Kamp 946b0b03348SPoul-Henning Kamp struct clonedevs { 947b0b03348SPoul-Henning Kamp LIST_HEAD(,cdev) head; 948b0b03348SPoul-Henning Kamp }; 949b0b03348SPoul-Henning Kamp 9509397290eSPoul-Henning Kamp void 9519397290eSPoul-Henning Kamp clone_setup(struct clonedevs **cdp) 9529397290eSPoul-Henning Kamp { 9539397290eSPoul-Henning Kamp 9549397290eSPoul-Henning Kamp *cdp = malloc(sizeof **cdp, M_DEVBUF, M_WAITOK | M_ZERO); 9559397290eSPoul-Henning Kamp LIST_INIT(&(*cdp)->head); 9569397290eSPoul-Henning Kamp } 9579397290eSPoul-Henning Kamp 958b0b03348SPoul-Henning Kamp int 959cf141467SKonstantin Belousov clone_create(struct clonedevs **cdp, struct cdevsw *csw, int *up, 960cf141467SKonstantin Belousov struct cdev **dp, int extra) 961b0b03348SPoul-Henning Kamp { 962b0b03348SPoul-Henning Kamp struct clonedevs *cd; 963027b1f71SPoul-Henning Kamp struct cdev *dev, *ndev, *dl, *de; 964b0b03348SPoul-Henning Kamp int unit, low, u; 965b0b03348SPoul-Henning Kamp 9669397290eSPoul-Henning Kamp KASSERT(*cdp != NULL, 9679397290eSPoul-Henning Kamp ("clone_setup() not called in driver \"%s\"", csw->d_name)); 968b0b03348SPoul-Henning Kamp KASSERT(!(extra & CLONE_UNITMASK), 969b0b03348SPoul-Henning Kamp ("Illegal extra bits (0x%x) in clone_create", extra)); 970b0b03348SPoul-Henning Kamp KASSERT(*up <= CLONE_UNITMASK, 971b0b03348SPoul-Henning Kamp ("Too high unit (0x%x) in clone_create", *up)); 97229d4cb24SEd Schouten KASSERT(csw->d_flags & D_NEEDMINOR, 97329d4cb24SEd Schouten ("clone_create() on cdevsw without minor numbers")); 974b0b03348SPoul-Henning Kamp 975b0b03348SPoul-Henning Kamp 976b0b03348SPoul-Henning Kamp /* 977b0b03348SPoul-Henning Kamp * Search the list for a lot of things in one go: 978b0b03348SPoul-Henning Kamp * A preexisting match is returned immediately. 979b0b03348SPoul-Henning Kamp * The lowest free unit number if we are passed -1, and the place 980b0b03348SPoul-Henning Kamp * in the list where we should insert that new element. 981b0b03348SPoul-Henning Kamp * The place to insert a specified unit number, if applicable 982b0b03348SPoul-Henning Kamp * the end of the list. 983b0b03348SPoul-Henning Kamp */ 984b0b03348SPoul-Henning Kamp unit = *up; 985*d2ba618aSKonstantin Belousov ndev = devfs_alloc(MAKEDEV_WAITOK); 986027b1f71SPoul-Henning Kamp dev_lock(); 987*d2ba618aSKonstantin Belousov prep_cdevsw(csw, MAKEDEV_WAITOK); 9888666b655SPoul-Henning Kamp low = extra; 989b0b03348SPoul-Henning Kamp de = dl = NULL; 9909397290eSPoul-Henning Kamp cd = *cdp; 991b0b03348SPoul-Henning Kamp LIST_FOREACH(dev, &cd->head, si_clone) { 992027b1f71SPoul-Henning Kamp KASSERT(dev->si_flags & SI_CLONELIST, 993027b1f71SPoul-Henning Kamp ("Dev %p(%s) should be on clonelist", dev, dev->si_name)); 994b0b03348SPoul-Henning Kamp u = dev2unit(dev); 995b0b03348SPoul-Henning Kamp if (u == (unit | extra)) { 996b0b03348SPoul-Henning Kamp *dp = dev; 997027b1f71SPoul-Henning Kamp dev_unlock(); 9989bc911d4SKonstantin Belousov devfs_free(ndev); 999b0b03348SPoul-Henning Kamp return (0); 1000b0b03348SPoul-Henning Kamp } 1001b0b03348SPoul-Henning Kamp if (unit == -1 && u == low) { 1002b0b03348SPoul-Henning Kamp low++; 1003b0b03348SPoul-Henning Kamp de = dev; 1004b0b03348SPoul-Henning Kamp continue; 10057bbb3a26SPoul-Henning Kamp } else if (u < (unit | extra)) { 10067bbb3a26SPoul-Henning Kamp de = dev; 10077bbb3a26SPoul-Henning Kamp continue; 10087bbb3a26SPoul-Henning Kamp } else if (u > (unit | extra)) { 1009b0b03348SPoul-Henning Kamp dl = dev; 1010b0b03348SPoul-Henning Kamp break; 1011b0b03348SPoul-Henning Kamp } 1012b0b03348SPoul-Henning Kamp } 1013b0b03348SPoul-Henning Kamp if (unit == -1) 10148666b655SPoul-Henning Kamp unit = low & CLONE_UNITMASK; 1015d3ce8327SEd Schouten dev = newdev(csw, unit | extra, ndev); 1016027b1f71SPoul-Henning Kamp if (dev->si_flags & SI_CLONELIST) { 1017027b1f71SPoul-Henning Kamp printf("dev %p (%s) is on clonelist\n", dev, dev->si_name); 10187bbb3a26SPoul-Henning Kamp printf("unit=%d, low=%d, extra=0x%x\n", unit, low, extra); 1019027b1f71SPoul-Henning Kamp LIST_FOREACH(dev, &cd->head, si_clone) { 1020027b1f71SPoul-Henning Kamp printf("\t%p %s\n", dev, dev->si_name); 1021027b1f71SPoul-Henning Kamp } 1022027b1f71SPoul-Henning Kamp panic("foo"); 1023027b1f71SPoul-Henning Kamp } 1024b0b03348SPoul-Henning Kamp KASSERT(!(dev->si_flags & SI_CLONELIST), 1025027b1f71SPoul-Henning Kamp ("Dev %p(%s) should not be on clonelist", dev, dev->si_name)); 1026b0b03348SPoul-Henning Kamp if (dl != NULL) 1027b0b03348SPoul-Henning Kamp LIST_INSERT_BEFORE(dl, dev, si_clone); 1028b0b03348SPoul-Henning Kamp else if (de != NULL) 1029b0b03348SPoul-Henning Kamp LIST_INSERT_AFTER(de, dev, si_clone); 1030b0b03348SPoul-Henning Kamp else 1031b0b03348SPoul-Henning Kamp LIST_INSERT_HEAD(&cd->head, dev, si_clone); 1032b0b03348SPoul-Henning Kamp dev->si_flags |= SI_CLONELIST; 1033b0b03348SPoul-Henning Kamp *up = unit; 10349bc911d4SKonstantin Belousov dev_unlock_and_free(); 1035b0b03348SPoul-Henning Kamp return (1); 1036b0b03348SPoul-Henning Kamp } 1037b0b03348SPoul-Henning Kamp 1038b0b03348SPoul-Henning Kamp /* 1039b0b03348SPoul-Henning Kamp * Kill everything still on the list. The driver should already have 104089c9c53dSPoul-Henning Kamp * disposed of any softc hung of the struct cdev *'s at this time. 1041b0b03348SPoul-Henning Kamp */ 1042b0b03348SPoul-Henning Kamp void 1043b0b03348SPoul-Henning Kamp clone_cleanup(struct clonedevs **cdp) 1044b0b03348SPoul-Henning Kamp { 1045de10ffa5SKonstantin Belousov struct cdev *dev; 1046de10ffa5SKonstantin Belousov struct cdev_priv *cp; 1047b0b03348SPoul-Henning Kamp struct clonedevs *cd; 1048b0b03348SPoul-Henning Kamp 1049b0b03348SPoul-Henning Kamp cd = *cdp; 1050b0b03348SPoul-Henning Kamp if (cd == NULL) 1051b0b03348SPoul-Henning Kamp return; 1052027b1f71SPoul-Henning Kamp dev_lock(); 1053de10ffa5SKonstantin Belousov while (!LIST_EMPTY(&cd->head)) { 1054de10ffa5SKonstantin Belousov dev = LIST_FIRST(&cd->head); 1055de10ffa5SKonstantin Belousov LIST_REMOVE(dev, si_clone); 1056027b1f71SPoul-Henning Kamp KASSERT(dev->si_flags & SI_CLONELIST, 1057027b1f71SPoul-Henning Kamp ("Dev %p(%s) should be on clonelist", dev, dev->si_name)); 1058de10ffa5SKonstantin Belousov dev->si_flags &= ~SI_CLONELIST; 105905427aafSKonstantin Belousov cp = cdev2priv(dev); 1060de10ffa5SKonstantin Belousov if (!(cp->cdp_flags & CDP_SCHED_DTR)) { 1061de10ffa5SKonstantin Belousov cp->cdp_flags |= CDP_SCHED_DTR; 1062b0b03348SPoul-Henning Kamp KASSERT(dev->si_flags & SI_NAMED, 1063d7cbfc1bSEd Schouten ("Driver has goofed in cloning underways udev %x unit %x", dev2udev(dev), dev2unit(dev))); 1064aa2f6ddcSPoul-Henning Kamp destroy_devl(dev); 1065b0b03348SPoul-Henning Kamp } 1066de10ffa5SKonstantin Belousov } 1067aeeb4202SKonstantin Belousov dev_unlock_and_free(); 1068b0b03348SPoul-Henning Kamp free(cd, M_DEVBUF); 1069b0b03348SPoul-Henning Kamp *cdp = NULL; 1070b0b03348SPoul-Henning Kamp } 1071de10ffa5SKonstantin Belousov 1072de10ffa5SKonstantin Belousov static TAILQ_HEAD(, cdev_priv) dev_ddtr = 1073de10ffa5SKonstantin Belousov TAILQ_HEAD_INITIALIZER(dev_ddtr); 1074de10ffa5SKonstantin Belousov static struct task dev_dtr_task; 1075de10ffa5SKonstantin Belousov 1076de10ffa5SKonstantin Belousov static void 1077de10ffa5SKonstantin Belousov destroy_dev_tq(void *ctx, int pending) 1078de10ffa5SKonstantin Belousov { 1079de10ffa5SKonstantin Belousov struct cdev_priv *cp; 1080de10ffa5SKonstantin Belousov struct cdev *dev; 1081de10ffa5SKonstantin Belousov void (*cb)(void *); 1082de10ffa5SKonstantin Belousov void *cb_arg; 1083de10ffa5SKonstantin Belousov 1084de10ffa5SKonstantin Belousov dev_lock(); 1085de10ffa5SKonstantin Belousov while (!TAILQ_EMPTY(&dev_ddtr)) { 1086de10ffa5SKonstantin Belousov cp = TAILQ_FIRST(&dev_ddtr); 1087de10ffa5SKonstantin Belousov dev = &cp->cdp_c; 1088de10ffa5SKonstantin Belousov KASSERT(cp->cdp_flags & CDP_SCHED_DTR, 1089de10ffa5SKonstantin Belousov ("cdev %p in dev_destroy_tq without CDP_SCHED_DTR", cp)); 1090de10ffa5SKonstantin Belousov TAILQ_REMOVE(&dev_ddtr, cp, cdp_dtr_list); 1091de10ffa5SKonstantin Belousov cb = cp->cdp_dtr_cb; 1092de10ffa5SKonstantin Belousov cb_arg = cp->cdp_dtr_cb_arg; 1093de10ffa5SKonstantin Belousov destroy_devl(dev); 1094aeeb4202SKonstantin Belousov dev_unlock_and_free(); 1095de10ffa5SKonstantin Belousov dev_rel(dev); 1096de10ffa5SKonstantin Belousov if (cb != NULL) 1097de10ffa5SKonstantin Belousov cb(cb_arg); 1098de10ffa5SKonstantin Belousov dev_lock(); 1099de10ffa5SKonstantin Belousov } 1100de10ffa5SKonstantin Belousov dev_unlock(); 1101de10ffa5SKonstantin Belousov } 1102de10ffa5SKonstantin Belousov 11039d53363bSKonstantin Belousov /* 11049d53363bSKonstantin Belousov * devmtx shall be locked on entry. devmtx will be unlocked after 11059d53363bSKonstantin Belousov * function return. 11069d53363bSKonstantin Belousov */ 11079d53363bSKonstantin Belousov static int 11089d53363bSKonstantin Belousov destroy_dev_sched_cbl(struct cdev *dev, void (*cb)(void *), void *arg) 1109de10ffa5SKonstantin Belousov { 1110de10ffa5SKonstantin Belousov struct cdev_priv *cp; 1111de10ffa5SKonstantin Belousov 11129d53363bSKonstantin Belousov mtx_assert(&devmtx, MA_OWNED); 111305427aafSKonstantin Belousov cp = cdev2priv(dev); 1114de10ffa5SKonstantin Belousov if (cp->cdp_flags & CDP_SCHED_DTR) { 1115de10ffa5SKonstantin Belousov dev_unlock(); 1116de10ffa5SKonstantin Belousov return (0); 1117de10ffa5SKonstantin Belousov } 1118de10ffa5SKonstantin Belousov dev_refl(dev); 1119de10ffa5SKonstantin Belousov cp->cdp_flags |= CDP_SCHED_DTR; 1120de10ffa5SKonstantin Belousov cp->cdp_dtr_cb = cb; 1121de10ffa5SKonstantin Belousov cp->cdp_dtr_cb_arg = arg; 1122de10ffa5SKonstantin Belousov TAILQ_INSERT_TAIL(&dev_ddtr, cp, cdp_dtr_list); 1123de10ffa5SKonstantin Belousov dev_unlock(); 1124de10ffa5SKonstantin Belousov taskqueue_enqueue(taskqueue_swi_giant, &dev_dtr_task); 1125de10ffa5SKonstantin Belousov return (1); 1126de10ffa5SKonstantin Belousov } 1127de10ffa5SKonstantin Belousov 1128de10ffa5SKonstantin Belousov int 11299d53363bSKonstantin Belousov destroy_dev_sched_cb(struct cdev *dev, void (*cb)(void *), void *arg) 11309d53363bSKonstantin Belousov { 1131cf141467SKonstantin Belousov 11329d53363bSKonstantin Belousov dev_lock(); 11339d53363bSKonstantin Belousov return (destroy_dev_sched_cbl(dev, cb, arg)); 11349d53363bSKonstantin Belousov } 11359d53363bSKonstantin Belousov 11369d53363bSKonstantin Belousov int 1137de10ffa5SKonstantin Belousov destroy_dev_sched(struct cdev *dev) 1138de10ffa5SKonstantin Belousov { 1139cf141467SKonstantin Belousov 1140de10ffa5SKonstantin Belousov return (destroy_dev_sched_cb(dev, NULL, NULL)); 1141de10ffa5SKonstantin Belousov } 1142de10ffa5SKonstantin Belousov 1143de10ffa5SKonstantin Belousov void 1144de10ffa5SKonstantin Belousov destroy_dev_drain(struct cdevsw *csw) 1145de10ffa5SKonstantin Belousov { 1146de10ffa5SKonstantin Belousov 1147de10ffa5SKonstantin Belousov dev_lock(); 1148de10ffa5SKonstantin Belousov while (!LIST_EMPTY(&csw->d_devs)) { 1149de10ffa5SKonstantin Belousov msleep(&csw->d_devs, &devmtx, PRIBIO, "devscd", hz/10); 1150de10ffa5SKonstantin Belousov } 1151de10ffa5SKonstantin Belousov dev_unlock(); 1152de10ffa5SKonstantin Belousov } 1153de10ffa5SKonstantin Belousov 1154de10ffa5SKonstantin Belousov void 1155de10ffa5SKonstantin Belousov drain_dev_clone_events(void) 1156de10ffa5SKonstantin Belousov { 1157de10ffa5SKonstantin Belousov 1158de10ffa5SKonstantin Belousov sx_xlock(&clone_drain_lock); 1159de10ffa5SKonstantin Belousov sx_xunlock(&clone_drain_lock); 1160de10ffa5SKonstantin Belousov } 1161de10ffa5SKonstantin Belousov 1162de10ffa5SKonstantin Belousov static void 1163de10ffa5SKonstantin Belousov devdtr_init(void *dummy __unused) 1164de10ffa5SKonstantin Belousov { 1165de10ffa5SKonstantin Belousov 1166de10ffa5SKonstantin Belousov TASK_INIT(&dev_dtr_task, 0, destroy_dev_tq, NULL); 1167de10ffa5SKonstantin Belousov } 1168de10ffa5SKonstantin Belousov 1169de10ffa5SKonstantin Belousov SYSINIT(devdtr, SI_SUB_DEVFS, SI_ORDER_SECOND, devdtr_init, NULL); 1170