[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