Commit 73880c80 authored by Gleb Natapov's avatar Gleb Natapov Committed by Avi Kivity

KVM: Break dependency between vcpu index in vcpus array and vcpu_id.

Archs are free to use vcpu_id as they see fit. For x86 it is used as
vcpu's apic id. New ioctl is added to configure boot vcpu id that was
assumed to be 0 till now.
Signed-off-by: default avatarGleb Natapov <gleb@redhat.com>
Signed-off-by: default avatarAvi Kivity <avi@redhat.com>
parent 1ed0ce00
...@@ -465,7 +465,6 @@ struct kvm_arch { ...@@ -465,7 +465,6 @@ struct kvm_arch {
unsigned long metaphysical_rr4; unsigned long metaphysical_rr4;
unsigned long vmm_init_rr; unsigned long vmm_init_rr;
int online_vcpus;
int is_sn2; int is_sn2;
struct kvm_ioapic *vioapic; struct kvm_ioapic *vioapic;
......
...@@ -25,6 +25,7 @@ config KVM ...@@ -25,6 +25,7 @@ config KVM
select PREEMPT_NOTIFIERS select PREEMPT_NOTIFIERS
select ANON_INODES select ANON_INODES
select HAVE_KVM_IRQCHIP select HAVE_KVM_IRQCHIP
select KVM_APIC_ARCHITECTURE
---help--- ---help---
Support hosting fully virtualized guest machines using hardware Support hosting fully virtualized guest machines using hardware
virtualization extensions. You will need a fairly recent virtualization extensions. You will need a fairly recent
......
...@@ -338,7 +338,7 @@ static struct kvm_vcpu *lid_to_vcpu(struct kvm *kvm, unsigned long id, ...@@ -338,7 +338,7 @@ static struct kvm_vcpu *lid_to_vcpu(struct kvm *kvm, unsigned long id,
union ia64_lid lid; union ia64_lid lid;
int i; int i;
for (i = 0; i < kvm->arch.online_vcpus; i++) { for (i = 0; i < atomic_read(&kvm->online_vcpus); i++) {
if (kvm->vcpus[i]) { if (kvm->vcpus[i]) {
lid.val = VCPU_LID(kvm->vcpus[i]); lid.val = VCPU_LID(kvm->vcpus[i]);
if (lid.id == id && lid.eid == eid) if (lid.id == id && lid.eid == eid)
...@@ -412,7 +412,7 @@ static int handle_global_purge(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) ...@@ -412,7 +412,7 @@ static int handle_global_purge(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
call_data.ptc_g_data = p->u.ptc_g_data; call_data.ptc_g_data = p->u.ptc_g_data;
for (i = 0; i < kvm->arch.online_vcpus; i++) { for (i = 0; i < atomic_read(&kvm->online_vcpus); i++) {
if (!kvm->vcpus[i] || kvm->vcpus[i]->arch.mp_state == if (!kvm->vcpus[i] || kvm->vcpus[i]->arch.mp_state ==
KVM_MP_STATE_UNINITIALIZED || KVM_MP_STATE_UNINITIALIZED ||
vcpu == kvm->vcpus[i]) vcpu == kvm->vcpus[i])
...@@ -852,8 +852,6 @@ struct kvm *kvm_arch_create_vm(void) ...@@ -852,8 +852,6 @@ struct kvm *kvm_arch_create_vm(void)
kvm_init_vm(kvm); kvm_init_vm(kvm);
kvm->arch.online_vcpus = 0;
return kvm; return kvm;
} }
...@@ -1356,8 +1354,6 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, ...@@ -1356,8 +1354,6 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm,
goto fail; goto fail;
} }
kvm->arch.online_vcpus++;
return vcpu; return vcpu;
fail: fail:
return ERR_PTR(r); return ERR_PTR(r);
......
...@@ -831,7 +831,7 @@ static void vcpu_set_itc(struct kvm_vcpu *vcpu, u64 val) ...@@ -831,7 +831,7 @@ static void vcpu_set_itc(struct kvm_vcpu *vcpu, u64 val)
kvm = (struct kvm *)KVM_VM_BASE; kvm = (struct kvm *)KVM_VM_BASE;
if (kvm_vcpu_is_bsp(vcpu)) { if (kvm_vcpu_is_bsp(vcpu)) {
for (i = 0; i < kvm->arch.online_vcpus; i++) { for (i = 0; i < atomic_read(&kvm->online_vcpus); i++) {
v = (struct kvm_vcpu *)((char *)vcpu + v = (struct kvm_vcpu *)((char *)vcpu +
sizeof(struct kvm_vcpu_data) * i); sizeof(struct kvm_vcpu_data) * i);
VMX(v, itc_offset) = itc_offset; VMX(v, itc_offset) = itc_offset;
......
...@@ -27,6 +27,7 @@ config KVM ...@@ -27,6 +27,7 @@ config KVM
select ANON_INODES select ANON_INODES
select HAVE_KVM_IRQCHIP select HAVE_KVM_IRQCHIP
select HAVE_KVM_EVENTFD select HAVE_KVM_EVENTFD
select KVM_APIC_ARCHITECTURE
---help--- ---help---
Support hosting fully virtualized guest machines using hardware Support hosting fully virtualized guest machines using hardware
virtualization extensions. You will need a fairly recent virtualization extensions. You will need a fairly recent
......
...@@ -430,6 +430,7 @@ struct kvm_trace_rec { ...@@ -430,6 +430,7 @@ struct kvm_trace_rec {
#ifdef __KVM_HAVE_PIT #ifdef __KVM_HAVE_PIT
#define KVM_CAP_PIT2 33 #define KVM_CAP_PIT2 33
#endif #endif
#define KVM_CAP_SET_BOOT_CPU_ID 34
#ifdef KVM_CAP_IRQ_ROUTING #ifdef KVM_CAP_IRQ_ROUTING
...@@ -537,6 +538,7 @@ struct kvm_irqfd { ...@@ -537,6 +538,7 @@ struct kvm_irqfd {
#define KVM_DEASSIGN_DEV_IRQ _IOW(KVMIO, 0x75, struct kvm_assigned_irq) #define KVM_DEASSIGN_DEV_IRQ _IOW(KVMIO, 0x75, struct kvm_assigned_irq)
#define KVM_IRQFD _IOW(KVMIO, 0x76, struct kvm_irqfd) #define KVM_IRQFD _IOW(KVMIO, 0x76, struct kvm_irqfd)
#define KVM_CREATE_PIT2 _IOW(KVMIO, 0x77, struct kvm_pit_config) #define KVM_CREATE_PIT2 _IOW(KVMIO, 0x77, struct kvm_pit_config)
#define KVM_SET_BOOT_CPU_ID _IO(KVMIO, 0x78)
/* /*
* ioctls for vcpu fds * ioctls for vcpu fds
......
...@@ -131,8 +131,12 @@ struct kvm { ...@@ -131,8 +131,12 @@ struct kvm {
int nmemslots; int nmemslots;
struct kvm_memory_slot memslots[KVM_MEMORY_SLOTS + struct kvm_memory_slot memslots[KVM_MEMORY_SLOTS +
KVM_PRIVATE_MEM_SLOTS]; KVM_PRIVATE_MEM_SLOTS];
#ifdef CONFIG_KVM_APIC_ARCHITECTURE
u32 bsp_vcpu_id;
struct kvm_vcpu *bsp_vcpu; struct kvm_vcpu *bsp_vcpu;
#endif
struct kvm_vcpu *vcpus[KVM_MAX_VCPUS]; struct kvm_vcpu *vcpus[KVM_MAX_VCPUS];
atomic_t online_vcpus;
struct list_head vm_list; struct list_head vm_list;
struct mutex lock; struct mutex lock;
struct kvm_io_bus mmio_bus; struct kvm_io_bus mmio_bus;
...@@ -550,8 +554,10 @@ static inline void kvm_irqfd_release(struct kvm *kvm) {} ...@@ -550,8 +554,10 @@ static inline void kvm_irqfd_release(struct kvm *kvm) {}
#endif /* CONFIG_HAVE_KVM_EVENTFD */ #endif /* CONFIG_HAVE_KVM_EVENTFD */
#ifdef CONFIG_KVM_APIC_ARCHITECTURE
static inline bool kvm_vcpu_is_bsp(struct kvm_vcpu *vcpu) static inline bool kvm_vcpu_is_bsp(struct kvm_vcpu *vcpu)
{ {
return vcpu->kvm->bsp_vcpu == vcpu; return vcpu->kvm->bsp_vcpu == vcpu;
} }
#endif #endif
#endif
...@@ -9,3 +9,6 @@ config HAVE_KVM_IRQCHIP ...@@ -9,3 +9,6 @@ config HAVE_KVM_IRQCHIP
config HAVE_KVM_EVENTFD config HAVE_KVM_EVENTFD
bool bool
select EVENTFD select EVENTFD
config KVM_APIC_ARCHITECTURE
bool
...@@ -689,11 +689,6 @@ static int kvm_vm_ioctl_deassign_device(struct kvm *kvm, ...@@ -689,11 +689,6 @@ static int kvm_vm_ioctl_deassign_device(struct kvm *kvm,
} }
#endif #endif
static inline int valid_vcpu(int n)
{
return likely(n >= 0 && n < KVM_MAX_VCPUS);
}
inline int kvm_is_mmio_pfn(pfn_t pfn) inline int kvm_is_mmio_pfn(pfn_t pfn)
{ {
if (pfn_valid(pfn)) { if (pfn_valid(pfn)) {
...@@ -1714,24 +1709,18 @@ static struct file_operations kvm_vcpu_fops = { ...@@ -1714,24 +1709,18 @@ static struct file_operations kvm_vcpu_fops = {
*/ */
static int create_vcpu_fd(struct kvm_vcpu *vcpu) static int create_vcpu_fd(struct kvm_vcpu *vcpu)
{ {
int fd = anon_inode_getfd("kvm-vcpu", &kvm_vcpu_fops, vcpu, 0); return anon_inode_getfd("kvm-vcpu", &kvm_vcpu_fops, vcpu, 0);
if (fd < 0)
kvm_put_kvm(vcpu->kvm);
return fd;
} }
/* /*
* Creates some virtual cpus. Good luck creating more than one. * 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, u32 id)
{ {
int r; int r;
struct kvm_vcpu *vcpu; struct kvm_vcpu *vcpu;
if (!valid_vcpu(n)) vcpu = kvm_arch_vcpu_create(kvm, id);
return -EINVAL;
vcpu = kvm_arch_vcpu_create(kvm, n);
if (IS_ERR(vcpu)) if (IS_ERR(vcpu))
return PTR_ERR(vcpu); return PTR_ERR(vcpu);
...@@ -1742,25 +1731,38 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, int n) ...@@ -1742,25 +1731,38 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, int n)
return r; return r;
mutex_lock(&kvm->lock); mutex_lock(&kvm->lock);
if (kvm->vcpus[n]) { if (atomic_read(&kvm->online_vcpus) == KVM_MAX_VCPUS) {
r = -EINVAL;
goto vcpu_destroy;
}
for (r = 0; r < atomic_read(&kvm->online_vcpus); r++)
if (kvm->vcpus[r]->vcpu_id == id) {
r = -EEXIST; r = -EEXIST;
goto vcpu_destroy; goto vcpu_destroy;
} }
kvm->vcpus[n] = vcpu;
if (n == 0) BUG_ON(kvm->vcpus[atomic_read(&kvm->online_vcpus)]);
kvm->bsp_vcpu = vcpu;
mutex_unlock(&kvm->lock);
/* Now it's all set up, let userspace reach it */ /* Now it's all set up, let userspace reach it */
kvm_get_kvm(kvm); kvm_get_kvm(kvm);
r = create_vcpu_fd(vcpu); r = create_vcpu_fd(vcpu);
if (r < 0) if (r < 0) {
goto unlink; kvm_put_kvm(kvm);
goto vcpu_destroy;
}
kvm->vcpus[atomic_read(&kvm->online_vcpus)] = vcpu;
smp_wmb();
atomic_inc(&kvm->online_vcpus);
#ifdef CONFIG_KVM_APIC_ARCHITECTURE
if (kvm->bsp_vcpu_id == id)
kvm->bsp_vcpu = vcpu;
#endif
mutex_unlock(&kvm->lock);
return r; return r;
unlink:
mutex_lock(&kvm->lock);
kvm->vcpus[n] = NULL;
vcpu_destroy: vcpu_destroy:
mutex_unlock(&kvm->lock); mutex_unlock(&kvm->lock);
kvm_arch_vcpu_destroy(vcpu); kvm_arch_vcpu_destroy(vcpu);
...@@ -2233,6 +2235,15 @@ static long kvm_vm_ioctl(struct file *filp, ...@@ -2233,6 +2235,15 @@ static long kvm_vm_ioctl(struct file *filp,
r = kvm_irqfd(kvm, data.fd, data.gsi, data.flags); r = kvm_irqfd(kvm, data.fd, data.gsi, data.flags);
break; break;
} }
#ifdef CONFIG_KVM_APIC_ARCHITECTURE
case KVM_SET_BOOT_CPU_ID:
r = 0;
if (atomic_read(&kvm->online_vcpus) != 0)
r = -EBUSY;
else
kvm->bsp_vcpu_id = arg;
break;
#endif
default: default:
r = kvm_arch_vm_ioctl(filp, ioctl, arg); r = kvm_arch_vm_ioctl(filp, ioctl, arg);
} }
...@@ -2299,6 +2310,9 @@ static long kvm_dev_ioctl_check_extension_generic(long arg) ...@@ -2299,6 +2310,9 @@ static long kvm_dev_ioctl_check_extension_generic(long arg)
case KVM_CAP_USER_MEMORY: case KVM_CAP_USER_MEMORY:
case KVM_CAP_DESTROY_MEMORY_REGION_WORKS: case KVM_CAP_DESTROY_MEMORY_REGION_WORKS:
case KVM_CAP_JOIN_MEMORY_REGIONS_WORKS: case KVM_CAP_JOIN_MEMORY_REGIONS_WORKS:
#ifdef CONFIG_KVM_APIC_ARCHITECTURE
case KVM_CAP_SET_BOOT_CPU_ID:
#endif
return 1; return 1;
#ifdef CONFIG_HAVE_KVM_IRQCHIP #ifdef CONFIG_HAVE_KVM_IRQCHIP
case KVM_CAP_IRQ_ROUTING: case KVM_CAP_IRQ_ROUTING:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment