If a guest reboots during a running migration, changes to the hash page table are not necessarily updated on the destination. Opening a new file descriptor to the HTAB forces the migration handler to resend the entire table.
Signed-off-by: Samuel Mendoza-Jonas <sam...@au1.ibm.com> --- hw/ppc/spapr.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ include/hw/ppc/spapr.h | 2 ++ 2 files changed, 49 insertions(+) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 0a2bfe6..1610c28 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -833,6 +833,13 @@ static void spapr_reset_htab(sPAPREnvironment *spapr) /* Kernel handles htab, we don't need to allocate one */ spapr->htab_shift = shift; kvmppc_kern_htab = true; + + /* Tell readers to update their file descriptor */ + pthread_mutex_lock(&spapr->htab_mutex); + if (spapr->htab_fd > 0) { + spapr->htab_fd_stale = true; + } + pthread_mutex_unlock(&spapr->htab_mutex); } else { if (!spapr->htab) { /* Allocate an htab if we don't yet have one */ @@ -850,6 +857,31 @@ static void spapr_reset_htab(sPAPREnvironment *spapr) } } +/* A guest reset will cause spapr->htab_fd to become stale if being used. + * Reopen the file descriptor to make sure the whole HTAB is properly read. + */ +static int spapr_check_htab_fd(sPAPREnvironment *spapr) +{ + int rc = 0; + + pthread_mutex_lock(&spapr->htab_mutex); + + if (spapr->htab_fd_stale) { + close(spapr->htab_fd); + spapr->htab_fd = kvmppc_get_htab_fd(false); + if (spapr->htab_fd < 0) { + error_report("Unable to open fd for reading hash table from KVM: " + "%s", strerror(errno)); + rc = -1; + } + spapr->htab_fd_stale = false; + } + + pthread_mutex_unlock(&spapr->htab_mutex); + return rc; +} + + static void ppc_spapr_reset(void) { PowerPCCPU *first_ppc_cpu; @@ -984,7 +1016,10 @@ static int htab_save_setup(QEMUFile *f, void *opaque) } else { assert(kvm_enabled()); + pthread_mutex_lock(&spapr->htab_mutex); spapr->htab_fd = kvmppc_get_htab_fd(false); + spapr->htab_fd_stale = false; + pthread_mutex_unlock(&spapr->htab_mutex); if (spapr->htab_fd < 0) { fprintf(stderr, "Unable to open fd for reading hash table from KVM: %s\n", strerror(errno)); @@ -1137,6 +1172,11 @@ static int htab_save_iterate(QEMUFile *f, void *opaque) if (!spapr->htab) { assert(kvm_enabled()); + rc = spapr_check_htab_fd(spapr); + if (rc < 0) { + return rc; + } + rc = kvmppc_save_htab(f, spapr->htab_fd, MAX_KVM_BUF_SIZE, MAX_ITERATION_NS); if (rc < 0) { @@ -1168,6 +1208,11 @@ static int htab_save_complete(QEMUFile *f, void *opaque) assert(kvm_enabled()); + rc = spapr_check_htab_fd(spapr); + if (rc < 0) { + return rc; + } + rc = kvmppc_save_htab(f, spapr->htab_fd, MAX_KVM_BUF_SIZE, -1); if (rc < 0) { return rc; @@ -1355,6 +1400,8 @@ static void ppc_spapr_init(MachineState *machine) spapr->htab_shift++; } + pthread_mutex_init(&spapr->htab_mutex, NULL); + /* Set up Interrupt Controller before we create the VCPUs */ spapr->icp = xics_system_init(smp_cpus * kvmppc_smt_threads() / smp_threads, XICS_IRQS); diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h index 749daf4..5e29bec 100644 --- a/include/hw/ppc/spapr.h +++ b/include/hw/ppc/spapr.h @@ -37,6 +37,8 @@ typedef struct sPAPREnvironment { int htab_save_index; bool htab_first_pass; int htab_fd; + bool htab_fd_stale; + pthread_mutex_t htab_mutex; } sPAPREnvironment; #define H_SUCCESS 0 -- 1.9.3