On Wed, 20 May 2026, Hamza Mahfooz wrote:

Conceptually, we shouldn't have to build the VMBus driver to answer the
question "does VMBus exist?" So, move vmbus_root_device and the
functions that access it directly to hyperv.h. Also, introduce
hv_set_vmbus_root_device() to allow vmbus_drv to set the root device.

Reported-by: Arnd Bergmann <[email protected]>
Closes: https://lore.kernel.org/r/[email protected]/
Fixes: f1a9e67c1138 ("mshv: limit SynIC management to MSHV-owned resources")
Signed-off-by: Hamza Mahfooz <[email protected]>
---
drivers/hv/vmbus_drv.c | 27 ++++++---------------------
include/linux/hyperv.h | 18 ++++++++++++++++--
2 files changed, 22 insertions(+), 23 deletions(-)

diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c
index 71f1b4d52f7f..b26e6b42fa49 100644
--- a/drivers/hv/vmbus_drv.c
+++ b/drivers/hv/vmbus_drv.c
@@ -47,9 +47,6 @@ struct vmbus_dynid {
        struct hv_vmbus_device_id id;
};

-/* VMBus Root Device */
-static struct device  *vmbus_root_device;
-
static int hyperv_cpuhp_online;

static DEFINE_PER_CPU(long, vmbus_evt);
@@ -95,18 +92,6 @@ static struct resource *fb_mmio;
static struct resource *hyperv_mmio;
static DEFINE_MUTEX(hyperv_mmio_lock);

-struct device *hv_get_vmbus_root_device(void)
-{
-       return vmbus_root_device;
-}
-EXPORT_SYMBOL_GPL(hv_get_vmbus_root_device);
-
-bool hv_vmbus_exists(void)
-{
-       return vmbus_root_device != NULL;
-}
-EXPORT_SYMBOL_GPL(hv_vmbus_exists);
-
static u8 channel_monitor_group(const struct vmbus_channel *channel)
{
        return (u8)channel->offermsg.monitorid / 32;
@@ -903,7 +888,7 @@ static int vmbus_dma_configure(struct device *child_device)
         * On x86/x64 coherence is assumed and these calls have no effect.
         */
        hv_setup_dma_ops(child_device,
-               device_get_dma_attr(vmbus_root_device) == DEV_DMA_COHERENT);
+               device_get_dma_attr(hv_get_vmbus_root_device()) == 
DEV_DMA_COHERENT);
        return 0;
}

@@ -2172,7 +2157,7 @@ int vmbus_device_register(struct hv_device 
*child_device_obj)
                     &child_device_obj->channel->offermsg.offer.if_instance);

        child_device_obj->device.bus = &hv_bus;
-       child_device_obj->device.parent = vmbus_root_device;
+       child_device_obj->device.parent = hv_get_vmbus_root_device();
        child_device_obj->device.release = vmbus_device_release;

        child_device_obj->device.dma_parms = &child_device_obj->dma_parms;
@@ -2561,7 +2546,7 @@ static int vmbus_acpi_add(struct platform_device *pdev)
        struct acpi_device *ancestor;
        struct acpi_device *device = ACPI_COMPANION(&pdev->dev);

-       vmbus_root_device = &device->dev;
+       hv_set_vmbus_root_device(&device->dev);

        /*
         * Older versions of Hyper-V for ARM64 fail to include the _CCA
@@ -2648,7 +2633,7 @@ static int vmbus_device_add(struct platform_device *pdev)
        struct device_node *np = pdev->dev.of_node;
        int ret;

-       vmbus_root_device = &pdev->dev;
+       hv_set_vmbus_root_device(&pdev->dev);

        ret = of_range_parser_init(&parser, np);
        if (ret)
@@ -2969,7 +2954,7 @@ static int __init hv_acpi_init(void)
        if (ret)
                return ret;

-       if (!vmbus_root_device) {
+       if (!hv_vmbus_exists()) {
                ret = -ENODEV;
                goto cleanup;
        }
@@ -3000,7 +2985,7 @@ static int __init hv_acpi_init(void)

cleanup:
        platform_driver_unregister(&vmbus_platform_driver);
-       vmbus_root_device = NULL;
+       hv_set_vmbus_root_device(NULL);
        return ret;
}

diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h
index 5459e776ec17..3e8ea7d9653c 100644
--- a/include/linux/hyperv.h
+++ b/include/linux/hyperv.h
@@ -1302,9 +1302,23 @@ static inline void *hv_get_drvdata(struct hv_device *dev)
        return dev_get_drvdata(&dev->device);
}

-struct device *hv_get_vmbus_root_device(void);
+/* Do *not* use this outside of hyperv.h */
+static struct device *__vmbus_root_device __read_mostly;

-bool hv_vmbus_exists(void);
+static inline void hv_set_vmbus_root_device(struct device *dev)
+{
+       __vmbus_root_device = dev;
+}
+
+static inline struct device *hv_get_vmbus_root_device(void)
+{
+       return __vmbus_root_device;
+}
+
+static inline bool hv_vmbus_exists(void)
+{
+       return hv_get_vmbus_root_device();
+}

struct hv_ring_buffer_debug_info {
        u32 current_interrupt_mask;
--
2.54.0


Thank you Hamza. Yes, one could do this. It still does not solve the problem of loading MSHV-root first, then VMBUS. The entire hv_vmbus_exists() test is a workaround that mostly works, but shouldn't be there in the first place. What really needs to happen is a SYNIC driver so components can load in arbitrary orders if compiled as modules. Which in turn is outside of my original goal to fix L1VH's kexec. The SYNIC abstraction needs to come no later than the root/nested capability.

Best,
Jork

Reply via email to