mshv: Fix level-triggered check on uninitialized data

In mshv_irqfd_assign(), the level-triggered validation for resample
irqfds checks irqfd_lapic_irq.lapic_control.level_triggered before
mshv_irqfd_update() has populated the field. Since the irqfd struct is
zero-allocated, level_triggered is always 0 at that point, causing the
check to always reject resample irqfds with -EINVAL. This makes
level-triggered interrupt resampling — used to avoid interrupt storms
with assigned devices — completely non-functional.

Move the check after the mshv_irqfd_update() call, which resolves the
IRQ routing entry and populates irqfd_lapic_irq with the actual trigger
mode.

Fixes: 621191d709 ("Drivers: hv: Introduce mshv_root module to expose /dev/mshv to VMMs")
Signed-off-by: Stanislav Kinsburskii <skinsburskii@linux.microsoft.com>
Reviewed-by: Anirudh Rayabharam (Microsoft) <anirudh@anirudhrb.com>
Signed-off-by: Wei Liu <wei.liu@kernel.org>
This commit is contained in:
Stanislav Kinsburskii
2026-07-31 20:01:57 +00:00
committed by Wei Liu
parent 0762262ac3
commit 0289a67cd7
+15 -12
View File
@@ -473,18 +473,6 @@ static int mshv_irqfd_assign(struct mshv_partition *pt,
init_poll_funcptr(&irqfd->irqfd_polltbl, mshv_irqfd_queue_proc);
spin_lock_irq(&pt->pt_irqfds_lock);
#if IS_ENABLED(CONFIG_X86)
if (args->flags & BIT(MSHV_IRQFD_BIT_RESAMPLE) &&
!irqfd->irqfd_lapic_irq.lapic_control.level_triggered) {
/*
* Resample Fd must be for level triggered interrupt
* Otherwise return with failure
*/
spin_unlock_irq(&pt->pt_irqfds_lock);
ret = -EINVAL;
goto fail;
}
#endif
ret = 0;
hlist_for_each_entry(tmp, &pt->pt_irqfds_list, irqfd_hnode) {
if (irqfd->irqfd_eventfd_ctx != tmp->irqfd_eventfd_ctx)
@@ -497,6 +485,21 @@ static int mshv_irqfd_assign(struct mshv_partition *pt,
idx = srcu_read_lock(&pt->pt_irq_srcu);
mshv_irqfd_update(pt, irqfd);
#if IS_ENABLED(CONFIG_X86)
if (args->flags & BIT(MSHV_IRQFD_BIT_RESAMPLE) &&
!irqfd->irqfd_lapic_irq.lapic_control.level_triggered) {
/*
* Resample Fd must be for level triggered interrupt
* Otherwise return with failure
*/
spin_unlock_irq(&pt->pt_irqfds_lock);
srcu_read_unlock(&pt->pt_irq_srcu, idx);
ret = -EINVAL;
goto fail;
}
#endif
hlist_add_head(&irqfd->irqfd_hnode, &pt->pt_irqfds_list);
spin_unlock_irq(&pt->pt_irqfds_lock);