From: Andrew Jones <drjo...@redhat.com>

When updating the stolen time we should always read the current
stolen time from the user provided memory, not from a kernel
cache. If we use a cache then we'll end up resetting stolen time
to zero on the first update after migration.

Signed-off-by: Andrew Jones <drjo...@redhat.com>
Signed-off-by: Marc Zyngier <m...@kernel.org>
Link: https://lore.kernel.org/r/20200804170604.42662-5-drjo...@redhat.com
---
 arch/arm64/include/asm/kvm_host.h |  1 -
 arch/arm64/kvm/pvtime.c           | 23 +++++++++--------------
 include/linux/kvm_host.h          | 20 ++++++++++++++++++++
 3 files changed, 29 insertions(+), 15 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_host.h 
b/arch/arm64/include/asm/kvm_host.h
index 65568b23868a..dd9c3b25aa1e 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -368,7 +368,6 @@ struct kvm_vcpu_arch {
 
        /* Guest PV state */
        struct {
-               u64 steal;
                u64 last_steal;
                gpa_t base;
        } steal;
diff --git a/arch/arm64/kvm/pvtime.c b/arch/arm64/kvm/pvtime.c
index 241ded7ee0ad..75234321d896 100644
--- a/arch/arm64/kvm/pvtime.c
+++ b/arch/arm64/kvm/pvtime.c
@@ -13,26 +13,22 @@
 void kvm_update_stolen_time(struct kvm_vcpu *vcpu)
 {
        struct kvm *kvm = vcpu->kvm;
+       u64 base = vcpu->arch.steal.base;
        u64 last_steal = vcpu->arch.steal.last_steal;
-       u64 steal;
-       __le64 steal_le;
-       u64 offset;
+       u64 offset = offsetof(struct pvclock_vcpu_stolen_time, stolen_time);
+       u64 steal = 0;
        int idx;
-       u64 base = vcpu->arch.steal.base;
 
        if (base == GPA_INVALID)
                return;
 
-       /* Let's do the local bookkeeping */
-       steal = vcpu->arch.steal.steal;
-       vcpu->arch.steal.last_steal = READ_ONCE(current->sched_info.run_delay);
-       steal += vcpu->arch.steal.last_steal - last_steal;
-       vcpu->arch.steal.steal = steal;
-
-       steal_le = cpu_to_le64(steal);
        idx = srcu_read_lock(&kvm->srcu);
-       offset = offsetof(struct pvclock_vcpu_stolen_time, stolen_time);
-       kvm_put_guest(kvm, base + offset, steal_le);
+       if (!kvm_get_guest(kvm, base + offset, steal)) {
+               steal = le64_to_cpu(steal);
+               vcpu->arch.steal.last_steal = 
READ_ONCE(current->sched_info.run_delay);
+               steal += vcpu->arch.steal.last_steal - last_steal;
+               kvm_put_guest(kvm, base + offset, cpu_to_le64(steal));
+       }
        srcu_read_unlock(&kvm->srcu, idx);
 }
 
@@ -66,7 +62,6 @@ gpa_t kvm_init_stolen_time(struct kvm_vcpu *vcpu)
         * Start counting stolen time from the time the guest requests
         * the feature enabled.
         */
-       vcpu->arch.steal.steal = 0;
        vcpu->arch.steal.last_steal = current->sched_info.run_delay;
 
        idx = srcu_read_lock(&kvm->srcu);
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index 84371fb06209..05e3c2fb3ef7 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -749,6 +749,26 @@ int kvm_write_guest_offset_cached(struct kvm *kvm, struct 
gfn_to_hva_cache *ghc,
 int kvm_gfn_to_hva_cache_init(struct kvm *kvm, struct gfn_to_hva_cache *ghc,
                              gpa_t gpa, unsigned long len);
 
+#define __kvm_get_guest(kvm, gfn, offset, v)                           \
+({                                                                     \
+       unsigned long __addr = gfn_to_hva(kvm, gfn);                    \
+       typeof(v) __user *__uaddr = (typeof(__uaddr))(__addr + offset); \
+       int __ret = -EFAULT;                                            \
+                                                                       \
+       if (!kvm_is_error_hva(__addr))                                  \
+               __ret = get_user(v, __uaddr);                           \
+       __ret;                                                          \
+})
+
+#define kvm_get_guest(kvm, gpa, v)                                     \
+({                                                                     \
+       gpa_t __gpa = gpa;                                              \
+       struct kvm *__kvm = kvm;                                        \
+                                                                       \
+       __kvm_get_guest(__kvm, __gpa >> PAGE_SHIFT,                     \
+                       offset_in_page(__gpa), v);                      \
+})
+
 #define __kvm_put_guest(kvm, gfn, offset, v)                           \
 ({                                                                     \
        unsigned long __addr = gfn_to_hva(kvm, gfn);                    \
-- 
2.27.0

_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

Reply via email to