[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] Fix unmask_evtchn() when the port is bound to a different



# HG changeset patch
# User kaf24@xxxxxxxxxxxxxxxxxxxx
# Node ID 455b2b93542c728b88aba30de3e95c7d06d20ade
# Parent  62d9ac63e7f509328815443d8604f849b64d0c9d
Fix unmask_evtchn() when the port is bound to a different
VCPU.

Signed-off-by: Keir Fraser <keir@xxxxxxxxxxxxx>

diff -r 62d9ac63e7f5 -r 455b2b93542c 
linux-2.6-xen-sparse/arch/xen/kernel/evtchn.c
--- a/linux-2.6-xen-sparse/arch/xen/kernel/evtchn.c     Tue Dec 13 18:08:26 2005
+++ b/linux-2.6-xen-sparse/arch/xen/kernel/evtchn.c     Tue Dec 13 18:20:29 2005
@@ -639,6 +639,44 @@
 }
 EXPORT_SYMBOL(notify_remote_via_irq);
 
+void mask_evtchn(int port)
+{
+       shared_info_t *s = HYPERVISOR_shared_info;
+       synch_set_bit(port, &s->evtchn_mask[0]);
+}
+EXPORT_SYMBOL(mask_evtchn);
+
+void unmask_evtchn(int port)
+{
+       shared_info_t *s = HYPERVISOR_shared_info;
+       unsigned int cpu = smp_processor_id();
+       vcpu_info_t *vcpu_info = &s->vcpu_info[cpu];
+
+       /* Slow path (hypercall) if this is a non-local port. */
+       if (unlikely(cpu != cpu_from_evtchn(port))) {
+               evtchn_op_t op = { .cmd = EVTCHNOP_unmask,
+                                  .u.unmask.port = port };
+               (void)HYPERVISOR_event_channel_op(&op);
+               return;
+       }
+
+       synch_clear_bit(port, &s->evtchn_mask[0]);
+
+       /*
+        * The following is basically the equivalent of 'hw_resend_irq'. Just
+        * like a real IO-APIC we 'lose the interrupt edge' if the channel is
+        * masked.
+        */
+       if (synch_test_bit(port, &s->evtchn_pending[0]) && 
+           !synch_test_and_set_bit(port / BITS_PER_LONG,
+                                   &vcpu_info->evtchn_pending_sel)) {
+               vcpu_info->evtchn_upcall_pending = 1;
+               if (!vcpu_info->evtchn_upcall_mask)
+                       force_evtchn_callback();
+       }
+}
+EXPORT_SYMBOL(unmask_evtchn);
+
 void irq_resume(void)
 {
        evtchn_op_t op;
diff -r 62d9ac63e7f5 -r 455b2b93542c 
linux-2.6-xen-sparse/include/asm-xen/evtchn.h
--- a/linux-2.6-xen-sparse/include/asm-xen/evtchn.h     Tue Dec 13 18:08:26 2005
+++ b/linux-2.6-xen-sparse/include/asm-xen/evtchn.h     Tue Dec 13 18:20:29 2005
@@ -79,46 +79,16 @@
  */
 extern void unbind_from_irqhandler(unsigned int irq, void *dev_id);
 
-/*
- * Unlike notify_remote_via_evtchn(), this is safe to use across
- * save/restore. Notifications on a broken connection are silently dropped.
- */
-void notify_remote_via_irq(int irq);
-
 extern void irq_resume(void);
 
 /* Entry point for notifications into Linux subsystems. */
 asmlinkage void evtchn_do_upcall(struct pt_regs *regs);
 
 /* Entry point for notifications into the userland character device. */
-void evtchn_device_upcall(int port);
+extern void evtchn_device_upcall(int port);
 
-static inline void mask_evtchn(int port)
-{
-       shared_info_t *s = HYPERVISOR_shared_info;
-       synch_set_bit(port, &s->evtchn_mask[0]);
-}
-
-static inline void unmask_evtchn(int port)
-{
-       shared_info_t *s = HYPERVISOR_shared_info;
-       vcpu_info_t *vcpu_info = &s->vcpu_info[smp_processor_id()];
-
-       synch_clear_bit(port, &s->evtchn_mask[0]);
-
-       /*
-        * The following is basically the equivalent of 'hw_resend_irq'. Just
-        * like a real IO-APIC we 'lose the interrupt edge' if the channel is
-        * masked.
-        */
-       if (synch_test_bit(port, &s->evtchn_pending[0]) && 
-           !synch_test_and_set_bit(port / BITS_PER_LONG,
-                                   &vcpu_info->evtchn_pending_sel)) {
-               vcpu_info->evtchn_upcall_pending = 1;
-               if (!vcpu_info->evtchn_upcall_mask)
-                       force_evtchn_callback();
-       }
-}
+extern void mask_evtchn(int port);
+extern void unmask_evtchn(int port);
 
 static inline void clear_evtchn(int port)
 {
@@ -134,6 +104,12 @@
        (void)HYPERVISOR_event_channel_op(&op);
 }
 
+/*
+ * Unlike notify_remote_via_evtchn(), this is safe to use across
+ * save/restore. Notifications on a broken connection are silently dropped.
+ */
+extern void notify_remote_via_irq(int irq);
+
 #endif /* __ASM_EVTCHN_H__ */
 
 /*
diff -r 62d9ac63e7f5 -r 455b2b93542c xen/common/event_channel.c
--- a/xen/common/event_channel.c        Tue Dec 13 18:08:26 2005
+++ b/xen/common/event_channel.c        Tue Dec 13 18:20:29 2005
@@ -3,7 +3,7 @@
  * 
  * Event notifications from VIRQs, PIRQs, and other domains.
  * 
- * Copyright (c) 2003-2004, K A Fraser.
+ * Copyright (c) 2003-2005, K A Fraser.
  * 
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -541,6 +541,41 @@
     return rc;
 }
 
+static long evtchn_unmask(evtchn_unmask_t *unmask)
+{
+    struct domain *d = current->domain;
+    shared_info_t *s = d->shared_info;
+    int            port = unmask->port;
+    struct vcpu   *v;
+
+    spin_lock(&d->evtchn_lock);
+
+    if ( unlikely(!port_is_valid(d, port)) )
+    {
+        spin_unlock(&d->evtchn_lock);
+        return -EINVAL;
+    }
+
+    v = d->vcpu[evtchn_from_port(d, port)->notify_vcpu_id];
+
+    /*
+     * These operations must happen in strict order. Based on
+     * include/xen/event.h:evtchn_set_pending(). 
+     */
+    if ( test_and_clear_bit(port, &s->evtchn_mask[0]) &&
+         test_bit          (port, &s->evtchn_pending[0]) &&
+         !test_and_set_bit (port / BITS_PER_LONG,
+                            &v->vcpu_info->evtchn_pending_sel) &&
+         !test_and_set_bit (0, &v->vcpu_info->evtchn_upcall_pending) )
+    {
+        evtchn_notify(v);
+    }
+
+    spin_unlock(&d->evtchn_lock);
+
+    return 0;
+}
+
 long do_event_channel_op(evtchn_op_t *uop)
 {
     long rc;
@@ -600,6 +635,10 @@
 
     case EVTCHNOP_bind_vcpu:
         rc = evtchn_bind_vcpu(&op.u.bind_vcpu);
+        break;
+
+    case EVTCHNOP_unmask:
+        rc = evtchn_unmask(&op.u.unmask);
         break;
 
     default:
diff -r 62d9ac63e7f5 -r 455b2b93542c xen/include/public/event_channel.h
--- a/xen/include/public/event_channel.h        Tue Dec 13 18:08:26 2005
+++ b/xen/include/public/event_channel.h        Tue Dec 13 18:20:29 2005
@@ -164,6 +164,16 @@
     uint32_t vcpu;
 } evtchn_bind_vcpu_t;
 
