diff --git a/SOURCES/libvirt-cpu_x86-Properly-disable-unknown-CPU-features.patch b/SOURCES/libvirt-cpu_x86-Properly-disable-unknown-CPU-features.patch new file mode 100644 index 0000000..a54fa77 --- /dev/null +++ b/SOURCES/libvirt-cpu_x86-Properly-disable-unknown-CPU-features.patch @@ -0,0 +1,453 @@ +From 73e87a037ccd6d9fd02c3fd0a082f014412c7555 Mon Sep 17 00:00:00 2001 +Message-Id: <73e87a037ccd6d9fd02c3fd0a082f014412c7555@dist-git> +From: Jiri Denemark +Date: Mon, 19 Jun 2017 13:18:52 +0200 +Subject: [PATCH] cpu_x86: Properly disable unknown CPU features + +CPU features unknown to a hypervisor will not be present in dataDisabled +even though the features won't naturally be enabled because. +Thus any features we asked for which are not in dataEnabled should be +considered disabled. + +Signed-off-by: Jiri Denemark +(cherry picked from commit 83e081b8ab32dd990b4e4ccc7bf8a1a416fc51c2) + +https://bugzilla.redhat.com/show_bug.cgi?id=1470582 + +Signed-off-by: Jiri Denemark +Reviewed-by: Pavel Hrdina +--- + src/cpu/cpu_x86.c | 9 +- + tests/cputest.c | 1 + + .../x86_64-cpuid-Core-i7-5600U-arat-disabled.xml | 5 + + .../x86_64-cpuid-Core-i7-5600U-arat-enabled.xml | 8 + + .../x86_64-cpuid-Core-i7-5600U-arat-guest.xml | 29 +++ + .../x86_64-cpuid-Core-i7-5600U-arat-host.xml | 30 +++ + .../x86_64-cpuid-Core-i7-5600U-arat-json.xml | 14 ++ + .../x86_64-cpuid-Core-i7-5600U-arat.json | 202 +++++++++++++++++++++ + .../x86_64-cpuid-Core-i7-5600U-arat.xml | 41 +++++ + 9 files changed, 335 insertions(+), 4 deletions(-) + create mode 100644 tests/cputestdata/x86_64-cpuid-Core-i7-5600U-arat-disabled.xml + create mode 100644 tests/cputestdata/x86_64-cpuid-Core-i7-5600U-arat-enabled.xml + create mode 100644 tests/cputestdata/x86_64-cpuid-Core-i7-5600U-arat-guest.xml + create mode 100644 tests/cputestdata/x86_64-cpuid-Core-i7-5600U-arat-host.xml + create mode 100644 tests/cputestdata/x86_64-cpuid-Core-i7-5600U-arat-json.xml + create mode 100644 tests/cputestdata/x86_64-cpuid-Core-i7-5600U-arat.json + create mode 100644 tests/cputestdata/x86_64-cpuid-Core-i7-5600U-arat.xml + +diff --git a/src/cpu/cpu_x86.c b/src/cpu/cpu_x86.c +index 53359ff9b6..2864454211 100644 +--- a/src/cpu/cpu_x86.c ++++ b/src/cpu/cpu_x86.c +@@ -2664,12 +2664,11 @@ virCPUx86UpdateLive(virCPUDefPtr cpu, + x86DataCopy(&disabled, &dataDisabled->data.x86) < 0) + goto cleanup; + +- x86DataSubtract(&enabled, &model->data); +- + for (i = 0; i < map->nfeatures; i++) { + virCPUx86FeaturePtr feature = map->features[i]; + +- if (x86DataIsSubset(&enabled, &feature->data)) { ++ if (x86DataIsSubset(&enabled, &feature->data) && ++ !x86DataIsSubset(&model->data, &feature->data)) { + VIR_DEBUG("Feature '%s' enabled by the hypervisor", feature->name); + if (cpu->check == VIR_CPU_CHECK_FULL) + virBufferAsprintf(&bufAdded, "%s,", feature->name); +@@ -2678,7 +2677,9 @@ virCPUx86UpdateLive(virCPUDefPtr cpu, + goto cleanup; + } + +- if (x86DataIsSubset(&disabled, &feature->data)) { ++ if (x86DataIsSubset(&disabled, &feature->data) || ++ (x86DataIsSubset(&model->data, &feature->data) && ++ !x86DataIsSubset(&enabled, &feature->data))) { + VIR_DEBUG("Feature '%s' disabled by the hypervisor", feature->name); + if (cpu->check == VIR_CPU_CHECK_FULL) + virBufferAsprintf(&bufRemoved, "%s,", feature->name); +diff --git a/tests/cputest.c b/tests/cputest.c +index 97b34de9ed..5190a83467 100644 +--- a/tests/cputest.c ++++ b/tests/cputest.c +@@ -991,6 +991,7 @@ mymain(void) + DO_TEST_CPUID(VIR_ARCH_X86_64, "Core-i7-4600U", true); + DO_TEST_CPUID(VIR_ARCH_X86_64, "Core-i7-4510U", true); + DO_TEST_CPUID(VIR_ARCH_X86_64, "Core-i7-5600U", true); ++ DO_TEST_CPUID(VIR_ARCH_X86_64, "Core-i7-5600U-arat", true); + DO_TEST_CPUID(VIR_ARCH_X86_64, "Core2-E6850", true); + DO_TEST_CPUID(VIR_ARCH_X86_64, "Core2-Q9500", false); + DO_TEST_CPUID(VIR_ARCH_X86_64, "FX-8150", false); +diff --git a/tests/cputestdata/x86_64-cpuid-Core-i7-5600U-arat-disabled.xml b/tests/cputestdata/x86_64-cpuid-Core-i7-5600U-arat-disabled.xml +new file mode 100644 +index 0000000000..4a0477f788 +--- /dev/null ++++ b/tests/cputestdata/x86_64-cpuid-Core-i7-5600U-arat-disabled.xml +@@ -0,0 +1,5 @@ ++ ++ ++ ++ ++ +diff --git a/tests/cputestdata/x86_64-cpuid-Core-i7-5600U-arat-enabled.xml b/tests/cputestdata/x86_64-cpuid-Core-i7-5600U-arat-enabled.xml +new file mode 100644 +index 0000000000..5cffacef59 +--- /dev/null ++++ b/tests/cputestdata/x86_64-cpuid-Core-i7-5600U-arat-enabled.xml +@@ -0,0 +1,8 @@ ++ ++ ++ ++ ++ ++ ++ ++ +diff --git a/tests/cputestdata/x86_64-cpuid-Core-i7-5600U-arat-guest.xml b/tests/cputestdata/x86_64-cpuid-Core-i7-5600U-arat-guest.xml +new file mode 100644 +index 0000000000..877895cf15 +--- /dev/null ++++ b/tests/cputestdata/x86_64-cpuid-Core-i7-5600U-arat-guest.xml +@@ -0,0 +1,29 @@ ++ ++ Broadwell ++ Intel ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +diff --git a/tests/cputestdata/x86_64-cpuid-Core-i7-5600U-arat-host.xml b/tests/cputestdata/x86_64-cpuid-Core-i7-5600U-arat-host.xml +new file mode 100644 +index 0000000000..9b24941e0e +--- /dev/null ++++ b/tests/cputestdata/x86_64-cpuid-Core-i7-5600U-arat-host.xml +@@ -0,0 +1,30 @@ ++ ++ x86_64 ++ Broadwell ++ Intel ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +diff --git a/tests/cputestdata/x86_64-cpuid-Core-i7-5600U-arat-json.xml b/tests/cputestdata/x86_64-cpuid-Core-i7-5600U-arat-json.xml +new file mode 100644 +index 0000000000..4f253fc08a +--- /dev/null ++++ b/tests/cputestdata/x86_64-cpuid-Core-i7-5600U-arat-json.xml +@@ -0,0 +1,14 @@ ++ ++ Broadwell ++ Intel ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +diff --git a/tests/cputestdata/x86_64-cpuid-Core-i7-5600U-arat.json b/tests/cputestdata/x86_64-cpuid-Core-i7-5600U-arat.json +new file mode 100644 +index 0000000000..f2aa7f3185 +--- /dev/null ++++ b/tests/cputestdata/x86_64-cpuid-Core-i7-5600U-arat.json +@@ -0,0 +1,202 @@ ++{ ++ "return": { ++ "model": { ++ "name": "base", ++ "props": { ++ "pfthreshold": false, ++ "pku": false, ++ "rtm": true, ++ "tsc_adjust": true, ++ "tsc-deadline": true, ++ "xstore-en": false, ++ "tsc-scale": false, ++ "sse": true, ++ "smap": true, ++ "stepping": 4, ++ "tce": false, ++ "kvm_steal_time": true, ++ "smep": true, ++ "rdpid": false, ++ "xcrypt": false, ++ "sse4_2": true, ++ "monitor": false, ++ "sse4_1": true, ++ "kvm-mmu": false, ++ "flushbyasid": false, ++ "kvm-steal-time": true, ++ "lm": true, ++ "tsc": true, ++ "adx": true, ++ "fxsr": true, ++ "sha-ni": false, ++ "tm": false, ++ "pclmuldq": true, ++ "xgetbv1": false, ++ "xstore": false, ++ "vmcb_clean": false, ++ "vme": true, ++ "vendor": "GenuineIntel", ++ "ffxsr": false, ++ "de": true, ++ "avx512f": false, ++ "pse": true, ++ "ds-cpl": false, ++ "tbm": false, ++ "ia64": false, ++ "phe-en": false, ++ "f16c": true, ++ "ds": false, ++ "mpx": false, ++ "tsc-adjust": true, ++ "aes": true, ++ "avx2": true, ++ "pbe": false, ++ "cx16": true, ++ "ds_cpl": false, ++ "movbe": true, ++ "perfctr-nb": false, ++ "nrip_save": false, ++ "kvm_mmu": false, ++ "ospke": false, ++ "avx512ifma": false, ++ "vmx": true, ++ "sep": true, ++ "xsaveopt": true, ++ "sse4a": false, ++ "avx512dq": false, ++ "i64": true, ++ "avx512-4vnniw": false, ++ "xsave": true, ++ "erms": true, ++ "hle": true, ++ "nodeid_msr": false, ++ "est": false, ++ "svm_lock": false, ++ "xop": false, ++ "model-id": "Intel(R) Core(TM) i7-5600U CPU @ 2.60GHz", ++ "abm": true, ++ "avx512er": false, ++ "sse4.1": true, ++ "sse4.2": true, ++ "pause-filter": false, ++ "lahf-lm": true, ++ "kvm-nopiodelay": true, ++ "cmp_legacy": false, ++ "acpi": false, ++ "fma4": false, ++ "popcnt": true, ++ "mmx": true, ++ "osxsave": false, ++ "pcommit": false, ++ "avx512pf": false, ++ "clwb": false, ++ "dca": false, ++ "pdcm": false, ++ "xcrypt-en": false, ++ "3dnow": false, ++ "invtsc": false, ++ "tm2": false, ++ "hypervisor": true, ++ "kvmclock-stable-bit": true, ++ "fxsr-opt": false, ++ "pcid": true, ++ "sse4-1": true, ++ "sse4-2": true, ++ "avx512-vpopcntdq": false, ++ "avx512-4fmaps": false, ++ "pause_filter": false, ++ "svm-lock": false, ++ "rdrand": true, ++ "nrip-save": false, ++ "avx512vl": false, ++ "x2apic": true, ++ "kvmclock": true, ++ "pge": true, ++ "family": 6, ++ "dtes64": false, ++ "xd": true, ++ "kvm_pv_eoi": true, ++ "ace2": false, ++ "kvm_pv_unhalt": true, ++ "xtpr": false, ++ "perfctr_nb": false, ++ "avx512bw": false, ++ "nx": true, ++ "lwp": false, ++ "msr": true, ++ "ace2-en": false, ++ "decodeassists": false, ++ "perfctr-core": false, ++ "pn": false, ++ "fma": true, ++ "nodeid-msr": false, ++ "kvm_asyncpf": true, ++ "clflush": true, ++ "cx8": true, ++ "mce": true, ++ "avx512cd": false, ++ "cr8legacy": false, ++ "mca": true, ++ "pni": true, ++ "rdseed": true, ++ "apic": true, ++ "fsgsbase": true, ++ "cmp-legacy": false, ++ "kvm-pv-unhalt": true, ++ "rdtscp": true, ++ "mmxext": false, ++ "cid": false, ++ "ssse3": true, ++ "extapic": false, ++ "pse36": true, ++ "mtrr": true, ++ "ibs": false, ++ "la57": false, ++ "avx": true, ++ "syscall": true, ++ "umip": false, ++ "invpcid": true, ++ "avx512vbmi": false, ++ "kvm-asyncpf": true, ++ "vmcb-clean": false, ++ "pmm": false, ++ "cmov": true, ++ "perfctr_core": false, ++ "misalignsse": false, ++ "clflushopt": false, ++ "pat": true, ++ "lbrv": false, ++ "3dnowprefetch": true, ++ "fpu": true, ++ "pae": true, ++ "wdt": false, ++ "tsc_scale": false, ++ "skinit": false, ++ "fxsr_opt": false, ++ "kvm_nopiodelay": true, ++ "pmm-en": false, ++ "phe": false, ++ "3dnowext": false, ++ "osvw": false, ++ "ht": false, ++ "pdpe1gb": true, ++ "kvm-pv-eoi": true, ++ "npt": false, ++ "xsavec": false, ++ "lahf_lm": true, ++ "pclmulqdq": true, ++ "svm": false, ++ "sse3": true, ++ "sse2": true, ++ "ss": true, ++ "topoext": false, ++ "smx": false, ++ "bmi1": true, ++ "bmi2": true, ++ "xsaves": false, ++ "model": 61 ++ } ++ } ++ }, ++ "id": "model-expansion" ++} +diff --git a/tests/cputestdata/x86_64-cpuid-Core-i7-5600U-arat.xml b/tests/cputestdata/x86_64-cpuid-Core-i7-5600U-arat.xml +new file mode 100644 +index 0000000000..ecb4a6e15c +--- /dev/null ++++ b/tests/cputestdata/x86_64-cpuid-Core-i7-5600U-arat.xml +@@ -0,0 +1,41 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +-- +2.13.2 + diff --git a/SOURCES/libvirt-qemu-Add-qemuProcessFetchGuestCPU.patch b/SOURCES/libvirt-qemu-Add-qemuProcessFetchGuestCPU.patch new file mode 100644 index 0000000..3890b04 --- /dev/null +++ b/SOURCES/libvirt-qemu-Add-qemuProcessFetchGuestCPU.patch @@ -0,0 +1,102 @@ +From 57a9f46878f57d1602a030cfd8484c8566201c40 Mon Sep 17 00:00:00 2001 +Message-Id: <57a9f46878f57d1602a030cfd8484c8566201c40@dist-git> +From: Jiri Denemark +Date: Tue, 11 Jul 2017 13:18:45 +0200 +Subject: [PATCH] qemu: Add qemuProcessFetchGuestCPU + +Separated from qemuProcessUpdateLiveGuestCPU. Its purpose is to fetch +guest CPU data from a running QEMU process. The data can later be used +to verify and update the active guest CPU definition. + +Signed-off-by: Jiri Denemark +Reviewed-by: Pavel Hrdina +(cherry picked from commit 40d246a22b46f1691d09cbce5904c79d712d8c16) + +https://bugzilla.redhat.com/show_bug.cgi?id=1470582 + +Signed-off-by: Jiri Denemark +Reviewed-by: Pavel Hrdina +--- + src/qemu/qemu_process.c | 58 +++++++++++++++++++++++++++++++++++++------------ + 1 file changed, 44 insertions(+), 14 deletions(-) + +diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c +index 4d7c8d8e40..d3fa8ef41e 100644 +--- a/src/qemu/qemu_process.c ++++ b/src/qemu/qemu_process.c +@@ -3905,6 +3905,47 @@ qemuProcessVerifyCPUFeatures(virDomainDefPtr def, + + + static int ++qemuProcessFetchGuestCPU(virQEMUDriverPtr driver, ++ virDomainObjPtr vm, ++ qemuDomainAsyncJob asyncJob, ++ virCPUDataPtr *enabled, ++ virCPUDataPtr *disabled) ++{ ++ qemuDomainObjPrivatePtr priv = vm->privateData; ++ virCPUDataPtr dataEnabled = NULL; ++ virCPUDataPtr dataDisabled = NULL; ++ int rc; ++ ++ *enabled = NULL; ++ *disabled = NULL; ++ ++ if (!ARCH_IS_X86(vm->def->os.arch)) ++ return 0; ++ ++ if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) < 0) ++ goto error; ++ ++ rc = qemuMonitorGetGuestCPU(priv->mon, vm->def->os.arch, ++ &dataEnabled, &dataDisabled); ++ ++ if (qemuDomainObjExitMonitor(driver, vm) < 0) ++ goto error; ++ ++ if (rc == -1) ++ goto error; ++ ++ *enabled = dataEnabled; ++ *disabled = dataDisabled; ++ return 0; ++ ++ error: ++ virCPUDataFree(dataEnabled); ++ virCPUDataFree(dataDisabled); ++ return -1; ++} ++ ++ ++static int + qemuProcessUpdateLiveGuestCPU(virQEMUDriverPtr driver, + virDomainObjPtr vm, + qemuDomainAsyncJob asyncJob) +@@ -3917,21 +3958,10 @@ qemuProcessUpdateLiveGuestCPU(virQEMUDriverPtr driver, + int ret = -1; + virCPUDefPtr orig = NULL; + +- if (ARCH_IS_X86(def->os.arch)) { +- if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) < 0) +- goto cleanup; +- +- rc = qemuMonitorGetGuestCPU(priv->mon, def->os.arch, &cpu, &disabled); +- +- if (qemuDomainObjExitMonitor(driver, vm) < 0) +- goto cleanup; +- +- if (rc < 0) { +- if (rc == -2) +- ret = 0; +- goto cleanup; +- } ++ if (qemuProcessFetchGuestCPU(driver, vm, asyncJob, &cpu, &disabled) < 0) ++ goto cleanup; + ++ if (cpu) { + if (qemuProcessVerifyKVMFeatures(def, cpu) < 0 || + qemuProcessVerifyHypervFeatures(def, cpu) < 0) + goto cleanup; +-- +2.13.2 + diff --git a/SOURCES/libvirt-qemu-Add-qemuProcessUpdateLiveGuestCPU.patch b/SOURCES/libvirt-qemu-Add-qemuProcessUpdateLiveGuestCPU.patch new file mode 100644 index 0000000..33bd482 --- /dev/null +++ b/SOURCES/libvirt-qemu-Add-qemuProcessUpdateLiveGuestCPU.patch @@ -0,0 +1,127 @@ +From e5840b68e6376a514c6c5de1897ac87dc57e7a58 Mon Sep 17 00:00:00 2001 +Message-Id: +From: Jiri Denemark +Date: Tue, 11 Jul 2017 13:51:17 +0200 +Subject: [PATCH] qemu: Add qemuProcessUpdateLiveGuestCPU + +Separated from qemuProcessUpdateAndVerifyCPU to handle updating of an +active guest CPU definition according to live data from QEMU. + +Signed-off-by: Jiri Denemark +Reviewed-by: Pavel Hrdina +(cherry picked from commit eef9f83b691e0713e4fc480b497b85517aba6ca4) + +https://bugzilla.redhat.com/show_bug.cgi?id=1470582 + +Signed-off-by: Jiri Denemark +Reviewed-by: Pavel Hrdina +--- + src/qemu/qemu_process.c | 72 ++++++++++++++++++++++++++++++------------------- + 1 file changed, 44 insertions(+), 28 deletions(-) + +diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c +index 1e7724e784..9df463094e 100644 +--- a/src/qemu/qemu_process.c ++++ b/src/qemu/qemu_process.c +@@ -3971,17 +3971,55 @@ qemuProcessVerifyCPU(virDomainObjPtr vm, + + + static int ++qemuProcessUpdateLiveGuestCPU(virDomainObjPtr vm, ++ virCPUDataPtr enabled, ++ virCPUDataPtr disabled) ++{ ++ virDomainDefPtr def = vm->def; ++ qemuDomainObjPrivatePtr priv = vm->privateData; ++ virCPUDefPtr orig = NULL; ++ int rc; ++ int ret = -1; ++ ++ if (!enabled) ++ return 0; ++ ++ if (!def->cpu || ++ (def->cpu->mode == VIR_CPU_MODE_CUSTOM && ++ !def->cpu->model)) ++ return 0; ++ ++ if (!(orig = virCPUDefCopy(def->cpu))) ++ goto cleanup; ++ ++ if ((rc = virCPUUpdateLive(def->os.arch, def->cpu, enabled, disabled)) < 0) { ++ goto cleanup; ++ } else if (rc == 0) { ++ /* Store the original CPU in priv if QEMU changed it and we didn't ++ * get the original CPU via migration, restore, or snapshot revert. ++ */ ++ if (!priv->origCPU && !virCPUDefIsEqual(def->cpu, orig, false)) ++ VIR_STEAL_PTR(priv->origCPU, orig); ++ ++ def->cpu->check = VIR_CPU_CHECK_FULL; ++ } ++ ++ ret = 0; ++ ++ cleanup: ++ virCPUDefFree(orig); ++ return ret; ++} ++ ++ ++static int + qemuProcessUpdateAndVerifyCPU(virQEMUDriverPtr driver, + virDomainObjPtr vm, + qemuDomainAsyncJob asyncJob) + { +- virDomainDefPtr def = vm->def; + virCPUDataPtr cpu = NULL; + virCPUDataPtr disabled = NULL; +- qemuDomainObjPrivatePtr priv = vm->privateData; +- int rc; + int ret = -1; +- virCPUDefPtr orig = NULL; + + if (qemuProcessFetchGuestCPU(driver, vm, asyncJob, &cpu, &disabled) < 0) + goto cleanup; +@@ -3989,36 +4027,14 @@ qemuProcessUpdateAndVerifyCPU(virQEMUDriverPtr driver, + if (qemuProcessVerifyCPU(vm, cpu) < 0) + goto cleanup; + +- if (cpu) { +- if (!def->cpu || +- (def->cpu->mode == VIR_CPU_MODE_CUSTOM && +- !def->cpu->model)) { +- ret = 0; +- goto cleanup; +- } +- +- if (!(orig = virCPUDefCopy(def->cpu))) +- goto cleanup; +- +- if ((rc = virCPUUpdateLive(def->os.arch, def->cpu, cpu, disabled)) < 0) { +- goto cleanup; +- } else if (rc == 0) { +- /* Store the original CPU in priv if QEMU changed it and we didn't +- * get the original CPU via migration, restore, or snapshot revert. +- */ +- if (!priv->origCPU && !virCPUDefIsEqual(def->cpu, orig, false)) +- VIR_STEAL_PTR(priv->origCPU, orig); +- +- def->cpu->check = VIR_CPU_CHECK_FULL; +- } +- } ++ if (qemuProcessUpdateLiveGuestCPU(vm, cpu, disabled) < 0) ++ goto cleanup; + + ret = 0; + + cleanup: + virCPUDataFree(cpu); + virCPUDataFree(disabled); +- virCPUDefFree(orig); + return ret; + } + +-- +2.13.2 + diff --git a/SOURCES/libvirt-qemu-Add-qemuProcessVerifyCPU.patch b/SOURCES/libvirt-qemu-Add-qemuProcessVerifyCPU.patch new file mode 100644 index 0000000..c557e14 --- /dev/null +++ b/SOURCES/libvirt-qemu-Add-qemuProcessVerifyCPU.patch @@ -0,0 +1,85 @@ +From 9d41cae9942d2909be00261b3ae2a2e1ec717808 Mon Sep 17 00:00:00 2001 +Message-Id: <9d41cae9942d2909be00261b3ae2a2e1ec717808@dist-git> +From: Jiri Denemark +Date: Tue, 11 Jul 2017 13:26:12 +0200 +Subject: [PATCH] qemu: Add qemuProcessVerifyCPU + +Separated from qemuProcessUpdateLiveGuestCPU. The function makes sure +a guest CPU provides all features required by a domain definition. + +Signed-off-by: Jiri Denemark +Reviewed-by: Pavel Hrdina +(cherry picked from commit 5cac2fe108f957b2629a29bea1747fdb3c8d7aa3) + +https://bugzilla.redhat.com/show_bug.cgi?id=1470582 + +Signed-off-by: Jiri Denemark +Reviewed-by: Pavel Hrdina +--- + src/qemu/qemu_process.c | 35 ++++++++++++++++++++++++++++------- + 1 file changed, 28 insertions(+), 7 deletions(-) + +diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c +index d3fa8ef41e..3f7a9f4c02 100644 +--- a/src/qemu/qemu_process.c ++++ b/src/qemu/qemu_process.c +@@ -3946,6 +3946,31 @@ qemuProcessFetchGuestCPU(virQEMUDriverPtr driver, + + + static int ++qemuProcessVerifyCPU(virDomainObjPtr vm, ++ virCPUDataPtr cpu) ++{ ++ virDomainDefPtr def = vm->def; ++ ++ if (!cpu) ++ return 0; ++ ++ if (qemuProcessVerifyKVMFeatures(def, cpu) < 0 || ++ qemuProcessVerifyHypervFeatures(def, cpu) < 0) ++ return -1; ++ ++ if (!def->cpu || ++ (def->cpu->mode == VIR_CPU_MODE_CUSTOM && ++ !def->cpu->model)) ++ return 0; ++ ++ if (qemuProcessVerifyCPUFeatures(def, cpu) < 0) ++ return -1; ++ ++ return 0; ++} ++ ++ ++static int + qemuProcessUpdateLiveGuestCPU(virQEMUDriverPtr driver, + virDomainObjPtr vm, + qemuDomainAsyncJob asyncJob) +@@ -3961,11 +3986,10 @@ qemuProcessUpdateLiveGuestCPU(virQEMUDriverPtr driver, + if (qemuProcessFetchGuestCPU(driver, vm, asyncJob, &cpu, &disabled) < 0) + goto cleanup; + +- if (cpu) { +- if (qemuProcessVerifyKVMFeatures(def, cpu) < 0 || +- qemuProcessVerifyHypervFeatures(def, cpu) < 0) +- goto cleanup; ++ if (qemuProcessVerifyCPU(vm, cpu) < 0) ++ goto cleanup; + ++ if (cpu) { + if (!def->cpu || + (def->cpu->mode == VIR_CPU_MODE_CUSTOM && + !def->cpu->model)) { +@@ -3973,9 +3997,6 @@ qemuProcessUpdateLiveGuestCPU(virQEMUDriverPtr driver, + goto cleanup; + } + +- if (qemuProcessVerifyCPUFeatures(def, cpu) < 0) +- goto cleanup; +- + if (!(orig = virCPUDefCopy(def->cpu))) + goto cleanup; + +-- +2.13.2 + diff --git a/SOURCES/libvirt-qemu-Don-t-update-CPU-when-checking-ABI-stability.patch b/SOURCES/libvirt-qemu-Don-t-update-CPU-when-checking-ABI-stability.patch new file mode 100644 index 0000000..85a5901 --- /dev/null +++ b/SOURCES/libvirt-qemu-Don-t-update-CPU-when-checking-ABI-stability.patch @@ -0,0 +1,61 @@ +From d260867d18aa20c4d79f4319b82453120d209eae Mon Sep 17 00:00:00 2001 +Message-Id: +From: Jiri Denemark +Date: Tue, 27 Jun 2017 15:06:10 +0200 +Subject: [PATCH] qemu: Don't update CPU when checking ABI stability + +When checking ABI stability between two domain definitions, we first +make migratable copies of them. However, we also asked for the guest CPU +to be updated, even though the updated CPU is supposed to be already +included in the original definitions. Moreover, if we do this on the +destination host during migration, we're potentially updating the +definition with according to an incompatible host CPU. + +While updating the CPU when checking ABI stability doesn't make any +sense, it actually just worked because updating the CPU doesn't do +anything for custom CPUs (only host-model CPUs are affected) and we +updated both definitions in the same way. + +Less then a year ago commit v2.3.0-rc1~42 stopped updating the CPU in +the definition we got internally and only the user supplied definition +was updated. However, the same commit started updating host-model CPUs +to custom CPUs which are not affected by the request to update the CPU. +So it still seemed to work right, unless a user upgraded libvirt 2.2.0 +to a newer version while there were some domains with host-model CPUs +running on the host. Such domains couldn't be migrated with a user +supplied XML since libvirt would complain: + + Target CPU mode custom does not match source host-model + +The fix is pretty straightforward, we just need to stop updating the CPU +when checking ABI stability. + +https://bugzilla.redhat.com/show_bug.cgi?id=1463957 + +Signed-off-by: Jiri Denemark +Reviewed-by: Pavel Hrdina +(cherry picked from commit ee68bb391efb684341edb6286a1278631167f08c) + +https://bugzilla.redhat.com/show_bug.cgi?id=1470582 + +Signed-off-by: Jiri Denemark +Reviewed-by: Pavel Hrdina +--- + src/qemu/qemu_domain.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c +index 1528c6a137..6ccc9f6f5b 100644 +--- a/src/qemu/qemu_domain.c ++++ b/src/qemu/qemu_domain.c +@@ -5910,7 +5910,6 @@ qemuDomainMigratableDefCheckABIStability(virQEMUDriverPtr driver, + + + #define COPY_FLAGS (VIR_DOMAIN_XML_SECURE | \ +- VIR_DOMAIN_XML_UPDATE_CPU | \ + VIR_DOMAIN_XML_MIGRATABLE) + + bool +-- +2.13.2 + diff --git a/SOURCES/libvirt-qemu-Export-virQEMUCapsGuestIsNative.patch b/SOURCES/libvirt-qemu-Export-virQEMUCapsGuestIsNative.patch new file mode 100644 index 0000000..75fc214 --- /dev/null +++ b/SOURCES/libvirt-qemu-Export-virQEMUCapsGuestIsNative.patch @@ -0,0 +1,47 @@ +From b06befbc433e1b6dc1a8ee5ee0814a20a2288685 Mon Sep 17 00:00:00 2001 +Message-Id: +From: Jiri Denemark +Date: Tue, 11 Jul 2017 15:15:01 +0200 +Subject: [PATCH] qemu: Export virQEMUCapsGuestIsNative + +Signed-off-by: Jiri Denemark +Reviewed-by: Pavel Hrdina +(cherry picked from commit ee4180bef124cbc08a702689dda6fd95b21b1387) + +https://bugzilla.redhat.com/show_bug.cgi?id=1470582 + +Signed-off-by: Jiri Denemark +Reviewed-by: Pavel Hrdina +--- + src/qemu/qemu_capabilities.c | 2 +- + src/qemu/qemu_capabilities.h | 3 +++ + 2 files changed, 4 insertions(+), 1 deletion(-) + +diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c +index eea57e4c9c..f22c11941c 100644 +--- a/src/qemu/qemu_capabilities.c ++++ b/src/qemu/qemu_capabilities.c +@@ -491,7 +491,7 @@ static const char *virQEMUCapsArchToString(virArch arch) + + /* Checks whether a domain with @guest arch can run natively on @host. + */ +-static bool ++bool + virQEMUCapsGuestIsNative(virArch host, + virArch guest) + { +diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h +index bbc6f6812f..c28c80d40a 100644 +--- a/src/qemu/qemu_capabilities.h ++++ b/src/qemu/qemu_capabilities.h +@@ -569,4 +569,7 @@ int virQEMUCapsFillDomainCaps(virCapsPtr caps, + virFirmwarePtr *firmwares, + size_t nfirmwares); + ++bool virQEMUCapsGuestIsNative(virArch host, ++ virArch guest); ++ + #endif /* __QEMU_CAPABILITIES_H__*/ +-- +2.13.2 + diff --git a/SOURCES/libvirt-qemu-Fix-qemuDomainGetBlockInfo-allocation-value-setting.patch b/SOURCES/libvirt-qemu-Fix-qemuDomainGetBlockInfo-allocation-value-setting.patch new file mode 100644 index 0000000..eb82b29 --- /dev/null +++ b/SOURCES/libvirt-qemu-Fix-qemuDomainGetBlockInfo-allocation-value-setting.patch @@ -0,0 +1,46 @@ +From 0220b2fed9ab4b07f32e8ebe4ab048d64a27e948 Mon Sep 17 00:00:00 2001 +Message-Id: <0220b2fed9ab4b07f32e8ebe4ab048d64a27e948@dist-git> +From: John Ferlan +Date: Wed, 12 Jul 2017 16:31:10 +0200 +Subject: [PATCH] qemu: Fix qemuDomainGetBlockInfo allocation value setting + +https://bugzilla.redhat.com/show_bug.cgi?id=1467826 + +Commit id 'b9b1aa639' was supposed to add logic to set the allocation +for sparse files when wr_highest_offset was zero; however, an unconditional +setting was done just prior. For block devices, this means allocation is +always returning 0 since 'actual-size' will be zero. + +Remove the unconditional setting and add the note about it being possible +to still be zero for block devices. As soon as the guest starts writing to +the volume, the allocation value will then be obtainable from qemu via +the wr_highest_offset. + +(cherry picked from commit fde654be5307a570b7b0f31537e18e70a274cd50) + +https://bugzilla.redhat.com/show_bug.cgi?id=1470127 [7.4.z - 0day] + +Signed-off-by: Jiri Denemark +--- + src/qemu/qemu_driver.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c +index a2fb41b91a..b6d72303ca 100644 +--- a/src/qemu/qemu_driver.c ++++ b/src/qemu/qemu_driver.c +@@ -11715,10 +11715,9 @@ qemuDomainGetBlockInfo(virDomainPtr dom, + * Additionally, if qemu hasn't written to the file yet, then set the + * allocation to whatever qemu returned for physical (e.g. the "actual- + * size" from the json query) as that will match the expected allocation +- * value for this API. */ ++ * value for this API. NB: May still be 0 for block. */ + if (entry->physical == 0 || info->allocation == 0 || + info->allocation == entry->physical) { +- info->allocation = entry->physical; + if (info->allocation == 0) + info->allocation = entry->physical; + +-- +2.13.3 + diff --git a/SOURCES/libvirt-qemu-Move-qemuProcessReconnect-to-the-end-of-qemu_process.c.patch b/SOURCES/libvirt-qemu-Move-qemuProcessReconnect-to-the-end-of-qemu_process.c.patch new file mode 100644 index 0000000..facaf96 --- /dev/null +++ b/SOURCES/libvirt-qemu-Move-qemuProcessReconnect-to-the-end-of-qemu_process.c.patch @@ -0,0 +1,687 @@ +From 6f532f2e3615bb573a186cfcfddf8fcc1eec7efd Mon Sep 17 00:00:00 2001 +Message-Id: <6f532f2e3615bb573a186cfcfddf8fcc1eec7efd@dist-git> +From: Jiri Denemark +Date: Tue, 11 Jul 2017 15:53:58 +0200 +Subject: [PATCH] qemu: Move qemuProcessReconnect to the end of qemu_process.c + +qemuProcessReconnect will need to call additional functions which were +originally defined further in qemu_process.c. + +Signed-off-by: Jiri Denemark +Reviewed-by: Pavel Hrdina +(cherry picked from commit aad362f93b4451e2f3c98923e5e44c4fe6d26d75) + +Conflicts: + src/qemu/qemu_process.c + +https://bugzilla.redhat.com/show_bug.cgi?id=1470582 + +Signed-off-by: Jiri Denemark +Reviewed-by: Pavel Hrdina +--- + src/qemu/qemu_process.c | 645 ++++++++++++++++++++++++------------------------ + 1 file changed, 323 insertions(+), 322 deletions(-) + +diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c +index 9df463094e..e6f56dc484 100644 +--- a/src/qemu/qemu_process.c ++++ b/src/qemu/qemu_process.c +@@ -3331,328 +3331,6 @@ qemuProcessBuildDestroyHugepagesPath(virQEMUDriverPtr driver, + } + + +-struct qemuProcessReconnectData { +- virConnectPtr conn; +- virQEMUDriverPtr driver; +- virDomainObjPtr obj; +-}; +-/* +- * Open an existing VM's monitor, re-detect VCPU threads +- * and re-reserve the security labels in use +- * +- * We own the virConnectPtr we are passed here - whoever started +- * this thread function has increased the reference counter to it +- * so that we now have to close it. +- * +- * This function also inherits a locked and ref'd domain object. +- * +- * This function needs to: +- * 1. Enter job +- * 1. just before monitor reconnect do lightweight MonitorEnter +- * (increase VM refcount and unlock VM) +- * 2. reconnect to monitor +- * 3. do lightweight MonitorExit (lock VM) +- * 4. continue reconnect process +- * 5. EndJob +- * +- * We can't do normal MonitorEnter & MonitorExit because these two lock the +- * monitor lock, which does not exists in this early phase. +- */ +-static void +-qemuProcessReconnect(void *opaque) +-{ +- struct qemuProcessReconnectData *data = opaque; +- virQEMUDriverPtr driver = data->driver; +- virDomainObjPtr obj = data->obj; +- qemuDomainObjPrivatePtr priv; +- virConnectPtr conn = data->conn; +- struct qemuDomainJobObj oldjob; +- int state; +- int reason; +- virQEMUDriverConfigPtr cfg; +- size_t i; +- unsigned int stopFlags = 0; +- bool jobStarted = false; +- virCapsPtr caps = NULL; +- +- VIR_FREE(data); +- +- qemuDomainObjRestoreJob(obj, &oldjob); +- if (oldjob.asyncJob == QEMU_ASYNC_JOB_MIGRATION_IN) +- stopFlags |= VIR_QEMU_PROCESS_STOP_MIGRATED; +- +- cfg = virQEMUDriverGetConfig(driver); +- priv = obj->privateData; +- +- if (!(caps = virQEMUDriverGetCapabilities(driver, false))) +- goto error; +- +- if (qemuDomainObjBeginJob(driver, obj, QEMU_JOB_MODIFY) < 0) +- goto error; +- jobStarted = true; +- +- /* XXX If we ever gonna change pid file pattern, come up with +- * some intelligence here to deal with old paths. */ +- if (!(priv->pidfile = virPidFileBuildPath(cfg->stateDir, obj->def->name))) +- goto error; +- +- /* Restore the masterKey */ +- if (qemuDomainMasterKeyReadFile(priv) < 0) +- goto error; +- +- virNWFilterReadLockFilterUpdates(); +- +- VIR_DEBUG("Reconnect monitor to %p '%s'", obj, obj->def->name); +- +- /* XXX check PID liveliness & EXE path */ +- if (qemuConnectMonitor(driver, obj, QEMU_ASYNC_JOB_NONE, NULL) < 0) +- goto error; +- +- if (qemuHostdevUpdateActiveDomainDevices(driver, obj->def) < 0) +- goto error; +- +- if (qemuConnectCgroup(driver, obj) < 0) +- goto error; +- +- if (qemuDomainPerfRestart(obj) < 0) +- goto error; +- +- /* XXX: Need to change as long as lock is introduced for +- * qemu_driver->sharedDevices. +- */ +- for (i = 0; i < obj->def->ndisks; i++) { +- virDomainDeviceDef dev; +- +- if (virStorageTranslateDiskSourcePool(conn, obj->def->disks[i]) < 0) +- goto error; +- +- /* XXX we should be able to restore all data from XML in the future. +- * This should be the only place that calls qemuDomainDetermineDiskChain +- * with @report_broken == false to guarantee best-effort domain +- * reconnect */ +- if (qemuDomainDetermineDiskChain(driver, obj, obj->def->disks[i], +- true, false) < 0) +- goto error; +- +- dev.type = VIR_DOMAIN_DEVICE_DISK; +- dev.data.disk = obj->def->disks[i]; +- if (qemuAddSharedDevice(driver, &dev, obj->def->name) < 0) +- goto error; +- } +- +- if (qemuProcessUpdateState(driver, obj) < 0) +- goto error; +- +- state = virDomainObjGetState(obj, &reason); +- if (state == VIR_DOMAIN_SHUTOFF || +- (state == VIR_DOMAIN_PAUSED && +- reason == VIR_DOMAIN_PAUSED_STARTING_UP)) { +- VIR_DEBUG("Domain '%s' wasn't fully started yet, killing it", +- obj->def->name); +- goto error; +- } +- +- /* If upgrading from old libvirtd we won't have found any +- * caps in the domain status, so re-query them +- */ +- if (!priv->qemuCaps && +- !(priv->qemuCaps = virQEMUCapsCacheLookupCopy(caps, +- driver->qemuCapsCache, +- obj->def->emulator, +- obj->def->os.machine))) +- goto error; +- +- /* In case the domain shutdown while we were not running, +- * we need to finish the shutdown process. And we need to do it after +- * we have virQEMUCaps filled in. +- */ +- if (state == VIR_DOMAIN_SHUTDOWN || +- (state == VIR_DOMAIN_PAUSED && +- reason == VIR_DOMAIN_PAUSED_SHUTTING_DOWN)) { +- VIR_DEBUG("Finishing shutdown sequence for domain %s", +- obj->def->name); +- qemuProcessShutdownOrReboot(driver, obj); +- goto cleanup; +- } +- +- if (qemuProcessBuildDestroyHugepagesPath(driver, obj, true) < 0) +- goto error; +- +- if ((qemuDomainAssignAddresses(obj->def, priv->qemuCaps, +- driver, obj, false)) < 0) { +- goto error; +- } +- +- /* if domain requests security driver we haven't loaded, report error, but +- * do not kill the domain +- */ +- ignore_value(qemuSecurityCheckAllLabel(driver->securityManager, +- obj->def)); +- +- if (qemuDomainRefreshVcpuInfo(driver, obj, QEMU_ASYNC_JOB_NONE, true) < 0) +- goto error; +- +- qemuDomainVcpuPersistOrder(obj->def); +- +- if (qemuSecurityReserveLabel(driver->securityManager, obj->def, obj->pid) < 0) +- goto error; +- +- qemuProcessNotifyNets(obj->def); +- +- if (qemuProcessFiltersInstantiate(obj->def)) +- goto error; +- +- if (qemuProcessRefreshDisks(driver, obj, QEMU_ASYNC_JOB_NONE) < 0) +- goto error; +- +- if (qemuBlockNodeNamesDetect(driver, obj) < 0) +- goto error; +- +- if (qemuRefreshVirtioChannelState(driver, obj, QEMU_ASYNC_JOB_NONE) < 0) +- goto error; +- +- /* If querying of guest's RTC failed, report error, but do not kill the domain. */ +- qemuRefreshRTC(driver, obj); +- +- if (qemuProcessRefreshBalloonState(driver, obj, QEMU_ASYNC_JOB_NONE) < 0) +- goto error; +- +- if (qemuProcessRecoverJob(driver, obj, conn, &oldjob, &stopFlags) < 0) +- goto error; +- +- if (qemuProcessUpdateDevices(driver, obj) < 0) +- goto error; +- +- qemuProcessReconnectCheckMemAliasOrderMismatch(obj); +- +- if (qemuConnectAgent(driver, obj) < 0) +- goto error; +- +- /* update domain state XML with possibly updated state in virDomainObj */ +- if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, obj, driver->caps) < 0) +- goto error; +- +- /* Run an hook to allow admins to do some magic */ +- if (virHookPresent(VIR_HOOK_DRIVER_QEMU)) { +- char *xml = qemuDomainDefFormatXML(driver, obj->def, 0); +- int hookret; +- +- hookret = virHookCall(VIR_HOOK_DRIVER_QEMU, obj->def->name, +- VIR_HOOK_QEMU_OP_RECONNECT, VIR_HOOK_SUBOP_BEGIN, +- NULL, xml, NULL); +- VIR_FREE(xml); +- +- /* +- * If the script raised an error abort the launch +- */ +- if (hookret < 0) +- goto error; +- } +- +- if (virAtomicIntInc(&driver->nactive) == 1 && driver->inhibitCallback) +- driver->inhibitCallback(true, driver->inhibitOpaque); +- +- cleanup: +- if (jobStarted) +- qemuDomainObjEndJob(driver, obj); +- if (!virDomainObjIsActive(obj)) +- qemuDomainRemoveInactive(driver, obj); +- virDomainObjEndAPI(&obj); +- virObjectUnref(conn); +- virObjectUnref(cfg); +- virObjectUnref(caps); +- virNWFilterUnlockFilterUpdates(); +- return; +- +- error: +- if (virDomainObjIsActive(obj)) { +- /* We can't get the monitor back, so must kill the VM +- * to remove danger of it ending up running twice if +- * user tries to start it again later +- */ +- if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_NO_SHUTDOWN)) { +- /* If we couldn't get the monitor and qemu supports +- * no-shutdown, we can safely say that the domain +- * crashed ... */ +- state = VIR_DOMAIN_SHUTOFF_CRASHED; +- } else { +- /* ... but if it doesn't we can't say what the state +- * really is and FAILED means "failed to start" */ +- state = VIR_DOMAIN_SHUTOFF_UNKNOWN; +- } +- /* If BeginJob failed, we jumped here without a job, let's hope another +- * thread didn't have a chance to start playing with the domain yet +- * (it's all we can do anyway). +- */ +- qemuProcessStop(driver, obj, state, QEMU_ASYNC_JOB_NONE, stopFlags); +- } +- goto cleanup; +-} +- +-static int +-qemuProcessReconnectHelper(virDomainObjPtr obj, +- void *opaque) +-{ +- virThread thread; +- struct qemuProcessReconnectData *src = opaque; +- struct qemuProcessReconnectData *data; +- +- /* If the VM was inactive, we don't need to reconnect */ +- if (!obj->pid) +- return 0; +- +- if (VIR_ALLOC(data) < 0) +- return -1; +- +- memcpy(data, src, sizeof(*data)); +- data->obj = obj; +- +- /* this lock and reference will be eventually transferred to the thread +- * that handles the reconnect */ +- virObjectLock(obj); +- virObjectRef(obj); +- +- /* Since we close the connection later on, we have to make sure that the +- * threads we start see a valid connection throughout their lifetime. We +- * simply increase the reference counter here. +- */ +- virObjectRef(data->conn); +- +- if (virThreadCreate(&thread, false, qemuProcessReconnect, data) < 0) { +- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", +- _("Could not create thread. QEMU initialization " +- "might be incomplete")); +- /* We can't spawn a thread and thus connect to monitor. Kill qemu. +- * It's safe to call qemuProcessStop without a job here since there +- * is no thread that could be doing anything else with the same domain +- * object. +- */ +- qemuProcessStop(src->driver, obj, VIR_DOMAIN_SHUTOFF_FAILED, +- QEMU_ASYNC_JOB_NONE, 0); +- qemuDomainRemoveInactive(src->driver, obj); +- +- virDomainObjEndAPI(&obj); +- virObjectUnref(data->conn); +- VIR_FREE(data); +- return -1; +- } +- +- return 0; +-} +- +-/** +- * qemuProcessReconnectAll +- * +- * Try to re-open the resources for live VMs that we care +- * about. +- */ +-void +-qemuProcessReconnectAll(virConnectPtr conn, virQEMUDriverPtr driver) +-{ +- struct qemuProcessReconnectData data = {.conn = conn, .driver = driver}; +- virDomainObjListForEach(driver->domains, qemuProcessReconnectHelper, &data); +-} +- + static int + qemuProcessVNCAllocatePorts(virQEMUDriverPtr driver, + virDomainGraphicsDefPtr graphics, +@@ -6958,3 +6636,326 @@ qemuProcessRefreshDisks(virQEMUDriverPtr driver, + virHashFree(table); + return ret; + } ++ ++ ++struct qemuProcessReconnectData { ++ virConnectPtr conn; ++ virQEMUDriverPtr driver; ++ virDomainObjPtr obj; ++}; ++/* ++ * Open an existing VM's monitor, re-detect VCPU threads ++ * and re-reserve the security labels in use ++ * ++ * We own the virConnectPtr we are passed here - whoever started ++ * this thread function has increased the reference counter to it ++ * so that we now have to close it. ++ * ++ * This function also inherits a locked and ref'd domain object. ++ * ++ * This function needs to: ++ * 1. Enter job ++ * 1. just before monitor reconnect do lightweight MonitorEnter ++ * (increase VM refcount and unlock VM) ++ * 2. reconnect to monitor ++ * 3. do lightweight MonitorExit (lock VM) ++ * 4. continue reconnect process ++ * 5. EndJob ++ * ++ * We can't do normal MonitorEnter & MonitorExit because these two lock the ++ * monitor lock, which does not exists in this early phase. ++ */ ++static void ++qemuProcessReconnect(void *opaque) ++{ ++ struct qemuProcessReconnectData *data = opaque; ++ virQEMUDriverPtr driver = data->driver; ++ virDomainObjPtr obj = data->obj; ++ qemuDomainObjPrivatePtr priv; ++ virConnectPtr conn = data->conn; ++ struct qemuDomainJobObj oldjob; ++ int state; ++ int reason; ++ virQEMUDriverConfigPtr cfg; ++ size_t i; ++ unsigned int stopFlags = 0; ++ bool jobStarted = false; ++ virCapsPtr caps = NULL; ++ ++ VIR_FREE(data); ++ ++ qemuDomainObjRestoreJob(obj, &oldjob); ++ if (oldjob.asyncJob == QEMU_ASYNC_JOB_MIGRATION_IN) ++ stopFlags |= VIR_QEMU_PROCESS_STOP_MIGRATED; ++ ++ cfg = virQEMUDriverGetConfig(driver); ++ priv = obj->privateData; ++ ++ if (!(caps = virQEMUDriverGetCapabilities(driver, false))) ++ goto error; ++ ++ if (qemuDomainObjBeginJob(driver, obj, QEMU_JOB_MODIFY) < 0) ++ goto error; ++ jobStarted = true; ++ ++ /* XXX If we ever gonna change pid file pattern, come up with ++ * some intelligence here to deal with old paths. */ ++ if (!(priv->pidfile = virPidFileBuildPath(cfg->stateDir, obj->def->name))) ++ goto error; ++ ++ /* Restore the masterKey */ ++ if (qemuDomainMasterKeyReadFile(priv) < 0) ++ goto error; ++ ++ virNWFilterReadLockFilterUpdates(); ++ ++ VIR_DEBUG("Reconnect monitor to %p '%s'", obj, obj->def->name); ++ ++ /* XXX check PID liveliness & EXE path */ ++ if (qemuConnectMonitor(driver, obj, QEMU_ASYNC_JOB_NONE, NULL) < 0) ++ goto error; ++ ++ if (qemuHostdevUpdateActiveDomainDevices(driver, obj->def) < 0) ++ goto error; ++ ++ if (qemuConnectCgroup(driver, obj) < 0) ++ goto error; ++ ++ if (qemuDomainPerfRestart(obj) < 0) ++ goto error; ++ ++ /* XXX: Need to change as long as lock is introduced for ++ * qemu_driver->sharedDevices. ++ */ ++ for (i = 0; i < obj->def->ndisks; i++) { ++ virDomainDeviceDef dev; ++ ++ if (virStorageTranslateDiskSourcePool(conn, obj->def->disks[i]) < 0) ++ goto error; ++ ++ /* XXX we should be able to restore all data from XML in the future. ++ * This should be the only place that calls qemuDomainDetermineDiskChain ++ * with @report_broken == false to guarantee best-effort domain ++ * reconnect */ ++ if (qemuDomainDetermineDiskChain(driver, obj, obj->def->disks[i], ++ true, false) < 0) ++ goto error; ++ ++ dev.type = VIR_DOMAIN_DEVICE_DISK; ++ dev.data.disk = obj->def->disks[i]; ++ if (qemuAddSharedDevice(driver, &dev, obj->def->name) < 0) ++ goto error; ++ } ++ ++ if (qemuProcessUpdateState(driver, obj) < 0) ++ goto error; ++ ++ state = virDomainObjGetState(obj, &reason); ++ if (state == VIR_DOMAIN_SHUTOFF || ++ (state == VIR_DOMAIN_PAUSED && ++ reason == VIR_DOMAIN_PAUSED_STARTING_UP)) { ++ VIR_DEBUG("Domain '%s' wasn't fully started yet, killing it", ++ obj->def->name); ++ goto error; ++ } ++ ++ /* If upgrading from old libvirtd we won't have found any ++ * caps in the domain status, so re-query them ++ */ ++ if (!priv->qemuCaps && ++ !(priv->qemuCaps = virQEMUCapsCacheLookupCopy(caps, ++ driver->qemuCapsCache, ++ obj->def->emulator, ++ obj->def->os.machine))) ++ goto error; ++ ++ /* In case the domain shutdown while we were not running, ++ * we need to finish the shutdown process. And we need to do it after ++ * we have virQEMUCaps filled in. ++ */ ++ if (state == VIR_DOMAIN_SHUTDOWN || ++ (state == VIR_DOMAIN_PAUSED && ++ reason == VIR_DOMAIN_PAUSED_SHUTTING_DOWN)) { ++ VIR_DEBUG("Finishing shutdown sequence for domain %s", ++ obj->def->name); ++ qemuProcessShutdownOrReboot(driver, obj); ++ goto cleanup; ++ } ++ ++ if (qemuProcessBuildDestroyHugepagesPath(driver, obj, true) < 0) ++ goto error; ++ ++ if ((qemuDomainAssignAddresses(obj->def, priv->qemuCaps, ++ driver, obj, false)) < 0) { ++ goto error; ++ } ++ ++ /* if domain requests security driver we haven't loaded, report error, but ++ * do not kill the domain ++ */ ++ ignore_value(qemuSecurityCheckAllLabel(driver->securityManager, ++ obj->def)); ++ ++ if (qemuDomainRefreshVcpuInfo(driver, obj, QEMU_ASYNC_JOB_NONE, true) < 0) ++ goto error; ++ ++ qemuDomainVcpuPersistOrder(obj->def); ++ ++ if (qemuSecurityReserveLabel(driver->securityManager, obj->def, obj->pid) < 0) ++ goto error; ++ ++ qemuProcessNotifyNets(obj->def); ++ ++ if (qemuProcessFiltersInstantiate(obj->def)) ++ goto error; ++ ++ if (qemuProcessRefreshDisks(driver, obj, QEMU_ASYNC_JOB_NONE) < 0) ++ goto error; ++ ++ if (qemuBlockNodeNamesDetect(driver, obj) < 0) ++ goto error; ++ ++ if (qemuRefreshVirtioChannelState(driver, obj, QEMU_ASYNC_JOB_NONE) < 0) ++ goto error; ++ ++ /* If querying of guest's RTC failed, report error, but do not kill the domain. */ ++ qemuRefreshRTC(driver, obj); ++ ++ if (qemuProcessRefreshBalloonState(driver, obj, QEMU_ASYNC_JOB_NONE) < 0) ++ goto error; ++ ++ if (qemuProcessRecoverJob(driver, obj, conn, &oldjob, &stopFlags) < 0) ++ goto error; ++ ++ if (qemuProcessUpdateDevices(driver, obj) < 0) ++ goto error; ++ ++ qemuProcessReconnectCheckMemAliasOrderMismatch(obj); ++ ++ if (qemuConnectAgent(driver, obj) < 0) ++ goto error; ++ ++ /* update domain state XML with possibly updated state in virDomainObj */ ++ if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, obj, driver->caps) < 0) ++ goto error; ++ ++ /* Run an hook to allow admins to do some magic */ ++ if (virHookPresent(VIR_HOOK_DRIVER_QEMU)) { ++ char *xml = qemuDomainDefFormatXML(driver, obj->def, 0); ++ int hookret; ++ ++ hookret = virHookCall(VIR_HOOK_DRIVER_QEMU, obj->def->name, ++ VIR_HOOK_QEMU_OP_RECONNECT, VIR_HOOK_SUBOP_BEGIN, ++ NULL, xml, NULL); ++ VIR_FREE(xml); ++ ++ /* ++ * If the script raised an error abort the launch ++ */ ++ if (hookret < 0) ++ goto error; ++ } ++ ++ if (virAtomicIntInc(&driver->nactive) == 1 && driver->inhibitCallback) ++ driver->inhibitCallback(true, driver->inhibitOpaque); ++ ++ cleanup: ++ if (jobStarted) ++ qemuDomainObjEndJob(driver, obj); ++ if (!virDomainObjIsActive(obj)) ++ qemuDomainRemoveInactive(driver, obj); ++ virDomainObjEndAPI(&obj); ++ virObjectUnref(conn); ++ virObjectUnref(cfg); ++ virObjectUnref(caps); ++ virNWFilterUnlockFilterUpdates(); ++ return; ++ ++ error: ++ if (virDomainObjIsActive(obj)) { ++ /* We can't get the monitor back, so must kill the VM ++ * to remove danger of it ending up running twice if ++ * user tries to start it again later ++ */ ++ if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_NO_SHUTDOWN)) { ++ /* If we couldn't get the monitor and qemu supports ++ * no-shutdown, we can safely say that the domain ++ * crashed ... */ ++ state = VIR_DOMAIN_SHUTOFF_CRASHED; ++ } else { ++ /* ... but if it doesn't we can't say what the state ++ * really is and FAILED means "failed to start" */ ++ state = VIR_DOMAIN_SHUTOFF_UNKNOWN; ++ } ++ /* If BeginJob failed, we jumped here without a job, let's hope another ++ * thread didn't have a chance to start playing with the domain yet ++ * (it's all we can do anyway). ++ */ ++ qemuProcessStop(driver, obj, state, QEMU_ASYNC_JOB_NONE, stopFlags); ++ } ++ goto cleanup; ++} ++ ++static int ++qemuProcessReconnectHelper(virDomainObjPtr obj, ++ void *opaque) ++{ ++ virThread thread; ++ struct qemuProcessReconnectData *src = opaque; ++ struct qemuProcessReconnectData *data; ++ ++ /* If the VM was inactive, we don't need to reconnect */ ++ if (!obj->pid) ++ return 0; ++ ++ if (VIR_ALLOC(data) < 0) ++ return -1; ++ ++ memcpy(data, src, sizeof(*data)); ++ data->obj = obj; ++ ++ /* this lock and reference will be eventually transferred to the thread ++ * that handles the reconnect */ ++ virObjectLock(obj); ++ virObjectRef(obj); ++ ++ /* Since we close the connection later on, we have to make sure that the ++ * threads we start see a valid connection throughout their lifetime. We ++ * simply increase the reference counter here. ++ */ ++ virObjectRef(data->conn); ++ ++ if (virThreadCreate(&thread, false, qemuProcessReconnect, data) < 0) { ++ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", ++ _("Could not create thread. QEMU initialization " ++ "might be incomplete")); ++ /* We can't spawn a thread and thus connect to monitor. Kill qemu. ++ * It's safe to call qemuProcessStop without a job here since there ++ * is no thread that could be doing anything else with the same domain ++ * object. ++ */ ++ qemuProcessStop(src->driver, obj, VIR_DOMAIN_SHUTOFF_FAILED, ++ QEMU_ASYNC_JOB_NONE, 0); ++ qemuDomainRemoveInactive(src->driver, obj); ++ ++ virDomainObjEndAPI(&obj); ++ virObjectUnref(data->conn); ++ VIR_FREE(data); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++/** ++ * qemuProcessReconnectAll ++ * ++ * Try to re-open the resources for live VMs that we care ++ * about. ++ */ ++void ++qemuProcessReconnectAll(virConnectPtr conn, virQEMUDriverPtr driver) ++{ ++ struct qemuProcessReconnectData data = {.conn = conn, .driver = driver}; ++ virDomainObjListForEach(driver->domains, qemuProcessReconnectHelper, &data); ++} +-- +2.13.2 + diff --git a/SOURCES/libvirt-qemu-Rename-qemuProcessUpdateLiveGuestCPU.patch b/SOURCES/libvirt-qemu-Rename-qemuProcessUpdateLiveGuestCPU.patch new file mode 100644 index 0000000..b4d8e50 --- /dev/null +++ b/SOURCES/libvirt-qemu-Rename-qemuProcessUpdateLiveGuestCPU.patch @@ -0,0 +1,47 @@ +From dfc345ac7bd7bc87c297fc9887453e8f3035191c Mon Sep 17 00:00:00 2001 +Message-Id: +From: Jiri Denemark +Date: Tue, 11 Jul 2017 13:30:09 +0200 +Subject: [PATCH] qemu: Rename qemuProcessUpdateLiveGuestCPU + +In addition to updating a guest CPU definition the function verifies +that all required features are provided to the guest. Let's make it +obvious by calling it qemuProcessUpdateAndVerifyCPU. + +Signed-off-by: Jiri Denemark +Reviewed-by: Pavel Hrdina +(cherry picked from commit e6ed55e4e9c9ec21ca87573b69225d2fafc54272) + +https://bugzilla.redhat.com/show_bug.cgi?id=1470582 + +Signed-off-by: Jiri Denemark +Reviewed-by: Pavel Hrdina +--- + src/qemu/qemu_process.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c +index 3f7a9f4c02..1e7724e784 100644 +--- a/src/qemu/qemu_process.c ++++ b/src/qemu/qemu_process.c +@@ -3971,7 +3971,7 @@ qemuProcessVerifyCPU(virDomainObjPtr vm, + + + static int +-qemuProcessUpdateLiveGuestCPU(virQEMUDriverPtr driver, ++qemuProcessUpdateAndVerifyCPU(virQEMUDriverPtr driver, + virDomainObjPtr vm, + qemuDomainAsyncJob asyncJob) + { +@@ -5875,7 +5875,7 @@ qemuProcessLaunch(virConnectPtr conn, + goto cleanup; + + VIR_DEBUG("Verifying and updating provided guest CPU"); +- if (qemuProcessUpdateLiveGuestCPU(driver, vm, asyncJob) < 0) ++ if (qemuProcessUpdateAndVerifyCPU(driver, vm, asyncJob) < 0) + goto cleanup; + + VIR_DEBUG("Setting up post-init cgroup restrictions"); +-- +2.13.2 + diff --git a/SOURCES/libvirt-qemu-Update-host-model-CPUs-on-reconnect.patch b/SOURCES/libvirt-qemu-Update-host-model-CPUs-on-reconnect.patch new file mode 100644 index 0000000..9e5a0e9 --- /dev/null +++ b/SOURCES/libvirt-qemu-Update-host-model-CPUs-on-reconnect.patch @@ -0,0 +1,94 @@ +From 9c2457dd94cf148dce04ee5fd3997003ca03a642 Mon Sep 17 00:00:00 2001 +Message-Id: <9c2457dd94cf148dce04ee5fd3997003ca03a642@dist-git> +From: Jiri Denemark +Date: Tue, 11 Jul 2017 14:16:40 +0200 +Subject: [PATCH] qemu: Update host-model CPUs on reconnect + +When libvirt starts a new QEMU domain, it replaces host-model CPUs with +the appropriate custom CPU definition. However, when reconnecting to a +domain started by older libvirt (< 2.3), the domain would still have a +host-model CPU in its active definition. + +https://bugzilla.redhat.com/show_bug.cgi?id=1463957 + +Signed-off-by: Jiri Denemark +Reviewed-by: Pavel Hrdina +(cherry picked from commit 7cf22b4879e819dee42e0a058f7ed149dc9d639a) + +https://bugzilla.redhat.com/show_bug.cgi?id=1470582 + +Signed-off-by: Jiri Denemark +Reviewed-by: Pavel Hrdina +--- + src/qemu/qemu_process.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 48 insertions(+) + +diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c +index e6f56dc484..8fe9ef36d7 100644 +--- a/src/qemu/qemu_process.c ++++ b/src/qemu/qemu_process.c +@@ -3718,6 +3718,30 @@ qemuProcessUpdateAndVerifyCPU(virQEMUDriverPtr driver, + + + static int ++qemuProcessUpdateCPU(virQEMUDriverPtr driver, ++ virDomainObjPtr vm, ++ qemuDomainAsyncJob asyncJob) ++{ ++ virCPUDataPtr cpu = NULL; ++ virCPUDataPtr disabled = NULL; ++ int ret = -1; ++ ++ if (qemuProcessFetchGuestCPU(driver, vm, asyncJob, &cpu, &disabled) < 0) ++ goto cleanup; ++ ++ if (qemuProcessUpdateLiveGuestCPU(vm, cpu, disabled) < 0) ++ goto cleanup; ++ ++ ret = 0; ++ ++ cleanup: ++ virCPUDataFree(cpu); ++ virCPUDataFree(disabled); ++ return ret; ++} ++ ++ ++static int + qemuPrepareNVRAM(virQEMUDriverConfigPtr cfg, + virDomainObjPtr vm) + { +@@ -6796,6 +6820,30 @@ qemuProcessReconnect(void *opaque) + ignore_value(qemuSecurityCheckAllLabel(driver->securityManager, + obj->def)); + ++ /* If the domain with a host-model CPU was started by an old libvirt ++ * (< 2.3) which didn't replace the CPU with a custom one, let's do it now ++ * since the rest of our code does not really expect a host-model CPU in a ++ * running domain. ++ */ ++ if (virQEMUCapsGuestIsNative(caps->host.arch, obj->def->os.arch) && ++ caps->host.cpu && ++ obj->def->cpu && ++ obj->def->cpu->mode == VIR_CPU_MODE_HOST_MODEL) { ++ virCPUDefPtr host; ++ ++ if (!(host = virCPUCopyMigratable(caps->host.cpu->arch, caps->host.cpu))) ++ goto error; ++ ++ if (virCPUUpdate(obj->def->os.arch, obj->def->cpu, host) < 0) { ++ virCPUDefFree(host); ++ goto error; ++ } ++ virCPUDefFree(host); ++ ++ if (qemuProcessUpdateCPU(driver, obj, QEMU_ASYNC_JOB_NONE) < 0) ++ goto error; ++ } ++ + if (qemuDomainRefreshVcpuInfo(driver, obj, QEMU_ASYNC_JOB_NONE, true) < 0) + goto error; + +-- +2.13.2 + diff --git a/SOURCES/libvirt-qemuDomainBuildNamespace-Handle-special-file-mount-points.patch b/SOURCES/libvirt-qemuDomainBuildNamespace-Handle-special-file-mount-points.patch new file mode 100644 index 0000000..0191509 --- /dev/null +++ b/SOURCES/libvirt-qemuDomainBuildNamespace-Handle-special-file-mount-points.patch @@ -0,0 +1,54 @@ +From 4f54b2f401e4e1a443f6c889cbd2373aaa249d28 Mon Sep 17 00:00:00 2001 +Message-Id: <4f54b2f401e4e1a443f6c889cbd2373aaa249d28@dist-git> +From: Michal Privoznik +Date: Mon, 17 Jul 2017 14:48:21 +0200 +Subject: [PATCH] qemuDomainBuildNamespace: Handle special file mount points + +RHEL-7.5: https://bugzilla.redhat.com/show_bug.cgi?id=1459592 +RHEL-7.4.z: https://bugzilla.redhat.com/show_bug.cgi?id=1471660 + +In 290a00e41d I've tried to fix the process of building a +qemu namespace when dealing with file mount points. What I +haven't realized then is that we might be dealing not with just +regular files but also special files (like sockets). Indeed, try +the following: + +1) socat unix-listen:/tmp/soket stdio +2) touch /dev/socket +3) mount --bind /tmp/socket /dev/socket +4) virsh start anyDomain + +Problem with my previous approach is that I wasn't creating the +temporary location (where mount points under /dev are moved) for +anything but directories and regular files. + +Signed-off-by: Michal Privoznik +Reviewed-by: John Ferlan +(cherry picked from commit 7154917908d9f712a950a2716c4687e57ccb74e7) +Signed-off-by: Michal Privoznik +Signed-off-by: Jiri Denemark +--- + src/qemu/qemu_domain.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c +index 6ccc9f6f5b..c9c668b892 100644 +--- a/src/qemu/qemu_domain.c ++++ b/src/qemu/qemu_domain.c +@@ -8305,9 +8305,11 @@ qemuDomainBuildNamespace(virQEMUDriverConfigPtr cfg, + goto cleanup; + } + +- /* At this point, devMountsPath is either a regular file or a directory. */ ++ /* At this point, devMountsPath is either: ++ * a file (regular or special), or ++ * a directory. */ + if ((S_ISDIR(sb.st_mode) && virFileMakePath(devMountsSavePath[i]) < 0) || +- (S_ISREG(sb.st_mode) && virFileTouch(devMountsSavePath[i], sb.st_mode) < 0)) { ++ (!S_ISDIR(sb.st_mode) && virFileTouch(devMountsSavePath[i], sb.st_mode) < 0)) { + virReportSystemError(errno, + _("Failed to create %s"), + devMountsSavePath[i]); +-- +2.13.3 + diff --git a/SPECS/libvirt.spec b/SPECS/libvirt.spec index 2ba76d4..6913178 100644 --- a/SPECS/libvirt.spec +++ b/SPECS/libvirt.spec @@ -228,7 +228,7 @@ Summary: Library providing a simple virtualization API Name: libvirt Version: 3.2.0 -Release: 14%{?dist}%{?extra_release} +Release: 14%{?dist}.2%{?extra_release} License: LGPLv2+ Group: Development/Libraries BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root @@ -470,6 +470,17 @@ Patch227: libvirt-qemu-snapshot-Load-data-necessary-for-relative-block-commit-to Patch228: libvirt-util-storage-Make-backingFormat-optional-in-virStorageFileGetMetadataInternal.patch Patch229: libvirt-qemu-Change-coalesce-settings-on-hotplug-when-they-are-different.patch Patch230: libvirt-qemu-Do-not-skip-virCPUUpdateLive-if-priv-origCPU-is-set.patch +Patch231: libvirt-qemu-Don-t-update-CPU-when-checking-ABI-stability.patch +Patch232: libvirt-cpu_x86-Properly-disable-unknown-CPU-features.patch +Patch233: libvirt-qemu-Add-qemuProcessFetchGuestCPU.patch +Patch234: libvirt-qemu-Add-qemuProcessVerifyCPU.patch +Patch235: libvirt-qemu-Rename-qemuProcessUpdateLiveGuestCPU.patch +Patch236: libvirt-qemu-Add-qemuProcessUpdateLiveGuestCPU.patch +Patch237: libvirt-qemu-Export-virQEMUCapsGuestIsNative.patch +Patch238: libvirt-qemu-Move-qemuProcessReconnect-to-the-end-of-qemu_process.c.patch +Patch239: libvirt-qemu-Update-host-model-CPUs-on-reconnect.patch +Patch240: libvirt-qemu-Fix-qemuDomainGetBlockInfo-allocation-value-setting.patch +Patch241: libvirt-qemuDomainBuildNamespace-Handle-special-file-mount-points.patch Requires: libvirt-daemon = %{version}-%{release} Requires: libvirt-daemon-config-network = %{version}-%{release} @@ -2318,6 +2329,21 @@ exit 0 %changelog +* Tue Jul 18 2017 Jiri Denemark - 3.2.0-14.el7_4.2 +- qemu: Fix qemuDomainGetBlockInfo allocation value setting (rhbz#1470127) +- qemuDomainBuildNamespace: Handle special file mount points (rhbz#1471660) + +* Thu Jul 13 2017 Jiri Denemark - 3.2.0-14.el7_4.1 +- qemu: Don't update CPU when checking ABI stability (rhbz#1470582) +- cpu_x86: Properly disable unknown CPU features (rhbz#1470582) +- qemu: Add qemuProcessFetchGuestCPU (rhbz#1470582) +- qemu: Add qemuProcessVerifyCPU (rhbz#1470582) +- qemu: Rename qemuProcessUpdateLiveGuestCPU (rhbz#1470582) +- qemu: Add qemuProcessUpdateLiveGuestCPU (rhbz#1470582) +- qemu: Export virQEMUCapsGuestIsNative (rhbz#1470582) +- qemu: Move qemuProcessReconnect to the end of qemu_process.c (rhbz#1470582) +- qemu: Update host-model CPUs on reconnect (rhbz#1470582) + * Wed Jun 21 2017 Jiri Denemark - 3.2.0-14 - qemu: Do not skip virCPUUpdateLive if priv->origCPU is set (rhbz#1441662)