summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/kern/subr_extent.c35
1 files changed, 26 insertions, 9 deletions
diff --git a/sys/kern/subr_extent.c b/sys/kern/subr_extent.c
index 092d0c66c45..b36408e4ee0 100644
--- a/sys/kern/subr_extent.c
+++ b/sys/kern/subr_extent.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: subr_extent.c,v 1.39 2009/06/09 19:16:39 oga Exp $ */
+/* $OpenBSD: subr_extent.c,v 1.40 2009/09/18 22:16:28 kettenis Exp $ */
/* $NetBSD: subr_extent.c,v 1.7 1996/11/21 18:46:34 cgd Exp $ */
/*-
@@ -499,26 +499,43 @@ extent_alloc_region(struct extent *ex, u_long start, u_long size, int flags)
*/
if (flags & EX_CONFLICTOK) {
/*
- * There are two possibilities:
+ * There are four possibilities:
*
- * 1. The current region overlaps.
+ * 1. The current region overlaps with
+ * the start of the requested region.
* Adjust the requested region to
* start at the end of the current
- * region, and try again.
+ * region and try again.
*
* 2. The current region falls
- * completely within the requested
- * region. Free the current region
- * and try again.
+ * completely within the requested
+ * region. Free the current region
+ * and try again.
+ *
+ * 3. The current region overlaps with
+ * the end of the requested region.
+ * Adjust the requested region to
+ * end at the start of the current
+ * region and try again.
+ *
+ * 4. The requested region falls
+ * completely within the current
+ * region. We're done.
*/
if (rp->er_start <= start) {
start = rp->er_end + 1;
size = end - start + 1;
- } else {
+ goto alloc_start;
+ } else if (rp->er_end < end) {
LIST_REMOVE(rp, er_link);
extent_free_region_descriptor(ex, rp);
+ goto alloc_start;
+ } else if (rp->er_start < end) {
+ end = rp->er_start - 1;
+ size = end - start + 1;
+ goto alloc_start;
}
- goto alloc_start;
+ return (0);
}
extent_free_region_descriptor(ex, myrp);