]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
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 7f850dfb40861cce8fb0ae2377653750bee41aa0..b5e7aea22110675a47ddaf58de496afd7aa01c07 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 3e434dc339fb500ad1a81649f19aa1645a64fed9..55257c2a1610ffbb5ff8bf5f7df420dae4036e62 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 8f874a96431393eade801da1ddbc727cbb6eb0c1..73ded328f9dcebf6721a4d840deb81285fe66633 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 3ca3db020e0e3bb588c45624241504af87634471..76de36e56cdfe828e17b46f88a6d60f14a7f0bc2 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 b4295474519f820a734fe335f9666f173a5b2153..d8ce30b893d97fbbfd53f2af3fbb990a1bcf80e6 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