126453f35SJulian Elischer /*- 28a36da99SPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 38a36da99SPedro F. Giffuni * 466cdbc28SPoul-Henning Kamp * Copyright (c) 1999-2002 Poul-Henning Kamp 526453f35SJulian Elischer * All rights reserved. 626453f35SJulian Elischer * 726453f35SJulian Elischer * Redistribution and use in source and binary forms, with or without 826453f35SJulian Elischer * modification, are permitted provided that the following conditions 926453f35SJulian Elischer * are met: 1026453f35SJulian Elischer * 1. Redistributions of source code must retain the above copyright 1126453f35SJulian Elischer * notice, this list of conditions and the following disclaimer. 1226453f35SJulian Elischer * 2. Redistributions in binary form must reproduce the above copyright 1326453f35SJulian Elischer * notice, this list of conditions and the following disclaimer in the 1426453f35SJulian Elischer * documentation and/or other materials provided with the distribution. 1526453f35SJulian Elischer * 1666cdbc28SPoul-Henning Kamp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1766cdbc28SPoul-Henning Kamp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1826453f35SJulian Elischer * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1966cdbc28SPoul-Henning Kamp * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2026453f35SJulian Elischer * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2126453f35SJulian Elischer * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2226453f35SJulian Elischer * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2326453f35SJulian Elischer * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2426453f35SJulian Elischer * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2526453f35SJulian Elischer * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2626453f35SJulian Elischer * SUCH DAMAGE. 2726453f35SJulian Elischer */ 2826453f35SJulian Elischer 29677b542eSDavid E. O'Brien #include <sys/cdefs.h> 30677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$"); 31677b542eSDavid E. O'Brien 3226453f35SJulian Elischer #include <sys/param.h> 33698bfad7SPoul-Henning Kamp #include <sys/kernel.h> 34f8a760b3SJulian Elischer #include <sys/systm.h> 3548504cc2SKonstantin Belousov #include <sys/bus.h> 3602574b19SPoul-Henning Kamp #include <sys/bio.h> 371b567820SBrian Feldman #include <sys/lock.h> 381b567820SBrian Feldman #include <sys/mutex.h> 39ecbb00a2SDoug Rabson #include <sys/module.h> 40698bfad7SPoul-Henning Kamp #include <sys/malloc.h> 4126453f35SJulian Elischer #include <sys/conf.h> 421dfcbb0cSJulian Elischer #include <sys/vnode.h> 43698bfad7SPoul-Henning Kamp #include <sys/queue.h> 44b2941431SPoul-Henning Kamp #include <sys/poll.h> 45de10ffa5SKonstantin Belousov #include <sys/sx.h> 46db901281SPoul-Henning Kamp #include <sys/ctype.h> 47d26dd2d9SRobert Watson #include <sys/ucred.h> 48de10ffa5SKonstantin Belousov #include <sys/taskqueue.h> 490ef1c826SPoul-Henning Kamp #include <machine/stdarg.h> 501dfcbb0cSJulian Elischer 519c0af131SPoul-Henning Kamp #include <fs/devfs/devfs_int.h> 5264345f0bSJohn Baldwin #include <vm/vm.h> 539c0af131SPoul-Henning Kamp 549ef295b7SPoul-Henning Kamp static MALLOC_DEFINE(M_DEVT, "cdev", "cdev storage"); 55698bfad7SPoul-Henning Kamp 56e606a3c6SPoul-Henning Kamp struct mtx devmtx; 57aa2f6ddcSPoul-Henning Kamp static void destroy_devl(struct cdev *dev); 589d53363bSKonstantin Belousov static int destroy_dev_sched_cbl(struct cdev *dev, 599d53363bSKonstantin Belousov void (*cb)(void *), void *arg); 60268e76d8SJohn Baldwin static void destroy_dev_tq(void *ctx, int pending); 61f1bb758dSKonstantin Belousov static int make_dev_credv(int flags, struct cdev **dres, struct cdevsw *devsw, 62f1bb758dSKonstantin Belousov int unit, struct ucred *cr, uid_t uid, gid_t gid, int mode, const char *fmt, 63d26dd2d9SRobert Watson va_list ap); 64f3732fd1SPoul-Henning Kamp 659bc911d4SKonstantin Belousov static struct cdev_priv_list cdevp_free_list = 669bc911d4SKonstantin Belousov TAILQ_HEAD_INITIALIZER(cdevp_free_list); 67aeeb4202SKonstantin Belousov static SLIST_HEAD(free_cdevsw, cdevsw) cdevsw_gt_post_list = 6813e403fdSAntoine Brodin SLIST_HEAD_INITIALIZER(cdevsw_gt_post_list); 699bc911d4SKonstantin Belousov 70a0e78d2eSPoul-Henning Kamp void 71a0e78d2eSPoul-Henning Kamp dev_lock(void) 72cd690b60SPoul-Henning Kamp { 738c4b6380SJohn Baldwin 74cd690b60SPoul-Henning Kamp mtx_lock(&devmtx); 75cd690b60SPoul-Henning Kamp } 76cd690b60SPoul-Henning Kamp 77aeeb4202SKonstantin Belousov /* 78aeeb4202SKonstantin Belousov * Free all the memory collected while the cdev mutex was 79aeeb4202SKonstantin Belousov * locked. Since devmtx is after the system map mutex, free() cannot 80aeeb4202SKonstantin Belousov * be called immediately and is postponed until cdev mutex can be 81aeeb4202SKonstantin Belousov * dropped. 82aeeb4202SKonstantin Belousov */ 839bc911d4SKonstantin Belousov static void 849bc911d4SKonstantin Belousov dev_unlock_and_free(void) 859bc911d4SKonstantin Belousov { 86aeeb4202SKonstantin Belousov struct cdev_priv_list cdp_free; 87aeeb4202SKonstantin Belousov struct free_cdevsw csw_free; 889bc911d4SKonstantin Belousov struct cdev_priv *cdp; 89aeeb4202SKonstantin Belousov struct cdevsw *csw; 909bc911d4SKonstantin Belousov 919bc911d4SKonstantin Belousov mtx_assert(&devmtx, MA_OWNED); 92aeeb4202SKonstantin Belousov 93aeeb4202SKonstantin Belousov /* 94aeeb4202SKonstantin Belousov * Make the local copy of the list heads while the dev_mtx is 95aeeb4202SKonstantin Belousov * held. Free it later. 96aeeb4202SKonstantin Belousov */ 97aeeb4202SKonstantin Belousov TAILQ_INIT(&cdp_free); 98aeeb4202SKonstantin Belousov TAILQ_CONCAT(&cdp_free, &cdevp_free_list, cdp_list); 99aeeb4202SKonstantin Belousov csw_free = cdevsw_gt_post_list; 100aeeb4202SKonstantin Belousov SLIST_INIT(&cdevsw_gt_post_list); 101aeeb4202SKonstantin Belousov 1029bc911d4SKonstantin Belousov mtx_unlock(&devmtx); 103aeeb4202SKonstantin Belousov 104aeeb4202SKonstantin Belousov while ((cdp = TAILQ_FIRST(&cdp_free)) != NULL) { 105aeeb4202SKonstantin Belousov TAILQ_REMOVE(&cdp_free, cdp, cdp_list); 1069bc911d4SKonstantin Belousov devfs_free(&cdp->cdp_c); 1079bc911d4SKonstantin Belousov } 108aeeb4202SKonstantin Belousov while ((csw = SLIST_FIRST(&csw_free)) != NULL) { 109aeeb4202SKonstantin Belousov SLIST_REMOVE_HEAD(&csw_free, d_postfree_list); 110aeeb4202SKonstantin Belousov free(csw, M_DEVT); 111aeeb4202SKonstantin Belousov } 1129bc911d4SKonstantin Belousov } 1139bc911d4SKonstantin Belousov 1149bc911d4SKonstantin Belousov static void 1159bc911d4SKonstantin Belousov dev_free_devlocked(struct cdev *cdev) 1169bc911d4SKonstantin Belousov { 1179bc911d4SKonstantin Belousov struct cdev_priv *cdp; 1189bc911d4SKonstantin Belousov 1199bc911d4SKonstantin Belousov mtx_assert(&devmtx, MA_OWNED); 12005427aafSKonstantin Belousov cdp = cdev2priv(cdev); 1213b50dff5SKonstantin Belousov KASSERT((cdp->cdp_flags & CDP_UNREF_DTR) == 0, 1223b50dff5SKonstantin Belousov ("destroy_dev() was not called after delist_dev(%p)", cdev)); 1239bc911d4SKonstantin Belousov TAILQ_INSERT_HEAD(&cdevp_free_list, cdp, cdp_list); 1249bc911d4SKonstantin Belousov } 1259bc911d4SKonstantin Belousov 126aeeb4202SKonstantin Belousov static void 127aeeb4202SKonstantin Belousov cdevsw_free_devlocked(struct cdevsw *csw) 128aeeb4202SKonstantin Belousov { 129aeeb4202SKonstantin Belousov 130aeeb4202SKonstantin Belousov mtx_assert(&devmtx, MA_OWNED); 131aeeb4202SKonstantin Belousov SLIST_INSERT_HEAD(&cdevsw_gt_post_list, csw, d_postfree_list); 132aeeb4202SKonstantin Belousov } 133aeeb4202SKonstantin Belousov 134a0e78d2eSPoul-Henning Kamp void 135a0e78d2eSPoul-Henning Kamp dev_unlock(void) 136cd690b60SPoul-Henning Kamp { 1372c15afd8SPoul-Henning Kamp 138cd690b60SPoul-Henning Kamp mtx_unlock(&devmtx); 139cd690b60SPoul-Henning Kamp } 140cd690b60SPoul-Henning Kamp 141cd690b60SPoul-Henning Kamp void 1429477d73eSPoul-Henning Kamp dev_ref(struct cdev *dev) 1439477d73eSPoul-Henning Kamp { 1449477d73eSPoul-Henning Kamp 1459477d73eSPoul-Henning Kamp mtx_assert(&devmtx, MA_NOTOWNED); 1469477d73eSPoul-Henning Kamp mtx_lock(&devmtx); 1479477d73eSPoul-Henning Kamp dev->si_refcount++; 1489477d73eSPoul-Henning Kamp mtx_unlock(&devmtx); 1499477d73eSPoul-Henning Kamp } 1509477d73eSPoul-Henning Kamp 1519477d73eSPoul-Henning Kamp void 152eb151cb9SPoul-Henning Kamp dev_refl(struct cdev *dev) 153cd690b60SPoul-Henning Kamp { 1542c15afd8SPoul-Henning Kamp 1551a1457d4SPoul-Henning Kamp mtx_assert(&devmtx, MA_OWNED); 156cd690b60SPoul-Henning Kamp dev->si_refcount++; 157cd690b60SPoul-Henning Kamp } 158cd690b60SPoul-Henning Kamp 159cd690b60SPoul-Henning Kamp void 160aa2f6ddcSPoul-Henning Kamp dev_rel(struct cdev *dev) 161cd690b60SPoul-Henning Kamp { 162aa2f6ddcSPoul-Henning Kamp int flag = 0; 163a0e78d2eSPoul-Henning Kamp 164ba285125SPoul-Henning Kamp mtx_assert(&devmtx, MA_NOTOWNED); 165ba285125SPoul-Henning Kamp dev_lock(); 166cd690b60SPoul-Henning Kamp dev->si_refcount--; 167cd690b60SPoul-Henning Kamp KASSERT(dev->si_refcount >= 0, 168cd690b60SPoul-Henning Kamp ("dev_rel(%s) gave negative count", devtoname(dev))); 169e606a3c6SPoul-Henning Kamp #if 0 170aa2f6ddcSPoul-Henning Kamp if (dev->si_usecount == 0 && 171aa2f6ddcSPoul-Henning Kamp (dev->si_flags & SI_CHEAPCLONE) && (dev->si_flags & SI_NAMED)) 172e606a3c6SPoul-Henning Kamp ; 173e606a3c6SPoul-Henning Kamp else 174e606a3c6SPoul-Henning Kamp #endif 175cd690b60SPoul-Henning Kamp if (dev->si_devsw == NULL && dev->si_refcount == 0) { 176cd690b60SPoul-Henning Kamp LIST_REMOVE(dev, si_list); 177ba285125SPoul-Henning Kamp flag = 1; 178ba285125SPoul-Henning Kamp } 179ba285125SPoul-Henning Kamp dev_unlock(); 180ba285125SPoul-Henning Kamp if (flag) 181e606a3c6SPoul-Henning Kamp devfs_free(dev); 182cd690b60SPoul-Henning Kamp } 183ba285125SPoul-Henning Kamp 1842c15afd8SPoul-Henning Kamp struct cdevsw * 1853979450bSKonstantin Belousov dev_refthread(struct cdev *dev, int *ref) 1862c15afd8SPoul-Henning Kamp { 1872c15afd8SPoul-Henning Kamp struct cdevsw *csw; 188de10ffa5SKonstantin Belousov struct cdev_priv *cdp; 1892c15afd8SPoul-Henning Kamp 1902c15afd8SPoul-Henning Kamp mtx_assert(&devmtx, MA_NOTOWNED); 1913979450bSKonstantin Belousov if ((dev->si_flags & SI_ETERNAL) != 0) { 1923979450bSKonstantin Belousov *ref = 0; 1933979450bSKonstantin Belousov return (dev->si_devsw); 1943979450bSKonstantin Belousov } 1952c15afd8SPoul-Henning Kamp dev_lock(); 1962c15afd8SPoul-Henning Kamp csw = dev->si_devsw; 197de10ffa5SKonstantin Belousov if (csw != NULL) { 19805427aafSKonstantin Belousov cdp = cdev2priv(dev); 199de10ffa5SKonstantin Belousov if ((cdp->cdp_flags & CDP_SCHED_DTR) == 0) 2009e8bd2acSAlexander Motin atomic_add_long(&dev->si_threadcount, 1); 201de10ffa5SKonstantin Belousov else 202de10ffa5SKonstantin Belousov csw = NULL; 203de10ffa5SKonstantin Belousov } 2042c15afd8SPoul-Henning Kamp dev_unlock(); 205ec86f8b2SConrad Meyer if (csw != NULL) 2063979450bSKonstantin Belousov *ref = 1; 2072c15afd8SPoul-Henning Kamp return (csw); 2082c15afd8SPoul-Henning Kamp } 2092c15afd8SPoul-Henning Kamp 2101663075cSKonstantin Belousov struct cdevsw * 2113979450bSKonstantin Belousov devvn_refthread(struct vnode *vp, struct cdev **devp, int *ref) 2121663075cSKonstantin Belousov { 2131663075cSKonstantin Belousov struct cdevsw *csw; 214de10ffa5SKonstantin Belousov struct cdev_priv *cdp; 2153979450bSKonstantin Belousov struct cdev *dev; 2161663075cSKonstantin Belousov 2171663075cSKonstantin Belousov mtx_assert(&devmtx, MA_NOTOWNED); 2183979450bSKonstantin Belousov if ((vp->v_vflag & VV_ETERNALDEV) != 0) { 2193979450bSKonstantin Belousov dev = vp->v_rdev; 2203979450bSKonstantin Belousov if (dev == NULL) 2213979450bSKonstantin Belousov return (NULL); 2223979450bSKonstantin Belousov KASSERT((dev->si_flags & SI_ETERNAL) != 0, 2233979450bSKonstantin Belousov ("Not eternal cdev")); 2243979450bSKonstantin Belousov *ref = 0; 2253979450bSKonstantin Belousov csw = dev->si_devsw; 2263979450bSKonstantin Belousov KASSERT(csw != NULL, ("Eternal cdev is destroyed")); 2273979450bSKonstantin Belousov *devp = dev; 2283979450bSKonstantin Belousov return (csw); 2293979450bSKonstantin Belousov } 2303979450bSKonstantin Belousov 2311663075cSKonstantin Belousov csw = NULL; 2321663075cSKonstantin Belousov dev_lock(); 2333979450bSKonstantin Belousov dev = vp->v_rdev; 2343979450bSKonstantin Belousov if (dev == NULL) { 2353979450bSKonstantin Belousov dev_unlock(); 2363979450bSKonstantin Belousov return (NULL); 2371663075cSKonstantin Belousov } 2383979450bSKonstantin Belousov cdp = cdev2priv(dev); 2393979450bSKonstantin Belousov if ((cdp->cdp_flags & CDP_SCHED_DTR) == 0) { 2403979450bSKonstantin Belousov csw = dev->si_devsw; 2413979450bSKonstantin Belousov if (csw != NULL) 2429e8bd2acSAlexander Motin atomic_add_long(&dev->si_threadcount, 1); 243de10ffa5SKonstantin Belousov } 2441663075cSKonstantin Belousov dev_unlock(); 2453979450bSKonstantin Belousov if (csw != NULL) { 2463979450bSKonstantin Belousov *devp = dev; 2473979450bSKonstantin Belousov *ref = 1; 2483979450bSKonstantin Belousov } 2491663075cSKonstantin Belousov return (csw); 2501663075cSKonstantin Belousov } 2511663075cSKonstantin Belousov 2522c15afd8SPoul-Henning Kamp void 2533979450bSKonstantin Belousov dev_relthread(struct cdev *dev, int ref) 2542c15afd8SPoul-Henning Kamp { 2552c15afd8SPoul-Henning Kamp 2562c15afd8SPoul-Henning Kamp mtx_assert(&devmtx, MA_NOTOWNED); 2573979450bSKonstantin Belousov if (!ref) 2583979450bSKonstantin Belousov return; 25906fe1129SKonstantin Belousov KASSERT(dev->si_threadcount > 0, 26006fe1129SKonstantin Belousov ("%s threadcount is wrong", dev->si_name)); 2619e8bd2acSAlexander Motin atomic_subtract_rel_long(&dev->si_threadcount, 1); 2622c15afd8SPoul-Henning Kamp } 263cd690b60SPoul-Henning Kamp 264b2941431SPoul-Henning Kamp int 265b2941431SPoul-Henning Kamp nullop(void) 266b2941431SPoul-Henning Kamp { 267b2941431SPoul-Henning Kamp 268b2941431SPoul-Henning Kamp return (0); 269b2941431SPoul-Henning Kamp } 270b2941431SPoul-Henning Kamp 271b2941431SPoul-Henning Kamp int 272b2941431SPoul-Henning Kamp eopnotsupp(void) 273b2941431SPoul-Henning Kamp { 274b2941431SPoul-Henning Kamp 275b2941431SPoul-Henning Kamp return (EOPNOTSUPP); 276b2941431SPoul-Henning Kamp } 27702574b19SPoul-Henning Kamp 27802574b19SPoul-Henning Kamp static int 27902574b19SPoul-Henning Kamp enxio(void) 28002574b19SPoul-Henning Kamp { 28102574b19SPoul-Henning Kamp return (ENXIO); 28202574b19SPoul-Henning Kamp } 28302574b19SPoul-Henning Kamp 284b2941431SPoul-Henning Kamp static int 285b2941431SPoul-Henning Kamp enodev(void) 286b2941431SPoul-Henning Kamp { 287b2941431SPoul-Henning Kamp return (ENODEV); 288b2941431SPoul-Henning Kamp } 289b2941431SPoul-Henning Kamp 290b2941431SPoul-Henning Kamp /* Define a dead_cdevsw for use when devices leave unexpectedly. */ 291b2941431SPoul-Henning Kamp 29202574b19SPoul-Henning Kamp #define dead_open (d_open_t *)enxio 29302574b19SPoul-Henning Kamp #define dead_close (d_close_t *)enxio 29402574b19SPoul-Henning Kamp #define dead_read (d_read_t *)enxio 29502574b19SPoul-Henning Kamp #define dead_write (d_write_t *)enxio 29602574b19SPoul-Henning Kamp #define dead_ioctl (d_ioctl_t *)enxio 297b2941431SPoul-Henning Kamp #define dead_poll (d_poll_t *)enodev 298b2941431SPoul-Henning Kamp #define dead_mmap (d_mmap_t *)enodev 29902574b19SPoul-Henning Kamp 30002574b19SPoul-Henning Kamp static void 30102574b19SPoul-Henning Kamp dead_strategy(struct bio *bp) 30202574b19SPoul-Henning Kamp { 30302574b19SPoul-Henning Kamp 30402574b19SPoul-Henning Kamp biofinish(bp, NULL, ENXIO); 30502574b19SPoul-Henning Kamp } 30602574b19SPoul-Henning Kamp 3072c6b49f6SPoul-Henning Kamp #define dead_dump (dumper_t *)enxio 30802574b19SPoul-Henning Kamp #define dead_kqfilter (d_kqfilter_t *)enxio 30964345f0bSJohn Baldwin #define dead_mmap_single (d_mmap_single_t *)enodev 31002574b19SPoul-Henning Kamp 31102574b19SPoul-Henning Kamp static struct cdevsw dead_cdevsw = { 312dc08ffecSPoul-Henning Kamp .d_version = D_VERSION, 3137ac40f5fSPoul-Henning Kamp .d_open = dead_open, 3147ac40f5fSPoul-Henning Kamp .d_close = dead_close, 3157ac40f5fSPoul-Henning Kamp .d_read = dead_read, 3167ac40f5fSPoul-Henning Kamp .d_write = dead_write, 3177ac40f5fSPoul-Henning Kamp .d_ioctl = dead_ioctl, 3187ac40f5fSPoul-Henning Kamp .d_poll = dead_poll, 3197ac40f5fSPoul-Henning Kamp .d_mmap = dead_mmap, 3207ac40f5fSPoul-Henning Kamp .d_strategy = dead_strategy, 3217ac40f5fSPoul-Henning Kamp .d_name = "dead", 3227ac40f5fSPoul-Henning Kamp .d_dump = dead_dump, 32364345f0bSJohn Baldwin .d_kqfilter = dead_kqfilter, 32464345f0bSJohn Baldwin .d_mmap_single = dead_mmap_single 32502574b19SPoul-Henning Kamp }; 32602574b19SPoul-Henning Kamp 327b2941431SPoul-Henning Kamp /* Default methods if driver does not specify method */ 328b2941431SPoul-Henning Kamp 329b2941431SPoul-Henning Kamp #define null_open (d_open_t *)nullop 330b2941431SPoul-Henning Kamp #define null_close (d_close_t *)nullop 331b2941431SPoul-Henning Kamp #define no_read (d_read_t *)enodev 332b2941431SPoul-Henning Kamp #define no_write (d_write_t *)enodev 333b2941431SPoul-Henning Kamp #define no_ioctl (d_ioctl_t *)enodev 334cfd7baceSRobert Noland #define no_mmap (d_mmap_t *)enodev 335ad3b9257SJohn-Mark Gurney #define no_kqfilter (d_kqfilter_t *)enodev 33664345f0bSJohn Baldwin #define no_mmap_single (d_mmap_single_t *)enodev 337b2941431SPoul-Henning Kamp 338b2941431SPoul-Henning Kamp static void 339b2941431SPoul-Henning Kamp no_strategy(struct bio *bp) 340b2941431SPoul-Henning Kamp { 341b2941431SPoul-Henning Kamp 342b2941431SPoul-Henning Kamp biofinish(bp, NULL, ENODEV); 343b2941431SPoul-Henning Kamp } 344b2941431SPoul-Henning Kamp 345b2941431SPoul-Henning Kamp static int 34689c9c53dSPoul-Henning Kamp no_poll(struct cdev *dev __unused, int events, struct thread *td __unused) 347b2941431SPoul-Henning Kamp { 348b2941431SPoul-Henning Kamp 349125dcf8cSKonstantin Belousov return (poll_no_poll(events)); 350b2941431SPoul-Henning Kamp } 351b2941431SPoul-Henning Kamp 352b2941431SPoul-Henning Kamp #define no_dump (dumper_t *)enodev 3534e4a7663SPoul-Henning Kamp 354516ad423SPoul-Henning Kamp static int 355516ad423SPoul-Henning Kamp giant_open(struct cdev *dev, int oflags, int devtype, struct thread *td) 356516ad423SPoul-Henning Kamp { 357aeeb4202SKonstantin Belousov struct cdevsw *dsw; 3583979450bSKonstantin Belousov int ref, retval; 359516ad423SPoul-Henning Kamp 3603979450bSKonstantin Belousov dsw = dev_refthread(dev, &ref); 361aeeb4202SKonstantin Belousov if (dsw == NULL) 362aeeb4202SKonstantin Belousov return (ENXIO); 363516ad423SPoul-Henning Kamp mtx_lock(&Giant); 364aeeb4202SKonstantin Belousov retval = dsw->d_gianttrick->d_open(dev, oflags, devtype, td); 365516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 3663979450bSKonstantin Belousov dev_relthread(dev, ref); 367516ad423SPoul-Henning Kamp return (retval); 368516ad423SPoul-Henning Kamp } 369516ad423SPoul-Henning Kamp 370516ad423SPoul-Henning Kamp static int 3719e223287SKonstantin Belousov giant_fdopen(struct cdev *dev, int oflags, struct thread *td, struct file *fp) 372516ad423SPoul-Henning Kamp { 373aeeb4202SKonstantin Belousov struct cdevsw *dsw; 3743979450bSKonstantin Belousov int ref, retval; 375516ad423SPoul-Henning Kamp 3763979450bSKonstantin Belousov dsw = dev_refthread(dev, &ref); 377aeeb4202SKonstantin Belousov if (dsw == NULL) 378aeeb4202SKonstantin Belousov return (ENXIO); 379516ad423SPoul-Henning Kamp mtx_lock(&Giant); 380aeeb4202SKonstantin Belousov retval = dsw->d_gianttrick->d_fdopen(dev, oflags, td, fp); 381516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 3823979450bSKonstantin Belousov dev_relthread(dev, ref); 383516ad423SPoul-Henning Kamp return (retval); 384516ad423SPoul-Henning Kamp } 385516ad423SPoul-Henning Kamp 386516ad423SPoul-Henning Kamp static int 387516ad423SPoul-Henning Kamp giant_close(struct cdev *dev, int fflag, int devtype, struct thread *td) 388516ad423SPoul-Henning Kamp { 389aeeb4202SKonstantin Belousov struct cdevsw *dsw; 3903979450bSKonstantin Belousov int ref, retval; 391516ad423SPoul-Henning Kamp 3923979450bSKonstantin Belousov dsw = dev_refthread(dev, &ref); 393aeeb4202SKonstantin Belousov if (dsw == NULL) 394aeeb4202SKonstantin Belousov return (ENXIO); 395516ad423SPoul-Henning Kamp mtx_lock(&Giant); 396aeeb4202SKonstantin Belousov retval = dsw->d_gianttrick->d_close(dev, fflag, devtype, td); 397516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 3983979450bSKonstantin Belousov dev_relthread(dev, ref); 399516ad423SPoul-Henning Kamp return (retval); 400516ad423SPoul-Henning Kamp } 401516ad423SPoul-Henning Kamp 402516ad423SPoul-Henning Kamp static void 403516ad423SPoul-Henning Kamp giant_strategy(struct bio *bp) 404516ad423SPoul-Henning Kamp { 405aeeb4202SKonstantin Belousov struct cdevsw *dsw; 406aeeb4202SKonstantin Belousov struct cdev *dev; 4073979450bSKonstantin Belousov int ref; 408516ad423SPoul-Henning Kamp 409aeeb4202SKonstantin Belousov dev = bp->bio_dev; 4103979450bSKonstantin Belousov dsw = dev_refthread(dev, &ref); 411aeeb4202SKonstantin Belousov if (dsw == NULL) { 412aeeb4202SKonstantin Belousov biofinish(bp, NULL, ENXIO); 413aeeb4202SKonstantin Belousov return; 414aeeb4202SKonstantin Belousov } 415516ad423SPoul-Henning Kamp mtx_lock(&Giant); 416aeeb4202SKonstantin Belousov dsw->d_gianttrick->d_strategy(bp); 417516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 4183979450bSKonstantin Belousov dev_relthread(dev, ref); 419516ad423SPoul-Henning Kamp } 420516ad423SPoul-Henning Kamp 421516ad423SPoul-Henning Kamp static int 422516ad423SPoul-Henning Kamp giant_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct thread *td) 423516ad423SPoul-Henning Kamp { 424aeeb4202SKonstantin Belousov struct cdevsw *dsw; 4253979450bSKonstantin Belousov int ref, retval; 426516ad423SPoul-Henning Kamp 4273979450bSKonstantin Belousov dsw = dev_refthread(dev, &ref); 428aeeb4202SKonstantin Belousov if (dsw == NULL) 429aeeb4202SKonstantin Belousov return (ENXIO); 430516ad423SPoul-Henning Kamp mtx_lock(&Giant); 43135b45029SKonstantin Belousov retval = dsw->d_gianttrick->d_ioctl(dev, cmd, data, fflag, td); 432516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 4333979450bSKonstantin Belousov dev_relthread(dev, ref); 434516ad423SPoul-Henning Kamp return (retval); 435516ad423SPoul-Henning Kamp } 436516ad423SPoul-Henning Kamp 437516ad423SPoul-Henning Kamp static int 438516ad423SPoul-Henning Kamp giant_read(struct cdev *dev, struct uio *uio, int ioflag) 439516ad423SPoul-Henning Kamp { 440aeeb4202SKonstantin Belousov struct cdevsw *dsw; 4413979450bSKonstantin Belousov int ref, retval; 442516ad423SPoul-Henning Kamp 4433979450bSKonstantin Belousov dsw = dev_refthread(dev, &ref); 444aeeb4202SKonstantin Belousov if (dsw == NULL) 445aeeb4202SKonstantin Belousov return (ENXIO); 446516ad423SPoul-Henning Kamp mtx_lock(&Giant); 44735b45029SKonstantin Belousov retval = dsw->d_gianttrick->d_read(dev, uio, ioflag); 448516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 4493979450bSKonstantin Belousov dev_relthread(dev, ref); 450516ad423SPoul-Henning Kamp return (retval); 451516ad423SPoul-Henning Kamp } 452516ad423SPoul-Henning Kamp 453516ad423SPoul-Henning Kamp static int 454516ad423SPoul-Henning Kamp giant_write(struct cdev *dev, struct uio *uio, int ioflag) 455516ad423SPoul-Henning Kamp { 456aeeb4202SKonstantin Belousov struct cdevsw *dsw; 4573979450bSKonstantin Belousov int ref, retval; 458516ad423SPoul-Henning Kamp 4593979450bSKonstantin Belousov dsw = dev_refthread(dev, &ref); 460aeeb4202SKonstantin Belousov if (dsw == NULL) 461aeeb4202SKonstantin Belousov return (ENXIO); 462516ad423SPoul-Henning Kamp mtx_lock(&Giant); 463aeeb4202SKonstantin Belousov retval = dsw->d_gianttrick->d_write(dev, uio, ioflag); 464516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 4653979450bSKonstantin Belousov dev_relthread(dev, ref); 466516ad423SPoul-Henning Kamp return (retval); 467516ad423SPoul-Henning Kamp } 468516ad423SPoul-Henning Kamp 469516ad423SPoul-Henning Kamp static int 470516ad423SPoul-Henning Kamp giant_poll(struct cdev *dev, int events, struct thread *td) 471516ad423SPoul-Henning Kamp { 472aeeb4202SKonstantin Belousov struct cdevsw *dsw; 4733979450bSKonstantin Belousov int ref, retval; 474516ad423SPoul-Henning Kamp 4753979450bSKonstantin Belousov dsw = dev_refthread(dev, &ref); 476aeeb4202SKonstantin Belousov if (dsw == NULL) 477aeeb4202SKonstantin Belousov return (ENXIO); 478516ad423SPoul-Henning Kamp mtx_lock(&Giant); 479aeeb4202SKonstantin Belousov retval = dsw->d_gianttrick->d_poll(dev, events, td); 480516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 4813979450bSKonstantin Belousov dev_relthread(dev, ref); 482516ad423SPoul-Henning Kamp return (retval); 483516ad423SPoul-Henning Kamp } 484516ad423SPoul-Henning Kamp 485516ad423SPoul-Henning Kamp static int 486516ad423SPoul-Henning Kamp giant_kqfilter(struct cdev *dev, struct knote *kn) 487516ad423SPoul-Henning Kamp { 488aeeb4202SKonstantin Belousov struct cdevsw *dsw; 4893979450bSKonstantin Belousov int ref, retval; 490516ad423SPoul-Henning Kamp 4913979450bSKonstantin Belousov dsw = dev_refthread(dev, &ref); 492aeeb4202SKonstantin Belousov if (dsw == NULL) 493aeeb4202SKonstantin Belousov return (ENXIO); 494516ad423SPoul-Henning Kamp mtx_lock(&Giant); 495aeeb4202SKonstantin Belousov retval = dsw->d_gianttrick->d_kqfilter(dev, kn); 496516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 4973979450bSKonstantin Belousov dev_relthread(dev, ref); 498516ad423SPoul-Henning Kamp return (retval); 499516ad423SPoul-Henning Kamp } 500516ad423SPoul-Henning Kamp 501516ad423SPoul-Henning Kamp static int 502cfd7baceSRobert Noland giant_mmap(struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr, int nprot, 5032fa8c8d2SJohn Baldwin vm_memattr_t *memattr) 504516ad423SPoul-Henning Kamp { 505aeeb4202SKonstantin Belousov struct cdevsw *dsw; 5063979450bSKonstantin Belousov int ref, retval; 507516ad423SPoul-Henning Kamp 5083979450bSKonstantin Belousov dsw = dev_refthread(dev, &ref); 509aeeb4202SKonstantin Belousov if (dsw == NULL) 510aeeb4202SKonstantin Belousov return (ENXIO); 511516ad423SPoul-Henning Kamp mtx_lock(&Giant); 512cfd7baceSRobert Noland retval = dsw->d_gianttrick->d_mmap(dev, offset, paddr, nprot, 5132fa8c8d2SJohn Baldwin memattr); 514516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 5153979450bSKonstantin Belousov dev_relthread(dev, ref); 516516ad423SPoul-Henning Kamp return (retval); 517516ad423SPoul-Henning Kamp } 518516ad423SPoul-Henning Kamp 51964345f0bSJohn Baldwin static int 52064345f0bSJohn Baldwin giant_mmap_single(struct cdev *dev, vm_ooffset_t *offset, vm_size_t size, 52164345f0bSJohn Baldwin vm_object_t *object, int nprot) 52264345f0bSJohn Baldwin { 52364345f0bSJohn Baldwin struct cdevsw *dsw; 5243979450bSKonstantin Belousov int ref, retval; 52564345f0bSJohn Baldwin 5263979450bSKonstantin Belousov dsw = dev_refthread(dev, &ref); 52764345f0bSJohn Baldwin if (dsw == NULL) 52864345f0bSJohn Baldwin return (ENXIO); 52964345f0bSJohn Baldwin mtx_lock(&Giant); 53064345f0bSJohn Baldwin retval = dsw->d_gianttrick->d_mmap_single(dev, offset, size, object, 53164345f0bSJohn Baldwin nprot); 53264345f0bSJohn Baldwin mtx_unlock(&Giant); 5333979450bSKonstantin Belousov dev_relthread(dev, ref); 53464345f0bSJohn Baldwin return (retval); 53564345f0bSJohn Baldwin } 536516ad423SPoul-Henning Kamp 53748504cc2SKonstantin Belousov static void 538d2ba618aSKonstantin Belousov notify(struct cdev *dev, const char *ev, int flags) 53948504cc2SKonstantin Belousov { 54048504cc2SKonstantin Belousov static const char prefix[] = "cdev="; 54148504cc2SKonstantin Belousov char *data; 54276d43557SKonstantin Belousov int namelen, mflags; 54348504cc2SKonstantin Belousov 54448504cc2SKonstantin Belousov if (cold) 54548504cc2SKonstantin Belousov return; 54676d43557SKonstantin Belousov mflags = (flags & MAKEDEV_NOWAIT) ? M_NOWAIT : M_WAITOK; 54748504cc2SKonstantin Belousov namelen = strlen(dev->si_name); 54876d43557SKonstantin Belousov data = malloc(namelen + sizeof(prefix), M_TEMP, mflags); 5499995e57bSAttilio Rao if (data == NULL) 5509995e57bSAttilio Rao return; 55148504cc2SKonstantin Belousov memcpy(data, prefix, sizeof(prefix) - 1); 55248504cc2SKonstantin Belousov memcpy(data + sizeof(prefix) - 1, dev->si_name, namelen + 1); 55376d43557SKonstantin Belousov devctl_notify_f("DEVFS", "CDEV", ev, data, mflags); 55448504cc2SKonstantin Belousov free(data, M_TEMP); 55548504cc2SKonstantin Belousov } 55648504cc2SKonstantin Belousov 55748504cc2SKonstantin Belousov static void 558d2ba618aSKonstantin Belousov notify_create(struct cdev *dev, int flags) 55948504cc2SKonstantin Belousov { 56048504cc2SKonstantin Belousov 561d2ba618aSKonstantin Belousov notify(dev, "CREATE", flags); 56248504cc2SKonstantin Belousov } 56348504cc2SKonstantin Belousov 56448504cc2SKonstantin Belousov static void 56548504cc2SKonstantin Belousov notify_destroy(struct cdev *dev) 56648504cc2SKonstantin Belousov { 56748504cc2SKonstantin Belousov 568d2ba618aSKonstantin Belousov notify(dev, "DESTROY", MAKEDEV_WAITOK); 56948504cc2SKonstantin Belousov } 57048504cc2SKonstantin Belousov 57189c9c53dSPoul-Henning Kamp static struct cdev * 57248ce5d4cSKonstantin Belousov newdev(struct make_dev_args *args, struct cdev *si) 5733f54a085SPoul-Henning Kamp { 574027b1f71SPoul-Henning Kamp struct cdev *si2; 57548ce5d4cSKonstantin Belousov struct cdevsw *csw; 5763f54a085SPoul-Henning Kamp 577027b1f71SPoul-Henning Kamp mtx_assert(&devmtx, MA_OWNED); 57848ce5d4cSKonstantin Belousov csw = args->mda_devsw; 57929d4cb24SEd Schouten if (csw->d_flags & D_NEEDMINOR) { 58029d4cb24SEd Schouten /* We may want to return an existing device */ 581ff7284eeSPoul-Henning Kamp LIST_FOREACH(si2, &csw->d_devs, si_list) { 58248ce5d4cSKonstantin Belousov if (dev2unit(si2) == args->mda_unit) { 5839bc911d4SKonstantin Belousov dev_free_devlocked(si); 584027b1f71SPoul-Henning Kamp return (si2); 5853f54a085SPoul-Henning Kamp } 586027b1f71SPoul-Henning Kamp } 58729d4cb24SEd Schouten } 58848ce5d4cSKonstantin Belousov si->si_drv0 = args->mda_unit; 589e606a3c6SPoul-Henning Kamp si->si_devsw = csw; 59048ce5d4cSKonstantin Belousov si->si_drv1 = args->mda_si_drv1; 59148ce5d4cSKonstantin Belousov si->si_drv2 = args->mda_si_drv2; 592ff7284eeSPoul-Henning Kamp LIST_INSERT_HEAD(&csw->d_devs, si, si_list); 593698bfad7SPoul-Henning Kamp return (si); 594bfbb9ce6SPoul-Henning Kamp } 595bfbb9ce6SPoul-Henning Kamp 5962a3faf2fSPoul-Henning Kamp static void 597cd690b60SPoul-Henning Kamp fini_cdevsw(struct cdevsw *devsw) 598cd690b60SPoul-Henning Kamp { 5991d45c50eSPoul-Henning Kamp struct cdevsw *gt; 600b3d82c03SPoul-Henning Kamp 6011d45c50eSPoul-Henning Kamp if (devsw->d_gianttrick != NULL) { 6021d45c50eSPoul-Henning Kamp gt = devsw->d_gianttrick; 6031d45c50eSPoul-Henning Kamp memcpy(devsw, gt, sizeof *devsw); 604aeeb4202SKonstantin Belousov cdevsw_free_devlocked(gt); 605516ad423SPoul-Henning Kamp devsw->d_gianttrick = NULL; 6061d45c50eSPoul-Henning Kamp } 607652d0472SPoul-Henning Kamp devsw->d_flags &= ~D_INIT; 608b0b03348SPoul-Henning Kamp } 609b0b03348SPoul-Henning Kamp 610d2ba618aSKonstantin Belousov static int 611d2ba618aSKonstantin Belousov prep_cdevsw(struct cdevsw *devsw, int flags) 612b0b03348SPoul-Henning Kamp { 613516ad423SPoul-Henning Kamp struct cdevsw *dsw2; 614b0b03348SPoul-Henning Kamp 615aeeb4202SKonstantin Belousov mtx_assert(&devmtx, MA_OWNED); 616aeeb4202SKonstantin Belousov if (devsw->d_flags & D_INIT) 617f1bb758dSKonstantin Belousov return (0); 618aeeb4202SKonstantin Belousov if (devsw->d_flags & D_NEEDGIANT) { 619aeeb4202SKonstantin Belousov dev_unlock(); 620d2ba618aSKonstantin Belousov dsw2 = malloc(sizeof *dsw2, M_DEVT, 621d2ba618aSKonstantin Belousov (flags & MAKEDEV_NOWAIT) ? M_NOWAIT : M_WAITOK); 622a0e78d2eSPoul-Henning Kamp dev_lock(); 623d2ba618aSKonstantin Belousov if (dsw2 == NULL && !(devsw->d_flags & D_INIT)) 624f1bb758dSKonstantin Belousov return (ENOMEM); 625aeeb4202SKonstantin Belousov } else 626aeeb4202SKonstantin Belousov dsw2 = NULL; 627aeeb4202SKonstantin Belousov if (devsw->d_flags & D_INIT) { 628aeeb4202SKonstantin Belousov if (dsw2 != NULL) 629aeeb4202SKonstantin Belousov cdevsw_free_devlocked(dsw2); 630f1bb758dSKonstantin Belousov return (0); 631aeeb4202SKonstantin Belousov } 632cd690b60SPoul-Henning Kamp 633*e5ac3049SKonstantin Belousov if (devsw->d_version != D_VERSION_04) { 634cd690b60SPoul-Henning Kamp printf( 635cd690b60SPoul-Henning Kamp "WARNING: Device driver \"%s\" has wrong version %s\n", 6367d7e053cSAlfred Perlstein devsw->d_name == NULL ? "???" : devsw->d_name, 6377d7e053cSAlfred Perlstein "and is disabled. Recompile KLD module."); 638cd690b60SPoul-Henning Kamp devsw->d_open = dead_open; 639cd690b60SPoul-Henning Kamp devsw->d_close = dead_close; 640cd690b60SPoul-Henning Kamp devsw->d_read = dead_read; 641cd690b60SPoul-Henning Kamp devsw->d_write = dead_write; 642cd690b60SPoul-Henning Kamp devsw->d_ioctl = dead_ioctl; 643cd690b60SPoul-Henning Kamp devsw->d_poll = dead_poll; 644cd690b60SPoul-Henning Kamp devsw->d_mmap = dead_mmap; 645cfd7baceSRobert Noland devsw->d_mmap_single = dead_mmap_single; 646cd690b60SPoul-Henning Kamp devsw->d_strategy = dead_strategy; 647cd690b60SPoul-Henning Kamp devsw->d_dump = dead_dump; 648cd690b60SPoul-Henning Kamp devsw->d_kqfilter = dead_kqfilter; 649cd690b60SPoul-Henning Kamp } 650cd690b60SPoul-Henning Kamp 651516ad423SPoul-Henning Kamp if (devsw->d_flags & D_NEEDGIANT) { 652516ad423SPoul-Henning Kamp if (devsw->d_gianttrick == NULL) { 653516ad423SPoul-Henning Kamp memcpy(dsw2, devsw, sizeof *dsw2); 654516ad423SPoul-Henning Kamp devsw->d_gianttrick = dsw2; 655aeeb4202SKonstantin Belousov dsw2 = NULL; 656aeeb4202SKonstantin Belousov } 657516ad423SPoul-Henning Kamp } 658516ad423SPoul-Henning Kamp 659516ad423SPoul-Henning Kamp #define FIXUP(member, noop, giant) \ 660516ad423SPoul-Henning Kamp do { \ 661516ad423SPoul-Henning Kamp if (devsw->member == NULL) { \ 662516ad423SPoul-Henning Kamp devsw->member = noop; \ 663516ad423SPoul-Henning Kamp } else if (devsw->d_flags & D_NEEDGIANT) \ 664516ad423SPoul-Henning Kamp devsw->member = giant; \ 665516ad423SPoul-Henning Kamp } \ 666516ad423SPoul-Henning Kamp while (0) 667516ad423SPoul-Henning Kamp 668516ad423SPoul-Henning Kamp FIXUP(d_open, null_open, giant_open); 669516ad423SPoul-Henning Kamp FIXUP(d_fdopen, NULL, giant_fdopen); 670516ad423SPoul-Henning Kamp FIXUP(d_close, null_close, giant_close); 671516ad423SPoul-Henning Kamp FIXUP(d_read, no_read, giant_read); 672516ad423SPoul-Henning Kamp FIXUP(d_write, no_write, giant_write); 673516ad423SPoul-Henning Kamp FIXUP(d_ioctl, no_ioctl, giant_ioctl); 674516ad423SPoul-Henning Kamp FIXUP(d_poll, no_poll, giant_poll); 675cfd7baceSRobert Noland FIXUP(d_mmap, no_mmap, giant_mmap); 676516ad423SPoul-Henning Kamp FIXUP(d_strategy, no_strategy, giant_strategy); 677516ad423SPoul-Henning Kamp FIXUP(d_kqfilter, no_kqfilter, giant_kqfilter); 67864345f0bSJohn Baldwin FIXUP(d_mmap_single, no_mmap_single, giant_mmap_single); 679516ad423SPoul-Henning Kamp 680b2941431SPoul-Henning Kamp if (devsw->d_dump == NULL) devsw->d_dump = no_dump; 681cd690b60SPoul-Henning Kamp 682cd690b60SPoul-Henning Kamp LIST_INIT(&devsw->d_devs); 683cd690b60SPoul-Henning Kamp 684cd690b60SPoul-Henning Kamp devsw->d_flags |= D_INIT; 685cd690b60SPoul-Henning Kamp 686aeeb4202SKonstantin Belousov if (dsw2 != NULL) 687aeeb4202SKonstantin Belousov cdevsw_free_devlocked(dsw2); 688f1bb758dSKonstantin Belousov return (0); 6892a3faf2fSPoul-Henning Kamp } 69011586717SBrian Somers 691f1bb758dSKonstantin Belousov static int 69268f7a013SJaakko Heinonen prep_devname(struct cdev *dev, const char *fmt, va_list ap) 69368f7a013SJaakko Heinonen { 69468f7a013SJaakko Heinonen int len; 69568f7a013SJaakko Heinonen char *from, *q, *s, *to; 69668f7a013SJaakko Heinonen 69768f7a013SJaakko Heinonen mtx_assert(&devmtx, MA_OWNED); 69868f7a013SJaakko Heinonen 699852b05c5SEd Schouten len = vsnrprintf(dev->si_name, sizeof(dev->si_name), 32, fmt, ap); 7008fac9b7bSEd Schouten if (len > sizeof(dev->si_name) - 1) 70168f7a013SJaakko Heinonen return (ENAMETOOLONG); 70268f7a013SJaakko Heinonen 70368f7a013SJaakko Heinonen /* Strip leading slashes. */ 7048fac9b7bSEd Schouten for (from = dev->si_name; *from == '/'; from++) 70568f7a013SJaakko Heinonen ; 70668f7a013SJaakko Heinonen 7078fac9b7bSEd Schouten for (to = dev->si_name; *from != '\0'; from++, to++) { 708b1e1f725SJaakko Heinonen /* 709b1e1f725SJaakko Heinonen * Spaces and double quotation marks cause 710b1e1f725SJaakko Heinonen * problems for the devctl(4) protocol. 711b1e1f725SJaakko Heinonen * Reject names containing those characters. 712b1e1f725SJaakko Heinonen */ 713b1e1f725SJaakko Heinonen if (isspace(*from) || *from == '"') 714b1e1f725SJaakko Heinonen return (EINVAL); 71568f7a013SJaakko Heinonen /* Treat multiple sequential slashes as single. */ 71668f7a013SJaakko Heinonen while (from[0] == '/' && from[1] == '/') 71768f7a013SJaakko Heinonen from++; 71868f7a013SJaakko Heinonen /* Trailing slash is considered invalid. */ 71968f7a013SJaakko Heinonen if (from[0] == '/' && from[1] == '\0') 72068f7a013SJaakko Heinonen return (EINVAL); 72168f7a013SJaakko Heinonen *to = *from; 72268f7a013SJaakko Heinonen } 72368f7a013SJaakko Heinonen *to = '\0'; 72468f7a013SJaakko Heinonen 7258fac9b7bSEd Schouten if (dev->si_name[0] == '\0') 72668f7a013SJaakko Heinonen return (EINVAL); 72768f7a013SJaakko Heinonen 72868f7a013SJaakko Heinonen /* Disallow "." and ".." components. */ 7298fac9b7bSEd Schouten for (s = dev->si_name;;) { 73068f7a013SJaakko Heinonen for (q = s; *q != '/' && *q != '\0'; q++) 73168f7a013SJaakko Heinonen ; 73268f7a013SJaakko Heinonen if (q - s == 1 && s[0] == '.') 73368f7a013SJaakko Heinonen return (EINVAL); 73468f7a013SJaakko Heinonen if (q - s == 2 && s[0] == '.' && s[1] == '.') 73568f7a013SJaakko Heinonen return (EINVAL); 73668f7a013SJaakko Heinonen if (*q != '/') 73768f7a013SJaakko Heinonen break; 73868f7a013SJaakko Heinonen s = q + 1; 73968f7a013SJaakko Heinonen } 74068f7a013SJaakko Heinonen 7418fac9b7bSEd Schouten if (devfs_dev_exists(dev->si_name) != 0) 74268f7a013SJaakko Heinonen return (EEXIST); 74368f7a013SJaakko Heinonen 74468f7a013SJaakko Heinonen return (0); 74568f7a013SJaakko Heinonen } 74668f7a013SJaakko Heinonen 74748ce5d4cSKonstantin Belousov void 74848ce5d4cSKonstantin Belousov make_dev_args_init_impl(struct make_dev_args *args, size_t sz) 74948ce5d4cSKonstantin Belousov { 75048ce5d4cSKonstantin Belousov 75148ce5d4cSKonstantin Belousov bzero(args, sz); 75248ce5d4cSKonstantin Belousov args->mda_size = sz; 75348ce5d4cSKonstantin Belousov } 75448ce5d4cSKonstantin Belousov 75568f7a013SJaakko Heinonen static int 75648ce5d4cSKonstantin Belousov make_dev_sv(struct make_dev_args *args1, struct cdev **dres, 75748ce5d4cSKonstantin Belousov const char *fmt, va_list ap) 7582a3faf2fSPoul-Henning Kamp { 75968f7a013SJaakko Heinonen struct cdev *dev, *dev_new; 76048ce5d4cSKonstantin Belousov struct make_dev_args args; 76168f7a013SJaakko Heinonen int res; 7622a3faf2fSPoul-Henning Kamp 76348ce5d4cSKonstantin Belousov bzero(&args, sizeof(args)); 76448ce5d4cSKonstantin Belousov if (sizeof(args) < args1->mda_size) 76548ce5d4cSKonstantin Belousov return (EINVAL); 76648ce5d4cSKonstantin Belousov bcopy(args1, &args, args1->mda_size); 76748ce5d4cSKonstantin Belousov KASSERT((args.mda_flags & MAKEDEV_WAITOK) == 0 || 76848ce5d4cSKonstantin Belousov (args.mda_flags & MAKEDEV_NOWAIT) == 0, 76948ce5d4cSKonstantin Belousov ("make_dev_sv: both WAITOK and NOWAIT specified")); 77048ce5d4cSKonstantin Belousov dev_new = devfs_alloc(args.mda_flags); 77168f7a013SJaakko Heinonen if (dev_new == NULL) 772f1bb758dSKonstantin Belousov return (ENOMEM); 773027b1f71SPoul-Henning Kamp dev_lock(); 77448ce5d4cSKonstantin Belousov res = prep_cdevsw(args.mda_devsw, args.mda_flags); 775f1bb758dSKonstantin Belousov if (res != 0) { 776d2ba618aSKonstantin Belousov dev_unlock(); 77768f7a013SJaakko Heinonen devfs_free(dev_new); 778f1bb758dSKonstantin Belousov return (res); 779d2ba618aSKonstantin Belousov } 78048ce5d4cSKonstantin Belousov dev = newdev(&args, dev_new); 781ff91cc99SJaakko Heinonen if ((dev->si_flags & SI_NAMED) == 0) { 78268f7a013SJaakko Heinonen res = prep_devname(dev, fmt, ap); 78368f7a013SJaakko Heinonen if (res != 0) { 78448ce5d4cSKonstantin Belousov if ((args.mda_flags & MAKEDEV_CHECKNAME) == 0) { 78568f7a013SJaakko Heinonen panic( 78648ce5d4cSKonstantin Belousov "make_dev_sv: bad si_name (error=%d, si_name=%s)", 78768f7a013SJaakko Heinonen res, dev->si_name); 78868f7a013SJaakko Heinonen } 78968f7a013SJaakko Heinonen if (dev == dev_new) { 79068f7a013SJaakko Heinonen LIST_REMOVE(dev, si_list); 79168f7a013SJaakko Heinonen dev_unlock(); 79268f7a013SJaakko Heinonen devfs_free(dev); 793889dffbaSKonstantin Belousov } else 794889dffbaSKonstantin Belousov dev_unlock(); 79568f7a013SJaakko Heinonen return (res); 79668f7a013SJaakko Heinonen } 797ff91cc99SJaakko Heinonen } 79848ce5d4cSKonstantin Belousov if ((args.mda_flags & MAKEDEV_REF) != 0) 799de10ffa5SKonstantin Belousov dev_refl(dev); 80048ce5d4cSKonstantin Belousov if ((args.mda_flags & MAKEDEV_ETERNAL) != 0) 8013979450bSKonstantin Belousov dev->si_flags |= SI_ETERNAL; 80298c469d4SPoul-Henning Kamp if (dev->si_flags & SI_CHEAPCLONE && 803e606a3c6SPoul-Henning Kamp dev->si_flags & SI_NAMED) { 80498c469d4SPoul-Henning Kamp /* 80598c469d4SPoul-Henning Kamp * This is allowed as it removes races and generally 80698c469d4SPoul-Henning Kamp * simplifies cloning devices. 807cd690b60SPoul-Henning Kamp * XXX: still ?? 80898c469d4SPoul-Henning Kamp */ 8099bc911d4SKonstantin Belousov dev_unlock_and_free(); 810f1bb758dSKonstantin Belousov *dres = dev; 811f1bb758dSKonstantin Belousov return (0); 81298c469d4SPoul-Henning Kamp } 813cd690b60SPoul-Henning Kamp KASSERT(!(dev->si_flags & SI_NAMED), 814ff7284eeSPoul-Henning Kamp ("make_dev() by driver %s on pre-existing device (min=%x, name=%s)", 81548ce5d4cSKonstantin Belousov args.mda_devsw->d_name, dev2unit(dev), devtoname(dev))); 8165ef2707eSPoul-Henning Kamp dev->si_flags |= SI_NAMED; 81748ce5d4cSKonstantin Belousov if (args.mda_cr != NULL) 81848ce5d4cSKonstantin Belousov dev->si_cred = crhold(args.mda_cr); 81948ce5d4cSKonstantin Belousov dev->si_uid = args.mda_uid; 82048ce5d4cSKonstantin Belousov dev->si_gid = args.mda_gid; 82148ce5d4cSKonstantin Belousov dev->si_mode = args.mda_mode; 8221744fcd0SJulian Elischer 8239285a87eSPoul-Henning Kamp devfs_create(dev); 82409828ba9SKonstantin Belousov clean_unrhdrl(devfs_inos); 825aeeb4202SKonstantin Belousov dev_unlock_and_free(); 82648504cc2SKonstantin Belousov 82748ce5d4cSKonstantin Belousov notify_create(dev, args.mda_flags); 82848504cc2SKonstantin Belousov 829f1bb758dSKonstantin Belousov *dres = dev; 830f1bb758dSKonstantin Belousov return (0); 8313f54a085SPoul-Henning Kamp } 8323f54a085SPoul-Henning Kamp 83348ce5d4cSKonstantin Belousov int 83448ce5d4cSKonstantin Belousov make_dev_s(struct make_dev_args *args, struct cdev **dres, 83548ce5d4cSKonstantin Belousov const char *fmt, ...) 83648ce5d4cSKonstantin Belousov { 83748ce5d4cSKonstantin Belousov va_list ap; 83848ce5d4cSKonstantin Belousov int res; 83948ce5d4cSKonstantin Belousov 84048ce5d4cSKonstantin Belousov va_start(ap, fmt); 84148ce5d4cSKonstantin Belousov res = make_dev_sv(args, dres, fmt, ap); 84248ce5d4cSKonstantin Belousov va_end(ap); 84348ce5d4cSKonstantin Belousov return (res); 84448ce5d4cSKonstantin Belousov } 84548ce5d4cSKonstantin Belousov 84648ce5d4cSKonstantin Belousov static int 84748ce5d4cSKonstantin Belousov make_dev_credv(int flags, struct cdev **dres, struct cdevsw *devsw, int unit, 84848ce5d4cSKonstantin Belousov struct ucred *cr, uid_t uid, gid_t gid, int mode, const char *fmt, 84948ce5d4cSKonstantin Belousov va_list ap) 85048ce5d4cSKonstantin Belousov { 85148ce5d4cSKonstantin Belousov struct make_dev_args args; 85248ce5d4cSKonstantin Belousov 85348ce5d4cSKonstantin Belousov make_dev_args_init(&args); 85448ce5d4cSKonstantin Belousov args.mda_flags = flags; 85548ce5d4cSKonstantin Belousov args.mda_devsw = devsw; 85648ce5d4cSKonstantin Belousov args.mda_cr = cr; 85748ce5d4cSKonstantin Belousov args.mda_uid = uid; 85848ce5d4cSKonstantin Belousov args.mda_gid = gid; 85948ce5d4cSKonstantin Belousov args.mda_mode = mode; 86048ce5d4cSKonstantin Belousov args.mda_unit = unit; 86148ce5d4cSKonstantin Belousov return (make_dev_sv(&args, dres, fmt, ap)); 86248ce5d4cSKonstantin Belousov } 86348ce5d4cSKonstantin Belousov 864d26dd2d9SRobert Watson struct cdev * 865edde8745SEd Schouten make_dev(struct cdevsw *devsw, int unit, uid_t uid, gid_t gid, int mode, 866d26dd2d9SRobert Watson const char *fmt, ...) 867d26dd2d9SRobert Watson { 868d26dd2d9SRobert Watson struct cdev *dev; 869d26dd2d9SRobert Watson va_list ap; 8706fa5abfdSMatt Macy int res __unused; 871d26dd2d9SRobert Watson 872d26dd2d9SRobert Watson va_start(ap, fmt); 8736fa5abfdSMatt Macy res = make_dev_credv(0, &dev, devsw, unit, NULL, uid, gid, mode, fmt, 8746fa5abfdSMatt Macy ap); 875d26dd2d9SRobert Watson va_end(ap); 87668f7a013SJaakko Heinonen KASSERT(res == 0 && dev != NULL, 87768f7a013SJaakko Heinonen ("make_dev: failed make_dev_credv (error=%d)", res)); 878d26dd2d9SRobert Watson return (dev); 879d26dd2d9SRobert Watson } 880d26dd2d9SRobert Watson 881d26dd2d9SRobert Watson struct cdev * 882edde8745SEd Schouten make_dev_cred(struct cdevsw *devsw, int unit, struct ucred *cr, uid_t uid, 883d26dd2d9SRobert Watson gid_t gid, int mode, const char *fmt, ...) 884d26dd2d9SRobert Watson { 885d26dd2d9SRobert Watson struct cdev *dev; 886d26dd2d9SRobert Watson va_list ap; 8876fa5abfdSMatt Macy int res __unused; 888d26dd2d9SRobert Watson 889d26dd2d9SRobert Watson va_start(ap, fmt); 8906fa5abfdSMatt Macy res = make_dev_credv(0, &dev, devsw, unit, cr, uid, gid, mode, fmt, ap); 891de10ffa5SKonstantin Belousov va_end(ap); 892de10ffa5SKonstantin Belousov 893f1bb758dSKonstantin Belousov KASSERT(res == 0 && dev != NULL, 89468f7a013SJaakko Heinonen ("make_dev_cred: failed make_dev_credv (error=%d)", res)); 895de10ffa5SKonstantin Belousov return (dev); 896de10ffa5SKonstantin Belousov } 897de10ffa5SKonstantin Belousov 898de10ffa5SKonstantin Belousov struct cdev * 899f1bb758dSKonstantin Belousov make_dev_credf(int flags, struct cdevsw *devsw, int unit, struct ucred *cr, 900f1bb758dSKonstantin Belousov uid_t uid, gid_t gid, int mode, const char *fmt, ...) 901de10ffa5SKonstantin Belousov { 902de10ffa5SKonstantin Belousov struct cdev *dev; 903de10ffa5SKonstantin Belousov va_list ap; 904f1bb758dSKonstantin Belousov int res; 905de10ffa5SKonstantin Belousov 906de10ffa5SKonstantin Belousov va_start(ap, fmt); 907f1bb758dSKonstantin Belousov res = make_dev_credv(flags, &dev, devsw, unit, cr, uid, gid, mode, 908de10ffa5SKonstantin Belousov fmt, ap); 909d26dd2d9SRobert Watson va_end(ap); 910d26dd2d9SRobert Watson 91168f7a013SJaakko Heinonen KASSERT(((flags & MAKEDEV_NOWAIT) != 0 && res == ENOMEM) || 91268f7a013SJaakko Heinonen ((flags & MAKEDEV_CHECKNAME) != 0 && res != ENOMEM) || res == 0, 91368f7a013SJaakko Heinonen ("make_dev_credf: failed make_dev_credv (error=%d)", res)); 914f1bb758dSKonstantin Belousov return (res == 0 ? dev : NULL); 915f1bb758dSKonstantin Belousov } 916f1bb758dSKonstantin Belousov 917f1bb758dSKonstantin Belousov int 9182e983aceSEd Schouten make_dev_p(int flags, struct cdev **cdev, struct cdevsw *devsw, 919f1bb758dSKonstantin Belousov struct ucred *cr, uid_t uid, gid_t gid, int mode, const char *fmt, ...) 920f1bb758dSKonstantin Belousov { 921f1bb758dSKonstantin Belousov va_list ap; 922f1bb758dSKonstantin Belousov int res; 923f1bb758dSKonstantin Belousov 924f1bb758dSKonstantin Belousov va_start(ap, fmt); 9252e983aceSEd Schouten res = make_dev_credv(flags, cdev, devsw, 0, cr, uid, gid, mode, 926f1bb758dSKonstantin Belousov fmt, ap); 927f1bb758dSKonstantin Belousov va_end(ap); 928f1bb758dSKonstantin Belousov 92968f7a013SJaakko Heinonen KASSERT(((flags & MAKEDEV_NOWAIT) != 0 && res == ENOMEM) || 93068f7a013SJaakko Heinonen ((flags & MAKEDEV_CHECKNAME) != 0 && res != ENOMEM) || res == 0, 93168f7a013SJaakko Heinonen ("make_dev_p: failed make_dev_credv (error=%d)", res)); 932f1bb758dSKonstantin Belousov return (res); 933d26dd2d9SRobert Watson } 934d26dd2d9SRobert Watson 935e606a3c6SPoul-Henning Kamp static void 936e606a3c6SPoul-Henning Kamp dev_dependsl(struct cdev *pdev, struct cdev *cdev) 937e606a3c6SPoul-Henning Kamp { 938e606a3c6SPoul-Henning Kamp 939e606a3c6SPoul-Henning Kamp cdev->si_parent = pdev; 940e606a3c6SPoul-Henning Kamp cdev->si_flags |= SI_CHILD; 941e606a3c6SPoul-Henning Kamp LIST_INSERT_HEAD(&pdev->si_children, cdev, si_siblings); 942e606a3c6SPoul-Henning Kamp } 943e606a3c6SPoul-Henning Kamp 944e606a3c6SPoul-Henning Kamp 9453344c5a1SPoul-Henning Kamp void 94689c9c53dSPoul-Henning Kamp dev_depends(struct cdev *pdev, struct cdev *cdev) 9473344c5a1SPoul-Henning Kamp { 9483344c5a1SPoul-Henning Kamp 949a0e78d2eSPoul-Henning Kamp dev_lock(); 950e606a3c6SPoul-Henning Kamp dev_dependsl(pdev, cdev); 951a0e78d2eSPoul-Henning Kamp dev_unlock(); 9523344c5a1SPoul-Henning Kamp } 9533344c5a1SPoul-Henning Kamp 954b50a7799SAndrey V. Elsukov static int 955b50a7799SAndrey V. Elsukov make_dev_alias_v(int flags, struct cdev **cdev, struct cdev *pdev, 956b50a7799SAndrey V. Elsukov const char *fmt, va_list ap) 9573f54a085SPoul-Henning Kamp { 95889c9c53dSPoul-Henning Kamp struct cdev *dev; 95968f7a013SJaakko Heinonen int error; 9603f54a085SPoul-Henning Kamp 961b50a7799SAndrey V. Elsukov KASSERT(pdev != NULL, ("make_dev_alias_v: pdev is NULL")); 962b50a7799SAndrey V. Elsukov KASSERT((flags & MAKEDEV_WAITOK) == 0 || (flags & MAKEDEV_NOWAIT) == 0, 963b50a7799SAndrey V. Elsukov ("make_dev_alias_v: both WAITOK and NOWAIT specified")); 964b50a7799SAndrey V. Elsukov KASSERT((flags & ~(MAKEDEV_WAITOK | MAKEDEV_NOWAIT | 965b50a7799SAndrey V. Elsukov MAKEDEV_CHECKNAME)) == 0, 966b50a7799SAndrey V. Elsukov ("make_dev_alias_v: invalid flags specified (flags=%02x)", flags)); 967b50a7799SAndrey V. Elsukov 968b50a7799SAndrey V. Elsukov dev = devfs_alloc(flags); 969b50a7799SAndrey V. Elsukov if (dev == NULL) 970b50a7799SAndrey V. Elsukov return (ENOMEM); 971a0e78d2eSPoul-Henning Kamp dev_lock(); 9723f54a085SPoul-Henning Kamp dev->si_flags |= SI_ALIAS; 97368f7a013SJaakko Heinonen error = prep_devname(dev, fmt, ap); 97468f7a013SJaakko Heinonen if (error != 0) { 975b50a7799SAndrey V. Elsukov if ((flags & MAKEDEV_CHECKNAME) == 0) { 976b50a7799SAndrey V. Elsukov panic("make_dev_alias_v: bad si_name " 977b50a7799SAndrey V. Elsukov "(error=%d, si_name=%s)", error, dev->si_name); 978b50a7799SAndrey V. Elsukov } 979b50a7799SAndrey V. Elsukov dev_unlock(); 980b50a7799SAndrey V. Elsukov devfs_free(dev); 981b50a7799SAndrey V. Elsukov return (error); 98268f7a013SJaakko Heinonen } 98368f7a013SJaakko Heinonen dev->si_flags |= SI_NAMED; 9849285a87eSPoul-Henning Kamp devfs_create(dev); 985ae95dc62SKonstantin Belousov dev_dependsl(pdev, dev); 98609828ba9SKonstantin Belousov clean_unrhdrl(devfs_inos); 987a0e78d2eSPoul-Henning Kamp dev_unlock(); 98848504cc2SKonstantin Belousov 989b50a7799SAndrey V. Elsukov notify_create(dev, flags); 990b50a7799SAndrey V. Elsukov *cdev = dev; 99148504cc2SKonstantin Belousov 992b50a7799SAndrey V. Elsukov return (0); 993b50a7799SAndrey V. Elsukov } 994b50a7799SAndrey V. Elsukov 995b50a7799SAndrey V. Elsukov struct cdev * 996b50a7799SAndrey V. Elsukov make_dev_alias(struct cdev *pdev, const char *fmt, ...) 997b50a7799SAndrey V. Elsukov { 998b50a7799SAndrey V. Elsukov struct cdev *dev; 999b50a7799SAndrey V. Elsukov va_list ap; 10006fa5abfdSMatt Macy int res __unused; 10016fa5abfdSMatt Macy 1002b50a7799SAndrey V. Elsukov va_start(ap, fmt); 10036fa5abfdSMatt Macy res = make_dev_alias_v(MAKEDEV_WAITOK, &dev, pdev, fmt, ap); 1004b50a7799SAndrey V. Elsukov va_end(ap); 1005b50a7799SAndrey V. Elsukov 1006b50a7799SAndrey V. Elsukov KASSERT(res == 0 && dev != NULL, 1007b50a7799SAndrey V. Elsukov ("make_dev_alias: failed make_dev_alias_v (error=%d)", res)); 10080ef1c826SPoul-Henning Kamp return (dev); 10090ef1c826SPoul-Henning Kamp } 10100ef1c826SPoul-Henning Kamp 1011b50a7799SAndrey V. Elsukov int 1012b50a7799SAndrey V. Elsukov make_dev_alias_p(int flags, struct cdev **cdev, struct cdev *pdev, 1013b50a7799SAndrey V. Elsukov const char *fmt, ...) 1014b50a7799SAndrey V. Elsukov { 1015b50a7799SAndrey V. Elsukov va_list ap; 1016b50a7799SAndrey V. Elsukov int res; 1017b50a7799SAndrey V. Elsukov 1018b50a7799SAndrey V. Elsukov va_start(ap, fmt); 1019b50a7799SAndrey V. Elsukov res = make_dev_alias_v(flags, cdev, pdev, fmt, ap); 1020b50a7799SAndrey V. Elsukov va_end(ap); 1021b50a7799SAndrey V. Elsukov return (res); 1022b50a7799SAndrey V. Elsukov } 1023b50a7799SAndrey V. Elsukov 1024aa76615dSJustin T. Gibbs int 1025aa76615dSJustin T. Gibbs make_dev_physpath_alias(int flags, struct cdev **cdev, struct cdev *pdev, 1026aa76615dSJustin T. Gibbs struct cdev *old_alias, const char *physpath) 1027aa76615dSJustin T. Gibbs { 1028aa76615dSJustin T. Gibbs char *devfspath; 1029aa76615dSJustin T. Gibbs int physpath_len; 1030aa76615dSJustin T. Gibbs int max_parentpath_len; 1031aa76615dSJustin T. Gibbs int parentpath_len; 1032aa76615dSJustin T. Gibbs int devfspathbuf_len; 1033aa76615dSJustin T. Gibbs int mflags; 1034aa76615dSJustin T. Gibbs int ret; 1035aa76615dSJustin T. Gibbs 1036aa76615dSJustin T. Gibbs *cdev = NULL; 1037aa76615dSJustin T. Gibbs devfspath = NULL; 1038aa76615dSJustin T. Gibbs physpath_len = strlen(physpath); 1039aa76615dSJustin T. Gibbs ret = EINVAL; 1040aa76615dSJustin T. Gibbs if (physpath_len == 0) 1041aa76615dSJustin T. Gibbs goto out; 1042aa76615dSJustin T. Gibbs 1043aa76615dSJustin T. Gibbs if (strncmp("id1,", physpath, 4) == 0) { 1044aa76615dSJustin T. Gibbs physpath += 4; 1045aa76615dSJustin T. Gibbs physpath_len -= 4; 1046aa76615dSJustin T. Gibbs if (physpath_len == 0) 1047aa76615dSJustin T. Gibbs goto out; 1048aa76615dSJustin T. Gibbs } 1049aa76615dSJustin T. Gibbs 1050aa76615dSJustin T. Gibbs max_parentpath_len = SPECNAMELEN - physpath_len - /*/*/1; 1051aa76615dSJustin T. Gibbs parentpath_len = strlen(pdev->si_name); 1052aa76615dSJustin T. Gibbs if (max_parentpath_len < parentpath_len) { 105320654f4eSAlexander Motin if (bootverbose) 105420654f4eSAlexander Motin printf("WARNING: Unable to alias %s " 1055aa76615dSJustin T. Gibbs "to %s/%s - path too long\n", 1056aa76615dSJustin T. Gibbs pdev->si_name, physpath, pdev->si_name); 1057aa76615dSJustin T. Gibbs ret = ENAMETOOLONG; 1058aa76615dSJustin T. Gibbs goto out; 1059aa76615dSJustin T. Gibbs } 1060aa76615dSJustin T. Gibbs 1061aa76615dSJustin T. Gibbs mflags = (flags & MAKEDEV_NOWAIT) ? M_NOWAIT : M_WAITOK; 1062aa76615dSJustin T. Gibbs devfspathbuf_len = physpath_len + /*/*/1 + parentpath_len + /*NUL*/1; 1063aa76615dSJustin T. Gibbs devfspath = malloc(devfspathbuf_len, M_DEVBUF, mflags); 1064aa76615dSJustin T. Gibbs if (devfspath == NULL) { 1065aa76615dSJustin T. Gibbs ret = ENOMEM; 1066aa76615dSJustin T. Gibbs goto out; 1067aa76615dSJustin T. Gibbs } 1068aa76615dSJustin T. Gibbs 1069aa76615dSJustin T. Gibbs sprintf(devfspath, "%s/%s", physpath, pdev->si_name); 10704d651f4eSKonstantin Belousov if (old_alias != NULL && strcmp(old_alias->si_name, devfspath) == 0) { 1071aa76615dSJustin T. Gibbs /* Retain the existing alias. */ 1072aa76615dSJustin T. Gibbs *cdev = old_alias; 1073aa76615dSJustin T. Gibbs old_alias = NULL; 1074aa76615dSJustin T. Gibbs ret = 0; 1075aa76615dSJustin T. Gibbs } else { 1076f403cfb1SKonstantin Belousov ret = make_dev_alias_p(flags, cdev, pdev, "%s", devfspath); 1077aa76615dSJustin T. Gibbs } 1078aa76615dSJustin T. Gibbs out: 1079aa76615dSJustin T. Gibbs if (old_alias != NULL) 1080aa76615dSJustin T. Gibbs destroy_dev(old_alias); 1081aa76615dSJustin T. Gibbs if (devfspath != NULL) 1082aa76615dSJustin T. Gibbs free(devfspath, M_DEVBUF); 1083aa76615dSJustin T. Gibbs return (ret); 1084aa76615dSJustin T. Gibbs } 1085aa76615dSJustin T. Gibbs 1086cd690b60SPoul-Henning Kamp static void 1087aa2f6ddcSPoul-Henning Kamp destroy_devl(struct cdev *dev) 1088d137acccSPoul-Henning Kamp { 1089743cd76aSPoul-Henning Kamp struct cdevsw *csw; 10900bad52e1SHans Petter Selasky struct cdev_privdata *p; 10913b50dff5SKonstantin Belousov struct cdev_priv *cdp; 1092743cd76aSPoul-Henning Kamp 1093aa2f6ddcSPoul-Henning Kamp mtx_assert(&devmtx, MA_OWNED); 1094743cd76aSPoul-Henning Kamp KASSERT(dev->si_flags & SI_NAMED, 10956bfa9a2dSEd Schouten ("WARNING: Driver mistake: destroy_dev on %d\n", dev2unit(dev))); 10963979450bSKonstantin Belousov KASSERT((dev->si_flags & SI_ETERNAL) == 0, 10973979450bSKonstantin Belousov ("WARNING: Driver mistake: destroy_dev on eternal %d\n", 10983979450bSKonstantin Belousov dev2unit(dev))); 10995ef2707eSPoul-Henning Kamp 11003b50dff5SKonstantin Belousov cdp = cdev2priv(dev); 11013b50dff5SKonstantin Belousov if ((cdp->cdp_flags & CDP_UNREF_DTR) == 0) { 11023b50dff5SKonstantin Belousov /* 11033b50dff5SKonstantin Belousov * Avoid race with dev_rel(), e.g. from the populate 11043b50dff5SKonstantin Belousov * loop. If CDP_UNREF_DTR flag is set, the reference 11053b50dff5SKonstantin Belousov * to be dropped at the end of destroy_devl() was 11063b50dff5SKonstantin Belousov * already taken by delist_dev_locked(). 11073b50dff5SKonstantin Belousov */ 11083b50dff5SKonstantin Belousov dev_refl(dev); 11093b50dff5SKonstantin Belousov 11109285a87eSPoul-Henning Kamp devfs_destroy(dev); 11113b50dff5SKonstantin Belousov } 1112cd690b60SPoul-Henning Kamp 1113cd690b60SPoul-Henning Kamp /* Remove name marking */ 1114b0b03348SPoul-Henning Kamp dev->si_flags &= ~SI_NAMED; 1115b0b03348SPoul-Henning Kamp 1116cd690b60SPoul-Henning Kamp /* If we are a child, remove us from the parents list */ 11173344c5a1SPoul-Henning Kamp if (dev->si_flags & SI_CHILD) { 11183344c5a1SPoul-Henning Kamp LIST_REMOVE(dev, si_siblings); 11193344c5a1SPoul-Henning Kamp dev->si_flags &= ~SI_CHILD; 11203344c5a1SPoul-Henning Kamp } 1121cd690b60SPoul-Henning Kamp 1122cd690b60SPoul-Henning Kamp /* Kill our children */ 11233344c5a1SPoul-Henning Kamp while (!LIST_EMPTY(&dev->si_children)) 1124aa2f6ddcSPoul-Henning Kamp destroy_devl(LIST_FIRST(&dev->si_children)); 1125cd690b60SPoul-Henning Kamp 1126cd690b60SPoul-Henning Kamp /* Remove from clone list */ 1127b0b03348SPoul-Henning Kamp if (dev->si_flags & SI_CLONELIST) { 1128b0b03348SPoul-Henning Kamp LIST_REMOVE(dev, si_clone); 1129b0b03348SPoul-Henning Kamp dev->si_flags &= ~SI_CLONELIST; 1130b0b03348SPoul-Henning Kamp } 1131cd690b60SPoul-Henning Kamp 1132743cd76aSPoul-Henning Kamp csw = dev->si_devsw; 11331abf2c36SBrian Feldman dev->si_devsw = NULL; /* already NULL for SI_ALIAS */ 11341abf2c36SBrian Feldman while (csw != NULL && csw->d_purge != NULL && dev->si_threadcount) { 1135743cd76aSPoul-Henning Kamp csw->d_purge(dev); 1136743cd76aSPoul-Henning Kamp msleep(csw, &devmtx, PRIBIO, "devprg", hz/10); 1137d595182fSPoul-Henning Kamp if (dev->si_threadcount) 1138d595182fSPoul-Henning Kamp printf("Still %lu threads in %s\n", 1139d595182fSPoul-Henning Kamp dev->si_threadcount, devtoname(dev)); 1140743cd76aSPoul-Henning Kamp } 1141e0c33ad5STor Egge while (dev->si_threadcount != 0) { 1142e0c33ad5STor Egge /* Use unique dummy wait ident */ 1143e0c33ad5STor Egge msleep(&csw, &devmtx, PRIBIO, "devdrn", hz / 10); 1144e0c33ad5STor Egge } 1145743cd76aSPoul-Henning Kamp 114682f4d640SKonstantin Belousov dev_unlock(); 11472793ea13SHans Petter Selasky if ((cdp->cdp_flags & CDP_UNREF_DTR) == 0) { 11482793ea13SHans Petter Selasky /* avoid out of order notify events */ 114948504cc2SKonstantin Belousov notify_destroy(dev); 11502793ea13SHans Petter Selasky } 115182f4d640SKonstantin Belousov mtx_lock(&cdevpriv_mtx); 11522793ea13SHans Petter Selasky while ((p = LIST_FIRST(&cdp->cdp_fdpriv)) != NULL) { 115382f4d640SKonstantin Belousov devfs_destroy_cdevpriv(p); 115482f4d640SKonstantin Belousov mtx_lock(&cdevpriv_mtx); 115582f4d640SKonstantin Belousov } 115682f4d640SKonstantin Belousov mtx_unlock(&cdevpriv_mtx); 115782f4d640SKonstantin Belousov dev_lock(); 115848504cc2SKonstantin Belousov 1159743cd76aSPoul-Henning Kamp dev->si_drv1 = 0; 1160743cd76aSPoul-Henning Kamp dev->si_drv2 = 0; 1161743cd76aSPoul-Henning Kamp bzero(&dev->__si_u, sizeof(dev->__si_u)); 1162743cd76aSPoul-Henning Kamp 1163cd690b60SPoul-Henning Kamp if (!(dev->si_flags & SI_ALIAS)) { 1164cd690b60SPoul-Henning Kamp /* Remove from cdevsw list */ 1165cd690b60SPoul-Henning Kamp LIST_REMOVE(dev, si_list); 1166cd690b60SPoul-Henning Kamp 1167e606a3c6SPoul-Henning Kamp /* If cdevsw has no more struct cdev *'s, clean it */ 1168de10ffa5SKonstantin Belousov if (LIST_EMPTY(&csw->d_devs)) { 1169a5993c33SPoul-Henning Kamp fini_cdevsw(csw); 1170de10ffa5SKonstantin Belousov wakeup(&csw->d_devs); 1171de10ffa5SKonstantin Belousov } 1172cd690b60SPoul-Henning Kamp } 11735ef2707eSPoul-Henning Kamp dev->si_flags &= ~SI_ALIAS; 11743b50dff5SKonstantin Belousov cdp->cdp_flags &= ~CDP_UNREF_DTR; 11753b50dff5SKonstantin Belousov dev->si_refcount--; 1176743cd76aSPoul-Henning Kamp 11773b50dff5SKonstantin Belousov if (dev->si_refcount > 0) 1178cd690b60SPoul-Henning Kamp LIST_INSERT_HEAD(&dead_cdevsw.d_devs, dev, si_list); 11793b50dff5SKonstantin Belousov else 11809bc911d4SKonstantin Belousov dev_free_devlocked(dev); 1181d137acccSPoul-Henning Kamp } 1182cd690b60SPoul-Henning Kamp 118307dbde67SHans Petter Selasky static void 118407dbde67SHans Petter Selasky delist_dev_locked(struct cdev *dev) 118507dbde67SHans Petter Selasky { 11863b50dff5SKonstantin Belousov struct cdev_priv *cdp; 118707dbde67SHans Petter Selasky struct cdev *child; 11883b50dff5SKonstantin Belousov 11893b50dff5SKonstantin Belousov mtx_assert(&devmtx, MA_OWNED); 11903b50dff5SKonstantin Belousov cdp = cdev2priv(dev); 11913b50dff5SKonstantin Belousov if ((cdp->cdp_flags & CDP_UNREF_DTR) != 0) 11923b50dff5SKonstantin Belousov return; 11933b50dff5SKonstantin Belousov cdp->cdp_flags |= CDP_UNREF_DTR; 11943b50dff5SKonstantin Belousov dev_refl(dev); 119507dbde67SHans Petter Selasky devfs_destroy(dev); 119607dbde67SHans Petter Selasky LIST_FOREACH(child, &dev->si_children, si_siblings) 119707dbde67SHans Petter Selasky delist_dev_locked(child); 11982793ea13SHans Petter Selasky dev_unlock(); 11992793ea13SHans Petter Selasky /* ensure the destroy event is queued in order */ 12002793ea13SHans Petter Selasky notify_destroy(dev); 12012793ea13SHans Petter Selasky dev_lock(); 120207dbde67SHans Petter Selasky } 120307dbde67SHans Petter Selasky 12042793ea13SHans Petter Selasky /* 12052793ea13SHans Petter Selasky * This function will delist a character device and its children from 12062793ea13SHans Petter Selasky * the directory listing and create a destroy event without waiting 12072793ea13SHans Petter Selasky * for all character device references to go away. At some later point 12082793ea13SHans Petter Selasky * destroy_dev() must be called to complete the character device 12092793ea13SHans Petter Selasky * destruction. After calling this function the character device name 12102793ea13SHans Petter Selasky * can instantly be re-used. 12112793ea13SHans Petter Selasky */ 121207dbde67SHans Petter Selasky void 121307dbde67SHans Petter Selasky delist_dev(struct cdev *dev) 121407dbde67SHans Petter Selasky { 12153b50dff5SKonstantin Belousov 12162793ea13SHans Petter Selasky WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, "delist_dev"); 121707dbde67SHans Petter Selasky dev_lock(); 121807dbde67SHans Petter Selasky delist_dev_locked(dev); 121907dbde67SHans Petter Selasky dev_unlock(); 122007dbde67SHans Petter Selasky } 122107dbde67SHans Petter Selasky 1222cd690b60SPoul-Henning Kamp void 122389c9c53dSPoul-Henning Kamp destroy_dev(struct cdev *dev) 1224cd690b60SPoul-Henning Kamp { 1225cd690b60SPoul-Henning Kamp 1226b7a813fcSKonstantin Belousov WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, "destroy_dev"); 1227a0e78d2eSPoul-Henning Kamp dev_lock(); 1228aa2f6ddcSPoul-Henning Kamp destroy_devl(dev); 12299bc911d4SKonstantin Belousov dev_unlock_and_free(); 1230cd690b60SPoul-Henning Kamp } 1231d137acccSPoul-Henning Kamp 1232c32cc149SBruce Evans const char * 123389c9c53dSPoul-Henning Kamp devtoname(struct cdev *dev) 1234b8e49f68SBill Fumerola { 1235b8e49f68SBill Fumerola 1236b8e49f68SBill Fumerola return (dev->si_name); 1237b8e49f68SBill Fumerola } 1238db901281SPoul-Henning Kamp 1239db901281SPoul-Henning Kamp int 124001de1b13SPoul-Henning Kamp dev_stdclone(char *name, char **namep, const char *stem, int *unit) 1241db901281SPoul-Henning Kamp { 1242db901281SPoul-Henning Kamp int u, i; 1243db901281SPoul-Henning Kamp 1244db901281SPoul-Henning Kamp i = strlen(stem); 124556700d46SBrian Somers if (bcmp(stem, name, i) != 0) 124656700d46SBrian Somers return (0); 1247db901281SPoul-Henning Kamp if (!isdigit(name[i])) 1248db901281SPoul-Henning Kamp return (0); 1249db901281SPoul-Henning Kamp u = 0; 125010786074SPoul-Henning Kamp if (name[i] == '0' && isdigit(name[i+1])) 125110786074SPoul-Henning Kamp return (0); 1252db901281SPoul-Henning Kamp while (isdigit(name[i])) { 1253db901281SPoul-Henning Kamp u *= 10; 1254db901281SPoul-Henning Kamp u += name[i++] - '0'; 1255db901281SPoul-Henning Kamp } 1256dab3d85fSBrian Feldman if (u > 0xffffff) 1257dab3d85fSBrian Feldman return (0); 1258db901281SPoul-Henning Kamp *unit = u; 1259db901281SPoul-Henning Kamp if (namep) 1260db901281SPoul-Henning Kamp *namep = &name[i]; 1261db901281SPoul-Henning Kamp if (name[i]) 1262db901281SPoul-Henning Kamp return (2); 1263db901281SPoul-Henning Kamp return (1); 1264db901281SPoul-Henning Kamp } 12658d25eb2cSPoul-Henning Kamp 12668d25eb2cSPoul-Henning Kamp /* 1267b0b03348SPoul-Henning Kamp * Helper functions for cloning device drivers. 1268b0b03348SPoul-Henning Kamp * 1269b0b03348SPoul-Henning Kamp * The objective here is to make it unnecessary for the device drivers to 1270b0b03348SPoul-Henning Kamp * use rman or similar to manage their unit number space. Due to the way 1271b0b03348SPoul-Henning Kamp * we do "on-demand" devices, using rman or other "private" methods 1272b0b03348SPoul-Henning Kamp * will be very tricky to lock down properly once we lock down this file. 1273b0b03348SPoul-Henning Kamp * 12749a98ae94SLukas Ertl * Instead we give the drivers these routines which puts the struct cdev *'s 12759a98ae94SLukas Ertl * that are to be managed on their own list, and gives the driver the ability 1276b0b03348SPoul-Henning Kamp * to ask for the first free unit number or a given specified unit number. 1277b0b03348SPoul-Henning Kamp * 1278b0b03348SPoul-Henning Kamp * In addition these routines support paired devices (pty, nmdm and similar) 1279b0b03348SPoul-Henning Kamp * by respecting a number of "flag" bits in the minor number. 1280b0b03348SPoul-Henning Kamp * 1281b0b03348SPoul-Henning Kamp */ 1282b0b03348SPoul-Henning Kamp 1283b0b03348SPoul-Henning Kamp struct clonedevs { 1284b0b03348SPoul-Henning Kamp LIST_HEAD(,cdev) head; 1285b0b03348SPoul-Henning Kamp }; 1286b0b03348SPoul-Henning Kamp 12879397290eSPoul-Henning Kamp void 12889397290eSPoul-Henning Kamp clone_setup(struct clonedevs **cdp) 12899397290eSPoul-Henning Kamp { 12909397290eSPoul-Henning Kamp 12919397290eSPoul-Henning Kamp *cdp = malloc(sizeof **cdp, M_DEVBUF, M_WAITOK | M_ZERO); 12929397290eSPoul-Henning Kamp LIST_INIT(&(*cdp)->head); 12939397290eSPoul-Henning Kamp } 12949397290eSPoul-Henning Kamp 1295b0b03348SPoul-Henning Kamp int 1296cf141467SKonstantin Belousov clone_create(struct clonedevs **cdp, struct cdevsw *csw, int *up, 1297cf141467SKonstantin Belousov struct cdev **dp, int extra) 1298b0b03348SPoul-Henning Kamp { 1299b0b03348SPoul-Henning Kamp struct clonedevs *cd; 1300027b1f71SPoul-Henning Kamp struct cdev *dev, *ndev, *dl, *de; 130148ce5d4cSKonstantin Belousov struct make_dev_args args; 1302b0b03348SPoul-Henning Kamp int unit, low, u; 1303b0b03348SPoul-Henning Kamp 13049397290eSPoul-Henning Kamp KASSERT(*cdp != NULL, 13059397290eSPoul-Henning Kamp ("clone_setup() not called in driver \"%s\"", csw->d_name)); 1306b0b03348SPoul-Henning Kamp KASSERT(!(extra & CLONE_UNITMASK), 1307b0b03348SPoul-Henning Kamp ("Illegal extra bits (0x%x) in clone_create", extra)); 1308b0b03348SPoul-Henning Kamp KASSERT(*up <= CLONE_UNITMASK, 1309b0b03348SPoul-Henning Kamp ("Too high unit (0x%x) in clone_create", *up)); 131029d4cb24SEd Schouten KASSERT(csw->d_flags & D_NEEDMINOR, 131129d4cb24SEd Schouten ("clone_create() on cdevsw without minor numbers")); 1312b0b03348SPoul-Henning Kamp 1313b0b03348SPoul-Henning Kamp 1314b0b03348SPoul-Henning Kamp /* 1315b0b03348SPoul-Henning Kamp * Search the list for a lot of things in one go: 1316b0b03348SPoul-Henning Kamp * A preexisting match is returned immediately. 1317b0b03348SPoul-Henning Kamp * The lowest free unit number if we are passed -1, and the place 1318b0b03348SPoul-Henning Kamp * in the list where we should insert that new element. 1319b0b03348SPoul-Henning Kamp * The place to insert a specified unit number, if applicable 1320b0b03348SPoul-Henning Kamp * the end of the list. 1321b0b03348SPoul-Henning Kamp */ 1322b0b03348SPoul-Henning Kamp unit = *up; 1323d2ba618aSKonstantin Belousov ndev = devfs_alloc(MAKEDEV_WAITOK); 1324027b1f71SPoul-Henning Kamp dev_lock(); 1325d2ba618aSKonstantin Belousov prep_cdevsw(csw, MAKEDEV_WAITOK); 13268666b655SPoul-Henning Kamp low = extra; 1327b0b03348SPoul-Henning Kamp de = dl = NULL; 13289397290eSPoul-Henning Kamp cd = *cdp; 1329b0b03348SPoul-Henning Kamp LIST_FOREACH(dev, &cd->head, si_clone) { 1330027b1f71SPoul-Henning Kamp KASSERT(dev->si_flags & SI_CLONELIST, 1331027b1f71SPoul-Henning Kamp ("Dev %p(%s) should be on clonelist", dev, dev->si_name)); 1332b0b03348SPoul-Henning Kamp u = dev2unit(dev); 1333b0b03348SPoul-Henning Kamp if (u == (unit | extra)) { 1334b0b03348SPoul-Henning Kamp *dp = dev; 1335027b1f71SPoul-Henning Kamp dev_unlock(); 13369bc911d4SKonstantin Belousov devfs_free(ndev); 1337b0b03348SPoul-Henning Kamp return (0); 1338b0b03348SPoul-Henning Kamp } 1339b0b03348SPoul-Henning Kamp if (unit == -1 && u == low) { 1340b0b03348SPoul-Henning Kamp low++; 1341b0b03348SPoul-Henning Kamp de = dev; 1342b0b03348SPoul-Henning Kamp continue; 13437bbb3a26SPoul-Henning Kamp } else if (u < (unit | extra)) { 13447bbb3a26SPoul-Henning Kamp de = dev; 13457bbb3a26SPoul-Henning Kamp continue; 13467bbb3a26SPoul-Henning Kamp } else if (u > (unit | extra)) { 1347b0b03348SPoul-Henning Kamp dl = dev; 1348b0b03348SPoul-Henning Kamp break; 1349b0b03348SPoul-Henning Kamp } 1350b0b03348SPoul-Henning Kamp } 1351b0b03348SPoul-Henning Kamp if (unit == -1) 13528666b655SPoul-Henning Kamp unit = low & CLONE_UNITMASK; 135348ce5d4cSKonstantin Belousov make_dev_args_init(&args); 135448ce5d4cSKonstantin Belousov args.mda_unit = unit | extra; 135548ce5d4cSKonstantin Belousov args.mda_devsw = csw; 135648ce5d4cSKonstantin Belousov dev = newdev(&args, ndev); 1357027b1f71SPoul-Henning Kamp if (dev->si_flags & SI_CLONELIST) { 1358027b1f71SPoul-Henning Kamp printf("dev %p (%s) is on clonelist\n", dev, dev->si_name); 13597bbb3a26SPoul-Henning Kamp printf("unit=%d, low=%d, extra=0x%x\n", unit, low, extra); 1360027b1f71SPoul-Henning Kamp LIST_FOREACH(dev, &cd->head, si_clone) { 1361027b1f71SPoul-Henning Kamp printf("\t%p %s\n", dev, dev->si_name); 1362027b1f71SPoul-Henning Kamp } 1363027b1f71SPoul-Henning Kamp panic("foo"); 1364027b1f71SPoul-Henning Kamp } 1365b0b03348SPoul-Henning Kamp KASSERT(!(dev->si_flags & SI_CLONELIST), 1366027b1f71SPoul-Henning Kamp ("Dev %p(%s) should not be on clonelist", dev, dev->si_name)); 1367b0b03348SPoul-Henning Kamp if (dl != NULL) 1368b0b03348SPoul-Henning Kamp LIST_INSERT_BEFORE(dl, dev, si_clone); 1369b0b03348SPoul-Henning Kamp else if (de != NULL) 1370b0b03348SPoul-Henning Kamp LIST_INSERT_AFTER(de, dev, si_clone); 1371b0b03348SPoul-Henning Kamp else 1372b0b03348SPoul-Henning Kamp LIST_INSERT_HEAD(&cd->head, dev, si_clone); 1373b0b03348SPoul-Henning Kamp dev->si_flags |= SI_CLONELIST; 1374b0b03348SPoul-Henning Kamp *up = unit; 13759bc911d4SKonstantin Belousov dev_unlock_and_free(); 1376b0b03348SPoul-Henning Kamp return (1); 1377b0b03348SPoul-Henning Kamp } 1378b0b03348SPoul-Henning Kamp 1379b0b03348SPoul-Henning Kamp /* 1380b0b03348SPoul-Henning Kamp * Kill everything still on the list. The driver should already have 138189c9c53dSPoul-Henning Kamp * disposed of any softc hung of the struct cdev *'s at this time. 1382b0b03348SPoul-Henning Kamp */ 1383b0b03348SPoul-Henning Kamp void 1384b0b03348SPoul-Henning Kamp clone_cleanup(struct clonedevs **cdp) 1385b0b03348SPoul-Henning Kamp { 1386de10ffa5SKonstantin Belousov struct cdev *dev; 1387de10ffa5SKonstantin Belousov struct cdev_priv *cp; 1388b0b03348SPoul-Henning Kamp struct clonedevs *cd; 1389b0b03348SPoul-Henning Kamp 1390b0b03348SPoul-Henning Kamp cd = *cdp; 1391b0b03348SPoul-Henning Kamp if (cd == NULL) 1392b0b03348SPoul-Henning Kamp return; 1393027b1f71SPoul-Henning Kamp dev_lock(); 1394de10ffa5SKonstantin Belousov while (!LIST_EMPTY(&cd->head)) { 1395de10ffa5SKonstantin Belousov dev = LIST_FIRST(&cd->head); 1396de10ffa5SKonstantin Belousov LIST_REMOVE(dev, si_clone); 1397027b1f71SPoul-Henning Kamp KASSERT(dev->si_flags & SI_CLONELIST, 1398027b1f71SPoul-Henning Kamp ("Dev %p(%s) should be on clonelist", dev, dev->si_name)); 1399de10ffa5SKonstantin Belousov dev->si_flags &= ~SI_CLONELIST; 140005427aafSKonstantin Belousov cp = cdev2priv(dev); 1401de10ffa5SKonstantin Belousov if (!(cp->cdp_flags & CDP_SCHED_DTR)) { 1402de10ffa5SKonstantin Belousov cp->cdp_flags |= CDP_SCHED_DTR; 1403b0b03348SPoul-Henning Kamp KASSERT(dev->si_flags & SI_NAMED, 1404dde58752SGleb Kurtsou ("Driver has goofed in cloning underways udev %jx unit %x", 1405dde58752SGleb Kurtsou (uintmax_t)dev2udev(dev), dev2unit(dev))); 1406aa2f6ddcSPoul-Henning Kamp destroy_devl(dev); 1407b0b03348SPoul-Henning Kamp } 1408de10ffa5SKonstantin Belousov } 1409aeeb4202SKonstantin Belousov dev_unlock_and_free(); 1410b0b03348SPoul-Henning Kamp free(cd, M_DEVBUF); 1411b0b03348SPoul-Henning Kamp *cdp = NULL; 1412b0b03348SPoul-Henning Kamp } 1413de10ffa5SKonstantin Belousov 1414de10ffa5SKonstantin Belousov static TAILQ_HEAD(, cdev_priv) dev_ddtr = 1415de10ffa5SKonstantin Belousov TAILQ_HEAD_INITIALIZER(dev_ddtr); 1416268e76d8SJohn Baldwin static struct task dev_dtr_task = TASK_INITIALIZER(0, destroy_dev_tq, NULL); 1417de10ffa5SKonstantin Belousov 1418de10ffa5SKonstantin Belousov static void 1419de10ffa5SKonstantin Belousov destroy_dev_tq(void *ctx, int pending) 1420de10ffa5SKonstantin Belousov { 1421de10ffa5SKonstantin Belousov struct cdev_priv *cp; 1422de10ffa5SKonstantin Belousov struct cdev *dev; 1423de10ffa5SKonstantin Belousov void (*cb)(void *); 1424de10ffa5SKonstantin Belousov void *cb_arg; 1425de10ffa5SKonstantin Belousov 1426de10ffa5SKonstantin Belousov dev_lock(); 1427de10ffa5SKonstantin Belousov while (!TAILQ_EMPTY(&dev_ddtr)) { 1428de10ffa5SKonstantin Belousov cp = TAILQ_FIRST(&dev_ddtr); 1429de10ffa5SKonstantin Belousov dev = &cp->cdp_c; 1430de10ffa5SKonstantin Belousov KASSERT(cp->cdp_flags & CDP_SCHED_DTR, 1431de10ffa5SKonstantin Belousov ("cdev %p in dev_destroy_tq without CDP_SCHED_DTR", cp)); 1432de10ffa5SKonstantin Belousov TAILQ_REMOVE(&dev_ddtr, cp, cdp_dtr_list); 1433de10ffa5SKonstantin Belousov cb = cp->cdp_dtr_cb; 1434de10ffa5SKonstantin Belousov cb_arg = cp->cdp_dtr_cb_arg; 1435de10ffa5SKonstantin Belousov destroy_devl(dev); 1436aeeb4202SKonstantin Belousov dev_unlock_and_free(); 1437de10ffa5SKonstantin Belousov dev_rel(dev); 1438de10ffa5SKonstantin Belousov if (cb != NULL) 1439de10ffa5SKonstantin Belousov cb(cb_arg); 1440de10ffa5SKonstantin Belousov dev_lock(); 1441de10ffa5SKonstantin Belousov } 1442de10ffa5SKonstantin Belousov dev_unlock(); 1443de10ffa5SKonstantin Belousov } 1444de10ffa5SKonstantin Belousov 14459d53363bSKonstantin Belousov /* 14469d53363bSKonstantin Belousov * devmtx shall be locked on entry. devmtx will be unlocked after 14479d53363bSKonstantin Belousov * function return. 14489d53363bSKonstantin Belousov */ 14499d53363bSKonstantin Belousov static int 14509d53363bSKonstantin Belousov destroy_dev_sched_cbl(struct cdev *dev, void (*cb)(void *), void *arg) 1451de10ffa5SKonstantin Belousov { 1452de10ffa5SKonstantin Belousov struct cdev_priv *cp; 1453de10ffa5SKonstantin Belousov 14549d53363bSKonstantin Belousov mtx_assert(&devmtx, MA_OWNED); 145505427aafSKonstantin Belousov cp = cdev2priv(dev); 1456de10ffa5SKonstantin Belousov if (cp->cdp_flags & CDP_SCHED_DTR) { 1457de10ffa5SKonstantin Belousov dev_unlock(); 1458de10ffa5SKonstantin Belousov return (0); 1459de10ffa5SKonstantin Belousov } 1460de10ffa5SKonstantin Belousov dev_refl(dev); 1461de10ffa5SKonstantin Belousov cp->cdp_flags |= CDP_SCHED_DTR; 1462de10ffa5SKonstantin Belousov cp->cdp_dtr_cb = cb; 1463de10ffa5SKonstantin Belousov cp->cdp_dtr_cb_arg = arg; 1464de10ffa5SKonstantin Belousov TAILQ_INSERT_TAIL(&dev_ddtr, cp, cdp_dtr_list); 1465de10ffa5SKonstantin Belousov dev_unlock(); 1466de10ffa5SKonstantin Belousov taskqueue_enqueue(taskqueue_swi_giant, &dev_dtr_task); 1467de10ffa5SKonstantin Belousov return (1); 1468de10ffa5SKonstantin Belousov } 1469de10ffa5SKonstantin Belousov 1470de10ffa5SKonstantin Belousov int 14719d53363bSKonstantin Belousov destroy_dev_sched_cb(struct cdev *dev, void (*cb)(void *), void *arg) 14729d53363bSKonstantin Belousov { 1473cf141467SKonstantin Belousov 14749d53363bSKonstantin Belousov dev_lock(); 14759d53363bSKonstantin Belousov return (destroy_dev_sched_cbl(dev, cb, arg)); 14769d53363bSKonstantin Belousov } 14779d53363bSKonstantin Belousov 14789d53363bSKonstantin Belousov int 1479de10ffa5SKonstantin Belousov destroy_dev_sched(struct cdev *dev) 1480de10ffa5SKonstantin Belousov { 1481cf141467SKonstantin Belousov 1482de10ffa5SKonstantin Belousov return (destroy_dev_sched_cb(dev, NULL, NULL)); 1483de10ffa5SKonstantin Belousov } 1484de10ffa5SKonstantin Belousov 1485de10ffa5SKonstantin Belousov void 1486de10ffa5SKonstantin Belousov destroy_dev_drain(struct cdevsw *csw) 1487de10ffa5SKonstantin Belousov { 1488de10ffa5SKonstantin Belousov 1489de10ffa5SKonstantin Belousov dev_lock(); 1490de10ffa5SKonstantin Belousov while (!LIST_EMPTY(&csw->d_devs)) { 1491de10ffa5SKonstantin Belousov msleep(&csw->d_devs, &devmtx, PRIBIO, "devscd", hz/10); 1492de10ffa5SKonstantin Belousov } 1493de10ffa5SKonstantin Belousov dev_unlock(); 1494de10ffa5SKonstantin Belousov } 1495de10ffa5SKonstantin Belousov 1496de10ffa5SKonstantin Belousov void 1497de10ffa5SKonstantin Belousov drain_dev_clone_events(void) 1498de10ffa5SKonstantin Belousov { 1499de10ffa5SKonstantin Belousov 1500de10ffa5SKonstantin Belousov sx_xlock(&clone_drain_lock); 1501de10ffa5SKonstantin Belousov sx_xunlock(&clone_drain_lock); 1502de10ffa5SKonstantin Belousov } 1503de10ffa5SKonstantin Belousov 15046c5e633cSKonstantin Belousov #include "opt_ddb.h" 15056c5e633cSKonstantin Belousov #ifdef DDB 15066c5e633cSKonstantin Belousov #include <sys/kernel.h> 15076c5e633cSKonstantin Belousov 15086c5e633cSKonstantin Belousov #include <ddb/ddb.h> 15096c5e633cSKonstantin Belousov 15106c5e633cSKonstantin Belousov DB_SHOW_COMMAND(cdev, db_show_cdev) 15116c5e633cSKonstantin Belousov { 15126c5e633cSKonstantin Belousov struct cdev_priv *cdp; 15136c5e633cSKonstantin Belousov struct cdev *dev; 15146c5e633cSKonstantin Belousov u_int flags; 15156c5e633cSKonstantin Belousov char buf[512]; 15166c5e633cSKonstantin Belousov 15176c5e633cSKonstantin Belousov if (!have_addr) { 15186c5e633cSKonstantin Belousov TAILQ_FOREACH(cdp, &cdevp_list, cdp_list) { 15196c5e633cSKonstantin Belousov dev = &cdp->cdp_c; 15206c5e633cSKonstantin Belousov db_printf("%s %p\n", dev->si_name, dev); 15216c5e633cSKonstantin Belousov if (db_pager_quit) 15226c5e633cSKonstantin Belousov break; 15236c5e633cSKonstantin Belousov } 15246c5e633cSKonstantin Belousov return; 15256c5e633cSKonstantin Belousov } 15266c5e633cSKonstantin Belousov 15276c5e633cSKonstantin Belousov dev = (struct cdev *)addr; 15286c5e633cSKonstantin Belousov cdp = cdev2priv(dev); 15296c5e633cSKonstantin Belousov db_printf("dev %s ref %d use %ld thr %ld inuse %u fdpriv %p\n", 15306c5e633cSKonstantin Belousov dev->si_name, dev->si_refcount, dev->si_usecount, 15316c5e633cSKonstantin Belousov dev->si_threadcount, cdp->cdp_inuse, cdp->cdp_fdpriv.lh_first); 15326c5e633cSKonstantin Belousov db_printf("devsw %p si_drv0 %d si_drv1 %p si_drv2 %p\n", 15336c5e633cSKonstantin Belousov dev->si_devsw, dev->si_drv0, dev->si_drv1, dev->si_drv2); 15346c5e633cSKonstantin Belousov flags = dev->si_flags; 15356c5e633cSKonstantin Belousov #define SI_FLAG(flag) do { \ 15366c5e633cSKonstantin Belousov if (flags & (flag)) { \ 15376c5e633cSKonstantin Belousov if (buf[0] != '\0') \ 15386c5e633cSKonstantin Belousov strlcat(buf, ", ", sizeof(buf)); \ 15396c5e633cSKonstantin Belousov strlcat(buf, (#flag) + 3, sizeof(buf)); \ 15406c5e633cSKonstantin Belousov flags &= ~(flag); \ 15416c5e633cSKonstantin Belousov } \ 15426c5e633cSKonstantin Belousov } while (0) 15436c5e633cSKonstantin Belousov buf[0] = '\0'; 15446c5e633cSKonstantin Belousov SI_FLAG(SI_ETERNAL); 15456c5e633cSKonstantin Belousov SI_FLAG(SI_ALIAS); 15466c5e633cSKonstantin Belousov SI_FLAG(SI_NAMED); 15476c5e633cSKonstantin Belousov SI_FLAG(SI_CHEAPCLONE); 15486c5e633cSKonstantin Belousov SI_FLAG(SI_CHILD); 15496c5e633cSKonstantin Belousov SI_FLAG(SI_DUMPDEV); 15506c5e633cSKonstantin Belousov SI_FLAG(SI_CLONELIST); 15516c5e633cSKonstantin Belousov db_printf("si_flags %s\n", buf); 15526c5e633cSKonstantin Belousov 15536c5e633cSKonstantin Belousov flags = cdp->cdp_flags; 15546c5e633cSKonstantin Belousov #define CDP_FLAG(flag) do { \ 15556c5e633cSKonstantin Belousov if (flags & (flag)) { \ 15566c5e633cSKonstantin Belousov if (buf[0] != '\0') \ 15576c5e633cSKonstantin Belousov strlcat(buf, ", ", sizeof(buf)); \ 15586c5e633cSKonstantin Belousov strlcat(buf, (#flag) + 4, sizeof(buf)); \ 15596c5e633cSKonstantin Belousov flags &= ~(flag); \ 15606c5e633cSKonstantin Belousov } \ 15616c5e633cSKonstantin Belousov } while (0) 15626c5e633cSKonstantin Belousov buf[0] = '\0'; 15636c5e633cSKonstantin Belousov CDP_FLAG(CDP_ACTIVE); 15646c5e633cSKonstantin Belousov CDP_FLAG(CDP_SCHED_DTR); 15656c5e633cSKonstantin Belousov db_printf("cdp_flags %s\n", buf); 15666c5e633cSKonstantin Belousov } 15676c5e633cSKonstantin Belousov #endif 1568