diff options
author | Adam Litke <agl@us.ibm.com> | 2009-12-10 17:35:15 -0500 |
---|---|---|
committer | Rusty Russell <rusty@rustcorp.com.au> | 2010-02-23 22:52:14 -0500 |
commit | 1f34c71afe5115e77a49c4e67720a66e27053e54 (patch) | |
tree | f6481c9a5fbafffd2bd8cbf17274fdc75ffc94b7 /drivers/virtio/virtio_balloon.c | |
parent | 9564e138b1f6eb137f7149772438d3f3fb3277dd (diff) |
virtio: Fix scheduling while atomic in virtio_balloon stats
This is a fix for my earlier patch: "virtio: Add memory statistics reporting to
the balloon driver (V4)".
I discovered that all_vm_events() can sleep and therefore stats collection
cannot be done in interrupt context. One solution is to handle the interrupt
by noting that stats need to be collected and waking the existing vballoon
kthread which will complete the work via stats_handle_request(). Rusty, is
this a saner way of doing business?
There is one issue that I would like a broader opinion on. In stats_request, I
update vb->need_stats_update and then wake up the kthread. The kthread uses
vb->need_stats_update as a condition variable. Do I need a memory barrier
between the update and wake_up to ensure that my kthread sees the correct
value? My testing suggests that it is not needed but I would like some
confirmation from the experts.
Signed-off-by: Adam Litke <agl@us.ibm.com>
To: Rusty Russell <rusty@rustcorp.com.au>
Cc: Anthony Liguori <aliguori@linux.vnet.ibm.com>
Cc: linux-kernel@vger.kernel.org
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
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 | ||