FreeBSD/Linux Kernel Cross Reference
sys/kern/kern_conf.c
1 /*-
2 * Copyright (c) 1999-2002 Poul-Henning Kamp
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD: releng/7.3/sys/kern/kern_conf.c 198595 2009-10-29 15:10:38Z jhb $");
29
30 #include <sys/param.h>
31 #include <sys/kernel.h>
32 #include <sys/systm.h>
33 #include <sys/bus.h>
34 #include <sys/bio.h>
35 #include <sys/lock.h>
36 #include <sys/mutex.h>
37 #include <sys/module.h>
38 #include <sys/malloc.h>
39 #include <sys/conf.h>
40 #include <sys/vnode.h>
41 #include <sys/queue.h>
42 #include <sys/poll.h>
43 #include <sys/sx.h>
44 #include <sys/ctype.h>
45 #include <sys/tty.h>
46 #include <sys/ucred.h>
47 #include <sys/taskqueue.h>
48 #include <machine/stdarg.h>
49
50 #include <fs/devfs/devfs_int.h>
51 #include <vm/vm.h>
52
53 static MALLOC_DEFINE(M_DEVT, "cdev", "cdev storage");
54
55 struct mtx devmtx;
56 static void destroy_devl(struct cdev *dev);
57 static int destroy_dev_sched_cbl(struct cdev *dev,
58 void (*cb)(void *), void *arg);
59 static struct cdev *make_dev_credv(int flags,
60 struct cdevsw *devsw, int minornr,
61 struct ucred *cr, uid_t uid, gid_t gid, int mode, const char *fmt,
62 va_list ap);
63
64 static struct cdev_priv_list cdevp_free_list =
65 TAILQ_HEAD_INITIALIZER(cdevp_free_list);
66 static SLIST_HEAD(free_cdevsw, cdevsw) cdevsw_gt_post_list =
67 SLIST_HEAD_INITIALIZER();
68
69 void
70 dev_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 */
82 static void
83 dev_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
113 static void
114 dev_free_devlocked(struct cdev *cdev)
115 {
116 struct cdev_priv *cdp;
117
118 mtx_assert(&devmtx, MA_OWNED);
119 cdp = cdev->si_priv;
120 TAILQ_INSERT_HEAD(&cdevp_free_list, cdp, cdp_list);
121 }
122
123 static void
124 cdevsw_free_devlocked(struct cdevsw *csw)
125 {
126
127 mtx_assert(&devmtx, MA_OWNED);
128 SLIST_INSERT_HEAD(&cdevsw_gt_post_list, csw, d_postfree_list);
129 }
130
131 void
132 dev_unlock(void)
133 {
134
135 mtx_unlock(&devmtx);
136 }
137
138 void
139 dev_ref(struct cdev *dev)
140 {
141
142 mtx_assert(&devmtx, MA_NOTOWNED);
143 mtx_lock(&devmtx);
144 dev->si_refcount++;
145 mtx_unlock(&devmtx);
146 }
147
148 void
149 dev_refl(struct cdev *dev)
150 {
151
152 mtx_assert(&devmtx, MA_OWNED);
153 dev->si_refcount++;
154 }
155
156 void
157 dev_rel(struct cdev *dev)
158 {
159 int flag = 0;
160
161 mtx_assert(&devmtx, MA_NOTOWNED);
162 dev_lock();
163 dev->si_refcount--;
164 KASSERT(dev->si_refcount >= 0,
165 ("dev_rel(%s) gave negative count", devtoname(dev)));
166 #if 0
167 if (dev->si_usecount == 0 &&
168 (dev->si_flags & SI_CHEAPCLONE) && (dev->si_flags & SI_NAMED))
169 ;
170 else
171 #endif
172 if (dev->si_devsw == NULL && dev->si_refcount == 0) {
173 LIST_REMOVE(dev, si_list);
174 flag = 1;
175 }
176 dev_unlock();
177 if (flag)
178 devfs_free(dev);
179 }
180
181 struct cdevsw *
182 dev_refthread(struct cdev *dev)
183 {
184 struct cdevsw *csw;
185 struct cdev_priv *cdp;
186
187 mtx_assert(&devmtx, MA_NOTOWNED);
188 dev_lock();
189 csw = dev->si_devsw;
190 if (csw != NULL) {
191 cdp = dev->si_priv;
192 if ((cdp->cdp_flags & CDP_SCHED_DTR) == 0)
193 dev->si_threadcount++;
194 else
195 csw = NULL;
196 }
197 dev_unlock();
198 return (csw);
199 }
200
201 struct cdevsw *
202 devvn_refthread(struct vnode *vp, struct cdev **devp)
203 {
204 struct cdevsw *csw;
205 struct cdev_priv *cdp;
206
207 mtx_assert(&devmtx, MA_NOTOWNED);
208 csw = NULL;
209 dev_lock();
210 *devp = vp->v_rdev;
211 if (*devp != NULL) {
212 cdp = (*devp)->si_priv;
213 if ((cdp->cdp_flags & CDP_SCHED_DTR) == 0) {
214 csw = (*devp)->si_devsw;
215 if (csw != NULL)
216 (*devp)->si_threadcount++;
217 }
218 }
219 dev_unlock();
220 return (csw);
221 }
222
223 void
224 dev_relthread(struct cdev *dev)
225 {
226
227 mtx_assert(&devmtx, MA_NOTOWNED);
228 dev_lock();
229 KASSERT(dev->si_threadcount > 0,
230 ("%s threadcount is wrong", dev->si_name));
231 dev->si_threadcount--;
232 dev_unlock();
233 }
234
235 int
236 nullop(void)
237 {
238
239 return (0);
240 }
241
242 int
243 eopnotsupp(void)
244 {
245
246 return (EOPNOTSUPP);
247 }
248
249 static int
250 enxio(void)
251 {
252 return (ENXIO);
253 }
254
255 static int
256 enodev(void)
257 {
258 return (ENODEV);
259 }
260
261 /* Define a dead_cdevsw for use when devices leave unexpectedly. */
262
263 #define dead_open (d_open_t *)enxio
264 #define dead_close (d_close_t *)enxio
265 #define dead_read (d_read_t *)enxio
266 #define dead_write (d_write_t *)enxio
267 #define dead_ioctl (d_ioctl_t *)enxio
268 #define dead_poll (d_poll_t *)enodev
269 #define dead_mmap (d_mmap_t *)enodev
270
271 static void
272 dead_strategy(struct bio *bp)
273 {
274
275 biofinish(bp, NULL, ENXIO);
276 }
277
278 #define dead_dump (dumper_t *)enxio
279 #define dead_kqfilter (d_kqfilter_t *)enxio
280 #define dead_mmap_single (d_mmap_single_t *)enodev
281
282 static struct cdevsw dead_cdevsw = {
283 .d_version = D_VERSION,
284 .d_flags = D_NEEDGIANT, /* XXX: does dead_strategy need this ? */
285 .d_open = dead_open,
286 .d_close = dead_close,
287 .d_read = dead_read,
288 .d_write = dead_write,
289 .d_ioctl = dead_ioctl,
290 .d_poll = dead_poll,
291 .d_mmap = dead_mmap,
292 .d_strategy = dead_strategy,
293 .d_name = "dead",
294 .d_dump = dead_dump,
295 .d_kqfilter = dead_kqfilter,
296 .d_mmap_single = dead_mmap_single
297 };
298
299 /* Default methods if driver does not specify method */
300
301 #define null_open (d_open_t *)nullop
302 #define null_close (d_close_t *)nullop
303 #define no_read (d_read_t *)enodev
304 #define no_write (d_write_t *)enodev
305 #define no_ioctl (d_ioctl_t *)enodev
306 #define no_mmap (d_mmap2_t *)enodev
307 #define no_kqfilter (d_kqfilter_t *)enodev
308 #define no_mmap_single (d_mmap_single_t *)enodev
309
310 static void
311 no_strategy(struct bio *bp)
312 {
313
314 biofinish(bp, NULL, ENODEV);
315 }
316
317 static int
318 no_poll(struct cdev *dev __unused, int events, struct thread *td __unused)
319 {
320
321 return (poll_no_poll(events));
322 }
323
324 #define no_dump (dumper_t *)enodev
325
326 static int
327 giant_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
328 {
329 struct cdevsw *dsw;
330 int retval;
331
332 dsw = dev_refthread(dev);
333 if (dsw == NULL)
334 return (ENXIO);
335 mtx_lock(&Giant);
336 retval = dsw->d_gianttrick->d_open(dev, oflags, devtype, td);
337 mtx_unlock(&Giant);
338 dev_relthread(dev);
339 return (retval);
340 }
341
342 static int
343 giant_fdopen(struct cdev *dev, int oflags, struct thread *td, struct file *fp)
344 {
345 struct cdevsw *dsw;
346 int retval;
347
348 dsw = dev_refthread(dev);
349 if (dsw == NULL)
350 return (ENXIO);
351 mtx_lock(&Giant);
352 retval = dsw->d_gianttrick->d_fdopen(dev, oflags, td, fp);
353 mtx_unlock(&Giant);
354 dev_relthread(dev);
355 return (retval);
356 }
357
358 static int
359 giant_close(struct cdev *dev, int fflag, int devtype, struct thread *td)
360 {
361 struct cdevsw *dsw;
362 int retval;
363
364 dsw = dev_refthread(dev);
365 if (dsw == NULL)
366 return (ENXIO);
367 mtx_lock(&Giant);
368 retval = dsw->d_gianttrick->d_close(dev, fflag, devtype, td);
369 mtx_unlock(&Giant);
370 dev_relthread(dev);
371 return (retval);
372 }
373
374 static void
375 giant_strategy(struct bio *bp)
376 {
377 struct cdevsw *dsw;
378 struct cdev *dev;
379
380 dev = bp->bio_dev;
381 dsw = dev_refthread(dev);
382 if (dsw == NULL) {
383 biofinish(bp, NULL, ENXIO);
384 return;
385 }
386 mtx_lock(&Giant);
387 dsw->d_gianttrick->d_strategy(bp);
388 mtx_unlock(&Giant);
389 dev_relthread(dev);
390 }
391
392 static int
393 giant_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct thread *td)
394 {
395 struct cdevsw *dsw;
396 int retval;
397
398 dsw = dev_refthread(dev);
399 if (dsw == NULL)
400 return (ENXIO);
401 mtx_lock(&Giant);
402 retval = dsw->d_gianttrick->d_ioctl(dev, cmd, data, fflag, td);
403 mtx_unlock(&Giant);
404 dev_relthread(dev);
405 return (retval);
406 }
407
408 static int
409 giant_read(struct cdev *dev, struct uio *uio, int ioflag)
410 {
411 struct cdevsw *dsw;
412 int retval;
413
414 dsw = dev_refthread(dev);
415 if (dsw == NULL)
416 return (ENXIO);
417 mtx_lock(&Giant);
418 retval = dsw->d_gianttrick->d_read(dev, uio, ioflag);
419 mtx_unlock(&Giant);
420 dev_relthread(dev);
421 return (retval);
422 }
423
424 static int
425 giant_write(struct cdev *dev, struct uio *uio, int ioflag)
426 {
427 struct cdevsw *dsw;
428 int retval;
429
430 dsw = dev_refthread(dev);
431 if (dsw == NULL)
432 return (ENXIO);
433 mtx_lock(&Giant);
434 retval = dsw->d_gianttrick->d_write(dev, uio, ioflag);
435 mtx_unlock(&Giant);
436 dev_relthread(dev);
437 return (retval);
438 }
439
440 static int
441 giant_poll(struct cdev *dev, int events, struct thread *td)
442 {
443 struct cdevsw *dsw;
444 int retval;
445
446 dsw = dev_refthread(dev);
447 if (dsw == NULL)
448 return (ENXIO);
449 mtx_lock(&Giant);
450 retval = dsw->d_gianttrick->d_poll(dev, events, td);
451 mtx_unlock(&Giant);
452 dev_relthread(dev);
453 return (retval);
454 }
455
456 static int
457 giant_kqfilter(struct cdev *dev, struct knote *kn)
458 {
459 struct cdevsw *dsw;
460 int retval;
461
462 dsw = dev_refthread(dev);
463 if (dsw == NULL)
464 return (ENXIO);
465 mtx_lock(&Giant);
466 retval = dsw->d_gianttrick->d_kqfilter(dev, kn);
467 mtx_unlock(&Giant);
468 dev_relthread(dev);
469 return (retval);
470 }
471
472 static int
473 giant_mmap(struct cdev *dev, vm_offset_t offset, vm_paddr_t *paddr, int nprot,
474 vm_memattr_t *memattr)
475 {
476 struct cdevsw *dsw;
477 int retval;
478
479 dsw = dev_refthread(dev);
480 if (dsw == NULL)
481 return (ENXIO);
482 mtx_lock(&Giant);
483 if (dsw->d_gianttrick->d_flags & D_MMAP2)
484 retval = dsw->d_gianttrick->d_mmap2(dev, offset, paddr, nprot,
485 memattr);
486 else
487 retval = dsw->d_gianttrick->d_mmap(dev, offset, paddr, nprot);
488 mtx_unlock(&Giant);
489 dev_relthread(dev);
490 return (retval);
491 }
492
493 static int
494 giant_mmap_single(struct cdev *dev, vm_ooffset_t *offset, vm_size_t size,
495 vm_object_t *object, int nprot)
496 {
497 struct cdevsw *dsw;
498 int retval;
499
500 dsw = dev_refthread(dev);
501 if (dsw == NULL)
502 return (ENXIO);
503 mtx_lock(&Giant);
504 retval = dsw->d_gianttrick->d_mmap_single(dev, offset, size, object,
505 nprot);
506 mtx_unlock(&Giant);
507 dev_relthread(dev);
508 return (retval);
509 }
510
511 /*
512 * struct cdev * and u_dev_t primitives
513 */
514
515 int
516 minor(struct cdev *x)
517 {
518 if (x == NULL)
519 return NODEV;
520 return(x->si_drv0 & MAXMINOR);
521 }
522
523 int
524 dev2unit(struct cdev *x)
525 {
526
527 if (x == NULL)
528 return NODEV;
529 return (minor2unit(minor(x)));
530 }
531
532 u_int
533 minor2unit(u_int _minor)
534 {
535
536 KASSERT((_minor & ~MAXMINOR) == 0, ("Illegal minor %x", _minor));
537 return ((_minor & 0xff) | ((_minor >> 8) & 0xffff00));
538 }
539
540 int
541 unit2minor(int unit)
542 {
543
544 KASSERT(unit <= 0xffffff, ("Invalid unit (%d) in unit2minor", unit));
545 return ((unit & 0xff) | ((unit << 8) & ~0xffff));
546 }
547
548 static void
549 notify(struct cdev *dev, const char *ev)
550 {
551 static const char prefix[] = "cdev=";
552 char *data;
553 int namelen;
554
555 if (cold)
556 return;
557 namelen = strlen(dev->si_name);
558 data = malloc(namelen + sizeof(prefix), M_TEMP, M_WAITOK);
559 memcpy(data, prefix, sizeof(prefix) - 1);
560 memcpy(data + sizeof(prefix) - 1, dev->si_name, namelen + 1);
561 devctl_notify("DEVFS", "CDEV", ev, data);
562 free(data, M_TEMP);
563 }
564
565 static void
566 notify_create(struct cdev *dev)
567 {
568
569 notify(dev, "CREATE");
570 }
571
572 static void
573 notify_destroy(struct cdev *dev)
574 {
575
576 notify(dev, "DESTROY");
577 }
578
579 static struct cdev *
580 newdev(struct cdevsw *csw, int y, struct cdev *si)
581 {
582 struct cdev *si2;
583 dev_t udev;
584
585 mtx_assert(&devmtx, MA_OWNED);
586 udev = y;
587 LIST_FOREACH(si2, &csw->d_devs, si_list) {
588 if (si2->si_drv0 == udev) {
589 dev_free_devlocked(si);
590 return (si2);
591 }
592 }
593 si->si_drv0 = udev;
594 si->si_devsw = csw;
595 LIST_INSERT_HEAD(&csw->d_devs, si, si_list);
596 return (si);
597 }
598
599 int
600 uminor(dev_t dev)
601 {
602 return (dev & MAXMINOR);
603 }
604
605 int
606 umajor(dev_t dev)
607 {
608 return ((dev & ~MAXMINOR) >> 8);
609 }
610
611 static void
612 fini_cdevsw(struct cdevsw *devsw)
613 {
614 struct cdevsw *gt;
615
616 if (devsw->d_gianttrick != NULL) {
617 gt = devsw->d_gianttrick;
618 memcpy(devsw, gt, sizeof *devsw);
619 cdevsw_free_devlocked(gt);
620 devsw->d_gianttrick = NULL;
621 }
622 devsw->d_flags &= ~D_INIT;
623 }
624
625 static void
626 prep_cdevsw(struct cdevsw *devsw)
627 {
628 struct cdevsw *dsw2;
629
630 mtx_assert(&devmtx, MA_OWNED);
631 if (devsw->d_flags & D_INIT)
632 return;
633 if (devsw->d_flags & D_NEEDGIANT) {
634 dev_unlock();
635 dsw2 = malloc(sizeof *dsw2, M_DEVT, M_WAITOK);
636 dev_lock();
637 } else
638 dsw2 = NULL;
639 if (devsw->d_flags & D_INIT) {
640 if (dsw2 != NULL)
641 cdevsw_free_devlocked(dsw2);
642 return;
643 }
644
645 if (devsw->d_version != D_VERSION_01 &&
646 devsw->d_version != D_VERSION_02) {
647 printf(
648 "WARNING: Device driver \"%s\" has wrong version %s\n",
649 devsw->d_name == NULL ? "???" : devsw->d_name,
650 "and is disabled. Recompile KLD module.");
651 devsw->d_open = dead_open;
652 devsw->d_close = dead_close;
653 devsw->d_read = dead_read;
654 devsw->d_write = dead_write;
655 devsw->d_ioctl = dead_ioctl;
656 devsw->d_poll = dead_poll;
657 devsw->d_mmap = dead_mmap;
658 devsw->d_strategy = dead_strategy;
659 devsw->d_dump = dead_dump;
660 devsw->d_kqfilter = dead_kqfilter;
661 }
662 if (devsw->d_version == D_VERSION_01)
663 devsw->d_mmap_single = NULL;
664
665 if (devsw->d_flags & D_TTY) {
666 if (devsw->d_ioctl == NULL) devsw->d_ioctl = ttyioctl;
667 if (devsw->d_read == NULL) devsw->d_read = ttyread;
668 if (devsw->d_write == NULL) devsw->d_write = ttywrite;
669 if (devsw->d_kqfilter == NULL) devsw->d_kqfilter = ttykqfilter;
670 if (devsw->d_poll == NULL) devsw->d_poll = ttypoll;
671 }
672
673 if (devsw->d_flags & D_NEEDGIANT) {
674 if (devsw->d_gianttrick == NULL) {
675 memcpy(dsw2, devsw, sizeof *dsw2);
676 devsw->d_gianttrick = dsw2;
677 devsw->d_flags |= D_MMAP2;
678 dsw2 = NULL;
679 }
680 }
681
682 #define FIXUP(member, noop, giant) \
683 do { \
684 if (devsw->member == NULL) { \
685 devsw->member = noop; \
686 } else if (devsw->d_flags & D_NEEDGIANT) \
687 devsw->member = giant; \
688 } \
689 while (0)
690
691 FIXUP(d_open, null_open, giant_open);
692 FIXUP(d_fdopen, NULL, giant_fdopen);
693 FIXUP(d_close, null_close, giant_close);
694 FIXUP(d_read, no_read, giant_read);
695 FIXUP(d_write, no_write, giant_write);
696 FIXUP(d_ioctl, no_ioctl, giant_ioctl);
697 FIXUP(d_poll, no_poll, giant_poll);
698 FIXUP(d_mmap2, no_mmap, giant_mmap);
699 FIXUP(d_strategy, no_strategy, giant_strategy);
700 FIXUP(d_kqfilter, no_kqfilter, giant_kqfilter);
701 FIXUP(d_mmap_single, no_mmap_single, giant_mmap_single);
702
703 if (devsw->d_dump == NULL) devsw->d_dump = no_dump;
704
705 LIST_INIT(&devsw->d_devs);
706
707 devsw->d_flags |= D_INIT;
708
709 if (dsw2 != NULL)
710 cdevsw_free_devlocked(dsw2);
711 }
712
713 struct cdev *
714 make_dev_credv(int flags, struct cdevsw *devsw, int minornr,
715 struct ucred *cr, uid_t uid,
716 gid_t gid, int mode, const char *fmt, va_list ap)
717 {
718 struct cdev *dev;
719 int i;
720
721 KASSERT((minornr & ~MAXMINOR) == 0,
722 ("Invalid minor (0x%x) in make_dev", minornr));
723
724 dev = devfs_alloc();
725 dev_lock();
726 prep_cdevsw(devsw);
727 dev = newdev(devsw, minornr, dev);
728 if (flags & MAKEDEV_REF)
729 dev_refl(dev);
730 if (dev->si_flags & SI_CHEAPCLONE &&
731 dev->si_flags & SI_NAMED) {
732 /*
733 * This is allowed as it removes races and generally
734 * simplifies cloning devices.
735 * XXX: still ??
736 */
737 dev_unlock_and_free();
738 return (dev);
739 }
740 KASSERT(!(dev->si_flags & SI_NAMED),
741 ("make_dev() by driver %s on pre-existing device (min=%x, name=%s)",
742 devsw->d_name, minor(dev), devtoname(dev)));
743
744 i = vsnrprintf(dev->__si_namebuf, sizeof dev->__si_namebuf, 32, fmt, ap);
745 if (i > (sizeof dev->__si_namebuf - 1)) {
746 printf("WARNING: Device name truncated! (%s)\n",
747 dev->__si_namebuf);
748 }
749
750 dev->si_flags |= SI_NAMED;
751 #ifdef MAC
752 if (cr != NULL)
753 dev->si_cred = crhold(cr);
754 else
755 #endif
756 dev->si_cred = NULL;
757 dev->si_uid = uid;
758 dev->si_gid = gid;
759 dev->si_mode = mode;
760
761 devfs_create(dev);
762 clean_unrhdrl(devfs_inos);
763 dev_unlock_and_free();
764
765 notify_create(dev);
766
767 return (dev);
768 }
769
770 struct cdev *
771 make_dev(struct cdevsw *devsw, int minornr, uid_t uid, gid_t gid, int mode,
772 const char *fmt, ...)
773 {
774 struct cdev *dev;
775 va_list ap;
776
777 va_start(ap, fmt);
778 dev = make_dev_credv(0, devsw, minornr, NULL, uid, gid, mode, fmt, ap);
779 va_end(ap);
780 return (dev);
781 }
782
783 struct cdev *
784 make_dev_cred(struct cdevsw *devsw, int minornr, struct ucred *cr, uid_t uid,
785 gid_t gid, int mode, const char *fmt, ...)
786 {
787 struct cdev *dev;
788 va_list ap;
789
790 va_start(ap, fmt);
791 dev = make_dev_credv(0, devsw, minornr, cr, uid, gid, mode, fmt, ap);
792 va_end(ap);
793
794 return (dev);
795 }
796
797 struct cdev *
798 make_dev_credf(int flags, struct cdevsw *devsw, int minornr,
799 struct ucred *cr, uid_t uid,
800 gid_t gid, int mode, const char *fmt, ...)
801 {
802 struct cdev *dev;
803 va_list ap;
804
805 va_start(ap, fmt);
806 dev = make_dev_credv(flags, devsw, minornr, cr, uid, gid, mode,
807 fmt, ap);
808 va_end(ap);
809
810 return (dev);
811 }
812
813 static void
814 dev_dependsl(struct cdev *pdev, struct cdev *cdev)
815 {
816
817 cdev->si_parent = pdev;
818 cdev->si_flags |= SI_CHILD;
819 LIST_INSERT_HEAD(&pdev->si_children, cdev, si_siblings);
820 }
821
822
823 void
824 dev_depends(struct cdev *pdev, struct cdev *cdev)
825 {
826
827 dev_lock();
828 dev_dependsl(pdev, cdev);
829 dev_unlock();
830 }
831
832 struct cdev *
833 make_dev_alias(struct cdev *pdev, const char *fmt, ...)
834 {
835 struct cdev *dev;
836 va_list ap;
837 int i;
838
839 KASSERT(pdev != NULL, ("NULL pdev"));
840 dev = devfs_alloc();
841 dev_lock();
842 dev->si_flags |= SI_ALIAS;
843 dev->si_flags |= SI_NAMED;
844 va_start(ap, fmt);
845 i = vsnrprintf(dev->__si_namebuf, sizeof dev->__si_namebuf, 32, fmt, ap);
846 if (i > (sizeof dev->__si_namebuf - 1)) {
847 printf("WARNING: Device name truncated! (%s)\n",
848 dev->__si_namebuf);
849 }
850 va_end(ap);
851
852 devfs_create(dev);
853 dev_dependsl(pdev, dev);
854 clean_unrhdrl(devfs_inos);
855 dev_unlock();
856
857 notify_create(dev);
858
859 return (dev);
860 }
861
862 static void
863 destroy_devl(struct cdev *dev)
864 {
865 struct cdevsw *csw;
866 struct cdev_privdata *p, *p1;
867
868 mtx_assert(&devmtx, MA_OWNED);
869 KASSERT(dev->si_flags & SI_NAMED,
870 ("WARNING: Driver mistake: destroy_dev on %d\n", minor(dev)));
871
872 devfs_destroy(dev);
873
874 /* Remove name marking */
875 dev->si_flags &= ~SI_NAMED;
876
877 /* If we are a child, remove us from the parents list */
878 if (dev->si_flags & SI_CHILD) {
879 LIST_REMOVE(dev, si_siblings);
880 dev->si_flags &= ~SI_CHILD;
881 }
882
883 /* Kill our children */
884 while (!LIST_EMPTY(&dev->si_children))
885 destroy_devl(LIST_FIRST(&dev->si_children));
886
887 /* Remove from clone list */
888 if (dev->si_flags & SI_CLONELIST) {
889 LIST_REMOVE(dev, si_clone);
890 dev->si_flags &= ~SI_CLONELIST;
891 }
892
893 dev->si_refcount++; /* Avoid race with dev_rel() */
894 csw = dev->si_devsw;
895 dev->si_devsw = NULL; /* already NULL for SI_ALIAS */
896 while (csw != NULL && csw->d_purge != NULL && dev->si_threadcount) {
897 csw->d_purge(dev);
898 msleep(csw, &devmtx, PRIBIO, "devprg", hz/10);
899 if (dev->si_threadcount)
900 printf("Still %lu threads in %s\n",
901 dev->si_threadcount, devtoname(dev));
902 }
903 while (dev->si_threadcount != 0) {
904 /* Use unique dummy wait ident */
905 msleep(&csw, &devmtx, PRIBIO, "devdrn", hz / 10);
906 }
907
908 dev_unlock();
909 notify_destroy(dev);
910 mtx_lock(&cdevpriv_mtx);
911 LIST_FOREACH_SAFE(p, &dev->si_priv->cdp_fdpriv, cdpd_list, p1) {
912 devfs_destroy_cdevpriv(p);
913 mtx_lock(&cdevpriv_mtx);
914 }
915 mtx_unlock(&cdevpriv_mtx);
916 dev_lock();
917
918 dev->si_drv1 = 0;
919 dev->si_drv2 = 0;
920 bzero(&dev->__si_u, sizeof(dev->__si_u));
921
922 if (!(dev->si_flags & SI_ALIAS)) {
923 /* Remove from cdevsw list */
924 LIST_REMOVE(dev, si_list);
925
926 /* If cdevsw has no more struct cdev *'s, clean it */
927 if (LIST_EMPTY(&csw->d_devs)) {
928 fini_cdevsw(csw);
929 wakeup(&csw->d_devs);
930 }
931 }
932 dev->si_flags &= ~SI_ALIAS;
933 dev->si_refcount--; /* Avoid race with dev_rel() */
934
935 if (dev->si_refcount > 0) {
936 LIST_INSERT_HEAD(&dead_cdevsw.d_devs, dev, si_list);
937 } else {
938 dev_free_devlocked(dev);
939 }
940 }
941
942 void
943 destroy_dev(struct cdev *dev)
944 {
945
946 dev_lock();
947 destroy_devl(dev);
948 dev_unlock_and_free();
949 }
950
951 const char *
952 devtoname(struct cdev *dev)
953 {
954 char *p;
955 struct cdevsw *csw;
956 int mynor;
957
958 if (dev->si_name[0] == '#' || dev->si_name[0] == '\0') {
959 p = dev->si_name;
960 csw = dev_refthread(dev);
961 if (csw != NULL) {
962 sprintf(p, "(%s)", csw->d_name);
963 dev_relthread(dev);
964 }
965 p += strlen(p);
966 mynor = minor(dev);
967 if (mynor < 0 || mynor > 255)
968 sprintf(p, "/%#x", (u_int)mynor);
969 else
970 sprintf(p, "/%d", mynor);
971 }
972 return (dev->si_name);
973 }
974
975 int
976 dev_stdclone(char *name, char **namep, const char *stem, int *unit)
977 {
978 int u, i;
979
980 i = strlen(stem);
981 if (bcmp(stem, name, i) != 0)
982 return (0);
983 if (!isdigit(name[i]))
984 return (0);
985 u = 0;
986 if (name[i] == '' && isdigit(name[i+1]))
987 return (0);
988 while (isdigit(name[i])) {
989 u *= 10;
990 u += name[i++] - '';
991 }
992 if (u > 0xffffff)
993 return (0);
994 *unit = u;
995 if (namep)
996 *namep = &name[i];
997 if (name[i])
998 return (2);
999 return (1);
1000 }
1001
1002 /*
1003 * Helper functions for cloning device drivers.
1004 *
1005 * The objective here is to make it unnecessary for the device drivers to
1006 * use rman or similar to manage their unit number space. Due to the way
1007 * we do "on-demand" devices, using rman or other "private" methods
1008 * will be very tricky to lock down properly once we lock down this file.
1009 *
1010 * Instead we give the drivers these routines which puts the struct cdev *'s
1011 * that are to be managed on their own list, and gives the driver the ability
1012 * to ask for the first free unit number or a given specified unit number.
1013 *
1014 * In addition these routines support paired devices (pty, nmdm and similar)
1015 * by respecting a number of "flag" bits in the minor number.
1016 *
1017 */
1018
1019 struct clonedevs {
1020 LIST_HEAD(,cdev) head;
1021 };
1022
1023 void
1024 clone_setup(struct clonedevs **cdp)
1025 {
1026
1027 *cdp = malloc(sizeof **cdp, M_DEVBUF, M_WAITOK | M_ZERO);
1028 LIST_INIT(&(*cdp)->head);
1029 }
1030
1031 int
1032 clone_create(struct clonedevs **cdp, struct cdevsw *csw, int *up, struct cdev **dp, int extra)
1033 {
1034 struct clonedevs *cd;
1035 struct cdev *dev, *ndev, *dl, *de;
1036 int unit, low, u;
1037
1038 KASSERT(*cdp != NULL,
1039 ("clone_setup() not called in driver \"%s\"", csw->d_name));
1040 KASSERT(!(extra & CLONE_UNITMASK),
1041 ("Illegal extra bits (0x%x) in clone_create", extra));
1042 KASSERT(*up <= CLONE_UNITMASK,
1043 ("Too high unit (0x%x) in clone_create", *up));
1044
1045
1046 /*
1047 * Search the list for a lot of things in one go:
1048 * A preexisting match is returned immediately.
1049 * The lowest free unit number if we are passed -1, and the place
1050 * in the list where we should insert that new element.
1051 * The place to insert a specified unit number, if applicable
1052 * the end of the list.
1053 */
1054 unit = *up;
1055 ndev = devfs_alloc();
1056 dev_lock();
1057 prep_cdevsw(csw);
1058 low = extra;
1059 de = dl = NULL;
1060 cd = *cdp;
1061 LIST_FOREACH(dev, &cd->head, si_clone) {
1062 KASSERT(dev->si_flags & SI_CLONELIST,
1063 ("Dev %p(%s) should be on clonelist", dev, dev->si_name));
1064 u = dev2unit(dev);
1065 if (u == (unit | extra)) {
1066 *dp = dev;
1067 dev_unlock();
1068 devfs_free(ndev);
1069 return (0);
1070 }
1071 if (unit == -1 && u == low) {
1072 low++;
1073 de = dev;
1074 continue;
1075 } else if (u < (unit | extra)) {
1076 de = dev;
1077 continue;
1078 } else if (u > (unit | extra)) {
1079 dl = dev;
1080 break;
1081 }
1082 }
1083 if (unit == -1)
1084 unit = low & CLONE_UNITMASK;
1085 dev = newdev(csw, unit2minor(unit | extra), ndev);
1086 if (dev->si_flags & SI_CLONELIST) {
1087 printf("dev %p (%s) is on clonelist\n", dev, dev->si_name);
1088 printf("unit=%d, low=%d, extra=0x%x\n", unit, low, extra);
1089 LIST_FOREACH(dev, &cd->head, si_clone) {
1090 printf("\t%p %s\n", dev, dev->si_name);
1091 }
1092 panic("foo");
1093 }
1094 KASSERT(!(dev->si_flags & SI_CLONELIST),
1095 ("Dev %p(%s) should not be on clonelist", dev, dev->si_name));
1096 if (dl != NULL)
1097 LIST_INSERT_BEFORE(dl, dev, si_clone);
1098 else if (de != NULL)
1099 LIST_INSERT_AFTER(de, dev, si_clone);
1100 else
1101 LIST_INSERT_HEAD(&cd->head, dev, si_clone);
1102 dev->si_flags |= SI_CLONELIST;
1103 *up = unit;
1104 dev_unlock_and_free();
1105 return (1);
1106 }
1107
1108 /*
1109 * Kill everything still on the list. The driver should already have
1110 * disposed of any softc hung of the struct cdev *'s at this time.
1111 */
1112 void
1113 clone_cleanup(struct clonedevs **cdp)
1114 {
1115 struct cdev *dev;
1116 struct cdev_priv *cp;
1117 struct clonedevs *cd;
1118
1119 cd = *cdp;
1120 if (cd == NULL)
1121 return;
1122 dev_lock();
1123 while (!LIST_EMPTY(&cd->head)) {
1124 dev = LIST_FIRST(&cd->head);
1125 LIST_REMOVE(dev, si_clone);
1126 KASSERT(dev->si_flags & SI_CLONELIST,
1127 ("Dev %p(%s) should be on clonelist", dev, dev->si_name));
1128 dev->si_flags &= ~SI_CLONELIST;
1129 cp = dev->si_priv;
1130 if (!(cp->cdp_flags & CDP_SCHED_DTR)) {
1131 cp->cdp_flags |= CDP_SCHED_DTR;
1132 KASSERT(dev->si_flags & SI_NAMED,
1133 ("Driver has goofed in cloning underways udev %x", dev->si_drv0));
1134 destroy_devl(dev);
1135 }
1136 }
1137 dev_unlock_and_free();
1138 free(cd, M_DEVBUF);
1139 *cdp = NULL;
1140 }
1141
1142 static TAILQ_HEAD(, cdev_priv) dev_ddtr =
1143 TAILQ_HEAD_INITIALIZER(dev_ddtr);
1144 static struct task dev_dtr_task;
1145
1146 static void
1147 destroy_dev_tq(void *ctx, int pending)
1148 {
1149 struct cdev_priv *cp;
1150 struct cdev *dev;
1151 void (*cb)(void *);
1152 void *cb_arg;
1153
1154 dev_lock();
1155 while (!TAILQ_EMPTY(&dev_ddtr)) {
1156 cp = TAILQ_FIRST(&dev_ddtr);
1157 dev = &cp->cdp_c;
1158 KASSERT(cp->cdp_flags & CDP_SCHED_DTR,
1159 ("cdev %p in dev_destroy_tq without CDP_SCHED_DTR", cp));
1160 TAILQ_REMOVE(&dev_ddtr, cp, cdp_dtr_list);
1161 cb = cp->cdp_dtr_cb;
1162 cb_arg = cp->cdp_dtr_cb_arg;
1163 destroy_devl(dev);
1164 dev_unlock_and_free();
1165 dev_rel(dev);
1166 if (cb != NULL)
1167 cb(cb_arg);
1168 dev_lock();
1169 }
1170 dev_unlock();
1171 }
1172
1173 /*
1174 * devmtx shall be locked on entry. devmtx will be unlocked after
1175 * function return.
1176 */
1177 static int
1178 destroy_dev_sched_cbl(struct cdev *dev, void (*cb)(void *), void *arg)
1179 {
1180 struct cdev_priv *cp;
1181
1182 mtx_assert(&devmtx, MA_OWNED);
1183 cp = dev->si_priv;
1184 if (cp->cdp_flags & CDP_SCHED_DTR) {
1185 dev_unlock();
1186 return (0);
1187 }
1188 dev_refl(dev);
1189 cp->cdp_flags |= CDP_SCHED_DTR;
1190 cp->cdp_dtr_cb = cb;
1191 cp->cdp_dtr_cb_arg = arg;
1192 TAILQ_INSERT_TAIL(&dev_ddtr, cp, cdp_dtr_list);
1193 dev_unlock();
1194 taskqueue_enqueue(taskqueue_swi_giant, &dev_dtr_task);
1195 return (1);
1196 }
1197
1198 int
1199 destroy_dev_sched_cb(struct cdev *dev, void (*cb)(void *), void *arg)
1200 {
1201 dev_lock();
1202 return (destroy_dev_sched_cbl(dev, cb, arg));
1203 }
1204
1205 int
1206 destroy_dev_sched(struct cdev *dev)
1207 {
1208 return (destroy_dev_sched_cb(dev, NULL, NULL));
1209 }
1210
1211 void
1212 destroy_dev_drain(struct cdevsw *csw)
1213 {
1214
1215 dev_lock();
1216 while (!LIST_EMPTY(&csw->d_devs)) {
1217 msleep(&csw->d_devs, &devmtx, PRIBIO, "devscd", hz/10);
1218 }
1219 dev_unlock();
1220 }
1221
1222 void
1223 drain_dev_clone_events(void)
1224 {
1225
1226 sx_xlock(&clone_drain_lock);
1227 sx_xunlock(&clone_drain_lock);
1228 }
1229
1230 static void
1231 devdtr_init(void *dummy __unused)
1232 {
1233
1234 TASK_INIT(&dev_dtr_task, 0, destroy_dev_tq, NULL);
1235 }
1236
1237 SYSINIT(devdtr, SI_SUB_DEVFS, SI_ORDER_SECOND, devdtr_init, NULL);
Cache object: 7c175d2c2ed6d0850470138ed4866499
|