|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH 2/3] evtchn: don't lose pending state if FIFO event array page is missing
>>> On 31.10.13 at 16:03, David Vrabel <david.vrabel@xxxxxxxxxx> wrote:
> 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>
Reviewed-by: Jan Beulich <jbeulich@xxxxxxxx>
> ---
> 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
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |