diff options
author | tegge <tegge@FreeBSD.org> | 2006-10-13 20:49:24 +0000 |
---|---|---|
committer | tegge <tegge@FreeBSD.org> | 2006-10-13 20:49:24 +0000 |
commit | 2d3b850cd60db622cf6958fb4cba363a0a3de593 (patch) | |
tree | fc4123f2291afc14d5075983505de4a238530282 /sys/kern/kern_conf.c | |
parent | c43e76ed8f5f00cf09f56e789a59c5db791dbd49 (diff) | |
download | FreeBSD-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.
Diffstat (limited to 'sys/kern/kern_conf.c')
-rw-r--r-- | sys/kern/kern_conf.c | 6 |
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); |