kern/162174: [patch] rman_manage_region() error return path leaves mutex locked

Ian Lepore freebsd at damnhippie.dyndns.org
Sun Oct 30 19:50:11 UTC 2011


>Number:         162174
>Category:       kern
>Synopsis:       [patch] rman_manage_region() error return path leaves mutex locked
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Sun Oct 30 19:50:11 UTC 2011
>Closed-Date:
>Last-Modified:
>Originator:     Ian Lepore <freebsd at damnhippie.dyndns.org>
>Release:        FreeBSD 8.2-STABLE
>Organization:
Symmetricom, Inc.
>Environment:
FreeBSD tflex 8.2-STABLE FreeBSD 8.2-STABLE #29: Tue Oct 11 13:32:35 UTC 2011     root at revolution.hippie.lan:/usr/obj/arm/usr/src/sys/TFLEX  arm

>Description:
If rman_manage_region() detects an overlapping region and returns EBUSY it
leaves the rman mutex locked, causing a panic on some future rman call.

>How-To-Repeat:

>Fix:
This patch was generated against 8.2-STABLE but applies cleanly to -current.
The error handling idiom in this module seems to be the "goto out" style so
I did this same way.

--- kern_subr.diff begins here ---
diff -r 96e180d3dc91 sys/kern/subr_rman.c
--- sys/kern/subr_rman.c.orig	Sat Oct 29 17:47:07 2011 -0600
+++ sys/kern/subr_rman.c	Sun Oct 30 13:23:14 2011 -0600
@@ -158,6 +158,7 @@ rman_init(struct rman *rm)
 int
 rman_manage_region(struct rman *rm, u_long start, u_long end)
 {
+	int rv;
 	struct resource_i *r, *s, *t;
 
 	DPRINTF(("rman_manage_region: <%s> request: start %#lx, end %#lx\n",
@@ -184,14 +185,16 @@ rman_manage_region(struct rman *rm, u_lo
 		TAILQ_INSERT_TAIL(&rm->rm_list, r, r_link);
 	} else {
 		/* Check for any overlap with the current region. */
-		if (r->r_start <= s->r_end && r->r_end >= s->r_start)
-			return EBUSY;
-
+		if (r->r_start <= s->r_end && r->r_end >= s->r_start) {
+			rv = EBUSY;
+			goto out;
+		}
 		/* Check for any overlap with the next region. */
 		t = TAILQ_NEXT(s, r_link);
-		if (t && r->r_start <= t->r_end && r->r_end >= t->r_start)
-			return EBUSY;
-
+		if (t && r->r_start <= t->r_end && r->r_end >= t->r_start) {
+			rv = EBUSY;
+			goto out;
+		}
 		/*
 		 * See if this region can be merged with the next region.  If
 		 * not, clear the pointer.
@@ -222,8 +225,10 @@ rman_manage_region(struct rman *rm, u_lo
 		}
 	}
 
+	rv = 0;
+out:
 	mtx_unlock(rm->rm_mtx);
-	return 0;
+	return (rv);
 }
 
 int
--- kern_subr.diff ends here ---

>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-bugs mailing list