aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRusty Russell <rusty@rustcorp.com.au>2008-02-04 23:50:12 -0500
committerRusty Russell <rusty@rustcorp.com.au>2008-02-04 07:50:13 -0500
commit6b35e40767c6c1ac783330109ae8e0c09ea6bc82 (patch)
treee820d770894cb945c3070fa6739b0149b1bfa2f9
parent55a7c066041e7850948d29ed813f62821a9ec046 (diff)
virtio: balloon driver
After discussions with Anthony Liguori, it seems that the virtio balloon can be made even simpler. Here's my attempt. The device configuration tells the driver how much memory it should take from the guest (ie. balloon size). The guest feeds the page numbers it has taken via one virtqueue. A second virtqueue feeds the page numbers the driver wants back: if the device has the VIRTIO_BALLOON_F_MUST_TELL_HOST bit, then this queue is compulsory, otherwise it's advisory (and the guest can simply fault the pages back in). This driver can be enhanced later to deflate the balloon via a shrinker, oom callback or we could even go for a complete set of in-guest regulators. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
-rw-r--r--drivers/virtio/Kconfig10
-rw-r--r--drivers/virtio/Makefile1
-rw-r--r--drivers/virtio/virtio_balloon.c284
-rw-r--r--include/linux/virtio_balloon.h18
4 files changed, 313 insertions, 0 deletions
diff --git a/drivers/virtio/Kconfig b/drivers/virtio/Kconfig
index 833db2f36e9b..3dd6294d10b6 100644
--- a/drivers/virtio/Kconfig
+++ b/drivers/virtio/Kconfig
@@ -23,3 +23,13 @@ config VIRTIO_PCI
23 23
24 If unsure, say M. 24 If unsure, say M.
25 25
26config VIRTIO_BALLOON
27 tristate "Virtio balloon driver (EXPERIMENTAL)"
28 select VIRTIO
29 select VIRTIO_RING
30 ---help---
31 This driver supports increasing and decreasing the amount
32 of memory within a KVM guest.
33
34 If unsure, say M.
35
diff --git a/drivers/virtio/Makefile b/drivers/virtio/Makefile
index cc84999f3057..6738c446c199 100644
--- a/drivers/virtio/Makefile
+++ b/drivers/virtio/Makefile
@@ -1,3 +1,4 @@
1obj-$(CONFIG_VIRTIO) += virtio.o 1obj-$(CONFIG_VIRTIO) += virtio.o
2obj-$(CONFIG_VIRTIO_RING) += virtio_ring.o 2obj-$(CONFIG_VIRTIO_RING) += virtio_ring.o
3obj-$(CONFIG_VIRTIO_PCI) += virtio_pci.o 3obj-$(CONFIG_VIRTIO_PCI) += virtio_pci.o
4obj-$(CONFIG_VIRTIO_BALLOON) += virtio_balloon.o
diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c
new file mode 100644
index 000000000000..622aece1acce
--- /dev/null
+++ b/drivers/virtio/virtio_balloon.c
@@ -0,0 +1,284 @@
1/* Virtio balloon implementation, inspired by Dor Loar and Marcelo
2 * Tosatti's implementations.
3 *
4 * Copyright 2008 Rusty Russell IBM Corporation
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20//#define DEBUG
21#include <linux/virtio.h>
22#include <linux/virtio_balloon.h>
23#include <linux/swap.h>
24#include <linux/kthread.h>
25#include <linux/freezer.h>
26
27struct virtio_balloon
28{
29 struct virtio_device *vdev;
30 struct virtqueue *inflate_vq, *deflate_vq;
31
32 /* Where the ballooning thread waits for config to change. */
33 wait_queue_head_t config_change;
34
35 /* The thread servicing the balloon. */
36 struct task_struct *thread;
37
38 /* Waiting for host to ack the pages we released. */
39 struct completion acked;
40
41 /* Do we have to tell Host *before* we reuse pages? */
42 bool tell_host_first;
43
44 /* The pages we've told the Host we're not using. */
45 unsigned int num_pages;
46 struct list_head pages;
47
48 /* The array of pfns we tell the Host about. */
49 unsigned int num_pfns;
50 u32 pfns[256];
51};
52
53static struct virtio_device_id id_table[] = {
54 { VIRTIO_ID_BALLOON, VIRTIO_DEV_ANY_ID },
55 { 0 },
56};
57
58static void balloon_ack(struct virtqueue *vq)
59{
60 struct virtio_balloon *vb;
61 unsigned int len;
62
63 vb = vq->vq_ops->get_buf(vq, &len);
64 if (vb)
65 complete(&vb->acked);
66}
67
68static void tell_host(struct virtio_balloon *vb, struct virtqueue *vq)
69{
70 struct scatterlist sg;
71
72 sg_init_one(&sg, vb->pfns, sizeof(vb->pfns[0]) * vb->num_pfns);
73
74 init_completion(&vb->acked);
75
76 /* We should always be able to add one buffer to an empty queue. */
77 if (vq->vq_ops->add_buf(vq, &sg, 1, 0, vb) != 0)
78 BUG();
79 vq->vq_ops->kick(vq);
80
81 /* When host has read buffer, this completes via balloon_ack */
82 wait_for_completion(&vb->acked);
83}
84
85static void fill_balloon(struct virtio_balloon *vb, size_t num)
86{
87 /* We can only do one array worth at a time. */
88 num = min(num, ARRAY_SIZE(vb->pfns));
89
90 for (vb->num_pfns = 0; vb->num_pfns < num; vb->num_pfns++) {
91 struct page *page = alloc_page(GFP_HIGHUSER | __GFP_NORETRY);
92 if (!page) {
93 if (printk_ratelimit())
94 dev_printk(KERN_INFO, &vb->vdev->dev,
95 "Out of puff! Can't get %zu pages\n",
96 num);
97 /* Sleep for at least 1/5 of a second before retry. */
98 msleep(200);
99 break;
100 }
101 vb->pfns[vb->num_pfns] = page_to_pfn(page);
102 totalram_pages--;
103 vb->num_pages++;
104 list_add(&page->lru, &vb->pages);
105 }
106
107 /* Didn't get any? Oh well. */
108 if (vb->num_pfns == 0)
109 return;
110
111 tell_host(vb, vb->inflate_vq);
112}
113
114static void release_pages_by_pfn(const u32 pfns[], unsigned int num)
115{
116 unsigned int i;
117
118 for (i = 0; i < num; i++) {
119 __free_page(pfn_to_page(pfns[i]));
120 totalram_pages++;
121 }
122}
123
124static void leak_balloon(struct virtio_balloon *vb, size_t num)
125{
126 struct page *page;
127
128 /* We can only do one array worth at a time. */
129 num = min(num, ARRAY_SIZE(vb->pfns));
130
131 for (vb->num_pfns = 0; vb->num_pfns < num; vb->num_pfns++) {
132 page = list_first_entry(&vb->pages, struct page, lru);
133 list_del(&page->lru);
134 vb->pfns[vb->num_pfns] = page_to_pfn(page);
135 vb->num_pages--;
136 }
137
138 if (vb->tell_host_first) {
139 tell_host(vb, vb->deflate_vq);
140 release_pages_by_pfn(vb->pfns, vb->num_pfns);
141 } else {
142 release_pages_by_pfn(vb->pfns, vb->num_pfns);
143 tell_host(vb, vb->deflate_vq);
144 }
145}
146
147static void virtballoon_changed(struct virtio_device *vdev)
148{
149 struct virtio_balloon *vb = vdev->priv;
150
151 wake_up(&vb->config_change);
152}
153
154static inline int towards_target(struct virtio_balloon *vb)
155{
156 u32 v;
157 __virtio_config_val(vb->vdev,
158 offsetof(struct virtio_balloon_config, num_pages),
159 &v);
160 return v - vb->num_pages;
161}
162
163static void update_balloon_size(struct virtio_balloon *vb)
164{
165 __le32 actual = cpu_to_le32(vb->num_pages);
166
167 vb->vdev->config->set(vb->vdev,
168 offsetof(struct virtio_balloon_config, actual),
169 &actual, sizeof(actual));
170}
171
172static int balloon(void *_vballoon)
173{
174 struct virtio_balloon *vb = _vballoon;
175
176 set_freezable();
177 while (!kthread_should_stop()) {
178 int diff;
179
180 try_to_freeze();
181 wait_event_interruptible(vb->config_change,
182 (diff = towards_target(vb)) != 0
183 || kthread_should_stop());
184 if (diff > 0)
185 fill_balloon(vb, diff);
186 else if (diff < 0)
187 leak_balloon(vb, -diff);
188 update_balloon_size(vb);
189 }
190 return 0;
191}
192
193static int virtballoon_probe(struct virtio_device *vdev)
194{
195 struct virtio_balloon *vb;
196 int err;
197
198 vdev->priv = vb = kmalloc(sizeof(*vb), GFP_KERNEL);
199 if (!vb) {
200 err = -ENOMEM;
201 goto out;
202 }
203
204 INIT_LIST_HEAD(&vb->pages);
205 vb->num_pages = 0;
206 init_waitqueue_head(&vb->config_change);
207 vb->vdev = vdev;
208
209 /* We expect two virtqueues. */
210 vb->inflate_vq = vdev->config->find_vq(vdev, 0, balloon_ack);
211 if (IS_ERR(vb->inflate_vq)) {
212 err = PTR_ERR(vb->inflate_vq);
213 goto out_free_vb;
214 }
215
216 vb->deflate_vq = vdev->config->find_vq(vdev, 1, balloon_ack);
217 if (IS_ERR(vb->deflate_vq)) {
218 err = PTR_ERR(vb->deflate_vq);
219 goto out_del_inflate_vq;
220 }
221
222 vb->thread = kthread_run(balloon, vb, "vballoon");
223 if (IS_ERR(vb->thread)) {
224 err = PTR_ERR(vb->thread);
225 goto out_del_deflate_vq;
226 }
227
228 vb->tell_host_first
229 = vdev->config->feature(vdev, VIRTIO_BALLOON_F_MUST_TELL_HOST);
230
231 return 0;
232
233out_del_deflate_vq:
234 vdev->config->del_vq(vb->deflate_vq);
235out_del_inflate_vq:
236 vdev->config->del_vq(vb->inflate_vq);
237out_free_vb:
238 kfree(vb);
239out:
240 return err;
241}
242
243static void virtballoon_remove(struct virtio_device *vdev)
244{
245 struct virtio_balloon *vb = vdev->priv;
246
247 kthread_stop(vb->thread);
248
249 /* There might be pages left in the balloon: free them. */
250 while (vb->num_pages)
251 leak_balloon(vb, vb->num_pages);
252
253 /* Now we reset the device so we can clean up the queues. */
254 vdev->config->reset(vdev);
255
256 vdev->config->del_vq(vb->deflate_vq);
257 vdev->config->del_vq(vb->inflate_vq);
258 kfree(vb);
259}
260
261static struct virtio_driver virtio_balloon = {
262 .driver.name = KBUILD_MODNAME,
263 .driver.owner = THIS_MODULE,
264 .id_table = id_table,
265 .probe = virtballoon_probe,
266 .remove = __devexit_p(virtballoon_remove),
267 .config_changed = virtballoon_changed,
268};
269
270static int __init init(void)
271{
272 return register_virtio_driver(&virtio_balloon);
273}
274
275static void __exit fini(void)
276{
277 unregister_virtio_driver(&virtio_balloon);
278}
279module_init(init);
280module_exit(fini);
281
282MODULE_DEVICE_TABLE(virtio, id_table);
283MODULE_DESCRIPTION("Virtio balloon driver");
284MODULE_LICENSE("GPL");
diff --git a/include/linux/virtio_balloon.h b/include/linux/virtio_balloon.h
new file mode 100644
index 000000000000..979524ee75b7
--- /dev/null
+++ b/include/linux/virtio_balloon.h
@@ -0,0 +1,18 @@
1#ifndef _LINUX_VIRTIO_BALLOON_H
2#define _LINUX_VIRTIO_BALLOON_H
3#include <linux/virtio_config.h>
4
5/* The ID for virtio_balloon */
6#define VIRTIO_ID_BALLOON 5
7
8/* The feature bitmap for virtio balloon */
9#define VIRTIO_BALLOON_F_MUST_TELL_HOST 0 /* Tell before reclaiming pages */
10
11struct virtio_balloon_config
12{
13 /* Number of pages host wants Guest to give up. */
14 __le32 num_pages;
15 /* Number of pages we've actually got in balloon. */
16 __le32 actual;
17};
18#endif /* _LINUX_VIRTIO_BALLOON_H */