[RFC PATCH 1/2] mem-hotplug: introduce sysfs `range' attribute

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



There may be memory holes in a memory section, and because of that we can
not know the real size of the section. In order to know the physical memory
area used int one memory section, we walks through iomem resources and
report the memory range in /sys/devices/system/memory/memoryX/range, like,

root@ivybridge:~# cat /sys/devices/system/memory/memory0/range
00001000-0008efff
00090000-0009ffff
00100000-07ffffff

Signed-off-by: Sheng Yong <shengyong1@xxxxxxxxxx>
---
 drivers/base/memory.c |   66 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 66 insertions(+)

diff --git a/drivers/base/memory.c b/drivers/base/memory.c
index 85be040..e72e5e4 100644
--- a/drivers/base/memory.c
+++ b/drivers/base/memory.c
@@ -21,6 +21,7 @@
 #include <linux/mutex.h>
 #include <linux/stat.h>
 #include <linux/slab.h>
+#include <linux/ioport.h>
 
 #include <linux/atomic.h>
 #include <asm/uaccess.h>
@@ -373,6 +374,69 @@ static ssize_t show_phys_device(struct device *dev,
 	return sprintf(buf, "%d\n", mem->phys_device);
 }
 
+static int get_range(u64 start, u64 end, void *arg)
+{
+	struct resource **head, *p, *tmp;
+
+	head = (struct resource **) arg;
+
+	if (!(*head)) {
+		*head = kmalloc(sizeof(struct resource), GFP_KERNEL);
+		if (!(*head))
+			return -ENOMEM;
+		(*head)->start = start;
+		(*head)->end = end;
+		(*head)->sibling = NULL;
+	} else {
+		p = *head;
+		while (p->sibling != NULL)
+			p = p->sibling;
+		if (p->end == start - 1) {
+			p->end = end;
+			return 0;
+		}
+		tmp = kmalloc(sizeof(struct resource), GFP_KERNEL);
+		if (!tmp)
+			return -ENOMEM;
+		tmp->start = start;
+		tmp->end = end;
+		tmp->sibling = NULL;
+		p->sibling = tmp;
+	}
+
+	return 0;
+}
+
+static ssize_t show_mem_range(struct device *dev,
+			      struct device_attribute *attr, char *buf)
+{
+	struct memory_block *mem = to_memory_block(dev);
+	unsigned long start_pfn, end_pfn, nr_pages;
+	struct resource *ranges = NULL, *p;
+	u64 start, end;
+	int cnt, err;
+
+	nr_pages = PAGES_PER_SECTION * sections_per_block;
+	start_pfn = section_nr_to_pfn(mem->start_section_nr);
+	end_pfn = start_pfn + nr_pages;
+
+	start = (u64) start_pfn << PAGE_SHIFT;
+	end = ((u64) end_pfn << PAGE_SHIFT) - 1;
+	err = walk_system_ram_res(start, end, &ranges, get_range);
+
+	cnt = 0;
+	while (ranges != NULL) {
+		p = ranges;
+		if (err == 0)
+			cnt += sprintf(buf, "%s%08llx-%08llx\n", buf,
+				       ranges->start, ranges->end);
+		ranges = ranges->sibling;
+		kfree(p);
+	}
+
+	return cnt;
+}
+
 #ifdef CONFIG_MEMORY_HOTREMOVE
 static ssize_t show_valid_zones(struct device *dev,
 				struct device_attribute *attr, char *buf)
@@ -416,6 +480,7 @@ static DEVICE_ATTR(phys_index, 0444, show_mem_start_phys_index, NULL);
 static DEVICE_ATTR(state, 0644, show_mem_state, store_mem_state);
 static DEVICE_ATTR(phys_device, 0444, show_phys_device, NULL);
 static DEVICE_ATTR(removable, 0444, show_mem_removable, NULL);
+static DEVICE_ATTR(range, 0444, show_mem_range, NULL);
 
 /*
  * Block size attribute stuff
@@ -565,6 +630,7 @@ static struct attribute *memory_memblk_attrs[] = {
 #ifdef CONFIG_MEMORY_HOTREMOVE
 	&dev_attr_valid_zones.attr,
 #endif
+	&dev_attr_range.attr,
 	NULL
 };
 
-- 
1.7.9.5

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@xxxxxxxxx.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@xxxxxxxxx";> email@xxxxxxxxx </a>




[Index of Archives]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Bugtraq]     [Linux]     [Linux OMAP]     [Linux MIPS]     [ECOS]     [Asterisk Internet PBX]     [Linux API]