kern_conf.c revision 209244
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 209244 2010-06-17 08:49:31Z ed $"); 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); 58209106Skibstatic int make_dev_credv(int flags, struct cdev **dres, struct cdevsw *devsw, 59209106Skib int unit, struct ucred *cr, uid_t uid, gid_t gid, int mode, const char *fmt, 60171181Skib va_list ap); 61171181Skib 62170950Skibstatic struct cdev_priv_list cdevp_free_list = 63170950Skib TAILQ_HEAD_INITIALIZER(cdevp_free_list); 64177301Skibstatic SLIST_HEAD(free_cdevsw, cdevsw) cdevsw_gt_post_list = 65201145Santoine SLIST_HEAD_INITIALIZER(cdevsw_gt_post_list); 66170950Skib 67135600Sphkvoid 68135600Sphkdev_lock(void) 69126082Sphk{ 70151450Sjhb 71126082Sphk mtx_lock(&devmtx); 72126082Sphk} 73126082Sphk 74177301Skib/* 75177301Skib * Free all the memory collected while the cdev mutex was 76177301Skib * locked. Since devmtx is after the system map mutex, free() cannot 77177301Skib * be called immediately and is postponed until cdev mutex can be 78177301Skib * dropped. 79177301Skib */ 80170950Skibstatic void 81170950Skibdev_unlock_and_free(void) 82170950Skib{ 83177301Skib struct cdev_priv_list cdp_free; 84177301Skib struct free_cdevsw csw_free; 85170950Skib struct cdev_priv *cdp; 86177301Skib struct cdevsw *csw; 87170950Skib 88170950Skib mtx_assert(&devmtx, MA_OWNED); 89177301Skib 90177301Skib /* 91177301Skib * Make the local copy of the list heads while the dev_mtx is 92177301Skib * held. Free it later. 93177301Skib */ 94177301Skib TAILQ_INIT(&cdp_free); 95177301Skib TAILQ_CONCAT(&cdp_free, &cdevp_free_list, cdp_list); 96177301Skib csw_free = cdevsw_gt_post_list; 97177301Skib SLIST_INIT(&cdevsw_gt_post_list); 98177301Skib 99177301Skib mtx_unlock(&devmtx); 100177301Skib 101177301Skib while ((cdp = TAILQ_FIRST(&cdp_free)) != NULL) { 102177301Skib TAILQ_REMOVE(&cdp_free, cdp, cdp_list); 103170950Skib devfs_free(&cdp->cdp_c); 104170950Skib } 105177301Skib while ((csw = SLIST_FIRST(&csw_free)) != NULL) { 106177301Skib SLIST_REMOVE_HEAD(&csw_free, d_postfree_list); 107177301Skib free(csw, M_DEVT); 108177301Skib } 109170950Skib} 110170950Skib 111170950Skibstatic void 112170950Skibdev_free_devlocked(struct cdev *cdev) 113170950Skib{ 114170950Skib struct cdev_priv *cdp; 115170950Skib 116170950Skib mtx_assert(&devmtx, MA_OWNED); 117179828Skib cdp = cdev2priv(cdev); 118170950Skib TAILQ_INSERT_HEAD(&cdevp_free_list, cdp, cdp_list); 119170950Skib} 120170950Skib 121177301Skibstatic void 122177301Skibcdevsw_free_devlocked(struct cdevsw *csw) 123177301Skib{ 124177301Skib 125177301Skib mtx_assert(&devmtx, MA_OWNED); 126177301Skib SLIST_INSERT_HEAD(&cdevsw_gt_post_list, csw, d_postfree_list); 127177301Skib} 128177301Skib 129135600Sphkvoid 130135600Sphkdev_unlock(void) 131126082Sphk{ 132135704Sphk 133126082Sphk mtx_unlock(&devmtx); 134126082Sphk} 135126082Sphk 136126082Sphkvoid 137144385Sphkdev_ref(struct cdev *dev) 138144385Sphk{ 139144385Sphk 140144385Sphk mtx_assert(&devmtx, MA_NOTOWNED); 141144385Sphk mtx_lock(&devmtx); 142144385Sphk dev->si_refcount++; 143144385Sphk mtx_unlock(&devmtx); 144144385Sphk} 145144385Sphk 146144385Sphkvoid 147144384Sphkdev_refl(struct cdev *dev) 148126082Sphk{ 149135704Sphk 150142232Sphk mtx_assert(&devmtx, MA_OWNED); 151126082Sphk dev->si_refcount++; 152126082Sphk} 153126082Sphk 154126082Sphkvoid 155142242Sphkdev_rel(struct cdev *dev) 156126082Sphk{ 157142242Sphk int flag = 0; 158135600Sphk 159136014Sphk mtx_assert(&devmtx, MA_NOTOWNED); 160136014Sphk dev_lock(); 161126082Sphk dev->si_refcount--; 162126082Sphk KASSERT(dev->si_refcount >= 0, 163126082Sphk ("dev_rel(%s) gave negative count", devtoname(dev))); 164150342Sphk#if 0 165142242Sphk if (dev->si_usecount == 0 && 166142242Sphk (dev->si_flags & SI_CHEAPCLONE) && (dev->si_flags & SI_NAMED)) 167150342Sphk ; 168150342Sphk else 169150342Sphk#endif 170154029Sbz if (dev->si_devsw == NULL && dev->si_refcount == 0) { 171126082Sphk LIST_REMOVE(dev, si_list); 172136014Sphk flag = 1; 173136014Sphk } 174136014Sphk dev_unlock(); 175136014Sphk if (flag) 176150342Sphk devfs_free(dev); 177126082Sphk} 178136014Sphk 179135704Sphkstruct cdevsw * 180135704Sphkdev_refthread(struct cdev *dev) 181135704Sphk{ 182135704Sphk struct cdevsw *csw; 183171181Skib struct cdev_priv *cdp; 184126082Sphk 185135704Sphk mtx_assert(&devmtx, MA_NOTOWNED); 186135704Sphk dev_lock(); 187135704Sphk csw = dev->si_devsw; 188171181Skib if (csw != NULL) { 189179828Skib cdp = cdev2priv(dev); 190171181Skib if ((cdp->cdp_flags & CDP_SCHED_DTR) == 0) 191171181Skib dev->si_threadcount++; 192171181Skib else 193171181Skib csw = NULL; 194171181Skib } 195135704Sphk dev_unlock(); 196135704Sphk return (csw); 197135704Sphk} 198135704Sphk 199163529Skibstruct cdevsw * 200163529Skibdevvn_refthread(struct vnode *vp, struct cdev **devp) 201163529Skib{ 202163529Skib struct cdevsw *csw; 203171181Skib struct cdev_priv *cdp; 204163529Skib 205163529Skib mtx_assert(&devmtx, MA_NOTOWNED); 206163529Skib csw = NULL; 207163529Skib dev_lock(); 208163529Skib *devp = vp->v_rdev; 209163529Skib if (*devp != NULL) { 210179828Skib cdp = cdev2priv(*devp); 211171181Skib if ((cdp->cdp_flags & CDP_SCHED_DTR) == 0) { 212171181Skib csw = (*devp)->si_devsw; 213171181Skib if (csw != NULL) 214171181Skib (*devp)->si_threadcount++; 215171181Skib } 216163529Skib } 217163529Skib dev_unlock(); 218163529Skib return (csw); 219163529Skib} 220163529Skib 221135704Sphkvoid 222135704Sphkdev_relthread(struct cdev *dev) 223135704Sphk{ 224135704Sphk 225135704Sphk mtx_assert(&devmtx, MA_NOTOWNED); 226135704Sphk dev_lock(); 227179248Skib KASSERT(dev->si_threadcount > 0, 228179248Skib ("%s threadcount is wrong", dev->si_name)); 229135704Sphk dev->si_threadcount--; 230135704Sphk dev_unlock(); 231135704Sphk} 232135704Sphk 233120514Sphkint 234120514Sphknullop(void) 235120514Sphk{ 23685603Sphk 237120514Sphk return (0); 238120514Sphk} 239120514Sphk 240120514Sphkint 241120514Sphkeopnotsupp(void) 242120514Sphk{ 243120514Sphk 244120514Sphk return (EOPNOTSUPP); 245120514Sphk} 246120514Sphk 247111179Sphkstatic int 248111179Sphkenxio(void) 249111179Sphk{ 250111179Sphk return (ENXIO); 251111179Sphk} 252111179Sphk 253120514Sphkstatic int 254120514Sphkenodev(void) 255120514Sphk{ 256120514Sphk return (ENODEV); 257120514Sphk} 258120514Sphk 259120514Sphk/* Define a dead_cdevsw for use when devices leave unexpectedly. */ 260120514Sphk 261111179Sphk#define dead_open (d_open_t *)enxio 262111179Sphk#define dead_close (d_close_t *)enxio 263111179Sphk#define dead_read (d_read_t *)enxio 264111179Sphk#define dead_write (d_write_t *)enxio 265111179Sphk#define dead_ioctl (d_ioctl_t *)enxio 266120514Sphk#define dead_poll (d_poll_t *)enodev 267120514Sphk#define dead_mmap (d_mmap_t *)enodev 268111179Sphk 269111179Sphkstatic void 270111179Sphkdead_strategy(struct bio *bp) 271111179Sphk{ 272111179Sphk 273111179Sphk biofinish(bp, NULL, ENXIO); 274111179Sphk} 275111179Sphk 276111220Sphk#define dead_dump (dumper_t *)enxio 277111179Sphk#define dead_kqfilter (d_kqfilter_t *)enxio 278193275Sjhb#define dead_mmap_single (d_mmap_single_t *)enodev 279111179Sphk 280111179Sphkstatic struct cdevsw dead_cdevsw = { 281126080Sphk .d_version = D_VERSION, 282126080Sphk .d_flags = D_NEEDGIANT, /* XXX: does dead_strategy need this ? */ 283111815Sphk .d_open = dead_open, 284111815Sphk .d_close = dead_close, 285111815Sphk .d_read = dead_read, 286111815Sphk .d_write = dead_write, 287111815Sphk .d_ioctl = dead_ioctl, 288111815Sphk .d_poll = dead_poll, 289111815Sphk .d_mmap = dead_mmap, 290111815Sphk .d_strategy = dead_strategy, 291111815Sphk .d_name = "dead", 292111815Sphk .d_dump = dead_dump, 293193275Sjhb .d_kqfilter = dead_kqfilter, 294193275Sjhb .d_mmap_single = dead_mmap_single 295111179Sphk}; 296111179Sphk 297120514Sphk/* Default methods if driver does not specify method */ 298111179Sphk 299120514Sphk#define null_open (d_open_t *)nullop 300120514Sphk#define null_close (d_close_t *)nullop 301120514Sphk#define no_read (d_read_t *)enodev 302120514Sphk#define no_write (d_write_t *)enodev 303120514Sphk#define no_ioctl (d_ioctl_t *)enodev 304201223Srnoland#define no_mmap (d_mmap_t *)enodev 305133741Sjmg#define no_kqfilter (d_kqfilter_t *)enodev 306193275Sjhb#define no_mmap_single (d_mmap_single_t *)enodev 307120514Sphk 308120514Sphkstatic void 309120514Sphkno_strategy(struct bio *bp) 310120514Sphk{ 311120514Sphk 312120514Sphk biofinish(bp, NULL, ENODEV); 313120514Sphk} 314120514Sphk 315120514Sphkstatic int 316130585Sphkno_poll(struct cdev *dev __unused, int events, struct thread *td __unused) 317120514Sphk{ 318120514Sphk 319189450Skib return (poll_no_poll(events)); 320120514Sphk} 321120514Sphk 322120514Sphk#define no_dump (dumper_t *)enodev 323120514Sphk 324149177Sphkstatic int 325149177Sphkgiant_open(struct cdev *dev, int oflags, int devtype, struct thread *td) 326149177Sphk{ 327177301Skib struct cdevsw *dsw; 328149177Sphk int retval; 329149177Sphk 330177301Skib dsw = dev_refthread(dev); 331177301Skib if (dsw == NULL) 332177301Skib return (ENXIO); 333149177Sphk mtx_lock(&Giant); 334177301Skib retval = dsw->d_gianttrick->d_open(dev, oflags, devtype, td); 335149177Sphk mtx_unlock(&Giant); 336177301Skib dev_relthread(dev); 337149177Sphk return (retval); 338149177Sphk} 339149177Sphk 340149177Sphkstatic int 341170152Skibgiant_fdopen(struct cdev *dev, int oflags, struct thread *td, struct file *fp) 342149177Sphk{ 343177301Skib struct cdevsw *dsw; 344149177Sphk int retval; 345149177Sphk 346177301Skib dsw = dev_refthread(dev); 347177301Skib if (dsw == NULL) 348177301Skib return (ENXIO); 349149177Sphk mtx_lock(&Giant); 350177301Skib retval = dsw->d_gianttrick->d_fdopen(dev, oflags, td, fp); 351149177Sphk mtx_unlock(&Giant); 352177301Skib dev_relthread(dev); 353149177Sphk return (retval); 354149177Sphk} 355149177Sphk 356149177Sphkstatic int 357149177Sphkgiant_close(struct cdev *dev, int fflag, int devtype, struct thread *td) 358149177Sphk{ 359177301Skib struct cdevsw *dsw; 360149177Sphk int retval; 361149177Sphk 362177301Skib dsw = dev_refthread(dev); 363177301Skib if (dsw == NULL) 364177301Skib return (ENXIO); 365149177Sphk mtx_lock(&Giant); 366177301Skib retval = dsw->d_gianttrick->d_close(dev, fflag, devtype, td); 367149177Sphk mtx_unlock(&Giant); 368177301Skib dev_relthread(dev); 369149177Sphk return (retval); 370149177Sphk} 371149177Sphk 372149177Sphkstatic void 373149177Sphkgiant_strategy(struct bio *bp) 374149177Sphk{ 375177301Skib struct cdevsw *dsw; 376177301Skib struct cdev *dev; 377149177Sphk 378177301Skib dev = bp->bio_dev; 379177301Skib dsw = dev_refthread(dev); 380177301Skib if (dsw == NULL) { 381177301Skib biofinish(bp, NULL, ENXIO); 382177301Skib return; 383177301Skib } 384149177Sphk mtx_lock(&Giant); 385177301Skib dsw->d_gianttrick->d_strategy(bp); 386149177Sphk mtx_unlock(&Giant); 387177301Skib dev_relthread(dev); 388149177Sphk} 389149177Sphk 390149177Sphkstatic int 391149177Sphkgiant_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct thread *td) 392149177Sphk{ 393177301Skib struct cdevsw *dsw; 394149177Sphk int retval; 395149177Sphk 396177301Skib dsw = dev_refthread(dev); 397177301Skib if (dsw == NULL) 398177301Skib return (ENXIO); 399149177Sphk mtx_lock(&Giant); 400177858Skib retval = dsw->d_gianttrick->d_ioctl(dev, cmd, data, fflag, td); 401149177Sphk mtx_unlock(&Giant); 402177301Skib dev_relthread(dev); 403149177Sphk return (retval); 404149177Sphk} 405149177Sphk 406149177Sphkstatic int 407149177Sphkgiant_read(struct cdev *dev, struct uio *uio, int ioflag) 408149177Sphk{ 409177301Skib struct cdevsw *dsw; 410149177Sphk int retval; 411149177Sphk 412177301Skib dsw = dev_refthread(dev); 413177301Skib if (dsw == NULL) 414177301Skib return (ENXIO); 415149177Sphk mtx_lock(&Giant); 416177858Skib retval = dsw->d_gianttrick->d_read(dev, uio, ioflag); 417149177Sphk mtx_unlock(&Giant); 418177301Skib dev_relthread(dev); 419149177Sphk return (retval); 420149177Sphk} 421149177Sphk 422149177Sphkstatic int 423149177Sphkgiant_write(struct cdev *dev, struct uio *uio, int ioflag) 424149177Sphk{ 425177301Skib struct cdevsw *dsw; 426149177Sphk int retval; 427149177Sphk 428177301Skib dsw = dev_refthread(dev); 429177301Skib if (dsw == NULL) 430177301Skib return (ENXIO); 431149177Sphk mtx_lock(&Giant); 432177301Skib retval = dsw->d_gianttrick->d_write(dev, uio, ioflag); 433149177Sphk mtx_unlock(&Giant); 434177301Skib dev_relthread(dev); 435149177Sphk return (retval); 436149177Sphk} 437149177Sphk 438149177Sphkstatic int 439149177Sphkgiant_poll(struct cdev *dev, int events, struct thread *td) 440149177Sphk{ 441177301Skib struct cdevsw *dsw; 442149177Sphk int retval; 443149177Sphk 444177301Skib dsw = dev_refthread(dev); 445177301Skib if (dsw == NULL) 446177301Skib return (ENXIO); 447149177Sphk mtx_lock(&Giant); 448177301Skib retval = dsw->d_gianttrick->d_poll(dev, events, td); 449149177Sphk mtx_unlock(&Giant); 450177301Skib dev_relthread(dev); 451149177Sphk return (retval); 452149177Sphk} 453149177Sphk 454149177Sphkstatic int 455149177Sphkgiant_kqfilter(struct cdev *dev, struct knote *kn) 456149177Sphk{ 457177301Skib struct cdevsw *dsw; 458149177Sphk int retval; 459149177Sphk 460177301Skib dsw = dev_refthread(dev); 461177301Skib if (dsw == NULL) 462177301Skib return (ENXIO); 463149177Sphk mtx_lock(&Giant); 464177301Skib retval = dsw->d_gianttrick->d_kqfilter(dev, kn); 465149177Sphk mtx_unlock(&Giant); 466177301Skib dev_relthread(dev); 467149177Sphk return (retval); 468149177Sphk} 469149177Sphk 470149177Sphkstatic int 471201223Srnolandgiant_mmap(struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr, int nprot, 472196615Sjhb vm_memattr_t *memattr) 473149177Sphk{ 474177301Skib struct cdevsw *dsw; 475149177Sphk int retval; 476149177Sphk 477177301Skib dsw = dev_refthread(dev); 478177301Skib if (dsw == NULL) 479177301Skib return (ENXIO); 480149177Sphk mtx_lock(&Giant); 481201223Srnoland retval = dsw->d_gianttrick->d_mmap(dev, offset, paddr, nprot, 482201223Srnoland memattr); 483149177Sphk mtx_unlock(&Giant); 484177301Skib dev_relthread(dev); 485149177Sphk return (retval); 486149177Sphk} 487149177Sphk 488193275Sjhbstatic int 489193275Sjhbgiant_mmap_single(struct cdev *dev, vm_ooffset_t *offset, vm_size_t size, 490193275Sjhb vm_object_t *object, int nprot) 491193275Sjhb{ 492193275Sjhb struct cdevsw *dsw; 493193275Sjhb int retval; 494149177Sphk 495193275Sjhb dsw = dev_refthread(dev); 496193275Sjhb if (dsw == NULL) 497193275Sjhb return (ENXIO); 498193275Sjhb mtx_lock(&Giant); 499193275Sjhb retval = dsw->d_gianttrick->d_mmap_single(dev, offset, size, object, 500193275Sjhb nprot); 501193275Sjhb mtx_unlock(&Giant); 502193275Sjhb dev_relthread(dev); 503193275Sjhb return (retval); 504193275Sjhb} 505193275Sjhb 506178991Skibstatic void 507207729Skibnotify(struct cdev *dev, const char *ev, int flags) 508178991Skib{ 509178991Skib static const char prefix[] = "cdev="; 510178991Skib char *data; 511209105Skib int namelen, mflags; 512178991Skib 513178991Skib if (cold) 514178991Skib return; 515209105Skib mflags = (flags & MAKEDEV_NOWAIT) ? M_NOWAIT : M_WAITOK; 516178991Skib namelen = strlen(dev->si_name); 517209105Skib data = malloc(namelen + sizeof(prefix), M_TEMP, mflags); 518192535Sattilio if (data == NULL) 519192535Sattilio return; 520178991Skib memcpy(data, prefix, sizeof(prefix) - 1); 521178991Skib memcpy(data + sizeof(prefix) - 1, dev->si_name, namelen + 1); 522209105Skib devctl_notify_f("DEVFS", "CDEV", ev, data, mflags); 523178991Skib free(data, M_TEMP); 524178991Skib} 525178991Skib 526178991Skibstatic void 527207729Skibnotify_create(struct cdev *dev, int flags) 528178991Skib{ 529178991Skib 530207729Skib notify(dev, "CREATE", flags); 531178991Skib} 532178991Skib 533178991Skibstatic void 534178991Skibnotify_destroy(struct cdev *dev) 535178991Skib{ 536178991Skib 537207729Skib notify(dev, "DESTROY", MAKEDEV_WAITOK); 538178991Skib} 539178991Skib 540130585Sphkstatic struct cdev * 541191116Sednewdev(struct cdevsw *csw, int unit, struct cdev *si) 54247028Sphk{ 543140733Sphk struct cdev *si2; 54448936Sphk 545140733Sphk mtx_assert(&devmtx, MA_OWNED); 546179726Sed if (csw->d_flags & D_NEEDMINOR) { 547179726Sed /* We may want to return an existing device */ 548179726Sed LIST_FOREACH(si2, &csw->d_devs, si_list) { 549191116Sed if (dev2unit(si2) == unit) { 550179726Sed dev_free_devlocked(si); 551179726Sed return (si2); 552179726Sed } 553140733Sphk } 55448936Sphk } 555191116Sed si->si_drv0 = unit; 556150342Sphk si->si_devsw = csw; 557144281Sphk LIST_INSERT_HEAD(&csw->d_devs, si, si_list); 558125850Sbde return (si); 55947028Sphk} 56047028Sphk 561125846Sphkstatic void 562144292Sphkfini_cdevsw(struct cdevsw *devsw) 56349535Sphk{ 564149324Sphk struct cdevsw *gt; 56549535Sphk 566149324Sphk if (devsw->d_gianttrick != NULL) { 567149324Sphk gt = devsw->d_gianttrick; 568149324Sphk memcpy(devsw, gt, sizeof *devsw); 569177301Skib cdevsw_free_devlocked(gt); 570149324Sphk devsw->d_gianttrick = NULL; 571149324Sphk } 572126156Sphk devsw->d_flags &= ~D_INIT; 573126082Sphk} 574126082Sphk 575207729Skibstatic int 576207729Skibprep_cdevsw(struct cdevsw *devsw, int flags) 577126077Sphk{ 578149177Sphk struct cdevsw *dsw2; 579126077Sphk 580177301Skib mtx_assert(&devmtx, MA_OWNED); 581177301Skib if (devsw->d_flags & D_INIT) 582209106Skib return (0); 583177301Skib if (devsw->d_flags & D_NEEDGIANT) { 584177301Skib dev_unlock(); 585207729Skib dsw2 = malloc(sizeof *dsw2, M_DEVT, 586207729Skib (flags & MAKEDEV_NOWAIT) ? M_NOWAIT : M_WAITOK); 587177301Skib dev_lock(); 588207729Skib if (dsw2 == NULL && !(devsw->d_flags & D_INIT)) 589209106Skib return (ENOMEM); 590177301Skib } else 591149177Sphk dsw2 = NULL; 592177301Skib if (devsw->d_flags & D_INIT) { 593177301Skib if (dsw2 != NULL) 594177301Skib cdevsw_free_devlocked(dsw2); 595209106Skib return (0); 596177301Skib } 597126082Sphk 598201223Srnoland if (devsw->d_version != D_VERSION_03) { 599126082Sphk printf( 600126082Sphk "WARNING: Device driver \"%s\" has wrong version %s\n", 601154266Salfred devsw->d_name == NULL ? "???" : devsw->d_name, 602154266Salfred "and is disabled. Recompile KLD module."); 603126082Sphk devsw->d_open = dead_open; 604126082Sphk devsw->d_close = dead_close; 605126082Sphk devsw->d_read = dead_read; 606126082Sphk devsw->d_write = dead_write; 607126082Sphk devsw->d_ioctl = dead_ioctl; 608126082Sphk devsw->d_poll = dead_poll; 609126082Sphk devsw->d_mmap = dead_mmap; 610201223Srnoland devsw->d_mmap_single = dead_mmap_single; 611126082Sphk devsw->d_strategy = dead_strategy; 612126082Sphk devsw->d_dump = dead_dump; 613126082Sphk devsw->d_kqfilter = dead_kqfilter; 614126082Sphk } 615126082Sphk 616149177Sphk if (devsw->d_flags & D_NEEDGIANT) { 617149177Sphk if (devsw->d_gianttrick == NULL) { 618149177Sphk memcpy(dsw2, devsw, sizeof *dsw2); 619149177Sphk devsw->d_gianttrick = dsw2; 620177301Skib dsw2 = NULL; 621177301Skib } 622149177Sphk } 623149177Sphk 624149177Sphk#define FIXUP(member, noop, giant) \ 625149177Sphk do { \ 626149177Sphk if (devsw->member == NULL) { \ 627149177Sphk devsw->member = noop; \ 628149177Sphk } else if (devsw->d_flags & D_NEEDGIANT) \ 629149177Sphk devsw->member = giant; \ 630149177Sphk } \ 631149177Sphk while (0) 632149177Sphk 633149177Sphk FIXUP(d_open, null_open, giant_open); 634149177Sphk FIXUP(d_fdopen, NULL, giant_fdopen); 635149177Sphk FIXUP(d_close, null_close, giant_close); 636149177Sphk FIXUP(d_read, no_read, giant_read); 637149177Sphk FIXUP(d_write, no_write, giant_write); 638149177Sphk FIXUP(d_ioctl, no_ioctl, giant_ioctl); 639149177Sphk FIXUP(d_poll, no_poll, giant_poll); 640201223Srnoland FIXUP(d_mmap, no_mmap, giant_mmap); 641149177Sphk FIXUP(d_strategy, no_strategy, giant_strategy); 642149177Sphk FIXUP(d_kqfilter, no_kqfilter, giant_kqfilter); 643193275Sjhb FIXUP(d_mmap_single, no_mmap_single, giant_mmap_single); 644149177Sphk 645120514Sphk if (devsw->d_dump == NULL) devsw->d_dump = no_dump; 646126082Sphk 647126082Sphk LIST_INIT(&devsw->d_devs); 648126082Sphk 649126082Sphk devsw->d_flags |= D_INIT; 650126082Sphk 651177301Skib if (dsw2 != NULL) 652177301Skib cdevsw_free_devlocked(dsw2); 653209106Skib return (0); 654125846Sphk} 655111622Sphk 656209106Skibstatic int 657209106Skibmake_dev_credv(int flags, struct cdev **dres, struct cdevsw *devsw, int unit, 658209106Skib struct ucred *cr, uid_t uid, gid_t gid, int mode, const char *fmt, 659209106Skib va_list ap) 660125846Sphk{ 661130585Sphk struct cdev *dev; 662209106Skib int i, res; 663125846Sphk 664209106Skib KASSERT((flags & MAKEDEV_WAITOK) == 0 || (flags & MAKEDEV_NOWAIT) == 0, 665209106Skib ("make_dev_credv: both WAITOK and NOWAIT specified")); 666207729Skib dev = devfs_alloc(flags); 667207729Skib if (dev == NULL) 668209106Skib return (ENOMEM); 669140733Sphk dev_lock(); 670209106Skib res = prep_cdevsw(devsw, flags); 671209106Skib if (res != 0) { 672207729Skib dev_unlock(); 673207729Skib devfs_free(dev); 674209106Skib return (res); 675207729Skib } 676183382Sed dev = newdev(devsw, unit, dev); 677171181Skib if (flags & MAKEDEV_REF) 678171181Skib dev_refl(dev); 679120529Sphk if (dev->si_flags & SI_CHEAPCLONE && 680150342Sphk dev->si_flags & SI_NAMED) { 681120529Sphk /* 682120529Sphk * This is allowed as it removes races and generally 683120529Sphk * simplifies cloning devices. 684126082Sphk * XXX: still ?? 685120529Sphk */ 686170950Skib dev_unlock_and_free(); 687209106Skib *dres = dev; 688209106Skib return (0); 689120529Sphk } 690126082Sphk KASSERT(!(dev->si_flags & SI_NAMED), 691144281Sphk ("make_dev() by driver %s on pre-existing device (min=%x, name=%s)", 692183397Sed devsw->d_name, dev2unit(dev), devtoname(dev))); 693126082Sphk 694110318Sphk i = vsnrprintf(dev->__si_namebuf, sizeof dev->__si_namebuf, 32, fmt, ap); 695110318Sphk if (i > (sizeof dev->__si_namebuf - 1)) { 696134501Spjd printf("WARNING: Device name truncated! (%s)\n", 697110318Sphk dev->__si_namebuf); 698110318Sphk } 699136947Sphk 70065747Sphk dev->si_flags |= SI_NAMED; 701147982Srwatson if (cr != NULL) 702147982Srwatson dev->si_cred = crhold(cr); 703144385Sphk dev->si_uid = uid; 704144385Sphk dev->si_gid = gid; 705144385Sphk dev->si_mode = mode; 70650092Sjulian 707111730Sphk devfs_create(dev); 708171202Skib clean_unrhdrl(devfs_inos); 709177301Skib dev_unlock_and_free(); 710178991Skib 711207729Skib notify_create(dev, flags); 712178991Skib 713209106Skib *dres = dev; 714209106Skib return (0); 71549535Sphk} 71649535Sphk 717147982Srwatsonstruct cdev * 718183382Sedmake_dev(struct cdevsw *devsw, int unit, uid_t uid, gid_t gid, int mode, 719147982Srwatson const char *fmt, ...) 720147982Srwatson{ 721147982Srwatson struct cdev *dev; 722147982Srwatson va_list ap; 723209106Skib int res; 724147982Srwatson 725147982Srwatson va_start(ap, fmt); 726209106Skib res = make_dev_credv(0, &dev, devsw, unit, NULL, uid, gid, mode, fmt, 727209106Skib ap); 728147982Srwatson va_end(ap); 729209106Skib KASSERT(res == 0 && dev != NULL, ("make_dev: failed make_dev_credv")); 730147982Srwatson return (dev); 731147982Srwatson} 732147982Srwatson 733147982Srwatsonstruct cdev * 734183382Sedmake_dev_cred(struct cdevsw *devsw, int unit, struct ucred *cr, uid_t uid, 735147982Srwatson gid_t gid, int mode, const char *fmt, ...) 736147982Srwatson{ 737147982Srwatson struct cdev *dev; 738147982Srwatson va_list ap; 739209106Skib int res; 740147982Srwatson 741147982Srwatson va_start(ap, fmt); 742209106Skib res = make_dev_credv(0, &dev, devsw, unit, cr, uid, gid, mode, fmt, ap); 743147982Srwatson va_end(ap); 744147982Srwatson 745209106Skib KASSERT(res == 0 && dev != NULL, 746209106Skib ("make_dev_cred: failed make_dev_credv")); 747147982Srwatson return (dev); 748147982Srwatson} 749147982Srwatson 750171181Skibstruct cdev * 751209106Skibmake_dev_credf(int flags, struct cdevsw *devsw, int unit, struct ucred *cr, 752209106Skib uid_t uid, gid_t gid, int mode, const char *fmt, ...) 753171181Skib{ 754171181Skib struct cdev *dev; 755171181Skib va_list ap; 756209106Skib int res; 757171181Skib 758171181Skib va_start(ap, fmt); 759209106Skib res = make_dev_credv(flags, &dev, devsw, unit, cr, uid, gid, mode, 760171181Skib fmt, ap); 761171181Skib va_end(ap); 762171181Skib 763209106Skib KASSERT((flags & MAKEDEV_NOWAIT) != 0 || res == 0, 764209106Skib ("make_dev_credf: failed make_dev_credv")); 765209106Skib return (res == 0 ? dev : NULL); 766171181Skib} 767171181Skib 768209106Skibint 769209244Sedmake_dev_p(int flags, struct cdev **cdev, struct cdevsw *devsw, 770209106Skib struct ucred *cr, uid_t uid, gid_t gid, int mode, const char *fmt, ...) 771209106Skib{ 772209106Skib va_list ap; 773209106Skib int res; 774209106Skib 775209106Skib va_start(ap, fmt); 776209244Sed res = make_dev_credv(flags, cdev, devsw, 0, cr, uid, gid, mode, 777209106Skib fmt, ap); 778209106Skib va_end(ap); 779209106Skib 780209106Skib KASSERT((flags & MAKEDEV_NOWAIT) != 0 || res == 0, 781209237Sjh ("make_dev_p: failed make_dev_credv")); 782209106Skib return (res); 783209106Skib} 784209106Skib 785150342Sphkstatic void 786150342Sphkdev_dependsl(struct cdev *pdev, struct cdev *cdev) 787150342Sphk{ 788150342Sphk 789150342Sphk cdev->si_parent = pdev; 790150342Sphk cdev->si_flags |= SI_CHILD; 791150342Sphk LIST_INSERT_HEAD(&pdev->si_children, cdev, si_siblings); 792150342Sphk} 793150342Sphk 794150342Sphk 79577215Sphkvoid 796130585Sphkdev_depends(struct cdev *pdev, struct cdev *cdev) 79777215Sphk{ 79877215Sphk 799135600Sphk dev_lock(); 800150342Sphk dev_dependsl(pdev, cdev); 801135600Sphk dev_unlock(); 80277215Sphk} 80377215Sphk 804130585Sphkstruct cdev * 805130585Sphkmake_dev_alias(struct cdev *pdev, const char *fmt, ...) 80664880Sphk{ 807130585Sphk struct cdev *dev; 80864880Sphk va_list ap; 80964880Sphk int i; 81064880Sphk 811180445Skib KASSERT(pdev != NULL, ("NULL pdev")); 812207729Skib dev = devfs_alloc(MAKEDEV_WAITOK); 813135600Sphk dev_lock(); 81464880Sphk dev->si_flags |= SI_ALIAS; 81565747Sphk dev->si_flags |= SI_NAMED; 81664880Sphk va_start(ap, fmt); 817110318Sphk i = vsnrprintf(dev->__si_namebuf, sizeof dev->__si_namebuf, 32, fmt, ap); 818110318Sphk if (i > (sizeof dev->__si_namebuf - 1)) { 819134501Spjd printf("WARNING: Device name truncated! (%s)\n", 820110318Sphk dev->__si_namebuf); 821110318Sphk } 82264880Sphk va_end(ap); 82364880Sphk 824111730Sphk devfs_create(dev); 825180445Skib dev_dependsl(pdev, dev); 826171202Skib clean_unrhdrl(devfs_inos); 827135600Sphk dev_unlock(); 828178991Skib 829207729Skib notify_create(dev, MAKEDEV_WAITOK); 830178991Skib 83164880Sphk return (dev); 83264880Sphk} 83364880Sphk 834126082Sphkstatic void 835142242Sphkdestroy_devl(struct cdev *dev) 83650549Sphk{ 837135843Sphk struct cdevsw *csw; 838179175Skib struct cdev_privdata *p, *p1; 839135843Sphk 840142242Sphk mtx_assert(&devmtx, MA_OWNED); 841135843Sphk KASSERT(dev->si_flags & SI_NAMED, 842183397Sed ("WARNING: Driver mistake: destroy_dev on %d\n", dev2unit(dev))); 843154029Sbz 844111730Sphk devfs_destroy(dev); 845126082Sphk 846126082Sphk /* Remove name marking */ 847126077Sphk dev->si_flags &= ~SI_NAMED; 848126077Sphk 849126082Sphk /* If we are a child, remove us from the parents list */ 85077215Sphk if (dev->si_flags & SI_CHILD) { 85177215Sphk LIST_REMOVE(dev, si_siblings); 85277215Sphk dev->si_flags &= ~SI_CHILD; 85377215Sphk } 854126082Sphk 855126082Sphk /* Kill our children */ 85677215Sphk while (!LIST_EMPTY(&dev->si_children)) 857142242Sphk destroy_devl(LIST_FIRST(&dev->si_children)); 858126082Sphk 859126082Sphk /* Remove from clone list */ 860126077Sphk if (dev->si_flags & SI_CLONELIST) { 861126077Sphk LIST_REMOVE(dev, si_clone); 862126077Sphk dev->si_flags &= ~SI_CLONELIST; 863126077Sphk } 864126082Sphk 865163328Stegge dev->si_refcount++; /* Avoid race with dev_rel() */ 866135843Sphk csw = dev->si_devsw; 867135934Sgreen dev->si_devsw = NULL; /* already NULL for SI_ALIAS */ 868135934Sgreen while (csw != NULL && csw->d_purge != NULL && dev->si_threadcount) { 869135843Sphk csw->d_purge(dev); 870135843Sphk msleep(csw, &devmtx, PRIBIO, "devprg", hz/10); 871158684Sphk if (dev->si_threadcount) 872158684Sphk printf("Still %lu threads in %s\n", 873158684Sphk dev->si_threadcount, devtoname(dev)); 874135843Sphk } 875163328Stegge while (dev->si_threadcount != 0) { 876163328Stegge /* Use unique dummy wait ident */ 877163328Stegge msleep(&csw, &devmtx, PRIBIO, "devdrn", hz / 10); 878163328Stegge } 879135843Sphk 880179175Skib dev_unlock(); 881178991Skib notify_destroy(dev); 882179175Skib mtx_lock(&cdevpriv_mtx); 883179828Skib LIST_FOREACH_SAFE(p, &cdev2priv(dev)->cdp_fdpriv, cdpd_list, p1) { 884179175Skib devfs_destroy_cdevpriv(p); 885179175Skib mtx_lock(&cdevpriv_mtx); 886179175Skib } 887179175Skib mtx_unlock(&cdevpriv_mtx); 888179175Skib dev_lock(); 889178991Skib 890135843Sphk dev->si_drv1 = 0; 891135843Sphk dev->si_drv2 = 0; 892135843Sphk bzero(&dev->__si_u, sizeof(dev->__si_u)); 893135843Sphk 894126082Sphk if (!(dev->si_flags & SI_ALIAS)) { 895126082Sphk /* Remove from cdevsw list */ 896126082Sphk LIST_REMOVE(dev, si_list); 897126082Sphk 898150342Sphk /* If cdevsw has no more struct cdev *'s, clean it */ 899171181Skib if (LIST_EMPTY(&csw->d_devs)) { 900135844Sphk fini_cdevsw(csw); 901171181Skib wakeup(&csw->d_devs); 902171181Skib } 903126082Sphk } 90465747Sphk dev->si_flags &= ~SI_ALIAS; 905163328Stegge dev->si_refcount--; /* Avoid race with dev_rel() */ 906135843Sphk 907126082Sphk if (dev->si_refcount > 0) { 908126082Sphk LIST_INSERT_HEAD(&dead_cdevsw.d_devs, dev, si_list); 909126082Sphk } else { 910170950Skib dev_free_devlocked(dev); 911126082Sphk } 91250549Sphk} 91350549Sphk 914126082Sphkvoid 915130585Sphkdestroy_dev(struct cdev *dev) 916126082Sphk{ 917126082Sphk 918185373Skib WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, "destroy_dev"); 919135600Sphk dev_lock(); 920171251Skib destroy_devl(dev); 921171251Skib dev_unlock_and_free(); 922126082Sphk} 923126082Sphk 92451225Sbdeconst char * 925130585Sphkdevtoname(struct cdev *dev) 92649982Sbillf{ 92749982Sbillf 92849982Sbillf return (dev->si_name); 92949982Sbillf} 93065374Sphk 93165374Sphkint 93291998Sphkdev_stdclone(char *name, char **namep, const char *stem, int *unit) 93365374Sphk{ 93465374Sphk int u, i; 93565374Sphk 93675519Sbrian i = strlen(stem); 93775519Sbrian if (bcmp(stem, name, i) != 0) 93865374Sphk return (0); 93965374Sphk if (!isdigit(name[i])) 94065374Sphk return (0); 94165374Sphk u = 0; 94286461Sphk if (name[i] == '0' && isdigit(name[i+1])) 94386461Sphk return (0); 94465374Sphk while (isdigit(name[i])) { 94565374Sphk u *= 10; 94665374Sphk u += name[i++] - '0'; 94765374Sphk } 948104523Sgreen if (u > 0xffffff) 949104523Sgreen return (0); 95065374Sphk *unit = u; 95165374Sphk if (namep) 95265374Sphk *namep = &name[i]; 95365374Sphk if (name[i]) 95465374Sphk return (2); 95565374Sphk return (1); 95665374Sphk} 95765632Sphk 95865632Sphk/* 959126077Sphk * Helper functions for cloning device drivers. 960126077Sphk * 961126077Sphk * The objective here is to make it unnecessary for the device drivers to 962126077Sphk * use rman or similar to manage their unit number space. Due to the way 963126077Sphk * we do "on-demand" devices, using rman or other "private" methods 964126077Sphk * will be very tricky to lock down properly once we lock down this file. 965126077Sphk * 966130936Sle * Instead we give the drivers these routines which puts the struct cdev *'s 967130936Sle * that are to be managed on their own list, and gives the driver the ability 968126077Sphk * to ask for the first free unit number or a given specified unit number. 969126077Sphk * 970126077Sphk * In addition these routines support paired devices (pty, nmdm and similar) 971126077Sphk * by respecting a number of "flag" bits in the minor number. 972126077Sphk * 973126077Sphk */ 974126077Sphk 975126077Sphkstruct clonedevs { 976126077Sphk LIST_HEAD(,cdev) head; 977126077Sphk}; 978126077Sphk 979126845Sphkvoid 980126845Sphkclone_setup(struct clonedevs **cdp) 981126845Sphk{ 982126845Sphk 983126845Sphk *cdp = malloc(sizeof **cdp, M_DEVBUF, M_WAITOK | M_ZERO); 984126845Sphk LIST_INIT(&(*cdp)->head); 985126845Sphk} 986126845Sphk 987126077Sphkint 988204412Skibclone_create(struct clonedevs **cdp, struct cdevsw *csw, int *up, 989204412Skib struct cdev **dp, int extra) 990126077Sphk{ 991126077Sphk struct clonedevs *cd; 992140733Sphk struct cdev *dev, *ndev, *dl, *de; 993126077Sphk int unit, low, u; 994126077Sphk 995126845Sphk KASSERT(*cdp != NULL, 996126845Sphk ("clone_setup() not called in driver \"%s\"", csw->d_name)); 997126077Sphk KASSERT(!(extra & CLONE_UNITMASK), 998126845Sphk ("Illegal extra bits (0x%x) in clone_create", extra)); 999126077Sphk KASSERT(*up <= CLONE_UNITMASK, 1000126845Sphk ("Too high unit (0x%x) in clone_create", *up)); 1001179726Sed KASSERT(csw->d_flags & D_NEEDMINOR, 1002179726Sed ("clone_create() on cdevsw without minor numbers")); 1003126077Sphk 1004126077Sphk 1005126077Sphk /* 1006126077Sphk * Search the list for a lot of things in one go: 1007126077Sphk * A preexisting match is returned immediately. 1008126077Sphk * The lowest free unit number if we are passed -1, and the place 1009126077Sphk * in the list where we should insert that new element. 1010126077Sphk * The place to insert a specified unit number, if applicable 1011126077Sphk * the end of the list. 1012126077Sphk */ 1013126077Sphk unit = *up; 1014207729Skib ndev = devfs_alloc(MAKEDEV_WAITOK); 1015140733Sphk dev_lock(); 1016207729Skib prep_cdevsw(csw, MAKEDEV_WAITOK); 1017126849Sphk low = extra; 1018126077Sphk de = dl = NULL; 1019126845Sphk cd = *cdp; 1020126077Sphk LIST_FOREACH(dev, &cd->head, si_clone) { 1021140733Sphk KASSERT(dev->si_flags & SI_CLONELIST, 1022140733Sphk ("Dev %p(%s) should be on clonelist", dev, dev->si_name)); 1023126077Sphk u = dev2unit(dev); 1024126077Sphk if (u == (unit | extra)) { 1025126077Sphk *dp = dev; 1026170950Skib dev_unlock(); 1027150342Sphk devfs_free(ndev); 1028126077Sphk return (0); 1029126077Sphk } 1030126077Sphk if (unit == -1 && u == low) { 1031126077Sphk low++; 1032126077Sphk de = dev; 1033126077Sphk continue; 1034150793Sphk } else if (u < (unit | extra)) { 1035150793Sphk de = dev; 1036150793Sphk continue; 1037150793Sphk } else if (u > (unit | extra)) { 1038126077Sphk dl = dev; 1039126077Sphk break; 1040126077Sphk } 1041126077Sphk } 1042126077Sphk if (unit == -1) 1043126849Sphk unit = low & CLONE_UNITMASK; 1044183381Sed dev = newdev(csw, unit | extra, ndev); 1045140733Sphk if (dev->si_flags & SI_CLONELIST) { 1046140733Sphk printf("dev %p (%s) is on clonelist\n", dev, dev->si_name); 1047150793Sphk printf("unit=%d, low=%d, extra=0x%x\n", unit, low, extra); 1048140733Sphk LIST_FOREACH(dev, &cd->head, si_clone) { 1049140733Sphk printf("\t%p %s\n", dev, dev->si_name); 1050140733Sphk } 1051140733Sphk panic("foo"); 1052140733Sphk } 1053126077Sphk KASSERT(!(dev->si_flags & SI_CLONELIST), 1054140733Sphk ("Dev %p(%s) should not be on clonelist", dev, dev->si_name)); 1055126077Sphk if (dl != NULL) 1056126077Sphk LIST_INSERT_BEFORE(dl, dev, si_clone); 1057126077Sphk else if (de != NULL) 1058126077Sphk LIST_INSERT_AFTER(de, dev, si_clone); 1059126077Sphk else 1060126077Sphk LIST_INSERT_HEAD(&cd->head, dev, si_clone); 1061126077Sphk dev->si_flags |= SI_CLONELIST; 1062126077Sphk *up = unit; 1063170950Skib dev_unlock_and_free(); 1064126077Sphk return (1); 1065126077Sphk} 1066126077Sphk 1067126077Sphk/* 1068126077Sphk * Kill everything still on the list. The driver should already have 1069130585Sphk * disposed of any softc hung of the struct cdev *'s at this time. 1070126077Sphk */ 1071126077Sphkvoid 1072126077Sphkclone_cleanup(struct clonedevs **cdp) 1073126077Sphk{ 1074171181Skib struct cdev *dev; 1075171181Skib struct cdev_priv *cp; 1076126077Sphk struct clonedevs *cd; 1077126077Sphk 1078126077Sphk cd = *cdp; 1079126077Sphk if (cd == NULL) 1080126077Sphk return; 1081140733Sphk dev_lock(); 1082171181Skib while (!LIST_EMPTY(&cd->head)) { 1083171181Skib dev = LIST_FIRST(&cd->head); 1084171181Skib LIST_REMOVE(dev, si_clone); 1085140733Sphk KASSERT(dev->si_flags & SI_CLONELIST, 1086140733Sphk ("Dev %p(%s) should be on clonelist", dev, dev->si_name)); 1087171181Skib dev->si_flags &= ~SI_CLONELIST; 1088179828Skib cp = cdev2priv(dev); 1089171181Skib if (!(cp->cdp_flags & CDP_SCHED_DTR)) { 1090171181Skib cp->cdp_flags |= CDP_SCHED_DTR; 1091171181Skib KASSERT(dev->si_flags & SI_NAMED, 1092191115Sed ("Driver has goofed in cloning underways udev %x unit %x", dev2udev(dev), dev2unit(dev))); 1093171181Skib destroy_devl(dev); 1094171181Skib } 1095126077Sphk } 1096177301Skib dev_unlock_and_free(); 1097126077Sphk free(cd, M_DEVBUF); 1098126077Sphk *cdp = NULL; 1099126077Sphk} 1100171181Skib 1101171181Skibstatic TAILQ_HEAD(, cdev_priv) dev_ddtr = 1102171181Skib TAILQ_HEAD_INITIALIZER(dev_ddtr); 1103171181Skibstatic struct task dev_dtr_task; 1104171181Skib 1105171181Skibstatic void 1106171181Skibdestroy_dev_tq(void *ctx, int pending) 1107171181Skib{ 1108171181Skib struct cdev_priv *cp; 1109171181Skib struct cdev *dev; 1110171181Skib void (*cb)(void *); 1111171181Skib void *cb_arg; 1112171181Skib 1113171181Skib dev_lock(); 1114171181Skib while (!TAILQ_EMPTY(&dev_ddtr)) { 1115171181Skib cp = TAILQ_FIRST(&dev_ddtr); 1116171181Skib dev = &cp->cdp_c; 1117171181Skib KASSERT(cp->cdp_flags & CDP_SCHED_DTR, 1118171181Skib ("cdev %p in dev_destroy_tq without CDP_SCHED_DTR", cp)); 1119171181Skib TAILQ_REMOVE(&dev_ddtr, cp, cdp_dtr_list); 1120171181Skib cb = cp->cdp_dtr_cb; 1121171181Skib cb_arg = cp->cdp_dtr_cb_arg; 1122171181Skib destroy_devl(dev); 1123177301Skib dev_unlock_and_free(); 1124171181Skib dev_rel(dev); 1125171181Skib if (cb != NULL) 1126171181Skib cb(cb_arg); 1127171181Skib dev_lock(); 1128171181Skib } 1129171181Skib dev_unlock(); 1130171181Skib} 1131171181Skib 1132171188Skib/* 1133171188Skib * devmtx shall be locked on entry. devmtx will be unlocked after 1134171188Skib * function return. 1135171188Skib */ 1136171188Skibstatic int 1137171188Skibdestroy_dev_sched_cbl(struct cdev *dev, void (*cb)(void *), void *arg) 1138171181Skib{ 1139171181Skib struct cdev_priv *cp; 1140171188Skib 1141171188Skib mtx_assert(&devmtx, MA_OWNED); 1142179828Skib cp = cdev2priv(dev); 1143171181Skib if (cp->cdp_flags & CDP_SCHED_DTR) { 1144171181Skib dev_unlock(); 1145171181Skib return (0); 1146171181Skib } 1147171181Skib dev_refl(dev); 1148171181Skib cp->cdp_flags |= CDP_SCHED_DTR; 1149171181Skib cp->cdp_dtr_cb = cb; 1150171181Skib cp->cdp_dtr_cb_arg = arg; 1151171181Skib TAILQ_INSERT_TAIL(&dev_ddtr, cp, cdp_dtr_list); 1152171181Skib dev_unlock(); 1153171181Skib taskqueue_enqueue(taskqueue_swi_giant, &dev_dtr_task); 1154171181Skib return (1); 1155171181Skib} 1156171181Skib 1157171181Skibint 1158171188Skibdestroy_dev_sched_cb(struct cdev *dev, void (*cb)(void *), void *arg) 1159171188Skib{ 1160204412Skib 1161171188Skib dev_lock(); 1162171188Skib return (destroy_dev_sched_cbl(dev, cb, arg)); 1163171188Skib} 1164171188Skib 1165171188Skibint 1166171181Skibdestroy_dev_sched(struct cdev *dev) 1167171181Skib{ 1168204412Skib 1169171181Skib return (destroy_dev_sched_cb(dev, NULL, NULL)); 1170171181Skib} 1171171181Skib 1172171181Skibvoid 1173171181Skibdestroy_dev_drain(struct cdevsw *csw) 1174171181Skib{ 1175171181Skib 1176171181Skib dev_lock(); 1177171181Skib while (!LIST_EMPTY(&csw->d_devs)) { 1178171181Skib msleep(&csw->d_devs, &devmtx, PRIBIO, "devscd", hz/10); 1179171181Skib } 1180171181Skib dev_unlock(); 1181171181Skib} 1182171181Skib 1183171181Skibvoid 1184171181Skibdrain_dev_clone_events(void) 1185171181Skib{ 1186171181Skib 1187171181Skib sx_xlock(&clone_drain_lock); 1188171181Skib sx_xunlock(&clone_drain_lock); 1189171181Skib} 1190171181Skib 1191171181Skibstatic void 1192171181Skibdevdtr_init(void *dummy __unused) 1193171181Skib{ 1194171181Skib 1195171181Skib TASK_INIT(&dev_dtr_task, 0, destroy_dev_tq, NULL); 1196171181Skib} 1197171181Skib 1198171181SkibSYSINIT(devdtr, SI_SUB_DEVFS, SI_ORDER_SECOND, devdtr_init, NULL); 1199