X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?a=blobdiff_plain;f=linux_module%2Fmain.c;h=b4c4637ee4902aa347a486c35a62f4b49a1e0c3f;hb=6234775894cac514f495b751a046db245ecb124a;hp=621ab5806442575193a07aedfef41817ffeb6a20;hpb=276cfa264720edddc1677e35c6a300596965de7d;p=palacios.git diff --git a/linux_module/main.c b/linux_module/main.c index 621ab58..b4c4637 100644 --- a/linux_module/main.c +++ b/linux_module/main.c @@ -3,8 +3,9 @@ (c) Jack Lange, 2010 */ - +#include #include +#include #include #include #include @@ -18,53 +19,67 @@ #include #include +#include +#include + +#include + #include "palacios.h" #include "mm.h" #include "vm.h" +#include "numa.h" +#include "allow_devmem.h" +#include "memcheck.h" +#include "lockcheck.h" #include "linux-exts.h" - +#include "util-hashtable.h" MODULE_LICENSE("GPL"); +// Module parameter +int cpu_list[NR_CPUS] = {}; +int cpu_list_len = 0; +module_param_array(cpu_list, int, &cpu_list_len, 0644); +MODULE_PARM_DESC(cpu_list, "Comma-delimited list of CPUs that Palacios will run on"); + +static int allow_devmem = 0; +module_param(allow_devmem, int, 0); +MODULE_PARM_DESC(allow_devmem, "Allow general user-space /dev/mem access even if kernel is strict"); + +// Palacios options parameter +static char *options; +module_param(options, charp, 0); +MODULE_PARM_DESC(options, "Generic options to internal Palacios modules"); + + int mod_allocs = 0; int mod_frees = 0; - static int v3_major_num = 0; -static u8 v3_minor_map[MAX_VMS / 8] = {[0 ... (MAX_VMS / 8) - 1] = 0}; - +static struct v3_guest * guest_map[MAX_VMS] = {[0 ... MAX_VMS - 1] = 0}; +static struct proc_dir_entry * palacios_proc_dir = NULL; struct class * v3_class = NULL; static struct cdev ctrl_dev; -static int register_vm( void ) { - int i, j = 0; - int avail = 0; - - for (i = 0; i < sizeof(v3_minor_map); i++) { - if (v3_minor_map[i] != 0xff) { - for (j = 0; j < 8; j++) { - if (!(v3_minor_map[i] & (0x1 << j))) { - avail = 1; - v3_minor_map[i] |= (0x1 << j); - break; - } - } - - if (avail == 1) { - break; - } + +// mapping from thread ids to their resource control blocks +struct hashtable *v3_thread_resource_map=0; + +static int register_vm(struct v3_guest * guest) { + int i = 0; + + for (i = 0; i < MAX_VMS; i++) { + if (guest_map[i] == NULL) { + guest_map[i] = guest; + return i; } } - if (avail == 0) { - return -1; - } - - return (i * 8) + j; + return -1; } @@ -72,85 +87,100 @@ static int register_vm( void ) { static long v3_dev_ioctl(struct file * filp, unsigned int ioctl, unsigned long arg) { void __user * argp = (void __user *)arg; - printk("V3 IOCTL %d\n", ioctl); + DEBUG("V3 IOCTL %d\n", ioctl); switch (ioctl) { - case V3_START_GUEST:{ + case V3_CREATE_GUEST:{ int vm_minor = 0; struct v3_guest_img user_image; - struct v3_guest * guest = kmalloc(sizeof(struct v3_guest), GFP_KERNEL); + struct v3_guest * guest = palacios_alloc(sizeof(struct v3_guest)); - if (IS_ERR(guest)) { - printk("Error allocating Kernel guest_image\n"); + if (!(guest)) { + ERROR("Palacios: Error allocating Kernel guest_image\n"); return -EFAULT; } memset(guest, 0, sizeof(struct v3_guest)); - printk("Starting V3 Guest...\n"); + INFO("Palacios: Creating V3 Guest...\n"); - vm_minor = register_vm(); + vm_minor = register_vm(guest); if (vm_minor == -1) { - printk("Too many VMs are currently running\n"); - return -EFAULT; + ERROR("Palacios Error: Too many VMs are currently running\n"); + goto out_err; } guest->vm_dev = MKDEV(v3_major_num, vm_minor); if (copy_from_user(&user_image, argp, sizeof(struct v3_guest_img))) { - printk("copy from user error getting guest image...\n"); - return -EFAULT; + ERROR("Palacios Error: copy from user error getting guest image...\n"); + goto out_err1; } guest->img_size = user_image.size; - printk("Allocating kernel memory for guest image (%llu bytes)\n", user_image.size); - guest->img = vmalloc(guest->img_size); + DEBUG("Palacios: Allocating kernel memory for guest image (%llu bytes)\n", user_image.size); + guest->img = palacios_valloc(guest->img_size); - if (IS_ERR(guest->img)) { - printk("Error: Could not allocate space for guest image\n"); - return -EFAULT; + if (!guest->img) { + ERROR("Palacios Error: Could not allocate space for guest image\n"); + goto out_err1; } if (copy_from_user(guest->img, user_image.guest_data, guest->img_size)) { - printk("Error loading guest data\n"); - return -EFAULT; + ERROR("Palacios: Error loading guest data\n"); + goto out_err2; } strncpy(guest->name, user_image.name, 127); - printk("Launching VM\n"); - INIT_LIST_HEAD(&(guest->exts)); - init_completion(&(guest->start_done)); - init_completion(&(guest->thread_done)); + if (create_palacios_vm(guest) == -1) { + ERROR("Palacios: Error creating guest\n"); + goto out_err2; + } - { - struct task_struct * launch_thread = NULL; - // At some point we're going to want to allow the user to specify a CPU mask - // But for now, well just launch from the local core, and rely on the global cpu mask + return vm_minor; - preempt_disable(); - launch_thread = kthread_create(start_palacios_vm, guest, guest->name); - - if (IS_ERR(launch_thread)) { - preempt_enable(); - printk("Palacios error creating launch thread for vm (%s)\n", guest->name); - return -EFAULT; - } - kthread_bind(launch_thread, smp_processor_id()); - preempt_enable(); +out_err2: + palacios_vfree(guest->img); +out_err1: + guest_map[vm_minor] = NULL; +out_err: + palacios_free(guest); + + return -1; + + break; + } + case V3_FREE_GUEST: { + unsigned long vm_idx = arg; + struct v3_guest * guest; + + if (vm_idx > MAX_VMS) { + ERROR("Invalid VM index: %ld\n", vm_idx); + return -1; + } + + guest = guest_map[vm_idx]; - wake_up_process(launch_thread); + if (!guest) { + ERROR("No VM at index %ld\n",vm_idx); + return -1; } - wait_for_completion(&(guest->start_done)); + INFO("Freeing VM (%s) (%p)\n", guest->name, guest); - return guest->vm_dev; + if (free_palacios_vm(guest)<0) { + ERROR("Cannot free guest at index %ld\n",vm_idx); + return -1; + } + + guest_map[vm_idx] = NULL; break; } case V3_ADD_MEMORY: { @@ -159,23 +189,66 @@ static long v3_dev_ioctl(struct file * filp, memset(&mem, 0, sizeof(struct v3_mem_region)); if (copy_from_user(&mem, argp, sizeof(struct v3_mem_region))) { - printk("copy from user error getting mem_region...\n"); + ERROR("copy from user error getting mem_region...\n"); + return -EFAULT; + } + + DEBUG("Adding %llu pages to Palacios memory\n", mem.num_pages); + + if (add_palacios_memory(&mem) == -1) { + ERROR("Error adding memory to Palacios\n"); + return -EFAULT; + } + + break; + } + + case V3_REMOVE_MEMORY: { + struct v3_mem_region mem; + + memset(&mem, 0, sizeof(struct v3_mem_region)); + + if (copy_from_user(&mem, argp, sizeof(struct v3_mem_region))) { + ERROR("copy from user error getting mem_region...\n"); return -EFAULT; } - printk("Adding %llu pages to Palacios memory\n", mem.num_pages); + DEBUG("Removing memory at address %p\n", (void*)(mem.base_addr)); - if (add_palacios_memory(mem.base_addr, mem.num_pages) == -1) { - printk("Error adding memory to Palacios\n"); + if (remove_palacios_memory(&mem) == -1) { + ERROR("Error removing memory from Palacios\n"); return -EFAULT; } break; } + + + + case V3_RESET_MEMORY: { + DEBUG("Resetting memory\n"); + if (palacios_deinit_mm() == -1) { + ERROR("Error deiniting the Palacios memory manager\n"); + return -EFAULT; + } + if (palacios_init_mm()) { + ERROR("Error initing the Palacios memory manager\n"); + return -EFAULT; + } + break; + } + + default: { + struct global_ctrl * ctrl = get_global_ctrl(ioctl); + + if (ctrl) { + return ctrl->handler(ioctl, arg); + } + + WARNING("\tUnhandled global ctrl cmd: %d\n", ioctl); - default: - printk("\tUnhandled\n"); return -EINVAL; + } } return 0; @@ -191,36 +264,401 @@ static struct file_operations v3_ctrl_fops = { +struct proc_dir_entry *palacios_get_procdir(void) +{ + // INFO("Returning procdir=%p\n",palacios_proc_dir); + return palacios_proc_dir; +} + + +#define MAX_CORES 1024 +#define MAX_REGIONS 1024 +#define MIN(x,y) ((x)<(y) ? (x) : (y)) + +static int read_guests_details(struct seq_file *s, void *v) +{ + unsigned int i = 0; + unsigned int j = 0; + uint64_t num_vcores, num_regions; + uint64_t alloc_num_vcores, alloc_num_regions; + struct v3_vm_base_state *base=0; + struct v3_vm_core_state *core=0; + struct v3_vm_mem_state *mem=0; + + + base = palacios_valloc(sizeof(struct v3_vm_base_state)); + + + if (!base) { + ERROR("No space for base state structure\n"); + goto out; + } + + + for(i = 0; i < MAX_VMS; i++) { + + if (guest_map[i] != NULL) { + + v3_get_state_sizes_vm(guest_map[i]->v3_ctx,&num_vcores,&num_regions); + + alloc_num_vcores = MIN(num_vcores,MAX_CORES); + alloc_num_regions = MIN(num_regions,MAX_REGIONS); + + core = palacios_valloc(sizeof(struct v3_vm_core_state) + alloc_num_vcores*sizeof(struct v3_vm_vcore_state)); + + if (!core) { + ERROR("No space for core state structure\n"); + goto out; + } + + mem = palacios_valloc(sizeof(struct v3_vm_mem_state) + alloc_num_regions*sizeof(struct v3_vm_mem_region)); + + if (!mem) { + ERROR("No space for memory state structure\n"); + goto out; + } + + seq_printf(s, + "---------------------------------------------------------------------------------------\n"); + seq_printf(s, + "Entry: %d\n" + "Name: %s\n" + "Device: /dev/v3-vm%d\n", + i,guest_map[i]->name, i); + + // Get extended data + core->num_vcores=alloc_num_vcores; + mem->num_regions=alloc_num_regions; + + if (v3_get_state_vm(guest_map[i]->v3_ctx, base, core, mem)) { + ERROR("Cannot get VM info\n"); + seq_printf(s, "\n"); + } else { + seq_printf(s, + "Type: %s\n" + "State: %s\n" + "Cores: %llu (%llu shown)\n" + "Regions: %llu (%llu shown)\n" + "Memsize: %llu (%llu ROS)\n\n", + base->vm_type==V3_VM_GENERAL ? "general" : + base->vm_type==V3_VM_HVM ? "HVM" : "UNKNOWN", + base->state==V3_VM_INVALID ? "INVALID" : + base->state==V3_VM_RUNNING ? "running" : + base->state==V3_VM_STOPPED ? "stopped" : + base->state==V3_VM_PAUSED ? "paused" : + base->state==V3_VM_ERROR ? "ERROR" : + base->state==V3_VM_SIMULATING ? "simulating" : + base->state==V3_VM_RESETTING ? "resetting" : "UNKNOWN", + num_vcores, + core->num_vcores, + num_regions, + mem->num_regions, + mem->mem_size, + mem->ros_mem_size); + + seq_printf(s, "Core States\n"); + + for (j=0;jnum_vcores;j++) { + seq_printf(s, + " vcore %u %s on pcore %lu %llu exits rip=0x%p %s %s %s %s\n", + j, + core->vcore[j].state==V3_VCORE_INVALID ? "INVALID" : + core->vcore[j].state==V3_VCORE_RUNNING ? "running" : + core->vcore[j].state==V3_VCORE_STOPPED ? "stopped" : + core->vcore[j].state==V3_VCORE_RESETTING ? "resetting" : "UNKNOWN", + core->vcore[j].pcore, + core->vcore[j].num_exits, + core->vcore[j].last_rip, + core->vcore[j].cpu_mode==V3_VCORE_CPU_REAL ? "real" : + core->vcore[j].cpu_mode==V3_VCORE_CPU_PROTECTED ? "protected" : + core->vcore[j].cpu_mode==V3_VCORE_CPU_PROTECTED_PAE ? "protectedpae" : + core->vcore[j].cpu_mode==V3_VCORE_CPU_LONG ? "long" : + core->vcore[j].cpu_mode==V3_VCORE_CPU_LONG_32_COMPAT ? "long32" : + core->vcore[j].cpu_mode==V3_VCORE_CPU_LONG_16_COMPAT ? "long16" : "UNKNOWN", + core->vcore[j].mem_mode==V3_VCORE_MEM_MODE_PHYSICAL ? "physical" : + core->vcore[j].mem_mode==V3_VCORE_MEM_MODE_VIRTUAL ? "virtual" : "UNKNOWN", + core->vcore[j].mem_state==V3_VCORE_MEM_STATE_SHADOW ? "shadow" : + core->vcore[j].mem_state==V3_VCORE_MEM_STATE_NESTED ? "nested" : "UNKNOWN", + core->vcore[j].vcore_type==V3_VCORE_GENERAL ? "" : + core->vcore[j].vcore_type==V3_VCORE_ROS ? "ros" : + core->vcore[j].vcore_type==V3_VCORE_HRT ? "hrt" : "UNKNOWN"); + } + + + seq_printf(s, "\nMemory Regions\n"); + for (j=0;jnum_regions;j++) { + seq_printf(s," region %u has HPAs 0x%016llx-0x%016llx (node %d) GPA 0x%016llx %s %s\n", + j, (uint64_t)mem->region[j].host_paddr, (uint64_t)mem->region[j].host_paddr+mem->region[j].size, + numa_addr_to_node((uintptr_t)(mem->region[j].host_paddr)), + (uint64_t)mem->region[j].guest_paddr, + mem->region[j].swapped ? "swapped" : "", + mem->region[j].pinned ? "pinned" : ""); + } + + } + seq_printf(s, + "---------------------------------------------------------------------------------------\n"); + + palacios_vfree(mem); mem=0; + palacios_vfree(core); core=0; + + } + + } + + + out: + if (mem) { palacios_vfree(mem); } + if (core) { palacios_vfree(core); } + if (base) { palacios_vfree(base); } + + return 0; +} + +static int read_guests(struct seq_file *s, void *v) +{ + unsigned int i = 0; + struct v3_vm_base_state *base=0; + struct v3_vm_core_state *core=0; + struct v3_vm_mem_state *mem=0; + uint64_t num_vcores, num_regions; + + + INFO("READ GUEST\n"); + + base = palacios_valloc(sizeof(struct v3_vm_base_state)); + + if (!base) { + ERROR("No space for base state structure\n"); + goto out; + } + + core = palacios_valloc(sizeof(struct v3_vm_core_state)); + + if (!core) { + ERROR("No space for core state structure\n"); + goto out; + } + + mem = palacios_valloc(sizeof(struct v3_vm_mem_state)); + + if (!mem) { + ERROR("No space for memory state structure\n"); + goto out; + } + + + for(i = 0; i < MAX_VMS; i++) { + if (guest_map[i] != NULL) { + + v3_get_state_sizes_vm(guest_map[i]->v3_ctx,&num_vcores,&num_regions); + + seq_printf(s,"%s\t/dev/v3-vm%d", guest_map[i]->name, i); + + // Skip getting per core and per-region + core->num_vcores=0; + mem->num_regions=0; + + if (v3_get_state_vm(guest_map[i]->v3_ctx, base, core, mem)) { + ERROR("Cannot get VM info\n"); + seq_printf(s, "\t\n"); + } else { + seq_printf(s,"\t%s\t%llu vcores\t%llu regions\t%llu mem\t%s\n", + base->state==V3_VM_INVALID ? "INVALID" : + base->state==V3_VM_RUNNING ? "running" : + base->state==V3_VM_STOPPED ? "stopped" : + base->state==V3_VM_PAUSED ? "paused" : + base->state==V3_VM_ERROR ? "ERROR" : + base->state==V3_VM_SIMULATING ? "simulating" : "UNKNOWN", + num_vcores, + num_regions, + mem->mem_size, + base->vm_type == V3_VM_GENERAL ? "general" : + base->vm_type == V3_VM_HVM ? "hvm" : "UNKNOWN"); + } + } + } + + + out: + if (mem) { palacios_vfree(mem); } + if (core) { palacios_vfree(core); } + if (base) { palacios_vfree(base); } + + return 0; +} + + +static int guests_short_proc_open(struct inode * inode, struct file * filp) +{ + struct proc_dir_entry * proc_entry = PDE(inode); + return single_open(filp, read_guests, proc_entry->data); +} + +static int guests_full_proc_open(struct inode * inode, struct file * filp) +{ + struct proc_dir_entry * proc_entry = PDE(inode); + return single_open(filp, read_guests_details, proc_entry->data); +} + + + + +static struct file_operations guest_full_proc_ops = { + .owner = THIS_MODULE, + .open = guests_full_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static struct file_operations guest_short_proc_ops = { + .owner = THIS_MODULE, + .open = guests_short_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +// Supply basic information that the user-space tools need +// to manipulate Palacios. The current use case here is to +// convey memory information +static int read_info(struct seq_file *s, void *v) +{ + uint64_t mem_block_size; + int i,j; + int max_node=-1; + seq_printf(s,"kernel MAX_ORDER:\t%d\n",MAX_ORDER); + seq_printf(s,"number of nodes:\t%d\n", numa_num_nodes()); + seq_printf(s,"number of cpus: \t%d\n", num_online_cpus()); + seq_printf(s,"\npalacios compiled mem_block_size:\t%d\n", V3_CONFIG_MEM_BLOCK_SIZE); + if (!v3_lookup_option("mem_block_size")) { + mem_block_size = V3_CONFIG_MEM_BLOCK_SIZE; + } else { + if (strict_strtoull(v3_lookup_option("mem_block_size"), 0, &mem_block_size)) { + // huh? + mem_block_size=-1; + } + } + seq_printf(s,"palacios run-time mem_block_size:\t%llu\n", mem_block_size); + + seq_printf(s,"\nCPU to node mappings\n"); + for (i=0;i node %d\n", i, numa_cpu_to_node(i)); + if (numa_cpu_to_node(i)>max_node) { + max_node=numa_cpu_to_node(i); + } + } + seq_printf(s,"\nNode to node distances\n"); + for (j=0;j<=max_node;j++) { + seq_printf(s," \t%2d", j); + } + seq_printf(s,"\n"); + for (i=0;i<=max_node;i++) { + seq_printf(s,"%2d ",i); + for (j=0;j<=max_node;j++) { + seq_printf(s,"\t%2d", numa_get_distance(i,j)); + } + seq_printf(s,"\n"); + } + seq_printf(s,"\nCPU to CPU distances\n"); + for (j=0;jdata); +} + + + +static struct file_operations info_proc_ops = { + .owner = THIS_MODULE, + .open = info_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + + +static inline uint_t thr_hash_func(addr_t key) +{ + return palacios_hash_long((long)key,64); +} + +static inline int thr_hash_comp(addr_t k1, addr_t k2) +{ + return k1==k2; +} + static int __init v3_init(void) { + dev_t dev = MKDEV(0, 0); // We dynamicallly assign the major number int ret = 0; + LOCKCHECK_INIT(); + MEMCHECK_INIT(); - palacios_init_mm(); + if (!(v3_thread_resource_map = palacios_create_htable(MAX_THREADS,thr_hash_func,thr_hash_comp))) { + ERROR("Could not create thread/resource map\n"); + ret = -1; + goto failure0; + } - // Initialize Palacios - - palacios_vmm_init(); + palacios_proc_dir = proc_mkdir("v3vee", NULL); + if (!palacios_proc_dir) { + ERROR("Could not create proc entry\n"); + ret = -1; + goto failure1; + } + // this will populate the v3vee tree... + if (palacios_init_mm()) { + goto failure2; + } + + if (allow_devmem) { + palacios_allow_devmem(); + } + + // numa is now a required interface and we need it + // up before primary initiatilization + palacios_init_numa(); + + // Initialize Palacios + palacios_vmm_init(options); // initialize extensions init_lnx_extensions(); v3_class = class_create(THIS_MODULE, "vms"); - if (IS_ERR(v3_class)) { - printk("Failed to register V3 VM device class\n"); - return PTR_ERR(v3_class); + if (!v3_class || IS_ERR(v3_class)) { + ERROR("Failed to register V3 VM device class\n"); + ret = PTR_ERR(v3_class); + goto failure3; } - printk("intializing V3 Control device\n"); + INFO("intializing V3 Control device\n"); ret = alloc_chrdev_region(&dev, 0, MAX_VMS + 1, "v3vee"); if (ret < 0) { - printk("Error registering device region for V3 devices\n"); - goto failure2; + ERROR("Error registering device region for V3 devices\n"); + goto failure4; } v3_major_num = MAJOR(dev); @@ -228,7 +666,7 @@ static int __init v3_init(void) { dev = MKDEV(v3_major_num, MAX_VMS + 1); - printk("Creating V3 Control device: Major %d, Minor %d\n", v3_major_num, MINOR(dev)); + DEBUG("Creating V3 Control device: Major %d, Minor %d\n", v3_major_num, MINOR(dev)); cdev_init(&ctrl_dev, &v3_ctrl_fops); ctrl_dev.owner = THIS_MODULE; ctrl_dev.ops = &v3_ctrl_fops; @@ -237,18 +675,66 @@ static int __init v3_init(void) { device_create(v3_class, NULL, dev, NULL, "v3vee"); if (ret != 0) { - printk("Error adding v3 control device\n"); - goto failure1; + ERROR("Error adding v3 control device\n"); + goto failure5; } + { + struct proc_dir_entry *entry; + + entry = create_proc_entry("v3-guests", 0444, palacios_proc_dir); + if (entry) { + entry->proc_fops = &guest_short_proc_ops; + INFO("/proc/v3vee/v3-guests successfully created\n"); + } else { + ERROR("Could not create proc entry\n"); + goto failure6; + } + entry = create_proc_entry("v3-guests-details", 0444, palacios_proc_dir); + if (entry) { + entry->proc_fops = &guest_full_proc_ops; + INFO("/proc/v3vee/v3-guests-details successfully created\n"); + } else { + ERROR("Could not create proc entry\n"); + goto failure7; + } + + entry = create_proc_entry("v3-info", 0444, palacios_proc_dir); + if (entry) { + entry->proc_fops = &info_proc_ops; + INFO("/proc/v3vee/v3-info successfully created\n"); + } else { + ERROR("Could not create proc entry\n"); + goto failure8; + } + } + return 0; - failure1: + failure8: + remove_proc_entry("v3-guests-details", palacios_proc_dir); + failure7: + remove_proc_entry("v3-guests", palacios_proc_dir); + failure6: + device_destroy(v3_class, dev); + failure5: unregister_chrdev_region(MKDEV(v3_major_num, 0), MAX_VMS + 1); - failure2: + failure4: class_destroy(v3_class); + failure3: + if (allow_devmem) { + palacios_restore_devmem(); + } + palacios_deinit_mm(); + failure2: + remove_proc_entry("v3vee", NULL); + failure1: + palacios_free_htable(v3_thread_resource_map,0,0); + failure0: + MEMCHECK_DEINIT(); + LOCKCHECK_DEINIT(); return ret; } @@ -259,21 +745,43 @@ static void __exit v3_exit(void) { extern u32 pg_frees; extern u32 mallocs; extern u32 frees; + extern u32 vmallocs; + extern u32 vfrees; + int i = 0; + struct v3_guest * guest; + dev_t dev; + + /* Stop and free any running VMs */ + for (i = 0; i < MAX_VMS; i++) { + if (guest_map[i] != NULL) { + guest = (struct v3_guest *)(guest_map[i]); - // should probably try to stop any guests + if (!guest->v3_ctx) { + ERROR("Orphan VM detected and skipped: index=%d name=%s\n", i, guest->name); + continue; + } + if (v3_stop_vm(guest->v3_ctx) < 0) + ERROR("Couldn't stop VM %d\n", i); + free_palacios_vm(guest); + guest_map[i] = NULL; + } + } - dev_t dev = MKDEV(v3_major_num, MAX_VMS + 1); + dev = MKDEV(v3_major_num, MAX_VMS + 1); - printk("Removing V3 Control device\n"); + INFO("Removing V3 Control device\n"); palacios_vmm_exit(); - printk("Palacios Mallocs = %d, Frees = %d\n", mallocs, frees); - printk("Palacios Page Allocs = %d, Page Frees = %d\n", pg_allocs, pg_frees); + palacios_deinit_numa(); + + DEBUG("Palacios Mallocs = %d, Frees = %d\n", mallocs, frees); + DEBUG("Palacios Vmallocs = %d, Vfrees = %d\n", vmallocs, vfrees); + DEBUG("Palacios Page Allocs = %d, Page Frees = %d\n", pg_allocs, pg_frees); unregister_chrdev_region(MKDEV(v3_major_num, 0), MAX_VMS + 1); @@ -285,9 +793,23 @@ static void __exit v3_exit(void) { deinit_lnx_extensions(); + if (allow_devmem) { + palacios_restore_devmem(); + } + palacios_deinit_mm(); - printk("Palacios Module Mallocs = %d, Frees = %d\n", mod_allocs, mod_frees); + remove_proc_entry("v3-info", palacios_proc_dir); + remove_proc_entry("v3-guests-details", palacios_proc_dir); + remove_proc_entry("v3-guests", palacios_proc_dir); + remove_proc_entry("v3vee", NULL); + + DEBUG("Palacios Module Mallocs = %d, Frees = %d\n", mod_allocs, mod_frees); + + palacios_free_htable(v3_thread_resource_map,0,0); + + MEMCHECK_DEINIT(); + LOCKCHECK_DEINIT(); } @@ -301,7 +823,7 @@ void * trace_malloc(size_t size, gfp_t flags) { void * addr = NULL; mod_allocs++; - addr = kmalloc(size, flags); + addr = palacios_alloc_extended(size, flags, -1); return addr; } @@ -309,5 +831,5 @@ void * trace_malloc(size_t size, gfp_t flags) { void trace_free(const void * objp) { mod_frees++; - kfree(objp); + palacios_free((void*)objp); }