[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH RFC/WIPv2 3/6] libxc: introduce soft reset



Add new xc_domain_soft_reset() function which performs so-called soft-reset
for a domain. During soft reset all source domain's memory is being reassigned
to the destination domain, cpu contexts are being copied,... The behavior is
similar to save/restore except for memory reassigning.

Signed-off-by: Vitaly Kuznetsov <vkuznets@xxxxxxxxxx>
---
 tools/libxc/Makefile               |   1 +
 tools/libxc/xc_domain_soft_reset.c | 300 +++++++++++++++++++++++++++++++++++++
 tools/libxc/xenguest.h             |  19 +++
 3 files changed, 320 insertions(+)
 create mode 100644 tools/libxc/xc_domain_soft_reset.c

diff --git a/tools/libxc/Makefile b/tools/libxc/Makefile
index 3b04027..b5d4b60 100644
--- a/tools/libxc/Makefile
+++ b/tools/libxc/Makefile
@@ -49,6 +49,7 @@ GUEST_SRCS-y += xc_offline_page.c xc_compression.c
 else
 GUEST_SRCS-y += xc_nomigrate.c
 endif
+GUEST_SRCS-y += xc_domain_soft_reset.c
 
 vpath %.c ../../xen/common/libelf
 CFLAGS += -I../../xen/common/libelf
