RE: [PATCH v3] drivers: hv: vmbus: Use kthread for vmbus interrupts on PREEMPT_RT

Michael Kelley <[email protected]>
Newsgroups org.kernel.vger.linux-rt-users,org.kernel.vger.linux-hyperv,org.kernel.vger.linux-kernel
Message-ID <SN6PR02MB415753FDA0DEEA0B4A8B9994D441A@SN6PR02MB4157.namprd02.prod.outlook.com>
From: Sebastian Andrzej Siewior <[email protected]> Sent: Thursday, March 12, 2026 10:07 AM
>

Let me try to address the range of questions here and in the follow-up
discussion. As background, an overview of VMBus interrupt handling is in:

Documentation/virt/hyperv/vmbus.rst

in the section entitled "Synthetic Interrupt Controller (synic)". The
relevant text is:

   The SINT is mapped to a single per-CPU architectural interrupt (i.e,
   an 8-bit x86/x64 interrupt vector, or an arm64 PPI INTID). Because
   each CPU in the guest has a synic and may receive VMBus interrupts,
   they are best modeled in Linux as per-CPU interrupts. This model works
   well on arm64 where a single per-CPU Linux IRQ is allocated for
   VMBUS_MESSAGE_SINT. This IRQ appears in /proc/interrupts as an IRQ labelled
   "Hyper-V VMbus". Since x86/x64 lacks support for per-CPU IRQs, an x86
   interrupt vector is statically allocated (HYPERVISOR_CALLBACK_VECTOR)
   across all CPUs and explicitly coded to call vmbus_isr(). In this case,
   there's no Linux IRQ, and the interrupts are visible in aggregate in
   /proc/interrupts on the "HYP" line.

The use of a statically allocated sysvec pre-dates my involvement in this
code starting in 2017, but I believe it was modelled after what Xen does,
and for the same reason -- to effectively create a per-CPU interrupt on
x86/x64. Acorn is also using HYPERVISOR_CALLBACK_VECTOR, but I
don't know if that is also to create a per-CPU interrupt.

More below ....

> On 2026-02-16 17:24:56 [+0100], Jan Kiszka wrote:
> > --- a/drivers/hv/vmbus_drv.c
> > +++ b/drivers/hv/vmbus_drv.c
> > @@ -25,6 +25,7 @@
> >  #include <linux/cpu.h>
> >  #include <linux/sched/isolation.h>
> >  #include <linux/sched/task_stack.h>
> > +#include <linux/smpboot.h>
> >
> >  #include <linux/delay.h>
> >  #include <linux/panic_notifier.h>
> > @@ -1350,7 +1351,7 @@ static void vmbus_message_sched(struct hv_per_cpu_context *hv_cpu, void *message
> >  	}
> >  }
> >
> > -void vmbus_isr(void)
> > +static void __vmbus_isr(void)
> >  {
> >  	struct hv_per_cpu_context *hv_cpu
> >  		= this_cpu_ptr(hv_context.cpu_context);
> > @@ -1363,6 +1364,53 @@ void vmbus_isr(void)
> >
> >  	add_interrupt_randomness(vmbus_interrupt);
> 
> This is feeding entropy and would like to see interrupt registers. But
> since this is invoked from a thread it won't.

I'll respond to this topic on the new thread for the new patch
where Jan has moved the call to add_interrupt_randomness().

> 
> >  }
> > +
> …
> > +void vmbus_isr(void)
> > +{
> > +	if (IS_ENABLED(CONFIG_PREEMPT_RT)) {
> > +		vmbus_irqd_wake();
> > +	} else {
> > +		lockdep_hardirq_threaded();
> 
> What clears this? This is wrongly placed. This should go to
> sysvec_hyperv_callback() instead with its matching canceling part. The
> add_interrupt_randomness() should also be there and not here.
> sysvec_hyperv_stimer0() managed to do so.

I don't have any knowledge to bring regarding the use of
lockdep_hardirq_threaded().

> 
> Different question: What guarantees that there won't be another
> interrupt before this one is done? The handshake appears to be
> deprecated. The interrupt itself returns ACKing (or not) but the actual
> handler is delayed to this thread. Depending on the userland it could
> take some time and I don't know how impatient the host is.

In more recent versions of Hyper-V, what's deprecated is Hyper-V implicitly
and automatically doing the EOI. So in sysvec_hyperv_callback(), apic_eoi()
is usually explicitly called to ack the interrupt.

There's no guarantee, in either the existing case or the new PREEMPT_RT
case, that another VMBus interrupt won't come in on the same CPU
before the tasklets scheduled by vmbus_message_sched() or
vmbus_chan_sched() have run. From a functional standpoint, the Linux
code and interaction with Hyper-V handles another interrupt correctly.

From a delay standpoint, there's not a problem for the normal (i.e., not
PREEMPT_RT) case because the tasklets run as the interrupt exits -- they
don't end up in ksoftirqd. For the PREEMPT_RT case, I can see your point
about delays since the tasklets are scheduled from the new per-CPU thread.
But my understanding is that Jan's motivation for these changes is not to
achieve true RT behavior, since Hyper-V doesn't provide that anyway.
The goal is simply to make PREEMPT_RT builds functional, though Jan may
have further comments on the goal.

> 
> > +		__vmbus_isr();
> Moving on. This (trying very hard here) even schedules tasklets. Why?
> You need to disable BH before doing so. Otherwise it ends in ksoftirqd.
> You don't want that.

Again, Jan can comment on the impact of delays due to ending up
in ksoftirqd.

> 
> Couldn't the whole logic be integrated into the IRQ code? Then we could
> have mask/ unmask if supported/ provided and threaded interrupts. Then
> sysvec_hyperv_reenlightenment() could use a proper threaded interrupt
> instead apic_eoi() + schedule_delayed_work().

As I described above, Hyper-V needs a per-CPU interrupt. It's faked up
on x86/x64 with the hardcoded HYPERVISOR_CALLBACK_VECTOR sysvec
entry, but on arm64 a normal Linux per-CPU IRQ is used. Once the execution
path gets to vmbus_isr(), the two architectures share the same code. Same
thing is done with the Hyper-V STIMER0 interrupt as a per-CPU interrupt.
If there's a better way to fake up a per-CPU interrupt on x86/x64, I'm open
to looking at it.

As I recently discovered in discussion with Jan, standard Linux IRQ handling
will *not* thread per-CPU interrupts. So even on arm64 with a standard
Linux per-CPU IRQ is used for VMBus and STIMER0 interrupts, we can't
request threading.

I need to refresh my memory on sysvec_hyperv_reenlightenment(). If
I recall correctly, it's not a per-CPU interrupt, so it probably doesn't
need to have a hardcoded vector. Overall, the Hyper-V reenlightenment
functionality is a bit of a fossil that isn't needed on modern x86/x64
processors that support TSC scaling. And it doesn't exist for arm64.
It might be worth seeing if it could be dropped entirely ...

Michael

> 
> > +	}
> > +}
> >  EXPORT_SYMBOL_FOR_MODULES(vmbus_isr, "mshv_vtl");
> >
> >  static irqreturn_t vmbus_percpu_isr(int irq, void *dev_id)
> 
> Sebastian
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.