diff --git a/xen/common/event_channel.c b/xen/common/event_channel.c index a8d182b584..53c17bd354 100644 --- a/xen/common/event_channel.c +++ b/xen/common/event_channel.c @@ -178,6 +178,13 @@ int evtchn_allocate_port(struct domain *d, evtchn_port_t port) return -ENOMEM; bucket_from_port(d, port) = chn; + /* + * d->valid_evtchns is used to check whether the bucket can be + * accessed without the per-domain lock. Therefore, + * d->valid_evtchns should be seen *after* the new bucket has + * been setup. + */ + smp_wmb(); write_atomic(&d->valid_evtchns, d->valid_evtchns + EVTCHNS_PER_BUCKET); } diff --git a/xen/include/xen/event.h b/xen/include/xen/event.h index ce45298377..c35f4b23b6 100644 --- a/xen/include/xen/event.h +++ b/xen/include/xen/event.h @@ -107,7 +107,17 @@ void notify_via_xen_event_channel(struct domain *ld, int lport); static inline bool_t port_is_valid(struct domain *d, unsigned int p) { - return p < read_atomic(&d->valid_evtchns); + if ( p >= read_atomic(&d->valid_evtchns) ) + return false; + + /* + * The caller will usually access the event channel afterwards and + * may be done without taking the per-domain lock. The barrier is + * going in pair the smp_wmb() barrier in evtchn_allocate_port(). + */ + smp_rmb(); + + return true; } static inline struct evtchn *evtchn_from_port(struct domain *d, unsigned int p)