Skip to content

Commit df06dae

Browse files
sean-jcbonzini
authored andcommitted
KVM: Don't actually set a request when evicting vCPUs for GFN cache invd
Don't actually set a request bit in vcpu->requests when making a request purely to force a vCPU to exit the guest. Logging a request but not actually consuming it would cause the vCPU to get stuck in an infinite loop during KVM_RUN because KVM would see the pending request and bail from VM-Enter to service the request. Note, it's currently impossible for KVM to set KVM_REQ_GPC_INVALIDATE as nothing in KVM is wired up to set guest_uses_pa=true. But, it'd be all too easy for arch code to introduce use of kvm_gfn_to_pfn_cache_init() without implementing handling of the request, especially since getting test coverage of MMU notifier interaction with specific KVM features usually requires a directed test. Opportunistically rename gfn_to_pfn_cache_invalidate_start()'s wake_vcpus to evict_vcpus. The purpose of the request is to get vCPUs out of guest mode, it's supposed to _avoid_ waking vCPUs that are blocking. Opportunistically rename KVM_REQ_GPC_INVALIDATE to be more specific as to what it wants to accomplish, and to genericize the name so that it can used for similar but unrelated scenarios, should they arise in the future. Add a comment and documentation to explain why the "no action" request exists. Add compile-time assertions to help detect improper usage. Use the inner assertless helper in the one s390 path that makes requests without a hardcoded request. Cc: David Woodhouse <dwmw@amazon.co.uk> Signed-off-by: Sean Christopherson <seanjc@google.com> Message-Id: <20220223165302.3205276-1-seanjc@google.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
1 parent 79593c0 commit df06dae

5 files changed

Lines changed: 55 additions & 16 deletions

File tree

Documentation/virt/kvm/vcpu-requests.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,16 @@ KVM_REQ_UNHALT
135135
such as a pending signal, which does not indicate the VCPU's halt
136136
emulation should stop, and therefore does not make the request.
137137

138+
KVM_REQ_OUTSIDE_GUEST_MODE
139+
140+
This "request" ensures the target vCPU has exited guest mode prior to the
141+
sender of the request continuing on. No action needs be taken by the target,
142+
and so no request is actually logged for the target. This request is similar
143+
to a "kick", but unlike a kick it guarantees the vCPU has actually exited
144+
guest mode. A kick only guarantees the vCPU will exit at some point in the
145+
future, e.g. a previous kick may have started the process, but there's no
146+
guarantee the to-be-kicked vCPU has fully exited guest mode.
147+
138148
KVM_REQUEST_MASK
139149
----------------
140150

arch/s390/kvm/kvm-s390.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3463,7 +3463,7 @@ void exit_sie(struct kvm_vcpu *vcpu)
34633463
/* Kick a guest cpu out of SIE to process a request synchronously */
34643464
void kvm_s390_sync_request(int req, struct kvm_vcpu *vcpu)
34653465
{
3466-
kvm_make_request(req, vcpu);
3466+
__kvm_make_request(req, vcpu);
34673467
kvm_s390_vcpu_request(vcpu);
34683468
}
34693469

