Files
Centos-kernel-stream-9/include/linux/memory.h
T
Thomas Huth d178d61f7c mm/memory_hotplug: introduce MEM_PREPARE_ONLINE/MEM_FINISH_OFFLINE notifiers
JIRA: https://issues.redhat.com/browse/RHEL-86670

commit c5f1e2d1890935a734c302b9b8579748222b8e1e
Author: Sumanth Korikkar <sumanthk@linux.ibm.com>
Date:   Mon Jan 8 14:27:43 2024 +0100

    mm/memory_hotplug: introduce MEM_PREPARE_ONLINE/MEM_FINISH_OFFLINE notifiers

    Patch series "implement "memmap on memory" feature on s390".

    This series provides "memmap on memory" support on s390 platform.  "memmap
    on memory" allows struct pages array to be allocated from the hotplugged
    memory range instead of allocating it from main system memory.

    s390 currently preallocates struct pages array for all potentially
    possible memory, which ensures memory onlining always succeeds, but with
    the cost of significant memory consumption from the available system
    memory during boottime.  In certain extreme configuration, this could lead
    to ipl failure.

    "memmap on memory" ensures struct pages array are populated from self
    contained hotplugged memory range instead of depleting the available
    system memory and this could eliminate ipl failure on s390 platform.

    On other platforms, system might go OOM when the physically hotplugged
    memory depletes the available memory before it is onlined.  Hence, "memmap
    on memory" feature was introduced as described in commit a08a2ae346
    ("mm,memory_hotplug: allocate memmap from the added memory range").

    Unlike other architectures, s390 memory blocks are not physically
    accessible until it is online.  To make it physically accessible two new
    memory notifiers MEM_PREPARE_ONLINE / MEM_FINISH_OFFLINE are added and
    this notifier lets the hypervisor inform that the memory should be made
    physically accessible.  This allows for "memmap on memory" initialization
    during memory hotplug onlining phase, which is performed before calling
    MEM_GOING_ONLINE notifier.

    Patch 1 introduces MEM_PREPARE_ONLINE/MEM_FINISH_OFFLINE memory notifiers
    to prepare the transition of memory to and from a physically accessible
    state.  New mhp_flag MHP_OFFLINE_INACCESSIBLE is introduced to ensure
    altmap cannot be written when adding memory - before it is set online.
    This enhancement is crucial for implementing the "memmap on memory"
    feature for s390 in a subsequent patch.

    Patches 2 allocates vmemmap pages from self-contained memory range for
    s390.  It allocates memory map (struct pages array) from the hotplugged
    memory range, rather than using system memory by passing altmap to vmemmap
    functions.

    Patch 3 removes unhandled memory notifier types on s390.

    Patch 4 implements MEM_PREPARE_ONLINE/MEM_FINISH_OFFLINE memory notifiers
    on s390.  MEM_PREPARE_ONLINE memory notifier makes memory block physical
    accessible via sclp assign command.  The notifier ensures self-contained
    memory maps are accessible and hence enabling the "memmap on memory" on
    s390.  MEM_FINISH_OFFLINE memory notifier shifts the memory block to an
    inaccessible state via sclp unassign command.

    Patch 5 finally enables MHP_MEMMAP_ON_MEMORY on s390.

    This patch (of 5):

    Introduce MEM_PREPARE_ONLINE/MEM_FINISH_OFFLINE memory notifiers to
    prepare the transition of memory to and from a physically accessible
    state.  This enhancement is crucial for implementing the "memmap on
    memory" feature for s390 in a subsequent patch.

    Platforms such as x86 can support physical memory hotplug via ACPI.  When
    there is physical memory hotplug, ACPI event leads to the memory addition
    with the following callchain:

    acpi_memory_device_add()
      -> acpi_memory_enable_device()
         -> __add_memory()

    After this, the hotplugged memory is physically accessible, and altmap
    support prepared, before the "memmap on memory" initialization in
    memory_block_online() is called.

    On s390, memory hotplug works in a different way.  The available hotplug
    memory has to be defined upfront in the hypervisor, but it is made
    physically accessible only when the user sets it online via sysfs,
    currently in the MEM_GOING_ONLINE notifier.  This is too late and "memmap
    on memory" initialization is performed before calling MEM_GOING_ONLINE
    notifier.

    During the memory hotplug addition phase, altmap support is prepared and
    during the memory onlining phase s390 requires memory to be physically
    accessible and then subsequently initiate the "memmap on memory"
    initialization process.

    The memory provider will handle new MEM_PREPARE_ONLINE /
    MEM_FINISH_OFFLINE notifications and make the memory accessible.

    The mhp_flag MHP_OFFLINE_INACCESSIBLE is introduced and is relevant when
    used along with MHP_MEMMAP_ON_MEMORY, because the altmap cannot be written
    (e.g., poisoned) when adding memory -- before it is set online.  This
    allows for adding memory with an altmap that is not currently made
    available by a hypervisor.  When onlining that memory, the hypervisor can
    be instructed to make that memory accessible via the new notifiers and the
    onlining phase will not require any memory allocations, which is helpful
    in low-memory situations.

    All architectures ignore unknown memory notifiers.  Therefore, the
    introduction of these new notifiers does not result in any functional
    modifications across architectures.

    Link: https://lkml.kernel.org/r/20240108132747.3238763-1-sumanthk@linux.ibm.com
    Link: https://lkml.kernel.org/r/20240108132747.3238763-2-sumanthk@linux.ibm.com
    Signed-off-by: Sumanth Korikkar <sumanthk@linux.ibm.com>
    Suggested-by: Gerald Schaefer <gerald.schaefer@linux.ibm.com>
    Suggested-by: David Hildenbrand <david@redhat.com>
    Acked-by: David Hildenbrand <david@redhat.com>
    Cc: Alexander Gordeev <agordeev@linux.ibm.com>
    Cc: Aneesh Kumar K.V <aneesh.kumar@linux.ibm.com>
    Cc: Anshuman Khandual <anshuman.khandual@arm.com>
    Cc: Heiko Carstens <hca@linux.ibm.com>
    Cc: Michal Hocko <mhocko@suse.com>
    Cc: Oscar Salvador <osalvador@suse.de>
    Cc: Vasily Gorbik <gor@linux.ibm.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

