diff --git a/xen/common/event_channel.c b/xen/common/event_channel.c index 2774cbba16..0e4c1953d6 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 e9c1fbe4d5..a443c98018 100644 --- a/xen/common/event_fifo.c +++ b/xen/common/event_fifo.c @@ -313,6 +313,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) { @@ -352,6 +363,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 06c0654fa6..075f4da451 100644 --- a/xen/include/xen/event.h +++ b/xen/include/xen/event.h @@ -138,6 +138,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); @@ -179,6 +184,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)