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 / main.c
1 /* 
2    Palacios main control interface
3    (c) Jack Lange, 2010
4  */
5
6
7 #include <linux/module.h>
8 #include <linux/moduleparam.h>
9 #include <linux/errno.h>
10 #include <linux/percpu.h>
11 #include <linux/fs.h>
12 #include <linux/uaccess.h>
13 #include <linux/device.h>
14 #include <linux/cdev.h>
15
16 #include <linux/io.h>
17
18 #include <linux/file.h>
19 #include <linux/spinlock.h>
20 #include <linux/kthread.h>
21
22 #include <linux/proc_fs.h>
23
24 #include <palacios/vmm.h>
25
26 #include "palacios.h"
27 #include "mm.h"
28 #include "vm.h"
29
30 #include "linux-exts.h"
31
32
33
34 MODULE_LICENSE("GPL");
35
36 // Module parameter
37 int cpu_list[NR_CPUS] = {};
38 int cpu_list_len = 0;
39 module_param_array(cpu_list, int, &cpu_list_len, 0644);
40 MODULE_PARM_DESC(cpu_list, "Comma-delimited list of CPUs that Palacios will run on");
41
42 int mod_allocs = 0;
43 int mod_frees = 0;
44
45
46 static int v3_major_num = 0;
47
48 static struct v3_guest * guest_map[MAX_VMS] = {[0 ... MAX_VMS - 1] = 0};
49 static struct proc_dir_entry *dir = 0;
50
51 struct class * v3_class = NULL;
52 static struct cdev ctrl_dev;
53
54 static int register_vm(struct v3_guest * guest) {
55     int i = 0;
56
57     for (i = 0; i < MAX_VMS; i++) {
58         if (guest_map[i] == NULL) {
59             guest_map[i] = guest;
60             return i;
61         }
62     }
63
64     return -1;
65 }
66
67
68
69 static long v3_dev_ioctl(struct file * filp,
70                          unsigned int ioctl, unsigned long arg) {
71     void __user * argp = (void __user *)arg;
72     DEBUG("V3 IOCTL %d\n", ioctl);
73
74
75     switch (ioctl) {
76         case V3_CREATE_GUEST:{
77             int vm_minor = 0;
78             struct v3_guest_img user_image;
79             struct v3_guest * guest = palacios_alloc(sizeof(struct v3_guest));
80
81             if (IS_ERR(guest)) {
82                 ERROR("Palacios: Error allocating Kernel guest_image\n");
83                 return -EFAULT;
84             }
85
86             memset(guest, 0, sizeof(struct v3_guest));
87
88             INFO("Palacios: Creating V3 Guest...\n");
89
90             vm_minor = register_vm(guest);
91
92             if (vm_minor == -1) {
93                 ERROR("Palacios Error: Too many VMs are currently running\n");
94                 goto out_err;
95             }
96
97             guest->vm_dev = MKDEV(v3_major_num, vm_minor);
98
99             if (copy_from_user(&user_image, argp, sizeof(struct v3_guest_img))) {
100                 ERROR("Palacios Error: copy from user error getting guest image...\n");
101                 goto out_err1;
102             }
103
104             guest->img_size = user_image.size;
105
106             DEBUG("Palacios: Allocating kernel memory for guest image (%llu bytes)\n", user_image.size);
107             guest->img = vmalloc(guest->img_size);
108
109             if (IS_ERR(guest->img)) {
110                 ERROR("Palacios Error: Could not allocate space for guest image\n");
111                 goto out_err1;
112             }
113
114             if (copy_from_user(guest->img, user_image.guest_data, guest->img_size)) {
115                 ERROR("Palacios: Error loading guest data\n");
116                 goto out_err2;
117             }      
118
119             strncpy(guest->name, user_image.name, 127);
120
121             INIT_LIST_HEAD(&(guest->exts));
122
123             if (create_palacios_vm(guest) == -1) {
124                 ERROR("Palacios: Error creating guest\n");
125                 goto out_err2;
126             }
127
128             return vm_minor;
129
130
131 out_err2:
132             vfree(guest->img);
133 out_err1:
134             guest_map[vm_minor] = NULL; 
135 out_err:
136             palacios_free(guest);
137
138             return -1;
139
140             break;
141         }
142         case V3_FREE_GUEST: {
143             unsigned long vm_idx = arg;
144             struct v3_guest * guest = guest_map[vm_idx];
145
146             if (!guest) {
147                 ERROR("No VM at index %ld\n",vm_idx);
148                 return -1;
149             }
150
151             INFO("Freeing VM (%s) (%p)\n", guest->name, guest);
152
153             if (free_palacios_vm(guest)<0) { 
154                 ERROR("Cannot free guest at index %ld\n",vm_idx);
155                 return -1;
156             }
157
158             guest_map[vm_idx] = NULL;
159             break;
160         }
161         case V3_ADD_MEMORY: {
162             struct v3_mem_region mem;
163             
164             memset(&mem, 0, sizeof(struct v3_mem_region));
165             
166             if (copy_from_user(&mem, argp, sizeof(struct v3_mem_region))) {
167                 ERROR("copy from user error getting mem_region...\n");
168                 return -EFAULT;
169             }
170
171             DEBUG("Adding %llu pages to Palacios memory\n", mem.num_pages);
172
173             if (add_palacios_memory(mem.base_addr, mem.num_pages) == -1) {
174                 ERROR("Error adding memory to Palacios\n");
175                 return -EFAULT;
176             }
177
178             break;
179         }
180
181         case V3_RESET_MEMORY: {
182             if (palacios_init_mm() == -1) {
183                 ERROR("Error resetting Palacios memory\n");
184                 return -EFAULT;
185             }
186             break;  
187         }
188
189         default: {
190             struct global_ctrl * ctrl = get_global_ctrl(ioctl);
191             
192             if (ctrl) {
193                 return ctrl->handler(ioctl, arg);
194             }
195
196             WARNING("\tUnhandled global ctrl cmd: %d\n", ioctl);
197
198             return -EINVAL;
199         }
200     }
201
202     return 0;
203 }
204
205
206
207 static struct file_operations v3_ctrl_fops = {
208     .owner = THIS_MODULE,
209     .unlocked_ioctl = v3_dev_ioctl,
210     .compat_ioctl = v3_dev_ioctl,
211 };
212
213
214
215 struct proc_dir_entry *palacios_get_procdir(void) 
216 {
217     return dir;
218 }
219
220 static int read_guests(char * buf, char ** start, off_t off, int count,
221                        int * eof, void * data)
222 {
223     int len = 0;
224     unsigned int i = 0;
225     
226     for(i = 0; i < MAX_VMS; i++) {
227         if (guest_map[i] != NULL) {
228             if (len<count) { 
229                 len += snprintf(buf+len, count-len,
230                                 "%s\t/dev/v3-vm%d\n", 
231                                 guest_map[i]->name, i);
232             }
233         }
234     }
235     
236     return len;
237 }
238
239 static int show_mem(char * buf, char ** start, off_t off, int count,
240                     int * eof, void * data)
241 {
242     int len = 0;
243     
244     len = snprintf(buf,count, "%p\n", (void *)get_palacios_base_addr());
245     len += snprintf(buf+len,count-len, "%lld\n", get_palacios_num_pages());
246     
247     return len;
248 }
249
250
251 static int __init v3_init(void) {
252     dev_t dev = MKDEV(0, 0); // We dynamicallly assign the major number
253     int ret = 0;
254
255
256     palacios_init_mm();
257
258     // Initialize Palacios
259     palacios_vmm_init();
260
261
262     // initialize extensions
263     init_lnx_extensions();
264
265
266     v3_class = class_create(THIS_MODULE, "vms");
267     if (IS_ERR(v3_class)) {
268         ERROR("Failed to register V3 VM device class\n");
269         return PTR_ERR(v3_class);
270     }
271
272     INFO("intializing V3 Control device\n");
273
274     ret = alloc_chrdev_region(&dev, 0, MAX_VMS + 1, "v3vee");
275
276     if (ret < 0) {
277         ERROR("Error registering device region for V3 devices\n");
278         goto failure2;
279     }
280
281     v3_major_num = MAJOR(dev);
282
283     dev = MKDEV(v3_major_num, MAX_VMS + 1);
284
285     
286     DEBUG("Creating V3 Control device: Major %d, Minor %d\n", v3_major_num, MINOR(dev));
287     cdev_init(&ctrl_dev, &v3_ctrl_fops);
288     ctrl_dev.owner = THIS_MODULE;
289     ctrl_dev.ops = &v3_ctrl_fops;
290     cdev_add(&ctrl_dev, dev, 1);
291     
292     device_create(v3_class, NULL, dev, NULL, "v3vee");
293
294     if (ret != 0) {
295         ERROR("Error adding v3 control device\n");
296         goto failure1;
297     }
298
299     dir = proc_mkdir("v3vee", NULL);
300     if(dir) {
301         struct proc_dir_entry *entry;
302
303         entry = create_proc_read_entry("v3-guests", 0444, dir, 
304                                        read_guests, NULL);
305         if (entry) {
306             INFO("/proc/v3vee/v3-guests successfully created\n");
307         } else {
308             ERROR("Could not create proc entry\n");
309             goto failure1;
310         }
311         
312         entry = create_proc_read_entry("v3-mem", 0444, dir,
313                                        show_mem, NULL);
314         if (entry) {
315             INFO("/proc/v3vee/v3-mem successfully added\n");
316         } else {
317             ERROR("Could not create proc entry\n");
318             goto failure1;
319         }
320     } else {
321         ERROR("Could not create proc entry\n");
322         goto failure1;
323     }
324         
325     return 0;
326
327  failure1:
328     unregister_chrdev_region(MKDEV(v3_major_num, 0), MAX_VMS + 1);
329  failure2:
330     class_destroy(v3_class);
331
332     return ret;
333 }
334
335
336 static void __exit v3_exit(void) {
337     extern u32 pg_allocs;
338     extern u32 pg_frees;
339     extern u32 mallocs;
340     extern u32 frees;
341     int i = 0;
342     struct v3_guest * guest;
343     dev_t dev;
344
345
346     /* Stop and free any running VMs */ 
347     for (i = 0; i < MAX_VMS; i++) {
348         if (guest_map[i] != NULL) {
349                 guest = (struct v3_guest *)guest_map[i];
350
351                 if (v3_stop_vm(guest->v3_ctx) < 0) 
352                         ERROR("Couldn't stop VM %d\n", i);
353
354                 free_palacios_vm(guest);
355                 guest_map[i] = NULL;
356         }
357     }
358
359     dev = MKDEV(v3_major_num, MAX_VMS + 1);
360
361     INFO("Removing V3 Control device\n");
362
363
364     palacios_vmm_exit();
365
366     DEBUG("Palacios Mallocs = %d, Frees = %d\n", mallocs, frees);
367     DEBUG("Palacios Page Allocs = %d, Page Frees = %d\n", pg_allocs, pg_frees);
368
369     unregister_chrdev_region(MKDEV(v3_major_num, 0), MAX_VMS + 1);
370
371     cdev_del(&ctrl_dev);
372
373     device_destroy(v3_class, dev);
374     class_destroy(v3_class);
375
376
377     deinit_lnx_extensions();
378
379     palacios_deinit_mm();
380
381     remove_proc_entry("v3-guests", dir);
382     remove_proc_entry("v3-mem", dir);
383     remove_proc_entry("v3vee", NULL);
384
385     DEBUG("Palacios Module Mallocs = %d, Frees = %d\n", mod_allocs, mod_frees);
386 }
387
388
389
390 module_init(v3_init);
391 module_exit(v3_exit);
392
393
394
395 void * trace_malloc(size_t size, gfp_t flags) {
396     void * addr = NULL;
397
398     mod_allocs++;
399     addr = kmalloc(size, flags);
400
401     return addr;
402 }
403
404
405 void trace_free(const void * objp) {
406     mod_frees++;
407     kfree(objp);
408 }