qemu/hw/virtio-balloon.c
<<
>>
Prefs
   1/*
   2 * Virtio Balloon Device
   3 *
   4 * Copyright IBM, Corp. 2008
   5 * Copyright (C) 2011 Red Hat, Inc.
   6 * Copyright (C) 2011 Amit Shah <amit.shah@redhat.com>
   7 *
   8 * Authors:
   9 *  Anthony Liguori   <aliguori@us.ibm.com>
  10 *
  11 * This work is licensed under the terms of the GNU GPL, version 2.  See
  12 * the COPYING file in the top-level directory.
  13 *
  14 */
  15
  16#include "iov.h"
  17#include "qemu-common.h"
  18#include "virtio.h"
  19#include "pc.h"
  20#include "cpu.h"
  21#include "balloon.h"
  22#include "virtio-balloon.h"
  23#include "kvm.h"
  24#include "exec-memory.h"
  25
  26#if defined(__linux__)
  27#include <sys/mman.h>
  28#endif
  29
  30typedef struct VirtIOBalloon
  31{
  32    VirtIODevice vdev;
  33    VirtQueue *ivq, *dvq, *svq;
  34    uint32_t num_pages;
  35    uint32_t actual;
  36    uint64_t stats[VIRTIO_BALLOON_S_NR];
  37    VirtQueueElement stats_vq_elem;
  38    size_t stats_vq_offset;
  39    DeviceState *qdev;
  40} VirtIOBalloon;
  41
  42static VirtIOBalloon *to_virtio_balloon(VirtIODevice *vdev)
  43{
  44    return (VirtIOBalloon *)vdev;
  45}
  46
  47static void balloon_page(void *addr, int deflate)
  48{
  49#if defined(__linux__)
  50    if (!kvm_enabled() || kvm_has_sync_mmu())
  51        qemu_madvise(addr, TARGET_PAGE_SIZE,
  52                deflate ? QEMU_MADV_WILLNEED : QEMU_MADV_DONTNEED);
  53#endif
  54}
  55
  56/*
  57 * reset_stats - Mark all items in the stats array as unset
  58 *
  59 * This function needs to be called at device intialization and before
  60 * before updating to a set of newly-generated stats.  This will ensure that no
  61 * stale values stick around in case the guest reports a subset of the supported
  62 * statistics.
  63 */
  64static inline void reset_stats(VirtIOBalloon *dev)
  65{
  66    int i;
  67    for (i = 0; i < VIRTIO_BALLOON_S_NR; dev->stats[i++] = -1);
  68}
  69
  70static void virtio_balloon_handle_output(VirtIODevice *vdev, VirtQueue *vq)
  71{
  72    VirtIOBalloon *s = to_virtio_balloon(vdev);
  73    VirtQueueElement elem;
  74    MemoryRegionSection section;
  75
  76    while (virtqueue_pop(vq, &elem)) {
  77        size_t offset = 0;
  78        uint32_t pfn;
  79
  80        while (iov_to_buf(elem.out_sg, elem.out_num, offset, &pfn, 4) == 4) {
  81            ram_addr_t pa;
  82            ram_addr_t addr;
  83
  84            pa = (ram_addr_t)ldl_p(&pfn) << VIRTIO_BALLOON_PFN_SHIFT;
  85            offset += 4;
  86
  87            /* FIXME: remove get_system_memory(), but how? */
  88            section = memory_region_find(get_system_memory(), pa, 1);
  89            if (!section.size || !memory_region_is_ram(section.mr))
  90                continue;
  91
  92            /* Using memory_region_get_ram_ptr is bending the rules a bit, but
  93               should be OK because we only want a single page.  */
  94            addr = section.offset_within_region;
  95            balloon_page(memory_region_get_ram_ptr(section.mr) + addr,
  96                         !!(vq == s->dvq));
  97        }
  98
  99        virtqueue_push(vq, &elem, offset);
 100        virtio_notify(vdev, vq);
 101    }
 102}
 103
 104static void virtio_balloon_receive_stats(VirtIODevice *vdev, VirtQueue *vq)
 105{
 106    VirtIOBalloon *s = DO_UPCAST(VirtIOBalloon, vdev, vdev);
 107    VirtQueueElement *elem = &s->stats_vq_elem;
 108    VirtIOBalloonStat stat;
 109    size_t offset = 0;
 110
 111    if (!virtqueue_pop(vq, elem)) {
 112        return;
 113    }
 114
 115    /* Initialize the stats to get rid of any stale values.  This is only
 116     * needed to handle the case where a guest supports fewer stats than it
 117     * used to (ie. it has booted into an old kernel).
 118     */
 119    reset_stats(s);
 120
 121    while (iov_to_buf(elem->out_sg, elem->out_num, offset, &stat, sizeof(stat))
 122           == sizeof(stat)) {
 123        uint16_t tag = tswap16(stat.tag);
 124        uint64_t val = tswap64(stat.val);
 125
 126        offset += sizeof(stat);
 127        if (tag < VIRTIO_BALLOON_S_NR)
 128            s->stats[tag] = val;
 129    }
 130    s->stats_vq_offset = offset;
 131}
 132
 133static void virtio_balloon_get_config(VirtIODevice *vdev, uint8_t *config_data)
 134{
 135    VirtIOBalloon *dev = to_virtio_balloon(vdev);
 136    struct virtio_balloon_config config;
 137
 138    config.num_pages = cpu_to_le32(dev->num_pages);
 139    config.actual = cpu_to_le32(dev->actual);
 140
 141    memcpy(config_data, &config, 8);
 142}
 143
 144static void virtio_balloon_set_config(VirtIODevice *vdev,
 145                                      const uint8_t *config_data)
 146{
 147    VirtIOBalloon *dev = to_virtio_balloon(vdev);
 148    struct virtio_balloon_config config;
 149    uint32_t oldactual = dev->actual;
 150    memcpy(&config, config_data, 8);
 151    dev->actual = le32_to_cpu(config.actual);
 152    if (dev->actual != oldactual) {
 153        qemu_balloon_changed(ram_size -
 154                             (dev->actual << VIRTIO_BALLOON_PFN_SHIFT));
 155    }
 156}
 157
 158static uint32_t virtio_balloon_get_features(VirtIODevice *vdev, uint32_t f)
 159{
 160    f |= (1 << VIRTIO_BALLOON_F_STATS_VQ);
 161    return f;
 162}
 163
 164static void virtio_balloon_stat(void *opaque, BalloonInfo *info)
 165{
 166    VirtIOBalloon *dev = opaque;
 167
 168#if 0
 169    /* Disable guest-provided stats for now. For more details please check:
 170     * https://bugzilla.redhat.com/show_bug.cgi?id=623903
 171     *
 172     * If you do enable it (which is probably not going to happen as we
 173     * need a new command for it), remember that you also need to fill the
 174     * appropriate members of the BalloonInfo structure so that the stats
 175     * are returned to the client.
 176     */
 177    if (dev->vdev.guest_features & (1 << VIRTIO_BALLOON_F_STATS_VQ)) {
 178        virtqueue_push(dev->svq, &dev->stats_vq_elem, dev->stats_vq_offset);
 179        virtio_notify(&dev->vdev, dev->svq);
 180        return;
 181    }
 182#endif
 183
 184    /* Stats are not supported.  Clear out any stale values that might
 185     * have been set by a more featureful guest kernel.
 186     */
 187    reset_stats(dev);
 188
 189    info->actual = ram_size - ((uint64_t) dev->actual <<
 190                               VIRTIO_BALLOON_PFN_SHIFT);
 191}
 192
 193static void virtio_balloon_to_target(void *opaque, ram_addr_t target)
 194{
 195    VirtIOBalloon *dev = opaque;
 196
 197    if (target > ram_size) {
 198        target = ram_size;
 199    }
 200    if (target) {
 201        dev->num_pages = (ram_size - target) >> VIRTIO_BALLOON_PFN_SHIFT;
 202        virtio_notify_config(&dev->vdev);
 203    }
 204}
 205
 206static void virtio_balloon_save(QEMUFile *f, void *opaque)
 207{
 208    VirtIOBalloon *s = opaque;
 209
 210    virtio_save(&s->vdev, f);
 211
 212    qemu_put_be32(f, s->num_pages);
 213    qemu_put_be32(f, s->actual);
 214}
 215
 216static int virtio_balloon_load(QEMUFile *f, void *opaque, int version_id)
 217{
 218    VirtIOBalloon *s = opaque;
 219    int ret;
 220
 221    if (version_id != 1)
 222        return -EINVAL;
 223
 224    ret = virtio_load(&s->vdev, f);
 225    if (ret) {
 226        return ret;
 227    }
 228
 229    s->num_pages = qemu_get_be32(f);
 230    s->actual = qemu_get_be32(f);
 231    return 0;
 232}
 233
 234VirtIODevice *virtio_balloon_init(DeviceState *dev)
 235{
 236    VirtIOBalloon *s;
 237    int ret;
 238
 239    s = (VirtIOBalloon *)virtio_common_init("virtio-balloon",
 240                                            VIRTIO_ID_BALLOON,
 241                                            8, sizeof(VirtIOBalloon));
 242
 243    s->vdev.get_config = virtio_balloon_get_config;
 244    s->vdev.set_config = virtio_balloon_set_config;
 245    s->vdev.get_features = virtio_balloon_get_features;
 246
 247    ret = qemu_add_balloon_handler(virtio_balloon_to_target,
 248                                   virtio_balloon_stat, s);
 249    if (ret < 0) {
 250        virtio_cleanup(&s->vdev);
 251        return NULL;
 252    }
 253
 254    s->ivq = virtio_add_queue(&s->vdev, 128, virtio_balloon_handle_output);
 255    s->dvq = virtio_add_queue(&s->vdev, 128, virtio_balloon_handle_output);
 256    s->svq = virtio_add_queue(&s->vdev, 128, virtio_balloon_receive_stats);
 257
 258    reset_stats(s);
 259
 260    s->qdev = dev;
 261    register_savevm(dev, "virtio-balloon", -1, 1,
 262                    virtio_balloon_save, virtio_balloon_load, s);
 263
 264    return &s->vdev;
 265}
 266
 267void virtio_balloon_exit(VirtIODevice *vdev)
 268{
 269    VirtIOBalloon *s = DO_UPCAST(VirtIOBalloon, vdev, vdev);
 270
 271    qemu_remove_balloon_handler(s);
 272    unregister_savevm(s->qdev, "virtio-balloon", s);
 273    virtio_cleanup(vdev);
 274}
 275