summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorphk <phk@FreeBSD.org>2004-09-27 06:18:25 +0000
committerphk <phk@FreeBSD.org>2004-09-27 06:18:25 +0000
commit27fb35d0b1b0865d3bafca2fdf1f22dd3e601a2b (patch)
tree85546e20562f0bf79d61025a6e3279bc11a5ab78
parentcbad2b873c5a42edafe4684eecaf02026ffd487a (diff)
downloadFreeBSD-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.c28
-rw-r--r--sys/sys/conf.h4
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 */
OpenPOWER on IntegriCloud