Revision 625a5bef hw/virtio-balloon.c

b/hw/virtio-balloon.c
16 16
#include "pc.h"
17 17
#include "sysemu.h"
18 18
#include "cpu.h"
19
#include "monitor.h"
19 20
#include "balloon.h"
20 21
#include "virtio-balloon.h"
21 22
#include "kvm.h"
23
#include "qlist.h"
24
#include "qint.h"
25
#include "qstring.h"
22 26

  
23 27
#if defined(__linux__)
24 28
#include <sys/mman.h>
......
27 31
typedef struct VirtIOBalloon
28 32
{
29 33
    VirtIODevice vdev;
30
    VirtQueue *ivq, *dvq;
34
    VirtQueue *ivq, *dvq, *svq;
31 35
    uint32_t num_pages;
32 36
    uint32_t actual;
37
    uint64_t stats[VIRTIO_BALLOON_S_NR];
38
    VirtQueueElement stats_vq_elem;
39
    size_t stats_vq_offset;
40
    MonitorCompletion *stats_callback;
41
    void *stats_opaque_callback_data;
33 42
} VirtIOBalloon;
34 43

  
35 44
static VirtIOBalloon *to_virtio_balloon(VirtIODevice *vdev)
......
46 55
#endif
47 56
}
48 57

  
58
/*
59
 * reset_stats - Mark all items in the stats array as unset
60
 *
61
 * This function needs to be called at device intialization and before
62
 * before updating to a set of newly-generated stats.  This will ensure that no
63
 * stale values stick around in case the guest reports a subset of the supported
64
 * statistics.
65
 */
66
static inline void reset_stats(VirtIOBalloon *dev)
67
{
68
    int i;
69
    for (i = 0; i < VIRTIO_BALLOON_S_NR; dev->stats[i++] = -1);
70
}
71

  
72
static void stat_put(QDict *dict, const char *label, uint64_t val)
73
{
74
    if (val != -1)
75
        qdict_put(dict, label, qint_from_int(val));
76
}
77

  
78
static QObject *get_stats_qobject(VirtIOBalloon *dev)
79
{
80
    QDict *dict = qdict_new();
81
    uint32_t actual = ram_size - (dev->actual << VIRTIO_BALLOON_PFN_SHIFT);
82

  
83
    stat_put(dict, "actual", actual);
84
    stat_put(dict, "mem_swapped_in", dev->stats[VIRTIO_BALLOON_S_SWAP_IN]);
85
    stat_put(dict, "mem_swapped_out", dev->stats[VIRTIO_BALLOON_S_SWAP_OUT]);
86
    stat_put(dict, "major_page_faults", dev->stats[VIRTIO_BALLOON_S_MAJFLT]);
87
    stat_put(dict, "minor_page_faults", dev->stats[VIRTIO_BALLOON_S_MINFLT]);
88
    stat_put(dict, "free_mem", dev->stats[VIRTIO_BALLOON_S_MEMFREE]);
89
    stat_put(dict, "total_mem", dev->stats[VIRTIO_BALLOON_S_MEMTOT]);
90

  
91
    return QOBJECT(dict);
92
}
93

  
49 94
/* FIXME: once we do a virtio refactoring, this will get subsumed into common
50 95
 * code */
51 96
static size_t memcpy_from_iovector(void *data, size_t offset, size_t size,
......
104 149
    }
