euleros inclusion category: feature bugzilla: NA CVE: NA
-------------------------------------------------
We separate the pmem memory and normal dram memory and alloc pages from pmem's peer node when building vmemmap.
Signed-off-by: Shijie Luo luoshijie1@huawei.com Signed-off-by: Kemeng Shi shikemeng@huawei.com Reviewed-by: louhongxiang louhongxiang@huawei.com Signed-off-by: Yuchen Tang tangyuchen5@huawei.com --- drivers/acpi/numa/srat.c | 7 +++++++ drivers/base/node.c | 8 ++++++++ include/linux/etmem.h | 24 ++++++++++++++++++++++++ mm/etmem.c | 27 +++++++++++++++++++++++++++ mm/sparse-vmemmap.c | 10 ++++++++++ 5 files changed, 76 insertions(+)
diff --git a/drivers/acpi/numa/srat.c b/drivers/acpi/numa/srat.c index 12f330b0eac0..59e9532c0f1a 100644 --- a/drivers/acpi/numa/srat.c +++ b/drivers/acpi/numa/srat.c @@ -17,6 +17,7 @@ #include <linux/numa.h> #include <linux/nodemask.h> #include <linux/topology.h> +#include <linux/etmem.h>
static nodemask_t nodes_found_map = NODE_MASK_NONE;
@@ -277,6 +278,12 @@ acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma) }
node_set(node, numa_nodes_parsed); +#ifdef CONFIG_ETMEM + if (ma->flags & ACPI_SRAT_MEM_NON_VOLATILE) + set_node_type(node, NODE_TYPE_PMEM); + else + set_node_type(node, NODE_TYPE_DRAM); +#endif
pr_info("SRAT: Node %u PXM %u [mem %#010Lx-%#010Lx]%s%s\n", node, pxm, diff --git a/drivers/base/node.c b/drivers/base/node.c index f4a7d5590c0c..69f8b93fc171 100644 --- a/drivers/base/node.c +++ b/drivers/base/node.c @@ -570,6 +570,14 @@ static ssize_t node_read_distance(struct device *dev, static DEVICE_ATTR(distance, 0444, node_read_distance, NULL);
#ifdef CONFIG_ETMEM +static ssize_t peer_node_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int nid = dev->id; + struct pglist_data *pgdat = NODE_DATA(nid); + + return sysfs_emit(buf, "%d\n", pgdat->peer_node); +} static DEVICE_ATTR_RO(peer_node); #endif
diff --git a/include/linux/etmem.h b/include/linux/etmem.h index fc19cdc0d567..8f6d7b15d6ea 100644 --- a/include/linux/etmem.h +++ b/include/linux/etmem.h @@ -23,6 +23,30 @@ static inline struct kvm *mm_kvm(struct mm_struct *mm) } #endif
+enum node_type { + NODE_TYPE_DRAM, + NODE_TYPE_PMEM, +}; + +#ifdef CONFIG_NUMA +extern enum node_type nodes_type[MAX_NUMNODES]; +static inline void set_node_type(int nid, enum node_type type) +{ + nodes_type[nid] = type; +} +static inline enum node_type get_node_type(int nid) +{ + return nodes_type[nid]; +} +#else +static inline void set_node_type(int nid, enum node_type type) {} +static inline enum node_type get_node_type(int nid) +{ + return NODE_TYPE_DRAM; +} +#endif + +extern unsigned int sysctl_vmemmap_block_from_dram; extern int add_page_for_swap(struct page *page, struct list_head *pagelist); extern struct page *get_page_from_vaddr(struct mm_struct *mm, unsigned long vaddr); diff --git a/mm/etmem.c b/mm/etmem.c index fe5ca89a4e76..e2ba83583246 100644 --- a/mm/etmem.c +++ b/mm/etmem.c @@ -9,6 +9,11 @@ #include <linux/etmem.h> #include "internal.h"
+unsigned int sysctl_vmemmap_block_from_dram; +#ifdef CONFIG_NUMA +enum node_type nodes_type[MAX_NUMNODES]; +#endif + /* * Return the nearest peer node in terms of *locality* * E.g. peer of node 0 is node 2 per SLIT @@ -37,6 +42,28 @@ int find_best_peer_node(int nid) return peer; }
+#ifdef CONFIG_SYSCTL +static struct ctl_table vm_vmemmap_table[] = { + { + .procname = "vmemmap_block_from_dram", + .data = &sysctl_vmemmap_block_from_dram, + .maxlen = sizeof(sysctl_vmemmap_block_from_dram), + .mode = 0600, + .proc_handler = proc_dointvec_minmax, + .extra1 = SYSCTL_ZERO, + .extra2 = SYSCTL_ONE, + }, + { } +}; + +static int __init vmemmap_sysctl_init(void) +{ + register_sysctl_init("vm", vm_vmemmap_table); + return 0; +} +late_initcall(vmemmap_sysctl_init); +#endif + int add_page_for_swap(struct page *page, struct list_head *pagelist) { int err = -EBUSY; diff --git a/mm/sparse-vmemmap.c b/mm/sparse-vmemmap.c index a2cbe44c48e1..3b954ebdb362 100644 --- a/mm/sparse-vmemmap.c +++ b/mm/sparse-vmemmap.c @@ -30,6 +30,7 @@
#include <asm/dma.h> #include <asm/pgalloc.h> +#include <linux/etmem.h>
/* * Allocate a block of memory to be used to back the virtual memory map @@ -55,6 +56,15 @@ void * __meminit vmemmap_alloc_block(unsigned long size, int node) static bool warned; struct page *page;
+#ifdef CONFIG_ETMEM + /* if node is pmem node, we should alloc_pages from + * it's peer node, because pmem node is not online + * at this time. + */ + if (get_node_type(node) == NODE_TYPE_PMEM && sysctl_vmemmap_block_from_dram) + node = NODE_DATA(node)->peer_node; +#endif + page = alloc_pages_node(node, gfp_mask, order); if (page) return page_address(page);