1
0
mirror of https://git.FreeBSD.org/src.git synced 2024-11-28 08:02:54 +00:00

vmm: avoid spurious rendezvous

A vcpu only checks if a rendezvous is in progress or not to decide if it
should handle a rendezvous. This could lead to spurios rendezvous where
a vcpu tries a handle a rendezvous it isn't part of. This situation is
properly handled by vm_handle_rendezvous but it could potentially
degrade the performance. Avoid that by an early check if the vcpu is
part of the rendezvous or not.

At the moment, rendezvous are only used to spin up application
processors and to send ioapic interrupts. Spinning up application
processors is done in the guest boot phase by sending INIT SIPI
sequences to single vcpus. This is known to cause spurious rendezvous
and only occurs in the boot phase. Sending ioapic interrupts is rare
because modern guest will use msi and the rendezvous is always send to
all vcpus.

Reviewed by:		jhb
MFC after:		1 week
Sponsored by:		Beckhoff Automation GmbH & Co. KG
Differential Revision:	https://reviews.freebsd.org/D37390
This commit is contained in:
Corvin Köhne 2022-11-15 11:53:49 +01:00
parent 17c8213559
commit 892feec221
No known key found for this signature in database
GPG Key ID: D854DA56315E026A
4 changed files with 14 additions and 7 deletions

View File

@ -159,7 +159,7 @@ struct pmap;
enum snapshot_req;
struct vm_eventinfo {
void *rptr; /* rendezvous cookie */
cpuset_t *rptr; /* rendezvous cookie */
int *sptr; /* suspend cookie */
int *iptr; /* reqidle cookie */
};
@ -331,10 +331,16 @@ void vm_await_start(struct vm *vm, const cpuset_t *waiting);
#endif /* _SYS__CPUSET_H_ */
static __inline int
vcpu_rendezvous_pending(struct vm_eventinfo *info)
vcpu_rendezvous_pending(struct vcpu *vcpu, struct vm_eventinfo *info)
{
return (*((uintptr_t *)(info->rptr)) != 0);
/*
* This check isn't done with atomic operations or under a lock because
* there's no need to. If the vcpuid bit is set, the vcpu is part of a
* rendezvous and the bit won't be cleared until the vcpu enters the
* rendezvous. On rendezvous exit, the cpuset is cleared and the vcpu
* will see an empty cpuset. So, the races are harmless.
*/
return (CPU_ISSET(vcpu_vcpuid(vcpu), info->rptr));
}
static __inline int

View File

@ -2053,7 +2053,7 @@ svm_run(void *vcpui, register_t rip, pmap_t pmap, struct vm_eventinfo *evinfo)
break;
}
if (vcpu_rendezvous_pending(evinfo)) {
if (vcpu_rendezvous_pending(vcpu->vcpu, evinfo)) {
enable_gintr();
vm_exit_rendezvous(vcpu->vcpu, state->rip);
break;

View File

@ -3071,7 +3071,7 @@ vmx_run(void *vcpui, register_t rip, pmap_t pmap, struct vm_eventinfo *evinfo)
break;
}
if (vcpu_rendezvous_pending(evinfo)) {
if (vcpu_rendezvous_pending(vcpu->vcpu, evinfo)) {
enable_intr();
vm_exit_rendezvous(vcpu->vcpu, rip);
break;

View File

@ -1438,6 +1438,7 @@ vm_handle_rendezvous(struct vcpu *vcpu)
if (CPU_CMP(&vm->rendezvous_req_cpus,
&vm->rendezvous_done_cpus) == 0) {
VMM_CTR0(vcpu, "Rendezvous completed");
CPU_ZERO(&vm->rendezvous_req_cpus);
vm->rendezvous_func = NULL;
wakeup(&vm->rendezvous_func);
break;
@ -1858,7 +1859,7 @@ vm_run(struct vcpu *vcpu, struct vm_exit *vme_user)
pmap = vmspace_pmap(vm->vmspace);
vme = &vcpu->exitinfo;
evinfo.rptr = &vm->rendezvous_func;
evinfo.rptr = &vm->rendezvous_req_cpus;
evinfo.sptr = &vm->suspend;
evinfo.iptr = &vcpu->reqidle;
restart: