the procedure of loading/unloading KVM modules should be changed. ------------------------------------------------------------------------------------------------------------ diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 363af32..e8239b6 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -58,6 +58,10 @@ #include "irq.h" #endif +#include <linux/sched-if.h> +#include <linux/ipi.h> +#include <linux/trace.h> + MODULE_AUTHOR("Qumranet"); MODULE_LICENSE("GPL"); @@ -778,6 +782,8 @@ int kvm_vcpu_init(struct kvm_vcpu *vcpu, struct kvm *kvm, unsigned id) vcpu->vcpu_id = id; init_waitqueue_head(&vcpu->wq); + vcpu->thread = current; + page = alloc_page(GFP_KERNEL | __GFP_ZERO); if (!page) { r = -ENOMEM; @@ -929,7 +935,7 @@ static const struct mmu_notifier_ops kvm_mmu_notifier_ops = { }; #endif /* CONFIG_MMU_NOTIFIER && KVM_ARCH_WANT_MMU_NOTIFIER */ -static struct kvm *kvm_create_vm(void) +static struct kvm *kvm_create_vm(unsigned int vm_type) { struct kvm *kvm = kvm_arch_create_vm(); #ifdef KVM_COALESCED_MMIO_PAGE_OFFSET @@ -938,6 +944,22 @@ static struct kvm *kvm_create_vm(void) if (IS_ERR(kvm)) goto out; + + if (vm_type != IDLE_VM) { + if(vm_type == HOST_VM){ + kvm->is_paused_by_controller = 1; + atomic_inc(&kvm->pause_count); + }; + }else + idle_vm_kvm = kvm; + + if (vm_type == HOST_VM) host_vm_kvm = kvm; + if ( sched_init_vm(kvm) != 0) { + printk("func %s line %d sched_init_vm failed\n", + __FUNCTION__, __LINE__); + goto out; + } + #ifdef CONFIG_HAVE_KVM_IRQCHIP INIT_LIST_HEAD(&kvm->irq_routing); INIT_HLIST_HEAD(&kvm->mask_notifier_list); @@ -1017,10 +1039,20 @@ void kvm_free_physmem(struct kvm *kvm) static void kvm_destroy_vm(struct kvm *kvm) { + int i; struct mm_struct *mm = kvm->mm; kvm_arch_sync_events(kvm); spin_lock(&kvm_lock); + if(!kvm->is_paused_by_controller) + vm_pause(kvm); + for(i = 0; i < KVM_MAX_VCPUS; ++i) { + if (kvm->vcpus[i]) { + sched_destroy_vcpu(kvm->vcpus[i]); + } + } + sched_destroy_vm(kvm); + list_del(&kvm->vm_list); spin_unlock(&kvm_lock); kvm_free_irq_routing(kvm); @@ -1622,9 +1654,14 @@ void kvm_vcpu_block(struct kvm_vcpu *vcpu) break; vcpu_put(vcpu); + set_bit(_VPF_blocked, &vcpu->pause_flags); + tasklet_schedule(&per_cpu(schedule_data, raw_smp_processor_id()).sched_tasklet); schedule(); vcpu_load(vcpu); } + clear_bit(_VPF_blocked, &vcpu->pause_flags); + vcpu_wake(vcpu); + tasklet_schedule(&per_cpu(schedule_data, raw_smp_processor_id()).sched_tasklet); finish_wait(&vcpu->wq, &wait); } @@ -1702,6 +1739,7 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, int n) { int r; struct kvm_vcpu *vcpu; + struct timespec now; if (!valid_vcpu(n)) return -EINVAL; @@ -1712,7 +1750,9 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, int n) preempt_notifier_init(&vcpu->preempt_notifier, &kvm_preempt_ops); - r = kvm_arch_vcpu_setup(vcpu); + r = 0; + if (!(unlikely(is_idle_vm(kvm) || is_host_vm(kvm)))) + r = kvm_arch_vcpu_setup(vcpu); if (r) return r; @@ -1725,10 +1765,31 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, int n) mutex_unlock(&kvm->lock); /* Now it's all set up, let userspace reach it */ - kvm_get_kvm(kvm); - r = create_vcpu_fd(vcpu); - if (r < 0) - goto unlink; + if( unlikely(is_idle_vm(kvm) || is_host_vm(kvm))) { + vcpu->pause_flags = 0; + atomic_set(&vcpu->pause_count, 0); + if(is_idle_vm(kvm)) + printk(" idle domain "); + else + printk(" host domain "); + printk("vcpu %p created\n", vcpu); + }else { + kvm_get_kvm(kvm); + r = create_vcpu_fd(vcpu); + if (r < 0) + goto unlink; + + set_bit(_VPF_blocked, &vcpu->pause_flags); + } + if ( is_host_vm(kvm)){ + set_bit(_VPF_blocked, &vcpu->pause_flags); + } + vcpu->status = VCPU_YIELD; + vcpu->runstate.state = is_idle_vcpu(vcpu)? RUNSTATE_running:RUNSTATE_offline; + now = current_kernel_time(); + vcpu->runstate.state_entry_time = timespec_to_ns(&now); + if (sched_init_vcpu(vcpu, n % num_online_cpus()) != 0) + goto unlink; return r; unlink: @@ -1845,12 +1906,19 @@ static long kvm_vcpu_ioctl(struct file *filp, if (vcpu->kvm->mm != current->mm) return -EIO; switch (ioctl) { - case KVM_RUN: + case KVM_RUN: { + struct sched_param param = { .sched_priority = MAX_RT_PRIO-1}; + r = -EINVAL; if (arg) goto out; + if(test_and_set_bool(vcpu->set_rt)){ + sched_setscheduler(current, SCHED_RR, ¶m); + } + r = kvm_arch_vcpu_ioctl_run(vcpu, vcpu->run); break; + } case KVM_GET_REGS: { struct kvm_regs *kvm_regs; @@ -2247,7 +2315,7 @@ static int kvm_dev_ioctl_create_vm(void) int fd; struct kvm *kvm; - kvm = kvm_create_vm(); + kvm = kvm_create_vm(NORMAL_VM); if (IS_ERR(kvm)) return PTR_ERR(kvm); fd = anon_inode_getfd("kvm-vm", &kvm_vm_fops, kvm, 0); @@ -2558,11 +2626,54 @@ static void kvm_sched_out(struct preempt_notifier *pn, kvm_arch_vcpu_put(vcpu); } +struct kvm *idle_vm_kvm; +struct kvm *host_vm_kvm; +EXPORT_SYMBOL(idle_vm_kvm); +EXPORT_SYMBOL(host_vm_kvm); + +static int init_idle_vm(void) +{ + struct kvm *idle_vm; + int cpu; + + /* Domain creation requires that scheduler structures are initialised. */ + scheduler_init(); + + idle_vm = kvm_create_vm(IDLE_VM); + if (IS_ERR(idle_vm)) + BUG_ON(1); + + + /* XXX: should we put the newly created vcpu to runqueue?*/ + for_each_online_cpu(cpu) { + if (kvm_vm_ioctl_create_vcpu(idle_vm_kvm, cpu) < 0) { + int i; + for(i=0;i<cpu;i++) + kvm_arch_vcpu_destroy(idle_vm->vcpus[i]); + printk("creating idle vcpus failed. quit!\n"); + return -1; + } + } + + scheduler_start(); + return 0; +} + +extern void kvm_force_tasklet_schedule(void* data); + +long (*sched_setaffinity_p)(pid_t pid, cpumask_t* in_mask); +EXPORT_SYMBOL_GPL(sched_setaffinity_p); + int kvm_init(void *opaque, unsigned int vcpu_size, struct module *module) { int r; int cpu; + int my_cpu = raw_smp_processor_id(); + + for_each_online_cpu ( cpu ){ + init_pending_ipi_buf(cpu); + } kvm_init_debug(); @@ -2588,6 +2699,16 @@ int kvm_init(void *opaque, unsigned int vcpu_size, if (r < 0) goto out_free_0a; + for_each_online_cpu(cpu){ + if(init_trace_buf(cpu)){ + int i; + for(i=0;i<cpu;i++) + free_trace_buf(i); + printk("alloc trace buf failed. quit!\n"); + goto out_free_1; + } + } + for_each_online_cpu(cpu) { smp_call_function_single(cpu, kvm_arch_check_processor_compat, @@ -2632,6 +2753,33 @@ int kvm_init(void *opaque, unsigned int vcpu_size, kvm_preempt_ops.sched_in = kvm_sched_in; kvm_preempt_ops.sched_out = kvm_sched_out; + if(init_idle_vm()) goto out; + + /* create the host vm */ + kvm_create_vm(HOST_VM); + for_each_online_cpu(cpu) { + if (kvm_vm_ioctl_create_vcpu(host_vm_kvm, cpu) < 0) { + kvm_destroy_vm(host_vm_kvm); + kvm_destroy_vm(idle_vm_kvm); + goto out; + } + } + + for(cpu = 0; cpu < KVM_MAX_VCPUS; ++cpu) { + struct kvm_vcpu* vcpu = host_vm_kvm->vcpus[cpu]; + if (vcpu) + clear_bit(_VPF_blocked, &vcpu->pause_flags); + } + + get_cpu(); + kvm_force_tasklet_schedule(NULL); + for_each_online_cpu(cpu) { + if(cpu != my_cpu) + smp_call_function_mask(cpumask_of_cpu(cpu), kvm_force_tasklet_schedule, NULL, 1); + } + put_cpu(); + vm_unpause_by_systemcontroller(host_vm_kvm); + return 0; out_free: @@ -2661,6 +2809,12 @@ EXPORT_SYMBOL_GPL(kvm_init); void kvm_exit(void) { + stop_auto_schedule(); + vm_pause_by_systemcontroller(host_vm_kvm); + kvm_destroy_vm(host_vm_kvm); + wait_scheduler_stops(); + kvm_destroy_vm(idle_vm_kvm); + scheduler_destroy(); kvm_trace_cleanup(); misc_deregister(&kvm_dev); kmem_cache_destroy(kvm_vcpu_cache); -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html