mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-11 12:28:41 +08:00
mm/memory_hotplug: skip adjust_managed_page_count() for PageOffline() pages when offlining
We currently have a hack for virtio-mem in place to handle memory offlining with PageOffline pages for which we already adjusted the managed page count. Let's enlighten memory offlining code so we can get rid of that hack, and document the situation. Link: https://lkml.kernel.org/r/20240607090939.89524-4-david@redhat.com Signed-off-by: David Hildenbrand <david@redhat.com> Acked-by: Oscar Salvador <osalvador@suse.de> Cc: Alexander Potapenko <glider@google.com> Cc: Dexuan Cui <decui@microsoft.com> Cc: Dmitry Vyukov <dvyukov@google.com> Cc: Eugenio Pérez <eperezma@redhat.com> Cc: Haiyang Zhang <haiyangz@microsoft.com> Cc: Jason Wang <jasowang@redhat.com> Cc: Juergen Gross <jgross@suse.com> Cc: "K. Y. Srinivasan" <kys@microsoft.com> Cc: Marco Elver <elver@google.com> Cc: Michael S. Tsirkin <mst@redhat.com> Cc: Mike Rapoport (IBM) <rppt@kernel.org> Cc: Oleksandr Tyshchenko <oleksandr_tyshchenko@epam.com> Cc: Stefano Stabellini <sstabellini@kernel.org> Cc: Wei Liu <wei.liu@kernel.org> Cc: Xuan Zhuo <xuanzhuo@linux.alibaba.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
This commit is contained in:
parent
412b9d1d0b
commit
9eb3f87f39
@ -1269,12 +1269,6 @@ static void virtio_mem_fake_offline_going_offline(unsigned long pfn,
|
|||||||
struct page *page;
|
struct page *page;
|
||||||
unsigned long i;
|
unsigned long i;
|
||||||
|
|
||||||
/*
|
|
||||||
* Drop our reference to the pages so the memory can get offlined
|
|
||||||
* and add the unplugged pages to the managed page counters (so
|
|
||||||
* offlining code can correctly subtract them again).
|
|
||||||
*/
|
|
||||||
adjust_managed_page_count(pfn_to_page(pfn), nr_pages);
|
|
||||||
/* Drop our reference to the pages so the memory can get offlined. */
|
/* Drop our reference to the pages so the memory can get offlined. */
|
||||||
for (i = 0; i < nr_pages; i++) {
|
for (i = 0; i < nr_pages; i++) {
|
||||||
page = pfn_to_page(pfn + i);
|
page = pfn_to_page(pfn + i);
|
||||||
@ -1293,10 +1287,9 @@ static void virtio_mem_fake_offline_cancel_offline(unsigned long pfn,
|
|||||||
unsigned long i;
|
unsigned long i;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get the reference we dropped when going offline and subtract the
|
* Get the reference again that we dropped via page_ref_dec_and_test()
|
||||||
* unplugged pages from the managed page counters.
|
* when going offline.
|
||||||
*/
|
*/
|
||||||
adjust_managed_page_count(pfn_to_page(pfn), -nr_pages);
|
|
||||||
for (i = 0; i < nr_pages; i++)
|
for (i = 0; i < nr_pages; i++)
|
||||||
page_ref_inc(pfn_to_page(pfn + i));
|
page_ref_inc(pfn_to_page(pfn + i));
|
||||||
}
|
}
|
||||||
|
@ -175,8 +175,8 @@ extern int mhp_init_memmap_on_memory(unsigned long pfn, unsigned long nr_pages,
|
|||||||
extern void mhp_deinit_memmap_on_memory(unsigned long pfn, unsigned long nr_pages);
|
extern void mhp_deinit_memmap_on_memory(unsigned long pfn, unsigned long nr_pages);
|
||||||
extern int online_pages(unsigned long pfn, unsigned long nr_pages,
|
extern int online_pages(unsigned long pfn, unsigned long nr_pages,
|
||||||
struct zone *zone, struct memory_group *group);
|
struct zone *zone, struct memory_group *group);
|
||||||
extern void __offline_isolated_pages(unsigned long start_pfn,
|
extern unsigned long __offline_isolated_pages(unsigned long start_pfn,
|
||||||
unsigned long end_pfn);
|
unsigned long end_pfn);
|
||||||
|
|
||||||
typedef void (*online_page_callback_t)(struct page *page, unsigned int order);
|
typedef void (*online_page_callback_t)(struct page *page, unsigned int order);
|
||||||
|
|
||||||
|
@ -1024,11 +1024,15 @@ PAGE_TYPE_OPS(Buddy, buddy, buddy)
|
|||||||
* putting them back to the buddy, it can do so via the memory notifier by
|
* putting them back to the buddy, it can do so via the memory notifier by
|
||||||
* decrementing the reference count in MEM_GOING_OFFLINE and incrementing the
|
* decrementing the reference count in MEM_GOING_OFFLINE and incrementing the
|
||||||
* reference count in MEM_CANCEL_OFFLINE. When offlining, the PageOffline()
|
* reference count in MEM_CANCEL_OFFLINE. When offlining, the PageOffline()
|
||||||
* pages (now with a reference count of zero) are treated like free pages,
|
* pages (now with a reference count of zero) are treated like free (unmanaged)
|
||||||
* allowing the containing memory block to get offlined. A driver that
|
* pages, allowing the containing memory block to get offlined. A driver that
|
||||||
* relies on this feature is aware that re-onlining the memory block will
|
* relies on this feature is aware that re-onlining the memory block will
|
||||||
* require not giving them to the buddy via generic_online_page().
|
* require not giving them to the buddy via generic_online_page().
|
||||||
*
|
*
|
||||||
|
* Memory offlining code will not adjust the managed page count for any
|
||||||
|
* PageOffline() pages, treating them like they were never exposed to the
|
||||||
|
* buddy using generic_online_page().
|
||||||
|
*
|
||||||
* There are drivers that mark a page PageOffline() and expect there won't be
|
* There are drivers that mark a page PageOffline() and expect there won't be
|
||||||
* any further access to page content. PFN walkers that read content of random
|
* any further access to page content. PFN walkers that read content of random
|
||||||
* pages should check PageOffline() and synchronize with such drivers using
|
* pages should check PageOffline() and synchronize with such drivers using
|
||||||
|
@ -1941,7 +1941,7 @@ int __ref offline_pages(unsigned long start_pfn, unsigned long nr_pages,
|
|||||||
struct zone *zone, struct memory_group *group)
|
struct zone *zone, struct memory_group *group)
|
||||||
{
|
{
|
||||||
const unsigned long end_pfn = start_pfn + nr_pages;
|
const unsigned long end_pfn = start_pfn + nr_pages;
|
||||||
unsigned long pfn, system_ram_pages = 0;
|
unsigned long pfn, managed_pages, system_ram_pages = 0;
|
||||||
const int node = zone_to_nid(zone);
|
const int node = zone_to_nid(zone);
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
struct memory_notify arg;
|
struct memory_notify arg;
|
||||||
@ -2062,7 +2062,7 @@ int __ref offline_pages(unsigned long start_pfn, unsigned long nr_pages,
|
|||||||
} while (ret);
|
} while (ret);
|
||||||
|
|
||||||
/* Mark all sections offline and remove free pages from the buddy. */
|
/* Mark all sections offline and remove free pages from the buddy. */
|
||||||
__offline_isolated_pages(start_pfn, end_pfn);
|
managed_pages = __offline_isolated_pages(start_pfn, end_pfn);
|
||||||
pr_debug("Offlined Pages %ld\n", nr_pages);
|
pr_debug("Offlined Pages %ld\n", nr_pages);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2078,7 +2078,7 @@ int __ref offline_pages(unsigned long start_pfn, unsigned long nr_pages,
|
|||||||
zone_pcp_enable(zone);
|
zone_pcp_enable(zone);
|
||||||
|
|
||||||
/* removal success */
|
/* removal success */
|
||||||
adjust_managed_page_count(pfn_to_page(start_pfn), -nr_pages);
|
adjust_managed_page_count(pfn_to_page(start_pfn), -managed_pages);
|
||||||
adjust_present_page_count(pfn_to_page(start_pfn), group, -nr_pages);
|
adjust_present_page_count(pfn_to_page(start_pfn), group, -nr_pages);
|
||||||
|
|
||||||
/* reinitialise watermarks and update pcp limits */
|
/* reinitialise watermarks and update pcp limits */
|
||||||
|
@ -6713,14 +6713,19 @@ void zone_pcp_reset(struct zone *zone)
|
|||||||
/*
|
/*
|
||||||
* All pages in the range must be in a single zone, must not contain holes,
|
* All pages in the range must be in a single zone, must not contain holes,
|
||||||
* must span full sections, and must be isolated before calling this function.
|
* must span full sections, and must be isolated before calling this function.
|
||||||
|
*
|
||||||
|
* Returns the number of managed (non-PageOffline()) pages in the range: the
|
||||||
|
* number of pages for which memory offlining code must adjust managed page
|
||||||
|
* counters using adjust_managed_page_count().
|
||||||
*/
|
*/
|
||||||
void __offline_isolated_pages(unsigned long start_pfn, unsigned long end_pfn)
|
unsigned long __offline_isolated_pages(unsigned long start_pfn,
|
||||||
|
unsigned long end_pfn)
|
||||||
{
|
{
|
||||||
|
unsigned long already_offline = 0, flags;
|
||||||
unsigned long pfn = start_pfn;
|
unsigned long pfn = start_pfn;
|
||||||
struct page *page;
|
struct page *page;
|
||||||
struct zone *zone;
|
struct zone *zone;
|
||||||
unsigned int order;
|
unsigned int order;
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
offline_mem_sections(pfn, end_pfn);
|
offline_mem_sections(pfn, end_pfn);
|
||||||
zone = page_zone(pfn_to_page(pfn));
|
zone = page_zone(pfn_to_page(pfn));
|
||||||
@ -6742,6 +6747,7 @@ void __offline_isolated_pages(unsigned long start_pfn, unsigned long end_pfn)
|
|||||||
if (PageOffline(page)) {
|
if (PageOffline(page)) {
|
||||||
BUG_ON(page_count(page));
|
BUG_ON(page_count(page));
|
||||||
BUG_ON(PageBuddy(page));
|
BUG_ON(PageBuddy(page));
|
||||||
|
already_offline++;
|
||||||
pfn++;
|
pfn++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -6754,6 +6760,8 @@ void __offline_isolated_pages(unsigned long start_pfn, unsigned long end_pfn)
|
|||||||
pfn += (1 << order);
|
pfn += (1 << order);
|
||||||
}
|
}
|
||||||
spin_unlock_irqrestore(&zone->lock, flags);
|
spin_unlock_irqrestore(&zone->lock, flags);
|
||||||
|
|
||||||
|
return end_pfn - start_pfn - already_offline;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user