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.


Avoid corruption when freeing a guest fails
[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
97
98 static struct vm_ctrl * get_ctrl(struct v3_guest * guest, unsigned int cmd) {
99     struct rb_node * n = guest->vm_ctrls.rb_node;
100     struct vm_ctrl * ctrl = NULL;
101
102     while (n) {
103         ctrl = rb_entry(n, struct vm_ctrl, tree_node);
104
105         if (cmd < ctrl->cmd) {
106             n = n->rb_left;
107         } else if (cmd > ctrl->cmd) {
108             n = n->rb_right;
109         } else {
110             return ctrl;
111         }
112     }
113
114     return NULL;
115 }
116
117 int remove_guest_ctrl(struct v3_guest * guest, unsigned int cmd) {
118     struct vm_ctrl * ctrl = get_ctrl(guest, cmd);
119
120     if (ctrl == NULL) {
121         INFO("Could not find control (%d) to remove\n", cmd);
122         return -1;
123     }
124
125     rb_erase(&(ctrl->tree_node), &(guest->vm_ctrls));
126
127     kfree(ctrl);
128
129     return 0;
130 }
131
132 static void free_guest_ctrls(struct v3_guest * guest) {
133     struct rb_node * node = rb_first(&(guest->vm_ctrls));
134     struct vm_ctrl * ctrl = NULL;
135     struct rb_node * tmp_node = NULL;
136
137     while (node) {
138         ctrl = rb_entry(node, struct vm_ctrl, tree_node);
139         tmp_node = node;
140         node = rb_next(node);
141         
142         WARNING("Cleaning up guest ctrl that was not removed explicitly (%d)\n", ctrl->cmd);
143
144         kfree(ctrl);
145     }
146 }
147
148
149
150
151
152
153 extern struct class * v3_class;
154
155
156 static long v3_vm_ioctl(struct file * filp,
157                         unsigned int ioctl, unsigned long arg) {
158
159     struct v3_guest * guest = filp->private_data;
160
161     INFO("V3 IOCTL %d\n", ioctl);
162
163     switch (ioctl) {
164         case V3_VM_LAUNCH: {
165             NOTICE("palacios: launching vm\n");
166
167             if (v3_start_vm(guest->v3_ctx, (0x1 << num_online_cpus()) - 1) < 0) { 
168                 WARNING("palacios: launch of vm failed\n");
169                 return -1;
170             }
171             
172             break;
173         }
174         case V3_VM_STOP: {
175             NOTICE("Stopping VM (%s) (%p)\n", guest->name, guest);
176
177             if (irqs_disabled()) {
178                 ERROR("WHAT!!?? IRQs are disabled??\n");
179                 break;
180             }
181
182             v3_stop_vm(guest->v3_ctx);
183             break;
184         }
185         case V3_VM_PAUSE: {
186             NOTICE("Pausing VM (%s)\n", guest->name);
187             v3_pause_vm(guest->v3_ctx);
188             break;
189         }
190         case V3_VM_CONTINUE: {
191             NOTICE("Continuing VM (%s)\n", guest->name);
192             v3_continue_vm(guest->v3_ctx);
193             break;
194         }
195         case V3_VM_SIMULATE: {
196             NOTICE("Simulating VM (%s) for %lu msecs\n", guest->name, arg);
197             v3_simulate_vm(guest->v3_ctx, arg);
198             break;
199         }
200
201
202 #ifdef V3_CONFIG_CHECKPOINT
203         case V3_VM_SAVE: {
204             struct v3_chkpt_info chkpt;
205             void __user * argp = (void __user *)arg;
206
207             memset(&chkpt, 0, sizeof(struct v3_chkpt_info));
208
209             if (copy_from_user(&chkpt, argp, sizeof(struct v3_chkpt_info))) {
210                 WARNING("Copy from user error getting checkpoint info\n");
211                 return -EFAULT;
212             }
213             
214             NOTICE("Saving Guest to %s:%s\n", chkpt.store, chkpt.url);
215
216             if (v3_save_vm(guest->v3_ctx, chkpt.store, chkpt.url) == -1) {
217                 WARNING("Error checkpointing VM state\n");
218                 return -EFAULT;
219             }
220             
221             break;
222         }
223         case V3_VM_LOAD: {
224             struct v3_chkpt_info chkpt;
225             void __user * argp = (void __user *)arg;
226
227             memset(&chkpt, 0, sizeof(struct v3_chkpt_info));
228
229             if (copy_from_user(&chkpt, argp, sizeof(struct v3_chkpt_info))) {
230                 WARNING("Copy from user error getting checkpoint info\n");
231                 return -EFAULT;
232             }
233             
234             NOTICE("Loading Guest to %s:%s\n", chkpt.store, chkpt.url);
235
236             if (v3_load_vm(guest->v3_ctx, chkpt.store, chkpt.url) == -1) {
237                 WARNING("Error Loading VM state\n");
238                 return -EFAULT;
239             }
240             
241             break;
242         }
243 #endif
244
245 #ifdef V3_CONFIG_LIVE_MIGRATION  
246         case V3_VM_SEND: {
247             struct v3_chkpt_info chkpt_info;
248             void __user * argp = (void __user *)arg;
249             
250             memset(&chkpt_info,0, sizeof(struct v3_chkpt_info));
251             
252             if(copy_from_user(&chkpt_info, argp, sizeof(struct v3_chkpt_info))){
253                 WARNING("Copy from user error getting checkpoint info\n");
254                 return -EFAULT;
255             }
256             
257             
258             NOTICE("Sending (live-migrating) Guest to %s:%s\n",chkpt_info.store, chkpt_info.url); 
259             
260             if (v3_send_vm(guest->v3_ctx, chkpt_info.store, chkpt_info.url) == -1) {
261                 WARNING("Error sending VM\n");
262                 return -EFAULT;
263             }
264             
265             break;
266         }
267
268         case V3_VM_RECEIVE: {
269             struct v3_chkpt_info chkpt_info;
270             void __user * argp = (void __user *)arg;
271             
272             memset(&chkpt_info,0, sizeof(struct v3_chkpt_info));
273
274             if(copy_from_user(&chkpt_info, argp, sizeof(struct v3_chkpt_info))){
275                 WARNING("Copy from user error getting checkpoint info\n");
276                 return -EFAULT;
277             }
278             
279             
280             NOTICE("Receiving (live-migrating) Guest to %s:%s\n",chkpt_info.store, chkpt_info.url);
281             
282             if (v3_receive_vm(guest->v3_ctx, chkpt_info.store, chkpt_info.url) == -1) {
283                 WARNING("Error receiving VM\n");
284                 return -EFAULT;
285             }
286             
287             break;
288         }
289 #endif
290
291         case V3_VM_DEBUG: {
292             struct v3_debug_cmd cmd;
293             struct v3_debug_event evt;
294             void __user * argp = (void __user *)arg;        
295
296             memset(&cmd, 0, sizeof(struct v3_debug_cmd));
297             
298             if (copy_from_user(&cmd, argp, sizeof(struct v3_debug_cmd))) {
299                 ERROR("Error: Could not copy debug command from user space\n");
300                 return -EFAULT;
301             }
302
303             evt.core_id = cmd.core;
304             evt.cmd = cmd.cmd;
305
306             INFO("Debugging VM\n");
307
308             if (v3_deliver_debug_event(guest->v3_ctx, &evt) == -1) {
309                 ERROR("Error could not deliver debug cmd\n");
310                 return -EFAULT;
311             }
312
313             break;
314         }
315         case V3_VM_MOVE_CORE: {
316             struct v3_core_move_cmd cmd;
317             void __user * argp = (void __user *)arg;
318
319             memset(&cmd, 0, sizeof(struct v3_core_move_cmd));
320             
321             if (copy_from_user(&cmd, argp, sizeof(struct v3_core_move_cmd))) {
322                 WARNING("copy from user error getting migrate command...\n");
323                 return -EFAULT;
324             }
325         
326             INFO("moving guest %s vcore %d to CPU %d\n", guest->name, cmd.vcore_id, cmd.pcore_id);
327
328             v3_move_vm_core(guest->v3_ctx, cmd.vcore_id, cmd.pcore_id);
329
330             break;
331         }
332         default: {
333             struct vm_ctrl * ctrl = get_ctrl(guest, ioctl);
334
335             if (ctrl) {
336                 return ctrl->handler(guest, ioctl, arg, ctrl->priv_data);
337             }
338             
339             
340             WARNING("\tUnhandled ctrl cmd: %d\n", ioctl);
341             return -EINVAL;
342         }
343     }
344
345     return 0;
346 }
347
348 static int v3_vm_open(struct inode * inode, struct file * filp) {
349     struct v3_guest * guest = container_of(inode->i_cdev, struct v3_guest, cdev);
350     filp->private_data = guest;
351     return 0;
352 }
353
354
355 static ssize_t v3_vm_read(struct file * filp, char __user * buf, size_t size, loff_t * offset) {
356     
357     return 0;
358 }
359
360
361 static ssize_t v3_vm_write(struct file * filp, const char __user * buf, size_t size, loff_t * offset) {
362
363     return 0;
364 }
365
366
367 static struct file_operations v3_vm_fops = {
368     .owner = THIS_MODULE,
369     .unlocked_ioctl = v3_vm_ioctl,
370     .compat_ioctl = v3_vm_ioctl,
371     .open = v3_vm_open,
372     .read = v3_vm_read, 
373     .write = v3_vm_write,
374 };
375
376
377 extern u32 pg_allocs;
378 extern u32 pg_frees;
379 extern u32 mallocs;
380 extern u32 frees;
381
382 int create_palacios_vm(struct v3_guest * guest)  {
383     int err;
384
385     if (init_vm_extensions(guest) < 0) {
386         WARNING("palacios: failed to initialize extensions\n");
387         return -1;
388     }
389
390     guest->v3_ctx = v3_create_vm(guest->img, (void *)guest, guest->name);
391
392     if (guest->v3_ctx == NULL) { 
393         WARNING("palacios: failed to create vm\n");
394         goto out_err;
395     }
396
397     NOTICE("Creating VM device: Major %d, Minor %d\n", MAJOR(guest->vm_dev), MINOR(guest->vm_dev));
398
399     cdev_init(&(guest->cdev), &v3_vm_fops);
400
401     guest->cdev.owner = THIS_MODULE;
402     guest->cdev.ops = &v3_vm_fops;
403
404
405     INFO("Adding VM device\n");
406     err = cdev_add(&(guest->cdev), guest->vm_dev, 1);
407
408     if (err) {
409         WARNING("Fails to add cdev\n");
410         goto out_err1;
411     }
412
413     if (device_create(v3_class, NULL, guest->vm_dev, guest, "v3-vm%d", MINOR(guest->vm_dev)) == NULL){
414         WARNING("Fails to create device\n");
415         goto out_err2;
416     }
417
418     NOTICE("palacios: vm created at /dev/v3-vm%d\n", MINOR(guest->vm_dev));
419
420     return 0;
421
422 out_err2:
423     cdev_del(&(guest->cdev));
424 out_err1:
425     v3_free_vm(guest->v3_ctx);
426 out_err:
427     deinit_vm_extensions(guest);
428     return -1;
429 }
430
431
432
433
434
435 int free_palacios_vm(struct v3_guest * guest) {
436
437     if (v3_free_vm(guest->v3_ctx)<0) { 
438         return -1;
439     }
440
441     device_destroy(v3_class, guest->vm_dev);
442
443     cdev_del(&(guest->cdev));
444
445     free_guest_ctrls(guest);
446
447
448     vfree(guest->img);
449     palacios_free(guest);
450
451     return 0;
452 }