qemu-kvm: Introduce writeback scope for cpu_synchronize_state
RFC PATCH 1/1 qemu-kvm: Introduce writeback scope for cpu_synchronize_state
This patch aims at addressing the mp_state writeback issue in a cleaner fashion. By introducing additional information about the scope of the scheduled vcpu state writeback, we can simply skin mp_state (and maybe other specific states in the future) when updating the in-kernel state.
The writeback scope is defined when calling cpu_synchronize_state. It accumulated, ie. once a full writeback was requested, this will stick until it was performed.
This unbreaks --disable-kvm builds of qemu-kvm again.
---
A corresponding upstream patch is ready to be posted as well, just waiting for comments on the general direction from KVM POV.
cpu-defs.h | 2 +- exec.c | 4 ++-- gdbstub.c | 8 ++++---- hw/apic.c | 5 ++--- hw/pc.c | 2 +- monitor.c | 6 ++---- qemu-kvm-ia64.c | 2 ++ qemu-kvm-x86.c | 6 ++++-- qemu-kvm.c | 44 +++++++++++++++++++++++++------------------- qemu-kvm.h | 13 ++++++------- target-i386/helper.c | 2 +- target-i386/machine.c | 7 ++----- target-ppc/machine.c | 4 ++-- 13 files changed, 54 insertions(+), 51 deletions(-)
cpu-defs.h +1 -1
@@ -142,7 +142,7 @@ struct KVMCPUState {pthread_t thread;int signalled;struct qemu_work_item *queued_work_first, *queued_work_last; -int regs_modified; +int writeback_scope; };#define CPU_TEMP_BUF_NLONGS 128
exec.c +2 -2
@@ -529,14 +529,14 @@ static void cpu_common_pre_save(void *opaque) {CPUState *env = opaque; -cpu_synchronize_state (env); +cpu_synchronize_state (env,CPU_SYNC_RUNTIME ); }static int cpu_common_pre_load (void *opaque) {CPUState *env = opaque; -cpu_synchronize_state (env); +cpu_synchronize_state (env,CPU_SYNC_RESET );return 0 ; }
gdbstub.c +4 -4
@@ -1598,7 +1598,7 @@ static void gdb_breakpoint_remove_all(void)static void gdb_set_cpu_pc (GDBState *s,target_ulong pc) {#if defined(TARGET_I386 ) -cpu_synchronize_state (s->c_cpu); +cpu_synchronize_state (s->c_cpu,CPU_SYNC_RUNTIME ); s->c_cpu->eip = pc;#elif defined (TARGET_PPC ) s->c_cpu->nip = pc;
@@ -1785,7 +1785,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) }break ;case 'g' : -cpu_synchronize_state (s->g_cpu); +cpu_synchronize_state (s->g_cpu,CPU_SYNC_RUNTIME ); len =0 ;for (addr =0 ; addr < num_g_regs; addr++) { reg_size =gdb_read_register (s->g_cpu, mem_buf + len, addr);
@@ -1795,7 +1795,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)put_packet (s, buf);break ;case 'G' : -cpu_synchronize_state (s->g_cpu); +cpu_synchronize_state (s->g_cpu,CPU_SYNC_RUNTIME ); registers = mem_buf; len =strlen (p) /2 ;hextomem ((uint8_t *)registers, p, len);
@@ -1959,7 +1959,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) thread =strtoull (p+16 , (char **)&p,16 ); env =find_cpu (thread);if (env !=NULL ) { -cpu_synchronize_state (env); +cpu_synchronize_state (env,CPU_SYNC_RUNTIME ); len =snprintf ((char *)mem_buf,sizeof (mem_buf),"CPU#%d [%s]" , env->cpu_index, env->halted ?"halted " :"running" );
hw/apic.c +2 -3
@@ -488,7 +488,7 @@ void apic_init_reset(CPUState *env)if (!s)return ; -cpu_synchronize_state (env); +cpu_synchronize_state (env,CPU_SYNC_RESET ); s->tpr =0 ; s->spurious_vec =0xff ; s->log_dest =0 ;
@@ -512,7 +512,6 @@ void apic_init_reset(CPUState *env)if (kvm_enabled () &&kvm_irqchip_in_kernel ()) { env->mp_state = env->halted ?KVM_MP_STATE_UNINITIALIZED :KVM_MP_STATE_RUNNABLE ; -kvm_load_mpstate (env); }#endif }
@@ -1070,7 +1069,7 @@ static void apic_reset(void *opaque)APICState *s = opaque;int bsp; -cpu_synchronize_state (s->cpu_env); +cpu_synchronize_state (s->cpu_env,CPU_SYNC_RESET ); bsp =cpu_is_bsp (s->cpu_env); s->apicbase = 0xfee00000 |
hw/pc.c +1 -1
@@ -1021,7 +1021,7 @@ CPUState *pc_new_cpu(const char *cpu_model)fprintf (stderr,"Unable to find x86 CPU definition\n" );exit (1 ); } - env->kvm_cpu_state.regs_modified =1 ; + env->kvm_cpu_state.writeback_scope =CPU_SYNC_RESET ;if ((env->cpuid_features &CPUID_APIC ) || smp_cpus >1 ) { env->cpuid_apic_id = env->cpu_index;/* APIC reset callback resets cpu */
monitor.c +2 -4
@@ -394,8 +394,7 @@ static CPUState *mon_get_cpu(void)if (!cur_mon->mon_cpu) {mon_set_cpu (0 ); } -cpu_synchronize_state (cur_mon->mon_cpu); -kvm_save_mpstate (cur_mon->mon_cpu); +cpu_synchronize_state (cur_mon->mon_cpu,CPU_SYNC_RUNTIME );return cur_mon->mon_cpu; }
@@ -486,8 +485,7 @@ static void do_info_cpus(Monitor *mon, QObject **ret_data)const char *answer;QDict *cpu =qdict_new (); -cpu_synchronize_state (env); -kvm_save_mpstate (env); +cpu_synchronize_state (env,CPU_SYNC_RUNTIME );qdict_put (cpu,"CPU" ,qint_from_int (env->cpu_index)); answer = (env == mon->mon_cpu) ?"yes" :"no" ;
qemu-kvm-ia64.c +2 -0
@@ -103,6 +103,8 @@ void kvm_arch_save_mpstate(CPUState *env) env->mp_state =-1 ; else env->mp_state = mp_state.mp_state; +if (kvm_irqchip_in_kernel (kvm_context)) + env->halted = (env->mp_state ==KVM_MP_STATE_HALTED );#endif }
qemu-kvm-x86.c +4 -2
@@ -1040,6 +1040,8 @@ void kvm_arch_save_mpstate(CPUState *env) env->mp_state =-1 ; else env->mp_state = mp_state.mp_state; +if (kvm_irqchip_in_kernel ()) + env->halted = (env->mp_state ==KVM_MP_STATE_HALTED );#else env->mp_state =-1 ;#endif
@@ -1675,11 +1677,11 @@ uint32_t kvm_arch_get_supported_cpuid(CPUState *env, uint32_t function,void kvm_arch_process_irqchip_events (CPUState *env) {if (env->interrupt_request &CPU_INTERRUPT_INIT ) { -kvm_cpu_synchronize_state (env); +kvm_cpu_synchronize_state (env,CPU_SYNC_RESET );do_cpu_init (env); }if (env->interrupt_request &CPU_INTERRUPT_SIPI ) { -kvm_cpu_synchronize_state (env); +kvm_cpu_synchronize_state (env,CPU_SYNC_RESET );do_cpu_sipi (env); } }
qemu-kvm.c +25 -19
75 lines not on this page · raw message
qemu-kvm.h +6 -7
@@ -1098,18 +1098,17 @@ static inline int kvm_sync_vcpus(void)#ifndef QEMU_KVM_NO_CPU void kvm_arch_get_registers (CPUState *env); +void kvm_arch_put_registers (CPUState *env,int scope); -static inline void kvm_arch_put_registers (CPUState *env) -{ -kvm_load_registers (env); -} +void kvm_cpu_synchronize_state (CPUState *env,int writeback_scope); -void kvm_cpu_synchronize_state (CPUState *env); +#define CPU_SYNC_RUNTIME (1 << 0) +#define CPU_SYNC_RESET (1 << 1) -static inline void cpu_synchronize_state (CPUState *env) +static inline void cpu_synchronize_state (CPUState *env,int writeback_scope) {if (kvm_enabled ()) { -kvm_cpu_synchronize_state (env); +kvm_cpu_synchronize_state (env, writeback_scope); } }
target-i386/helper.c +1 -1
@@ -745,7 +745,7 @@ void cpu_dump_state(CPUState *env, FILE *f,char cc_op_name[32 ];static const char *seg_name[6 ] = {"ES" ,"CS" ,"SS" ,"DS" ,"FS" ,"GS" }; -cpu_synchronize_state (env); +cpu_synchronize_state (env,CPU_SYNC_RUNTIME ); eflags = env->eflags;#ifdef TARGET_X86_64
target-i386/machine.c +2 -5
@@ -323,8 +323,7 @@ static void cpu_pre_save(void *opaque)CPUState *env = opaque;int i, bit; -cpu_synchronize_state (env); -kvm_save_mpstate (env); +cpu_synchronize_state (env,CPU_SYNC_RUNTIME );/* FPU */ env->fpus_vmstate = (env->fpus & ~0x3800 ) | (env->fpstt &0x7 ) <<11 ;
@@ -355,7 +354,7 @@ static int cpu_pre_load(void *opaque) {CPUState *env = opaque; -cpu_synchronize_state (env); +cpu_synchronize_state (env,CPU_SYNC_RESET );return 0 ; }
@@ -386,8 +385,6 @@ static int cpu_post_load(void *opaque, int version_id) }tlb_flush (env,1 ); -kvm_load_mpstate (env); -return 0 ; }
target-ppc/machine.c +2 -2
@@ -8,7 +8,7 @@ void cpu_save(QEMUFile *f, void *opaque)CPUState *env = (CPUState *)opaque;unsigned int i, j; -cpu_synchronize_state (env); +cpu_synchronize_state (env,CPU_SYNC_RUNTIME );for (i =0 ; i <32 ; i++)qemu_put_betls (f, &env->gpr[i]);
@@ -97,7 +97,7 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)CPUState *env = (CPUState *)opaque;unsigned int i, j; -cpu_synchronize_state (env); +cpu_synchronize_state (env,CPU_SYNC_RESET );for (i =0 ; i <32 ; i++)qemu_get_betls (f, &env->gpr[i]);
Am 16.11.2009 um 18:00 schrieb Jan Kiszka <[email protected]>:
Quoted 9 lines
This patch aims at addressing the
mp_statewriteback issue in a cleaner fashion. By introducing additional information about the scope of the scheduled vcpu state writeback, we can simply skinmp_state(and maybe other specific states in the future) when updating the in-kernel state.The writeback scope is defined when calling
cpu_synchronize_state. It accumulated, ie. once a full writeback was requested, this will stick until it was performed.
Quoted 7 lines
This unbreaks --disable-kvm builds of qemu-kvm again.
Signed-off-by Jan Kiszka <[email protected]>---
A corresponding upstream patch is ready to be posted as well, just waiting for comments on the general direction from KVM POV.
I think I'd rather have a sync function that implicitly does the RUNTIME sync, the way it is now, and an 'advanced' one you can pass a constant what it syncs.
That way most code continues to work the way it is now. It also makes it easier readable IMHO.
Alex
Quoted 2 lines · Jan Kiszka
This patch aims at addressing the
mp_statewriteback issue in a cleaner fashion.
What's the issue? the fact that mp_state is updated whenever state is synchronized, while it could be simultaneously updated from other vcpus (which latter updates are then lost)?
Quoted 8 lines
By introducing additional information about the scope of the scheduled vcpu state writeback, we can simply skin
mp_state(and maybe other specific states in the future) when updating the in-kernel state.The writeback scope is defined when calling
cpu_synchronize_state. It accumulated, ie. once a full writeback was requested, this will stick until it was performed.
Maybe it's just simpler to divorce mp_state from the rest of the state.
Signature · 1 line
Do not meddle in the internals of kernels, for they are subtle and quick to panic.
Quoted 7 lines · Avi Kivity
Quoted 2 lines · Jan Kiszka
This patch aims at addressing the
mp_statewriteback issue in a cleaner fashion.What's the issue? the fact that
mp_stateis updated whenever state is synchronized, while it could be simultaneously updated from other vcpus (which latter updates are then lost)?
Right, the issue b8a7857071 addressed. But that approach spreads more kvm_* fragments in unrelated qemu code, e.g. the monitor, and fails to update other parts (gdbstub). And it doesn't care about what happens if kvm is off at build or runtime. Such things are better addressed in upstream by encapsulating kvm calls in synchronization points.
Quoted 11 lines
Quoted 9 lines
By introducing additional information about the scope of the scheduled vcpu state writeback, we can simply skin
mp_state(and maybe other specific states in the future) when updating the in-kernel state.The writeback scope is defined when calling
cpu_synchronize_state. It accumulated, ie. once a full writeback was requested, this will stick until it was performed.Maybe it's just simpler to divorce
mp_statefrom the rest of the state.
That won't solve the core issue. mp_state *is* part of the state, and needs to be read (to update halted) and sometimes also written when the state was hard reset.
Jan
Quoted 11 lines · Jan Kiszka
Quoted 9 lines · Avi Kivity
Quoted 3 lines · Jan Kiszka
This patch aims at addressing the
mp_statewriteback issue in a cleaner fashion.What's the issue? the fact that
mp_stateis updated whenever state is synchronized, while it could be simultaneously updated from other vcpus (which latter updates are then lost)?
Quoted 6 lines
Right, the issue
b8a7857071addressed. But that approach spreads more kvm_* fragments in unrelated qemu code, e.g. the monitor, and fails to update other parts (gdbstub). And it doesn't care about what happens if kvm is off at build or runtime. Such things are better addressed in upstream by encapsulating kvm calls in synchronization points.
Note we have the same issue with nmi and the sipi vector - any vcpu state that is updated outside the vcpu thread. These are particularly bad since we can't exclude them from updates without excluding other state as well.
The whole issue is tricky. I'm inclined to pretend we never meant any vcpu state (outside lapic) to be asynchronous and declare the whole thing a bug. We could fix it by modeling external changes to state (INIT, SIPI, NMI) as messages queued to the vcpu, to be processed in the vcpu thread. The queue would be drained before running the vcpu or before reading state from userspace, so the message queue contents can never be observed and never lost.
Of course, we can't really implement this as a queue (SIGSTOP vcpu thread -> overflow), but a word is sufficient. INIT writes the word, everything else uses compare-and-swap or set_bit to raise events (e.g. SIPI = do { oldq = vcpu->queue; newq = (oldq & ~SIPI_MASK) | sipi_vector | RUNNING; } while (!cas(&vcpu->queue, oldq, newq)))
Signature · 1 line
Do not meddle in the internals of kernels, for they are subtle and quick to panic.
Quoted 12 lines · Avi Kivity
Quoted 11 lines · Jan Kiszka
Quoted 9 lines · Avi Kivity
Quoted 3 lines · Jan Kiszka
This patch aims at addressing the
mp_statewriteback issue in a cleaner fashion.What's the issue? the fact that
mp_stateis updated whenever state is synchronized, while it could be simultaneously updated from other vcpus (which latter updates are then lost)?
Quoted 8 lines
Quoted 6 lines
Right, the issue
b8a7857071addressed. But that approach spreads more kvm_* fragments in unrelated qemu code, e.g. the monitor, and fails to update other parts (gdbstub). And it doesn't care about what happens if kvm is off at build or runtime. Such things are better addressed in upstream by encapsulating kvm calls in synchronization points.Note we have the same issue with nmi and the sipi vector - any vcpu
Good point.
Quoted 3 lines
state that is updated outside the vcpu thread. These are particularly bad since we can't exclude them from updates without excluding other state as well.
We easily can, using the very same mechanism: No need to overwrite any of the kvm_vcpu_events during runtime, only on reset/vmload).
Quoted 9 lines
The whole issue is tricky. I'm inclined to pretend we never meant any vcpu state (outside lapic) to be asynchronous and declare the whole thing a bug. We could fix it by modeling external changes to state (INIT, SIPI, NMI) as messages queued to the vcpu, to be processed in the vcpu thread. The queue would be drained before running the vcpu or before reading state from userspace, so the message queue contents can never be observed and never lost.
Quoted 6 lines
Of course, we can't really implement this as a queue (SIGSTOP vcpu thread -> overflow), but a word is sufficient. INIT writes the word, everything else uses compare-and-swap or
set_bitto raise events (e.g. SIPI = do { oldq =vcpu->queue; newq = (oldq & ~SIPI_MASK) |sipi_vector| RUNNING; } while (!cas(&vcpu->queue, oldq, newq)))
I do not yet see why we need this complication, why the proposed model isn't enough.
Jan
Quoted 9 lines · Jan Kiszka
Quoted 6 lines
state that is updated outside the vcpu thread. These are particularly bad since we can't exclude them from updates without excluding other state as well.
We easily can, using the very same mechanism: No need to overwrite any of the
kvm_vcpu_eventsduring runtime, only on reset/vmload).
That's because qemu has no need for this. But kvm is more than just serving qemu, we try to be more general. That said, I can't really see anyone wanting to arbitrarily inject an exception.
Quoted 15 lines
Quoted 8 lines
The whole issue is tricky. I'm inclined to pretend we never meant any vcpu state (outside lapic) to be asynchronous and declare the whole thing a bug. We could fix it by modeling external changes to state (INIT, SIPI, NMI) as messages queued to the vcpu, to be processed in the vcpu thread. The queue would be drained before running the vcpu or before reading state from userspace, so the message queue contents can never be observed and never lost.
Quoted 7 lines
Of course, we can't really implement this as a queue (SIGSTOP vcpu thread -> overflow), but a word is sufficient. INIT writes the word, everything else uses compare-and-swap or
set_bitto raise events (e.g. SIPI = do { oldq =vcpu->queue; newq = (oldq& ~SIPI_MASK) |sipi_vector| RUNNING; } while (!cas(&vcpu->queue, oldq, newq)))
Quoted 3 lines
I do not yet see why we need this complication, why the proposed model isn't enough.
The current interface is subtly dangerous, you can't run set(get()) as you would expect.
(well you can't with the lapic or the tsc msr either...)
Signature · 1 line
error compiling committee.c: too many arguments to function
Quoted 7 lines · Avi Kivity
Quoted 6 lines · Jan Kiszka
Quoted 6 lines
state that is updated outside the vcpu thread. These are particularly bad since we can't exclude them from updates without excluding other state as well.
Quoted 7 lines
Quoted 3 lines
We easily can, using the very same mechanism: No need to overwrite any of the
kvm_vcpu_eventsduring runtime, only on reset/vmload).That's because qemu has no need for this. But kvm is more than just serving qemu, we try to be more general. That said, I can't really see anyone wanting to arbitrarily inject an exception.
Well, the current API comes with millions of ways to shoot yourself into the foot. I don't think we can avoid them all.
Quoted 16 lines
Quoted 16 lines
Quoted 16 lines
The whole issue is tricky. I'm inclined to pretend we never meant any vcpu state (outside lapic) to be asynchronous and declare the whole thing a bug. We could fix it by modeling external changes to state (INIT, SIPI, NMI) as messages queued to the vcpu, to be processed in the vcpu thread. The queue would be drained before running the vcpu or before reading state from userspace, so the message queue contents can never be observed and never lost.
Of course, we can't really implement this as a queue (SIGSTOP vcpu thread -> overflow), but a word is sufficient. INIT writes the word, everything else uses compare-and-swap or
set_bitto raise events (e.g. SIPI = do { oldq =vcpu->queue; newq = (oldq& ~SIPI_MASK) |sipi_vector| RUNNING; } while (!cas(&vcpu->queue, oldq, newq)))
Quoted 9 lines
Quoted 3 lines
I do not yet see why we need this complication, why the proposed model isn't enough.
The current interface is subtly dangerous, you can't run set(get()) as you would expect.
(well you can't with the lapic or the tsc msr either...)
We may start documenting such dependency in kvm/api.txt. On the other hand, if you have a get/set interface vs. an inject channel, I think it's obvious that one can overwrite the other.
Jan
Quoted 8 lines · Jan Kiszka
Quoted 5 lines
That's because qemu has no need for this. But kvm is more than just serving qemu, we try to be more general. That said, I can't really see anyone wanting to arbitrarily inject an exception.
Well, the current API comes with millions of ways to shoot yourself into the foot. I don't think we can avoid them all.
It would be nice to make the API saner. Do you know of more holes?
Quoted 10 lines
Quoted 6 lines
The current interface is subtly dangerous, you can't run set(get()) as you would expect.
(well you can't with the lapic or the tsc msr either...)
We may start documenting such dependency in
kvm/api.txt. On the other hand, if you have a get/set interface vs. an inject channel, I think it's obvious that one can overwrite the other.
Problem is, the inject channels are implied (APIC messages in smp guests). Documentation is good, but if we can avoid it that's better.
Note the only way to rmw vcpu events during smp is pausing the guest, because of this race.
Signature · 1 line
error compiling committee.c: too many arguments to function
Quoted 23 lines · Avi Kivity
Quoted 8 lines · Jan Kiszka
Quoted 5 lines
That's because qemu has no need for this. But kvm is more than just serving qemu, we try to be more general. That said, I can't really see anyone wanting to arbitrarily inject an exception.
Well, the current API comes with millions of ways to shoot yourself into the foot. I don't think we can avoid them all.
It would be nice to make the API saner. Do you know of more holes?
Quoted 10 lines
Quoted 6 lines
The current interface is subtly dangerous, you can't run set(get()) as you would expect.
(well you can't with the lapic or the tsc msr either...)
We may start documenting such dependency in
kvm/api.txt. On the other hand, if you have a get/set interface vs. an inject channel, I think it's obvious that one can overwrite the other.
Quoted 5 lines
Problem is, the inject channels are implied (APIC messages in smp guests). Documentation is good, but if we can avoid it that's better.
Note the only way to rmw vcpu events during smp is pausing the guest, because of this race.
That's what qemu does on reset and load.
The alternative would be a complex get&lock/put&unlock + a queue for async events during the lock + an option to ignore what was queued when doing a true reset. Back to square #1: we would still need the proposed high-level interface to communicate the difference between replay and drop queue.
Jan
Quoted 9 lines · Jan Kiszka
Quoted 7 lines
Problem is, the inject channels are implied (APIC messages in smp guests). Documentation is good, but if we can avoid it that's better.
Note the only way to rmw vcpu events during smp is pausing the guest, because of this race.
That's what qemu does on reset and load.
These aren't rmw.
Quoted 6 lines
The alternative would be a complex get&lock/put&unlock + a queue for async events during the lock + an option to ignore what was queued when doing a true reset. Back to square #1: we would still need the proposed high-level interface to communicate the difference between replay and drop queue.
There's no need for get+lock / put+unlock; a normal get/put with the addition that get flushes the queue suffices. To make sure queued events don't affect set you need to stop the entire VM before setting state, but you need to do that anyway for non-rmw writes.
Signature · 1 line
error compiling committee.c: too many arguments to function
Quoted 5 lines · Avi Kivity
Quoted 4 lines · Jan Kiszka
Quoted 4 lines
Problem is, the inject channels are implied (APIC messages in smp guests). Documentation is good, but if we can avoid it that's better.
Quoted 7 lines
Quoted 5 lines
Quoted 3 lines
Note the only way to rmw vcpu events during smp is pausing the guest, because of this race.
That's what qemu does on reset and load.
These aren't rmw.
Not logically, but ATM technically.
Quoted 9 lines
Quoted 7 lines
The alternative would be a complex get&lock/put&unlock + a queue for async events during the lock + an option to ignore what was queued when doing a true reset. Back to square #1: we would still need the proposed high-level interface to communicate the difference between replay and drop queue.
There's no need for get+lock / put+unlock; a normal get/put with the
You need to track when to queue and when to apply directly. Call it lock or call it something else.
Quoted 4 lines
addition that get flushes the queue suffices. To make sure queued events don't affect set you need to stop the entire VM before setting state, but you need to do that anyway for non-rmw writes.
Well, sounds good, but it will be a non-trivial change in the interface semantics. At bare minimum, we would need a new mp_state interface. If we would count mp_state to our new event structure (hmm...), then we could confine the semantical changes to that new IOCTL pair. But how to deal with existing KVM kernels with their mp_state interface? It's a bit like the vcpu state thing: we are already down a specific road, and it's hard to turn around.
Jan
Quoted 8 lines · Jan Kiszka
Quoted 8 lines
Quoted 8 lines
The alternative would be a complex get&lock/put&unlock + a queue for async events during the lock + an option to ignore what was queued when doing a true reset. Back to square #1: we would still need the proposed high-level interface to communicate the difference between replay and drop queue.
Quoted 5 lines
Quoted 2 lines
There's no need for get+lock / put+unlock; a normal get/put with the
You need to track when to queue and when to apply directly. Call it lock or call it something else.
You always queue. When starting vcpu_run() or reading state to userspace you flush the queue.
The hardware equivalent is posting APIC messages, and the core executing them.
Quoted 5 lines
Quoted 5 lines
addition that get flushes the queue suffices. To make sure queued events don't affect set you need to stop the entire VM before setting state, but you need to do that anyway for non-rmw writes.
Quoted 8 lines
Well, sounds good, but it will be a non-trivial change in the interface semantics. At bare minimum, we would need a new
mp_stateinterface. If we would countmp_stateto our new event structure (hmm...), then we could confine the semantical changes to that new IOCTL pair. But how to deal with existing KVM kernels with theirmp_stateinterface? It's a bit like the vcpu state thing: we are already down a specific road, and it's hard to turn around.
I think we're not on the same page here. As I see it, no interface change is needed at all.
It's true that existing kernels don't handle this properly, which is why I said I'm willing to treat it as a bug (and thus the -stable treatment etc.). I admit it's a stretch since this is not going to be trivial (though I think less complex that you believe).
Putting mp_state into the events structure is reasonable regardless of this issue (and doable since we haven't pushed it to 2.6.33 yet). But I want to understand why you think it's needed.
Signature · 1 line
error compiling committee.c: too many arguments to function
Quoted 8 lines · Avi Kivity
Quoted 7 lines · Jan Kiszka
Quoted 7 lines
Quoted 7 lines
The alternative would be a complex get&lock/put&unlock + a queue for async events during the lock + an option to ignore what was queued when doing a true reset. Back to square #1: we would still need the proposed high-level interface to communicate the difference between replay and drop queue.
Quoted 8 lines
Quoted 5 lines
Quoted 2 lines
There's no need for get+lock / put+unlock; a normal get/put with the
You need to track when to queue and when to apply directly. Call it lock or call it something else.
You always queue. When starting
vcpu_run()or reading state to userspace you flush the queue.
Now I finally got your idea.
Quoted 21 lines
The hardware equivalent is posting APIC messages, and the core executing them.
Quoted 5 lines
Quoted 5 lines
addition that get flushes the queue suffices. To make sure queued events don't affect set you need to stop the entire VM before setting state, but you need to do that anyway for non-rmw writes.
Quoted 8 lines
Well, sounds good, but it will be a non-trivial change in the interface semantics. At bare minimum, we would need a new
mp_stateinterface. If we would countmp_stateto our new event structure (hmm...), then we could confine the semantical changes to that new IOCTL pair. But how to deal with existing KVM kernels with theirmp_stateinterface? It's a bit like the vcpu state thing: we are already down a specific road, and it's hard to turn around.I think we're not on the same page here. As I see it, no interface change is needed at all.
Quoted 9 lines
It's true that existing kernels don't handle this properly, which is why I said I'm willing to treat it as a bug (and thus the -stable treatment etc.). I admit it's a stretch since this is not going to be trivial (though I think less complex that you believe).
Putting
mp_stateinto the events structure is reasonable regardless of this issue (and doable since we haven't pushed it to 2.6.33 yet). But I want to understand why you think it's needed.
That wouldn't be required anymore with the "always queue" policy.
But what would you queue at all? Only mp_state, nmi_pending and sipi_vector? Or also all the relevant PIC and LAPIC states that might be changed asynchronously?
Jan
Quoted 43 lines · Jan Kiszka
Quoted 8 lines · Avi Kivity
Quoted 7 lines · Jan Kiszka
Quoted 7 lines
Quoted 7 lines
The alternative would be a complex get&lock/put&unlock + a queue for async events during the lock + an option to ignore what was queued when doing a true reset. Back to square #1: we would still need the proposed high-level interface to communicate the difference between replay and drop queue.
Quoted 7 lines
Quoted 5 lines
Quoted 2 lines
There's no need for get+lock / put+unlock; a normal get/put with the
You need to track when to queue and when to apply directly. Call it lock or call it something else.
You always queue. When starting
vcpu_run()or reading state to userspace you flush the queue.Now I finally got your idea.
Quoted 24 lines
The hardware equivalent is posting APIC messages, and the core executing them.
Quoted 5 lines
Quoted 5 lines
addition that get flushes the queue suffices. To make sure queued events don't affect set you need to stop the entire VM before setting state, but you need to do that anyway for non-rmw writes.
Quoted 8 lines
Well, sounds good, but it will be a non-trivial change in the interface semantics. At bare minimum, we would need a new
mp_stateinterface. If we would countmp_stateto our new event structure (hmm...), then we could confine the semantical changes to that new IOCTL pair. But how to deal with existing KVM kernels with theirmp_stateinterface? It's a bit like the vcpu state thing: we are already down a specific road, and it's hard to turn around.I think we're not on the same page here. As I see it, no interface change is needed at all.
It's true that existing kernels don't handle this properly, which is why I said I'm willing to treat it as a bug (and thus the -stable treatment etc.). I admit it's a stretch since this is not going to be trivial (though I think less complex that you believe).
Quoted 6 lines
Quoted 4 lines
Putting
mp_stateinto the events structure is reasonable regardless of this issue (and doable since we haven't pushed it to 2.6.33 yet). But I want to understand why you think it's needed.That wouldn't be required anymore with the "always queue" policy.
Hmm, unless we need mp_state manipulation analogously to KVM_NMI vs.KVM_SET_VCPU_STATE: The former will queue, the latter write, but may be overwritten by anything queued. If you just queue KVM_SET_MP_STATE, you still have a conflict between concurrent manipulations from user space, something we want to resolve automagically.
Quoted 5 lines
But what would you queue at all? Only
mp_state,nmi_pendingandsipi_vector? Or also all the relevant PIC and LAPIC states that might be changed asynchronously?
Jan
Quoted 9 lines · Jan Kiszka
Quoted 9 lines
I think we're not on the same page here. As I see it, no interface change is needed at all.
It's true that existing kernels don't handle this properly, which is why I said I'm willing to treat it as a bug (and thus the -stable treatment etc.). I admit it's a stretch since this is not going to be trivial (though I think less complex that you believe).
Quoted 7 lines
Quoted 5 lines
Putting
mp_stateinto the events structure is reasonable regardless of this issue (and doable since we haven't pushed it to 2.6.33 yet). But I want to understand why you think it's needed.That wouldn't be required anymore with the "always queue" policy.
It makes sense from a grouping point of view... maybe.
Quoted 2 lines
But what would you queue at all? Only
mp_state,nmi_pendingandsipi_vector?
INIT, too.
Quoted 3 lines
Or also all the relevant PIC and LAPIC states that might be changed asynchronously?
LAPIC cannot support RMW atm because of the timer counts. We may in the future support LAPIC as well if needed. PIC and IOAPIC need full vm stop due to many async sources (KVM_IRQ_LINE from multiple threads, device assignment interrupts, irqfd, lapic EOI messages). vcpu state has the advantage of being almost completely synchronous.
Signature · 1 line
error compiling committee.c: too many arguments to function
Quoted 18 lines · Avi Kivity
Quoted 9 lines · Jan Kiszka
Quoted 9 lines
I think we're not on the same page here. As I see it, no interface change is needed at all.
It's true that existing kernels don't handle this properly, which is why I said I'm willing to treat it as a bug (and thus the -stable treatment etc.). I admit it's a stretch since this is not going to be trivial (though I think less complex that you believe).
Quoted 7 lines
Quoted 5 lines
Putting
mp_stateinto the events structure is reasonable regardless of this issue (and doable since we haven't pushed it to 2.6.33 yet). But I want to understand why you think it's needed.That wouldn't be required anymore with the "always queue" policy.
Quoted 6 lines
It makes sense from a grouping point of view... maybe.
Quoted 2 lines
But what would you queue at all? Only
mp_state,nmi_pendingandsipi_vector?INIT, too.
INIT should be handled by queuing up the next mp_state.
BTW, as we do not inject mp_state changes from user space during runtime, the issue I saw with the current interface is not existing. We just need to add that queuing feature to asynchronous in-kernel mp_state changes, and we should be fine.
Let's assume we will have such changes in future kernels: should qemu-kvm and qemu upstream also bother about older kernels and establish workarounds? Because then we need to find a cleaner approach than the current one, and my proposed patch comes into the game again.
Jan
Quoted 5 lines · Jan Kiszka
Quoted 3 lines
INIT, too.
INIT should be handled by queuing up the next
mp_state.
And clearing the previous queue; otherwise our queue is unbounded.
Quoted 11 lines
BTW, as we do not inject
mp_statechanges from user space during runtime, the issue I saw with the current interface is not existing. We just need to add that queuing feature to asynchronous in-kernelmp_statechanges, and we should be fine.Let's assume we will have such changes in future kernels: should qemu-kvm and qemu upstream also bother about older kernels and establish workarounds? Because then we need to find a cleaner approach than the current one, and my proposed patch comes into the game again.
If we treat this as a bug, then we fix the older kernels too.
Signature · 1 line
Do not meddle in the internals of kernels, for they are subtle and quick to panic.
Quoted 9 lines · Jan Kiszka
Quoted 3 lines
That wouldn't be required anymore with the "always queue" policy.
Hmm, unless we need
mp_statemanipulation analogously toKVM_NMIvs.KVM_SET_VCPU_STATE: The former will queue, the latter write, but may be overwritten by anything queued. If you just queueKVM_SET_MP_STATE, you still have a conflict between concurrent manipulations from user space, something we want to resolve automagically.
The idea is to queue. But queueing INIT state clears the queue (we're pretending to send an INIT signal over the apic bus).
Signature · 1 line
Do not meddle in the internals of kernels, for they are subtle and quick to panic.