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