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 | |
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.
-rw-r--r-- | sys/kern/kern_conf.c | 28 | ||||
-rw-r--r-- | sys/sys/conf.h | 4 |
2 files changed, 21 insertions, 11 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 { diff --git a/sys/sys/conf.h b/sys/sys/conf.h index e416e1b..33a2f70 100644 --- a/sys/sys/conf.h +++ b/sys/sys/conf.h @@ -149,8 +149,8 @@ typedef int d_poll_t(struct cdev *dev, int events, struct thread *td); typedef int d_kqfilter_t(struct cdev *dev, struct knote *kn); typedef int d_mmap_t(struct cdev *dev, vm_offset_t offset, vm_paddr_t *paddr, int nprot); +typedef void d_purge_t(struct cdev *dev); -typedef int d_spare1_t(struct cdev *dev); typedef int d_spare2_t(struct cdev *dev); typedef int dumper_t( @@ -214,7 +214,7 @@ struct cdevsw { d_strategy_t *d_strategy; dumper_t *d_dump; d_kqfilter_t *d_kqfilter; - d_spare1_t *d_spare1; + d_purge_t *d_purge; d_spare2_t *d_spare2; /* These fields should not be messed with by drivers */ |