Conflicts:
    include/linux/memremap.h
    (contextual conflict due to the RH_KABI_RESERVE() macros there)
    mm/memory_hotplug.c
    (contextual conflict due to earlier out-of-order backports)
Signed-off-by: Thomas Huth <thuth@redhat.com>
2025-05-12 13:03:03 +02:00

194 lines
6.5 KiB
C

/* SPDX-License-Identifier: GPL-2.0 */
/*
* include/linux/memory.h - generic memory definition
*
* This is mainly for topological representation. We define the
* basic "struct memory_block" here, which can be embedded in per-arch
* definitions or NUMA information.
*
* Basic handling of the devices is done in drivers/base/memory.c
* and system devices are handled in drivers/base/sys.c.
*
* Memory block are exported via sysfs in the class/memory/devices/
* directory.
*
*/
#ifndef _LINUX_MEMORY_H_
#define _LINUX_MEMORY_H_
#include <linux/node.h>
#include <linux/compiler.h>
#include <linux/mutex.h>
#define MIN_MEMORY_BLOCK_SIZE (1UL << SECTION_SIZE_BITS)
/**
* struct memory_group - a logical group of memory blocks
* @nid: The node id for all memory blocks inside the memory group.
* @blocks: List of all memory blocks belonging to this memory group.
* @present_kernel_pages: Present (online) memory outside ZONE_MOVABLE of this
* memory group.
* @present_movable_pages: Present (online) memory in ZONE_MOVABLE of this
* memory group.
* @is_dynamic: The memory group type: static vs. dynamic
* @s.max_pages: Valid with &memory_group.is_dynamic == false. The maximum
* number of pages we'll have in this static memory group.
* @d.unit_pages: Valid with &memory_group.is_dynamic == true. Unit in pages
* in which memory is added/removed in this dynamic memory group.
* This granularity defines the alignment of a unit in physical
* address space; it has to be at least as big as a single
* memory block.
*
* A memory group logically groups memory blocks; each memory block
* belongs to at most one memory group. A memory group corresponds to
* a memory device, such as a DIMM or a NUMA node, which spans multiple
* memory blocks and might even span multiple non-contiguous physical memory
* ranges.
*
* Modification of members after registration is serialized by memory
* hot(un)plug code.
*/
struct memory_group {
int nid;
struct list_head memory_blocks;
unsigned long present_kernel_pages;
unsigned long present_movable_pages;
bool is_dynamic;
union {
struct {
unsigned long max_pages;
} s;
struct {
unsigned long unit_pages;
} d;
};
};
struct memory_block {
unsigned long start_section_nr;
unsigned long state; /* serialized by the dev->lock */
int online_type; /* for passing data to online routine */
int nid; /* NID for this memory block */
/*
* The single zone of this memory block if all PFNs of this memory block
* that are System RAM (not a memory hole, not ZONE_DEVICE ranges) are
* managed by a single zone. NULL if multiple zones (including nodes)
* apply.
*/
struct zone *zone;
struct device dev;
struct vmem_altmap *altmap;
struct memory_group *group; /* group (if any) for this block */
struct list_head group_next; /* next block inside memory group */
#if defined(CONFIG_MEMORY_FAILURE) && defined(CONFIG_MEMORY_HOTPLUG)
atomic_long_t nr_hwpoison;
#endif
};
int arch_get_memory_phys_device(unsigned long start_pfn);
unsigned long memory_block_size_bytes(void);
int set_memory_block_size_order(unsigned int order);
/* These states are exposed to userspace as text strings in sysfs */
#define MEM_ONLINE (1<<0) /* exposed to userspace */
#define MEM_GOING_OFFLINE (1<<1) /* exposed to userspace */
#define MEM_OFFLINE (1<<2) /* exposed to userspace */
#define MEM_GOING_ONLINE (1<<3)
#define MEM_CANCEL_ONLINE (1<<4)
#define MEM_CANCEL_OFFLINE (1<<5)
#define MEM_PREPARE_ONLINE (1<<6)
#define MEM_FINISH_OFFLINE (1<<7)
struct memory_notify {
/*
* The altmap_start_pfn and altmap_nr_pages fields are designated for
* specifying the altmap range and are exclusively intended for use in
* MEM_PREPARE_ONLINE/MEM_FINISH_OFFLINE notifiers.
*/
unsigned long altmap_start_pfn;
unsigned long altmap_nr_pages;
unsigned long start_pfn;
unsigned long nr_pages;
int status_change_nid_normal;
int status_change_nid;
};
struct notifier_block;
struct mem_section;
/*
* Priorities for the hotplug memory callback routines (stored in decreasing
* order in the callback chain)
*/
#define DEFAULT_CALLBACK_PRI 0
#define SLAB_CALLBACK_PRI 1
#define HMAT_CALLBACK_PRI 2
#define CXL_CALLBACK_PRI 5
#define MM_COMPUTE_BATCH_PRI 10
#define CPUSET_CALLBACK_PRI 10
#define MEMTIER_HOTPLUG_PRI 100
#define KSM_CALLBACK_PRI 100
#ifndef CONFIG_MEMORY_HOTPLUG
static inline void memory_dev_init(void)
{
return;
}
static inline int register_memory_notifier(struct notifier_block *nb)
{
return 0;
}
static inline void unregister_memory_notifier(struct notifier_block *nb)
{
}
static inline int memory_notify(unsigned long val, void *v)
{
return 0;
}
static inline int hotplug_memory_notifier(notifier_fn_t fn, int pri)
{
return 0;
}
#else /* CONFIG_MEMORY_HOTPLUG */
extern int register_memory_notifier(struct notifier_block *nb);
extern void unregister_memory_notifier(struct notifier_block *nb);
int create_memory_block_devices(unsigned long start, unsigned long size,
struct vmem_altmap *altmap,
struct memory_group *group);
void remove_memory_block_devices(unsigned long start, unsigned long size);
extern void memory_dev_init(void);
extern int memory_notify(unsigned long val, void *v);
extern struct memory_block *find_memory_block(unsigned long section_nr);
typedef int (*walk_memory_blocks_func_t)(struct memory_block *, void *);
extern int walk_memory_blocks(unsigned long start, unsigned long size,
void *arg, walk_memory_blocks_func_t func);
extern int for_each_memory_block(void *arg, walk_memory_blocks_func_t func);
#define CONFIG_MEM_BLOCK_SIZE (PAGES_PER_SECTION<<PAGE_SHIFT)
extern int memory_group_register_static(int nid, unsigned long max_pages);
extern int memory_group_register_dynamic(int nid, unsigned long unit_pages);
extern int memory_group_unregister(int mgid);
struct memory_group *memory_group_find_by_id(int mgid);
typedef int (*walk_memory_groups_func_t)(struct memory_group *, void *);
int walk_dynamic_memory_groups(int nid, walk_memory_groups_func_t func,
struct memory_group *excluded, void *arg);
#define hotplug_memory_notifier(fn, pri) ({ \
static __meminitdata struct notifier_block fn##_mem_nb =\
{ .notifier_call = fn, .priority = pri };\
register_memory_notifier(&fn##_mem_nb); \
})
#ifdef CONFIG_NUMA
void memory_block_add_nid(struct memory_block *mem, int nid,
enum meminit_context context);
#endif /* CONFIG_NUMA */
#endif /* CONFIG_MEMORY_HOTPLUG */
/*
* Kernel text modification mutex, used for code patching. Users of this lock
* can sleep.
*/
extern struct mutex text_mutex;
#endif /* _LINUX_MEMORY_H_ */