diff options
author | phk <phk@FreeBSD.org> | 2004-09-27 06:18:25 +0000 |
---|---|---|
committer | phk <phk@FreeBSD.org> | 2004-09-27 06:18:25 +0000 |
commit | 27fb35d0b1b0865d3bafca2fdf1f22dd3e601a2b (patch) | |
tree | 85546e20562f0bf79d61025a6e3279bc11a5ab78 /sys/kern/kern_conf.c | |
parent | cbad2b873c5a42edafe4684eecaf02026ffd487a (diff) | |
download | FreeBSD-src-27fb35d0b1b0865d3bafca2fdf1f22dd3e601a2b.zip FreeBSD-src-27fb35d0b1b0865d3bafca2fdf1f22dd3e601a2b.tar.gz |
Add cdevsw->d_purge() support.
This device method shall wake up any threads sleeping in the device driver
and make the depart the drivers code for good.
Diffstat (limited to 'sys/kern/kern_conf.c')
-rw-r--r-- | sys/kern/kern_conf.c | 28 |
1 files changed, 19 insertions, 9 deletions
diff --git a/sys/kern/kern_conf.c b/sys/kern/kern_conf.c index 770f4b6..65eb9e8 100644 --- a/sys/kern/kern_conf.c +++ b/sys/kern/kern_conf.c @@ -551,11 +551,11 @@ make_dev_alias(struct cdev *pdev, const char *fmt, ...) static void idestroy_dev(struct cdev *dev) { - if (!(dev->si_flags & SI_NAMED)) { - printf( "WARNING: Driver mistake: destroy_dev on %d/%d\n", - major(dev), minor(dev)); - panic("don't do that"); - } + struct cdevsw *csw; + + KASSERT(dev->si_flags & SI_NAMED, + ("WARNING: Driver mistake: destroy_dev on %d/%d\n", + major(dev), minor(dev))); devfs_destroy(dev); @@ -578,6 +578,19 @@ idestroy_dev(struct cdev *dev) dev->si_flags &= ~SI_CLONELIST; } + csw = dev->si_devsw; + dev->si_devsw = NULL; + while (csw->d_purge != NULL && dev->si_threadcount) { + printf("Purging %lu threads from %s\n", + dev->si_threadcount, devtoname(dev)); + csw->d_purge(dev); + msleep(csw, &devmtx, PRIBIO, "devprg", hz/10); + } + + dev->si_drv1 = 0; + dev->si_drv2 = 0; + bzero(&dev->__si_u, sizeof(dev->__si_u)); + if (!(dev->si_flags & SI_ALIAS)) { /* Remove from cdevsw list */ LIST_REMOVE(dev, si_list); @@ -588,11 +601,8 @@ idestroy_dev(struct cdev *dev) LIST_REMOVE(dev, si_hash); } - dev->si_drv1 = 0; - dev->si_drv2 = 0; - dev->si_devsw = NULL; - bzero(&dev->__si_u, sizeof(dev->__si_u)); dev->si_flags &= ~SI_ALIAS; + if (dev->si_refcount > 0) { LIST_INSERT_HEAD(&dead_cdevsw.d_devs, dev, si_list); } else { |