# HG changeset patch
# User kfraser@xxxxxxxxxxxxxxxxxxxxx
# Node ID 93f0957e02ce59777167d46adf1c37e290194c32
# Parent c6747b81d30814a8b3fcfed45a891072df38075c
[BALLOON] Add a sysfs interface.
Information is located under /sys/devices/system/memory.
Original patch from Satoshi UCHIDA <s-uchida@xxxxxxxxxxxxx>
Signed-off-by: Keir Fraser <keir@xxxxxxxxxxxxx>
---
linux-2.6-xen-sparse/drivers/xen/balloon/Makefile | 2
linux-2.6-xen-sparse/drivers/xen/balloon/balloon.c | 91 +++++------
linux-2.6-xen-sparse/drivers/xen/balloon/common.h | 58 +++++++
linux-2.6-xen-sparse/drivers/xen/balloon/sysfs.c | 165 +++++++++++++++++++++
4 files changed, 264 insertions(+), 52 deletions(-)
diff -r c6747b81d308 -r 93f0957e02ce
linux-2.6-xen-sparse/drivers/xen/balloon/Makefile
--- a/linux-2.6-xen-sparse/drivers/xen/balloon/Makefile Mon Oct 23 13:10:24
2006 +0100
+++ b/linux-2.6-xen-sparse/drivers/xen/balloon/Makefile Mon Oct 23 14:09:01
2006 +0100
@@ -1,2 +1,2 @@
-obj-y += balloon.o
+obj-y := balloon.o sysfs.o
diff -r c6747b81d308 -r 93f0957e02ce
linux-2.6-xen-sparse/drivers/xen/balloon/balloon.c
--- a/linux-2.6-xen-sparse/drivers/xen/balloon/balloon.c Mon Oct 23
13:10:24 2006 +0100
+++ b/linux-2.6-xen-sparse/drivers/xen/balloon/balloon.c Mon Oct 23
14:09:01 2006 +0100
@@ -53,10 +53,8 @@
#include <asm/uaccess.h>
#include <asm/tlb.h>
#include <linux/list.h>
-
#include <xen/xenbus.h>
-
-#define PAGES2KB(_p) ((_p)<<(PAGE_SHIFT-10))
+#include "common.h"
#ifdef CONFIG_PROC_FS
static struct proc_dir_entry *balloon_pde;
@@ -71,9 +69,7 @@ static DECLARE_MUTEX(balloon_mutex);
*/
DEFINE_SPINLOCK(balloon_lock);
-/* We aim for 'current allocation' == 'target allocation'. */
-static unsigned long current_pages;
-static unsigned long target_pages;
+struct balloon_stats balloon_stats;
/* We increase/decrease in batches which fit in a page */
static unsigned long frame_list[PAGE_SIZE / sizeof(unsigned long)];
@@ -81,18 +77,8 @@ static unsigned long frame_list[PAGE_SIZ
/* VM /proc information for memory */
extern unsigned long totalram_pages;
-/* We may hit the hard limit in Xen. If we do then we remember it. */
-static unsigned long hard_limit;
-
-/*
- * Drivers may alter the memory reservation independently, but they must
- * inform the balloon driver so that we can avoid hitting the hard limit.
- */
-static unsigned long driver_pages;
-
/* List of ballooned pages, threaded through the mem_map array. */
static LIST_HEAD(ballooned_pages);
-static unsigned long balloon_low, balloon_high;
/* Main work function, always executed in process context. */
static void balloon_process(void *unused);
@@ -124,10 +110,10 @@ static void balloon_append(struct page *
/* Lowmem is re-populated first, so highmem pages go at list tail. */
if (PageHighMem(page)) {
list_add_tail(PAGE_TO_LIST(page), &ballooned_pages);
- balloon_high++;
+ bs.balloon_high++;
} else {
list_add(PAGE_TO_LIST(page), &ballooned_pages);
- balloon_low++;
+ bs.balloon_low++;
}
}
@@ -143,9 +129,9 @@ static struct page *balloon_retrieve(voi
UNLIST_PAGE(page);
if (PageHighMem(page))
- balloon_high--;
+ bs.balloon_high--;
else
- balloon_low--;
+ bs.balloon_low--;
return page;
}
@@ -172,9 +158,9 @@ static void balloon_alarm(unsigned long
static unsigned long current_target(void)
{
- unsigned long target = min(target_pages, hard_limit);
- if (target > (current_pages + balloon_low + balloon_high))
- target = current_pages + balloon_low + balloon_high;
+ unsigned long target = min(bs.target_pages, bs.hard_limit);
+ if (target > (bs.current_pages + bs.balloon_low + bs.balloon_high))
+ target = bs.current_pages + bs.balloon_low + bs.balloon_high;
return target;
}
@@ -216,7 +202,8 @@ static int increase_reservation(unsigned
BUG_ON(ret != rc);
}
if (rc >= 0)
- hard_limit = current_pages + rc - driver_pages;
+ bs.hard_limit = (bs.current_pages + rc -
+ bs.driver_pages);
goto out;
}
@@ -248,8 +235,8 @@ static int increase_reservation(unsigned
__free_page(page);
}
- current_pages += nr_pages;
- totalram_pages = current_pages;
+ bs.current_pages += nr_pages;
+ totalram_pages = bs.current_pages;
out:
balloon_unlock(flags);
@@ -317,8 +304,8 @@ static int decrease_reservation(unsigned
ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation, &reservation);
BUG_ON(ret != nr_pages);
- current_pages -= nr_pages;
- totalram_pages = current_pages;
+ bs.current_pages -= nr_pages;
+ totalram_pages = bs.current_pages;
balloon_unlock(flags);
@@ -339,7 +326,7 @@ static void balloon_process(void *unused
down(&balloon_mutex);
do {
- credit = current_target() - current_pages;
+ credit = current_target() - bs.current_pages;
if (credit > 0)
need_sleep = (increase_reservation(credit) != 0);
if (credit < 0)
@@ -352,18 +339,18 @@ static void balloon_process(void *unused
} while ((credit != 0) && !need_sleep);
/* Schedule more work if there is some still to be done. */
- if (current_target() != current_pages)
+ if (current_target() != bs.current_pages)
mod_timer(&balloon_timer, jiffies + HZ);
up(&balloon_mutex);
}
/* Resets the Xen limit, sets new target, and kicks off processing. */
-static void set_new_target(unsigned long target)
+void balloon_set_new_target(unsigned long target)
{
/* No need for lock. Not read-modify-write updates. */
- hard_limit = ~0UL;
- target_pages = target;
+ bs.hard_limit = ~0UL;
+ bs.target_pages = target;
schedule_work(&balloon_worker);
}
@@ -388,7 +375,7 @@ static void watch_target(struct xenbus_w
/* The given memory/target value is in KiB, so it needs converting to
* pages. PAGE_SHIFT converts bytes to pages, hence PAGE_SHIFT - 10.
*/
- set_new_target(new_target >> (PAGE_SHIFT - 10));
+ balloon_set_new_target(new_target >> (PAGE_SHIFT - 10));
}
static int balloon_init_watcher(struct notifier_block *notifier,
@@ -424,7 +411,7 @@ static int balloon_write(struct file *fi
memstring[sizeof(memstring)-1] = '\0';
target_bytes = memparse(memstring, &endchar);
- set_new_target(target_bytes >> PAGE_SHIFT);
+ balloon_set_new_target(target_bytes >> PAGE_SHIFT);
return count;
}
@@ -442,12 +429,13 @@ static int balloon_read(char *page, char
"High-mem balloon: %8lu kB\n"
"Driver pages: %8lu kB\n"
"Xen hard limit: ",
- PAGES2KB(current_pages), PAGES2KB(target_pages),
- PAGES2KB(balloon_low), PAGES2KB(balloon_high),
- PAGES2KB(driver_pages));
-
- if (hard_limit != ~0UL)
- len += sprintf(page + len, "%8lu kB\n", PAGES2KB(hard_limit));
+ PAGES2KB(bs.current_pages), PAGES2KB(bs.target_pages),
+ PAGES2KB(bs.balloon_low), PAGES2KB(bs.balloon_high),
+ PAGES2KB(bs.driver_pages));
+
+ if (bs.hard_limit != ~0UL)
+ len += sprintf(page + len, "%8lu kB\n",
+ PAGES2KB(bs.hard_limit));
else
len += sprintf(page + len, " ??? kB\n");
@@ -468,13 +456,13 @@ static int __init balloon_init(void)
IPRINTK("Initialising balloon driver.\n");
- current_pages = min(xen_start_info->nr_pages, max_pfn);
- totalram_pages = current_pages;
- target_pages = current_pages;
- balloon_low = 0;
- balloon_high = 0;
- driver_pages = 0UL;
- hard_limit = ~0UL;
+ bs.current_pages = min(xen_start_info->nr_pages, max_pfn);
+ totalram_pages = bs.current_pages;
+ bs.target_pages = bs.current_pages;
+ bs.balloon_low = 0;
+ bs.balloon_high = 0;
+ bs.driver_pages = 0UL;
+ bs.hard_limit = ~0UL;
init_timer(&balloon_timer);
balloon_timer.data = 0;
@@ -489,6 +477,7 @@ static int __init balloon_init(void)
balloon_pde->read_proc = balloon_read;
balloon_pde->write_proc = balloon_write;
#endif
+ balloon_sysfs_init();
/* Initialise the balloon with excess memory space. */
for (pfn = xen_start_info->nr_pages; pfn < max_pfn; pfn++) {
@@ -512,7 +501,7 @@ void balloon_update_driver_allowance(lon
unsigned long flags;
balloon_lock(flags);
- driver_pages += delta;
+ bs.driver_pages += delta;
balloon_unlock(flags);
}
@@ -578,7 +567,7 @@ struct page **alloc_empty_pages_and_page
goto err;
}
- totalram_pages = --current_pages;
+ totalram_pages = --bs.current_pages;
balloon_unlock(flags);
}
@@ -624,7 +613,7 @@ void balloon_release_driver_page(struct
balloon_lock(flags);
balloon_append(page);
- driver_pages--;
+ bs.driver_pages--;
balloon_unlock(flags);
schedule_work(&balloon_worker);
diff -r c6747b81d308 -r 93f0957e02ce
linux-2.6-xen-sparse/drivers/xen/balloon/common.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/linux-2.6-xen-sparse/drivers/xen/balloon/common.h Mon Oct 23 14:09:01
2006 +0100
@@ -0,0 +1,58 @@
+/******************************************************************************
+ * balloon/common.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef __XEN_BALLOON_COMMON_H__
+#define __XEN_BALLOON_COMMON_H__
+
+#define PAGES2KB(_p) ((_p)<<(PAGE_SHIFT-10))
+
+struct balloon_stats {
+ /* We aim for 'current allocation' == 'target allocation'. */
+ unsigned long current_pages;
+ unsigned long target_pages;
+ /* We may hit the hard limit in Xen. If we do then we remember it. */
+ unsigned long hard_limit;
+ /*
+ * Drivers may alter the memory reservation independently, but they
+ * must inform the balloon driver so we avoid hitting the hard limit.
+ */
+ unsigned long driver_pages;
+ /* Number of pages in high- and low-memory balloons. */
+ unsigned long balloon_low;
+ unsigned long balloon_high;
+};
+
+extern struct balloon_stats balloon_stats;
+#define bs balloon_stats
+
+int balloon_sysfs_init(void);
+void balloon_sysfs_exit(void);
+
+void balloon_set_new_target(unsigned long target);
+
+#endif /* __XEN_BALLOON_COMMON_H__ */
diff -r c6747b81d308 -r 93f0957e02ce
linux-2.6-xen-sparse/drivers/xen/balloon/sysfs.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/linux-2.6-xen-sparse/drivers/xen/balloon/sysfs.c Mon Oct 23 14:09:01
2006 +0100
@@ -0,0 +1,165 @@
+/******************************************************************************
+ * balloon/sysfs.c
+ *
+ * Xen balloon driver - sysfs interfaces.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <linux/config.h>
+#include <linux/capability.h>
+#include <linux/stat.h>
+#include <linux/sysdev.h>
+#include "common.h"
+
+#define BALLOON_CLASS_NAME "memory"
+
+#define BALLOON_SHOW(name, format, args...) \
+ static ssize_t show_##name(struct sys_device *dev, \
+ char *buf) \
+ { \
+ return sprintf(buf, format, ##args); \
+ } \
+ static SYSDEV_ATTR(name, S_IRUGO, show_##name, NULL)
+
+BALLOON_SHOW(current_kb, "%lu\n", PAGES2KB(bs.current_pages));
+BALLOON_SHOW(low_kb, "%lu\n", PAGES2KB(bs.balloon_low));
+BALLOON_SHOW(high_kb, "%lu\n", PAGES2KB(bs.balloon_high));
+BALLOON_SHOW(hard_limit_kb,
+ (bs.hard_limit!=~0UL) ? "%lu\n" : "???\n",
+ (bs.hard_limit!=~0UL) ? PAGES2KB(bs.hard_limit) : 0);
+BALLOON_SHOW(driver_kb, "%lu\n", PAGES2KB(bs.driver_pages));
+
+static ssize_t show_target_kb(struct sys_device *dev, char *buf)
+{
+ return sprintf(buf, "%lu\n", PAGES2KB(bs.target_pages));
+}
+
+static ssize_t store_target_kb(struct sys_device *dev,
+ const char *buf,
+ size_t count)
+{
+ char memstring[64], *endchar;
+ unsigned long long target_bytes;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ if (count <= 1)
+ return -EBADMSG; /* runt */
+ if (count > sizeof(memstring))
+ return -EFBIG; /* too long */
+ strcpy(memstring, buf);
+
+ target_bytes = memparse(memstring, &endchar);
+ balloon_set_new_target(target_bytes >> PAGE_SHIFT);
+
+ return count;
+}
+
+static SYSDEV_ATTR(target_kb, S_IRUGO | S_IWUSR,
+ show_target_kb, store_target_kb);
+
+static struct sysdev_attribute *balloon_attrs[] = {
+ &attr_target_kb,
+};
+
+static struct attribute *balloon_info_attrs[] = {
+ &attr_current_kb.attr,
+ &attr_low_kb.attr,
+ &attr_high_kb.attr,
+ &attr_hard_limit_kb.attr,
+ &attr_driver_kb.attr,
+ NULL
+};
+
+static struct attribute_group balloon_info_group = {
+ .name = "info",
+ .attrs = balloon_info_attrs,
+};
+
+static struct sysdev_class balloon_sysdev_class = {
+ set_kset_name(BALLOON_CLASS_NAME),
+};
+
+static struct sys_device balloon_sysdev;
+
+static int register_balloon(struct sys_device *sysdev)
+{
+ int i, error;
+
+ error = sysdev_class_register(&balloon_sysdev_class);
+ if (error)
+ return error;
+
+ sysdev->id = 0;
+ sysdev->cls = &balloon_sysdev_class;
+
+ error = sysdev_register(sysdev);
+ if (error) {
+ sysdev_class_unregister(&balloon_sysdev_class);
+ return error;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(balloon_attrs); i++) {
+ error = sysdev_create_file(sysdev, balloon_attrs[i]);
+ if (error)
+ goto fail;
+ }
+
+ error = sysfs_create_group(&sysdev->kobj, &balloon_info_group);
+ if (error)
+ goto fail;
+
+ return 0;
+
+ fail:
+ while (--i >= 0)
+ sysdev_remove_file(sysdev, balloon_attrs[i]);
+ sysdev_unregister(sysdev);
+ sysdev_class_unregister(&balloon_sysdev_class);
+ return error;
+}
+
+static void unregister_balloon(struct sys_device *sysdev)
+{
+ int i;
+
+ sysfs_remove_group(&sysdev->kobj, &balloon_info_group);
+ for (i = 0; i < ARRAY_SIZE(balloon_attrs); i++)
+ sysdev_remove_file(sysdev, balloon_attrs[i]);
+ sysdev_unregister(sysdev);
+ sysdev_class_unregister(&balloon_sysdev_class);
+}
+
+int balloon_sysfs_init(void)
+{
+ return register_balloon(&balloon_sysdev);
+}
+
+void balloon_sysfs_exit(void)
+{
+ unregister_balloon(&balloon_sysdev);
+}
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|