From: Jacob Pan Date: Tue, 7 Jan 2025 18:09:18 +0000 (-0800) Subject: hv_balloon: Fallback to generic_online_page() for non-HV hot added mem X-Git-Tag: v6.14-rc1~95^2~4 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=1da602ec36a3e208c070ec23895e84cbb621a12e;p=thirdparty%2Flinux.git hv_balloon: Fallback to generic_online_page() for non-HV hot added mem The Hyper-V balloon driver installs a custom callback for handling page onlining operations performed by the memory hotplug subsystem. This custom callback is global, and overrides the default callback (generic_online_page) that Linux otherwise uses. The custom callback properly handles memory that is hot-added by the balloon driver as part of a Hyper-V hot-add region. But memory can also be hot-added directly by a device driver for a vPCI device, particularly GPUs. In such a case, the custom callback installed by the balloon driver runs, but won't find the page in its hot-add region list and doesn't online it, which could cause driver initialization failures. Fix this by having the balloon custom callback run generic_online_page() when the page isn't part of a Hyper-V hot-add region, thereby doing the default Linux behavior. This allows device driver hot-adds to work properly. Similar cases are handled the same way in the virtio-mem driver. Suggested-by: Vikram Sethi Tested-by: Michael Frohlich Reviewed-by: Michael Kelley Signed-off-by: Jacob Pan Link: https://lore.kernel.org/r/20250107180918.1053933-1-jacob.pan@linux.microsoft.com Signed-off-by: Wei Liu Message-ID: <20250107180918.1053933-1-jacob.pan@linux.microsoft.com> --- diff --git a/drivers/hv/hv_balloon.c b/drivers/hv/hv_balloon.c index 871b73ca3a0fb..fec2f18679e3f 100644 --- a/drivers/hv/hv_balloon.c +++ b/drivers/hv/hv_balloon.c @@ -766,16 +766,18 @@ static void hv_online_page(struct page *pg, unsigned int order) struct hv_hotadd_state *has; unsigned long pfn = page_to_pfn(pg); - guard(spinlock_irqsave)(&dm_device.ha_lock); - list_for_each_entry(has, &dm_device.ha_region_list, list) { - /* The page belongs to a different HAS. */ - if (pfn < has->start_pfn || - (pfn + (1UL << order) > has->end_pfn)) - continue; + scoped_guard(spinlock_irqsave, &dm_device.ha_lock) { + list_for_each_entry(has, &dm_device.ha_region_list, list) { + /* The page belongs to a different HAS. */ + if (pfn < has->start_pfn || + (pfn + (1UL << order) > has->end_pfn)) + continue; - hv_bring_pgs_online(has, pfn, 1UL << order); - break; + hv_bring_pgs_online(has, pfn, 1UL << order); + return; + } } + generic_online_page(pg, order); } static int pfn_covered(unsigned long start_pfn, unsigned long pfn_cnt)