u32 pfns[256];
/* Memory statistics */
+ int need_stats_update;
struct virtio_balloon_stat stats[VIRTIO_BALLOON_S_NR];
};
* the stats queue operates in reverse. The driver initializes the virtqueue
* with a single buffer. From that point forward, all conversations consist of
* a hypervisor request (a call to this function) which directs us to refill
- * the virtqueue with a fresh stats buffer.
+ * the virtqueue with a fresh stats buffer. Since stats collection can sleep,
+ * we notify our kthread which does the actual work via stats_handle_request().
*/
-static void stats_ack(struct virtqueue *vq)
+static void stats_request(struct virtqueue *vq)
{
struct virtio_balloon *vb;
unsigned int len;
- struct scatterlist sg;
vb = vq->vq_ops->get_buf(vq, &len);
if (!vb)
return;
+ vb->need_stats_update = 1;
+ wake_up(&vb->config_change);
+}
+
+static void stats_handle_request(struct virtio_balloon *vb)
+{
+ struct virtqueue *vq;
+ struct scatterlist sg;
+ vb->need_stats_update = 0;
update_balloon_stats(vb);
+ vq = vb->stats_vq;
sg_init_one(&sg, vb->stats, sizeof(vb->stats));
if (vq->vq_ops->add_buf(vq, &sg, 1, 0, vb) < 0)
BUG();
try_to_freeze();
wait_event_interruptible(vb->config_change,
(diff = towards_target(vb)) != 0
+ || vb->need_stats_update
|| kthread_should_stop()
|| freezing(current));
+ if (vb->need_stats_update)
+ stats_handle_request(vb);
if (diff > 0)
fill_balloon(vb, diff);
else if (diff < 0)
{
struct virtio_balloon *vb;
struct virtqueue *vqs[3];
- vq_callback_t *callbacks[] = { balloon_ack, balloon_ack, stats_ack };
+ vq_callback_t *callbacks[] = { balloon_ack, balloon_ack, stats_request };
const char *names[] = { "inflate", "deflate", "stats" };
int err, nvqs;