aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPetr Mladek <pmladek@suse.com>2016-01-25 11:38:06 -0500
committerMichael S. Tsirkin <mst@redhat.com>2016-03-10 18:40:18 -0500
commitfd0e21c31e1e6383af978239d07ced6e4e5d82c3 (patch)
treeaa3b42f69bdbf3bc8a9def98841d4b4c2fa1df85
parentfad7b7b27b6a168ca8ebc84482043886f837b89d (diff)
virtio_balloon: Allow to resize and update the balloon stats in parallel
The virtio balloon statistics are not updated when the balloon is being resized. But it seems that both tasks could be done in parallel. stats_handle_request() updates the statistics in the balloon structure and then communicates with the host. update_balloon_stats() calls all_vm_events() that just reads some per-CPU variables. The values might change during and after the call but it is expected and happens even without this patch. update_balloon_stats() also calls si_meminfo(). It is a bit more complex function. It too just reads some variables and looks lock-less safe. In each case, it seems to be called lock-less on several similar locations, e.g. from post_status() in dm_thread_func(), or from vmballoon_send_get_target(). The communication with the host is done via a separate virtqueue, see vb->stats_vq vs. vb->inflate_vq and vb->deflate_vq. Therefore it could be used in parallel with fill_balloon() and leak_balloon(). This patch splits the existing work into two pieces. One is for updating the balloon stats. The other is for resizing of the balloon. It seems that they can be proceed in parallel without any extra locking. Signed-off-by: Petr Mladek <pmladek@suse.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
-rw-r--r--drivers/virtio/virtio_balloon.c36
1 files changed, 21 insertions, 15 deletions
diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c
index 2c9a92f1e525..9057cc768ca5 100644
--- a/drivers/virtio/virtio_balloon.c
+++ b/drivers/virtio/virtio_balloon.c
@@ -49,7 +49,8 @@ struct virtio_balloon {
49 struct virtqueue *inflate_vq, *deflate_vq, *stats_vq; 49 struct virtqueue *inflate_vq, *deflate_vq, *stats_vq;
50 50
51 /* The balloon servicing is delegated to a freezable workqueue. */ 51 /* The balloon servicing is delegated to a freezable workqueue. */
52 struct work_struct work; 52 struct work_struct update_balloon_stats_work;
53 struct work_struct update_balloon_size_work;
53 54
54 /* Prevent updating balloon when it is being canceled. */ 55 /* Prevent updating balloon when it is being canceled. */
55 spinlock_t stop_update_lock; 56 spinlock_t stop_update_lock;
@@ -76,7 +77,6 @@ struct virtio_balloon {
76 u32 pfns[VIRTIO_BALLOON_ARRAY_PFNS_MAX]; 77 u32 pfns[VIRTIO_BALLOON_ARRAY_PFNS_MAX];
77 78
78 /* Memory statistics */ 79 /* Memory statistics */
79 int need_stats_update;
80 struct virtio_balloon_stat stats[VIRTIO_BALLOON_S_NR]; 80 struct virtio_balloon_stat stats[VIRTIO_BALLOON_S_NR];
81 81
82 /* To register callback in oom notifier call chain */ 82 /* To register callback in oom notifier call chain */
@@ -123,6 +123,7 @@ static void tell_host(struct virtio_balloon *vb, struct virtqueue *vq)
123 123
124 /* When host has read buffer, this completes via balloon_ack */ 124 /* When host has read buffer, this completes via balloon_ack */
125 wait_event(vb->acked, virtqueue_get_buf(vq, &len)); 125 wait_event(vb->acked, virtqueue_get_buf(vq, &len));
126
126} 127}
127 128
128static void set_page_pfns(u32 pfns[], struct page *page) 129static void set_page_pfns(u32 pfns[], struct page *page)
@@ -262,11 +263,9 @@ static void stats_request(struct virtqueue *vq)
262{ 263{
263 struct virtio_balloon *vb = vq->vdev->priv; 264 struct virtio_balloon *vb = vq->vdev->priv;
264 265
265 vb->need_stats_update = 1;
266
267 spin_lock(&vb->stop_update_lock); 266 spin_lock(&vb->stop_update_lock);
268 if (!vb->stop_update) 267 if (!vb->stop_update)
269 queue_work(system_freezable_wq, &vb->work); 268 queue_work(system_freezable_wq, &vb->update_balloon_stats_work);
270 spin_unlock(&vb->stop_update_lock); 269 spin_unlock(&vb->stop_update_lock);
271} 270}
272 271
@@ -276,7 +275,6 @@ static void stats_handle_request(struct virtio_balloon *vb)
276 struct scatterlist sg; 275 struct scatterlist sg;
277 unsigned int len; 276 unsigned int len;
278 277
279 vb->need_stats_update = 0;
280 update_balloon_stats(vb); 278 update_balloon_stats(vb);
281 279
282 vq = vb->stats_vq; 280 vq = vb->stats_vq;
@@ -294,7 +292,7 @@ static void virtballoon_changed(struct virtio_device *vdev)
294 292
295 spin_lock_irqsave(&vb->stop_update_lock, flags); 293 spin_lock_irqsave(&vb->stop_update_lock, flags);
296 if (!vb->stop_update) 294 if (!vb->stop_update)
297 queue_work(system_freezable_wq, &vb->work); 295 queue_work(system_freezable_wq, &vb->update_balloon_size_work);
298 spin_unlock_irqrestore(&vb->stop_update_lock, flags); 296 spin_unlock_irqrestore(&vb->stop_update_lock, flags);
299} 297}
300 298
@@ -358,17 +356,24 @@ static int virtballoon_oom_notify(struct notifier_block *self,
358 return NOTIFY_OK; 356 return NOTIFY_OK;
359} 357}
360 358
361static void balloon(struct work_struct *work) 359static void update_balloon_stats_func(struct work_struct *work)
360{
361 struct virtio_balloon *vb;
362
363 vb = container_of(work, struct virtio_balloon,
364 update_balloon_stats_work);
365 stats_handle_request(vb);
366}
367
368static void update_balloon_size_func(struct work_struct *work)
362{ 369{
363 struct virtio_balloon *vb; 370 struct virtio_balloon *vb;
364 s64 diff; 371 s64 diff;
365 372
366 vb = container_of(work, struct virtio_balloon, work); 373 vb = container_of(work, struct virtio_balloon,
374 update_balloon_size_work);
367 diff = towards_target(vb); 375 diff = towards_target(vb);
368 376
369 if (vb->need_stats_update)
370 stats_handle_request(vb);
371
372 if (diff > 0) 377 if (diff > 0)
373 diff -= fill_balloon(vb, diff); 378 diff -= fill_balloon(vb, diff);
374 else if (diff < 0) 379 else if (diff < 0)
@@ -494,14 +499,14 @@ static int virtballoon_probe(struct virtio_device *vdev)
494 goto out; 499 goto out;
495 } 500 }
496 501
497 INIT_WORK(&vb->work, balloon); 502 INIT_WORK(&vb->update_balloon_stats_work, update_balloon_stats_func);
503 INIT_WORK(&vb->update_balloon_size_work, update_balloon_size_func);
498 spin_lock_init(&vb->stop_update_lock); 504 spin_lock_init(&vb->stop_update_lock);
499 vb->stop_update = false; 505 vb->stop_update = false;
500 vb->num_pages = 0; 506 vb->num_pages = 0;
501 mutex_init(&vb->balloon_lock); 507 mutex_init(&vb->balloon_lock);
502 init_waitqueue_head(&vb->acked); 508 init_waitqueue_head(&vb->acked);
503 vb->vdev = vdev; 509 vb->vdev = vdev;
504 vb->need_stats_update = 0;
505 510
506 balloon_devinfo_init(&vb->vb_dev_info); 511 balloon_devinfo_init(&vb->vb_dev_info);
507#ifdef CONFIG_BALLOON_COMPACTION 512#ifdef CONFIG_BALLOON_COMPACTION
@@ -552,7 +557,8 @@ static void virtballoon_remove(struct virtio_device *vdev)
552 spin_lock_irq(&vb->stop_update_lock); 557 spin_lock_irq(&vb->stop_update_lock);
553 vb->stop_update = true; 558 vb->stop_update = true;
554 spin_unlock_irq(&vb->stop_update_lock); 559 spin_unlock_irq(&vb->stop_update_lock);
555 cancel_work_sync(&vb->work); 560 cancel_work_sync(&vb->update_balloon_size_work);
561 cancel_work_sync(&vb->update_balloon_stats_work);
556 562
557 remove_common(vb); 563 remove_common(vb);
558 kfree(vb); 564 kfree(vb);