svn commit: r183750 - head/sys/kern

Warner Losh imp at FreeBSD.org
Fri Oct 10 17:49:47 UTC 2008


Author: imp
Date: Fri Oct 10 17:49:47 2008
New Revision: 183750
URL: http://svn.freebsd.org/changeset/base/183750

Log:
  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.

Modified:
  head/sys/kern/subr_bus.c

Modified: head/sys/kern/subr_bus.c
==============================================================================
--- head/sys/kern/subr_bus.c	Fri Oct 10 17:48:39 2008	(r183749)
+++ head/sys/kern/subr_bus.c	Fri Oct 10 17:49:47 2008	(r183750)
@@ -1344,20 +1344,22 @@ devclass_alloc_unit(devclass_t dc, int *
 	 * 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)));
 


More information about the svn-src-head mailing list