diff mbox series

[v3,01/17] KVM: Fix arguments to kvm_{un,}map_gfn()

Message ID 20201214083905.2017260-2-dwmw2@infradead.org (mailing list archive)
State New, archived
Headers show
Series KVM: Add minimal support for Xen HVM guests | expand

Commit Message

David Woodhouse Dec. 14, 2020, 8:38 a.m. UTC
From: David Woodhouse <dwmw@amazon.co.uk>

It shouldn't take a vcpu.

Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
---
 arch/x86/kvm/x86.c       | 8 ++++----
 include/linux/kvm_host.h | 4 ++--
 virt/kvm/kvm_main.c      | 8 ++++----
 3 files changed, 10 insertions(+), 10 deletions(-)

Comments

Vitaly Kuznetsov Dec. 14, 2020, 9:13 p.m. UTC | #1
David Woodhouse <dwmw2@infradead.org> writes:

> From: David Woodhouse <dwmw@amazon.co.uk>
>
> It shouldn't take a vcpu.
>
> Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
> ---
>  arch/x86/kvm/x86.c       | 8 ++++----
>  include/linux/kvm_host.h | 4 ++--
>  virt/kvm/kvm_main.c      | 8 ++++----
>  3 files changed, 10 insertions(+), 10 deletions(-)
>
> diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
> index e545a8a613b1..c7f1ba21212e 100644
> --- a/arch/x86/kvm/x86.c
> +++ b/arch/x86/kvm/x86.c
> @@ -2957,7 +2957,7 @@ static void record_steal_time(struct kvm_vcpu *vcpu)
>  		return;
>  
>  	/* -EAGAIN is returned in atomic context so we can just return. */
> -	if (kvm_map_gfn(vcpu, vcpu->arch.st.msr_val >> PAGE_SHIFT,
> +	if (kvm_map_gfn(vcpu->kvm, vcpu->arch.st.msr_val >> PAGE_SHIFT,
>  			&map, &vcpu->arch.st.cache, false))
>  		return;
>  
> @@ -2992,7 +2992,7 @@ static void record_steal_time(struct kvm_vcpu *vcpu)
>  
>  	st->version += 1;
>  
> -	kvm_unmap_gfn(vcpu, &map, &vcpu->arch.st.cache, true, false);
> +	kvm_unmap_gfn(vcpu->kvm, &map, &vcpu->arch.st.cache, true, false);
>  }
>  
>  int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
> @@ -3981,7 +3981,7 @@ static void kvm_steal_time_set_preempted(struct kvm_vcpu *vcpu)
>  	if (vcpu->arch.st.preempted)
>  		return;
>  
> -	if (kvm_map_gfn(vcpu, vcpu->arch.st.msr_val >> PAGE_SHIFT, &map,
> +	if (kvm_map_gfn(vcpu->kvm, vcpu->arch.st.msr_val >> PAGE_SHIFT, &map,
>  			&vcpu->arch.st.cache, true))
>  		return;
>  
> @@ -3990,7 +3990,7 @@ static void kvm_steal_time_set_preempted(struct kvm_vcpu *vcpu)
>  
>  	st->preempted = vcpu->arch.st.preempted = KVM_VCPU_PREEMPTED;
>  
> -	kvm_unmap_gfn(vcpu, &map, &vcpu->arch.st.cache, true, true);
> +	kvm_unmap_gfn(vcpu->kvm, &map, &vcpu->arch.st.cache, true, true);
>  }
>  
>  void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
> diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
> index 7f2e2a09ebbd..8eb5eb1399f5 100644
> --- a/include/linux/kvm_host.h
> +++ b/include/linux/kvm_host.h
> @@ -806,11 +806,11 @@ struct kvm_memory_slot *kvm_vcpu_gfn_to_memslot(struct kvm_vcpu *vcpu, gfn_t gfn
>  kvm_pfn_t kvm_vcpu_gfn_to_pfn_atomic(struct kvm_vcpu *vcpu, gfn_t gfn);
>  kvm_pfn_t kvm_vcpu_gfn_to_pfn(struct kvm_vcpu *vcpu, gfn_t gfn);
>  int kvm_vcpu_map(struct kvm_vcpu *vcpu, gpa_t gpa, struct kvm_host_map *map);
> -int kvm_map_gfn(struct kvm_vcpu *vcpu, gfn_t gfn, struct kvm_host_map *map,
> +int kvm_map_gfn(struct kvm *kvm, gfn_t gfn, struct kvm_host_map *map,
>  		struct gfn_to_pfn_cache *cache, bool atomic);
>  struct page *kvm_vcpu_gfn_to_page(struct kvm_vcpu *vcpu, gfn_t gfn);
>  void kvm_vcpu_unmap(struct kvm_vcpu *vcpu, struct kvm_host_map *map, bool dirty);
> -int kvm_unmap_gfn(struct kvm_vcpu *vcpu, struct kvm_host_map *map,
> +int kvm_unmap_gfn(struct kvm *kvm, struct kvm_host_map *map,
>  		  struct gfn_to_pfn_cache *cache, bool dirty, bool atomic);
>  unsigned long kvm_vcpu_gfn_to_hva(struct kvm_vcpu *vcpu, gfn_t gfn);
>  unsigned long kvm_vcpu_gfn_to_hva_prot(struct kvm_vcpu *vcpu, gfn_t gfn, bool *writable);
> diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
> index 2541a17ff1c4..f01a8df7806a 100644
> --- a/virt/kvm/kvm_main.c
> +++ b/virt/kvm/kvm_main.c
> @@ -2181,10 +2181,10 @@ static int __kvm_map_gfn(struct kvm_memslots *slots, gfn_t gfn,
>  	return 0;
>  }
>  
> -int kvm_map_gfn(struct kvm_vcpu *vcpu, gfn_t gfn, struct kvm_host_map *map,
> +int kvm_map_gfn(struct kvm *kvm, gfn_t gfn, struct kvm_host_map *map,
>  		struct gfn_to_pfn_cache *cache, bool atomic)
>  {
> -	return __kvm_map_gfn(kvm_memslots(vcpu->kvm), gfn, map,
> +	return __kvm_map_gfn(kvm_memslots(kvm), gfn, map,
>  			cache, atomic);
>  }
>  EXPORT_SYMBOL_GPL(kvm_map_gfn);
> @@ -2232,10 +2232,10 @@ static void __kvm_unmap_gfn(struct kvm_memory_slot *memslot,
>  	map->page = NULL;
>  }
>  
> -int kvm_unmap_gfn(struct kvm_vcpu *vcpu, struct kvm_host_map *map, 
> +int kvm_unmap_gfn(struct kvm *kvm, struct kvm_host_map *map,
>  		  struct gfn_to_pfn_cache *cache, bool dirty, bool atomic)
>  {
> -	__kvm_unmap_gfn(gfn_to_memslot(vcpu->kvm, map->gfn), map,
> +	__kvm_unmap_gfn(gfn_to_memslot(kvm, map->gfn), map,
>  			cache, dirty, atomic);
>  	return 0;
>  }

What about different address space ids? 

gfn_to_memslot() now calls kvm_memslots() which gives memslots for
address space id = 0 but what if we want something different? Note,
different vCPUs can (in theory) be in different address spaces so we
actually need 'vcpu' and not 'kvm' then.
David Woodhouse Dec. 14, 2020, 9:21 p.m. UTC | #2
On 14 December 2020 21:13:40 GMT, Vitaly Kuznetsov <vkuznets@redhat.com> wrote:
>What about different address space ids? 
>
>gfn_to_memslot() now calls kvm_memslots() which gives memslots for
>address space id = 0 but what if we want something different? Note,
>different vCPUs can (in theory) be in different address spaces so we
>actually need 'vcpu' and not 'kvm' then.

Sure, but then you want a different function; this one is called 'kvm_map_gfn()' and it operates on kvm_memslots(). It *doesn't* operate on the vcpu at all.

Which is why it's so bizarre that its argument is a 'vcpu' which it only ever uses to get vcpu->kvm from it. It should just take the kvm pointer.
Vitaly Kuznetsov Dec. 14, 2020, 9:41 p.m. UTC | #3
David Woodhouse <dwmw2@infradead.org> writes:

> On 14 December 2020 21:13:40 GMT, Vitaly Kuznetsov <vkuznets@redhat.com> wrote:
>>What about different address space ids? 
>>
>>gfn_to_memslot() now calls kvm_memslots() which gives memslots for
>>address space id = 0 but what if we want something different? Note,
>>different vCPUs can (in theory) be in different address spaces so we
>>actually need 'vcpu' and not 'kvm' then.
>
> Sure, but then you want a different function; this one is called
> 'kvm_map_gfn()' and it operates on kvm_memslots(). It *doesn't*
> operate on the vcpu at all.
>

Actually, we already have kvm_vcpu_map() which uses kvm_vcpu_memslots()
inside so no new function is needed.

> Which is why it's so bizarre that its argument is a 'vcpu' which it
> only ever uses to get vcpu->kvm from it. It should just take the kvm
> pointer.

Your change is correct but I'm not sure that it's entirely clear that
kvm_map_gfn() implicitly uses 'as_id=0' and I don't even see a comment
about the fact :-(
David Woodhouse Dec. 14, 2020, 9:45 p.m. UTC | #4
On 14 December 2020 21:41:23 GMT, Vitaly Kuznetsov <vkuznets@redhat.com> wrote:
>>Your change is correct but I'm not sure that it's entirely clear that
>kvm_map_gfn() implicitly uses 'as_id=0' and I don't even see a comment
>about the fact :-(

Isn't that true of all the kvm_read_guest and kvm_write_guest functions and indeed of kvm_memslots() itself?
Vitaly Kuznetsov Dec. 15, 2020, 12:07 p.m. UTC | #5
David Woodhouse <dwmw2@infradead.org> writes:

> On 14 December 2020 21:41:23 GMT, Vitaly Kuznetsov <vkuznets@redhat.com> wrote:
>>>Your change is correct but I'm not sure that it's entirely clear that
>>kvm_map_gfn() implicitly uses 'as_id=0' and I don't even see a comment
>>about the fact :-(
>
> Isn't that true of all the kvm_read_guest and kvm_write_guest
> functions and indeed of kvm_memslots() itself?

Yes, sadly. Multiple address spaces support was added to KVM as a
generic feature but the only use-case for it at this moment is SMM on
x86 which is 'special', i.e. currently there's only one user for 
kvm_map_gfn()/kvm_unmap_gfn() which is steal time accounting and it's
not easy to come up with a use-case when this PV feature needs to be
used from SMM. On the other hand, if we try using multiple address
spaces in KVM for e.g. emulating something like Hyper-V VSM, it becomes
unclear which address space id needs to be used even for steal
time. To be entirely correct, we probably need to remember as_id which
was active when steal time was enabled and stick to it later when we
want to update the data. If we do that, kvm_map_gfn() will lose its only
user.

All the above doesn't make your patch incorrect of course, I just used
it to express my observation that we seem to be using as_id=0 blindly
and the API we have contributes to that.
David Woodhouse Dec. 15, 2020, 12:45 p.m. UTC | #6
On Tue, 2020-12-15 at 13:07 +0100, Vitaly Kuznetsov wrote:
> Yes, sadly. Multiple address spaces support was added to KVM as a
> generic feature but the only use-case for it at this moment is SMM on
> x86 which is 'special', i.e. currently there's only one user for 
> kvm_map_gfn()/kvm_unmap_gfn() which is steal time accounting and it's
> not easy to come up with a use-case when this PV feature needs to be
> used from SMM. On the other hand, if we try using multiple address
> spaces in KVM for e.g. emulating something like Hyper-V VSM, it becomes
> unclear which address space id needs to be used even for steal
> time. To be entirely correct, we probably need to remember as_id which
> was active when steal time was enabled and stick to it later when we
> want to update the data. If we do that, kvm_map_gfn() will lose its only
> user.

I'm also OK with just completely deleting kvm_map_gfn(). I'm not even
using it any more myself; I just kept this patch in my v3 series
because it's a sane cleanup.

The steal time accounting doesn't *need* to have a kernel mapping of
the page just so it can do atomic xchg on it; we can do that just fine
on userspace addresses, and do exactly that for futexes.

So I'm probably going to knock up a kvm_cmpxchg_guest_offset_cached()
and make the steal time code use that, on the *userspace* address.
There's already a futex_atomic_cmpxchg_inatomic() which does the actual
operation. (It returns -EFAULT for an absent page and lets the caller
worry about faulting it in, which isn't quite what I want, but it's a
good start and I can either wrap the existing arch-provided function
like futexes do, or use it as a basis for a version that waits.)

And by an amazing coincidence that's also the function I need for
accelerating Xen event channel support... :)
diff mbox series

Patch

diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index e545a8a613b1..c7f1ba21212e 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -2957,7 +2957,7 @@  static void record_steal_time(struct kvm_vcpu *vcpu)
 		return;
 
 	/* -EAGAIN is returned in atomic context so we can just return. */
-	if (kvm_map_gfn(vcpu, vcpu->arch.st.msr_val >> PAGE_SHIFT,
+	if (kvm_map_gfn(vcpu->kvm, vcpu->arch.st.msr_val >> PAGE_SHIFT,
 			&map, &vcpu->arch.st.cache, false))
 		return;
 
@@ -2992,7 +2992,7 @@  static void record_steal_time(struct kvm_vcpu *vcpu)
 
 	st->version += 1;
 
-	kvm_unmap_gfn(vcpu, &map, &vcpu->arch.st.cache, true, false);
+	kvm_unmap_gfn(vcpu->kvm, &map, &vcpu->arch.st.cache, true, false);
 }
 
 int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
@@ -3981,7 +3981,7 @@  static void kvm_steal_time_set_preempted(struct kvm_vcpu *vcpu)
 	if (vcpu->arch.st.preempted)
 		return;
 
-	if (kvm_map_gfn(vcpu, vcpu->arch.st.msr_val >> PAGE_SHIFT, &map,
+	if (kvm_map_gfn(vcpu->kvm, vcpu->arch.st.msr_val >> PAGE_SHIFT, &map,
 			&vcpu->arch.st.cache, true))
 		return;
 
@@ -3990,7 +3990,7 @@  static void kvm_steal_time_set_preempted(struct kvm_vcpu *vcpu)
 
 	st->preempted = vcpu->arch.st.preempted = KVM_VCPU_PREEMPTED;
 
-	kvm_unmap_gfn(vcpu, &map, &vcpu->arch.st.cache, true, true);
+	kvm_unmap_gfn(vcpu->kvm, &map, &vcpu->arch.st.cache, true, true);
 }
 
 void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index 7f2e2a09ebbd..8eb5eb1399f5 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -806,11 +806,11 @@  struct kvm_memory_slot *kvm_vcpu_gfn_to_memslot(struct kvm_vcpu *vcpu, gfn_t gfn
 kvm_pfn_t kvm_vcpu_gfn_to_pfn_atomic(struct kvm_vcpu *vcpu, gfn_t gfn);
 kvm_pfn_t kvm_vcpu_gfn_to_pfn(struct kvm_vcpu *vcpu, gfn_t gfn);
 int kvm_vcpu_map(struct kvm_vcpu *vcpu, gpa_t gpa, struct kvm_host_map *map);
-int kvm_map_gfn(struct kvm_vcpu *vcpu, gfn_t gfn, struct kvm_host_map *map,
+int kvm_map_gfn(struct kvm *kvm, gfn_t gfn, struct kvm_host_map *map,
 		struct gfn_to_pfn_cache *cache, bool atomic);
 struct page *kvm_vcpu_gfn_to_page(struct kvm_vcpu *vcpu, gfn_t gfn);
 void kvm_vcpu_unmap(struct kvm_vcpu *vcpu, struct kvm_host_map *map, bool dirty);
-int kvm_unmap_gfn(struct kvm_vcpu *vcpu, struct kvm_host_map *map,
+int kvm_unmap_gfn(struct kvm *kvm, struct kvm_host_map *map,
 		  struct gfn_to_pfn_cache *cache, bool dirty, bool atomic);
 unsigned long kvm_vcpu_gfn_to_hva(struct kvm_vcpu *vcpu, gfn_t gfn);
 unsigned long kvm_vcpu_gfn_to_hva_prot(struct kvm_vcpu *vcpu, gfn_t gfn, bool *writable);
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 2541a17ff1c4..f01a8df7806a 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -2181,10 +2181,10 @@  static int __kvm_map_gfn(struct kvm_memslots *slots, gfn_t gfn,
 	return 0;
 }
 
-int kvm_map_gfn(struct kvm_vcpu *vcpu, gfn_t gfn, struct kvm_host_map *map,
+int kvm_map_gfn(struct kvm *kvm, gfn_t gfn, struct kvm_host_map *map,
 		struct gfn_to_pfn_cache *cache, bool atomic)
 {
-	return __kvm_map_gfn(kvm_memslots(vcpu->kvm), gfn, map,
+	return __kvm_map_gfn(kvm_memslots(kvm), gfn, map,
 			cache, atomic);
 }
 EXPORT_SYMBOL_GPL(kvm_map_gfn);
@@ -2232,10 +2232,10 @@  static void __kvm_unmap_gfn(struct kvm_memory_slot *memslot,
 	map->page = NULL;
 }
 
-int kvm_unmap_gfn(struct kvm_vcpu *vcpu, struct kvm_host_map *map, 
+int kvm_unmap_gfn(struct kvm *kvm, struct kvm_host_map *map,
 		  struct gfn_to_pfn_cache *cache, bool dirty, bool atomic)
 {
-	__kvm_unmap_gfn(gfn_to_memslot(vcpu->kvm, map->gfn), map,
+	__kvm_unmap_gfn(gfn_to_memslot(kvm, map->gfn), map,
 			cache, dirty, atomic);
 	return 0;
 }