+/*
+ * EVTCHNOP_unmask: Unmask the specified local event-channel port and deliver
+ * a notification to the appropriate VCPU if an event is pending.
+ */
+#define EVTCHNOP_unmask           9
+typedef struct evtchn_unmask {
+    /* IN parameters. */
+    evtchn_port_t port;
+} evtchn_unmask_t;
+
 typedef struct evtchn_op {
     uint32_t cmd; /* EVTCHNOP_* */
     union {
@@ -176,6 +186,7 @@
         evtchn_send_t             send;
         evtchn_status_t           status;
         evtchn_bind_vcpu_t        bind_vcpu;
+        evtchn_unmask_t           unmask;
     } u;
 } evtchn_op_t;
 
diff -r 62d9ac63e7f5 -r 455b2b93542c xen/include/xen/event.h
--- a/xen/include/xen/event.h   Tue Dec 13 18:08:26 2005
+++ b/xen/include/xen/event.h   Tue Dec 13 18:20:29 2005
@@ -3,7 +3,7 @@
  * 
  * A nice interface for passing asynchronous events to guest OSes.
  * 
- * Copyright (c) 2002, K A Fraser
+ * Copyright (c) 2002-2005, K A Fraser
  */
 
 #ifndef __XEN_EVENT_H__

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.