Skip to content

Commit 9564e13

Browse files
Adam Litkerustyrussell
authored andcommitted
virtio: Add memory statistics reporting to the balloon driver (V4)
Changes since V3: - Do not do endian conversions as they will be done in the host - Report stats that reference a quantity of memory in bytes - Minor coding style updates Changes since V2: - Increase stat field size to 64 bits - Report all sizes in kb (not pages) - Drop anon_pages stat and fix endianness conversion Changes since V1: - Use a virtqueue instead of the device config space When using ballooning to manage overcommitted memory on a host, a system for guests to communicate their memory usage to the host can provide information that will minimize the impact of ballooning on the guests. The current method employs a daemon running in each guest that communicates memory statistics to a host daemon at a specified time interval. The host daemon aggregates this information and inflates and/or deflates balloons according to the level of host memory pressure. This approach is effective but overly complex since a daemon must be installed inside each guest and coordinated to communicate with the host. A simpler approach is to collect memory statistics in the virtio balloon driver and communicate them directly to the hypervisor. This patch enables the guest-side support by adding stats collection and reporting to the virtio balloon driver. Signed-off-by: Adam Litke <[email protected]> Cc: Anthony Liguori <[email protected]> Cc: [email protected] Signed-off-by: Rusty Russell <[email protected]> (minor fixes)
1 parent 1f08b83 commit 9564e13

File tree

2 files changed

+101
-8
lines changed

2 files changed

+101
-8
lines changed

drivers/virtio/virtio_balloon.c

Lines changed: 86 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
struct virtio_balloon
2929
{
3030
struct virtio_device *vdev;
31-
struct virtqueue *inflate_vq, *deflate_vq;
31+
struct virtqueue *inflate_vq, *deflate_vq, *stats_vq;
3232

3333
/* Where the ballooning thread waits for config to change. */
3434
wait_queue_head_t config_change;
@@ -49,6 +49,9 @@ struct virtio_balloon
4949
/* The array of pfns we tell the Host about. */
5050
unsigned int num_pfns;
5151
u32 pfns[256];
52+
53+
/* Memory statistics */
54+
struct virtio_balloon_stat stats[VIRTIO_BALLOON_S_NR];
5255
};
5356

5457
static struct virtio_device_id id_table[] = {
@@ -154,6 +157,62 @@ static void leak_balloon(struct virtio_balloon *vb, size_t num)
154157
}
155158
}
156159

