Statistics
| Branch: | Revision:

root / hw / virtio-balloon.c @ bc20ba98

History | View | Annotate | Download (7.8 kB)

1
/*
2
 * Virtio Block Device
3
 *
4
 * Copyright IBM, Corp. 2008
5
 *
6
 * Authors:
7
 *  Anthony Liguori   <aliguori@us.ibm.com>
8
 *
9
 * This work is licensed under the terms of the GNU GPL, version 2.  See
10
 * the COPYING file in the top-level directory.
11
 *
12
 */
13

    
14
#include "iov.h"
15
#include "qemu-common.h"
16
#include "virtio.h"
17
#include "pc.h"
18
#include "sysemu.h"
19
#include "cpu.h"
20
#include "monitor.h"
21
#include "balloon.h"
22
#include "virtio-balloon.h"
23
#include "kvm.h"
24
#include "qlist.h"
25
#include "qint.h"
26
#include "qstring.h"
27

    
28
#if defined(__linux__)
29
#include <sys/mman.h>
30
#endif
31

    
32
typedef struct VirtIOBalloon
33
{
34
    VirtIODevice vdev;
35
    VirtQueue *ivq, *dvq, *svq;
36
    uint32_t num_pages;
37
    uint32_t actual;
38
    uint64_t stats[VIRTIO_BALLOON_S_NR];
39
    VirtQueueElement stats_vq_elem;
40
    size_t stats_vq_offset;
41
    MonitorCompletion *stats_callback;
42
    void *stats_opaque_callback_data;
43
} VirtIOBalloon;
44

    
45
static VirtIOBalloon *to_virtio_balloon(VirtIODevice *vdev)
46
{
47
    return (VirtIOBalloon *)vdev;
48
}
49

    
50
static void balloon_page(void *addr, int deflate)
51
{
52
#if defined(__linux__)
53
    if (!kvm_enabled() || kvm_has_sync_mmu())
54
        madvise(addr, TARGET_PAGE_SIZE,
55
                deflate ? MADV_WILLNEED : MADV_DONTNEED);
56
#endif
57
}
58

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

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

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

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

    
93
    return QOBJECT(dict);
94
}
95

    
96
static void virtio_balloon_handle_output(VirtIODevice *vdev, VirtQueue *vq)
97
{
98
    VirtIOBalloon *s = to_virtio_balloon(vdev);
99
    VirtQueueElement elem;
100

    
101
    while (virtqueue_pop(vq, &elem)) {
102
        size_t offset = 0;
103
        uint32_t pfn;
104

    
105
        while (iov_to_buf(elem.out_sg, elem.out_num, &pfn, offset, 4) == 4) {
106
            ram_addr_t pa;
107
            ram_addr_t addr;
108

    
109
            pa = (ram_addr_t)ldl_p(&pfn) << VIRTIO_BALLOON_PFN_SHIFT;
110
            offset += 4;
111

    
112
            addr = cpu_get_physical_page_desc(pa);
113
            if ((addr & ~TARGET_PAGE_MASK) != IO_MEM_RAM)
114
                continue;
115

    
116
            /* Using qemu_get_ram_ptr is bending the rules a bit, but
117
               should be OK because we only want a single page.  */
118
            balloon_page(qemu_get_ram_ptr(addr), !!(vq == s->dvq));
119
        }
120

    
121
        virtqueue_push(vq, &elem, offset);
122
        virtio_notify(vdev, vq);
123
    }
124
}
125

    
126
static void complete_stats_request(VirtIOBalloon *vb)
127
{
128
    QObject *stats;
129

    
130
    if (!vb->stats_opaque_callback_data)
131
        return;
132

    
133
    stats = get_stats_qobject(vb);
134
    vb->stats_callback(vb->stats_opaque_callback_data, stats);
135
    qobject_decref(stats);
136
    vb->stats_opaque_callback_data = NULL;
137
    vb->stats_callback = NULL;
138
}
139

    
140
static void virtio_balloon_receive_stats(VirtIODevice *vdev, VirtQueue *vq)
141
{
142
    VirtIOBalloon *s = DO_UPCAST(VirtIOBalloon, vdev, vdev);
143
    VirtQueueElement *elem = &s->stats_vq_elem;
144
    VirtIOBalloonStat stat;
145
    size_t offset = 0;
146

    
147
    if (!virtqueue_pop(vq, elem)) {
148
        return;
149
    }
150

    
151
    /* Initialize the stats to get rid of any stale values.  This is only
152
     * needed to handle the case where a guest supports fewer stats than it
153
     * used to (ie. it has booted into an old kernel).
154
     */
155
    reset_stats(s);
156

    
157
    while (iov_to_buf(elem->out_sg, elem->out_num, &stat, offset, sizeof(stat))
158
           == sizeof(stat)) {
159
        uint16_t tag = tswap16(stat.tag);
160
        uint64_t val = tswap64(stat.val);
161

    
162
        offset += sizeof(stat);
163
        if (tag < VIRTIO_BALLOON_S_NR)
164
            s->stats[tag] = val;
165
    }
166
    s->stats_vq_offset = offset;
167

    
168
    complete_stats_request(s);
169
}
170

    
171
static void virtio_balloon_get_config(VirtIODevice *vdev, uint8_t *config_data)
172
{
173
    VirtIOBalloon *dev = to_virtio_balloon(vdev);
174
    struct virtio_balloon_config config;
175

    
176
    config.num_pages = cpu_to_le32(dev->num_pages);
177
    config.actual = cpu_to_le32(dev->actual);
178

    
179
    memcpy(config_data, &config, 8);
180
}
181

    
182
static void virtio_balloon_set_config(VirtIODevice *vdev,
183
                                      const uint8_t *config_data)
