Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v4.14 255 lines 7.0 kB view raw
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#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 34 35#include <linux/kernel.h> 36#include <linux/errno.h> 37#include <linux/mm_types.h> 38#include <linux/init.h> 39#include <linux/capability.h> 40 41#include <xen/xen.h> 42#include <xen/interface/xen.h> 43#include <xen/balloon.h> 44#include <xen/xenbus.h> 45#include <xen/features.h> 46#include <xen/page.h> 47 48#define PAGES2KB(_p) ((_p)<<(PAGE_SHIFT-10)) 49 50#define BALLOON_CLASS_NAME "xen_memory" 51 52static struct device balloon_dev; 53 54static int register_balloon(struct device *dev); 55 56/* React to a change in the target key */ 57static void watch_target(struct xenbus_watch *watch, 58 const char *path, const char *token) 59{ 60 unsigned long long new_target, static_max; 61 int err; 62 static bool watch_fired; 63 static long target_diff; 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 new_target >>= PAGE_SHIFT - 10; 75 76 if (!watch_fired) { 77 watch_fired = true; 78 err = xenbus_scanf(XBT_NIL, "memory", "static-max", "%llu", 79 &static_max); 80 if (err != 1) 81 static_max = new_target; 82 else 83 static_max >>= PAGE_SHIFT - 10; 84 target_diff = xen_pv_domain() ? 0 85 : static_max - balloon_stats.target_pages; 86 } 87 88 balloon_set_new_target(new_target - target_diff); 89} 90static struct xenbus_watch target_watch = { 91 .node = "memory/target", 92 .callback = watch_target, 93}; 94 95 96static int balloon_init_watcher(struct notifier_block *notifier, 97 unsigned long event, 98 void *data) 99{ 100 int err; 101 102 err = register_xenbus_watch(&target_watch); 103 if (err) 104 pr_err("Failed to set balloon watcher\n"); 105 106 return NOTIFY_DONE; 107} 108 109static struct notifier_block xenstore_notifier = { 110 .notifier_call = balloon_init_watcher, 111}; 112 113void xen_balloon_init(void) 114{ 115 register_balloon(&balloon_dev); 116 117 register_xen_selfballooning(&balloon_dev); 118 119 register_xenstore_notifier(&xenstore_notifier); 120} 121EXPORT_SYMBOL_GPL(xen_balloon_init); 122 123#define BALLOON_SHOW(name, format, args...) \ 124 static ssize_t show_##name(struct device *dev, \ 125 struct device_attribute *attr, \ 126 char *buf) \ 127 { \ 128 return sprintf(buf, format, ##args); \ 129 } \ 130 static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL) 131 132BALLOON_SHOW(current_kb, "%lu\n", PAGES2KB(balloon_stats.current_pages)); 133BALLOON_SHOW(low_kb, "%lu\n", PAGES2KB(balloon_stats.balloon_low)); 134BALLOON_SHOW(high_kb, "%lu\n", PAGES2KB(balloon_stats.balloon_high)); 135 136static DEVICE_ULONG_ATTR(schedule_delay, 0444, balloon_stats.schedule_delay); 137static DEVICE_ULONG_ATTR(max_schedule_delay, 0644, balloon_stats.max_schedule_delay); 138static DEVICE_ULONG_ATTR(retry_count, 0444, balloon_stats.retry_count); 139static DEVICE_ULONG_ATTR(max_retry_count, 0644, balloon_stats.max_retry_count); 140 141static ssize_t show_target_kb(struct device *dev, struct device_attribute *attr, 142 char *buf) 143{ 144 return sprintf(buf, "%lu\n", PAGES2KB(balloon_stats.target_pages)); 145} 146 147static ssize_t store_target_kb(struct device *dev, 148 struct device_attribute *attr, 149 const char *buf, 150 size_t count) 151{ 152 char *endchar; 153 unsigned long long target_bytes; 154 155 if (!capable(CAP_SYS_ADMIN)) 156 return -EPERM; 157 158 target_bytes = simple_strtoull(buf, &endchar, 0) * 1024; 159 160 balloon_set_new_target(target_bytes >> PAGE_SHIFT); 161 162 return count; 163} 164 165static DEVICE_ATTR(target_kb, S_IRUGO | S_IWUSR, 166 show_target_kb, store_target_kb); 167 168 169static ssize_t show_target(struct device *dev, struct device_attribute *attr, 170 char *buf) 171{ 172 return sprintf(buf, "%llu\n", 173 (unsigned long long)balloon_stats.target_pages 174 << PAGE_SHIFT); 175} 176 177static ssize_t store_target(struct device *dev, 178 struct device_attribute *attr, 179 const char *buf, 180 size_t count) 181{ 182 char *endchar; 183 unsigned long long target_bytes; 184 185 if (!capable(CAP_SYS_ADMIN)) 186 return -EPERM; 187 188 target_bytes = memparse(buf, &endchar); 189 190 balloon_set_new_target(target_bytes >> PAGE_SHIFT); 191 192 return count; 193} 194 195static DEVICE_ATTR(target, S_IRUGO | S_IWUSR, 196 show_target, store_target); 197 198 199static struct attribute *balloon_attrs[] = { 200 &dev_attr_target_kb.attr, 201 &dev_attr_target.attr, 202 &dev_attr_schedule_delay.attr.attr, 203 &dev_attr_max_schedule_delay.attr.attr, 204 &dev_attr_retry_count.attr.attr, 205 &dev_attr_max_retry_count.attr.attr, 206 NULL 207}; 208 209static const struct attribute_group balloon_group = { 210 .attrs = balloon_attrs 211}; 212 213static struct attribute *balloon_info_attrs[] = { 214 &dev_attr_current_kb.attr, 215 &dev_attr_low_kb.attr, 216 &dev_attr_high_kb.attr, 217 NULL 218}; 219 220static const struct attribute_group balloon_info_group = { 221 .name = "info", 222 .attrs = balloon_info_attrs 223}; 224 225static const struct attribute_group *balloon_groups[] = { 226 &balloon_group, 227 &balloon_info_group, 228 NULL 229}; 230 231static struct bus_type balloon_subsys = { 232 .name = BALLOON_CLASS_NAME, 233 .dev_name = BALLOON_CLASS_NAME, 234}; 235 236static int register_balloon(struct device *dev) 237{ 238 int error; 239 240 error = subsys_system_register(&balloon_subsys, NULL); 241 if (error) 242 return error; 243 244 dev->id = 0; 245 dev->bus = &balloon_subsys; 246 dev->groups = balloon_groups; 247 248 error = device_register(dev); 249 if (error) { 250 bus_unregister(&balloon_subsys); 251 return error; 252 } 253 254 return 0; 255}