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