184
{
185
    VirtIOBalloon *dev = to_virtio_balloon(vdev);
186
    struct virtio_balloon_config config;
187
    memcpy(&config, config_data, 8);
188
    dev->actual = config.actual;
189
}
190

    
191
static uint32_t virtio_balloon_get_features(VirtIODevice *vdev, uint32_t f)
192
{
193
    f |= (1 << VIRTIO_BALLOON_F_STATS_VQ);
194
    return f;
195
}
196

    
197
static void virtio_balloon_to_target(void *opaque, ram_addr_t target,
198
                                     MonitorCompletion cb, void *cb_data)
199
{
200
    VirtIOBalloon *dev = opaque;
201

    
202
    if (target > ram_size)
203
        target = ram_size;
204

    
205
    if (target) {
206
        dev->num_pages = (ram_size - target) >> VIRTIO_BALLOON_PFN_SHIFT;
207
        virtio_notify_config(&dev->vdev);
208
    } else {
209
        /* For now, only allow one request at a time.  This restriction can be
210
         * removed later by queueing callback and data pairs.
211
         */
212
        if (dev->stats_callback != NULL) {
213
            return;
214
        }
215
        dev->stats_callback = cb;
216
        dev->stats_opaque_callback_data = cb_data; 
217
        if (dev->vdev.guest_features & (1 << VIRTIO_BALLOON_F_STATS_VQ)) {
218
            virtqueue_push(dev->svq, &dev->stats_vq_elem, dev->stats_vq_offset);
219
            virtio_notify(&dev->vdev, dev->svq);
220
        } else {
221
            /* Stats are not supported.  Clear out any stale values that might
222
             * have been set by a more featureful guest kernel.
223
             */
224
            reset_stats(dev);
225
            complete_stats_request(dev);
226
        }
227
    }
228
}
229

    
230
static void virtio_balloon_save(QEMUFile *f, void *opaque)
231
{
232
    VirtIOBalloon *s = opaque;
233

    
234
    virtio_save(&s->vdev, f);
235

    
236
    qemu_put_be32(f, s->num_pages);
237
    qemu_put_be32(f, s->actual);
238
}
239

    
240
static int virtio_balloon_load(QEMUFile *f, void *opaque, int version_id)
241
{
242
    VirtIOBalloon *s = opaque;
243

    
244
    if (version_id != 1)
245
        return -EINVAL;
246

    
247
    virtio_load(&s->vdev, f);
248

    
249
    s->num_pages = qemu_get_be32(f);
250
    s->actual = qemu_get_be32(f);
251
    return 0;
252
}
253

    
254
VirtIODevice *virtio_balloon_init(DeviceState *dev)
255
{
256
    VirtIOBalloon *s;
257

    
258
    s = (VirtIOBalloon *)virtio_common_init("virtio-balloon",
259
                                            VIRTIO_ID_BALLOON,
260
                                            8, sizeof(VirtIOBalloon));
261

    
262
    s->vdev.get_config = virtio_balloon_get_config;
263
    s->vdev.set_config = virtio_balloon_set_config;
264
    s->vdev.get_features = virtio_balloon_get_features;
265

    
266
    s->ivq = virtio_add_queue(&s->vdev, 128, virtio_balloon_handle_output);
267
    s->dvq = virtio_add_queue(&s->vdev, 128, virtio_balloon_handle_output);
268
    s->svq = virtio_add_queue(&s->vdev, 128, virtio_balloon_receive_stats);
269

    
270
    reset_stats(s);
271
    qemu_add_balloon_handler(virtio_balloon_to_target, s);
272

    
273
    register_savevm(dev, "virtio-balloon", -1, 1,
274
                    virtio_balloon_save, virtio_balloon_load, s);
275

    
276
    return &s->vdev;
277
}