Skip to content

Commit

Permalink
KVM: Dynamically allocate vcpus
Browse files Browse the repository at this point in the history
This patch converts the vcpus array in "struct kvm" to a pointer
array, 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).

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Signed-off-by: Avi Kivity <avi@qumranet.com>
  • Loading branch information
Rusty Russell authored and Avi Kivity committed Oct 13, 2007
1 parent a2fa3e9 commit fb3f0f5
Show file tree
Hide file tree
Showing 5 changed files with 236 additions and 218 deletions.
12 changes: 6 additions & 6 deletions drivers/kvm/kvm.h
Original file line number Diff line number Diff line change
Expand Up @@ -300,10 +300,8 @@ void kvm_io_bus_register_dev(struct kvm_io_bus *bus,
struct kvm_io_device *dev);

struct kvm_vcpu {
int valid;
struct kvm *kvm;
int vcpu_id;
void *_priv;
struct mutex mutex;
int cpu;
u64 host_tsc;
Expand Down Expand Up @@ -404,8 +402,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 kvm_vcpu *vcpus[KVM_MAX_VCPUS];
int memory_config_version;
int busy;
unsigned long rmap_overflow;
Expand All @@ -428,7 +425,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);
Expand Down Expand Up @@ -470,7 +468,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);
Expand All @@ -481,6 +478,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);

Expand Down
198 changes: 103 additions & 95 deletions drivers/kvm/kvm_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -266,8 +266,10 @@ void kvm_flush_remote_tlbs(struct kvm *kvm)
atomic_set(&completed, 0);
cpus_clear(cpus);
needed = 0;
for (i = 0; i < kvm->nvcpus; ++i) {
vcpu = &kvm->vcpus[i];
for (i = 0; i < KVM_MAX_VCPUS; ++i) {
vcpu = kvm->vcpus[i];
if (!vcpu)
continue;
if (test_and_set_bit(KVM_TLB_FLUSH, &vcpu->requests))
continue;
cpu = vcpu->cpu;
Expand All @@ -291,10 +293,61 @@ void kvm_flush_remote_tlbs(struct kvm *kvm)
}
}

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);
Expand All @@ -303,14 +356,6 @@ 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;
}
spin_lock(&kvm_lock);
list_add(&kvm->vm_list, &vm_list);
spin_unlock(&kvm_lock);
Expand Down Expand Up @@ -367,30 +412,11 @@ static void free_pio_guest_pages(struct kvm_vcpu *vcpu)

static void kvm_unload_vcpu_mmu(struct kvm_vcpu *vcpu)
{
if (!vcpu->valid)
return;

vcpu_load(vcpu);
kvm_mmu_unload(vcpu);
vcpu_put(vcpu);
}

static void kvm_free_vcpu(struct kvm_vcpu *vcpu)
{
if (!vcpu->valid)
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;
Expand All @@ -399,9 +425,15 @@ static void kvm_free_vcpus(struct kvm *kvm)
* 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]);
if (kvm->vcpus[i])
kvm_unload_vcpu_mmu(kvm->vcpus[i]);
for (i = 0; i < KVM_MAX_VCPUS; ++i) {
if (kvm->vcpus[i]) {
kvm_arch_ops->vcpu_free(kvm->vcpus[i]);
kvm->vcpus[i] = NULL;
}
}

}

static int kvm_dev_release(struct inode *inode, struct file *filp)
Expand Down Expand Up @@ -2372,77 +2404,47 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, int n)
{
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->valid) {
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);
if (r < 0)
goto out_free_vcpus;
return -EINVAL;

r = kvm_mmu_create(vcpu);
if (r < 0)
goto out_free_vcpus;
vcpu = kvm_arch_ops->vcpu_create(kvm, n);
if (IS_ERR(vcpu))
return PTR_ERR(vcpu);

kvm_arch_ops->vcpu_load(vcpu);
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);
if (kvm->vcpus[n]) {
r = -EEXIST;
spin_unlock(&kvm->lock);
goto mmu_unload;
}
kvm->vcpus[n] = vcpu;
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;

vcpu->valid = 1;
unlink:
spin_lock(&kvm->lock);
kvm->vcpus[n] = NULL;
spin_unlock(&kvm->lock);

return r;
mmu_unload:
vcpu_load(vcpu);
kvm_mmu_unload(vcpu);
vcpu_put(vcpu);

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:
free_vcpu:
kvm_arch_ops->vcpu_free(vcpu);
return r;
}

Expand Down Expand Up @@ -2935,9 +2937,12 @@ static void decache_vcpus_on_cpu(int cpu)
int i;

spin_lock(&kvm_lock);
list_for_each_entry(vm, &vm_list, vm_list)
list_for_each_entry(vm, &vm_list, vm_list) {
spin_lock(&vm->lock);
for (i = 0; i < KVM_MAX_VCPUS; ++i) {
vcpu = &vm->vcpus[i];
vcpu = vm->vcpus[i];
if (!vcpu)
continue;
/*
* If the vcpu is locked, then it is running on some
* other cpu and therefore it is not cached on the
Expand All @@ -2954,6 +2959,8 @@ static void decache_vcpus_on_cpu(int cpu)
mutex_unlock(&vcpu->mutex);
}
}
spin_unlock(&vm->lock);
}
spin_unlock(&kvm_lock);
}

Expand Down Expand Up @@ -3078,8 +3085,9 @@ static u64 stat_get(void *_offset)
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];
total += *(u32 *)((void *)vcpu + offset);
vcpu = kvm->vcpus[i];
if (vcpu)
total += *(u32 *)((void *)vcpu + offset);
}
spin_unlock(&kvm_lock);
return total;
Expand Down
2 changes: 1 addition & 1 deletion drivers/kvm/kvm_svm.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ static const u32 host_save_user_msrs[] = {
struct kvm_vcpu;

struct vcpu_svm {
struct kvm_vcpu *vcpu;
struct kvm_vcpu vcpu;
struct vmcb *vmcb;
unsigned long vmcb_pa;
struct svm_cpu_data *svm_data;
Expand Down
Loading

0 comments on commit fb3f0f5

Please sign in to comment.