diff options
author | Alexey Kardashevskiy <aik@ozlabs.ru> | 2013-07-18 14:33:03 -0500 |
---|---|---|
committer | Anthony Liguori <aliguori@us.ibm.com> | 2013-07-29 10:37:09 -0500 |
commit | e68cb8b4fa7e20e666a3bfc571a0e075733d22bd (patch) | |
tree | 4c9044897a8ea511ef068291f93d003bd32aee5a /hw | |
parent | 1112cf94c82dfc743b62b5bcb96dd20f47b683a8 (diff) | |
download | qemu-e68cb8b4fa7e20e666a3bfc571a0e075733d22bd.zip qemu-e68cb8b4fa7e20e666a3bfc571a0e075733d22bd.tar.gz qemu-e68cb8b4fa7e20e666a3bfc571a0e075733d22bd.tar.bz2 |
pseries: savevm support with KVM
At present, the savevm / migration support for the pseries machine will not
work when KVM is enabled. That's because KVM manages the guest's hash page
table in the host kernel, so qemu has no visibility of it. This patch
fixes this by using new kernel interfaces to extract and reinsert the
guest's hash table during the migration process.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Message-id: 1374175984-8930-11-git-send-email-aliguori@us.ibm.com
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
Diffstat (limited to 'hw')
-rw-r--r-- | hw/ppc/spapr.c | 106 |
1 files changed, 84 insertions, 22 deletions
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 734a782..7144829 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -735,17 +735,27 @@ static int htab_save_setup(QEMUFile *f, void *opaque) { sPAPREnvironment *spapr = opaque; - spapr->htab_save_index = 0; - spapr->htab_first_pass = true; - /* "Iteration" header */ qemu_put_be32(f, spapr->htab_shift); + if (spapr->htab) { + spapr->htab_save_index = 0; + spapr->htab_first_pass = true; + } else { + assert(kvm_enabled()); + + spapr->htab_fd = kvmppc_get_htab_fd(false); + if (spapr->htab_fd < 0) { + fprintf(stderr, "Unable to open fd for reading hash table from KVM: %s\n", + strerror(errno)); + return -1; + } + } + + return 0; } -#define MAX_ITERATION_NS 5000000 /* 5 ms */ - static void htab_save_first_pass(QEMUFile *f, sPAPREnvironment *spapr, int64_t max_ns) { @@ -796,8 +806,8 @@ static void htab_save_first_pass(QEMUFile *f, sPAPREnvironment *spapr, spapr->htab_save_index = index; } -static bool htab_save_later_pass(QEMUFile *f, sPAPREnvironment *spapr, - int64_t max_ns) +static int htab_save_later_pass(QEMUFile *f, sPAPREnvironment *spapr, + int64_t max_ns) { bool final = max_ns < 0; int htabslots = HTAB_SIZE(spapr) / HASH_PTE_SIZE_64; @@ -870,21 +880,32 @@ static bool htab_save_later_pass(QEMUFile *f, sPAPREnvironment *spapr, spapr->htab_save_index = index; - return (examined >= htabslots) && (sent == 0); + return (examined >= htabslots) && (sent == 0) ? 1 : 0; } +#define MAX_ITERATION_NS 5000000 /* 5 ms */ +#define MAX_KVM_BUF_SIZE 2048 + static int htab_save_iterate(QEMUFile *f, void *opaque) { sPAPREnvironment *spapr = opaque; - bool nothingleft = false;; + int rc = 0; /* Iteration header */ qemu_put_be32(f, 0); - if (spapr->htab_first_pass) { + if (!spapr->htab) { + assert(kvm_enabled()); + + rc = kvmppc_save_htab(f, spapr->htab_fd, + MAX_KVM_BUF_SIZE, MAX_ITERATION_NS); + if (rc < 0) { + return rc; + } + } else if (spapr->htab_first_pass) { htab_save_first_pass(f, spapr, MAX_ITERATION_NS); } else { - nothingleft = htab_save_later_pass(f, spapr, MAX_ITERATION_NS); + rc = htab_save_later_pass(f, spapr, MAX_ITERATION_NS); } /* End marker */ @@ -892,7 +913,7 @@ static int htab_save_iterate(QEMUFile *f, void *opaque) qemu_put_be16(f, 0); qemu_put_be16(f, 0); - return nothingleft ? 1 : 0; + return rc; } static int htab_save_complete(QEMUFile *f, void *opaque) @@ -902,7 +923,20 @@ static int htab_save_complete(QEMUFile *f, void *opaque) /* Iteration header */ qemu_put_be32(f, 0); - htab_save_later_pass(f, spapr, -1); + if (!spapr->htab) { + int rc; + + assert(kvm_enabled()); + + rc = kvmppc_save_htab(f, spapr->htab_fd, MAX_KVM_BUF_SIZE, -1); + if (rc < 0) { + return rc; + } + close(spapr->htab_fd); + spapr->htab_fd = -1; + } else { + htab_save_later_pass(f, spapr, -1); + } /* End marker */ qemu_put_be32(f, 0); @@ -916,6 +950,7 @@ static int htab_load(QEMUFile *f, void *opaque, int version_id) { sPAPREnvironment *spapr = opaque; uint32_t section_hdr; + int fd = -1; if (version_id < 1 || version_id > 1) { fprintf(stderr, "htab_load() bad version\n"); @@ -932,6 +967,16 @@ static int htab_load(QEMUFile *f, void *opaque, int version_id) return 0; } + if (!spapr->htab) { + assert(kvm_enabled()); + + fd = kvmppc_get_htab_fd(true); + if (fd < 0) { + fprintf(stderr, "Unable to open fd to restore KVM hash table: %s\n", + strerror(errno)); + } + } + while (true) { uint32_t index; uint16_t n_valid, n_invalid; @@ -945,24 +990,41 @@ static int htab_load(QEMUFile *f, void *opaque, int version_id) break; } - if ((index + n_valid + n_invalid) >= + if ((index + n_valid + n_invalid) > (HTAB_SIZE(spapr) / HASH_PTE_SIZE_64)) { /* Bad index in stream */ fprintf(stderr, "htab_load() bad index %d (%hd+%hd entries) " - "in htab stream\n", index, n_valid, n_invalid); + "in htab stream (htab_shift=%d)\n", index, n_valid, n_invalid, + spapr->htab_shift); return -EINVAL; } - if (n_valid) { - qemu_get_buffer(f, HPTE(spapr->htab, index), - HASH_PTE_SIZE_64 * n_valid); - } - if (n_invalid) { - memset(HPTE(spapr->htab, index + n_valid), 0, - HASH_PTE_SIZE_64 * n_invalid); + if (spapr->htab) { + if (n_valid) { + qemu_get_buffer(f, HPTE(spapr->htab, index), + HASH_PTE_SIZE_64 * n_valid); + } + if (n_invalid) { + memset(HPTE(spapr->htab, index + n_valid), 0, + HASH_PTE_SIZE_64 * n_invalid); + } + } else { + int rc; + + assert(fd >= 0); + + rc = kvmppc_load_htab_chunk(f, fd, index, n_valid, n_invalid); + if (rc < 0) { + return rc; + } } } + if (!spapr->htab) { + assert(fd >= 0); + close(fd); + } + return 0; } |