[PATCH v2 00/11] KVM: x86/xen: Don't drop event deliveries which race memslot updates
From: David Woodhouse
Date: Wed Oct 14 2026 - 18:07:47 EST
From: David Woodhouse <dwmw@xxxxxxxxxxxx>
Sashiko analysis and torture testing of the upcoming conversion of the
gfn_to_pfn_cache from rwlock to atomic SRCU¹ highlighted a pre-existing
problem: refreshing a cache can fail while a memslot is briefly marked
KVM_MEMSLOT_INVALID during a memslot update. The Xen event channel and
timer delivery paths silently dropped events when they hit that window.
Return -EAGAIN from __kvm_gpc_refresh() to distinguish the transient
case from a genuinely unbacked GFN, and add a retry loop for the common
case callers which can just wait for the memslot update to complete, as
well as dealing with the corner cases which can't:
- The Xen attribute ioctls wait, so userspace never sees the
transient state.
- Timer delivery leaves ->arch.xen.timer_pending set and retries from
kvm_xen_inject_timer_irqs() on the next vCPU entry.
- The guest's own EVTCHNOP_send hypercall runs under vcpu_run's
kvm->srcu read section — the very reader the memslot update is
waiting for — so it cannot wait. Leave the hypercall uncompleted
without advancing RIP, so the guest re-executes it. This is how
Xen itself restarts preempted hypercalls.
Patch 3 steps the hypercall page MSR write out of the vCPU's kvm->srcu
read section around xen_lock, so an ioctl waiting out a memslot update
while holding that lock cannot deadlock it.
Patches 7-10 are pulled forward from the SRCU series because they stand
alone:
- Three from Sean², extracting vcpu_info delivery into a separate
helper and taking the shared_info and vcpu_info pages out of dirty
tracking. Rebased: his series had first converted the GPC locks to
read_trylock(), which this one doesn't carry.
- Requesting the guest TLB flush from record_steal_time() itself, as
a standalone cleanup in preparation for converting that to GPC.
The final patch adds a selftest racing a guest EVTCHNOP_send loop
against a tight memslot delete/recreate loop. Tested with that and
xen_shinfo_test; an instrumented run showed 10 of its 4000 sends
hitting the update window and re-executing.
Based on kvm/next (d4b7fb647204).
v2: https://git.infradead.org/?p=users/dwmw2/linux.git;a=shortlog;h=refs/heads/gpc-eagain-v2
- Take kvm->srcu around the kvm_gpc_check() loop and the wallclock
write in kvm_xen_shared_info_init(), which had lost it.
- New patch 3: don't block on xen_lock within the vCPU's kvm->srcu
read section (three-way deadlock against a waiting ioctl and a
memslot update). Document the rule at the lock's definition.
- On -EINVAL (deactivated shared_info, or an invalid port), clear
timer_pending but keep timer_expires: a halted vCPU would
otherwise spin aborting its own block, and the event is still
reported as pending through KVM_XEN_VCPU_GET_ATTR.
- Drop the wait argument from kvm_xen_inject_timer_irqs(); neither
caller may wait.
- Extend the KVM_GET_DIRTY_LOG note in api.rst to the vcpu_info area.
- Teach lockdep that the wait functions as a synchronize_srcu(), so
it reports any lock held across it which a kvm->srcu read section
can take.
- Comment fixes; drop a leftover cosmetic hunk.
Thanks to the Sashiko review bot for finding three of those on v1.
v1: https://git.infradead.org/?p=users/dwmw2/linux.git;a=shortlog;h=refs/heads/gpc-eagain
https://lore.kernel.org/kvm/20261013204824.454208-1-dwmw2@xxxxxxxxxxxxx/
¹ https://git.infradead.org/?p=users/dwmw2/linux.git;a=shortlog;h=refs/heads/gpc-srcu-v2
² https://lore.kernel.org/kvm/20260529165114.748639-1-seanjc@xxxxxxxxxx/
David Woodhouse (8):
KVM: pfncache: Return -EAGAIN for a lookup which hits an invalid memslot
KVM: pfncache: Add a 'wait' argument to the refresh and activate functions
KVM: x86/xen: Don't block on xen_lock within the vCPU's kvm->srcu section
KVM: x86/xen: Wait out memslot updates in the Xen attribute ioctls
KVM: x86/xen: Don't lose the timer event when delivery fails transiently
KVM: x86/xen: Retry event channel delivery which races a memslot update
KVM: x86: Request the guest TLB flush from record_steal_time()
KVM: selftests: Add Xen evtchn vs memslot-update race test
Sean Christopherson (3):
KVM: x86/xen: Extract delivery of event to vCPU into a separate helper
KVM: x86/xen: Explicitly tag "shared info" page as never being dirty tracked
KVM: x86/xen: Don't dirty track "vCPU info" page
Documentation/virt/kvm/api.rst | 5 +-
arch/x86/include/asm/kvm_host.h | 4 +
arch/x86/kvm/msrs.c | 2 +-
arch/x86/kvm/x86.c | 28 +-
arch/x86/kvm/xen.c | 341 ++++++++++++------
include/linux/kvm_host.h | 27 +-
include/linux/kvm_types.h | 1 +
tools/testing/selftests/kvm/Makefile.kvm | 1 +
.../kvm/x86/xen_evtchn_memslot_race_test.c | 178 +++++++++
.../selftests/kvm/x86/xen_shinfo_test.c | 11 +-
virt/kvm/pfncache.c | 137 +++++--
11 files changed, 564 insertions(+), 171 deletions(-)
create mode 100644 tools/testing/selftests/kvm/x86/xen_evtchn_memslot_race_test.c
base-commit: d4b7fb647204f0c81dfeae2d1a708e4d858e0c94
--
2.43.0