From 00f75a257f970be28fce18fcea14dc124fd73540 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Mon, 4 Dec 2006 09:21:10 +0000 Subject: [PATCH 01/12] Add XEN_FRAMEBUFFER to -xen defconfigs. Signed-off-by: Atsushi SAKAI --- buildconfigs/linux-defconfig_xen_ia64 | 2 ++ buildconfigs/linux-defconfig_xen_x86_32 | 2 ++ buildconfigs/linux-defconfig_xen_x86_64 | 2 ++ 3 files changed, 6 insertions(+) diff --git a/buildconfigs/linux-defconfig_xen_ia64 b/buildconfigs/linux-defconfig_xen_ia64 index 1bdc8edb4c..e04b1db69f 100644 --- a/buildconfigs/linux-defconfig_xen_ia64 +++ b/buildconfigs/linux-defconfig_xen_ia64 @@ -1548,6 +1548,8 @@ CONFIG_XEN_PCIDEV_BACKEND_SLOT=y # CONFIG_XEN_TPMDEV_BACKEND is not set CONFIG_XEN_BLKDEV_FRONTEND=y CONFIG_XEN_NETDEV_FRONTEND=y +CONFIG_XEN_FRAMEBUFFER=y +CONFIG_XEN_KEYBOARD=y # CONFIG_XEN_SCRUB_PAGES is not set CONFIG_XEN_DISABLE_SERIAL=y CONFIG_XEN_SYSFS=y diff --git a/buildconfigs/linux-defconfig_xen_x86_32 b/buildconfigs/linux-defconfig_xen_x86_32 index 6128a1012b..993da59152 100644 --- a/buildconfigs/linux-defconfig_xen_x86_32 +++ b/buildconfigs/linux-defconfig_xen_x86_32 @@ -3034,6 +3034,8 @@ CONFIG_XEN_NETDEV_LOOPBACK=y # CONFIG_XEN_TPMDEV_BACKEND is not set CONFIG_XEN_BLKDEV_FRONTEND=y CONFIG_XEN_NETDEV_FRONTEND=y +CONFIG_XEN_FRAMEBUFFER=y +CONFIG_XEN_KEYBOARD=y CONFIG_XEN_SCRUB_PAGES=y CONFIG_XEN_DISABLE_SERIAL=y CONFIG_XEN_SYSFS=y diff --git a/buildconfigs/linux-defconfig_xen_x86_64 b/buildconfigs/linux-defconfig_xen_x86_64 index 0bca78b24f..ebee7ab056 100644 --- a/buildconfigs/linux-defconfig_xen_x86_64 +++ b/buildconfigs/linux-defconfig_xen_x86_64 @@ -2866,6 +2866,8 @@ CONFIG_XEN_TPMDEV_BACKEND=m # CONFIG_XEN_TPMDEV_CLOSE_IF_VTPM_FAILS is not set CONFIG_XEN_BLKDEV_FRONTEND=y CONFIG_XEN_NETDEV_FRONTEND=y +CONFIG_XEN_FRAMEBUFFER=y +CONFIG_XEN_KEYBOARD=y CONFIG_XEN_SCRUB_PAGES=y CONFIG_XEN_DISABLE_SERIAL=y CONFIG_XEN_SYSFS=y From a52cacaef95c4d42492298af9fb5281e6939e55c Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Mon, 4 Dec 2006 09:29:26 +0000 Subject: [PATCH 02/12] [QEMU] Error reporting in IDE device model. Following on from my patch to make blktap report I/O errors back to guest OS, a similar problem exists in the QEMU codebase. The IDE driver never reports I/O errors during read/write operations back to the guest OS. Instead all I/O operations are reported as succesfull. If, for example, the host FS holding the disk image fills up, then writes may fail due to lack of space. Since the guest OS never sees these failures, it assumes all is well & will continue writing. Eventually this can lead to severe & unrecoverable filesystem corruption. The attached patch fixes QEMU ide driver such that any failure of a read or write operation sets the appropriate IDE status/error registers. Having read the ATA-6 spec I think the most compliant behaviour is to set the status register to 'READY_STAT | ERR_STAT', and the error register to ABRT_ERR. There is already a convenience function ide_abort_command() in the QEMU codebase which does just this, so the attached patch simply calls that function. With this patch the guest OS sees the I/O failure & the kernel logs IDE errors and then retries the operation. This at least ensures that the guest can be shutdown the out of space issue in the host corrected and the guest restarted, without any serious filesystem damage having occurred. From: Daniel Berrange Signed-off-by: Keir Fraser --- tools/ioemu/hw/ide.c | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/tools/ioemu/hw/ide.c b/tools/ioemu/hw/ide.c index 94d5beaad5..532afbbffd 100644 --- a/tools/ioemu/hw/ide.c +++ b/tools/ioemu/hw/ide.c @@ -680,7 +680,7 @@ static void ide_set_sector(IDEState *s, int64_t sector_num) static void ide_sector_read(IDEState *s) { int64_t sector_num; - int ret, n; + int n; s->status = READY_STAT | SEEK_STAT; s->error = 0; /* not needed by IDE spec, but needed by Windows */ @@ -695,7 +695,11 @@ static void ide_sector_read(IDEState *s) #endif if (n > s->req_nb_sectors) n = s->req_nb_sectors; - ret = bdrv_read(s->bs, sector_num, s->io_buffer, n); + if (bdrv_read(s->bs, sector_num, s->io_buffer, n) != 0) { + ide_abort_command(s); + ide_set_irq(s); + return; + } ide_transfer_start(s, s->io_buffer, 512 * n, ide_sector_read); ide_set_irq(s); ide_set_sector(s, sector_num + n); @@ -721,7 +725,11 @@ static int ide_read_dma_cb(IDEState *s, if (n > MAX_MULT_SECTORS) n = MAX_MULT_SECTORS; sector_num = ide_get_sector(s); - bdrv_read(s->bs, sector_num, s->io_buffer, n); + if (bdrv_read(s->bs, sector_num, s->io_buffer, n) != 0) { + ide_abort_command(s); + ide_set_irq(s); + return 0; + } s->io_buffer_index = 0; s->io_buffer_size = n * 512; len = s->io_buffer_size; @@ -767,7 +775,7 @@ static void ide_sector_write_timer_cb(void *opaque) static void ide_sector_write(IDEState *s) { int64_t sector_num; - int ret, n, n1; + int n, n1; s->status = READY_STAT | SEEK_STAT; sector_num = ide_get_sector(s); @@ -777,7 +785,11 @@ static void ide_sector_write(IDEState *s) n = s->nsector; if (n > s->req_nb_sectors) n = s->req_nb_sectors; - ret = bdrv_write(s->bs, sector_num, s->io_buffer, n); + if (bdrv_write(s->bs, sector_num, s->io_buffer, n) != 0) { + ide_abort_command(s); + ide_set_irq(s); + return; + } s->nsector -= n; if (s->nsector == 0) { /* no more sector to write */ @@ -823,8 +835,13 @@ static int ide_write_dma_cb(IDEState *s, if (len == 0) { n = s->io_buffer_size >> 9; sector_num = ide_get_sector(s); - bdrv_write(s->bs, sector_num, s->io_buffer, - s->io_buffer_size >> 9); + if (bdrv_write(s->bs, sector_num, s->io_buffer, + s->io_buffer_size >> 9) != 0) { + ide_abort_command(s); + ide_set_irq(s); + return 0; + } + sector_num += n; ide_set_sector(s, sector_num); s->nsector -= n; From 78bc404b6b298e69910b4eefcad0aa50595d6023 Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Mon, 4 Dec 2006 10:20:56 +0000 Subject: [PATCH 03/12] With PERMISSIVE turned on, diagnose missing Enums and Bools, and improve the diagnosis of missing structure values. Signed-off-by: Ewan Mellor --- tools/libxen/src/xen_common.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/tools/libxen/src/xen_common.c b/tools/libxen/src/xen_common.c index 50b8e377e0..ea0909d1a4 100644 --- a/tools/libxen/src/xen_common.c +++ b/tools/libxen/src/xen_common.c @@ -518,8 +518,14 @@ static void parse_into(xen_session *s, xmlNode *value_node, xmlChar *string = string_from_value(value_node, "string"); if (string == NULL) { +#if PERMISSIVE + fprintf(stderr, + "Expected an Enum from the server, but didn't get one\n"); + ((int *)value)[slot] = 0; +#else server_error( s, "Expected an Enum from the server, but didn't get one"); +#endif } else { @@ -567,8 +573,14 @@ static void parse_into(xen_session *s, xmlNode *value_node, xmlChar *string = string_from_value(value_node, "boolean"); if (string == NULL) { +#if PERMISSIVE + fprintf(stderr, + "Expected a Bool from the server, but didn't get one\n"); + ((bool *)value)[slot] = false; +#else server_error( s, "Expected a Bool from the server, but didn't get one"); +#endif } else { @@ -764,7 +776,6 @@ static void parse_into(xen_session *s, xmlNode *value_node, cur = cur->next; } -#if !PERMISSIVE /* Check that we've filled all fields. */ for (size_t i = 0; i < member_count; i++) { @@ -781,15 +792,20 @@ static void parse_into(xen_session *s, xmlNode *value_node, if (j == seen_count) { +#if PERMISSIVE + fprintf(stderr, + "Struct did not contain expected field %s.\n", + mem->key); +#else server_error_2(s, "Struct did not contain expected field", mem->key); free(result); free(checklist); return; +#endif } } -#endif free(checklist); ((void **)value)[slot] = result; From 3dca64847830af9a0a3bd74cdc869b6f2e402523 Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Mon, 4 Dec 2006 10:24:54 +0000 Subject: [PATCH 04/12] More capitalisation fixes. Signed-off-by: Ewan Mellor --- tools/libxen/src/xen_vm.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/tools/libxen/src/xen_vm.c b/tools/libxen/src/xen_vm.c index aac8d4006d..9743222c02 100644 --- a/tools/libxen/src/xen_vm.c +++ b/tools/libxen/src/xen_vm.c @@ -85,28 +85,28 @@ static const struct_member xen_vm_record_struct_members[] = { .key = "memory_static_min", .type = &abstract_type_int, .offset = offsetof(xen_vm_record, memory_static_min) }, - { .key = "vcpus_policy", + { .key = "VCPUs_policy", .type = &abstract_type_string, .offset = offsetof(xen_vm_record, vcpus_policy) }, - { .key = "vcpus_params", + { .key = "VCPUs_params", .type = &abstract_type_string, .offset = offsetof(xen_vm_record, vcpus_params) }, - { .key = "vcpus_number", + { .key = "VCPUs_number", .type = &abstract_type_int, .offset = offsetof(xen_vm_record, vcpus_number) }, - { .key = "vcpus_utilisation", + { .key = "VCPUs_utilisation", .type = &abstract_type_int_float_map, .offset = offsetof(xen_vm_record, vcpus_utilisation) }, - { .key = "vcpus_features_required", + { .key = "VCPUs_features_required", .type = &xen_cpu_feature_set_abstract_type_, .offset = offsetof(xen_vm_record, vcpus_features_required) }, - { .key = "vcpus_features_can_use", + { .key = "VCPUs_features_can_use", .type = &xen_cpu_feature_set_abstract_type_, .offset = offsetof(xen_vm_record, vcpus_features_can_use) }, - { .key = "vcpus_features_force_on", + { .key = "VCPUs_features_force_on", .type = &xen_cpu_feature_set_abstract_type_, .offset = offsetof(xen_vm_record, vcpus_features_force_on) }, - { .key = "vcpus_features_force_off", + { .key = "VCPUs_features_force_off", .type = &xen_cpu_feature_set_abstract_type_, .offset = offsetof(xen_vm_record, vcpus_features_force_off) }, { .key = "actions_after_shutdown", @@ -1124,7 +1124,7 @@ xen_vm_set_vcpus_policy(xen_session *session, xen_vm vm, char *policy) .u.string_val = policy } }; - xen_call_(session, "VM.set_vcpus_policy", param_values, 2, NULL, NULL); + xen_call_(session, "VM.set_VCPUs_policy", param_values, 2, NULL, NULL); return session->ok; } @@ -1140,7 +1140,7 @@ xen_vm_set_vcpus_params(xen_session *session, xen_vm vm, char *params) .u.string_val = params } }; - xen_call_(session, "VM.set_vcpus_params", param_values, 2, NULL, NULL); + xen_call_(session, "VM.set_VCPUs_params", param_values, 2, NULL, NULL); return session->ok; } @@ -1156,7 +1156,7 @@ xen_vm_set_vcpus_features_force_on(xen_session *session, xen_vm vm, struct xen_c .u.set_val = (arbitrary_set *)force_on } }; - xen_call_(session, "VM.set_vcpus_features_force_on", param_values, 2, NULL, NULL); + xen_call_(session, "VM.set_VCPUs_features_force_on", param_values, 2, NULL, NULL); return session->ok; } @@ -1172,7 +1172,7 @@ xen_vm_set_vcpus_features_force_off(xen_session *session, xen_vm vm, struct xen_ .u.set_val = (arbitrary_set *)force_off } }; - xen_call_(session, "VM.set_vcpus_features_force_off", param_values, 2, NULL, NULL); + xen_call_(session, "VM.set_VCPUs_features_force_off", param_values, 2, NULL, NULL); return session->ok; } From aeb915bbac8121ff17bafe8946b72247a73d1349 Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Mon, 4 Dec 2006 10:27:23 +0000 Subject: [PATCH 05/12] Tidy error message. Signed-off-by: Ewan Mellor --- tools/python/xen/xend/XendDomainInfo.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py index 0aa71fc4e6..5488b17f8f 100644 --- a/tools/python/xen/xend/XendDomainInfo.py +++ b/tools/python/xen/xend/XendDomainInfo.py @@ -1709,8 +1709,10 @@ class XendDomainInfo: dom = XendDomain.instance().domain_lookup_nr(name) if dom and dom.info['uuid'] != self.info['uuid']: - raise VmError("VM name '%s' already exists as domain %s" % - (name, str(dom.domid))) + raise VmError("VM name '%s' already exists%s" % + (name, + dom.domid is not None and + ("as domain %s" % str(dom.domid)) or "")) def update(self, info = None, refresh = True): From d529c3d93bb3e11d25c0d20d1aea5c97cfb1dcf6 Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Mon, 4 Dec 2006 13:37:53 +0000 Subject: [PATCH 06/12] Added rudimentary "xend reload" functionality. This allows you to reconfigure the services offered by Xend, without restarting the daemon itself. Signed-off-by: Ewan Mellor --- tools/examples/init.d/xend | 5 +- tools/misc/xend | 4 +- tools/python/xen/xend/server/SrvDaemon.py | 8 ++ tools/python/xen/xend/server/SrvServer.py | 119 +++++++++++++--------- 4 files changed, 86 insertions(+), 50 deletions(-) diff --git a/tools/examples/init.d/xend b/tools/examples/init.d/xend index 8ad407637c..c12b1a0386 100755 --- a/tools/examples/init.d/xend +++ b/tools/examples/init.d/xend @@ -36,7 +36,10 @@ case "$1" in status) xend status ;; - restart|reload|force-reload) + reload) + xend reload + ;; + restart|force-reload) xend restart await_daemons_up ;; diff --git a/tools/misc/xend b/tools/misc/xend index b0ee27f556..c35fbf00e0 100644 --- a/tools/misc/xend +++ b/tools/misc/xend @@ -109,7 +109,7 @@ def main(): daemon = SrvDaemon.instance() if not sys.argv[1:]: - print 'usage: %s {start|stop|restart}' % sys.argv[0] + print 'usage: %s {start|stop|reload|restart}' % sys.argv[0] elif sys.argv[1] == 'start': if os.uname()[0] != "SunOS": start_xenstored() @@ -123,6 +123,8 @@ def main(): return daemon.start(trace=1) elif sys.argv[1] == 'stop': return daemon.stop() + elif sys.argv[1] == 'reload': + return daemon.reloadConfig() elif sys.argv[1] == 'restart': start_xenstored() start_consoled() diff --git a/tools/python/xen/xend/server/SrvDaemon.py b/tools/python/xen/xend/server/SrvDaemon.py index 35c64869d4..155062a704 100644 --- a/tools/python/xen/xend/server/SrvDaemon.py +++ b/tools/python/xen/xend/server/SrvDaemon.py @@ -60,6 +60,14 @@ class Daemon: return running + def reloadConfig(self): + """ + """ + pid = read_pid(XEND_PID_FILE) + if find_process(pid, XEND_PROCESS_NAME): + os.kill(pid, signal.SIGHUP) + + def status(self): """Returns the status of the xend daemon. The return value is defined by the LSB: diff --git a/tools/python/xen/xend/server/SrvServer.py b/tools/python/xen/xend/server/SrvServer.py index f995a13bf9..1b0ed9c0db 100644 --- a/tools/python/xen/xend/server/SrvServer.py +++ b/tools/python/xen/xend/server/SrvServer.py @@ -65,6 +65,7 @@ class XendServers: def __init__(self): self.servers = [] self.cleaningUp = False + self.reloadingConfig = False def add(self, server): self.servers.append(server) @@ -78,6 +79,11 @@ class XendServers: except: pass + def reloadConfig(self, signum = 0, frame = None): + log.debug("SrvServer.reloadConfig()") + self.reloadingConfig = True + self.cleanup(signum, frame) + def start(self, status): # Running the network script will spawn another process, which takes # the status fd with it unless we set FD_CLOEXEC. Failing to do this @@ -86,61 +92,71 @@ class XendServers: fcntl.fcntl(status, fcntl.F_SETFD, fcntl.FD_CLOEXEC) Vifctl.network('start') - threads = [] - for server in self.servers: - thread = Thread(target=server.run, name=server.__class__.__name__) - if isinstance(server, HttpServer): - thread.setDaemon(True) - thread.start() - threads.append(thread) - - - # check for when all threads have initialized themselves and then - # close the status pipe - - threads_left = True - while threads_left: - threads_left = False - - for server in self.servers: - if not server.ready: - threads_left = True - break - - if threads_left: - time.sleep(.5) - - if status: - status.write('0') - status.close() # Prepare to catch SIGTERM (received when 'xend stop' is executed) # and call each server's cleanup if possible signal.signal(signal.SIGTERM, self.cleanup) + signal.signal(signal.SIGHUP, self.reloadConfig) - # Interruptible Thread.join - Python Bug #1167930 - # Replaces: for t in threads: t.join() - # Reason: The above will cause python signal handlers to be - # blocked so we're not able to catch SIGTERM in any - # way for cleanup - runningThreads = threads - while len(runningThreads) > 0: - try: - for t in threads: - t.join(1.0) - runningThreads = [t for t in threads - if t.isAlive() and not t.isDaemon()] - if self.cleaningUp and len(runningThreads) > 0: - log.debug("Waiting for %s." % - [x.getName() for x in runningThreads]) - except: - pass + while True: + threads = [] + for server in self.servers: + thread = Thread(target=server.run, name=server.__class__.__name__) + if isinstance(server, HttpServer): + thread.setDaemon(True) + thread.start() + threads.append(thread) -def create(): - root = SrvDir() - root.putChild('xend', SrvRoot()) - servers = XendServers() + # check for when all threads have initialized themselves and then + # close the status pipe + + threads_left = True + while threads_left: + threads_left = False + + for server in self.servers: + if not server.ready: + threads_left = True + break + + if threads_left: + time.sleep(.5) + + if status: + status.write('0') + status.close() + status = None + + # Interruptible Thread.join - Python Bug #1167930 + # Replaces: for t in threads: t.join() + # Reason: The above will cause python signal handlers to be + # blocked so we're not able to catch SIGTERM in any + # way for cleanup + runningThreads = threads + while len(runningThreads) > 0: + try: + for t in threads: + t.join(1.0) + runningThreads = [t for t in threads + if t.isAlive() and not t.isDaemon()] + if self.cleaningUp and len(runningThreads) > 0: + log.debug("Waiting for %s." % + [x.getName() for x in runningThreads]) + except: + pass + + if self.reloadingConfig: + log.info("Restarting all servers...") + self.cleaningUp = False + self.reloadingConfig = False + xroot.set_config() + self.servers = [] + _loadConfig(self) + else: + break + +def _loadConfig(servers): if xroot.get_xend_http_server(): servers.add(HttpServer(root, xroot.get_xend_address(), @@ -188,4 +204,11 @@ def create(): if xroot.get_xend_unix_xmlrpc_server(): servers.add(XMLRPCServer(XendAPI.AUTH_PAM)) + + +def create(): + root = SrvDir() + root.putChild('xend', SrvRoot()) + servers = XendServers() + _loadConfig(servers) return servers From bcf6d372d8bb4772e77880d13fb47b6f32c97da1 Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Mon, 4 Dec 2006 13:56:27 +0000 Subject: [PATCH 07/12] Diagnose a failing server, rather than just locking up the whole daemon. Signed-off-by: Ewan Mellor --- tools/python/xen/xend/server/SrvServer.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tools/python/xen/xend/server/SrvServer.py b/tools/python/xen/xend/server/SrvServer.py index 1b0ed9c0db..6bfff3a318 100644 --- a/tools/python/xen/xend/server/SrvServer.py +++ b/tools/python/xen/xend/server/SrvServer.py @@ -111,6 +111,7 @@ class XendServers: # check for when all threads have initialized themselves and then # close the status pipe + retryCount = 0 threads_left = True while threads_left: threads_left = False @@ -122,6 +123,14 @@ class XendServers: if threads_left: time.sleep(.5) + retryCount += 1 + if retryCount > 60: + for server in self.servers: + if not server.ready: + log.error("Server " + + server.__class__.__name__ + + " did not initialise!") + break if status: status.write('0') From 549aad081dd9b21f551edfdd16746de8a67aecf0 Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Mon, 4 Dec 2006 13:57:18 +0000 Subject: [PATCH 08/12] Close the server when instructed, so that we can reload on the same port, and diagnose a server that fails to start. Signed-off-by: Ewan Mellor --- tools/python/xen/xend/server/XMLRPCServer.py | 40 +++++++++++++------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/tools/python/xen/xend/server/XMLRPCServer.py b/tools/python/xen/xend/server/XMLRPCServer.py index 45540995bd..c29b4b6bdd 100644 --- a/tools/python/xen/xend/server/XMLRPCServer.py +++ b/tools/python/xen/xend/server/XMLRPCServer.py @@ -16,6 +16,8 @@ # Copyright (C) 2006 XenSource Ltd. #============================================================================ +import errno +import socket import types import xmlrpclib from xen.util.xmlrpclib2 import UnixXMLRPCServer, TCPXMLRPCServer @@ -105,20 +107,25 @@ class XMLRPCServer: "; authentication has been disabled for this server." or ".") - if self.use_tcp: - log.info("Opening TCP XML-RPC server on %s%d%s", - self.host and '%s:' % self.host or - 'all interfaces, port ', - self.port, authmsg) - self.server = TCPXMLRPCServer((self.host, self.port), - self.hosts_allowed, - logRequests = False) - else: - log.info("Opening Unix domain socket XML-RPC server on %s%s", - self.path, authmsg) - self.server = UnixXMLRPCServer(self.path, self.hosts_allowed, - logRequests = False) - + try: + if self.use_tcp: + log.info("Opening TCP XML-RPC server on %s%d%s", + self.host and '%s:' % self.host or + 'all interfaces, port ', + self.port, authmsg) + self.server = TCPXMLRPCServer((self.host, self.port), + self.hosts_allowed, + logRequests = False) + else: + log.info("Opening Unix domain socket XML-RPC server on %s%s", + self.path, authmsg) + self.server = UnixXMLRPCServer(self.path, self.hosts_allowed, + logRequests = False) + except socket.error, exn: + log.error('Cannot start server: %s!', exn.args[1]) + ready = True + running = False + return # Register Xen API Functions # ------------------------------------------------------------------- @@ -177,6 +184,11 @@ class XMLRPCServer: def cleanup(self): log.debug("XMLRPCServer.cleanup()") + try: + self.server.socket.close() + except Exception, exn: + log.exception(exn) + pass def shutdown(self): self.running = False From 4a0a4459e934bc73e3bce714bfd01c16e90c7ce2 Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Mon, 4 Dec 2006 17:52:33 +0000 Subject: [PATCH 09/12] Fix numpad handling in QEMU's VNC server. The keymaps that we have include information on which keys change depending upon the numlock setting, but this isn't being used. By forcing numlock on and off as necessary, when receiving these keysyms through the VNC connection, we ensure that the server's numlock status is the same as the client's. Signed-off-by: Ewan Mellor --- tools/ioemu/keymaps.c | 63 ++++++++++++++++++++++++++++++++++++++-- tools/ioemu/vnc.c | 32 ++++++++++++++++++++ tools/ioemu/vnc_keysym.h | 14 +++++++++ 3 files changed, 107 insertions(+), 2 deletions(-) diff --git a/tools/ioemu/keymaps.c b/tools/ioemu/keymaps.c index bd893288aa..e7dd4a8b11 100644 --- a/tools/ioemu/keymaps.c +++ b/tools/ioemu/keymaps.c @@ -36,8 +36,10 @@ static int get_keysym(const char *name) #define MAX_EXTRA_COUNT 256 typedef struct { uint16_t keysym2keycode[MAX_NORMAL_KEYCODE]; + int keysym2numlock[MAX_NORMAL_KEYCODE]; struct { int keysym; + int numlock; uint16_t keycode; } keysym2keycode_extra[MAX_EXTRA_COUNT]; int extra_count; @@ -50,6 +52,8 @@ static kbd_layout_t *parse_keyboard_layout(const char *language, char file_name[1024]; char line[1024]; int len; + int *keycode2numlock; + int i; snprintf(file_name, sizeof(file_name), "%s/keymaps/%s", bios_dir, language); @@ -63,6 +67,15 @@ static kbd_layout_t *parse_keyboard_layout(const char *language, "Could not read keymap file: '%s'\n", file_name); return 0; } + + /* Allocate a temporary map tracking which keycodes change when numlock is + set. Keycodes are 16 bit, so 65536 is safe. */ + keycode2numlock = malloc(65536 * sizeof(int)); + if (!keycode2numlock) { + perror("Could not read keymap file"); + return 0; + } + for(;;) { if (fgets(line, 1024, f) == NULL) break; @@ -86,13 +99,19 @@ static kbd_layout_t *parse_keyboard_layout(const char *language, if (keysym == 0) { // fprintf(stderr, "Warning: unknown keysym %s\n", line); } else { - const char *rest = end_of_keysym + 1; - int keycode = strtol(rest, NULL, 0); + char *rest = end_of_keysym + 1; + int keycode = strtol(rest, &rest, 0); + int numlock = (rest != NULL && + strstr(rest, "numlock") != NULL); + + keycode2numlock[keycode] = numlock; + /* if(keycode&0x80) keycode=(keycode<<8)^0x80e0; */ if (keysym < MAX_NORMAL_KEYCODE) { //fprintf(stderr,"Setting keysym %s (%d) to %d\n",line,keysym,keycode); k->keysym2keycode[keysym] = keycode; + k->keysym2numlock[keysym] = numlock; } else { if (k->extra_count >= MAX_EXTRA_COUNT) { fprintf(stderr, @@ -107,6 +126,8 @@ static kbd_layout_t *parse_keyboard_layout(const char *language, keysym = keysym; k->keysym2keycode_extra[k->extra_count]. keycode = keycode; + k->keysym2keycode_extra[k->extra_count]. + numlock = numlock; k->extra_count++; } } @@ -115,6 +136,22 @@ static kbd_layout_t *parse_keyboard_layout(const char *language, } } fclose(f); + + for (int i = 0; i < MAX_NORMAL_KEYCODE; i++) { + if (k->keysym2numlock[i] != 1) { + k->keysym2numlock[i] = -keycode2numlock[k->keysym2keycode[i]]; + } + } + + for (int i = 0; i < k->extra_count; i++) { + if (k->keysym2keycode_extra[i].numlock != 1) { + k->keysym2keycode_extra[i].numlock = + -keycode2numlock[k->keysym2keycode_extra[i].keycode]; + } + } + + free(keycode2numlock); + return k; } @@ -143,3 +180,25 @@ static int keysym2scancode(void *kbd_layout, int keysym) } return 0; } + +/** + * Returns 1 if the given keysym requires numlock to be pressed, -1 if it + * requires it to be cleared, and 0 otherwise. + */ +static int keysym2numlock(void *kbd_layout, int keysym) +{ + kbd_layout_t *k = kbd_layout; + if (keysym < MAX_NORMAL_KEYCODE) { + return k->keysym2numlock[keysym]; + } else { + int i; +#ifdef XK_ISO_Left_Tab + if (keysym == XK_ISO_Left_Tab) + keysym = XK_Tab; +#endif + for (i = 0; i < k->extra_count; i++) + if (k->keysym2keycode_extra[i].keysym == keysym) + return k->keysym2keycode_extra[i].numlock; + } + return 0; +} diff --git a/tools/ioemu/vnc.c b/tools/ioemu/vnc.c index 86d3720f90..6d7cc31d4a 100644 --- a/tools/ioemu/vnc.c +++ b/tools/ioemu/vnc.c @@ -115,6 +115,7 @@ struct VncState int ctl_keys; /* Ctrl+Alt starts calibration */ int shift_keys; /* Shift / CapsLock keys */ + int numlock; }; #define DIRTY_PIXEL_BITS 64 @@ -854,14 +855,40 @@ static void pointer_event(VncState *vs, int button_mask, int x, int y) } } +static void press_key(VncState *vs, int keycode) +{ + kbd_put_keycode(keysym2scancode(vs->kbd_layout, keycode) & 0x7f); + kbd_put_keycode(keysym2scancode(vs->kbd_layout, keycode) | 0x80); +} + static void do_key_event(VncState *vs, int down, uint32_t sym) { sym &= 0xFFFF; if (is_graphic_console()) { int keycode; + int numlock; keycode = keysym2scancode(vs->kbd_layout, sym); + numlock = keysym2numlock(vs->kbd_layout, sym); + + /* If the numlock state needs to change then simulate an additional + keypress before sending this one. This will happen if the user + toggles numlock away from the VNC window. + */ + if (numlock == 1) { + if (!vs->numlock) { + vs->numlock = 1; + press_key(vs, XK_Num_Lock); + } + } + else if (numlock == -1) { + if (vs->numlock) { + vs->numlock = 0; + press_key(vs, XK_Num_Lock); + } + } + if (keycode & 0x80) kbd_put_keycode(0xe0); if (down) @@ -932,6 +959,10 @@ static void do_key_event(VncState *vs, int down, uint32_t sym) vs->shift_keys ^= 2; break; + case XK_Num_Lock: + vs->numlock = !vs->numlock; + break; + case XK_1 ... XK_9: if ((vs->ctl_keys & 3) != 3) break; @@ -1355,6 +1386,7 @@ int vnc_display_init(DisplayState *ds, int display, int find_unused, struct sock vs->lsock = -1; vs->csock = -1; vs->depth = 4; + vs->numlock = 0; vs->ds = ds; diff --git a/tools/ioemu/vnc_keysym.h b/tools/ioemu/vnc_keysym.h index 14fe47f9e1..5c47104442 100644 --- a/tools/ioemu/vnc_keysym.h +++ b/tools/ioemu/vnc_keysym.h @@ -231,6 +231,19 @@ static name2keysym_t name2keysym[]={ {"Home", 0xff50}, /* XK_Home */ {"End", 0xff57}, /* XK_End */ {"Scroll_Lock", 0xff14}, /* XK_Scroll_Lock */ +{"KP_Home", 0xff95}, +{"KP_Left", 0xff96}, +{"KP_Up", 0xff97}, +{"KP_Right", 0xff98}, +{"KP_Down", 0xff99}, +{"KP_Prior", 0xff9a}, +{"KP_Page_Up", 0xff9a}, +{"KP_Next", 0xff9b}, +{"KP_Page_Down", 0xff9b}, +{"KP_End", 0xff9c}, +{"KP_Begin", 0xff9d}, +{"KP_Insert", 0xff9e}, +{"KP_Delete", 0xff9f}, {"F1", 0xffbe}, /* XK_F1 */ {"F2", 0xffbf}, /* XK_F2 */ {"F3", 0xffc0}, /* XK_F3 */ @@ -258,6 +271,7 @@ static name2keysym_t name2keysym[]={ {"KP_8", 0xffb8}, /* XK_KP_8 */ {"KP_9", 0xffb9}, /* XK_KP_9 */ {"KP_Add", 0xffab}, /* XK_KP_Add */ +{"KP_Separator", 0xffac},/* XK_KP_Separator */ {"KP_Decimal", 0xffae}, /* XK_KP_Decimal */ {"KP_Divide", 0xffaf}, /* XK_KP_Divide */ {"KP_Enter", 0xff8d}, /* XK_KP_Enter */ From bb34321ece2d83d8b9b76cf3898ed1e0bf5fc8c2 Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Mon, 4 Dec 2006 18:05:32 +0000 Subject: [PATCH 10/12] Tidy. Signed-off-by: Ewan Mellor --- tools/ioemu/keymaps.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/ioemu/keymaps.c b/tools/ioemu/keymaps.c index e7dd4a8b11..b86ab2a0b0 100644 --- a/tools/ioemu/keymaps.c +++ b/tools/ioemu/keymaps.c @@ -137,13 +137,13 @@ static kbd_layout_t *parse_keyboard_layout(const char *language, } fclose(f); - for (int i = 0; i < MAX_NORMAL_KEYCODE; i++) { + for (i = 0; i < MAX_NORMAL_KEYCODE; i++) { if (k->keysym2numlock[i] != 1) { k->keysym2numlock[i] = -keycode2numlock[k->keysym2keycode[i]]; } } - for (int i = 0; i < k->extra_count; i++) { + for (i = 0; i < k->extra_count; i++) { if (k->keysym2keycode_extra[i].numlock != 1) { k->keysym2keycode_extra[i].numlock = -keycode2numlock[k->keysym2keycode_extra[i].keycode]; From 89ebc69e6a6a0ee090c1e04c8a704a1b2ce16eb1 Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Mon, 4 Dec 2006 19:13:55 +0000 Subject: [PATCH 11/12] This adds a recently added parameter to the vm.start call. Signed-off-by: Stefan Berger --- tools/xm-test/lib/XmTestLib/XenManagedDomain.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/xm-test/lib/XmTestLib/XenManagedDomain.py b/tools/xm-test/lib/XmTestLib/XenManagedDomain.py index 94fbe44d3e..1b211fe016 100644 --- a/tools/xm-test/lib/XmTestLib/XenManagedDomain.py +++ b/tools/xm-test/lib/XmTestLib/XenManagedDomain.py @@ -94,12 +94,13 @@ class XenManagedDomain(XenDomain): #Only support PV for now. self.type = "PV" - def start(self, noConsole=False): + def start(self, noConsole=False, startpaused=False): #start the VM server = self.server if self.vm_uuid: try: - xapi.execute(server.VM.start, self.session, self.vm_uuid) + xapi.execute(server.VM.start, self.session, self.vm_uuid, + startpaused) except: raise DomainError("Could not start domain") else: From e65d392f390523b99285af9dbcf31e25027f832a Mon Sep 17 00:00:00 2001 From: Tim Deegan Date: Tue, 5 Dec 2006 12:42:29 +0000 Subject: [PATCH 12/12] [XEN] sh_gfn_to_mfn_foreign() must handle guest pfns above 4GB on PAE Signed-off-by: Tim Deegan --- xen/arch/x86/mm/shadow/common.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/xen/arch/x86/mm/shadow/common.c b/xen/arch/x86/mm/shadow/common.c index a109716c9f..1f295758d8 100644 --- a/xen/arch/x86/mm/shadow/common.c +++ b/xen/arch/x86/mm/shadow/common.c @@ -1246,7 +1246,7 @@ sh_gfn_to_mfn_foreign(struct domain *d, unsigned long gpfn) /* Read another domain's p2m entries */ { mfn_t mfn; - unsigned long addr = gpfn << PAGE_SHIFT; + paddr_t addr = ((paddr_t)gpfn) << PAGE_SHIFT; l2_pgentry_t *l2e; l1_pgentry_t *l1e; @@ -1274,7 +1274,16 @@ sh_gfn_to_mfn_foreign(struct domain *d, unsigned long gpfn) #if CONFIG_PAGING_LEVELS >= 3 { l3_pgentry_t *l3e = sh_map_domain_page(mfn); - l3e += l3_table_offset(addr); +#if CONFIG_PAGING_LEVELS == 3 + /* On PAE hosts the p2m has eight l3 entries, not four (see + * shadow_set_p2m_entry()) so we can't use l3_table_offset. + * Instead, just count the number of l3es from zero. It's safe + * to do this because we already checked that the gfn is within + * the bounds of the p2m. */ + l3e += (((addr) & VADDR_MASK) >> L3_PAGETABLE_SHIFT); +#else + l3e += l3_table_offset(addr); +#endif if ( (l3e_get_flags(*l3e) & _PAGE_PRESENT) == 0 ) { sh_unmap_domain_page(l3e);