[PATCH] imalloc supersets

John Rose johnrose at austin.ibm.com
Fri Jul 23 06:36:41 EST 2004


My first patch  left out a change to pgtable.h.  My apologies, attached
is the corrected patch.  So, anyone have thoughts on this? :)

Thanks-
John

diff -X /home/johnrose/tmp/diffignore.txt -urpN sles9-rc5-vanilla/arch/ppc64/mm/imalloc.c sles9-rc5-sav/arch/ppc64/mm/imalloc.c
--- sles9-rc5-vanilla/arch/ppc64/mm/imalloc.c	2004-07-16 16:11:54.000000000 -0500
+++ sles9-rc5-sav/arch/ppc64/mm/imalloc.c	2004-07-22 15:08:55.000000000 -0500
@@ -37,33 +37,51 @@ static int get_free_im_addr(unsigned lon
 	return 0;
 }

+/* Return whether the region described by v_addr and size is a subset
+ * of the region described by parent
+ */
+static inline int im_region_is_subset(unsigned long v_addr, unsigned long size,
+			struct vm_struct *parent)
+{
+	return (int) (v_addr >= (unsigned long) parent->addr &&
+	              v_addr < (unsigned long) parent->addr + parent->size &&
+	    	      size < parent->size);
+}
+
+/* Return whether the region described by v_addr and size is a superset
+ * of the region described by child
+ */
+static int im_region_is_superset(unsigned long v_addr, unsigned long size,
+		struct vm_struct *child)
+{
+	struct vm_struct parent;
+
+	parent.addr = (void *) v_addr;
+	parent.size = size;
+
+	return im_region_is_subset((unsigned long) child->addr, child->size,
+			&parent);
+}
+
 /* Return whether the region described by v_addr and size overlaps
  * the region described by vm.  Overlapping regions meet the
  * following conditions:
  * 1) The regions share some part of the address space
  * 2) The regions aren't identical
- * 3) The first region is not a subset of the second
+ * 3) Neither region is a subset of the other
  */
