int port2;
long rc = 0;
- again:
- spin_lock(&d1->event_lock);
-
if ( !port_is_valid(d1, port1) )
- {
- rc = -EINVAL;
- goto out;
- }
+ return -EINVAL;
chn1 = evtchn_from_port(d1, port1);
+ again:
+ spin_lock(&d1->event_lock);
+
/* Guest cannot close a Xen-attached event channel. */
if ( unlikely(consumer_is_xen(chn1)) && guest )
{
if ( (v = domain_vcpu(d, vcpu_id)) == NULL )
return -ENOENT;
- spin_lock(&d->event_lock);
-
if ( !port_is_valid(d, port) )
- {
- rc = -EINVAL;
- goto out;
- }
+ return -EINVAL;
chn = evtchn_from_port(d, port);
+ spin_lock(&d->event_lock);
+
/* Guest cannot re-bind a Xen-attached event channel. */
if ( unlikely(consumer_is_xen(chn)) )
{
read_unlock(&evtchn->lock);
}
+/*
+ * While calling the function is okay without holding a suitable lock yet
+ * (see the comment ahead of struct evtchn_port_ops for which ones those
+ * are), for a dying domain it may start returning false at any point - see
+ * evtchn_destroy(). This is not a fundamental problem though, as the
+ * struct evtchn instance won't disappear (and will continue to hold valid
+ * data) until final cleanup of the domain, at which point the domain itself
+ * cannot be looked up anymore and hence calls here can't occur any longer
+ * in the first place.
+ */
static inline bool_t port_is_valid(struct domain *d, unsigned int p)
{
if ( p >= read_atomic(&d->valid_evtchns) )