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

[Xen-changelog] [xen stable-4.5] evtchn: don't reuse ports that are still "busy"



commit 74b7f4631e72a6381d39021a8d9d60f40e29ef9d
Author:     David Vrabel <david.vrabel@xxxxxxxxxx>
AuthorDate: Tue Dec 15 15:39:20 2015 +0100
Commit:     Jan Beulich <jbeulich@xxxxxxxx>
CommitDate: Tue Dec 15 15:39:20 2015 +0100

    evtchn: don't reuse ports that are still "busy"
    
    When using the FIFO ABI a guest may close an event channel that is
    still LINKED.  If this port is reused, subsequent events may be lost
    because they may become pending on the wrong queue.
    
    This could be fixed by requiring guests to only close event channels
    that are not linked.  This is difficult since: a) irq cleanup in the
    guest may be done in a context that cannot wait for the event to be
    unlinked; b) the guest may attempt to rebind a PIRQ whose previous
    close is still pending; and c) existing guests already have the
    problematic behaviour.
    
    Instead, simply check a port is not "busy" (i.e., it's not linked)
    before reusing it.
    
    Guests should still drain any queues for VCPUs that are being
    offlined, or the port will become unusable until the VCPU is onlined
    and starts processing events again.
    
    Signed-off-by: David Vrabel <david.vrabel@xxxxxxxxxx>
    Reviewed-by: Jan Beulich <jbeulich@xxxxxxxx>
    master commit: 78e24c269b0a4a8b864ece725e6d4209ed95dfa7
    master date: 2015-12-02 15:21:46 +0100
---
 xen/common/event_channel.c |    3 ++-
 xen/common/event_fifo.c    |   12 ++++++++++++
 xen/include/xen/event.h    |   12 ++++++++++++
 3 files changed, 26 insertions(+), 1 deletions(-)

diff --git a/xen/common/event_channel.c b/xen/common/event_channel.c
index eece46b..7956ef1 100644
--- a/xen/common/event_channel.c
+++ b/xen/common/event_channel.c
@@ -171,7 +171,8 @@ static int get_free_port(struct domain *d)
     {
         if ( port > d->max_evtchn_port )
             return -ENOSPC;
-        if ( evtchn_from_port(d, port)->state == ECS_FREE )
+        if ( evtchn_from_port(d, port)->state == ECS_FREE
+             && !evtchn_port_is_busy(d, port) )
             return port;
     }
 
diff --git a/xen/common/event_fifo.c b/xen/common/event_fifo.c
index b81fae4..5a28968 100644
--- a/xen/common/event_fifo.c
+++ b/xen/common/event_fifo.c
@@ -312,6 +312,17 @@ static bool_t evtchn_fifo_is_masked(struct domain *d,
     return test_bit(EVTCHN_FIFO_MASKED, word);
 }
 
+static bool_t evtchn_fifo_is_busy(struct domain *d, evtchn_port_t port)
+{
+    event_word_t *word;
+
+    word = evtchn_fifo_word_from_port(d, port);
+    if ( unlikely(!word) )
+        return 0;
+
+    return test_bit(EVTCHN_FIFO_LINKED, word);
+}
+
 static int evtchn_fifo_set_priority(struct domain *d, struct evtchn *evtchn,
                                     unsigned int priority)
 {
@@ -351,6 +362,7 @@ static const struct evtchn_port_ops evtchn_port_ops_fifo =
     .unmask        = evtchn_fifo_unmask,
     .is_pending    = evtchn_fifo_is_pending,
     .is_masked     = evtchn_fifo_is_masked,
+    .is_busy       = evtchn_fifo_is_busy,
     .set_priority  = evtchn_fifo_set_priority,
     .print_state   = evtchn_fifo_print_state,
 };
diff --git a/xen/include/xen/event.h b/xen/include/xen/event.h
index 88526f8..19e1e3a 100644
--- a/xen/include/xen/event.h
+++ b/xen/include/xen/event.h
@@ -141,6 +141,11 @@ struct evtchn_port_ops {
     void (*unmask)(struct domain *d, struct evtchn *evtchn);
     bool_t (*is_pending)(struct domain *d, const struct evtchn *evtchn);
     bool_t (*is_masked)(struct domain *d, const struct evtchn *evtchn);
+    /*
+     * Is the port unavailable because it's still being cleaned up
+     * after being closed?
+     */
+    bool_t (*is_busy)(struct domain *d, evtchn_port_t port);
     int (*set_priority)(struct domain *d, struct evtchn *evtchn,
                         unsigned int priority);
     void (*print_state)(struct domain *d, const struct evtchn *evtchn);
@@ -182,6 +187,13 @@ static inline bool_t evtchn_port_is_masked(struct domain 
*d,
     return d->evtchn_port_ops->is_masked(d, evtchn);
 }
 
+static inline bool_t evtchn_port_is_busy(struct domain *d, evtchn_port_t port)
+{
+    if ( d->evtchn_port_ops->is_busy )
+        return d->evtchn_port_ops->is_busy(d, port);
+    return 0;
+}
+
 static inline int evtchn_port_set_priority(struct domain *d,
                                            struct evtchn *evtchn,
                                            unsigned int priority)
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.5

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxx
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®.