Revision 625a5bef

b/balloon.h
16 16

  
17 17
#include "cpu-defs.h"
18 18

  
19
typedef ram_addr_t (QEMUBalloonEvent)(void *opaque, ram_addr_t target);
19
typedef void (QEMUBalloonEvent)(void *opaque, ram_addr_t target,
20
                                MonitorCompletion cb, void *cb_data);
20 21

  
21 22
void qemu_add_balloon_handler(QEMUBalloonEvent *func, void *opaque);
22 23

  
23
void qemu_balloon(ram_addr_t target);
24
int qemu_balloon(ram_addr_t target, MonitorCompletion cb, void *opaque);
24 25

  
25
ram_addr_t qemu_balloon_status(void);
26
int qemu_balloon_status(MonitorCompletion cb, void *opaque);
26 27

  
27 28
#endif
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);
b/hw/virtio-balloon.h
25 25

  
26 26
/* The feature bitmap for virtio balloon */
27 27
#define VIRTIO_BALLOON_F_MUST_TELL_HOST 0 /* Tell before reclaiming pages */
28
#define VIRTIO_BALLOON_F_STATS_VQ 1       /* Memory stats virtqueue */
28 29

  
29 30
/* Size of a PFN in the balloon interface. */
30 31
#define VIRTIO_BALLOON_PFN_SHIFT 12
......
37 38
    uint32_t actual;
38 39
};
39 40

  
41
/* Memory Statistics */
42
#define VIRTIO_BALLOON_S_SWAP_IN  0   /* Amount of memory swapped in */
43
#define VIRTIO_BALLOON_S_SWAP_OUT 1   /* Amount of memory swapped out */
44
#define VIRTIO_BALLOON_S_MAJFLT   2   /* Number of major faults */
45
#define VIRTIO_BALLOON_S_MINFLT   3   /* Number of minor faults */
46
#define VIRTIO_BALLOON_S_MEMFREE  4   /* Total amount of free memory */
47
#define VIRTIO_BALLOON_S_MEMTOT   5   /* Total amount of memory */
48
#define VIRTIO_BALLOON_S_NR       6
49

  
50
typedef struct VirtIOBalloonStat {
51
    uint16_t tag;
52
    uint64_t val;
53
} __attribute__((packed)) VirtIOBalloonStat;
54

  
40 55
#endif
b/monitor.c
2152 2152
                                    vm_running, singlestep);
2153 2153
}
2154 2154

  
2155
static ram_addr_t balloon_get_value(void)
2155
static void print_balloon_stat(const char *key, QObject *obj, void *opaque)
2156 2156
{
2157
    ram_addr_t actual;
2158

  
2159
    if (kvm_enabled() && !kvm_has_sync_mmu()) {
2160
        qemu_error_new(QERR_KVM_MISSING_CAP, "synchronous MMU", "balloon");
2161
        return 0;
2162
    }
2163

  
2164
    actual = qemu_balloon_status();
2165
    if (actual == 0) {
2166
        qemu_error_new(QERR_DEVICE_NOT_ACTIVE, "balloon");
2167
        return 0;
2168
    }
2169

  
2170
    return actual;
2171
}
2157
    Monitor *mon = opaque;
2172 2158

  
2173
/**
2174
 * do_balloon(): Request VM to change its memory allocation
2175
 */
2176
static void do_balloon(Monitor *mon, const QDict *qdict, QObject **ret_data)
2177
{
2178
    if (balloon_get_value()) {
2179
        /* ballooning is active */
2180
        qemu_balloon(qdict_get_int(qdict, "value"));
2181
    }
2159
    if (strcmp(key, "actual"))
2160
        monitor_printf(mon, ",%s=%" PRId64, key,
2161
                       qint_get_int(qobject_to_qint(obj)));
2182 2162
}
2183 2163

  
2184 2164
static void monitor_print_balloon(Monitor *mon, const QObject *data)
......
2186 2166
    QDict *qdict;
2187 2167

  
2188 2168
    qdict = qobject_to_qdict(data);
2169
    if (!qdict_haskey(qdict, "actual"))
2170
        return;
2189 2171

  
2190
    monitor_printf(mon, "balloon: actual=%" PRId64 "\n",
2191
                        qdict_get_int(qdict, "balloon") >> 20);
2172
    monitor_printf(mon, "balloon: actual=%" PRId64,
2173
                   qdict_get_int(qdict, "actual") >> 20);
2174
    qdict_iter(qdict, print_balloon_stat, mon);
2175
    monitor_printf(mon, "\n");
