aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/xen/xen-balloon.c
diff options
context:
space:
mode:
authorDaniel De Graaf <dgdegra@tycho.nsa.gov>2011-03-14 11:29:37 -0400
committerKonrad Rzeszutek Wilk <konrad.wilk@oracle.com>2011-03-16 10:05:34 -0400
commit803eb047a28d239809fff1f87274cdaa94e0d8ea (patch)
tree67451cde4571c547314c6c28ae151741b3ff89af /drivers/xen/xen-balloon.c
parent40095de1f9082f058970b985a96d2fbef43f94f4 (diff)
xen-balloon: Move core balloon functionality out of module
The basic functionality of ballooning pages is useful for Xen drivers in general. Rather than require a dependency on the balloon module, split the functionality that is reused into the core. The balloon module is still required to follow ballooning requests from xenstore or to view balloon statistics in sysfs. Acked-by: Ian Campbell <ian.campbell@citrix.com> Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Diffstat (limited to 'drivers/xen/xen-balloon.c')
-rw-r--r--drivers/xen/xen-balloon.c256
1 files changed, 256 insertions, 0 deletions
diff --git a/drivers/xen/xen-balloon.c b/drivers/xen/xen-balloon.c
new file mode 100644
index 000000000000..a4ff225ee868
--- /dev/null
+++ b/drivers/xen/xen-balloon.c
@@ -0,0 +1,256 @@
1/******************************************************************************
2 * Xen balloon driver - enables returning/claiming memory to/from Xen.
3 *
4 * Copyright (c) 2003, B Dragovic
5 * Copyright (c) 2003-2004, M Williamson, K Fraser
6 * Copyright (c) 2005 Dan M. Smith, IBM Corporation
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License version 2
10 * as published by the Free Software Foundation; or, when distributed
11 * separately from the Linux kernel or incorporated into other
12 * software packages, subject to the following license:
13 *
14 * Permission is hereby granted, free of charge, to any person obtaining a copy
15 * of this source file (the "Software"), to deal in the Software without
16 * restriction, including without limitation the rights to use, copy, modify,
17 * merge, publish, distribute, sublicense, and/or sell copies of the Software,
18 * and to permit persons to whom the Software is furnished to do so, subject to
19 * the following conditions:
20 *
21 * The above copyright notice and this permission notice shall be included in
22 * all copies or substantial portions of the Software.
23 *
24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
29 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
30 * IN THE SOFTWARE.
31 */
32
33#include <linux/kernel.h>
34#include <linux/module.h>
35#include <linux/sysdev.h>
36#include <linux/capability.h>
37
38#include <xen/xen.h>
39#include <xen/interface/xen.h>
40#include <xen/balloon.h>
41#include <xen/xenbus.h>
42#include <xen/features.h>
43#include <xen/page.h>
44
45#define PAGES2KB(_p) ((_p)<<(PAGE_SHIFT-10))
46
47#define BALLOON_CLASS_NAME "xen_memory"
48
49static struct sys_device balloon_sysdev;
50
51static int register_balloon(struct sys_device *sysdev);
52
53static struct xenbus_watch target_watch =
54{
55 .node = "memory/target"
56};
57
58/* React to a change in the target key */
59static void watch_target(struct xenbus_watch *watch,
60 const char **vec, unsigned int len)
61{
62 unsigned long long new_target;
63 int err;
64
65 err = xenbus_scanf(XBT_NIL, "memory", "target", "%llu", &new_target);
66 if (err != 1) {
67 /* This is ok (for domain0 at least) - so just return */
68 return;
69 }
70
71 /* The given memory/target value is in KiB, so it needs converting to
72 * pages. PAGE_SHIFT converts bytes to pages, hence PAGE_SHIFT - 10.
73 */
74 balloon_set_new_target(new_target >> (PAGE_SHIFT - 10));
75}
76
77static int balloon_init_watcher(struct notifier_block *notifier,
78 unsigned long event,
79 void *data)
80{
81 int err;
82
83 err = register_xenbus_watch(&target_watch);
84 if (err)
85 printk(KERN_ERR "Failed to set balloon watcher\n");
86
87 return NOTIFY_DONE;
88}
89
90static struct notifier_block xenstore_notifier;
91
92static int __init balloon_init(void)
93{
94 if (!xen_domain())
95 return -ENODEV;
96
97 pr_info("xen-balloon: Initialising balloon driver.\n");
98
99 register_balloon(&balloon_sysdev);
100
101 target_watch.callback = watch_target;
102 xenstore_notifier.notifier_call = balloon_init_watcher;
103
104 register_xenstore_notifier(&xenstore_notifier);
105
106 return 0;
107}
108subsys_initcall(balloon_init);
109
110static void balloon_exit(void)
111{
112 /* XXX - release balloon here */
113 return;
114}
115
116module_exit(balloon_exit);
117
118#define BALLOON_SHOW(name, format, args...) \
119 static ssize_t show_##name(struct sys_device *dev, \
120 struct sysdev_attribute *attr, \
121 char *buf) \
122 { \
123 return sprintf(buf, format, ##args); \
124 } \
125 static SYSDEV_ATTR(name, S_IRUGO, show_##name, NULL)
126
127BALLOON_SHOW(current_kb, "%lu\n", PAGES2KB(balloon_stats.current_pages));
128BALLOON_SHOW(low_kb, "%lu\n", PAGES2KB(balloon_stats.balloon_low));
129BALLOON_SHOW(high_kb, "%lu\n", PAGES2KB(balloon_stats.balloon_high));
130
131static SYSDEV_ULONG_ATTR(schedule_delay, 0444, balloon_stats.schedule_delay);
132static SYSDEV_ULONG_ATTR(max_schedule_delay, 0644, balloon_stats.max_schedule_delay);
133static SYSDEV_ULONG_ATTR(retry_count, 0444, balloon_stats.retry_count);
134static SYSDEV_ULONG_ATTR(max_retry_count, 0644, balloon_stats.max_retry_count);
135
136static ssize_t show_target_kb(struct sys_device *dev, struct sysdev_attribute *attr,
137 char *buf)
138{
139 return sprintf(buf, "%lu\n", PAGES2KB(balloon_stats.target_pages));
140}
141
142static ssize_t store_target_kb(struct sys_device *dev,
143 struct sysdev_attribute *attr,
144 const char *buf,
145 size_t count)
146{
147 char *endchar;
148 unsigned long long target_bytes;
149
150 if (!capable(CAP_SYS_ADMIN))
151 return -EPERM;
152
153 target_bytes = simple_strtoull(buf, &endchar, 0) * 1024;
154
155 balloon_set_new_target(target_bytes >> PAGE_SHIFT);
156
157 return count;
158}
159
160static SYSDEV_ATTR(target_kb, S_IRUGO | S_IWUSR,
161 show_target_kb, store_target_kb);
162
163
164static ssize_t show_target(struct sys_device *dev, struct sysdev_attribute *attr,
165 char *buf)
166{
167 return sprintf(buf, "%llu\n",
168 (unsigned long long)balloon_stats.target_pages
169 << PAGE_SHIFT);
170}
171
172static ssize_t store_target(struct sys_device *dev,
173 struct sysdev_attribute *attr,
174 const char *buf,
175 size_t count)
176{
177 char *endchar;
178 unsigned long long target_bytes;
179
180 if (!capable(CAP_SYS_ADMIN))
181 return -EPERM;
182
183 target_bytes = memparse(buf, &endchar);
184
185 balloon_set_new_target(target_bytes >> PAGE_SHIFT);
186
187 return count;
188}
189
190static SYSDEV_ATTR(target, S_IRUGO | S_IWUSR,
191 show_target, store_target);
192
193
194static struct sysdev_attribute *balloon_attrs[] = {
195 &attr_target_kb,
196 &attr_target,
197 &attr_schedule_delay.attr,
198 &attr_max_schedule_delay.attr,
199 &attr_retry_count.attr,
200 &attr_max_retry_count.attr
201};
202
203static struct attribute *balloon_info_attrs[] = {
204 &attr_current_kb.attr,
205 &attr_low_kb.attr,
206 &attr_high_kb.attr,
207 NULL
208};
209
210static struct attribute_group balloon_info_group = {
211 .name = "info",
212 .attrs = balloon_info_attrs
213};
214
215static struct sysdev_class balloon_sysdev_class = {
216 .name = BALLOON_CLASS_NAME
217};
218
219static int register_balloon(struct sys_device *sysdev)
220{
221 int i, error;
222
223 error = sysdev_class_register(&balloon_sysdev_class);
224 if (error)
225 return error;
226
227 sysdev->id = 0;
228 sysdev->cls = &balloon_sysdev_class;
229
230 error = sysdev_register(sysdev);
231 if (error) {
232 sysdev_class_unregister(&balloon_sysdev_class);
233 return error;
234 }
235
236 for (i = 0; i < ARRAY_SIZE(balloon_attrs); i++) {
237 error = sysdev_create_file(sysdev, balloon_attrs[i]);
238 if (error)
239 goto fail;
240 }
241
242 error = sysfs_create_group(&sysdev->kobj, &balloon_info_group);
243 if (error)
244 goto fail;
245
246 return 0;
247
248 fail:
249 while (--i >= 0)
250 sysdev_remove_file(sysdev, balloon_attrs[i]);
251 sysdev_unregister(sysdev);
252 sysdev_class_unregister(&balloon_sysdev_class);
253 return error;
254}
255
256MODULE_LICENSE("GPL");