Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


Fail gracefully on VM create or free errors
[palacios.git] / linux_module / vm.c
1 /* 
2  * VM specific Controls
3  * (c) Jack Lange, 2010
4  */
5
6 #include <linux/device.h>
7 #include <linux/cdev.h>
8 #include <linux/errno.h>
9 #include <linux/percpu.h>
10 #include <linux/fs.h>
11 #include <linux/uaccess.h>
12 #include <linux/poll.h>
13 #include <linux/anon_inodes.h>
14 #include <linux/sched.h>
15 #include <linux/vmalloc.h>
16 #include <linux/file.h>
17 #include <linux/spinlock.h>
18 #include <linux/rbtree.h>
19 #include <linux/module.h>
20
21 #include <palacios/vmm.h>
22 #include <palacios/vmm_host_events.h>
23
24 #include "palacios.h"
25 #include "vm.h"
26 #include "linux-exts.h"
27
28
29 struct vm_ctrl {
30     unsigned int cmd;
31
32     int (*handler)(struct v3_guest * guest, 
33                    unsigned int cmd, unsigned long arg, 
34                    void * priv_data);
35
36     void * priv_data;
37
38     struct rb_node tree_node;
39 };
40
41
42 static inline struct vm_ctrl * __insert_ctrl(struct v3_guest * vm, 
43                                              struct vm_ctrl * ctrl) {
44     struct rb_node ** p = &(vm->vm_ctrls.rb_node);
45     struct rb_node * parent = NULL;
46     struct vm_ctrl * tmp_ctrl = NULL;
47
48     while (*p) {
49         parent = *p;
50         tmp_ctrl = rb_entry(parent, struct vm_ctrl, tree_node);
51
52         if (ctrl->cmd < tmp_ctrl->cmd) {
53             p = &(*p)->rb_left;
54         } else if (ctrl->cmd > tmp_ctrl->cmd) {
55             p = &(*p)->rb_right;
56         } else {
57             return tmp_ctrl;
58         }
59     }
60
61     rb_link_node(&(ctrl->tree_node), parent, p);
62
63     return NULL;
64 }
65
66
67
68 int add_guest_ctrl(struct v3_guest * guest, unsigned int cmd, 
69                    int (*handler)(struct v3_guest * guest, 
70                                   unsigned int cmd, unsigned long arg, 
71                                   void * priv_data),
72                    void * priv_data) {
73     struct vm_ctrl * ctrl = palacios_alloc(sizeof(struct vm_ctrl));
74
75     if (ctrl == NULL) {
76         WARNING("Error: Could not allocate vm ctrl %d\n", cmd);
77         return -1;
78     }
79
80     ctrl->cmd = cmd;
81     ctrl->handler = handler;
82     ctrl->priv_data = priv_data;
83
84     if (__insert_ctrl(guest, ctrl) != NULL) {
85         WARNING("Could not insert guest ctrl %d\n", cmd);
86         palacios_free(ctrl);
87         return -1;
88     }
89     
90     rb_insert_color(&(ctrl->tree_node), &(guest->vm_ctrls));
91
92     return 0;
93 }
94
95
96 static struct vm_ctrl * get_ctrl(struct v3_guest * guest, unsigned int cmd) {
97     struct rb_node * n = guest->vm_ctrls.rb_node;
98     struct vm_ctrl * ctrl = NULL;
99
100     while (n) {
101         ctrl = rb_entry(n, struct vm_ctrl, tree_node);
102
103         if (cmd < ctrl->cmd) {
104             n = n->rb_left;
105         } else if (cmd > ctrl->cmd) {
106             n = n->rb_right;
107         } else {
108             return ctrl;
109         }
110     }
111
112     return NULL;
113 }
114
115
116
117
118
119
120
121 extern struct class * v3_class;
122
123
124 static long v3_vm_ioctl(struct file * filp,
125                         unsigned int ioctl, unsigned long arg) {
126
127     struct v3_guest * guest = filp->private_data;
128
129     INFO("V3 IOCTL %d\n", ioctl);
130
131     switch (ioctl) {
132         case V3_VM_LAUNCH: {
133             NOTICE("palacios: launching vm\n");
134
135             if (v3_start_vm(guest->v3_ctx, (0x1 << num_online_cpus()) - 1) < 0) { 
136                 WARNING("palacios: launch of vm failed\n");
137                 return -1;
138             }
139             
140             break;
141         }
142         case V3_VM_STOP: {
143             NOTICE("Stopping VM (%s) (%p)\n", guest->name, guest);
144
145             if (irqs_disabled()) {
146                 ERROR("WHAT!!?? IRQs are disabled??\n");
147                 break;
148             }
149
150             v3_stop_vm(guest->v3_ctx);
151             break;
152         }
153         case V3_VM_PAUSE: {
154             NOTICE("Pausing VM (%s)\n", guest->name);
155             v3_pause_vm(guest->v3_ctx);
156             break;
157         }
158         case V3_VM_CONTINUE: {
159             NOTICE("Continuing VM (%s)\n", guest->name);
160             v3_continue_vm(guest->v3_ctx);
161             break;
162         }
163         case V3_VM_SIMULATE: {
164             NOTICE("Simulating VM (%s) for %lu msecs\n", guest->name, arg);
165             v3_simulate_vm(guest->v3_ctx, arg);
166             break;
167         }
168
169
170 #ifdef V3_CONFIG_CHECKPOINT
171         case V3_VM_SAVE: {
172             struct v3_chkpt_info chkpt;
173             void __user * argp = (void __user *)arg;
174
175             memset(&chkpt, 0, sizeof(struct v3_chkpt_info));
176
177             if (copy_from_user(&chkpt, argp, sizeof(struct v3_chkpt_info))) {
178                 WARNING("Copy from user error getting checkpoint info\n");
179                 return -EFAULT;
180             }
181             
182             NOTICE("Saving Guest to %s:%s\n", chkpt.store, chkpt.url);
183
184             if (v3_save_vm(guest->v3_ctx, chkpt.store, chkpt.url) == -1) {
185                 WARNING("Error checkpointing VM state\n");
186                 return -EFAULT;
187             }
188             
189             break;
190         }
191         case V3_VM_LOAD: {
192             struct v3_chkpt_info chkpt;
193             void __user * argp = (void __user *)arg;
194
195             memset(&chkpt, 0, sizeof(struct v3_chkpt_info));
196
197             if (copy_from_user(&chkpt, argp, sizeof(struct v3_chkpt_info))) {
198                 WARNING("Copy from user error getting checkpoint info\n");
199                 return -EFAULT;
200             }
201             
202             NOTICE("Loading Guest to %s:%s\n", chkpt.store, chkpt.url);
203
204             if (v3_load_vm(guest->v3_ctx, chkpt.store, chkpt.url) == -1) {
205                 WARNING("Error Loading VM state\n");
206                 return -EFAULT;
207             }
208             
209             break;
210         }
211 #endif
212         case V3_VM_DEBUG: {
213             struct v3_debug_cmd cmd;
214             struct v3_debug_event evt;
215             void __user * argp = (void __user *)arg;        
216
217             memset(&cmd, 0, sizeof(struct v3_debug_cmd));
218             
219             if (copy_from_user(&cmd, argp, sizeof(struct v3_debug_cmd))) {
220                 ERROR("Error: Could not copy debug command from user space\n");
221                 return -EFAULT;
222             }
223
224             evt.core_id = cmd.core;
225             evt.cmd = cmd.cmd;
226
227             INFO("Debugging VM\n");
228
229             if (v3_deliver_debug_event(guest->v3_ctx, &evt) == -1) {
230                 ERROR("Error could not deliver debug cmd\n");
231                 return -EFAULT;
232             }
233
234             break;
235         }
236         case V3_VM_MOVE_CORE: {
237             struct v3_core_move_cmd cmd;
238             void __user * argp = (void __user *)arg;
239
240             memset(&cmd, 0, sizeof(struct v3_core_move_cmd));
241             
242             if (copy_from_user(&cmd, argp, sizeof(struct v3_core_move_cmd))) {
243                 WARNING("copy from user error getting migrate command...\n");
244                 return -EFAULT;
245             }
246         
247             INFO("moving guest %s vcore %d to CPU %d\n", guest->name, cmd.vcore_id, cmd.pcore_id);
248
249             v3_move_vm_core(guest->v3_ctx, cmd.vcore_id, cmd.pcore_id);
250
251             break;
252         }
253         default: {
254             struct vm_ctrl * ctrl = get_ctrl(guest, ioctl);
255
256             if (ctrl) {
257                 return ctrl->handler(guest, ioctl, arg, ctrl->priv_data);
258             }
259             
260             
261             WARNING("\tUnhandled ctrl cmd: %d\n", ioctl);
262             return -EINVAL;
263         }
264     }
265
266     return 0;
267 }
268
269 static int v3_vm_open(struct inode * inode, struct file * filp) {
270     struct v3_guest * guest = container_of(inode->i_cdev, struct v3_guest, cdev);
271     filp->private_data = guest;
272     return 0;
273 }
274
275
276 static ssize_t v3_vm_read(struct file * filp, char __user * buf, size_t size, loff_t * offset) {
277     
278     return 0;
279 }
280
281
282 static ssize_t v3_vm_write(struct file * filp, const char __user * buf, size_t size, loff_t * offset) {
283
284     return 0;
285 }
286
287
288 static struct file_operations v3_vm_fops = {
289     .owner = THIS_MODULE,
290     .unlocked_ioctl = v3_vm_ioctl,
291     .compat_ioctl = v3_vm_ioctl,
292     .open = v3_vm_open,
293     .read = v3_vm_read, 
294     .write = v3_vm_write,
295 };
296
297
298 extern u32 pg_allocs;
299 extern u32 pg_frees;
300 extern u32 mallocs;
301 extern u32 frees;
302
303 int create_palacios_vm(struct v3_guest * guest)  {
304     int err;
305
306     if (init_vm_extensions(guest) < 0) {
307         WARNING("palacios: failed to initialize extensions\n");
308         return -1;
309     }
310
311     guest->v3_ctx = v3_create_vm(guest->img, (void *)guest, guest->name);
312
313     if (guest->v3_ctx == NULL) { 
314         WARNING("palacios: failed to create vm\n");
315         goto out_err;
316     }
317
318     NOTICE("Creating VM device: Major %d, Minor %d\n", MAJOR(guest->vm_dev), MINOR(guest->vm_dev));
319
320     cdev_init(&(guest->cdev), &v3_vm_fops);
321
322     guest->cdev.owner = THIS_MODULE;
323     guest->cdev.ops = &v3_vm_fops;
324
325
326     INFO("Adding VM device\n");
327     err = cdev_add(&(guest->cdev), guest->vm_dev, 1);
328
329     if (err) {
330         WARNING("Fails to add cdev\n");
331         goto out_err1;
332     }
333
334     if (device_create(v3_class, NULL, guest->vm_dev, guest, "v3-vm%d", MINOR(guest->vm_dev)) == NULL){
335         WARNING("Fails to create device\n");
336         goto out_err2;
337     }
338
339     NOTICE("palacios: vm created at /dev/v3-vm%d\n", MINOR(guest->vm_dev));
340
341     return 0;
342
343 out_err2:
344     cdev_del(&(guest->cdev));
345 out_err1:
346     v3_free_vm(guest->v3_ctx);
347 out_err:
348     deinit_vm_extensions(guest);
349     return -1;
350 }
351
352
353
354
355
356 int free_palacios_vm(struct v3_guest * guest) {
357
358     v3_free_vm(guest->v3_ctx);
359
360     device_destroy(v3_class, guest->vm_dev);
361
362     cdev_del(&(guest->cdev));
363
364     vfree(guest->img);
365     palacios_free(guest);
366
367     return 0;
368 }