summaryrefslogtreecommitdiffstats
path: root/sys/kern/subr_bus.c
diff options
context:
space:
mode:
authorimp <imp@FreeBSD.org>2008-10-10 17:49:47 +0000
committerimp <imp@FreeBSD.org>2008-10-10 17:49:47 +0000
commit793aee6634d7f8e1b53e354aaefabfad9981766a (patch)
tree9aac7ea9882577b384d8479cf20be73d28d0a1c8 /sys/kern/subr_bus.c
parentd24475776ed80afe8823e0b39730ffbd59d5815f (diff)
downloadFreeBSD-src-793aee6634d7f8e1b53e354aaefabfad9981766a.zip
FreeBSD-src-793aee6634d7f8e1b53e354aaefabfad9981766a.tar.gz
Close, but not eliminate, a race condition. It is one that properly
designed drivers would never hit, but was exposed in diving into another problem... When expanding the devclass array, free the old memory after updating the pointer to the new memory. For the following single race case, this helps: allocate new memory copy to new memory free old memory <interrupt> read pointer to freed memory update pointer to new memory Now we do allocate new memory copy to new memory update pointer to new memory free old memory Which closes this problem, but doesn't even begin to address the multicpu races, which all should be covered by Giant at the moment, but likely aren't completely. Note: reviewers were ok with this fix, but suggested the use case wasn't one we wanted to encourage. Reviewed by: jhb, scottl.
Diffstat (limited to 'sys/kern/subr_bus.c')
-rw-r--r--sys/kern/subr_bus.c10
1 files changed, 6 insertions, 4 deletions
diff --git a/sys/kern/subr_bus.c b/sys/kern/subr_bus.c
index c623ce2..d7a7366 100644
--- a/sys/kern/subr_bus.c
+++ b/sys/kern/subr_bus.c
@@ -1344,20 +1344,22 @@ devclass_alloc_unit(devclass_t dc, int *unitp)
* this one.
*/
if (unit >= dc->maxunit) {
- device_t *newlist;
+ device_t *newlist, *oldlist;
int newsize;
+ oldlist = dc->devices;
newsize = roundup((unit + 1), MINALLOCSIZE / sizeof(device_t));
newlist = malloc(sizeof(device_t) * newsize, M_BUS, M_NOWAIT);
if (!newlist)
return (ENOMEM);
- bcopy(dc->devices, newlist, sizeof(device_t) * dc->maxunit);
+ if (oldlist != NULL)
+ bcopy(oldlist, newlist, sizeof(device_t) * dc->maxunit);
bzero(newlist + dc->maxunit,
sizeof(device_t) * (newsize - dc->maxunit));
- if (dc->devices)
- free(dc->devices, M_BUS);
dc->devices = newlist;
dc->maxunit = newsize;
+ if (oldlist != NULL)
+ free(oldlist, M_BUS);
}
PDEBUG(("now: unit %d in devclass %s", unit, DEVCLANAME(dc)));
OpenPOWER on IntegriCloud