source: rtems-libbsd/freebsd/sys/kern/kern_conf.c @ 8ae7a21

4.11
Last change on this file since 8ae7a21 was 8ae7a21, checked in by Christian Mauderer <Christian.Mauderer@…>, on 06/29/16 at 08:22:03

kern_conf.c: Import from FreeBSD.

  • Property mode set to 100644
File size: 34.2 KB
Line 
1#include <machine/rtems-bsd-kernel-space.h>
2
3/*-
4 * Copyright (c) 1999-2002 Poul-Henning Kamp
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#include <sys/cdefs.h>
30__FBSDID("$FreeBSD$");
31
32#include <rtems/bsd/sys/param.h>
33#include <sys/kernel.h>
34#include <sys/systm.h>
35#include <sys/bus.h>
36#include <sys/bio.h>
37#include <rtems/bsd/sys/lock.h>
38#include <sys/mutex.h>
39#include <sys/module.h>
40#include <sys/malloc.h>
41#include <sys/conf.h>
42#include <sys/vnode.h>
43#include <sys/queue.h>
44#include <sys/poll.h>
45#include <sys/sx.h>
46#include <sys/ctype.h>
47#include <sys/ucred.h>
48#include <sys/taskqueue.h>
49#include <machine/stdarg.h>
50
51#include <fs/devfs/devfs_int.h>
52#include <vm/vm.h>
53
54static MALLOC_DEFINE(M_DEVT, "cdev", "cdev storage");
55
56struct mtx devmtx;
57static void destroy_devl(struct cdev *dev);
58static int destroy_dev_sched_cbl(struct cdev *dev,
59    void (*cb)(void *), void *arg);
60static int make_dev_credv(int flags, struct cdev **dres, struct cdevsw *devsw,
61    int unit, struct ucred *cr, uid_t uid, gid_t gid, int mode, const char *fmt,
62    va_list ap);
63
64static struct cdev_priv_list cdevp_free_list =
65    TAILQ_HEAD_INITIALIZER(cdevp_free_list);
66static SLIST_HEAD(free_cdevsw, cdevsw) cdevsw_gt_post_list =
67    SLIST_HEAD_INITIALIZER(cdevsw_gt_post_list);
68
69void
70dev_lock(void)
71{
72
73        mtx_lock(&devmtx);
74}
75
76/*
77 * Free all the memory collected while the cdev mutex was
78 * locked. Since devmtx is after the system map mutex, free() cannot
79 * be called immediately and is postponed until cdev mutex can be
80 * dropped.
81 */
82static void
83dev_unlock_and_free(void)
84{
85        struct cdev_priv_list cdp_free;
86        struct free_cdevsw csw_free;
87        struct cdev_priv *cdp;
88        struct cdevsw *csw;
89
90        mtx_assert(&devmtx, MA_OWNED);
91
92        /*
93         * Make the local copy of the list heads while the dev_mtx is
94         * held. Free it later.
95         */
96        TAILQ_INIT(&cdp_free);
97        TAILQ_CONCAT(&cdp_free, &cdevp_free_list, cdp_list);
98        csw_free = cdevsw_gt_post_list;
99        SLIST_INIT(&cdevsw_gt_post_list);
100
101        mtx_unlock(&devmtx);
102
103        while ((cdp = TAILQ_FIRST(&cdp_free)) != NULL) {
104                TAILQ_REMOVE(&cdp_free, cdp, cdp_list);
105                devfs_free(&cdp->cdp_c);
106        }
107        while ((csw = SLIST_FIRST(&csw_free)) != NULL) {
108                SLIST_REMOVE_HEAD(&csw_free, d_postfree_list);
109                free(csw, M_DEVT);
110        }
111}
112
113static void
114dev_free_devlocked(struct cdev *cdev)
115{
116        struct cdev_priv *cdp;
117
118        mtx_assert(&devmtx, MA_OWNED);
119        cdp = cdev2priv(cdev);
120        KASSERT((cdp->cdp_flags & CDP_UNREF_DTR) == 0,
121            ("destroy_dev() was not called after delist_dev(%p)", cdev));
122        TAILQ_INSERT_HEAD(&cdevp_free_list, cdp, cdp_list);
123}
124
125static void
126cdevsw_free_devlocked(struct cdevsw *csw)
127{
128
129        mtx_assert(&devmtx, MA_OWNED);
130        SLIST_INSERT_HEAD(&cdevsw_gt_post_list, csw, d_postfree_list);
131}
132
133void
134dev_unlock(void)
135{
136
137        mtx_unlock(&devmtx);
138}
139
140void
141dev_ref(struct cdev *dev)
142{
143
144        mtx_assert(&devmtx, MA_NOTOWNED);
145        mtx_lock(&devmtx);
146        dev->si_refcount++;
147        mtx_unlock(&devmtx);
148}
149
150void
151dev_refl(struct cdev *dev)
152{
153
154        mtx_assert(&devmtx, MA_OWNED);
155        dev->si_refcount++;
156}
157
158void
159dev_rel(struct cdev *dev)
160{
161        int flag = 0;
162
163        mtx_assert(&devmtx, MA_NOTOWNED);
164        dev_lock();
165        dev->si_refcount--;
166        KASSERT(dev->si_refcount >= 0,
167            ("dev_rel(%s) gave negative count", devtoname(dev)));
168#if 0
169        if (dev->si_usecount == 0 &&
170            (dev->si_flags & SI_CHEAPCLONE) && (dev->si_flags & SI_NAMED))
171                ;
172        else
173#endif
174        if (dev->si_devsw == NULL && dev->si_refcount == 0) {
175                LIST_REMOVE(dev, si_list);
176                flag = 1;
177        }
178        dev_unlock();
179        if (flag)
180                devfs_free(dev);
181}
182
183struct cdevsw *
184dev_refthread(struct cdev *dev, int *ref)
185{
186        struct cdevsw *csw;
187        struct cdev_priv *cdp;
188
189        mtx_assert(&devmtx, MA_NOTOWNED);
190        if ((dev->si_flags & SI_ETERNAL) != 0) {
191                *ref = 0;
192                return (dev->si_devsw);
193        }
194        dev_lock();
195        csw = dev->si_devsw;
196        if (csw != NULL) {
197                cdp = cdev2priv(dev);
198                if ((cdp->cdp_flags & CDP_SCHED_DTR) == 0)
199                        dev->si_threadcount++;
200                else
201                        csw = NULL;
202        }
203        dev_unlock();
204        *ref = 1;
205        return (csw);
206}
207
208struct cdevsw *
209devvn_refthread(struct vnode *vp, struct cdev **devp, int *ref)
210{
211        struct cdevsw *csw;
212        struct cdev_priv *cdp;
213        struct cdev *dev;
214
215        mtx_assert(&devmtx, MA_NOTOWNED);
216        if ((vp->v_vflag & VV_ETERNALDEV) != 0) {
217                dev = vp->v_rdev;
218                if (dev == NULL)
219                        return (NULL);
220                KASSERT((dev->si_flags & SI_ETERNAL) != 0,
221                    ("Not eternal cdev"));
222                *ref = 0;
223                csw = dev->si_devsw;
224                KASSERT(csw != NULL, ("Eternal cdev is destroyed"));
225                *devp = dev;
226                return (csw);
227        }
228
229        csw = NULL;
230        dev_lock();
231        dev = vp->v_rdev;
232        if (dev == NULL) {
233                dev_unlock();
234                return (NULL);
235        }
236        cdp = cdev2priv(dev);
237        if ((cdp->cdp_flags & CDP_SCHED_DTR) == 0) {
238                csw = dev->si_devsw;
239                if (csw != NULL)
240                        dev->si_threadcount++;
241        }
242        dev_unlock();
243        if (csw != NULL) {
244                *devp = dev;
245                *ref = 1;
246        }
247        return (csw);
248}
249
250void   
251dev_relthread(struct cdev *dev, int ref)
252{
253
254        mtx_assert(&devmtx, MA_NOTOWNED);
255        if (!ref)
256                return;
257        dev_lock();
258        KASSERT(dev->si_threadcount > 0,
259            ("%s threadcount is wrong", dev->si_name));
260        dev->si_threadcount--;
261        dev_unlock();
262}
263
264int
265nullop(void)
266{
267
268        return (0);
269}
270
271int
272eopnotsupp(void)
273{
274
275        return (EOPNOTSUPP);
276}
277
278static int
279enxio(void)
280{
281        return (ENXIO);
282}
283
284static int
285enodev(void)
286{
287        return (ENODEV);
288}
289
290/* Define a dead_cdevsw for use when devices leave unexpectedly. */
291
292#define dead_open       (d_open_t *)enxio
293#define dead_close      (d_close_t *)enxio
294#define dead_read       (d_read_t *)enxio
295#define dead_write      (d_write_t *)enxio
296#define dead_ioctl      (d_ioctl_t *)enxio
297#define dead_poll       (d_poll_t *)enodev
298#define dead_mmap       (d_mmap_t *)enodev
299
300static void
301dead_strategy(struct bio *bp)
302{
303
304        biofinish(bp, NULL, ENXIO);
305}
306
307#define dead_dump       (dumper_t *)enxio
308#define dead_kqfilter   (d_kqfilter_t *)enxio
309#define dead_mmap_single (d_mmap_single_t *)enodev
310
311static struct cdevsw dead_cdevsw = {
312        .d_version =    D_VERSION,
313        .d_open =       dead_open,
314        .d_close =      dead_close,
315        .d_read =       dead_read,
316        .d_write =      dead_write,
317        .d_ioctl =      dead_ioctl,
318        .d_poll =       dead_poll,
319        .d_mmap =       dead_mmap,
320        .d_strategy =   dead_strategy,
321        .d_name =       "dead",
322        .d_dump =       dead_dump,
323        .d_kqfilter =   dead_kqfilter,
324        .d_mmap_single = dead_mmap_single
325};
326
327/* Default methods if driver does not specify method */
328
329#define null_open       (d_open_t *)nullop
330#define null_close      (d_close_t *)nullop
331#define no_read         (d_read_t *)enodev
332#define no_write        (d_write_t *)enodev
333#define no_ioctl        (d_ioctl_t *)enodev
334#define no_mmap         (d_mmap_t *)enodev
335#define no_kqfilter     (d_kqfilter_t *)enodev
336#define no_mmap_single  (d_mmap_single_t *)enodev
337
338static void
339no_strategy(struct bio *bp)
340{
341
342        biofinish(bp, NULL, ENODEV);
343}
344
345static int
346no_poll(struct cdev *dev __unused, int events, struct thread *td __unused)
347{
348
349        return (poll_no_poll(events));
350}
351
352#define no_dump         (dumper_t *)enodev
353
354static int
355giant_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
356{
357        struct cdevsw *dsw;
358        int ref, retval;
359
360        dsw = dev_refthread(dev, &ref);
361        if (dsw == NULL)
362                return (ENXIO);
363        mtx_lock(&Giant);
364        retval = dsw->d_gianttrick->d_open(dev, oflags, devtype, td);
365        mtx_unlock(&Giant);
366        dev_relthread(dev, ref);
367        return (retval);
368}
369
370static int
371giant_fdopen(struct cdev *dev, int oflags, struct thread *td, struct file *fp)
372{
373        struct cdevsw *dsw;
374        int ref, retval;
375
376        dsw = dev_refthread(dev, &ref);
377        if (dsw == NULL)
378                return (ENXIO);
379        mtx_lock(&Giant);
380        retval = dsw->d_gianttrick->d_fdopen(dev, oflags, td, fp);
381        mtx_unlock(&Giant);
382        dev_relthread(dev, ref);
383        return (retval);
384}
385
386static int
387giant_close(struct cdev *dev, int fflag, int devtype, struct thread *td)
388{
389        struct cdevsw *dsw;
390        int ref, retval;
391
392        dsw = dev_refthread(dev, &ref);
393        if (dsw == NULL)
394                return (ENXIO);
395        mtx_lock(&Giant);
396        retval = dsw->d_gianttrick->d_close(dev, fflag, devtype, td);
397        mtx_unlock(&Giant);
398        dev_relthread(dev, ref);
399        return (retval);
400}
401
402static void
403giant_strategy(struct bio *bp)
404{
405        struct cdevsw *dsw;
406        struct cdev *dev;
407        int ref;
408
409        dev = bp->bio_dev;
410        dsw = dev_refthread(dev, &ref);
411        if (dsw == NULL) {
412                biofinish(bp, NULL, ENXIO);
413                return;
414        }
415        mtx_lock(&Giant);
416        dsw->d_gianttrick->d_strategy(bp);
417        mtx_unlock(&Giant);
418        dev_relthread(dev, ref);
419}
420
421static int
422giant_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct thread *td)
423{
424        struct cdevsw *dsw;
425        int ref, retval;
426
427        dsw = dev_refthread(dev, &ref);
428        if (dsw == NULL)
429                return (ENXIO);
430        mtx_lock(&Giant);
431        retval = dsw->d_gianttrick->d_ioctl(dev, cmd, data, fflag, td);
432        mtx_unlock(&Giant);
433        dev_relthread(dev, ref);
434        return (retval);
435}
436 
437static int
438giant_read(struct cdev *dev, struct uio *uio, int ioflag)
439{
440        struct cdevsw *dsw;
441        int ref, retval;
442
443        dsw = dev_refthread(dev, &ref);
444        if (dsw == NULL)
445                return (ENXIO);
446        mtx_lock(&Giant);
447        retval = dsw->d_gianttrick->d_read(dev, uio, ioflag);
448        mtx_unlock(&Giant);
449        dev_relthread(dev, ref);
450        return (retval);
451}
452
453static int
454giant_write(struct cdev *dev, struct uio *uio, int ioflag)
455{
456        struct cdevsw *dsw;
457        int ref, retval;
458
459        dsw = dev_refthread(dev, &ref);
460        if (dsw == NULL)
461                return (ENXIO);
462        mtx_lock(&Giant);
463        retval = dsw->d_gianttrick->d_write(dev, uio, ioflag);
464        mtx_unlock(&Giant);
465        dev_relthread(dev, ref);
466        return (retval);
467}
468
469static int
470giant_poll(struct cdev *dev, int events, struct thread *td)
471{
472        struct cdevsw *dsw;
473        int ref, retval;
474
475        dsw = dev_refthread(dev, &ref);
476        if (dsw == NULL)
477                return (ENXIO);
478        mtx_lock(&Giant);
479        retval = dsw->d_gianttrick->d_poll(dev, events, td);
480        mtx_unlock(&Giant);
481        dev_relthread(dev, ref);
482        return (retval);
483}
484
485static int
486giant_kqfilter(struct cdev *dev, struct knote *kn)
487{
488        struct cdevsw *dsw;
489        int ref, retval;
490
491        dsw = dev_refthread(dev, &ref);
492        if (dsw == NULL)
493                return (ENXIO);
494        mtx_lock(&Giant);
495        retval = dsw->d_gianttrick->d_kqfilter(dev, kn);
496        mtx_unlock(&Giant);
497        dev_relthread(dev, ref);
498        return (retval);
499}
500
501static int
502giant_mmap(struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr, int nprot,
503    vm_memattr_t *memattr)
504{
505        struct cdevsw *dsw;
506        int ref, retval;
507
508        dsw = dev_refthread(dev, &ref);
509        if (dsw == NULL)
510                return (ENXIO);
511        mtx_lock(&Giant);
512        retval = dsw->d_gianttrick->d_mmap(dev, offset, paddr, nprot,
513            memattr);
514        mtx_unlock(&Giant);
515        dev_relthread(dev, ref);
516        return (retval);
517}
518
519static int
520giant_mmap_single(struct cdev *dev, vm_ooffset_t *offset, vm_size_t size,
521    vm_object_t *object, int nprot)
522{
523        struct cdevsw *dsw;
524        int ref, retval;
525
526        dsw = dev_refthread(dev, &ref);
527        if (dsw == NULL)
528                return (ENXIO);
529        mtx_lock(&Giant);
530        retval = dsw->d_gianttrick->d_mmap_single(dev, offset, size, object,
531            nprot);
532        mtx_unlock(&Giant);
533        dev_relthread(dev, ref);
534        return (retval);
535}
536
537static void
538notify(struct cdev *dev, const char *ev, int flags)
539{
540        static const char prefix[] = "cdev=";
541        char *data;
542        int namelen, mflags;
543
544        if (cold)
545                return;
546        mflags = (flags & MAKEDEV_NOWAIT) ? M_NOWAIT : M_WAITOK;
547        namelen = strlen(dev->si_name);
548        data = malloc(namelen + sizeof(prefix), M_TEMP, mflags);
549        if (data == NULL)
550                return;
551        memcpy(data, prefix, sizeof(prefix) - 1);
552        memcpy(data + sizeof(prefix) - 1, dev->si_name, namelen + 1);
553        devctl_notify_f("DEVFS", "CDEV", ev, data, mflags);
554        free(data, M_TEMP);
555}
556
557static void
558notify_create(struct cdev *dev, int flags)
559{
560
561        notify(dev, "CREATE", flags);
562}
563
564static void
565notify_destroy(struct cdev *dev)
566{
567
568        notify(dev, "DESTROY", MAKEDEV_WAITOK);
569}
570
571static struct cdev *
572newdev(struct cdevsw *csw, int unit, struct cdev *si)
573{
574        struct cdev *si2;
575
576        mtx_assert(&devmtx, MA_OWNED);
577        if (csw->d_flags & D_NEEDMINOR) {
578                /* We may want to return an existing device */
579                LIST_FOREACH(si2, &csw->d_devs, si_list) {
580                        if (dev2unit(si2) == unit) {
581                                dev_free_devlocked(si);
582                                return (si2);
583                        }
584                }
585        }
586        si->si_drv0 = unit;
587        si->si_devsw = csw;
588        LIST_INSERT_HEAD(&csw->d_devs, si, si_list);
589        return (si);
590}
591
592static void
593fini_cdevsw(struct cdevsw *devsw)
594{
595        struct cdevsw *gt;
596
597        if (devsw->d_gianttrick != NULL) {
598                gt = devsw->d_gianttrick;
599                memcpy(devsw, gt, sizeof *devsw);
600                cdevsw_free_devlocked(gt);
601                devsw->d_gianttrick = NULL;
602        }
603        devsw->d_flags &= ~D_INIT;
604}
605
606static int
607prep_cdevsw(struct cdevsw *devsw, int flags)
608{
609        struct cdevsw *dsw2;
610
611        mtx_assert(&devmtx, MA_OWNED);
612        if (devsw->d_flags & D_INIT)
613                return (0);
614        if (devsw->d_flags & D_NEEDGIANT) {
615                dev_unlock();
616                dsw2 = malloc(sizeof *dsw2, M_DEVT,
617                     (flags & MAKEDEV_NOWAIT) ? M_NOWAIT : M_WAITOK);
618                dev_lock();
619                if (dsw2 == NULL && !(devsw->d_flags & D_INIT))
620                        return (ENOMEM);
621        } else
622                dsw2 = NULL;
623        if (devsw->d_flags & D_INIT) {
624                if (dsw2 != NULL)
625                        cdevsw_free_devlocked(dsw2);
626                return (0);
627        }
628
629        if (devsw->d_version != D_VERSION_03) {
630                printf(
631                    "WARNING: Device driver \"%s\" has wrong version %s\n",
632                    devsw->d_name == NULL ? "???" : devsw->d_name,
633                    "and is disabled.  Recompile KLD module.");
634                devsw->d_open = dead_open;
635                devsw->d_close = dead_close;
636                devsw->d_read = dead_read;
637                devsw->d_write = dead_write;
638                devsw->d_ioctl = dead_ioctl;
639                devsw->d_poll = dead_poll;
640                devsw->d_mmap = dead_mmap;
641                devsw->d_mmap_single = dead_mmap_single;
642                devsw->d_strategy = dead_strategy;
643                devsw->d_dump = dead_dump;
644                devsw->d_kqfilter = dead_kqfilter;
645        }
646       
647        if (devsw->d_flags & D_NEEDGIANT) {
648                if (devsw->d_gianttrick == NULL) {
649                        memcpy(dsw2, devsw, sizeof *dsw2);
650                        devsw->d_gianttrick = dsw2;
651                        dsw2 = NULL;
652                }
653        }
654
655#define FIXUP(member, noop, giant)                              \
656        do {                                                    \
657                if (devsw->member == NULL) {                    \
658                        devsw->member = noop;                   \
659                } else if (devsw->d_flags & D_NEEDGIANT)        \
660                        devsw->member = giant;                  \
661                }                                               \
662        while (0)
663
664        FIXUP(d_open,           null_open,      giant_open);
665        FIXUP(d_fdopen,         NULL,           giant_fdopen);
666        FIXUP(d_close,          null_close,     giant_close);
667        FIXUP(d_read,           no_read,        giant_read);
668        FIXUP(d_write,          no_write,       giant_write);
669        FIXUP(d_ioctl,          no_ioctl,       giant_ioctl);
670        FIXUP(d_poll,           no_poll,        giant_poll);
671        FIXUP(d_mmap,           no_mmap,        giant_mmap);
672        FIXUP(d_strategy,       no_strategy,    giant_strategy);
673        FIXUP(d_kqfilter,       no_kqfilter,    giant_kqfilter);
674        FIXUP(d_mmap_single,    no_mmap_single, giant_mmap_single);
675
676        if (devsw->d_dump == NULL)      devsw->d_dump = no_dump;
677
678        LIST_INIT(&devsw->d_devs);
679
680        devsw->d_flags |= D_INIT;
681
682        if (dsw2 != NULL)
683                cdevsw_free_devlocked(dsw2);
684        return (0);
685}
686
687static int
688prep_devname(struct cdev *dev, const char *fmt, va_list ap)
689{
690        int len;
691        char *from, *q, *s, *to;
692
693        mtx_assert(&devmtx, MA_OWNED);
694
695        len = vsnrprintf(dev->__si_namebuf, sizeof(dev->__si_namebuf), 32,
696            fmt, ap);
697        if (len > sizeof(dev->__si_namebuf) - 1)
698                return (ENAMETOOLONG);
699
700        /* Strip leading slashes. */
701        for (from = dev->__si_namebuf; *from == '/'; from++)
702                ;
703
704        for (to = dev->__si_namebuf; *from != '\0'; from++, to++) {
705                /* Treat multiple sequential slashes as single. */
706                while (from[0] == '/' && from[1] == '/')
707                        from++;
708                /* Trailing slash is considered invalid. */
709                if (from[0] == '/' && from[1] == '\0')
710                        return (EINVAL);
711                *to = *from;
712        }
713        *to = '\0';
714
715        if (dev->__si_namebuf[0] == '\0')
716                return (EINVAL);
717
718        /* Disallow "." and ".." components. */
719        for (s = dev->__si_namebuf;;) {
720                for (q = s; *q != '/' && *q != '\0'; q++)
721                        ;
722                if (q - s == 1 && s[0] == '.')
723                        return (EINVAL);
724                if (q - s == 2 && s[0] == '.' && s[1] == '.')
725                        return (EINVAL);
726                if (*q != '/')
727                        break;
728                s = q + 1;
729        }
730
731        if (devfs_dev_exists(dev->__si_namebuf) != 0)
732                return (EEXIST);
733
734        return (0);
735}
736
737static int
738make_dev_credv(int flags, struct cdev **dres, struct cdevsw *devsw, int unit,
739    struct ucred *cr, uid_t uid, gid_t gid, int mode, const char *fmt,
740    va_list ap)
741{
742        struct cdev *dev, *dev_new;
743        int res;
744
745        KASSERT((flags & MAKEDEV_WAITOK) == 0 || (flags & MAKEDEV_NOWAIT) == 0,
746            ("make_dev_credv: both WAITOK and NOWAIT specified"));
747        dev_new = devfs_alloc(flags);
748        if (dev_new == NULL)
749                return (ENOMEM);
750        dev_lock();
751        res = prep_cdevsw(devsw, flags);
752        if (res != 0) {
753                dev_unlock();
754                devfs_free(dev_new);
755                return (res);
756        }
757        dev = newdev(devsw, unit, dev_new);
758        if ((dev->si_flags & SI_NAMED) == 0) {
759                res = prep_devname(dev, fmt, ap);
760                if (res != 0) {
761                        if ((flags & MAKEDEV_CHECKNAME) == 0) {
762                                panic(
763                        "make_dev_credv: bad si_name (error=%d, si_name=%s)",
764                                    res, dev->si_name);
765                        }
766                        if (dev == dev_new) {
767                                LIST_REMOVE(dev, si_list);
768                                dev_unlock();
769                                devfs_free(dev);
770                        } else
771                                dev_unlock();
772                        return (res);
773                }
774        }
775        if (flags & MAKEDEV_REF)
776                dev_refl(dev);
777        if (flags & MAKEDEV_ETERNAL)
778                dev->si_flags |= SI_ETERNAL;
779        if (dev->si_flags & SI_CHEAPCLONE &&
780            dev->si_flags & SI_NAMED) {
781                /*
782                 * This is allowed as it removes races and generally
783                 * simplifies cloning devices.
784                 * XXX: still ??
785                 */
786                dev_unlock_and_free();
787                *dres = dev;
788                return (0);
789        }
790        KASSERT(!(dev->si_flags & SI_NAMED),
791            ("make_dev() by driver %s on pre-existing device (min=%x, name=%s)",
792            devsw->d_name, dev2unit(dev), devtoname(dev)));
793        dev->si_flags |= SI_NAMED;
794        if (cr != NULL)
795                dev->si_cred = crhold(cr);
796        dev->si_uid = uid;
797        dev->si_gid = gid;
798        dev->si_mode = mode;
799
800        devfs_create(dev);
801        clean_unrhdrl(devfs_inos);
802        dev_unlock_and_free();
803
804        notify_create(dev, flags);
805
806        *dres = dev;
807        return (0);
808}
809
810struct cdev *
811make_dev(struct cdevsw *devsw, int unit, uid_t uid, gid_t gid, int mode,
812    const char *fmt, ...)
813{
814        struct cdev *dev;
815        va_list ap;
816        int res;
817
818        va_start(ap, fmt);
819        res = make_dev_credv(0, &dev, devsw, unit, NULL, uid, gid, mode, fmt,
820            ap);
821        va_end(ap);
822        KASSERT(res == 0 && dev != NULL,
823            ("make_dev: failed make_dev_credv (error=%d)", res));
824        return (dev);
825}
826
827struct cdev *
828make_dev_cred(struct cdevsw *devsw, int unit, struct ucred *cr, uid_t uid,
829    gid_t gid, int mode, const char *fmt, ...)
830{
831        struct cdev *dev;
832        va_list ap;
833        int res;
834
835        va_start(ap, fmt);
836        res = make_dev_credv(0, &dev, devsw, unit, cr, uid, gid, mode, fmt, ap);
837        va_end(ap);
838
839        KASSERT(res == 0 && dev != NULL,
840            ("make_dev_cred: failed make_dev_credv (error=%d)", res));
841        return (dev);
842}
843
844struct cdev *
845make_dev_credf(int flags, struct cdevsw *devsw, int unit, struct ucred *cr,
846    uid_t uid, gid_t gid, int mode, const char *fmt, ...)
847{
848        struct cdev *dev;
849        va_list ap;
850        int res;
851
852        va_start(ap, fmt);
853        res = make_dev_credv(flags, &dev, devsw, unit, cr, uid, gid, mode,
854            fmt, ap);
855        va_end(ap);
856
857        KASSERT(((flags & MAKEDEV_NOWAIT) != 0 && res == ENOMEM) ||
858            ((flags & MAKEDEV_CHECKNAME) != 0 && res != ENOMEM) || res == 0,
859            ("make_dev_credf: failed make_dev_credv (error=%d)", res));
860        return (res == 0 ? dev : NULL);
861}
862
863int
864make_dev_p(int flags, struct cdev **cdev, struct cdevsw *devsw,
865    struct ucred *cr, uid_t uid, gid_t gid, int mode, const char *fmt, ...)
866{
867        va_list ap;
868        int res;
869
870        va_start(ap, fmt);
871        res = make_dev_credv(flags, cdev, devsw, 0, cr, uid, gid, mode,
872            fmt, ap);
873        va_end(ap);
874
875        KASSERT(((flags & MAKEDEV_NOWAIT) != 0 && res == ENOMEM) ||
876            ((flags & MAKEDEV_CHECKNAME) != 0 && res != ENOMEM) || res == 0,
877            ("make_dev_p: failed make_dev_credv (error=%d)", res));
878        return (res);
879}
880
881static void
882dev_dependsl(struct cdev *pdev, struct cdev *cdev)
883{
884
885        cdev->si_parent = pdev;
886        cdev->si_flags |= SI_CHILD;
887        LIST_INSERT_HEAD(&pdev->si_children, cdev, si_siblings);
888}
889
890
891void
892dev_depends(struct cdev *pdev, struct cdev *cdev)
893{
894
895        dev_lock();
896        dev_dependsl(pdev, cdev);
897        dev_unlock();
898}
899
900static int
901make_dev_alias_v(int flags, struct cdev **cdev, struct cdev *pdev,
902    const char *fmt, va_list ap)
903{
904        struct cdev *dev;
905        int error;
906
907        KASSERT(pdev != NULL, ("make_dev_alias_v: pdev is NULL"));
908        KASSERT((flags & MAKEDEV_WAITOK) == 0 || (flags & MAKEDEV_NOWAIT) == 0,
909            ("make_dev_alias_v: both WAITOK and NOWAIT specified"));
910        KASSERT((flags & ~(MAKEDEV_WAITOK | MAKEDEV_NOWAIT |
911            MAKEDEV_CHECKNAME)) == 0,
912            ("make_dev_alias_v: invalid flags specified (flags=%02x)", flags));
913
914        dev = devfs_alloc(flags);
915        if (dev == NULL)
916                return (ENOMEM);
917        dev_lock();
918        dev->si_flags |= SI_ALIAS;
919        error = prep_devname(dev, fmt, ap);
920        if (error != 0) {
921                if ((flags & MAKEDEV_CHECKNAME) == 0) {
922                        panic("make_dev_alias_v: bad si_name "
923                            "(error=%d, si_name=%s)", error, dev->si_name);
924                }
925                dev_unlock();
926                devfs_free(dev);
927                return (error);
928        }
929        dev->si_flags |= SI_NAMED;
930        devfs_create(dev);
931        dev_dependsl(pdev, dev);
932        clean_unrhdrl(devfs_inos);
933        dev_unlock();
934
935        notify_create(dev, flags);
936        *cdev = dev;
937
938        return (0);
939}
940
941struct cdev *
942make_dev_alias(struct cdev *pdev, const char *fmt, ...)
943{
944        struct cdev *dev;
945        va_list ap;
946        int res;
947
948        va_start(ap, fmt);
949        res = make_dev_alias_v(MAKEDEV_WAITOK, &dev, pdev, fmt, ap);
950        va_end(ap);
951
952        KASSERT(res == 0 && dev != NULL,
953            ("make_dev_alias: failed make_dev_alias_v (error=%d)", res));
954        return (dev);
955}
956
957int
958make_dev_alias_p(int flags, struct cdev **cdev, struct cdev *pdev,
959    const char *fmt, ...)
960{
961        va_list ap;
962        int res;
963
964        va_start(ap, fmt);
965        res = make_dev_alias_v(flags, cdev, pdev, fmt, ap);
966        va_end(ap);
967        return (res);
968}
969
970int
971make_dev_physpath_alias(int flags, struct cdev **cdev, struct cdev *pdev,
972    struct cdev *old_alias, const char *physpath)
973{
974        char *devfspath;
975        int physpath_len;
976        int max_parentpath_len;
977        int parentpath_len;
978        int devfspathbuf_len;
979        int mflags;
980        int ret;
981
982        *cdev = NULL;
983        devfspath = NULL;
984        physpath_len = strlen(physpath);
985        ret = EINVAL;
986        if (physpath_len == 0)
987                goto out;
988
989        if (strncmp("id1,", physpath, 4) == 0) {
990                physpath += 4;
991                physpath_len -= 4;
992                if (physpath_len == 0)
993                        goto out;
994        }
995
996        max_parentpath_len = SPECNAMELEN - physpath_len - /*/*/1;
997        parentpath_len = strlen(pdev->si_name);
998        if (max_parentpath_len < parentpath_len) {
999                if (bootverbose)
1000                        printf("WARNING: Unable to alias %s "
1001                            "to %s/%s - path too long\n",
1002                            pdev->si_name, physpath, pdev->si_name);
1003                ret = ENAMETOOLONG;
1004                goto out;
1005        }
1006
1007        mflags = (flags & MAKEDEV_NOWAIT) ? M_NOWAIT : M_WAITOK;
1008        devfspathbuf_len = physpath_len + /*/*/1 + parentpath_len + /*NUL*/1;
1009        devfspath = malloc(devfspathbuf_len, M_DEVBUF, mflags);
1010        if (devfspath == NULL) {
1011                ret = ENOMEM;
1012                goto out;
1013        }
1014
1015        sprintf(devfspath, "%s/%s", physpath, pdev->si_name);
1016        if (old_alias != NULL && strcmp(old_alias->si_name, devfspath) == 0) {
1017                /* Retain the existing alias. */
1018                *cdev = old_alias;
1019                old_alias = NULL;
1020                ret = 0;
1021        } else {
1022                ret = make_dev_alias_p(flags, cdev, pdev, "%s", devfspath);
1023        }
1024out:
1025        if (old_alias != NULL) 
1026                destroy_dev(old_alias);
1027        if (devfspath != NULL)
1028                free(devfspath, M_DEVBUF);
1029        return (ret);
1030}
1031
1032static void
1033destroy_devl(struct cdev *dev)
1034{
1035        struct cdevsw *csw;
1036        struct cdev_privdata *p;
1037        struct cdev_priv *cdp;
1038
1039        mtx_assert(&devmtx, MA_OWNED);
1040        KASSERT(dev->si_flags & SI_NAMED,
1041            ("WARNING: Driver mistake: destroy_dev on %d\n", dev2unit(dev)));
1042        KASSERT((dev->si_flags & SI_ETERNAL) == 0,
1043            ("WARNING: Driver mistake: destroy_dev on eternal %d\n",
1044             dev2unit(dev)));
1045
1046        cdp = cdev2priv(dev);
1047        if ((cdp->cdp_flags & CDP_UNREF_DTR) == 0) {
1048                /*
1049                 * Avoid race with dev_rel(), e.g. from the populate
1050                 * loop.  If CDP_UNREF_DTR flag is set, the reference
1051                 * to be dropped at the end of destroy_devl() was
1052                 * already taken by delist_dev_locked().
1053                 */
1054                dev_refl(dev);
1055
1056                devfs_destroy(dev);
1057        }
1058
1059        /* Remove name marking */
1060        dev->si_flags &= ~SI_NAMED;
1061
1062        /* If we are a child, remove us from the parents list */
1063        if (dev->si_flags & SI_CHILD) {
1064                LIST_REMOVE(dev, si_siblings);
1065                dev->si_flags &= ~SI_CHILD;
1066        }
1067
1068        /* Kill our children */
1069        while (!LIST_EMPTY(&dev->si_children))
1070                destroy_devl(LIST_FIRST(&dev->si_children));
1071
1072        /* Remove from clone list */
1073        if (dev->si_flags & SI_CLONELIST) {
1074                LIST_REMOVE(dev, si_clone);
1075                dev->si_flags &= ~SI_CLONELIST;
1076        }
1077
1078        csw = dev->si_devsw;
1079        dev->si_devsw = NULL;   /* already NULL for SI_ALIAS */
1080        while (csw != NULL && csw->d_purge != NULL && dev->si_threadcount) {
1081                csw->d_purge(dev);
1082                msleep(csw, &devmtx, PRIBIO, "devprg", hz/10);
1083                if (dev->si_threadcount)
1084                        printf("Still %lu threads in %s\n",
1085                            dev->si_threadcount, devtoname(dev));
1086        }
1087        while (dev->si_threadcount != 0) {
1088                /* Use unique dummy wait ident */
1089                msleep(&csw, &devmtx, PRIBIO, "devdrn", hz / 10);
1090        }
1091
1092        dev_unlock();
1093        if ((cdp->cdp_flags & CDP_UNREF_DTR) == 0) {
1094                /* avoid out of order notify events */
1095                notify_destroy(dev);
1096        }
1097        mtx_lock(&cdevpriv_mtx);
1098        while ((p = LIST_FIRST(&cdp->cdp_fdpriv)) != NULL) {
1099                devfs_destroy_cdevpriv(p);
1100                mtx_lock(&cdevpriv_mtx);
1101        }
1102        mtx_unlock(&cdevpriv_mtx);
1103        dev_lock();
1104
1105        dev->si_drv1 = 0;
1106        dev->si_drv2 = 0;
1107        bzero(&dev->__si_u, sizeof(dev->__si_u));
1108
1109        if (!(dev->si_flags & SI_ALIAS)) {
1110                /* Remove from cdevsw list */
1111                LIST_REMOVE(dev, si_list);
1112
1113                /* If cdevsw has no more struct cdev *'s, clean it */
1114                if (LIST_EMPTY(&csw->d_devs)) {
1115                        fini_cdevsw(csw);
1116                        wakeup(&csw->d_devs);
1117                }
1118        }
1119        dev->si_flags &= ~SI_ALIAS;
1120        cdp->cdp_flags &= ~CDP_UNREF_DTR;
1121        dev->si_refcount--;
1122
1123        if (dev->si_refcount > 0)
1124                LIST_INSERT_HEAD(&dead_cdevsw.d_devs, dev, si_list);
1125        else
1126                dev_free_devlocked(dev);
1127}
1128
1129static void
1130delist_dev_locked(struct cdev *dev)
1131{
1132        struct cdev_priv *cdp;
1133        struct cdev *child;
1134
1135        mtx_assert(&devmtx, MA_OWNED);
1136        cdp = cdev2priv(dev);
1137        if ((cdp->cdp_flags & CDP_UNREF_DTR) != 0)
1138                return;
1139        cdp->cdp_flags |= CDP_UNREF_DTR;
1140        dev_refl(dev);
1141        devfs_destroy(dev);
1142        LIST_FOREACH(child, &dev->si_children, si_siblings)
1143                delist_dev_locked(child);
1144        dev_unlock();   
1145        /* ensure the destroy event is queued in order */
1146        notify_destroy(dev);
1147        dev_lock();
1148}
1149
1150/*
1151 * This function will delist a character device and its children from
1152 * the directory listing and create a destroy event without waiting
1153 * for all character device references to go away. At some later point
1154 * destroy_dev() must be called to complete the character device
1155 * destruction. After calling this function the character device name
1156 * can instantly be re-used.
1157 */
1158void
1159delist_dev(struct cdev *dev)
1160{
1161
1162        WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, "delist_dev");
1163        dev_lock();
1164        delist_dev_locked(dev);
1165        dev_unlock();
1166}
1167
1168void
1169destroy_dev(struct cdev *dev)
1170{
1171
1172        WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, "destroy_dev");
1173        dev_lock();
1174        destroy_devl(dev);
1175        dev_unlock_and_free();
1176}
1177
1178const char *
1179devtoname(struct cdev *dev)
1180{
1181
1182        return (dev->si_name);
1183}
1184
1185int
1186dev_stdclone(char *name, char **namep, const char *stem, int *unit)
1187{
1188        int u, i;
1189
1190        i = strlen(stem);
1191        if (bcmp(stem, name, i) != 0)
1192                return (0);
1193        if (!isdigit(name[i]))
1194                return (0);
1195        u = 0;
1196        if (name[i] == '0' && isdigit(name[i+1]))
1197                return (0);
1198        while (isdigit(name[i])) {
1199                u *= 10;
1200                u += name[i++] - '0';
1201        }
1202        if (u > 0xffffff)
1203                return (0);
1204        *unit = u;
1205        if (namep)
1206                *namep = &name[i];
1207        if (name[i])
1208                return (2);
1209        return (1);
1210}
1211
1212/*
1213 * Helper functions for cloning device drivers.
1214 *
1215 * The objective here is to make it unnecessary for the device drivers to
1216 * use rman or similar to manage their unit number space.  Due to the way
1217 * we do "on-demand" devices, using rman or other "private" methods
1218 * will be very tricky to lock down properly once we lock down this file.
1219 *
1220 * Instead we give the drivers these routines which puts the struct cdev *'s
1221 * that are to be managed on their own list, and gives the driver the ability
1222 * to ask for the first free unit number or a given specified unit number.
1223 *
1224 * In addition these routines support paired devices (pty, nmdm and similar)
1225 * by respecting a number of "flag" bits in the minor number.
1226 *
1227 */
1228
1229struct clonedevs {
1230        LIST_HEAD(,cdev)        head;
1231};
1232
1233void
1234clone_setup(struct clonedevs **cdp)
1235{
1236
1237        *cdp = malloc(sizeof **cdp, M_DEVBUF, M_WAITOK | M_ZERO);
1238        LIST_INIT(&(*cdp)->head);
1239}
1240
1241int
1242clone_create(struct clonedevs **cdp, struct cdevsw *csw, int *up,
1243    struct cdev **dp, int extra)
1244{
1245        struct clonedevs *cd;
1246        struct cdev *dev, *ndev, *dl, *de;
1247        int unit, low, u;
1248
1249        KASSERT(*cdp != NULL,
1250            ("clone_setup() not called in driver \"%s\"", csw->d_name));
1251        KASSERT(!(extra & CLONE_UNITMASK),
1252            ("Illegal extra bits (0x%x) in clone_create", extra));
1253        KASSERT(*up <= CLONE_UNITMASK,
1254            ("Too high unit (0x%x) in clone_create", *up));
1255        KASSERT(csw->d_flags & D_NEEDMINOR,
1256            ("clone_create() on cdevsw without minor numbers"));
1257
1258
1259        /*
1260         * Search the list for a lot of things in one go:
1261         *   A preexisting match is returned immediately.
1262         *   The lowest free unit number if we are passed -1, and the place
1263         *       in the list where we should insert that new element.
1264         *   The place to insert a specified unit number, if applicable
1265         *       the end of the list.
1266         */
1267        unit = *up;
1268        ndev = devfs_alloc(MAKEDEV_WAITOK);
1269        dev_lock();
1270        prep_cdevsw(csw, MAKEDEV_WAITOK);
1271        low = extra;
1272        de = dl = NULL;
1273        cd = *cdp;
1274        LIST_FOREACH(dev, &cd->head, si_clone) {
1275                KASSERT(dev->si_flags & SI_CLONELIST,
1276                    ("Dev %p(%s) should be on clonelist", dev, dev->si_name));
1277                u = dev2unit(dev);
1278                if (u == (unit | extra)) {
1279                        *dp = dev;
1280                        dev_unlock();
1281                        devfs_free(ndev);
1282                        return (0);
1283                }
1284                if (unit == -1 && u == low) {
1285                        low++;
1286                        de = dev;
1287                        continue;
1288                } else if (u < (unit | extra)) {
1289                        de = dev;
1290                        continue;
1291                } else if (u > (unit | extra)) {
1292                        dl = dev;
1293                        break;
1294                }
1295        }
1296        if (unit == -1)
1297                unit = low & CLONE_UNITMASK;
1298        dev = newdev(csw, unit | extra, ndev);
1299        if (dev->si_flags & SI_CLONELIST) {
1300                printf("dev %p (%s) is on clonelist\n", dev, dev->si_name);
1301                printf("unit=%d, low=%d, extra=0x%x\n", unit, low, extra);
1302                LIST_FOREACH(dev, &cd->head, si_clone) {
1303                        printf("\t%p %s\n", dev, dev->si_name);
1304                }
1305                panic("foo");
1306        }
1307        KASSERT(!(dev->si_flags & SI_CLONELIST),
1308            ("Dev %p(%s) should not be on clonelist", dev, dev->si_name));
1309        if (dl != NULL)
1310                LIST_INSERT_BEFORE(dl, dev, si_clone);
1311        else if (de != NULL)
1312                LIST_INSERT_AFTER(de, dev, si_clone);
1313        else
1314                LIST_INSERT_HEAD(&cd->head, dev, si_clone);
1315        dev->si_flags |= SI_CLONELIST;
1316        *up = unit;
1317        dev_unlock_and_free();
1318        return (1);
1319}
1320
1321/*
1322 * Kill everything still on the list.  The driver should already have
1323 * disposed of any softc hung of the struct cdev *'s at this time.
1324 */
1325void
1326clone_cleanup(struct clonedevs **cdp)
1327{
1328        struct cdev *dev;
1329        struct cdev_priv *cp;
1330        struct clonedevs *cd;
1331       
1332        cd = *cdp;
1333        if (cd == NULL)
1334                return;
1335        dev_lock();
1336        while (!LIST_EMPTY(&cd->head)) {
1337                dev = LIST_FIRST(&cd->head);
1338                LIST_REMOVE(dev, si_clone);
1339                KASSERT(dev->si_flags & SI_CLONELIST,
1340                    ("Dev %p(%s) should be on clonelist", dev, dev->si_name));
1341                dev->si_flags &= ~SI_CLONELIST;
1342                cp = cdev2priv(dev);
1343                if (!(cp->cdp_flags & CDP_SCHED_DTR)) {
1344                        cp->cdp_flags |= CDP_SCHED_DTR;
1345                        KASSERT(dev->si_flags & SI_NAMED,
1346                                ("Driver has goofed in cloning underways udev %x unit %x", dev2udev(dev), dev2unit(dev)));
1347                        destroy_devl(dev);
1348                }
1349        }
1350        dev_unlock_and_free();
1351        free(cd, M_DEVBUF);
1352        *cdp = NULL;
1353}
1354
1355static TAILQ_HEAD(, cdev_priv) dev_ddtr =
1356        TAILQ_HEAD_INITIALIZER(dev_ddtr);
1357static struct task dev_dtr_task;
1358
1359static void
1360destroy_dev_tq(void *ctx, int pending)
1361{
1362        struct cdev_priv *cp;
1363        struct cdev *dev;
1364        void (*cb)(void *);
1365        void *cb_arg;
1366
1367        dev_lock();
1368        while (!TAILQ_EMPTY(&dev_ddtr)) {
1369                cp = TAILQ_FIRST(&dev_ddtr);
1370                dev = &cp->cdp_c;
1371                KASSERT(cp->cdp_flags & CDP_SCHED_DTR,
1372                    ("cdev %p in dev_destroy_tq without CDP_SCHED_DTR", cp));
1373                TAILQ_REMOVE(&dev_ddtr, cp, cdp_dtr_list);
1374                cb = cp->cdp_dtr_cb;
1375                cb_arg = cp->cdp_dtr_cb_arg;
1376                destroy_devl(dev);
1377                dev_unlock_and_free();
1378                dev_rel(dev);
1379                if (cb != NULL)
1380                        cb(cb_arg);
1381                dev_lock();
1382        }
1383        dev_unlock();
1384}
1385
1386/*
1387 * devmtx shall be locked on entry. devmtx will be unlocked after
1388 * function return.
1389 */
1390static int
1391destroy_dev_sched_cbl(struct cdev *dev, void (*cb)(void *), void *arg)
1392{
1393        struct cdev_priv *cp;
1394
1395        mtx_assert(&devmtx, MA_OWNED);
1396        cp = cdev2priv(dev);
1397        if (cp->cdp_flags & CDP_SCHED_DTR) {
1398                dev_unlock();
1399                return (0);
1400        }
1401        dev_refl(dev);
1402        cp->cdp_flags |= CDP_SCHED_DTR;
1403        cp->cdp_dtr_cb = cb;
1404        cp->cdp_dtr_cb_arg = arg;
1405        TAILQ_INSERT_TAIL(&dev_ddtr, cp, cdp_dtr_list);
1406        dev_unlock();
1407        taskqueue_enqueue(taskqueue_swi_giant, &dev_dtr_task);
1408        return (1);
1409}
1410
1411int
1412destroy_dev_sched_cb(struct cdev *dev, void (*cb)(void *), void *arg)
1413{
1414
1415        dev_lock();
1416        return (destroy_dev_sched_cbl(dev, cb, arg));
1417}
1418
1419int
1420destroy_dev_sched(struct cdev *dev)
1421{
1422
1423        return (destroy_dev_sched_cb(dev, NULL, NULL));
1424}
1425
1426void
1427destroy_dev_drain(struct cdevsw *csw)
1428{
1429
1430        dev_lock();
1431        while (!LIST_EMPTY(&csw->d_devs)) {
1432                msleep(&csw->d_devs, &devmtx, PRIBIO, "devscd", hz/10);
1433        }
1434        dev_unlock();
1435}
1436
1437void
1438drain_dev_clone_events(void)
1439{
1440
1441        sx_xlock(&clone_drain_lock);
1442        sx_xunlock(&clone_drain_lock);
1443}
1444
1445static void
1446devdtr_init(void *dummy __unused)
1447{
1448
1449        TASK_INIT(&dev_dtr_task, 0, destroy_dev_tq, NULL);
1450}
1451
1452SYSINIT(devdtr, SI_SUB_DEVFS, SI_ORDER_SECOND, devdtr_init, NULL);
1453
1454#include <rtems/bsd/local/opt_ddb.h>
1455#ifdef DDB
1456#include <sys/kernel.h>
1457
1458#include <ddb/ddb.h>
1459
1460DB_SHOW_COMMAND(cdev, db_show_cdev)
1461{
1462        struct cdev_priv *cdp;
1463        struct cdev *dev;
1464        u_int flags;
1465        char buf[512];
1466
1467        if (!have_addr) {
1468                TAILQ_FOREACH(cdp, &cdevp_list, cdp_list) {
1469                        dev = &cdp->cdp_c;
1470                        db_printf("%s %p\n", dev->si_name, dev);
1471                        if (db_pager_quit)
1472                                break;
1473                }
1474                return;
1475        }
1476
1477        dev = (struct cdev *)addr;
1478        cdp = cdev2priv(dev);
1479        db_printf("dev %s ref %d use %ld thr %ld inuse %u fdpriv %p\n",
1480            dev->si_name, dev->si_refcount, dev->si_usecount,
1481            dev->si_threadcount, cdp->cdp_inuse, cdp->cdp_fdpriv.lh_first);
1482        db_printf("devsw %p si_drv0 %d si_drv1 %p si_drv2 %p\n",
1483            dev->si_devsw, dev->si_drv0, dev->si_drv1, dev->si_drv2);
1484        flags = dev->si_flags;
1485#define SI_FLAG(flag)   do {                                            \
1486        if (flags & (flag)) {                                           \
1487                if (buf[0] != '\0')                                     \
1488                        strlcat(buf, ", ", sizeof(buf));                \
1489                strlcat(buf, (#flag) + 3, sizeof(buf));                 \
1490                flags &= ~(flag);                                       \
1491        }                                                               \
1492} while (0)
1493        buf[0] = '\0';
1494        SI_FLAG(SI_ETERNAL);
1495        SI_FLAG(SI_ALIAS);
1496        SI_FLAG(SI_NAMED);
1497        SI_FLAG(SI_CHEAPCLONE);
1498        SI_FLAG(SI_CHILD);
1499        SI_FLAG(SI_DEVOPEN);
1500        SI_FLAG(SI_CONSOPEN);
1501        SI_FLAG(SI_DUMPDEV);
1502        SI_FLAG(SI_CANDELETE);
1503        SI_FLAG(SI_CLONELIST);
1504        db_printf("si_flags %s\n", buf);
1505
1506        flags = cdp->cdp_flags;
1507#define CDP_FLAG(flag)  do {                                            \
1508        if (flags & (flag)) {                                           \
1509                if (buf[0] != '\0')                                     \
1510                        strlcat(buf, ", ", sizeof(buf));                \
1511                strlcat(buf, (#flag) + 4, sizeof(buf));                 \
1512                flags &= ~(flag);                                       \
1513        }                                                               \
1514} while (0)
1515        buf[0] = '\0';
1516        CDP_FLAG(CDP_ACTIVE);
1517        CDP_FLAG(CDP_SCHED_DTR);
1518        db_printf("cdp_flags %s\n", buf);
1519}
1520#endif
Note: See TracBrowser for help on using the repository browser.