105 150
}
106 151

  
152
static void complete_stats_request(VirtIOBalloon *vb)
153
{
154
    QObject *stats;
155

  
156
    if (!vb->stats_opaque_callback_data)
157
        return;
158

  
159
    stats = get_stats_qobject(vb);
160
    vb->stats_callback(vb->stats_opaque_callback_data, stats);
161
    qobject_decref(stats);
162
    vb->stats_opaque_callback_data = NULL;
163
    vb->stats_callback = NULL;
164
}
165

  
166
static void virtio_balloon_receive_stats(VirtIODevice *vdev, VirtQueue *vq)
167
{
168
    VirtIOBalloon *s = DO_UPCAST(VirtIOBalloon, vdev, vdev);
169
    VirtQueueElement *elem = &s->stats_vq_elem;
170
    VirtIOBalloonStat stat;
171
    size_t offset = 0;
172

  
173
    if (!virtqueue_pop(vq, elem)) {
174
        return;
175
    }
176

  
177
    /* Initialize the stats to get rid of any stale values.  This is only
178
     * needed to handle the case where a guest supports fewer stats than it
179
     * used to (ie. it has booted into an old kernel).
180
     */
181
    reset_stats(s);
182

  
183
    while (memcpy_from_iovector(&stat, offset, sizeof(stat), elem->out_sg,
184
                                elem->out_num) == sizeof(stat)) {
185
        uint16_t tag = tswap16(stat.tag);
186
        uint64_t val = tswap64(stat.val);
187

  
188
        offset += sizeof(stat);
189
        if (tag < VIRTIO_BALLOON_S_NR)
190
            s->stats[tag] = val;
191
    }
192
    s->stats_vq_offset = offset;
193

  
194
    complete_stats_request(s);
195
}
196

  
107 197
static void virtio_balloon_get_config(VirtIODevice *vdev, uint8_t *config_data)
108 198
{
109 199
    VirtIOBalloon *dev = to_virtio_balloon(vdev);
......
126 216

  
127 217
static uint32_t virtio_balloon_get_features(VirtIODevice *vdev, uint32_t f)
128 218
{
219
    f |= (1 << VIRTIO_BALLOON_F_STATS_VQ);
129 220
    return f;
130 221
}
131 222

  
132
static ram_addr_t virtio_balloon_to_target(void *opaque, ram_addr_t target)
223
static void virtio_balloon_to_target(void *opaque, ram_addr_t target,
224
                                     MonitorCompletion cb, void *cb_data)
133 225
{
134 226
    VirtIOBalloon *dev = opaque;
135 227

  
......
139 231
    if (target) {
140 232
        dev->num_pages = (ram_size - target) >> VIRTIO_BALLOON_PFN_SHIFT;
141 233
        virtio_notify_config(&dev->vdev);
234
    } else {
235
        /* For now, only allow one request at a time.  This restriction can be
236
         * removed later by queueing callback and data pairs.
237
         */
238
        if (dev->stats_callback != NULL) {
239
            return;
240
        }
241
        dev->stats_callback = cb;
242
        dev->stats_opaque_callback_data = cb_data; 
243
        if (dev->vdev.guest_features & (1 << VIRTIO_BALLOON_F_STATS_VQ)) {
244
            virtqueue_push(dev->svq, &dev->stats_vq_elem, dev->stats_vq_offset);
245
            virtio_notify(&dev->vdev, dev->svq);
246
        } else {
247
            /* Stats are not supported.  Clear out any stale values that might
248
             * have been set by a more featureful guest kernel.
249
             */
250
            reset_stats(dev);
251
            complete_stats_request(dev);
252
        }
142 253
    }
143

  
144
    return ram_size - (dev->actual << VIRTIO_BALLOON_PFN_SHIFT);
145 254
}
146 255

  
147 256
static void virtio_balloon_save(QEMUFile *f, void *opaque)
......
152 261

  
153 262
    qemu_put_be32(f, s->num_pages);
154 263
    qemu_put_be32(f, s->actual);
264
    qemu_put_buffer(f, (uint8_t *)&s->stats_vq_elem, sizeof(VirtQueueElement));
265
    qemu_put_buffer(f, (uint8_t *)&s->stats_vq_offset, sizeof(size_t));
266
    qemu_put_buffer(f, (uint8_t *)&s->stats_callback, sizeof(MonitorCompletion));
267
    qemu_put_buffer(f, (uint8_t *)&s->stats_opaque_callback_data, sizeof(void));
155 268
}
156 269

  
157 270
static int virtio_balloon_load(QEMUFile *f, void *opaque, int version_id)
......
165 278

  
166 279
    s->num_pages = qemu_get_be32(f);
167 280
    s->actual = qemu_get_be32(f);
281
    qemu_get_buffer(f, (uint8_t *)&s->stats_vq_elem, sizeof(VirtQueueElement));
282
    qemu_get_buffer(f, (uint8_t *)&s->stats_vq_offset, sizeof(size_t));
283
    qemu_get_buffer(f, (uint8_t *)&s->stats_callback, sizeof(MonitorCompletion));
284
    qemu_get_buffer(f, (uint8_t *)&s->stats_opaque_callback_data, sizeof(void));
168 285

  
169 286
    return 0;
170 287
}
......
183 300

  
184 301
    s->ivq = virtio_add_queue(&s->vdev, 128, virtio_balloon_handle_output);
185 302
    s->dvq = virtio_add_queue(&s->vdev, 128, virtio_balloon_handle_output);
303
    s->svq = virtio_add_queue(&s->vdev, 128, virtio_balloon_receive_stats);
186 304

  
305
    reset_stats(s);
187 306
    qemu_add_balloon_handler(virtio_balloon_to_target, s);
188 307

  
189 308
    register_savevm("virtio-balloon", -1, 1, virtio_balloon_save, virtio_balloon_load, s);

Also available in: Unified diff