2192 2176
}
2193 2177

  
2194 2178
/**
2195 2179
 * do_info_balloon(): Balloon information
2196 2180
 *
2197
 * Return a QDict with the following information:
2181
 * Make an asynchronous request for balloon info.  When the request completes
2182
 * a QDict will be returned according to the following specification:
2198 2183
 *
2199
 * - "balloon": current balloon value in bytes
2184
 * - "actual": current balloon value in bytes
2185
 * The following fields may or may not be present:
2186
 * - "mem_swapped_in": Amount of memory swapped in (bytes)
2187
 * - "mem_swapped_out": Amount of memory swapped out (bytes)
2188
 * - "major_page_faults": Number of major faults
2189
 * - "minor_page_faults": Number of minor faults
2190
 * - "free_mem": Total amount of free and unused memory (bytes)
2191
 * - "total_mem": Total amount of available memory (bytes)
2200 2192
 *
2201 2193
 * Example:
2202 2194
 *
2203
 * { "balloon": 1073741824 }
2195
 * { "actual": 1073741824, "mem_swapped_in": 0, "mem_swapped_out": 0,
2196
 *   "major_page_faults": 142, "minor_page_faults": 239245,
2197
 *   "free_mem": 1014185984, "total_mem": 1044668416 }
2198
 */
2199
static int do_info_balloon(Monitor *mon, MonitorCompletion cb, void *opaque)
2200
{
2201
    int ret;
2202

  
2203
    if (kvm_enabled() && !kvm_has_sync_mmu()) {
2204
        qemu_error_new(QERR_KVM_MISSING_CAP, "synchronous MMU", "balloon");
2205
        return -1;
2206
    }
2207

  
2208
    ret = qemu_balloon_status(cb, opaque);
2209
    if (!ret) {
2210
        qemu_error_new(QERR_DEVICE_NOT_ACTIVE, "balloon");
2211
        return -1;
2212
    }
2213

  
2214
    return 0;
2215
}
2216

  
2217
/**
2218
 * do_balloon(): Request VM to change its memory allocation
2204 2219
 */
2205
static void do_info_balloon(Monitor *mon, QObject **ret_data)
2220
static int do_balloon(Monitor *mon, const QDict *params,
2221
                       MonitorCompletion cb, void *opaque)
2206 2222
{
2207
    ram_addr_t actual;
2223
    int ret;
2224

  
2225
    if (kvm_enabled() && !kvm_has_sync_mmu()) {
2226
        qemu_error_new(QERR_KVM_MISSING_CAP, "synchronous MMU", "balloon");
2227
        return -1;
2228
    }
2208 2229

  
2209
    actual = balloon_get_value();
2210
    if (actual != 0) {
2211
        *ret_data = qobject_from_jsonf("{ 'balloon': %" PRId64 "}",
2212
                                       (int64_t) actual);
2230
    ret = qemu_balloon(qdict_get_int(params, "value"), cb, opaque);
2231
    if (ret == 0) {
2232
        qemu_error_new(QERR_DEVICE_NOT_ACTIVE, "balloon");
2233
        return -1;
2213 2234
    }
2235

  
2236
    return 0;
2214 2237
}
2215 2238

  
2216 2239
static qemu_acl *find_acl(Monitor *mon, const char *name)
......
2696 2719
        .params     = "",
2697 2720
        .help       = "show balloon information",
2698 2721
        .user_print = monitor_print_balloon,
2699
        .mhandler.info_new = do_info_balloon,
2722
        .mhandler.info_async = do_info_balloon,
2723
        .async      = 1,
2700 2724
    },
2701 2725
    {
2702 2726
        .name       = "qtree",
b/qemu-monitor.hx
891 891
        .params     = "target",
892 892
        .help       = "request VM to change it's memory allocation (in MB)",
893 893
        .user_print = monitor_user_noop,
894
        .mhandler.cmd_new = do_balloon,
894
        .mhandler.cmd_async = do_balloon,
895
        .async      = 1,
895 896
    },
896 897

  
897 898
STEXI
b/vl.c
365 365
    qemu_balloon_event_opaque = opaque;
366 366
}
367 367

  
368
void qemu_balloon(ram_addr_t target)
368
int qemu_balloon(ram_addr_t target, MonitorCompletion cb, void *opaque)
369 369
{
370
    if (qemu_balloon_event)
371
        qemu_balloon_event(qemu_balloon_event_opaque, target);
370
    if (qemu_balloon_event) {
371
        qemu_balloon_event(qemu_balloon_event_opaque, target, cb, opaque);
372
        return 1;
373
    } else {
374
        return 0;
375
    }
372 376
}
373 377

  
374
ram_addr_t qemu_balloon_status(void)
378
int qemu_balloon_status(MonitorCompletion cb, void *opaque)
375 379
{
376
    if (qemu_balloon_event)
377
        return qemu_balloon_event(qemu_balloon_event_opaque, 0);
378
    return 0;
380
    if (qemu_balloon_event) {
381
        qemu_balloon_event(qemu_balloon_event_opaque, 0, cb, opaque);
382
        return 1;
383
    } else {
384
        return 0;
385
    }
379 386
}
380 387

  
381 388

  

Also available in: Unified diff