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: stable/11/sys/kern/kern_conf.c 353783 2019-10-20 22:01:35Z kevans $");
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)));
167154029Sbz	if (dev->si_devsw == NULL && dev->si_refcount == 0) {
168126082Sphk		LIST_REMOVE(dev, si_list);
169136014Sphk		flag = 1;
170136014Sphk	}
171136014Sphk	dev_unlock();
172136014Sphk	if (flag)
173150342Sphk		devfs_free(dev);
174126082Sphk}
175136014Sphk
176135704Sphkstruct cdevsw *
177210923Skibdev_refthread(struct cdev *dev, int *ref)
178135704Sphk{
179135704Sphk	struct cdevsw *csw;
180171181Skib	struct cdev_priv *cdp;
181126082Sphk
182135704Sphk	mtx_assert(&devmtx, MA_NOTOWNED);
183210923Skib	if ((dev->si_flags & SI_ETERNAL) != 0) {
184210923Skib		*ref = 0;
185210923Skib		return (dev->si_devsw);
186210923Skib	}
187135704Sphk	dev_lock();
188135704Sphk	csw = dev->si_devsw;
189171181Skib	if (csw != NULL) {
190179828Skib		cdp = cdev2priv(dev);
191171181Skib		if ((cdp->cdp_flags & CDP_SCHED_DTR) == 0)
192256885Smav			atomic_add_long(&dev->si_threadcount, 1);
193171181Skib		else
194171181Skib			csw = NULL;
195171181Skib	}
196135704Sphk	dev_unlock();
197210923Skib	*ref = 1;
198135704Sphk	return (csw);
199135704Sphk}
200135704Sphk
201163529Skibstruct cdevsw *
202210923Skibdevvn_refthread(struct vnode *vp, struct cdev **devp, int *ref)
203163529Skib{
204163529Skib	struct cdevsw *csw;
205171181Skib	struct cdev_priv *cdp;
206210923Skib	struct cdev *dev;
207163529Skib
208163529Skib	mtx_assert(&devmtx, MA_NOTOWNED);
209210923Skib	if ((vp->v_vflag & VV_ETERNALDEV) != 0) {
210210923Skib		dev = vp->v_rdev;
211210923Skib		if (dev == NULL)
212210923Skib			return (NULL);
213210923Skib		KASSERT((dev->si_flags & SI_ETERNAL) != 0,
214210923Skib		    ("Not eternal cdev"));
215210923Skib		*ref = 0;
216210923Skib		csw = dev->si_devsw;
217210923Skib		KASSERT(csw != NULL, ("Eternal cdev is destroyed"));
218210923Skib		*devp = dev;
219210923Skib		return (csw);
220210923Skib	}
221210923Skib
222163529Skib	csw = NULL;
223163529Skib	dev_lock();
224210923Skib	dev = vp->v_rdev;
225210923Skib	if (dev == NULL) {
226210923Skib		dev_unlock();
227210923Skib		return (NULL);
228163529Skib	}
229210923Skib	cdp = cdev2priv(dev);
230210923Skib	if ((cdp->cdp_flags & CDP_SCHED_DTR) == 0) {
231210923Skib		csw = dev->si_devsw;
232210923Skib		if (csw != NULL)
233256885Smav			atomic_add_long(&dev->si_threadcount, 1);
234210923Skib	}
235163529Skib	dev_unlock();
236210923Skib	if (csw != NULL) {
237210923Skib		*devp = dev;
238210923Skib		*ref = 1;
239210923Skib	}
240163529Skib	return (csw);
241163529Skib}
242163529Skib
243135704Sphkvoid
244210923Skibdev_relthread(struct cdev *dev, int ref)
245135704Sphk{
246135704Sphk
247135704Sphk	mtx_assert(&devmtx, MA_NOTOWNED);
248210923Skib	if (!ref)
249210923Skib		return;
250179248Skib	KASSERT(dev->si_threadcount > 0,
251179248Skib	    ("%s threadcount is wrong", dev->si_name));
252256885Smav	atomic_subtract_rel_long(&dev->si_threadcount, 1);
253135704Sphk}
254135704Sphk
255120514Sphkint
256120514Sphknullop(void)
257120514Sphk{
25885603Sphk
259120514Sphk	return (0);
260120514Sphk}
261120514Sphk
262120514Sphkint
263120514Sphkeopnotsupp(void)
264120514Sphk{
265120514Sphk
266120514Sphk	return (EOPNOTSUPP);
267120514Sphk}
268120514Sphk
269111179Sphkstatic int
270111179Sphkenxio(void)
271111179Sphk{
272111179Sphk	return (ENXIO);
273111179Sphk}
274111179Sphk
275120514Sphkstatic int
276120514Sphkenodev(void)
277120514Sphk{
278120514Sphk	return (ENODEV);
279120514Sphk}
280120514Sphk
281120514Sphk/* Define a dead_cdevsw for use when devices leave unexpectedly. */
282120514Sphk
283111179Sphk#define dead_open	(d_open_t *)enxio
284111179Sphk#define dead_close	(d_close_t *)enxio
285111179Sphk#define dead_read	(d_read_t *)enxio
286111179Sphk#define dead_write	(d_write_t *)enxio
287111179Sphk#define dead_ioctl	(d_ioctl_t *)enxio
288120514Sphk#define dead_poll	(d_poll_t *)enodev
289120514Sphk#define dead_mmap	(d_mmap_t *)enodev
290111179Sphk
291111179Sphkstatic void
292111179Sphkdead_strategy(struct bio *bp)
293111179Sphk{
294111179Sphk
295111179Sphk	biofinish(bp, NULL, ENXIO);
296111179Sphk}
297111179Sphk
298111220Sphk#define dead_dump	(dumper_t *)enxio
299111179Sphk#define dead_kqfilter	(d_kqfilter_t *)enxio
300193275Sjhb#define dead_mmap_single (d_mmap_single_t *)enodev
301111179Sphk
302111179Sphkstatic struct cdevsw dead_cdevsw = {
303126080Sphk	.d_version =	D_VERSION,
304111815Sphk	.d_open =	dead_open,
305111815Sphk	.d_close =	dead_close,
306111815Sphk	.d_read =	dead_read,
307111815Sphk	.d_write =	dead_write,
308111815Sphk	.d_ioctl =	dead_ioctl,
309111815Sphk	.d_poll =	dead_poll,
310111815Sphk	.d_mmap =	dead_mmap,
311111815Sphk	.d_strategy =	dead_strategy,
312111815Sphk	.d_name =	"dead",
313111815Sphk	.d_dump =	dead_dump,
314193275Sjhb	.d_kqfilter =	dead_kqfilter,
315193275Sjhb	.d_mmap_single = dead_mmap_single
316111179Sphk};
317111179Sphk
318120514Sphk/* Default methods if driver does not specify method */
319111179Sphk
320120514Sphk#define null_open	(d_open_t *)nullop
321120514Sphk#define null_close	(d_close_t *)nullop
322120514Sphk#define no_read		(d_read_t *)enodev
323120514Sphk#define no_write	(d_write_t *)enodev
324120514Sphk#define no_ioctl	(d_ioctl_t *)enodev
325201223Srnoland#define no_mmap		(d_mmap_t *)enodev
326133741Sjmg#define no_kqfilter	(d_kqfilter_t *)enodev
327193275Sjhb#define no_mmap_single	(d_mmap_single_t *)enodev
328120514Sphk
329120514Sphkstatic void
330120514Sphkno_strategy(struct bio *bp)
331120514Sphk{
332120514Sphk
333120514Sphk	biofinish(bp, NULL, ENODEV);
334120514Sphk}
335120514Sphk
336120514Sphkstatic int
337130585Sphkno_poll(struct cdev *dev __unused, int events, struct thread *td __unused)
338120514Sphk{
339120514Sphk
340189450Skib	return (poll_no_poll(events));
341120514Sphk}
342120514Sphk
343120514Sphk#define no_dump		(dumper_t *)enodev
344120514Sphk
345149177Sphkstatic int
346149177Sphkgiant_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
347149177Sphk{
348177301Skib	struct cdevsw *dsw;
349210923Skib	int ref, retval;
350149177Sphk
351210923Skib	dsw = dev_refthread(dev, &ref);
352177301Skib	if (dsw == NULL)
353177301Skib		return (ENXIO);
354149177Sphk	mtx_lock(&Giant);
355177301Skib	retval = dsw->d_gianttrick->d_open(dev, oflags, devtype, td);
356149177Sphk	mtx_unlock(&Giant);
357210923Skib	dev_relthread(dev, ref);
358149177Sphk	return (retval);
359149177Sphk}
360149177Sphk
361149177Sphkstatic int
362170152Skibgiant_fdopen(struct cdev *dev, int oflags, struct thread *td, struct file *fp)
363149177Sphk{
364177301Skib	struct cdevsw *dsw;
365210923Skib	int ref, retval;
366149177Sphk
367210923Skib	dsw = dev_refthread(dev, &ref);
368177301Skib	if (dsw == NULL)
369177301Skib		return (ENXIO);
370149177Sphk	mtx_lock(&Giant);
371177301Skib	retval = dsw->d_gianttrick->d_fdopen(dev, oflags, td, fp);
372149177Sphk	mtx_unlock(&Giant);
373210923Skib	dev_relthread(dev, ref);
374149177Sphk	return (retval);
375149177Sphk}
376149177Sphk
377149177Sphkstatic int
378149177Sphkgiant_close(struct cdev *dev, int fflag, int devtype, struct thread *td)
379149177Sphk{
380177301Skib	struct cdevsw *dsw;
381210923Skib	int ref, retval;
382149177Sphk
383210923Skib	dsw = dev_refthread(dev, &ref);
384177301Skib	if (dsw == NULL)
385177301Skib		return (ENXIO);
386149177Sphk	mtx_lock(&Giant);
387177301Skib	retval = dsw->d_gianttrick->d_close(dev, fflag, devtype, td);
388149177Sphk	mtx_unlock(&Giant);
389210923Skib	dev_relthread(dev, ref);
390149177Sphk	return (retval);
391149177Sphk}
392149177Sphk
393149177Sphkstatic void
394149177Sphkgiant_strategy(struct bio *bp)
395149177Sphk{
396177301Skib	struct cdevsw *dsw;
397177301Skib	struct cdev *dev;
398210923Skib	int ref;
399149177Sphk
400177301Skib	dev = bp->bio_dev;
401210923Skib	dsw = dev_refthread(dev, &ref);
402177301Skib	if (dsw == NULL) {
403177301Skib		biofinish(bp, NULL, ENXIO);
404177301Skib		return;
405177301Skib	}
406149177Sphk	mtx_lock(&Giant);
407177301Skib	dsw->d_gianttrick->d_strategy(bp);
408149177Sphk	mtx_unlock(&Giant);
409210923Skib	dev_relthread(dev, ref);
410149177Sphk}
411149177Sphk
412149177Sphkstatic int
413149177Sphkgiant_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct thread *td)
414149177Sphk{
415177301Skib	struct cdevsw *dsw;
416210923Skib	int ref, retval;
417149177Sphk
418210923Skib	dsw = dev_refthread(dev, &ref);
419177301Skib	if (dsw == NULL)
420177301Skib		return (ENXIO);
421149177Sphk	mtx_lock(&Giant);
422177858Skib	retval = dsw->d_gianttrick->d_ioctl(dev, cmd, data, fflag, td);
423149177Sphk	mtx_unlock(&Giant);
424210923Skib	dev_relthread(dev, ref);
425149177Sphk	return (retval);
426149177Sphk}
427149177Sphk
428149177Sphkstatic int
429149177Sphkgiant_read(struct cdev *dev, struct uio *uio, int ioflag)
430149177Sphk{
431177301Skib	struct cdevsw *dsw;
432210923Skib	int ref, retval;
433149177Sphk
434210923Skib	dsw = dev_refthread(dev, &ref);
435177301Skib	if (dsw == NULL)
436177301Skib		return (ENXIO);
437149177Sphk	mtx_lock(&Giant);
438177858Skib	retval = dsw->d_gianttrick->d_read(dev, uio, ioflag);
439149177Sphk	mtx_unlock(&Giant);
440210923Skib	dev_relthread(dev, ref);
441149177Sphk	return (retval);
442149177Sphk}
443149177Sphk
444149177Sphkstatic int
445149177Sphkgiant_write(struct cdev *dev, struct uio *uio, int ioflag)
446149177Sphk{
447177301Skib	struct cdevsw *dsw;
448210923Skib	int ref, retval;
449149177Sphk
450210923Skib	dsw = dev_refthread(dev, &ref);
451177301Skib	if (dsw == NULL)
452177301Skib		return (ENXIO);
453149177Sphk	mtx_lock(&Giant);
454177301Skib	retval = dsw->d_gianttrick->d_write(dev, uio, ioflag);
455149177Sphk	mtx_unlock(&Giant);
456210923Skib	dev_relthread(dev, ref);
457149177Sphk	return (retval);
458149177Sphk}
459149177Sphk
460149177Sphkstatic int
461149177Sphkgiant_poll(struct cdev *dev, int events, struct thread *td)
462149177Sphk{
463177301Skib	struct cdevsw *dsw;
464210923Skib	int ref, retval;
465149177Sphk
466210923Skib	dsw = dev_refthread(dev, &ref);
467177301Skib	if (dsw == NULL)
468177301Skib		return (ENXIO);
469149177Sphk	mtx_lock(&Giant);
470177301Skib	retval = dsw->d_gianttrick->d_poll(dev, events, td);
471149177Sphk	mtx_unlock(&Giant);
472210923Skib	dev_relthread(dev, ref);
473149177Sphk	return (retval);
474149177Sphk}
475149177Sphk
476149177Sphkstatic int
477149177Sphkgiant_kqfilter(struct cdev *dev, struct knote *kn)
478149177Sphk{
479177301Skib	struct cdevsw *dsw;
480210923Skib	int ref, retval;
481149177Sphk
482210923Skib	dsw = dev_refthread(dev, &ref);
483177301Skib	if (dsw == NULL)
484177301Skib		return (ENXIO);
485149177Sphk	mtx_lock(&Giant);
486177301Skib	retval = dsw->d_gianttrick->d_kqfilter(dev, kn);
487149177Sphk	mtx_unlock(&Giant);
488210923Skib	dev_relthread(dev, ref);
489149177Sphk	return (retval);
490149177Sphk}
491149177Sphk
492149177Sphkstatic int
493201223Srnolandgiant_mmap(struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr, int nprot,
494196615Sjhb    vm_memattr_t *memattr)
495149177Sphk{
496177301Skib	struct cdevsw *dsw;
497210923Skib	int ref, retval;
498149177Sphk
499210923Skib	dsw = dev_refthread(dev, &ref);
500177301Skib	if (dsw == NULL)
501177301Skib		return (ENXIO);
502149177Sphk	mtx_lock(&Giant);
503201223Srnoland	retval = dsw->d_gianttrick->d_mmap(dev, offset, paddr, nprot,
504201223Srnoland	    memattr);
505149177Sphk	mtx_unlock(&Giant);
506210923Skib	dev_relthread(dev, ref);
507149177Sphk	return (retval);
508149177Sphk}
509149177Sphk
510193275Sjhbstatic int
511193275Sjhbgiant_mmap_single(struct cdev *dev, vm_ooffset_t *offset, vm_size_t size,
512193275Sjhb    vm_object_t *object, int nprot)
513193275Sjhb{
514193275Sjhb	struct cdevsw *dsw;
515210923Skib	int ref, retval;
516149177Sphk
517210923Skib	dsw = dev_refthread(dev, &ref);
518193275Sjhb	if (dsw == NULL)
519193275Sjhb		return (ENXIO);
520193275Sjhb	mtx_lock(&Giant);
521193275Sjhb	retval = dsw->d_gianttrick->d_mmap_single(dev, offset, size, object,
522193275Sjhb	    nprot);
523193275Sjhb	mtx_unlock(&Giant);
524210923Skib	dev_relthread(dev, ref);
525193275Sjhb	return (retval);
526193275Sjhb}
527193275Sjhb
528178991Skibstatic void
529207729Skibnotify(struct cdev *dev, const char *ev, int flags)
530178991Skib{
531178991Skib	static const char prefix[] = "cdev=";
532178991Skib	char *data;
533209105Skib	int namelen, mflags;
534178991Skib
535178991Skib	if (cold)
536178991Skib		return;
537209105Skib	mflags = (flags & MAKEDEV_NOWAIT) ? M_NOWAIT : M_WAITOK;
538178991Skib	namelen = strlen(dev->si_name);
539209105Skib	data = malloc(namelen + sizeof(prefix), M_TEMP, mflags);
540192535Sattilio	if (data == NULL)
541192535Sattilio		return;
542178991Skib	memcpy(data, prefix, sizeof(prefix) - 1);
543178991Skib	memcpy(data + sizeof(prefix) - 1, dev->si_name, namelen + 1);
544209105Skib	devctl_notify_f("DEVFS", "CDEV", ev, data, mflags);
545178991Skib	free(data, M_TEMP);
546178991Skib}
547178991Skib
548178991Skibstatic void
549207729Skibnotify_create(struct cdev *dev, int flags)
550178991Skib{
551178991Skib
552207729Skib	notify(dev, "CREATE", flags);
553178991Skib}
554178991Skib
555178991Skibstatic void
556178991Skibnotify_destroy(struct cdev *dev)
557178991Skib{
558178991Skib
559207729Skib	notify(dev, "DESTROY", MAKEDEV_WAITOK);
560178991Skib}
561178991Skib
562130585Sphkstatic struct cdev *
563293346Skibnewdev(struct make_dev_args *args, struct cdev *si)
56447028Sphk{
565140733Sphk	struct cdev *si2;
566293346Skib	struct cdevsw *csw;
56748936Sphk
568140733Sphk	mtx_assert(&devmtx, MA_OWNED);
569293346Skib	csw = args->mda_devsw;
570353783Skevans	si2 = NULL;
571179726Sed	if (csw->d_flags & D_NEEDMINOR) {
572179726Sed		/* We may want to return an existing device */
573179726Sed		LIST_FOREACH(si2, &csw->d_devs, si_list) {
574293346Skib			if (dev2unit(si2) == args->mda_unit) {
575179726Sed				dev_free_devlocked(si);
576353783Skevans				si = si2;
577353783Skevans				break;
578179726Sed			}
579140733Sphk		}
580353783Skevans
581353783Skevans		/*
582353783Skevans		 * If we're returning an existing device, we should make sure
583353783Skevans		 * it isn't already initialized.  This would have been caught
584353783Skevans		 * in consumers anyways, but it's good to catch such a case
585353783Skevans		 * early.  We still need to complete initialization of the
586353783Skevans		 * device, and we'll use whatever make_dev_args were passed in
587353783Skevans		 * to do so.
588353783Skevans		 */
589353783Skevans		KASSERT(si2 == NULL || (si2->si_flags & SI_NAMED) == 0,
590353783Skevans		    ("make_dev() by driver %s on pre-existing device (min=%x, name=%s)",
591353783Skevans		    args->mda_devsw->d_name, dev2unit(si2), devtoname(si2)));
59248936Sphk	}
593293346Skib	si->si_drv0 = args->mda_unit;
594293346Skib	si->si_drv1 = args->mda_si_drv1;
595293346Skib	si->si_drv2 = args->mda_si_drv2;
596353783Skevans	/* Only push to csw->d_devs if it's not a cloned device. */
597353783Skevans	if (si2 == NULL) {
598353783Skevans		si->si_devsw = csw;
599353783Skevans		LIST_INSERT_HEAD(&csw->d_devs, si, si_list);
600353783Skevans	} else {
601353783Skevans		KASSERT(si->si_devsw == csw,
602353783Skevans		    ("%s: inconsistent devsw between clone_create() and make_dev()",
603353783Skevans		    __func__));
604353783Skevans	}
605125850Sbde	return (si);
60647028Sphk}
60747028Sphk
608125846Sphkstatic void
609144292Sphkfini_cdevsw(struct cdevsw *devsw)
61049535Sphk{
611149324Sphk	struct cdevsw *gt;
61249535Sphk
613149324Sphk	if (devsw->d_gianttrick != NULL) {
614149324Sphk		gt = devsw->d_gianttrick;
615149324Sphk		memcpy(devsw, gt, sizeof *devsw);
616177301Skib		cdevsw_free_devlocked(gt);
617149324Sphk		devsw->d_gianttrick = NULL;
618149324Sphk	}
619126156Sphk	devsw->d_flags &= ~D_INIT;
620126082Sphk}
621126082Sphk
622207729Skibstatic int
623207729Skibprep_cdevsw(struct cdevsw *devsw, int flags)
624126077Sphk{
625149177Sphk	struct cdevsw *dsw2;
626126077Sphk
627177301Skib	mtx_assert(&devmtx, MA_OWNED);
628177301Skib	if (devsw->d_flags & D_INIT)
629209106Skib		return (0);
630177301Skib	if (devsw->d_flags & D_NEEDGIANT) {
631177301Skib		dev_unlock();
632207729Skib		dsw2 = malloc(sizeof *dsw2, M_DEVT,
633207729Skib		     (flags & MAKEDEV_NOWAIT) ? M_NOWAIT : M_WAITOK);
634177301Skib		dev_lock();
635207729Skib		if (dsw2 == NULL && !(devsw->d_flags & D_INIT))
636209106Skib			return (ENOMEM);
637177301Skib	} else
638149177Sphk		dsw2 = NULL;
639177301Skib	if (devsw->d_flags & D_INIT) {
640177301Skib		if (dsw2 != NULL)
641177301Skib			cdevsw_free_devlocked(dsw2);
642209106Skib		return (0);
643177301Skib	}
644126082Sphk
645201223Srnoland	if (devsw->d_version != D_VERSION_03) {
646126082Sphk		printf(
647126082Sphk		    "WARNING: Device driver \"%s\" has wrong version %s\n",
648154266Salfred		    devsw->d_name == NULL ? "???" : devsw->d_name,
649154266Salfred		    "and is disabled.  Recompile KLD module.");
650126082Sphk		devsw->d_open = dead_open;
651126082Sphk		devsw->d_close = dead_close;
652126082Sphk		devsw->d_read = dead_read;
653126082Sphk		devsw->d_write = dead_write;
654126082Sphk		devsw->d_ioctl = dead_ioctl;
655126082Sphk		devsw->d_poll = dead_poll;
656126082Sphk		devsw->d_mmap = dead_mmap;
657201223Srnoland		devsw->d_mmap_single = dead_mmap_single;
658126082Sphk		devsw->d_strategy = dead_strategy;
659126082Sphk		devsw->d_dump = dead_dump;
660126082Sphk		devsw->d_kqfilter = dead_kqfilter;
661126082Sphk	}
662126082Sphk
663149177Sphk	if (devsw->d_flags & D_NEEDGIANT) {
664149177Sphk		if (devsw->d_gianttrick == NULL) {
665149177Sphk			memcpy(dsw2, devsw, sizeof *dsw2);
666149177Sphk			devsw->d_gianttrick = dsw2;
667177301Skib			dsw2 = NULL;
668177301Skib		}
669149177Sphk	}
670149177Sphk
671149177Sphk#define FIXUP(member, noop, giant) 				\
672149177Sphk	do {							\
673149177Sphk		if (devsw->member == NULL) {			\
674149177Sphk			devsw->member = noop;			\
675149177Sphk		} else if (devsw->d_flags & D_NEEDGIANT)	\
676149177Sphk			devsw->member = giant;			\
677149177Sphk		}						\
678149177Sphk	while (0)
679149177Sphk
680149177Sphk	FIXUP(d_open,		null_open,	giant_open);
681149177Sphk	FIXUP(d_fdopen,		NULL,		giant_fdopen);
682149177Sphk	FIXUP(d_close,		null_close,	giant_close);
683149177Sphk	FIXUP(d_read,		no_read,	giant_read);
684149177Sphk	FIXUP(d_write,		no_write,	giant_write);
685149177Sphk	FIXUP(d_ioctl,		no_ioctl,	giant_ioctl);
686149177Sphk	FIXUP(d_poll,		no_poll,	giant_poll);
687201223Srnoland	FIXUP(d_mmap,		no_mmap,	giant_mmap);
688149177Sphk	FIXUP(d_strategy,	no_strategy,	giant_strategy);
689149177Sphk	FIXUP(d_kqfilter,	no_kqfilter,	giant_kqfilter);
690193275Sjhb	FIXUP(d_mmap_single,	no_mmap_single,	giant_mmap_single);
691149177Sphk
692120514Sphk	if (devsw->d_dump == NULL)	devsw->d_dump = no_dump;
693126082Sphk
694126082Sphk	LIST_INIT(&devsw->d_devs);
695126082Sphk
696126082Sphk	devsw->d_flags |= D_INIT;
697126082Sphk
698177301Skib	if (dsw2 != NULL)
699177301Skib		cdevsw_free_devlocked(dsw2);
700209106Skib	return (0);
701125846Sphk}
702111622Sphk
703209106Skibstatic int
704213526Sjhprep_devname(struct cdev *dev, const char *fmt, va_list ap)
705213526Sjh{
706213526Sjh	int len;
707213526Sjh	char *from, *q, *s, *to;
708213526Sjh
709213526Sjh	mtx_assert(&devmtx, MA_OWNED);
710213526Sjh
711231386Sed	len = vsnrprintf(dev->si_name, sizeof(dev->si_name), 32, fmt, ap);
712231379Sed	if (len > sizeof(dev->si_name) - 1)
713213526Sjh		return (ENAMETOOLONG);
714213526Sjh
715213526Sjh	/* Strip leading slashes. */
716231379Sed	for (from = dev->si_name; *from == '/'; from++)
717213526Sjh		;
718213526Sjh
719231379Sed	for (to = dev->si_name; *from != '\0'; from++, to++) {
720244584Sjh		/*
721244584Sjh		 * Spaces and double quotation marks cause
722244584Sjh		 * problems for the devctl(4) protocol.
723244584Sjh		 * Reject names containing those characters.
724244584Sjh		 */
725244584Sjh		if (isspace(*from) || *from == '"')
726244584Sjh			return (EINVAL);
727213526Sjh		/* Treat multiple sequential slashes as single. */
728213526Sjh		while (from[0] == '/' && from[1] == '/')
729213526Sjh			from++;
730213526Sjh		/* Trailing slash is considered invalid. */
731213526Sjh		if (from[0] == '/' && from[1] == '\0')
732213526Sjh			return (EINVAL);
733213526Sjh		*to = *from;
734213526Sjh	}
735213526Sjh	*to = '\0';
736213526Sjh
737231379Sed	if (dev->si_name[0] == '\0')
738213526Sjh		return (EINVAL);
739213526Sjh
740213526Sjh	/* Disallow "." and ".." components. */
741231379Sed	for (s = dev->si_name;;) {
742213526Sjh		for (q = s; *q != '/' && *q != '\0'; q++)
743213526Sjh			;
744213526Sjh		if (q - s == 1 && s[0] == '.')
745213526Sjh			return (EINVAL);
746213526Sjh		if (q - s == 2 && s[0] == '.' && s[1] == '.')
747213526Sjh			return (EINVAL);
748213526Sjh		if (*q != '/')
749213526Sjh			break;
750213526Sjh		s = q + 1;
751213526Sjh	}
752213526Sjh
753231379Sed	if (devfs_dev_exists(dev->si_name) != 0)
754213526Sjh		return (EEXIST);
755213526Sjh
756213526Sjh	return (0);
757213526Sjh}
758213526Sjh
759293346Skibvoid
760293346Skibmake_dev_args_init_impl(struct make_dev_args *args, size_t sz)
761293346Skib{
762293346Skib
763293346Skib	bzero(args, sz);
764293346Skib	args->mda_size = sz;
765293346Skib}
766293346Skib
767213526Sjhstatic int
768293346Skibmake_dev_sv(struct make_dev_args *args1, struct cdev **dres,
769293346Skib    const char *fmt, va_list ap)
770125846Sphk{
771213526Sjh	struct cdev *dev, *dev_new;
772293346Skib	struct make_dev_args args;
773213526Sjh	int res;
774125846Sphk
775293346Skib	bzero(&args, sizeof(args));
776293346Skib	if (sizeof(args) < args1->mda_size)
777293346Skib		return (EINVAL);
778293346Skib	bcopy(args1, &args, args1->mda_size);
779293346Skib	KASSERT((args.mda_flags & MAKEDEV_WAITOK) == 0 ||
780293346Skib	    (args.mda_flags & MAKEDEV_NOWAIT) == 0,
781293346Skib	    ("make_dev_sv: both WAITOK and NOWAIT specified"));
782293346Skib	dev_new = devfs_alloc(args.mda_flags);
783213526Sjh	if (dev_new == NULL)
784209106Skib		return (ENOMEM);
785140733Sphk	dev_lock();
786293346Skib	res = prep_cdevsw(args.mda_devsw, args.mda_flags);
787209106Skib	if (res != 0) {
788207729Skib		dev_unlock();
789213526Sjh		devfs_free(dev_new);
790209106Skib		return (res);
791207729Skib	}
792293346Skib	dev = newdev(&args, dev_new);
793214917Sjh	if ((dev->si_flags & SI_NAMED) == 0) {
794213526Sjh		res = prep_devname(dev, fmt, ap);
795213526Sjh		if (res != 0) {
796293346Skib			if ((args.mda_flags & MAKEDEV_CHECKNAME) == 0) {
797213526Sjh				panic(
798293346Skib			"make_dev_sv: bad si_name (error=%d, si_name=%s)",
799213526Sjh				    res, dev->si_name);
800213526Sjh			}
801213526Sjh			if (dev == dev_new) {
802213526Sjh				LIST_REMOVE(dev, si_list);
803213526Sjh				dev_unlock();
804213526Sjh				devfs_free(dev);
805224521Skib			} else
806224521Skib				dev_unlock();
807213526Sjh			return (res);
808214917Sjh		}
809213526Sjh	}
810293346Skib	if ((args.mda_flags & MAKEDEV_REF) != 0)
811171181Skib		dev_refl(dev);
812293346Skib	if ((args.mda_flags & MAKEDEV_ETERNAL) != 0)
813210923Skib		dev->si_flags |= SI_ETERNAL;
814126082Sphk	KASSERT(!(dev->si_flags & SI_NAMED),
815144281Sphk	    ("make_dev() by driver %s on pre-existing device (min=%x, name=%s)",
816293346Skib	    args.mda_devsw->d_name, dev2unit(dev), devtoname(dev)));
81765747Sphk	dev->si_flags |= SI_NAMED;
818293346Skib	if (args.mda_cr != NULL)
819293346Skib		dev->si_cred = crhold(args.mda_cr);
820293346Skib	dev->si_uid = args.mda_uid;
821293346Skib	dev->si_gid = args.mda_gid;
822293346Skib	dev->si_mode = args.mda_mode;
82350092Sjulian
824111730Sphk	devfs_create(dev);
825171202Skib	clean_unrhdrl(devfs_inos);
826177301Skib	dev_unlock_and_free();
827178991Skib
828293346Skib	notify_create(dev, args.mda_flags);
829178991Skib
830209106Skib	*dres = dev;
831209106Skib	return (0);
83249535Sphk}
83349535Sphk
834293346Skibint
835293346Skibmake_dev_s(struct make_dev_args *args, struct cdev **dres,
836293346Skib    const char *fmt, ...)
837293346Skib{
838293346Skib	va_list ap;
839293346Skib	int res;
840293346Skib
841293346Skib	va_start(ap, fmt);
842293346Skib	res = make_dev_sv(args, dres, fmt, ap);
843293346Skib	va_end(ap);
844293346Skib	return (res);
845293346Skib}
846293346Skib
847293346Skibstatic int
848293346Skibmake_dev_credv(int flags, struct cdev **dres, struct cdevsw *devsw, int unit,
849293346Skib    struct ucred *cr, uid_t uid, gid_t gid, int mode, const char *fmt,
850293346Skib    va_list ap)
851293346Skib{
852293346Skib	struct make_dev_args args;
853293346Skib
854293346Skib	make_dev_args_init(&args);
855293346Skib	args.mda_flags = flags;
856293346Skib	args.mda_devsw = devsw;
857293346Skib	args.mda_cr = cr;
858293346Skib	args.mda_uid = uid;
859293346Skib	args.mda_gid = gid;
860293346Skib	args.mda_mode = mode;
861293346Skib	args.mda_unit = unit;
862293346Skib	return (make_dev_sv(&args, dres, fmt, ap));
863293346Skib}
864293346Skib
865147982Srwatsonstruct cdev *
866183382Sedmake_dev(struct cdevsw *devsw, int unit, uid_t uid, gid_t gid, int mode,
867147982Srwatson    const char *fmt, ...)
868147982Srwatson{
869147982Srwatson	struct cdev *dev;
870147982Srwatson	va_list ap;
871209106Skib	int res;
872147982Srwatson
873147982Srwatson	va_start(ap, fmt);
874209106Skib	res = make_dev_credv(0, &dev, devsw, unit, NULL, uid, gid, mode, fmt,
875209106Skib	    ap);
876147982Srwatson	va_end(ap);
877213526Sjh	KASSERT(res == 0 && dev != NULL,
878213526Sjh	    ("make_dev: failed make_dev_credv (error=%d)", res));
879147982Srwatson	return (dev);
880147982Srwatson}
881147982Srwatson
882147982Srwatsonstruct cdev *
883183382Sedmake_dev_cred(struct cdevsw *devsw, int unit, struct ucred *cr, uid_t uid,
884147982Srwatson    gid_t gid, int mode, const char *fmt, ...)
885147982Srwatson{
886147982Srwatson	struct cdev *dev;
887147982Srwatson	va_list ap;
888209106Skib	int res;
889147982Srwatson
890147982Srwatson	va_start(ap, fmt);
891209106Skib	res = make_dev_credv(0, &dev, devsw, unit, cr, uid, gid, mode, fmt, ap);
892147982Srwatson	va_end(ap);
893147982Srwatson
894209106Skib	KASSERT(res == 0 && dev != NULL,
895213526Sjh	    ("make_dev_cred: failed make_dev_credv (error=%d)", res));
896147982Srwatson	return (dev);
897147982Srwatson}
898147982Srwatson
899171181Skibstruct cdev *
900209106Skibmake_dev_credf(int flags, struct cdevsw *devsw, int unit, struct ucred *cr,
901209106Skib    uid_t uid, gid_t gid, int mode, const char *fmt, ...)
902171181Skib{
903171181Skib	struct cdev *dev;
904171181Skib	va_list ap;
905209106Skib	int res;
906171181Skib
907171181Skib	va_start(ap, fmt);
908209106Skib	res = make_dev_credv(flags, &dev, devsw, unit, cr, uid, gid, mode,
909171181Skib	    fmt, ap);
910171181Skib	va_end(ap);
911171181Skib
912213526Sjh	KASSERT(((flags & MAKEDEV_NOWAIT) != 0 && res == ENOMEM) ||
913213526Sjh	    ((flags & MAKEDEV_CHECKNAME) != 0 && res != ENOMEM) || res == 0,
914213526Sjh	    ("make_dev_credf: failed make_dev_credv (error=%d)", res));
915209106Skib	return (res == 0 ? dev : NULL);
916171181Skib}
917171181Skib
918209106Skibint
919209244Sedmake_dev_p(int flags, struct cdev **cdev, struct cdevsw *devsw,
920209106Skib    struct ucred *cr, uid_t uid, gid_t gid, int mode, const char *fmt, ...)
921209106Skib{
922209106Skib	va_list ap;
923209106Skib	int res;
924209106Skib
925209106Skib	va_start(ap, fmt);
926209244Sed	res = make_dev_credv(flags, cdev, devsw, 0, cr, uid, gid, mode,
927209106Skib	    fmt, ap);
928209106Skib	va_end(ap);
929209106Skib
930213526Sjh	KASSERT(((flags & MAKEDEV_NOWAIT) != 0 && res == ENOMEM) ||
931213526Sjh	    ((flags & MAKEDEV_CHECKNAME) != 0 && res != ENOMEM) || res == 0,
932213526Sjh	    ("make_dev_p: failed make_dev_credv (error=%d)", res));
933209106Skib	return (res);
934209106Skib}
935209106Skib
936150342Sphkstatic void
937150342Sphkdev_dependsl(struct cdev *pdev, struct cdev *cdev)
938150342Sphk{
939150342Sphk
940150342Sphk	cdev->si_parent = pdev;
941150342Sphk	cdev->si_flags |= SI_CHILD;
942150342Sphk	LIST_INSERT_HEAD(&pdev->si_children, cdev, si_siblings);
943150342Sphk}
944150342Sphk
945150342Sphk
94677215Sphkvoid
947130585Sphkdev_depends(struct cdev *pdev, struct cdev *cdev)
94877215Sphk{
94977215Sphk
950135600Sphk	dev_lock();
951150342Sphk	dev_dependsl(pdev, cdev);
952135600Sphk	dev_unlock();
95377215Sphk}
95477215Sphk
955221397Saestatic int
956221397Saemake_dev_alias_v(int flags, struct cdev **cdev, struct cdev *pdev,
957221397Sae    const char *fmt, va_list ap)
95864880Sphk{
959130585Sphk	struct cdev *dev;
960213526Sjh	int error;
96164880Sphk
962221397Sae	KASSERT(pdev != NULL, ("make_dev_alias_v: pdev is NULL"));
963221397Sae	KASSERT((flags & MAKEDEV_WAITOK) == 0 || (flags & MAKEDEV_NOWAIT) == 0,
964221397Sae	    ("make_dev_alias_v: both WAITOK and NOWAIT specified"));
965221397Sae	KASSERT((flags & ~(MAKEDEV_WAITOK | MAKEDEV_NOWAIT |
966221397Sae	    MAKEDEV_CHECKNAME)) == 0,
967221397Sae	    ("make_dev_alias_v: invalid flags specified (flags=%02x)", flags));
968221397Sae
969221397Sae	dev = devfs_alloc(flags);
970221397Sae	if (dev == NULL)
971221397Sae		return (ENOMEM);
972135600Sphk	dev_lock();
97364880Sphk	dev->si_flags |= SI_ALIAS;
974213526Sjh	error = prep_devname(dev, fmt, ap);
975213526Sjh	if (error != 0) {
976221397Sae		if ((flags & MAKEDEV_CHECKNAME) == 0) {
977221397Sae			panic("make_dev_alias_v: bad si_name "
978221397Sae			    "(error=%d, si_name=%s)", error, dev->si_name);
979221397Sae		}
980221397Sae		dev_unlock();
981221397Sae		devfs_free(dev);
982221397Sae		return (error);
983110318Sphk	}
984213526Sjh	dev->si_flags |= SI_NAMED;
985111730Sphk	devfs_create(dev);
986180445Skib	dev_dependsl(pdev, dev);
987171202Skib	clean_unrhdrl(devfs_inos);
988135600Sphk	dev_unlock();
989178991Skib
990221397Sae	notify_create(dev, flags);
991221397Sae	*cdev = dev;
992178991Skib
993221397Sae	return (0);
994221397Sae}
995221397Sae
996221397Saestruct cdev *
997221397Saemake_dev_alias(struct cdev *pdev, const char *fmt, ...)
998221397Sae{
999221397Sae	struct cdev *dev;
1000221397Sae	va_list ap;
1001221397Sae	int res;
1002221397Sae
1003221397Sae	va_start(ap, fmt);
1004221397Sae	res = make_dev_alias_v(MAKEDEV_WAITOK, &dev, pdev, fmt, ap);
1005221397Sae	va_end(ap);
1006221397Sae
1007221397Sae	KASSERT(res == 0 && dev != NULL,
1008221397Sae	    ("make_dev_alias: failed make_dev_alias_v (error=%d)", res));
100964880Sphk	return (dev);
101064880Sphk}
101164880Sphk
1012221397Saeint
1013221397Saemake_dev_alias_p(int flags, struct cdev **cdev, struct cdev *pdev,
1014221397Sae    const char *fmt, ...)
1015221397Sae{
1016221397Sae	va_list ap;
1017221397Sae	int res;
1018221397Sae
1019221397Sae	va_start(ap, fmt);
1020221397Sae	res = make_dev_alias_v(flags, cdev, pdev, fmt, ap);
1021221397Sae	va_end(ap);
1022221397Sae	return (res);
1023221397Sae}
1024221397Sae
1025223085Sgibbsint
1026223085Sgibbsmake_dev_physpath_alias(int flags, struct cdev **cdev, struct cdev *pdev,
1027223085Sgibbs    struct cdev *old_alias, const char *physpath)
1028223085Sgibbs{
1029223085Sgibbs	char *devfspath;
1030223085Sgibbs	int physpath_len;
1031223085Sgibbs	int max_parentpath_len;
1032223085Sgibbs	int parentpath_len;
1033223085Sgibbs	int devfspathbuf_len;
1034223085Sgibbs	int mflags;
1035223085Sgibbs	int ret;
1036223085Sgibbs
1037223085Sgibbs	*cdev = NULL;
1038223085Sgibbs	devfspath = NULL;
1039223085Sgibbs	physpath_len = strlen(physpath);
1040223085Sgibbs	ret = EINVAL;
1041223085Sgibbs	if (physpath_len == 0)
1042223085Sgibbs		goto out;
1043223085Sgibbs
1044223085Sgibbs	if (strncmp("id1,", physpath, 4) == 0) {
1045223085Sgibbs		physpath += 4;
1046223085Sgibbs		physpath_len -= 4;
1047223085Sgibbs		if (physpath_len == 0)
1048223085Sgibbs			goto out;
1049223085Sgibbs	}
1050223085Sgibbs
1051223085Sgibbs	max_parentpath_len = SPECNAMELEN - physpath_len - /*/*/1;
1052223085Sgibbs	parentpath_len = strlen(pdev->si_name);
1053223085Sgibbs	if (max_parentpath_len < parentpath_len) {
1054235899Smav		if (bootverbose)
1055235899Smav			printf("WARNING: Unable to alias %s "
1056235899Smav			    "to %s/%s - path too long\n",
1057235899Smav			    pdev->si_name, physpath, pdev->si_name);
1058223085Sgibbs		ret = ENAMETOOLONG;
1059223085Sgibbs		goto out;
1060223085Sgibbs	}
1061223085Sgibbs
1062223085Sgibbs	mflags = (flags & MAKEDEV_NOWAIT) ? M_NOWAIT : M_WAITOK;
1063223085Sgibbs	devfspathbuf_len = physpath_len + /*/*/1 + parentpath_len + /*NUL*/1;
1064223085Sgibbs	devfspath = malloc(devfspathbuf_len, M_DEVBUF, mflags);
1065223085Sgibbs	if (devfspath == NULL) {
1066223085Sgibbs		ret = ENOMEM;
1067223085Sgibbs		goto out;
1068223085Sgibbs	}
1069223085Sgibbs
1070223085Sgibbs	sprintf(devfspath, "%s/%s", physpath, pdev->si_name);
1071227444Skib	if (old_alias != NULL && strcmp(old_alias->si_name, devfspath) == 0) {
1072223085Sgibbs		/* Retain the existing alias. */
1073223085Sgibbs		*cdev = old_alias;
1074223085Sgibbs		old_alias = NULL;
1075223085Sgibbs		ret = 0;
1076223085Sgibbs	} else {
1077227443Skib		ret = make_dev_alias_p(flags, cdev, pdev, "%s", devfspath);
1078223085Sgibbs	}
1079223085Sgibbsout:
1080223085Sgibbs	if (old_alias != NULL)
1081223085Sgibbs		destroy_dev(old_alias);
1082223085Sgibbs	if (devfspath != NULL)
1083223085Sgibbs		free(devfspath, M_DEVBUF);
1084223085Sgibbs	return (ret);
1085223085Sgibbs}
1086223085Sgibbs
1087126082Sphkstatic void
1088142242Sphkdestroy_devl(struct cdev *dev)
108950549Sphk{
1090135843Sphk	struct cdevsw *csw;
1091216371Shselasky	struct cdev_privdata *p;
1092277391Skib	struct cdev_priv *cdp;
1093135843Sphk
1094142242Sphk	mtx_assert(&devmtx, MA_OWNED);
1095135843Sphk	KASSERT(dev->si_flags & SI_NAMED,
1096183397Sed	    ("WARNING: Driver mistake: destroy_dev on %d\n", dev2unit(dev)));
1097210923Skib	KASSERT((dev->si_flags & SI_ETERNAL) == 0,
1098210923Skib	    ("WARNING: Driver mistake: destroy_dev on eternal %d\n",
1099210923Skib	     dev2unit(dev)));
1100154029Sbz
1101277391Skib	cdp = cdev2priv(dev);
1102277391Skib	if ((cdp->cdp_flags & CDP_UNREF_DTR) == 0) {
1103277391Skib		/*
1104277391Skib		 * Avoid race with dev_rel(), e.g. from the populate
1105277391Skib		 * loop.  If CDP_UNREF_DTR flag is set, the reference
1106277391Skib		 * to be dropped at the end of destroy_devl() was
1107277391Skib		 * already taken by delist_dev_locked().
1108277391Skib		 */
1109277391Skib		dev_refl(dev);
1110126082Sphk
1111277391Skib		devfs_destroy(dev);
1112277391Skib	}
1113277391Skib
1114126082Sphk	/* Remove name marking */
1115126077Sphk	dev->si_flags &= ~SI_NAMED;
1116126077Sphk
1117126082Sphk	/* If we are a child, remove us from the parents list */
111877215Sphk	if (dev->si_flags & SI_CHILD) {
111977215Sphk		LIST_REMOVE(dev, si_siblings);
112077215Sphk		dev->si_flags &= ~SI_CHILD;
112177215Sphk	}
1122126082Sphk
1123126082Sphk	/* Kill our children */
112477215Sphk	while (!LIST_EMPTY(&dev->si_children))
1125142242Sphk		destroy_devl(LIST_FIRST(&dev->si_children));
1126126082Sphk
1127126082Sphk	/* Remove from clone list */
1128126077Sphk	if (dev->si_flags & SI_CLONELIST) {
1129126077Sphk		LIST_REMOVE(dev, si_clone);
1130126077Sphk		dev->si_flags &= ~SI_CLONELIST;
1131126077Sphk	}
1132126082Sphk
1133135843Sphk	csw = dev->si_devsw;
1134135934Sgreen	dev->si_devsw = NULL;	/* already NULL for SI_ALIAS */
1135135934Sgreen	while (csw != NULL && csw->d_purge != NULL && dev->si_threadcount) {
1136135843Sphk		csw->d_purge(dev);
1137135843Sphk		msleep(csw, &devmtx, PRIBIO, "devprg", hz/10);
1138158684Sphk		if (dev->si_threadcount)
1139158684Sphk			printf("Still %lu threads in %s\n",
1140158684Sphk			    dev->si_threadcount, devtoname(dev));
1141135843Sphk	}
1142163328Stegge	while (dev->si_threadcount != 0) {
1143163328Stegge		/* Use unique dummy wait ident */
1144163328Stegge		msleep(&csw, &devmtx, PRIBIO, "devdrn", hz / 10);
1145163328Stegge	}
1146135843Sphk
1147179175Skib	dev_unlock();
1148280345Shselasky	if ((cdp->cdp_flags & CDP_UNREF_DTR) == 0) {
1149280345Shselasky		/* avoid out of order notify events */
1150280345Shselasky		notify_destroy(dev);
1151280345Shselasky	}
1152179175Skib	mtx_lock(&cdevpriv_mtx);
1153280345Shselasky	while ((p = LIST_FIRST(&cdp->cdp_fdpriv)) != NULL) {
1154179175Skib		devfs_destroy_cdevpriv(p);
1155179175Skib		mtx_lock(&cdevpriv_mtx);
1156179175Skib	}
1157179175Skib	mtx_unlock(&cdevpriv_mtx);
1158179175Skib	dev_lock();
1159178991Skib
1160135843Sphk	dev->si_drv1 = 0;
1161135843Sphk	dev->si_drv2 = 0;
1162135843Sphk	bzero(&dev->__si_u, sizeof(dev->__si_u));
1163135843Sphk
1164126082Sphk	if (!(dev->si_flags & SI_ALIAS)) {
1165126082Sphk		/* Remove from cdevsw list */
1166126082Sphk		LIST_REMOVE(dev, si_list);
1167126082Sphk
1168150342Sphk		/* If cdevsw has no more struct cdev *'s, clean it */
1169171181Skib		if (LIST_EMPTY(&csw->d_devs)) {
1170135844Sphk			fini_cdevsw(csw);
1171171181Skib			wakeup(&csw->d_devs);
1172171181Skib		}
1173126082Sphk	}
117465747Sphk	dev->si_flags &= ~SI_ALIAS;
1175277391Skib	cdp->cdp_flags &= ~CDP_UNREF_DTR;
1176277391Skib	dev->si_refcount--;
1177135843Sphk
1178277391Skib	if (dev->si_refcount > 0)
1179126082Sphk		LIST_INSERT_HEAD(&dead_cdevsw.d_devs, dev, si_list);
1180277391Skib	else
1181170950Skib		dev_free_devlocked(dev);
118250549Sphk}
118350549Sphk
1184277179Shselaskystatic void
1185277179Shselaskydelist_dev_locked(struct cdev *dev)
1186277179Shselasky{
1187277391Skib	struct cdev_priv *cdp;
1188277179Shselasky	struct cdev *child;
1189277391Skib
1190277391Skib	mtx_assert(&devmtx, MA_OWNED);
1191277391Skib	cdp = cdev2priv(dev);
1192277391Skib	if ((cdp->cdp_flags & CDP_UNREF_DTR) != 0)
1193277391Skib		return;
1194277391Skib	cdp->cdp_flags |= CDP_UNREF_DTR;
1195277391Skib	dev_refl(dev);
1196277179Shselasky	devfs_destroy(dev);
1197277179Shselasky	LIST_FOREACH(child, &dev->si_children, si_siblings)
1198277179Shselasky		delist_dev_locked(child);
1199280345Shselasky	dev_unlock();
1200280345Shselasky	/* ensure the destroy event is queued in order */
1201280345Shselasky	notify_destroy(dev);
1202280345Shselasky	dev_lock();
1203277179Shselasky}
1204277179Shselasky
1205280345Shselasky/*
1206280345Shselasky * This function will delist a character device and its children from
1207280345Shselasky * the directory listing and create a destroy event without waiting
1208280345Shselasky * for all character device references to go away. At some later point
1209280345Shselasky * destroy_dev() must be called to complete the character device
1210280345Shselasky * destruction. After calling this function the character device name
1211280345Shselasky * can instantly be re-used.
1212280345Shselasky */
1213126082Sphkvoid
1214277179Shselaskydelist_dev(struct cdev *dev)
1215277179Shselasky{
1216277391Skib
1217280345Shselasky	WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, "delist_dev");
1218277179Shselasky	dev_lock();
1219277179Shselasky	delist_dev_locked(dev);
1220277179Shselasky	dev_unlock();
1221277179Shselasky}
1222277179Shselasky
1223277179Shselaskyvoid
1224130585Sphkdestroy_dev(struct cdev *dev)
1225126082Sphk{
1226126082Sphk
1227185373Skib	WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, "destroy_dev");
1228135600Sphk	dev_lock();
1229171251Skib	destroy_devl(dev);
1230171251Skib	dev_unlock_and_free();
1231126082Sphk}
1232126082Sphk
123351225Sbdeconst char *
1234130585Sphkdevtoname(struct cdev *dev)
123549982Sbillf{
123649982Sbillf
123749982Sbillf	return (dev->si_name);
123849982Sbillf}
123965374Sphk
124065374Sphkint
124191998Sphkdev_stdclone(char *name, char **namep, const char *stem, int *unit)
124265374Sphk{
124365374Sphk	int u, i;
124465374Sphk
124575519Sbrian	i = strlen(stem);
124675519Sbrian	if (bcmp(stem, name, i) != 0)
124765374Sphk		return (0);
124865374Sphk	if (!isdigit(name[i]))
124965374Sphk		return (0);
125065374Sphk	u = 0;
125186461Sphk	if (name[i] == '0' && isdigit(name[i+1]))
125286461Sphk		return (0);
125365374Sphk	while (isdigit(name[i])) {
125465374Sphk		u *= 10;
125565374Sphk		u += name[i++] - '0';
125665374Sphk	}
1257104523Sgreen	if (u > 0xffffff)
1258104523Sgreen		return (0);
125965374Sphk	*unit = u;
126065374Sphk	if (namep)
126165374Sphk		*namep = &name[i];
126265374Sphk	if (name[i])
126365374Sphk		return (2);
126465374Sphk	return (1);
126565374Sphk}
126665632Sphk
126765632Sphk/*
1268126077Sphk * Helper functions for cloning device drivers.
1269126077Sphk *
1270126077Sphk * The objective here is to make it unnecessary for the device drivers to
1271126077Sphk * use rman or similar to manage their unit number space.  Due to the way
1272126077Sphk * we do "on-demand" devices, using rman or other "private" methods
1273126077Sphk * will be very tricky to lock down properly once we lock down this file.
1274126077Sphk *
1275130936Sle * Instead we give the drivers these routines which puts the struct cdev *'s
1276130936Sle * that are to be managed on their own list, and gives the driver the ability
1277126077Sphk * to ask for the first free unit number or a given specified unit number.
1278126077Sphk *
1279126077Sphk * In addition these routines support paired devices (pty, nmdm and similar)
1280126077Sphk * by respecting a number of "flag" bits in the minor number.
1281126077Sphk *
1282126077Sphk */
1283126077Sphk
1284126077Sphkstruct clonedevs {
1285126077Sphk	LIST_HEAD(,cdev)	head;
1286126077Sphk};
1287126077Sphk
1288126845Sphkvoid
1289126845Sphkclone_setup(struct clonedevs **cdp)
1290126845Sphk{
1291126845Sphk
1292126845Sphk	*cdp = malloc(sizeof **cdp, M_DEVBUF, M_WAITOK | M_ZERO);
1293126845Sphk	LIST_INIT(&(*cdp)->head);
1294126845Sphk}
1295126845Sphk
1296126077Sphkint
1297204412Skibclone_create(struct clonedevs **cdp, struct cdevsw *csw, int *up,
1298204412Skib    struct cdev **dp, int extra)
1299126077Sphk{
1300126077Sphk	struct clonedevs *cd;
1301140733Sphk	struct cdev *dev, *ndev, *dl, *de;
1302293346Skib	struct make_dev_args args;
1303126077Sphk	int unit, low, u;
1304126077Sphk
1305126845Sphk	KASSERT(*cdp != NULL,
1306126845Sphk	    ("clone_setup() not called in driver \"%s\"", csw->d_name));
1307126077Sphk	KASSERT(!(extra & CLONE_UNITMASK),
1308126845Sphk	    ("Illegal extra bits (0x%x) in clone_create", extra));
1309126077Sphk	KASSERT(*up <= CLONE_UNITMASK,
1310126845Sphk	    ("Too high unit (0x%x) in clone_create", *up));
1311179726Sed	KASSERT(csw->d_flags & D_NEEDMINOR,
1312179726Sed	    ("clone_create() on cdevsw without minor numbers"));
1313126077Sphk
1314126077Sphk
1315126077Sphk	/*
1316126077Sphk	 * Search the list for a lot of things in one go:
1317126077Sphk	 *   A preexisting match is returned immediately.
1318126077Sphk	 *   The lowest free unit number if we are passed -1, and the place
1319126077Sphk	 *	 in the list where we should insert that new element.
1320126077Sphk	 *   The place to insert a specified unit number, if applicable
1321126077Sphk	 *       the end of the list.
1322126077Sphk	 */
1323126077Sphk	unit = *up;
1324207729Skib	ndev = devfs_alloc(MAKEDEV_WAITOK);
1325140733Sphk	dev_lock();
1326207729Skib	prep_cdevsw(csw, MAKEDEV_WAITOK);
1327126849Sphk	low = extra;
1328126077Sphk	de = dl = NULL;
1329126845Sphk	cd = *cdp;
1330126077Sphk	LIST_FOREACH(dev, &cd->head, si_clone) {
1331140733Sphk		KASSERT(dev->si_flags & SI_CLONELIST,
1332140733Sphk		    ("Dev %p(%s) should be on clonelist", dev, dev->si_name));
1333126077Sphk		u = dev2unit(dev);
1334126077Sphk		if (u == (unit | extra)) {
1335126077Sphk			*dp = dev;
1336170950Skib			dev_unlock();
1337150342Sphk			devfs_free(ndev);
1338126077Sphk			return (0);
1339126077Sphk		}
1340126077Sphk		if (unit == -1 && u == low) {
1341126077Sphk			low++;
1342126077Sphk			de = dev;
1343126077Sphk			continue;
1344150793Sphk		} else if (u < (unit | extra)) {
1345150793Sphk			de = dev;
1346150793Sphk			continue;
1347150793Sphk		} else if (u > (unit | extra)) {
1348126077Sphk			dl = dev;
1349126077Sphk			break;
1350126077Sphk		}
1351126077Sphk	}
1352126077Sphk	if (unit == -1)
1353126849Sphk		unit = low & CLONE_UNITMASK;
1354293346Skib	make_dev_args_init(&args);
1355293346Skib	args.mda_unit = unit | extra;
1356293346Skib	args.mda_devsw = csw;
1357293346Skib	dev = newdev(&args, ndev);
1358140733Sphk	if (dev->si_flags & SI_CLONELIST) {
1359140733Sphk		printf("dev %p (%s) is on clonelist\n", dev, dev->si_name);
1360150793Sphk		printf("unit=%d, low=%d, extra=0x%x\n", unit, low, extra);
1361140733Sphk		LIST_FOREACH(dev, &cd->head, si_clone) {
1362140733Sphk			printf("\t%p %s\n", dev, dev->si_name);
1363140733Sphk		}
1364140733Sphk		panic("foo");
1365140733Sphk	}
1366126077Sphk	KASSERT(!(dev->si_flags & SI_CLONELIST),
1367140733Sphk	    ("Dev %p(%s) should not be on clonelist", dev, dev->si_name));
1368126077Sphk	if (dl != NULL)
1369126077Sphk		LIST_INSERT_BEFORE(dl, dev, si_clone);
1370126077Sphk	else if (de != NULL)
1371126077Sphk		LIST_INSERT_AFTER(de, dev, si_clone);
1372126077Sphk	else
1373126077Sphk		LIST_INSERT_HEAD(&cd->head, dev, si_clone);
1374126077Sphk	dev->si_flags |= SI_CLONELIST;
1375126077Sphk	*up = unit;
1376170950Skib	dev_unlock_and_free();
1377126077Sphk	return (1);
1378126077Sphk}
1379126077Sphk
1380126077Sphk/*
1381126077Sphk * Kill everything still on the list.  The driver should already have
1382130585Sphk * disposed of any softc hung of the struct cdev *'s at this time.
1383126077Sphk */
1384126077Sphkvoid
1385126077Sphkclone_cleanup(struct clonedevs **cdp)
1386126077Sphk{
1387171181Skib	struct cdev *dev;
1388171181Skib	struct cdev_priv *cp;
1389126077Sphk	struct clonedevs *cd;
1390126077Sphk
1391126077Sphk	cd = *cdp;
1392126077Sphk	if (cd == NULL)
1393126077Sphk		return;
1394140733Sphk	dev_lock();
1395171181Skib	while (!LIST_EMPTY(&cd->head)) {
1396171181Skib		dev = LIST_FIRST(&cd->head);
1397171181Skib		LIST_REMOVE(dev, si_clone);
1398140733Sphk		KASSERT(dev->si_flags & SI_CLONELIST,
1399140733Sphk		    ("Dev %p(%s) should be on clonelist", dev, dev->si_name));
1400171181Skib		dev->si_flags &= ~SI_CLONELIST;
1401179828Skib		cp = cdev2priv(dev);
1402171181Skib		if (!(cp->cdp_flags & CDP_SCHED_DTR)) {
1403171181Skib			cp->cdp_flags |= CDP_SCHED_DTR;
1404171181Skib			KASSERT(dev->si_flags & SI_NAMED,
1405275856Sgleb				("Driver has goofed in cloning underways udev %jx unit %x",
1406275856Sgleb				(uintmax_t)dev2udev(dev), dev2unit(dev)));
1407171181Skib			destroy_devl(dev);
1408171181Skib		}
1409126077Sphk	}
1410177301Skib	dev_unlock_and_free();
1411126077Sphk	free(cd, M_DEVBUF);
1412126077Sphk	*cdp = NULL;
1413126077Sphk}
1414171181Skib
1415171181Skibstatic TAILQ_HEAD(, cdev_priv) dev_ddtr =
1416171181Skib	TAILQ_HEAD_INITIALIZER(dev_ddtr);
1417228804Sjhbstatic struct task dev_dtr_task = TASK_INITIALIZER(0, destroy_dev_tq, NULL);
1418171181Skib
1419171181Skibstatic void
1420171181Skibdestroy_dev_tq(void *ctx, int pending)
1421171181Skib{
1422171181Skib	struct cdev_priv *cp;
1423171181Skib	struct cdev *dev;
1424171181Skib	void (*cb)(void *);
1425171181Skib	void *cb_arg;
1426171181Skib
1427171181Skib	dev_lock();
1428171181Skib	while (!TAILQ_EMPTY(&dev_ddtr)) {
1429171181Skib		cp = TAILQ_FIRST(&dev_ddtr);
1430171181Skib		dev = &cp->cdp_c;
1431171181Skib		KASSERT(cp->cdp_flags & CDP_SCHED_DTR,
1432171181Skib		    ("cdev %p in dev_destroy_tq without CDP_SCHED_DTR", cp));
1433171181Skib		TAILQ_REMOVE(&dev_ddtr, cp, cdp_dtr_list);
1434171181Skib		cb = cp->cdp_dtr_cb;
1435171181Skib		cb_arg = cp->cdp_dtr_cb_arg;
1436171181Skib		destroy_devl(dev);
1437177301Skib		dev_unlock_and_free();
1438171181Skib		dev_rel(dev);
1439171181Skib		if (cb != NULL)
1440171181Skib			cb(cb_arg);
1441171181Skib		dev_lock();
1442171181Skib	}
1443171181Skib	dev_unlock();
1444171181Skib}
1445171181Skib
1446171188Skib/*
1447171188Skib * devmtx shall be locked on entry. devmtx will be unlocked after
1448171188Skib * function return.
1449171188Skib */
1450171188Skibstatic int
1451171188Skibdestroy_dev_sched_cbl(struct cdev *dev, void (*cb)(void *), void *arg)
1452171181Skib{
1453171181Skib	struct cdev_priv *cp;
1454171188Skib
1455171188Skib	mtx_assert(&devmtx, MA_OWNED);
1456179828Skib	cp = cdev2priv(dev);
1457171181Skib	if (cp->cdp_flags & CDP_SCHED_DTR) {
1458171181Skib		dev_unlock();
1459171181Skib		return (0);
1460171181Skib	}
1461171181Skib	dev_refl(dev);
1462171181Skib	cp->cdp_flags |= CDP_SCHED_DTR;
1463171181Skib	cp->cdp_dtr_cb = cb;
1464171181Skib	cp->cdp_dtr_cb_arg = arg;
1465171181Skib	TAILQ_INSERT_TAIL(&dev_ddtr, cp, cdp_dtr_list);
1466171181Skib	dev_unlock();
1467171181Skib	taskqueue_enqueue(taskqueue_swi_giant, &dev_dtr_task);
1468171181Skib	return (1);
1469171181Skib}
1470171181Skib
1471171181Skibint
1472171188Skibdestroy_dev_sched_cb(struct cdev *dev, void (*cb)(void *), void *arg)
1473171188Skib{
1474204412Skib
1475171188Skib	dev_lock();
1476171188Skib	return (destroy_dev_sched_cbl(dev, cb, arg));
1477171188Skib}
1478171188Skib
1479171188Skibint
1480171181Skibdestroy_dev_sched(struct cdev *dev)
1481171181Skib{
1482204412Skib
1483171181Skib	return (destroy_dev_sched_cb(dev, NULL, NULL));
1484171181Skib}
1485171181Skib
1486171181Skibvoid
1487171181Skibdestroy_dev_drain(struct cdevsw *csw)
1488171181Skib{
1489171181Skib
1490171181Skib	dev_lock();
1491171181Skib	while (!LIST_EMPTY(&csw->d_devs)) {
1492171181Skib		msleep(&csw->d_devs, &devmtx, PRIBIO, "devscd", hz/10);
1493171181Skib	}
1494171181Skib	dev_unlock();
1495171181Skib}
1496171181Skib
1497171181Skibvoid
1498171181Skibdrain_dev_clone_events(void)
1499171181Skib{
1500171181Skib
1501171181Skib	sx_xlock(&clone_drain_lock);
1502171181Skib	sx_xunlock(&clone_drain_lock);
1503171181Skib}
1504171181Skib
1505210924Skib#include "opt_ddb.h"
1506210924Skib#ifdef DDB
1507210924Skib#include <sys/kernel.h>
1508210924Skib
1509210924Skib#include <ddb/ddb.h>
1510210924Skib
1511210924SkibDB_SHOW_COMMAND(cdev, db_show_cdev)
1512210924Skib{
1513210924Skib	struct cdev_priv *cdp;
1514210924Skib	struct cdev *dev;
1515210924Skib	u_int flags;
1516210924Skib	char buf[512];
1517210924Skib
1518210924Skib	if (!have_addr) {
1519210924Skib		TAILQ_FOREACH(cdp, &cdevp_list, cdp_list) {
1520210924Skib			dev = &cdp->cdp_c;
1521210924Skib			db_printf("%s %p\n", dev->si_name, dev);
1522210924Skib			if (db_pager_quit)
1523210924Skib				break;
1524210924Skib		}
1525210924Skib		return;
1526210924Skib	}
1527210924Skib
1528210924Skib	dev = (struct cdev *)addr;
1529210924Skib	cdp = cdev2priv(dev);
1530210924Skib	db_printf("dev %s ref %d use %ld thr %ld inuse %u fdpriv %p\n",
1531210924Skib	    dev->si_name, dev->si_refcount, dev->si_usecount,
1532210924Skib	    dev->si_threadcount, cdp->cdp_inuse, cdp->cdp_fdpriv.lh_first);
1533210924Skib	db_printf("devsw %p si_drv0 %d si_drv1 %p si_drv2 %p\n",
1534210924Skib	    dev->si_devsw, dev->si_drv0, dev->si_drv1, dev->si_drv2);
1535210924Skib	flags = dev->si_flags;
1536210924Skib#define	SI_FLAG(flag)	do {						\
1537210924Skib	if (flags & (flag)) {						\
1538210924Skib		if (buf[0] != '\0')					\
1539210924Skib			strlcat(buf, ", ", sizeof(buf));		\
1540210924Skib		strlcat(buf, (#flag) + 3, sizeof(buf));			\
1541210924Skib		flags &= ~(flag);					\
1542210924Skib	}								\
1543210924Skib} while (0)
1544210924Skib	buf[0] = '\0';
1545210924Skib	SI_FLAG(SI_ETERNAL);
1546210924Skib	SI_FLAG(SI_ALIAS);
1547210924Skib	SI_FLAG(SI_NAMED);
1548210924Skib	SI_FLAG(SI_CHILD);
1549210924Skib	SI_FLAG(SI_DUMPDEV);
1550210924Skib	SI_FLAG(SI_CLONELIST);
1551210924Skib	db_printf("si_flags %s\n", buf);
1552210924Skib
1553210924Skib	flags = cdp->cdp_flags;
1554210924Skib#define	CDP_FLAG(flag)	do {						\
1555210924Skib	if (flags & (flag)) {						\
1556210924Skib		if (buf[0] != '\0')					\
1557210924Skib			strlcat(buf, ", ", sizeof(buf));		\
1558210924Skib		strlcat(buf, (#flag) + 4, sizeof(buf));			\
1559210924Skib		flags &= ~(flag);					\
1560210924Skib	}								\
1561210924Skib} while (0)
1562210924Skib	buf[0] = '\0';
1563210924Skib	CDP_FLAG(CDP_ACTIVE);
1564210924Skib	CDP_FLAG(CDP_SCHED_DTR);
1565210924Skib	db_printf("cdp_flags %s\n", buf);
1566210924Skib}
1567210924Skib#endif
1568