Author: royger
Date: Wed Dec 10 11:42:02 2014
New Revision: 275678
URL: https://svnweb.freebsd.org/changeset/base/275678

Log:
  xen: mask event channels while binding them to a vCPU
  
  Mask the event channel source before trying to bind it to a CPU, this
  prevents stray interrupts from firing while assigning them and hitting the
  KASSERT in xen_intr_handle_upcall.
  
  Sponsored by: Citrix Systems R&D

Modified:
  head/sys/x86/xen/xen_intr.c

Modified: head/sys/x86/xen/xen_intr.c
==============================================================================
--- head/sys/x86/xen/xen_intr.c Wed Dec 10 11:35:41 2014        (r275677)
+++ head/sys/x86/xen/xen_intr.c Wed Dec 10 11:42:02 2014        (r275678)
@@ -851,7 +851,7 @@ xen_intr_assign_cpu(struct intsrc *base_
        struct evtchn_bind_vcpu bind_vcpu;
        struct xenisrc *isrc;
        u_int to_cpu, vcpu_id;
-       int error;
+       int error, masked;
 
 #ifdef XENHVM
        if (xen_vector_callback_enabled == 0)
@@ -869,6 +869,11 @@ xen_intr_assign_cpu(struct intsrc *base_
                return (EINVAL);
        }
 
+       /*
+        * Mask the event channel while binding it to prevent interrupt
+        * delivery with an inconsistent state in isrc->xi_cpu.
+        */
+       masked = evtchn_test_and_set_mask(isrc->xi_port);
        if ((isrc->xi_type == EVTCHN_TYPE_VIRQ) ||
                (isrc->xi_type == EVTCHN_TYPE_IPI)) {
                /*
@@ -879,29 +884,25 @@ xen_intr_assign_cpu(struct intsrc *base_
                evtchn_cpu_mask_port(isrc->xi_cpu, isrc->xi_port);
                isrc->xi_cpu = to_cpu;
                evtchn_cpu_unmask_port(isrc->xi_cpu, isrc->xi_port);
-               mtx_unlock(&xen_intr_isrc_lock);
-               return (0);
+               goto out;
        }
 
        bind_vcpu.port = isrc->xi_port;
        bind_vcpu.vcpu = vcpu_id;
 
-       /*
-        * Allow interrupts to be fielded on the new VCPU before
-        * we ask the hypervisor to deliver them there.
-        */
-       evtchn_cpu_unmask_port(to_cpu, isrc->xi_port);
        error = HYPERVISOR_event_channel_op(EVTCHNOP_bind_vcpu, &bind_vcpu);
        if (isrc->xi_cpu != to_cpu) {
                if (error == 0) {
                        /* Commit to new binding by removing the old one. */
                        evtchn_cpu_mask_port(isrc->xi_cpu, isrc->xi_port);
                        isrc->xi_cpu = to_cpu;
-               } else {
-                       /* Roll-back to previous binding. */
-                       evtchn_cpu_mask_port(to_cpu, isrc->xi_port);
+                       evtchn_cpu_unmask_port(isrc->xi_cpu, isrc->xi_port);
                }
        }
+
+out:
+       if (masked == 0)
+               evtchn_unmask_port(isrc->xi_port);
        mtx_unlock(&xen_intr_isrc_lock);
        return (0);
 #else
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to