KVM: Store immutable gfn_to_pfn_cache properties
authorMichal Luczaj <mhal@rbox.co>
Thu, 13 Oct 2022 21:12:24 +0000 (21:12 +0000)
committerDavid Woodhouse <dwmw@amazon.co.uk>
Wed, 30 Nov 2022 19:25:23 +0000 (19:25 +0000)
Move the assignment of immutable properties @kvm, @vcpu, and @usage to
the initializer.  Make _activate() and _deactivate() use stored values.

Note, @len is also effectively immutable for most cases, but not in the
case of the Xen runstate cache, which may be split across two pages and
the length of the first segment will depend on its address.

Suggested-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Michal Luczaj <mhal@rbox.co>
[sean: handle @len in a separate patch]
Signed-off-by: Sean Christopherson <seanjc@google.com>
[dwmw2: acknowledge that @len can actually change for some use cases]
Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
arch/x86/kvm/x86.c
arch/x86/kvm/xen.c
include/linux/kvm_host.h
include/linux/kvm_types.h
virt/kvm/pfncache.c

index 7f850df..b5e7aea 100644 (file)
@@ -2317,13 +2317,11 @@ static void kvm_write_system_time(struct kvm_vcpu *vcpu, gpa_t system_time,
        kvm_make_request(KVM_REQ_GLOBAL_CLOCK_UPDATE, vcpu);
 
        /* we verify if the enable bit is set... */
-       if (system_time & 1) {
-               kvm_gpc_activate(vcpu->kvm, &vcpu->arch.pv_time, vcpu,
-                                KVM_HOST_USES_PFN, system_time & ~1ULL,
+       if (system_time & 1)
+               kvm_gpc_activate(&vcpu->arch.pv_time, system_time & ~1ULL,
                                 sizeof(struct pvclock_vcpu_time_info));
-       } else {
-               kvm_gpc_deactivate(vcpu->kvm, &vcpu->arch.pv_time);
-       }
+       else
+               kvm_gpc_deactivate(&vcpu->arch.pv_time);
 
        return;
 }
@@ -3391,7 +3389,7 @@ static int kvm_pv_enable_async_pf_int(struct kvm_vcpu *vcpu, u64 data)
 
 static void kvmclock_reset(struct kvm_vcpu *vcpu)
 {
-       kvm_gpc_deactivate(vcpu->kvm, &vcpu->arch.pv_time);
+       kvm_gpc_deactivate(&vcpu->arch.pv_time);
        vcpu->arch.time = 0;
 }
 
@@ -11542,7 +11540,7 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)
        vcpu->arch.regs_avail = ~0;
        vcpu->arch.regs_dirty = ~0;
 
-       kvm_gpc_init(&vcpu->arch.pv_time);
+       kvm_gpc_init(&vcpu->arch.pv_time, vcpu->kvm, vcpu, KVM_HOST_USES_PFN);
 
        if (!irqchip_in_kernel(vcpu->kvm) || kvm_vcpu_is_reset_bsp(vcpu))
                vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE;