diff --git a/tools/libxc/xc_domain_soft_reset.c 
b/tools/libxc/xc_domain_soft_reset.c
new file mode 100644
index 0000000..c5d9873
--- /dev/null
+++ b/tools/libxc/xc_domain_soft_reset.c
@@ -0,0 +1,300 @@
+/******************************************************************************
+ * xc_domain_soft_reset.c
+ *
+ * Do soft reset.
+ *
+ * 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 <inttypes.h>
+#include <time.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/time.h>
+
+#include "xc_private.h"
+#include "xc_core.h"
+#include "xc_bitops.h"
+#include "xc_dom.h"
+#include "xg_private.h"
+#include "xg_save_restore.h"
+
+#include <xen/hvm/params.h>
+
+static unsigned long saverestore_hvm_param(xc_interface *xch, uint32_t 
source_dom,
+                                           uint32_t dest_dom, int param)
+{
+       uint64_t val = 0;
+       xc_hvm_param_get(xch, source_dom, param, &val);
+
+       if ( val )
+           xc_hvm_param_set(xch, dest_dom, param, val);
+
+    return val;
+}
+
+int xc_domain_soft_reset(xc_interface *xch, uint32_t source_dom,
+                         uint32_t dest_dom, int hvm, domid_t console_domid,
+                         unsigned int console_evtchn,
+                         unsigned long *console_mfn,
+                         domid_t store_domid, unsigned int store_evtchn,
+                         unsigned long *store_mfn)
+{
+    DECLARE_DOMCTL;
+    xc_dominfo_t info;
+    int rc = 1, i;
+
+    /* A copy of the CPU context of the guest. */
+    vcpu_guest_context_any_t _ctxt;
+    vcpu_guest_context_any_t *ctxt = &_ctxt;
+
+    /* HVM: a buffer for holding HVM context */
+    uint32_t hvm_buf_size = 0;
+    uint8_t *hvm_buf = NULL;
+    unsigned long console_pfn, store_pfn, io_pfn, buffio_pfn;
+    unsigned long mfn, pfn, max_pfn, pagetype;
+    start_info_any_t *start_info;
+    struct xc_domain_meminfo minfo;
+
+    DPRINTF("%s: soft reset domid %u -> %u", __func__, source_dom, dest_dom);
+
+    if ( xc_domain_getinfo(xch, source_dom, 1, &info) != 1 )
+    {
+        PERROR("Could not get domain info");
+        return 1;
+    }
+
+    max_pfn = xc_domain_maximum_gpfn(xch, source_dom);
+
+    if (!hvm)
+    {
+        memset(&minfo, 0, sizeof(minfo));
+        if ( xc_map_domain_meminfo(xch, source_dom, &minfo) )
+        {
+            PERROR("Could not map domain %d memory information\n", source_dom);
+            goto out;
+        }
+        for (pfn = 0; pfn < minfo.p2m_size; pfn++)
+        {
+            rc = xc_domain_transfer_pages(xch, source_dom, dest_dom, 
minfo.p2m_table[pfn], 1);
+            if ( rc != 0 )
+            {
+                PERROR("failed to transfer pfn %lx, rc=%d\n", pfn, rc);
+                goto out;
+            }
+        }
+    }
+
+    if (hvm) {
+        rc = xc_domain_transfer_pages(xch, source_dom, dest_dom, 0, max_pfn + 
1);
+        if ( rc != 0 )
+        {
+            PERROR("failed to transfer pages, rc=%d\n", rc);
+            goto out;
+        }
+
+           hvm_buf_size = xc_domain_hvm_getcontext(xch, source_dom, 0, 0);
+           if ( hvm_buf_size == -1 )
+           {
+                   PERROR("Couldn't get HVM context size from Xen");
+                   goto out;
+           }
+
+        hvm_buf = malloc(hvm_buf_size);
+           if ( !hvm_buf )
+           {
+                   ERROR("Couldn't allocate memory");
+                   goto out;
+           }
+
+        if ( xc_domain_hvm_getcontext(xch, source_dom, hvm_buf,
+                                      hvm_buf_size) == -1 )
+        {
+            PERROR("HVM:Could not get hvm buffer");
+            goto out;
+        }
+
+        if ( xc_domain_hvm_setcontext(xch, dest_dom, hvm_buf,
+                                      hvm_buf_size) == -1 )
+        {
+            PERROR("HVM:Could not set hvm buffer");
+            goto out;
+        }
+
+           store_pfn = saverestore_hvm_param(xch, source_dom, dest_dom,
+                                          HVM_PARAM_STORE_PFN);
+        if ( store_pfn )
+            xc_clear_domain_page(xch, dest_dom, store_pfn);
+        *store_mfn = store_pfn;
+
+           console_pfn = saverestore_hvm_param(xch, source_dom, dest_dom,
+                                            HVM_PARAM_CONSOLE_PFN);
+        if ( console_pfn )
+            xc_clear_domain_page(xch, dest_dom, console_pfn);
+        *console_mfn = console_pfn;
+
+           buffio_pfn = saverestore_hvm_param(xch, source_dom, dest_dom,
+                                           HVM_PARAM_BUFIOREQ_PFN);
+        if ( buffio_pfn )
+            xc_clear_domain_page(xch, dest_dom, buffio_pfn);
+
+        io_pfn = saverestore_hvm_param(xch, source_dom, dest_dom,
+                                       HVM_PARAM_IOREQ_PFN);
+        if ( io_pfn )
+            xc_clear_domain_page(xch, dest_dom, buffio_pfn);
+
+           saverestore_hvm_param(xch, source_dom, dest_dom, 
HVM_PARAM_IDENT_PT);
+           saverestore_hvm_param(xch, source_dom, dest_dom, 
HVM_PARAM_PAGING_RING_PFN);
+           saverestore_hvm_param(xch, source_dom, dest_dom, 
HVM_PARAM_ACCESS_RING_PFN);
+           saverestore_hvm_param(xch, source_dom, dest_dom, 
HVM_PARAM_VM86_TSS);
+           saverestore_hvm_param(xch, source_dom, dest_dom, 
HVM_PARAM_ACPI_IOPORTS_LOCATION);
+           saverestore_hvm_param(xch, source_dom, dest_dom, 
HVM_PARAM_VIRIDIAN);
+           saverestore_hvm_param(xch, source_dom, dest_dom, 
HVM_PARAM_PAE_ENABLED);
+           saverestore_hvm_param(xch, source_dom, dest_dom, 
HVM_PARAM_STORE_EVTCHN);
+
+           saverestore_hvm_param(xch, source_dom, dest_dom, 
HVM_PARAM_IOREQ_SERVER_PFN);
+           saverestore_hvm_param(xch, source_dom, dest_dom, 
HVM_PARAM_NR_IOREQ_SERVER_PAGES);
+           saverestore_hvm_param(xch, source_dom, dest_dom, 
HVM_PARAM_VM_GENERATION_ID_ADDR);
+
+        if (xc_dom_gnttab_hvm_seed(xch, dest_dom, console_pfn, store_pfn,
+                                   console_domid, store_domid))
+        {
+            PERROR("error seeding hvm grant table");
+            goto out;
+        }
+
+    }
+    else
+    {
+        for ( i = 0; i <= info.max_vcpu_id; i++ )
+        {
+            if ( xc_vcpu_getcontext(xch, source_dom, i, ctxt) )
+            {
+                PERROR("No context for VCPU%d", i);
+                goto out;
+            }
+            domctl.cmd = XEN_DOMCTL_get_ext_vcpucontext;
+            domctl.domain = source_dom;
+            memset(&domctl.u, 0, sizeof(domctl.u));
+            domctl.u.ext_vcpucontext.vcpu = i;
+            if ( xc_domctl(xch, &domctl) < 0 )
+            {
+                PERROR("No extended context for VCPU%d", i);
+                goto out;
+            }
+
+            if ( xc_vcpu_setcontext(xch, dest_dom, i, ctxt) )
+            {
+                PERROR("Failed to set vcpu context for VCPU%d", i);
+                goto out;
+            }
+
+            domctl.cmd = XEN_DOMCTL_set_ext_vcpucontext;
+            domctl.domain = dest_dom;
+            if ( xc_domctl(xch, &domctl) < 0 )
+            {
+                PERROR("Failed to set extended context for VCPU%d", i);
+                goto out;
+            }
+
+            if ( i == 0 )
+            {
+                /* Mounting start_info for PV guest */
+                pfn = GET_FIELD(ctxt, user_regs.edx, minfo.guest_width);
+                pagetype = minfo.pfn_type[i] & XEN_DOMCTL_PFINFO_LTAB_MASK;
+                if ( (pfn >= minfo.p2m_size) ||
+                     (pagetype != XEN_DOMCTL_PFINFO_NOTAB) )
+                {
+                    ERROR("start_info frame number is bad");
+                    goto out;
+                }
+
+                mfn = minfo.p2m_table[pfn];
+                SET_FIELD(ctxt, user_regs.edx, mfn, minfo.guest_width);
+                start_info = xc_map_foreign_range(
+                    xch, dest_dom, PAGE_SIZE, PROT_READ | PROT_WRITE, mfn);
+                if ( start_info == NULL )
+                {
+                    PERROR("xc_map_foreign_range failed (for start_info)");
+                    goto out;
+                }
+
+                SET_FIELD(start_info, nr_pages, minfo.p2m_size,
+                          minfo.guest_width);
+                SET_FIELD(start_info, shared_info,
+                          info.shared_info_frame<<PAGE_SHIFT, 
minfo.guest_width);
+                SET_FIELD(start_info, flags, 0, minfo.guest_width);
+                if ( GET_FIELD(start_info, store_mfn, minfo.guest_width) >
+                     minfo.p2m_size )
+                {
+                    ERROR("Suspend record xenstore frame number is bad");
+                    munmap(start_info, PAGE_SIZE);
+                    goto out;
+                }
+                *store_mfn = minfo.p2m_table[GET_FIELD(start_info, store_mfn,
+                                                       minfo.guest_width)];
+                SET_FIELD(start_info, store_mfn, *store_mfn,
+                          minfo.guest_width);
+                SET_FIELD(start_info, store_evtchn, store_evtchn,
+                          minfo.guest_width);
+                if ( GET_FIELD(start_info, console.domU.mfn,
+                               minfo.guest_width) > minfo.p2m_size )
+                {
+                    ERROR("Suspend record console frame number is bad");
+                    munmap(start_info, PAGE_SIZE);
+                    goto out;
+                }
+                console_pfn = GET_FIELD(start_info, console.domU.mfn,
+                                        minfo.guest_width);
+                *console_mfn = minfo.p2m_table[console_pfn];
+                SET_FIELD(start_info, console.domU.mfn, *console_mfn,
+                          minfo.guest_width);
+                SET_FIELD(start_info, console.domU.evtchn, console_evtchn,
+                          minfo.guest_width);
+                munmap(start_info, PAGE_SIZE);
+            }
+        }
+
+        if (xc_dom_gnttab_seed(xch, dest_dom, *console_mfn, *store_mfn,
+                               console_domid, store_domid))
+        {
+            PERROR("error seeding grant table");
+            goto out;
+        }
+    }
+    rc = 0;
+out:
+    if (!hvm)
+        xc_unmap_domain_meminfo(xch, &minfo);
+
+    if (hvm_buf) free(hvm_buf);
+
+    if ( (rc != 0) && (dest_dom != 0) ) {
+            PERROR("Faled to perform soft reset, destroying domain %d", 
dest_dom);
+           xc_domain_destroy(xch, dest_dom);
+    }
+
+    return !!rc;
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/tools/libxc/xenguest.h b/tools/libxc/xenguest.h
index 40bbac8..c1dbabd 100644
--- a/tools/libxc/xenguest.h
+++ b/tools/libxc/xenguest.h
@@ -131,6 +131,25 @@ int xc_domain_restore(xc_interface *xch, int io_fd, 
uint32_t dom,
  * of the new domain is automatically appended to the filename,
  * separated by a ".".
  */
+
+/**
+ * This function doest soft reset for a domain. During soft reset all
+ * source domain's memory is being reassigned to the destination domain,
+ * cpu contexts are being copied,...
+ *
+ * @parm xch a handle to an open hypervisor interface
+ * @parm source_dom the id of the source domain
+ * @parm dest_dom the id of the destination domain
+ * @parm hvm non-zero if this is an HVM domain
+ * @return 0 on success, -1 on failure
+ */
+int xc_domain_soft_reset(xc_interface *xch, uint32_t source_dom,
+                         uint32_t dest_dom, int hvm, domid_t console_domid,
+                         unsigned int console_evtchn,
+                         unsigned long *console_mfn,
+                         domid_t store_domid, unsigned int store_evtchn,
+                         unsigned long *store_mfn);
+
 #define XC_DEVICE_MODEL_RESTORE_FILE "/var/lib/xen/qemu-resume"
 
 /**
-- 
1.9.3


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.