Statistics
| Branch: | Revision:

root / hw / virtio-balloon.c @ 99a0949b

History | View | Annotate | Download (4.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 "qemu-common.h"
15
#include "virtio.h"
16
#include "pc.h"
17
#include "sysemu.h"
18
#include "cpu.h"
19
#include "balloon.h"
20
#include "virtio-balloon.h"
21
#include "kvm.h"
22

    
23
#if defined(__linux__)
24
#include <sys/mman.h>
25
#endif
26

    
27
typedef struct VirtIOBalloon
28
{
29
    VirtIODevice vdev;
30
    VirtQueue *ivq, *dvq;
31
    uint32_t num_pages;
32
    uint32_t actual;
33
} VirtIOBalloon;
34

    
35
static VirtIOBalloon *to_virtio_balloon(VirtIODevice *vdev)
36
{
37
    return (VirtIOBalloon *)vdev;
38
}
39

    
40
static void balloon_page(void *addr, int deflate)
41
{
42
#if defined(__linux__)
43
    if (!kvm_enabled() || kvm_has_sync_mmu())
44
        madvise(addr, TARGET_PAGE_SIZE,
45
                deflate ? MADV_WILLNEED : MADV_DONTNEED);
46
#endif
47
}
48

    
49
/* FIXME: once we do a virtio refactoring, this will get subsumed into common
50
 * code */
51
static size_t memcpy_from_iovector(void *data, size_t offset, size_t size,
52
                                   struct iovec *iov, int iovlen)
53
{
54
    int i;
55
    uint8_t *ptr = data;
56
    size_t iov_off = 0;
57
    size_t data_off = 0;
58

    
59
    for (i = 0; i < iovlen && size; i++) {
60
        if (offset < (iov_off + iov[i].iov_len)) {
61
            size_t len = MIN((iov_off + iov[i].iov_len) - offset , size);
62

    
63
            memcpy(ptr + data_off, iov[i].iov_base + (offset - iov_off), len);
64

    
65
            data_off += len;
66
            offset += len;
67
            size -= len;
68
        }
69

    
70
        iov_off += iov[i].iov_len;
71
    }
72

    
73
    return data_off;
74
}
75

    
76
static void virtio_balloon_handle_output(VirtIODevice *vdev, VirtQueue *vq)
77
{
78
    VirtIOBalloon *s = to_virtio_balloon(vdev);
79
    VirtQueueElement elem;
80

    
81
    while (virtqueue_pop(vq, &elem)) {
82
        size_t offset = 0;
83
        uint32_t pfn;
84

    
85
        while (memcpy_from_iovector(&pfn, offset, 4,
86
                                    elem.out_sg, elem.out_num) == 4) {
87
            a_ram_addr pa;
88
            a_ram_addr addr;
89

    
90
            pa = (a_ram_addr)ldl_p(&pfn) << VIRTIO_BALLOON_PFN_SHIFT;
91
            offset += 4;
92

    
93
            addr = cpu_get_physical_page_desc(pa);
94
            if ((addr & ~TARGET_PAGE_MASK) != IO_MEM_RAM)
95
                continue;
96

    
97
            /* Using qemu_get_ram_ptr is bending the rules a bit, but
98
               should be OK because we only want a single page.  */
99
            balloon_page(qemu_get_ram_ptr(addr), !!(vq == s->dvq));
100
        }
101

    
102
        virtqueue_push(vq, &elem, offset);
103
        virtio_notify(vdev, vq);
104
    }
105
}
106

    
107
static void virtio_balloon_get_config(VirtIODevice *vdev, uint8_t *config_data)
108
{
109
    VirtIOBalloon *dev = to_virtio_balloon(vdev);
110
    struct virtio_balloon_config config;
111

    
112
    config.num_pages = cpu_to_le32(dev->num_pages);
113
    config.actual = cpu_to_le32(dev->actual);
114

    
115
    memcpy(config_data, &config, 8);
116
}
117

    
118
static void virtio_balloon_set_config(VirtIODevice *vdev,
119
                                      const uint8_t *config_data)
120
{
121
    VirtIOBalloon *dev = to_virtio_balloon(vdev);
122
    struct virtio_balloon_config config;
123
    memcpy(&config, config_data, 8);
124
    dev->actual = config.actual;
125
}
126

    
127
static uint32_t virtio_balloon_get_features(VirtIODevice *vdev)
128
{
129
    return 0;
130
}
131

    
132
static a_ram_addr virtio_balloon_to_target(void *opaque, a_ram_addr target)
133
{
134
    VirtIOBalloon *dev = opaque;
135

    
136
    if (target > ram_size)
137
        target = ram_size;
138

    
139
    if (target) {
140
        dev->num_pages = (ram_size - target) >> VIRTIO_BALLOON_PFN_SHIFT;
141
        virtio_notify_config(&dev->vdev);
142
    }
143

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

    
147
static void virtio_balloon_save(QEMUFile *f, void *opaque)
148
{
149
    VirtIOBalloon *s = opaque;
150

    
151
    virtio_save(&s->vdev, f);
152

    
153
    qemu_put_be32(f, s->num_pages);
154
    qemu_put_be32(f, s->actual);
155
}
156

    
157
static int virtio_balloon_load(QEMUFile *f, void *opaque, int version_id)
158
{
159
    VirtIOBalloon *s = opaque;
160

    
161
    if (version_id != 1)
162
        return -EINVAL;
163

    
164
    virtio_load(&s->vdev, f);
165

    
166
    s->num_pages = qemu_get_be32(f);
167
    s->actual = qemu_get_be32(f);
168

    
169
    return 0;
170
}
171

    
172
VirtIODevice *virtio_balloon_init(DeviceState *dev)
173
{
174
    VirtIOBalloon *s;
175

    
176
    s = (VirtIOBalloon *)virtio_common_init("virtio-balloon",
177
                                            VIRTIO_ID_BALLOON,
178
                                            8, sizeof(VirtIOBalloon));
179

    
180
    s->vdev.get_config = virtio_balloon_get_config;
181
    s->vdev.set_config = virtio_balloon_set_config;
182
    s->vdev.get_features = virtio_balloon_get_features;
183

    
184
    s->ivq = virtio_add_queue(&s->vdev, 128, virtio_balloon_handle_output);
185
    s->dvq = virtio_add_queue(&s->vdev, 128, virtio_balloon_handle_output);
186

    
187
    qemu_add_balloon_handler(virtio_balloon_to_target, s);
188

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

    
191
    return &s->vdev;
192
}