Skip to content

Commit

Permalink
virtio_balloon: Allow to resize and update the balloon stats in parallel
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: Michael S. Tsirkin <[email protected]>
  • Loading branch information
pmladek authored and mstsirkin committed Mar 10, 2016
1 parent fad7b7b commit fd0e21c
Showing 1 changed file with 21 additions and 15 deletions.
36 changes: 21 additions & 15 deletions drivers/virtio/virtio_balloon.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ struct virtio_balloon {
struct virtqueue *inflate_vq, *deflate_vq, *stats_vq;

/* The balloon servicing is delegated to a freezable workqueue. */
struct work_struct work;
struct work_struct update_balloon_stats_work;
struct work_struct update_balloon_size_work;

/* Prevent updating balloon when it is being canceled. */
spinlock_t stop_update_lock;
Expand All @@ -76,7 +77,6 @@ struct virtio_balloon {
u32 pfns[VIRTIO_BALLOON_ARRAY_PFNS_MAX];

/* Memory statistics */
int need_stats_update;
struct virtio_balloon_stat stats[VIRTIO_BALLOON_S_NR];

/* To register callback in oom notifier call chain */
Expand Down Expand Up @@ -123,6 +123,7 @@ static void tell_host(struct virtio_balloon *vb, struct virtqueue *vq)

/* When host has read buffer, this completes via balloon_ack */
wait_event(vb->acked, virtqueue_get_buf(vq, &len));

}

static void set_page_pfns(u32 pfns[], struct page *page)
Expand Down Expand Up @@ -262,11 +263,9 @@ static void stats_request(struct virtqueue *vq)
{
struct virtio_balloon *vb = vq->vdev->priv;

vb->need_stats_update = 1;

spin_lock(&vb->stop_update_lock);
if (!vb->stop_update)
queue_work(system_freezable_wq, &vb->work);
queue_work(system_freezable_wq, &vb->update_balloon_stats_work);
spin_unlock(&vb->stop_update_lock);
}

Expand All @@ -276,7 +275,6 @@ static void stats_handle_request(struct virtio_balloon *vb)
struct scatterlist sg;
unsigned int len;

vb->need_stats_update = 0;
update_balloon_stats(vb);

vq = vb->stats_vq;
Expand All @@ -294,7 +292,7 @@ static void virtballoon_changed(struct virtio_device *vdev)

spin_lock_irqsave(&vb->stop_update_lock, flags);
if (!vb->stop_update)
queue_work(system_freezable_wq, &vb->work);
queue_work(system_freezable_wq, &vb->update_balloon_size_work);
spin_unlock_irqrestore(&vb->stop_update_lock, flags);
}

Expand Down Expand Up @@ -358,17 +356,24 @@ static int virtballoon_oom_notify(struct notifier_block *self,
return NOTIFY_OK;
}

static void balloon(struct work_struct *work)
static void update_balloon_stats_func(struct work_struct *work)
{
struct virtio_balloon *vb;

vb = container_of(work, struct virtio_balloon,
update_balloon_stats_work);
stats_handle_request(vb);
}

static void update_balloon_size_func(struct work_struct *work)
{
struct virtio_balloon *vb;
s64 diff;

vb = container_of(work, struct virtio_balloon, work);
vb = container_of(work, struct virtio_balloon,
update_balloon_size_work);
diff = towards_target(vb);

if (vb->need_stats_update)
stats_handle_request(vb);

if (diff > 0)
diff -= fill_balloon(vb, diff);
else if (diff < 0)
Expand Down Expand Up @@ -494,14 +499,14 @@ static int virtballoon_probe(struct virtio_device *vdev)
goto out;
}

INIT_WORK(&vb->work, balloon);
INIT_WORK(&vb->update_balloon_stats_work, update_balloon_stats_func);
INIT_WORK(&vb->update_balloon_size_work, update_balloon_size_func);
spin_lock_init(&vb->stop_update_lock);
vb->stop_update = false;
vb->num_pages = 0;
mutex_init(&vb->balloon_lock);
init_waitqueue_head(&vb->acked);
vb->vdev = vdev;
vb->need_stats_update = 0;

balloon_devinfo_init(&vb->vb_dev_info);
#ifdef CONFIG_BALLOON_COMPACTION
Expand Down Expand Up @@ -552,7 +557,8 @@ static void virtballoon_remove(struct virtio_device *vdev)
spin_lock_irq(&vb->stop_update_lock);
vb->stop_update = true;
spin_unlock_irq(&vb->stop_update_lock);
cancel_work_sync(&vb->work);
cancel_work_sync(&vb->update_balloon_size_work);
cancel_work_sync(&vb->update_balloon_stats_work);

remove_common(vb);
kfree(vb);
Expand Down

0 comments on commit fd0e21c

Please sign in to comment.