kern_conf.c revision 277391
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 277391 2015-01-19 17:36:52Z kib $"); 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); 58228804Sjhbstatic void destroy_dev_tq(void *ctx, int pending); 59209106Skibstatic int make_dev_credv(int flags, struct cdev **dres, struct cdevsw *devsw, 60209106Skib int unit, 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); 119277391Skib KASSERT((cdp->cdp_flags & CDP_UNREF_DTR) == 0, 120277391Skib ("destroy_dev() was not called after delist_dev(%p)", cdev)); 121170950Skib TAILQ_INSERT_HEAD(&cdevp_free_list, cdp, cdp_list); 122170950Skib} 123170950Skib 124177301Skibstatic void 125177301Skibcdevsw_free_devlocked(struct cdevsw *csw) 126177301Skib{ 127177301Skib 128177301Skib mtx_assert(&devmtx, MA_OWNED); 129177301Skib SLIST_INSERT_HEAD(&cdevsw_gt_post_list, csw, d_postfree_list); 130177301Skib} 131177301Skib 132135600Sphkvoid 133135600Sphkdev_unlock(void) 134126082Sphk{ 135135704Sphk 136126082Sphk mtx_unlock(&devmtx); 137126082Sphk} 138126082Sphk 139126082Sphkvoid 140144385Sphkdev_ref(struct cdev *dev) 141144385Sphk{ 142144385Sphk 143144385Sphk mtx_assert(&devmtx, MA_NOTOWNED); 144144385Sphk mtx_lock(&devmtx); 145144385Sphk dev->si_refcount++; 146144385Sphk mtx_unlock(&devmtx); 147144385Sphk} 148144385Sphk 149144385Sphkvoid 150144384Sphkdev_refl(struct cdev *dev) 151126082Sphk{ 152135704Sphk 153142232Sphk mtx_assert(&devmtx, MA_OWNED); 154126082Sphk dev->si_refcount++; 155126082Sphk} 156126082Sphk 157126082Sphkvoid 158142242Sphkdev_rel(struct cdev *dev) 159126082Sphk{ 160142242Sphk int flag = 0; 161135600Sphk 162136014Sphk mtx_assert(&devmtx, MA_NOTOWNED); 163136014Sphk dev_lock(); 164126082Sphk dev->si_refcount--; 165126082Sphk KASSERT(dev->si_refcount >= 0, 166126082Sphk ("dev_rel(%s) gave negative count", devtoname(dev))); 167150342Sphk#if 0 168142242Sphk if (dev->si_usecount == 0 && 169142242Sphk (dev->si_flags & SI_CHEAPCLONE) && (dev->si_flags & SI_NAMED)) 170150342Sphk ; 171150342Sphk else 172150342Sphk#endif 173154029Sbz if (dev->si_devsw == NULL && dev->si_refcount == 0) { 174126082Sphk LIST_REMOVE(dev, si_list); 175136014Sphk flag = 1; 176136014Sphk } 177136014Sphk dev_unlock(); 178136014Sphk if (flag) 179150342Sphk devfs_free(dev); 180126082Sphk} 181136014Sphk 182135704Sphkstruct cdevsw * 183210923Skibdev_refthread(struct cdev *dev, int *ref) 184135704Sphk{ 185135704Sphk struct cdevsw *csw; 186171181Skib struct cdev_priv *cdp; 187126082Sphk 188135704Sphk mtx_assert(&devmtx, MA_NOTOWNED); 189210923Skib if ((dev->si_flags & SI_ETERNAL) != 0) { 190210923Skib *ref = 0; 191210923Skib return (dev->si_devsw); 192210923Skib } 193135704Sphk dev_lock(); 194135704Sphk csw = dev->si_devsw; 195171181Skib if (csw != NULL) { 196179828Skib cdp = cdev2priv(dev); 197171181Skib if ((cdp->cdp_flags & CDP_SCHED_DTR) == 0) 198256885Smav atomic_add_long(&dev->si_threadcount, 1); 199171181Skib else 200171181Skib csw = NULL; 201171181Skib } 202135704Sphk dev_unlock(); 203210923Skib *ref = 1; 204135704Sphk return (csw); 205135704Sphk} 206135704Sphk 207163529Skibstruct cdevsw * 208210923Skibdevvn_refthread(struct vnode *vp, struct cdev **devp, int *ref) 209163529Skib{ 210163529Skib struct cdevsw *csw; 211171181Skib struct cdev_priv *cdp; 212210923Skib struct cdev *dev; 213163529Skib 214163529Skib mtx_assert(&devmtx, MA_NOTOWNED); 215210923Skib if ((vp->v_vflag & VV_ETERNALDEV) != 0) { 216210923Skib dev = vp->v_rdev; 217210923Skib if (dev == NULL) 218210923Skib return (NULL); 219210923Skib KASSERT((dev->si_flags & SI_ETERNAL) != 0, 220210923Skib ("Not eternal cdev")); 221210923Skib *ref = 0; 222210923Skib csw = dev->si_devsw; 223210923Skib KASSERT(csw != NULL, ("Eternal cdev is destroyed")); 224210923Skib *devp = dev; 225210923Skib return (csw); 226210923Skib } 227210923Skib 228163529Skib csw = NULL; 229163529Skib dev_lock(); 230210923Skib dev = vp->v_rdev; 231210923Skib if (dev == NULL) { 232210923Skib dev_unlock(); 233210923Skib return (NULL); 234163529Skib } 235210923Skib cdp = cdev2priv(dev); 236210923Skib if ((cdp->cdp_flags & CDP_SCHED_DTR) == 0) { 237210923Skib csw = dev->si_devsw; 238210923Skib if (csw != NULL) 239256885Smav atomic_add_long(&dev->si_threadcount, 1); 240210923Skib } 241163529Skib dev_unlock(); 242210923Skib if (csw != NULL) { 243210923Skib *devp = dev; 244210923Skib *ref = 1; 245210923Skib } 246163529Skib return (csw); 247163529Skib} 248163529Skib 249135704Sphkvoid 250210923Skibdev_relthread(struct cdev *dev, int ref) 251135704Sphk{ 252135704Sphk 253135704Sphk mtx_assert(&devmtx, MA_NOTOWNED); 254210923Skib if (!ref) 255210923Skib return; 256179248Skib KASSERT(dev->si_threadcount > 0, 257179248Skib ("%s threadcount is wrong", dev->si_name)); 258256885Smav atomic_subtract_rel_long(&dev->si_threadcount, 1); 259135704Sphk} 260135704Sphk 261120514Sphkint 262120514Sphknullop(void) 263120514Sphk{ 26485603Sphk 265120514Sphk return (0); 266120514Sphk} 267120514Sphk 268120514Sphkint 269120514Sphkeopnotsupp(void) 270120514Sphk{ 271120514Sphk 272120514Sphk return (EOPNOTSUPP); 273120514Sphk} 274120514Sphk 275111179Sphkstatic int 276111179Sphkenxio(void) 277111179Sphk{ 278111179Sphk return (ENXIO); 279111179Sphk} 280111179Sphk 281120514Sphkstatic int 282120514Sphkenodev(void) 283120514Sphk{ 284120514Sphk return (ENODEV); 285120514Sphk} 286120514Sphk 287120514Sphk/* Define a dead_cdevsw for use when devices leave unexpectedly. */ 288120514Sphk 289111179Sphk#define dead_open (d_open_t *)enxio 290111179Sphk#define dead_close (d_close_t *)enxio 291111179Sphk#define dead_read (d_read_t *)enxio 292111179Sphk#define dead_write (d_write_t *)enxio 293111179Sphk#define dead_ioctl (d_ioctl_t *)enxio 294120514Sphk#define dead_poll (d_poll_t *)enodev 295120514Sphk#define dead_mmap (d_mmap_t *)enodev 296111179Sphk 297111179Sphkstatic void 298111179Sphkdead_strategy(struct bio *bp) 299111179Sphk{ 300111179Sphk 301111179Sphk biofinish(bp, NULL, ENXIO); 302111179Sphk} 303111179Sphk 304111220Sphk#define dead_dump (dumper_t *)enxio 305111179Sphk#define dead_kqfilter (d_kqfilter_t *)enxio 306193275Sjhb#define dead_mmap_single (d_mmap_single_t *)enodev 307111179Sphk 308111179Sphkstatic struct cdevsw dead_cdevsw = { 309126080Sphk .d_version = D_VERSION, 310111815Sphk .d_open = dead_open, 311111815Sphk .d_close = dead_close, 312111815Sphk .d_read = dead_read, 313111815Sphk .d_write = dead_write, 314111815Sphk .d_ioctl = dead_ioctl, 315111815Sphk .d_poll = dead_poll, 316111815Sphk .d_mmap = dead_mmap, 317111815Sphk .d_strategy = dead_strategy, 318111815Sphk .d_name = "dead", 319111815Sphk .d_dump = dead_dump, 320193275Sjhb .d_kqfilter = dead_kqfilter, 321193275Sjhb .d_mmap_single = dead_mmap_single 322111179Sphk}; 323111179Sphk 324120514Sphk/* Default methods if driver does not specify method */ 325111179Sphk 326120514Sphk#define null_open (d_open_t *)nullop 327120514Sphk#define null_close (d_close_t *)nullop 328120514Sphk#define no_read (d_read_t *)enodev 329120514Sphk#define no_write (d_write_t *)enodev 330120514Sphk#define no_ioctl (d_ioctl_t *)enodev 331201223Srnoland#define no_mmap (d_mmap_t *)enodev 332133741Sjmg#define no_kqfilter (d_kqfilter_t *)enodev 333193275Sjhb#define no_mmap_single (d_mmap_single_t *)enodev 334120514Sphk 335120514Sphkstatic void 336120514Sphkno_strategy(struct bio *bp) 337120514Sphk{ 338120514Sphk 339120514Sphk biofinish(bp, NULL, ENODEV); 340120514Sphk} 341120514Sphk 342120514Sphkstatic int 343130585Sphkno_poll(struct cdev *dev __unused, int events, struct thread *td __unused) 344120514Sphk{ 345120514Sphk 346189450Skib return (poll_no_poll(events)); 347120514Sphk} 348120514Sphk 349120514Sphk#define no_dump (dumper_t *)enodev 350120514Sphk 351149177Sphkstatic int 352149177Sphkgiant_open(struct cdev *dev, int oflags, int devtype, struct thread *td) 353149177Sphk{ 354177301Skib struct cdevsw *dsw; 355210923Skib int ref, retval; 356149177Sphk 357210923Skib dsw = dev_refthread(dev, &ref); 358177301Skib if (dsw == NULL) 359177301Skib return (ENXIO); 360149177Sphk mtx_lock(&Giant); 361177301Skib retval = dsw->d_gianttrick->d_open(dev, oflags, devtype, td); 362149177Sphk mtx_unlock(&Giant); 363210923Skib dev_relthread(dev, ref); 364149177Sphk return (retval); 365149177Sphk} 366149177Sphk 367149177Sphkstatic int 368170152Skibgiant_fdopen(struct cdev *dev, int oflags, struct thread *td, struct file *fp) 369149177Sphk{ 370177301Skib struct cdevsw *dsw; 371210923Skib int ref, retval; 372149177Sphk 373210923Skib dsw = dev_refthread(dev, &ref); 374177301Skib if (dsw == NULL) 375177301Skib return (ENXIO); 376149177Sphk mtx_lock(&Giant); 377177301Skib retval = dsw->d_gianttrick->d_fdopen(dev, oflags, td, fp); 378149177Sphk mtx_unlock(&Giant); 379210923Skib dev_relthread(dev, ref); 380149177Sphk return (retval); 381149177Sphk} 382149177Sphk 383149177Sphkstatic int 384149177Sphkgiant_close(struct cdev *dev, int fflag, int devtype, struct thread *td) 385149177Sphk{ 386177301Skib struct cdevsw *dsw; 387210923Skib int ref, retval; 388149177Sphk 389210923Skib dsw = dev_refthread(dev, &ref); 390177301Skib if (dsw == NULL) 391177301Skib return (ENXIO); 392149177Sphk mtx_lock(&Giant); 393177301Skib retval = dsw->d_gianttrick->d_close(dev, fflag, devtype, td); 394149177Sphk mtx_unlock(&Giant); 395210923Skib dev_relthread(dev, ref); 396149177Sphk return (retval); 397149177Sphk} 398149177Sphk 399149177Sphkstatic void 400149177Sphkgiant_strategy(struct bio *bp) 401149177Sphk{ 402177301Skib struct cdevsw *dsw; 403177301Skib struct cdev *dev; 404210923Skib int ref; 405149177Sphk 406177301Skib dev = bp->bio_dev; 407210923Skib dsw = dev_refthread(dev, &ref); 408177301Skib if (dsw == NULL) { 409177301Skib biofinish(bp, NULL, ENXIO); 410177301Skib return; 411177301Skib } 412149177Sphk mtx_lock(&Giant); 413177301Skib dsw->d_gianttrick->d_strategy(bp); 414149177Sphk mtx_unlock(&Giant); 415210923Skib dev_relthread(dev, ref); 416149177Sphk} 417149177Sphk 418149177Sphkstatic int 419149177Sphkgiant_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct thread *td) 420149177Sphk{ 421177301Skib struct cdevsw *dsw; 422210923Skib int ref, retval; 423149177Sphk 424210923Skib dsw = dev_refthread(dev, &ref); 425177301Skib if (dsw == NULL) 426177301Skib return (ENXIO); 427149177Sphk mtx_lock(&Giant); 428177858Skib retval = dsw->d_gianttrick->d_ioctl(dev, cmd, data, fflag, td); 429149177Sphk mtx_unlock(&Giant); 430210923Skib dev_relthread(dev, ref); 431149177Sphk return (retval); 432149177Sphk} 433149177Sphk 434149177Sphkstatic int 435149177Sphkgiant_read(struct cdev *dev, struct uio *uio, int ioflag) 436149177Sphk{ 437177301Skib struct cdevsw *dsw; 438210923Skib int ref, retval; 439149177Sphk 440210923Skib dsw = dev_refthread(dev, &ref); 441177301Skib if (dsw == NULL) 442177301Skib return (ENXIO); 443149177Sphk mtx_lock(&Giant); 444177858Skib retval = dsw->d_gianttrick->d_read(dev, uio, ioflag); 445149177Sphk mtx_unlock(&Giant); 446210923Skib dev_relthread(dev, ref); 447149177Sphk return (retval); 448149177Sphk} 449149177Sphk 450149177Sphkstatic int 451149177Sphkgiant_write(struct cdev *dev, struct uio *uio, int ioflag) 452149177Sphk{ 453177301Skib struct cdevsw *dsw; 454210923Skib int ref, retval; 455149177Sphk 456210923Skib dsw = dev_refthread(dev, &ref); 457177301Skib if (dsw == NULL) 458177301Skib return (ENXIO); 459149177Sphk mtx_lock(&Giant); 460177301Skib retval = dsw->d_gianttrick->d_write(dev, uio, ioflag); 461149177Sphk mtx_unlock(&Giant); 462210923Skib dev_relthread(dev, ref); 463149177Sphk return (retval); 464149177Sphk} 465149177Sphk 466149177Sphkstatic int 467149177Sphkgiant_poll(struct cdev *dev, int events, struct thread *td) 468149177Sphk{ 469177301Skib struct cdevsw *dsw; 470210923Skib int ref, retval; 471149177Sphk 472210923Skib dsw = dev_refthread(dev, &ref); 473177301Skib if (dsw == NULL) 474177301Skib return (ENXIO); 475149177Sphk mtx_lock(&Giant); 476177301Skib retval = dsw->d_gianttrick->d_poll(dev, events, td); 477149177Sphk mtx_unlock(&Giant); 478210923Skib dev_relthread(dev, ref); 479149177Sphk return (retval); 480149177Sphk} 481149177Sphk 482149177Sphkstatic int 483149177Sphkgiant_kqfilter(struct cdev *dev, struct knote *kn) 484149177Sphk{ 485177301Skib struct cdevsw *dsw; 486210923Skib int ref, retval; 487149177Sphk 488210923Skib dsw = dev_refthread(dev, &ref); 489177301Skib if (dsw == NULL) 490177301Skib return (ENXIO); 491149177Sphk mtx_lock(&Giant); 492177301Skib retval = dsw->d_gianttrick->d_kqfilter(dev, kn); 493149177Sphk mtx_unlock(&Giant); 494210923Skib dev_relthread(dev, ref); 495149177Sphk return (retval); 496149177Sphk} 497149177Sphk 498149177Sphkstatic int 499201223Srnolandgiant_mmap(struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr, int nprot, 500196615Sjhb vm_memattr_t *memattr) 501149177Sphk{ 502177301Skib struct cdevsw *dsw; 503210923Skib int ref, retval; 504149177Sphk 505210923Skib dsw = dev_refthread(dev, &ref); 506177301Skib if (dsw == NULL) 507177301Skib return (ENXIO); 508149177Sphk mtx_lock(&Giant); 509201223Srnoland retval = dsw->d_gianttrick->d_mmap(dev, offset, paddr, nprot, 510201223Srnoland memattr); 511149177Sphk mtx_unlock(&Giant); 512210923Skib dev_relthread(dev, ref); 513149177Sphk return (retval); 514149177Sphk} 515149177Sphk 516193275Sjhbstatic int 517193275Sjhbgiant_mmap_single(struct cdev *dev, vm_ooffset_t *offset, vm_size_t size, 518193275Sjhb vm_object_t *object, int nprot) 519193275Sjhb{ 520193275Sjhb struct cdevsw *dsw; 521210923Skib int ref, retval; 522149177Sphk 523210923Skib dsw = dev_refthread(dev, &ref); 524193275Sjhb if (dsw == NULL) 525193275Sjhb return (ENXIO); 526193275Sjhb mtx_lock(&Giant); 527193275Sjhb retval = dsw->d_gianttrick->d_mmap_single(dev, offset, size, object, 528193275Sjhb nprot); 529193275Sjhb mtx_unlock(&Giant); 530210923Skib dev_relthread(dev, ref); 531193275Sjhb return (retval); 532193275Sjhb} 533193275Sjhb 534178991Skibstatic void 535207729Skibnotify(struct cdev *dev, const char *ev, int flags) 536178991Skib{ 537178991Skib static const char prefix[] = "cdev="; 538178991Skib char *data; 539209105Skib int namelen, mflags; 540178991Skib 541178991Skib if (cold) 542178991Skib return; 543209105Skib mflags = (flags & MAKEDEV_NOWAIT) ? M_NOWAIT : M_WAITOK; 544178991Skib namelen = strlen(dev->si_name); 545209105Skib data = malloc(namelen + sizeof(prefix), M_TEMP, mflags); 546192535Sattilio if (data == NULL) 547192535Sattilio return; 548178991Skib memcpy(data, prefix, sizeof(prefix) - 1); 549178991Skib memcpy(data + sizeof(prefix) - 1, dev->si_name, namelen + 1); 550209105Skib devctl_notify_f("DEVFS", "CDEV", ev, data, mflags); 551178991Skib free(data, M_TEMP); 552178991Skib} 553178991Skib 554178991Skibstatic void 555207729Skibnotify_create(struct cdev *dev, int flags) 556178991Skib{ 557178991Skib 558207729Skib notify(dev, "CREATE", flags); 559178991Skib} 560178991Skib 561178991Skibstatic void 562178991Skibnotify_destroy(struct cdev *dev) 563178991Skib{ 564178991Skib 565207729Skib notify(dev, "DESTROY", MAKEDEV_WAITOK); 566178991Skib} 567178991Skib 568130585Sphkstatic struct cdev * 569191116Sednewdev(struct cdevsw *csw, int unit, struct cdev *si) 57047028Sphk{ 571140733Sphk struct cdev *si2; 57248936Sphk 573140733Sphk mtx_assert(&devmtx, MA_OWNED); 574179726Sed if (csw->d_flags & D_NEEDMINOR) { 575179726Sed /* We may want to return an existing device */ 576179726Sed LIST_FOREACH(si2, &csw->d_devs, si_list) { 577191116Sed if (dev2unit(si2) == unit) { 578179726Sed dev_free_devlocked(si); 579179726Sed return (si2); 580179726Sed } 581140733Sphk } 58248936Sphk } 583191116Sed si->si_drv0 = unit; 584150342Sphk si->si_devsw = csw; 585144281Sphk LIST_INSERT_HEAD(&csw->d_devs, si, si_list); 586125850Sbde return (si); 58747028Sphk} 58847028Sphk 589125846Sphkstatic void 590144292Sphkfini_cdevsw(struct cdevsw *devsw) 59149535Sphk{ 592149324Sphk struct cdevsw *gt; 59349535Sphk 594149324Sphk if (devsw->d_gianttrick != NULL) { 595149324Sphk gt = devsw->d_gianttrick; 596149324Sphk memcpy(devsw, gt, sizeof *devsw); 597177301Skib cdevsw_free_devlocked(gt); 598149324Sphk devsw->d_gianttrick = NULL; 599149324Sphk } 600126156Sphk devsw->d_flags &= ~D_INIT; 601126082Sphk} 602126082Sphk 603207729Skibstatic int 604207729Skibprep_cdevsw(struct cdevsw *devsw, int flags) 605126077Sphk{ 606149177Sphk struct cdevsw *dsw2; 607126077Sphk 608177301Skib mtx_assert(&devmtx, MA_OWNED); 609177301Skib if (devsw->d_flags & D_INIT) 610209106Skib return (0); 611177301Skib if (devsw->d_flags & D_NEEDGIANT) { 612177301Skib dev_unlock(); 613207729Skib dsw2 = malloc(sizeof *dsw2, M_DEVT, 614207729Skib (flags & MAKEDEV_NOWAIT) ? M_NOWAIT : M_WAITOK); 615177301Skib dev_lock(); 616207729Skib if (dsw2 == NULL && !(devsw->d_flags & D_INIT)) 617209106Skib return (ENOMEM); 618177301Skib } else 619149177Sphk dsw2 = NULL; 620177301Skib if (devsw->d_flags & D_INIT) { 621177301Skib if (dsw2 != NULL) 622177301Skib cdevsw_free_devlocked(dsw2); 623209106Skib return (0); 624177301Skib } 625126082Sphk 626201223Srnoland if (devsw->d_version != D_VERSION_03) { 627126082Sphk printf( 628126082Sphk "WARNING: Device driver \"%s\" has wrong version %s\n", 629154266Salfred devsw->d_name == NULL ? "???" : devsw->d_name, 630154266Salfred "and is disabled. Recompile KLD module."); 631126082Sphk devsw->d_open = dead_open; 632126082Sphk devsw->d_close = dead_close; 633126082Sphk devsw->d_read = dead_read; 634126082Sphk devsw->d_write = dead_write; 635126082Sphk devsw->d_ioctl = dead_ioctl; 636126082Sphk devsw->d_poll = dead_poll; 637126082Sphk devsw->d_mmap = dead_mmap; 638201223Srnoland devsw->d_mmap_single = dead_mmap_single; 639126082Sphk devsw->d_strategy = dead_strategy; 640126082Sphk devsw->d_dump = dead_dump; 641126082Sphk devsw->d_kqfilter = dead_kqfilter; 642126082Sphk } 643126082Sphk 644149177Sphk if (devsw->d_flags & D_NEEDGIANT) { 645149177Sphk if (devsw->d_gianttrick == NULL) { 646149177Sphk memcpy(dsw2, devsw, sizeof *dsw2); 647149177Sphk devsw->d_gianttrick = dsw2; 648177301Skib dsw2 = NULL; 649177301Skib } 650149177Sphk } 651149177Sphk 652149177Sphk#define FIXUP(member, noop, giant) \ 653149177Sphk do { \ 654149177Sphk if (devsw->member == NULL) { \ 655149177Sphk devsw->member = noop; \ 656149177Sphk } else if (devsw->d_flags & D_NEEDGIANT) \ 657149177Sphk devsw->member = giant; \ 658149177Sphk } \ 659149177Sphk while (0) 660149177Sphk 661149177Sphk FIXUP(d_open, null_open, giant_open); 662149177Sphk FIXUP(d_fdopen, NULL, giant_fdopen); 663149177Sphk FIXUP(d_close, null_close, giant_close); 664149177Sphk FIXUP(d_read, no_read, giant_read); 665149177Sphk FIXUP(d_write, no_write, giant_write); 666149177Sphk FIXUP(d_ioctl, no_ioctl, giant_ioctl); 667149177Sphk FIXUP(d_poll, no_poll, giant_poll); 668201223Srnoland FIXUP(d_mmap, no_mmap, giant_mmap); 669149177Sphk FIXUP(d_strategy, no_strategy, giant_strategy); 670149177Sphk FIXUP(d_kqfilter, no_kqfilter, giant_kqfilter); 671193275Sjhb FIXUP(d_mmap_single, no_mmap_single, giant_mmap_single); 672149177Sphk 673120514Sphk if (devsw->d_dump == NULL) devsw->d_dump = no_dump; 674126082Sphk 675126082Sphk LIST_INIT(&devsw->d_devs); 676126082Sphk 677126082Sphk devsw->d_flags |= D_INIT; 678126082Sphk 679177301Skib if (dsw2 != NULL) 680177301Skib cdevsw_free_devlocked(dsw2); 681209106Skib return (0); 682125846Sphk} 683111622Sphk 684209106Skibstatic int 685213526Sjhprep_devname(struct cdev *dev, const char *fmt, va_list ap) 686213526Sjh{ 687213526Sjh int len; 688213526Sjh char *from, *q, *s, *to; 689213526Sjh 690213526Sjh mtx_assert(&devmtx, MA_OWNED); 691213526Sjh 692231386Sed len = vsnrprintf(dev->si_name, sizeof(dev->si_name), 32, fmt, ap); 693231379Sed if (len > sizeof(dev->si_name) - 1) 694213526Sjh return (ENAMETOOLONG); 695213526Sjh 696213526Sjh /* Strip leading slashes. */ 697231379Sed for (from = dev->si_name; *from == '/'; from++) 698213526Sjh ; 699213526Sjh 700231379Sed for (to = dev->si_name; *from != '\0'; from++, to++) { 701244584Sjh /* 702244584Sjh * Spaces and double quotation marks cause 703244584Sjh * problems for the devctl(4) protocol. 704244584Sjh * Reject names containing those characters. 705244584Sjh */ 706244584Sjh if (isspace(*from) || *from == '"') 707244584Sjh return (EINVAL); 708213526Sjh /* Treat multiple sequential slashes as single. */ 709213526Sjh while (from[0] == '/' && from[1] == '/') 710213526Sjh from++; 711213526Sjh /* Trailing slash is considered invalid. */ 712213526Sjh if (from[0] == '/' && from[1] == '\0') 713213526Sjh return (EINVAL); 714213526Sjh *to = *from; 715213526Sjh } 716213526Sjh *to = '\0'; 717213526Sjh 718231379Sed if (dev->si_name[0] == '\0') 719213526Sjh return (EINVAL); 720213526Sjh 721213526Sjh /* Disallow "." and ".." components. */ 722231379Sed for (s = dev->si_name;;) { 723213526Sjh for (q = s; *q != '/' && *q != '\0'; q++) 724213526Sjh ; 725213526Sjh if (q - s == 1 && s[0] == '.') 726213526Sjh return (EINVAL); 727213526Sjh if (q - s == 2 && s[0] == '.' && s[1] == '.') 728213526Sjh return (EINVAL); 729213526Sjh if (*q != '/') 730213526Sjh break; 731213526Sjh s = q + 1; 732213526Sjh } 733213526Sjh 734231379Sed if (devfs_dev_exists(dev->si_name) != 0) 735213526Sjh return (EEXIST); 736213526Sjh 737213526Sjh return (0); 738213526Sjh} 739213526Sjh 740213526Sjhstatic int 741209106Skibmake_dev_credv(int flags, struct cdev **dres, struct cdevsw *devsw, int unit, 742209106Skib struct ucred *cr, uid_t uid, gid_t gid, int mode, const char *fmt, 743209106Skib va_list ap) 744125846Sphk{ 745213526Sjh struct cdev *dev, *dev_new; 746213526Sjh int res; 747125846Sphk 748209106Skib KASSERT((flags & MAKEDEV_WAITOK) == 0 || (flags & MAKEDEV_NOWAIT) == 0, 749209106Skib ("make_dev_credv: both WAITOK and NOWAIT specified")); 750213526Sjh dev_new = devfs_alloc(flags); 751213526Sjh if (dev_new == NULL) 752209106Skib return (ENOMEM); 753140733Sphk dev_lock(); 754209106Skib res = prep_cdevsw(devsw, flags); 755209106Skib if (res != 0) { 756207729Skib dev_unlock(); 757213526Sjh devfs_free(dev_new); 758209106Skib return (res); 759207729Skib } 760213526Sjh dev = newdev(devsw, unit, dev_new); 761214917Sjh if ((dev->si_flags & SI_NAMED) == 0) { 762213526Sjh res = prep_devname(dev, fmt, ap); 763213526Sjh if (res != 0) { 764213526Sjh if ((flags & MAKEDEV_CHECKNAME) == 0) { 765213526Sjh panic( 766213526Sjh "make_dev_credv: bad si_name (error=%d, si_name=%s)", 767213526Sjh res, dev->si_name); 768213526Sjh } 769213526Sjh if (dev == dev_new) { 770213526Sjh LIST_REMOVE(dev, si_list); 771213526Sjh dev_unlock(); 772213526Sjh devfs_free(dev); 773224521Skib } else 774224521Skib dev_unlock(); 775213526Sjh return (res); 776214917Sjh } 777213526Sjh } 778171181Skib if (flags & MAKEDEV_REF) 779171181Skib dev_refl(dev); 780210923Skib if (flags & MAKEDEV_ETERNAL) 781210923Skib dev->si_flags |= SI_ETERNAL; 782120529Sphk if (dev->si_flags & SI_CHEAPCLONE && 783150342Sphk dev->si_flags & SI_NAMED) { 784120529Sphk /* 785120529Sphk * This is allowed as it removes races and generally 786120529Sphk * simplifies cloning devices. 787126082Sphk * XXX: still ?? 788120529Sphk */ 789170950Skib dev_unlock_and_free(); 790209106Skib *dres = dev; 791209106Skib return (0); 792120529Sphk } 793126082Sphk KASSERT(!(dev->si_flags & SI_NAMED), 794144281Sphk ("make_dev() by driver %s on pre-existing device (min=%x, name=%s)", 795183397Sed devsw->d_name, dev2unit(dev), devtoname(dev))); 79665747Sphk dev->si_flags |= SI_NAMED; 797147982Srwatson if (cr != NULL) 798147982Srwatson dev->si_cred = crhold(cr); 799144385Sphk dev->si_uid = uid; 800144385Sphk dev->si_gid = gid; 801144385Sphk dev->si_mode = mode; 80250092Sjulian 803111730Sphk devfs_create(dev); 804171202Skib clean_unrhdrl(devfs_inos); 805177301Skib dev_unlock_and_free(); 806178991Skib 807207729Skib notify_create(dev, flags); 808178991Skib 809209106Skib *dres = dev; 810209106Skib return (0); 81149535Sphk} 81249535Sphk 813147982Srwatsonstruct cdev * 814183382Sedmake_dev(struct cdevsw *devsw, int unit, uid_t uid, gid_t gid, int mode, 815147982Srwatson const char *fmt, ...) 816147982Srwatson{ 817147982Srwatson struct cdev *dev; 818147982Srwatson va_list ap; 819209106Skib int res; 820147982Srwatson 821147982Srwatson va_start(ap, fmt); 822209106Skib res = make_dev_credv(0, &dev, devsw, unit, NULL, uid, gid, mode, fmt, 823209106Skib ap); 824147982Srwatson va_end(ap); 825213526Sjh KASSERT(res == 0 && dev != NULL, 826213526Sjh ("make_dev: failed make_dev_credv (error=%d)", res)); 827147982Srwatson return (dev); 828147982Srwatson} 829147982Srwatson 830147982Srwatsonstruct cdev * 831183382Sedmake_dev_cred(struct cdevsw *devsw, int unit, struct ucred *cr, uid_t uid, 832147982Srwatson gid_t gid, int mode, const char *fmt, ...) 833147982Srwatson{ 834147982Srwatson struct cdev *dev; 835147982Srwatson va_list ap; 836209106Skib int res; 837147982Srwatson 838147982Srwatson va_start(ap, fmt); 839209106Skib res = make_dev_credv(0, &dev, devsw, unit, cr, uid, gid, mode, fmt, ap); 840147982Srwatson va_end(ap); 841147982Srwatson 842209106Skib KASSERT(res == 0 && dev != NULL, 843213526Sjh ("make_dev_cred: failed make_dev_credv (error=%d)", res)); 844147982Srwatson return (dev); 845147982Srwatson} 846147982Srwatson 847171181Skibstruct cdev * 848209106Skibmake_dev_credf(int flags, struct cdevsw *devsw, int unit, struct ucred *cr, 849209106Skib uid_t uid, gid_t gid, int mode, const char *fmt, ...) 850171181Skib{ 851171181Skib struct cdev *dev; 852171181Skib va_list ap; 853209106Skib int res; 854171181Skib 855171181Skib va_start(ap, fmt); 856209106Skib res = make_dev_credv(flags, &dev, devsw, unit, cr, uid, gid, mode, 857171181Skib fmt, ap); 858171181Skib va_end(ap); 859171181Skib 860213526Sjh KASSERT(((flags & MAKEDEV_NOWAIT) != 0 && res == ENOMEM) || 861213526Sjh ((flags & MAKEDEV_CHECKNAME) != 0 && res != ENOMEM) || res == 0, 862213526Sjh ("make_dev_credf: failed make_dev_credv (error=%d)", res)); 863209106Skib return (res == 0 ? dev : NULL); 864171181Skib} 865171181Skib 866209106Skibint 867209244Sedmake_dev_p(int flags, struct cdev **cdev, struct cdevsw *devsw, 868209106Skib struct ucred *cr, uid_t uid, gid_t gid, int mode, const char *fmt, ...) 869209106Skib{ 870209106Skib va_list ap; 871209106Skib int res; 872209106Skib 873209106Skib va_start(ap, fmt); 874209244Sed res = make_dev_credv(flags, cdev, devsw, 0, cr, uid, gid, mode, 875209106Skib fmt, ap); 876209106Skib va_end(ap); 877209106Skib 878213526Sjh KASSERT(((flags & MAKEDEV_NOWAIT) != 0 && res == ENOMEM) || 879213526Sjh ((flags & MAKEDEV_CHECKNAME) != 0 && res != ENOMEM) || res == 0, 880213526Sjh ("make_dev_p: failed make_dev_credv (error=%d)", res)); 881209106Skib return (res); 882209106Skib} 883209106Skib 884150342Sphkstatic void 885150342Sphkdev_dependsl(struct cdev *pdev, struct cdev *cdev) 886150342Sphk{ 887150342Sphk 888150342Sphk cdev->si_parent = pdev; 889150342Sphk cdev->si_flags |= SI_CHILD; 890150342Sphk LIST_INSERT_HEAD(&pdev->si_children, cdev, si_siblings); 891150342Sphk} 892150342Sphk 893150342Sphk 89477215Sphkvoid 895130585Sphkdev_depends(struct cdev *pdev, struct cdev *cdev) 89677215Sphk{ 89777215Sphk 898135600Sphk dev_lock(); 899150342Sphk dev_dependsl(pdev, cdev); 900135600Sphk dev_unlock(); 90177215Sphk} 90277215Sphk 903221397Saestatic int 904221397Saemake_dev_alias_v(int flags, struct cdev **cdev, struct cdev *pdev, 905221397Sae const char *fmt, va_list ap) 90664880Sphk{ 907130585Sphk struct cdev *dev; 908213526Sjh int error; 90964880Sphk 910221397Sae KASSERT(pdev != NULL, ("make_dev_alias_v: pdev is NULL")); 911221397Sae KASSERT((flags & MAKEDEV_WAITOK) == 0 || (flags & MAKEDEV_NOWAIT) == 0, 912221397Sae ("make_dev_alias_v: both WAITOK and NOWAIT specified")); 913221397Sae KASSERT((flags & ~(MAKEDEV_WAITOK | MAKEDEV_NOWAIT | 914221397Sae MAKEDEV_CHECKNAME)) == 0, 915221397Sae ("make_dev_alias_v: invalid flags specified (flags=%02x)", flags)); 916221397Sae 917221397Sae dev = devfs_alloc(flags); 918221397Sae if (dev == NULL) 919221397Sae return (ENOMEM); 920135600Sphk dev_lock(); 92164880Sphk dev->si_flags |= SI_ALIAS; 922213526Sjh error = prep_devname(dev, fmt, ap); 923213526Sjh if (error != 0) { 924221397Sae if ((flags & MAKEDEV_CHECKNAME) == 0) { 925221397Sae panic("make_dev_alias_v: bad si_name " 926221397Sae "(error=%d, si_name=%s)", error, dev->si_name); 927221397Sae } 928221397Sae dev_unlock(); 929221397Sae devfs_free(dev); 930221397Sae return (error); 931110318Sphk } 932213526Sjh dev->si_flags |= SI_NAMED; 933111730Sphk devfs_create(dev); 934180445Skib dev_dependsl(pdev, dev); 935171202Skib clean_unrhdrl(devfs_inos); 936135600Sphk dev_unlock(); 937178991Skib 938221397Sae notify_create(dev, flags); 939221397Sae *cdev = dev; 940178991Skib 941221397Sae return (0); 942221397Sae} 943221397Sae 944221397Saestruct cdev * 945221397Saemake_dev_alias(struct cdev *pdev, const char *fmt, ...) 946221397Sae{ 947221397Sae struct cdev *dev; 948221397Sae va_list ap; 949221397Sae int res; 950221397Sae 951221397Sae va_start(ap, fmt); 952221397Sae res = make_dev_alias_v(MAKEDEV_WAITOK, &dev, pdev, fmt, ap); 953221397Sae va_end(ap); 954221397Sae 955221397Sae KASSERT(res == 0 && dev != NULL, 956221397Sae ("make_dev_alias: failed make_dev_alias_v (error=%d)", res)); 95764880Sphk return (dev); 95864880Sphk} 95964880Sphk 960221397Saeint 961221397Saemake_dev_alias_p(int flags, struct cdev **cdev, struct cdev *pdev, 962221397Sae const char *fmt, ...) 963221397Sae{ 964221397Sae va_list ap; 965221397Sae int res; 966221397Sae 967221397Sae va_start(ap, fmt); 968221397Sae res = make_dev_alias_v(flags, cdev, pdev, fmt, ap); 969221397Sae va_end(ap); 970221397Sae return (res); 971221397Sae} 972221397Sae 973223085Sgibbsint 974223085Sgibbsmake_dev_physpath_alias(int flags, struct cdev **cdev, struct cdev *pdev, 975223085Sgibbs struct cdev *old_alias, const char *physpath) 976223085Sgibbs{ 977223085Sgibbs char *devfspath; 978223085Sgibbs int physpath_len; 979223085Sgibbs int max_parentpath_len; 980223085Sgibbs int parentpath_len; 981223085Sgibbs int devfspathbuf_len; 982223085Sgibbs int mflags; 983223085Sgibbs int ret; 984223085Sgibbs 985223085Sgibbs *cdev = NULL; 986223085Sgibbs devfspath = NULL; 987223085Sgibbs physpath_len = strlen(physpath); 988223085Sgibbs ret = EINVAL; 989223085Sgibbs if (physpath_len == 0) 990223085Sgibbs goto out; 991223085Sgibbs 992223085Sgibbs if (strncmp("id1,", physpath, 4) == 0) { 993223085Sgibbs physpath += 4; 994223085Sgibbs physpath_len -= 4; 995223085Sgibbs if (physpath_len == 0) 996223085Sgibbs goto out; 997223085Sgibbs } 998223085Sgibbs 999223085Sgibbs max_parentpath_len = SPECNAMELEN - physpath_len - /*/*/1; 1000223085Sgibbs parentpath_len = strlen(pdev->si_name); 1001223085Sgibbs if (max_parentpath_len < parentpath_len) { 1002235899Smav if (bootverbose) 1003235899Smav printf("WARNING: Unable to alias %s " 1004235899Smav "to %s/%s - path too long\n", 1005235899Smav pdev->si_name, physpath, pdev->si_name); 1006223085Sgibbs ret = ENAMETOOLONG; 1007223085Sgibbs goto out; 1008223085Sgibbs } 1009223085Sgibbs 1010223085Sgibbs mflags = (flags & MAKEDEV_NOWAIT) ? M_NOWAIT : M_WAITOK; 1011223085Sgibbs devfspathbuf_len = physpath_len + /*/*/1 + parentpath_len + /*NUL*/1; 1012223085Sgibbs devfspath = malloc(devfspathbuf_len, M_DEVBUF, mflags); 1013223085Sgibbs if (devfspath == NULL) { 1014223085Sgibbs ret = ENOMEM; 1015223085Sgibbs goto out; 1016223085Sgibbs } 1017223085Sgibbs 1018223085Sgibbs sprintf(devfspath, "%s/%s", physpath, pdev->si_name); 1019227444Skib if (old_alias != NULL && strcmp(old_alias->si_name, devfspath) == 0) { 1020223085Sgibbs /* Retain the existing alias. */ 1021223085Sgibbs *cdev = old_alias; 1022223085Sgibbs old_alias = NULL; 1023223085Sgibbs ret = 0; 1024223085Sgibbs } else { 1025227443Skib ret = make_dev_alias_p(flags, cdev, pdev, "%s", devfspath); 1026223085Sgibbs } 1027223085Sgibbsout: 1028223085Sgibbs if (old_alias != NULL) 1029223085Sgibbs destroy_dev(old_alias); 1030223085Sgibbs if (devfspath != NULL) 1031223085Sgibbs free(devfspath, M_DEVBUF); 1032223085Sgibbs return (ret); 1033223085Sgibbs} 1034223085Sgibbs 1035126082Sphkstatic void 1036142242Sphkdestroy_devl(struct cdev *dev) 103750549Sphk{ 1038135843Sphk struct cdevsw *csw; 1039216371Shselasky struct cdev_privdata *p; 1040277391Skib struct cdev_priv *cdp; 1041135843Sphk 1042142242Sphk mtx_assert(&devmtx, MA_OWNED); 1043135843Sphk KASSERT(dev->si_flags & SI_NAMED, 1044183397Sed ("WARNING: Driver mistake: destroy_dev on %d\n", dev2unit(dev))); 1045210923Skib KASSERT((dev->si_flags & SI_ETERNAL) == 0, 1046210923Skib ("WARNING: Driver mistake: destroy_dev on eternal %d\n", 1047210923Skib dev2unit(dev))); 1048154029Sbz 1049277391Skib cdp = cdev2priv(dev); 1050277391Skib if ((cdp->cdp_flags & CDP_UNREF_DTR) == 0) { 1051277391Skib /* 1052277391Skib * Avoid race with dev_rel(), e.g. from the populate 1053277391Skib * loop. If CDP_UNREF_DTR flag is set, the reference 1054277391Skib * to be dropped at the end of destroy_devl() was 1055277391Skib * already taken by delist_dev_locked(). 1056277391Skib */ 1057277391Skib dev_refl(dev); 1058126082Sphk 1059277391Skib devfs_destroy(dev); 1060277391Skib } 1061277391Skib 1062126082Sphk /* Remove name marking */ 1063126077Sphk dev->si_flags &= ~SI_NAMED; 1064126077Sphk 1065126082Sphk /* If we are a child, remove us from the parents list */ 106677215Sphk if (dev->si_flags & SI_CHILD) { 106777215Sphk LIST_REMOVE(dev, si_siblings); 106877215Sphk dev->si_flags &= ~SI_CHILD; 106977215Sphk } 1070126082Sphk 1071126082Sphk /* Kill our children */ 107277215Sphk while (!LIST_EMPTY(&dev->si_children)) 1073142242Sphk destroy_devl(LIST_FIRST(&dev->si_children)); 1074126082Sphk 1075126082Sphk /* Remove from clone list */ 1076126077Sphk if (dev->si_flags & SI_CLONELIST) { 1077126077Sphk LIST_REMOVE(dev, si_clone); 1078126077Sphk dev->si_flags &= ~SI_CLONELIST; 1079126077Sphk } 1080126082Sphk 1081135843Sphk csw = dev->si_devsw; 1082135934Sgreen dev->si_devsw = NULL; /* already NULL for SI_ALIAS */ 1083135934Sgreen while (csw != NULL && csw->d_purge != NULL && dev->si_threadcount) { 1084135843Sphk csw->d_purge(dev); 1085135843Sphk msleep(csw, &devmtx, PRIBIO, "devprg", hz/10); 1086158684Sphk if (dev->si_threadcount) 1087158684Sphk printf("Still %lu threads in %s\n", 1088158684Sphk dev->si_threadcount, devtoname(dev)); 1089135843Sphk } 1090163328Stegge while (dev->si_threadcount != 0) { 1091163328Stegge /* Use unique dummy wait ident */ 1092163328Stegge msleep(&csw, &devmtx, PRIBIO, "devdrn", hz / 10); 1093163328Stegge } 1094135843Sphk 1095179175Skib dev_unlock(); 1096178991Skib notify_destroy(dev); 1097179175Skib mtx_lock(&cdevpriv_mtx); 1098216371Shselasky while ((p = LIST_FIRST(&cdev2priv(dev)->cdp_fdpriv)) != NULL) { 1099179175Skib devfs_destroy_cdevpriv(p); 1100179175Skib mtx_lock(&cdevpriv_mtx); 1101179175Skib } 1102179175Skib mtx_unlock(&cdevpriv_mtx); 1103179175Skib dev_lock(); 1104178991Skib 1105135843Sphk dev->si_drv1 = 0; 1106135843Sphk dev->si_drv2 = 0; 1107135843Sphk bzero(&dev->__si_u, sizeof(dev->__si_u)); 1108135843Sphk 1109126082Sphk if (!(dev->si_flags & SI_ALIAS)) { 1110126082Sphk /* Remove from cdevsw list */ 1111126082Sphk LIST_REMOVE(dev, si_list); 1112126082Sphk 1113150342Sphk /* If cdevsw has no more struct cdev *'s, clean it */ 1114171181Skib if (LIST_EMPTY(&csw->d_devs)) { 1115135844Sphk fini_cdevsw(csw); 1116171181Skib wakeup(&csw->d_devs); 1117171181Skib } 1118126082Sphk } 111965747Sphk dev->si_flags &= ~SI_ALIAS; 1120277391Skib cdp->cdp_flags &= ~CDP_UNREF_DTR; 1121277391Skib dev->si_refcount--; 1122135843Sphk 1123277391Skib if (dev->si_refcount > 0) 1124126082Sphk LIST_INSERT_HEAD(&dead_cdevsw.d_devs, dev, si_list); 1125277391Skib else 1126170950Skib dev_free_devlocked(dev); 112750549Sphk} 112850549Sphk 1129277179Shselaskystatic void 1130277179Shselaskydelist_dev_locked(struct cdev *dev) 1131277179Shselasky{ 1132277391Skib struct cdev_priv *cdp; 1133277179Shselasky struct cdev *child; 1134277391Skib 1135277391Skib mtx_assert(&devmtx, MA_OWNED); 1136277391Skib cdp = cdev2priv(dev); 1137277391Skib if ((cdp->cdp_flags & CDP_UNREF_DTR) != 0) 1138277391Skib return; 1139277391Skib cdp->cdp_flags |= CDP_UNREF_DTR; 1140277391Skib dev_refl(dev); 1141277179Shselasky devfs_destroy(dev); 1142277179Shselasky LIST_FOREACH(child, &dev->si_children, si_siblings) 1143277179Shselasky delist_dev_locked(child); 1144277179Shselasky} 1145277179Shselasky 1146126082Sphkvoid 1147277179Shselaskydelist_dev(struct cdev *dev) 1148277179Shselasky{ 1149277391Skib 1150277179Shselasky dev_lock(); 1151277179Shselasky delist_dev_locked(dev); 1152277179Shselasky dev_unlock(); 1153277179Shselasky} 1154277179Shselasky 1155277179Shselaskyvoid 1156130585Sphkdestroy_dev(struct cdev *dev) 1157126082Sphk{ 1158126082Sphk 1159185373Skib WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, "destroy_dev"); 1160135600Sphk dev_lock(); 1161171251Skib destroy_devl(dev); 1162171251Skib dev_unlock_and_free(); 1163126082Sphk} 1164126082Sphk 116551225Sbdeconst char * 1166130585Sphkdevtoname(struct cdev *dev) 116749982Sbillf{ 116849982Sbillf 116949982Sbillf return (dev->si_name); 117049982Sbillf} 117165374Sphk 117265374Sphkint 117391998Sphkdev_stdclone(char *name, char **namep, const char *stem, int *unit) 117465374Sphk{ 117565374Sphk int u, i; 117665374Sphk 117775519Sbrian i = strlen(stem); 117875519Sbrian if (bcmp(stem, name, i) != 0) 117965374Sphk return (0); 118065374Sphk if (!isdigit(name[i])) 118165374Sphk return (0); 118265374Sphk u = 0; 118386461Sphk if (name[i] == '0' && isdigit(name[i+1])) 118486461Sphk return (0); 118565374Sphk while (isdigit(name[i])) { 118665374Sphk u *= 10; 118765374Sphk u += name[i++] - '0'; 118865374Sphk } 1189104523Sgreen if (u > 0xffffff) 1190104523Sgreen return (0); 119165374Sphk *unit = u; 119265374Sphk if (namep) 119365374Sphk *namep = &name[i]; 119465374Sphk if (name[i]) 119565374Sphk return (2); 119665374Sphk return (1); 119765374Sphk} 119865632Sphk 119965632Sphk/* 1200126077Sphk * Helper functions for cloning device drivers. 1201126077Sphk * 1202126077Sphk * The objective here is to make it unnecessary for the device drivers to 1203126077Sphk * use rman or similar to manage their unit number space. Due to the way 1204126077Sphk * we do "on-demand" devices, using rman or other "private" methods 1205126077Sphk * will be very tricky to lock down properly once we lock down this file. 1206126077Sphk * 1207130936Sle * Instead we give the drivers these routines which puts the struct cdev *'s 1208130936Sle * that are to be managed on their own list, and gives the driver the ability 1209126077Sphk * to ask for the first free unit number or a given specified unit number. 1210126077Sphk * 1211126077Sphk * In addition these routines support paired devices (pty, nmdm and similar) 1212126077Sphk * by respecting a number of "flag" bits in the minor number. 1213126077Sphk * 1214126077Sphk */ 1215126077Sphk 1216126077Sphkstruct clonedevs { 1217126077Sphk LIST_HEAD(,cdev) head; 1218126077Sphk}; 1219126077Sphk 1220126845Sphkvoid 1221126845Sphkclone_setup(struct clonedevs **cdp) 1222126845Sphk{ 1223126845Sphk 1224126845Sphk *cdp = malloc(sizeof **cdp, M_DEVBUF, M_WAITOK | M_ZERO); 1225126845Sphk LIST_INIT(&(*cdp)->head); 1226126845Sphk} 1227126845Sphk 1228126077Sphkint 1229204412Skibclone_create(struct clonedevs **cdp, struct cdevsw *csw, int *up, 1230204412Skib struct cdev **dp, int extra) 1231126077Sphk{ 1232126077Sphk struct clonedevs *cd; 1233140733Sphk struct cdev *dev, *ndev, *dl, *de; 1234126077Sphk int unit, low, u; 1235126077Sphk 1236126845Sphk KASSERT(*cdp != NULL, 1237126845Sphk ("clone_setup() not called in driver \"%s\"", csw->d_name)); 1238126077Sphk KASSERT(!(extra & CLONE_UNITMASK), 1239126845Sphk ("Illegal extra bits (0x%x) in clone_create", extra)); 1240126077Sphk KASSERT(*up <= CLONE_UNITMASK, 1241126845Sphk ("Too high unit (0x%x) in clone_create", *up)); 1242179726Sed KASSERT(csw->d_flags & D_NEEDMINOR, 1243179726Sed ("clone_create() on cdevsw without minor numbers")); 1244126077Sphk 1245126077Sphk 1246126077Sphk /* 1247126077Sphk * Search the list for a lot of things in one go: 1248126077Sphk * A preexisting match is returned immediately. 1249126077Sphk * The lowest free unit number if we are passed -1, and the place 1250126077Sphk * in the list where we should insert that new element. 1251126077Sphk * The place to insert a specified unit number, if applicable 1252126077Sphk * the end of the list. 1253126077Sphk */ 1254126077Sphk unit = *up; 1255207729Skib ndev = devfs_alloc(MAKEDEV_WAITOK); 1256140733Sphk dev_lock(); 1257207729Skib prep_cdevsw(csw, MAKEDEV_WAITOK); 1258126849Sphk low = extra; 1259126077Sphk de = dl = NULL; 1260126845Sphk cd = *cdp; 1261126077Sphk LIST_FOREACH(dev, &cd->head, si_clone) { 1262140733Sphk KASSERT(dev->si_flags & SI_CLONELIST, 1263140733Sphk ("Dev %p(%s) should be on clonelist", dev, dev->si_name)); 1264126077Sphk u = dev2unit(dev); 1265126077Sphk if (u == (unit | extra)) { 1266126077Sphk *dp = dev; 1267170950Skib dev_unlock(); 1268150342Sphk devfs_free(ndev); 1269126077Sphk return (0); 1270126077Sphk } 1271126077Sphk if (unit == -1 && u == low) { 1272126077Sphk low++; 1273126077Sphk de = dev; 1274126077Sphk continue; 1275150793Sphk } else if (u < (unit | extra)) { 1276150793Sphk de = dev; 1277150793Sphk continue; 1278150793Sphk } else if (u > (unit | extra)) { 1279126077Sphk dl = dev; 1280126077Sphk break; 1281126077Sphk } 1282126077Sphk } 1283126077Sphk if (unit == -1) 1284126849Sphk unit = low & CLONE_UNITMASK; 1285183381Sed dev = newdev(csw, unit | extra, ndev); 1286140733Sphk if (dev->si_flags & SI_CLONELIST) { 1287140733Sphk printf("dev %p (%s) is on clonelist\n", dev, dev->si_name); 1288150793Sphk printf("unit=%d, low=%d, extra=0x%x\n", unit, low, extra); 1289140733Sphk LIST_FOREACH(dev, &cd->head, si_clone) { 1290140733Sphk printf("\t%p %s\n", dev, dev->si_name); 1291140733Sphk } 1292140733Sphk panic("foo"); 1293140733Sphk } 1294126077Sphk KASSERT(!(dev->si_flags & SI_CLONELIST), 1295140733Sphk ("Dev %p(%s) should not be on clonelist", dev, dev->si_name)); 1296126077Sphk if (dl != NULL) 1297126077Sphk LIST_INSERT_BEFORE(dl, dev, si_clone); 1298126077Sphk else if (de != NULL) 1299126077Sphk LIST_INSERT_AFTER(de, dev, si_clone); 1300126077Sphk else 1301126077Sphk LIST_INSERT_HEAD(&cd->head, dev, si_clone); 1302126077Sphk dev->si_flags |= SI_CLONELIST; 1303126077Sphk *up = unit; 1304170950Skib dev_unlock_and_free(); 1305126077Sphk return (1); 1306126077Sphk} 1307126077Sphk 1308126077Sphk/* 1309126077Sphk * Kill everything still on the list. The driver should already have 1310130585Sphk * disposed of any softc hung of the struct cdev *'s at this time. 1311126077Sphk */ 1312126077Sphkvoid 1313126077Sphkclone_cleanup(struct clonedevs **cdp) 1314126077Sphk{ 1315171181Skib struct cdev *dev; 1316171181Skib struct cdev_priv *cp; 1317126077Sphk struct clonedevs *cd; 1318126077Sphk 1319126077Sphk cd = *cdp; 1320126077Sphk if (cd == NULL) 1321126077Sphk return; 1322140733Sphk dev_lock(); 1323171181Skib while (!LIST_EMPTY(&cd->head)) { 1324171181Skib dev = LIST_FIRST(&cd->head); 1325171181Skib LIST_REMOVE(dev, si_clone); 1326140733Sphk KASSERT(dev->si_flags & SI_CLONELIST, 1327140733Sphk ("Dev %p(%s) should be on clonelist", dev, dev->si_name)); 1328171181Skib dev->si_flags &= ~SI_CLONELIST; 1329179828Skib cp = cdev2priv(dev); 1330171181Skib if (!(cp->cdp_flags & CDP_SCHED_DTR)) { 1331171181Skib cp->cdp_flags |= CDP_SCHED_DTR; 1332171181Skib KASSERT(dev->si_flags & SI_NAMED, 1333275856Sgleb ("Driver has goofed in cloning underways udev %jx unit %x", 1334275856Sgleb (uintmax_t)dev2udev(dev), dev2unit(dev))); 1335171181Skib destroy_devl(dev); 1336171181Skib } 1337126077Sphk } 1338177301Skib dev_unlock_and_free(); 1339126077Sphk free(cd, M_DEVBUF); 1340126077Sphk *cdp = NULL; 1341126077Sphk} 1342171181Skib 1343171181Skibstatic TAILQ_HEAD(, cdev_priv) dev_ddtr = 1344171181Skib TAILQ_HEAD_INITIALIZER(dev_ddtr); 1345228804Sjhbstatic struct task dev_dtr_task = TASK_INITIALIZER(0, destroy_dev_tq, NULL); 1346171181Skib 1347171181Skibstatic void 1348171181Skibdestroy_dev_tq(void *ctx, int pending) 1349171181Skib{ 1350171181Skib struct cdev_priv *cp; 1351171181Skib struct cdev *dev; 1352171181Skib void (*cb)(void *); 1353171181Skib void *cb_arg; 1354171181Skib 1355171181Skib dev_lock(); 1356171181Skib while (!TAILQ_EMPTY(&dev_ddtr)) { 1357171181Skib cp = TAILQ_FIRST(&dev_ddtr); 1358171181Skib dev = &cp->cdp_c; 1359171181Skib KASSERT(cp->cdp_flags & CDP_SCHED_DTR, 1360171181Skib ("cdev %p in dev_destroy_tq without CDP_SCHED_DTR", cp)); 1361171181Skib TAILQ_REMOVE(&dev_ddtr, cp, cdp_dtr_list); 1362171181Skib cb = cp->cdp_dtr_cb; 1363171181Skib cb_arg = cp->cdp_dtr_cb_arg; 1364171181Skib destroy_devl(dev); 1365177301Skib dev_unlock_and_free(); 1366171181Skib dev_rel(dev); 1367171181Skib if (cb != NULL) 1368171181Skib cb(cb_arg); 1369171181Skib dev_lock(); 1370171181Skib } 1371171181Skib dev_unlock(); 1372171181Skib} 1373171181Skib 1374171188Skib/* 1375171188Skib * devmtx shall be locked on entry. devmtx will be unlocked after 1376171188Skib * function return. 1377171188Skib */ 1378171188Skibstatic int 1379171188Skibdestroy_dev_sched_cbl(struct cdev *dev, void (*cb)(void *), void *arg) 1380171181Skib{ 1381171181Skib struct cdev_priv *cp; 1382171188Skib 1383171188Skib mtx_assert(&devmtx, MA_OWNED); 1384179828Skib cp = cdev2priv(dev); 1385171181Skib if (cp->cdp_flags & CDP_SCHED_DTR) { 1386171181Skib dev_unlock(); 1387171181Skib return (0); 1388171181Skib } 1389171181Skib dev_refl(dev); 1390171181Skib cp->cdp_flags |= CDP_SCHED_DTR; 1391171181Skib cp->cdp_dtr_cb = cb; 1392171181Skib cp->cdp_dtr_cb_arg = arg; 1393171181Skib TAILQ_INSERT_TAIL(&dev_ddtr, cp, cdp_dtr_list); 1394171181Skib dev_unlock(); 1395171181Skib taskqueue_enqueue(taskqueue_swi_giant, &dev_dtr_task); 1396171181Skib return (1); 1397171181Skib} 1398171181Skib 1399171181Skibint 1400171188Skibdestroy_dev_sched_cb(struct cdev *dev, void (*cb)(void *), void *arg) 1401171188Skib{ 1402204412Skib 1403171188Skib dev_lock(); 1404171188Skib return (destroy_dev_sched_cbl(dev, cb, arg)); 1405171188Skib} 1406171188Skib 1407171188Skibint 1408171181Skibdestroy_dev_sched(struct cdev *dev) 1409171181Skib{ 1410204412Skib 1411171181Skib return (destroy_dev_sched_cb(dev, NULL, NULL)); 1412171181Skib} 1413171181Skib 1414171181Skibvoid 1415171181Skibdestroy_dev_drain(struct cdevsw *csw) 1416171181Skib{ 1417171181Skib 1418171181Skib dev_lock(); 1419171181Skib while (!LIST_EMPTY(&csw->d_devs)) { 1420171181Skib msleep(&csw->d_devs, &devmtx, PRIBIO, "devscd", hz/10); 1421171181Skib } 1422171181Skib dev_unlock(); 1423171181Skib} 1424171181Skib 1425171181Skibvoid 1426171181Skibdrain_dev_clone_events(void) 1427171181Skib{ 1428171181Skib 1429171181Skib sx_xlock(&clone_drain_lock); 1430171181Skib sx_xunlock(&clone_drain_lock); 1431171181Skib} 1432171181Skib 1433210924Skib#include "opt_ddb.h" 1434210924Skib#ifdef DDB 1435210924Skib#include <sys/kernel.h> 1436210924Skib 1437210924Skib#include <ddb/ddb.h> 1438210924Skib 1439210924SkibDB_SHOW_COMMAND(cdev, db_show_cdev) 1440210924Skib{ 1441210924Skib struct cdev_priv *cdp; 1442210924Skib struct cdev *dev; 1443210924Skib u_int flags; 1444210924Skib char buf[512]; 1445210924Skib 1446210924Skib if (!have_addr) { 1447210924Skib TAILQ_FOREACH(cdp, &cdevp_list, cdp_list) { 1448210924Skib dev = &cdp->cdp_c; 1449210924Skib db_printf("%s %p\n", dev->si_name, dev); 1450210924Skib if (db_pager_quit) 1451210924Skib break; 1452210924Skib } 1453210924Skib return; 1454210924Skib } 1455210924Skib 1456210924Skib dev = (struct cdev *)addr; 1457210924Skib cdp = cdev2priv(dev); 1458210924Skib db_printf("dev %s ref %d use %ld thr %ld inuse %u fdpriv %p\n", 1459210924Skib dev->si_name, dev->si_refcount, dev->si_usecount, 1460210924Skib dev->si_threadcount, cdp->cdp_inuse, cdp->cdp_fdpriv.lh_first); 1461210924Skib db_printf("devsw %p si_drv0 %d si_drv1 %p si_drv2 %p\n", 1462210924Skib dev->si_devsw, dev->si_drv0, dev->si_drv1, dev->si_drv2); 1463210924Skib flags = dev->si_flags; 1464210924Skib#define SI_FLAG(flag) do { \ 1465210924Skib if (flags & (flag)) { \ 1466210924Skib if (buf[0] != '\0') \ 1467210924Skib strlcat(buf, ", ", sizeof(buf)); \ 1468210924Skib strlcat(buf, (#flag) + 3, sizeof(buf)); \ 1469210924Skib flags &= ~(flag); \ 1470210924Skib } \ 1471210924Skib} while (0) 1472210924Skib buf[0] = '\0'; 1473210924Skib SI_FLAG(SI_ETERNAL); 1474210924Skib SI_FLAG(SI_ALIAS); 1475210924Skib SI_FLAG(SI_NAMED); 1476210924Skib SI_FLAG(SI_CHEAPCLONE); 1477210924Skib SI_FLAG(SI_CHILD); 1478210924Skib SI_FLAG(SI_DUMPDEV); 1479210924Skib SI_FLAG(SI_CLONELIST); 1480210924Skib db_printf("si_flags %s\n", buf); 1481210924Skib 1482210924Skib flags = cdp->cdp_flags; 1483210924Skib#define CDP_FLAG(flag) do { \ 1484210924Skib if (flags & (flag)) { \ 1485210924Skib if (buf[0] != '\0') \ 1486210924Skib strlcat(buf, ", ", sizeof(buf)); \ 1487210924Skib strlcat(buf, (#flag) + 4, sizeof(buf)); \ 1488210924Skib flags &= ~(flag); \ 1489210924Skib } \ 1490210924Skib} while (0) 1491210924Skib buf[0] = '\0'; 1492210924Skib CDP_FLAG(CDP_ACTIVE); 1493210924Skib CDP_FLAG(CDP_SCHED_DTR); 1494210924Skib db_printf("cdp_flags %s\n", buf); 1495210924Skib} 1496210924Skib#endif 1497