aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/virtio
diff options
context:
space:
mode:
authorAdam Litke <agl@us.ibm.com>2009-12-10 17:35:15 -0500
committerRusty Russell <rusty@rustcorp.com.au>2010-02-23 22:52:14 -0500
commit1f34c71afe5115e77a49c4e67720a66e27053e54 (patch)
treef6481c9a5fbafffd2bd8cbf17274fdc75ffc94b7 /drivers/virtio
parent9564e138b1f6eb137f7149772438d3f3fb3277dd (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')
-rw-r--r--drivers/virtio/virtio_balloon.c22
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 */
198static void stats_ack(struct virtqueue *vq) 200static 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
212static 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