include/linux/kvm_host.h

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ static inline bool is_error_page(struct page *page)
148148
#define KVM_REQUEST_MASK GENMASK(7,0)
149149
#define KVM_REQUEST_NO_WAKEUP BIT(8)
150150
#define KVM_REQUEST_WAIT BIT(9)
151+
#define KVM_REQUEST_NO_ACTION BIT(10)
151152
/*
152153
* Architecture-independent vcpu->requests bit members
153154
* Bits 4-7 are reserved for more arch-independent bits.
@@ -156,9 +157,18 @@ static inline bool is_error_page(struct page *page)
156157
#define KVM_REQ_VM_DEAD (1 | KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP)
157158
#define KVM_REQ_UNBLOCK 2
158159
#define KVM_REQ_UNHALT 3
159-
#define KVM_REQ_GPC_INVALIDATE (5 | KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP)
160160
#define KVM_REQUEST_ARCH_BASE 8
161161

162+
/*
163+
* KVM_REQ_OUTSIDE_GUEST_MODE exists is purely as way to force the vCPU to
164+
* OUTSIDE_GUEST_MODE. KVM_REQ_OUTSIDE_GUEST_MODE differs from a vCPU "kick"
165+
* in that it ensures the vCPU has reached OUTSIDE_GUEST_MODE before continuing
166+
* on. A kick only guarantees that the vCPU is on its way out, e.g. a previous
167+
* kick may have set vcpu->mode to EXITING_GUEST_MODE, and so there's no
168+
* guarantee the vCPU received an IPI and has actually exited guest mode.
169+
*/
170+
#define KVM_REQ_OUTSIDE_GUEST_MODE (KVM_REQUEST_NO_ACTION | KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP)
171+
162172
#define KVM_ARCH_REQ_FLAGS(nr, flags) ({ \
163173
BUILD_BUG_ON((unsigned)(nr) >= (sizeof_field(struct kvm_vcpu, requests) * 8) - KVM_REQUEST_ARCH_BASE); \
164174
(unsigned)(((nr) + KVM_REQUEST_ARCH_BASE) | (flags)); \
@@ -1222,7 +1232,9 @@ void kvm_vcpu_mark_page_dirty(struct kvm_vcpu *vcpu, gfn_t gfn);
12221232
* @vcpu: vCPU to be used for marking pages dirty and to be woken on
12231233
* invalidation.
12241234
* @guest_uses_pa: indicates that the resulting host physical PFN is used while
1225-
* @vcpu is IN_GUEST_MODE so invalidations should wake it.
1235+
* @vcpu is IN_GUEST_MODE; invalidations of the cache from MMU
1236+
* notifiers (but not for KVM memslot changes!) will also force
1237+
* @vcpu to exit the guest to refresh the cache.
12261238
* @kernel_map: requests a kernel virtual mapping (kmap / memremap).
12271239
* @gpa: guest physical address to map.
12281240
* @len: sanity check; the range being access must fit a single page.
@@ -1233,10 +1245,9 @@ void kvm_vcpu_mark_page_dirty(struct kvm_vcpu *vcpu, gfn_t gfn);
12331245
* -EFAULT for an untranslatable guest physical address.
12341246
*
12351247
* This primes a gfn_to_pfn_cache and links it into the @kvm's list for
1236-
* invalidations to be processed. Invalidation callbacks to @vcpu using
1237-
* %KVM_REQ_GPC_INVALIDATE will occur only for MMU notifiers, not for KVM
1238-
* memslot changes. Callers are required to use kvm_gfn_to_pfn_cache_check()
1239-
* to ensure that the cache is valid before accessing the target page.
1248+
* invalidations to be processed. Callers are required to use
1249+
* kvm_gfn_to_pfn_cache_check() to ensure that the cache is valid before
1250+
* accessing the target page.
12401251
*/
12411252
int kvm_gfn_to_pfn_cache_init(struct kvm *kvm, struct gfn_to_pfn_cache *gpc,
12421253
struct kvm_vcpu *vcpu, bool guest_uses_pa,
@@ -1984,7 +1995,7 @@ static inline int kvm_ioeventfd(struct kvm *kvm, struct kvm_ioeventfd *args)
19841995

19851996
void kvm_arch_irq_routing_update(struct kvm *kvm);
19861997

1987-
static inline void kvm_make_request(int req, struct kvm_vcpu *vcpu)
1998+
static inline void __kvm_make_request(int req, struct kvm_vcpu *vcpu)
19881999
{
19892000
/*
19902001
* Ensure the rest of the request is published to kvm_check_request's
@@ -1994,6 +2005,19 @@ static inline void kvm_make_request(int req, struct kvm_vcpu *vcpu)
19942005
set_bit(req & KVM_REQUEST_MASK, (void *)&vcpu->requests);
19952006
}
19962007

2008+
static __always_inline void kvm_make_request(int req, struct kvm_vcpu *vcpu)
2009+
{
2010+
/*
2011+
* Request that don't require vCPU action should never be logged in
2012+
* vcpu->requests. The vCPU won't clear the request, so it will stay
2013+
* logged indefinitely and prevent the vCPU from entering the guest.
2014+
*/
2015+
BUILD_BUG_ON(!__builtin_constant_p(req) ||
2016+
(req & KVM_REQUEST_NO_ACTION));
2017+
2018+
__kvm_make_request(req, vcpu);
2019+
}
2020+
19972021
static inline bool kvm_request_pending(struct kvm_vcpu *vcpu)
19982022
{
19992023
return READ_ONCE(vcpu->requests);

virt/kvm/kvm_main.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,8 @@ static void kvm_make_vcpu_request(struct kvm_vcpu *vcpu, unsigned int req,
253253
{
254254
int cpu;
255255

256-
kvm_make_request(req, vcpu);
256+
if (likely(!(req & KVM_REQUEST_NO_ACTION)))
257+
__kvm_make_request(req, vcpu);
257258

258259
if (!(req & KVM_REQUEST_NO_WAKEUP) && kvm_vcpu_wake_up(vcpu))
259260
return;

virt/kvm/pfncache.c

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ void gfn_to_pfn_cache_invalidate_start(struct kvm *kvm, unsigned long start,
2727
{
2828
DECLARE_BITMAP(vcpu_bitmap, KVM_MAX_VCPUS);
2929
struct gfn_to_pfn_cache *gpc;
30-
bool wake_vcpus = false;
30+
bool evict_vcpus = false;
3131

3232
spin_lock(&kvm->gpc_lock);
3333
list_for_each_entry(gpc, &kvm->gpc_list, list) {
@@ -40,11 +40,11 @@ void gfn_to_pfn_cache_invalidate_start(struct kvm *kvm, unsigned long start,
4040

4141
/*
4242
* If a guest vCPU could be using the physical address,
43-
* it needs to be woken.
43+
* it needs to be forced out of guest mode.
4444
*/
4545
if (gpc->guest_uses_pa) {
46-
if (!wake_vcpus) {
47-
wake_vcpus = true;
46+
if (!evict_vcpus) {
47+
evict_vcpus = true;
4848
bitmap_zero(vcpu_bitmap, KVM_MAX_VCPUS);
4949
}
5050
__set_bit(gpc->vcpu->vcpu_idx, vcpu_bitmap);
@@ -67,14 +67,18 @@ void gfn_to_pfn_cache_invalidate_start(struct kvm *kvm, unsigned long start,
6767
}
6868
spin_unlock(&kvm->gpc_lock);
6969

70-
if (wake_vcpus) {
71-
unsigned int req = KVM_REQ_GPC_INVALIDATE;
70+
if (evict_vcpus) {
71+
/*
72+
* KVM needs to ensure the vCPU is fully out of guest context
73+
* before allowing the invalidation to continue.
74+
*/
75+
unsigned int req = KVM_REQ_OUTSIDE_GUEST_MODE;
7276
bool called;
7377

7478
/*
7579
* If the OOM reaper is active, then all vCPUs should have
7680
* been stopped already, so perform the request without
77-
* KVM_REQUEST_WAIT and be sad if any needed to be woken.
81+
* KVM_REQUEST_WAIT and be sad if any needed to be IPI'd.
7882
*/
7983
if (!may_block)
8084
req &= ~KVM_REQUEST_WAIT;

0 commit comments

Comments
 (0)