-static inline int im_region_overlaps(unsigned long v_addr, unsigned long size,
+static int im_region_overlaps(unsigned long v_addr, unsigned long size,
 		     struct vm_struct *vm)
 {
+	if (im_region_is_superset(v_addr, size, vm))
+		return 0;
+
 	return (v_addr + size > (unsigned long) vm->addr + vm->size &&
 		v_addr < (unsigned long) vm->addr + vm->size) ||
 	       (v_addr < (unsigned long) vm->addr &&
 		v_addr + size > (unsigned long) vm->addr);
 }

-/* Return whether the region described by v_addr and size is a subset
- * of the region described by vm
- */
-static inline int im_region_is_subset(unsigned long v_addr, unsigned long size,
-			struct vm_struct *vm)
-{
-	return (int) (v_addr >= (unsigned long) vm->addr &&
-	              v_addr < (unsigned long) vm->addr + vm->size &&
-	    	      size < vm->size);
-}
-
 /* Determine imalloc status of region described by v_addr and size.
  * Can return one of the following:
  * IM_REGION_UNUSED   -  Entire region is unallocated in imalloc space.
@@ -73,28 +91,37 @@ static inline int im_region_is_subset(un
  * IM_REGION_EXISTS -    Exact region already allocated in imalloc space.
  *                       vm will be assigned to a ptr to the existing imlist
  *                       member.
- * IM_REGION_OVERLAPS -  A portion of the region is already allocated in
- *                       imalloc space.
+ * IM_REGION_OVERLAPS -  Region overlaps an allocated region in imalloc space.
+ * IM_REGION_SUPERSET -  Region is a superset of a region that is already
+ *                       allocated in imalloc space.
  */
 static int im_region_status(unsigned long v_addr, unsigned long size,
 		    struct vm_struct **vm)
 {
 	struct vm_struct *tmp;

-	for (tmp = imlist; tmp; tmp = tmp->next)
-		if (v_addr < (unsigned long) tmp->addr + tmp->size)
+	for (tmp = imlist; tmp; tmp = tmp->next)
+		if (v_addr < (unsigned long) tmp->addr + tmp->size)
 			break;
-
+
 	if (tmp) {
 		if (im_region_overlaps(v_addr, size, tmp))
 			return IM_REGION_OVERLAP;

 		*vm = tmp;
-		if (im_region_is_subset(v_addr, size, tmp))
+		if (im_region_is_subset(v_addr, size, tmp)) {
+			/* Return with tmp pointing to superset */
 			return IM_REGION_SUBSET;
+		}
+		if (im_region_is_superset(v_addr, size, tmp)) {
+			/* Return with tmp pointing to first subset */
+			return IM_REGION_SUPERSET;
+		}
 		else if (v_addr == (unsigned long) tmp->addr &&
-		 	 size == tmp->size)
+		 	 size == tmp->size) {
+			/* Return with tmp pointing to exact region */
 			return IM_REGION_EXISTS;
+		}
 	}

 	*vm = NULL;
@@ -208,6 +235,10 @@ static struct vm_struct * __im_get_area(
 		tmp = split_im_region(req_addr, size, tmp);
 		break;
 	case IM_REGION_EXISTS:
+		/* Return requested region */
+		break;
+	case IM_REGION_SUPERSET:
+		/* Return first existing subset of requested region */
 		break;
 	default:
 		printk(KERN_ERR "%s() unexpected imalloc region status\n",
diff -X /home/johnrose/tmp/diffignore.txt -urpN sles9-rc5-vanilla/arch/ppc64/mm/init.c sles9-rc5-sav/arch/ppc64/mm/init.c
--- sles9-rc5-vanilla/arch/ppc64/mm/init.c	2004-07-16 16:11:54.000000000 -0500
+++ sles9-rc5-sav/arch/ppc64/mm/init.c	2004-07-22 15:17:56.000000000 -0500
@@ -392,9 +392,28 @@ void iounmap(void *addr)
 	return;
 }

+static int iounmap_subset_regions(void *addr, unsigned long size)
+{
+	struct vm_struct *area;
+
+	/* Check whether subsets of this region exist */
+	area = im_get_area((unsigned long) addr, size, IM_REGION_SUPERSET);
+	if (area == NULL)
+		return 1;
+
+	while (area) {
+		iounmap(area->addr);
+		area = im_get_area((unsigned long) addr, size,
+				IM_REGION_SUPERSET);
+	}
+
+	return 0;
+}
+
 int iounmap_explicit(void *addr, unsigned long size)
 {
 	struct vm_struct *area;
+	int rc;

 	/* addr could be in EEH or IO region, map it to IO region regardless.
 	 */
@@ -407,12 +426,18 @@ int iounmap_explicit(void *addr, unsigne
 	area = im_get_area((unsigned long) addr, size,
 			    IM_REGION_EXISTS | IM_REGION_SUBSET);
 	if (area == NULL) {
-		printk(KERN_ERR "%s() cannot unmap nonexistant range 0x%lx\n",
-				__FUNCTION__, (unsigned long) addr);
-		return 1;
+		/* Determine whether subset regions exist.  If so, unmap */
+		rc = iounmap_subset_regions(addr, size);
+		if (rc) {
+			printk(KERN_ERR
+			       "%s() cannot unmap nonexistant range 0x%lx\n",
+ 				__FUNCTION__, (unsigned long) addr);
+			return 1;
+		}
+	} else {
+		iounmap(area->addr);
 	}

-	iounmap(area->addr);
 	return 0;
 }

diff -X /home/johnrose/tmp/diffignore.txt -urpN sles9-rc5-vanilla/include/asm-ppc64/pgtable.h sles9-rc5-sav/include/asm-ppc64/pgtable.h
--- sles9-rc5-vanilla/include/asm-ppc64/pgtable.h	2004-07-16 16:12:00.000000000 -0500
+++ sles9-rc5-sav/include/asm-ppc64/pgtable.h	2004-07-22 15:09:35.000000000 -0500
@@ -467,6 +467,7 @@ extern void hpte_init_iSeries(void);
 #define IM_REGION_SUBSET	0x2
 #define IM_REGION_EXISTS	0x4
 #define IM_REGION_OVERLAP	0x8
+#define IM_REGION_SUPERSET	0x10

 extern struct vm_struct * im_get_free_area(unsigned long size);
 extern struct vm_struct * im_get_area(unsigned long v_addr, unsigned long size,

On Mon, 2004-07-19 at 13:30, John Rose wrote:
> The patch below implements the ability to query outstanding imalloc regions for
> a given virtual address range.  The patch extends im_get_area() to allow a
> region criterion of IM_REGION_SUPERSET.  For a particular "superset" virtual
> address and size passed into im_get_area(), the function returns the first
> outstanding region that is contained within this superset region.
>
> The patch also changes iounmap_explicit() to allow for the unmapping of all
> regions that fit under a "supserset".
>
> This ability is necessary for PHB DLPAR.  For a PHB removal, the RPA requires
> that all of its children slots already be dynamically removed.  Each of these
> slot-level removals has fractured the imalloc region assigned to the PHB at
> boot.  At PHB removal time, it is necessary to iounmap() the remaining
> artifacts of the initial PHB region.
>
> Thanks-
> John
>
> Signed-off-by:  John Rose <johnrose at austin.ibm.com>


** Sent via the linuxppc64-dev mail list. See http://lists.linuxppc.org/





More information about the Linuxppc64-dev mailing list