e30ecd8da4
- Update to Xen 4.3.0-rc4 OBS-URL: https://build.opensuse.org/package/show/Virtualization/xen?expand=0&rev=251
6059 lines
212 KiB
Diff
6059 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,66 @@ static void xen_platform_ioport_writeb(v
|
|
}
|
|
}
|
|
|
|
+static uint32_t ioport_base;
|
|
+
|
|
+static void platform_ioport_write(void *opaque, uint32_t addr, uint32_t val)
|
|
+{
|
|
+ DECLARE_DOMCTL;
|
|
+ int rc;
|
|
+
|
|
+ if (val == 0)
|
|
+ qemu_invalidate_map_cache();
|
|
+
|
|
+ switch (addr - ioport_base) {
|
|
+ case 0:
|
|
+ fprintf(logfile, "Init hypercall page %x, addr %x.\n", val, addr);
|
|
+ domctl.domain = (domid_t)domid;
|
|
+ domctl.u.hypercall_init.gmfn = val;
|
|
+ domctl.cmd = XEN_DOMCTL_hypercall_init;
|
|
+ rc = xc_domctl(xc_handle, &domctl);
|
|
+ fprintf(logfile, "result -> %d.\n", rc);
|
|
+ break;
|
|
+ case 4:
|
|
+ fprintf(logfile, "Disconnect IDE hard disk...\n");
|
|
+ ide_unplug_harddisks();
|
|
+ fprintf(logfile, "Disconnect SCSI hard disk...\n");
|
|
+ pci_unplug_scsi();
|
|
+ fprintf(logfile, "Disconnect netifs...\n");
|
|
+ pci_unplug_netifs();
|
|
+ fprintf(logfile, "Shutdown taps...\n");
|
|
+ net_tap_shutdown_all();
|
|
+ fprintf(logfile, "Done.\n");
|
|
+ break;
|
|
+ case 8:
|
|
+ if (val ==1 ) {
|
|
+ fprintf(logfile, "Disconnect IDE hard disk...\n");
|
|
+ ide_unplug_harddisks();
|
|
+ fprintf(logfile, "Done.\n");
|
|
+ } else if (val == 2) {
|
|
+ fprintf(logfile, "Disconnect netifs...\n");
|
|
+ pci_unplug_netifs();
|
|
+ fprintf(logfile, "Shutdown taps...\n");
|
|
+ net_tap_shutdown_all();
|
|
+ fprintf(logfile, "Done.\n");
|
|
+ }
|
|
+ break;
|
|
+ default:
|
|
+ fprintf(logfile, "Write to bad port %x (base %x) on evtchn device.\n",
|
|
+ addr, ioport_base);
|
|
+ break;
|
|
+ }
|
|
+}
|
|
+
|
|
static void platform_ioport_map(PCIDevice *pci_dev, int region_num, uint32_t addr, uint32_t size, int type)
|
|
{
|
|
+ ioport_base = addr;
|
|
+
|
|
+ register_ioport_write(addr, 16, 4, platform_ioport_write, NULL);
|
|
+/*
|
|
PCIXenPlatformState *d = (PCIXenPlatformState *)pci_dev;
|
|
register_ioport_write(addr, size, 1, xen_platform_ioport_writeb, d);
|
|
register_ioport_read(addr, size, 1, xen_platform_ioport_readb, d);
|
|
+*/
|
|
}
|
|
|
|
static uint32_t platform_mmio_read(void *opaque, target_phys_addr_t addr)
|
|
Index: xen-4.3.0-testing/tools/qemu-xen-traditional-dir-remote/hw/ide.c
|
|
===================================================================
|
|
--- xen-4.3.0-testing.orig/tools/qemu-xen-traditional-dir-remote/hw/ide.c
|
|
+++ xen-4.3.0-testing/tools/qemu-xen-traditional-dir-remote/hw/ide.c
|
|
@@ -935,8 +935,9 @@ static inline void ide_dma_submit_check(
|
|
|
|
static inline void ide_set_irq(IDEState *s)
|
|
{
|
|
- BMDMAState *bm = s->bmdma;
|
|
- if (!s->bs) return; /* ouch! (see ide_flush_cb) */
|
|
+ BMDMAState *bm;
|
|
+ if (!s || !s->bs) return; /* ouch! (see ide_flush_cb) */
|
|
+ bm = s->bmdma;
|
|
if (!(s->cmd & IDE_CMD_DISABLE_IRQ)) {
|
|
if (bm) {
|
|
bm->status |= BM_STATUS_INT;
|
|
@@ -1224,14 +1225,14 @@ static void ide_read_dma_cb(void *opaque
|
|
int n;
|
|
int64_t sector_num;
|
|
|
|
+ if (!s || !s->bs) return; /* ouch! (see ide_flush_cb) */
|
|
+
|
|
if (ret < 0) {
|
|
dma_buf_commit(s, 1);
|
|
ide_dma_error(s);
|
|
return;
|
|
}
|
|
|
|
- if (!s->bs) return; /* ouch! (see ide_flush_cb) */
|
|
-
|
|
n = s->io_buffer_size >> 9;
|
|
sector_num = ide_get_sector(s);
|
|
if (n > 0) {
|
|
@@ -1335,6 +1336,8 @@ static void ide_write_flush_cb(void *opa
|
|
BMDMAState *bm = opaque;
|
|
IDEState *s = bm->ide_if;
|
|
|
|
+ if (!s) return; /* yikes */
|
|
+
|
|
if (ret != 0) {
|
|
ide_dma_error(s);
|
|
return;
|
|
@@ -1366,13 +1369,13 @@ static void ide_write_dma_cb(void *opaqu
|
|
int n;
|
|
int64_t sector_num;
|
|
|
|
+ if (!s || !s->bs) return; /* ouch! (see ide_flush_cb) */
|
|
+
|
|
if (ret < 0) {
|
|
if (ide_handle_write_error(s, -ret, BM_STATUS_DMA_RETRY))
|
|
return;
|
|
}
|
|
|
|
- if (!s->bs) return; /* ouch! (see ide_flush_cb) */
|
|
-
|
|
n = s->io_buffer_size >> 9;
|
|
sector_num = ide_get_sector(s);
|
|
if (n > 0) {
|
|
@@ -1429,7 +1432,7 @@ static void ide_flush_cb(void *opaque, i
|
|
{
|
|
IDEState *s = opaque;
|
|
|
|
- if (!s->bs) return; /* ouch! (see below) */
|
|
+ if (!s || !s->bs) return; /* ouch! (see below) */
|
|
|
|
if (ret) {
|
|
/* We are completely doomed. The IDE spec does not permit us
|
|
@@ -1686,7 +1689,7 @@ static void ide_atapi_cmd_read_dma_cb(vo
|
|
IDEState *s = bm->ide_if;
|
|
int data_offset, n;
|
|
|
|
- if (!s->bs) return; /* ouch! (see ide_flush_cb) */
|
|
+ if (!s || !s->bs) return; /* ouch! (see ide_flush_cb) */
|
|
|
|
if (ret < 0) {
|
|
ide_atapi_io_error(s, ret);
|
|
@@ -2365,7 +2368,7 @@ static void cdrom_change_cb(void *opaque
|
|
IDEState *s = opaque;
|
|
uint64_t nb_sectors;
|
|
|
|
- if (!s->bs) return; /* ouch! (see ide_flush_cb) */
|
|
+ if (!s || !s->bs) return; /* ouch! (see ide_flush_cb) */
|
|
|
|
bdrv_get_geometry(s->bs, &nb_sectors);
|
|
s->nb_sectors = nb_sectors;
|
|
Index: xen-4.3.0-testing/tools/qemu-xen-traditional-dir-remote/vl.c
|
|
===================================================================
|
|
--- xen-4.3.0-testing.orig/tools/qemu-xen-traditional-dir-remote/vl.c
|
|
+++ xen-4.3.0-testing/tools/qemu-xen-traditional-dir-remote/vl.c
|
|
@@ -30,6 +30,7 @@
|
|
#include "hw/isa.h"
|
|
#include "hw/baum.h"
|
|
#include "hw/bt.h"
|
|
+#include "hw/watchdog.h"
|
|
#include "net.h"
|
|
#include "console.h"
|
|
#include "sysemu.h"
|
|
@@ -200,7 +201,7 @@ DriveInfo drives_table[MAX_DRIVES+1];
|
|
int nb_drives;
|
|
enum vga_retrace_method vga_retrace_method = VGA_RETRACE_DUMB;
|
|
int vga_ram_size;
|
|
-static DisplayState *display_state;
|
|
+DisplayState *display_state;
|
|
int nographic;
|
|
static int curses;
|
|
static int sdl;
|
|
@@ -2627,6 +2628,8 @@ int drive_init(struct drive_opt *arg, in
|
|
strncpy(drives_table[nb_drives].serial, serial, sizeof(serial));
|
|
nb_drives++;
|
|
|
|
+ bdrv_flags = BDRV_O_RDWR;
|
|
+
|
|
switch(type) {
|
|
case IF_IDE:
|
|
case IF_XEN:
|
|
@@ -2640,6 +2643,7 @@ int drive_init(struct drive_opt *arg, in
|
|
break;
|
|
case MEDIA_CDROM:
|
|
bdrv_set_type_hint(bdrv, BDRV_TYPE_CDROM);
|
|
+ bdrv_flags &= ~BDRV_O_RDWR;
|
|
break;
|
|
}
|
|
break;
|
|
@@ -2660,7 +2664,6 @@ int drive_init(struct drive_opt *arg, in
|
|
}
|
|
if (!file[0])
|
|
return -2;
|
|
- bdrv_flags = 0;
|
|
if (snapshot) {
|
|
bdrv_flags |= BDRV_O_SNAPSHOT;
|
|
cache = 2; /* always use write-back with snapshot */
|
|
@@ -4175,6 +4178,10 @@ static void help(int exitcode)
|
|
"-startdate select initial date of the clock\n"
|
|
"-icount [N|auto]\n"
|
|
" enable virtual instruction counter with 2^N clock ticks per instruction\n"
|
|
+ "-watchdog i6300esb|ib700\n"
|
|
+ " enable virtual hardware watchdog [default=none]\n"
|
|
+ "-watchdog-action reset|shutdown|poweroff|pause|debug|none\n"
|
|
+ " action when watchdog fires [default=reset]\n"
|
|
"-echr chr set terminal escape character instead of ctrl-a\n"
|
|
"-virtioconsole c\n"
|
|
" set virtio console\n"
|
|
@@ -4322,6 +4329,8 @@ enum {
|
|
QEMU_OPTION_localtime,
|
|
QEMU_OPTION_startdate,
|
|
QEMU_OPTION_icount,
|
|
+ QEMU_OPTION_watchdog,
|
|
+ QEMU_OPTION_watchdog_action,
|
|
QEMU_OPTION_echr,
|
|
QEMU_OPTION_virtiocon,
|
|
QEMU_OPTION_show_cursor,
|
|
@@ -4448,6 +4457,8 @@ static const QEMUOption qemu_options[] =
|
|
{ "localtime", 0, QEMU_OPTION_localtime },
|
|
{ "startdate", HAS_ARG, QEMU_OPTION_startdate },
|
|
{ "icount", HAS_ARG, QEMU_OPTION_icount },
|
|
+ { "watchdog", HAS_ARG, QEMU_OPTION_watchdog },
|
|
+ { "watchdog-action", HAS_ARG, QEMU_OPTION_watchdog_action },
|
|
{ "echr", HAS_ARG, QEMU_OPTION_echr },
|
|
{ "virtioconsole", HAS_ARG, QEMU_OPTION_virtiocon },
|
|
{ "show-cursor", 0, QEMU_OPTION_show_cursor },
|
|
@@ -4949,6 +4960,8 @@ int main(int argc, char **argv, char **e
|
|
tb_size = 0;
|
|
autostart= 1;
|
|
|
|
+ register_watchdogs();
|
|
+
|
|
optind = 1;
|
|
for(;;) {
|
|
if (optind >= argc)
|
|
@@ -5323,6 +5336,17 @@ int main(int argc, char **argv, char **e
|
|
serial_devices[serial_device_index] = optarg;
|
|
serial_device_index++;
|
|
break;
|
|
+ case QEMU_OPTION_watchdog:
|
|
+ i = select_watchdog(optarg);
|
|
+ if (i > 0)
|
|
+ exit (i == 1 ? 1 : 0);
|
|
+ break;
|
|
+ case QEMU_OPTION_watchdog_action:
|
|
+ if (select_watchdog_action(optarg) == -1) {
|
|
+ fprintf(stderr, "Unknown -watchdog-action parameter\n");
|
|
+ exit(1);
|
|
+ }
|
|
+ break;
|
|
case QEMU_OPTION_virtiocon:
|
|
if (virtio_console_index >= MAX_VIRTIO_CONSOLES) {
|
|
fprintf(stderr, "qemu: too many virtio consoles\n");
|
|
@@ -5838,9 +5862,9 @@ int main(int argc, char **argv, char **e
|
|
if ((msg = xenbus_read(XBT_NIL, "domid", &domid_s)))
|
|
fprintf(stderr,"Can not read our own domid: %s\n", msg);
|
|
else
|
|
- xenstore_parse_domain_config(atoi(domid_s));
|
|
+ xenstore_parse_domain_config(atoi(domid_s), machine);
|
|
#else
|
|
- xenstore_parse_domain_config(domid);
|
|
+ xenstore_parse_domain_config(domid, machine);
|
|
#endif /* CONFIG_STUBDOM */
|
|
}
|
|
|
|
Index: xen-4.3.0-testing/tools/python/xen/xend/XendConstants.py
|
|
===================================================================
|
|
--- xen-4.3.0-testing.orig/tools/python/xen/xend/XendConstants.py
|
|
+++ xen-4.3.0-testing/tools/python/xen/xend/XendConstants.py
|
|
@@ -94,7 +94,7 @@ DOM_STATES_OLD = [
|
|
SHUTDOWN_TIMEOUT = (60.0 * 5)
|
|
|
|
"""Minimum time between domain restarts in seconds."""
|
|
-MINIMUM_RESTART_TIME = 60
|
|
+MINIMUM_RESTART_TIME = 10
|
|
|
|
RESTART_IN_PROGRESS = 'xend/restart_in_progress'
|
|
DUMPCORE_IN_PROGRESS = 'xend/dumpcore_in_progress'
|
|
Index: xen-4.3.0-testing/tools/python/xen/xend/XendLogging.py
|
|
===================================================================
|
|
--- xen-4.3.0-testing.orig/tools/python/xen/xend/XendLogging.py
|
|
+++ xen-4.3.0-testing/tools/python/xen/xend/XendLogging.py
|
|
@@ -76,7 +76,7 @@ if 'TRACE' not in logging.__dict__:
|
|
log = logging.getLogger("xend")
|
|
|
|
|
|
-MAX_BYTES = 1 << 20 # 1MB
|
|
+MAX_BYTES = 0
|
|
BACKUP_COUNT = 5
|
|
|
|
STDERR_FORMAT = "[%(name)s] %(levelname)s (%(module)s:%(lineno)d) %(message)s"
|
|
Index: xen-4.3.0-testing/tools/python/xen/xend/server/XMLRPCServer.py
|
|
===================================================================
|
|
--- xen-4.3.0-testing.orig/tools/python/xen/xend/server/XMLRPCServer.py
|
|
+++ xen-4.3.0-testing/tools/python/xen/xend/server/XMLRPCServer.py
|
|
@@ -95,7 +95,7 @@ methods = ['device_create', 'device_conf
|
|
'destroyDevice','getDeviceSxprs',
|
|
'setMemoryTarget', 'setName', 'setVCpuCount', 'shutdown',
|
|
'send_sysrq', 'getVCPUInfo', 'waitForDevices',
|
|
- 'getRestartCount', 'getBlockDeviceClass']
|
|
+ 'getRestartCount', 'getBlockDeviceClass', 'chgvncpasswd']
|
|
|
|
exclude = ['domain_create', 'domain_restore']
|
|
|
|
Index: xen-4.3.0-testing/tools/qemu-xen-traditional-dir-remote/block_int.h
|
|
===================================================================
|
|
--- xen-4.3.0-testing.orig/tools/qemu-xen-traditional-dir-remote/block_int.h
|
|
+++ xen-4.3.0-testing/tools/qemu-xen-traditional-dir-remote/block_int.h
|
|
@@ -122,6 +122,9 @@ struct BlockDriverState {
|
|
BlockDriver *drv; /* NULL means no media */
|
|
void *opaque;
|
|
|
|
+ int boot_sector_enabled;
|
|
+ uint8_t boot_sector_data[512];
|
|
+
|
|
char filename[1024];
|
|
char backing_file[1024]; /* if non zero, the image is a diff of
|
|
this file image */
|
|
Index: xen-4.3.0-testing/tools/qemu-xen-traditional-dir-remote/block.h
|
|
===================================================================
|
|
--- xen-4.3.0-testing.orig/tools/qemu-xen-traditional-dir-remote/block.h
|
|
+++ xen-4.3.0-testing/tools/qemu-xen-traditional-dir-remote/block.h
|
|
@@ -82,6 +82,7 @@ int64_t bdrv_getlength(BlockDriverState
|
|
void bdrv_get_geometry(BlockDriverState *bs, uint64_t *nb_sectors_ptr);
|
|
void bdrv_guess_geometry(BlockDriverState *bs, int *pcyls, int *pheads, int *psecs);
|
|
int bdrv_commit(BlockDriverState *bs);
|
|
+void bdrv_set_boot_sector(BlockDriverState *bs, const uint8_t *data, int size);
|
|
/* async block I/O */
|
|
typedef struct BlockDriverAIOCB BlockDriverAIOCB;
|
|
typedef void BlockDriverCompletionFunc(void *opaque, int ret);
|
|
Index: xen-4.3.0-testing/tools/qemu-xen-traditional-dir-remote/hw/watchdog.c
|
|
===================================================================
|
|
--- /dev/null
|
|
+++ xen-4.3.0-testing/tools/qemu-xen-traditional-dir-remote/hw/watchdog.c
|
|
@@ -0,0 +1,146 @@
|
|
+/*
|
|
+ * Virtual hardware watchdog.
|
|
+ *
|
|
+ * Copyright (C) 2009 Red Hat Inc.
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or
|
|
+ * modify it under the terms of the GNU General Public License
|
|
+ * as published by the Free Software Foundation; either version 2
|
|
+ * of the License, or (at your option) any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
|
+ * USA.
|
|
+ *
|
|
+ * By Richard W.M. Jones (rjones@redhat.com).
|
|
+ */
|
|
+
|
|
+#include "qemu-common.h"
|
|
+#include "sys-queue.h"
|
|
+#include "sysemu.h"
|
|
+#include "hw/watchdog.h"
|
|
+
|
|
+/* Possible values for action parameter. */
|
|
+#define WDT_RESET 1 /* Hard reset. */
|
|
+#define WDT_SHUTDOWN 2 /* Shutdown. */
|
|
+#define WDT_POWEROFF 3 /* Quit. */
|
|
+#define WDT_PAUSE 4 /* Pause. */
|
|
+#define WDT_DEBUG 5 /* Prints a message and continues running. */
|
|
+#define WDT_NONE 6 /* Do nothing. */
|
|
+
|
|
+static WatchdogTimerModel *watchdog;
|
|
+static int watchdog_action = WDT_RESET;
|
|
+static LIST_HEAD(watchdog_list, WatchdogTimerModel) watchdog_list;
|
|
+
|
|
+void watchdog_add_model(WatchdogTimerModel *model)
|
|
+{
|
|
+ LIST_INSERT_HEAD(&watchdog_list, model, entry);
|
|
+}
|
|
+
|
|
+/* Returns:
|
|
+ * 0 = continue
|
|
+ * 1 = exit program with error
|
|
+ * 2 = exit program without error
|
|
+ */
|
|
+int select_watchdog(const char *p)
|
|
+{
|
|
+ WatchdogTimerModel *model;
|
|
+
|
|
+ if (watchdog) {
|
|
+ fprintf(stderr,
|
|
+ "qemu: only one watchdog option may be given\n");
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ /* -watchdog ? lists available devices and exits cleanly. */
|
|
+ if (strcmp(p, "?") == 0) {
|
|
+ LIST_FOREACH(model, &watchdog_list, entry) {
|
|
+ fprintf(stderr, "\t%s\t%s\n",
|
|
+ model->wdt_name, model->wdt_description);
|
|
+ }
|
|
+ return 2;
|
|
+ }
|
|
+
|
|
+ LIST_FOREACH(model, &watchdog_list, entry) {
|
|
+ if (strcasecmp(model->wdt_name, p) == 0) {
|
|
+ watchdog = model;
|
|
+ return 0;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ fprintf(stderr, "Unknown -watchdog device. Supported devices are:\n");
|
|
+ LIST_FOREACH(model, &watchdog_list, entry) {
|
|
+ fprintf(stderr, "\t%s\t%s\n",
|
|
+ model->wdt_name, model->wdt_description);
|
|
+ }
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+int select_watchdog_action(const char *p)
|
|
+{
|
|
+ if (strcasecmp(p, "reset") == 0)
|
|
+ watchdog_action = WDT_RESET;
|
|
+ else if (strcasecmp(p, "shutdown") == 0)
|
|
+ watchdog_action = WDT_SHUTDOWN;
|
|
+ else if (strcasecmp(p, "poweroff") == 0)
|
|
+ watchdog_action = WDT_POWEROFF;
|
|
+ else if (strcasecmp(p, "pause") == 0)
|
|
+ watchdog_action = WDT_PAUSE;
|
|
+ else if (strcasecmp(p, "debug") == 0)
|
|
+ watchdog_action = WDT_DEBUG;
|
|
+ else if (strcasecmp(p, "none") == 0)
|
|
+ watchdog_action = WDT_NONE;
|
|
+ else
|
|
+ return -1;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* This actually performs the "action" once a watchdog has expired,
|
|
+ * ie. reboot, shutdown, exit, etc.
|
|
+ */
|
|
+void watchdog_perform_action(void)
|
|
+{
|
|
+ switch(watchdog_action) {
|
|
+ case WDT_RESET: /* same as 'system_reset' in monitor */
|
|
+ qemu_system_reset_request();
|
|
+ break;
|
|
+
|
|
+ case WDT_SHUTDOWN: /* same as 'system_powerdown' in monitor */
|
|
+ qemu_system_powerdown_request();
|
|
+ break;
|
|
+
|
|
+ case WDT_POWEROFF: /* same as 'quit' command in monitor */
|
|
+ exit(0);
|
|
+ break;
|
|
+
|
|
+ case WDT_PAUSE: /* same as 'stop' command in monitor */
|
|
+ vm_stop(0);
|
|
+ break;
|
|
+
|
|
+ case WDT_DEBUG:
|
|
+ fprintf(stderr, "watchdog: timer fired\n");
|
|
+ break;
|
|
+
|
|
+ case WDT_NONE:
|
|
+ break;
|
|
+ }
|
|
+}
|
|
+
|
|
+void watchdog_pc_init(PCIBus *pci_bus)
|
|
+{
|
|
+ if (watchdog)
|
|
+ watchdog->wdt_pc_init(pci_bus);
|
|
+}
|
|
+
|
|
+void register_watchdogs(void)
|
|
+{
|
|
+ wdt_ib700_init();
|
|
+ wdt_i6300esb_init();
|
|
+}
|
|
Index: xen-4.3.0-testing/tools/qemu-xen-traditional-dir-remote/hw/watchdog.h
|
|
===================================================================
|
|
--- /dev/null
|
|
+++ xen-4.3.0-testing/tools/qemu-xen-traditional-dir-remote/hw/watchdog.h
|
|
@@ -0,0 +1,54 @@
|
|
+/*
|
|
+ * Virtual hardware watchdog.
|
|
+ *
|
|
+ * Copyright (C) 2009 Red Hat Inc.
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or
|
|
+ * modify it under the terms of the GNU General Public License
|
|
+ * as published by the Free Software Foundation; either version 2
|
|
+ * of the License, or (at your option) any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
|
+ * USA.
|
|
+ *
|
|
+ * By Richard W.M. Jones (rjones@redhat.com).
|
|
+ */
|
|
+
|
|
+#ifndef QEMU_WATCHDOG_H
|
|
+#define QEMU_WATCHDOG_H
|
|
+
|
|
+extern void wdt_i6300esb_init(void);
|
|
+extern void wdt_ib700_init(void);
|
|
+
|
|
+
|
|
+struct WatchdogTimerModel {
|
|
+ LIST_ENTRY(WatchdogTimerModel) entry;
|
|
+
|
|
+ /* Short name of the device - used to select it on the command line. */
|
|
+ const char *wdt_name;
|
|
+ /* Longer description (eg. manufacturer and full model number). */
|
|
+ const char *wdt_description;
|
|
+
|
|
+ /* This callback should create/register the device. It is called
|
|
+ * indirectly from hw/pc.c when the virtual PC is being set up.
|
|
+ */
|
|
+ void (*wdt_pc_init)(PCIBus *pci_bus);
|
|
+};
|
|
+typedef struct WatchdogTimerModel WatchdogTimerModel;
|
|
+
|
|
+/* in hw/watchdog.c */
|
|
+extern int select_watchdog(const char *p);
|
|
+extern int select_watchdog_action(const char *action);
|
|
+extern void watchdog_add_model(WatchdogTimerModel *model);
|
|
+extern void watchdog_perform_action(void);
|
|
+extern void watchdog_pc_init(PCIBus *pci_bus);
|
|
+extern void register_watchdogs(void);
|
|
+
|
|
+#endif /* QEMU_WATCHDOG_H */
|
|
Index: xen-4.3.0-testing/tools/qemu-xen-traditional-dir-remote/hw/wdt_i6300esb.c
|
|
===================================================================
|
|
--- /dev/null
|
|
+++ xen-4.3.0-testing/tools/qemu-xen-traditional-dir-remote/hw/wdt_i6300esb.c
|
|
@@ -0,0 +1,470 @@
|
|
+/*
|
|
+ * Virtual hardware watchdog.
|
|
+ *
|
|
+ * Copyright (C) 2009 Red Hat Inc.
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or
|
|
+ * modify it under the terms of the GNU General Public License
|
|
+ * as published by the Free Software Foundation; either version 2
|
|
+ * of the License, or (at your option) any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
|
+ * USA.
|
|
+ *
|
|
+ * By Richard W.M. Jones (rjones@redhat.com).
|
|
+ */
|
|
+
|
|
+#include <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
|