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

[Xen-devel] [PATCH 2/3] evtchn: don't lose pending state if FIFO event array page is missing



From: David Vrabel <david.vrabel@xxxxxxxxxx>

When the FIFO-based ABI is in use, if an event is bound when the
corresponding event array page is missing any attempt to set the event
pending will lose the event (because there is nowhere to write the
pending state).

This wasn't initially considered an issue because guests were expected
to only bind events once they had expanded the event array, however:

1. A domain may start with events already bound (by the toolstack).

2. The guest does not know what the port number will be until the
   event is bound (it doesn't know how many already bound events there
   are), so it does not know how many event array pages are required.
   This makes it difficult to expand in advanced (the current Linux
   implementation expands after binding for example).

To prevent pending events from being lost because there is no array
page, temporarily store the pending state in evtchn->pending.  When an
array page is added, use this state to set the port as pending.

Signed-off-by: David Vrabel <david.vrabel@xxxxxxxxxx>
---
 xen/common/event_fifo.c |   47 +++++++++++++++++++++++++++++++++++++++++------
 xen/include/xen/sched.h |    1 +
 2 files changed, 42 insertions(+), 6 deletions(-)

diff --git a/xen/common/event_fifo.c b/xen/common/event_fifo.c
index bec8d87..64dbfff 100644
--- a/xen/common/event_fifo.c
+++ b/xen/common/event_fifo.c
@@ -61,8 +61,16 @@ static void evtchn_fifo_set_pending(struct vcpu *v, struct 
evtchn *evtchn)
 
     port = evtchn->port;
     word = evtchn_fifo_word_from_port(d, port);
+
+    /*
+     * Event array page may not exist yet, save the pending state for
+     * when the page is added.
+     */
     if ( unlikely(!word) )
+    {
+        evtchn->pending = 1;
         return;
+    }
 
     /*
      * No locking around getting the queue. This may race with
@@ -322,16 +330,29 @@ static void cleanup_event_array(struct domain *d)
     xfree(d->evtchn_fifo);
 }
 
-static void set_priority_all(struct domain *d, unsigned int priority)
+static void setup_ports(struct domain *d)
 {
     unsigned int port;
 
+    /*
+     * For each port that is already bound:
+     *
+     * - save its pending state.
+     * - set default priority.
+     */
     for ( port = 1; port < d->max_evtchns; port++ )
     {
+        struct evtchn *evtchn;
+
         if ( !port_is_valid(d, port) )
             break;
 
-        evtchn_port_set_priority(d, evtchn_from_port(d, port), priority);
+        evtchn = evtchn_from_port(d, port);
+
+        if ( test_bit(port, &shared_info(d, evtchn_pending)) )
+            evtchn->pending = 1;
+
+        evtchn_fifo_set_priority(d, evtchn, EVTCHN_FIFO_PRIORITY_DEFAULT);
     }
 }
 
@@ -369,9 +390,6 @@ int evtchn_fifo_init_control(struct evtchn_init_control 
*init_control)
     /*
      * If this is the first control block, setup an empty event array
      * and switch to the fifo port ops.
-     *
-     * Any ports currently bound will have their priority set to the
-     * default.
      */
     if ( rc == 0 && !d->evtchn_fifo )
     {
@@ -382,7 +400,7 @@ int evtchn_fifo_init_control(struct evtchn_init_control 
*init_control)
         {
             d->evtchn_port_ops = &evtchn_port_ops_fifo;
             d->max_evtchns = EVTCHN_FIFO_NR_CHANNELS;
-            set_priority_all(d, EVTCHN_FIFO_PRIORITY_DEFAULT);
+            setup_ports(d);
         }
     }
 
@@ -395,6 +413,7 @@ static int add_page_to_event_array(struct domain *d, 
unsigned long gfn)
 {
     void *virt;
     unsigned int slot;
+    unsigned int port = d->evtchn_fifo->num_evtchns;
     int rc;
 
     slot = d->evtchn_fifo->num_evtchns / EVTCHN_FIFO_EVENT_WORDS_PER_PAGE;
@@ -408,6 +427,22 @@ static int add_page_to_event_array(struct domain *d, 
unsigned long gfn)
     d->evtchn_fifo->event_array[slot] = virt;
     d->evtchn_fifo->num_evtchns += EVTCHN_FIFO_EVENT_WORDS_PER_PAGE;
 
+    /*
+     * Re-raise any events that were pending while this array page was
+     * missing.
+     */
+    for ( ; port < d->evtchn_fifo->num_evtchns; port++ )
+    {
+        struct evtchn *evtchn;
+
+        if ( !port_is_valid(d, port) )
+            break;
+
+        evtchn = evtchn_from_port(d, port);
+        if ( evtchn->pending )
+            evtchn_fifo_set_pending(d->vcpu[evtchn->notify_vcpu_id], evtchn);
+    }
+
     return 0;
 }
 
diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h
index 25bf637..624ea15 100644
--- a/xen/include/xen/sched.h
+++ b/xen/include/xen/sched.h
@@ -97,6 +97,7 @@ struct evtchn
         u16 virq;      /* state == ECS_VIRQ */
     } u;
     u8 priority;
+    u8 pending:1;
 #ifdef FLASK_ENABLE
     void *ssid;
 #endif
-- 
1.7.2.5


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

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