From c804adf4b64a5755c885b681c32591d2e67aa636 Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Thu, 6 Oct 2005 16:07:52 +0100 Subject: [PATCH 1/2] Change how event channels are allocated and used by the control tools. /dev/xen/evtchn is now used by daemons to connect to remote domains: the advantage is that the local ports are garbage collected automatically if the daemon dies. xen no longer constructs end-to-end event-channel port pairs -- it allocates an unbound port in new domU and writes that port to xenstore. It is then picked up by teh appropriate daemon which does interdomain bind via /dev/xen/evtchn. Signed-off-by: Keir Fraser --- .../drivers/xen/evtchn/evtchn.c | 125 ++++++++++++++---- linux-2.6-xen-sparse/include/asm-xen/evtchn.h | 15 --- .../include/asm-xen/linux-public/evtchn.h | 89 +++++++++++++ .../include/asm-xen/linux-public/privcmd.h | 68 ++++++---- tools/console/daemon/io.c | 57 ++++---- tools/debugger/pdb/pdb_xen.c | 6 +- tools/ioemu/target-i386-dm/helper2.c | 25 ++-- tools/ioemu/vl.c | 6 +- tools/python/xen/lowlevel/xc/xc.c | 6 +- tools/python/xen/xend/XendCheckpoint.py | 6 +- tools/python/xen/xend/XendDomainInfo.py | 71 ++-------- tools/python/xen/xend/image.py | 21 ++- tools/python/xen/xend/server/channel.py | 76 ----------- tools/xenstore/xenstored_domain.c | 36 +++-- xen/common/event_channel.c | 8 +- 15 files changed, 330 insertions(+), 285 deletions(-) create mode 100644 linux-2.6-xen-sparse/include/asm-xen/linux-public/evtchn.h delete mode 100755 tools/python/xen/xend/server/channel.py 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 388a1367ca..658157c4c3 100644 --- a/linux-2.6-xen-sparse/drivers/xen/evtchn/evtchn.c +++ b/linux-2.6-xen-sparse/drivers/xen/evtchn/evtchn.c @@ -44,9 +44,9 @@ #include #include #include -#define XEN_EVTCHN_MASK_OPS -#include #include +#include +#include struct per_user_data { /* Notification ring, accessed via /dev/xen/evtchn. */ @@ -78,7 +78,8 @@ void evtchn_device_upcall(int port) u->ring[EVTCHN_RING_MASK(u->ring_prod)] = (u16)port; if (u->ring_cons == u->ring_prod++) { wake_up_interruptible(&u->evtchn_wait); - kill_fasync(&u->evtchn_async_queue, SIGIO, POLL_IN); + kill_fasync(&u->evtchn_async_queue, + SIGIO, POLL_IN); } } else { u->ring_overflow = 1; @@ -208,38 +209,100 @@ static ssize_t evtchn_write(struct file *file, const char *buf, static int evtchn_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - int rc = 0; + int rc; struct per_user_data *u = file->private_data; + evtchn_op_t op = { 0 }; spin_lock_irq(&port_user_lock); switch (cmd) { - case EVTCHN_RESET: - /* Initialise the ring to empty. Clear errors. */ - u->ring_cons = u->ring_prod = u->ring_overflow = 0; - break; + case IOCTL_EVTCHN_BIND_VIRQ: { + struct ioctl_evtchn_bind_virq bind; - case EVTCHN_BIND: - if (arg >= NR_EVENT_CHANNELS) { - rc = -EINVAL; - } else if (port_user[arg] != NULL) { - rc = -EISCONN; - } else { - port_user[arg] = u; - unmask_evtchn(arg); - } - break; + rc = -EFAULT; + if (copy_from_user(&bind, (void *)arg, sizeof(bind))) + break; - case EVTCHN_UNBIND: - if (arg >= NR_EVENT_CHANNELS) { + op.cmd = EVTCHNOP_bind_virq; + op.u.bind_virq.virq = bind.virq; + op.u.bind_virq.vcpu = 0; + rc = HYPERVISOR_event_channel_op(&op); + if (rc != 0) + break; + + rc = op.u.bind_virq.port; + port_user[rc] = u; + unmask_evtchn(rc); + break; + } + + case IOCTL_EVTCHN_BIND_INTERDOMAIN: { + struct ioctl_evtchn_bind_interdomain bind; + + rc = -EFAULT; + 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; + rc = HYPERVISOR_event_channel_op(&op); + if (rc != 0) + break; + + rc = op.u.bind_interdomain.port1; + port_user[rc] = u; + unmask_evtchn(rc); + break; + } + + case IOCTL_EVTCHN_BIND_UNBOUND_PORT: { + struct ioctl_evtchn_bind_unbound_port bind; + + rc = -EFAULT; + if (copy_from_user(&bind, (void *)arg, sizeof(bind))) + break; + + 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); + if (rc != 0) + break; + + rc = op.u.alloc_unbound.port; + port_user[rc] = u; + unmask_evtchn(rc); + break; + } + + case IOCTL_EVTCHN_UNBIND: { + struct ioctl_evtchn_unbind unbind; + + rc = -EFAULT; + if (copy_from_user(&unbind, (void *)arg, sizeof(unbind))) + break; + + if (unbind.port >= NR_EVENT_CHANNELS) { rc = -EINVAL; - } else if (port_user[arg] != u) { + } else if (port_user[unbind.port] != u) { rc = -ENOTCONN; } else { - port_user[arg] = NULL; - mask_evtchn(arg); + port_user[unbind.port] = NULL; + mask_evtchn(unbind.port); + rc = 0; } break; + } + + case IOCTL_EVTCHN_RESET: { + /* Initialise the ring to empty. Clear errors. */ + u->ring_cons = u->ring_prod = u->ring_overflow = 0; + rc = 0; + break; + } default: rc = -ENOSYS; @@ -295,6 +358,7 @@ static int evtchn_release(struct inode *inode, struct file *filp) { int i; struct per_user_data *u = filp->private_data; + evtchn_op_t op = { 0 }; spin_lock_irq(&port_user_lock); @@ -302,11 +366,16 @@ static int evtchn_release(struct inode *inode, struct file *filp) for (i = 0; i < NR_EVENT_CHANNELS; i++) { - if (port_user[i] == u) - { - port_user[i] = NULL; - mask_evtchn(i); - } + if (port_user[i] != u) + continue; + + port_user[i] = NULL; + mask_evtchn(i); + + op.cmd = EVTCHNOP_close; + op.u.close.dom = DOMID_SELF; + op.u.close.port = i; + BUG_ON(HYPERVISOR_event_channel_op(&op)); } spin_unlock_irq(&port_user_lock); 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 149f01fe7b..214dd7d1c9 100644 --- a/linux-2.6-xen-sparse/include/asm-xen/evtchn.h +++ b/linux-2.6-xen-sparse/include/asm-xen/evtchn.h @@ -129,21 +129,6 @@ static inline void notify_remote_via_evtchn(int port) (void)HYPERVISOR_event_channel_op(&op); } -/* - * CHARACTER-DEVICE DEFINITIONS - */ - -/* /dev/xen/evtchn resides at device number major=10, minor=201 */ -#define EVTCHN_MINOR 201 - -/* /dev/xen/evtchn ioctls: */ -/* EVTCHN_RESET: Clear and reinit the event buffer. Clear error condition. */ -#define EVTCHN_RESET _IO('E', 1) -/* EVTCHN_BIND: Bind to teh specified event-channel port. */ -#define EVTCHN_BIND _IO('E', 2) -/* EVTCHN_UNBIND: Unbind from the specified event-channel port. */ -#define EVTCHN_UNBIND _IO('E', 3) - #endif /* __ASM_EVTCHN_H__ */ /* diff --git a/linux-2.6-xen-sparse/include/asm-xen/linux-public/evtchn.h b/linux-2.6-xen-sparse/include/asm-xen/linux-public/evtchn.h new file mode 100644 index 0000000000..9f47eaf44c --- /dev/null +++ b/linux-2.6-xen-sparse/include/asm-xen/linux-public/evtchn.h @@ -0,0 +1,89 @@ +/****************************************************************************** + * evtchn.h + * + * Interface to /dev/xen/evtchn. + * + * Copyright (c) 2003-2005, K A Fraser + * + * This file may be distributed separately from the Linux kernel, or + * incorporated into other software packages, subject to the following license: + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this source file (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef __LINUX_PUBLIC_EVTCHN_H__ +#define __LINUX_PUBLIC_EVTCHN_H__ + +/* /dev/xen/evtchn resides at device number major=10, minor=201 */ +#define EVTCHN_MINOR 201 + +/* + * Bind a fresh port to VIRQ @virq. + * Return allocated port. + */ +#define IOCTL_EVTCHN_BIND_VIRQ \ + _IOC(_IOC_NONE, 'E', 0, sizeof(struct ioctl_evtchn_bind_virq)) +struct ioctl_evtchn_bind_virq { + unsigned int virq; +}; + +/* + * Bind a fresh port to remote <@remote_domain, @remote_port>. + * Return allocated port. + */ +#define IOCTL_EVTCHN_BIND_INTERDOMAIN \ + _IOC(_IOC_NONE, 'E', 1, sizeof(struct ioctl_evtchn_bind_interdomain)) +struct ioctl_evtchn_bind_interdomain { + unsigned int remote_domain, remote_port; +}; + +/* + * Allocate a fresh port for binding to @remote_domain. + * Return allocated port. + */ +#define IOCTL_EVTCHN_BIND_UNBOUND_PORT \ + _IOC(_IOC_NONE, 'E', 2, sizeof(struct ioctl_evtchn_bind_unbound_port)) +struct ioctl_evtchn_bind_unbound_port { + unsigned int remote_domain; +}; + +/* + * Unbind previously allocated @port. + */ +#define IOCTL_EVTCHN_UNBIND \ + _IOC(_IOC_NONE, 'E', 3, sizeof(struct ioctl_evtchn_unbind)) +struct ioctl_evtchn_unbind { + unsigned int port; +}; + +/* Clear and reinitialise the event buffer. Clear error condition. */ +#define IOCTL_EVTCHN_RESET \ + _IOC(_IOC_NONE, 'E', 4, 0) + +#endif /* __LINUX_PUBLIC_EVTCHN_H__ */ + +/* + * Local variables: + * c-file-style: "linux" + * indent-tabs-mode: t + * c-indent-level: 8 + * c-basic-offset: 8 + * tab-width: 8 + * End: + */ diff --git a/linux-2.6-xen-sparse/include/asm-xen/linux-public/privcmd.h b/linux-2.6-xen-sparse/include/asm-xen/linux-public/privcmd.h index d0533e179f..1246dbd64b 100644 --- a/linux-2.6-xen-sparse/include/asm-xen/linux-public/privcmd.h +++ b/linux-2.6-xen-sparse/include/asm-xen/linux-public/privcmd.h @@ -3,7 +3,7 @@ * * Interface to /proc/xen/privcmd. * - * Copyright (c) 2003-2004, K A Fraser + * Copyright (c) 2003-2005, K A Fraser * * This file may be distributed separately from the Linux kernel, or * incorporated into other software packages, subject to the following license: @@ -27,39 +27,39 @@ * IN THE SOFTWARE. */ -#ifndef __PRIVCMD_H__ -#define __PRIVCMD_H__ +#ifndef __LINUX_PUBLIC_PRIVCMD_H__ +#define __LINUX_PUBLIC_PRIVCMD_H__ typedef struct privcmd_hypercall { - unsigned long op; - unsigned long arg[5]; + unsigned long op; + unsigned long arg[5]; } privcmd_hypercall_t; typedef struct privcmd_mmap_entry { - unsigned long va; - unsigned long mfn; - unsigned long npages; + unsigned long va; + unsigned long mfn; + unsigned long npages; } privcmd_mmap_entry_t; typedef struct privcmd_mmap { - int num; - domid_t dom; /* target domain */ - privcmd_mmap_entry_t *entry; + int num; + domid_t dom; /* target domain */ + privcmd_mmap_entry_t *entry; } privcmd_mmap_t; typedef struct privcmd_mmapbatch { - int num; /* number of pages to populate */ - domid_t dom; /* target domain */ - unsigned long addr; /* virtual address */ - unsigned long *arr; /* array of mfns - top nibble set on err */ + int num; /* number of pages to populate */ + domid_t dom; /* target domain */ + unsigned long addr; /* virtual address */ + unsigned long *arr; /* array of mfns - top nibble set on err */ } privcmd_mmapbatch_t; typedef struct privcmd_blkmsg { - unsigned long op; - void *buf; - int buf_size; + unsigned long op; + void *buf; + int buf_size; } privcmd_blkmsg_t; /* @@ -67,16 +67,26 @@ typedef struct privcmd_blkmsg * @arg: &privcmd_hypercall_t * Return: Value returned from execution of the specified hypercall. */ -#define IOCTL_PRIVCMD_HYPERCALL \ - _IOC(_IOC_NONE, 'P', 0, sizeof(privcmd_hypercall_t)) +#define IOCTL_PRIVCMD_HYPERCALL \ + _IOC(_IOC_NONE, 'P', 0, sizeof(privcmd_hypercall_t)) -#define IOCTL_PRIVCMD_MMAP \ - _IOC(_IOC_NONE, 'P', 2, sizeof(privcmd_mmap_t)) -#define IOCTL_PRIVCMD_MMAPBATCH \ - _IOC(_IOC_NONE, 'P', 3, sizeof(privcmd_mmapbatch_t)) -#define IOCTL_PRIVCMD_GET_MACH2PHYS_START_MFN \ - _IOC(_IOC_READ, 'P', 4, sizeof(unsigned long)) -#define IOCTL_PRIVCMD_INITDOMAIN_STORE \ - _IOC(_IOC_READ, 'P', 5, 0) +#define IOCTL_PRIVCMD_MMAP \ + _IOC(_IOC_NONE, 'P', 2, sizeof(privcmd_mmap_t)) +#define IOCTL_PRIVCMD_MMAPBATCH \ + _IOC(_IOC_NONE, 'P', 3, sizeof(privcmd_mmapbatch_t)) +#define IOCTL_PRIVCMD_GET_MACH2PHYS_START_MFN \ + _IOC(_IOC_READ, 'P', 4, sizeof(unsigned long)) +#define IOCTL_PRIVCMD_INITDOMAIN_STORE \ + _IOC(_IOC_READ, 'P', 5, 0) -#endif /* __PRIVCMD_H__ */ +#endif /* __LINUX_PUBLIC_PRIVCMD_H__ */ + +/* + * Local variables: + * c-file-style: "linux" + * indent-tabs-mode: t + * c-indent-level: 8 + * c-basic-offset: 8 + * tab-width: 8 + * End: + */ diff --git a/tools/console/daemon/io.c b/tools/console/daemon/io.c index a841af1c95..dab3177d14 100644 --- a/tools/console/daemon/io.c +++ b/tools/console/daemon/io.c @@ -1,4 +1,4 @@ -/*\ +/* * Copyright (C) International Business Machines Corp., 2005 * Author(s): Anthony Liguori * @@ -16,14 +16,15 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -\*/ + */ #define _GNU_SOURCE #include "utils.h" #include "io.h" -#include "xenctrl.h" -#include "xs.h" +#include +#include +#include #include #include @@ -225,16 +226,14 @@ int xs_gather(struct xs_handle *xs, const char *dir, ...) return ret; } -#define EVENTCHN_BIND _IO('E', 2) -#define EVENTCHN_UNBIND _IO('E', 3) - static int domain_create_ring(struct domain *dom) { - int err, local_port, ring_ref; + int err, remote_port, ring_ref, rc; + struct ioctl_evtchn_bind_interdomain bind; err = xs_gather(xs, dom->conspath, "ring-ref", "%u", &ring_ref, - "port", "%i", &local_port, + "port", "%i", &remote_port, NULL); if (err) goto out; @@ -252,26 +251,28 @@ static int domain_create_ring(struct domain *dom) dom->ring_ref = ring_ref; } - if (local_port != dom->local_port) { - dom->local_port = -1; - if (dom->evtchn_fd != -1) - close(dom->evtchn_fd); - /* Opening evtchn independently for each console is a bit - * wastefule, but that's how the code is structured... */ - dom->evtchn_fd = open("/dev/xen/evtchn", O_RDWR); - if (dom->evtchn_fd == -1) { - err = errno; - goto out; - } - - if (ioctl(dom->evtchn_fd, EVENTCHN_BIND, local_port) == -1) { - err = errno; - close(dom->evtchn_fd); - dom->evtchn_fd = -1; - goto out; - } - dom->local_port = local_port; + dom->local_port = -1; + if (dom->evtchn_fd != -1) + close(dom->evtchn_fd); + + /* Opening evtchn independently for each console is a bit + * wasteful, but that's how the code is structured... */ + dom->evtchn_fd = open("/dev/xen/evtchn", O_RDWR); + if (dom->evtchn_fd == -1) { + err = errno; + goto out; } + + bind.remote_domain = dom->domid; + bind.remote_port = remote_port; + rc = ioctl(dom->evtchn_fd, IOCTL_EVTCHN_BIND_INTERDOMAIN, &bind); + if (rc == -1) { + err = errno; + close(dom->evtchn_fd); + dom->evtchn_fd = -1; + goto out; + } + dom->local_port = rc; out: return err; diff --git a/tools/debugger/pdb/pdb_xen.c b/tools/debugger/pdb/pdb_xen.c index e89f364f61..b2c994c188 100644 --- a/tools/debugger/pdb/pdb_xen.c +++ b/tools/debugger/pdb/pdb_xen.c @@ -43,11 +43,7 @@ pdb_close (int xc_handle) #include - -/* /dev/xen/evtchn ioctls */ -#define EVTCHN_RESET _IO('E', 1) /* clear & reinit buffer */ -#define EVTCHN_BIND _IO('E', 2) /* bind to event channel */ -#define EVTCHN_UNBIND _IO('E', 3) /* unbind from event channel */ +#include int xen_evtchn_bind (int evtchn_fd, int idx) diff --git a/tools/ioemu/target-i386-dm/helper2.c b/tools/ioemu/target-i386-dm/helper2.c index a3c22d5f1a..d32ef006ba 100644 --- a/tools/ioemu/target-i386-dm/helper2.c +++ b/tools/ioemu/target-i386-dm/helper2.c @@ -49,11 +49,14 @@ #include #include +#include #include "cpu.h" #include "exec-all.h" #include "vl.h" +extern int domid; + void *shared_vram; shared_iopage_t *shared_page = NULL; @@ -119,7 +122,7 @@ target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) //the evtchn fd for polling int evtchn_fd = -1; //the evtchn port for polling the notification, should be inputed as bochs's parameter -u16 ioreq_port = 0; +u16 ioreq_remote_port, ioreq_local_port; //some functions to handle the io req packet void @@ -156,9 +159,9 @@ ioreq_t* cpu_get_ioreq(void) int rc; u16 buf[2]; rc = read(evtchn_fd, buf, 2); - if (rc == 2 && buf[0] == ioreq_port){//got only one matched 16bit port index + if (rc == 2 && buf[0] == ioreq_local_port){//got only one matched 16bit port index // unmask the wanted port again - write(evtchn_fd, &ioreq_port, 2); + write(evtchn_fd, &ioreq_local_port, 2); //get the io packet from shared memory return __cpu_get_ioreq(); @@ -417,7 +420,6 @@ do_interrupt(CPUState *env, int vector) void destroy_vmx_domain(void) { - extern int domid; extern FILE* logfile; char destroy_cmd[20]; sprintf(destroy_cmd, "xm destroy %d", domid); @@ -485,9 +487,9 @@ int main_loop(void) #endif if (env->send_event) { int ret; - ret = xc_evtchn_send(xc_handle, ioreq_port); + ret = xc_evtchn_send(xc_handle, ioreq_local_port); if (ret == -1) { - fprintf(logfile, "evtchn_send failed on port: %d\n", ioreq_port); + fprintf(logfile, "evtchn_send failed on port: %d\n", ioreq_local_port); } } } @@ -499,7 +501,6 @@ static void qemu_vmx_reset(void *unused) { char cmd[255]; - extern int domid; /* pause domain first, to avoid repeated reboot request*/ xc_domain_pause (xc_handle, domid); @@ -512,6 +513,8 @@ CPUState * cpu_init() { CPUX86State *env; + struct ioctl_evtchn_bind_interdomain bind; + int rc; cpu_exec_init(); qemu_register_reset(qemu_vmx_reset, NULL); @@ -532,12 +535,14 @@ cpu_init() return NULL; } - fprintf(logfile, "listening to port: %d\n", ioreq_port); - /*unmask the wanted port -- bind*/ - if (ioctl(evtchn_fd, ('E'<<8)|2, ioreq_port) == -1) { + bind.remote_domain = domid; + bind.remote_port = ioreq_remote_port; + rc = ioctl(evtchn_fd, IOCTL_EVTCHN_BIND_INTERDOMAIN, &bind); + if (rc == -1) { perror("ioctl"); return NULL; } + ioreq_local_port = rc; return env; } diff --git a/tools/ioemu/vl.c b/tools/ioemu/vl.c index 5a4617dbc9..e09153f8b8 100644 --- a/tools/ioemu/vl.c +++ b/tools/ioemu/vl.c @@ -2806,9 +2806,9 @@ int main(int argc, char **argv) case QEMU_OPTION_p: { - extern short ioreq_port; - ioreq_port = atoi(optarg); - printf("port: %d\n", ioreq_port); + extern short ioreq_remote_port; + ioreq_remote_port = atoi(optarg); + printf("port: %d\n", ioreq_remote_port); } break; case QEMU_OPTION_l: diff --git a/tools/python/xen/lowlevel/xc/xc.c b/tools/python/xen/lowlevel/xc/xc.c index 7ff5b40ca9..5074b4b3c6 100644 --- a/tools/python/xen/lowlevel/xc/xc.c +++ b/tools/python/xen/lowlevel/xc/xc.c @@ -435,10 +435,10 @@ static PyObject *pyxc_evtchn_alloc_unbound(PyObject *self, u32 dom = DOMID_SELF, remote_dom; int port = 0; - static char *kwd_list[] = { "remote_dom", "dom", "port", NULL }; + static char *kwd_list[] = { "remote_dom", "dom", NULL }; - if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i|ii", kwd_list, - &remote_dom, &dom, &port) ) + if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i|i", kwd_list, + &remote_dom, &dom) ) return NULL; if ( xc_evtchn_alloc_unbound(xc->xc_handle, remote_dom, dom, &port) != 0 ) diff --git a/tools/python/xen/xend/XendCheckpoint.py b/tools/python/xen/xend/XendCheckpoint.py index ab8ba6fb4e..6e6e60156f 100644 --- a/tools/python/xen/xend/XendCheckpoint.py +++ b/tools/python/xen/xend/XendCheckpoint.py @@ -126,8 +126,8 @@ def restore(xd, fd): raise XendError( "not a valid guest state file: pfn count out of range") - store_evtchn = dominfo.store_channel.port2 - console_evtchn = dominfo.console_channel.port2 + store_evtchn = dominfo.store_channel + console_evtchn = dominfo.console_channel cmd = [PATH_XC_RESTORE, str(xc.handle()), str(fd), str(dominfo.getDomid()), str(nr_pfns), @@ -146,7 +146,7 @@ def restore(xd, fd): dominfo.getDomainPath()) IntroduceDomain(dominfo.getDomid(), store_mfn, - dominfo.store_channel.port1, + dominfo.store_channel, dominfo.getDomainPath()) else: m = re.match(r"^(console-mfn) (\d+)$", line) diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py index 19814c6bdc..4cdaa0e54e 100644 --- a/tools/python/xen/xend/XendDomainInfo.py +++ b/tools/python/xen/xend/XendDomainInfo.py @@ -32,8 +32,6 @@ import errno import xen.lowlevel.xc from xen.util.blkif import blkdev_uname_to_file -from xen.xend.server import channel - from xen.xend import image from xen.xend import scheduler from xen.xend import sxp @@ -785,32 +783,6 @@ class XendDomainInfo: self.domid, self.info['name']) - def closeChannel(self, chan, entry): - """Close the given channel, if set, and remove the given entry in the - store. Nothrow guarantee.""" - - if chan: - chan.close() - try: - self.removeDom(entry) - except: - log.exception('Removing entry %s failed', entry) - - - def closeStoreChannel(self): - """Close the store channel, if any. Nothrow guarantee.""" - - self.closeChannel(self.store_channel, "store/port") - self.store_channel = None - - - def closeConsoleChannel(self): - """Close the console channel, if any. Nothrow guarantee.""" - - self.closeChannel(self.console_channel, "console/port") - self.console_channel = None - - ## public: def setConsoleRef(self, ref): @@ -960,12 +932,8 @@ class XendDomainInfo: sxpr.append(['up_time', str(up_time) ]) sxpr.append(['start_time', str(self.info['start_time']) ]) - if self.store_channel: - sxpr.append(self.store_channel.sxpr()) if self.store_mfn: sxpr.append(['store_mfn', self.store_mfn]) - if self.console_channel: - sxpr.append(['console_channel', self.console_channel.sxpr()]) if self.console_mfn: sxpr.append(['console_mfn', self.console_mfn]) @@ -1073,7 +1041,7 @@ class XendDomainInfo: self.create_channel() self.image.createImage() IntroduceDomain(self.domid, self.store_mfn, - self.store_channel.port1, self.dompath) + self.store_channel, self.dompath) ## public: @@ -1083,8 +1051,6 @@ class XendDomainInfo: guarantee.""" self.release_devices() - self.closeStoreChannel() - self.closeConsoleChannel() if self.image: try: @@ -1164,35 +1130,22 @@ class XendDomainInfo: @param path under which port is stored in db """ - port = 0 if path: try: - port = int(self.readDom(path)) + return int(self.readDom(path)) except: # The port is not yet set, i.e. the channel has not yet been # created. pass - # Stale port information from above causes an Invalid Argument to be - # thrown by the eventChannel call below. To recover, we throw away - # port if it turns out to be bad, and just create a new channel. - # If creating a new channel with two new ports fails, then something - # else is going wrong, so we bail. - while True: - try: - ret = channel.eventChannel(0, self.domid, port1 = port, - port2 = 0) - break - except: - log.exception("Exception in eventChannel(0, %d, %d, %d)", - self.domid, port, 0) - if port == 0: - raise - else: - port = 0 - log.error("Recovering from above exception.") - self.storeDom(path, ret.port1) - return ret + try: + port = xc.evtchn_alloc_unbound(dom=self.domid, remote_dom=0) + except: + log.exception("Exception in alloc_unbound(%d)", self.domid) + raise + + self.storeDom(path, port) + return port def create_channel(self): """Create the channels to the domain. @@ -1419,11 +1372,11 @@ class XendDomainInfo: def initStoreConnection(self): - ref = xc.init_store(self.store_channel.port2) + ref = xc.init_store(self.store_channel) if ref and ref >= 0: self.setStoreRef(ref) try: - IntroduceDomain(self.domid, ref, self.store_channel.port1, + IntroduceDomain(self.domid, ref, self.store_channel, self.dompath) except RuntimeError, ex: if ex.args[0] == errno.EISCONN: diff --git a/tools/python/xen/xend/image.py b/tools/python/xen/xend/image.py index 0e71568c1d..9ad3d29f00 100644 --- a/tools/python/xen/xend/image.py +++ b/tools/python/xen/xend/image.py @@ -25,8 +25,6 @@ from xen.xend import sxp from xen.xend.XendError import VmError from xen.xend.XendLogging import log -from xen.xend.server import channel - xc = xen.lowlevel.xc.new() @@ -168,11 +166,11 @@ class LinuxImageHandler(ImageHandler): def buildDomain(self): if self.vm.store_channel: - store_evtchn = self.vm.store_channel.port2 + store_evtchn = self.vm.store_channel else: store_evtchn = 0 if self.vm.console_channel: - console_evtchn = self.vm.console_channel.port2 + console_evtchn = self.vm.console_channel else: console_evtchn = 0 @@ -228,16 +226,17 @@ class VmxImageHandler(ImageHandler): def buildDomain(self): # Create an event channel - self.device_channel = channel.eventChannel(0, self.vm.getDomid()) - log.info("VMX device model port: %d", self.device_channel.port2) + self.device_channel = xc.evtchn_alloc_unbound(dom=self.vm.getDomid(), + remote_dom=0) + log.info("VMX device model port: %d", self.device_channel) if self.vm.store_channel: - store_evtchn = self.vm.store_channel.port2 + store_evtchn = self.vm.store_channel else: store_evtchn = 0 log.debug("dom = %d", self.vm.getDomid()) log.debug("image = %s", self.kernel) - log.debug("control_evtchn = %d", self.device_channel.port2) + log.debug("control_evtchn = %d", self.device_channel) log.debug("store_evtchn = %d", store_evtchn) log.debug("memsize = %d", self.vm.getMemoryTarget() / 1024) log.debug("flags = %d", self.flags) @@ -245,7 +244,7 @@ class VmxImageHandler(ImageHandler): ret = xc.vmx_build(dom = self.vm.getDomid(), image = self.kernel, - control_evtchn = self.device_channel.port2, + control_evtchn = self.device_channel, store_evtchn = store_evtchn, memsize = self.vm.getMemoryTarget() / 1024, flags = self.flags, @@ -334,7 +333,7 @@ class VmxImageHandler(ImageHandler): if len(vnc): args = args + vnc args = args + ([ "-d", "%d" % self.vm.getDomid(), - "-p", "%d" % self.device_channel.port1, + "-p", "%d" % self.device_channel, "-m", "%s" % (self.vm.getMemoryTarget() / 1024)]) args = args + self.dmargs env = dict(os.environ) @@ -358,8 +357,6 @@ class VmxImageHandler(ImageHandler): return vncconnect def destroy(self): - if self.device_channel: - self.device_channel.close() import signal if not self.pid: return diff --git a/tools/python/xen/xend/server/channel.py b/tools/python/xen/xend/server/channel.py deleted file mode 100755 index 095a14786a..0000000000 --- a/tools/python/xen/xend/server/channel.py +++ /dev/null @@ -1,76 +0,0 @@ -#============================================================================ -# This library is free software; you can redistribute it and/or -# modify it under the terms of version 2.1 of the GNU Lesser General Public -# License as published by the Free Software Foundation. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -#============================================================================ -# Copyright (C) 2004, 2005 Mike Wray -# Copyright (C) 2005 XenSource Ltd -#============================================================================ - -import xen.lowlevel.xc - -from xen.xend.XendLogging import log - - -xc = xen.lowlevel.xc.new() - - -class EventChannel: - """An event channel between domains. - """ - - def __init__(self, dom1, dom2, port1, port2): - self.dom1 = dom1 - self.dom2 = dom2 - self.port1 = port1 - self.port2 = port2 - - - def close(self): - """Close the event channel. Nothrow guarantee. - """ - def evtchn_close(dom, port): - try: - xc.evtchn_close(dom=dom, port=port) - except Exception: - log.exception("Exception closing event channel %d, %d.", dom, - port) - - evtchn_close(self.dom1, self.port1) - evtchn_close(self.dom2, self.port2) - - - def sxpr(self): - return ['event-channel', - ['dom1', self.dom1 ], - ['port1', self.port1 ], - ['dom2', self.dom2 ], - ['port2', self.port2 ] - ] - - - def __repr__(self): - return ("" - % (self.dom1, self.port1, self.dom2, self.port2)) - - -def eventChannel(dom1, dom2, port1 = 0, port2 = 0): - """Create an event channel between domains. - - @return EventChannel (None on error) - """ - v = xc.evtchn_bind_interdomain(dom1=dom1, dom2=dom2, - port1=port1, port2=port2) - if v and v.get('port1'): - return EventChannel(dom1, dom2, v['port1'], v['port2']) - else: - return None diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c index 9ac1b28eef..69ace083d9 100644 --- a/tools/xenstore/xenstored_domain.c +++ b/tools/xenstore/xenstored_domain.c @@ -36,6 +36,8 @@ #include "xenstored_watch.h" #include "xenstored_test.h" +#include + static int *xc_handle; static int eventchn_fd; static int virq_port; @@ -77,9 +79,6 @@ struct ringbuf_head char buf[0]; } __attribute__((packed)); -#define EVENTCHN_BIND _IO('E', 2) -#define EVENTCHN_UNBIND _IO('E', 3) - /* FIXME: Mark connection as broken (close it?) when this happens. */ static bool check_buffer(const struct ringbuf_head *h) { @@ -207,14 +206,17 @@ static int readchn(struct connection *conn, void *data, unsigned int len) static int destroy_domain(void *_domain) { struct domain *domain = _domain; + struct ioctl_evtchn_unbind unbind; list_del(&domain->list); - if (domain->port && - (ioctl(eventchn_fd, EVENTCHN_UNBIND, domain->port) != 0)) - eprintf("> Unbinding port %i failed!\n", domain->port); + if (domain->port) { + unbind.port = domain->port; + if (ioctl(eventchn_fd, IOCTL_EVTCHN_UNBIND, &unbind) == -1) + eprintf("> Unbinding port %i failed!\n", domain->port); + } - if(domain->page) + if (domain->page) munmap(domain->page, getpagesize()); return 0; @@ -278,6 +280,9 @@ static struct domain *new_domain(void *context, domid_t domid, const char *path) { struct domain *domain; + struct ioctl_evtchn_bind_interdomain bind; + int rc; + domain = talloc(context, struct domain); domain->port = 0; domain->shutdown = 0; @@ -298,10 +303,13 @@ static struct domain *new_domain(void *context, domid_t domid, domain->output = domain->page + getpagesize()/2; /* Tell kernel we're interested in this event. */ - if (ioctl(eventchn_fd, EVENTCHN_BIND, port) != 0) + bind.remote_domain = domid; + bind.remote_port = port; + rc = ioctl(eventchn_fd, IOCTL_EVTCHN_BIND_INTERDOMAIN, &bind); + if (rc == -1) return NULL; - domain->port = port; + domain->port = rc; domain->conn = new_connection(writechn, readchn); domain->conn->domain = domain; return domain; @@ -445,6 +453,8 @@ void restore_existing_connections(void) int domain_init(void) { struct stat st; + struct ioctl_evtchn_bind_virq bind; + int rc; /* The size of the ringbuffer: half a page minus head structure. */ ringbuf_datasize = getpagesize() / 2 - sizeof(struct ringbuf_head); @@ -482,11 +492,11 @@ int domain_init(void) if (eventchn_fd < 0) barf_perror("Failed to open evtchn device"); - if (xc_evtchn_bind_virq(*xc_handle, VIRQ_DOM_EXC, &virq_port)) - barf_perror("Failed to bind to domain exception virq"); - - if (ioctl(eventchn_fd, EVENTCHN_BIND, virq_port) != 0) + bind.virq = VIRQ_DOM_EXC; + rc = ioctl(eventchn_fd, IOCTL_EVTCHN_BIND_VIRQ, &bind); + if (rc == -1) barf_perror("Failed to bind to domain exception virq port"); + virq_port = rc; return eventchn_fd; } diff --git a/xen/common/event_channel.c b/xen/common/event_channel.c index eea5ee1633..b83e0bb9dc 100644 --- a/xen/common/event_channel.c +++ b/xen/common/event_channel.c @@ -36,7 +36,13 @@ #define evtchn_from_port(d,p) \ (&(bucket_from_port(d,p))[(p)&(EVTCHNS_PER_BUCKET-1)]) -#define ERROR_EXIT(_errno) do { rc = (_errno); goto out; } while ( 0 ) +#define ERROR_EXIT(_errno) \ + do { \ + DPRINTK("EVTCHNOP failure: domain %d, error %d, line %d\n", \ + current->domain->domain_id, (_errno), __LINE__); \ + rc = (_errno); \ + goto out; \ + } while ( 0 ) static int get_free_port(struct domain *d) { From 07a233ac7c228b36a4c2a9abc09abbbeb04aab81 Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Thu, 6 Oct 2005 17:02:38 +0100 Subject: [PATCH 2/2] User tools send evtchn notifications via /dev/xen/evtchn rather than using hypercall directly. Signed-off-by: Keir Fraser --- .../drivers/xen/evtchn/evtchn.c | 18 +++ .../include/asm-xen/linux-public/evtchn.h | 11 +- tools/console/daemon/io.c | 11 +- tools/ioemu/target-i386-dm/helper2.c | 8 +- tools/libxc/xc_evtchn.c | 81 +----------- tools/libxc/xenctrl.h | 60 +-------- tools/python/xen/lowlevel/xc/xc.c | 121 +----------------- tools/xenstore/Makefile | 7 +- tools/xenstore/fake_libxc.c | 12 +- tools/xenstore/xenstored_core.c | 14 +- tools/xenstore/xenstored_core.h | 2 + tools/xenstore/xenstored_domain.c | 19 ++- tools/xenstore/xenstored_domain.h | 2 +- tools/xenstore/xs_dom0_test.c | 43 ------- 14 files changed, 76 insertions(+), 333 deletions(-) delete mode 100644 tools/xenstore/xs_dom0_test.c 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 658157c4c3..b273e65fbd 100644 --- a/linux-2.6-xen-sparse/drivers/xen/evtchn/evtchn.c +++ b/linux-2.6-xen-sparse/drivers/xen/evtchn/evtchn.c @@ -297,6 +297,24 @@ static int evtchn_ioctl(struct inode *inode, struct file *file, break; } + case IOCTL_EVTCHN_NOTIFY: { + struct ioctl_evtchn_notify notify; + + rc = -EFAULT; + if (copy_from_user(¬ify, (void *)arg, sizeof(notify))) + break; + + if (notify.port >= NR_EVENT_CHANNELS) { + rc = -EINVAL; + } else if (port_user[notify.port] != u) { + rc = -ENOTCONN; + } else { + notify_remote_via_evtchn(notify.port); + rc = 0; + } + break; + } + case IOCTL_EVTCHN_RESET: { /* Initialise the ring to empty. Clear errors. */ u->ring_cons = u->ring_prod = u->ring_overflow = 0; diff --git a/linux-2.6-xen-sparse/include/asm-xen/linux-public/evtchn.h b/linux-2.6-xen-sparse/include/asm-xen/linux-public/evtchn.h index 9f47eaf44c..456f246530 100644 --- a/linux-2.6-xen-sparse/include/asm-xen/linux-public/evtchn.h +++ b/linux-2.6-xen-sparse/include/asm-xen/linux-public/evtchn.h @@ -72,9 +72,18 @@ struct ioctl_evtchn_unbind { unsigned int port; }; +/* + * Unbind previously allocated @port. + */ +#define IOCTL_EVTCHN_NOTIFY \ + _IOC(_IOC_NONE, 'E', 4, sizeof(struct ioctl_evtchn_notify)) +struct ioctl_evtchn_notify { + unsigned int port; +}; + /* Clear and reinitialise the event buffer. Clear error condition. */ #define IOCTL_EVTCHN_RESET \ - _IOC(_IOC_NONE, 'E', 4, 0) + _IOC(_IOC_NONE, 'E', 5, 0) #endif /* __LINUX_PUBLIC_EVTCHN_H__ */ diff --git a/tools/console/daemon/io.c b/tools/console/daemon/io.c index dab3177d14..cde27b2dc7 100644 --- a/tools/console/daemon/io.c +++ b/tools/console/daemon/io.c @@ -81,6 +81,13 @@ struct ring_head #define XENCONS_FULL(ring) (((ring)->prod - (ring)->cons) == XENCONS_RING_SIZE) #define XENCONS_SPACE(ring) (XENCONS_RING_SIZE - ((ring)->prod - (ring)->cons)) +static void evtchn_notify(struct domain *dom) +{ + struct ioctl_evtchn_notify notify; + notify.port = dom->local_port; + (void)ioctl(dom->evtchn_fd, IOCTL_EVTCHN_NOTIFY, ¬ify); +} + static void buffer_append(struct domain *dom) { struct buffer *buffer = &dom->buffer; @@ -121,7 +128,7 @@ static void buffer_append(struct domain *dom) } if (notify) - xc_evtchn_send(xc, dom->local_port); + evtchn_notify(dom); } static bool buffer_empty(struct buffer *buffer) @@ -440,7 +447,7 @@ static void handle_tty_read(struct domain *dom) inring->buf[XENCONS_IDX(inring->prod)] = msg[i]; inring->prod++; } - xc_evtchn_send(xc, dom->local_port); + evtchn_notify(dom); } else { close(dom->tty_fd); dom->tty_fd = -1; diff --git a/tools/ioemu/target-i386-dm/helper2.c b/tools/ioemu/target-i386-dm/helper2.c index d32ef006ba..5f0c3712cc 100644 --- a/tools/ioemu/target-i386-dm/helper2.c +++ b/tools/ioemu/target-i386-dm/helper2.c @@ -486,11 +486,9 @@ int main_loop(void) do_ioapic(); #endif if (env->send_event) { - int ret; - ret = xc_evtchn_send(xc_handle, ioreq_local_port); - if (ret == -1) { - fprintf(logfile, "evtchn_send failed on port: %d\n", ioreq_local_port); - } + struct ioctl_evtchn_notify notify; + notify.port = ioreq_local_port; + (void)ioctl(evtchn_fd, IOCTL_EVTCHN_NOTIFY, ¬ify); } } destroy_vmx_domain(); diff --git a/tools/libxc/xc_evtchn.c b/tools/libxc/xc_evtchn.c index ed6256654b..a318889b85 100644 --- a/tools/libxc/xc_evtchn.c +++ b/tools/libxc/xc_evtchn.c @@ -33,95 +33,22 @@ static int do_evtchn_op(int xc_handle, evtchn_op_t *op) int xc_evtchn_alloc_unbound(int xc_handle, - u32 remote_dom, u32 dom, - int *port) + u32 remote_dom) { int rc; evtchn_op_t op = { .cmd = EVTCHNOP_alloc_unbound, - .u.alloc_unbound.remote_dom = (domid_t)remote_dom, - .u.alloc_unbound.dom = (domid_t)dom, - .u.alloc_unbound.port = (port != NULL) ? *port : 0 }; + .u.alloc_unbound.dom = (domid_t)dom, + .u.alloc_unbound.remote_dom = (domid_t)remote_dom }; if ( (rc = do_evtchn_op(xc_handle, &op)) == 0 ) - { - if ( port != NULL ) - *port = op.u.alloc_unbound.port; - } + rc = op.u.alloc_unbound.port; return rc; } -int xc_evtchn_bind_interdomain(int xc_handle, - u32 dom1, - u32 dom2, - int *port1, - int *port2) -{ - int rc; - evtchn_op_t op = { - .cmd = EVTCHNOP_bind_interdomain, - .u.bind_interdomain.dom1 = (domid_t)dom1, - .u.bind_interdomain.dom2 = (domid_t)dom2, - .u.bind_interdomain.port1 = (port1 != NULL) ? *port1 : 0, - .u.bind_interdomain.port2 = (port2 != NULL) ? *port2 : 0 }; - - if ( (rc = do_evtchn_op(xc_handle, &op)) == 0 ) - { - if ( port1 != NULL ) - *port1 = op.u.bind_interdomain.port1; - if ( port2 != NULL ) - *port2 = op.u.bind_interdomain.port2; - } - - return rc; -} - - -int xc_evtchn_bind_virq(int xc_handle, - int virq, - int *port) -{ - int rc; - evtchn_op_t op = { - .cmd = EVTCHNOP_bind_virq, - .u.bind_virq.virq = (u32)virq, - .u.bind_virq.vcpu = 0 }; - - if ( (rc = do_evtchn_op(xc_handle, &op)) == 0 ) - { - if ( port != NULL ) - *port = op.u.bind_virq.port; - } - - return rc; -} - - -int xc_evtchn_close(int xc_handle, - u32 dom, - int port) -{ - evtchn_op_t op = { - .cmd = EVTCHNOP_close, - .u.close.dom = (domid_t)dom, - .u.close.port = port }; - return do_evtchn_op(xc_handle, &op); -} - - -int xc_evtchn_send(int xc_handle, - int local_port) -{ - evtchn_op_t op = { - .cmd = EVTCHNOP_send, - .u.send.local_port = local_port }; - return do_evtchn_op(xc_handle, &op); -} - - int xc_evtchn_status(int xc_handle, u32 dom, int port, diff --git a/tools/libxc/xenctrl.h b/tools/libxc/xenctrl.h index 3e74c62fa0..5ba19a891b 100644 --- a/tools/libxc/xenctrl.h +++ b/tools/libxc/xenctrl.h @@ -306,68 +306,14 @@ typedef evtchn_status_t xc_evtchn_status_t; * well-known port within a domain to receive events on. * * @parm xc_handle a handle to an open hypervisor interface - * @parm remote_dom the ID of the domain who will later bind * @parm dom the ID of the local domain (the 'allocatee') - * @parm port a pointer to a port. This is an in/out parameter. If *port is - * 0, then a new port will be assigned, if port is > 0 then that - * port is allocated if the port is unallocated. - * @return 0 on success, -1 on failure + * @parm remote_dom the ID of the domain who will later bind + * @return allocated port (in @dom) on success, -1 on failure */ int xc_evtchn_alloc_unbound(int xc_handle, - u32 remote_dom, u32 dom, - int *port); + u32 remote_dom); -/** - * This function creates a pair of ports between two domains. A port can only - * be bound once within a domain. - * - * @parm xc_handle a handle to an open hypervisor interface - * @parm dom1 one of the two domains to connect. Can be DOMID_SELF. - * @parm dom2 the other domain to connect. Can be DOMID_SELF. - * @parm port1 an in/out parameter. If > 0, then try to connect *port. If - * 0, then allocate a new port and store the port in *port. - * @parm port2 the port connected on port2. This parameter behaves the same - * way as port1. - * @return 0 on success, -1 on error. - */ -int xc_evtchn_bind_interdomain(int xc_handle, - u32 dom1, - u32 dom2, - int *port1, - int *port2); -int xc_evtchn_bind_virq(int xc_handle, - int virq, - int *port); - -/** - * This function will close a single port on an event channel. - * - * @parm xc_handle a handle to an open hypervisor interface - * @parm dom the domain that the port exists on. May be DOMID_SELF. - * @parm port the port to close - * @return 0 on success, -1 on error - */ -int xc_evtchn_close(int xc_handle, - u32 dom, /* may be DOMID_SELF */ - int port); - -/** - * This function generates a notify event on a bound port. - * - * Notifies can be read within Linux by opening /dev/xen/evtchn and reading - * a 16 bit value. The result will be the port the event occurred on. When - * events occur, the port is masked until the 16 bit port value is written back - * to the file. When /dev/xen/evtchn is opened, it has to be bound via an - * ioctl to each port to listen on. The ioctl for binding is _IO('E', 2). The - * parameter is the port to listen on. - * - * @parm xc_handle a handle to an open hypervisor interface - * @parm local_port the port to generate the notify on - * @return 0 on success, -1 on error - */ -int xc_evtchn_send(int xc_handle, - int local_port); int xc_evtchn_status(int xc_handle, u32 dom, /* may be DOMID_SELF */ int port, diff --git a/tools/python/xen/lowlevel/xc/xc.c b/tools/python/xen/lowlevel/xc/xc.c index 5074b4b3c6..f42dce8d4c 100644 --- a/tools/python/xen/lowlevel/xc/xc.c +++ b/tools/python/xen/lowlevel/xc/xc.c @@ -433,7 +433,7 @@ static PyObject *pyxc_evtchn_alloc_unbound(PyObject *self, XcObject *xc = (XcObject *)self; u32 dom = DOMID_SELF, remote_dom; - int port = 0; + int port; static char *kwd_list[] = { "remote_dom", "dom", NULL }; @@ -441,97 +441,12 @@ static PyObject *pyxc_evtchn_alloc_unbound(PyObject *self, &remote_dom, &dom) ) return NULL; - if ( xc_evtchn_alloc_unbound(xc->xc_handle, remote_dom, dom, &port) != 0 ) + if ( (port = xc_evtchn_alloc_unbound(xc->xc_handle, dom, remote_dom)) < 0 ) return PyErr_SetFromErrno(xc_error); return PyInt_FromLong(port); } -static PyObject *pyxc_evtchn_bind_interdomain(PyObject *self, - PyObject *args, - PyObject *kwds) -{ - XcObject *xc = (XcObject *)self; - - u32 dom1 = DOMID_SELF, dom2 = DOMID_SELF; - int port1 = 0, port2 = 0; - - static char *kwd_list[] = { "dom1", "dom2", "port1", "port2", NULL }; - - if ( !PyArg_ParseTupleAndKeywords(args, kwds, "|iiii", kwd_list, - &dom1, &dom2, &port1, &port2) ) - return NULL; - - if ( xc_evtchn_bind_interdomain(xc->xc_handle, dom1, - dom2, &port1, &port2) != 0 ) - return PyErr_SetFromErrno(xc_error); - - return Py_BuildValue("{s:i,s:i}", - "port1", port1, - "port2", port2); -} - -static PyObject *pyxc_evtchn_bind_virq(PyObject *self, - PyObject *args, - PyObject *kwds) -{ - XcObject *xc = (XcObject *)self; - - int virq, port; - - static char *kwd_list[] = { "virq", NULL }; - - if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i", kwd_list, &virq) ) - return NULL; - - if ( xc_evtchn_bind_virq(xc->xc_handle, virq, &port) != 0 ) - return PyErr_SetFromErrno(xc_error); - - return PyInt_FromLong(port); -} - -static PyObject *pyxc_evtchn_close(PyObject *self, - PyObject *args, - PyObject *kwds) -{ - XcObject *xc = (XcObject *)self; - - u32 dom = DOMID_SELF; - int port; - - static char *kwd_list[] = { "port", "dom", NULL }; - - if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i|i", kwd_list, - &port, &dom) ) - return NULL; - - if ( xc_evtchn_close(xc->xc_handle, dom, port) != 0 ) - return PyErr_SetFromErrno(xc_error); - - Py_INCREF(zero); - return zero; -} - -static PyObject *pyxc_evtchn_send(PyObject *self, - PyObject *args, - PyObject *kwds) -{ - XcObject *xc = (XcObject *)self; - - int port; - - static char *kwd_list[] = { "port", NULL }; - - if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i", kwd_list, &port) ) - return NULL; - - if ( xc_evtchn_send(xc->xc_handle, port) != 0 ) - return PyErr_SetFromErrno(xc_error); - - Py_INCREF(zero); - return zero; -} - static PyObject *pyxc_evtchn_status(PyObject *self, PyObject *args, PyObject *kwds) @@ -1032,38 +947,6 @@ static PyMethodDef pyxc_methods[] = { " dom [int]: Remote domain to accept connections from.\n\n" "Returns: [int] Unbound event-channel port.\n" }, - { "evtchn_bind_interdomain", - (PyCFunction)pyxc_evtchn_bind_interdomain, - METH_VARARGS | METH_KEYWORDS, "\n" - "Open an event channel between two domains.\n" - " dom1 [int, SELF]: First domain to be connected.\n" - " dom2 [int, SELF]: Second domain to be connected.\n\n" - "Returns: [dict] dictionary is empty on failure.\n" - " port1 [int]: Port-id for endpoint at dom1.\n" - " port2 [int]: Port-id for endpoint at dom2.\n" }, - - { "evtchn_bind_virq", - (PyCFunction)pyxc_evtchn_bind_virq, - METH_VARARGS | METH_KEYWORDS, "\n" - "Bind an event channel to the specified VIRQ.\n" - " virq [int]: VIRQ to bind.\n\n" - "Returns: [int] Bound event-channel port.\n" }, - - { "evtchn_close", - (PyCFunction)pyxc_evtchn_close, - METH_VARARGS | METH_KEYWORDS, "\n" - "Close an event channel. If interdomain, sets remote end to 'unbound'.\n" - " dom [int, SELF]: Dom-id of one endpoint of the channel.\n" - " port [int]: Port-id of one endpoint of the channel.\n\n" - "Returns: [int] 0 on success; -1 on error.\n" }, - - { "evtchn_send", - (PyCFunction)pyxc_evtchn_send, - METH_VARARGS | METH_KEYWORDS, "\n" - "Send an event along a locally-connected event channel.\n" - " port [int]: Port-id of a local channel endpoint.\n\n" - "Returns: [int] 0 on success; -1 on error.\n" }, - { "evtchn_status", (PyCFunction)pyxc_evtchn_status, METH_VARARGS | METH_KEYWORDS, "\n" diff --git a/tools/xenstore/Makefile b/tools/xenstore/Makefile index 7930789c8c..3b82bf2887 100644 --- a/tools/xenstore/Makefile +++ b/tools/xenstore/Makefile @@ -29,7 +29,7 @@ CLIENTS_OBJS := $(patsubst xenstore-%,xenstore_%.o,$(CLIENTS)) all: libxenstore.so xenstored $(CLIENTS) xs_tdb_dump -testcode: xs_test xenstored_test xs_random xs_dom0_test +testcode: xs_test xenstored_test xs_random xenstored: xenstored_core.o xenstored_watch.o xenstored_domain.o xenstored_transaction.o xs_lib.o talloc.o utils.o tdb.o $(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -lxenctrl -o $@ @@ -74,7 +74,7 @@ libxenstore.so: xs.opic xs_lib.opic clean: testsuite-clean rm -f *.o *.opic *.so rm -f xenstored xs_random xs_stress xs_crashme - rm -f xs_test xenstored_test xs_dom0_test + rm -f xs_test xenstored_test $(RM) $(PROG_DEP) print-dir: @@ -120,9 +120,6 @@ stresstest: xs_stress xenstored_test $(TESTDIR) rm -rf $(TESTDIR)/store $(TESTDIR)/transactions export $(TESTENV); PID=`./xenstored_test --output-pid --trace-file=/tmp/trace`; ./xs_stress 5000; ret=$$?; kill $$PID; exit $$ret -xs_dom0_test: xs_dom0_test.o utils.o - $(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -lxenctrl -o $@ - TAGS: etags `find . -name '*.[ch]'` diff --git a/tools/xenstore/fake_libxc.c b/tools/xenstore/fake_libxc.c index a435d65bd0..5a02b2e597 100644 --- a/tools/xenstore/fake_libxc.c +++ b/tools/xenstore/fake_libxc.c @@ -36,12 +36,11 @@ static int xs_test_pid; static u16 port; /* The event channel maps to a signal, shared page to an mmapped file. */ -int xc_evtchn_send(int xc_handle __attribute__((unused)), int local_port) +void evtchn_notify(int local_port) { assert(local_port == port); if (kill(xs_test_pid, SIGUSR2) != 0) barf_perror("fake event channel failed"); - return 0; } void *xc_map_foreign_range(int xc_handle, u32 dom __attribute__((unused)), @@ -107,15 +106,6 @@ int xc_domain_getinfo(int xc_handle __attribute__((unused)), return 1; } -int xc_evtchn_bind_virq(int xc_handle __attribute__((unused)), - int virq __attribute__((unused)), - int *port) -{ - if (port) - *port = 0; - return 0; -} - static void send_to_fd(int signo __attribute__((unused))) { int saved_errno = errno; diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c index b892b8517e..da305ad7ce 100644 --- a/tools/xenstore/xenstored_core.c +++ b/tools/xenstore/xenstored_core.c @@ -52,6 +52,8 @@ #include "xenctrl.h" #include "tdb.h" +int event_fd; + static bool verbose; LIST_HEAD(connections); static int tracefd = -1; @@ -309,8 +311,7 @@ static int destroy_conn(void *_conn) return 0; } -static int initialize_set(fd_set *inset, fd_set *outset, int sock, int ro_sock, - int event_fd) +static int initialize_set(fd_set *inset, fd_set *outset, int sock, int ro_sock) { struct connection *i; int max; @@ -1464,7 +1465,7 @@ static struct option options[] = { int main(int argc, char *argv[]) { - int opt, *sock, *ro_sock, event_fd, max; + int opt, *sock, *ro_sock, max; struct sockaddr_un addr; fd_set inset, outset; bool dofork = true; @@ -1568,7 +1569,7 @@ int main(int argc, char *argv[]) #endif /* Get ready to listen to the tools. */ - max = initialize_set(&inset, &outset, *sock, *ro_sock, event_fd); + max = initialize_set(&inset, &outset, *sock, *ro_sock); /* Main loop. */ /* FIXME: Rewrite so noone can starve. */ @@ -1588,7 +1589,7 @@ int main(int argc, char *argv[]) accept_connection(*ro_sock, false); if (FD_ISSET(event_fd, &inset)) - handle_event(event_fd); + handle_event(); list_for_each_entry(i, &connections, list) { if (i->domain) @@ -1624,7 +1625,6 @@ int main(int argc, char *argv[]) } } - max = initialize_set(&inset, &outset, *sock, *ro_sock, - event_fd); + max = initialize_set(&inset, &outset, *sock, *ro_sock); } } diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h index 404343b734..1967d8425c 100644 --- a/tools/xenstore/xenstored_core.h +++ b/tools/xenstore/xenstored_core.h @@ -173,4 +173,6 @@ void trace_destroy(const void *data, const char *type); void trace_watch_timeout(const struct connection *conn, const char *node, const char *token); void trace(const char *fmt, ...); +extern int event_fd; + #endif /* _XENSTORED_CORE_H */ diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c index 69ace083d9..a7cd4493ad 100644 --- a/tools/xenstore/xenstored_domain.c +++ b/tools/xenstore/xenstored_domain.c @@ -79,6 +79,17 @@ struct ringbuf_head char buf[0]; } __attribute__((packed)); +#ifndef TESTING +static void evtchn_notify(int port) +{ + struct ioctl_evtchn_notify notify; + notify.port = port; + (void)ioctl(event_fd, IOCTL_EVTCHN_NOTIFY, ¬ify); +} +#else +extern void evtchn_notify(int port); +#endif + /* FIXME: Mark connection as broken (close it?) when this happens. */ static bool check_buffer(const struct ringbuf_head *h) { @@ -164,9 +175,7 @@ static int writechn(struct connection *conn, const void *data, unsigned int len) memcpy(dest, data, len); mb(); update_output_chunk(conn->domain->output, len); - /* FIXME: Probably not neccessary. */ - mb(); - xc_evtchn_send(*xc_handle, conn->domain->port); + evtchn_notify(conn->domain->port); return len; } @@ -199,7 +208,7 @@ static int readchn(struct connection *conn, void *data, unsigned int len) /* If it was full, tell them we've taken some. */ if (was_full) - xc_evtchn_send(*xc_handle, conn->domain->port); + evtchn_notify(conn->domain->port); return len; } @@ -249,7 +258,7 @@ static void domain_cleanup(void) } /* We scan all domains rather than use the information given here. */ -void handle_event(int event_fd) +void handle_event(void) { u16 port; diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h index a896e1a3af..e8d5ec8c88 100644 --- a/tools/xenstore/xenstored_domain.h +++ b/tools/xenstore/xenstored_domain.h @@ -20,7 +20,7 @@ #ifndef _XENSTORED_DOMAIN_H #define _XENSTORED_DOMAIN_H -void handle_event(int event_fd); +void handle_event(void); /* domid, mfn, eventchn, path */ void do_introduce(struct connection *conn, struct buffered_data *in); diff --git a/tools/xenstore/xs_dom0_test.c b/tools/xenstore/xs_dom0_test.c deleted file mode 100644 index e92c3470ae..0000000000 --- a/tools/xenstore/xs_dom0_test.c +++ /dev/null @@ -1,43 +0,0 @@ -/* Test introduction of domain 0 */ -#include -#include -#include "xs.h" -#include "utils.h" -#include -#include -#include -#include -#include - -int main() -{ - int h, local = 0, kernel = 0; - long err; - void *page; - - h = xc_interface_open(); - if (h < 0) - barf_perror("Failed to open xc"); - - if (xc_evtchn_bind_interdomain(h, DOMID_SELF, 0, &local, &kernel) != 0) - barf_perror("Failed to bind interdomain"); - - printf("Got ports %i & %i\n", local, kernel); - - err = ioctl(h, IOCTL_PRIVCMD_INITDOMAIN_STORE, kernel); - if (err < 0) - barf_perror("Failed to initialize store"); - printf("Got mfn %li\n", err); - - page = xc_map_foreign_range(h, 0, getpagesize(), PROT_READ|PROT_WRITE, - err); - if (!page) - barf_perror("Failed to map page %li", err); - printf("Mapped page at %p\n", page); - printf("Page says %s\n", (char *)page); - munmap(page, getpagesize()); - printf("unmapped\n"); - - return 0; -} -