160+
static inline void update_stat(struct virtio_balloon *vb, int idx,
161+
u16 tag, u64 val)
162+
{
163+
BUG_ON(idx >= VIRTIO_BALLOON_S_NR);
164+
vb->stats[idx].tag = tag;
165+
vb->stats[idx].val = val;
166+
}
167+
168+
#define pages_to_bytes(x) ((u64)(x) << PAGE_SHIFT)
169+
170+
static void update_balloon_stats(struct virtio_balloon *vb)
171+
{
172+
unsigned long events[NR_VM_EVENT_ITEMS];
173+
struct sysinfo i;
174+
int idx = 0;
175+
176+
all_vm_events(events);
177+
si_meminfo(&i);
178+
179+
update_stat(vb, idx++, VIRTIO_BALLOON_S_SWAP_IN,
180+
pages_to_bytes(events[PSWPIN]));
181+
update_stat(vb, idx++, VIRTIO_BALLOON_S_SWAP_OUT,
182+
pages_to_bytes(events[PSWPOUT]));
183+
update_stat(vb, idx++, VIRTIO_BALLOON_S_MAJFLT, events[PGMAJFAULT]);
184+
update_stat(vb, idx++, VIRTIO_BALLOON_S_MINFLT, events[PGFAULT]);
185+
update_stat(vb, idx++, VIRTIO_BALLOON_S_MEMFREE,
186+
pages_to_bytes(i.freeram));
187+
update_stat(vb, idx++, VIRTIO_BALLOON_S_MEMTOT,
188+
pages_to_bytes(i.totalram));
189+
}
190+
191+
/*
192+
* While most virtqueues communicate guest-initiated requests to the hypervisor,
193+
* the stats queue operates in reverse. The driver initializes the virtqueue
194+
* with a single buffer. From that point forward, all conversations consist of
195+
* a hypervisor request (a call to this function) which directs us to refill
196+
* the virtqueue with a fresh stats buffer.
197+
*/
198+
static void stats_ack(struct virtqueue *vq)
199+
{
200+
struct virtio_balloon *vb;
201+
unsigned int len;
202+
struct scatterlist sg;
203+
204+
vb = vq->vq_ops->get_buf(vq, &len);
205+
if (!vb)
206+
return;
207+
208+
update_balloon_stats(vb);
209+
210+
sg_init_one(&sg, vb->stats, sizeof(vb->stats));
211+
if (vq->vq_ops->add_buf(vq, &sg, 1, 0, vb) < 0)
212+
BUG();
213+
vq->vq_ops->kick(vq);
214+
}
215+
157216
static void virtballoon_changed(struct virtio_device *vdev)
158217
{
159218
struct virtio_balloon *vb = vdev->priv;
@@ -204,10 +263,10 @@ static int balloon(void *_vballoon)
204263
static int virtballoon_probe(struct virtio_device *vdev)
205264
{
206265
struct virtio_balloon *vb;
207-
struct virtqueue *vqs[2];
208-
vq_callback_t *callbacks[] = { balloon_ack, balloon_ack };
209-
const char *names[] = { "inflate", "deflate" };
210-
int err;
266+
struct virtqueue *vqs[3];
267+
vq_callback_t *callbacks[] = { balloon_ack, balloon_ack, stats_ack };
268+
const char *names[] = { "inflate", "deflate", "stats" };
269+
int err, nvqs;
211270

212271
vdev->priv = vb = kmalloc(sizeof(*vb), GFP_KERNEL);
213272
if (!vb) {
@@ -220,13 +279,29 @@ static int virtballoon_probe(struct virtio_device *vdev)
220279
init_waitqueue_head(&vb->config_change);
221280
vb->vdev = vdev;
222281

223-
/* We expect two virtqueues. */
224-
err = vdev->config->find_vqs(vdev, 2, vqs, callbacks, names);
282+
/* We expect two virtqueues: inflate and deflate,
283+
* and optionally stat. */
284+
nvqs = virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_STATS_VQ) ? 3 : 2;
285+
err = vdev->config->find_vqs(vdev, nvqs, vqs, callbacks, names);
225286
if (err)
226287
goto out_free_vb;
227288

228289
vb->inflate_vq = vqs[0];
229290
vb->deflate_vq = vqs[1];
291+
if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_STATS_VQ)) {
292+
struct scatterlist sg;
293+
vb->stats_vq = vqs[2];
294+
295+
/*
296+
* Prime this virtqueue with one buffer so the hypervisor can
297+
* use it to signal us later.
298+
*/
299+
sg_init_one(&sg, vb->stats, sizeof vb->stats);
300+
if (vb->stats_vq->vq_ops->add_buf(vb->stats_vq,
301+
&sg, 1, 0, vb) < 0)
302+
BUG();
303+
vb->stats_vq->vq_ops->kick(vb->stats_vq);
304+
}
230305

231306
vb->thread = kthread_run(balloon, vb, "vballoon");
232307
if (IS_ERR(vb->thread)) {
@@ -264,7 +339,10 @@ static void __devexit virtballoon_remove(struct virtio_device *vdev)
264339
kfree(vb);
265340
}
266341

267-
static unsigned int features[] = { VIRTIO_BALLOON_F_MUST_TELL_HOST };
342+
static unsigned int features[] = {
343+
VIRTIO_BALLOON_F_MUST_TELL_HOST,
344+
VIRTIO_BALLOON_F_STATS_VQ,
345+
};
268346

269347
static struct virtio_driver virtio_balloon_driver = {
270348
.feature_table = features,

include/linux/virtio_balloon.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
/* The feature bitmap for virtio balloon */
99
#define VIRTIO_BALLOON_F_MUST_TELL_HOST 0 /* Tell before reclaiming pages */
10+
#define VIRTIO_BALLOON_F_STATS_VQ 1 /* Memory Stats virtqueue */
1011

1112
/* Size of a PFN in the balloon interface. */
1213
#define VIRTIO_BALLOON_PFN_SHIFT 12
@@ -18,4 +19,18 @@ struct virtio_balloon_config
1819
/* Number of pages we've actually got in balloon. */
1920
__le32 actual;
2021
};
22+
23+
#define VIRTIO_BALLOON_S_SWAP_IN 0 /* Amount of memory swapped in */
24+
#define VIRTIO_BALLOON_S_SWAP_OUT 1 /* Amount of memory swapped out */
25+
#define VIRTIO_BALLOON_S_MAJFLT 2 /* Number of major faults */
26+
#define VIRTIO_BALLOON_S_MINFLT 3 /* Number of minor faults */
27+
#define VIRTIO_BALLOON_S_MEMFREE 4 /* Total amount of free memory */
28+
#define VIRTIO_BALLOON_S_MEMTOT 5 /* Total amount of memory */
29+
#define VIRTIO_BALLOON_S_NR 6
30+
31+
struct virtio_balloon_stat {
32+
u16 tag;
33+
u64 val;
34+
} __attribute__((packed));
35+
2136
#endif /* _LINUX_VIRTIO_BALLOON_H */

0 commit comments

Comments
 (0)