86c3c4dd54
`xendomains` systemd services xen.spec - remove unneeded patch, autoload is handled by PCI device, without PCI device xen_platform_pci would not work anyway xen.sles11sp1.fate311487.xen_platform_pci.dmistring.patch - Update our xen-3.0.4 version of unplug code in qemu-trad add comments about the usage of the code rename handler function reenable handlers for writing/reading from emulated PCI device - Change unplugging of emulated devices in PVonHVM guests Since 3.0.4 xen-platform-pci.ko triggerd the unplug by writing to the PCI space of the emulated PCI device. 3.3 introduced an official unplug protocol. The option to unplug wit the official protocol is disabled per default. Remove our version and enable the unplug via official protocol OBS-URL: https://build.opensuse.org/package/show/Virtualization/xen?expand=0&rev=268
6064 lines
212 KiB
Diff
6064 lines
212 KiB
Diff
From 9ca313aa0824f2d350a7a6c9b1ef6c47e0408f1d Mon Sep 17 00:00:00 2001
|
|
From: aliguori <aliguori@c046a42c-6fe2-441c-8c8c-71466251a162>
|
|
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 <aliguori@us.ibm.com>
|
|
|
|
|
|
|
|
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 /<xend-domain-lock-path>/<domain-uuid>.
|
|
+# 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 <vm name> -i <vm uuid> -p <physical host> 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 /<xend-domain-lock-path>/<vm-uuid>
|
|
+# Return 0 on success, non-zero on error.
|
|
+#
|
|
+# lock-util [-s] -i <vm uuid> path"
|
|
+# -s Lock status. If lock is acquired, print any contents
|
|
+# on stdout and return 0. Return non-zero if lock is
|
|
+# available.
|
|
+# path /<xend-domain-lock-path>/<vm-uuid>
|
|
+# 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)
|
|
+# /<xend-domain-lock-path>/<vm-uuid>/lock. Every two seconds it
|
|
+# will write <vm-name>, <vm-id>, <vm-host>, and <tick> to the lock.
|
|
+# <tick> is running counter.
|
|
+# On domain stop event, domain-lock will unlock and remove
|
|
+# /<xend-domain-lock-path>/<vm-uuid>/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<xmdomain.cfg>
|
|
format, and possible options used in either the configfile or for I<vars>.
|
|
|
|
I<configfile> 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 soon> as the domain is started. This B<does
|
|
not> mean the guest OS in the domain has actually booted, or is
|
|
@@ -160,7 +160,7 @@ B<EXAMPLES>
|
|
|
|
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<without config file>
|
|
@@ -299,7 +299,8 @@ scheduling by the Xen hypervisor.
|
|
|
|
=item B<s - shutdown>
|
|
|
|
-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<c - crashed>
|
|
|
|
@@ -312,8 +313,6 @@ restart on crash. See L<xmdomain.cfg> f
|
|
The domain is in process of dying, but hasn't completely shutdown or
|
|
crashed.
|
|
|
|
-FIXME: Is this right?
|
|
-
|
|
=back
|
|
|
|
B<NOTES>
|
|
@@ -737,8 +736,6 @@ Xen ships with a number of domain schedu
|
|
time with the B<sched=> parameter on the Xen command line. By
|
|
default B<credit> is used for scheduling.
|
|
|
|
-FIXME: we really need a scheduler expert to write up this section.
|
|
-
|
|
=over 4
|
|
|
|
=item B<sched-credit> [ B<-d> I<domain-id> [ B<-w>[B<=>I<WEIGHT>] | B<-c>[B<=>I<CAP>] ] ]
|
|
@@ -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<latency-hint>
|
|
|
|
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<broken>. I'm not sure under what
|
|
-circumstances this should actually work.
|
|
-
|
|
=item B<mac=>I<macaddr>
|
|
|
|
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<devid> is the virtual interface device number within the domain
|
|
(i.e. the 3 in vif22.3).
|
|
|
|
-FIXME: this is currently B<broken>. Network devices aren't completely
|
|
-removed from domain 0.
|
|
-
|
|
=item B<network-list> [B<-l>|B<--long>]> I<domain-id>
|
|
|
|
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<xm>(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<xm create> 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<xm create> to be
|
|
+should be symlinks to files in /etc/xen/vm to allow I<xm create> to be
|
|
used without full paths.
|
|
|
|
Options are specified by I<name = value> 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<acpi_firmware>
|
|
+
|
|
+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<smbios_firmware>
|
|
+
|
|
+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<NFS Root>
|
|
|
|
-FIXME: write me
|
|
-
|
|
=item I<LVM Root>
|
|
|
|
-FIXME: write me
|
|
-
|
|
=item I<Two Networks>
|
|
|
|
-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 '<domain id=%s name=%s memory=%s state=%s>' % \
|
|
(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' : ('<Domain> <Mem>',
|
|
'Set the current memory usage for a domain.'),
|
|
+ 'mem-swap-target' : ('<Domain> <Mem>',
|
|
+ 'Set the memory usage for a domain.'),
|
|
'migrate' : ('<Domain> <Host>',
|
|
'Migrate a domain to another machine.'),
|
|
'pause' : ('<Domain>', 'Pause execution of a domain.'),
|
|
@@ -121,7 +124,7 @@ SUBCOMMAND_HELP = {
|
|
'reset' : ('<Domain>', 'Reset a domain.'),
|
|
'restore' : ('<CheckpointFile> [-p]',
|
|
'Restore a domain from a saved state.'),
|
|
- 'save' : ('[-c] <Domain> <CheckpointFile>',
|
|
+ 'save' : ('[-c|-f] <Domain> <CheckpointFile>',
|
|
'Save a domain state to restore later.'),
|
|
'shutdown' : ('<Domain> [-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' : ('<Domain>',\
|
|
+ '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 <plc@novell.com>
|
|
+# 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 <plc@novell.com>
|
|
+# 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 <xc_private.h>
|
|
|
|
#include <assert.h>
|
|
#include <xenguest.h>
|
|
@@ -335,11 +337,71 @@ static void xen_platform_ioport_writeb(v
|
|
}
|
|
}
|
|
|
|
+static uint32_t ioport_base;
|
|
+
|
|
+static void suse_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:
|
|
+ /* FIXME Unknown who makes use of this code! */
|
|
+ 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:
|
|
+ /* xen-kmp used this since xen-3.0.4, instead the official protocol from xen-3.3+
|
|
+ * pre vmdp 1.7 made use of 4 and 8 depending on how vmdp was configured.
|
|
+ * If vmdp was to control both disk and LAN it would use 4.
|
|
+ * If it controlled just disk or just LAN, it would use 8 below. */
|
|
+ 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 %x to bad port %x (base %x) on evtchn device.\n",
|
|
+ val, 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, suse_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 <inttypes.h>
|
|
+
|
|
+#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 <vm name> -i <vm uuid> -p <physical host> path"
|
|
+ echo "usage: domain-lock [-s] -i <vm uuid> 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 <vm uuid> -x <sfex device>"
|
|
+ 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/<domain_name>.<domaind_id>.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
|