On 5/26/2026 7:13 AM, Michael Kelley wrote:
> From: Michael Kelley <[email protected]>
> 
> When the VMBus driver is not part of the kernel (CONFIG_HYPERV_VMBUS=n),
> the MSHV root driver fails to link:
> 
> ERROR: modpost: "hv_vmbus_exists" [drivers/hv/mshv_root.ko] undefined!
> 
> Fix this while meeting these requirements:
> * It must be possible to include the MSHV root driver without the
>   VMBus driver. In such case, the MSHV root driver can be built-in
>   to the kernel image, or it can be built as a separate module.
> * If both the MSHV root driver and the VMBus driver are present, the
>   MSHV root driver and VMBus driver can both be built-in, or they can
>   both be separate modules. Or the MSHV root driver can be a module
>   while the VMBus driver can be built-in, but the reverse is
>   disallowed. Regardless of the build choices, the VMBus driver must
>   be loaded before the MSHV driver in order for the SynIC to be
>   managed properly (see comments in the MSHV SynIC code).
> 
> The fix has two parts:
> * Add a Kconfig entry for MSHV_ROOT to depend on HYPERV_VMBUS if
>   HYPERV_VMBUS is present. The entry disallows MSHV_ROOT being
>   built-in when HYPERV_VMBUS is a module, but without requiring that
>   HYPERV_VMBUS be built.
> * Add a stub implementation of hv_vmbus_exists() for when the
>   VMBus driver is not present so that the MSHV root driver has
>   no module dependency on VMBus. When the VMBus driver *is*
>   present, the module dependency ensures that the VMBus driver
>   loads first when both are built as modules.
> 
> Existing code ensures that the VMBus driver loads first if it is
> built-in. The VMBus driver uses subsys_initcall(), which is
> initcall level 4. The MSHV root driver uses module_init(), which
> becomes device_init() when built-in, and device_init() is
> initcall level 6.
> 
> Reported-by: Arnd Bergmann <[email protected]>
> Closes: https://lore.kernel.org/all/[email protected]/
> Signed-off-by: Michael Kelley <[email protected]>
> Acked-by: Arnd Bergmann <[email protected]>
> Reviewed-by: Jork Loeser <[email protected]>
> ---
> Changes in v2:
> * Instead of putting IS_ENABLED(CONFIG_HYPERV_VMBUS) around each of
>   the two calls to hv_vmbus_exists() in mshv_synic.c, provide a stub
>   for hv_vmbus_exists() when CONFIG_HYPERV_VMBUS is not set. The
>   effect is the same as in v1, but the code is cleaner. [Jork Loeser]
> 
> Arnd: I've kept your Ack even though I changed how hv_vmbus_exists()
> is stubbed out since the effect is the same. Let me know if
> you have any concerns.
> 
>  drivers/hv/Kconfig     | 1 +
>  include/linux/hyperv.h | 4 ++++
>  2 files changed, 5 insertions(+)
> 
> diff --git a/drivers/hv/Kconfig b/drivers/hv/Kconfig
> index 2d0b3fcb0ff8..aa11bcefddf2 100644
> --- a/drivers/hv/Kconfig
> +++ b/drivers/hv/Kconfig
> @@ -74,6 +74,7 @@ config MSHV_ROOT
>       # e.g. When withdrawing memory, the hypervisor gives back 4k pages in
>       # no particular order, making it impossible to reassemble larger pages
>       depends on PAGE_SIZE_4KB
> +     depends on HYPERV_VMBUS if HYPERV_VMBUS
>       select EVENTFD
>       select VIRT_XFER_TO_GUEST_WORK
>       select HMM_MIRROR
> diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h
> index 41a3d82f0722..734b7ef98f4d 100644
> --- a/include/linux/hyperv.h
> +++ b/include/linux/hyperv.h
> @@ -1304,7 +1304,11 @@ static inline void *hv_get_drvdata(struct hv_device 
> *dev)
>  
>  struct device *hv_get_vmbus_root_device(void);
>  
> +#if IS_ENABLED(CONFIG_HYPERV_VMBUS)
>  bool hv_vmbus_exists(void);
> +#else
> +static inline bool hv_vmbus_exists(void) { return false; }
> +#endif
>  
>  struct hv_ring_buffer_debug_info {
>       u32 current_interrupt_mask;

Reviewed-by: Hardik Garg <[email protected]>



Thanks,
Hardik

Reply via email to