From 9ca313aa0824f2d350a7a6c9b1ef6c47e0408f1d Mon Sep 17 00:00:00 2001 From: aliguori Date: Sat, 23 Aug 2008 23:27:37 +0000 Subject: [PATCH] VNC: Support for ExtendedKeyEvent client message This patch adds support for the ExtendedKeyEvent client message. This message allows a client to send raw scan codes directly to the server. If the client and server are using the same keymap, then it's unnecessary to use the '-k' option with QEMU when this extension is supported. This is extension is currently only implemented by gtk-vnc based clients (gvncviewer, virt-manager, vinagre, etc.). Signed-off-by: Anthony Liguori git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@5076 c046a42c-6fe2-441c-8c8c-71466251a162 --- vnc.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 files changed, 50 insertions(+), 9 deletions(-) Index: xen-4.3.0-testing/tools/qemu-xen-traditional-dir-remote/vnc.c =================================================================== --- xen-4.3.0-testing.orig/tools/qemu-xen-traditional-dir-remote/vnc.c +++ xen-4.3.0-testing/tools/qemu-xen-traditional-dir-remote/vnc.c @@ -1285,35 +1285,22 @@ static void press_key_altgr_down(VncStat } } -static void do_key_event(VncState *vs, int down, uint32_t sym) +static void do_key_event(VncState *vs, int down, int keycode, int sym, int shift) { - int keycode; int shift_keys = 0; - int shift = 0; int keypad = 0; int altgr = 0; int altgr_keys = 0; if (is_graphic_console()) { - if (sym >= 'A' && sym <= 'Z') { - sym = sym - 'A' + 'a'; - shift = 1; - } - else { + if (!shift) shift = keysym_is_shift(vs->kbd_layout, sym & 0xFFFF); - } altgr = keysym_is_altgr(vs->kbd_layout, sym & 0xFFFF); } shift_keys = vs->modifiers_state[0x2a] | vs->modifiers_state[0x36]; altgr_keys = vs->modifiers_state[0xb8]; - keycode = keysym2scancode(vs->kbd_layout, sym & 0xFFFF); - if (keycode == 0) { - fprintf(stderr, "Key lost : keysym=0x%x(%d)\n", sym, sym); - return; - } - /* QEMU console switch */ switch(keycode) { case 0x2a: /* Left Shift */ @@ -1342,6 +1329,11 @@ static void do_key_event(VncState *vs, i } break; case 0x3a: /* CapsLock */ + if(!down){ + vs->modifiers_state[keycode] ^= 1; + kbd_put_keycode(keycode | 0x80); + } + return; case 0x45: /* NumLock */ if (down) { kbd_put_keycode(keycode & 0x7f); @@ -1445,7 +1437,28 @@ static void do_key_event(VncState *vs, i static void key_event(VncState *vs, int down, uint32_t sym) { - do_key_event(vs, down, sym); + int keycode; + int shift = 0; + + if ( sym == 0xffea && keyboard_layout && !strcmp(keyboard_layout,"es") ) + sym = 0xffe9; + + if (sym >= 'A' && sym <= 'Z' && is_graphic_console()) { + sym = sym - 'A' + 'a'; + shift = 1; + } + keycode = keysym2scancode(vs->kbd_layout, sym & 0xFFFF); + do_key_event(vs, down, keycode, sym, shift); +} + +static void ext_key_event(VncState *vs, int down, + uint32_t sym, uint16_t keycode) +{ + /* if the user specifies a keyboard layout, always use it */ + if (keyboard_layout) + key_event(vs, down, sym); + else + do_key_event(vs, down, keycode, sym, 0); } static void framebuffer_set_updated(VncState *vs, int x, int y, int w, int h) @@ -1534,6 +1547,15 @@ static void framebuffer_update_request(V qemu_mod_timer(vs->timer, qemu_get_clock(rt_clock)); } +static void send_ext_key_event_ack(VncState *vs) +{ + vnc_write_u8(vs, 0); + vnc_write_u8(vs, 0); + vnc_write_u16(vs, 1); + vnc_framebuffer_update(vs, 0, 0, ds_get_width(vs->ds), ds_get_height(vs->ds), -258); + vnc_flush(vs); +} + static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings) { int i; @@ -1562,6 +1584,9 @@ static void set_encodings(VncState *vs, case -257: vs->has_pointer_type_change = 1; break; + case -258: + send_ext_key_event_ack(vs); + break; case 0x574D5669: vs->has_WMVi = 1; default: @@ -1734,6 +1759,25 @@ static int protocol_client_msg(VncState } set_encodings(vs, (int32_t *)(data + 4), limit); + + /* + * The initialization of a VNC connection can race with xenfb changing + * the resolution. This happens when the VNC connection is already + * established, but the client has not yet advertised has_resize, so it + * won't get notified of the switch. + * + * Therefore we resend the resolution as soon as the client has sent its + * encodings. + */ + if (vs->has_resize) { + /* Resize the VNC window */ + vnc_write_u8(vs, 0); /* msg id */ + vnc_write_u8(vs, 0); + vnc_write_u16(vs, 1); /* number of rects */ + vnc_framebuffer_update(vs, 0, 0, vs->serverds.width, vs->serverds.height, -223); + + vnc_flush(vs); + } break; case 3: if (len == 1) @@ -1774,6 +1818,24 @@ static int protocol_client_msg(VncState client_cut_text(vs, read_u32(data, 4), (char *)(data + 8)); break; + case 255: + if (len == 1) + return 2; + + switch (read_u8(data, 1)) { + case 0: + if (len == 2) + return 12; + + ext_key_event(vs, read_u16(data, 2), + read_u32(data, 4), read_u32(data, 8)); + break; + default: + printf("Msg: %d\n", read_u16(data, 0)); + vnc_client_error(vs); + break; + } + break; default: printf("Msg: %d\n", data[0]); vnc_client_error(vs); @@ -2445,10 +2507,11 @@ void vnc_display_init(DisplayState *ds) vs->ds = ds; - if (!keyboard_layout) - keyboard_layout = "en-us"; + if (keyboard_layout) + vs->kbd_layout = init_keyboard_layout(keyboard_layout); + else + vs->kbd_layout = init_keyboard_layout("en-us"); - vs->kbd_layout = init_keyboard_layout(keyboard_layout); if (!vs->kbd_layout) exit(1); vs->modifiers_state[0x45] = 1; /* NumLock on - on boot */ @@ -2564,6 +2627,7 @@ int vnc_display_password(DisplayState *d if (password && password[0]) { if (!(vs->password = qemu_strdup(password))) return -1; + vs->auth = VNC_AUTH_VNC; } return 0; Index: xen-4.3.0-testing/tools/hotplug/Linux/init.d/sysconfig.xendomains =================================================================== --- xen-4.3.0-testing.orig/tools/hotplug/Linux/init.d/sysconfig.xendomains +++ xen-4.3.0-testing/tools/hotplug/Linux/init.d/sysconfig.xendomains @@ -98,7 +98,6 @@ XENDOMAINS_RESTORE=true # Note that the script tries to be clever if both RESTORE and AUTO are # set: It will first restore saved domains and then only start domains # in AUTO which are not running yet. -# Note that the name matching is somewhat fuzzy. # XENDOMAINS_AUTO=/etc/xen/auto Index: xen-4.3.0-testing/tools/examples/xend-config.sxp =================================================================== --- xen-4.3.0-testing.orig/tools/examples/xend-config.sxp +++ xen-4.3.0-testing/tools/examples/xend-config.sxp @@ -58,11 +58,12 @@ #(xend-http-server no) -#(xend-unix-server no) +(xend-unix-server yes) #(xend-tcp-xmlrpc-server no) #(xend-unix-xmlrpc-server yes) +# Only enable xend-relocation-server on trusted networks as it lacks +# encryption and authentication. #(xend-relocation-server no) -(xend-relocation-server yes) #(xend-relocation-ssl-server no) #(xend-udev-event-server no) @@ -170,7 +171,12 @@ # two fake interfaces per guest domain. To do things like this, write # yourself a wrapper script, and call network-bridge from it, as appropriate. # -(network-script network-bridge) +# SuSE users note: +# On openSUSE >= 11.1 and SLES >= 11, networks should be configured using +# native platform tool - YaST. vif-bridge and qemu-ifup can be used to +# connect vifs to the YaST-managed networks. +#(network-script network-bridge) +(network-script ) # The script used to control virtual interfaces. This can be overridden on a # per-vif basis when creating a domain or a configuring a new vif. The @@ -194,6 +200,26 @@ #(network-script network-route) #(vif-script vif-route) +# SuSE users note: +# If using a routed network configuration it is advised to NOT use +# network-route and vif-route scripts but instead use sysconfig scripts +# in dom0 and vif-route-ifup script to "connect" the domU vif to dom0. +# Since this configuration requires a vif sysconfig script in dom0, a static +# vif name must be used. E.g. in dom0 the vif sysconfig script +# (/etc/sysconfig/network/ifcfg-xen1.0) may contain +# +# NAME='XEN vm 1 virtual interface 0' +# BOOTPROTO='static' +# STARTMODE='hotplug' +# ... +# +# The corresponding domain vif configuration would contain e.g. +# vif=[ 'mac=00:16:3e:aa:bb:cc,script=vif-route-ifup,vifname=xen1.0', ] +# +# If the vif-route-ifup script will be used for all domains, it can be +# set here as the default vif script, alleviating the need for +# 'script=' in domain vif configuration. +#(vif-script vif-route-ifup) ## Use the following if network traffic is routed with NAT, as an alternative # to the settings for bridged networking given above. @@ -203,7 +229,7 @@ # dom0-min-mem is the lowest permissible memory level (in MB) for dom0. # This is a minimum both for auto-ballooning (as enabled by # enable-dom0-ballooning below) and for xm mem-set when applied to dom0. -(dom0-min-mem 196) +(dom0-min-mem 512) # Whether to enable auto-ballooning of dom0 to allow domUs to be created. # If enable-dom0-ballooning = no, dom0 will never balloon out. @@ -224,6 +250,9 @@ (dom0-cpus 0) # Whether to enable core-dumps when domains crash. +# This setting overrides the per-domain dump value 'on_crash' and causes a +# core dump on all crashed domains. For finer grain control, it is best to +# disable this setting (which is default) and use the per-domain controls. #(enable-dump no) # The tool used for initiating virtual TPM migration @@ -295,6 +324,70 @@ # device assignment could really work properly even after we do this. #(pci-passthrough-strict-check yes) +# Domain Locking +# In a multihost environment, domain locking provides a simple mechanism that +# prevents simultaneously running a domain on more than one host. +# +# If enabled, xend will execute a external lock utility (defined below) +# on each domain start and stop event. Disabled by default. Set to yes +# to enable domain locking. +# +#(xend-domain-lock no) + +# Path where domain lock is stored if xend-domain-lock is enabled. +# Note: This path must be accessible to all VM Servers participating +# in domain locking, e.g. by specifying a shared mount point. +# Lock is placed in //. +# Default is /var/lib/xen/images/vm_locks/ +# +#(xend-domain-lock-path /var/lib/images/vm_locks) + +# External locking utility called by xend for acquiring/releasing +# domain lock. By default /etc/xen/scripts/domain-lock will be used +# if xend-domain-lock is set to yes. Set to path of custom locking +# utility to override the default. +# +# Synopsis of lock-util: +# lock-util [-l|-u] -n -i -p path" +# -l Acquire (create) lock +# -u Remove lock +# -n vm-name Name of domain +# -i vm-id Id or UUID of domain +# -p phy-host Name of physical host (dom0) +# path // +# Return 0 on success, non-zero on error. +# +# lock-util [-s] -i path" +# -s Lock status. If lock is acquired, print any contents +# on stdout and return 0. Return non-zero if lock is +# available. +# path // +# If lock is acquired, print any contents on stdout and return 0. +# Return non-zero if lock is available. +# +# Default lock-util behavior: +# On domain start event, domain-lock will create and flock(1) +# ///lock. Every two seconds it +# will write , , , and to the lock. +# is running counter. +# On domain stop event, domain-lock will unlock and remove +# ///lock. +# +# Note: If xend-domain-lock-path is a cluster-unaware file system, +# administrator intervention may be required to remove stale +# locks. Consider two hosts using NFS for xend-domain-lock-path +# when HostA, running vm1, crashes. HostB could not acquire a +# lock for vm1 since the NFS server holds an exclusive lock +# acquired by HostA. The lock file must be manually removed +# before starting vm1 on HostB. +# +#(xend-domain-lock-utility domain-lock) + +# Some locking mechanism provide cluster wide locking service like sfex. +# And that requires a shared locking device. +#(xend-domain-lock-utility domain-lock-sfex) +#(xend-domain-lock-device "/dev/iwmvg/hbdevice") + # If we have a very big scsi device configuration, start of xend is slow, # because xend scans all the device paths to build its internal PSCSI device # list. If we need only a few devices for assigning to a guest, we can reduce Index: xen-4.3.0-testing/tools/python/xen/xm/create.py =================================================================== --- xen-4.3.0-testing.orig/tools/python/xen/xm/create.py +++ xen-4.3.0-testing/tools/python/xen/xm/create.py @@ -36,7 +36,7 @@ from xen.xend.server.DevConstants import from xen.util import blkif from xen.util import vscsi_util import xen.util.xsm.xsm as security -from xen.xm.main import serverType, SERVER_XEN_API, get_single_vm +from xen.xm.main import serverType, SERVER_XEN_API, SERVER_LEGACY_XMLRPC, get_single_vm from xen.util import utils, auxbin from xen.util.pci import dev_dict_to_sxp, \ parse_pci_name_extended, PciDeviceParseError @@ -73,7 +73,7 @@ gopts.opt('quiet', short='q', use="Quiet.") gopts.opt('path', val='PATH', - fn=set_value, default='.:' + auxbin.xen_configdir(), + fn=set_value, default='.:' + auxbin.xen_configdir() + "/vm", use="Search path for configuration scripts. " "The value of PATH is a colon-separated directory list.") @@ -242,6 +242,10 @@ gopts.var('viridian', val='VIRIDIAN', use="""Expose Viridian interface to x86 HVM guest? (Default is 0).""") +gopts.var('extid', val='EXTID', + fn=set_int, default=0, + use="Specify extention ID for a HVM domain.") + gopts.var('acpi', val='ACPI', fn=set_int, default=1, use="Disable or enable ACPI of HVM domain.") @@ -473,6 +477,26 @@ gopts.var('nfs_root', val="PATH", fn=set_value, default=None, use="Set the path of the root NFS directory.") +gopts.var('smbios_firmware', val='FILE', + fn=set_value, default=None, + use="Path to a file that contains extra SMBIOS firmware structures.") + +gopts.var('acpi_firmware', val='FILE', + fn=set_value, default=None, + use="Path to a file that contains extra ACPI firmware tables.") + +gopts.var('actmem', val='NUM', + fn=set_value, default='0', + use="Number of pages to swap.") + +gopts.var('xenpaging_file', val='PATH', + fn=set_value, default=None, + use="pagefile to use (optional)") + +gopts.var('xenpaging_extra', val='string1,string2', + fn=append_value, default=[], + use="additional args for xenpaging (optional)") + gopts.var('device_model', val='FILE', fn=set_value, default=None, use="Path to device model program.") @@ -517,6 +541,21 @@ gopts.var('usbdevice', val='NAME', fn=set_value, default='', use="Name of USB device to add?") +gopts.var('watchdog', val='NAME', + fn=set_value, default='', + use="Watchdog device to use. May be ib700 or i6300esb") + +gopts.var('watchdog_action', val='reset|shutdown|poweroff|pause|none|dump', + fn=set_value, default="reset", + use="""Action when watchdog timer expires: + - reset: Default, forcefully reset the guest; + - shutdown: Gracefully shutdown the guest (not recommended); + - poweroff: Forcefully power off the guest; + - pause: Pause the guest; + - none: Do nothing; + - dump: Automatically dump the guest; + """) + gopts.var('description', val='NAME', fn=set_value, default='', use="Description of a domain") @@ -1032,7 +1071,11 @@ def configure_hvm(config_image, vals): args = [ 'acpi', 'apic', 'boot', 'cpuid', 'cpuid_check', + 'actmem', + 'xenpaging_file', + 'xenpaging_extra', 'device_model', 'display', + 'smbios_firmware', 'acpi_firmware', 'fda', 'fdb', 'gfx_passthru', 'guest_os_type', 'hap', 'hpet', @@ -1047,7 +1090,8 @@ def configure_hvm(config_image, vals): 'timer_mode', 'usb', 'usbdevice', 'vcpus', 'vnc', 'vncconsole', 'vncdisplay', 'vnclisten', - 'vncunused', 'viridian', 'vpt_align', + 'vncunused', 'vpt_align', + 'watchdog', 'watchdog_action', 'xauthority', 'xen_extended_power_mgmt', 'xen_platform_pci', 'memory_sharing' ] @@ -1056,6 +1100,10 @@ def configure_hvm(config_image, vals): config_image.append([a, vals.__dict__[a]]) if vals.vncpasswd is not None: config_image.append(['vncpasswd', vals.vncpasswd]) + if vals.extid and vals.extid == 1: + config_image.append(['viridian', vals.extid]) + elif vals.viridian: + config_image.append(['viridian', vals.viridian]) def make_config(vals): @@ -1274,9 +1322,8 @@ def preprocess_access_control(vals): def preprocess_ip(vals): if vals.ip or vals.dhcp != 'off': - dummy_nfs_server = '127.0.255.255' ip = (vals.ip - + ':' + (vals.nfs_server or dummy_nfs_server) + + ':' + (vals.nfs_server or '') + ':' + vals.gateway + ':' + vals.netmask + ':' + vals.hostname @@ -1465,7 +1512,7 @@ def main(argv): except IOError, exn: raise OptionError("Cannot read file %s: %s" % (config, exn[1])) - if serverType == SERVER_XEN_API: + if serverType == SERVER_XEN_API or serverType == SERVER_LEGACY_XMLRPC: from xen.xm.xenapi_create import sxp2xml sxp2xml_inst = sxp2xml() doc = sxp2xml_inst.convert_sxp_to_xml(config, transient=True) @@ -1473,7 +1520,7 @@ def main(argv): if opts.vals.dryrun and not opts.is_xml: SXPPrettyPrint.prettyprint(config) - if opts.vals.xmldryrun and serverType == SERVER_XEN_API: + if opts.vals.xmldryrun: print doc.toprettyxml() if opts.vals.dryrun or opts.vals.xmldryrun: Index: xen-4.3.0-testing/docs/man/xm.pod.1 =================================================================== --- xen-4.3.0-testing.orig/docs/man/xm.pod.1 +++ xen-4.3.0-testing/docs/man/xm.pod.1 @@ -79,7 +79,7 @@ in the config file. See L format, and possible options used in either the configfile or for I. I can either be an absolute path to a file, or a relative -path to a file located in /etc/xen. +path to a file located in /etc/xen/vm. Create will return B as the domain is started. This B mean the guest OS in the domain has actually booted, or is @@ -160,7 +160,7 @@ B xm create Fedora4 -This creates a domain with the file /etc/xen/Fedora4, and returns as +This creates a domain with the file /etc/xen/vm/Fedora4, and returns as soon as it is run. =item I @@ -299,7 +299,8 @@ scheduling by the Xen hypervisor. =item B -FIXME: Why would you ever see this state? +The guest has requested to be shutdown, rebooted or suspended, and the +domain is in the process of being destroyed in response. =item B @@ -312,8 +313,6 @@ restart on crash. See L f The domain is in process of dying, but hasn't completely shutdown or crashed. -FIXME: Is this right? - =back B @@ -737,8 +736,6 @@ Xen ships with a number of domain schedu time with the B parameter on the Xen command line. By default B is used for scheduling. -FIXME: we really need a scheduler expert to write up this section. - =over 4 =item B [ B<-d> I [ B<-w>[B<=>I] | B<-c>[B<=>I] ] ] @@ -801,8 +798,6 @@ The normal EDF scheduling usage in nanos The normal EDF scheduling usage in nanoseconds -FIXME: these are lame, should explain more. - =item I Scaled period if domain is doing heavy I/O. @@ -952,9 +947,6 @@ the default setting in xend-config.sxp f Passes the specified IP Address to the adapter on creation. -FIXME: this currently appears to be B. I'm not sure under what -circumstances this should actually work. - =item BI The MAC address that the domain will see on its Ethernet device. If @@ -980,9 +972,6 @@ Removes the network device from the doma I is the virtual interface device number within the domain (i.e. the 3 in vif22.3). -FIXME: this is currently B. Network devices aren't completely -removed from domain 0. - =item B [B<-l>|B<--long>]> I List virtual network interfaces for a domain. The returned output is Index: xen-4.3.0-testing/docs/man/xmdomain.cfg.pod.5 =================================================================== --- xen-4.3.0-testing.orig/docs/man/xmdomain.cfg.pod.5 +++ xen-4.3.0-testing/docs/man/xmdomain.cfg.pod.5 @@ -4,9 +4,9 @@ xmdomain.cfg - xm domain config file for =head1 SYNOPSIS - /etc/xen/myxendomain - /etc/xen/myxendomain2 - /etc/xen/auto/myxenautostarted + /etc/xen/auto/ + /etc/xen/examples/ + /etc/xen/vm/ =head1 DESCRIPTION @@ -14,14 +14,14 @@ The B(1) program uses python executa domains to create from scratch. Each of these config files needs to contain a number of required options, and may specify many more. -Domain configuration files live in /etc/xen by default, if you store +Domain configuration files live in /etc/xen/vm by default. If you store config files anywhere else the full path to the config file must be specified in the I command. /etc/xen/auto is a special case. Domain config files in that directory will be started automatically at system boot if the xendomain init script is enabled. The contents of /etc/xen/auto -should be symlinks to files in /etc/xen to allow I to be +should be symlinks to files in /etc/xen/vm to allow I to be used without full paths. Options are specified by I statements in the @@ -243,6 +243,25 @@ this the xen kernel must be compiled wit This defaults to 1, meaning running the domain as a UP. +=item B + +Specify a path to a file that contains extra ACPI firmware tables to pass in to +a guest. The file can contain several tables in their binary AML form +concatenated together. Each table self describes its length so no additional +information is needed. These tables will be added to the ACPI table set in the +guest. Note that existing tables cannot be overridden by this feature. For +example this cannot be used to override tables like DSDT, FADT, etc. + +=item B + +Specify a path to a file that contains extra SMBIOS firmware structures to pass +in to a guest. The file can contain a set DMTF predefined structures which will +override the internal defaults. Not all predefined structures can be overridden, +only the following types: 0, 1, 2, 3, 11, 22, 39. The file can also contain any +number of vendor defined SMBIOS structures (type 128 - 255). Since SMBIOS +structures do not present their overall size, each entry in the file must be +preceded by a 32b integer indicating the size of the next structure. + =back =head1 DOMAIN SHUTDOWN OPTIONS @@ -333,16 +352,10 @@ at hda1, which is the root filesystem. =item I -FIXME: write me - =item I -FIXME: write me - =item I -FIXME: write me - =back =head1 SEE ALSO Index: xen-4.3.0-testing/tools/python/xen/xend/server/DevController.py =================================================================== --- xen-4.3.0-testing.orig/tools/python/xen/xend/server/DevController.py +++ xen-4.3.0-testing/tools/python/xen/xend/server/DevController.py @@ -149,13 +149,16 @@ class DevController: (status, err) = self.waitForBackend(devid) if status == Timeout: - self.destroyDevice(devid, False) + #Clean timeout backend resource + dev = self.convertToDeviceNumber(devid) + self.writeBackend(dev, HOTPLUG_STATUS_NODE, HOTPLUG_STATUS_ERROR) + self.destroyDevice(devid, True) raise VmError("Device %s (%s) could not be connected. " "Hotplug scripts not working." % (devid, self.deviceClass)) elif status == Error: - self.destroyDevice(devid, False) + self.destroyDevice(devid, True) if err is None: raise VmError("Device %s (%s) could not be connected. " "Backend device not found." % @@ -554,7 +557,17 @@ class DevController: xswatch(statusPath, hotplugStatusCallback, ev, result) - ev.wait(DEVICE_CREATE_TIMEOUT) + for i in range(1, 50): + ev.wait(DEVICE_CREATE_TIMEOUT/50) + status = xstransact.Read(statusPath) + if status is not None: + if status == HOTPLUG_STATUS_ERROR: + result['status'] = Error + elif status == HOTPLUG_STATUS_BUSY: + result['status'] = Busy + else: + result['status'] = Connected + break err = xstransact.Read(backpath, HOTPLUG_ERROR_NODE) @@ -571,7 +584,12 @@ class DevController: xswatch(statusPath, deviceDestroyCallback, ev, result) - ev.wait(DEVICE_DESTROY_TIMEOUT) + for i in range(1, 50): + ev.wait(DEVICE_DESTROY_TIMEOUT/50) + status = xstransact.Read(statusPath) + if status is None: + result['status'] = Disconnected + break return result['status'] @@ -592,6 +610,31 @@ class DevController: return (Missing, None) + def waitForFrontend(self, devid): + def frontendStatusCallback(statusPath, ev, result): + status = xstransact.Read(statusPath) + log.debug("frontendStatusCallback %s = %s" % (statusPath, status)) + try: + status = int(status) + if status == xenbusState['Connected']: + result['status'] = Connected + elif status == xenbusState['Closed']: + result['status'] = Error + else: + raise + except: + return 1 + ev.set() + return 0 + frontpath = self.frontendPath(devid) + statusPath = frontpath + '/state' + ev = Event() + result = { 'status': Timeout } + xswatch(statusPath, frontendStatusCallback, ev, result) + ev.wait(5) + return result['status'] + + def backendPath(self, backdom, devid): """Construct backend path given the backend domain and device id. Index: xen-4.3.0-testing/tools/python/xen/xend/XendBootloader.py =================================================================== --- xen-4.3.0-testing.orig/tools/python/xen/xend/XendBootloader.py +++ xen-4.3.0-testing/tools/python/xen/xend/XendBootloader.py @@ -12,7 +12,7 @@ # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # -import os, select, errno, stat, signal, tty +import os, select, errno, stat, signal, tty, time import random import shlex from xen.xend import sxp @@ -38,8 +38,25 @@ def bootloader(blexec, disk, dom, quiet msg = "Bootloader isn't executable" log.error(msg) raise VmError(msg) - if not os.access(disk, os.R_OK): - msg = "Disk isn't accessible" + + # domUloader requires '--entry=foo' in blargs, which is derived from + # 'bootargs' entry in domain configuration file. Ensure it exists + # here so a reasonable error message can be returned. + if blexec.find('domUloader.py') != -1: + if blargs.find('entry') == -1: + msg = "domUloader requires specification of bootargs" + log.error(msg) + raise VmError(msg) + + avail = False + for i in xrange(1, 500): + avail = os.access(disk, os.R_OK) + if avail: + break + time.sleep(.1) + + if not avail: + msg = "Disk '%s' isn't accessible" % disk log.error(msg) raise VmError(msg) Index: xen-4.3.0-testing/tools/python/xen/xend/XendDomainInfo.py =================================================================== --- xen-4.3.0-testing.orig/tools/python/xen/xend/XendDomainInfo.py +++ xen-4.3.0-testing/tools/python/xen/xend/XendDomainInfo.py @@ -74,7 +74,7 @@ from xen.xend.XendPSCSI import XendPSCSI from xen.xend.XendDSCSI import XendDSCSI, XendDSCSI_HBA MIGRATE_TIMEOUT = 30.0 -BOOTLOADER_LOOPBACK_DEVICE = '/dev/xvdp' +BOOTLOADER_LOOPBACK_DEVICES = ['/dev/xvd' + chr(x) for x in range(ord('z'), ord('d'), -1)] xc = xen.lowlevel.xc.xc() xoptions = XendOptions.instance() @@ -303,7 +303,8 @@ def dom_get(dom): return None from xen.xend.server.pciif import parse_pci_name, PciDevice,\ - get_assigned_pci_devices, get_all_assigned_pci_devices + get_assigned_pci_devices, get_all_assigned_pci_devices,\ + prepare_host_pci_devices, reattach_host_pci_devices def do_FLR(domid, is_hvm): @@ -317,6 +318,20 @@ def do_FLR(domid, is_hvm): "parse it's resources - "+str(e)) dev.do_FLR(is_hvm, xoptions.get_pci_dev_assign_strict_check()) +def prepare_domain_pci_devices(domconfig): + ordered_refs = domconfig.ordered_device_refs() + for dev_uuid in ordered_refs: + devclass, devconfig = domconfig['devices'][dev_uuid] + if devclass == 'pci': + prepare_host_pci_devices(devconfig) + +def reattach_domain_pci_devices(domconfig): + ordered_refs = domconfig.ordered_device_refs() + for dev_uuid in ordered_refs: + devclass, devconfig = domconfig['devices'][dev_uuid] + if devclass == 'pci': + reattach_host_pci_devices(devconfig) + class XendDomainInfo: """An object represents a domain. @@ -470,6 +485,8 @@ class XendDomainInfo: if self._stateGet() in (XEN_API_VM_POWER_STATE_HALTED, XEN_API_VM_POWER_STATE_SUSPENDED, XEN_API_VM_POWER_STATE_CRASHED): try: + prepare_domain_pci_devices(self.info); + self.acquire_running_lock(); XendTask.log_progress(0, 30, self._constructDomain) XendTask.log_progress(31, 60, self._initDomain) @@ -496,6 +513,7 @@ class XendDomainInfo: state = self._stateGet() if state in (DOM_STATE_SUSPENDED, DOM_STATE_HALTED): try: + prepare_domain_pci_devices(self.info) self._constructDomain() try: @@ -712,6 +730,8 @@ class XendDomainInfo: the device. """ + if self.domid is None: + return self.iommu_check_pod_mode() # Test whether the devices can be assigned @@ -851,6 +871,9 @@ class XendDomainInfo: if self.domid is not None: try: + if dev_type == 'pci': + prepare_host_pci_devices(dev_config_dict) + dev_config_dict['devid'] = devid = \ self._createDevice(dev_type, dev_config_dict) if dev_type == 'tap2': @@ -864,6 +887,7 @@ class XendDomainInfo: if dev_type == 'pci': for dev in dev_config_dict['devs']: XendAPIStore.deregister(dev['uuid'], 'DPCI') + reattach_host_pci_devices(dev_config_dict) elif dev_type == 'vscsi': for dev in dev_config_dict['devs']: XendAPIStore.deregister(dev['uuid'], 'DSCSI') @@ -908,6 +932,10 @@ class XendDomainInfo: dev_config = pci_convert_sxp_to_dict(dev_sxp) dev = dev_config['devs'][0] + # For attach only. For boot, prepare work has been done already in earlier stage. + if self.domid is not None and pci_state == 'Initialising' and pci_sub_state != 'Booting': + prepare_host_pci_devices(dev_config) + stubdomid = self.getStubdomDomid() # Do HVM specific processing if self.info.is_hvm(): @@ -984,6 +1012,9 @@ class XendDomainInfo: new_dev_sxp = dev_control.configuration(devid) self.info.device_update(dev_uuid, new_dev_sxp) + if pci_state == 'Closing': + reattach_host_pci_devices(dev_config) + # If there is no device left, destroy pci and remove config. if num_devs == 0: if self.info.is_hvm(): @@ -1203,6 +1234,9 @@ class XendDomainInfo: except ValueError: pass devid = dev_control.convertToDeviceNumber(dev) + else: + # devid could be a name, e.g. hdc + devid = dev_control.convertToDeviceNumber(devid) dev_info = self._getDeviceInfo_vbd(devid) if dev_info is None: raise VmError("Device %s not connected" % devid) @@ -1295,8 +1329,15 @@ class XendDomainInfo: frontpath = self.getDeviceController(deviceClass).frontendPath(dev) backpath = xstransact.Read(frontpath, "backend") thread.start_new_thread(self.getDeviceController(deviceClass).finishDeviceCleanup, (backpath, path)) - - rc = self.getDeviceController(deviceClass).destroyDevice(devid, force) + if deviceClass =='vusb': + dev = self.getDeviceController(deviceClass).convertToDeviceNumber(devid) + state = self.getDeviceController(deviceClass).readBackend(dev, 'state') + if state == '1': + rc = self.getDeviceController(deviceClass).destroyDevice(devid, True) + else: + rc = self.getDeviceController(deviceClass).destroyDevice(devid, force) + else: + rc = self.getDeviceController(deviceClass).destroyDevice(devid, force) if not force and rm_cfg: # The backend path, other than the device itself, # has to be passed because its accompanied frontend @@ -1459,6 +1500,52 @@ class XendDomainInfo: pci_conf = self.info['devices'][dev_uuid][1] return map(pci_dict_to_bdf_str, pci_conf['devs']) + def capAndSetMemoryTarget(self, target): + """Potentially lowers the requested target to the largest possible + value (i.e., caps it), and then sets the memory target of this domain + to that value. + @param target in MiB. + """ + max_target = 0 + if self.domid == 0: + try: + from balloon import get_dom0_max_target + max_target = get_dom0_max_target() / 1024 + except: + # It's nice to cap the max at sane values, but harmless to set + # them high. Carry on. + pass + if max_target and target > max_target: + log.debug("Requested memory target %d MiB; maximum reasonable is %d MiB.", + target, max_target) + target = max_target + self.setMemoryTarget(target) + + def chgvncpasswd(self, passwd): + if self._stateGet() != DOM_STATE_HALTED: + path = '/local/domain/0/backend/vfb/%u/0/' % self.getDomid() + xstransact.Write(path, 'vncpasswd', passwd) + self.image.signalDeviceModel("chgvncpasswd", "vncpasswdchged") + + for dev_uuid, (dev_type, dev_info) in self.info['devices'].items(): + if dev_type == 'vfb': + dev_info['vncpasswd'] = passwd + dev_info['other_config']['vncpasswd'] = passwd + self.info.device_update(dev_uuid, cfg_xenapi = dev_info) + break + xen.xend.XendDomain.instance().managed_config_save(self) + + def setSwapTarget(self, target): + """Set the swap target of this domain. + @param target: In MiB. + """ + log.debug("Setting swap target of domain %s (%s) to %d MiB.", + self.info['name_label'], str(self.domid), target) + + if self.domid > 0: + self.storeDom("memory/target-tot_pages", target * 1024) + self.info['platform']['actmem'] = str(target) + def setMemoryTarget(self, target): """Set the memory target of this domain. @param target: In MiB. @@ -1923,6 +2010,8 @@ class XendDomainInfo: self.info['name_label'] = name if to_store: self.storeVm("name", name) + if self.dompath: + self.storeDom("name", name) def getName(self): return self.info['name_label'] @@ -2247,6 +2336,8 @@ class XendDomainInfo: self.info['name_label'], self.domid, self.info['uuid'], new_name, new_uuid) self._unwatchVm() + if self.image: + self.image.destroyXenPaging() self._releaseDevices() # Remove existing vm node in xenstore self._removeVm() @@ -2283,7 +2374,7 @@ class XendDomainInfo: # To prohibit directory traversal based_name = os.path.basename(self.info['name_label']) - coredir = "/var/xen/dump/%s" % (based_name) + coredir = "/var/lib/xen/dump/%s" % (based_name) if not os.path.exists(coredir): try: mkdir.parents(coredir, stat.S_IRWXU) @@ -2333,6 +2424,10 @@ class XendDomainInfo: deviceClass, config = self.info['devices'].get(dev_uuid) self._waitForDevice(deviceClass, config['devid']) + def _waitForDeviceFrontUUID(self, dev_uuid): + deviceClass, config = self.info['devices'].get(dev_uuid) + self.getDeviceController(deviceClass).waitForFrontend(config['devid']) + def _waitForDevice_destroy(self, deviceClass, devid, backpath): return self.getDeviceController(deviceClass).waitForDevice_destroy( devid, backpath) @@ -2734,7 +2829,10 @@ class XendDomainInfo: from xen.xend import XendDomain doms = XendDomain.instance().list('all') for dom in filter (lambda d: d.domid != self.domid, doms): - cpuinfo = dom.getVCPUInfo() + try: + cpuinfo = dom.getVCPUInfo() + except: + continue for vcpu in sxp.children(cpuinfo, 'vcpu'): if sxp.child_value(vcpu, 'online') == 0: continue cpumap = list(sxp.child_value(vcpu,'cpumap')) @@ -2884,7 +2982,7 @@ class XendDomainInfo: self.guest_bitsize = self.image.getBitSize() # Make sure there's enough RAM available for the domain - balloon.free(memory + shadow + vtd_mem, self) + balloon.free(memory + shadow + vtd_mem + 512, self) # Set up the shadow memory shadow_cur = xc.shadow_mem_control(self.domid, shadow / 1024) @@ -2919,6 +3017,9 @@ class XendDomainInfo: self._createDevices() + if self.image: + self.image.createXenPaging() + self.image.cleanupTmpImages() self.info['start_time'] = time.time() @@ -2943,6 +3044,8 @@ class XendDomainInfo: self.refresh_shutdown_lock.acquire() try: self.unwatchShutdown() + if self.image: + self.image.destroyXenPaging() self._releaseDevices() bootloader_tidy(self) @@ -2956,6 +3059,11 @@ class XendDomainInfo: self._stateSet(DOM_STATE_HALTED) self.domid = None # Do not push into _stateSet()! + + try: + self.release_running_lock() + except: + log.exception("Failed to release domain lock.") finally: self.refresh_shutdown_lock.release() @@ -3011,7 +3119,7 @@ class XendDomainInfo: # TODO: recategorise - called from XendCheckpoint # - def completeRestore(self, store_mfn, console_mfn): + def completeRestore(self, store_mfn, console_mfn, console_port): log.debug("XendDomainInfo.completeRestore") @@ -3022,6 +3130,8 @@ class XendDomainInfo: self.image = image.create(self, self.info) if self.image: self.image.createDeviceModel(True) + self.image.createXenPaging() + self.console_port = console_port self._storeDomDetails() self._registerWatches() self.refreshShutdown() @@ -3099,9 +3209,15 @@ class XendDomainInfo: log.debug("%s KiB need to add to Memory pool" %self.alloc_mem) MemoryPool.instance().increase_memory(self.alloc_mem) + reattach_domain_pci_devices(self.info) self._cleanup_phantom_devs(paths) self._cleanupVm() + if "change_home_server" in self.info: + chs = self.info["change_home_server"] + if (type(chs) is str and chs == "False") or \ + (type(chs) is bool and chs is False): + self.setChangeHomeServer(None) if ("transient" in self.info["other_config"] and \ bool(self.info["other_config"]["transient"])) or \ ("change_home_server" in self.info and \ @@ -3157,6 +3273,8 @@ class XendDomainInfo: # could also fetch a parsed note from xenstore fast = self.info.get_notes().get('SUSPEND_CANCEL') and 1 or 0 if not fast: + if self.image: + self.image.destroyXenPaging() self._releaseDevices() self.testDeviceComplete() self.testvifsComplete() @@ -3172,6 +3290,8 @@ class XendDomainInfo: self._storeDomDetails() self._createDevices() + if self.image: + self.image.createXenPaging() log.debug("XendDomainInfo.resumeDomain: devices created") xc.domain_resume(self.domid, fast) @@ -3271,32 +3391,38 @@ class XendDomainInfo: # This is a file, not a device. pygrub can cope with a # file if it's raw, but if it's QCOW or other such formats # used through blktap, then we need to mount it first. - - log.info("Mounting %s on %s." % - (fn, BOOTLOADER_LOOPBACK_DEVICE)) - - vbd = { - 'mode': 'RO', - 'device': BOOTLOADER_LOOPBACK_DEVICE, - } - - from xen.xend import XendDomain - dom0 = XendDomain.instance().privilegedDomain() - mounted_vbd_uuid = dom0.create_vbd(vbd, disk); - dom0._waitForDeviceUUID(mounted_vbd_uuid) - fn = BOOTLOADER_LOOPBACK_DEVICE - + # Try all possible loopback_devices + for loopback_device in BOOTLOADER_LOOPBACK_DEVICES: + log.info("Mounting %s on %s." % (fn, loopback_device)) + vbd = { 'mode' : 'RW', 'device' : loopback_device, } + try: + from xen.xend import XendDomain + dom0 = XendDomain.instance().privilegedDomain() + mounted_vbd_uuid = dom0.create_vbd(vbd, disk) + dom0._waitForDeviceFrontUUID(mounted_vbd_uuid) + fn = loopback_device + break + except VmError, e: + if str(e).find('already connected.') != -1: + continue + elif str(e).find('isn\'t accessible') != -1: + dom0.destroyDevice('vbd', loopback_device, force = True, rm_cfg = True) + continue + else: + raise + else: + raise try: blcfg = bootloader(blexec, fn, self, False, bootloader_args, kernel, ramdisk, args) finally: if mounted: log.info("Unmounting %s from %s." % - (fn, BOOTLOADER_LOOPBACK_DEVICE)) - _, vbd_info = dom0.info['devices'][mounted_vbd_uuid] - dom0.destroyDevice(dom0.getBlockDeviceClass(vbd_info['devid']), - BOOTLOADER_LOOPBACK_DEVICE, force = True) - + (fn, loopback_device)) + if devtype in ['tap', 'tap2']: + dom0.destroyDevice('tap', loopback_device, rm_cfg = True) + else: + dom0.destroyDevice('vbd', loopback_device, rm_cfg = True) if blcfg is None: msg = "Had a bootloader specified, but can't find disk" log.error(msg) @@ -3908,6 +4034,14 @@ class XendDomainInfo: else: config['mode'] = 'RW' + if dev_class == 'console': + if not config.has_key('protocol'): + con_type = config.get('type', '') + if con_type == 'vnc': + config['protocol'] = 'rfb' + elif con_type == 'sdl': + config['protocol'] = 'rdp' + return config def get_dev_property(self, dev_class, dev_uuid, field): @@ -4415,6 +4549,91 @@ class XendDomainInfo: def has_device(self, dev_class, dev_uuid): return (dev_uuid in self.info['%s_refs' % dev_class.lower()]) + # Return name of host contained in lock file. + def get_lock_host(self, path): + lock_cmd = '%s -s -i %s ' % \ + (xoptions.get_xend_domain_lock_utility(), \ + self.info['uuid']) + lock_dev = xoptions.get_xend_domain_lock_device() + if lock_dev: + lock_cmd += '-x %d ' % lock_dev + lock_cmd += path + fin = os.popen(lock_cmd, 'r') + hostname = "unknown" + + try: + tokens = fin.readline().split() + for token in tokens: + item = token.split('=') + if item[0] == 'host': + hostname = item[1] + return hostname + finally: + fin.close() + + # Acquire a lock for the domain. No-op if domain locking is turned off. + def acquire_running_lock(self): + if not xoptions.get_xend_domain_lock(): + return + + log.debug("Acquiring lock for domain %s" % self.info['name_label']) + path = xoptions.get_xend_domain_lock_path() + path = os.path.join(path, self.get_uuid()) + + lock_cmd = '%s -l -p %s -n %s -i %s ' % \ + (xoptions.get_xend_domain_lock_utility(), \ + XendNode.instance().get_name(), \ + self.info['name_label'], \ + self.info['uuid']) + lock_dev = xoptions.get_xend_domain_lock_device() + if lock_dev: + lock_cmd += '-x %d ' % lock_dev + lock_cmd += path + + try: + if not os.path.exists(path): + mkdir.parents(path, stat.S_IRWXU) + except: + log.exception("%s could not be created." % path) + raise XendError("%s could not be created." % path) + + status = os.system(lock_cmd) >> 8 + if status != 0: + log.debug("Failed to aqcuire lock: status = %d" % status) + raise XendError("The VM is locked and appears to be running on host %s." % self.get_lock_host(path)) + + # Release lock for domain. No-op if domain locking is turned off. + def release_running_lock(self, name = None): + if not xoptions.get_xend_domain_lock(): + return + + dom_name = self.info['name_label'] + if name: + dom_name = name + log.debug("Releasing lock for domain %s" % dom_name) + + path = xoptions.get_xend_domain_lock_path() + path = os.path.join(path, self.get_uuid()) + + lock_cmd = '%s -u -p %s -n %s -i %s ' % \ + (xoptions.get_xend_domain_lock_utility(), \ + XendNode.instance().get_name(), \ + dom_name, \ + self.info['uuid']) + lock_dev = xoptions.get_xend_domain_lock_device() + if lock_dev: + lock_cmd += '-x %d ' % lock_dev + lock_cmd += path + + status = os.system(lock_cmd) >> 8 + if status != 0: + log.exception("Failed to release lock: status = %s" % status) + try: + if len(os.listdir(path)) == 0: + shutil.rmtree(path) + except: + log.exception("Failed to remove unmanaged directory %s." % path) + def __str__(self): return '' % \ (str(self.domid), self.info['name_label'], Index: xen-4.3.0-testing/tools/python/xen/xm/main.py =================================================================== --- xen-4.3.0-testing.orig/tools/python/xen/xm/main.py +++ xen-4.3.0-testing/tools/python/xen/xm/main.py @@ -21,6 +21,7 @@ """Grand unified management application for Xen. """ +import getpass import atexit import cmd import os @@ -114,6 +115,8 @@ SUBCOMMAND_HELP = { 'Set the maximum amount reservation for a domain.'), 'mem-set' : (' ', 'Set the current memory usage for a domain.'), + 'mem-swap-target' : (' ', + 'Set the memory usage for a domain.'), 'migrate' : (' ', 'Migrate a domain to another machine.'), 'pause' : ('', 'Pause execution of a domain.'), @@ -121,7 +124,7 @@ SUBCOMMAND_HELP = { 'reset' : ('', 'Reset a domain.'), 'restore' : (' [-p]', 'Restore a domain from a saved state.'), - 'save' : ('[-c] ', + 'save' : ('[-c|-f] ', 'Save a domain state to restore later.'), 'shutdown' : (' [-waRH]', 'Shutdown a domain.'), 'top' : ('', 'Monitor a host and the domains in real time.'), @@ -280,6 +283,9 @@ SUBCOMMAND_HELP = { 'getenforce' : ('', 'Returns the current enforcing mode for the Flask XSM module (Enforcing,Permissive)'), 'setenforce' : ('[ (Enforcing|1) | (Permissive|0) ]', 'Modifies the current enforcing mode for the Flask XSM module'), + #change vnc password + 'change-vnc-passwd' : ('',\ + 'Change vnc password'), } SUBCOMMAND_OPTIONS = { @@ -341,6 +347,7 @@ SUBCOMMAND_OPTIONS = { ), 'save': ( ('-c', '--checkpoint', 'Leave domain running after creating snapshot'), + ('-f', '--force', 'Force to overwrite exist file'), ), 'restore': ( ('-p', '--paused', 'Do not unpause domain after restoring it'), @@ -404,6 +411,7 @@ common_commands = [ "usb-del", "domstate", "vcpu-set", + "change-vnc-passwd", ] domain_commands = [ @@ -441,6 +449,7 @@ domain_commands = [ "vcpu-list", "vcpu-pin", "vcpu-set", + "change-vnc-passwd", ] host_commands = [ @@ -862,18 +871,21 @@ def xm_event_monitor(args): def xm_save(args): - arg_check(args, "save", 2, 3) + arg_check(args, "save", 2, 4) try: - (options, params) = getopt.gnu_getopt(args, 'c', ['checkpoint']) + (options, params) = getopt.gnu_getopt(args, 'cf', ['checkpoint', 'force']) except getopt.GetoptError, opterr: err(opterr) usage('save') checkpoint = False + force = False for (k, v) in options: if k in ['-c', '--checkpoint']: checkpoint = True + if k in ['-f', '--force']: + force = True if len(params) != 2: err("Wrong number of parameters") @@ -887,9 +899,9 @@ def xm_save(args): sys.exit(1) if serverType == SERVER_XEN_API: - server.xenapi.VM.save(get_single_vm(dom), savefile, checkpoint) + server.xenapi.VM.save(get_single_vm(dom), savefile, checkpoint, force) else: - server.xend.domain.save(dom, savefile, checkpoint) + server.xend.domain.save(dom, savefile, checkpoint, force) def xm_restore(args): arg_check(args, "restore", 1, 2) @@ -1580,6 +1592,17 @@ def xm_mem_set(args): mem_target = int_unit(args[1], 'm') server.xend.domain.setMemoryTarget(dom, mem_target) +def xm_mem_swap_target(args): + arg_check(args, "mem-swap-target", 2) + + dom = args[0] + + if serverType == SERVER_XEN_API: + err("xenapi not supported") + else: + swap_target = int_unit(args[1], 'm') + server.xend.domain.swaptarget_set(dom, swap_target) + def xm_usb_add(args): arg_check(args, "usb-add", 2) server.xend.domain.usb_add(args[0],args[1]) @@ -2199,6 +2222,10 @@ def xm_debug_keys(args): def xm_top(args): arg_check(args, "top", 0) + # A hack to get a clear error message if ran as non-root + if os.geteuid() != 0: + raise IOError() + os.system('xentop') def xm_dmesg(args): @@ -2586,10 +2613,22 @@ def xm_usb_list(args): ni = parse_dev_info(x[1]) ni['idx'] = int(x[0]) usbver = sxp.child_value(x[1], 'usb-ver') + + substr = re.search("^\d{1,}", usbver) + if substr: + usbver = substr.group() + else: + print "Unknown usb-ver" + continue + if int(usbver) == 1: ni['usb-ver'] = 'USB1.1' - else: + elif int(usbver) == 2: ni['usb-ver'] = 'USB2.0' + else: + print "Unknown usb-ver" + continue + print "%(idx)-3d %(backend-id)-3d %(state)-5d %(usb-ver)-7s %(be-path)-30s " % ni ports = sxp.child(x[1], 'port') @@ -3751,6 +3790,10 @@ def xm_cpupool_migrate(args): else: server.xend.cpu_pool.migrate(domname, poolname) +def xm_chgvncpasswd(args): + arg_check(args, "change-vnc-passwd", 1) + pwd = getpass.getpass("Enter new password: ") + server.xend.domain.chgvncpasswd(args[0], pwd) commands = { "shell": xm_shell, @@ -3782,6 +3825,7 @@ commands = { # memory commands "mem-max": xm_mem_max, "mem-set": xm_mem_set, + "mem-swap-target": xm_mem_swap_target, # cpu commands "vcpu-pin": xm_vcpu_pin, "vcpu-list": xm_vcpu_list, @@ -3857,6 +3901,8 @@ commands = { "usb-del": xm_usb_del, #domstate "domstate": xm_domstate, + #change vnc password: + "change-vnc-passwd": xm_chgvncpasswd, } ## The commands supported by a separate argument parser in xend.xm. Index: xen-4.3.0-testing/tools/python/xen/xend/XendNode.py =================================================================== --- xen-4.3.0-testing.orig/tools/python/xen/xend/XendNode.py +++ xen-4.3.0-testing/tools/python/xen/xend/XendNode.py @@ -162,6 +162,7 @@ class XendNode: self._init_cpu_pools() + self._init_lock_devices() def _init_networks(self): # Initialise networks @@ -382,6 +383,17 @@ class XendNode: XendCPUPool.recreate_active_pools() + def _init_lock_devices(self): + if xendoptions().get_xend_domain_lock(): + if xendoptions().get_xend_domain_lock_utility().endswith("domain-lock-sfex"): + lock_device = xendoptions().get_xend_domain_lock_device() + if not lock_device: + raise XendError("The block device for sfex is not properly configured") + status = os.system("lvchange -ay %s" % lock_device) >> 8 + if status != 0: + raise XendError("The block device for sfex could not be initialized") + + def add_network(self, interface): # TODO log.debug("add_network(): Not implemented.") @@ -949,11 +961,35 @@ class XendNode: info['cpu_mhz'] = info['cpu_khz'] / 1000 - # physinfo is in KiB, need it in MiB - info['total_memory'] = info['total_memory'] / 1024 - info['free_memory'] = info['free_memory'] / 1024 + configured_floor = xendoptions().get_dom0_min_mem() * 1024 + from xen.xend import balloon + try: + kernel_floor = balloon.get_dom0_min_target() + except: + kernel_floor = 0 + dom0_min_mem = max(configured_floor, kernel_floor) + dom0_mem = balloon.get_dom0_current_alloc() + extra_mem = 0 + if dom0_min_mem > 0 and dom0_mem > dom0_min_mem: + extra_mem = dom0_mem - dom0_min_mem + info['free_memory'] = info['free_memory'] + info['scrub_memory'] + info['max_free_memory'] = info['free_memory'] + extra_mem info['free_cpus'] = len(XendCPUPool.unbound_cpus()) + # Convert KiB to MiB, rounding down to be conservative + info['total_memory'] = info['total_memory'] / 1024 + info['free_memory'] = info['free_memory'] / 1024 + info['max_free_memory'] = info['max_free_memory'] / 1024 + + # FIXME: These are hard-coded to be the inverse of the getXenMemory + # functions in image.py. Find a cleaner way. + info['max_para_memory'] = info['max_free_memory'] - 4 + if info['max_para_memory'] < 0: + info['max_para_memory'] = 0 + info['max_hvm_memory'] = int((info['max_free_memory']-12) * (1-2.4/1024)) + if info['max_hvm_memory'] < 0: + info['max_hvm_memory'] = 0 + ITEM_ORDER = ['nr_cpus', 'nr_nodes', 'cores_per_socket', @@ -964,6 +1000,9 @@ class XendNode: 'total_memory', 'free_memory', 'free_cpus', + 'max_free_memory', + 'max_para_memory', + 'max_hvm_memory', ] if show_numa != 0: Index: xen-4.3.0-testing/tools/python/xen/xend/balloon.py =================================================================== --- xen-4.3.0-testing.orig/tools/python/xen/xend/balloon.py +++ xen-4.3.0-testing/tools/python/xen/xend/balloon.py @@ -43,6 +43,8 @@ SLEEP_TIME_GROWTH = 0.1 # label actually shown in the PROC_XEN_BALLOON file. #labels = { 'current' : 'Current allocation', # 'target' : 'Requested target', +# 'min-target' : 'Minimum target', +# 'max-target' : 'Maximum target', # 'low-balloon' : 'Low-mem balloon', # 'high-balloon' : 'High-mem balloon', # 'limit' : 'Xen hard limit' } @@ -69,6 +71,23 @@ def get_dom0_target_alloc(): raise VmError('Failed to query target memory allocation of dom0.') return kb +def get_dom0_min_target(): + """Returns the minimum amount of memory (in KiB) that dom0 will accept.""" + + kb = _get_proc_balloon('min-target') + if kb == None: + raise VmError('Failed to query minimum target memory allocation of dom0.') + return kb + +def get_dom0_max_target(): + """Returns the maximum amount of memory (in KiB) that is potentially + visible to dom0.""" + + kb = _get_proc_balloon('max-target') + if kb == None: + raise VmError('Failed to query maximum target memory allocation of dom0.') + return kb + def free(need_mem, dominfo): """Balloon out memory from the privileged domain so that there is the specified required amount (in KiB) free. Index: xen-4.3.0-testing/tools/python/xen/xend/server/SrvDomain.py =================================================================== --- xen-4.3.0-testing.orig/tools/python/xen/xend/server/SrvDomain.py +++ xen-4.3.0-testing/tools/python/xen/xend/server/SrvDomain.py @@ -187,7 +187,7 @@ class SrvDomain(SrvDir): def op_mem_target_set(self, _, req): - return self.call(self.dom.setMemoryTarget, + return self.call(self.dom.capAndSetMemoryTarget, [['target', 'int']], req) Index: xen-4.3.0-testing/tools/python/xen/xend/osdep.py =================================================================== --- xen-4.3.0-testing.orig/tools/python/xen/xend/osdep.py +++ xen-4.3.0-testing/tools/python/xen/xend/osdep.py @@ -42,6 +42,8 @@ def _linux_balloon_stat_proc(label): xend2linux_labels = { 'current' : 'Current allocation', 'target' : 'Requested target', + 'min-target' : 'Minimum target', + 'max-target' : 'Maximum target', 'low-balloon' : 'Low-mem balloon', 'high-balloon' : 'High-mem balloon', 'limit' : 'Xen hard limit' } @@ -141,10 +143,14 @@ def _linux_get_cpuinfo(): d = {} for line in f: keyvalue = line.split(':') - if len(keyvalue) != 2: + if len(keyvalue) < 2: continue key = keyvalue[0].strip() - val = keyvalue[1].strip() + for i in range(1, len(keyvalue)): + if i == 1: + val = keyvalue[i].lstrip() + else: + val = val + ":" + keyvalue[i] if key == 'processor': if p != -1: cpuinfo[p] = d Index: xen-4.3.0-testing/tools/hotplug/Linux/Makefile =================================================================== --- xen-4.3.0-testing.orig/tools/hotplug/Linux/Makefile +++ xen-4.3.0-testing/tools/hotplug/Linux/Makefile @@ -11,7 +11,7 @@ XENCOMMONS_SYSCONFIG = init.d/sysconfig. # Xen script dir and scripts to go there. XEN_SCRIPTS = network-bridge vif-bridge -XEN_SCRIPTS += network-route vif-route +XEN_SCRIPTS += network-route vif-route vif-route-ifup XEN_SCRIPTS += network-nat vif-nat XEN_SCRIPTS += vif-openvswitch XEN_SCRIPTS += vif2 @@ -23,6 +23,8 @@ XEN_SCRIPTS += xen-hotplug-cleanup XEN_SCRIPTS += external-device-migrate XEN_SCRIPTS += vscsi XEN_SCRIPTS += block-iscsi +XEN_SCRIPTS += domain-lock vm-monitor +XEN_SCRIPTS += domain-lock-sfex XEN_SCRIPT_DATA = xen-script-common.sh locking.sh logging.sh XEN_SCRIPT_DATA += xen-hotplug-common.sh xen-network-common.sh vif-common.sh XEN_SCRIPT_DATA += block-common.sh Index: xen-4.3.0-testing/tools/hotplug/Linux/vif-route-ifup =================================================================== --- /dev/null +++ xen-4.3.0-testing/tools/hotplug/Linux/vif-route-ifup @@ -0,0 +1,34 @@ +#!/bin/bash +#============================================================================ +# /etc/xen/vif-route-ifup +# +# Script for configuring a vif in routed mode. +# The hotplugging system will call this script if it is specified either in +# the device configuration given to Xend, or the default Xend configuration +# in /etc/xen/xend-config.sxp. If the script is specified in neither of those +# places, then vif-bridge is the default. +# +# Usage: +# vif-route-ifup (add|remove|online|offline) +# +# Environment vars: +# dev vif interface name (required). +#============================================================================ + +dir=$(dirname "$0") +. "$dir/vif-common.sh" + +case "$command" in + online) + ifup ${dev} + ;; + offline) + do_without_error ifdown ${dev} + ;; +esac + +log debug "Successful vif-route-ifup $command for ${dev}." +if [ "$command" = "online" ] +then + success +fi Index: xen-4.3.0-testing/tools/qemu-xen-traditional-dir-remote/net.h =================================================================== --- xen-4.3.0-testing.orig/tools/qemu-xen-traditional-dir-remote/net.h +++ xen-4.3.0-testing/tools/qemu-xen-traditional-dir-remote/net.h @@ -107,8 +107,8 @@ void net_host_device_add(const char *dev void net_host_device_remove(int vlan_id, const char *device); #ifndef DEFAULT_NETWORK_SCRIPT -#define DEFAULT_NETWORK_SCRIPT "/etc/qemu-ifup" -#define DEFAULT_NETWORK_DOWN_SCRIPT "/etc/qemu-ifdown" +#define DEFAULT_NETWORK_SCRIPT "/etc/xen/qemu-ifup" +#define DEFAULT_NETWORK_DOWN_SCRIPT "/etc/xen/qemu-ifdown" #endif #ifdef __sun__ #define SMBD_COMMAND "/usr/sfw/sbin/smbd" Index: xen-4.3.0-testing/tools/qemu-xen-traditional-dir-remote/net.c =================================================================== --- xen-4.3.0-testing.orig/tools/qemu-xen-traditional-dir-remote/net.c +++ xen-4.3.0-testing/tools/qemu-xen-traditional-dir-remote/net.c @@ -1759,9 +1759,10 @@ int net_client_init(const char *device, } if (get_param_value(script_arg, sizeof(script_arg), "scriptarg", p) == 0 && get_param_value(script_arg, sizeof(script_arg), "bridge", p) == 0) { /* deprecated; for xend compatibility */ - pstrcpy(script_arg, sizeof(script_arg), ""); + ret = net_tap_init(vlan, device, name, ifname, setup_script, NULL, NULL); + } else { + ret = net_tap_init(vlan, device, name, ifname, setup_script, down_script, script_arg); } - ret = net_tap_init(vlan, device, name, ifname, setup_script, down_script, script_arg); } } else #endif Index: xen-4.3.0-testing/tools/python/xen/xend/image.py =================================================================== --- xen-4.3.0-testing.orig/tools/python/xen/xend/image.py +++ xen-4.3.0-testing/tools/python/xen/xend/image.py @@ -17,7 +17,7 @@ #============================================================================ -import os, os.path, string +import os, os.path, string, struct, stat import re import math import time @@ -122,7 +122,13 @@ class ImageHandler: self.vm.permissionsVm("image/cmdline", { 'dom': self.vm.getDomid(), 'read': True } ) self.device_model = vmConfig['platform'].get('device_model') + self.actmem = str(vmConfig['platform'].get('actmem')) + self.xenpaging_file = str(vmConfig['platform'].get('xenpaging_file')) + self.xenpaging_extra = vmConfig['platform'].get('xenpaging_extra') + self.xenpaging_pid = None + self.smbios_firmware =(str(vmConfig['platform'].get('smbios_firmware'))) + self.acpi_firmware =(str(vmConfig['platform'].get('acpi_firmware'))) self.display = vmConfig['platform'].get('display') self.xauthority = vmConfig['platform'].get('xauthority') self.vncconsole = int(vmConfig['platform'].get('vncconsole', 0)) @@ -392,6 +398,87 @@ class ImageHandler: sentinel_fifos_inuse[sentinel_path_fifo] = 1 self.sentinel_path_fifo = sentinel_path_fifo + def createXenPaging(self): + if not self.vm.info.is_hvm(): + return + if self.actmem == "0": + return + if self.xenpaging_pid: + return + xenpaging_bin = auxbin.pathTo("xenpaging") + args = [xenpaging_bin] + args = args + ([ "-f", "/var/lib/xen/xenpaging/%s.%d.paging" % (str(self.vm.info['name_label']), self.vm.getDomid())]) + if self.xenpaging_extra: + args = args + (self.xenpaging_extra) + args = args + ([ "-d", "%d" % self.vm.getDomid()]) + self.xenpaging_logfile = "/var/log/xen/xenpaging-%s.log" % str(self.vm.info['name_label']) + logfile_mode = os.O_WRONLY|os.O_CREAT|os.O_APPEND|os.O_TRUNC + null = os.open("/dev/null", os.O_RDONLY) + try: + os.unlink(self.xenpaging_logfile) + except: + pass + logfd = os.open(self.xenpaging_logfile, logfile_mode, 0644) + sys.stderr.flush() + contract = osdep.prefork("%s:%d" % (self.vm.getName(), self.vm.getDomid())) + xenpaging_pid = os.fork() + if xenpaging_pid == 0: #child + try: + osdep.postfork(contract) + os.dup2(null, 0) + os.dup2(logfd, 1) + os.dup2(logfd, 2) + try: + env = dict(os.environ) + log.info("starting %s" % args) + os.execve(xenpaging_bin, args, env) + except Exception, e: + log.warn('failed to execute xenpaging: %s' % utils.exception_string(e)) + os._exit(126) + except: + log.warn("starting xenpaging failed") + os._exit(127) + else: + osdep.postfork(contract, abandon=True) + self.xenpaging_pid = xenpaging_pid + os.close(null) + os.close(logfd) + self.vm.storeDom("xenpaging/xenpaging-pid", self.xenpaging_pid) + self.vm.storeDom("memory/target-tot_pages", int(self.actmem) * 1024) + + def destroyXenPaging(self): + if self.actmem == "0": + return + if self.xenpaging_pid: + try: + os.kill(self.xenpaging_pid, signal.SIGHUP) + except OSError, exn: + log.exception(exn) + for i in xrange(100): + try: + (p, rv) = os.waitpid(self.xenpaging_pid, os.WNOHANG) + if p == self.xenpaging_pid: + break + except OSError: + # This is expected if Xend has been restarted within + # the life of this domain. In this case, we can kill + # the process, but we can't wait for it because it's + # not our child. We continue this loop, and after it is + # terminated make really sure the process is going away + # (SIGKILL). + pass + time.sleep(0.1) + else: + log.warning("xenpaging %d took more than 10s " + "to terminate: sending SIGKILL" % self.xenpaging_pid) + try: + os.kill(self.xenpaging_pid, signal.SIGKILL) + os.waitpid(self.xenpaging_pid, 0) + except OSError: + # This happens if the process doesn't exist. + pass + self.xenpaging_pid = None + def createDeviceModel(self, restore = False): if self.device_model is None: return @@ -828,6 +915,7 @@ class HVMImageHandler(ImageHandler): self.apic = int(vmConfig['platform'].get('apic', 0)) self.acpi = int(vmConfig['platform'].get('acpi', 0)) + self.extid = int(vmConfig['platform'].get('extid', 0)) self.guest_os_type = vmConfig['platform'].get('guest_os_type') self.memory_sharing = int(vmConfig['memory_sharing']) try: @@ -855,7 +943,8 @@ class HVMImageHandler(ImageHandler): dmargs = [ 'boot', 'fda', 'fdb', 'soundhw', 'localtime', 'serial', 'stdvga', 'isa', - 'acpi', 'usb', 'usbdevice', 'gfx_passthru' ] + 'acpi', 'usb', 'usbdevice', 'gfx_passthru', + 'watchdog', 'watchdog_action' ] for a in dmargs: v = vmConfig['platform'].get(a) @@ -863,6 +952,7 @@ class HVMImageHandler(ImageHandler): # python doesn't allow '-' in variable names if a == 'stdvga': a = 'std-vga' if a == 'keymap': a = 'k' + if a == 'watchdog_action': a = 'watchdog-action' # Handle booleans gracefully if a in ['localtime', 'std-vga', 'isa', 'usb', 'acpi']: @@ -912,11 +1002,13 @@ class HVMImageHandler(ImageHandler): mac = devinfo.get('mac') if mac is None: raise VmError("MAC address not specified or generated.") - bridge = devinfo.get('bridge', 'xenbr0') + bridge = devinfo.get('bridge', None) model = devinfo.get('model', 'rtl8139') ret.append("-net") - ret.append("nic,vlan=%d,macaddr=%s,model=%s" % - (nics, mac, model)) + net = "nic,vlan=%d,macaddr=%s,model=%s" % (nics, mac, model) + if bridge: + net += ",bridge=%s" % bridge + ret.append(net) vifname = "vif%d.%d-emu" % (self.vm.getDomid(), nics-1) ret.append("-net") if osdep.tapif_script is not None: @@ -941,6 +1033,38 @@ class HVMImageHandler(ImageHandler): self.vm.getDomid() ]) return args + def _readFirmwareFile(self, filename): + # Sanity check + if filename is None or filename.strip() == "": + size = struct.pack('i', int(0)) + return size + "" + + log.debug("Reading firmware file %s", filename) + # Open + try: + fd = os.open(filename, os.O_RDONLY) + except Exception, e: + raise VmError('Unable to open firmware file %s' % filename) + + # Validate file size + statinfo = os.fstat(fd) + if statinfo.st_size == 0 or statinfo.st_size > sys.maxint: + os.close(fd) + raise VmError('Firmware file %s is an invalid size' % filename) + if not stat.S_ISREG(statinfo.st_mode): + os.close(fd) + raise VmError('Firmware file %s is an invalid file type' % filename) + size = struct.pack('i', statinfo.st_size) + + # Read entire file + try: + buf = os.read(fd, statinfo.st_size) + except Exception, e: + os.close(fd) + raise VmError('Failed reading firmware file %s' % filename) + os.close(fd) + return size+buf + def buildDomain(self): store_evtchn = self.vm.getStorePort() @@ -956,6 +1080,8 @@ class HVMImageHandler(ImageHandler): log.debug("vcpu_avail = %li", self.vm.getVCpuAvail()) log.debug("acpi = %d", self.acpi) log.debug("apic = %d", self.apic) + log.debug("smbios_firmware= %s", self.smbios_firmware) + log.debug("acpi_firmware = %s", self.acpi_firmware) rc = xc.hvm_build(domid = self.vm.getDomid(), image = self.loader, @@ -964,7 +1090,9 @@ class HVMImageHandler(ImageHandler): vcpus = self.vm.getVCpuCount(), vcpu_avail = self.vm.getVCpuAvail(), acpi = self.acpi, - apic = self.apic) + apic = self.apic, + smbios_firmware= self._readFirmwareFile(self.smbios_firmware), + acpi_firmware = self._readFirmwareFile(self.acpi_firmware)) rc['notes'] = { 'SUSPEND_CANCEL': 1 } rc['store_mfn'] = xc.hvm_get_param(self.vm.getDomid(), @@ -1036,7 +1164,7 @@ class X86_HVM_ImageHandler(HVMImageHandl def configure(self, vmConfig): HVMImageHandler.configure(self, vmConfig) - self.pae = int(vmConfig['platform'].get('pae', 0)) + self.pae = int(vmConfig['platform'].get('pae', 1)) self.vramsize = int(vmConfig['platform'].get('videoram',4)) * 1024 def buildDomain(self): Index: xen-4.3.0-testing/tools/qemu-xen-traditional-dir-remote/i386-dm/qemu-ifup-Linux =================================================================== --- xen-4.3.0-testing.orig/tools/qemu-xen-traditional-dir-remote/i386-dm/qemu-ifup-Linux +++ xen-4.3.0-testing/tools/qemu-xen-traditional-dir-remote/i386-dm/qemu-ifup-Linux @@ -1,36 +1,22 @@ #!/bin/sh -#. /etc/rc.d/init.d/functions -#ulimit -c unlimited - echo 'config qemu network with xen bridge for ' $* +# If bridge is not specified, try device with default route. bridge=$2 +if [ -z "$bridge" ]; then + bridge=$(ip route list | awk '/^default / { print $NF }') +fi -# -# Old style bridge setup with netloop, used to have a bridge name -# of xenbrX, enslaving pethX and vif0.X, and then configuring -# eth0. -# -# New style bridge setup does not use netloop, so the bridge name -# is ethX and the physical device is enslaved pethX -# -# So if... -# -# - User asks for xenbrX -# - AND xenbrX doesn't exist -# - AND there is a ethX device which is a bridge -# -# ..then we translate xenbrX to ethX -# -# This lets old config files work without modification -# -if [ ! -e "/sys/class/net/$bridge" ] && [ -z "${bridge##xenbr*}" ] +# Exit if $bridge is not a bridge. Exit with 0 status +# so qemu-dm process is not terminated. No networking in +# vm is bad but not catastrophic. The vm could still run +# cpu and disk IO workloads. +# Include an useful error message in qemu-dm log file. +if [ ! -e "/sys/class/net/${bridge}/bridge" ] then - if [ -e "/sys/class/net/eth${bridge#xenbr}/bridge" ] - then - bridge="eth${bridge#xenbr}" - fi + echo "WARNING! ${bridge} is not a bridge. qemu-ifup exiting. VM may not have a functioning networking stack." + exit 0 fi ifconfig $1 0.0.0.0 up Index: xen-4.3.0-testing/tools/qemu-xen-traditional-dir-remote/monitor.c =================================================================== --- xen-4.3.0-testing.orig/tools/qemu-xen-traditional-dir-remote/monitor.c +++ xen-4.3.0-testing/tools/qemu-xen-traditional-dir-remote/monitor.c @@ -26,6 +26,7 @@ #include "hw/pcmcia.h" #include "hw/pc.h" #include "hw/pci.h" +#include "hw/watchdog.h" #include "gdbstub.h" #include "net.h" #include "qemu-char.h" @@ -531,6 +532,13 @@ static void do_gdbserver(const char *por } #endif +static void do_watchdog_action(const char *action) +{ + if (select_watchdog_action(action) == -1) { + qemu_printf("Unknown watchdog action '%s'\n", action); + } +} + static void term_printc(int c) { term_printf("'"); @@ -1497,6 +1505,7 @@ static const term_cmd_t term_cmds[] = { "device|all", "commit changes to the disk images (if -snapshot is used) or backing files" }, { "info", "s?", do_info, "subcommand", "show various information about the system state" }, +#ifdef CONFIG_TRUSTED_CLIENT { "q|quit", "", do_quit, "", "quit the emulator" }, { "eject", "-fB", do_eject, @@ -1509,6 +1518,7 @@ static const term_cmd_t term_cmds[] = { "filename", "output logs to 'filename'" }, { "log", "s", do_log, "item1[,...]", "activate logging of the specified items to '/tmp/qemu.log'" }, +#endif { "savevm", "s?", do_savevm, "tag|id", "save a VM snapshot. If no tag or id are provided, a new snapshot is created" }, { "loadvm", "s", do_loadvm, @@ -1538,8 +1548,10 @@ static const term_cmd_t term_cmds[] = { "", "reset the system" }, { "system_powerdown", "", do_system_powerdown, "", "send system power down event" }, +#ifdef CONFIG_TRUSTED_CLIENT { "sum", "ii", do_sum, "addr size", "compute the checksum of a memory region" }, +#endif { "usb_add", "s", do_usb_add, "device", "add USB device (e.g. 'host:bus.addr' or 'host:vendor_id:product_id')" }, { "usb_del", "s", do_usb_del, @@ -1558,6 +1570,7 @@ static const term_cmd_t term_cmds[] = { "state", "change mouse button state (1=L, 2=M, 4=R)" }, { "mouse_set", "i", do_mouse_set, "index", "set which mouse device receives events" }, +#ifdef CONFIG_TRUSTED_CLIENT #ifdef HAS_AUDIO { "wavcapture", "si?i?i?", do_wav_capture, "path [frequency bits channels]", @@ -1565,6 +1578,7 @@ static const term_cmd_t term_cmds[] = { #endif { "stopcapture", "i", do_stop_capture, "capture index", "stop capture" }, +#endif { "memsave", "lis", do_memory_save, "addr size file", "save to disk virtual memory dump starting at 'addr' of size 'size'", }, { "pmemsave", "lis", do_physical_memory_save, @@ -1599,6 +1613,8 @@ static const term_cmd_t term_cmds[] = { "target", "request VM to change it's memory allocation (in MB)" }, { "set_link", "ss", do_set_link, "name [up|down]", "change the link status of a network adapter" }, + { "watchdog_action", "s", do_watchdog_action, + "[reset|shutdown|poweroff|pause|debug|none]", "change watchdog action" }, { "cpu_set", "is", do_cpu_set_nr, "cpu [online|offline]", "change cpu state" }, { NULL, NULL, }, @@ -1646,6 +1662,7 @@ static const term_cmd_t info_cmds[] = { "", "show KVM information", }, { "usb", "", usb_info, "", "show guest USB devices", }, +#ifdef CONFIG_TRUSTED_CLIENT { "usbhost", "", usb_host_info, "", "show host USB devices", }, { "profile", "", do_info_profile, @@ -1677,6 +1694,7 @@ static const term_cmd_t info_cmds[] = { { "migrate", "", do_info_migrate, "", "show migration status" }, { "balloon", "", do_info_balloon, "", "show balloon information" }, +#endif { NULL, NULL, }, }; Index: xen-4.3.0-testing/tools/qemu-xen-traditional-dir-remote/hw/ne2000.c =================================================================== --- xen-4.3.0-testing.orig/tools/qemu-xen-traditional-dir-remote/hw/ne2000.c +++ xen-4.3.0-testing/tools/qemu-xen-traditional-dir-remote/hw/ne2000.c @@ -218,7 +218,7 @@ static int ne2000_can_receive(void *opaq NE2000State *s = opaque; if (s->cmd & E8390_STOP) - return 1; + return 0; return !ne2000_buffer_full(s); } Index: xen-4.3.0-testing/tools/qemu-xen-traditional-dir-remote/hw/pc.c =================================================================== --- xen-4.3.0-testing.orig/tools/qemu-xen-traditional-dir-remote/hw/pc.c +++ xen-4.3.0-testing/tools/qemu-xen-traditional-dir-remote/hw/pc.c @@ -41,6 +41,7 @@ #include "virtio-balloon.h" #include "virtio-console.h" #include "hpet_emul.h" +#include "watchdog.h" #ifdef CONFIG_PASSTHROUGH #include "pass-through.h" @@ -413,7 +414,8 @@ static void bochs_bios_write(void *opaqu case 0x400: case 0x401: fprintf(stderr, "BIOS panic at rombios.c, line %d\n", val); - exit(1); + /* according to documentation, these can be safely ignored */ + break; case 0x402: case 0x403: #ifdef DEBUG_BIOS @@ -436,8 +438,9 @@ static void bochs_bios_write(void *opaqu /* LGPL'ed VGA BIOS messages */ case 0x501: case 0x502: + /* according to documentation, these can be safely ignored */ fprintf(stderr, "VGA BIOS panic, line %d\n", val); - exit(1); + break; case 0x500: case 0x503: #ifdef DEBUG_BIOS @@ -472,45 +475,28 @@ static void bochs_bios_init(void) /* Generate an initial boot sector which sets state and jump to a specified vector */ -static void generate_bootsect(uint8_t *option_rom, - uint32_t gpr[8], uint16_t segs[6], uint16_t ip) +static void generate_bootsect(uint32_t gpr[8], uint16_t segs[6], uint16_t ip) { - uint8_t rom[512], *p, *reloc; - uint8_t sum; + uint8_t bootsect[512], *p; int i; + int hda; - memset(rom, 0, sizeof(rom)); + hda = drive_get_index(IF_IDE, 0, 0); + if (hda == -1) { + fprintf(stderr, "A disk image must be given for 'hda' when booting " + "a Linux kernel\n(if you really don't want it, use /dev/zero)\n"); + exit(1); + } + memset(bootsect, 0, sizeof(bootsect)); - p = rom; - /* Make sure we have an option rom signature */ - *p++ = 0x55; - *p++ = 0xaa; - - /* ROM size in sectors*/ - *p++ = 1; - - /* Hook int19 */ - - *p++ = 0x50; /* push ax */ - *p++ = 0x1e; /* push ds */ - *p++ = 0x31; *p++ = 0xc0; /* xor ax, ax */ - *p++ = 0x8e; *p++ = 0xd8; /* mov ax, ds */ - - *p++ = 0xc7; *p++ = 0x06; /* movvw _start,0x64 */ - *p++ = 0x64; *p++ = 0x00; - reloc = p; - *p++ = 0x00; *p++ = 0x00; - - *p++ = 0x8c; *p++ = 0x0e; /* mov cs,0x66 */ - *p++ = 0x66; *p++ = 0x00; - - *p++ = 0x1f; /* pop ds */ - *p++ = 0x58; /* pop ax */ - *p++ = 0xcb; /* lret */ - - /* Actual code */ - *reloc = (p - rom); + /* Copy the MSDOS partition table if possible */ + bdrv_read(drives_table[hda].bdrv, 0, bootsect, 1); + /* Make sure we have a partition signature */ + bootsect[510] = 0x55; + bootsect[511] = 0xaa; + /* Actual code */ + p = bootsect; *p++ = 0xfa; /* CLI */ *p++ = 0xfc; /* CLD */ @@ -540,13 +526,7 @@ static void generate_bootsect(uint8_t *o *p++ = segs[1]; /* CS */ *p++ = segs[1] >> 8; - /* sign rom */ - sum = 0; - for (i = 0; i < (sizeof(rom) - 1); i++) - sum += rom[i]; - rom[sizeof(rom) - 1] = -sum; - - memcpy(option_rom, rom, sizeof(rom)); + bdrv_set_boot_sector(drives_table[hda].bdrv, bootsect, sizeof(bootsect)); } static long get_file_size(FILE *f) @@ -563,8 +543,7 @@ static long get_file_size(FILE *f) return size; } -static void load_linux(uint8_t *option_rom, - const char *kernel_filename, +static void load_linux(const char *kernel_filename, const char *initrd_filename, const char *kernel_cmdline) { @@ -630,7 +609,9 @@ static void load_linux(uint8_t *option_r /* Special pages are placed at end of low RAM: pick an arbitrary one and * subtract a suitably large amount of padding (64kB) to skip BIOS data. */ - xc_get_hvm_param(xc_handle, domid, HVM_PARAM_BUFIOREQ_PFN, &end_low_ram); + //xc_get_hvm_param(xc_handle, domid, HVM_PARAM_BUFIOREQ_PFN, &end_low_ram); + /* BUFIO Page beyond last_pfn, use 0x7ffc instead. Fix ME. */ + end_low_ram = 0x7ffc; end_low_ram = (end_low_ram << 12) - (64*1024); /* highest address for loading the initrd */ @@ -719,7 +700,7 @@ static void load_linux(uint8_t *option_r memset(gpr, 0, sizeof gpr); gpr[4] = cmdline_addr-real_addr-16; /* SP (-16 is paranoia) */ - generate_bootsect(option_rom, gpr, seg, 0); + generate_bootsect(gpr, seg, 0); #endif } @@ -930,14 +911,6 @@ vga_bios_error: int size, offset; offset = 0; - if (linux_boot) { - option_rom_offset = qemu_ram_alloc(TARGET_PAGE_SIZE); - load_linux(phys_ram_base + option_rom_offset, - kernel_filename, initrd_filename, kernel_cmdline); - cpu_register_physical_memory(0xd0000, TARGET_PAGE_SIZE, - option_rom_offset | IO_MEM_ROM); - offset = TARGET_PAGE_SIZE; - } for (i = 0; i < nb_option_roms; i++) { size = get_image_size(option_rom[i]); @@ -971,6 +944,9 @@ vga_bios_error: bochs_bios_init(); + if (linux_boot) + load_linux(kernel_filename, initrd_filename, kernel_cmdline); + cpu_irq = qemu_allocate_irqs(pic_irq_request, NULL, 1); i8259 = i8259_init(cpu_irq[0]); ferr_irq = i8259[13]; @@ -1075,6 +1051,8 @@ vga_bios_error: } } + watchdog_pc_init(pci_bus); + for(i = 0; i < nb_nics; i++) { NICInfo *nd = &nd_table[i]; Index: xen-4.3.0-testing/tools/python/xen/xend/server/HalDaemon.py =================================================================== --- /dev/null +++ xen-4.3.0-testing/tools/python/xen/xend/server/HalDaemon.py @@ -0,0 +1,243 @@ +#!/usr/bin/env python +# -*- mode: python; -*- +#============================================================================ +# 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) 2007 Pat Campbell +# Copyright (C) 2007 Novell Inc. +#============================================================================ + +"""hald (Hardware Abstraction Layer Daemon) watcher for Xen management + of removable block device media. + +""" + +import gobject +import dbus +import dbus.glib +import os +import types +import sys +import signal +import traceback +from xen.xend.xenstore.xstransact import xstransact, complete +from xen.xend.xenstore.xsutil import xshandle +from xen.xend import PrettyPrint +from xen.xend import XendLogging +from xen.xend.XendLogging import log + +DEVICE_TYPES = ['vbd', 'tap'] + +class HalDaemon: + """The Hald block device watcher for XEN + """ + + """Default path to the log file. """ + logfile_default = "/var/log/xen/hald.log" + + """Default level of information to be logged.""" + loglevel_default = 'INFO' + + + def __init__(self): + + XendLogging.init(self.logfile_default, self.loglevel_default) + log.debug( "%s", "__init__") + + self.udi_dict = {} + self.debug = 0 + self.dbpath = "/local/domain/0/backend" + self.bus = dbus.SystemBus() + self.hal_manager_obj = self.bus.get_object('org.freedesktop.Hal', '/org/freedesktop/Hal/Manager') + self.hal_manager = dbus.Interface( self.hal_manager_obj, 'org.freedesktop.Hal.Manager') + self.gatherBlockDevices() + self.registerDeviceCallbacks() + + def run(self): + log.debug( "%s", "In new run" ); + try: + self.mainloop = gobject.MainLoop() + self.mainloop.run() + except KeyboardInterrupt, ex: + log.debug('Keyboard exception handler: %s', ex ) + self.mainloop.quit() + except Exception, ex: + log.debug('Generic exception handler: %s', ex ) + self.mainloop.quit() + + def __del__(self): + log.debug( "%s", "In del " ); + self.unRegisterDeviceCallbacks() + self.mainloop.quit() + + def shutdown(self): + log.debug( "%s", "In shutdown now " ); + self.unRegisterDeviceCallbacks() + self.mainloop.quit() + + def stop(self): + log.debug( "%s", "In stop now " ); + self.unRegisterDeviceCallbacks() + self.mainloop.quit() + + def gatherBlockDevices(self): + + # Get all the current devices from hal and save in a dictionary + try: + device_names = self.hal_manager.GetAllDevices() + i = 0; + for name in device_names: + #log.debug("device name, device=%s",name) + dev_obj = self.bus.get_object ('org.freedesktop.Hal', name) + dev = dbus.Interface (dev_obj, 'org.freedesktop.Hal.Device') + dev_properties = dev_obj.GetAllProperties(dbus_interface="org.freedesktop.Hal.Device") + if dev_properties.has_key('block.device'): + dev_str = dev_properties['block.device'] + dev_major = dev_properties['block.major'] + dev_minor = dev_properties['block.minor'] + udi_info = {} + udi_info['device'] = dev_str + udi_info['major'] = dev_major + udi_info['minor'] = dev_minor + udi_info['udi'] = name + self.udi_dict[i] = udi_info + i = i + 1 + except Exception, ex: + print >>sys.stderr, 'Exception gathering block devices:', ex + log.warn("Exception gathering block devices (%s)",ex) + + # + def registerDeviceCallbacks(self): + # setup the callbacks for when the gdl changes + self.hal_manager.connect_to_signal('DeviceAdded', self.device_added_callback) + self.hal_manager.connect_to_signal('DeviceRemoved', self.device_removed_callback) + + # + def unRegisterDeviceCallbacks(self): + # setup the callbacks for when the gdl changes + self.hal_manager.remove_signal_receiver(self.device_added_callback,'DeviceAdded') + self.hal_manager.remove_signal_receiver(self.device_removed_callback,'DeviceRemoved') + + # + def device_removed_callback(self,udi): + log.debug('UDI %s was removed',udi) + self.show_dict(self.udi_dict) + for key in self.udi_dict: + udi_info = self.udi_dict[key] + if udi_info['udi'] == udi: + device = udi_info['device'] + major = udi_info['major'] + minor = udi_info['minor'] + self.change_xenstore( "remove", device, major, minor) + + # Adds device to dictionary if not already there + def device_added_callback(self,udi): + log.debug('UDI %s was added', udi) + self.show_dict(self.udi_dict) + dev_obj = self.bus.get_object ('org.freedesktop.Hal', udi) + dev = dbus.Interface (dev_obj, 'org.freedesktop.Hal.Device') + device = dev.GetProperty ('block.device') + major = dev.GetProperty ('block.major') + minor = dev.GetProperty ('block.minor') + udi_info = {} + udi_info['device'] = device + udi_info['major'] = major + udi_info['minor'] = minor + udi_info['udi'] = udi + already = 0 + cnt = 0; + for key in self.udi_dict: + info = self.udi_dict[key] + if info['udi'] == udi: + already = 1 + break + cnt = cnt + 1 + if already == 0: + self.udi_dict[cnt] = udi_info; + log.debug('UDI %s was added, device:%s major:%s minor:%s index:%d\n', udi, device, major, minor, cnt) + self.change_xenstore( "add", device, major, minor) + + # Debug helper, shows dictionary contents + def show_dict(self,dict=None): + if self.debug == 0 : + return + if dict == None : + dict = self.udi_dict + for key in dict: + log.debug('udi_info %s udi_info:%s',key,dict[key]) + + # Set or clear xenstore media-present depending on the action argument + # for every vbd that has this block device + def change_xenstore(self,action, device, major, minor): + for type in DEVICE_TYPES: + path = self.dbpath + '/' + type + domains = xstransact.List(path) + log.debug('domains: %s', domains) + for domain in domains: # for each domain + devices = xstransact.List( path + '/' + domain) + log.debug('devices: %s',devices) + for device in devices: # for each vbd device + str = device.split('/') + vbd_type = None; + vbd_physical_device = None + vbd_media = None + vbd_device_path = path + '/' + domain + '/' + device + listing = xstransact.List(vbd_device_path) + for entry in listing: # for each entry + item = path + '/' + entry + value = xstransact.Read( vbd_device_path + '/' + entry) + log.debug('%s=%s',item,value) + if item.find('media-present') != -1: + vbd_media = item; + vbd_media_path = item + if item.find('physical-device') != -1: + vbd_physical_device = value; + if item.find('type') != -1: + vbd_type = value; + if vbd_type is not None and vbd_physical_device is not None and vbd_media is not None : + inode = vbd_physical_device.split(':') + imajor = parse_hex(inode[0]) + iminor = parse_hex(inode[1]) + log.debug("action:%s major:%s- minor:%s- imajor:%s- iminor:%s- inode: %s", + action,major,minor, imajor, iminor, inode) + if int(imajor) == int(major) and int(iminor) == int(minor): + if action == "add": + xs_dict = {'media': "1"} + xstransact.Write(vbd_device_path, 'media-present', "1" ) + log.debug("wrote xenstore media-present 1 path:%s",vbd_media_path) + else: + xstransact.Write(vbd_device_path, 'media-present', "0" ) + log.debug("wrote xenstore media 0 path:%s",vbd_media_path) + +def mylog( fmt, *args): + f = open('/tmp/haldaemon.log', 'a') + print >>f, "HalDaemon ", fmt % args + f.close() + + +def parse_hex(val): + try: + if isinstance(val, types.StringTypes): + return int(val, 16) + else: + return val + except ValueError: + return None + +if __name__ == "__main__": + watcher = HalDaemon() + watcher.run() + print 'Falling off end' + + Index: xen-4.3.0-testing/tools/python/xen/xend/server/Hald.py =================================================================== --- /dev/null +++ xen-4.3.0-testing/tools/python/xen/xend/server/Hald.py @@ -0,0 +1,125 @@ +#============================================================================ +# 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) 2007 Pat Campbell +# Copyright (C) 2007 Novell Inc. +#============================================================================ + +import errno +import types +import os +import sys +import time +import signal +from traceback import print_exc + +from xen.xend.XendLogging import log + +class Hald: + def __init__(self): + self.ready = False + self.running = True + + def run(self): + """Starts the HalDaemon process + """ + self.ready = True + try: + myfile = self.find("xen/xend/server/HalDaemon.py") + args = (["python", myfile ]) + self.pid = self.daemonize("python", args ) + #log.debug( "%s %s pid:%d", "Hald.py starting ", args, self.pid ) + except: + self.pid = -1 + log.debug("Unable to start HalDaemon process") + + def shutdown(self): + """Shutdown the HalDaemon process + """ + log.debug("%s pid:%d", "Hald.shutdown()", self.pid) + self.running = False + self.ready = False + if self.pid != -1: + try: + os.kill(self.pid, signal.SIGINT) + except: + print_exc() + + def daemonize(self,prog, args): + """Runs a program as a daemon with the list of arguments. Returns the PID + of the daemonized program, or returns 0 on error. + Copied from xm/create.py instead of importing to reduce coupling + """ + r, w = os.pipe() + pid = os.fork() + + if pid == 0: + os.close(r) + w = os.fdopen(w, 'w') + os.setsid() + try: + pid2 = os.fork() + except: + pid2 = None + if pid2 == 0: + os.chdir("/") + env = os.environ.copy() + env['PYTHONPATH'] = self.getpythonpath() + for fd in range(0, 256): + try: + os.close(fd) + except: + pass + os.open("/dev/null", os.O_RDWR) + os.dup2(0, 1) + os.dup2(0, 2) + os.execvpe(prog, args, env) + os._exit(1) + else: + w.write(str(pid2 or 0)) + w.close() + os._exit(0) + os.close(w) + r = os.fdopen(r) + daemon_pid = int(r.read()) + r.close() + os.waitpid(pid, 0) + #log.debug( "daemon_pid: %d", daemon_pid ) + return daemon_pid + + def getpythonpath(self): + str = " " + for p in sys.path: + if str != " ": + str = str + ":" + p + else: + if str != "": + str = p + return str + + def find(self,path, matchFunc=os.path.isfile): + """Find a module in the sys.path + From web page: http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52224 + """ + for dirname in sys.path: + candidate = os.path.join(dirname, path) + if matchFunc(candidate): + return candidate + raise Error("Can't find file %s" % path) + +if __name__ == "__main__": + watcher = Hald() + watcher.run() + time.sleep(10) + watcher.shutdown() Index: xen-4.3.0-testing/tools/python/xen/xend/server/SrvServer.py =================================================================== --- xen-4.3.0-testing.orig/tools/python/xen/xend/server/SrvServer.py +++ xen-4.3.0-testing/tools/python/xen/xend/server/SrvServer.py @@ -57,6 +57,7 @@ from xen.web.SrvDir import SrvDir from SrvRoot import SrvRoot from XMLRPCServer import XMLRPCServer +from xen.xend.server.Hald import Hald xoptions = XendOptions.instance() @@ -252,6 +253,8 @@ def _loadConfig(servers, root, reload): if xoptions.get_xend_unix_xmlrpc_server(): servers.add(XMLRPCServer(XendAPI.AUTH_PAM, False)) + servers.add(Hald()) + def create(): root = SrvDir() Index: xen-4.3.0-testing/tools/qemu-xen-traditional-dir-remote/xenstore.c =================================================================== --- xen-4.3.0-testing.orig/tools/qemu-xen-traditional-dir-remote/xenstore.c +++ xen-4.3.0-testing/tools/qemu-xen-traditional-dir-remote/xenstore.c @@ -18,12 +18,14 @@ #include "exec-all.h" #include "sysemu.h" +#include "console.h" #include "hw.h" #include "pci.h" #include "qemu-timer.h" #include "qemu-xen.h" #include "xen_backend.h" +extern DisplayState *display_state; struct xs_handle *xsh = NULL; static char *media_filename[MAX_DRIVES+1]; static QEMUTimer *insert_timer = NULL; @@ -133,7 +135,8 @@ static void insert_media(void *opaque) else format = &bdrv_raw; - bdrv_open2(bs, media_filename[i], 0, format); + /* Temporary BDRV_O_RDWR */ + bdrv_open2(bs, media_filename[i], BDRV_O_RDWR, format); #ifdef CONFIG_STUBDOM { char *buf, *backend, *params_path, *params; @@ -443,13 +446,13 @@ void xenstore_init(void) } } -void xenstore_parse_domain_config(int hvm_domid) +void xenstore_parse_domain_config(int hvm_domid, QEMUMachine *machine) { char **e_danger = NULL; char *buf = NULL; - char *fpath = NULL, *bpath = NULL, + char *fpath = NULL, *bpath = NULL, *btype = NULL, *dev = NULL, *params = NULL, *drv = NULL; - int i, ret; + int i, j, ret, is_tap; unsigned int len, num, hd_index, pci_devid = 0; BlockDriverState *bs; BlockDriver *format; @@ -486,6 +489,14 @@ void xenstore_parse_domain_config(int hv e_danger[i]); if (bpath == NULL) continue; + /* check to see if type is tap or not */ + if (pasprintf(&buf, "%s/type", bpath) == -1) + continue; + free(btype); + btype = xs_read(xsh, XBT_NULL, buf, &len); + if (btype == NULL) + continue; + is_tap = !strncmp(btype, "tap", 3); /* read the name of the device */ if (pasprintf(&buf, "%s/dev", bpath) == -1) continue; @@ -500,7 +511,8 @@ void xenstore_parse_domain_config(int hv } for (i = 0; i < num; i++) { - format = NULL; /* don't know what the format is yet */ + flags = 0; + format = NULL; /* don't know what the format is yet */ /* read the backend path */ xenstore_get_backend_path(&bpath, "vbd", danger_path, hvm_domid, e_danger[i]); if (bpath == NULL) @@ -525,12 +537,7 @@ void xenstore_parse_domain_config(int hv continue; free(danger_type); danger_type = xs_read(xsh, XBT_NULL, danger_buf, &len); - if (pasprintf(&buf, "%s/params", bpath) == -1) - continue; - free(params); - params = xs_read(xsh, XBT_NULL, buf, &len); - if (params == NULL) - continue; + /* read the name of the device */ if (pasprintf(&buf, "%s/type", bpath) == -1) continue; @@ -538,6 +545,35 @@ void xenstore_parse_domain_config(int hv drv = xs_read(xsh, XBT_NULL, buf, &len); if (drv == NULL) continue; + + free(params); + if (!strcmp(drv,"iscsi") || !strcmp(drv, "npiv") || + !strcmp(drv,"dmmd")) { + if (pasprintf(&buf, "%s/node", bpath) == -1) + continue; + + /* wait for block-[iscsi|npiv|dmmd] script to complete and populate the + * node entry. try 30 times (30 secs) */ + for (j = 0; j < 30; j++) { + params = xs_read(xsh, XBT_NULL, buf, &len); + if (params != NULL) + break; + sleep(1); + } + if (params == NULL) { + fprintf(stderr, "qemu: %s device not found -- timed out \n", drv); + continue; + } + } + else + { + if (pasprintf(&buf, "%s/params", bpath) == -1) + continue; + params = xs_read(xsh, XBT_NULL, buf, &len); + if (params == NULL) + continue; + } + /* Obtain blktap sub-type prefix */ if ((!strcmp(drv, "tap") || !strcmp(drv, "qdisk")) && params[0]) { char *offset = strchr(params, ':'); @@ -562,6 +598,17 @@ void xenstore_parse_domain_config(int hv format = &bdrv_raw; } + /* read the mode of the device */ + if (pasprintf(&buf, "%s/mode", bpath) == -1) + continue; + free(mode); + mode = xs_read(xsh, XBT_NULL, buf, &len); + + if (!strcmp(mode, "r") || !strcmp(mode, "ro")) + flags |= BDRV_O_RDONLY; + if (!strcmp(mode, "w") || !strcmp(mode, "rw")) + flags |= BDRV_O_RDWR; + #if 0 /* Phantom VBDs are disabled because the use of paths * from guest-controlled areas in xenstore is unsafe. @@ -596,6 +643,21 @@ void xenstore_parse_domain_config(int hv #endif bs = bdrv_new(dev); + + /* if cdrom physical put a watch on media-present */ + if (bdrv_get_type_hint(bs) == BDRV_TYPE_CDROM) { + if (drv && !strcmp(drv, "phy")) { + if (pasprintf(&buf, "%s/media-present", bpath) != -1) { + if (bdrv_is_inserted(bs)) + xs_write(xsh, XBT_NULL, buf, "1", strlen("1")); + else { + xs_write(xsh, XBT_NULL, buf, "0", strlen("0")); + } + xs_watch(xsh, buf, "media-present"); + } + } + } + /* check if it is a cdrom */ if (danger_type && !strcmp(danger_type, "cdrom")) { bdrv_set_type_hint(bs, BDRV_TYPE_CDROM); @@ -614,7 +676,7 @@ void xenstore_parse_domain_config(int hv #ifdef CONFIG_STUBDOM if (pasprintf(&danger_buf, "%s/device/vbd/%s", danger_path, e_danger[i]) == -1) continue; - if (bdrv_open2(bs, danger_buf, BDRV_O_CACHE_WB /* snapshot and write-back */, &bdrv_raw) == 0) { + if (bdrv_open2(bs, danger_buf, flags|BDRV_O_CACHE_WB /* snapshot and write-back */, &bdrv_raw) == 0) { if (pasprintf(&buf, "%s/params", bpath) == -1) continue; free(params); @@ -640,6 +702,12 @@ void xenstore_parse_domain_config(int hv format = &bdrv_host_device; else format = &bdrv_raw; + } else if (!strcmp(drv,"iscsi")) { + format = &bdrv_raw; + } else if (!strcmp(drv,"npiv")) { + format = &bdrv_raw; + } else if (!strcmp(drv,"dmmd")) { + format = &bdrv_raw; } else { format = bdrv_find_format(drv); if (!format) { @@ -672,11 +740,19 @@ void xenstore_parse_domain_config(int hv #endif - drives_table[nb_drives].bdrv = bs; - drives_table[nb_drives].used = 1; - media_filename[nb_drives] = strdup(bs->filename); - nb_drives++; - + if (machine == &xenfv_machine) { + drives_table[nb_drives].bdrv = bs; + drives_table[nb_drives].used = 1; +#ifdef CONFIG_STUBDOM + media_filename[nb_drives] = strdup(danger_buf); +#else + media_filename[nb_drives] = strdup(bs->filename); +#endif + nb_drives++; + } else { + qemu_aio_flush(); + bdrv_close(bs); + } } #ifdef CONFIG_STUBDOM @@ -762,6 +838,7 @@ void xenstore_parse_domain_config(int hv free(mode); free(params); free(dev); + free(btype); free(bpath); free(buf); free(danger_buf); @@ -872,6 +949,19 @@ static void xenstore_process_dm_command_ } else if (!strncmp(command, "continue", len)) { fprintf(logfile, "dm-command: continue after state save\n"); xen_pause_requested = 0; + } else if (!strncmp(command, "chgvncpasswd", len)) { + fprintf(logfile, "dm-command: change vnc passwd\n"); + if (pasprintf(&path, + "/local/domain/0/backend/vfb/%u/0/vncpasswd", domid) == -1) { + fprintf(logfile, "out of memory reading dm command parameter\n"); + goto out; + } + par = xs_read(xsh, XBT_NULL, path, &len); + if (!par) + goto out; + if (vnc_display_password(display_state, par) == 0) + xenstore_record_dm_state("vncpasswdchged"); + free(par); } else if (!strncmp(command, "usb-add", len)) { fprintf(logfile, "dm-command: usb-add a usb device\n"); if (pasprintf(&path, @@ -930,6 +1020,9 @@ static void xenstore_process_dm_command_ do_pci_add(par); free(par); #endif + } else if (!strncmp(command, "flush-cache", len)) { + fprintf(logfile, "dm-command: flush caches\n"); + qemu_invalidate_map_cache(); } else { fprintf(logfile, "dm-command: unknown command\"%*s\"\n", len, command); } @@ -1086,6 +1179,50 @@ static void xenstore_process_vcpu_set_ev return; } +static void xenstore_process_media_change_event(char **vec) +{ + char *media_present = NULL; + unsigned int len; + + media_present = xs_read(xsh, XBT_NULL, vec[XS_WATCH_PATH], &len); + + if (media_present) { + BlockDriverState *bs; + char *buf = NULL, *cp = NULL, *path = NULL, *dev = NULL; + + path = strdup(vec[XS_WATCH_PATH]); + cp = strstr(path, "media-present"); + if (cp){ + *(cp-1) = '\0'; + pasprintf(&buf, "%s/dev", path); + dev = xs_read(xsh, XBT_NULL, buf, &len); + if (dev) { + if ( !strncmp(dev, "xvd", 3)) { + memmove(dev, dev+1, strlen(dev)); + dev[0] = 'h'; + dev[1] = 'd'; + } + bs = bdrv_find(dev); + if (!bs) { + term_printf("device not found\n"); + return; + } + if (strcmp(media_present, "0") == 0 && bs) { + bdrv_close(bs); + } + else if (strcmp(media_present, "1") == 0 && + bs != NULL && bs->drv == NULL) { + if (bdrv_open(bs, bs->filename, 0 /* snapshot */) < 0) { + fprintf(logfile, "%s() qemu: could not open cdrom disk '%s'\n", + __func__, bs->filename); + } + bs->media_changed = 1; + } + } + } + } +} + void xenstore_process_event(void *opaque) { char **vec, *offset, *bpath = NULL, *buf = NULL, *drv = NULL, *image = NULL; @@ -1121,6 +1258,11 @@ void xenstore_process_event(void *opaque xenstore_watch_callbacks[i].cb(vec[XS_WATCH_TOKEN], xenstore_watch_callbacks[i].opaque); + if (!strcmp(vec[XS_WATCH_TOKEN], "media-present")) { + xenstore_process_media_change_event(vec); + goto out; + } + hd_index = drive_name_to_index(vec[XS_WATCH_TOKEN]); if (hd_index == -1) { fprintf(stderr,"medium change watch on `%s' -" Index: xen-4.3.0-testing/tools/python/xen/xend/XendAuthSessions.py =================================================================== --- xen-4.3.0-testing.orig/tools/python/xen/xend/XendAuthSessions.py +++ xen-4.3.0-testing/tools/python/xen/xend/XendAuthSessions.py @@ -84,7 +84,7 @@ class XendAuthSessions: # if PAM doesn't exist, let's ignore it return False - pam_auth.start("login") + pam_auth.start("xen-api") pam_auth.set_item(PAM.PAM_USER, username) def _pam_conv(auth, query_list, user_data = None): Index: xen-4.3.0-testing/tools/qemu-xen-traditional-dir-remote/Makefile =================================================================== --- xen-4.3.0-testing.orig/tools/qemu-xen-traditional-dir-remote/Makefile +++ xen-4.3.0-testing/tools/qemu-xen-traditional-dir-remote/Makefile @@ -46,14 +46,6 @@ $(filter %-user,$(SUBDIR_RULES)): libqem recurse-all: $(SUBDIR_RULES) -CPPFLAGS += -I$(XEN_ROOT)/tools/libxc -CPPFLAGS += -I$(XEN_ROOT)/tools/blktap/lib -CPPFLAGS += -I$(XEN_ROOT)/tools/xenstore -CPPFLAGS += -I$(XEN_ROOT)/tools/include - -tapdisk-ioemu: tapdisk-ioemu.c cutils.c block.c block-raw.c block-cow.c block-qcow.c aes.c block-vmdk.c block-cloop.c block-dmg.c block-bochs.c block-vpc.c block-vvfat.c block-qcow2.c hw/xen_blktap.c osdep.c - $(CC) -DQEMU_TOOL $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) $(LDFLAGS) $(BASE_LDFLAGS) -o $@ $^ -lz $(LIBS) - ####################################################################### # BLOCK_OBJS is code used by both qemu system emulation and qemu-img @@ -72,6 +64,21 @@ endif BLOCK_OBJS += block-raw-posix.o endif +####################################################################### +# tapdisk-ioemu + +hw/tapdisk-xen_blktap.o: hw/xen_blktap.c + $(CC) $(CFLAGS) $(CPPFLAGS) -DQEMU_IMG -DQEMU_TOOL -c -o $@ $< +tapdisk-ioemu.o: tapdisk-ioemu.c + $(CC) $(CFLAGS) $(CPPFLAGS) -DQEMU_IMG -DQEMU_TOOL -c -o $@ $< + +tapdisk-ioemu: CPPFLAGS += -I$(XEN_ROOT)/tools/libxc +tapdisk-ioemu: CPPFLAGS += -I$(XEN_ROOT)/tools/blktap/lib +tapdisk-ioemu: CPPFLAGS += -I$(XEN_ROOT)/tools/xenstore +tapdisk-ioemu: CPPFLAGS += -I$(XEN_ROOT)/tools/include +tapdisk-ioemu: tapdisk-ioemu.o $(BLOCK_OBJS) qemu-tool.o hw/tapdisk-xen_blktap.o + $(CC) $(LDFLAGS) -o $@ $^ -lz $(LIBS) + ###################################################################### # libqemu_common.a: Target independent part of system emulation. The # long term path is to suppress *all* target specific code in case of @@ -243,7 +250,7 @@ endif install: all $(if $(BUILD_DOCS),install-doc) mkdir -p "$(DESTDIR)$(bindir)" ifneq ($(TOOLS),) - $(INSTALL) -m 755 -s $(TOOLS) "$(DESTDIR)$(bindir)" + $(INSTALL) -m 755 $(TOOLS) "$(DESTDIR)$(bindir)" endif ifneq ($(BLOBS),) mkdir -p "$(DESTDIR)$(datadir)" Index: xen-4.3.0-testing/tools/qemu-xen-traditional-dir-remote/Makefile.target =================================================================== --- xen-4.3.0-testing.orig/tools/qemu-xen-traditional-dir-remote/Makefile.target +++ xen-4.3.0-testing/tools/qemu-xen-traditional-dir-remote/Makefile.target @@ -580,6 +580,10 @@ OBJS += e1000.o # Serial mouse OBJS += msmouse.o +# Generic watchdog support and some watchdog devices +OBJS += watchdog.o +OBJS += wdt_ib700.o wdt_i6300esb.o + ifeq ($(TARGET_BASE_ARCH), i386) # Hardware support ifdef CONFIG_AUDIO @@ -755,7 +759,7 @@ clean: install: all install-hook ifneq ($(PROGS),) - $(INSTALL) -m 755 -s $(PROGS) "$(DESTDIR)$(bindir)" + $(INSTALL) -m 755 $(PROGS) "$(DESTDIR)$(bindir)" endif # Include automatically generated dependency files Index: xen-4.3.0-testing/tools/python/xen/xend/XendCheckpoint.py =================================================================== --- xen-4.3.0-testing.orig/tools/python/xen/xend/XendCheckpoint.py +++ xen-4.3.0-testing/tools/python/xen/xend/XendCheckpoint.py @@ -123,6 +123,11 @@ def save(fd, dominfo, network, live, dst str(int(live) | (int(hvm) << 2)) ] log.debug("[xc_save]: %s", string.join(cmd)) + # It is safe to release the domain lock at this point if not + # checkpointing + if checkpoint == False: + dominfo.release_running_lock(domain_name) + def saveInputHandler(line, tochild): log.debug("In saveInputHandler %s", line) if line == "suspend": @@ -172,7 +177,10 @@ def save(fd, dominfo, network, live, dst dominfo.destroy() dominfo.testDeviceComplete() try: - dominfo.setName(domain_name, False) + if checkpoint: + dominfo.setName(domain_name) + else: + dominfo.setName(domain_name, False) except VmError: # Ignore this. The name conflict (hopefully) arises because we # are doing localhost migration; if we are doing a suspend of a @@ -184,6 +192,9 @@ def save(fd, dominfo, network, live, dst log.exception("Save failed on domain %s (%s) - resuming.", domain_name, dominfo.getDomid()) dominfo.resumeDomain() + # Reacquire the domain lock + if checkpoint == False: + dominfo.acquire_running_lock() try: dominfo.setName(domain_name) @@ -326,8 +337,7 @@ def restore(xd, fd, dominfo = None, paus restore_image.setCpuid() # xc_restore will wait for source to close connection - - dominfo.completeRestore(handler.store_mfn, handler.console_mfn) + dominfo.completeRestore(handler.store_mfn, handler.console_mfn, console_port) # # We shouldn't hold the domains_lock over a waitForDevices @@ -351,6 +361,7 @@ def restore(xd, fd, dominfo = None, paus if not paused: dominfo.unpause() + dominfo.acquire_running_lock() return dominfo except Exception, exn: dominfo.destroy() Index: xen-4.3.0-testing/tools/python/xen/xend/XendAPI.py =================================================================== --- xen-4.3.0-testing.orig/tools/python/xen/xend/XendAPI.py +++ xen-4.3.0-testing/tools/python/xen/xend/XendAPI.py @@ -1941,10 +1941,10 @@ class XendAPI(object): bool(live), port, node, ssl, bool(chs)) return xen_api_success_void() - def VM_save(self, _, vm_ref, dest, checkpoint): + def VM_save(self, _, vm_ref, dest, checkpoint, force): xendom = XendDomain.instance() xeninfo = xendom.get_vm_by_uuid(vm_ref) - xendom.domain_save(xeninfo.getDomid(), dest, checkpoint) + xendom.domain_save(xeninfo.getDomid(), dest, checkpoint, force) return xen_api_success_void() def VM_restore(self, _, src, paused): Index: xen-4.3.0-testing/tools/python/xen/xend/XendDomain.py =================================================================== --- xen-4.3.0-testing.orig/tools/python/xen/xend/XendDomain.py +++ xen-4.3.0-testing/tools/python/xen/xend/XendDomain.py @@ -1505,7 +1505,7 @@ class XendDomain: pass sock.close() - def domain_save(self, domid, dst, checkpoint=False): + def domain_save(self, domid, dst, checkpoint=False, force=False): """Start saving a domain to file. @param domid: Domain ID or Name @@ -1521,6 +1521,9 @@ class XendDomain: if not dominfo: raise XendInvalidDomain(str(domid)) + if os.access(dst, os.F_OK) and not force: + raise XendError("Save file:%s exist!\n" % dst) + if dominfo.getDomid() == DOM0_ID: raise XendError("Cannot save privileged domain %s" % str(domid)) if dominfo._stateGet() != DOM_STATE_RUNNING: @@ -1832,6 +1835,21 @@ class XendDomain: log.exception(ex) raise XendError(str(ex)) + def domain_swaptarget_set(self, domid, mem): + """Set the memory limit for a domain. + + @param domid: Domain ID or Name + @type domid: int or string. + @param mem: memory limit (in MiB) + @type mem: int + @raise XendError: fail to set memory + @rtype: 0 + """ + dominfo = self.domain_lookup_nr(domid) + if not dominfo: + raise XendInvalidDomain(str(domid)) + dominfo.setSwapTarget(mem) + def domain_maxmem_set(self, domid, mem): """Set the memory limit for a domain. Index: xen-4.3.0-testing/tools/python/xen/xend/XendAPIConstants.py =================================================================== --- xen-4.3.0-testing.orig/tools/python/xen/xend/XendAPIConstants.py +++ xen-4.3.0-testing/tools/python/xen/xend/XendAPIConstants.py @@ -45,8 +45,10 @@ XEN_API_ON_NORMAL_EXIT = [ XEN_API_ON_CRASH_BEHAVIOUR = [ 'destroy', 'coredump_and_destroy', + 'coredump_destroy', 'restart', 'coredump_and_restart', + 'coredump_restart', 'preserve', 'rename_restart' ] Index: xen-4.3.0-testing/tools/python/xen/xend/XendConfig.py =================================================================== --- xen-4.3.0-testing.orig/tools/python/xen/xend/XendConfig.py +++ xen-4.3.0-testing/tools/python/xen/xend/XendConfig.py @@ -147,6 +147,11 @@ XENAPI_PLATFORM_CFG_TYPES = { 'apic': int, 'boot': str, 'device_model': str, + 'actmem': str, + 'xenpaging_file': str, + 'xenpaging_extra': str, + 'smbios_firmware': str, + 'acpi_firmware': str, 'loader': str, 'display' : str, 'fda': str, @@ -159,6 +164,7 @@ XENAPI_PLATFORM_CFG_TYPES = { 'nographic': int, 'nomigrate': int, 'pae' : int, + 'extid': int, 'rtc_timeoffset': int, 'parallel': str, 'serial': str, @@ -192,6 +198,8 @@ XENAPI_PLATFORM_CFG_TYPES = { 'xen_platform_pci': int, "gfx_passthru": int, 'oos' : int, + 'watchdog': str, + 'watchdog_action': str, } # Xen API console 'other_config' keys. @@ -512,8 +520,20 @@ class XendConfig(dict): self['platform']['nomigrate'] = 0 if self.is_hvm(): + if 'actmem' not in self['platform']: + self['platform']['actmem'] = "0" + if 'xenpaging_file' not in self['platform']: + self['platform']['xenpaging_file'] = "" + if 'xenpaging_extra' not in self['platform']: + self['platform']['xenpaging_extra'] = [] + if 'smbios_firmware' not in self['platform']: + self['platform']['smbios_firmware'] = "" + if 'acpi_firmware' not in self['platform']: + self['platform']['acpi_firmware'] = "" if 'timer_mode' not in self['platform']: self['platform']['timer_mode'] = 1 + if 'extid' in self['platform'] and int(self['platform']['extid']) == 1: + self['platform']['viridian'] = 1 if 'viridian' not in self['platform']: self['platform']['viridian'] = 0 if 'rtc_timeoffset' not in self['platform']: @@ -1865,7 +1885,14 @@ class XendConfig(dict): ports = sxp.child(dev_sxp, 'port') for port in ports[1:]: try: - num, bus = port + # When ['port' ['1','']] is saved into sxp file, it will become (port (1 )) + # If using this sxp file, here variable "port" will be port=1, + # we should process it, otherwise, it will report error. + if len(port) == 1: + num = port[0] + bus = "" + else: + num, bus = port dev_config['port-%i' % int(num)] = str(bus) except TypeError: pass Index: xen-4.3.0-testing/tools/qemu-xen-traditional-dir-remote/hw/xen_console.c =================================================================== --- xen-4.3.0-testing.orig/tools/qemu-xen-traditional-dir-remote/hw/xen_console.c +++ xen-4.3.0-testing/tools/qemu-xen-traditional-dir-remote/hw/xen_console.c @@ -38,6 +38,8 @@ #include "qemu-char.h" #include "xen_backend.h" +static int log_guest = 0; + struct buffer { uint8_t *data; size_t consumed; @@ -54,8 +56,24 @@ struct XenConsole { void *sring; CharDriverState *chr; int backlog; + int log_fd; }; +static int write_all(int fd, const char* buf, size_t len) +{ + while (len) { + ssize_t ret = write(fd, buf, len); + if (ret == -1 && errno == EINTR) + continue; + if (ret < 0) + return -1; + len -= ret; + buf += ret; + } + + return 0; +} + static void buffer_append(struct XenConsole *con) { struct buffer *buffer = &con->buffer; @@ -83,6 +101,15 @@ static void buffer_append(struct XenCons intf->out_cons = cons; xen_be_send_notify(&con->xendev); + if (con->log_fd != -1) { + int logret; + logret = write_all(con->log_fd, buffer->data + buffer->size - size, size); + if (logret < 0) { + xen_be_printf(&con->xendev, 1, "Write to log failed on domain %d: %d (%s)\n", + con->xendev.dom, errno, strerror(errno)); + } + } + if (buffer->max_capacity && buffer->size > buffer->max_capacity) { /* Discard the middle of the data. */ @@ -176,6 +203,37 @@ static void xencons_send(struct XenConso } } +static int create_domain_log(struct XenConsole *con) +{ + char *logfile; + char *path, *domname; + int fd; + const char *logdir = "/var/log/xen/console"; + + path = xs_get_domain_path(xenstore, con->xendev.dom); + domname = xenstore_read_str(path, "name"); + free(path); + if (!domname) + return -1; + + if (mkdir(logdir, 0755) && errno != EEXIST) + { + xen_be_printf(&con->xendev, 1, "Directory %s does not exist and fail to create it!", logdir); + return -1; + } + + if (asprintf(&logfile, "%s/guest-%s.log", logdir, domname) < 0) + return -1; + qemu_free(domname); + + fd = open(logfile, O_WRONLY|O_CREAT|O_APPEND, 0644); + free(logfile); + if (fd == -1) + xen_be_printf(&con->xendev, 1, "Failed to open log %s: %d (%s)", logfile, errno, strerror(errno)); + + return fd; +} + /* -------------------------------------------------------------------- */ static int con_init(struct XenDevice *xendev) @@ -183,6 +241,7 @@ static int con_init(struct XenDevice *xe struct XenConsole *con = container_of(xendev, struct XenConsole, xendev); char *type, *dom, label[32]; const char *output; + char *logenv = NULL; /* setup */ dom = xs_get_domain_path(xenstore, con->xendev.dom); @@ -209,6 +268,10 @@ static int con_init(struct XenDevice *xe con->chr = qemu_chr_open(label, output, NULL); xenstore_store_pv_console_info(con->xendev.dev, con->chr, output); + logenv = getenv("XENCONSOLED_TRACE"); + if (logenv != NULL && strlen(logenv) == strlen("guest") && !strcmp(logenv, "guest")) { + log_guest = 1; + } return 0; } @@ -246,6 +309,9 @@ static int con_initialise(struct XenDevi con->xendev.remote_port, con->xendev.local_port, con->buffer.max_capacity); + con->log_fd = -1; + if (log_guest) + con->log_fd = create_domain_log(con); return 0; } @@ -266,6 +332,12 @@ static void con_disconnect(struct XenDev xc_gnttab_munmap(xendev->gnttabdev, con->sring, 1); con->sring = NULL; } + + if (con->log_fd != -1) { + close(con->log_fd); + con->log_fd = -1; + } + } static void con_event(struct XenDevice *xendev) Index: xen-4.3.0-testing/tools/python/xen/xm/xenapi_create.py =================================================================== --- xen-4.3.0-testing.orig/tools/python/xen/xm/xenapi_create.py +++ xen-4.3.0-testing/tools/python/xen/xm/xenapi_create.py @@ -740,7 +740,7 @@ class sxp2xml: if get_child_by_name(config, "maxmem"): memory.attributes["static_max"] = \ - str(int(get_child_by_name(config, "maxmem")*1024*1024)) + str(int(get_child_by_name(config, "maxmem"))*1024*1024) vm.appendChild(memory) @@ -1046,7 +1046,12 @@ class sxp2xml: 'acpi', 'apic', 'boot', + 'actmem', + 'xenpaging_file', + 'xenpaging_extra', 'device_model', + 'smbios_firmware', + 'acpi_firmware', 'loader', 'fda', 'fdb', @@ -1074,7 +1079,9 @@ class sxp2xml: 'xen_platform_pci', 'tsc_mode' 'description', - 'nomigrate' + 'nomigrate', + 'watchdog', + 'watchdog_action' ] platform_configs = [] Index: xen-4.3.0-testing/tools/qemu-xen-traditional-dir-remote/hw/xen_machine_fv.c =================================================================== --- xen-4.3.0-testing.orig/tools/qemu-xen-traditional-dir-remote/hw/xen_machine_fv.c +++ xen-4.3.0-testing/tools/qemu-xen-traditional-dir-remote/hw/xen_machine_fv.c @@ -270,6 +270,7 @@ void qemu_invalidate_entry(uint8_t *buff #endif /* defined(MAPCACHE) */ +extern void init_blktap(void); static void xen_init_fv(ram_addr_t ram_size, int vga_ram_size, const char *boot_device, @@ -295,6 +296,11 @@ static void xen_init_fv(ram_addr_t ram_s } #endif +#ifndef CONFIG_STUBDOM + /* Initialize tapdisk client */ + init_blktap(); +#endif + #ifdef CONFIG_STUBDOM /* the hvmop is not supported on older hypervisors */ xc_set_hvm_param(xc_handle, domid, HVM_PARAM_DM_DOMAIN, DOMID_SELF); #endif Index: xen-4.3.0-testing/tools/qemu-xen-traditional-dir-remote/hw/xen_blktap.c =================================================================== --- xen-4.3.0-testing.orig/tools/qemu-xen-traditional-dir-remote/hw/xen_blktap.c +++ xen-4.3.0-testing/tools/qemu-xen-traditional-dir-remote/hw/xen_blktap.c @@ -46,7 +46,7 @@ #define BLKTAP_CTRL_DIR "/var/run/tap" /* If enabled, print debug messages to stderr */ -#if 1 +#if 0 #define DPRINTF(_f, _a...) fprintf(stderr, __FILE__ ":%d: " _f, __LINE__, ##_a) #else #define DPRINTF(_f, _a...) ((void)0) @@ -65,6 +65,7 @@ int read_fd; int write_fd; static pid_t process; +int connected_disks = 0; fd_list_entry_t *fd_start = NULL; static void handle_blktap_iomsg(void* private); @@ -218,11 +219,13 @@ static int map_new_dev(struct td_state * return -1; } -static int open_disk(struct td_state *s, char *path, int readonly) +static int open_disk(struct td_state *s, char *path, int driver, int readonly) { BlockDriverState* bs; + BlockDriver* drv; char* devname; static int devnumber = 0; + int flags = readonly ? BDRV_O_RDONLY : BDRV_O_RDWR; int i; DPRINTF("Opening %s as blktap%d\n", path, devnumber); @@ -230,7 +233,25 @@ static int open_disk(struct td_state *s, bs = bdrv_new(devname); free(devname); - if (bdrv_open(bs, path, 0) != 0) { + /* Search for disk driver */ + for (i = 0; blktap_drivers[i].idnum >= 0; i++) { + if (blktap_drivers[i].idnum == driver) + break; + } + + if (blktap_drivers[i].idnum < 0) { + fprintf(stderr, "Could not find image format id %d\n", driver); + return -ENOMEM; + } + + drv = blktap_drivers[i].drv; + DPRINTF("%s driver specified\n", drv ? drv->format_name : "No"); + + /* Open the image + * Use BDRV_O_CACHE_WB for write-through caching, + * no flags for write-back caching + */ + if (bdrv_open2(bs, path, flags|BDRV_O_CACHE_WB, drv) != 0) { fprintf(stderr, "Could not open image file %s\n", path); return -ENOMEM; } @@ -240,6 +261,12 @@ static int open_disk(struct td_state *s, s->size = bs->total_sectors; s->sector_size = 512; + if (s->size == 0) { + fprintf(stderr, "Error: Disk image %s is too small\n", + path); + return -ENOMEM; + } + s->info = ((s->flags & TD_RDONLY) ? VDISK_READONLY : 0); #ifndef QEMU_TOOL @@ -337,6 +364,15 @@ static void qemu_send_responses(void* op } /** + * Callback function for AIO flush + */ +static void qemu_flush_response(void* opaque, int ret) { + if (ret != 0) { + DPRINTF("aio_flush: ret = %d (%s)\n", ret, strerror(-ret)); + } +} + +/** * Callback function for the IO message pipe. Reads requests from the ring * and processes them (call qemu read/write functions). * @@ -355,6 +391,7 @@ static void handle_blktap_iomsg(void* pr blkif_t *blkif = s->blkif; tapdev_info_t *info = s->ring_info; int page_size = getpagesize(); + int sync; struct aiocb_info *aiocb_info; @@ -387,7 +424,7 @@ static void handle_blktap_iomsg(void* pr /* Don't allow writes on readonly devices */ if ((s->flags & TD_RDONLY) && - (req->operation == BLKIF_OP_WRITE)) { + (req->operation != BLKIF_OP_READ)) { blkif->pending_list[idx].status = BLKIF_RSP_ERROR; goto send_response; } @@ -408,7 +445,7 @@ static void handle_blktap_iomsg(void* pr DPRINTF("Sector request failed:\n"); DPRINTF("%s request, idx [%d,%d] size [%llu], " "sector [%llu,%llu]\n", - (req->operation == BLKIF_OP_WRITE ? + (req->operation != BLKIF_OP_READ ? "WRITE" : "READ"), idx,i, (long long unsigned) @@ -421,8 +458,14 @@ static void handle_blktap_iomsg(void* pr blkif->pending_list[idx].secs_pending += nsects; - switch (req->operation) + sync = 0; + switch (req->operation) { + case BLKIF_OP_WRITE_BARRIER: + sync = 1; + bdrv_aio_flush(s->bs, qemu_flush_response, NULL); + /* fall through */ + case BLKIF_OP_WRITE: aiocb_info = malloc(sizeof(*aiocb_info)); @@ -442,6 +485,10 @@ static void handle_blktap_iomsg(void* pr DPRINTF("ERROR: bdrv_write() == NULL\n"); goto send_response; } + + if (sync) + bdrv_aio_flush(s->bs, qemu_flush_response, NULL); + break; case BLKIF_OP_READ: @@ -519,9 +566,10 @@ static void handle_blktap_ctrlmsg(void* /* Allocate the disk structs */ s = state_init(); + connected_disks++; /*Open file*/ - if (s == NULL || open_disk(s, path, msg->readonly)) { + if (s == NULL || open_disk(s, path, msg->drivertype, msg->readonly)) { msglen = sizeof(msg_hdr_t); msg->type = CTLMSG_IMG_FAIL; msg->len = msglen; @@ -569,7 +617,8 @@ static void handle_blktap_ctrlmsg(void* case CTLMSG_CLOSE: s = get_state(msg->cookie); if (s) unmap_disk(s); - break; + connected_disks--; + break; case CTLMSG_PID: memset(buf, 0x00, MSG_SIZE); Index: xen-4.3.0-testing/tools/qemu-xen-traditional-dir-remote/hw/xen_blktap.h =================================================================== --- xen-4.3.0-testing.orig/tools/qemu-xen-traditional-dir-remote/hw/xen_blktap.h +++ xen-4.3.0-testing/tools/qemu-xen-traditional-dir-remote/hw/xen_blktap.h @@ -52,4 +52,18 @@ typedef struct fd_list_entry { int init_blktap(void); +typedef struct disk_info { + int idnum; + struct BlockDriver *drv; +} disk_info_t; + +static disk_info_t blktap_drivers[] = { + { DISK_TYPE_AIO, &bdrv_raw }, + { DISK_TYPE_SYNC, &bdrv_raw }, + { DISK_TYPE_VMDK, &bdrv_vmdk }, + { DISK_TYPE_QCOW, &bdrv_qcow }, + { DISK_TYPE_QCOW2, &bdrv_qcow2 }, + { -1, NULL } +}; + #endif /*XEN_BLKTAP_H_*/ Index: xen-4.3.0-testing/tools/qemu-xen-traditional-dir-remote/configure =================================================================== --- xen-4.3.0-testing.orig/tools/qemu-xen-traditional-dir-remote/configure +++ xen-4.3.0-testing/tools/qemu-xen-traditional-dir-remote/configure @@ -1511,7 +1511,7 @@ bsd) ;; esac -tools= +tools="tapdisk-ioemu" if test `expr "$target_list" : ".*softmmu.*"` != 0 ; then tools="qemu-img\$(EXESUF) $tools" if [ "$linux" = "yes" ] ; then Index: xen-4.3.0-testing/tools/qemu-xen-traditional-dir-remote/qemu-tool.c =================================================================== --- xen-4.3.0-testing.orig/tools/qemu-xen-traditional-dir-remote/qemu-tool.c +++ xen-4.3.0-testing/tools/qemu-xen-traditional-dir-remote/qemu-tool.c @@ -68,7 +68,7 @@ void qemu_bh_delete(QEMUBH *bh) qemu_free(bh); } -int qemu_set_fd_handler2(int fd, +int __attribute__((weak)) qemu_set_fd_handler2(int fd, IOCanRWHandler *fd_read_poll, IOHandler *fd_read, IOHandler *fd_write, Index: xen-4.3.0-testing/tools/qemu-xen-traditional-dir-remote/tapdisk-ioemu.c =================================================================== --- xen-4.3.0-testing.orig/tools/qemu-xen-traditional-dir-remote/tapdisk-ioemu.c +++ xen-4.3.0-testing/tools/qemu-xen-traditional-dir-remote/tapdisk-ioemu.c @@ -12,34 +12,13 @@ extern void qemu_aio_init(void); extern void qemu_aio_poll(void); -extern void bdrv_init(void); - -extern void *qemu_mallocz(size_t size); -extern void qemu_free(void *ptr); extern void *fd_start; +extern int connected_disks; int domid = 0; FILE* logfile; -void term_printf(const char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - vprintf(fmt, ap); - va_end(ap); -} - -void term_print_filename(const char *filename) -{ - term_printf(filename); -} - - -typedef void IOReadHandler(void *opaque, const uint8_t *buf, int size); -typedef int IOCanRWHandler(void *opaque); -typedef void IOHandler(void *opaque); - typedef struct IOHandlerRecord { int fd; IOCanRWHandler *fd_read_poll; @@ -98,25 +77,29 @@ int main(void) int max_fd; fd_set rfds; struct timeval tv; - void *old_fd_start = NULL; + int old_connected_disks = 0; + + /* Daemonize */ + if (fork() != 0) + exit(0); - logfile = stderr; - bdrv_init(); - qemu_aio_init(); init_blktap(); - /* Daemonize */ - if (fork() != 0) - exit(0); - + logfile = fopen("/var/log/xen/tapdisk-ioemu.log", "a"); + if (logfile) { + setbuf(logfile, NULL); + fclose(stderr); + stderr = logfile; + } else { + logfile = stderr; + } + /* * Main loop: Pass events to the corrsponding handlers and check for * completed aio operations. */ while (1) { - qemu_aio_poll(); - max_fd = -1; FD_ZERO(&rfds); for(ioh = first_io_handler; ioh != NULL; ioh = ioh->next) @@ -146,11 +129,17 @@ int main(void) pioh = &ioh->next; } + if (old_connected_disks != connected_disks) + fprintf(stderr, "connected disks: %d => %d\n", + old_connected_disks, connected_disks); + /* Exit when the last image has been closed */ - if (old_fd_start != NULL && fd_start == NULL) + if (old_connected_disks != 0 && connected_disks == 0) { + fprintf(stderr, "Last image is closed, exiting.\n"); exit(0); + } - old_fd_start = fd_start; + old_connected_disks = connected_disks; } return 0; } Index: xen-4.3.0-testing/tools/qemu-xen-traditional-dir-remote/block.c =================================================================== --- xen-4.3.0-testing.orig/tools/qemu-xen-traditional-dir-remote/block.c +++ xen-4.3.0-testing/tools/qemu-xen-traditional-dir-remote/block.c @@ -350,7 +350,7 @@ int bdrv_file_open(BlockDriverState **pb int bdrv_open(BlockDriverState *bs, const char *filename, int flags) { - return bdrv_open2(bs, filename, flags, NULL); + return bdrv_open2(bs, filename, flags|BDRV_O_RDWR, NULL); } int bdrv_open2(BlockDriverState *bs, const char *filename, int flags, @@ -419,12 +419,13 @@ int bdrv_open2(BlockDriverState *bs, con } bs->drv = drv; bs->opaque = qemu_mallocz(drv->instance_size); - /* Note: for compatibility, we open disk image files as RDWR, and - RDONLY as fallback */ if (!(flags & BDRV_O_FILE)) - open_flags = (flags & BDRV_O_ACCESS) | (flags & BDRV_O_CACHE_MASK); + open_flags = flags; else open_flags = flags & ~(BDRV_O_FILE | BDRV_O_SNAPSHOT); + if (!(open_flags & BDRV_O_RDWR)) + bs->read_only = 1; + ret = drv->bdrv_open(bs, filename, open_flags); if ((ret == -EACCES || ret == -EPERM) && !(flags & BDRV_O_FILE)) { ret = drv->bdrv_open(bs, filename, open_flags & ~BDRV_O_RDWR); @@ -595,6 +596,16 @@ int bdrv_read(BlockDriverState *bs, int6 if (bdrv_check_request(bs, sector_num, nb_sectors)) return -EIO; + + if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) { + memcpy(buf, bs->boot_sector_data, 512); + sector_num++; + nb_sectors--; + buf += 512; + if (nb_sectors == 0) + return 0; + } + if (drv->bdrv_pread) { int ret, len; len = nb_sectors * 512; @@ -630,6 +641,10 @@ int bdrv_write(BlockDriverState *bs, int if (bdrv_check_request(bs, sector_num, nb_sectors)) return -EIO; + if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) { + memcpy(bs->boot_sector_data, buf, 512); + } + if (drv->bdrv_pwrite) { int ret, len, count = 0; len = nb_sectors * 512; @@ -933,6 +948,16 @@ void bdrv_guess_geometry(BlockDriverStat } } +/* force a given boot sector. */ +void bdrv_set_boot_sector(BlockDriverState *bs, const uint8_t *data, int size) +{ + bs->boot_sector_enabled = 1; + if (size > 512) + size = 512; + memcpy(bs->boot_sector_data, data, size); + memset(bs->boot_sector_data + size, 0, 512 - size); +} + void bdrv_set_geometry_hint(BlockDriverState *bs, int cyls, int heads, int secs) { @@ -1463,6 +1488,14 @@ BlockDriverAIOCB *bdrv_aio_read(BlockDri if (bdrv_check_request(bs, sector_num, nb_sectors)) return NULL; + /* XXX: we assume that nb_sectors == 0 is suppored by the async read */ + if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) { + memcpy(buf, bs->boot_sector_data, 512); + sector_num++; + nb_sectors--; + buf += 512; + } + ret = drv->bdrv_aio_read(bs, sector_num, buf, nb_sectors, cb, opaque); if (ret) { @@ -1488,6 +1521,10 @@ BlockDriverAIOCB *bdrv_aio_write(BlockDr if (bdrv_check_request(bs, sector_num, nb_sectors)) return NULL; + if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) { + memcpy(bs->boot_sector_data, buf, 512); + } + ret = drv->bdrv_aio_write(bs, sector_num, buf, nb_sectors, cb, opaque); if (ret) { Index: xen-4.3.0-testing/tools/qemu-xen-traditional-dir-remote/hw/usb-msd.c =================================================================== --- xen-4.3.0-testing.orig/tools/qemu-xen-traditional-dir-remote/hw/usb-msd.c +++ xen-4.3.0-testing/tools/qemu-xen-traditional-dir-remote/hw/usb-msd.c @@ -551,7 +551,7 @@ USBDevice *usb_msd_init(const char *file s = qemu_mallocz(sizeof(MSDState)); bdrv = bdrv_new("usb"); - if (bdrv_open2(bdrv, filename, 0, drv) < 0) + if (bdrv_open2(bdrv, filename, BDRV_O_RDWR, drv) < 0) goto fail; s->bs = bdrv; *pbs = bdrv; Index: xen-4.3.0-testing/tools/qemu-xen-traditional-dir-remote/qemu-img.c =================================================================== --- xen-4.3.0-testing.orig/tools/qemu-xen-traditional-dir-remote/qemu-img.c +++ xen-4.3.0-testing/tools/qemu-xen-traditional-dir-remote/qemu-img.c @@ -32,7 +32,7 @@ #endif /* Default to cache=writeback as data integrity is not important for qemu-tcg. */ -#define BRDV_O_FLAGS BDRV_O_CACHE_WB +#define BDRV_O_FLAGS BDRV_O_CACHE_WB static void QEMU_NORETURN error(const char *fmt, ...) { @@ -185,7 +185,7 @@ static int read_password(char *buf, int #endif static BlockDriverState *bdrv_new_open(const char *filename, - const char *fmt) + const char *fmt, int flags) { BlockDriverState *bs; BlockDriver *drv; @@ -201,7 +201,7 @@ static BlockDriverState *bdrv_new_open(c } else { drv = &bdrv_raw; } - if (bdrv_open2(bs, filename, BRDV_O_FLAGS, drv) < 0) { + if (bdrv_open2(bs, filename, flags, drv) < 0) { error("Could not open '%s'", filename); } if (bdrv_is_encrypted(bs)) { @@ -253,7 +253,7 @@ static int img_create(int argc, char **a size = 0; if (base_filename) { BlockDriverState *bs; - bs = bdrv_new_open(base_filename, NULL); + bs = bdrv_new_open(base_filename, NULL, BDRV_O_RDWR); bdrv_get_geometry(bs, &size); size *= 512; bdrv_delete(bs); @@ -332,7 +332,7 @@ static int img_commit(int argc, char **a } else { drv = NULL; } - if (bdrv_open2(bs, filename, BRDV_O_FLAGS, drv) < 0) { + if (bdrv_open2(bs, filename, BDRV_O_RDWR, drv) < 0) { error("Could not open '%s'", filename); } ret = bdrv_commit(bs); @@ -455,7 +455,8 @@ static int img_convert(int argc, char ** total_sectors = 0; for (bs_i = 0; bs_i < bs_n; bs_i++) { - bs[bs_i] = bdrv_new_open(argv[optind + bs_i], fmt); + bs[bs_i] = bdrv_new_open(argv[optind + bs_i], fmt, + BDRV_O_CACHE_WB|BDRV_O_RDONLY); if (!bs[bs_i]) error("Could not open '%s'", argv[optind + bs_i]); bdrv_get_geometry(bs[bs_i], &bs_sectors); @@ -483,7 +484,7 @@ static int img_convert(int argc, char ** } } - out_bs = bdrv_new_open(out_filename, out_fmt); + out_bs = bdrv_new_open(out_filename, out_fmt, BDRV_O_CACHE_WB|BDRV_O_RDWR); bs_i = 0; bs_offset = 0; @@ -706,7 +707,7 @@ static int img_info(int argc, char **arg } else { drv = NULL; } - if (bdrv_open2(bs, filename, BRDV_O_FLAGS, drv) < 0) { + if (bdrv_open2(bs, filename, BDRV_O_FLAGS|BDRV_O_RDWR, drv) < 0) { error("Could not open '%s'", filename); } bdrv_get_format(bs, fmt_name, sizeof(fmt_name)); @@ -810,7 +811,7 @@ static void img_snapshot(int argc, char if (!bs) error("Not enough memory"); - if (bdrv_open2(bs, filename, 0, NULL) < 0) { + if (bdrv_open2(bs, filename, BDRV_O_RDWR, NULL) < 0) { error("Could not open '%s'", filename); } Index: xen-4.3.0-testing/tools/qemu-xen-traditional-dir-remote/block-qcow2.c =================================================================== --- xen-4.3.0-testing.orig/tools/qemu-xen-traditional-dir-remote/block-qcow2.c +++ xen-4.3.0-testing/tools/qemu-xen-traditional-dir-remote/block-qcow2.c @@ -916,7 +916,7 @@ static int alloc_cluster_link_l2(BlockDr goto err; for (i = 0; i < j; i++) - free_any_clusters(bs, old_cluster[i], 1); + free_any_clusters(bs, be64_to_cpu(old_cluster[i]) & ~QCOW_OFLAG_COPIED, 1); ret = 0; err: Index: xen-4.3.0-testing/tools/qemu-xen-traditional-dir-remote/hw/xen_platform.c =================================================================== --- xen-4.3.0-testing.orig/tools/qemu-xen-traditional-dir-remote/hw/xen_platform.c +++ xen-4.3.0-testing/tools/qemu-xen-traditional-dir-remote/hw/xen_platform.c @@ -30,6 +30,8 @@ #include "qemu-xen.h" #include "net.h" #include "xen_platform.h" +#include "sysemu.h" +#include #include #include @@ -335,11 +337,66 @@ static void xen_platform_ioport_writeb(v } } +static uint32_t ioport_base; + +static void platform_ioport_write(void *opaque, uint32_t addr, uint32_t val) +{ + DECLARE_DOMCTL; + int rc; + + if (val == 0) + qemu_invalidate_map_cache(); + + switch (addr - ioport_base) { + case 0: + fprintf(logfile, "Init hypercall page %x, addr %x.\n", val, addr); + domctl.domain = (domid_t)domid; + domctl.u.hypercall_init.gmfn = val; + domctl.cmd = XEN_DOMCTL_hypercall_init; + rc = xc_domctl(xc_handle, &domctl); + fprintf(logfile, "result -> %d.\n", rc); + break; + case 4: + fprintf(logfile, "Disconnect IDE hard disk...\n"); + ide_unplug_harddisks(); + fprintf(logfile, "Disconnect SCSI hard disk...\n"); + pci_unplug_scsi(); + fprintf(logfile, "Disconnect netifs...\n"); + pci_unplug_netifs(); + fprintf(logfile, "Shutdown taps...\n"); + net_tap_shutdown_all(); + fprintf(logfile, "Done.\n"); + break; + case 8: + if (val ==1 ) { + fprintf(logfile, "Disconnect IDE hard disk...\n"); + ide_unplug_harddisks(); + fprintf(logfile, "Done.\n"); + } else if (val == 2) { + fprintf(logfile, "Disconnect netifs...\n"); + pci_unplug_netifs(); + fprintf(logfile, "Shutdown taps...\n"); + net_tap_shutdown_all(); + fprintf(logfile, "Done.\n"); + } + break; + default: + fprintf(logfile, "Write to bad port %x (base %x) on evtchn device.\n", + addr, ioport_base); + break; + } +} + static void platform_ioport_map(PCIDevice *pci_dev, int region_num, uint32_t addr, uint32_t size, int type) { + ioport_base = addr; + + register_ioport_write(addr, 16, 4, platform_ioport_write, NULL); +/* PCIXenPlatformState *d = (PCIXenPlatformState *)pci_dev; register_ioport_write(addr, size, 1, xen_platform_ioport_writeb, d); register_ioport_read(addr, size, 1, xen_platform_ioport_readb, d); +*/ } static uint32_t platform_mmio_read(void *opaque, target_phys_addr_t addr) Index: xen-4.3.0-testing/tools/qemu-xen-traditional-dir-remote/hw/ide.c =================================================================== --- xen-4.3.0-testing.orig/tools/qemu-xen-traditional-dir-remote/hw/ide.c +++ xen-4.3.0-testing/tools/qemu-xen-traditional-dir-remote/hw/ide.c @@ -935,8 +935,9 @@ static inline void ide_dma_submit_check( static inline void ide_set_irq(IDEState *s) { - BMDMAState *bm = s->bmdma; - if (!s->bs) return; /* ouch! (see ide_flush_cb) */ + BMDMAState *bm; + if (!s || !s->bs) return; /* ouch! (see ide_flush_cb) */ + bm = s->bmdma; if (!(s->cmd & IDE_CMD_DISABLE_IRQ)) { if (bm) { bm->status |= BM_STATUS_INT; @@ -1224,14 +1225,14 @@ static void ide_read_dma_cb(void *opaque int n; int64_t sector_num; + if (!s || !s->bs) return; /* ouch! (see ide_flush_cb) */ + if (ret < 0) { dma_buf_commit(s, 1); ide_dma_error(s); return; } - if (!s->bs) return; /* ouch! (see ide_flush_cb) */ - n = s->io_buffer_size >> 9; sector_num = ide_get_sector(s); if (n > 0) { @@ -1335,6 +1336,8 @@ static void ide_write_flush_cb(void *opa BMDMAState *bm = opaque; IDEState *s = bm->ide_if; + if (!s) return; /* yikes */ + if (ret != 0) { ide_dma_error(s); return; @@ -1366,13 +1369,13 @@ static void ide_write_dma_cb(void *opaqu int n; int64_t sector_num; + if (!s || !s->bs) return; /* ouch! (see ide_flush_cb) */ + if (ret < 0) { if (ide_handle_write_error(s, -ret, BM_STATUS_DMA_RETRY)) return; } - if (!s->bs) return; /* ouch! (see ide_flush_cb) */ - n = s->io_buffer_size >> 9; sector_num = ide_get_sector(s); if (n > 0) { @@ -1429,7 +1432,7 @@ static void ide_flush_cb(void *opaque, i { IDEState *s = opaque; - if (!s->bs) return; /* ouch! (see below) */ + if (!s || !s->bs) return; /* ouch! (see below) */ if (ret) { /* We are completely doomed. The IDE spec does not permit us @@ -1686,7 +1689,7 @@ static void ide_atapi_cmd_read_dma_cb(vo IDEState *s = bm->ide_if; int data_offset, n; - if (!s->bs) return; /* ouch! (see ide_flush_cb) */ + if (!s || !s->bs) return; /* ouch! (see ide_flush_cb) */ if (ret < 0) { ide_atapi_io_error(s, ret); @@ -2365,7 +2368,7 @@ static void cdrom_change_cb(void *opaque IDEState *s = opaque; uint64_t nb_sectors; - if (!s->bs) return; /* ouch! (see ide_flush_cb) */ + if (!s || !s->bs) return; /* ouch! (see ide_flush_cb) */ bdrv_get_geometry(s->bs, &nb_sectors); s->nb_sectors = nb_sectors; Index: xen-4.3.0-testing/tools/qemu-xen-traditional-dir-remote/vl.c =================================================================== --- xen-4.3.0-testing.orig/tools/qemu-xen-traditional-dir-remote/vl.c +++ xen-4.3.0-testing/tools/qemu-xen-traditional-dir-remote/vl.c @@ -30,6 +30,7 @@ #include "hw/isa.h" #include "hw/baum.h" #include "hw/bt.h" +#include "hw/watchdog.h" #include "net.h" #include "console.h" #include "sysemu.h" @@ -200,7 +201,7 @@ DriveInfo drives_table[MAX_DRIVES+1]; int nb_drives; enum vga_retrace_method vga_retrace_method = VGA_RETRACE_DUMB; int vga_ram_size; -static DisplayState *display_state; +DisplayState *display_state; int nographic; static int curses; static int sdl; @@ -2627,6 +2628,8 @@ int drive_init(struct drive_opt *arg, in strncpy(drives_table[nb_drives].serial, serial, sizeof(serial)); nb_drives++; + bdrv_flags = BDRV_O_RDWR; + switch(type) { case IF_IDE: case IF_XEN: @@ -2640,6 +2643,7 @@ int drive_init(struct drive_opt *arg, in break; case MEDIA_CDROM: bdrv_set_type_hint(bdrv, BDRV_TYPE_CDROM); + bdrv_flags &= ~BDRV_O_RDWR; break; } break; @@ -2660,7 +2664,6 @@ int drive_init(struct drive_opt *arg, in } if (!file[0]) return -2; - bdrv_flags = 0; if (snapshot) { bdrv_flags |= BDRV_O_SNAPSHOT; cache = 2; /* always use write-back with snapshot */ @@ -4175,6 +4178,10 @@ static void help(int exitcode) "-startdate select initial date of the clock\n" "-icount [N|auto]\n" " enable virtual instruction counter with 2^N clock ticks per instruction\n" + "-watchdog i6300esb|ib700\n" + " enable virtual hardware watchdog [default=none]\n" + "-watchdog-action reset|shutdown|poweroff|pause|debug|none\n" + " action when watchdog fires [default=reset]\n" "-echr chr set terminal escape character instead of ctrl-a\n" "-virtioconsole c\n" " set virtio console\n" @@ -4322,6 +4329,8 @@ enum { QEMU_OPTION_localtime, QEMU_OPTION_startdate, QEMU_OPTION_icount, + QEMU_OPTION_watchdog, + QEMU_OPTION_watchdog_action, QEMU_OPTION_echr, QEMU_OPTION_virtiocon, QEMU_OPTION_show_cursor, @@ -4448,6 +4457,8 @@ static const QEMUOption qemu_options[] = { "localtime", 0, QEMU_OPTION_localtime }, { "startdate", HAS_ARG, QEMU_OPTION_startdate }, { "icount", HAS_ARG, QEMU_OPTION_icount }, + { "watchdog", HAS_ARG, QEMU_OPTION_watchdog }, + { "watchdog-action", HAS_ARG, QEMU_OPTION_watchdog_action }, { "echr", HAS_ARG, QEMU_OPTION_echr }, { "virtioconsole", HAS_ARG, QEMU_OPTION_virtiocon }, { "show-cursor", 0, QEMU_OPTION_show_cursor }, @@ -4949,6 +4960,8 @@ int main(int argc, char **argv, char **e tb_size = 0; autostart= 1; + register_watchdogs(); + optind = 1; for(;;) { if (optind >= argc) @@ -5323,6 +5336,17 @@ int main(int argc, char **argv, char **e serial_devices[serial_device_index] = optarg; serial_device_index++; break; + case QEMU_OPTION_watchdog: + i = select_watchdog(optarg); + if (i > 0) + exit (i == 1 ? 1 : 0); + break; + case QEMU_OPTION_watchdog_action: + if (select_watchdog_action(optarg) == -1) { + fprintf(stderr, "Unknown -watchdog-action parameter\n"); + exit(1); + } + break; case QEMU_OPTION_virtiocon: if (virtio_console_index >= MAX_VIRTIO_CONSOLES) { fprintf(stderr, "qemu: too many virtio consoles\n"); @@ -5838,9 +5862,9 @@ int main(int argc, char **argv, char **e if ((msg = xenbus_read(XBT_NIL, "domid", &domid_s))) fprintf(stderr,"Can not read our own domid: %s\n", msg); else - xenstore_parse_domain_config(atoi(domid_s)); + xenstore_parse_domain_config(atoi(domid_s), machine); #else - xenstore_parse_domain_config(domid); + xenstore_parse_domain_config(domid, machine); #endif /* CONFIG_STUBDOM */ } Index: xen-4.3.0-testing/tools/python/xen/xend/XendConstants.py =================================================================== --- xen-4.3.0-testing.orig/tools/python/xen/xend/XendConstants.py +++ xen-4.3.0-testing/tools/python/xen/xend/XendConstants.py @@ -94,7 +94,7 @@ DOM_STATES_OLD = [ SHUTDOWN_TIMEOUT = (60.0 * 5) """Minimum time between domain restarts in seconds.""" -MINIMUM_RESTART_TIME = 60 +MINIMUM_RESTART_TIME = 10 RESTART_IN_PROGRESS = 'xend/restart_in_progress' DUMPCORE_IN_PROGRESS = 'xend/dumpcore_in_progress' Index: xen-4.3.0-testing/tools/python/xen/xend/XendLogging.py =================================================================== --- xen-4.3.0-testing.orig/tools/python/xen/xend/XendLogging.py +++ xen-4.3.0-testing/tools/python/xen/xend/XendLogging.py @@ -76,7 +76,7 @@ if 'TRACE' not in logging.__dict__: log = logging.getLogger("xend") -MAX_BYTES = 1 << 20 # 1MB +MAX_BYTES = 0 BACKUP_COUNT = 5 STDERR_FORMAT = "[%(name)s] %(levelname)s (%(module)s:%(lineno)d) %(message)s" Index: xen-4.3.0-testing/tools/python/xen/xend/server/XMLRPCServer.py =================================================================== --- xen-4.3.0-testing.orig/tools/python/xen/xend/server/XMLRPCServer.py +++ xen-4.3.0-testing/tools/python/xen/xend/server/XMLRPCServer.py @@ -95,7 +95,7 @@ methods = ['device_create', 'device_conf 'destroyDevice','getDeviceSxprs', 'setMemoryTarget', 'setName', 'setVCpuCount', 'shutdown', 'send_sysrq', 'getVCPUInfo', 'waitForDevices', - 'getRestartCount', 'getBlockDeviceClass'] + 'getRestartCount', 'getBlockDeviceClass', 'chgvncpasswd'] exclude = ['domain_create', 'domain_restore'] Index: xen-4.3.0-testing/tools/qemu-xen-traditional-dir-remote/block_int.h =================================================================== --- xen-4.3.0-testing.orig/tools/qemu-xen-traditional-dir-remote/block_int.h +++ xen-4.3.0-testing/tools/qemu-xen-traditional-dir-remote/block_int.h @@ -122,6 +122,9 @@ struct BlockDriverState { BlockDriver *drv; /* NULL means no media */ void *opaque; + int boot_sector_enabled; + uint8_t boot_sector_data[512]; + char filename[1024]; char backing_file[1024]; /* if non zero, the image is a diff of this file image */ Index: xen-4.3.0-testing/tools/qemu-xen-traditional-dir-remote/block.h =================================================================== --- xen-4.3.0-testing.orig/tools/qemu-xen-traditional-dir-remote/block.h +++ xen-4.3.0-testing/tools/qemu-xen-traditional-dir-remote/block.h @@ -82,6 +82,7 @@ int64_t bdrv_getlength(BlockDriverState void bdrv_get_geometry(BlockDriverState *bs, uint64_t *nb_sectors_ptr); void bdrv_guess_geometry(BlockDriverState *bs, int *pcyls, int *pheads, int *psecs); int bdrv_commit(BlockDriverState *bs); +void bdrv_set_boot_sector(BlockDriverState *bs, const uint8_t *data, int size); /* async block I/O */ typedef struct BlockDriverAIOCB BlockDriverAIOCB; typedef void BlockDriverCompletionFunc(void *opaque, int ret); Index: xen-4.3.0-testing/tools/qemu-xen-traditional-dir-remote/hw/watchdog.c =================================================================== --- /dev/null +++ xen-4.3.0-testing/tools/qemu-xen-traditional-dir-remote/hw/watchdog.c @@ -0,0 +1,146 @@ +/* + * Virtual hardware watchdog. + * + * Copyright (C) 2009 Red Hat Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * By Richard W.M. Jones (rjones@redhat.com). + */ + +#include "qemu-common.h" +#include "sys-queue.h" +#include "sysemu.h" +#include "hw/watchdog.h" + +/* Possible values for action parameter. */ +#define WDT_RESET 1 /* Hard reset. */ +#define WDT_SHUTDOWN 2 /* Shutdown. */ +#define WDT_POWEROFF 3 /* Quit. */ +#define WDT_PAUSE 4 /* Pause. */ +#define WDT_DEBUG 5 /* Prints a message and continues running. */ +#define WDT_NONE 6 /* Do nothing. */ + +static WatchdogTimerModel *watchdog; +static int watchdog_action = WDT_RESET; +static LIST_HEAD(watchdog_list, WatchdogTimerModel) watchdog_list; + +void watchdog_add_model(WatchdogTimerModel *model) +{ + LIST_INSERT_HEAD(&watchdog_list, model, entry); +} + +/* Returns: + * 0 = continue + * 1 = exit program with error + * 2 = exit program without error + */ +int select_watchdog(const char *p) +{ + WatchdogTimerModel *model; + + if (watchdog) { + fprintf(stderr, + "qemu: only one watchdog option may be given\n"); + return 1; + } + + /* -watchdog ? lists available devices and exits cleanly. */ + if (strcmp(p, "?") == 0) { + LIST_FOREACH(model, &watchdog_list, entry) { + fprintf(stderr, "\t%s\t%s\n", + model->wdt_name, model->wdt_description); + } + return 2; + } + + LIST_FOREACH(model, &watchdog_list, entry) { + if (strcasecmp(model->wdt_name, p) == 0) { + watchdog = model; + return 0; + } + } + + fprintf(stderr, "Unknown -watchdog device. Supported devices are:\n"); + LIST_FOREACH(model, &watchdog_list, entry) { + fprintf(stderr, "\t%s\t%s\n", + model->wdt_name, model->wdt_description); + } + return 1; +} + +int select_watchdog_action(const char *p) +{ + if (strcasecmp(p, "reset") == 0) + watchdog_action = WDT_RESET; + else if (strcasecmp(p, "shutdown") == 0) + watchdog_action = WDT_SHUTDOWN; + else if (strcasecmp(p, "poweroff") == 0) + watchdog_action = WDT_POWEROFF; + else if (strcasecmp(p, "pause") == 0) + watchdog_action = WDT_PAUSE; + else if (strcasecmp(p, "debug") == 0) + watchdog_action = WDT_DEBUG; + else if (strcasecmp(p, "none") == 0) + watchdog_action = WDT_NONE; + else + return -1; + + return 0; +} + +/* This actually performs the "action" once a watchdog has expired, + * ie. reboot, shutdown, exit, etc. + */ +void watchdog_perform_action(void) +{ + switch(watchdog_action) { + case WDT_RESET: /* same as 'system_reset' in monitor */ + qemu_system_reset_request(); + break; + + case WDT_SHUTDOWN: /* same as 'system_powerdown' in monitor */ + qemu_system_powerdown_request(); + break; + + case WDT_POWEROFF: /* same as 'quit' command in monitor */ + exit(0); + break; + + case WDT_PAUSE: /* same as 'stop' command in monitor */ + vm_stop(0); + break; + + case WDT_DEBUG: + fprintf(stderr, "watchdog: timer fired\n"); + break; + + case WDT_NONE: + break; + } +} + +void watchdog_pc_init(PCIBus *pci_bus) +{ + if (watchdog) + watchdog->wdt_pc_init(pci_bus); +} + +void register_watchdogs(void) +{ + wdt_ib700_init(); + wdt_i6300esb_init(); +} Index: xen-4.3.0-testing/tools/qemu-xen-traditional-dir-remote/hw/watchdog.h =================================================================== --- /dev/null +++ xen-4.3.0-testing/tools/qemu-xen-traditional-dir-remote/hw/watchdog.h @@ -0,0 +1,54 @@ +/* + * Virtual hardware watchdog. + * + * Copyright (C) 2009 Red Hat Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * By Richard W.M. Jones (rjones@redhat.com). + */ + +#ifndef QEMU_WATCHDOG_H +#define QEMU_WATCHDOG_H + +extern void wdt_i6300esb_init(void); +extern void wdt_ib700_init(void); + + +struct WatchdogTimerModel { + LIST_ENTRY(WatchdogTimerModel) entry; + + /* Short name of the device - used to select it on the command line. */ + const char *wdt_name; + /* Longer description (eg. manufacturer and full model number). */ + const char *wdt_description; + + /* This callback should create/register the device. It is called + * indirectly from hw/pc.c when the virtual PC is being set up. + */ + void (*wdt_pc_init)(PCIBus *pci_bus); +}; +typedef struct WatchdogTimerModel WatchdogTimerModel; + +/* in hw/watchdog.c */ +extern int select_watchdog(const char *p); +extern int select_watchdog_action(const char *action); +extern void watchdog_add_model(WatchdogTimerModel *model); +extern void watchdog_perform_action(void); +extern void watchdog_pc_init(PCIBus *pci_bus); +extern void register_watchdogs(void); + +#endif /* QEMU_WATCHDOG_H */ Index: xen-4.3.0-testing/tools/qemu-xen-traditional-dir-remote/hw/wdt_i6300esb.c =================================================================== --- /dev/null +++ xen-4.3.0-testing/tools/qemu-xen-traditional-dir-remote/hw/wdt_i6300esb.c @@ -0,0 +1,470 @@ +/* + * Virtual hardware watchdog. + * + * Copyright (C) 2009 Red Hat Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * By Richard W.M. Jones (rjones@redhat.com). + */ + +#include + +#include "qemu-common.h" +#include "qemu-timer.h" +#include "watchdog.h" +#include "hw.h" +#include "isa.h" +#include "pc.h" +#include "pci.h" + +/*#define I6300ESB_DEBUG 1*/ + +#ifdef I6300ESB_DEBUG +#define i6300esb_debug(fs,...) \ + fprintf(stderr,"i6300esb: %s: "fs,__func__,##__VA_ARGS__) +#else +#define i6300esb_debug(fs,...) +#endif + +#ifndef PCI_DEVICE_ID_INTEL_ESB_9 +#define PCI_DEVICE_ID_INTEL_ESB_9 0x25ab +#endif + +/* PCI configuration registers */ +#define ESB_CONFIG_REG 0x60 /* Config register */ +#define ESB_LOCK_REG 0x68 /* WDT lock register */ + +/* Memory mapped registers (offset from base address) */ +#define ESB_TIMER1_REG 0x00 /* Timer1 value after each reset */ +#define ESB_TIMER2_REG 0x04 /* Timer2 value after each reset */ +#define ESB_GINTSR_REG 0x08 /* General Interrupt Status Register */ +#define ESB_RELOAD_REG 0x0c /* Reload register */ + +/* Lock register bits */ +#define ESB_WDT_FUNC (0x01 << 2) /* Watchdog functionality */ +#define ESB_WDT_ENABLE (0x01 << 1) /* Enable WDT */ +#define ESB_WDT_LOCK (0x01 << 0) /* Lock (nowayout) */ + +/* Config register bits */ +#define ESB_WDT_REBOOT (0x01 << 5) /* Enable reboot on timeout */ +#define ESB_WDT_FREQ (0x01 << 2) /* Decrement frequency */ +#define ESB_WDT_INTTYPE (0x11 << 0) /* Interrupt type on timer1 timeout */ + +/* Reload register bits */ +#define ESB_WDT_RELOAD (0x01 << 8) /* prevent timeout */ + +/* Magic constants */ +#define ESB_UNLOCK1 0x80 /* Step 1 to unlock reset registers */ +#define ESB_UNLOCK2 0x86 /* Step 2 to unlock reset registers */ + +/* Device state. */ +struct I6300State { + PCIDevice dev; /* PCI device state, must be first field. */ + + int reboot_enabled; /* "Reboot" on timer expiry. The real action + * performed depends on the -watchdog-action + * param passed on QEMU command line. + */ + int clock_scale; /* Clock scale. */ +#define CLOCK_SCALE_1KHZ 0 +#define CLOCK_SCALE_1MHZ 1 + + int int_type; /* Interrupt type generated. */ +#define INT_TYPE_IRQ 0 /* APIC 1, INT 10 */ +#define INT_TYPE_SMI 2 +#define INT_TYPE_DISABLED 3 + + int free_run; /* If true, reload timer on expiry. */ + int locked; /* If true, enabled field cannot be changed. */ + int enabled; /* If true, watchdog is enabled. */ + + QEMUTimer *timer; /* The actual watchdog timer. */ + + uint32_t timer1_preload; /* Values preloaded into timer1, timer2. */ + uint32_t timer2_preload; + int stage; /* Stage (1 or 2). */ + + int unlock_state; /* Guest writes 0x80, 0x86 to unlock the + * registers, and we transition through + * states 0 -> 1 -> 2 when this happens. + */ + + int previous_reboot_flag; /* If the watchdog caused the previous + * reboot, this flag will be set. + */ +}; + +typedef struct I6300State I6300State; + +/* This function is called when the watchdog has either been enabled + * (hence it starts counting down) or has been keep-alived. + */ +static void i6300esb_restart_timer(I6300State *d, int stage) +{ + int64_t timeout; + + if (!d->enabled) + return; + + d->stage = stage; + + if (d->stage <= 1) + timeout = d->timer1_preload; + else + timeout = d->timer2_preload; + + if (d->clock_scale == CLOCK_SCALE_1KHZ) + timeout <<= 15; + else + timeout <<= 5; + + /* Get the timeout in units of ticks_per_sec. */ + timeout = ticks_per_sec * timeout / 33000000; + + i6300esb_debug("stage %d, timeout %" PRIi64 "\n", d->stage, timeout); + + qemu_mod_timer(d->timer, qemu_get_clock(vm_clock) + timeout); +} + +/* This is called when the guest disables the watchdog. */ +static void i6300esb_disable_timer(I6300State *d) +{ + i6300esb_debug("timer disabled\n"); + + qemu_del_timer(d->timer); +} + +static void i6300esb_reset(I6300State *d) +{ + /* XXX We should probably reset other parts of the state here, + * but we should also reset our state on general machine reset + * too. For now just disable the timer so it doesn't fire + * again after the reboot. + */ + i6300esb_disable_timer(d); +} + +/* This function is called when the watchdog expires. Note that + * the hardware has two timers, and so expiry happens in two stages. + * If d->stage == 1 then we perform the first stage action (usually, + * sending an interrupt) and then restart the timer again for the + * second stage. If the second stage expires then the watchdog + * really has run out. + */ +static void i6300esb_timer_expired(void *vp) +{ + I6300State *d = (I6300State *) vp; + + i6300esb_debug("stage %d\n", d->stage); + + if (d->stage == 1) { + /* What to do at the end of stage 1? */ + switch (d->int_type) { + case INT_TYPE_IRQ: + fprintf(stderr, "i6300esb_timer_expired: I would send APIC 1 INT 10 here if I knew how (XXX)\n"); + break; + case INT_TYPE_SMI: + fprintf(stderr, "i6300esb_timer_expired: I would send SMI here if I knew how (XXX)\n"); + break; + } + + /* Start the second stage. */ + i6300esb_restart_timer(d, 2); + } else { + /* Second stage expired, reboot for real. */ + if (d->reboot_enabled) { + d->previous_reboot_flag = 1; + watchdog_perform_action(); /* This reboots, exits, etc */ + i6300esb_reset(d); + } + + /* In "free running mode" we start stage 1 again. */ + if (d->free_run) + i6300esb_restart_timer(d, 1); + } +} + +static void i6300esb_config_write(PCIDevice *dev, uint32_t addr, + uint32_t data, int len) +{ + I6300State *d = (I6300State *) dev; + int old; + + i6300esb_debug("addr = %x, data = %x, len = %d\n", addr, data, len); + + if (addr == ESB_CONFIG_REG && len == 2) { + d->reboot_enabled = (data & ESB_WDT_REBOOT) == 0; + d->clock_scale = + (data & ESB_WDT_FREQ) != 0 ? CLOCK_SCALE_1MHZ : CLOCK_SCALE_1KHZ; + d->int_type = (data & ESB_WDT_INTTYPE); + } else if (addr == ESB_LOCK_REG && len == 1) { + if (!d->locked) { + d->locked = (data & ESB_WDT_LOCK) != 0; + d->free_run = (data & ESB_WDT_FUNC) != 0; + old = d->enabled; + d->enabled = (data & ESB_WDT_ENABLE) != 0; + if (!old && d->enabled) /* Enabled transitioned from 0 -> 1 */ + i6300esb_restart_timer(d, 1); + else if (!d->enabled) + i6300esb_disable_timer(d); + } + } else { + pci_default_write_config(dev, addr, data, len); + } +} + +static uint32_t i6300esb_config_read(PCIDevice *dev, uint32_t addr, int len) +{ + I6300State *d = (I6300State *) dev; + uint32_t data; + + i6300esb_debug ("addr = %x, len = %d\n", addr, len); + + if (addr == ESB_CONFIG_REG && len == 2) { + data = + (d->reboot_enabled ? 0 : ESB_WDT_REBOOT) | + (d->clock_scale == CLOCK_SCALE_1MHZ ? ESB_WDT_FREQ : 0) | + d->int_type; + return data; + } else if (addr == ESB_LOCK_REG && len == 1) { + data = + (d->free_run ? ESB_WDT_FUNC : 0) | + (d->locked ? ESB_WDT_LOCK : 0) | + (d->enabled ? ESB_WDT_ENABLE : 0); + return data; + } else { + return pci_default_read_config(dev, addr, len); + } +} + +static uint32_t i6300esb_mem_readb(void *vp, target_phys_addr_t addr) +{ + i6300esb_debug ("addr = %x\n", (int) addr); + + return 0; +} + +static uint32_t i6300esb_mem_readw(void *vp, target_phys_addr_t addr) +{ + uint32_t data = 0; + I6300State *d = (I6300State *) vp; + + i6300esb_debug("addr = %x\n", (int) addr); + + if (addr == 0xc) { + /* The previous reboot flag is really bit 9, but there is + * a bug in the Linux driver where it thinks it's bit 12. + * Set both. + */ + data = d->previous_reboot_flag ? 0x1200 : 0; + } + + return data; +} + +static uint32_t i6300esb_mem_readl(void *vp, target_phys_addr_t addr) +{ + i6300esb_debug("addr = %x\n", (int) addr); + + return 0; +} + +static void i6300esb_mem_writeb(void *vp, target_phys_addr_t addr, uint32_t val) +{ + I6300State *d = (I6300State *) vp; + + i6300esb_debug("addr = %x, val = %x\n", (int) addr, val); + + if (addr == 0xc && val == 0x80) + d->unlock_state = 1; + else if (addr == 0xc && val == 0x86 && d->unlock_state == 1) + d->unlock_state = 2; +} + +static void i6300esb_mem_writew(void *vp, target_phys_addr_t addr, uint32_t val) +{ + I6300State *d = (I6300State *) vp; + + i6300esb_debug("addr = %x, val = %x\n", (int) addr, val); + + if (addr == 0xc && val == 0x80) + d->unlock_state = 1; + else if (addr == 0xc && val == 0x86 && d->unlock_state == 1) + d->unlock_state = 2; + else { + if (d->unlock_state == 2) { + if (addr == 0xc) { + if ((val & 0x100) != 0) + /* This is the "ping" from the userspace watchdog in + * the guest ... + */ + i6300esb_restart_timer(d, 1); + + /* Setting bit 9 resets the previous reboot flag. + * There's a bug in the Linux driver where it sets + * bit 12 instead. + */ + if ((val & 0x200) != 0 || (val & 0x1000) != 0) { + d->previous_reboot_flag = 0; + } + } + + d->unlock_state = 0; + } + } +} + +static void i6300esb_mem_writel(void *vp, target_phys_addr_t addr, uint32_t val) +{ + I6300State *d = (I6300State *) vp; + + i6300esb_debug ("addr = %x, val = %x\n", (int) addr, val); + + if (addr == 0xc && val == 0x80) + d->unlock_state = 1; + else if (addr == 0xc && val == 0x86 && d->unlock_state == 1) + d->unlock_state = 2; + else { + if (d->unlock_state == 2) { + if (addr == 0) + d->timer1_preload = val & 0xfffff; + else if (addr == 4) + d->timer2_preload = val & 0xfffff; + + d->unlock_state = 0; + } + } +} + +static void i6300esb_map(PCIDevice *dev, int region_num, + uint32_t addr, uint32_t size, int type) +{ + static CPUReadMemoryFunc *mem_read[3] = { + i6300esb_mem_readb, + i6300esb_mem_readw, + i6300esb_mem_readl, + }; + static CPUWriteMemoryFunc *mem_write[3] = { + i6300esb_mem_writeb, + i6300esb_mem_writew, + i6300esb_mem_writel, + }; + I6300State *d = (I6300State *) dev; + int io_mem; + + i6300esb_debug("addr = %x, size = %x, type = %d\n", addr, size, type); + + io_mem = cpu_register_io_memory (0, mem_read, mem_write, d); + cpu_register_physical_memory (addr, 0x10, io_mem); + /* qemu_register_coalesced_mmio (addr, 0x10); ? */ +} + +static void i6300esb_save(QEMUFile *f, void *vp) +{ + I6300State *d = (I6300State *) vp; + + pci_device_save(&d->dev, f); + qemu_put_be32(f, d->reboot_enabled); + qemu_put_be32(f, d->clock_scale); + qemu_put_be32(f, d->int_type); + qemu_put_be32(f, d->free_run); + qemu_put_be32(f, d->locked); + qemu_put_be32(f, d->enabled); + qemu_put_timer(f, d->timer); + qemu_put_be32(f, d->timer1_preload); + qemu_put_be32(f, d->timer2_preload); + qemu_put_be32(f, d->stage); + qemu_put_be32(f, d->unlock_state); + qemu_put_be32(f, d->previous_reboot_flag); +} + +static int i6300esb_load(QEMUFile *f, void *vp, int version) +{ + I6300State *d = (I6300State *) vp; + + if (version != sizeof (I6300State)) + return -EINVAL; + + pci_device_load(&d->dev, f); + d->reboot_enabled = qemu_get_be32(f); + d->clock_scale = qemu_get_be32(f); + d->int_type = qemu_get_be32(f); + d->free_run = qemu_get_be32(f); + d->locked = qemu_get_be32(f); + d->enabled = qemu_get_be32(f); + qemu_get_timer(f, d->timer); + d->timer1_preload = qemu_get_be32(f); + d->timer2_preload = qemu_get_be32(f); + d->stage = qemu_get_be32(f); + d->unlock_state = qemu_get_be32(f); + d->previous_reboot_flag = qemu_get_be32(f); + + return 0; +} + +/* Create and initialize a virtual Intel 6300ESB during PC creation. */ +static void i6300esb_pc_init(PCIBus *pci_bus) +{ + I6300State *d; + uint8_t *pci_conf; + + if (!pci_bus) { + fprintf(stderr, "wdt_i6300esb: no PCI bus in this machine\n"); + return; + } + + d = (I6300State *) + pci_register_device (pci_bus, "i6300esb_wdt", sizeof (I6300State), + -1, + i6300esb_config_read, i6300esb_config_write); + + d->reboot_enabled = 1; + d->clock_scale = CLOCK_SCALE_1KHZ; + d->int_type = INT_TYPE_IRQ; + d->free_run = 0; + d->locked = 0; + d->enabled = 0; + d->timer = qemu_new_timer(vm_clock, i6300esb_timer_expired, d); + d->timer1_preload = 0xfffff; + d->timer2_preload = 0xfffff; + d->stage = 1; + d->unlock_state = 0; + d->previous_reboot_flag = 0; + + pci_conf = d->dev.config; + pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_INTEL); + pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_ESB_9); + pci_config_set_class(pci_conf, PCI_CLASS_SYSTEM_OTHER); + pci_conf[0x0e] = 0x00; + + pci_register_io_region(&d->dev, 0, 0x10, + PCI_ADDRESS_SPACE_MEM, i6300esb_map); + + register_savevm("i6300esb_wdt", -1, sizeof(I6300State), + i6300esb_save, i6300esb_load, d); +} + +static WatchdogTimerModel model = { + .wdt_name = "i6300esb", + .wdt_description = "Intel 6300ESB", + .wdt_pc_init = i6300esb_pc_init, +}; + +void wdt_i6300esb_init(void) +{ + watchdog_add_model(&model); +} Index: xen-4.3.0-testing/tools/qemu-xen-traditional-dir-remote/hw/wdt_ib700.c =================================================================== --- /dev/null +++ xen-4.3.0-testing/tools/qemu-xen-traditional-dir-remote/hw/wdt_ib700.c @@ -0,0 +1,112 @@ +/* + * Virtual hardware watchdog. + * + * Copyright (C) 2009 Red Hat Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * By Richard W.M. Jones (rjones@redhat.com). + */ + +#include "qemu-common.h" +#include "qemu-timer.h" +#include "watchdog.h" +#include "hw.h" +#include "isa.h" +#include "pc.h" + +/*#define IB700_DEBUG 1*/ + +#ifdef IB700_DEBUG +#define ib700_debug(fs,...) \ + fprintf(stderr,"ib700: %s: "fs,__func__,##__VA_ARGS__) +#else +#define ib700_debug(fs,...) +#endif + +/* This is the timer. We use a global here because the watchdog + * code ensures there is only one watchdog (it is located at a fixed, + * unchangable IO port, so there could only ever be one anyway). + */ +static QEMUTimer *timer = NULL; + +/* A write to this register enables the timer. */ +static void ib700_write_enable_reg(void *vp, uint32_t addr, uint32_t data) +{ + static int time_map[] = { + 30, 28, 26, 24, 22, 20, 18, 16, + 14, 12, 10, 8, 6, 4, 2, 0 + }; + int64 timeout; + + ib700_debug("addr = %x, data = %x\n", addr, data); + + timeout = (int64_t) time_map[data & 0xF] * ticks_per_sec; + qemu_mod_timer(timer, qemu_get_clock (vm_clock) + timeout); +} + +/* A write (of any value) to this register disables the timer. */ +static void ib700_write_disable_reg(void *vp, uint32_t addr, uint32_t data) +{ + ib700_debug("addr = %x, data = %x\n", addr, data); + + qemu_del_timer(timer); +} + +/* This is called when the watchdog expires. */ +static void ib700_timer_expired(void *vp) +{ + ib700_debug("watchdog expired\n"); + + watchdog_perform_action(); + qemu_del_timer(timer); +} + +static void ib700_save(QEMUFile *f, void *vp) +{ + qemu_put_timer(f, timer); +} + +static int ib700_load(QEMUFile *f, void *vp, int version) +{ + if (version != 0) + return -EINVAL; + + qemu_get_timer(f, timer); + + return 0; +} + +/* Create and initialize a virtual IB700 during PC creation. */ +static void ib700_pc_init(PCIBus *unused) +{ + timer = qemu_new_timer(vm_clock, ib700_timer_expired, NULL); + register_savevm("ib700_wdt", -1, 0, ib700_save, ib700_load, NULL); + + register_ioport_write(0x441, 2, 1, ib700_write_disable_reg, NULL); + register_ioport_write(0x443, 2, 1, ib700_write_enable_reg, NULL); +} + +static WatchdogTimerModel model = { + .wdt_name = "ib700", + .wdt_description = "iBASE 700", + .wdt_pc_init = ib700_pc_init, +}; + +void wdt_ib700_init(void) +{ + watchdog_add_model(&model); +} Index: xen-4.3.0-testing/tools/libxl/libxl_dm.c =================================================================== --- xen-4.3.0-testing.orig/tools/libxl/libxl_dm.c +++ xen-4.3.0-testing/tools/libxl/libxl_dm.c @@ -220,6 +220,12 @@ static char ** libxl__build_device_model } } } + if (b_info->u.hvm.watchdog || b_info->u.hvm.watchdog_action) { + flexarray_append(dm_args, "-watchdog"); + if (b_info->u.hvm.watchdog_action) { + flexarray_vappend(dm_args, "-watchdog-action", b_info->u.hvm.watchdog_action, NULL); + } + } if (b_info->u.hvm.soundhw) { flexarray_vappend(dm_args, "-soundhw", b_info->u.hvm.soundhw, NULL); } @@ -507,6 +513,12 @@ static char ** libxl__build_device_model } } } + if (b_info->u.hvm.watchdog || b_info->u.hvm.watchdog_action) { + flexarray_append(dm_args, "-watchdog"); + if (b_info->u.hvm.watchdog_action) { + flexarray_vappend(dm_args, "-watchdog-action", b_info->u.hvm.watchdog_action, NULL); + } + } if (b_info->u.hvm.soundhw) { flexarray_vappend(dm_args, "-soundhw", b_info->u.hvm.soundhw, NULL); } Index: xen-4.3.0-testing/tools/libxl/libxl_types.idl =================================================================== --- xen-4.3.0-testing.orig/tools/libxl/libxl_types.idl +++ xen-4.3.0-testing/tools/libxl/libxl_types.idl @@ -332,6 +332,8 @@ libxl_domain_build_info = Struct("domain ("soundhw", string), ("xen_platform_pci", libxl_defbool), ("usbdevice_list", libxl_string_list), + ("watchdog", string), + ("watchdog_action", string), ])), ("pv", Struct(None, [("kernel", string), ("slack_memkb", MemKB), Index: xen-4.3.0-testing/tools/libxl/xl_cmdimpl.c =================================================================== --- xen-4.3.0-testing.orig/tools/libxl/xl_cmdimpl.c +++ xen-4.3.0-testing/tools/libxl/xl_cmdimpl.c @@ -1516,6 +1516,8 @@ skip_vfb: xlu_cfg_replace_string (config, "soundhw", &b_info->u.hvm.soundhw, 0); xlu_cfg_get_defbool(config, "xen_platform_pci", &b_info->u.hvm.xen_platform_pci, 0); + xlu_cfg_replace_string (config, "watchdog", &b_info->u.hvm.watchdog, 0); + xlu_cfg_replace_string (config, "watchdog_action", &b_info->u.hvm.watchdog_action, 0); if(b_info->u.hvm.vnc.listen && b_info->u.hvm.vnc.display Index: xen-4.3.0-testing/tools/python/xen/xm/cpupool.py =================================================================== --- xen-4.3.0-testing.orig/tools/python/xen/xm/cpupool.py +++ xen-4.3.0-testing/tools/python/xen/xm/cpupool.py @@ -157,9 +157,17 @@ def make_cpus_config(cfg_cpus): # ["0,2","1,3"] -> [[0,2],[1,3]] # ["0-3,^1","1-4,^2"] -> [[0,2,3],[1,3,4]] try: - for c in cfg_cpus: - cpus = cnv(c) - cpus_list.append(cpus) + cpus_str = "" + list_len = len(cfg_cpus) + n = 0 + while n < list_len: + if type(cfg_cpus[n]) != str: + raise SyntaxError('cpus = %s' % cfg_cpus) + cpus_str += cfg_cpus[n] + n += 1 + if n < list_len: + cpus_str += ', ' + cpus_list = cnv(cpus_str) except ValueError, e: raise err('cpus = %s: %s' % (cfg_cpus, e)) else: Index: xen-4.3.0-testing/tools/python/xen/xend/server/netif.py =================================================================== --- xen-4.3.0-testing.orig/tools/python/xen/xend/server/netif.py +++ xen-4.3.0-testing/tools/python/xen/xend/server/netif.py @@ -23,6 +23,7 @@ import os import random import re +import commands from xen.xend import XendOptions, sxp from xen.xend.server.DevController import DevController @@ -101,6 +102,14 @@ class NetifController(DevController): def __init__(self, vm): DevController.__init__(self, vm) + def createDevice(self, config): + bridge = config.get('bridge') + if bridge is not None: + bridge_result = commands.getstatusoutput("/sbin/ifconfig %s" % bridge) + if bridge_result[0] != 0: + raise VmError('Network bridge does not exist: %s' % bridge) + DevController.createDevice(self, config) + def getDeviceDetails(self, config): """@see DevController.getDeviceDetails""" Index: xen-4.3.0-testing/tools/python/xen/util/pci.py =================================================================== --- xen-4.3.0-testing.orig/tools/python/xen/util/pci.py +++ xen-4.3.0-testing/tools/python/xen/util/pci.py @@ -20,6 +20,8 @@ from xen.xend import sxp from xen.xend.XendConstants import AUTO_PHP_SLOT from xen.xend.XendSXPDev import dev_dict_to_sxp from xen.xend.XendLogging import log +from xen.xend.xenstore.xstransact import xstransact +from xen.xend.XendError import XendError # for 2.3 compatibility try: @@ -27,9 +29,11 @@ try: except NameError: from sets import Set as set +XS_PCIBACK_PATH = '/xm/pciback' PROC_PCI_PATH = '/proc/bus/pci/devices' PROC_PCI_NUM_RESOURCES = 7 +SYSFS_PCI_DRVS_PATH = 'bus/pci/drivers' SYSFS_PCI_DEVS_PATH = '/bus/pci/devices' SYSFS_PCI_DEV_RESOURCE_PATH = '/resource' SYSFS_PCI_DEV_CONFIG_PATH = '/config' @@ -161,7 +165,7 @@ def PCI_BDF(domain, bus, slot, func): def check_pci_opts(opts): def f((k, v)): - if k not in ['msitranslate', 'power_mgmt'] or \ + if k not in ['msitranslate', 'power_mgmt', 'managed'] or \ not v.lower() in ['0', '1', 'yes', 'no']: raise PciDeviceParseError('Invalid pci option %s=%s: ' % (k, v)) @@ -427,6 +431,9 @@ def __pci_dict_to_fmt_str(fmt, dev): def pci_dict_to_bdf_str(dev): return __pci_dict_to_fmt_str('%04x:%02x:%02x.%01x', dev) +def pci_dict_to_xs_bdf_str(dev): + return __pci_dict_to_fmt_str('%04x-%02x-%02x-%01x', dev) + def pci_dict_to_xc_str(dev): return __pci_dict_to_fmt_str('0x%x, 0x%x, 0x%x, 0x%x', dev) @@ -560,6 +567,115 @@ def find_all_assignable_devices(): dev_list = dev_list + [dev] return dev_list +def pci_assignable_add(dev): + '''detach pci device from driver that we need to unbind from and rebind + to pciback driver, then it can be assigned to guest. + ''' + sysfs_mnt = find_sysfs_mnt() + pcidev_path = sysfs_mnt + SYSFS_PCI_DEVS_PATH + pciback_path = sysfs_mnt + SYSFS_PCIBACK_PATH + + # See if the device exists + pci_bdf = pci_dict_to_bdf_str(dev) + path = pcidev_path + '/' + pci_bdf + if not os.path.exists(path): + log.debug("Pci device %s doesn't exist" % pci_bdf) + return -1 + + # Check to see if it's already assigned to pciback + path = pciback_path + '/' + pci_bdf + if os.path.exists(path): + log.debug("Pci device %s is already assigned to pciback" % pci_bdf) + return 0 + + # Check to see if there's already a driver that we need to unbind from + path = pcidev_path + '/' + pci_bdf + '/driver' + drv_path = None + if os.path.exists(path): + drv_path = os.path.realpath(path).replace(" ", "\ ") + cmd = 'echo %s > %s/unbind' % (pci_bdf, drv_path) + if os.system(cmd): + log.debug("Couldn't unbind device") + return -1; + + # Store driver_path for rebinding to dom0 + if drv_path is not None: + xs_pci_bdf = pci_dict_to_xs_bdf_str(dev) + path = XS_PCIBACK_PATH + '/' + xs_pci_bdf + xstransact.Mkdir(path) + xstransact.Write(path, 'driver_path', drv_path) + else: + log.debug("Not bound to a driver, will not be rebound") + + # Bind to pciback + try: + # Scan through /sys/.../pciback/slots looking for pcidev's BDF + slots = os.popen('cat %s/slots' % pciback_path).read() + if re.search(pci_bdf, slots) is None: + # write bdf to new_slot + cmd = 'echo %s > %s/new_slot' % (pci_bdf, pciback_path) + if os.system(cmd): + raise XendError("Couldn't add device to pciback new_slot") + + # Bind to pciback + cmd = 'echo %s > %s/bind' % (pci_bdf, pciback_path) + if os.system(cmd): + raise XendError("Couldn't bind device to pciback") + except XendError: + # rebind to original driver + if drv_path is not None: + log.debug("Rebind to original driver") + cmd = 'echo %s > %s/bind' % (pci_bdf, drv_path) + if os.system(cmd): + log.debug("Failed to rebind") + return -1 + + return 0 + +def pci_assignable_remove(dev): + '''unbind pci device from pciback, and rebind to host pci driver where it + was detached from in pci-assignable-add. + ''' + sysfs_mnt = find_sysfs_mnt() + pcidrv_path = sysfs_mnt + SYSFS_PCI_DRVS_PATH + pciback_path = sysfs_mnt + SYSFS_PCIBACK_PATH + pci_bdf = pci_dict_to_bdf_str(dev) + + # Unbind from pciback + path = pciback_path + '/' + pci_bdf + if os.path.exists(path): + # unbind + cmd = 'echo %s > %s/unbind' % (pci_bdf, pciback_path) + if os.system(cmd): + log.debug("Couldn't unbind device to pciback") + return -1 + + # remove slots if necessary + slots = os.popen('cat %s/slots' % pciback_path).read() + if re.search(pci_bdf, slots): + # write bdf to remove_slot + cmd = 'echo %s > %s/remove_slot' % (pci_bdf, pciback_path) + if os.system(cmd): + log.debug("Couldn't remove pciback slot") + return -1 + else: + log.debug("Not bound to pciback") + + # Rebind if necessary + xs_pci_bdf = pci_dict_to_xs_bdf_str(dev) + path = XS_PCIBACK_PATH + '/' + xs_pci_bdf + drv_path = xstransact.Read(path, 'driver_path') + if drv_path: + cmd = 'echo %s > %s/bind' % (pci_bdf, drv_path) + if os.system(cmd): + log.debug("Couldn't rebind to driver %s" % drv_path) + return -1 + xstransact.Remove(path) + else: + log.debug("Counldn't find path for original driver. Not rebinding") + + return 0 + def transform_list(target, src): ''' src: its element is pci string (Format: xxxx:xx:xx.x). target: its element is pci string, or a list of pci string. Index: xen-4.3.0-testing/tools/python/xen/xend/server/pciif.py =================================================================== --- xen-4.3.0-testing.orig/tools/python/xen/xend/server/pciif.py +++ xen-4.3.0-testing/tools/python/xen/xend/server/pciif.py @@ -86,6 +86,48 @@ def get_all_assigned_pci_devices(domid = pci_str_list = pci_str_list + get_assigned_pci_devices(int(d)) return pci_str_list +def reattach_host_pci_devices(devconfig): + pci_dev_list = devconfig.get('devs', []) + for pci_dev in pci_dev_list: + managed = 0 + pci_opts_config = pci_dev.get('opts', []) + for opt in pci_opts_config: + if opt[0] == 'managed': + managed = opt[1] + if managed: + if pci_assignable_remove(pci_dev) != 0: + raise VmError('pci_assignable_remove failed') + +def detach_host_pci_devices(devconfig): + pci_dev_list = devconfig.get('devs', []) + reattach = 0 + for pci_dev in pci_dev_list: + managed = 0 + pci_opts_config = pci_dev.get('opts', []) + for opt in pci_opts_config: + if opt[0] == 'managed': + managed = opt[1] + if managed: + if pci_assignable_add(pci_dev) != 0: + log.debug('pci_assignable_add failed') + reattach = 1 + break + + if reattach: + reattach_host_pci_devices(devconfig) + raise VmError('detach_host_pci_devices failed') + +def prepare_host_pci_devices(devconfig): + # Test whether the device used by other domain + pci_dev_list = devconfig.get('devs', []) + for pci_dev in pci_dev_list: + pci_name = pci_dict_to_bdf_str(pci_dev) + if pci_name in get_all_assigned_pci_devices(): + raise VmError("failed to assign device %s that has" + " already been assigned to other domain." % pci_name) + # Detach 'managed' devices + detach_host_pci_devices(devconfig) + class PciController(DevController): def __init__(self, vm): Index: xen-4.3.0-testing/tools/python/xen/lowlevel/xc/xc.c =================================================================== --- xen-4.3.0-testing.orig/tools/python/xen/lowlevel/xc/xc.c +++ xen-4.3.0-testing/tools/python/xen/lowlevel/xc/xc.c @@ -954,18 +954,23 @@ static PyObject *pyxc_hvm_build(XcObject struct hvm_info_table *va_hvm; uint8_t *va_map, sum; #endif - int i; - char *image; + int i, datalen; + char *image, *smbios_str, *acpi_str; int memsize, target=-1, vcpus = 1, acpi = 0, apic = 1; + PyObject *acpi_firmware = NULL; + PyObject *smbios_firmware = NULL; PyObject *vcpu_avail_handle = NULL; uint8_t vcpu_avail[(HVM_MAX_VCPUS + 7)/8]; + struct xc_hvm_build_args hvm_args = {}; static char *kwd_list[] = { "domid", "memsize", "image", "target", "vcpus", - "vcpu_avail", "acpi", "apic", NULL }; - if ( !PyArg_ParseTupleAndKeywords(args, kwds, "iis|iiOii", kwd_list, + "vcpu_avail", "acpi", "apic", + "smbios_firmware", "acpi_firmware", NULL }; + if ( !PyArg_ParseTupleAndKeywords(args, kwds, "iis|iiOiiOO", kwd_list, &dom, &memsize, &image, &target, &vcpus, - &vcpu_avail_handle, &acpi, &apic) ) + &vcpu_avail_handle, &acpi, + &apic, &smbios_firmware, &acpi_firmware) ) return NULL; memset(vcpu_avail, 0, sizeof(vcpu_avail)); @@ -996,8 +1001,38 @@ static PyObject *pyxc_hvm_build(XcObject if ( target == -1 ) target = memsize; - if ( xc_hvm_build_target_mem(self->xc_handle, dom, memsize, - target, image) != 0 ) + memset(&hvm_args, 0, sizeof(struct xc_hvm_build_args)); + hvm_args.mem_size = (uint64_t)memsize << 20; + hvm_args.mem_target = (uint64_t)target << 20; + hvm_args.image_file_name = image; + + if ( PyString_Check(smbios_firmware ) ) + { + smbios_str = PyString_AsString(smbios_firmware); + if ( smbios_str ) + { + datalen = *(int *)smbios_str; + if ( datalen ) { + hvm_args.smbios_module.data = &((uint8_t *)smbios_str)[4]; + hvm_args.smbios_module.length = (uint32_t)datalen; + } + } + } + + if ( PyString_Check(acpi_firmware ) ) + { + acpi_str = PyString_AsString(acpi_firmware); + if (acpi_str) + { + datalen = *(int *)acpi_str; + if ( datalen ) { + hvm_args.acpi_module.data = &((uint8_t *)acpi_str)[4]; + hvm_args.acpi_module.length = (uint32_t)datalen; + } + } + } + + if ( xc_hvm_build(self->xc_handle, dom, &hvm_args) != 0 ) return pyxc_error_to_exception(self->xc_handle); #if !defined(__ia64__) Index: xen-4.3.0-testing/tools/python/README.sxpcfg =================================================================== --- xen-4.3.0-testing.orig/tools/python/README.sxpcfg +++ xen-4.3.0-testing/tools/python/README.sxpcfg @@ -51,6 +51,11 @@ image - vncunused (HVM) - device_model + - actmem + - xenpaging_file + - xenpaging_extra + - smbios_firmware + - acpi_firmware - display - xauthority - vncconsole Index: xen-4.3.0-testing/tools/python/README.XendConfig =================================================================== --- xen-4.3.0-testing.orig/tools/python/README.XendConfig +++ xen-4.3.0-testing/tools/python/README.XendConfig @@ -118,6 +118,11 @@ otherConfig image.vncdisplay image.vncunused image.hvm.device_model + image.hvm.actmem + image.hvm.xenpaging_file + image.hvm.xenpaging_extra + image.hvm.smbios_firmware + image.hvm.apci_firmware image.hvm.display image.hvm.xauthority image.hvm.vncconsole Index: xen-4.3.0-testing/tools/hotplug/Linux/domain-lock =================================================================== --- /dev/null +++ xen-4.3.0-testing/tools/hotplug/Linux/domain-lock @@ -0,0 +1,83 @@ +#!/bin/bash + +basedir=$(dirname "$0") + +usage() { + echo "usage: domain-lock [-l|-u] -n -i -p path" + echo "usage: domain-lock [-s] -i path" + echo "" + echo "-l lock" + echo "-u unlock" + echo "-s status (default)" + echo "-n Virtual Machine name" + echo "-i Virtual Machine Id or UUID" + echo "-p Virtual Machine Server (physical host) name" + echo "path A per-VM, unique location where external lock will be managed" + exit 1 +} + +remove_lock(){ + local path=$1/lock + local name=$2 + + pid=`ps -efwww | grep vm-monitor | grep $name | awk '{print $2}'` + if [ -n "$pid" ]; then + kill $pid + rm -f $path + fi +} + +get_status(){ + local path=$1/lock + [ -f $path ] || exit 1 + + rc=`flock -xn $path /bin/true` + cat $path + exit $rc +} + +mode="status" + +while getopts ":lusn:i:p:" opt; do + case $opt in + l ) + mode="lock" + ;; + u ) + mode="unlock" + ;; + s ) + mode="status" + ;; + p ) + vm_host=$OPTARG + ;; + n ) + vm_name=$OPTARG + ;; + i ) + vm_uuid=$OPTARG + ;; + \? ) + usage + ;; + esac +done + +shift $(($OPTIND - 1)) +vm_path=$1 + +case $mode in + lock ) + [ -z "$vm_path" ] || [ -z "$vm_name" ] || [ -z "$vm_uuid" ] || [ -z "$vm_host" ] && usage + $basedir/set-lock $vm_path $vm_name $vm_uuid $vm_host + ;; + unlock ) + [ -z "$vm_path" ] || [ -z "$vm_name" ] || [ -z "$vm_uuid" ] || [ -z "$vm_host" ] && usage + remove_lock $vm_path $vm_name $vm_uuid $vm_host + ;; + status ) + [ -z "$vm_path" ] && usage + get_status $vm_path + ;; +esac Index: xen-4.3.0-testing/tools/hotplug/Linux/vm-monitor =================================================================== --- /dev/null +++ xen-4.3.0-testing/tools/hotplug/Linux/vm-monitor @@ -0,0 +1,41 @@ +#!/bin/bash + +basedir=$(dirname "$0") +HA_TICK=2 + +monitor() { + local path=$1 + local name=$2 + local uuid=$3 + local host=$4 + local count=0 + path=$path/lock + + while : + do + echo "name=$name uuid=$uuid host=$host count=$count" > $path + count=$(($count+1)) + sleep $HA_TICK + done& +} + +create_lock() { + local path=$1/lock + local rc=0 + + [ -f $path ] || touch $path + flock -x -w $HA_TICK $path $basedir/vm-monitor $* + rc=$? + if [ $rc -eq 1 ]; then + echo `cat $path` + exit 1 + else + exit $rc + fi +} + +if [ $0 = "$basedir/set-lock" ]; then + create_lock $* +elif [ $0 = "$basedir/vm-monitor" ]; then + monitor $* +fi Index: xen-4.3.0-testing/tools/python/xen/xend/XendOptions.py =================================================================== --- xen-4.3.0-testing.orig/tools/python/xen/xend/XendOptions.py +++ xen-4.3.0-testing/tools/python/xen/xend/XendOptions.py @@ -154,6 +154,20 @@ class XendOptions: use loose check automatically if necessary.""" pci_dev_assign_strict_check_default = True + """Default for the flag indicating whether xend should create + a lock file for domains when they are started.""" + xend_domain_lock = 'no' + + """Default domain lock storage path.""" + xend_domain_lock_path_default = '/var/lib/xen/images/vm_locks' + + """Default script to acquire/release domain lock""" + xend_domain_lock_utility = auxbin.scripts_dir() + "/domain-lock" + + """Default block device for lock service""" + xend_domain_lock_device = "" + + def __init__(self): self.configure() @@ -401,6 +415,26 @@ class XendOptions: else: return None + def get_xend_domain_lock(self): + """Get the flag indicating whether xend should create a lock file + for domains when they are started.""" + return self.get_config_bool("xend-domain-lock", self.xend_domain_lock) + + def get_xend_domain_lock_path(self): + """ Get the path for domain lock storage + """ + return self.get_config_string("xend-domain-lock-path", self.xend_domain_lock_path_default) + + def get_xend_domain_lock_utility(self): + s = self.get_config_string('xend-domain-lock-utility') + + if s: + return os.path.join(auxbin.scripts_dir(), s) + else: + return self.xend_domain_lock_utility + + def get_xend_domain_lock_device(self): + return self.get_config_string('xend-domain-lock-device', self.xend_domain_lock_device) def get_vnc_tls(self): return self.get_config_string('vnc-tls', self.xend_vnc_tls) Index: xen-4.3.0-testing/tools/hotplug/Linux/domain-lock-sfex =================================================================== --- /dev/null +++ xen-4.3.0-testing/tools/hotplug/Linux/domain-lock-sfex @@ -0,0 +1,166 @@ +#!/bin/bash + +# pre-condition +# 1. device is ready: logical volume activated if used +# 2. device already initialized +# 3. index is assigned correctly + +#error code: +# 0: success +# 1: error + +if [ `uname -m` = "x86_64" ]; then + SFEX_DAEMON=/usr/lib64/heartbeat/sfex_daemon +else + SFEX_DAEMON=/usr/lib/heartbeat/sfex_daemon +fi +SFEX_INIT=/usr/sbin/sfex_init +COLLISION_TIMEOUT=1 +LOCK_TIMEOUT=3 +MONITOR_INTERVAL=2 +LOCAL_LOCK_FILE=/var/lock/sfex + +usage() { + echo "usage: domain-lock-sfex [-l|-u|-s] -i -x " + echo "" + echo "-l lock" + echo "-u unlock" + echo "-s status (default)" + echo "-i Virtual Machine Id or UUID" + echo "-x SFEX device which used for sfex lock" + exit 1 +} + +get_lock_host() { + local rscname=$1 + local device=$2 + r=`$SFEX_DAEMON -s -u $rscname $device` + echo $r +} + +get_status() { + local rscname=$1 + if /usr/bin/pgrep -f "$SFEX_DAEMON .* ${rscname} " > /dev/null 2>&1; then + return 0 + else + return 1 + fi +} + +acquire_lock() { + local rscname=$1 + local device=$2 + get_status $rscname + ## We assume xend will take care to avoid starting same VM twice on the same machine. + if [ $? -eq 0 ]; then + return 0 + fi + $SFEX_DAEMON -c $COLLISION_TIMEOUT -t $LOCK_TIMEOUT -m $MONITOR_INTERVAL -u $rscname $device + rc=$? + if [ $rc -ne 0 ]; then + return $rc + fi + sleep 4 + get_status $rscname + if [ $? -eq 0 ]; then + return 0 + fi + return 1 +} + +# release has to success +release_lock(){ + local rscname=$1 + + ## If the lock is already released + get_status $rscname + if [ $? -ne 0 ]; then + return 0 + fi + + pid=`/usr/bin/pgrep -f "$SFEX_DAEMON .* ${rscname} "` + /bin/kill $pid + + count=0 + while [ $count -lt 10 ] + do + get_status $rscname + if [ $? -eq 1 ]; then + return 0 + fi + count=`expr $count + 1` + sleep 1 + done + + /bin/kill -9 $pid + while : + do + get_status $rscname + if [ $? -eq 1 ]; then + break; + fi + sleep 1 + done + + return 0 +} + +mode="status" + +while getopts ":lusn:i:p:x:" opt; do +case $opt in +l ) +mode="lock" +;; +u ) +mode="unlock" +;; +s ) +mode="status" +;; +n ) +vm_name=$OPTARG +;; +i ) +vm_uuid=$OPTARG +;; +p ) +vm_host=$OPTARG +;; +x ) +vm_sfex_device=$OPTARG +;; +\? ) +usage +;; +esac +done + +shift $(($OPTIND - 1)) +[ -z $vm_uuid ] && usage +[ -z $vm_sfex_device ] && usage + +case $mode in +lock ) + ( + flock -x 200 + acquire_lock $vm_uuid $vm_sfex_device + rc=$? + flock -u 200 + exit $rc + ) 200>$LOCAL_LOCK_FILE-$vm_uuid +;; +unlock ) + ( + flock -x 200 + release_lock $vm_uuid + rc=$? + flock -u 200 + exit $rc + ) 200>$LOCAL_LOCK_FILE-$vm_uuid +;; +status ) + get_lock_host $vm_uuid $vm_sfex_device +;; +esac + Index: xen-4.3.0-testing/tools/python/xen/xend/server/BlktapController.py =================================================================== --- xen-4.3.0-testing.orig/tools/python/xen/xend/server/BlktapController.py +++ xen-4.3.0-testing/tools/python/xen/xend/server/BlktapController.py @@ -15,6 +15,7 @@ blktap1_disk_types = [ 'ram', 'qcow', 'qcow2', + 'cdrom', 'ioemu', ] Index: xen-4.3.0-testing/tools/qemu-xen-traditional-dir-remote/qemu-xen.h =================================================================== --- xen-4.3.0-testing.orig/tools/qemu-xen-traditional-dir-remote/qemu-xen.h +++ xen-4.3.0-testing/tools/qemu-xen-traditional-dir-remote/qemu-xen.h @@ -1,6 +1,8 @@ #ifndef QEMU_XEN_H #define QEMU_XEN_H +#include "hw/boards.h" + /* vl.c */ extern int restore; extern int vga_ram_size; @@ -47,6 +49,7 @@ void unset_vram_mapping(void *opaque); #endif void pci_unplug_netifs(void); +void pci_unplug_scsi(void); void destroy_hvm_domain(void); void unregister_iomem(target_phys_addr_t start); @@ -64,7 +67,7 @@ void handle_buffered_pio(void); /* xenstore.c */ void xenstore_init(void); uint32_t xenstore_read_target(void); -void xenstore_parse_domain_config(int domid); +void xenstore_parse_domain_config(int domid, QEMUMachine *machine); int xenstore_parse_disable_pf_config(void); int xenstore_fd(void); void xenstore_process_event(void *opaque); Index: xen-4.3.0-testing/tools/qemu-xen-traditional-dir-remote/hw/pci.c =================================================================== --- xen-4.3.0-testing.orig/tools/qemu-xen-traditional-dir-remote/hw/pci.c +++ xen-4.3.0-testing/tools/qemu-xen-traditional-dir-remote/hw/pci.c @@ -871,6 +871,50 @@ void pci_unplug_netifs(void) } } +void pci_unplug_scsi(void) +{ + PCIBus *bus; + PCIDevice *dev; + PCIIORegion *region; + int x; + int i; + + /* We only support one PCI bus */ + for (bus = first_bus; bus; bus = NULL) { + for (x = 0; x < 256; x++) { + dev = bus->devices[x]; + if (dev && + dev->config[0xa] == 0 && + dev->config[0xb] == 1 +#ifdef CONFIG_PASSTHROUGH + && test_pci_devfn(x) != 1 +#endif + ) { + /* Found a scsi disk. Remove it from the bus. Note that + we don't free it here, since there could still be + references to it floating around. There are only + ever one or two structures leaked, and it's not + worth finding them all. */ + bus->devices[x] = NULL; + for (i = 0; i < PCI_NUM_REGIONS; i++) { + region = &dev->io_regions[i]; + if (region->addr == (uint32_t)-1 || + region->size == 0) + continue; + fprintf(logfile, "region type %d at [%x,%x).\n", + region->type, region->addr, + region->addr+region->size); + if (region->type == PCI_ADDRESS_SPACE_IO) { + isa_unassign_ioport(region->addr, region->size); + } else if (region->type == PCI_ADDRESS_SPACE_MEM) { + unregister_iomem(region->addr); + } + } + } + } + } +} + typedef struct { PCIDevice dev; PCIBus *bus; Index: xen-4.3.0-testing/tools/examples/xmexample.hvm =================================================================== --- xen-4.3.0-testing.orig/tools/examples/xmexample.hvm +++ xen-4.3.0-testing/tools/examples/xmexample.hvm @@ -142,6 +142,15 @@ disk = [ 'file:/var/lib/xen/images/disk. # Device Model to be used device_model = 'qemu-dm' +# the amount of memory in MiB for the guest +#actmem=42 + +# Optional: guest page file +#xenpaging_file="/var/lib/xen/xenpaging/..paging" + +# Optional: extra cmdline options for xenpaging +#xenpaging_extra=[ 'string', 'string' ] + #----------------------------------------------------------------------------- # boot on floppy (a), hard disk (c), Network (n) or CD-ROM (d) # default: hard disk, cd-rom, floppy