aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/virtio
diff options
context:
space:
mode:
authorAdam Litke <agl@us.ibm.com>2009-11-30 11:14:15 -0500
committerRusty Russell <rusty@rustcorp.com.au>2010-02-23 22:52:08 -0500
commit9564e138b1f6eb137f7149772438d3f3fb3277dd (patch)
tree2e53562c2b7ab7051d448b8f81766dc61ad524b5 /drivers/virtio
parent1f08b833ddbdb1c8e81c4b1053c2ebb7b89cb437 (diff)
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 <agl@us.ibm.com> Cc: Anthony Liguori <anthony@codemonkey.ws> Cc: virtualization@lists.linux-foundation.org Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> (minor fixes)
Diffstat (limited to 'drivers/virtio')
-rw-r--r--drivers/virtio/virtio_balloon.c94
1 files changed, 86 insertions, 8 deletions
diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c
index 505be88c82ae..cd778b1752b5 100644
--- a/drivers/virtio/virtio_balloon.c
+++ b/drivers/virtio/virtio_balloon.c
@@ -28,7 +28,7 @@
28struct virtio_balloon 28struct virtio_balloon
29{ 29{
30 struct virtio_device *vdev; 30 struct virtio_device *vdev;
31 struct virtqueue *inflate_vq, *deflate_vq; 31 struct virtqueue *inflate_vq, *deflate_vq, *stats_vq;
32 32
33 /* Where the ballooning thread waits for config to change. */ 33 /* Where the ballooning thread waits for config to change. */
34 wait_queue_head_t config_change; 34 wait_queue_head_t config_change;
@@ -49,6 +49,9 @@ struct virtio_balloon
49 /* The array of pfns we tell the Host about. */ 49 /* The array of pfns we tell the Host about. */
50 unsigned int num_pfns; 50 unsigned int num_pfns;
51 u32 pfns[256]; 51 u32 pfns[256];
52
53 /* Memory statistics */
54 struct virtio_balloon_stat stats[VIRTIO_BALLOON_S_NR];
52}; 55};
53 56
54static struct virtio_device_id id_table[] = { 57static struct virtio_device_id id_table[] = {
@@ -154,6 +157,62 @@ static void leak_balloon(struct virtio_balloon *vb, size_t num)
154 } 157 }
155} 158}
156 159
160static 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
170static 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 */
198static 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
157static void virtballoon_changed(struct virtio_device *vdev) 216static void virtballoon_changed(struct virtio_device *vdev)
158{ 217{
159 struct virtio_balloon *vb = vdev->priv; 218 struct virtio_balloon *vb = vdev->priv;
@@ -204,10 +263,10 @@ static int balloon(void *_vballoon)
204static int virtballoon_probe(struct virtio_device *vdev) 263static int virtballoon_probe(struct virtio_device *vdev)
205{ 264{
206 struct virtio_balloon *vb; 265 struct virtio_balloon *vb;
207 struct virtqueue *vqs[2]; 266 struct virtqueue *vqs[3];
208 vq_callback_t *callbacks[] = { balloon_ack, balloon_ack }; 267 vq_callback_t *callbacks[] = { balloon_ack, balloon_ack, stats_ack };
209 const char *names[] = { "inflate", "deflate" }; 268 const char *names[] = { "inflate", "deflate", "stats" };
210 int err; 269 int err, nvqs;
211 270
212 vdev->priv = vb = kmalloc(sizeof(*vb), GFP_KERNEL); 271 vdev->priv = vb = kmalloc(sizeof(*vb), GFP_KERNEL);
213 if (!vb) { 272 if (!vb) {
@@ -220,13 +279,29 @@ static int virtballoon_probe(struct virtio_device *vdev)
220 init_waitqueue_head(&vb->config_change); 279 init_waitqueue_head(&vb->config_change);
221 vb->vdev = vdev; 280 vb->vdev = vdev;
222 281
223 /* We expect two virtqueues. */ 282 /* We expect two virtqueues: inflate and deflate,
224 err = vdev->config->find_vqs(vdev, 2, vqs, callbacks, names); 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);
225 if (err) 286 if (err)
226 goto out_free_vb; 287 goto out_free_vb;
227 288
228 vb->inflate_vq = vqs[0]; 289 vb->inflate_vq = vqs[0];
229 vb->deflate_vq = vqs[1]; 290 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 }
230 305
231 vb->thread = kthread_run(balloon, vb, "vballoon"); 306 vb->thread = kthread_run(balloon, vb, "vballoon");
232 if (IS_ERR(vb->thread)) { 307 if (IS_ERR(vb->thread)) {
@@ -264,7 +339,10 @@ static void __devexit virtballoon_remove(struct virtio_device *vdev)
264 kfree(vb); 339 kfree(vb);
265} 340}
266 341
267static unsigned int features[] = { VIRTIO_BALLOON_F_MUST_TELL_HOST }; 342static unsigned int features[] = {
343 VIRTIO_BALLOON_F_MUST_TELL_HOST,
344 VIRTIO_BALLOON_F_STATS_VQ,
345};
268 346
269static struct virtio_driver virtio_balloon_driver = { 347static struct virtio_driver virtio_balloon_driver = {
270 .feature_table = features, 348 .feature_table = features,