[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen master] evtchn: don't lose pending state if FIFO event array page is missing
commit 917c12302985f7702664faa572f9a2963f4aa947 Author: David Vrabel <david.vrabel@xxxxxxxxxx> AuthorDate: Wed Nov 6 10:20:24 2013 +0100 Commit: Jan Beulich <jbeulich@xxxxxxxx> CommitDate: Wed Nov 6 10:20:24 2013 +0100 evtchn: don't lose pending state if FIFO event array page is missing 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> Reviewed-by: Jan Beulich <jbeulich@xxxxxxxx> Acked-by: Keir Fraser <keir@xxxxxxx> --- 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 0628727..2397537 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 -- generated by git-patchbot for /home/xen/git/xen.git#master _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |