On Thu, 2007-07-26 at 00:31 -0400, Gregory Haskins wrote:
> This is a cleanup patch to "de-VMX" the general code. It was developed in the
> preempt-hooks branch, but it should apply elsewhere as well.
Hi Gregory,
Great minds think alike. This is a little rough, but I decided to send
it out tonight because it would make your life easier...
===
Dynamically allocate vcpus
This patch converts the vcpus array in "struct kvm" to a linked list
of VCPUs, and changes the "vcpu_create" and "vcpu_setup" hooks into
one "vcpu_create" call which does the allocation and initialization of
the vcpu (calling back into the kvm_vcpu_init core helper).
It is untested on SMP or SVM, and needs some love (kvm_vcpu_uninit?
What kind of function name is that?) but the idea is that SVM and VMX
can enclose the common "kvm_vcpu" in private structures.
Signed-off-by: Rusty Russell <[EMAIL PROTECTED]>
diff -r 677938752656 drivers/kvm/kvm.h
--- a/drivers/kvm/kvm.h Wed Jul 25 13:43:25 2007 +1000
+++ b/drivers/kvm/kvm.h Wed Jul 25 16:16:56 2007 +1000
@@ -309,6 +309,7 @@ void kvm_io_bus_register_dev(struct kvm_
struct kvm_io_device *dev);
struct kvm_vcpu {
+ struct list_head list;
struct kvm *kvm;
int vcpu_id;
union {
@@ -429,8 +430,7 @@ struct kvm {
struct list_head active_mmu_pages;
int n_free_mmu_pages;
struct hlist_head mmu_page_hash[KVM_NUM_MMU_PAGES];
- int nvcpus;
- struct kvm_vcpu vcpus[KVM_MAX_VCPUS];
+ struct list_head vcpus;
int memory_config_version;
int busy;
unsigned long rmap_overflow;
@@ -453,7 +453,8 @@ struct kvm_arch_ops {
int (*hardware_setup)(void); /* __init */
void (*hardware_unsetup)(void); /* __exit */
- int (*vcpu_create)(struct kvm_vcpu *vcpu);
+ /* Create, but do not attach this VCPU */
+ struct kvm_vcpu *(*vcpu_create)(struct kvm *kvm, unsigned id);
void (*vcpu_free)(struct kvm_vcpu *vcpu);
void (*vcpu_load)(struct kvm_vcpu *vcpu);
@@ -495,7 +496,6 @@ struct kvm_arch_ops {
void (*inject_gp)(struct kvm_vcpu *vcpu, unsigned err_code);
int (*run)(struct kvm_vcpu *vcpu, struct kvm_run *run);
- int (*vcpu_setup)(struct kvm_vcpu *vcpu);
void (*skip_emulated_instruction)(struct kvm_vcpu *vcpu);
void (*patch_hypercall)(struct kvm_vcpu *vcpu,
unsigned char *hypercall_addr);
@@ -513,6 +513,9 @@ extern struct kvm_arch_ops *kvm_arch_ops
#define kvm_printf(kvm, fmt ...) printk(KERN_DEBUG fmt)
#define vcpu_printf(vcpu, fmt...) kvm_printf(vcpu->kvm, fmt)
+
+int kvm_vcpu_init(struct kvm_vcpu *vcpu, struct kvm *kvm, unsigned id);
+void kvm_vcpu_uninit(struct kvm_vcpu *vcpu);
int kvm_init_arch(struct kvm_arch_ops *ops, struct module *module);
void kvm_exit_arch(void);
diff -r 677938752656 drivers/kvm/kvm_main.c
--- a/drivers/kvm/kvm_main.c Wed Jul 25 13:43:25 2007 +1000
+++ b/drivers/kvm/kvm_main.c Wed Jul 25 18:25:15 2007 +1000
@@ -139,11 +139,6 @@ unsigned long segment_base(u16 selector)
}
EXPORT_SYMBOL_GPL(segment_base);
-static inline int valid_vcpu(int n)
-{
- return likely(n >= 0 && n < KVM_MAX_VCPUS);
-}
-
int kvm_read_guest(struct kvm_vcpu *vcpu, gva_t addr, unsigned long size,
void *dest)
{
@@ -258,7 +253,7 @@ static void ack_flush(void *_completed)
void kvm_flush_remote_tlbs(struct kvm *kvm)
{
- int i, cpu, needed;
+ int cpu, needed;
cpumask_t cpus;
struct kvm_vcpu *vcpu;
atomic_t completed;
@@ -266,8 +261,7 @@ void kvm_flush_remote_tlbs(struct kvm *k
atomic_set(&completed, 0);
cpus_clear(cpus);
needed = 0;
- for (i = 0; i < kvm->nvcpus; ++i) {
- vcpu = &kvm->vcpus[i];
+ list_for_each_entry(vcpu, &kvm->vcpus, list) {
if (test_and_set_bit(KVM_TLB_FLUSH, &vcpu->requests))
continue;
cpu = vcpu->cpu;
@@ -291,10 +285,62 @@ void kvm_flush_remote_tlbs(struct kvm *k
}
}
+int kvm_vcpu_init(struct kvm_vcpu *vcpu, struct kvm *kvm, unsigned id)
+{
+ struct page *page;
+ int r;
+
+ mutex_init(&vcpu->mutex);
+ vcpu->cpu = -1;
+ vcpu->mmu.root_hpa = INVALID_PAGE;
+ vcpu->kvm = kvm;
+ vcpu->vcpu_id = id;
+
+ page = alloc_page(GFP_KERNEL | __GFP_ZERO);
+ if (!page) {
+ r = -ENOMEM;
+ goto fail;
+ }
+ vcpu->run = page_address(page);
+
+ page = alloc_page(GFP_KERNEL | __GFP_ZERO);
+ if (!page) {
+ r = -ENOMEM;
+ goto fail_free_run;
+ }
+ vcpu->pio_data = page_address(page);
+
+ vcpu->host_fx_image = (char*)ALIGN((hva_t)vcpu->fx_buf,
+ FX_IMAGE_ALIGN);
+ vcpu->guest_fx_image = vcpu->host_fx_image + FX_IMAGE_SIZE;
+
+ r = kvm_mmu_create(vcpu);
+ if (r < 0)
+ goto fail_free_pio_data;
+
+ return 0;
+
+fail_free_pio_data:
+ free_page((unsigned long)vcpu->pio_data);
+fail_free_run:
+ free_page((unsigned long)vcpu->run);
+fail:
+ return -ENOMEM;
+}
+EXPORT_SYMBOL_GPL(kvm_vcpu_init);
+
+void kvm_vcpu_uninit(struct kvm_vcpu *vcpu)
+{
+ kvm_mmu_destroy(vcpu);
+ free_page((unsigned long)vcpu->pio_data);
+ free_page((unsigned long)vcpu->run);
+
+}
+EXPORT_SYMBOL_GPL(kvm_vcpu_uninit);
+
static struct kvm *kvm_create_vm(void)
{
struct kvm *kvm = kzalloc(sizeof(struct kvm), GFP_KERNEL);
- int i;
if (!kvm)
return ERR_PTR(-ENOMEM);
@@ -303,14 +349,7 @@ static struct kvm *kvm_create_vm(void)
spin_lock_init(&kvm->lock);
INIT_LIST_HEAD(&kvm->active_mmu_pages);
kvm_io_bus_init(&kvm->mmio_bus);
- for (i = 0; i < KVM_MAX_VCPUS; ++i) {
- struct kvm_vcpu *vcpu = &kvm->vcpus[i];
-
- mutex_init(&vcpu->mutex);
- vcpu->cpu = -1;
- vcpu->kvm = kvm;
- vcpu->mmu.root_hpa = INVALID_PAGE;
- }
+ INIT_LIST_HEAD(&kvm->vcpus);
spin_lock(&kvm_lock);
list_add(&kvm->vm_list, &vm_list);
spin_unlock(&kvm_lock);
@@ -362,41 +401,32 @@ static void free_pio_guest_pages(struct
static void kvm_unload_vcpu_mmu(struct kvm_vcpu *vcpu)
{
- if (!vcpu->vmcs)
- return;
-
vcpu_load(vcpu);
kvm_mmu_unload(vcpu);
vcpu_put(vcpu);
}
-static void kvm_free_vcpu(struct kvm_vcpu *vcpu)
-{
- if (!vcpu->vmcs)
- return;
-
- vcpu_load(vcpu);
- kvm_mmu_destroy(vcpu);
- vcpu_put(vcpu);
- kvm_arch_ops->vcpu_free(vcpu);
- free_page((unsigned long)vcpu->run);
- vcpu->run = NULL;
- free_page((unsigned long)vcpu->pio_data);
- vcpu->pio_data = NULL;
- free_pio_guest_pages(vcpu);
-}
-
static void kvm_free_vcpus(struct kvm *kvm)
{
- unsigned int i;
+ struct kvm_vcpu *vcpu;
/*
* Unpin any mmu pages first.
*/
- for (i = 0; i < KVM_MAX_VCPUS; ++i)
- kvm_unload_vcpu_mmu(&kvm->vcpus[i]);
- for (i = 0; i < KVM_MAX_VCPUS; ++i)
- kvm_free_vcpu(&kvm->vcpus[i]);
+ list_for_each_entry(vcpu, &kvm->vcpus, list)
+ kvm_unload_vcpu_mmu(vcpu);
+
+ spin_lock(&kvm->lock);
+ while (!list_empty(&kvm->vcpus)) {
+ vcpu = list_first_entry(&kvm->vcpus, struct kvm_vcpu, list);
+ list_del(&vcpu->list);
+
+ /* Drop lock to free it, now it's detached. */
+ spin_unlock(&kvm->lock);
+ kvm_arch_ops->vcpu_free(vcpu);
+ spin_lock(&kvm->lock);
+ }
+ spin_unlock(&kvm->lock);
}
static void kvm_destroy_vm(struct kvm *kvm)
@@ -2375,79 +2405,51 @@ static int create_vcpu_fd(struct kvm_vcp
/*
* Creates some virtual cpus. Good luck creating more than one.
*/
-static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, int n)
+static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, unsigned int id)
{
int r;
- struct kvm_vcpu *vcpu;
- struct page *page;
-
- r = -EINVAL;
- if (!valid_vcpu(n))
- goto out;
-
- vcpu = &kvm->vcpus[n];
- vcpu->vcpu_id = n;
-
- mutex_lock(&vcpu->mutex);
-
- if (vcpu->vmcs) {
- mutex_unlock(&vcpu->mutex);
- return -EEXIST;
- }
-
- page = alloc_page(GFP_KERNEL | __GFP_ZERO);
- r = -ENOMEM;
- if (!page)
- goto out_unlock;
- vcpu->run = page_address(page);
-
- page = alloc_page(GFP_KERNEL | __GFP_ZERO);
- r = -ENOMEM;
- if (!page)
- goto out_free_run;
- vcpu->pio_data = page_address(page);
-
- vcpu->host_fx_image = (char*)ALIGN((hva_t)vcpu->fx_buf,
- FX_IMAGE_ALIGN);
- vcpu->guest_fx_image = vcpu->host_fx_image + FX_IMAGE_SIZE;
- vcpu->cr0 = 0x10;
-
- r = kvm_arch_ops->vcpu_create(vcpu);
+ struct kvm_vcpu *vcpu, *i;
+
+ vcpu = kvm_arch_ops->vcpu_create(kvm, id);
+ if (IS_ERR(vcpu))
+ return PTR_ERR(vcpu);
+
+ vcpu_load(vcpu);
+ r = kvm_mmu_setup(vcpu);
+ vcpu_put(vcpu);
if (r < 0)
- goto out_free_vcpus;
-
- r = kvm_mmu_create(vcpu);
- if (r < 0)
- goto out_free_vcpus;
-
- kvm_arch_ops->vcpu_load(vcpu);
- r = kvm_mmu_setup(vcpu);
- if (r >= 0)
- r = kvm_arch_ops->vcpu_setup(vcpu);
- vcpu_put(vcpu);
-
- if (r < 0)
- goto out_free_vcpus;
-
+ goto free_vcpu;
+
+ spin_lock(&kvm->lock);
+ /* What do we care if they create duplicate CPU ids? But be nice. */
+ list_for_each_entry(i, &kvm->vcpus, list) {
+ if (i->vcpu_id == id) {
+ r = -EEXIST;
+ spin_unlock(&kvm->lock);
+ goto mmu_unload;
+ }
+ }
+ list_add_tail(&vcpu->list, &kvm->vcpus);
+ spin_unlock(&kvm->lock);
+
+ /* Now it's all set up, let userspace reach it */
r = create_vcpu_fd(vcpu);
if (r < 0)
- goto out_free_vcpus;
-
- spin_lock(&kvm_lock);
- if (n >= kvm->nvcpus)
- kvm->nvcpus = n + 1;
- spin_unlock(&kvm_lock);
-
+ goto unlink;
return r;
-out_free_vcpus:
- kvm_free_vcpu(vcpu);
-out_free_run:
- free_page((unsigned long)vcpu->run);
- vcpu->run = NULL;
-out_unlock:
- mutex_unlock(&vcpu->mutex);
-out:
+unlink:
+ spin_lock(&kvm->lock);
+ list_del(&vcpu->list);
+ spin_unlock(&kvm->lock);
+
+mmu_unload:
+ vcpu_load(vcpu);
+ kvm_mmu_unload(vcpu);
+ vcpu_put(vcpu);
+
+free_vcpu:
+ kvm_arch_ops->vcpu_free(vcpu);
return r;
}
@@ -2935,12 +2937,11 @@ static void decache_vcpus_on_cpu(int cpu
{
struct kvm *vm;
struct kvm_vcpu *vcpu;
- int i;
spin_lock(&kvm_lock);
- list_for_each_entry(vm, &vm_list, vm_list)
- for (i = 0; i < KVM_MAX_VCPUS; ++i) {
- vcpu = &vm->vcpus[i];
+ list_for_each_entry(vm, &vm_list, vm_list) {
+ spin_lock(&vm->lock);
+ list_for_each_entry(vcpu, &vm->vcpus, list) {
/*
* If the vcpu is locked, then it is running on some
* other cpu and therefore it is not cached on the
@@ -2957,6 +2958,8 @@ static void decache_vcpus_on_cpu(int cpu
mutex_unlock(&vcpu->mutex);
}
}
+ spin_unlock(&vm->lock);
+ }
spin_unlock(&kvm_lock);
}
@@ -3072,14 +3075,14 @@ static u64 stat_get(void *_offset)
u64 total = 0;
struct kvm *kvm;
struct kvm_vcpu *vcpu;
- int i;
spin_lock(&kvm_lock);
- list_for_each_entry(kvm, &vm_list, vm_list)
- for (i = 0; i < KVM_MAX_VCPUS; ++i) {
- vcpu = &kvm->vcpus[i];
+ list_for_each_entry(kvm, &vm_list, vm_list) {
+ spin_lock(&kvm->lock);
+ list_for_each_entry(vcpu, &kvm->vcpus, list)
total += *(u32 *)((void *)vcpu + offset);
- }
+ spin_unlock(&kvm->lock);
+ }
spin_unlock(&kvm_lock);
return total;
}
diff -r 677938752656 drivers/kvm/svm.c
--- a/drivers/kvm/svm.c Wed Jul 25 13:43:25 2007 +1000
+++ b/drivers/kvm/svm.c Wed Jul 25 18:25:25 2007 +1000
@@ -454,11 +454,6 @@ static void init_sys_seg(struct vmcb_seg
seg->attrib = SVM_SELECTOR_P_MASK | type;
seg->limit = 0xffff;
seg->base = 0;
-}
-
-static int svm_vcpu_setup(struct kvm_vcpu *vcpu)
-{
- return 0;
}
static void init_vmcb(struct vmcb *vmcb)
@@ -566,18 +561,29 @@ static void init_vmcb(struct vmcb *vmcb)
/* rdx = ?? */
}
-static int svm_create_vcpu(struct kvm_vcpu *vcpu)
-{
+struct kvm_vcpu *svm_create_vcpu(struct kvm *kvm, unsigned int id)
+{
+ int err;
struct page *page;
- int r;
-
- r = -ENOMEM;
+ struct kvm_vcpu *vcpu = kzalloc(GFP_KERNEL, sizeof(*vcpu));
+
+ if (!vcpu)
+ return ERR_PTR(-ENOMEM);
+
+ err = kvm_vcpu_init(vcpu, kvm, id);
+ if (err)
+ goto free_vcpu;
+
vcpu->svm = kzalloc(sizeof *vcpu->svm, GFP_KERNEL);
- if (!vcpu->svm)
- goto out1;
+ if (!vcpu->svm) {
+ err = -ENOMEM;
+ goto uninit_vcpu;
+ }
page = alloc_page(GFP_KERNEL);
- if (!page)
- goto out2;
+ if (!page) {
+ err = -ENOMEM;
+ goto free_svm;
+ }
vcpu->svm->vmcb = page_address(page);
clear_page(vcpu->svm->vmcb);
@@ -591,22 +597,25 @@ static int svm_create_vcpu(struct kvm_vc
vcpu->apic_base = 0xfee00000 | MSR_IA32_APICBASE_ENABLE;
if (vcpu->vcpu_id == 0)
vcpu->apic_base |= MSR_IA32_APICBASE_BSP;
-
- return 0;
-
-out2:
+ vcpu->cr0 = 0x10;
+
+ return vcpu;
+
+free_svm:
kfree(vcpu->svm);
-out1:
- return r;
+uninit_vcpu:
+ kvm_vcpu_uninit(vcpu);
+free_vcpu:
+ kfree(vcpu);
+ return ERR_PTR(err);
}
static void svm_free_vcpu(struct kvm_vcpu *vcpu)
{
- if (!vcpu->svm)
- return;
- if (vcpu->svm->vmcb)
- __free_page(pfn_to_page(vcpu->svm->vmcb_pa >> PAGE_SHIFT));
+ __free_page(pfn_to_page(vcpu->svm->vmcb_pa >> PAGE_SHIFT));
kfree(vcpu->svm);
+ kvm_vcpu_uninit(vcpu);
+ kfree(vcpu);
}
static void svm_vcpu_load(struct kvm_vcpu *vcpu)
@@ -1798,7 +1807,6 @@ static struct kvm_arch_ops svm_arch_ops
.run = svm_vcpu_run,
.skip_emulated_instruction = skip_emulated_instruction,
- .vcpu_setup = svm_vcpu_setup,
.patch_hypercall = svm_patch_hypercall,
};
diff -r 677938752656 drivers/kvm/vmx.c
--- a/drivers/kvm/vmx.c Wed Jul 25 13:43:25 2007 +1000
+++ b/drivers/kvm/vmx.c Wed Jul 25 18:22:26 2007 +1000
@@ -2234,39 +2234,60 @@ static void vmx_free_vcpu(struct kvm_vcp
static void vmx_free_vcpu(struct kvm_vcpu *vcpu)
{
vmx_free_vmcs(vcpu);
-}
-
-static int vmx_create_vcpu(struct kvm_vcpu *vcpu)
-{
- struct vmcs *vmcs;
+ kfree(vcpu->host_msrs);
+ kfree(vcpu->guest_msrs);
+ kvm_vcpu_uninit(vcpu);
+ kfree(vcpu);
+}
+
+static struct kvm_vcpu *vmx_create_vcpu(struct kvm *kvm, unsigned int id)
+{
+ int err;
+ struct kvm_vcpu *vcpu = kzalloc(sizeof(*vcpu), GFP_KERNEL);
+
+ if (!vcpu)
+ return ERR_PTR(-ENOMEM);
+
+ err = kvm_vcpu_init(vcpu, kvm, id);
+ if (err)
+ goto free_vcpu;
vcpu->guest_msrs = kmalloc(PAGE_SIZE, GFP_KERNEL);
- if (!vcpu->guest_msrs)
- return -ENOMEM;
+ if (!vcpu->guest_msrs) {
+ err = -ENOMEM;
+ goto uninit_vcpu;
+ }
vcpu->host_msrs = kmalloc(PAGE_SIZE, GFP_KERNEL);
if (!vcpu->host_msrs)
- goto out_free_guest_msrs;
-
- vmcs = alloc_vmcs();
- if (!vmcs)
- goto out_free_msrs;
-
- vmcs_clear(vmcs);
- vcpu->vmcs = vmcs;
+ goto free_guest_msrs;
+
+ vcpu->vmcs = alloc_vmcs();
+ if (!vcpu->vmcs)
+ goto free_msrs;
+
+ vmcs_clear(vcpu->vmcs);
vcpu->launched = 0;
- return 0;
-
-out_free_msrs:
+ vmx_vcpu_load(vcpu);
+ err = vmx_vcpu_setup(vcpu);
+ vmx_vcpu_put(vcpu);
+ if (err)
+ goto free_vmcs;
+
+ return vcpu;
+
+free_vmcs:
+ free_vmcs(vcpu->vmcs);
+free_msrs:
kfree(vcpu->host_msrs);
- vcpu->host_msrs = NULL;
-
-out_free_guest_msrs:
+free_guest_msrs:
kfree(vcpu->guest_msrs);
- vcpu->guest_msrs = NULL;
-
- return -ENOMEM;
+uninit_vcpu:
+ kvm_vcpu_uninit(vcpu);
+free_vcpu:
+ kfree(vcpu);
+ return ERR_PTR(err);
}
static struct kvm_arch_ops vmx_arch_ops = {
@@ -2314,7 +2335,6 @@ static struct kvm_arch_ops vmx_arch_ops
.run = vmx_vcpu_run,
.skip_emulated_instruction = skip_emulated_instruction,
- .vcpu_setup = vmx_vcpu_setup,
.patch_hypercall = vmx_patch_hypercall,
};
-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems? Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >> http://get.splunk.com/
_______________________________________________
kvm-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/kvm-devel