[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH] vmx-io.patch
Fix some of the race conditions that show up when the device models are running on one CPU and the VMX domain is running on another on a SMP system. Signed-off-by: Arun Sharma <arun.sharma@xxxxxxxxx> --- 1.58/xen/arch/x86/vmx.c 2005-05-26 19:36:15 -07:00 +++ edited/arch/x86/vmx.c 2005-05-27 11:52:20 -07:00 @@ -465,7 +465,7 @@ set_bit(ARCH_VMX_IO_WAIT, &d->arch.arch_vmx.flags); p->state = STATE_IOREQ_READY; evtchn_send(IOPACKET_PORT); - do_block(); + vmx_wait_io(); } enum { COPY_IN = 0, COPY_OUT }; @@ -1266,7 +1266,6 @@ case EXIT_REASON_PENDING_INTERRUPT: __vmwrite(CPU_BASED_VM_EXEC_CONTROL, MONITOR_CPU_BASED_EXEC_CONTROLS); - vmx_intr_assist(ed); break; case EXIT_REASON_TASK_SWITCH: __vmx_bug(®s); ===== arch/x86/vmx_io.c 1.24 vs edited ===== --- 1.24/xen/arch/x86/vmx_io.c 2005-05-16 01:41:48 -07:00 +++ edited/arch/x86/vmx_io.c 2005-05-27 11:53:09 -07:00 @@ -34,9 +34,6 @@ #include <asm/vmx_virpit.h> #ifdef CONFIG_VMX - -extern long do_block(); - #if defined (__i386__) static void load_cpu_user_regs(struct cpu_user_regs *regs) { @@ -186,7 +183,6 @@ { vcpu_iodata_t *vio; ioreq_t *p; - struct domain *d = ed->domain; struct cpu_user_regs *regs = guest_cpu_user_regs(); unsigned long old_eax; int sign; @@ -196,12 +192,6 @@ mpci_p = &ed->arch.arch_vmx.vmx_platform.mpci; inst_decoder_regs = mpci_p->inst_decoder_regs; - /* clear the pending event */ - ed->vcpu_info->evtchn_upcall_pending = 0; - /* clear the pending bit for port 2 */ - clear_bit(IOPACKET_PORT>>5, &ed->vcpu_info->evtchn_pending_sel); - clear_bit(IOPACKET_PORT, &d->shared_info->evtchn_pending[0]); - vio = (vcpu_iodata_t *) ed->arch.arch_vmx.vmx_platform.shared_page_va; if (vio == 0) { VMX_DBG_LOG(DBG_LEVEL_1, @@ -217,8 +207,8 @@ /* clear IO wait VMX flag */ if (test_bit(ARCH_VMX_IO_WAIT, &ed->arch.arch_vmx.flags)) { if (p->state != STATE_IORESP_READY) { - printk("got a false I/O reponse\n"); - do_block(); + /* An interrupt send event raced us */ + return; } else { p->state = STATE_INVALID; } @@ -282,6 +272,51 @@ } } +int vmx_clear_pending_io_event(struct exec_domain *ed) +{ + struct domain *d = ed->domain; + + /* evtchn_pending is shared by other event channels in 0-31 range */ + if (!d->shared_info->evtchn_pending[IOPACKET_PORT>>5]) + clear_bit(IOPACKET_PORT>>5, &ed->vcpu_info->evtchn_pending_sel); + + /* Note: VMX domains may need upcalls as well */ + if (!ed->vcpu_info->evtchn_pending_sel) + ed->vcpu_info->evtchn_upcall_pending = 0; + + /* clear the pending bit for IOPACKET_PORT */ + return test_and_clear_bit(IOPACKET_PORT, + &d->shared_info->evtchn_pending[0]); +} + +/* Because we've cleared the pending events first, we need to guarantee that + * all events to be handled by xen for VMX domains are taken care of here. + * + * interrupts are guaranteed to be checked before resuming guest. + * VMX upcalls have been already arranged for if necessary. + */ +void vmx_check_events(struct exec_domain *d) +{ + /* clear the event *before* checking for work. This should avoid + the set-and-check races */ + if (vmx_clear_pending_io_event(current)) + vmx_io_assist(d); +} + +/* On exit from vmx_wait_io, we're guaranteed to have a I/O response from + the device model */ +void vmx_wait_io() +{ + extern void do_block(); + + do { + do_block(); + vmx_check_events(current); + if (!test_bit(ARCH_VMX_IO_WAIT, ¤t->arch.arch_vmx.flags)) + break; + } while(1); +} + #if defined(__i386__) || defined(__x86_64__) static inline int __fls(u32 word) { @@ -440,22 +475,17 @@ __vmwrite(HOST_ESP, (unsigned long)get_stack_bottom()); if (event_pending(d)) { - if (test_bit(IOPACKET_PORT, &d->domain->shared_info->evtchn_pending[0])) - vmx_io_assist(d); + vmx_check_events(d); - else if (test_bit(ARCH_VMX_IO_WAIT, &d->arch.arch_vmx.flags)) { - printk("got an event while blocked on I/O\n"); - do_block(); - } - - /* Assumption: device model will not inject an interrupt - * while an ioreq_t is pending i.e. the response and - * interrupt can come together. But an interrupt without - * a response to ioreq_t is not ok. - */ + if (test_bit(ARCH_VMX_IO_WAIT, &d->arch.arch_vmx.flags)) + vmx_wait_io(); } - if (!test_bit(ARCH_VMX_IO_WAIT, &d->arch.arch_vmx.flags)) - vmx_intr_assist(d); + + /* We can't resume the guest if we're waiting on I/O */ + ASSERT(!test_bit(ARCH_VMX_IO_WAIT, &d->arch.arch_vmx.flags)); + + /* We always check for interrupts before resuming guest */ + vmx_intr_assist(d); } #endif /* CONFIG_VMX */ ===== arch/x86/vmx_platform.c 1.19 vs edited ===== --- 1.19/xen/arch/x86/vmx_platform.c 2005-05-26 20:16:05 -07:00 +++ edited/arch/x86/vmx_platform.c 2005-05-27 11:52:21 -07:00 @@ -470,7 +470,6 @@ struct mi_per_cpu_info *mpci_p; struct cpu_user_regs *inst_decoder_regs; extern long evtchn_send(int lport); - extern long do_block(void); mpci_p = ¤t->arch.arch_vmx.vmx_platform.mpci; inst_decoder_regs = mpci_p->inst_decoder_regs; @@ -520,7 +519,7 @@ #endif evtchn_send(IOPACKET_PORT); - do_block(); + vmx_wait_io(); } void handle_mmio(unsigned long va, unsigned long gpa) ===== include/asm-x86/vmx_platform.h 1.9 vs edited ===== --- 1.9/xen/include/asm-x86/vmx_platform.h 2005-04-28 07:04:11 -07:00 +++ edited/include/asm-x86/vmx_platform.h 2005-05-27 11:52:21 -07:00 @@ -85,6 +85,7 @@ }; extern void handle_mmio(unsigned long, unsigned long); +extern void vmx_wait_io(void); extern int vmx_setup_platform(struct exec_domain *, struct cpu_user_regs *); // XXX - think about this -- maybe use bit 30 of the mfn to signify an MMIO frame. _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |