s390/mm: implement MEM_PREPARE_ONLINE/MEM_FINISH_OFFLINE notifiers
authorSumanth Korikkar <sumanthk@linux.ibm.com>
Mon, 8 Jan 2024 13:27:46 +0000 (14:27 +0100)
committerAndrew Morton <akpm@linux-foundation.org>
Thu, 22 Feb 2024 00:00:02 +0000 (16:00 -0800)
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.

Implementation considerations:
* When MHP_MEMMAP_ON_MEMORY is disabled, the system retains the old
  behavior. This means the memory map is allocated from default memory.
* If MACHINE_HAS_EDAT1 is unavailable, MHP_MEMMAP_ON_MEMORY is
  automatically disabled. This ensures that vmemmap pagetables do not
  consume additional memory from the default memory allocator.
* The MEM_GOING_ONLINE notifier has been modified to perform no
  operation, as MEM_PREPARE_ONLINE already executes the sclp assign
  command.
* The MEM_CANCEL_ONLINE/MEM_OFFLINE notifier now performs no operation, as
  MEM_FINISH_OFFLINE already executes the sclp unassign command.

Link: https://lkml.kernel.org/r/20240108132747.3238763-5-sumanthk@linux.ibm.com
Reviewed-by: Gerald Schaefer <gerald.schaefer@linux.ibm.com>
Reviewed-by: David Hildenbrand <david@redhat.com>
Signed-off-by: Sumanth Korikkar <sumanthk@linux.ibm.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>
drivers/s390/char/sclp_cmd.c

index 355e63e44e9546148053aa85de94d430dbfce913..7815e9bea69a1349a5b73a1aa556577cdf72b47c 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/mm.h>
 #include <linux/mmzone.h>
 #include <linux/memory.h>
+#include <linux/memory_hotplug.h>
 #include <linux/module.h>
 #include <asm/ctlreg.h>
 #include <asm/chpid.h>
@@ -26,6 +27,7 @@
 #include <asm/sclp.h>
 #include <asm/numa.h>
 #include <asm/facility.h>
+#include <asm/page-states.h>
 
 #include "sclp.h"
 
@@ -340,13 +342,38 @@ static int sclp_mem_notifier(struct notifier_block *nb,
                if (contains_standby_increment(start, start + size))
                        rc = -EPERM;
                break;
-       case MEM_GOING_ONLINE:
+       case MEM_PREPARE_ONLINE:
+               /*
+                * Access the altmap_start_pfn and altmap_nr_pages fields
+                * within the struct memory_notify specifically when dealing
+                * with only MEM_PREPARE_ONLINE/MEM_FINISH_OFFLINE notifiers.
+                *
+                * When altmap is in use, take the specified memory range
+                * online, which includes the altmap.
+                */
+               if (arg->altmap_nr_pages) {
+                       start = PFN_PHYS(arg->altmap_start_pfn);
+                       size += PFN_PHYS(arg->altmap_nr_pages);
+               }
                rc = sclp_mem_change_state(start, size, 1);
+               if (rc || !arg->altmap_nr_pages)
+                       break;
+               /*
+                * Set CMMA state to nodat here, since the struct page memory
+                * at the beginning of the memory block will not go through the
+                * buddy allocator later.
+                */
+               __arch_set_page_nodat((void *)__va(start), arg->altmap_nr_pages);
                break;
-       case MEM_CANCEL_ONLINE:
-               sclp_mem_change_state(start, size, 0);
-               break;
-       case MEM_OFFLINE:
+       case MEM_FINISH_OFFLINE:
+               /*
+                * When altmap is in use, take the specified memory range
+                * offline, which includes the altmap.
+                */
+               if (arg->altmap_nr_pages) {
+                       start = PFN_PHYS(arg->altmap_start_pfn);
+                       size += PFN_PHYS(arg->altmap_nr_pages);
+               }
                sclp_mem_change_state(start, size, 0);
                break;
        default:
@@ -397,7 +424,9 @@ static void __init add_memory_merged(u16 rn)
        if (!size)
                goto skip_add;
        for (addr = start; addr < start + size; addr += block_size)
-               add_memory(0, addr, block_size, MHP_NONE);
+               add_memory(0, addr, block_size,
+                          MACHINE_HAS_EDAT1 ?
+                          MHP_MEMMAP_ON_MEMORY | MHP_OFFLINE_INACCESSIBLE : MHP_NONE);
 skip_add:
        first_rn = rn;
        num = 1;