[PATCH 05/29] lmb: Add lmb_reserve_area/lmb_free_area

From: Yinghai Lu
Date: Tue Mar 30 2010 - 07:22:40 EST


They will check if the region array is big enough.

__check_and_double_region_array will try to double the region if that array
spare slots is not big enough.
Old array will be copied to new array.

Arch code should update lmb.default_alloc_limit, so the new array have
accessiable address

-v2: change get_max_mapped() to lmb.default_alloc_limit according to Michael Ellerman and Ben
change to lmb_reserve_area and lmb_free_area according to Michael Ellerman
-v3: call check_and_double after reserve/free, so could avoid to use fin_lmb_area. Suggested by
Michael Ellerman

Signed-off-by: Yinghai Lu <yinghai@xxxxxxxxxx>
---
include/linux/lmb.h | 4 +++
mm/lmb.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 70 insertions(+), 0 deletions(-)

diff --git a/include/linux/lmb.h b/include/linux/lmb.h
index 4cf2f3b..598662f 100644
--- a/include/linux/lmb.h
+++ b/include/linux/lmb.h
@@ -33,6 +33,7 @@ struct lmb_region {
struct lmb {
unsigned long debug;
u64 rmo_size;
+ u64 default_alloc_limit;
struct lmb_region memory;
struct lmb_region reserved;
};
@@ -83,6 +84,9 @@ lmb_end_pfn(struct lmb_region *type, unsigned long region_nr)
lmb_size_pages(type, region_nr);
}

+void lmb_reserve_area(u64 start, u64 end, char *name);
+void lmb_free_area(u64 start, u64 end);
+void lmb_add_memory(u64 start, u64 end);
u64 __lmb_find_area(u64 ei_start, u64 ei_last, u64 start, u64 end,
u64 size, u64 align);
u64 lmb_find_area(u64 start, u64 end, u64 size, u64 align);
diff --git a/mm/lmb.c b/mm/lmb.c
index 30c6917..94e90b6 100644
--- a/mm/lmb.c
+++ b/mm/lmb.c
@@ -564,6 +564,72 @@ int lmb_find(struct lmb_property *res)
return -1;
}

+static void __init __check_and_double_region_array(struct lmb_region *type,
+ struct lmb_property *static_region)
+{
+ u64 size, mem;
+ struct lmb_property *new, *old;
+ unsigned long rgnsz = type->nr_regions;
+
+ /* Do we have enough slots left ? */
+ if ((rgnsz - type->cnt) > 2)
+ return;
+
+ old = type->region;
+ /* Double the array size */
+ size = sizeof(struct lmb_property) * rgnsz * 2;
+
+ mem = __lmb_alloc_base(size, sizeof(struct lmb_property), lmb.default_alloc_limit);
+ if (mem == 0)
+ panic("can not find more space for lmb.reserved.region array");
+
+ new = __va(mem);
+ /* Copy old to new */
+ memcpy(&new[0], &old[0], sizeof(struct lmb_property) * rgnsz);
+ memset(&new[rgnsz], 0, sizeof(struct lmb_property) * rgnsz);
+
+ memset(&old[0], 0, sizeof(struct lmb_property) * rgnsz);
+ type->region = new;
+ type->nr_regions = rgnsz * 2;
+ printk(KERN_DEBUG "lmb.reserved.region array is doubled to %ld at [%llx - %llx]\n",
+ type->nr_regions, mem, mem + size - 1);
+
+ /* Free old one ?*/
+ if (old != static_region)
+ lmb_free(__pa(old), sizeof(struct lmb_property) * rgnsz);
+}
+
+void __init lmb_add_memory(u64 start, u64 end)
+{
+ lmb_add_region(&lmb.memory, start, end - start);
+ __check_and_double_region_array(&lmb.memory, &lmb_memory_region[0]);
+}
+
+void __init lmb_reserve_area(u64 start, u64 end, char *name)
+{
+ if (start == end)
+ return;
+
+ if (WARN_ONCE(start > end, "lmb_reserve_area: wrong range [%#llx, %#llx]\n", start, end))
+ return;
+
+ lmb_add_region(&lmb.reserved, start, end - start);
+ __check_and_double_region_array(&lmb.reserved, &lmb_reserved_region[0]);
+}
+
+void __init lmb_free_area(u64 start, u64 end)
+{
+ if (start == end)
+ return;
+
+ if (WARN_ONCE(start > end, "lmb_free_area: wrong range [%#llx, %#llx]\n", start, end))
+ return;
+
+ /* keep punching hole, could run out of slots too */
+ lmb_free(start, end - start);
+ __check_and_double_region_array(&lmb.reserved, &lmb_reserved_region[0]);
+}
+
u64 __init __lmb_find_area(u64 ei_start, u64 ei_last, u64 start, u64 end,
u64 size, u64 align)
{
--
1.6.4.2

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/