target/arm: Propagate errno when writing list
Before this change, write_kvmstate_to_list() and
write_list_to_kvmstate() tolerated even if it failed to access some
register, and returned a bool indicating whether one of the register
accesses failed. However, it does not make sen not to fail early as the
the callers check the returned value and fail early anyway.
So let write_kvmstate_to_list() and write_list_to_kvmstate() fail early
too. This will allow to propagate errno to the callers and log it if
appropriate.
Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
diff --git a/target/arm/kvm-stub.c b/target/arm/kvm-stub.c
index 965a486..f659afd 100644
--- a/target/arm/kvm-stub.c
+++ b/target/arm/kvm-stub.c
@@ -13,12 +13,12 @@
#include "cpu.h"
#include "kvm_arm.h"
-bool write_kvmstate_to_list(ARMCPU *cpu)
+int write_kvmstate_to_list(ARMCPU *cpu)
{
g_assert_not_reached();
}
-bool write_list_to_kvmstate(ARMCPU *cpu, int level)
+int write_list_to_kvmstate(ARMCPU *cpu, int level)
{
g_assert_not_reached();
}
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index f022c64..4cef0ef 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -501,12 +501,12 @@
}
assert(cpu->cpreg_array_len == arraylen);
- if (!write_kvmstate_to_list(cpu)) {
+ ret = write_kvmstate_to_list(cpu);
+ if (ret) {
/* Shouldn't happen unless kernel is inconsistent about
* what registers exist.
*/
fprintf(stderr, "Initial read of kernel register state failed\n");
- ret = -EINVAL;
goto out;
}
@@ -515,11 +515,10 @@
return ret;
}
-bool write_kvmstate_to_list(ARMCPU *cpu)
+int write_kvmstate_to_list(ARMCPU *cpu)
{
CPUState *cs = CPU(cpu);
int i;
- bool ok = true;
for (i = 0; i < cpu->cpreg_array_len; i++) {
struct kvm_one_reg r;
@@ -545,17 +544,16 @@
g_assert_not_reached();
}
if (ret) {
- ok = false;
+ return ret;
}
}
- return ok;
+ return 0;
}
-bool write_list_to_kvmstate(ARMCPU *cpu, int level)
+int write_list_to_kvmstate(ARMCPU *cpu, int level)
{
CPUState *cs = CPU(cpu);
int i;
- bool ok = true;
for (i = 0; i < cpu->cpreg_array_len; i++) {
struct kvm_one_reg r;
@@ -581,14 +579,10 @@
}
ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &r);
if (ret) {
- /* We might fail for "unknown register" and also for
- * "you tried to set a register which is constant with
- * a different value from what it actually contains".
- */
- ok = false;
+ return ret;
}
}
- return ok;
+ return 0;
}
void kvm_arm_cpu_pre_save(ARMCPU *cpu)
@@ -620,8 +614,9 @@
fprintf(stderr, "kvm_arm_vcpu_init failed: %s\n", strerror(-ret));
abort();
}
- if (!write_kvmstate_to_list(cpu)) {
- fprintf(stderr, "write_kvmstate_to_list failed\n");
+ ret = write_kvmstate_to_list(cpu);
+ if (ret < 0) {
+ fprintf(stderr, "write_kvmstate_to_list failed: %s\n", strerror(-ret));
abort();
}
/*
diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c
index 1197253..f787919 100644
--- a/target/arm/kvm64.c
+++ b/target/arm/kvm64.c
@@ -1202,8 +1202,9 @@
write_cpustate_to_list(cpu, true);
- if (!write_list_to_kvmstate(cpu, level)) {
- return -EINVAL;
+ ret = write_list_to_kvmstate(cpu, level);
+ if (ret) {
+ return ret;
}
/*
@@ -1418,8 +1419,9 @@
return ret;
}
- if (!write_kvmstate_to_list(cpu)) {
- return -EINVAL;
+ ret = write_kvmstate_to_list(cpu);
+ if (ret) {
+ return ret;
}
/* Note that it's OK to have registers which aren't in CPUState,
* so we can ignore a failure return here.
diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h
index 99017b6..05fce74 100644
--- a/target/arm/kvm_arm.h
+++ b/target/arm/kvm_arm.h
@@ -106,13 +106,9 @@
* This updates KVM's working data structures from TCG data or
* from incoming migration state.
*
- * Returns: true if all register values were updated correctly,
- * false if some register was unknown to the kernel or could not
- * be written (eg constant register with the wrong value).
- * Note that we do not stop early on failure -- we will attempt
- * writing all registers in the list.
+ * Returns: 0 if success, else < 0 error code
*/
-bool write_list_to_kvmstate(ARMCPU *cpu, int level);
+int write_list_to_kvmstate(ARMCPU *cpu, int level);
/**
* write_kvmstate_to_list:
@@ -123,12 +119,9 @@
* copy info from KVM's working data structures into TCG or
* for outbound migration.
*
- * Returns: true if all register values were read correctly,
- * false if some register was unknown or could not be read.
- * Note that we do not stop early on failure -- we will attempt
- * reading all registers in the list.
+ * Returns: 0 if success, else < 0 error code
*/
-bool write_kvmstate_to_list(ARMCPU *cpu);
+int write_kvmstate_to_list(ARMCPU *cpu);
/**
* kvm_arm_cpu_pre_save:
diff --git a/target/arm/machine.c b/target/arm/machine.c
index 5f26152..4b84c85 100644
--- a/target/arm/machine.c
+++ b/target/arm/machine.c
@@ -714,15 +714,16 @@
static int cpu_pre_save(void *opaque)
{
ARMCPU *cpu = opaque;
+ int ret;
if (!kvm_enabled()) {
pmu_op_start(&cpu->env);
}
if (kvm_enabled()) {
- if (!write_kvmstate_to_list(cpu)) {
- /* This should never fail */
- g_assert_not_reached();
+ ret = write_kvmstate_to_list(cpu);
+ if (ret) {
+ return ret;
}
/*
@@ -780,7 +781,7 @@
{
ARMCPU *cpu = opaque;
CPUARMState *env = &cpu->env;
- int i, v;
+ int i, v, ret;
/*
* Handle migration compatibility from old QEMU which didn't
@@ -824,7 +825,9 @@
}
if (kvm_enabled()) {
- if (!write_list_to_kvmstate(cpu, KVM_PUT_FULL_STATE)) {
+ ret = write_list_to_kvmstate(cpu, KVM_PUT_FULL_STATE);
+ if (ret) {
+ error_report("Failed to set KVM register: %s", strerror(-ret));
return -1;
}
/* Note that it's OK for the TCG side not to know about