diff options
Diffstat (limited to 'drivers/virtio/virtio_balloon.c')
-rw-r--r-- | drivers/virtio/virtio_balloon.c | 22 |
1 files changed, 18 insertions, 4 deletions
diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c index cd778b1752b5..3db3d242c3ee 100644 --- a/drivers/virtio/virtio_balloon.c +++ b/drivers/virtio/virtio_balloon.c | |||
@@ -51,6 +51,7 @@ struct virtio_balloon | |||
51 | u32 pfns[256]; | 51 | u32 pfns[256]; |
52 | 52 | ||
53 | /* Memory statistics */ | 53 | /* Memory statistics */ |
54 | int need_stats_update; | ||
54 | struct virtio_balloon_stat stats[VIRTIO_BALLOON_S_NR]; | 55 | struct virtio_balloon_stat stats[VIRTIO_BALLOON_S_NR]; |
55 | }; | 56 | }; |
56 | 57 | ||
@@ -193,20 +194,30 @@ static void update_balloon_stats(struct virtio_balloon *vb) | |||
193 | * the stats queue operates in reverse. The driver initializes the virtqueue | 194 | * 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 | * 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 | * a hypervisor request (a call to this function) which directs us to refill |
196 | * the virtqueue with a fresh stats buffer. | 197 | * the virtqueue with a fresh stats buffer. Since stats collection can sleep, |
198 | * we notify our kthread which does the actual work via stats_handle_request(). | ||
197 | */ | 199 | */ |
198 | static void stats_ack(struct virtqueue *vq) | 200 | static void stats_request(struct virtqueue *vq) |
199 | { | 201 | { |
200 | struct virtio_balloon *vb; | 202 | struct virtio_balloon *vb; |
201 | unsigned int len; | 203 | unsigned int len; |
202 | struct scatterlist sg; | ||
203 | 204 | ||
204 | vb = vq->vq_ops->get_buf(vq, &len); | 205 | vb = vq->vq_ops->get_buf(vq, &len); |
205 | if (!vb) | 206 | if (!vb) |
206 | return; | 207 | return; |
208 | vb->need_stats_update = 1; | ||
209 | wake_up(&vb->config_change); | ||
210 | } | ||
211 | |||
212 | static void stats_handle_request(struct virtio_balloon *vb) | ||
213 | { | ||
214 | struct virtqueue *vq; | ||
215 | struct scatterlist sg; | ||
207 | 216 | ||
217 | vb->need_stats_update = 0; | ||
208 | update_balloon_stats(vb); | 218 | update_balloon_stats(vb); |
209 | 219 | ||
220 | vq = vb->stats_vq; | ||
210 | sg_init_one(&sg, vb->stats, sizeof(vb->stats)); | 221 | sg_init_one(&sg, vb->stats, sizeof(vb->stats)); |
211 | if (vq->vq_ops->add_buf(vq, &sg, 1, 0, vb) < 0) | 222 | if (vq->vq_ops->add_buf(vq, &sg, 1, 0, vb) < 0) |
212 | BUG(); | 223 | BUG(); |
@@ -249,8 +260,11 @@ static int balloon(void *_vballoon) | |||
249 | try_to_freeze(); | 260 | try_to_freeze(); |
250 | wait_event_interruptible(vb->config_change, | 261 | wait_event_interruptible(vb->config_change, |
251 | (diff = towards_target(vb)) != 0 | 262 | (diff = towards_target(vb)) != 0 |
263 | || vb->need_stats_update | ||
252 | || kthread_should_stop() | 264 | || kthread_should_stop() |
253 | || freezing(current)); | 265 | || freezing(current)); |
266 | if (vb->need_stats_update) | ||
267 | stats_handle_request(vb); | ||
254 | if (diff > 0) | 268 | if (diff > 0) |
255 | fill_balloon(vb, diff); | 269 | fill_balloon(vb, diff); |
256 | else if (diff < 0) | 270 | else if (diff < 0) |
@@ -264,7 +278,7 @@ static int virtballoon_probe(struct virtio_device *vdev) | |||
264 | { | 278 | { |
265 | struct virtio_balloon *vb; | 279 | struct virtio_balloon *vb; |
266 | struct virtqueue *vqs[3]; | 280 | struct virtqueue *vqs[3]; |
267 | vq_callback_t *callbacks[] = { balloon_ack, balloon_ack, stats_ack }; | 281 | vq_callback_t *callbacks[] = { balloon_ack, balloon_ack, stats_request }; |
268 | const char *names[] = { "inflate", "deflate", "stats" }; | 282 | const char *names[] = { "inflate", "deflate", "stats" }; |
269 | int err, nvqs; | 283 | int err, nvqs; |
270 | 284 | ||