|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-unstable] merge
# HG changeset patch
# User Tim Deegan <tim@xxxxxxx>
# Date 1322760252 0
# Node ID f30a33c5b5bd1e2b0bdffa3a649490157e451a4e
# Parent f25a004a6de8efc15d95408f3e92081393360acb
# Parent 3e5683b6b37f9010772dac4a92166b1666485ddd
merge
---
diff -r f25a004a6de8 -r f30a33c5b5bd Config.mk
--- a/Config.mk Thu Dec 01 17:21:24 2011 +0000
+++ b/Config.mk Thu Dec 01 17:24:12 2011 +0000
@@ -232,7 +232,7 @@
OCAML_TOOLS ?= y
CONFIG_MINITERM ?= n
CONFIG_LOMOUNT ?= n
-CONFIG_SYSTEM_LIBAIO ?= n
+CONFIG_SYSTEM_LIBAIO ?= y
ifeq ($(OCAML_TOOLS),y)
OCAML_TOOLS := $(shell ocamlopt -v > /dev/null 2>&1 && echo "y" || echo "n")
diff -r f25a004a6de8 -r f30a33c5b5bd docs/gen-html-index
--- a/docs/gen-html-index Thu Dec 01 17:21:24 2011 +0000
+++ b/docs/gen-html-index Thu Dec 01 17:24:12 2011 +0000
@@ -10,7 +10,6 @@
use Getopt::Long;
use IO::File;
use File::Basename;
-use List::MoreUtils qw/ uniq /;
Getopt::Long::Configure('bundling');
@@ -99,6 +98,12 @@
}
}
+sub uniq (@) {
+ my %h;
+ foreach (@_) { $h{$_} = 1; }
+ return keys %h;
+}
+
for (@docs) { s,^\Q$outdir\E/,, }
@docs = grep { -e "$outdir/$_" && (make_linktext($_) ne "NO-INDEX") } @docs;
diff -r f25a004a6de8 -r f30a33c5b5bd docs/man/xl.pod.1
--- a/docs/man/xl.pod.1 Thu Dec 01 17:21:24 2011 +0000
+++ b/docs/man/xl.pod.1 Thu Dec 01 17:24:12 2011 +0000
@@ -32,19 +32,51 @@
=head1 NOTES
+=over 4
+
+=item start the script B</etc/init.d/xencommons> at boot time
+
Most B<xl> operations rely upon B<xenstored> and B<xenconsoled>: make
sure you start the script B</etc/init.d/xencommons> at boot time to
initialize all the daemons needed by B<xl>.
+=item setup a B<xenbr0> bridge in dom0
+
In the most common network configuration, you need to setup a bridge in dom0
named B<xenbr0> in order to have a working network in the guest domains.
Please refer to the documentation of your Linux distribution to know how to
setup the bridge.
+=item B<autoballoon>
+
+If you specify the amount of memory dom0 has, passing B<dom0_mem> to
+Xen, it is highly reccomended to disable B<autoballoon>. Edit
+B</etc/xen/xl.conf> and set it to 0.
+
+=item run xl as B<root>
+
Most B<xl> commands require root privileges to run due to the
communications channels used to talk to the hypervisor. Running as
non root will return an error.
+=back
+
+=head1 GLOBAL OPTIONS
+
+Some global options are always available:
+
+=over 4
+
+=item B<-v>
+
+Verbose.
+
+=item B<-N>
+
+Dry run: do not actually execute the command.
+
+=back
+
=head1 DOMAIN SUBCOMMANDS
The following subcommands manipulate domains directly. As stated
@@ -52,13 +84,19 @@
=over 4
-=item B<create> [I<OPTIONS>] I<configfile>
+=item B<button-press> I<domain-id> I<button>
-The create subcommand requires a config file: see L<xl.cfg(5)> for
-full details of that file format and possible options.
+Indicate an ACPI button press to the domain. I<button> is may be 'power' or
+'sleep'. This command is only available for HVM domains.
-I<configfile> can either be an absolute path to a file, or a relative
-path to a file located in /etc/xen.
+=item B<create> [I<configfile>] [I<OPTIONS>]
+
+The create subcommand takes a config file as first argument: see
+L<xl.cfg> for full details of that file format and possible options.
+If I<configfile> is missing B<XL> creates the domain starting from the
+default value for every option.
+
+I<configfile> has to be an absolute path to a file.
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
@@ -76,11 +114,6 @@
Use the given configuration file.
-=item B<-n>, B<--dryrun>
-
-Dry run - prints the resulting configuration in SXP but does not create
-the domain.
-
=item B<-p>
Leave the domain paused after it is created.
@@ -88,7 +121,15 @@
=item B<-c>
Attach console to the domain as soon as it has started. This is
-useful for determining issues with crashing domains.
+useful for determining issues with crashing domains and just as a
+general convenience since you often want to watch the
+domain boot.
+
+=item B<key=value>
+
+It is possible to pass I<key=value> pairs on the command line to provide
+options as if they were written in the configuration file; these override
+whatever is in the I<configfile>.
=back
@@ -105,7 +146,7 @@
=back
-=item B<console> I<domain-id>
+=item B<console> [I<OPTIONS>] I<domain-id>
Attach to domain I<domain-id>'s console. If you've set up your domains to
have a traditional log in console this will look much like a normal
@@ -113,17 +154,20 @@
Use the key combination Ctrl+] to detach the domain console.
-=item B<vncviewer> [I<OPTIONS>] I<domain-id>
-
-Attach to domain's VNC server, forking a vncviewer process.
-
B<OPTIONS>
=over 4
-=item I<--autopass>
+=item I<-t [pv|serial]>
-Pass VNC password to vncviewer via stdin.
+Connect to a PV console or connect to an emulated serial console.
+PV consoles are the only consoles available for PV domains while HVM
+domains can have both. If this option is not specified it defaults to
+emulated serial for HVM guests and PV console for PV guests.
+
+=item I<-n NUM>
+
+Connect to console number I<NUM>. Console numbers start from 0.
=back
@@ -153,6 +197,10 @@
be written to a distribution specific directory for dump files. Such
as: /var/lib/xen/dump or /var/xen/dump.
+=item B<getenforce>
+
+Returns the current enforcing mode of the Flask Xen security module.
+
=item B<help> [I<--long>]
Displays the short help message (i.e. common commands).
@@ -226,7 +274,8 @@
=item B<s - shutdown>
-FIXME: Why would you ever see this state?
+The guest OS has shut down (SCHEDOP_shutdown has been called) but the
+domain is not dying yet.
=item B<c - crashed>
@@ -239,8 +288,6 @@
The domain is in process of dying, but hasn't completely shutdown or
crashed.
-FIXME: Is this right?
-
=back
B<NOTES>
@@ -256,6 +303,10 @@
=back
+=item B<loadpolicy> I<policyfile>
+
+Loads a new policy int the Flask Xen security module.
+
=item B<mem-max> I<domain-id> I<mem>
Specify the maximum amount of memory the domain is able to use, appending 't'
@@ -297,7 +348,7 @@
=item B<-e>
On the new host, do not wait in the background (on <host>) for the death of the
-domain.
+domain. See the corresponding option of the I<create> subcommand.
=item B<-C> I<config>
@@ -317,6 +368,7 @@
command run from the console. The command returns as soon as it has
executed the reboot action, which may be significantly before the
domain actually reboots.
+It requires PV drivers installed in your guest OS.
The behavior of what happens to a domain when it reboots is set by the
B<on_reboot> parameter of the domain configuration file when the
@@ -337,6 +389,7 @@
=item B<-e>
Do not wait in the background for the death of the domain on the new host.
+See the corresponding option of the I<create> subcommand.
=item B<-d>
@@ -344,6 +397,10 @@
=back
+=item B<setenforce> I<1|0|Enforcing|Permissive>
+
+Sets the current enforcing mode of the Flask Xen security module
+
=item B<save> [I<OPTIONS>] I<domain-id> I<CheckpointFile> [I<ConfigFile>]
Saves a running domain to a state file so that it can be restored
@@ -353,7 +410,6 @@
Passing a config file argument allows the user to manually select the VM config
file used to create the domain.
-
=over 4
=item B<-c>
@@ -370,6 +426,7 @@
succeed, and may take a variable length of time depending on what
services must be shutdown in the domain. The command returns
immediately after signally the domain unless that B<-w> flag is used.
+For HVM domains it requires PV drivers to be installed in your guest OS.
The behavior of what happens to a domain when it reboots is set by the
B<on_shutdown> parameter of the domain configuration file when the
@@ -387,9 +444,17 @@
=item B<sysrq> I<domain-id> I<letter>
-Send a I<Magic System Request> signal to the domain. For more
-information on available magic sys req operations, see sysrq.txt in
-your Linux Kernel sources.
+Send a <Magic System Request> to the domain, each type of request is
+represented by a different letter.
+It can be used to send SysRq requests to Linux guests, see sysrq.txt in
+your Linux Kernel sources for more information.
+It requires PV drivers to be installed in your guest OS.
+
+=item B<trigger> I<domain-id> I<nmi|reset|init|power|sleep> [I<VCPU>]
+
+Send a trigger to a domain, where the trigger can be: nmi, reset, init, power
+or sleep. Optionally a specific vcpu number can be passed as an argument.
+This command is only available for HVM domains.
=item B<unpause> I<domain-id>
@@ -410,10 +475,6 @@
configured VCPU count is an error. Trying to set VCPUs to < 1 will be
quietly ignored.
-Because this operation requires cooperation from the domain operating
-system, there is no guarantee that it will succeed. This command will
-not work with a full virt domain.
-
=item B<vcpu-list> [I<domain-id>]
Lists VCPU information for a specific domain. If no domain is
@@ -430,27 +491,19 @@
this, by ensuring certain VCPUs can only run on certain physical
CPUs.
-=item B<button-press> I<domain-id> I<button>
+=item B<vncviewer> [I<OPTIONS>] I<domain-id>
-Indicate an ACPI button press to the domain. I<button> is may be 'power' or
-'sleep'.
+Attach to domain's VNC server, forking a vncviewer process.
-=item B<trigger> I<domain-id> I<nmi|reset|init|power|sleep> [I<VCPU>]
+B<OPTIONS>
-Send a trigger to a domain, where the trigger can be: nmi, reset, init, power
-or sleep. Optionally a specific vcpu number can be passed as an argument.
+=over 4
-=item B<getenforce>
+=item I<--autopass>
-Returns the current enforcing mode of the Flask Xen security module.
+Pass VNC password to vncviewer via stdin.
-=item B<setenforce> I<1|0|Enforcing|Permissive>
-
-Sets the current enforcing mode of the Flask Xen security module
-
-=item B<loadpolicy> I<policyfile>
-
-Loads a new policy int the Flask Xen security module.
+=back
=back
@@ -460,7 +513,8 @@
=item B<debug-keys> I<keys>
-Send debug I<keys> to Xen.
+Send debug I<keys> to Xen. It is the same as pressing the Xen
+"conswitch" (Ctrl-A by default) three times and then pressing "keys".
=item B<dmesg> [B<-c>]
@@ -483,39 +537,41 @@
Print information about the Xen host in I<name : value> format. When
reporting a Xen bug, please provide this information as part of the
-bug report.
+bug report. See I<http://wiki.xen.org/xenwiki/ReportingBugs> on how to
+report Xen bugs.
-Sample output looks as follows (lines wrapped manually to make the man
-page more readable):
+Sample output looks as follows:
- host : talon
- release : 2.6.12.6-xen0
- version : #1 Mon Nov 14 14:26:26 EST 2005
- machine : i686
- nr_cpus : 2
+ host : scarlett
+ release : 3.1.0-rc4+
+ version : #1001 SMP Wed Oct 19 11:09:54 UTC 2011
+ machine : x86_64
+ nr_cpus : 4
nr_nodes : 1
- cores_per_socket : 1
+ cores_per_socket : 4
threads_per_core : 1
- cpu_mhz : 696
- hw_caps : 0383fbff:00000000:00000000:00000040
- total_memory : 767
- free_memory : 37
- xen_major : 3
- xen_minor : 0
- xen_extra : -devel
- xen_caps : xen-3.0-x86_32
+ cpu_mhz : 2266
+ hw_caps :
bfebfbff:28100800:00000000:00003b40:009ce3bd:00000000:00000001:00000000
+ virt_caps : hvm hvm_directio
+ total_memory : 6141
+ free_memory : 4274
+ free_cpus : 0
+ xen_major : 4
+ xen_minor : 2
+ xen_extra : -unstable
+ xen_caps : xen-3.0-x86_64 xen-3.0-x86_32p hvm-3.0-x86_32
hvm-3.0-x86_32p hvm-3.0-x86_64
xen_scheduler : credit
xen_pagesize : 4096
- platform_params : virt_start=0xfc000000
- xen_changeset : Mon Nov 14 18:13:38 2005 +0100
- 7793:090e44133d40
- cc_compiler : gcc version 3.4.3 (Mandrakelinux
- 10.2 3.4.3-7mdk)
- cc_compile_by : sdague
- cc_compile_domain : (none)
- cc_compile_date : Mon Nov 14 14:16:48 EST 2005
+ platform_params : virt_start=0xffff800000000000
+ xen_changeset : Wed Nov 02 17:09:09 2011 +0000 24066:54a5e994a241
+ xen_commandline : com1=115200,8n1 guest_loglvl=all dom0_mem=750M
console=com1
+ cc_compiler : gcc version 4.4.5 (Debian 4.4.5-8)
+ cc_compile_by : sstabellini
+ cc_compile_domain : uk.xensource.com
+ cc_compile_date : Tue Nov 8 12:03:05 UTC 2011
xend_config_format : 4
+
B<FIELDS>
Not all fields will be explained here, but some of the less obvious
@@ -527,7 +583,8 @@
A vector showing what hardware capabilities are supported by your
processor. This is equivalent to, though more cryptic, the flags
-field in /proc/cpuinfo on a normal Linux machine.
+field in /proc/cpuinfo on a normal Linux machine: they both derive from
+the feature bits returned by the cpuid command on x86 platforms.
=item B<free_memory>
@@ -568,6 +625,9 @@
=item B<pci-list-assignable-devices>
List all the assignable PCI devices.
+These are devices in the system which are configured to be
+available for passthrough and are bound to a suitable PCI
+backend driver in domain 0 rather than a real driver.
=back
@@ -635,10 +695,6 @@
Use the given configuration file.
-=item B<-n>, B<--dryrun>
-
-Dry run - prints the resulting configuration.
-
=back
=item B<cpupool-list> [I<-c|--cpus>] [I<cpu-pool>]
@@ -676,8 +732,8 @@
=head1 VIRTUAL DEVICE COMMANDS
Most virtual devices can be added and removed while guests are
-running. The effect to the guest OS is much the same as any hotplug
-event.
+running, assuming that the necessary support exists in the guest. The
+effect to the guest OS is much the same as any hotplug event.
=head2 BLOCK DEVICES
@@ -699,7 +755,8 @@
=item I<disc-spec-component>
A disc specification in the same format used for the B<disk> variable in
-the domain config file. See F<xl-disk-configuration>.
+the domain config file. See
+L<http://xenbits.xen.org/docs/unstable/misc/xl-disk-configuration.txt>.
=back
@@ -754,8 +811,9 @@
Creates a new network device in the domain specified by I<domain-id>.
I<network-device> describes the device to attach, using the same format as the
-B<vif> string in the domain config file. See L<xl.cfg(5)> for the
-description.
+B<vif> string in the domain config file. See L<xl.cfg> and
+L<http://xenbits.xen.org/docs/unstable/misc/xl-network-configuration.html>
+for more informations.
=item B<network-detach> I<domain-id> I<devid|mac>
@@ -793,17 +851,100 @@
=back
+=head2 TMEM
+
+=over 4
+
+=item B<tmem-list> I[<-l>] I<domain-id>
+
+List tmem pools. If I<-l> is specified, also list tmem stats.
+
+=item B<tmem-freeze> I<domain-id>
+
+Freeze tmem pools.
+
+=item B<tmem-destroy> I<domain-id>
+
+Destroy tmem pools.
+
+=item B<tmem-thaw> I<domain-id>
+
+Thaw tmem pools.
+
+=item B<tmem-set> I<domain-id> [I<OPTIONS>]
+
+Change tmem settings.
+
+B<OPTIONS>
+
+=over 4
+
+=item B<-w> I<WEIGHT>
+
+Weight (int)
+
+=item B<-c> I<CAP>
+
+Cap (int)
+
+=item B<-p> I<COMPRESS>
+
+Compress (int)
+
+=back
+
+=item B<tmem-shared-auth> I<domain-id> [I<OPTIONS>]
+
+De/authenticate shared tmem pool.
+
+B<OPTIONS>
+
+=over 4
+
+=item B<-u> I<UUID>
+
+Specify uuid (abcdef01-2345-6789-1234-567890abcdef)
+
+=item B<-a> I<AUTH>
+
+0=auth,1=deauth
+
+=back
+
+=item B<tmem-freeable>
+
+Get information about how much freeable memory (MB) is in-use by tmem.
+
+=back
+
+=head1 TO BE DOCUMENTED
+
+We need better documentation for:
+
+=over 4
+
+=item B<tmem>
+
+Trascendent Memory.
+
+=item B<Flask>
+
+Xen Flask security module.
+
+=back
+
=head1 SEE ALSO
-L<xl.cfg(5)>, L<xlcpupool.cfg(5)>, B<xentop(1)>
+The following man pages:
-=head1 AUTHOR
+L<xl.cfg>(5), L<xlcpupool.cfg>(5), B<xentop>(1)
- Stefano Stabellini <stefano.stabellini@xxxxxxxxxxxxx>
- Vincent Hanquez <vincent.hanquez@xxxxxxxxxxxxx>
- Ian Jackson <ian.jackson@xxxxxxxxxxxxx>
- Ian Campbell <Ian.Campbell@xxxxxxxxxx>
+And the following documents on the xen.org website:
+
+L<http://xenbits.xen.org/docs/unstable/misc/xl-network-configuration.html>
+L<http://xenbits.xen.org/docs/unstable/misc/xl-disk-configuration.txt>
=head1 BUGS
-Send bugs to xen-devel@xxxxxxxxxxxxxxxxxxxx
+Send bugs to xen-devel@xxxxxxxxxxxxxxxxxxx, see
+http://wiki.xen.org/xenwiki/ReportingBugs on how to send bug reports.
diff -r f25a004a6de8 -r f30a33c5b5bd tools/libxc/Makefile
--- a/tools/libxc/Makefile Thu Dec 01 17:21:24 2011 +0000
+++ b/tools/libxc/Makefile Thu Dec 01 17:24:12 2011 +0000
@@ -42,7 +42,7 @@
GUEST_SRCS-y :=
GUEST_SRCS-y += xg_private.c xc_suspend.c
GUEST_SRCS-$(CONFIG_MIGRATE) += xc_domain_restore.c xc_domain_save.c
-GUEST_SRCS-$(CONFIG_MIGRATE) += xc_offline_page.c
+GUEST_SRCS-$(CONFIG_MIGRATE) += xc_offline_page.c xc_compression.c
GUEST_SRCS-$(CONFIG_HVM) += xc_hvm_build.c
vpath %.c ../../xen/common/libelf
diff -r f25a004a6de8 -r f30a33c5b5bd tools/libxc/xc_compression.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/libxc/xc_compression.c Thu Dec 01 17:24:12 2011 +0000
@@ -0,0 +1,552 @@
+/******************************************************************************
+ * xc_compression.c
+ *
+ * Checkpoint Compression using Page Delta Algorithm.
+ * - A LRU cache of recently dirtied guest pages is maintained.
+ * - For each dirty guest page in the checkpoint, if a previous version of the
+ * page exists in the cache, XOR both pages and send the non-zero sections
+ * to the receiver. The cache is then updated with the newer copy of guest
page.
+ * - The receiver will XOR the non-zero sections against its copy of the guest
+ * page, thereby bringing the guest page up-to-date with the sender side.
+ *
+ * Copyright (c) 2011 Shriram Rajagopalan (rshriram@xxxxxxxxx).
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
USA
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <inttypes.h>
+#include <errno.h>
+#include "xc_private.h"
+#include "xenctrl.h"
+#include "xg_save_restore.h"
+#include "xg_private.h"
+#include "xc_dom.h"
+
+/* Page Cache for Delta Compression*/
+#define DELTA_CACHE_SIZE (XC_PAGE_SIZE * 8192)
+
+/* Internal page buffer to hold dirty pages of a checkpoint,
+ * to be compressed after the domain is resumed for execution.
+ */
+#define PAGE_BUFFER_SIZE (XC_PAGE_SIZE * 8192)
+
+struct cache_page
+{
+ char *page;
+ xen_pfn_t pfn;
+ struct cache_page *next;
+ struct cache_page *prev;
+};
+
+struct compression_ctx
+{
+ /* compression buffer - holds compressed data */
+ char *compbuf;
+ unsigned long compbuf_size;
+ unsigned long compbuf_pos;
+
+ /* Page buffer to hold pages to be compressed */
+ char *inputbuf;
+ /* pfns of pages to be compressed */
+ xen_pfn_t *sendbuf_pfns;
+ unsigned int pfns_len;
+ unsigned int pfns_index;
+
+ /* Compression Cache (LRU) */
+ char *cache_base;
+ struct cache_page **pfn2cache;
+ struct cache_page *cache;
+ struct cache_page *page_list_head;
+ struct cache_page *page_list_tail;
+ unsigned long dom_pfnlist_size;
+};
+
+#define RUNFLAG 0
+#define SKIPFLAG ((char)128)
+#define FLAGMASK SKIPFLAG
+#define LENMASK ((char)127)
+
+/*
+ * see xg_save_restore.h for details on the compressed stream format.
+ * delta size = 4 bytes.
+ * run header = 1 byte (1 bit for runtype, 7bits for run length).
+ * i.e maximum size of a run = 127 * 4 = 508 bytes.
+ * Worst case compression: Entire page has changed.
+ * In the worst case, the size of the compressed page is
+ * 8 runs of 508 bytes + 1 run of 32 bytes + 9 run headers
+ * = 4105 bytes.
+ * We could detect this worst case and send the entire page with a
+ * FULL_PAGE marker, reducing the total size to 4097 bytes. The cost
+ * of this size reduction is an additional memcpy, on top of two previous
+ * memcpy (to the compressed stream and the cache page in the for loop).
+ *
+ * We might as well sacrifice an extra 8 bytes instead of a memcpy.
+ */
+#define WORST_COMP_PAGE_SIZE (XC_PAGE_SIZE + 9)
+
+/*
+ * A zero length skip indicates full page.
+ */
+#define EMPTY_PAGE 0
+#define FULL_PAGE SKIPFLAG
+#define FULL_PAGE_SIZE (XC_PAGE_SIZE + 1)
+#define MAX_DELTAS (XC_PAGE_SIZE/sizeof(uint32_t))
+
+/*
+ * Add a pagetable page or a new page (uncached)
+ * if srcpage is a pagetable page, cache_page is null.
+ * if srcpage is a page that was not previously in the cache,
+ * cache_page points to a free page slot in the cache where
+ * this new page can be copied to.
+ */
+static int add_full_page(comp_ctx *ctx, char *srcpage, char *cache_page)
+{
+ char *dest = (ctx->compbuf + ctx->compbuf_pos);
+
+ if ( (ctx->compbuf_pos + FULL_PAGE_SIZE) > ctx->compbuf_size)
+ return -1;
+
+ if (cache_page)
+ memcpy(cache_page, srcpage, XC_PAGE_SIZE);
+ dest[0] = FULL_PAGE;
+ memcpy(&dest[1], srcpage, XC_PAGE_SIZE);
+ ctx->compbuf_pos += FULL_PAGE_SIZE;
+
+ return FULL_PAGE_SIZE;
+}
+
+static int compress_page(comp_ctx *ctx, char *srcpage, char *cache_page)
+{
+ char *dest = (ctx->compbuf + ctx->compbuf_pos);
+ uint32_t *new, *old;
+
+ int off, runptr = 0;
+ int wascopying = 0, copying = 0, bytes_skipped = 0;
+ int complen = 0, pageoff = 0, runbytes = 0;
+
+ char runlen = 0;
+
+ if ( (ctx->compbuf_pos + WORST_COMP_PAGE_SIZE) > ctx->compbuf_size)
+ return -1;
+
+ /*
+ * There are no alignment issues here since srcpage is
+ * domU's page passed from xc_domain_save and cache_page is
+ * a ptr to cache page (cache is page aligned).
+ */
+ new = (uint32_t*)srcpage;
+ old = (uint32_t*)cache_page;
+
+ for (off = 0; off <= MAX_DELTAS; off++)
+ {
+ /*
+ * At (off == MAX_DELTAS), we are processing the last run
+ * in the page. Since there is no XORing, make wascopying != copying
+ * to satisfy the if-block below.
+ */
+ copying = ((off < MAX_DELTAS) ? (old[off] != new[off]) : !wascopying);
+
+ if (runlen)
+ {
+ /* switching between run types or current run is full */
+ if ( (wascopying != copying) || (runlen == LENMASK) )
+ {
+ runbytes = runlen * sizeof(uint32_t);
+ runlen |= (wascopying ? RUNFLAG : SKIPFLAG);
+ dest[complen++] = runlen;
+
+ if (wascopying) /* RUNFLAG */
+ {
+ pageoff = runptr * sizeof(uint32_t);
+ memcpy(dest + complen, srcpage + pageoff, runbytes);
+ memcpy(cache_page + pageoff, srcpage + pageoff, runbytes);
+ complen += runbytes;
+ }
+ else /* SKIPFLAG */
+ {
+ bytes_skipped += runbytes;
+ }
+
+ runlen = 0;
+ runptr = off;
+ }
+ }
+ runlen++;
+ wascopying = copying;
+ }
+
+ /*
+ * Check for empty page.
+ */
+ if (bytes_skipped == XC_PAGE_SIZE)
+ {
+ complen = 1;
+ dest[0] = EMPTY_PAGE;
+ }
+ ctx->compbuf_pos += complen;
+
+ return complen;
+}
+
+static
+char *get_cache_page(comp_ctx *ctx, xen_pfn_t pfn,
+ int *israw)
+{
+ struct cache_page *item = NULL;
+
+ item = ctx->pfn2cache[pfn];
+
+ if (!item)
+ {
+ *israw = 1;
+
+ /* If the list is full, evict a page from the tail end. */
+ item = ctx->page_list_tail;
+ if (item->pfn != INVALID_P2M_ENTRY)
+ ctx->pfn2cache[item->pfn] = NULL;
+
+ item->pfn = pfn;
+ ctx->pfn2cache[pfn] = item;
+ }
+
+ /* if requested item is in cache move to head of list */
+ if (item != ctx->page_list_head)
+ {
+ if (item == ctx->page_list_tail)
+ {
+ /* item at tail of list. */
+ ctx->page_list_tail = item->prev;
+ (ctx->page_list_tail)->next = NULL;
+ }
+ else
+ {
+ /* item in middle of list */
+ item->prev->next = item->next;
+ item->next->prev = item->prev;
+ }
+
+ item->prev = NULL;
+ item->next = ctx->page_list_head;
+ (ctx->page_list_head)->prev = item;
+ ctx->page_list_head = item;
+ }
+
+ return (ctx->page_list_head)->page;
+}
+
+/* Remove pagetable pages from cache and move to tail, as free pages */
+static
+void invalidate_cache_page(comp_ctx *ctx, xen_pfn_t pfn)
+{
+ struct cache_page *item = NULL;
+
+ item = ctx->pfn2cache[pfn];
+ if (item)
+ {
+ if (item != ctx->page_list_tail)
+ {
+ /* item at head of list */
+ if (item == ctx->page_list_head)
+ {
+ ctx->page_list_head = (ctx->page_list_head)->next;
+ (ctx->page_list_head)->prev = NULL;
+ }
+ else /* item in middle of list */
+ {
+ item->prev->next = item->next;
+ item->next->prev = item->prev;
+ }
+
+ item->next = NULL;
+ item->prev = ctx->page_list_tail;
+ (ctx->page_list_tail)->next = item;
+ ctx->page_list_tail = item;
+ }
+ ctx->pfn2cache[pfn] = NULL;
+ (ctx->page_list_tail)->pfn = INVALID_P2M_ENTRY;
+ }
+}
+
+int xc_compression_add_page(xc_interface *xch, comp_ctx *ctx,
+ char *page, xen_pfn_t pfn, int israw)
+{
+ if (pfn > ctx->dom_pfnlist_size)
+ {
+ ERROR("Invalid pfn passed into "
+ "xc_compression_add_page %" PRIpfn "\n", pfn);
+ return -2;
+ }
+
+ /* pagetable page */
+ if (israw)
+ invalidate_cache_page(ctx, pfn);
+ ctx->sendbuf_pfns[ctx->pfns_len] = israw ? INVALID_P2M_ENTRY : pfn;
+ memcpy(ctx->inputbuf + ctx->pfns_len * XC_PAGE_SIZE, page, XC_PAGE_SIZE);
+ ctx->pfns_len++;
+
+ /* check if we have run out of space. If so,
+ * we need to synchronously compress the pages and flush them out
+ */
+ if (ctx->pfns_len == NRPAGES(PAGE_BUFFER_SIZE))
+ return -1;
+ return 0;
+}
+
+int xc_compression_compress_pages(xc_interface *xch, comp_ctx *ctx,
+ char *compbuf, unsigned long compbuf_size,
+ unsigned long *compbuf_len)
+{
+ char *cache_copy = NULL, *current_page = NULL;
+ int israw, rc = 1;
+
+ if (!ctx->pfns_len || (ctx->pfns_index == ctx->pfns_len)) {
+ ctx->pfns_len = ctx->pfns_index = 0;
+ return 0;
+ }
+
+ ctx->compbuf_pos = 0;
+ ctx->compbuf = compbuf;
+ ctx->compbuf_size = compbuf_size;
+
+ for (; ctx->pfns_index < ctx->pfns_len; ctx->pfns_index++)
+ {
+ israw = 0;
+ cache_copy = NULL;
+ current_page = ctx->inputbuf + ctx->pfns_index * XC_PAGE_SIZE;
+
+ if (ctx->sendbuf_pfns[ctx->pfns_index] == INVALID_P2M_ENTRY)
+ israw = 1;
+ else
+ cache_copy = get_cache_page(ctx,
+ ctx->sendbuf_pfns[ctx->pfns_index],
+ &israw);
+
+ if (israw)
+ rc = (add_full_page(ctx, current_page, cache_copy) >= 0);
+ else
+ rc = (compress_page(ctx, current_page, cache_copy) >= 0);
+
+ if ( !rc )
+ {
+ /* Out of space in outbuf! flush and come back */
+ rc = -1;
+ break;
+ }
+ }
+ if (compbuf_len)
+ *compbuf_len = ctx->compbuf_pos;
+
+ return rc;
+}
+
+inline
+void xc_compression_reset_pagebuf(xc_interface *xch, comp_ctx *ctx)
+{
+ ctx->pfns_index = ctx->pfns_len = 0;
+}
+
+int xc_compression_uncompress_page(xc_interface *xch, char *compbuf,
+ unsigned long compbuf_size,
+ unsigned long *compbuf_pos, char *destpage)
+{
+ unsigned long pos;
+ unsigned int len = 0, pagepos = 0;
+ char flag;
+
+ pos = *compbuf_pos;
+ if (pos >= compbuf_size)
+ {
+ ERROR("Out of bounds exception in compression buffer (a):"
+ "read ptr:%lu, bufsize = %lu\n",
+ *compbuf_pos, compbuf_size);
+ return -1;
+ }
+
+ switch (compbuf[pos])
+ {
+ case EMPTY_PAGE:
+ pos++;
+ break;
+
+ case FULL_PAGE:
+ {
+ /* Check if the input buffer has 4KB of data */
+ if ((pos + FULL_PAGE_SIZE) > compbuf_size)
+ {
+ ERROR("Out of bounds exception in compression buffer (b):"
+ "read ptr = %lu, bufsize = %lu\n",
+ *compbuf_pos, compbuf_size);
+ return -1;
+ }
+ memcpy(destpage, &compbuf[pos + 1], XC_PAGE_SIZE);
+ pos += FULL_PAGE_SIZE;
+ }
+ break;
+
+ default: /* Normal page with one or more runs */
+ {
+ do
+ {
+ flag = compbuf[pos] & FLAGMASK;
+ len = (compbuf[pos] & LENMASK) * sizeof(uint32_t);
+ /* Sanity Check: Zero-length runs are allowed only for
+ * FULL_PAGE and EMPTY_PAGE.
+ */
+ if (!len)
+ {
+ ERROR("Zero length run encountered for normal page: "
+ "buffer (d):read ptr = %lu, flag = %u, "
+ "bufsize = %lu, pagepos = %u\n",
+ pos, (unsigned int)flag, compbuf_size, pagepos);
+ return -1;
+ }
+
+ pos++;
+ if (flag == RUNFLAG)
+ {
+ /* Check if the input buffer has len bytes of data
+ * and whether it would fit in the destination page.
+ */
+ if (((pos + len) > compbuf_size)
+ || ((pagepos + len) > XC_PAGE_SIZE))
+ {
+ ERROR("Out of bounds exception in compression "
+ "buffer (c):read ptr = %lu, runlen = %u, "
+ "bufsize = %lu, pagepos = %u\n",
+ pos, len, compbuf_size, pagepos);
+ return -1;
+ }
+ memcpy(&destpage[pagepos], &compbuf[pos], len);
+ pos += len;
+ }
+ pagepos += len;
+ } while ((pagepos < XC_PAGE_SIZE) && (pos < compbuf_size));
+
+ /* Make sure we have copied/skipped 4KB worth of data */
+ if (pagepos != XC_PAGE_SIZE)
+ {
+ ERROR("Invalid data in compression buffer:"
+ "read ptr = %lu, bufsize = %lu, pagepos = %u\n",
+ pos, compbuf_size, pagepos);
+ return -1;
+ }
+ }
+ }
+ *compbuf_pos = pos;
+ return 0;
+}
+
+void xc_compression_free_context(xc_interface *xch, comp_ctx *ctx)
+{
+ if (!ctx) return;
+
+ if (ctx->inputbuf)
+ free(ctx->inputbuf);
+ if (ctx->sendbuf_pfns)
+ free(ctx->sendbuf_pfns);
+ if (ctx->cache_base)
+ free(ctx->cache_base);
+ if (ctx->pfn2cache)
+ free(ctx->pfn2cache);
+ if (ctx->cache)
+ free(ctx->cache);
+ free(ctx);
+}
+
+comp_ctx *xc_compression_create_context(xc_interface *xch,
+ unsigned long p2m_size)
+{
+ unsigned long i;
+ comp_ctx *ctx = NULL;
+ unsigned long num_cache_pages = DELTA_CACHE_SIZE/XC_PAGE_SIZE;
+
+ ctx = (comp_ctx *)malloc(sizeof(comp_ctx));
+ if (!ctx)
+ {
+ ERROR("Failed to allocate compression_ctx\n");
+ goto error;
+ }
+ memset(ctx, 0, sizeof(comp_ctx));
+
+ ctx->inputbuf = xc_memalign(xch, XC_PAGE_SIZE, PAGE_BUFFER_SIZE);
+ if (!ctx->inputbuf)
+ {
+ ERROR("Failed to allocate page buffer\n");
+ goto error;
+ }
+
+ ctx->cache_base = xc_memalign(xch, XC_PAGE_SIZE, DELTA_CACHE_SIZE);
+ if (!ctx->cache_base)
+ {
+ ERROR("Failed to allocate delta cache\n");
+ goto error;
+ }
+
+ ctx->sendbuf_pfns = malloc(NRPAGES(PAGE_BUFFER_SIZE) *
+ sizeof(xen_pfn_t));
+ if (!ctx->sendbuf_pfns)
+ {
+ ERROR("Could not alloc sendbuf_pfns\n");
+ goto error;
+ }
+ memset(ctx->sendbuf_pfns, -1,
+ NRPAGES(PAGE_BUFFER_SIZE) * sizeof(xen_pfn_t));
+
+ ctx->pfn2cache = calloc(p2m_size, sizeof(struct cache_page *));
+ if (!ctx->pfn2cache)
+ {
+ ERROR("Could not alloc pfn2cache map\n");
+ goto error;
+ }
+
+ ctx->cache = malloc(num_cache_pages * sizeof(struct cache_page));
+ if (!ctx->cache)
+ {
+ ERROR("Could not alloc compression cache\n");
+ goto error;
+ }
+
+ for (i = 0; i < num_cache_pages; i++)
+ {
+ ctx->cache[i].pfn = INVALID_P2M_ENTRY;
+ ctx->cache[i].page = ctx->cache_base + i * XC_PAGE_SIZE;
+ ctx->cache[i].prev = (i == 0) ? NULL : &(ctx->cache[i - 1]);
+ ctx->cache[i].next = ((i+1) == num_cache_pages)? NULL :
+ &(ctx->cache[i + 1]);
+ }
+ ctx->page_list_head = &(ctx->cache[0]);
+ ctx->page_list_tail = &(ctx->cache[num_cache_pages -1]);
+ ctx->dom_pfnlist_size = p2m_size;
+
+ return ctx;
+error:
+ xc_compression_free_context(xch, ctx);
+ return NULL;
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff -r f25a004a6de8 -r f30a33c5b5bd tools/libxc/xc_domain_restore.c
--- a/tools/libxc/xc_domain_restore.c Thu Dec 01 17:21:24 2011 +0000
+++ b/tools/libxc/xc_domain_restore.c Thu Dec 01 17:24:12 2011 +0000
@@ -43,6 +43,7 @@
xen_pfn_t *p2m_batch; /* A table of P2M mappings in the current region. */
int completed; /* Set when a consistent image is available */
int last_checkpoint; /* Set when we should commit to the current
checkpoint when it completes. */
+ int compressing; /* Set when sender signals that pages would be sent
compressed (for Remus) */
struct domain_info_context dinfo;
};
@@ -663,6 +664,10 @@
/* pages is of length nr_physpages, pfn_types is of length nr_pages */
unsigned int nr_physpages, nr_pages;
+ /* checkpoint compression state */
+ int compressing;
+ unsigned long compbuf_pos, compbuf_size;
+
/* Types of the pfns in the current region */
unsigned long* pfn_types;
@@ -701,6 +706,7 @@
{
int count, countpages, oldcount, i;
void* ptmp;
+ unsigned long compbuf_size;
if ( RDEXACT(fd, &count, sizeof(count)) )
{
@@ -820,6 +826,40 @@
}
return pagebuf_get_one(xch, ctx, buf, fd, dom);
+ case XC_SAVE_ID_ENABLE_COMPRESSION:
+ /* We cannot set compression flag directly in pagebuf structure,
+ * since this pagebuf still has uncompressed pages that are yet to
+ * be applied. We enable the compression field in pagebuf structure
+ * after receiving the first tailbuf.
+ */
+ ctx->compressing = 1;
+ // DPRINTF("compression flag received");
+ return pagebuf_get_one(xch, ctx, buf, fd, dom);
+
+ case XC_SAVE_ID_COMPRESSED_DATA:
+
+ /* read the length of compressed chunk coming in */
+ if ( RDEXACT(fd, &compbuf_size, sizeof(unsigned long)) )
+ {
+ PERROR("Error when reading compbuf_size");
+ return -1;
+ }
+ if (!compbuf_size) return 1;
+
+ buf->compbuf_size += compbuf_size;
+ if (!(ptmp = realloc(buf->pages, buf->compbuf_size))) {
+ ERROR("Could not (re)allocate compression buffer");
+ return -1;
+ }
+ buf->pages = ptmp;
+
+ if ( RDEXACT(fd, buf->pages + (buf->compbuf_size - compbuf_size),
+ compbuf_size) ) {
+ PERROR("Error when reading compression buffer");
+ return -1;
+ }
+ return compbuf_size;
+
default:
if ( (count > MAX_BATCH_SIZE) || (count < 0) ) {
ERROR("Max batch size exceeded (%d). Giving up.", count);
@@ -857,6 +897,13 @@
if (!countpages)
return count;
+ /* If Remus Checkpoint Compression is turned on, we will only be
+ * receiving the pfn lists now. The compressed pages will come in later,
+ * following a <XC_SAVE_ID_COMPRESSED_DATA, compressedChunkSize> tuple.
+ */
+ if (buf->compressing)
+ return pagebuf_get_one(xch, ctx, buf, fd, dom);
+
oldcount = buf->nr_physpages;
buf->nr_physpages += countpages;
if (!buf->pages) {
@@ -885,6 +932,7 @@
int rc;
buf->nr_physpages = buf->nr_pages = 0;
+ buf->compbuf_pos = buf->compbuf_size = 0;
do {
rc = pagebuf_get_one(xch, ctx, buf, fd, dom);
@@ -1102,7 +1150,21 @@
/* In verify mode, we use a copy; otherwise we work in place */
page = pagebuf->verify ? (void *)buf : (region_base + i*PAGE_SIZE);
- memcpy(page, pagebuf->pages + (curpage + curbatch) * PAGE_SIZE,
PAGE_SIZE);
+ /* Remus - page decompression */
+ if (pagebuf->compressing)
+ {
+ if (xc_compression_uncompress_page(xch, pagebuf->pages,
+ pagebuf->compbuf_size,
+ &pagebuf->compbuf_pos,
+ (char *)page))
+ {
+ ERROR("Failed to uncompress page (pfn=%lx)\n", pfn);
+ goto err_mapped;
+ }
+ }
+ else
+ memcpy(page, pagebuf->pages + (curpage + curbatch) * PAGE_SIZE,
+ PAGE_SIZE);
pagetype &= XEN_DOMCTL_PFINFO_LTABTYPE_MASK;
@@ -1364,6 +1426,7 @@
if ( !ctx->completed ) {
pagebuf.nr_physpages = pagebuf.nr_pages = 0;
+ pagebuf.compbuf_pos = pagebuf.compbuf_size = 0;
if ( pagebuf_get_one(xch, ctx, &pagebuf, io_fd, dom) < 0 ) {
PERROR("Error when reading batch");
goto out;
@@ -1406,6 +1469,7 @@
}
pagebuf.nr_physpages = pagebuf.nr_pages = 0;
+ pagebuf.compbuf_pos = pagebuf.compbuf_size = 0;
n += j; /* crude stats */
@@ -1449,6 +1513,13 @@
*/
if ( !ctx->last_checkpoint )
fcntl(io_fd, F_SETFL, orig_io_fd_flags | O_NONBLOCK);
+
+ /*
+ * If sender had sent enable compression flag, switch to compressed
+ * checkpoints mode once the first checkpoint is received.
+ */
+ if (ctx->compressing)
+ pagebuf.compressing = 1;
}
if (pagebuf.viridian != 0)
diff -r f25a004a6de8 -r f30a33c5b5bd tools/libxc/xc_domain_save.c
--- a/tools/libxc/xc_domain_save.c Thu Dec 01 17:21:24 2011 +0000
+++ b/tools/libxc/xc_domain_save.c Thu Dec 01 17:24:12 2011 +0000
@@ -218,6 +218,56 @@
return noncached_write(xch, ob, fd, buf, len);
}
+static int write_compressed(xc_interface *xch, comp_ctx *compress_ctx,
+ int dobuf, struct outbuf* ob, int fd)
+{
+ int rc = 0;
+ int header = sizeof(int) + sizeof(unsigned long);
+ int marker = XC_SAVE_ID_COMPRESSED_DATA;
+ unsigned long compbuf_len = 0;
+
+ do
+ {
+ /* check for available space (atleast 8k) */
+ if ((ob->pos + header + XC_PAGE_SIZE * 2) > ob->size)
+ {
+ if (outbuf_flush(xch, ob, fd) < 0)
+ {
+ ERROR("Error when flushing outbuf intermediate");
+ return -1;
+ }
+ }
+
+ rc = xc_compression_compress_pages(xch, compress_ctx,
+ ob->buf + ob->pos + header,
+ ob->size - ob->pos - header,
+ &compbuf_len);
+ if (!rc)
+ return 0;
+
+ if (outbuf_hardwrite(xch, ob, fd, &marker, sizeof(marker)) < 0)
+ {
+ PERROR("Error when writing marker (errno %d)", errno);
+ return -1;
+ }
+
+ if (outbuf_hardwrite(xch, ob, fd, &compbuf_len, sizeof(compbuf_len)) <
0)
+ {
+ PERROR("Error when writing compbuf_len (errno %d)", errno);
+ return -1;
+ }
+
+ ob->pos += (size_t) compbuf_len;
+ if (!dobuf && outbuf_flush(xch, ob, fd) < 0)
+ {
+ ERROR("Error when writing compressed chunk");
+ return -1;
+ }
+ } while (rc != 0);
+
+ return 0;
+}
+
struct time_stats {
struct timeval wall;
long long d0_cpu, d1_cpu;
@@ -815,11 +865,35 @@
unsigned long mfn;
- struct outbuf ob;
+ /* Without checkpoint compression, the dirty pages, pfn arrays
+ * and tailbuf (vcpu ctx, shared info page, etc.) are written
+ * directly to outbuf. All of this is done while the domain is
+ * suspended.
+ *
+ * When checkpoint compression is enabled, the dirty pages are
+ * buffered, compressed "after" the domain is resumed and then
+ * written to outbuf. Since tailbuf data are collected while a
+ * domain is suspended, they cannot be directly written to the
+ * outbuf as there is no dirty page data preceeding tailbuf.
+ *
+ * So,two output buffers are maintained. Tailbuf data goes into
+ * ob_tailbuf. The dirty pages are compressed after resuming the
+ * domain and written to ob_pagebuf. ob_tailbuf is then appended
+ * to ob_pagebuf and finally flushed out.
+ */
+ struct outbuf ob_pagebuf, ob_tailbuf, *ob = NULL;
struct save_ctx _ctx;
struct save_ctx *ctx = &_ctx;
struct domain_info_context *dinfo = &ctx->dinfo;
+ /* Compression context */
+ comp_ctx *compress_ctx= NULL;
+ /* Even if XCFLAGS_CHECKPOINT_COMPRESS is set, we enable compression only
+ * after sending XC_SAVE_ID_ENABLE_COMPRESSION and the tailbuf for
+ * first time.
+ */
+ int compressing = 0;
+
int completed = 0;
if ( hvm && !callbacks->switch_qemu_logdirty )
@@ -829,7 +903,7 @@
return 1;
}
- outbuf_init(xch, &ob, OUTBUF_SIZE);
+ outbuf_init(xch, &ob_pagebuf, OUTBUF_SIZE);
memset(ctx, 0, sizeof(*ctx));
@@ -917,6 +991,16 @@
}
}
+ if ( flags & XCFLAGS_CHECKPOINT_COMPRESS )
+ {
+ if (!(compress_ctx = xc_compression_create_context(xch,
dinfo->p2m_size)))
+ {
+ ERROR("Failed to create compression context");
+ goto out;
+ }
+ outbuf_init(xch, &ob_tailbuf, OUTBUF_SIZE/4);
+ }
+
last_iter = !live;
/* pretend we sent all the pages last iteration */
@@ -1025,9 +1109,11 @@
}
copypages:
-#define wrexact(fd, buf, len) write_buffer(xch, last_iter, &ob, (fd), (buf),
(len))
-#define wruncached(fd, live, buf, len) write_uncached(xch, last_iter, &ob,
(fd), (buf), (len))
+#define wrexact(fd, buf, len) write_buffer(xch, last_iter, ob, (fd), (buf),
(len))
+#define wruncached(fd, live, buf, len) write_uncached(xch, last_iter, ob,
(fd), (buf), (len))
+#define wrcompressed(fd) write_compressed(xch, compress_ctx, last_iter, ob,
(fd))
+ ob = &ob_pagebuf; /* Holds pfn_types, pages/compressed pages */
/* Now write out each data page, canonicalising page tables as we go... */
for ( ; ; )
{
@@ -1270,7 +1356,7 @@
{
/* If the page is not a normal data page, write out any
run of pages we may have previously acumulated */
- if ( run )
+ if ( !compressing && run )
{
if ( wruncached(io_fd, live,
(char*)region_base+(PAGE_SIZE*(j-run)),
@@ -1305,7 +1391,41 @@
goto out;
}
- if ( wruncached(io_fd, live, page, PAGE_SIZE) != PAGE_SIZE
)
+ if (compressing)
+ {
+ int c_err;
+ /* Mark pagetable page to be sent uncompressed */
+ c_err = xc_compression_add_page(xch, compress_ctx,
page,
+ pfn, 1 /* raw page */);
+ if (c_err == -2) /* OOB PFN */
+ {
+ ERROR("Could not add pagetable page "
+ "(pfn:%" PRIpfn "to page buffer\n", pfn);
+ goto out;
+ }
+
+ if (c_err == -1)
+ {
+ /*
+ * We are out of buffer space to hold dirty
+ * pages. Compress and flush the current buffer
+ * to make space. This is a corner case, that
+ * slows down checkpointing as the compression
+ * happens while domain is suspended. Happens
+ * seldom and if you find this occuring
+ * frequently, increase the PAGE_BUFFER_SIZE
+ * in xc_compression.c.
+ */
+ if (wrcompressed(io_fd) < 0)
+ {
+ ERROR("Error when writing compressed"
+ " data (4b)\n");
+ goto out;
+ }
+ }
+ }
+ else if ( wruncached(io_fd, live, page,
+ PAGE_SIZE) != PAGE_SIZE )
{
PERROR("Error when writing to state file (4b)"
" (errno %d)", errno);
@@ -1315,7 +1435,34 @@
else
{
/* We have a normal page: accumulate it for writing. */
- run++;
+ if (compressing)
+ {
+ int c_err;
+ /* For checkpoint compression, accumulate the page in
the
+ * page buffer, to be compressed later.
+ */
+ c_err = xc_compression_add_page(xch, compress_ctx,
spage,
+ pfn, 0 /* not raw page
*/);
+
+ if (c_err == -2) /* OOB PFN */
+ {
+ ERROR("Could not add page "
+ "(pfn:%" PRIpfn "to page buffer\n", pfn);
+ goto out;
+ }
+
+ if (c_err == -1)
+ {
+ if (wrcompressed(io_fd) < 0)
+ {
+ ERROR("Error when writing compressed"
+ " data (4c)\n");
+ goto out;
+ }
+ }
+ }
+ else
+ run++;
}
} /* end of the write out for this batch */
@@ -1423,6 +1570,15 @@
DPRINTF("All memory is saved\n");
+ /* After last_iter, buffer the rest of pagebuf & tailbuf data into a
+ * separate output buffer and flush it after the compressed page chunks.
+ */
+ if (compressing)
+ {
+ ob = &ob_tailbuf;
+ ob->pos = 0;
+ }
+
{
struct {
int id;
@@ -1534,6 +1690,25 @@
}
}
+ /* Enable compression logic on both sides by sending this
+ * one time marker.
+ * NOTE: We could have simplified this procedure by sending
+ * the enable/disable compression flag before the beginning of
+ * the main for loop. But this would break compatibility for
+ * live migration code, with older versions of xen. So we have
+ * to enable it after the last_iter, when the XC_SAVE_ID_*
+ * elements are sent.
+ */
+ if (!compressing && (flags & XCFLAGS_CHECKPOINT_COMPRESS))
+ {
+ i = XC_SAVE_ID_ENABLE_COMPRESSION;
+ if ( wrexact(io_fd, &i, sizeof(int)) )
+ {
+ PERROR("Error when writing enable_compression marker");
+ goto out;
+ }
+ }
+
/* Zero terminate */
i = 0;
if ( wrexact(io_fd, &i, sizeof(int)) )
@@ -1778,14 +1953,38 @@
if ( !rc && callbacks->postcopy )
callbacks->postcopy(callbacks->data);
+ /* guest has been resumed. Now we can compress data
+ * at our own pace.
+ */
+ if (!rc && compressing)
+ {
+ ob = &ob_pagebuf;
+ if (wrcompressed(io_fd) < 0)
+ {
+ ERROR("Error when writing compressed data, after postcopy\n");
+ rc = 1;
+ goto out;
+ }
+ /* Append the tailbuf data to the main outbuf */
+ if ( wrexact(io_fd, ob_tailbuf.buf, ob_tailbuf.pos) )
+ {
+ rc = 1;
+ PERROR("Error when copying tailbuf into outbuf");
+ goto out;
+ }
+ }
+
/* Flush last write and discard cache for file. */
- if ( outbuf_flush(xch, &ob, io_fd) < 0 ) {
+ if ( outbuf_flush(xch, ob, io_fd) < 0 ) {
PERROR("Error when flushing output buffer");
rc = 1;
}
discard_file_cache(xch, io_fd, 1 /* flush */);
+ /* Enable compression now, finally */
+ compressing = (flags & XCFLAGS_CHECKPOINT_COMPRESS);
+
/* checkpoint_cb can spend arbitrarily long in between rounds */
if (!rc && callbacks->checkpoint &&
callbacks->checkpoint(callbacks->data) > 0)
@@ -1827,6 +2026,9 @@
DPRINTF("Warning - couldn't disable qemu log-dirty mode");
}
+ if (compress_ctx)
+ xc_compression_free_context(xch, compress_ctx);
+
if ( live_shinfo )
munmap(live_shinfo, PAGE_SIZE);
diff -r f25a004a6de8 -r f30a33c5b5bd tools/libxc/xc_linux.c
--- a/tools/libxc/xc_linux.c Thu Dec 01 17:21:24 2011 +0000
+++ b/tools/libxc/xc_linux.c Thu Dec 01 17:24:12 2011 +0000
@@ -55,6 +55,18 @@
errno = saved_errno;
}
+void *xc_memalign(xc_interface *xch, size_t alignment, size_t size)
+{
+ int ret;
+ void *ptr;
+
+ ret = posix_memalign(&ptr, alignment, size);
+ if (ret != 0 || !ptr)
+ return NULL;
+
+ return ptr;
+}
+
/*
* Local variables:
* mode: C
diff -r f25a004a6de8 -r f30a33c5b5bd tools/libxc/xc_linux_osdep.c
--- a/tools/libxc/xc_linux_osdep.c Thu Dec 01 17:21:24 2011 +0000
+++ b/tools/libxc/xc_linux_osdep.c Thu Dec 01 17:24:12 2011 +0000
@@ -91,10 +91,9 @@
{
size_t size = npages * XC_PAGE_SIZE;
void *p;
- int ret;
- ret = posix_memalign(&p, XC_PAGE_SIZE, size);
- if (ret != 0 || !p)
+ p = xc_memalign(xch, XC_PAGE_SIZE, size);
+ if (!p)
return NULL;
if ( mlock(p, size) < 0 )
diff -r f25a004a6de8 -r f30a33c5b5bd tools/libxc/xc_minios.c
--- a/tools/libxc/xc_minios.c Thu Dec 01 17:21:24 2011 +0000
+++ b/tools/libxc/xc_minios.c Thu Dec 01 17:24:12 2011 +0000
@@ -73,7 +73,7 @@
static void *minios_privcmd_alloc_hypercall_buffer(xc_interface *xch,
xc_osdep_handle h, int npages)
{
- return memalign(PAGE_SIZE, npages * PAGE_SIZE);
+ return xc_memalign(xch, PAGE_SIZE, npages * PAGE_SIZE);
}
static void minios_privcmd_free_hypercall_buffer(xc_interface *xch,
xc_osdep_handle h, void *ptr, int npages)
@@ -437,6 +437,11 @@
fsync(fd);
}
+void *xc_memalign(xc_interface *xch, size_t alignment, size_t size)
+{
+ return memalign(alignment, size);
+}
+
static xc_osdep_handle minios_gnttab_open(xc_gnttab *xcg)
{
int fd = alloc_fd(FTYPE_GNTMAP);
diff -r f25a004a6de8 -r f30a33c5b5bd tools/libxc/xc_netbsd.c
--- a/tools/libxc/xc_netbsd.c Thu Dec 01 17:21:24 2011 +0000
+++ b/tools/libxc/xc_netbsd.c Thu Dec 01 17:24:12 2011 +0000
@@ -71,8 +71,9 @@
static void *netbsd_privcmd_alloc_hypercall_buffer(xc_interface *xch,
xc_osdep_handle h, int npages)
{
size_t size = npages * XC_PAGE_SIZE;
- void *p = valloc(size);
+ void *p;
+ p = xc_memalign(xch, XC_PAGE_SIZE, size);
if (!p)
return NULL;
@@ -378,6 +379,11 @@
errno = saved_errno;
}
+void *xc_memalign(xc_interface *xch, size_t alignment, size_t size)
+{
+ return valloc(size);
+}
+
static struct xc_osdep_ops *netbsd_osdep_init(xc_interface *xch, enum
xc_osdep_type type)
{
switch ( type )
diff -r f25a004a6de8 -r f30a33c5b5bd tools/libxc/xc_solaris.c
--- a/tools/libxc/xc_solaris.c Thu Dec 01 17:21:24 2011 +0000
+++ b/tools/libxc/xc_solaris.c Thu Dec 01 17:24:12 2011 +0000
@@ -70,7 +70,7 @@
static void *solaris_privcmd_alloc_hypercall_buffer(xc_interface *xch,
xc_osdep_handle h, int npages)
{
- return memalign(XC_PAGE_SIZE, npages * XC_PAGE_SIZE);
+ return xc_memalign(xch, XC_PAGE_SIZE, npages * XC_PAGE_SIZE);
}
static void solaris_privcmd_free_hypercall_buffer(xc_interface *xch,
xc_osdep_handle h, void *ptr, int npages)
@@ -314,6 +314,11 @@
// TODO: Implement for Solaris!
}
+void *xc_memalign(xc_interface *xch, size_t alignment, size_t size)
+{
+ return memalign(alignment, size);
+}
+
static struct xc_osdep_ops *solaris_osdep_init(xc_interface *xch, enum
xc_osdep_type type)
{
switch ( type )
diff -r f25a004a6de8 -r f30a33c5b5bd tools/libxc/xenctrl.h
--- a/tools/libxc/xenctrl.h Thu Dec 01 17:21:24 2011 +0000
+++ b/tools/libxc/xenctrl.h Thu Dec 01 17:24:12 2011 +0000
@@ -1156,6 +1156,8 @@
uint64_t *time,
xc_hypercall_buffer_t *data);
+void *xc_memalign(xc_interface *xch, size_t alignment, size_t size);
+
/**
* Memory maps a range within one domain to a local address range. Mappings
* should be unmapped with munmap and should follow the same rules as mmap
@@ -1935,4 +1937,64 @@
int verbose);
/* Useful for callers who also use libelf. */
+/**
+ * Checkpoint Compression
+ */
+typedef struct compression_ctx comp_ctx;
+comp_ctx *xc_compression_create_context(xc_interface *xch,
+ unsigned long p2m_size);
+void xc_compression_free_context(xc_interface *xch, comp_ctx *ctx);
+
+/**
+ * Add a page to compression page buffer, to be compressed later.
+ *
+ * returns 0 if the page was successfully added to the page buffer
+ *
+ * returns -1 if there is no space in buffer. In this case, the
+ * application should call xc_compression_compress_pages to compress
+ * the buffer (or atleast part of it), thereby freeing some space in
+ * the page buffer.
+ *
+ * returns -2 if the pfn is out of bounds, where the bound is p2m_size
+ * parameter passed during xc_compression_create_context.
+ */
+int xc_compression_add_page(xc_interface *xch, comp_ctx *ctx, char *page,
+ unsigned long pfn, int israw);
+
+/**
+ * Delta compress pages in the compression buffer and inserts the
+ * compressed data into the supplied compression buffer compbuf, whose
+ * size is compbuf_size.
+ * After compression, the pages are copied to the internal LRU cache.
+ *
+ * This function compresses as many pages as possible into the
+ * supplied compression buffer. It maintains an internal iterator to
+ * keep track of pages in the input buffer that are yet to be compressed.
+ *
+ * returns -1 if the compression buffer has run out of space.
+ * returns 1 on success.
+ * returns 0 if no more pages are left to be compressed.
+ * When the return value is non-zero, compbuf_len indicates the actual
+ * amount of data present in compbuf (<=compbuf_size).
+ */
+int xc_compression_compress_pages(xc_interface *xch, comp_ctx *ctx,
+ char *compbuf, unsigned long compbuf_size,
+ unsigned long *compbuf_len);
+
+/**
+ * Resets the internal page buffer that holds dirty pages before compression.
+ * Also resets the iterators.
+ */
+void xc_compression_reset_pagebuf(xc_interface *xch, comp_ctx *ctx);
+
+/**
+ * Caller must supply the compression buffer (compbuf),
+ * its size (compbuf_size) and a reference to index variable (compbuf_pos)
+ * that is used internally. Each call pulls out one page from the compressed
+ * chunk and copies it to dest.
+ */
+int xc_compression_uncompress_page(xc_interface *xch, char *compbuf,
+ unsigned long compbuf_size,
+ unsigned long *compbuf_pos, char *dest);
+
#endif /* XENCTRL_H */
diff -r f25a004a6de8 -r f30a33c5b5bd tools/libxc/xenguest.h
--- a/tools/libxc/xenguest.h Thu Dec 01 17:21:24 2011 +0000
+++ b/tools/libxc/xenguest.h Thu Dec 01 17:24:12 2011 +0000
@@ -27,6 +27,7 @@
#define XCFLAGS_DEBUG 2
#define XCFLAGS_HVM 4
#define XCFLAGS_STDVGA 8
+#define XCFLAGS_CHECKPOINT_COMPRESS 16
#define X86_64_B_SIZE 64
#define X86_32_B_SIZE 32
diff -r f25a004a6de8 -r f30a33c5b5bd tools/libxc/xg_save_restore.h
--- a/tools/libxc/xg_save_restore.h Thu Dec 01 17:21:24 2011 +0000
+++ b/tools/libxc/xg_save_restore.h Thu Dec 01 17:24:12 2011 +0000
@@ -67,7 +67,7 @@
*
* consists of p2m_size bytes comprising an array of xen_pfn_t sized entries.
*
- * BODY PHASE
+ * BODY PHASE - Format A (for live migration or Remus without compression)
* ----------
*
* A series of chunks with a common header:
@@ -87,6 +87,122 @@
*
* If chunk type is 0 then body phase is complete.
*
+ *
+ * BODY PHASE - Format B (for Remus with compression)
+ * ----------
+ *
+ * A series of chunks with a common header:
+ * int : chunk type
+ *
+ * If the chunk type is +ve then chunk contains array of PFNs corresponding
+ * to guest memory and type contains the number of PFNs in the batch:
+ *
+ * unsigned long[] : PFN array, length == number of pages in batch
+ * Each entry consists of XEN_DOMCTL_PFINFO_*
+ * in bits 31-28 and the PFN number in bits 27-0.
+ *
+ * If the chunk type is -ve then chunk consists of one of a number of
+ * metadata types. See definitions of XC_SAVE_ID_* below.
+ *
+ * If the chunk type is -ve and equals XC_SAVE_ID_COMPRESSED_DATA, then the
+ * chunk consists of compressed page data, in the following format:
+ *
+ * unsigned long : Size of the compressed chunk to follow
+ * compressed data : variable length data of size indicated above.
+ * This chunk consists of compressed page data.
+ * The number of pages in one chunk depends on
+ * the amount of space available in the sender's
+ * output buffer.
+ *
+ * Format of compressed data:
+ * compressed_data = <deltas>*
+ * delta = <marker, run*>
+ * marker = (RUNFLAG|SKIPFLAG) bitwise-or RUNLEN [1 byte marker]
+ * RUNFLAG = 0
+ * SKIPFLAG = 1 << 7
+ * RUNLEN = 7-bit unsigned value indicating number of WORDS in the
run
+ * run = string of bytes of length sizeof(WORD) * RUNLEN
+ *
+ * If marker contains RUNFLAG, then RUNLEN * sizeof(WORD) bytes of data
following
+ * the marker is copied into the target page at the appropriate offset
indicated by
+ * the offset_ptr
+ * If marker contains SKIPFLAG, then the offset_ptr is advanced
+ * by RUNLEN * sizeof(WORD).
+ *
+ * If chunk type is 0 then body phase is complete.
+ *
+ * There can be one or more chunks with type XC_SAVE_ID_COMPRESSED_DATA,
+ * containing compressed pages. The compressed chunks are collated to form
+ * one single compressed chunk for the entire iteration. The number of pages
+ * present in this final compressed chunk will be equal to the total number
+ * of valid PFNs specified by the +ve chunks.
+ *
+ * At the sender side, compressed pages are inserted into the output stream
+ * in the same order as they would have been if compression logic was absent.
+ *
+ * Until last iteration, the BODY is sent in Format A, to maintain live
+ * migration compatibility with receivers of older Xen versions.
+ * At the last iteration, if Remus compression was enabled, the sender sends
+ * a trigger, XC_SAVE_ID_ENABLE_COMPRESSION to tell the receiver to parse the
+ * BODY in Format B from the next iteration onwards.
+ *
+ * An example sequence of chunks received in Format B:
+ * +16 +ve chunk
+ * unsigned long[16] PFN array
+ * +100 +ve chunk
+ * unsigned long[100] PFN array
+ * +50 +ve chunk
+ * unsigned long[50] PFN array
+ *
+ * XC_SAVE_ID_COMPRESSED_DATA TAG
+ * N Length of compressed data
+ * N bytes of DATA Decompresses to 166 pages
+ *
+ * XC_SAVE_ID_* other xc save chunks
+ * 0 END BODY TAG
+ *
+ * Corner case with checkpoint compression:
+ * At sender side, after pausing the domain, dirty pages are usually
+ * copied out to a temporary buffer. After the domain is resumed,
+ * compression is done and the compressed chunk(s) are sent, followed by
+ * other XC_SAVE_ID_* chunks.
+ * If the temporary buffer gets full while scanning for dirty pages,
+ * the sender stops buffering of dirty pages, compresses the temporary
+ * buffer and sends the compressed data with XC_SAVE_ID_COMPRESSED_DATA.
+ * The sender then resumes the buffering of dirty pages and continues
+ * scanning for the dirty pages.
+ * For e.g., assume that the temporary buffer can hold 4096 pages and
+ * there are 5000 dirty pages. The following is the sequence of chunks
+ * that the receiver will see:
+ *
+ * +1024 +ve chunk
+ * unsigned long[1024] PFN array
+ * +1024 +ve chunk
+ * unsigned long[1024] PFN array
+ * +1024 +ve chunk
+ * unsigned long[1024] PFN array
+ * +1024 +ve chunk
+ * unsigned long[1024] PFN array
+ *
+ * XC_SAVE_ID_COMPRESSED_DATA TAG
+ * N Length of compressed data
+ * N bytes of DATA Decompresses to 4096 pages
+ *
+ * +4 +ve chunk
+ * unsigned long[4] PFN array
+ *
+ * XC_SAVE_ID_COMPRESSED_DATA TAG
+ * M Length of compressed data
+ * M bytes of DATA Decompresses to 4 pages
+ *
+ * XC_SAVE_ID_* other xc save chunks
+ * 0 END BODY TAG
+ *
+ * In other words, XC_SAVE_ID_COMPRESSED_DATA can be interleaved with
+ * +ve chunks arbitrarily. But at the receiver end, the following condition
+ * always holds true until the end of BODY PHASE:
+ * num(PFN entries +ve chunks) >= num(pages received in compressed form)
+ *
* TAIL PHASE
* ----------
*
@@ -135,6 +251,8 @@
#define XC_SAVE_ID_LAST_CHECKPOINT -9 /* Commit to restoring after
completion of current iteration. */
#define XC_SAVE_ID_HVM_ACPI_IOPORTS_LOCATION -10
#define XC_SAVE_ID_HVM_VIRIDIAN -11
+#define XC_SAVE_ID_COMPRESSED_DATA -12 /* Marker to indicate arrival of
compressed data */
+#define XC_SAVE_ID_ENABLE_COMPRESSION -13 /* Marker to enable compression
logic at receiver side */
/*
** We process save/restore/migrate in batches of pages; the below
diff -r f25a004a6de8 -r f30a33c5b5bd tools/libxl/libxl.c
--- a/tools/libxl/libxl.c Thu Dec 01 17:21:24 2011 +0000
+++ b/tools/libxl/libxl.c Thu Dec 01 17:24:12 2011 +0000
@@ -3330,6 +3330,19 @@
return 0;
}
+int libxl_fd_set_cloexec(int fd)
+{
+ int flags = 0;
+
+ if ((flags = fcntl(fd, F_GETFD)) == -1) {
+ flags = 0;
+ }
+ if ((flags & FD_CLOEXEC)) {
+ return 0;
+ }
+ return fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
+}
+
/*
* Local variables:
* mode: C
diff -r f25a004a6de8 -r f30a33c5b5bd tools/libxl/libxl.h
--- a/tools/libxl/libxl.h Thu Dec 01 17:21:24 2011 +0000
+++ b/tools/libxl/libxl.h Thu Dec 01 17:24:12 2011 +0000
@@ -635,6 +635,9 @@
const char *libxl_run_dir_path(void);
const char *libxl_xenpaging_dir_path(void);
+/* misc */
+int libxl_fd_set_cloexec(int fd);
+
#endif /* LIBXL_H */
/*
diff -r f25a004a6de8 -r f30a33c5b5bd tools/libxl/libxl_internal.c
--- a/tools/libxl/libxl_internal.c Thu Dec 01 17:21:24 2011 +0000
+++ b/tools/libxl/libxl_internal.c Thu Dec 01 17:24:12 2011 +0000
@@ -306,19 +306,6 @@
return 0;
}
-int libxl__fd_set_cloexec(int fd)
-{
- int flags = 0;
-
- if ((flags = fcntl(fd, F_GETFD)) == -1) {
- flags = 0;
- }
- if ((flags & FD_CLOEXEC)) {
- return 0;
- }
- return fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
-}
-
libxl_device_model_version libxl__device_model_version_running(libxl__gc *gc,
uint32_t domid)
{
diff -r f25a004a6de8 -r f30a33c5b5bd tools/libxl/libxl_internal.h
--- a/tools/libxl/libxl_internal.h Thu Dec 01 17:21:24 2011 +0000
+++ b/tools/libxl/libxl_internal.h Thu Dec 01 17:24:12 2011 +0000
@@ -503,7 +503,6 @@
_hidden int libxl__file_reference_map(libxl_file_reference *f);
_hidden int libxl__file_reference_unmap(libxl_file_reference *f);
-_hidden int libxl__fd_set_cloexec(int fd);
_hidden int libxl__e820_alloc(libxl__gc *gc, uint32_t domid,
libxl_domain_config *d_config);
diff -r f25a004a6de8 -r f30a33c5b5bd tools/libxl/libxl_qmp.c
--- a/tools/libxl/libxl_qmp.c Thu Dec 01 17:21:24 2011 +0000
+++ b/tools/libxl/libxl_qmp.c Thu Dec 01 17:24:12 2011 +0000
@@ -324,7 +324,7 @@
if (fcntl(qmp->qmp_fd, F_SETFL, flags | O_NONBLOCK) == -1) {
return -1;
}
- libxl__fd_set_cloexec(qmp->qmp_fd);
+ libxl_fd_set_cloexec(qmp->qmp_fd);
memset(&qmp->addr, 0, sizeof (&qmp->addr));
qmp->addr.sun_family = AF_UNIX;
diff -r f25a004a6de8 -r f30a33c5b5bd tools/libxl/xl_cmdimpl.c
--- a/tools/libxl/xl_cmdimpl.c Thu Dec 01 17:21:24 2011 +0000
+++ b/tools/libxl/xl_cmdimpl.c Thu Dec 01 17:24:12 2011 +0000
@@ -1459,8 +1459,12 @@
union { uint32_t u32; char b[4]; } u32buf;
uint32_t badflags;
- restore_fd = migrate_fd >= 0 ? migrate_fd :
- open(restore_file, O_RDONLY);
+ if (migrate_fd >= 0) {
+ restore_fd = migrate_fd;
+ } else {
+ restore_fd = open(restore_file, O_RDONLY);
+ libxl_fd_set_cloexec(restore_fd);
+ }
CHK_ERRNO( libxl_read_exactly(ctx, restore_fd, &hdr,
sizeof(hdr), restore_file, "header") );
diff -r f25a004a6de8 -r f30a33c5b5bd
tools/python/xen/lowlevel/checkpoint/checkpoint.c
--- a/tools/python/xen/lowlevel/checkpoint/checkpoint.c Thu Dec 01 17:21:24
2011 +0000
+++ b/tools/python/xen/lowlevel/checkpoint/checkpoint.c Thu Dec 01 17:24:12
2011 +0000
@@ -104,13 +104,14 @@
PyObject* postcopy_cb = NULL;
PyObject* checkpoint_cb = NULL;
unsigned int interval = 0;
+ unsigned int flags = 0;
int fd;
struct save_callbacks callbacks;
int rc;
- if (!PyArg_ParseTuple(args, "O|OOOI", &iofile, &suspend_cb, &postcopy_cb,
- &checkpoint_cb, &interval))
+ if (!PyArg_ParseTuple(args, "O|OOOII", &iofile, &suspend_cb, &postcopy_cb,
+ &checkpoint_cb, &interval, &flags))
return NULL;
self->interval = interval;
@@ -160,7 +161,7 @@
callbacks.data = self;
self->threadstate = PyEval_SaveThread();
- rc = checkpoint_start(&self->cps, fd, &callbacks);
+ rc = checkpoint_start(&self->cps, fd, &callbacks, flags);
PyEval_RestoreThread(self->threadstate);
if (rc < 0) {
diff -r f25a004a6de8 -r f30a33c5b5bd
tools/python/xen/lowlevel/checkpoint/checkpoint.h
--- a/tools/python/xen/lowlevel/checkpoint/checkpoint.h Thu Dec 01 17:21:24
2011 +0000
+++ b/tools/python/xen/lowlevel/checkpoint/checkpoint.h Thu Dec 01 17:24:12
2011 +0000
@@ -40,13 +40,15 @@
timer_t timer;
} checkpoint_state;
+#define CHECKPOINT_FLAGS_COMPRESSION 1
char* checkpoint_error(checkpoint_state* s);
void checkpoint_init(checkpoint_state* s);
int checkpoint_open(checkpoint_state* s, unsigned int domid);
void checkpoint_close(checkpoint_state* s);
int checkpoint_start(checkpoint_state* s, int fd,
- struct save_callbacks* callbacks);
+ struct save_callbacks* callbacks,
+ unsigned int remus_flags);
int checkpoint_suspend(checkpoint_state* s);
int checkpoint_resume(checkpoint_state* s);
int checkpoint_postflush(checkpoint_state* s);
diff -r f25a004a6de8 -r f30a33c5b5bd
tools/python/xen/lowlevel/checkpoint/libcheckpoint.c
--- a/tools/python/xen/lowlevel/checkpoint/libcheckpoint.c Thu Dec 01
17:21:24 2011 +0000
+++ b/tools/python/xen/lowlevel/checkpoint/libcheckpoint.c Thu Dec 01
17:24:12 2011 +0000
@@ -170,7 +170,8 @@
}
int checkpoint_start(checkpoint_state* s, int fd,
- struct save_callbacks* callbacks)
+ struct save_callbacks* callbacks,
+ unsigned int remus_flags)
{
int hvm, rc;
int flags = XCFLAGS_LIVE;
@@ -188,6 +189,8 @@
if (switch_qemu_logdirty(s, 1))
return -1;
}
+ if (remus_flags & CHECKPOINT_FLAGS_COMPRESSION)
+ flags |= XCFLAGS_CHECKPOINT_COMPRESS;
callbacks->switch_qemu_logdirty = noop_switch_logdirty;
diff -r f25a004a6de8 -r f30a33c5b5bd tools/python/xen/remus/save.py
--- a/tools/python/xen/remus/save.py Thu Dec 01 17:21:24 2011 +0000
+++ b/tools/python/xen/remus/save.py Thu Dec 01 17:24:12 2011 +0000
@@ -133,7 +133,7 @@
class Saver(object):
def __init__(self, domid, fd, suspendcb=None, resumecb=None,
- checkpointcb=None, interval=0):
+ checkpointcb=None, interval=0, flags=0):
"""Create a Saver object for taking guest checkpoints.
domid: name, number or UUID of a running domain
fd: a stream to which checkpoint data will be written.
@@ -141,12 +141,14 @@
resumecb: callback invoked before guest resumes
checkpointcb: callback invoked when a checkpoint is complete. Return
True to take another checkpoint, or False to stop.
+ flags: Remus flags to be passed to xc_domain_save
"""
self.fd = fd
self.suspendcb = suspendcb
self.resumecb = resumecb
self.checkpointcb = checkpointcb
self.interval = interval
+ self.flags = flags
self.vm = vm.VM(domid)
@@ -164,7 +166,8 @@
try:
self.checkpointer.open(self.vm.domid)
self.checkpointer.start(self.fd, self.suspendcb, self.resumecb,
- self.checkpointcb, self.interval)
+ self.checkpointcb, self.interval,
+ self.flags)
except xen.lowlevel.checkpoint.error, e:
raise CheckpointError(e)
finally:
diff -r f25a004a6de8 -r f30a33c5b5bd tools/remus/remus
--- a/tools/remus/remus Thu Dec 01 17:21:24 2011 +0000
+++ b/tools/remus/remus Thu Dec 01 17:24:12 2011 +0000
@@ -16,6 +16,9 @@
class CfgException(Exception): pass
class Cfg(object):
+
+ REMUS_FLAGS_COMPRESSION = 1
+
def __init__(self):
# must be set
self.domid = 0
@@ -25,6 +28,7 @@
self.port = XendOptions.instance().get_xend_relocation_port()
self.interval = 200
self.netbuffer = True
+ self.flags = self.REMUS_FLAGS_COMPRESSION
self.timer = False
parser = optparse.OptionParser()
@@ -38,6 +42,8 @@
help='replicate to /dev/null (no disk checkpoints,
only memory & net buffering)')
parser.add_option('', '--no-net', dest='nonet', action='store_true',
help='run without net buffering (benchmark option)')
+ parser.add_option('', '--no-compression', dest='nocompress',
action='store_true',
+ help='run without checkpoint compression')
parser.add_option('', '--timer', dest='timer', action='store_true',
help='force pause at checkpoint interval
(experimental)')
self.parser = parser
@@ -56,6 +62,8 @@
self.nullremus = True
if opts.nonet:
self.netbuffer = False
+ if opts.nocompress:
+ self.flags &= ~self.REMUS_FLAGS_COMPRESSION
if opts.timer:
self.timer = True
@@ -190,7 +198,7 @@
rc = 0
checkpointer = save.Saver(cfg.domid, fd, postsuspend, preresume, commit,
- interval)
+ interval, cfg.flags)
try:
checkpointer.start()
diff -r f25a004a6de8 -r f30a33c5b5bd xen/arch/x86/Makefile
--- a/xen/arch/x86/Makefile Thu Dec 01 17:21:24 2011 +0000
+++ b/xen/arch/x86/Makefile Thu Dec 01 17:24:12 2011 +0000
@@ -30,9 +30,10 @@
obj-y += msi.o
obj-y += ioport_emulate.o
obj-y += irq.o
-obj-y += microcode.o
obj-y += microcode_amd.o
obj-y += microcode_intel.o
+# This must come after the vendor specific files.
+obj-y += microcode.o
obj-y += mm.o
obj-y += mpparse.o
obj-y += nmi.o
diff -r f25a004a6de8 -r f30a33c5b5bd xen/arch/x86/efi/boot.c
--- a/xen/arch/x86/efi/boot.c Thu Dec 01 17:21:24 2011 +0000
+++ b/xen/arch/x86/efi/boot.c Thu Dec 01 17:24:12 2011 +0000
@@ -49,6 +49,7 @@
static struct file __initdata cfg;
static struct file __initdata kernel;
static struct file __initdata ramdisk;
+static struct file __initdata ucode;
static struct file __initdata xsm;
static multiboot_info_t __initdata mbi = {
@@ -174,6 +175,8 @@
efi_bs->FreePages(kernel.addr, PFN_UP(kernel.size));
if ( ramdisk.addr )
efi_bs->FreePages(ramdisk.addr, PFN_UP(ramdisk.size));
+ if ( ucode.addr )
+ efi_bs->FreePages(ucode.addr, PFN_UP(ucode.size));
if ( xsm.addr )
efi_bs->FreePages(xsm.addr, PFN_UP(xsm.size));
@@ -806,6 +809,17 @@
efi_bs->FreePool(name.w);
}
+ name.s = get_value(&cfg, section.s, "ucode");
+ if ( !name.s )
+ name.s = get_value(&cfg, "global", "ucode");
+ if ( name.s )
+ {
+ microcode_set_module(mbi.mods_count);
+ split_value(name.s);
+ read_file(dir_handle, s2w(&name), &ucode);
+ efi_bs->FreePool(name.w);
+ }
+
name.s = get_value(&cfg, section.s, "xsm");
if ( name.s )
{
diff -r f25a004a6de8 -r f30a33c5b5bd xen/arch/x86/microcode.c
--- a/xen/arch/x86/microcode.c Thu Dec 01 17:21:24 2011 +0000
+++ b/xen/arch/x86/microcode.c Thu Dec 01 17:24:12 2011 +0000
@@ -22,20 +22,56 @@
*/
#include <xen/config.h>
+#include <xen/cpu.h>
#include <xen/lib.h>
#include <xen/kernel.h>
#include <xen/init.h>
+#include <xen/notifier.h>
#include <xen/sched.h>
#include <xen/smp.h>
+#include <xen/softirq.h>
#include <xen/spinlock.h>
+#include <xen/tasklet.h>
#include <xen/guest_access.h>
-#include <asm/current.h>
#include <asm/msr.h>
-#include <asm/uaccess.h>
#include <asm/processor.h>
+#include <asm/setup.h>
#include <asm/microcode.h>
+static module_t __initdata ucode_mod;
+static void *(*__initdata ucode_mod_map)(const module_t *);
+static unsigned int __initdata ucode_mod_idx;
+static bool_t __initdata ucode_mod_forced;
+static cpumask_t __initdata init_mask;
+
+void __init microcode_set_module(unsigned int idx)
+{
+ ucode_mod_idx = idx;
+ ucode_mod_forced = 1;
+}
+
+static void __init parse_ucode(char *s)
+{
+ if ( !ucode_mod_forced )
+ ucode_mod_idx = simple_strtoul(s, NULL, 0);
+}
+custom_param("ucode", parse_ucode);
+
+void __init microcode_grab_module(
+ unsigned long *module_map,
+ const multiboot_info_t *mbi,
+ void *(*map)(const module_t *))
+{
+ module_t *mod = (module_t *)__va(mbi->mods_addr);
+
+ if ( !ucode_mod_idx || ucode_mod_idx >= mbi->mods_count ||
+ !__test_and_clear_bit(ucode_mod_idx, module_map) )
+ return;
+ ucode_mod = mod[ucode_mod_idx];
+ ucode_mod_map = map;
+}
+
const struct microcode_ops *microcode_ops;
static DEFINE_SPINLOCK(microcode_mutex);
@@ -69,30 +105,50 @@
int err;
struct ucode_cpu_info *uci = &per_cpu(ucode_cpu_info, cpu);
struct cpu_signature nsig;
+ unsigned int cpu2;
- if ( !uci->mc.mc_valid )
- return -EIO;
+ spin_lock(µcode_mutex);
- /*
- * Let's verify that the 'cached' ucode does belong
- * to this cpu (a bit of paranoia):
- */
- err = microcode_ops->collect_cpu_info(cpu, &nsig);
+ err = microcode_ops->collect_cpu_info(cpu, &uci->cpu_sig);
if ( err )
{
- microcode_fini_cpu(cpu);
+ __microcode_fini_cpu(cpu);
+ spin_unlock(µcode_mutex);
return err;
}
- if ( microcode_ops->microcode_resume_match(cpu, &nsig) )
+ if ( uci->mc.mc_valid )
{
- return microcode_ops->apply_microcode(cpu);
+ err = microcode_ops->microcode_resume_match(cpu, uci->mc.mc_valid);
+ if ( err >= 0 )
+ {
+ if ( err )
+ err = microcode_ops->apply_microcode(cpu);
+ spin_unlock(µcode_mutex);
+ return err;
+ }
}
- else
+
+ nsig = uci->cpu_sig;
+ __microcode_fini_cpu(cpu);
+ uci->cpu_sig = nsig;
+
+ err = -EIO;
+ for_each_online_cpu ( cpu2 )
{
- microcode_fini_cpu(cpu);
- return -EIO;
+ uci = &per_cpu(ucode_cpu_info, cpu2);
+ if ( uci->mc.mc_valid &&
+ microcode_ops->microcode_resume_match(cpu, uci->mc.mc_valid) > 0 )
+ {
+ err = microcode_ops->apply_microcode(cpu);
+ break;
+ }
}
+
+ __microcode_fini_cpu(cpu);
+ spin_unlock(µcode_mutex);
+
+ return err;
}
static int microcode_update_cpu(const void *buf, size_t size)
@@ -162,3 +218,78 @@
return continue_hypercall_on_cpu(info->cpu, do_microcode_update, info);
}
+
+static void __init _do_microcode_update(unsigned long data)
+{
+ microcode_update_cpu((void *)data, ucode_mod.mod_end);
+ cpumask_set_cpu(smp_processor_id(), &init_mask);
+}
+
+static int __init microcode_init(void)
+{
+ void *data;
+ static struct tasklet __initdata tasklet;
+ unsigned int cpu;
+
+ if ( !microcode_ops || !ucode_mod.mod_end )
+ return 0;
+
+ data = ucode_mod_map(&ucode_mod);
+ if ( !data )
+ return -ENOMEM;
+
+ softirq_tasklet_init(&tasklet, _do_microcode_update, (unsigned long)data);
+
+ for_each_online_cpu ( cpu )
+ {
+ tasklet_schedule_on_cpu(&tasklet, cpu);
+ do {
+ process_pending_softirqs();
+ } while ( !cpumask_test_cpu(cpu, &init_mask) );
+ }
+
+ ucode_mod_map(NULL);
+
+ return 0;
+}
+__initcall(microcode_init);
+
+static int microcode_percpu_callback(
+ struct notifier_block *nfb, unsigned long action, void *hcpu)
+{
+ unsigned int cpu = (unsigned long)hcpu;
+
+ switch ( action )
+ {
+ case CPU_DEAD:
+ microcode_fini_cpu(cpu);
+ break;
+ }
+
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block microcode_percpu_nfb = {
+ .notifier_call = microcode_percpu_callback,
+};
+
+static int __init microcode_presmp_init(void)
+{
+ if ( microcode_ops )
+ {
+ if ( ucode_mod.mod_end )
+ {
+ void *data = ucode_mod_map(&ucode_mod);
+
+ if ( data )
+ microcode_update_cpu(data, ucode_mod.mod_end);
+
+ ucode_mod_map(NULL);
+ }
+
+ register_cpu_notifier(µcode_percpu_nfb);
+ }
+
+ return 0;
+}
+presmp_initcall(microcode_presmp_init);
diff -r f25a004a6de8 -r f30a33c5b5bd xen/arch/x86/microcode_amd.c
--- a/xen/arch/x86/microcode_amd.c Thu Dec 01 17:21:24 2011 +0000
+++ b/xen/arch/x86/microcode_amd.c Thu Dec 01 17:24:12 2011 +0000
@@ -23,27 +23,53 @@
#include <xen/spinlock.h>
#include <asm/msr.h>
-#include <asm/uaccess.h>
#include <asm/processor.h>
#include <asm/microcode.h>
#define pr_debug(x...) ((void)0)
+struct equiv_cpu_entry {
+ uint32_t installed_cpu;
+ uint32_t fixed_errata_mask;
+ uint32_t fixed_errata_compare;
+ uint16_t equiv_cpu;
+ uint16_t reserved;
+} __attribute__((packed));
+
+struct microcode_header_amd {
+ uint32_t data_code;
+ uint32_t patch_id;
+ uint8_t mc_patch_data_id[2];
+ uint8_t mc_patch_data_len;
+ uint8_t init_flag;
+ uint32_t mc_patch_data_checksum;
+ uint32_t nb_dev_id;
+ uint32_t sb_dev_id;
+ uint16_t processor_rev_id;
+ uint8_t nb_rev_id;
+ uint8_t sb_rev_id;
+ uint8_t bios_api_rev;
+ uint8_t reserved1[3];
+ uint32_t match_reg[8];
+} __attribute__((packed));
+
#define UCODE_MAGIC 0x00414d44
#define UCODE_EQUIV_CPU_TABLE_TYPE 0x00000000
#define UCODE_UCODE_TYPE 0x00000001
#define UCODE_MAX_SIZE (2048)
-#define DEFAULT_UCODE_DATASIZE (896)
#define MC_HEADER_SIZE (sizeof(struct microcode_header_amd))
-#define DEFAULT_UCODE_TOTALSIZE (DEFAULT_UCODE_DATASIZE + MC_HEADER_SIZE)
-#define DWSIZE (sizeof(uint32_t))
+
+struct microcode_amd {
+ struct microcode_header_amd hdr;
+ unsigned int mpb[(UCODE_MAX_SIZE - MC_HEADER_SIZE) / 4];
+ unsigned int equiv_cpu_table_size;
+ struct equiv_cpu_entry equiv_cpu_table[];
+};
/* serialize access to the physical write */
static DEFINE_SPINLOCK(microcode_update_lock);
-struct equiv_cpu_entry *equiv_cpu_table;
-
static int collect_cpu_info(int cpu, struct cpu_signature *csig)
{
struct cpuinfo_x86 *c = &cpu_data[cpu];
@@ -65,10 +91,11 @@
return 0;
}
-static int microcode_fits(void *mc, int cpu)
+static int microcode_fits(const struct microcode_amd *mc_amd, int cpu)
{
struct ucode_cpu_info *uci = &per_cpu(ucode_cpu_info, cpu);
- struct microcode_header_amd *mc_header = mc;
+ const struct microcode_header_amd *mc_header = &mc_amd->hdr;
+ const struct equiv_cpu_entry *equiv_cpu_table = mc_amd->equiv_cpu_table;
unsigned int current_cpu_id;
unsigned int equiv_cpu_id = 0x0;
unsigned int i;
@@ -99,7 +126,7 @@
}
if ( mc_header->patch_id <= uci->cpu_sig.rev )
- return -EINVAL;
+ return 0;
printk(KERN_DEBUG "microcode: CPU%d found a matching microcode "
"update with version 0x%x (current=0x%x)\n",
@@ -186,17 +213,15 @@
return 0;
}
-static int install_equiv_cpu_table(const void *buf, uint32_t size,
- unsigned long *offset)
+static int install_equiv_cpu_table(
+ struct microcode_amd *mc_amd,
+ const uint32_t *buf_pos,
+ unsigned long *offset)
{
- const uint32_t *buf_pos = buf;
- unsigned long off;
-
- off = *offset;
- *offset = 0;
+ uint32_t size = buf_pos[2];
/* No more data */
- if ( off >= size )
+ if ( size + 12 >= *offset )
return -EINVAL;
if ( buf_pos[1] != UCODE_EQUIV_CPU_TABLE_TYPE )
@@ -213,15 +238,8 @@
return -EINVAL;
}
- equiv_cpu_table = xmalloc_bytes(size);
- if ( equiv_cpu_table == NULL )
- {
- printk(KERN_ERR "microcode: error, can't allocate "
- "memory for equiv CPU table\n");
- return -ENOMEM;
- }
-
- memcpy(equiv_cpu_table, (const void *)&buf_pos[3], size);
+ memcpy(mc_amd->equiv_cpu_table, &buf_pos[3], size);
+ mc_amd->equiv_cpu_table_size = size;
*offset = size + 12; /* add header length */
@@ -231,11 +249,11 @@
static int cpu_request_microcode(int cpu, const void *buf, size_t size)
{
const uint32_t *buf_pos;
- unsigned long offset = 0;
+ struct microcode_amd *mc_amd, *mc_old;
+ unsigned long offset = size;
int error = 0;
int ret;
struct ucode_cpu_info *uci = &per_cpu(ucode_cpu_info, cpu);
- void *mc;
/* We should bind the task to the CPU */
BUG_ON(cpu != raw_smp_processor_id());
@@ -249,59 +267,85 @@
return -EINVAL;
}
- error = install_equiv_cpu_table(buf, (uint32_t)(buf_pos[2]), &offset);
+ mc_amd = xmalloc_bytes(sizeof(*mc_amd) + buf_pos[2]);
+ if ( !mc_amd )
+ {
+ printk(KERN_ERR "microcode: error! "
+ "Can not allocate memory for microcode patch\n");
+ return -ENOMEM;
+ }
+
+ error = install_equiv_cpu_table(mc_amd, buf, &offset);
if ( error )
{
+ xfree(mc_amd);
printk(KERN_ERR "microcode: installing equivalent cpu table failed\n");
return -EINVAL;
}
- mc = xmalloc_bytes(UCODE_MAX_SIZE);
- if ( mc == NULL )
- {
- printk(KERN_ERR "microcode: error! "
- "Can not allocate memory for microcode patch\n");
- error = -ENOMEM;
- goto out;
- }
-
+ mc_old = uci->mc.mc_amd;
/* implicitely validates uci->mc.mc_valid */
- uci->mc.mc_amd = mc;
+ uci->mc.mc_amd = mc_amd;
/*
* It's possible the data file has multiple matching ucode,
* lets keep searching till the latest version
*/
- while ( (ret = get_next_ucode_from_buffer_amd(mc, buf, size, &offset)) ==
0)
+ while ( (ret = get_next_ucode_from_buffer_amd(&mc_amd->hdr, buf, size,
+ &offset)) == 0 )
{
- error = microcode_fits(mc, cpu);
+ error = microcode_fits(mc_amd, cpu);
if (error <= 0)
continue;
error = apply_microcode(cpu);
if (error == 0)
+ {
+ error = 1;
break;
+ }
}
+ if ( ret < 0 )
+ error = ret;
+
/* On success keep the microcode patch for
* re-apply on resume.
*/
- if (error) {
- xfree(mc);
- mc = NULL;
+ if (error == 1)
+ {
+ xfree(mc_old);
+ return 0;
}
- uci->mc.mc_amd = mc;
-
-out:
- xfree(equiv_cpu_table);
- equiv_cpu_table = NULL;
+ xfree(mc_amd);
+ uci->mc.mc_amd = mc_old;
return error;
}
-static int microcode_resume_match(int cpu, struct cpu_signature *nsig)
+static int microcode_resume_match(int cpu, const void *mc)
{
- return 0;
+ struct ucode_cpu_info *uci = &per_cpu(ucode_cpu_info, cpu);
+ struct microcode_amd *mc_amd = uci->mc.mc_amd;
+ const struct microcode_amd *src = mc;
+ int res = microcode_fits(src, cpu);
+
+ if ( res <= 0 )
+ return res;
+
+ if ( src != mc_amd )
+ {
+ xfree(mc_amd);
+ mc_amd = xmalloc_bytes(sizeof(*src) + src->equiv_cpu_table_size);
+ uci->mc.mc_amd = mc_amd;
+ if ( !mc_amd )
+ return -ENOMEM;
+ memcpy(mc_amd, src, UCODE_MAX_SIZE);
+ memcpy(mc_amd->equiv_cpu_table, src->equiv_cpu_table,
+ src->equiv_cpu_table_size);
+ }
+
+ return 1;
}
static const struct microcode_ops microcode_amd_ops = {
@@ -317,4 +361,4 @@
microcode_ops = µcode_amd_ops;
return 0;
}
-__initcall(microcode_init_amd);
+presmp_initcall(microcode_init_amd);
diff -r f25a004a6de8 -r f30a33c5b5bd xen/arch/x86/microcode_intel.c
--- a/xen/arch/x86/microcode_intel.c Thu Dec 01 17:21:24 2011 +0000
+++ b/xen/arch/x86/microcode_intel.c Thu Dec 01 17:24:12 2011 +0000
@@ -30,12 +30,43 @@
#include <xen/spinlock.h>
#include <asm/msr.h>
-#include <asm/uaccess.h>
#include <asm/processor.h>
#include <asm/microcode.h>
#define pr_debug(x...) ((void)0)
+struct microcode_header_intel {
+ unsigned int hdrver;
+ unsigned int rev;
+ unsigned int date;
+ unsigned int sig;
+ unsigned int cksum;
+ unsigned int ldrver;
+ unsigned int pf;
+ unsigned int datasize;
+ unsigned int totalsize;
+ unsigned int reserved[3];
+};
+
+struct microcode_intel {
+ struct microcode_header_intel hdr;
+ unsigned int bits[0];
+};
+
+/* microcode format is extended from prescott processors */
+struct extended_signature {
+ unsigned int sig;
+ unsigned int pf;
+ unsigned int cksum;
+};
+
+struct extended_sigtable {
+ unsigned int count;
+ unsigned int cksum;
+ unsigned int reserved[3];
+ struct extended_signature sigs[0];
+};
+
#define DEFAULT_UCODE_DATASIZE (2000)
#define MC_HEADER_SIZE (sizeof(struct microcode_header_intel))
#define DEFAULT_UCODE_TOTALSIZE (DEFAULT_UCODE_DATASIZE + MC_HEADER_SIZE)
@@ -98,7 +129,8 @@
}
static inline int microcode_update_match(
- int cpu_num, struct microcode_header_intel *mc_header, int sig, int pf)
+ int cpu_num, const struct microcode_header_intel *mc_header,
+ int sig, int pf)
{
struct ucode_cpu_info *uci = &per_cpu(ucode_cpu_info, cpu_num);
@@ -200,11 +232,11 @@
* return 1 - found update
* return < 0 - error
*/
-static int get_matching_microcode(void *mc, int cpu)
+static int get_matching_microcode(const void *mc, int cpu)
{
struct ucode_cpu_info *uci = &per_cpu(ucode_cpu_info, cpu);
- struct microcode_header_intel *mc_header = mc;
- struct extended_sigtable *ext_header;
+ const struct microcode_header_intel *mc_header = mc;
+ const struct extended_sigtable *ext_header;
unsigned long total_size = get_totalsize(mc_header);
int ext_sigcount, i;
struct extended_signature *ext_sig;
@@ -229,6 +261,8 @@
}
return 0;
find:
+ if ( uci->mc.mc_intel && uci->mc.mc_intel->hdr.rev >= mc_header->rev )
+ return 0;
pr_debug("microcode: CPU%d found a matching microcode update with"
" version 0x%x (current=0x%x)\n",
cpu, mc_header->rev, uci->cpu_sig.rev);
@@ -239,10 +273,8 @@
return -ENOMEM;
}
- /* free previous update file */
+ memcpy(new_mc, mc, total_size);
xfree(uci->mc.mc_intel);
-
- memcpy(new_mc, mc, total_size);
uci->mc.mc_intel = new_mc;
return 1;
}
@@ -361,12 +393,9 @@
return error;
}
-static int microcode_resume_match(int cpu, struct cpu_signature *nsig)
+static int microcode_resume_match(int cpu, const void *mc)
{
- struct ucode_cpu_info *uci = &per_cpu(ucode_cpu_info, cpu);
-
- return (sigmatch(nsig->sig, uci->cpu_sig.sig, nsig->pf, uci->cpu_sig.pf) &&
- (uci->cpu_sig.rev > nsig->rev));
+ return get_matching_microcode(mc, cpu);
}
static const struct microcode_ops microcode_intel_ops = {
@@ -382,4 +411,4 @@
microcode_ops = µcode_intel_ops;
return 0;
}
-__initcall(microcode_init_intel);
+presmp_initcall(microcode_init_intel);
diff -r f25a004a6de8 -r f30a33c5b5bd xen/arch/x86/setup.c
--- a/xen/arch/x86/setup.c Thu Dec 01 17:21:24 2011 +0000
+++ b/xen/arch/x86/setup.c Thu Dec 01 17:24:12 2011 +0000
@@ -550,10 +550,10 @@
{
char *memmap_type = NULL;
char *cmdline, *kextra, *loader;
- unsigned int initrdidx = 1;
+ unsigned int initrdidx;
multiboot_info_t *mbi = __va(mbi_p);
module_t *mod = (module_t *)__va(mbi->mods_addr);
- unsigned long nr_pages, modules_headroom;
+ unsigned long nr_pages, modules_headroom, *module_map;
int i, j, e820_warn = 0, bytes = 0;
bool_t acpi_boot_table_init_done = 0;
struct ns16550_defaults ns16550 = {
@@ -1229,7 +1229,13 @@
init_IRQ();
- xsm_init(&initrdidx, mbi, bootstrap_map);
+ module_map = xmalloc_array(unsigned long, BITS_TO_LONGS(mbi->mods_count));
+ bitmap_fill(module_map, mbi->mods_count);
+ __clear_bit(0, module_map); /* Dom0 kernel is always first */
+
+ xsm_init(module_map, mbi, bootstrap_map);
+
+ microcode_grab_module(module_map, mbi, bootstrap_map);
timer_init();
@@ -1356,6 +1362,12 @@
if ( xen_cpuidle )
xen_processor_pmbits |= XEN_PROCESSOR_PM_CX;
+ initrdidx = find_first_bit(module_map, mbi->mods_count);
+ if ( bitmap_weight(module_map, mbi->mods_count) > 1 )
+ printk(XENLOG_WARNING
+ "Multiple initrd candidates, picking module #%u\n",
+ initrdidx);
+
/*
* We're going to setup domain0 using the module(s) that we stashed safely
* above our heap. The second module, if present, is an initrd ramdisk.
diff -r f25a004a6de8 -r f30a33c5b5bd xen/include/asm-x86/microcode.h
--- a/xen/include/asm-x86/microcode.h Thu Dec 01 17:21:24 2011 +0000
+++ b/xen/include/asm-x86/microcode.h Thu Dec 01 17:24:12 2011 +0000
@@ -7,74 +7,12 @@
struct ucode_cpu_info;
struct microcode_ops {
- int (*microcode_resume_match)(int cpu, struct cpu_signature *nsig);
+ int (*microcode_resume_match)(int cpu, const void *mc);
int (*cpu_request_microcode)(int cpu, const void *buf, size_t size);
int (*collect_cpu_info)(int cpu, struct cpu_signature *csig);
int (*apply_microcode)(int cpu);
};
-struct microcode_header_intel {
- unsigned int hdrver;
- unsigned int rev;
- unsigned int date;
- unsigned int sig;
- unsigned int cksum;
- unsigned int ldrver;
- unsigned int pf;
- unsigned int datasize;
- unsigned int totalsize;
- unsigned int reserved[3];
-};
-
-struct microcode_intel {
- struct microcode_header_intel hdr;
- unsigned int bits[0];
-};
-
-/* microcode format is extended from prescott processors */
-struct extended_signature {
- unsigned int sig;
- unsigned int pf;
- unsigned int cksum;
-};
-
-struct extended_sigtable {
- unsigned int count;
- unsigned int cksum;
- unsigned int reserved[3];
- struct extended_signature sigs[0];
-};
-
-struct equiv_cpu_entry {
- uint32_t installed_cpu;
- uint32_t fixed_errata_mask;
- uint32_t fixed_errata_compare;
- uint16_t equiv_cpu;
- uint16_t reserved;
-} __attribute__((packed));
-
-struct microcode_header_amd {
- uint32_t data_code;
- uint32_t patch_id;
- uint8_t mc_patch_data_id[2];
- uint8_t mc_patch_data_len;
- uint8_t init_flag;
- uint32_t mc_patch_data_checksum;
- uint32_t nb_dev_id;
- uint32_t sb_dev_id;
- uint16_t processor_rev_id;
- uint8_t nb_rev_id;
- uint8_t sb_rev_id;
- uint8_t bios_api_rev;
- uint8_t reserved1[3];
- uint32_t match_reg[8];
-} __attribute__((packed));
-
-struct microcode_amd {
- struct microcode_header_amd hdr;
- unsigned int mpb[0];
-};
-
struct cpu_signature {
unsigned int sig;
unsigned int pf;
diff -r f25a004a6de8 -r f30a33c5b5bd xen/include/asm-x86/processor.h
--- a/xen/include/asm-x86/processor.h Thu Dec 01 17:21:24 2011 +0000
+++ b/xen/include/asm-x86/processor.h Thu Dec 01 17:24:12 2011 +0000
@@ -599,6 +599,7 @@
int rdmsr_hypervisor_regs(uint32_t idx, uint64_t *val);
int wrmsr_hypervisor_regs(uint32_t idx, uint64_t val);
+void microcode_set_module(unsigned int);
int microcode_update(XEN_GUEST_HANDLE(const_void), unsigned long len);
int microcode_resume_cpu(int cpu);
diff -r f25a004a6de8 -r f30a33c5b5bd xen/include/asm-x86/setup.h
--- a/xen/include/asm-x86/setup.h Thu Dec 01 17:21:24 2011 +0000
+++ b/xen/include/asm-x86/setup.h Thu Dec 01 17:24:12 2011 +0000
@@ -44,4 +44,7 @@
int xen_in_range(unsigned long mfn);
void arch_get_xen_caps(xen_capabilities_info_t *info);
+void microcode_grab_module(
+ unsigned long *, const multiboot_info_t *, void *(*)(const module_t *));
+
#endif
diff -r f25a004a6de8 -r f30a33c5b5bd xen/include/xsm/xsm.h
--- a/xen/include/xsm/xsm.h Thu Dec 01 17:21:24 2011 +0000
+++ b/xen/include/xsm/xsm.h Thu Dec 01 17:24:12 2011 +0000
@@ -454,14 +454,15 @@
}
#ifdef XSM_ENABLE
-extern int xsm_init(unsigned int *initrdidx, const multiboot_info_t *mbi,
+extern int xsm_init(unsigned long *module_map, const multiboot_info_t *mbi,
void *(*bootstrap_map)(const module_t *));
-extern int xsm_policy_init(unsigned int *initrdidx, const multiboot_info_t
*mbi,
+extern int xsm_policy_init(unsigned long *module_map,
+ const multiboot_info_t *mbi,
void *(*bootstrap_map)(const module_t *));
extern int register_xsm(struct xsm_operations *ops);
extern int unregister_xsm(struct xsm_operations *ops);
#else
-static inline int xsm_init (unsigned int *initrdidx,
+static inline int xsm_init (unsigned long *module_map,
const multiboot_info_t *mbi,
void *(*bootstrap_map)(const module_t *))
{
diff -r f25a004a6de8 -r f30a33c5b5bd xen/xsm/xsm_core.c
--- a/xen/xsm/xsm_core.c Thu Dec 01 17:21:24 2011 +0000
+++ b/xen/xsm/xsm_core.c Thu Dec 01 17:24:12 2011 +0000
@@ -43,7 +43,7 @@
}
}
-int __init xsm_init(unsigned int *initrdidx, const multiboot_info_t *mbi,
+int __init xsm_init(unsigned long *module_map, const multiboot_info_t *mbi,
void *(*bootstrap_map)(const module_t *))
{
int ret = 0;
@@ -52,7 +52,7 @@
if ( XSM_MAGIC )
{
- ret = xsm_policy_init(initrdidx, mbi, bootstrap_map);
+ ret = xsm_policy_init(module_map, mbi, bootstrap_map);
if ( ret )
{
bootstrap_map(NULL);
diff -r f25a004a6de8 -r f30a33c5b5bd xen/xsm/xsm_policy.c
--- a/xen/xsm/xsm_policy.c Thu Dec 01 17:21:24 2011 +0000
+++ b/xen/xsm/xsm_policy.c Thu Dec 01 17:24:12 2011 +0000
@@ -20,11 +20,12 @@
#include <xsm/xsm.h>
#include <xen/multiboot.h>
+#include <asm/bitops.h>
char *__initdata policy_buffer = NULL;
u32 __initdata policy_size = 0;
-int xsm_policy_init(unsigned int *initrdidx, const multiboot_info_t *mbi,
+int xsm_policy_init(unsigned long *module_map, const multiboot_info_t *mbi,
void *(*bootstrap_map)(const module_t *))
{
int i;
@@ -35,10 +36,13 @@
/*
* Try all modules and see whichever could be the binary policy.
- * Adjust the initrdidx if module[1] is the binary policy.
+ * Adjust module_map for the module that is the binary policy.
*/
for ( i = mbi->mods_count-1; i >= 1; i-- )
{
+ if ( !test_bit(i, module_map) )
+ continue;
+
_policy_start = bootstrap_map(mod + i);
_policy_len = mod[i].mod_end;
@@ -50,8 +54,7 @@
printk("Policy len 0x%lx, start at %p.\n",
_policy_len,_policy_start);
- if ( i == 1 )
- *initrdidx = (mbi->mods_count > 2) ? 2 : 0;
+ __clear_bit(i, module_map);
break;
}
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |