kern_conf.c revision 201145
111126Sjulian/*- 2103722Sphk * Copyright (c) 1999-2002 Poul-Henning Kamp 311126Sjulian * All rights reserved. 411126Sjulian * 511126Sjulian * Redistribution and use in source and binary forms, with or without 611126Sjulian * modification, are permitted provided that the following conditions 711126Sjulian * are met: 811126Sjulian * 1. Redistributions of source code must retain the above copyright 911126Sjulian * notice, this list of conditions and the following disclaimer. 1011126Sjulian * 2. Redistributions in binary form must reproduce the above copyright 1111126Sjulian * notice, this list of conditions and the following disclaimer in the 1211126Sjulian * documentation and/or other materials provided with the distribution. 1311126Sjulian * 14103722Sphk * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15103722Sphk * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1611126Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17103722Sphk * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1811126Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1911126Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2011126Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2111126Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2211126Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2311126Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2411126Sjulian * SUCH DAMAGE. 2511126Sjulian */ 2611126Sjulian 27116182Sobrien#include <sys/cdefs.h> 28116182Sobrien__FBSDID("$FreeBSD: head/sys/kern/kern_conf.c 201145 2009-12-28 22:56:30Z antoine $"); 29116182Sobrien 3011126Sjulian#include <sys/param.h> 3148936Sphk#include <sys/kernel.h> 3283366Sjulian#include <sys/systm.h> 33178991Skib#include <sys/bus.h> 34111179Sphk#include <sys/bio.h> 3590737Sgreen#include <sys/lock.h> 3690737Sgreen#include <sys/mutex.h> 3736735Sdfr#include <sys/module.h> 3848936Sphk#include <sys/malloc.h> 3911126Sjulian#include <sys/conf.h> 4012954Sjulian#include <sys/vnode.h> 4148936Sphk#include <sys/queue.h> 42120514Sphk#include <sys/poll.h> 43171181Skib#include <sys/sx.h> 4465374Sphk#include <sys/ctype.h> 45147982Srwatson#include <sys/ucred.h> 46171181Skib#include <sys/taskqueue.h> 4749535Sphk#include <machine/stdarg.h> 4811126Sjulian 49149144Sphk#include <fs/devfs/devfs_int.h> 50193275Sjhb#include <vm/vm.h> 51149144Sphk 52131996Sphkstatic MALLOC_DEFINE(M_DEVT, "cdev", "cdev storage"); 5348936Sphk 54150342Sphkstruct mtx devmtx; 55142242Sphkstatic void destroy_devl(struct cdev *dev); 56171188Skibstatic int destroy_dev_sched_cbl(struct cdev *dev, 57171188Skib void (*cb)(void *), void *arg); 58171181Skibstatic struct cdev *make_dev_credv(int flags, 59183382Sed struct cdevsw *devsw, int unit, 60171181Skib struct ucred *cr, uid_t uid, gid_t gid, int mode, const char *fmt, 61171181Skib va_list ap); 62171181Skib 63170950Skibstatic struct cdev_priv_list cdevp_free_list = 64170950Skib TAILQ_HEAD_INITIALIZER(cdevp_free_list); 65177301Skibstatic SLIST_HEAD(free_cdevsw, cdevsw) cdevsw_gt_post_list = 66201145Santoine SLIST_HEAD_INITIALIZER(cdevsw_gt_post_list); 67170950Skib 68135600Sphkvoid 69135600Sphkdev_lock(void) 70126082Sphk{ 71151450Sjhb 72126082Sphk mtx_lock(&devmtx); 73126082Sphk} 74126082Sphk 75177301Skib/* 76177301Skib * Free all the memory collected while the cdev mutex was 77177301Skib * locked. Since devmtx is after the system map mutex, free() cannot 78177301Skib * be called immediately and is postponed until cdev mutex can be 79177301Skib * dropped. 80177301Skib */ 81170950Skibstatic void 82170950Skibdev_unlock_and_free(void) 83170950Skib{ 84177301Skib struct cdev_priv_list cdp_free; 85177301Skib struct free_cdevsw csw_free; 86170950Skib struct cdev_priv *cdp; 87177301Skib struct cdevsw *csw; 88170950Skib 89170950Skib mtx_assert(&devmtx, MA_OWNED); 90177301Skib 91177301Skib /* 92177301Skib * Make the local copy of the list heads while the dev_mtx is 93177301Skib * held. Free it later. 94177301Skib */ 95177301Skib TAILQ_INIT(&cdp_free); 96177301Skib TAILQ_CONCAT(&cdp_free, &cdevp_free_list, cdp_list); 97177301Skib csw_free = cdevsw_gt_post_list; 98177301Skib SLIST_INIT(&cdevsw_gt_post_list); 99177301Skib 100177301Skib mtx_unlock(&devmtx); 101177301Skib 102177301Skib while ((cdp = TAILQ_FIRST(&cdp_free)) != NULL) { 103177301Skib TAILQ_REMOVE(&cdp_free, cdp, cdp_list); 104170950Skib devfs_free(&cdp->cdp_c); 105170950Skib } 106177301Skib while ((csw = SLIST_FIRST(&csw_free)) != NULL) { 107177301Skib SLIST_REMOVE_HEAD(&csw_free, d_postfree_list); 108177301Skib free(csw, M_DEVT); 109177301Skib } 110170950Skib} 111170950Skib 112170950Skibstatic void 113170950Skibdev_free_devlocked(struct cdev *cdev) 114170950Skib{ 115170950Skib struct cdev_priv *cdp; 116170950Skib 117170950Skib mtx_assert(&devmtx, MA_OWNED); 118179828Skib cdp = cdev2priv(cdev); 119170950Skib TAILQ_INSERT_HEAD(&cdevp_free_list, cdp, cdp_list); 120170950Skib} 121170950Skib 122177301Skibstatic void 123177301Skibcdevsw_free_devlocked(struct cdevsw *csw) 124177301Skib{ 125177301Skib 126177301Skib mtx_assert(&devmtx, MA_OWNED); 127177301Skib SLIST_INSERT_HEAD(&cdevsw_gt_post_list, csw, d_postfree_list); 128177301Skib} 129177301Skib 130135600Sphkvoid 131135600Sphkdev_unlock(void) 132126082Sphk{ 133135704Sphk 134126082Sphk mtx_unlock(&devmtx); 135126082Sphk} 136126082Sphk 137126082Sphkvoid 138144385Sphkdev_ref(struct cdev *dev) 139144385Sphk{ 140144385Sphk 141144385Sphk mtx_assert(&devmtx, MA_NOTOWNED); 142144385Sphk mtx_lock(&devmtx); 143144385Sphk dev->si_refcount++; 144144385Sphk mtx_unlock(&devmtx); 145144385Sphk} 146144385Sphk 147144385Sphkvoid 148144384Sphkdev_refl(struct cdev *dev) 149126082Sphk{ 150135704Sphk 151142232Sphk mtx_assert(&devmtx, MA_OWNED); 152126082Sphk dev->si_refcount++; 153126082Sphk} 154126082Sphk 155126082Sphkvoid 156142242Sphkdev_rel(struct cdev *dev) 157126082Sphk{ 158142242Sphk int flag = 0; 159135600Sphk 160136014Sphk mtx_assert(&devmtx, MA_NOTOWNED); 161136014Sphk dev_lock(); 162126082Sphk dev->si_refcount--; 163126082Sphk KASSERT(dev->si_refcount >= 0, 164126082Sphk ("dev_rel(%s) gave negative count", devtoname(dev))); 165150342Sphk#if 0 166142242Sphk if (dev->si_usecount == 0 && 167142242Sphk (dev->si_flags & SI_CHEAPCLONE) && (dev->si_flags & SI_NAMED)) 168150342Sphk ; 169150342Sphk else 170150342Sphk#endif 171154029Sbz if (dev->si_devsw == NULL && dev->si_refcount == 0) { 172126082Sphk LIST_REMOVE(dev, si_list); 173136014Sphk flag = 1; 174136014Sphk } 175136014Sphk dev_unlock(); 176136014Sphk if (flag) 177150342Sphk devfs_free(dev); 178126082Sphk} 179136014Sphk 180135704Sphkstruct cdevsw * 181135704Sphkdev_refthread(struct cdev *dev) 182135704Sphk{ 183135704Sphk struct cdevsw *csw; 184171181Skib struct cdev_priv *cdp; 185126082Sphk 186135704Sphk mtx_assert(&devmtx, MA_NOTOWNED); 187135704Sphk dev_lock(); 188135704Sphk csw = dev->si_devsw; 189171181Skib if (csw != NULL) { 190179828Skib cdp = cdev2priv(dev); 191171181Skib if ((cdp->cdp_flags & CDP_SCHED_DTR) == 0) 192171181Skib dev->si_threadcount++; 193171181Skib else 194171181Skib csw = NULL; 195171181Skib } 196135704Sphk dev_unlock(); 197135704Sphk return (csw); 198135704Sphk} 199135704Sphk 200163529Skibstruct cdevsw * 201163529Skibdevvn_refthread(struct vnode *vp, struct cdev **devp) 202163529Skib{ 203163529Skib struct cdevsw *csw; 204171181Skib struct cdev_priv *cdp; 205163529Skib 206163529Skib mtx_assert(&devmtx, MA_NOTOWNED); 207163529Skib csw = NULL; 208163529Skib dev_lock(); 209163529Skib *devp = vp->v_rdev; 210163529Skib if (*devp != NULL) { 211179828Skib cdp = cdev2priv(*devp); 212171181Skib if ((cdp->cdp_flags & CDP_SCHED_DTR) == 0) { 213171181Skib csw = (*devp)->si_devsw; 214171181Skib if (csw != NULL) 215171181Skib (*devp)->si_threadcount++; 216171181Skib } 217163529Skib } 218163529Skib dev_unlock(); 219163529Skib return (csw); 220163529Skib} 221163529Skib 222135704Sphkvoid 223135704Sphkdev_relthread(struct cdev *dev) 224135704Sphk{ 225135704Sphk 226135704Sphk mtx_assert(&devmtx, MA_NOTOWNED); 227135704Sphk dev_lock(); 228179248Skib KASSERT(dev->si_threadcount > 0, 229179248Skib ("%s threadcount is wrong", dev->si_name)); 230135704Sphk dev->si_threadcount--; 231135704Sphk dev_unlock(); 232135704Sphk} 233135704Sphk 234120514Sphkint 235120514Sphknullop(void) 236120514Sphk{ 23785603Sphk 238120514Sphk return (0); 239120514Sphk} 240120514Sphk 241120514Sphkint 242120514Sphkeopnotsupp(void) 243120514Sphk{ 244120514Sphk 245120514Sphk return (EOPNOTSUPP); 246120514Sphk} 247120514Sphk 248111179Sphkstatic int 249111179Sphkenxio(void) 250111179Sphk{ 251111179Sphk return (ENXIO); 252111179Sphk} 253111179Sphk 254120514Sphkstatic int 255120514Sphkenodev(void) 256120514Sphk{ 257120514Sphk return (ENODEV); 258120514Sphk} 259120514Sphk 260120514Sphk/* Define a dead_cdevsw for use when devices leave unexpectedly. */ 261120514Sphk 262111179Sphk#define dead_open (d_open_t *)enxio 263111179Sphk#define dead_close (d_close_t *)enxio 264111179Sphk#define dead_read (d_read_t *)enxio 265111179Sphk#define dead_write (d_write_t *)enxio 266111179Sphk#define dead_ioctl (d_ioctl_t *)enxio 267120514Sphk#define dead_poll (d_poll_t *)enodev 268120514Sphk#define dead_mmap (d_mmap_t *)enodev 269111179Sphk 270111179Sphkstatic void 271111179Sphkdead_strategy(struct bio *bp) 272111179Sphk{ 273111179Sphk 274111179Sphk biofinish(bp, NULL, ENXIO); 275111179Sphk} 276111179Sphk 277111220Sphk#define dead_dump (dumper_t *)enxio 278111179Sphk#define dead_kqfilter (d_kqfilter_t *)enxio 279193275Sjhb#define dead_mmap_single (d_mmap_single_t *)enodev 280111179Sphk 281111179Sphkstatic struct cdevsw dead_cdevsw = { 282126080Sphk .d_version = D_VERSION, 283126080Sphk .d_flags = D_NEEDGIANT, /* XXX: does dead_strategy need this ? */ 284111815Sphk .d_open = dead_open, 285111815Sphk .d_close = dead_close, 286111815Sphk .d_read = dead_read, 287111815Sphk .d_write = dead_write, 288111815Sphk .d_ioctl = dead_ioctl, 289111815Sphk .d_poll = dead_poll, 290111815Sphk .d_mmap = dead_mmap, 291111815Sphk .d_strategy = dead_strategy, 292111815Sphk .d_name = "dead", 293111815Sphk .d_dump = dead_dump, 294193275Sjhb .d_kqfilter = dead_kqfilter, 295193275Sjhb .d_mmap_single = dead_mmap_single 296111179Sphk}; 297111179Sphk 298120514Sphk/* Default methods if driver does not specify method */ 299111179Sphk 300120514Sphk#define null_open (d_open_t *)nullop 301120514Sphk#define null_close (d_close_t *)nullop 302120514Sphk#define no_read (d_read_t *)enodev 303120514Sphk#define no_write (d_write_t *)enodev 304120514Sphk#define no_ioctl (d_ioctl_t *)enodev 305196615Sjhb#define no_mmap (d_mmap2_t *)enodev 306133741Sjmg#define no_kqfilter (d_kqfilter_t *)enodev 307193275Sjhb#define no_mmap_single (d_mmap_single_t *)enodev 308120514Sphk 309120514Sphkstatic void 310120514Sphkno_strategy(struct bio *bp) 311120514Sphk{ 312120514Sphk 313120514Sphk biofinish(bp, NULL, ENODEV); 314120514Sphk} 315120514Sphk 316120514Sphkstatic int 317130585Sphkno_poll(struct cdev *dev __unused, int events, struct thread *td __unused) 318120514Sphk{ 319120514Sphk 320189450Skib return (poll_no_poll(events)); 321120514Sphk} 322120514Sphk 323120514Sphk#define no_dump (dumper_t *)enodev 324120514Sphk 325149177Sphkstatic int 326149177Sphkgiant_open(struct cdev *dev, int oflags, int devtype, struct thread *td) 327149177Sphk{ 328177301Skib struct cdevsw *dsw; 329149177Sphk int retval; 330149177Sphk 331177301Skib dsw = dev_refthread(dev); 332177301Skib if (dsw == NULL) 333177301Skib return (ENXIO); 334149177Sphk mtx_lock(&Giant); 335177301Skib retval = dsw->d_gianttrick->d_open(dev, oflags, devtype, td); 336149177Sphk mtx_unlock(&Giant); 337177301Skib dev_relthread(dev); 338149177Sphk return (retval); 339149177Sphk} 340149177Sphk 341149177Sphkstatic int 342170152Skibgiant_fdopen(struct cdev *dev, int oflags, struct thread *td, struct file *fp) 343149177Sphk{ 344177301Skib struct cdevsw *dsw; 345149177Sphk int retval; 346149177Sphk 347177301Skib dsw = dev_refthread(dev); 348177301Skib if (dsw == NULL) 349177301Skib return (ENXIO); 350149177Sphk mtx_lock(&Giant); 351177301Skib retval = dsw->d_gianttrick->d_fdopen(dev, oflags, td, fp); 352149177Sphk mtx_unlock(&Giant); 353177301Skib dev_relthread(dev); 354149177Sphk return (retval); 355149177Sphk} 356149177Sphk 357149177Sphkstatic int 358149177Sphkgiant_close(struct cdev *dev, int fflag, int devtype, struct thread *td) 359149177Sphk{ 360177301Skib struct cdevsw *dsw; 361149177Sphk int retval; 362149177Sphk 363177301Skib dsw = dev_refthread(dev); 364177301Skib if (dsw == NULL) 365177301Skib return (ENXIO); 366149177Sphk mtx_lock(&Giant); 367177301Skib retval = dsw->d_gianttrick->d_close(dev, fflag, devtype, td); 368149177Sphk mtx_unlock(&Giant); 369177301Skib dev_relthread(dev); 370149177Sphk return (retval); 371149177Sphk} 372149177Sphk 373149177Sphkstatic void 374149177Sphkgiant_strategy(struct bio *bp) 375149177Sphk{ 376177301Skib struct cdevsw *dsw; 377177301Skib struct cdev *dev; 378149177Sphk 379177301Skib dev = bp->bio_dev; 380177301Skib dsw = dev_refthread(dev); 381177301Skib if (dsw == NULL) { 382177301Skib biofinish(bp, NULL, ENXIO); 383177301Skib return; 384177301Skib } 385149177Sphk mtx_lock(&Giant); 386177301Skib dsw->d_gianttrick->d_strategy(bp); 387149177Sphk mtx_unlock(&Giant); 388177301Skib dev_relthread(dev); 389149177Sphk} 390149177Sphk 391149177Sphkstatic int 392149177Sphkgiant_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct thread *td) 393149177Sphk{ 394177301Skib struct cdevsw *dsw; 395149177Sphk int retval; 396149177Sphk 397177301Skib dsw = dev_refthread(dev); 398177301Skib if (dsw == NULL) 399177301Skib return (ENXIO); 400149177Sphk mtx_lock(&Giant); 401177858Skib retval = dsw->d_gianttrick->d_ioctl(dev, cmd, data, fflag, td); 402149177Sphk mtx_unlock(&Giant); 403177301Skib dev_relthread(dev); 404149177Sphk return (retval); 405149177Sphk} 406149177Sphk 407149177Sphkstatic int 408149177Sphkgiant_read(struct cdev *dev, struct uio *uio, int ioflag) 409149177Sphk{ 410177301Skib struct cdevsw *dsw; 411149177Sphk int retval; 412149177Sphk 413177301Skib dsw = dev_refthread(dev); 414177301Skib if (dsw == NULL) 415177301Skib return (ENXIO); 416149177Sphk mtx_lock(&Giant); 417177858Skib retval = dsw->d_gianttrick->d_read(dev, uio, ioflag); 418149177Sphk mtx_unlock(&Giant); 419177301Skib dev_relthread(dev); 420149177Sphk return (retval); 421149177Sphk} 422149177Sphk 423149177Sphkstatic int 424149177Sphkgiant_write(struct cdev *dev, struct uio *uio, int ioflag) 425149177Sphk{ 426177301Skib struct cdevsw *dsw; 427149177Sphk int retval; 428149177Sphk 429177301Skib dsw = dev_refthread(dev); 430177301Skib if (dsw == NULL) 431177301Skib return (ENXIO); 432149177Sphk mtx_lock(&Giant); 433177301Skib retval = dsw->d_gianttrick->d_write(dev, uio, ioflag); 434149177Sphk mtx_unlock(&Giant); 435177301Skib dev_relthread(dev); 436149177Sphk return (retval); 437149177Sphk} 438149177Sphk 439149177Sphkstatic int 440149177Sphkgiant_poll(struct cdev *dev, int events, struct thread *td) 441149177Sphk{ 442177301Skib struct cdevsw *dsw; 443149177Sphk int retval; 444149177Sphk 445177301Skib dsw = dev_refthread(dev); 446177301Skib if (dsw == NULL) 447177301Skib return (ENXIO); 448149177Sphk mtx_lock(&Giant); 449177301Skib retval = dsw->d_gianttrick->d_poll(dev, events, td); 450149177Sphk mtx_unlock(&Giant); 451177301Skib dev_relthread(dev); 452149177Sphk return (retval); 453149177Sphk} 454149177Sphk 455149177Sphkstatic int 456149177Sphkgiant_kqfilter(struct cdev *dev, struct knote *kn) 457149177Sphk{ 458177301Skib struct cdevsw *dsw; 459149177Sphk int retval; 460149177Sphk 461177301Skib dsw = dev_refthread(dev); 462177301Skib if (dsw == NULL) 463177301Skib return (ENXIO); 464149177Sphk mtx_lock(&Giant); 465177301Skib retval = dsw->d_gianttrick->d_kqfilter(dev, kn); 466149177Sphk mtx_unlock(&Giant); 467177301Skib dev_relthread(dev); 468149177Sphk return (retval); 469149177Sphk} 470149177Sphk 471149177Sphkstatic int 472196615Sjhbgiant_mmap(struct cdev *dev, vm_offset_t offset, vm_paddr_t *paddr, int nprot, 473196615Sjhb vm_memattr_t *memattr) 474149177Sphk{ 475177301Skib struct cdevsw *dsw; 476149177Sphk int retval; 477149177Sphk 478177301Skib dsw = dev_refthread(dev); 479177301Skib if (dsw == NULL) 480177301Skib return (ENXIO); 481149177Sphk mtx_lock(&Giant); 482196615Sjhb if (dsw->d_gianttrick->d_flags & D_MMAP2) 483196615Sjhb retval = dsw->d_gianttrick->d_mmap2(dev, offset, paddr, nprot, 484196615Sjhb memattr); 485196615Sjhb else 486196615Sjhb retval = dsw->d_gianttrick->d_mmap(dev, offset, paddr, nprot); 487149177Sphk mtx_unlock(&Giant); 488177301Skib dev_relthread(dev); 489149177Sphk return (retval); 490149177Sphk} 491149177Sphk 492193275Sjhbstatic int 493193275Sjhbgiant_mmap_single(struct cdev *dev, vm_ooffset_t *offset, vm_size_t size, 494193275Sjhb vm_object_t *object, int nprot) 495193275Sjhb{ 496193275Sjhb struct cdevsw *dsw; 497193275Sjhb int retval; 498149177Sphk 499193275Sjhb dsw = dev_refthread(dev); 500193275Sjhb if (dsw == NULL) 501193275Sjhb return (ENXIO); 502193275Sjhb mtx_lock(&Giant); 503193275Sjhb retval = dsw->d_gianttrick->d_mmap_single(dev, offset, size, object, 504193275Sjhb nprot); 505193275Sjhb mtx_unlock(&Giant); 506193275Sjhb dev_relthread(dev); 507193275Sjhb return (retval); 508193275Sjhb} 509193275Sjhb 510178991Skibstatic void 511178991Skibnotify(struct cdev *dev, const char *ev) 512178991Skib{ 513178991Skib static const char prefix[] = "cdev="; 514178991Skib char *data; 515178991Skib int namelen; 516178991Skib 517178991Skib if (cold) 518178991Skib return; 519178991Skib namelen = strlen(dev->si_name); 520192535Sattilio data = malloc(namelen + sizeof(prefix), M_TEMP, M_NOWAIT); 521192535Sattilio if (data == NULL) 522192535Sattilio return; 523178991Skib memcpy(data, prefix, sizeof(prefix) - 1); 524178991Skib memcpy(data + sizeof(prefix) - 1, dev->si_name, namelen + 1); 525178991Skib devctl_notify("DEVFS", "CDEV", ev, data); 526178991Skib free(data, M_TEMP); 527178991Skib} 528178991Skib 529178991Skibstatic void 530178991Skibnotify_create(struct cdev *dev) 531178991Skib{ 532178991Skib 533178991Skib notify(dev, "CREATE"); 534178991Skib} 535178991Skib 536178991Skibstatic void 537178991Skibnotify_destroy(struct cdev *dev) 538178991Skib{ 539178991Skib 540178991Skib notify(dev, "DESTROY"); 541178991Skib} 542178991Skib 543130585Sphkstatic struct cdev * 544191116Sednewdev(struct cdevsw *csw, int unit, struct cdev *si) 54547028Sphk{ 546140733Sphk struct cdev *si2; 54748936Sphk 548140733Sphk mtx_assert(&devmtx, MA_OWNED); 549179726Sed if (csw->d_flags & D_NEEDMINOR) { 550179726Sed /* We may want to return an existing device */ 551179726Sed LIST_FOREACH(si2, &csw->d_devs, si_list) { 552191116Sed if (dev2unit(si2) == unit) { 553179726Sed dev_free_devlocked(si); 554179726Sed return (si2); 555179726Sed } 556140733Sphk } 55748936Sphk } 558191116Sed si->si_drv0 = unit; 559150342Sphk si->si_devsw = csw; 560144281Sphk LIST_INSERT_HEAD(&csw->d_devs, si, si_list); 561125850Sbde return (si); 56247028Sphk} 56347028Sphk 564125846Sphkstatic void 565144292Sphkfini_cdevsw(struct cdevsw *devsw) 56649535Sphk{ 567149324Sphk struct cdevsw *gt; 56849535Sphk 569149324Sphk if (devsw->d_gianttrick != NULL) { 570149324Sphk gt = devsw->d_gianttrick; 571149324Sphk memcpy(devsw, gt, sizeof *devsw); 572177301Skib cdevsw_free_devlocked(gt); 573149324Sphk devsw->d_gianttrick = NULL; 574149324Sphk } 575126156Sphk devsw->d_flags &= ~D_INIT; 576126082Sphk} 577126082Sphk 578126082Sphkstatic void 579126077Sphkprep_cdevsw(struct cdevsw *devsw) 580126077Sphk{ 581149177Sphk struct cdevsw *dsw2; 582126077Sphk 583177301Skib mtx_assert(&devmtx, MA_OWNED); 584177301Skib if (devsw->d_flags & D_INIT) 585177301Skib return; 586177301Skib if (devsw->d_flags & D_NEEDGIANT) { 587177301Skib dev_unlock(); 588149177Sphk dsw2 = malloc(sizeof *dsw2, M_DEVT, M_WAITOK); 589177301Skib dev_lock(); 590177301Skib } else 591149177Sphk dsw2 = NULL; 592177301Skib if (devsw->d_flags & D_INIT) { 593177301Skib if (dsw2 != NULL) 594177301Skib cdevsw_free_devlocked(dsw2); 595177301Skib return; 596177301Skib } 597126082Sphk 598193275Sjhb if (devsw->d_version != D_VERSION_01 && 599193275Sjhb devsw->d_version != D_VERSION_02) { 600126082Sphk printf( 601126082Sphk "WARNING: Device driver \"%s\" has wrong version %s\n", 602154266Salfred devsw->d_name == NULL ? "???" : devsw->d_name, 603154266Salfred "and is disabled. Recompile KLD module."); 604126082Sphk devsw->d_open = dead_open; 605126082Sphk devsw->d_close = dead_close; 606126082Sphk devsw->d_read = dead_read; 607126082Sphk devsw->d_write = dead_write; 608126082Sphk devsw->d_ioctl = dead_ioctl; 609126082Sphk devsw->d_poll = dead_poll; 610126082Sphk devsw->d_mmap = dead_mmap; 611126082Sphk devsw->d_strategy = dead_strategy; 612126082Sphk devsw->d_dump = dead_dump; 613126082Sphk devsw->d_kqfilter = dead_kqfilter; 614126082Sphk } 615193275Sjhb if (devsw->d_version == D_VERSION_01) 616193275Sjhb devsw->d_mmap_single = NULL; 617126082Sphk 618149177Sphk if (devsw->d_flags & D_NEEDGIANT) { 619149177Sphk if (devsw->d_gianttrick == NULL) { 620149177Sphk memcpy(dsw2, devsw, sizeof *dsw2); 621149177Sphk devsw->d_gianttrick = dsw2; 622196615Sjhb devsw->d_flags |= D_MMAP2; 623177301Skib dsw2 = NULL; 624177301Skib } 625149177Sphk } 626149177Sphk 627149177Sphk#define FIXUP(member, noop, giant) \ 628149177Sphk do { \ 629149177Sphk if (devsw->member == NULL) { \ 630149177Sphk devsw->member = noop; \ 631149177Sphk } else if (devsw->d_flags & D_NEEDGIANT) \ 632149177Sphk devsw->member = giant; \ 633149177Sphk } \ 634149177Sphk while (0) 635149177Sphk 636149177Sphk FIXUP(d_open, null_open, giant_open); 637149177Sphk FIXUP(d_fdopen, NULL, giant_fdopen); 638149177Sphk FIXUP(d_close, null_close, giant_close); 639149177Sphk FIXUP(d_read, no_read, giant_read); 640149177Sphk FIXUP(d_write, no_write, giant_write); 641149177Sphk FIXUP(d_ioctl, no_ioctl, giant_ioctl); 642149177Sphk FIXUP(d_poll, no_poll, giant_poll); 643196615Sjhb FIXUP(d_mmap2, no_mmap, giant_mmap); 644149177Sphk FIXUP(d_strategy, no_strategy, giant_strategy); 645149177Sphk FIXUP(d_kqfilter, no_kqfilter, giant_kqfilter); 646193275Sjhb FIXUP(d_mmap_single, no_mmap_single, giant_mmap_single); 647149177Sphk 648120514Sphk if (devsw->d_dump == NULL) devsw->d_dump = no_dump; 649126082Sphk 650126082Sphk LIST_INIT(&devsw->d_devs); 651126082Sphk 652126082Sphk devsw->d_flags |= D_INIT; 653126082Sphk 654177301Skib if (dsw2 != NULL) 655177301Skib cdevsw_free_devlocked(dsw2); 656125846Sphk} 657111622Sphk 658171181Skibstruct cdev * 659183382Sedmake_dev_credv(int flags, struct cdevsw *devsw, int unit, 660171181Skib struct ucred *cr, uid_t uid, 661147982Srwatson gid_t gid, int mode, const char *fmt, va_list ap) 662125846Sphk{ 663130585Sphk struct cdev *dev; 664125846Sphk int i; 665125846Sphk 666150342Sphk dev = devfs_alloc(); 667140733Sphk dev_lock(); 668177301Skib prep_cdevsw(devsw); 669183382Sed dev = newdev(devsw, unit, dev); 670171181Skib if (flags & MAKEDEV_REF) 671171181Skib dev_refl(dev); 672120529Sphk if (dev->si_flags & SI_CHEAPCLONE && 673150342Sphk dev->si_flags & SI_NAMED) { 674120529Sphk /* 675120529Sphk * This is allowed as it removes races and generally 676120529Sphk * simplifies cloning devices. 677126082Sphk * XXX: still ?? 678120529Sphk */ 679170950Skib dev_unlock_and_free(); 680120529Sphk return (dev); 681120529Sphk } 682126082Sphk KASSERT(!(dev->si_flags & SI_NAMED), 683144281Sphk ("make_dev() by driver %s on pre-existing device (min=%x, name=%s)", 684183397Sed devsw->d_name, dev2unit(dev), devtoname(dev))); 685126082Sphk 686110318Sphk i = vsnrprintf(dev->__si_namebuf, sizeof dev->__si_namebuf, 32, fmt, ap); 687110318Sphk if (i > (sizeof dev->__si_namebuf - 1)) { 688134501Spjd printf("WARNING: Device name truncated! (%s)\n", 689110318Sphk dev->__si_namebuf); 690110318Sphk } 691136947Sphk 69265747Sphk dev->si_flags |= SI_NAMED; 693147982Srwatson if (cr != NULL) 694147982Srwatson dev->si_cred = crhold(cr); 695147982Srwatson else 696147982Srwatson dev->si_cred = NULL; 697144385Sphk dev->si_uid = uid; 698144385Sphk dev->si_gid = gid; 699144385Sphk dev->si_mode = mode; 70050092Sjulian 701111730Sphk devfs_create(dev); 702171202Skib clean_unrhdrl(devfs_inos); 703177301Skib dev_unlock_and_free(); 704178991Skib 705178991Skib notify_create(dev); 706178991Skib 70749535Sphk return (dev); 70849535Sphk} 70949535Sphk 710147982Srwatsonstruct cdev * 711183382Sedmake_dev(struct cdevsw *devsw, int unit, uid_t uid, gid_t gid, int mode, 712147982Srwatson const char *fmt, ...) 713147982Srwatson{ 714147982Srwatson struct cdev *dev; 715147982Srwatson va_list ap; 716147982Srwatson 717147982Srwatson va_start(ap, fmt); 718183382Sed dev = make_dev_credv(0, devsw, unit, NULL, uid, gid, mode, fmt, ap); 719147982Srwatson va_end(ap); 720147982Srwatson return (dev); 721147982Srwatson} 722147982Srwatson 723147982Srwatsonstruct cdev * 724183382Sedmake_dev_cred(struct cdevsw *devsw, int unit, struct ucred *cr, uid_t uid, 725147982Srwatson gid_t gid, int mode, const char *fmt, ...) 726147982Srwatson{ 727147982Srwatson struct cdev *dev; 728147982Srwatson va_list ap; 729147982Srwatson 730147982Srwatson va_start(ap, fmt); 731183382Sed dev = make_dev_credv(0, devsw, unit, cr, uid, gid, mode, fmt, ap); 732147982Srwatson va_end(ap); 733147982Srwatson 734147982Srwatson return (dev); 735147982Srwatson} 736147982Srwatson 737171181Skibstruct cdev * 738183382Sedmake_dev_credf(int flags, struct cdevsw *devsw, int unit, 739171181Skib struct ucred *cr, uid_t uid, 740171181Skib gid_t gid, int mode, const char *fmt, ...) 741171181Skib{ 742171181Skib struct cdev *dev; 743171181Skib va_list ap; 744171181Skib 745171181Skib va_start(ap, fmt); 746183382Sed dev = make_dev_credv(flags, devsw, unit, cr, uid, gid, mode, 747171181Skib fmt, ap); 748171181Skib va_end(ap); 749171181Skib 750171181Skib return (dev); 751171181Skib} 752171181Skib 753150342Sphkstatic void 754150342Sphkdev_dependsl(struct cdev *pdev, struct cdev *cdev) 755150342Sphk{ 756150342Sphk 757150342Sphk cdev->si_parent = pdev; 758150342Sphk cdev->si_flags |= SI_CHILD; 759150342Sphk LIST_INSERT_HEAD(&pdev->si_children, cdev, si_siblings); 760150342Sphk} 761150342Sphk 762150342Sphk 76377215Sphkvoid 764130585Sphkdev_depends(struct cdev *pdev, struct cdev *cdev) 76577215Sphk{ 76677215Sphk 767135600Sphk dev_lock(); 768150342Sphk dev_dependsl(pdev, cdev); 769135600Sphk dev_unlock(); 77077215Sphk} 77177215Sphk 772130585Sphkstruct cdev * 773130585Sphkmake_dev_alias(struct cdev *pdev, const char *fmt, ...) 77464880Sphk{ 775130585Sphk struct cdev *dev; 77664880Sphk va_list ap; 77764880Sphk int i; 77864880Sphk 779180445Skib KASSERT(pdev != NULL, ("NULL pdev")); 780150342Sphk dev = devfs_alloc(); 781135600Sphk dev_lock(); 78264880Sphk dev->si_flags |= SI_ALIAS; 78365747Sphk dev->si_flags |= SI_NAMED; 78464880Sphk va_start(ap, fmt); 785110318Sphk i = vsnrprintf(dev->__si_namebuf, sizeof dev->__si_namebuf, 32, fmt, ap); 786110318Sphk if (i > (sizeof dev->__si_namebuf - 1)) { 787134501Spjd printf("WARNING: Device name truncated! (%s)\n", 788110318Sphk dev->__si_namebuf); 789110318Sphk } 79064880Sphk va_end(ap); 79164880Sphk 792111730Sphk devfs_create(dev); 793180445Skib dev_dependsl(pdev, dev); 794171202Skib clean_unrhdrl(devfs_inos); 795135600Sphk dev_unlock(); 796178991Skib 797178991Skib notify_create(dev); 798178991Skib 79964880Sphk return (dev); 80064880Sphk} 80164880Sphk 802126082Sphkstatic void 803142242Sphkdestroy_devl(struct cdev *dev) 80450549Sphk{ 805135843Sphk struct cdevsw *csw; 806179175Skib struct cdev_privdata *p, *p1; 807135843Sphk 808142242Sphk mtx_assert(&devmtx, MA_OWNED); 809135843Sphk KASSERT(dev->si_flags & SI_NAMED, 810183397Sed ("WARNING: Driver mistake: destroy_dev on %d\n", dev2unit(dev))); 811154029Sbz 812111730Sphk devfs_destroy(dev); 813126082Sphk 814126082Sphk /* Remove name marking */ 815126077Sphk dev->si_flags &= ~SI_NAMED; 816126077Sphk 817126082Sphk /* If we are a child, remove us from the parents list */ 81877215Sphk if (dev->si_flags & SI_CHILD) { 81977215Sphk LIST_REMOVE(dev, si_siblings); 82077215Sphk dev->si_flags &= ~SI_CHILD; 82177215Sphk } 822126082Sphk 823126082Sphk /* Kill our children */ 82477215Sphk while (!LIST_EMPTY(&dev->si_children)) 825142242Sphk destroy_devl(LIST_FIRST(&dev->si_children)); 826126082Sphk 827126082Sphk /* Remove from clone list */ 828126077Sphk if (dev->si_flags & SI_CLONELIST) { 829126077Sphk LIST_REMOVE(dev, si_clone); 830126077Sphk dev->si_flags &= ~SI_CLONELIST; 831126077Sphk } 832126082Sphk 833163328Stegge dev->si_refcount++; /* Avoid race with dev_rel() */ 834135843Sphk csw = dev->si_devsw; 835135934Sgreen dev->si_devsw = NULL; /* already NULL for SI_ALIAS */ 836135934Sgreen while (csw != NULL && csw->d_purge != NULL && dev->si_threadcount) { 837135843Sphk csw->d_purge(dev); 838135843Sphk msleep(csw, &devmtx, PRIBIO, "devprg", hz/10); 839158684Sphk if (dev->si_threadcount) 840158684Sphk printf("Still %lu threads in %s\n", 841158684Sphk dev->si_threadcount, devtoname(dev)); 842135843Sphk } 843163328Stegge while (dev->si_threadcount != 0) { 844163328Stegge /* Use unique dummy wait ident */ 845163328Stegge msleep(&csw, &devmtx, PRIBIO, "devdrn", hz / 10); 846163328Stegge } 847135843Sphk 848179175Skib dev_unlock(); 849178991Skib notify_destroy(dev); 850179175Skib mtx_lock(&cdevpriv_mtx); 851179828Skib LIST_FOREACH_SAFE(p, &cdev2priv(dev)->cdp_fdpriv, cdpd_list, p1) { 852179175Skib devfs_destroy_cdevpriv(p); 853179175Skib mtx_lock(&cdevpriv_mtx); 854179175Skib } 855179175Skib mtx_unlock(&cdevpriv_mtx); 856179175Skib dev_lock(); 857178991Skib 858135843Sphk dev->si_drv1 = 0; 859135843Sphk dev->si_drv2 = 0; 860135843Sphk bzero(&dev->__si_u, sizeof(dev->__si_u)); 861135843Sphk 862126082Sphk if (!(dev->si_flags & SI_ALIAS)) { 863126082Sphk /* Remove from cdevsw list */ 864126082Sphk LIST_REMOVE(dev, si_list); 865126082Sphk 866150342Sphk /* If cdevsw has no more struct cdev *'s, clean it */ 867171181Skib if (LIST_EMPTY(&csw->d_devs)) { 868135844Sphk fini_cdevsw(csw); 869171181Skib wakeup(&csw->d_devs); 870171181Skib } 871126082Sphk } 87265747Sphk dev->si_flags &= ~SI_ALIAS; 873163328Stegge dev->si_refcount--; /* Avoid race with dev_rel() */ 874135843Sphk 875126082Sphk if (dev->si_refcount > 0) { 876126082Sphk LIST_INSERT_HEAD(&dead_cdevsw.d_devs, dev, si_list); 877126082Sphk } else { 878170950Skib dev_free_devlocked(dev); 879126082Sphk } 88050549Sphk} 88150549Sphk 882126082Sphkvoid 883130585Sphkdestroy_dev(struct cdev *dev) 884126082Sphk{ 885126082Sphk 886185373Skib WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, "destroy_dev"); 887135600Sphk dev_lock(); 888171251Skib destroy_devl(dev); 889171251Skib dev_unlock_and_free(); 890126082Sphk} 891126082Sphk 89251225Sbdeconst char * 893130585Sphkdevtoname(struct cdev *dev) 89449982Sbillf{ 89549982Sbillf 89649982Sbillf return (dev->si_name); 89749982Sbillf} 89865374Sphk 89965374Sphkint 90091998Sphkdev_stdclone(char *name, char **namep, const char *stem, int *unit) 90165374Sphk{ 90265374Sphk int u, i; 90365374Sphk 90475519Sbrian i = strlen(stem); 90575519Sbrian if (bcmp(stem, name, i) != 0) 90665374Sphk return (0); 90765374Sphk if (!isdigit(name[i])) 90865374Sphk return (0); 90965374Sphk u = 0; 91086461Sphk if (name[i] == '0' && isdigit(name[i+1])) 91186461Sphk return (0); 91265374Sphk while (isdigit(name[i])) { 91365374Sphk u *= 10; 91465374Sphk u += name[i++] - '0'; 91565374Sphk } 916104523Sgreen if (u > 0xffffff) 917104523Sgreen return (0); 91865374Sphk *unit = u; 91965374Sphk if (namep) 92065374Sphk *namep = &name[i]; 92165374Sphk if (name[i]) 92265374Sphk return (2); 92365374Sphk return (1); 92465374Sphk} 92565632Sphk 92665632Sphk/* 927126077Sphk * Helper functions for cloning device drivers. 928126077Sphk * 929126077Sphk * The objective here is to make it unnecessary for the device drivers to 930126077Sphk * use rman or similar to manage their unit number space. Due to the way 931126077Sphk * we do "on-demand" devices, using rman or other "private" methods 932126077Sphk * will be very tricky to lock down properly once we lock down this file. 933126077Sphk * 934130936Sle * Instead we give the drivers these routines which puts the struct cdev *'s 935130936Sle * that are to be managed on their own list, and gives the driver the ability 936126077Sphk * to ask for the first free unit number or a given specified unit number. 937126077Sphk * 938126077Sphk * In addition these routines support paired devices (pty, nmdm and similar) 939126077Sphk * by respecting a number of "flag" bits in the minor number. 940126077Sphk * 941126077Sphk */ 942126077Sphk 943126077Sphkstruct clonedevs { 944126077Sphk LIST_HEAD(,cdev) head; 945126077Sphk}; 946126077Sphk 947126845Sphkvoid 948126845Sphkclone_setup(struct clonedevs **cdp) 949126845Sphk{ 950126845Sphk 951126845Sphk *cdp = malloc(sizeof **cdp, M_DEVBUF, M_WAITOK | M_ZERO); 952126845Sphk LIST_INIT(&(*cdp)->head); 953126845Sphk} 954126845Sphk 955126077Sphkint 956166438Sbmsclone_create(struct clonedevs **cdp, struct cdevsw *csw, int *up, struct cdev **dp, int extra) 957126077Sphk{ 958126077Sphk struct clonedevs *cd; 959140733Sphk struct cdev *dev, *ndev, *dl, *de; 960126077Sphk int unit, low, u; 961126077Sphk 962126845Sphk KASSERT(*cdp != NULL, 963126845Sphk ("clone_setup() not called in driver \"%s\"", csw->d_name)); 964126077Sphk KASSERT(!(extra & CLONE_UNITMASK), 965126845Sphk ("Illegal extra bits (0x%x) in clone_create", extra)); 966126077Sphk KASSERT(*up <= CLONE_UNITMASK, 967126845Sphk ("Too high unit (0x%x) in clone_create", *up)); 968179726Sed KASSERT(csw->d_flags & D_NEEDMINOR, 969179726Sed ("clone_create() on cdevsw without minor numbers")); 970126077Sphk 971126077Sphk 972126077Sphk /* 973126077Sphk * Search the list for a lot of things in one go: 974126077Sphk * A preexisting match is returned immediately. 975126077Sphk * The lowest free unit number if we are passed -1, and the place 976126077Sphk * in the list where we should insert that new element. 977126077Sphk * The place to insert a specified unit number, if applicable 978126077Sphk * the end of the list. 979126077Sphk */ 980126077Sphk unit = *up; 981150342Sphk ndev = devfs_alloc(); 982140733Sphk dev_lock(); 983177301Skib prep_cdevsw(csw); 984126849Sphk low = extra; 985126077Sphk de = dl = NULL; 986126845Sphk cd = *cdp; 987126077Sphk LIST_FOREACH(dev, &cd->head, si_clone) { 988140733Sphk KASSERT(dev->si_flags & SI_CLONELIST, 989140733Sphk ("Dev %p(%s) should be on clonelist", dev, dev->si_name)); 990126077Sphk u = dev2unit(dev); 991126077Sphk if (u == (unit | extra)) { 992126077Sphk *dp = dev; 993170950Skib dev_unlock(); 994150342Sphk devfs_free(ndev); 995126077Sphk return (0); 996126077Sphk } 997126077Sphk if (unit == -1 && u == low) { 998126077Sphk low++; 999126077Sphk de = dev; 1000126077Sphk continue; 1001150793Sphk } else if (u < (unit | extra)) { 1002150793Sphk de = dev; 1003150793Sphk continue; 1004150793Sphk } else if (u > (unit | extra)) { 1005126077Sphk dl = dev; 1006126077Sphk break; 1007126077Sphk } 1008126077Sphk } 1009126077Sphk if (unit == -1) 1010126849Sphk unit = low & CLONE_UNITMASK; 1011183381Sed dev = newdev(csw, unit | extra, ndev); 1012140733Sphk if (dev->si_flags & SI_CLONELIST) { 1013140733Sphk printf("dev %p (%s) is on clonelist\n", dev, dev->si_name); 1014150793Sphk printf("unit=%d, low=%d, extra=0x%x\n", unit, low, extra); 1015140733Sphk LIST_FOREACH(dev, &cd->head, si_clone) { 1016140733Sphk printf("\t%p %s\n", dev, dev->si_name); 1017140733Sphk } 1018140733Sphk panic("foo"); 1019140733Sphk } 1020126077Sphk KASSERT(!(dev->si_flags & SI_CLONELIST), 1021140733Sphk ("Dev %p(%s) should not be on clonelist", dev, dev->si_name)); 1022126077Sphk if (dl != NULL) 1023126077Sphk LIST_INSERT_BEFORE(dl, dev, si_clone); 1024126077Sphk else if (de != NULL) 1025126077Sphk LIST_INSERT_AFTER(de, dev, si_clone); 1026126077Sphk else 1027126077Sphk LIST_INSERT_HEAD(&cd->head, dev, si_clone); 1028126077Sphk dev->si_flags |= SI_CLONELIST; 1029126077Sphk *up = unit; 1030170950Skib dev_unlock_and_free(); 1031126077Sphk return (1); 1032126077Sphk} 1033126077Sphk 1034126077Sphk/* 1035126077Sphk * Kill everything still on the list. The driver should already have 1036130585Sphk * disposed of any softc hung of the struct cdev *'s at this time. 1037126077Sphk */ 1038126077Sphkvoid 1039126077Sphkclone_cleanup(struct clonedevs **cdp) 1040126077Sphk{ 1041171181Skib struct cdev *dev; 1042171181Skib struct cdev_priv *cp; 1043126077Sphk struct clonedevs *cd; 1044126077Sphk 1045126077Sphk cd = *cdp; 1046126077Sphk if (cd == NULL) 1047126077Sphk return; 1048140733Sphk dev_lock(); 1049171181Skib while (!LIST_EMPTY(&cd->head)) { 1050171181Skib dev = LIST_FIRST(&cd->head); 1051171181Skib LIST_REMOVE(dev, si_clone); 1052140733Sphk KASSERT(dev->si_flags & SI_CLONELIST, 1053140733Sphk ("Dev %p(%s) should be on clonelist", dev, dev->si_name)); 1054171181Skib dev->si_flags &= ~SI_CLONELIST; 1055179828Skib cp = cdev2priv(dev); 1056171181Skib if (!(cp->cdp_flags & CDP_SCHED_DTR)) { 1057171181Skib cp->cdp_flags |= CDP_SCHED_DTR; 1058171181Skib KASSERT(dev->si_flags & SI_NAMED, 1059191115Sed ("Driver has goofed in cloning underways udev %x unit %x", dev2udev(dev), dev2unit(dev))); 1060171181Skib destroy_devl(dev); 1061171181Skib } 1062126077Sphk } 1063177301Skib dev_unlock_and_free(); 1064126077Sphk free(cd, M_DEVBUF); 1065126077Sphk *cdp = NULL; 1066126077Sphk} 1067171181Skib 1068171181Skibstatic TAILQ_HEAD(, cdev_priv) dev_ddtr = 1069171181Skib TAILQ_HEAD_INITIALIZER(dev_ddtr); 1070171181Skibstatic struct task dev_dtr_task; 1071171181Skib 1072171181Skibstatic void 1073171181Skibdestroy_dev_tq(void *ctx, int pending) 1074171181Skib{ 1075171181Skib struct cdev_priv *cp; 1076171181Skib struct cdev *dev; 1077171181Skib void (*cb)(void *); 1078171181Skib void *cb_arg; 1079171181Skib 1080171181Skib dev_lock(); 1081171181Skib while (!TAILQ_EMPTY(&dev_ddtr)) { 1082171181Skib cp = TAILQ_FIRST(&dev_ddtr); 1083171181Skib dev = &cp->cdp_c; 1084171181Skib KASSERT(cp->cdp_flags & CDP_SCHED_DTR, 1085171181Skib ("cdev %p in dev_destroy_tq without CDP_SCHED_DTR", cp)); 1086171181Skib TAILQ_REMOVE(&dev_ddtr, cp, cdp_dtr_list); 1087171181Skib cb = cp->cdp_dtr_cb; 1088171181Skib cb_arg = cp->cdp_dtr_cb_arg; 1089171181Skib destroy_devl(dev); 1090177301Skib dev_unlock_and_free(); 1091171181Skib dev_rel(dev); 1092171181Skib if (cb != NULL) 1093171181Skib cb(cb_arg); 1094171181Skib dev_lock(); 1095171181Skib } 1096171181Skib dev_unlock(); 1097171181Skib} 1098171181Skib 1099171188Skib/* 1100171188Skib * devmtx shall be locked on entry. devmtx will be unlocked after 1101171188Skib * function return. 1102171188Skib */ 1103171188Skibstatic int 1104171188Skibdestroy_dev_sched_cbl(struct cdev *dev, void (*cb)(void *), void *arg) 1105171181Skib{ 1106171181Skib struct cdev_priv *cp; 1107171188Skib 1108171188Skib mtx_assert(&devmtx, MA_OWNED); 1109179828Skib cp = cdev2priv(dev); 1110171181Skib if (cp->cdp_flags & CDP_SCHED_DTR) { 1111171181Skib dev_unlock(); 1112171181Skib return (0); 1113171181Skib } 1114171181Skib dev_refl(dev); 1115171181Skib cp->cdp_flags |= CDP_SCHED_DTR; 1116171181Skib cp->cdp_dtr_cb = cb; 1117171181Skib cp->cdp_dtr_cb_arg = arg; 1118171181Skib TAILQ_INSERT_TAIL(&dev_ddtr, cp, cdp_dtr_list); 1119171181Skib dev_unlock(); 1120171181Skib taskqueue_enqueue(taskqueue_swi_giant, &dev_dtr_task); 1121171181Skib return (1); 1122171181Skib} 1123171181Skib 1124171181Skibint 1125171188Skibdestroy_dev_sched_cb(struct cdev *dev, void (*cb)(void *), void *arg) 1126171188Skib{ 1127171188Skib dev_lock(); 1128171188Skib return (destroy_dev_sched_cbl(dev, cb, arg)); 1129171188Skib} 1130171188Skib 1131171188Skibint 1132171181Skibdestroy_dev_sched(struct cdev *dev) 1133171181Skib{ 1134171181Skib return (destroy_dev_sched_cb(dev, NULL, NULL)); 1135171181Skib} 1136171181Skib 1137171181Skibvoid 1138171181Skibdestroy_dev_drain(struct cdevsw *csw) 1139171181Skib{ 1140171181Skib 1141171181Skib dev_lock(); 1142171181Skib while (!LIST_EMPTY(&csw->d_devs)) { 1143171181Skib msleep(&csw->d_devs, &devmtx, PRIBIO, "devscd", hz/10); 1144171181Skib } 1145171181Skib dev_unlock(); 1146171181Skib} 1147171181Skib 1148171181Skibvoid 1149171181Skibdrain_dev_clone_events(void) 1150171181Skib{ 1151171181Skib 1152171181Skib sx_xlock(&clone_drain_lock); 1153171181Skib sx_xunlock(&clone_drain_lock); 1154171181Skib} 1155171181Skib 1156171181Skibstatic void 1157171181Skibdevdtr_init(void *dummy __unused) 1158171181Skib{ 1159171181Skib 1160171181Skib TASK_INIT(&dev_dtr_task, 0, destroy_dev_tq, NULL); 1161171181Skib} 1162171181Skib 1163171181SkibSYSINIT(devdtr, SI_SUB_DEVFS, SI_ORDER_SECOND, devdtr_init, NULL); 1164