index 3e434dc..55257c2 100644 (file)
@@ -42,13 +42,12 @@ static int kvm_xen_shared_info_init(struct kvm *kvm, gfn_t gfn)
        int idx = srcu_read_lock(&kvm->srcu);
 
        if (gfn == GPA_INVALID) {
-               kvm_gpc_deactivate(kvm, gpc);
+               kvm_gpc_deactivate(gpc);
                goto out;
        }
 
        do {
-               ret = kvm_gpc_activate(kvm, gpc, NULL, KVM_HOST_USES_PFN, gpa,
-                                      PAGE_SIZE);
+               ret = kvm_gpc_activate(gpc, gpa, PAGE_SIZE);
                if (ret)
                        goto out;
 
@@ -323,8 +322,8 @@ static void kvm_xen_update_runstate_guest(struct kvm_vcpu *v, bool atomic)
                         * to the second page now because the guest changed to
                         * 64-bit mode, the second GPC won't have been set up.
                         */
-                       if (kvm_gpc_activate(v->kvm, gpc2, NULL, KVM_HOST_USES_PFN,
-                                            gpc1->gpa + user_len1, user_len2))
+                       if (kvm_gpc_activate(gpc2, gpc1->gpa + user_len1,
+                                            user_len2))
                                return;
 
                        /*
@@ -711,15 +710,13 @@ int kvm_xen_vcpu_set_attr(struct kvm_vcpu *vcpu, struct kvm_xen_vcpu_attr *data)
                             offsetof(struct compat_vcpu_info, time));
 
                if (data->u.gpa == GPA_INVALID) {
-                       kvm_gpc_deactivate(vcpu->kvm, &vcpu->arch.xen.vcpu_info_cache);
+                       kvm_gpc_deactivate(&vcpu->arch.xen.vcpu_info_cache);
                        r = 0;
                        break;
                }
 
-               r = kvm_gpc_activate(vcpu->kvm,
-                                    &vcpu->arch.xen.vcpu_info_cache, NULL,
-                                    KVM_HOST_USES_PFN, data->u.gpa,
-                                    sizeof(struct vcpu_info));
+               r = kvm_gpc_activate(&vcpu->arch.xen.vcpu_info_cache,
+                                    data->u.gpa, sizeof(struct vcpu_info));
                if (!r)
                        kvm_make_request(KVM_REQ_CLOCK_UPDATE, vcpu);
 
@@ -727,15 +724,13 @@ int kvm_xen_vcpu_set_attr(struct kvm_vcpu *vcpu, struct kvm_xen_vcpu_attr *data)
 
        case KVM_XEN_VCPU_ATTR_TYPE_VCPU_TIME_INFO:
                if (data->u.gpa == GPA_INVALID) {
-                       kvm_gpc_deactivate(vcpu->kvm,
-                                          &vcpu->arch.xen.vcpu_time_info_cache);
+                       kvm_gpc_deactivate(&vcpu->arch.xen.vcpu_time_info_cache);
                        r = 0;
                        break;
                }
 
-               r = kvm_gpc_activate(vcpu->kvm,
-                                    &vcpu->arch.xen.vcpu_time_info_cache,
-                                    NULL, KVM_HOST_USES_PFN, data->u.gpa,
+               r = kvm_gpc_activate(&vcpu->arch.xen.vcpu_time_info_cache,
+                                    data->u.gpa,
                                     sizeof(struct pvclock_vcpu_time_info));
                if (!r)
                        kvm_make_request(KVM_REQ_CLOCK_UPDATE, vcpu);
@@ -751,10 +746,8 @@ int kvm_xen_vcpu_set_attr(struct kvm_vcpu *vcpu, struct kvm_xen_vcpu_attr *data)
                if (data->u.gpa == GPA_INVALID) {
                        r = 0;
                deactivate_out:
-                       kvm_gpc_deactivate(vcpu->kvm,
-                                          &vcpu->arch.xen.runstate_cache);
-                       kvm_gpc_deactivate(vcpu->kvm,
-                                          &vcpu->arch.xen.runstate2_cache);
+                       kvm_gpc_deactivate(&vcpu->arch.xen.runstate_cache);
+                       kvm_gpc_deactivate(&vcpu->arch.xen.runstate2_cache);
                        break;
                }
 
@@ -770,20 +763,18 @@ int kvm_xen_vcpu_set_attr(struct kvm_vcpu *vcpu, struct kvm_xen_vcpu_attr *data)
 
                /* How much fits in the (first) page? */
                sz1 = PAGE_SIZE - (data->u.gpa & ~PAGE_MASK);
-               r = kvm_gpc_activate(vcpu->kvm, &vcpu->arch.xen.runstate_cache,
-                                    NULL, KVM_HOST_USES_PFN, data->u.gpa, sz1);
+               r = kvm_gpc_activate(&vcpu->arch.xen.runstate_cache,
+                                    data->u.gpa, sz1);
                if (r)
                        goto deactivate_out;
 
                /* Either map the second page, or deactivate the second GPC */
                if (sz1 >= sz) {
-                       kvm_gpc_deactivate(vcpu->kvm,
-                                          &vcpu->arch.xen.runstate2_cache);
+                       kvm_gpc_deactivate(&vcpu->arch.xen.runstate2_cache);
                } else {
                        sz2 = sz - sz1;
                        BUG_ON((data->u.gpa + sz1) & ~PAGE_MASK);
-                       r = kvm_gpc_activate(vcpu->kvm, &vcpu->arch.xen.runstate2_cache,
-                                            NULL, KVM_HOST_USES_PFN,
+                       r = kvm_gpc_activate(&vcpu->arch.xen.runstate2_cache,
                                             data->u.gpa + sz1, sz2);
                        if (r)
                                goto deactivate_out;
@@ -2051,10 +2042,14 @@ void kvm_xen_init_vcpu(struct kvm_vcpu *vcpu)
 
        timer_setup(&vcpu->arch.xen.poll_timer, cancel_evtchn_poll, 0);
 
-       kvm_gpc_init(&vcpu->arch.xen.runstate_cache);
-       kvm_gpc_init(&vcpu->arch.xen.runstate2_cache);
-       kvm_gpc_init(&vcpu->arch.xen.vcpu_info_cache);
-       kvm_gpc_init(&vcpu->arch.xen.vcpu_time_info_cache);
+       kvm_gpc_init(&vcpu->arch.xen.runstate_cache, vcpu->kvm, NULL,
+                    KVM_HOST_USES_PFN);
+       kvm_gpc_init(&vcpu->arch.xen.runstate2_cache, vcpu->kvm, NULL,
+                    KVM_HOST_USES_PFN);
+       kvm_gpc_init(&vcpu->arch.xen.vcpu_info_cache, vcpu->kvm, NULL,
+                    KVM_HOST_USES_PFN);
+       kvm_gpc_init(&vcpu->arch.xen.vcpu_time_info_cache, vcpu->kvm, NULL,
+                    KVM_HOST_USES_PFN);
 }
 
 void kvm_xen_destroy_vcpu(struct kvm_vcpu *vcpu)
@@ -2062,10 +2057,10 @@ void kvm_xen_destroy_vcpu(struct kvm_vcpu *vcpu)
        if (kvm_xen_timer_enabled(vcpu))
                kvm_xen_stop_timer(vcpu);
 
-       kvm_gpc_deactivate(vcpu->kvm, &vcpu->arch.xen.runstate_cache);
-       kvm_gpc_deactivate(vcpu->kvm, &vcpu->arch.xen.runstate2_cache);
-       kvm_gpc_deactivate(vcpu->kvm, &vcpu->arch.xen.vcpu_info_cache);
-       kvm_gpc_deactivate(vcpu->kvm, &vcpu->arch.xen.vcpu_time_info_cache);
+       kvm_gpc_deactivate(&vcpu->arch.xen.runstate_cache);
+       kvm_gpc_deactivate(&vcpu->arch.xen.runstate2_cache);
+       kvm_gpc_deactivate(&vcpu->arch.xen.vcpu_info_cache);
+       kvm_gpc_deactivate(&vcpu->arch.xen.vcpu_time_info_cache);
 
        del_timer_sync(&vcpu->arch.xen.poll_timer);
 }
@@ -2073,7 +2068,7 @@ void kvm_xen_destroy_vcpu(struct kvm_vcpu *vcpu)
 void kvm_xen_init_vm(struct kvm *kvm)
 {
        idr_init(&kvm->arch.xen.evtchn_ports);
-       kvm_gpc_init(&kvm->arch.xen.shinfo_cache);
+       kvm_gpc_init(&kvm->arch.xen.shinfo_cache, kvm, NULL, KVM_HOST_USES_PFN);
 }
 
 void kvm_xen_destroy_vm(struct kvm *kvm)
@@ -2081,7 +2076,7 @@ void kvm_xen_destroy_vm(struct kvm *kvm)
        struct evtchnfd *evtchnfd;
        int i;
 
-       kvm_gpc_deactivate(kvm, &kvm->arch.xen.shinfo_cache);
+       kvm_gpc_deactivate(&kvm->arch.xen.shinfo_cache);
 
        idr_for_each_entry(&kvm->arch.xen.evtchn_ports, evtchnfd, i) {
                if (!evtchnfd->deliver.port.port)
index 8f874a9..73ded32 100644 (file)
@@ -1260,18 +1260,7 @@ void kvm_vcpu_mark_page_dirty(struct kvm_vcpu *vcpu, gfn_t gfn);
  * kvm_gpc_init - initialize gfn_to_pfn_cache.
  *
  * @gpc:          struct gfn_to_pfn_cache object.
- *
- * This sets up a gfn_to_pfn_cache by initializing locks.  Note, the cache must
- * be zero-allocated (or zeroed by the caller before init).
- */
-void kvm_gpc_init(struct gfn_to_pfn_cache *gpc);
-
-/**
- * kvm_gpc_activate - prepare a cached kernel mapping and HPA for a given guest
- *                    physical address.
- *
  * @kvm:          pointer to kvm instance.
- * @gpc:          struct gfn_to_pfn_cache object.
  * @vcpu:         vCPU to be used for marking pages dirty and to be woken on
  *                invalidation.
  * @usage:        indicates if the resulting host physical PFN is used while
@@ -1280,20 +1269,31 @@ void kvm_gpc_init(struct gfn_to_pfn_cache *gpc);
  *                changes!---will also force @vcpu to exit the guest and
  *                refresh the cache); and/or if the PFN used directly
  *                by KVM (and thus needs a kernel virtual mapping).
+ *
+ * This sets up a gfn_to_pfn_cache by initializing locks and assigning the
+ * immutable attributes.  Note, the cache must be zero-allocated (or zeroed by
+ * the caller before init).
+ */
+void kvm_gpc_init(struct gfn_to_pfn_cache *gpc, struct kvm *kvm,
+                 struct kvm_vcpu *vcpu, enum pfn_cache_usage usage);
+
+/**
+ * kvm_gpc_activate - prepare a cached kernel mapping and HPA for a given guest
+ *                    physical address.
+ *
+ * @gpc:          struct gfn_to_pfn_cache object.
  * @gpa:          guest physical address to map.
  * @len:          sanity check; the range being access must fit a single page.
  *
  * @return:       0 for success.
  *                -EINVAL for a mapping which would cross a page boundary.
- *                 -EFAULT for an untranslatable guest physical address.
+ *                -EFAULT for an untranslatable guest physical address.
  *
- * This primes a gfn_to_pfn_cache and links it into the @kvm's list for
+ * This primes a gfn_to_pfn_cache and links it into the @gpc->kvm's list for
  * invalidations to be processed.  Callers are required to use kvm_gpc_check()
  * to ensure that the cache is valid before accessing the target page.
  */
-int kvm_gpc_activate(struct kvm *kvm, struct gfn_to_pfn_cache *gpc,
-                    struct kvm_vcpu *vcpu, enum pfn_cache_usage usage,
-                    gpa_t gpa, unsigned long len);
+int kvm_gpc_activate(struct gfn_to_pfn_cache *gpc, gpa_t gpa, unsigned long len);
 
 /**
  * kvm_gpc_check - check validity of a gfn_to_pfn_cache.
@@ -1352,13 +1352,12 @@ void kvm_gpc_unmap(struct kvm *kvm, struct gfn_to_pfn_cache *gpc);
 /**
  * kvm_gpc_deactivate - deactivate and unlink a gfn_to_pfn_cache.
  *
- * @kvm:          pointer to kvm instance.
  * @gpc:          struct gfn_to_pfn_cache object.
  *
- * This removes a cache from the @kvm's list to be processed on MMU notifier
+ * This removes a cache from the VM's list to be processed on MMU notifier
  * invocation.
  */
-void kvm_gpc_deactivate(struct kvm *kvm, struct gfn_to_pfn_cache *gpc);
+void kvm_gpc_deactivate(struct gfn_to_pfn_cache *gpc);
 
 void kvm_sigset_activate(struct kvm_vcpu *vcpu);
 void kvm_sigset_deactivate(struct kvm_vcpu *vcpu);
index 3ca3db0..76de36e 100644 (file)
@@ -67,6 +67,7 @@ struct gfn_to_pfn_cache {
        gpa_t gpa;
        unsigned long uhva;
        struct kvm_memory_slot *memslot;
+       struct kvm *kvm;
        struct kvm_vcpu *vcpu;
        struct list_head list;
        rwlock_t lock;
index b429547..d8ce30b 100644 (file)
@@ -362,25 +362,29 @@ void kvm_gpc_unmap(struct kvm *kvm, struct gfn_to_pfn_cache *gpc)
 }
 EXPORT_SYMBOL_GPL(kvm_gpc_unmap);
 
-void kvm_gpc_init(struct gfn_to_pfn_cache *gpc)
+void kvm_gpc_init(struct gfn_to_pfn_cache *gpc, struct kvm *kvm,
+                 struct kvm_vcpu *vcpu, enum pfn_cache_usage usage)
 {
+       WARN_ON_ONCE(!usage || (usage & KVM_GUEST_AND_HOST_USE_PFN) != usage);
+       WARN_ON_ONCE((usage & KVM_GUEST_USES_PFN) && !vcpu);
+
        rwlock_init(&gpc->lock);
        mutex_init(&gpc->refresh_lock);
+
+       gpc->kvm = kvm;
+       gpc->vcpu = vcpu;
+       gpc->usage = usage;
 }
 EXPORT_SYMBOL_GPL(kvm_gpc_init);
 
-int kvm_gpc_activate(struct kvm *kvm, struct gfn_to_pfn_cache *gpc,
-                    struct kvm_vcpu *vcpu, enum pfn_cache_usage usage,
-                    gpa_t gpa, unsigned long len)
+int kvm_gpc_activate(struct gfn_to_pfn_cache *gpc, gpa_t gpa, unsigned long len)
 {
-       WARN_ON_ONCE(!usage || (usage & KVM_GUEST_AND_HOST_USE_PFN) != usage);
+       struct kvm *kvm = gpc->kvm;
 
        if (!gpc->active) {
                gpc->khva = NULL;
                gpc->pfn = KVM_PFN_ERR_FAULT;
                gpc->uhva = KVM_HVA_ERR_BAD;
-               gpc->vcpu = vcpu;
-               gpc->usage = usage;
                gpc->valid = false;
 
                spin_lock(&kvm->gpc_lock);
@@ -400,8 +404,10 @@ int kvm_gpc_activate(struct kvm *kvm, struct gfn_to_pfn_cache *gpc,
 }
 EXPORT_SYMBOL_GPL(kvm_gpc_activate);
 
-void kvm_gpc_deactivate(struct kvm *kvm, struct gfn_to_pfn_cache *gpc)
+void kvm_gpc_deactivate(struct gfn_to_pfn_cache *gpc)
 {
+       struct kvm *kvm = gpc->kvm;
+
        if (gpc->active) {
                /*
                 * Deactivate the cache before removing it from the list, KVM