summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authortegge <tegge@FreeBSD.org>2006-10-13 20:49:24 +0000
committertegge <tegge@FreeBSD.org>2006-10-13 20:49:24 +0000
commit2d3b850cd60db622cf6958fb4cba363a0a3de593 (patch)
treefc4123f2291afc14d5075983505de4a238530282
parentc43e76ed8f5f00cf09f56e789a59c5db791dbd49 (diff)
downloadFreeBSD-src-2d3b850cd60db622cf6958fb4cba363a0a3de593.zip
FreeBSD-src-2d3b850cd60db622cf6958fb4cba363a0a3de593.tar.gz
Wait for thread count to reach zero in destroy_devl() even when no purge
method is defined, to avoid memory being modified after free. Temporarily increase refcount in destroy_devl() to avoid a double free if dev_rel() is called while waiting for thread count to reach zero.
-rw-r--r--sys/kern/kern_conf.c6
1 files changed, 6 insertions, 0 deletions
diff --git a/sys/kern/kern_conf.c b/sys/kern/kern_conf.c
index 9987063..d331d53 100644
--- a/sys/kern/kern_conf.c
+++ b/sys/kern/kern_conf.c
@@ -658,6 +658,7 @@ destroy_devl(struct cdev *dev)
dev->si_flags &= ~SI_CLONELIST;
}
+ dev->si_refcount++; /* Avoid race with dev_rel() */
csw = dev->si_devsw;
dev->si_devsw = NULL; /* already NULL for SI_ALIAS */
while (csw != NULL && csw->d_purge != NULL && dev->si_threadcount) {
@@ -667,6 +668,10 @@ destroy_devl(struct cdev *dev)
printf("Still %lu threads in %s\n",
dev->si_threadcount, devtoname(dev));
}
+ while (dev->si_threadcount != 0) {
+ /* Use unique dummy wait ident */
+ msleep(&csw, &devmtx, PRIBIO, "devdrn", hz / 10);
+ }
dev->si_drv1 = 0;
dev->si_drv2 = 0;
@@ -681,6 +686,7 @@ destroy_devl(struct cdev *dev)
fini_cdevsw(csw);
}
dev->si_flags &= ~SI_ALIAS;
+ dev->si_refcount--; /* Avoid race with dev_rel() */
if (dev->si_refcount > 0) {
LIST_INSERT_HEAD(&dead_cdevsw.d_devs, dev, si_list);
OpenPOWER on IntegriCloud