aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>2005-10-07 10:57:13 +0100
committerkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>2005-10-07 10:57:13 +0100
commitf16cb294c517a54219dc95d1dea1ddab32a7fdea (patch)
treee8e0e00d520b3500663e8e1cb0959fc551216328
parent57e576dc3cc61826682f745203cbb817f7242d94 (diff)
downloadxen-f16cb294c517a54219dc95d1dea1ddab32a7fdea.tar.gz
xen-f16cb294c517a54219dc95d1dea1ddab32a7fdea.tar.bz2
xen-f16cb294c517a54219dc95d1dea1ddab32a7fdea.zip
Big simplification of the Xen event-channel interface.
EVTCHNOP_bind_interdomain in particular is much simpler. Signed-off-by: Keir Fraser <keir@xensource.com>
-rw-r--r--linux-2.6-xen-sparse/arch/xen/kernel/evtchn.c10
-rw-r--r--linux-2.6-xen-sparse/drivers/xen/blkback/interface.c8
-rw-r--r--linux-2.6-xen-sparse/drivers/xen/blktap/interface.c8
-rw-r--r--linux-2.6-xen-sparse/drivers/xen/evtchn/evtchn.c22
-rw-r--r--linux-2.6-xen-sparse/drivers/xen/netback/interface.c8
-rw-r--r--linux-2.6-xen-sparse/drivers/xen/tpmback/interface.c8
-rw-r--r--linux-2.6-xen-sparse/include/asm-xen/evtchn.h6
-rw-r--r--tools/ioemu/vl.c2
-rw-r--r--tools/python/xen/lowlevel/xc/xc.c13
-rw-r--r--tools/python/xen/xend/XendDomainInfo.py1
-rw-r--r--xen/common/event_channel.c271
-rw-r--r--xen/include/public/event_channel.h55
12 files changed, 138 insertions, 274 deletions
diff --git a/linux-2.6-xen-sparse/arch/xen/kernel/evtchn.c b/linux-2.6-xen-sparse/arch/xen/kernel/evtchn.c
index c9555d5e70..a709dd4198 100644
--- a/linux-2.6-xen-sparse/arch/xen/kernel/evtchn.c
+++ b/linux-2.6-xen-sparse/arch/xen/kernel/evtchn.c
@@ -219,7 +219,6 @@ void unbind_virq_from_irq(int virq)
spin_lock(&irq_mapping_update_lock);
if (--irq_bindcount[irq] == 0) {
- op.u.close.dom = DOMID_SELF;
op.u.close.port = evtchn;
BUG_ON(HYPERVISOR_event_channel_op(&op) != 0);
@@ -283,7 +282,6 @@ void unbind_ipi_from_irq(int ipi)
spin_lock(&irq_mapping_update_lock);
if (--irq_bindcount[irq] == 0) {
- op.u.close.dom = DOMID_SELF;
op.u.close.port = evtchn;
BUG_ON(HYPERVISOR_event_channel_op(&op) != 0);
@@ -326,7 +324,6 @@ void unbind_evtchn_from_irq(unsigned int irq)
spin_lock(&irq_mapping_update_lock);
if ((--irq_bindcount[irq] == 0) && (evtchn != -1)) {
- op.u.close.dom = DOMID_SELF;
op.u.close.port = evtchn;
BUG_ON(HYPERVISOR_event_channel_op(&op) != 0);
@@ -513,7 +510,10 @@ static inline void pirq_query_unmask(int pirq)
static unsigned int startup_pirq(unsigned int irq)
{
evtchn_op_t op = { .cmd = EVTCHNOP_bind_pirq };
- int evtchn;
+ int evtchn = irq_to_evtchn[irq];
+
+ if (VALID_EVTCHN(evtchn))
+ goto out;
op.u.bind_pirq.pirq = irq;
/* NB. We are happy to share unless we are probing. */
@@ -532,6 +532,7 @@ static unsigned int startup_pirq(unsigned int irq)
evtchn_to_irq[evtchn] = irq;
irq_to_evtchn[irq] = evtchn;
+ out:
unmask_evtchn(evtchn);
pirq_unmask_notify(irq_to_pirq(irq));
@@ -548,7 +549,6 @@ static void shutdown_pirq(unsigned int irq)
mask_evtchn(evtchn);
- op.u.close.dom = DOMID_SELF;
op.u.close.port = evtchn;
BUG_ON(HYPERVISOR_event_channel_op(&op) != 0);
diff --git a/linux-2.6-xen-sparse/drivers/xen/blkback/interface.c b/linux-2.6-xen-sparse/drivers/xen/blkback/interface.c
index 5deb5b0cb6..458d6e9c36 100644
--- a/linux-2.6-xen-sparse/drivers/xen/blkback/interface.c
+++ b/linux-2.6-xen-sparse/drivers/xen/blkback/interface.c
@@ -71,10 +71,8 @@ int blkif_map(blkif_t *blkif, unsigned long shared_page, unsigned int evtchn)
int err;
evtchn_op_t op = {
.cmd = EVTCHNOP_bind_interdomain,
- .u.bind_interdomain.dom1 = DOMID_SELF,
- .u.bind_interdomain.dom2 = blkif->domid,
- .u.bind_interdomain.port1 = 0,
- .u.bind_interdomain.port2 = evtchn };
+ .u.bind_interdomain.remote_dom = blkif->domid,
+ .u.bind_interdomain.remote_port = evtchn };
if ( (blkif->blk_ring_area = alloc_vm_area(PAGE_SIZE)) == NULL )
return -ENOMEM;
@@ -92,7 +90,7 @@ int blkif_map(blkif_t *blkif, unsigned long shared_page, unsigned int evtchn)
return err;
}
- blkif->evtchn = op.u.bind_interdomain.port1;
+ blkif->evtchn = op.u.bind_interdomain.local_port;
sring = (blkif_sring_t *)blkif->blk_ring_area->addr;
SHARED_RING_INIT(sring);
diff --git a/linux-2.6-xen-sparse/drivers/xen/blktap/interface.c b/linux-2.6-xen-sparse/drivers/xen/blktap/interface.c
index 364025d8f8..1394922ac7 100644
--- a/linux-2.6-xen-sparse/drivers/xen/blktap/interface.c
+++ b/linux-2.6-xen-sparse/drivers/xen/blktap/interface.c
@@ -71,10 +71,8 @@ int blkif_map(blkif_t *blkif, unsigned long shared_page, unsigned int evtchn)
int err;
evtchn_op_t op = {
.cmd = EVTCHNOP_bind_interdomain,
- .u.bind_interdomain.dom1 = DOMID_SELF,
- .u.bind_interdomain.dom2 = blkif->domid,
- .u.bind_interdomain.port1 = 0,
- .u.bind_interdomain.port2 = evtchn };
+ .u.bind_interdomain.remote_dom = blkif->domid,
+ .u.bind_interdomain.remote_port = evtchn };
if ((blkif->blk_ring_area = alloc_vm_area(PAGE_SIZE)) == NULL)
return -ENOMEM;
@@ -92,7 +90,7 @@ int blkif_map(blkif_t *blkif, unsigned long shared_page, unsigned int evtchn)
return err;
}
- blkif->evtchn = op.u.bind_interdomain.port1;
+ blkif->evtchn = op.u.bind_interdomain.local_port;
sring = (blkif_sring_t *)blkif->blk_ring_area->addr;
SHARED_RING_INIT(sring);
diff --git a/linux-2.6-xen-sparse/drivers/xen/evtchn/evtchn.c b/linux-2.6-xen-sparse/drivers/xen/evtchn/evtchn.c
index b273e65fbd..fd39bd8a05 100644
--- a/linux-2.6-xen-sparse/drivers/xen/evtchn/evtchn.c
+++ b/linux-2.6-xen-sparse/drivers/xen/evtchn/evtchn.c
@@ -223,7 +223,7 @@ static int evtchn_ioctl(struct inode *inode, struct file *file,
if (copy_from_user(&bind, (void *)arg, sizeof(bind)))
break;
- op.cmd = EVTCHNOP_bind_virq;
+ op.cmd = EVTCHNOP_bind_virq;
op.u.bind_virq.virq = bind.virq;
op.u.bind_virq.vcpu = 0;
rc = HYPERVISOR_event_channel_op(&op);
@@ -243,16 +243,14 @@ static int evtchn_ioctl(struct inode *inode, struct file *file,
if (copy_from_user(&bind, (void *)arg, sizeof(bind)))
break;
- op.cmd = EVTCHNOP_bind_interdomain;
- op.u.bind_interdomain.dom1 = DOMID_SELF;
- op.u.bind_interdomain.dom2 = bind.remote_domain;
- op.u.bind_interdomain.port1 = 0;
- op.u.bind_interdomain.port2 = bind.remote_port;
+ op.cmd = EVTCHNOP_bind_interdomain;
+ op.u.bind_interdomain.remote_dom = bind.remote_domain;
+ op.u.bind_interdomain.remote_port = bind.remote_port;
rc = HYPERVISOR_event_channel_op(&op);
if (rc != 0)
break;
- rc = op.u.bind_interdomain.port1;
+ rc = op.u.bind_interdomain.local_port;
port_user[rc] = u;
unmask_evtchn(rc);
break;
@@ -265,7 +263,7 @@ static int evtchn_ioctl(struct inode *inode, struct file *file,
if (copy_from_user(&bind, (void *)arg, sizeof(bind)))
break;
- op.cmd = EVTCHNOP_alloc_unbound;
+ op.cmd = EVTCHNOP_alloc_unbound;
op.u.alloc_unbound.dom = DOMID_SELF;
op.u.alloc_unbound.remote_dom = bind.remote_domain;
rc = HYPERVISOR_event_channel_op(&op);
@@ -292,6 +290,11 @@ static int evtchn_ioctl(struct inode *inode, struct file *file,
} else {
port_user[unbind.port] = NULL;
mask_evtchn(unbind.port);
+
+ op.cmd = EVTCHNOP_close;
+ op.u.close.port = unbind.port;
+ BUG_ON(HYPERVISOR_event_channel_op(&op));
+
rc = 0;
}
break;
@@ -390,8 +393,7 @@ static int evtchn_release(struct inode *inode, struct file *filp)
port_user[i] = NULL;
mask_evtchn(i);
- op.cmd = EVTCHNOP_close;
- op.u.close.dom = DOMID_SELF;
+ op.cmd = EVTCHNOP_close;
op.u.close.port = i;
BUG_ON(HYPERVISOR_event_channel_op(&op));
}
diff --git a/linux-2.6-xen-sparse/drivers/xen/netback/interface.c b/linux-2.6-xen-sparse/drivers/xen/netback/interface.c
index ab8f9518c7..3e4537c90f 100644
--- a/linux-2.6-xen-sparse/drivers/xen/netback/interface.c
+++ b/linux-2.6-xen-sparse/drivers/xen/netback/interface.c
@@ -180,10 +180,8 @@ int netif_map(netif_t *netif, unsigned long tx_ring_ref,
int err;
evtchn_op_t op = {
.cmd = EVTCHNOP_bind_interdomain,
- .u.bind_interdomain.dom1 = DOMID_SELF,
- .u.bind_interdomain.dom2 = netif->domid,
- .u.bind_interdomain.port1 = 0,
- .u.bind_interdomain.port2 = evtchn };
+ .u.bind_interdomain.remote_dom = netif->domid,
+ .u.bind_interdomain.remote_port = evtchn };
netif->comms_area = alloc_vm_area(2*PAGE_SIZE);
if (netif->comms_area == NULL)
@@ -202,7 +200,7 @@ int netif_map(netif_t *netif, unsigned long tx_ring_ref,
return err;
}
- netif->evtchn = op.u.bind_interdomain.port1;
+ netif->evtchn = op.u.bind_interdomain.local_port;
netif->irq = bind_evtchn_to_irqhandler(
netif->evtchn, netif_be_int, 0, netif->dev->name, netif);
diff --git a/linux-2.6-xen-sparse/drivers/xen/tpmback/interface.c b/linux-2.6-xen-sparse/drivers/xen/tpmback/interface.c
index 514cf1130a..2f426e08b8 100644
--- a/linux-2.6-xen-sparse/drivers/xen/tpmback/interface.c
+++ b/linux-2.6-xen-sparse/drivers/xen/tpmback/interface.c
@@ -120,10 +120,8 @@ tpmif_map(tpmif_t *tpmif, unsigned long shared_page, unsigned int evtchn)
int err;
evtchn_op_t op = {
.cmd = EVTCHNOP_bind_interdomain,
- .u.bind_interdomain.dom1 = DOMID_SELF,
- .u.bind_interdomain.dom2 = tpmif->domid,
- .u.bind_interdomain.port1 = 0,
- .u.bind_interdomain.port2 = evtchn };
+ .u.bind_interdomain.remote_dom = tpmif->domid,
+ .u.bind_interdomain.remote_port = evtchn };
if ((tpmif->tx_area = alloc_vm_area(PAGE_SIZE)) == NULL)
return -ENOMEM;
@@ -141,7 +139,7 @@ tpmif_map(tpmif_t *tpmif, unsigned long shared_page, unsigned int evtchn)
return err;
}
- tpmif->evtchn = op.u.bind_interdomain.port1;
+ tpmif->evtchn = op.u.bind_interdomain.local_port;
tpmif->tx = (tpmif_tx_interface_t *)tpmif->tx_area->addr;
diff --git a/linux-2.6-xen-sparse/include/asm-xen/evtchn.h b/linux-2.6-xen-sparse/include/asm-xen/evtchn.h
index 214dd7d1c9..c9feb34606 100644
--- a/linux-2.6-xen-sparse/include/asm-xen/evtchn.h
+++ b/linux-2.6-xen-sparse/include/asm-xen/evtchn.h
@@ -123,9 +123,9 @@ static inline void clear_evtchn(int port)
static inline void notify_remote_via_evtchn(int port)
{
- evtchn_op_t op = {
- .cmd = EVTCHNOP_send,
- .u.send.local_port = port };
+ evtchn_op_t op;
+ op.cmd = EVTCHNOP_send,
+ op.u.send.port = port;
(void)HYPERVISOR_event_channel_op(&op);
}
diff --git a/tools/ioemu/vl.c b/tools/ioemu/vl.c
index e09153f8b8..ae2761b813 100644
--- a/tools/ioemu/vl.c
+++ b/tools/ioemu/vl.c
@@ -2806,7 +2806,7 @@ int main(int argc, char **argv)
case QEMU_OPTION_p:
{
- extern short ioreq_remote_port;
+ extern u16 ioreq_remote_port;
ioreq_remote_port = atoi(optarg);
printf("port: %d\n", ioreq_remote_port);
}
diff --git a/tools/python/xen/lowlevel/xc/xc.c b/tools/python/xen/lowlevel/xc/xc.c
index f42dce8d4c..c78c5061ed 100644
--- a/tools/python/xen/lowlevel/xc/xc.c
+++ b/tools/python/xen/lowlevel/xc/xc.c
@@ -432,13 +432,13 @@ static PyObject *pyxc_evtchn_alloc_unbound(PyObject *self,
{
XcObject *xc = (XcObject *)self;
- u32 dom = DOMID_SELF, remote_dom;
+ u32 dom, remote_dom;
int port;
- static char *kwd_list[] = { "remote_dom", "dom", NULL };
+ static char *kwd_list[] = { "dom", "remote_dom", NULL };
- if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i|i", kwd_list,
- &remote_dom, &dom) )
+ if ( !PyArg_ParseTupleAndKeywords(args, kwds, "ii", kwd_list,
+ &dom, &remote_dom) )
return NULL;
if ( (port = xc_evtchn_alloc_unbound(xc->xc_handle, dom, remote_dom)) < 0 )
@@ -943,8 +943,9 @@ static PyMethodDef pyxc_methods[] = {
{ "evtchn_alloc_unbound",
(PyCFunction)pyxc_evtchn_alloc_unbound,
METH_VARARGS | METH_KEYWORDS, "\n"
- "Allocate an unbound local port that will await a remote connection.\n"
- " dom [int]: Remote domain to accept connections from.\n\n"
+ "Allocate an unbound port that will await a remote connection.\n"
+ " dom [int]: Domain whose port space to allocate from.\n"
+ " remote_dom [int]: Remote domain to accept connections from.\n\n"
"Returns: [int] Unbound event-channel port.\n" },
{ "evtchn_status",
diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py
index 8327c5842d..be6b6fe89c 100644
--- a/tools/python/xen/xend/XendDomainInfo.py
+++ b/tools/python/xen/xend/XendDomainInfo.py
@@ -197,6 +197,7 @@ def recreate(xeninfo):
log.info("Recreating domain %d with new UUID %s.", domid, uuid)
vm = XendDomainInfo(uuid, xeninfo, domid, True)
+ vm.removeDom()
vm.storeVmDetails()
vm.storeDomDetails()
diff --git a/xen/common/event_channel.c b/xen/common/event_channel.c
index b83e0bb9dc..8dd52eb49f 100644
--- a/xen/common/event_channel.c
+++ b/xen/common/event_channel.c
@@ -70,7 +70,7 @@ static long evtchn_alloc_unbound(evtchn_alloc_unbound_t *alloc)
{
struct evtchn *chn;
struct domain *d;
- int port = alloc->port;
+ int port;
domid_t dom = alloc->dom;
long rc = 0;
@@ -84,176 +84,80 @@ static long evtchn_alloc_unbound(evtchn_alloc_unbound_t *alloc)
spin_lock(&d->evtchn_lock);
- /* Obtain, or ensure that we already have, a valid <port>. */
- if ( port == 0 )
- {
- if ( (port = get_free_port(d)) < 0 )
- ERROR_EXIT(port);
- }
- else if ( !port_is_valid(d, port) )
- ERROR_EXIT(-EINVAL);
+ if ( (port = get_free_port(d)) < 0 )
+ ERROR_EXIT(port);
chn = evtchn_from_port(d, port);
- /* Validate channel's current state. */
- switch ( chn->state )
- {
- case ECS_FREE:
- chn->state = ECS_UNBOUND;
- chn->u.unbound.remote_domid = alloc->remote_dom;
- break;
+ chn->state = ECS_UNBOUND;
+ chn->u.unbound.remote_domid = alloc->remote_dom;
- case ECS_UNBOUND:
- if ( chn->u.unbound.remote_domid != alloc->remote_dom )
- ERROR_EXIT(-EINVAL);
- break;
-
- default:
- ERROR_EXIT(-EINVAL);
- }
+ alloc->port = port;
out:
spin_unlock(&d->evtchn_lock);
put_domain(d);
- alloc->port = port;
-
return rc;
}
static long evtchn_bind_interdomain(evtchn_bind_interdomain_t *bind)
{
- struct evtchn *chn1, *chn2;
- struct domain *d1, *d2;
- int port1 = bind->port1, port2 = bind->port2;
- domid_t dom1 = bind->dom1, dom2 = bind->dom2;
+ struct evtchn *lchn, *rchn;
+ struct domain *ld = current->domain, *rd;
+ int lport, rport = bind->remote_port;
long rc = 0;
- if ( !IS_PRIV(current->domain) && (dom1 != DOMID_SELF) )
- return -EPERM;
-
- if ( dom1 == DOMID_SELF )
- dom1 = current->domain->domain_id;
- if ( dom2 == DOMID_SELF )
- dom2 = current->domain->domain_id;
-
- if ( ((d1 = find_domain_by_id(dom1)) == NULL) ||
- ((d2 = find_domain_by_id(dom2)) == NULL) )
- {
- if ( d1 != NULL )
- put_domain(d1);
+ if ( (rd = find_domain_by_id(bind->remote_dom)) == NULL )
return -ESRCH;
- }
/* Avoid deadlock by first acquiring lock of domain with smaller id. */
- if ( d1 < d2 )
+ if ( ld < rd )
{
- spin_lock(&d1->evtchn_lock);
- spin_lock(&d2->evtchn_lock);
+ spin_lock(&ld->evtchn_lock);
+ spin_lock(&rd->evtchn_lock);
}
else
{
- if ( d1 != d2 )
- spin_lock(&d2->evtchn_lock);
- spin_lock(&d1->evtchn_lock);
+ if ( ld != rd )
+ spin_lock(&rd->evtchn_lock);
+ spin_lock(&ld->evtchn_lock);
}
- /* Obtain, or ensure that we already have, a valid <port1>. */
- if ( port1 == 0 )
- {
- if ( (port1 = get_free_port(d1)) < 0 )
- ERROR_EXIT(port1);
- }
- else if ( !port_is_valid(d1, port1) )
- ERROR_EXIT(-EINVAL);
- chn1 = evtchn_from_port(d1, port1);
+ if ( (lport = get_free_port(ld)) < 0 )
+ ERROR_EXIT(lport);
+ lchn = evtchn_from_port(ld, lport);
- /* Obtain, or ensure that we already have, a valid <port2>. */
- if ( port2 == 0 )
- {
- /* Make port1 non-free while we allocate port2 (in case dom1==dom2). */
- u16 state = chn1->state;
- chn1->state = ECS_INTERDOMAIN;
- port2 = get_free_port(d2);
- chn1->state = state;
- if ( port2 < 0 )
- ERROR_EXIT(port2);
- }
- else if ( !port_is_valid(d2, port2) )
+ if ( !port_is_valid(rd, rport) )
ERROR_EXIT(-EINVAL);
- chn2 = evtchn_from_port(d2, port2);
-
- /* Validate <dom1,port1>'s current state. */
- switch ( chn1->state )
- {
- case ECS_FREE:
- break;
-
- case ECS_UNBOUND:
- if ( chn1->u.unbound.remote_domid != dom2 )
- ERROR_EXIT(-EINVAL);
- break;
-
- case ECS_INTERDOMAIN:
- if ( chn1->u.interdomain.remote_dom != d2 )
- ERROR_EXIT(-EINVAL);
- if ( (chn1->u.interdomain.remote_port != port2) && (bind->port2 != 0) )
- ERROR_EXIT(-EINVAL);
- port2 = chn1->u.interdomain.remote_port;
- goto out;
-
- default:
+ rchn = evtchn_from_port(rd, rport);
+ if ( (rchn->state != ECS_UNBOUND) ||
+ (rchn->u.unbound.remote_domid != ld->domain_id) )
ERROR_EXIT(-EINVAL);
- }
-
- /* Validate <dom2,port2>'s current state. */
- switch ( chn2->state )
- {
- case ECS_FREE:
- if ( !IS_PRIV(current->domain) && (dom2 != DOMID_SELF) )
- ERROR_EXIT(-EPERM);
- break;
-
- case ECS_UNBOUND:
- if ( chn2->u.unbound.remote_domid != dom1 )
- ERROR_EXIT(-EINVAL);
- break;
-
- case ECS_INTERDOMAIN:
- if ( chn2->u.interdomain.remote_dom != d1 )
- ERROR_EXIT(-EINVAL);
- if ( (chn2->u.interdomain.remote_port != port1) && (bind->port1 != 0) )
- ERROR_EXIT(-EINVAL);
- port1 = chn2->u.interdomain.remote_port;
- goto out;
- default:
- ERROR_EXIT(-EINVAL);
- }
+ lchn->u.interdomain.remote_dom = rd;
+ lchn->u.interdomain.remote_port = (u16)rport;
+ lchn->state = ECS_INTERDOMAIN;
+
+ rchn->u.interdomain.remote_dom = ld;
+ rchn->u.interdomain.remote_port = (u16)lport;
+ rchn->state = ECS_INTERDOMAIN;
/*
- * Everything checked out okay -- bind <dom1,port1> to <dom2,port2>.
+ * We may have lost notifications on the remote unbound port. Fix that up
+ * here by conservatively always setting a notification on the local port.
*/
+ evtchn_set_pending(ld->vcpu[lchn->notify_vcpu_id], lport);
- chn1->u.interdomain.remote_dom = d2;
- chn1->u.interdomain.remote_port = (u16)port2;
- chn1->state = ECS_INTERDOMAIN;
-
- chn2->u.interdomain.remote_dom = d1;
- chn2->u.interdomain.remote_port = (u16)port1;
- chn2->state = ECS_INTERDOMAIN;
+ bind->local_port = lport;
out:
- spin_unlock(&d1->evtchn_lock);
- if ( d1 != d2 )
- spin_unlock(&d2->evtchn_lock);
+ spin_unlock(&ld->evtchn_lock);
+ if ( ld != rd )
+ spin_unlock(&rd->evtchn_lock);
- put_domain(d1);
- put_domain(d2);
-
- bind->port1 = port1;
- bind->port2 = port2;
+ put_domain(rd);
return rc;
}
@@ -264,39 +168,34 @@ static long evtchn_bind_virq(evtchn_bind_virq_t *bind)
struct evtchn *chn;
struct vcpu *v;
struct domain *d = current->domain;
- int port, virq = bind->virq;
+ int port, virq = bind->virq, vcpu = bind->vcpu;
+ long rc = 0;
if ( virq >= ARRAY_SIZE(v->virq_to_evtchn) )
return -EINVAL;
- if ( (v = d->vcpu[bind->vcpu]) == NULL )
+ if ( (vcpu >= ARRAY_SIZE(d->vcpu)) || ((v = d->vcpu[vcpu]) == NULL) )
return -ENOENT;
spin_lock(&d->evtchn_lock);
- /*
- * Port 0 is the fallback port for VIRQs that haven't been explicitly
- * bound yet.
- */
- if ( ((port = v->virq_to_evtchn[virq]) != 0) ||
- ((port = get_free_port(d)) < 0) )
- goto out;
+ if ( v->virq_to_evtchn[virq] != 0 )
+ ERROR_EXIT(-EEXIST);
+
+ if ( (port = get_free_port(d)) < 0 )
+ ERROR_EXIT(port);
chn = evtchn_from_port(d, port);
chn->state = ECS_VIRQ;
- chn->notify_vcpu_id = v->vcpu_id;
+ chn->notify_vcpu_id = vcpu;
chn->u.virq = virq;
- v->virq_to_evtchn[virq] = port;
+ v->virq_to_evtchn[virq] = bind->port = port;
out:
spin_unlock(&d->evtchn_lock);
- if ( port < 0 )
- return port;
-
- bind->port = port;
- return 0;
+ return rc;
}
@@ -304,27 +203,27 @@ static long evtchn_bind_ipi(evtchn_bind_ipi_t *bind)
{
struct evtchn *chn;
struct domain *d = current->domain;
- int port;
+ int port, vcpu = bind->vcpu;
+ long rc = 0;
- if ( d->vcpu[bind->vcpu] == NULL )
+ if ( (vcpu >= ARRAY_SIZE(d->vcpu)) || (d->vcpu[vcpu] == NULL) )
return -ENOENT;
spin_lock(&d->evtchn_lock);
- if ( (port = get_free_port(d)) >= 0 )
- {
- chn = evtchn_from_port(d, port);
- chn->state = ECS_IPI;
- chn->notify_vcpu_id = bind->vcpu;
- }
-
- spin_unlock(&d->evtchn_lock);
+ if ( (port = get_free_port(d)) < 0 )
+ ERROR_EXIT(port);
- if ( port < 0 )
- return port;
+ chn = evtchn_from_port(d, port);
+ chn->state = ECS_IPI;
+ chn->notify_vcpu_id = vcpu;
bind->port = port;
- return 0;
+
+ out:
+ spin_unlock(&d->evtchn_lock);
+
+ return rc;
}
@@ -332,16 +231,19 @@ static long evtchn_bind_pirq(evtchn_bind_pirq_t *bind)
{
struct evtchn *chn;
struct domain *d = current->domain;
- int port, rc, pirq = bind->pirq;
+ int port, pirq = bind->pirq;
+ long rc;
if ( pirq >= ARRAY_SIZE(d->pirq_to_evtchn) )
return -EINVAL;
spin_lock(&d->evtchn_lock);
- if ( ((rc = port = d->pirq_to_evtchn[pirq]) != 0) ||
- ((rc = port = get_free_port(d)) < 0) )
- goto out;
+ if ( d->pirq_to_evtchn[pirq] != 0 )
+ ERROR_EXIT(-EEXIST);
+
+ if ( (port = get_free_port(d)) < 0 )
+ ERROR_EXIT(port);
chn = evtchn_from_port(d, port);
@@ -357,14 +259,12 @@ static long evtchn_bind_pirq(evtchn_bind_pirq_t *bind)
chn->state = ECS_PIRQ;
chn->u.pirq = pirq;
+ bind->port = port;
+
out:
spin_unlock(&d->evtchn_lock);
- if ( rc < 0 )
- return rc;
-
- bind->port = port;
- return 0;
+ return rc;
}
@@ -478,22 +378,7 @@ static long __evtchn_close(struct domain *d1, int port1)
static long evtchn_close(evtchn_close_t *close)
{
- struct domain *d;
- long rc;
- domid_t dom = close->dom;
-
- if ( dom == DOMID_SELF )
- dom = current->domain->domain_id;
- else if ( !IS_PRIV(current->domain) )
- return -EPERM;
-
- if ( (d = find_domain_by_id(dom)) == NULL )
- return -ESRCH;
-
- rc = __evtchn_close(d, close->port);
-
- put_domain(d);
- return rc;
+ return __evtchn_close(current->domain, close->port);
}
@@ -523,6 +408,9 @@ long evtchn_send(int lport)
case ECS_IPI:
evtchn_set_pending(ld->vcpu[lchn->notify_vcpu_id], lport);
break;
+ case ECS_UNBOUND:
+ /* silently drop the notification */
+ break;
default:
ret = -EINVAL;
}
@@ -611,9 +499,8 @@ static long evtchn_bind_vcpu(evtchn_bind_vcpu_t *bind)
struct evtchn *chn;
long rc = 0;
- if ( (vcpu >= MAX_VIRT_CPUS) || (d->vcpu[vcpu] == NULL) ) {
- return -EINVAL;
- }
+ if ( (vcpu >= ARRAY_SIZE(d->vcpu)) || (d->vcpu[vcpu] == NULL) )
+ return -ENOENT;
spin_lock(&d->evtchn_lock);
@@ -689,7 +576,7 @@ long do_event_channel_op(evtchn_op_t *uop)
break;
case EVTCHNOP_send:
- rc = evtchn_send(op.u.send.local_port);
+ rc = evtchn_send(op.u.send.port);
break;
case EVTCHNOP_status:
diff --git a/xen/include/public/event_channel.h b/xen/include/public/event_channel.h
index 37efd85af3..b5b9ac99fc 100644
--- a/xen/include/public/event_channel.h
+++ b/xen/include/public/event_channel.h
@@ -10,9 +10,9 @@
#define __XEN_PUBLIC_EVENT_CHANNEL_H__
/*
- * EVTCHNOP_alloc_unbound: Allocate a port in <dom> for later binding to
- * <remote_dom>. <port> may be wildcarded by setting to zero, in which case a
- * fresh port will be allocated, and the field filled in on return.
+ * EVTCHNOP_alloc_unbound: Allocate a port in domain <dom> and mark as
+ * accepting interdomain bindings from domain <remote_dom>. A fresh port
+ * is allocated in <dom> and returned as <port>.
* NOTES:
* 1. If the caller is unprivileged then <dom> must be DOMID_SELF.
*/
@@ -20,36 +20,24 @@
typedef struct evtchn_alloc_unbound {
/* IN parameters */
domid_t dom, remote_dom;
- /* IN/OUT parameters */
+ /* OUT parameters */
u32 port;
} evtchn_alloc_unbound_t;
/*
* EVTCHNOP_bind_interdomain: Construct an interdomain event channel between
- * <dom1> and <dom2>. Either <port1> or <port2> may be wildcarded by setting to
- * zero. On successful return both <port1> and <port2> are filled in and
- * <dom1,port1> is fully bound to <dom2,port2>.
- *
- * NOTES:
- * 1. A wildcarded port is allocated from the relevant domain's free list
- * (i.e., some port that was previously EVTCHNSTAT_closed). However, if the
- * remote port pair is already fully bound then a port is not allocated,
- * and instead the existing local port is returned to the caller.
- * 2. If the caller is unprivileged then <dom1> must be DOMID_SELF.
- * 3. If the caller is unprivileged and <dom2,port2> is EVTCHNSTAT_closed
- * then <dom2> must be DOMID_SELF.
- * 4. If either port is already bound then it must be bound to the other
- * specified domain and port (if not wildcarded).
- * 5. If either port is awaiting binding (EVTCHNSTAT_unbound) then it must
- * be awaiting binding to the other domain, and the other port pair must
- * be closed or unbound.
+ * the calling domain and <remote_dom>. <remote_dom,remote_port> must identify
+ * a port that is unbound and marked as accepting bindings from the calling
+ * domain. A fresh port is allocated in the calling domain and returned as
+ * <local_port>.
*/
#define EVTCHNOP_bind_interdomain 0
typedef struct evtchn_bind_interdomain {
/* IN parameters. */
- domid_t dom1, dom2;
- /* IN/OUT parameters. */
- u32 port1, port2;
+ domid_t remote_dom;
+ u32 remote_port;
+ /* OUT parameters. */
+ u32 local_port;
} evtchn_bind_interdomain_t;
/*
@@ -99,31 +87,24 @@ typedef struct evtchn_bind_ipi {
} evtchn_bind_ipi_t;
/*
- * EVTCHNOP_close: Close the communication channel which has an endpoint at
- * <dom, port>. If the channel is interdomain then the remote end is placed in
- * the unbound state (EVTCHNSTAT_unbound), awaiting a new connection.
- * NOTES:
- * 1. <dom> may be specified as DOMID_SELF.
- * 2. Only a sufficiently-privileged domain may close an event channel
- * for which <dom> is not DOMID_SELF.
+ * EVTCHNOP_close: Close a local event channel <port>. If the channel is
+ * interdomain then the remote end is placed in the unbound state
+ * (EVTCHNSTAT_unbound), awaiting a new connection.
*/
#define EVTCHNOP_close 3
typedef struct evtchn_close {
/* IN parameters. */
- domid_t dom;
- u32 port;
- /* No OUT parameters. */
+ u32 port;
} evtchn_close_t;
/*
* EVTCHNOP_send: Send an event to the remote end of the channel whose local
- * endpoint is <DOMID_SELF, local_port>.
+ * endpoint is <port>.
*/
#define EVTCHNOP_send 4
typedef struct evtchn_send {
/* IN parameters. */
- u32 local_port;
- /* No OUT parameters. */
+ u32 port;
} evtchn_send_t;
/*