Commit 37cd944c authored by Heiko Carstens's avatar Heiko Carstens Committed by Martin Schwidefsky

s390/pgtable: add mapping statistics

Add statistics that show how memory is mapped within the kernel
identity mapping. This is more or less the same like git
commit ce0c0e50 ("x86, generic: CPA add statistics about state
of direct mapping v4") for x86.

I also intentionally copied the lower case "k" within DirectMap4k vs
the upper case "M" and "G" within the two other lines. Let's have
consistent inconsistencies across architectures.

The output of /proc/meminfo now contains these additional lines:

DirectMap4k:        2048 kB
DirectMap1M:     3991552 kB
DirectMap2G:     4194304 kB

The implementation on s390 is lockless unlike the x86 version, since I
assume changes to the kernel mapping are a very rare event. Therefore
it really doesn't matter if these statistics could potentially be
inconsistent if read while kernel pages tables are being changed.
Signed-off-by: default avatarHeiko Carstens <heiko.carstens@de.ibm.com>
Acked-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent bab247ff
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include <linux/mm_types.h> #include <linux/mm_types.h>
#include <linux/page-flags.h> #include <linux/page-flags.h>
#include <linux/radix-tree.h> #include <linux/radix-tree.h>
#include <linux/atomic.h>
#include <asm/bug.h> #include <asm/bug.h>
#include <asm/page.h> #include <asm/page.h>
...@@ -37,6 +38,24 @@ extern void vmem_map_init(void); ...@@ -37,6 +38,24 @@ extern void vmem_map_init(void);
pmd_t *vmem_pmd_alloc(void); pmd_t *vmem_pmd_alloc(void);
pte_t *vmem_pte_alloc(void); pte_t *vmem_pte_alloc(void);
enum {
PG_DIRECT_MAP_4K = 0,
PG_DIRECT_MAP_1M,
PG_DIRECT_MAP_2G,
PG_DIRECT_MAP_MAX
};
extern atomic_long_t direct_pages_count[PG_DIRECT_MAP_MAX];
static inline void update_page_count(int level, long count)
{
if (IS_ENABLED(CONFIG_PROC_FS))
atomic_long_add(count, &direct_pages_count[level]);
}
struct seq_file;
void arch_report_meminfo(struct seq_file *m);
/* /*
* The S390 doesn't have any external MMU info: the kernel page * The S390 doesn't have any external MMU info: the kernel page
* tables contain all the necessary information. * tables contain all the necessary information.
......
...@@ -40,6 +40,20 @@ void __storage_key_init_range(unsigned long start, unsigned long end) ...@@ -40,6 +40,20 @@ void __storage_key_init_range(unsigned long start, unsigned long end)
} }
#endif #endif
#ifdef CONFIG_PROC_FS
atomic_long_t direct_pages_count[PG_DIRECT_MAP_MAX];
void arch_report_meminfo(struct seq_file *m)
{
seq_printf(m, "DirectMap4k: %8lu kB\n",
atomic_long_read(&direct_pages_count[PG_DIRECT_MAP_4K]) << 2);
seq_printf(m, "DirectMap1M: %8lu kB\n",
atomic_long_read(&direct_pages_count[PG_DIRECT_MAP_1M]) << 10);
seq_printf(m, "DirectMap2G: %8lu kB\n",
atomic_long_read(&direct_pages_count[PG_DIRECT_MAP_2G]) << 21);
}
#endif /* CONFIG_PROC_FS */
static void pgt_set(unsigned long *old, unsigned long new, unsigned long addr, static void pgt_set(unsigned long *old, unsigned long new, unsigned long addr,
unsigned long dtt) unsigned long dtt)
{ {
...@@ -114,6 +128,8 @@ static int split_pmd_page(pmd_t *pmdp, unsigned long addr) ...@@ -114,6 +128,8 @@ static int split_pmd_page(pmd_t *pmdp, unsigned long addr)
} }
pmd_val(new) = __pa(pt_dir) | _SEGMENT_ENTRY; pmd_val(new) = __pa(pt_dir) | _SEGMENT_ENTRY;
pgt_set((unsigned long *)pmdp, pmd_val(new), addr, CRDTE_DTT_SEGMENT); pgt_set((unsigned long *)pmdp, pmd_val(new), addr, CRDTE_DTT_SEGMENT);
update_page_count(PG_DIRECT_MAP_4K, PTRS_PER_PTE);
update_page_count(PG_DIRECT_MAP_1M, -1);
return 0; return 0;
} }
...@@ -181,6 +197,8 @@ static int split_pud_page(pud_t *pudp, unsigned long addr) ...@@ -181,6 +197,8 @@ static int split_pud_page(pud_t *pudp, unsigned long addr)
} }
pud_val(new) = __pa(pm_dir) | _REGION3_ENTRY; pud_val(new) = __pa(pm_dir) | _REGION3_ENTRY;
pgt_set((unsigned long *)pudp, pud_val(new), addr, CRDTE_DTT_REGION3); pgt_set((unsigned long *)pudp, pud_val(new), addr, CRDTE_DTT_REGION3);
update_page_count(PG_DIRECT_MAP_1M, PTRS_PER_PMD);
update_page_count(PG_DIRECT_MAP_2G, -1);
return 0; return 0;
} }
......
...@@ -80,6 +80,7 @@ pte_t __ref *vmem_pte_alloc(void) ...@@ -80,6 +80,7 @@ pte_t __ref *vmem_pte_alloc(void)
*/ */
static int vmem_add_mem(unsigned long start, unsigned long size) static int vmem_add_mem(unsigned long start, unsigned long size)
{ {
unsigned long pages4k, pages1m, pages2g;
unsigned long end = start + size; unsigned long end = start + size;
unsigned long address = start; unsigned long address = start;
pgd_t *pg_dir; pgd_t *pg_dir;
...@@ -88,6 +89,7 @@ static int vmem_add_mem(unsigned long start, unsigned long size) ...@@ -88,6 +89,7 @@ static int vmem_add_mem(unsigned long start, unsigned long size)
pte_t *pt_dir; pte_t *pt_dir;
int ret = -ENOMEM; int ret = -ENOMEM;
pages4k = pages1m = pages2g = 0;
while (address < end) { while (address < end) {
pg_dir = pgd_offset_k(address); pg_dir = pgd_offset_k(address);
if (pgd_none(*pg_dir)) { if (pgd_none(*pg_dir)) {
...@@ -102,6 +104,7 @@ static int vmem_add_mem(unsigned long start, unsigned long size) ...@@ -102,6 +104,7 @@ static int vmem_add_mem(unsigned long start, unsigned long size)
!debug_pagealloc_enabled()) { !debug_pagealloc_enabled()) {
pud_val(*pu_dir) = address | pgprot_val(REGION3_KERNEL); pud_val(*pu_dir) = address | pgprot_val(REGION3_KERNEL);
address += PUD_SIZE; address += PUD_SIZE;
pages2g++;
continue; continue;
} }
if (pud_none(*pu_dir)) { if (pud_none(*pu_dir)) {
...@@ -116,6 +119,7 @@ static int vmem_add_mem(unsigned long start, unsigned long size) ...@@ -116,6 +119,7 @@ static int vmem_add_mem(unsigned long start, unsigned long size)
!debug_pagealloc_enabled()) { !debug_pagealloc_enabled()) {
pmd_val(*pm_dir) = address | pgprot_val(SEGMENT_KERNEL); pmd_val(*pm_dir) = address | pgprot_val(SEGMENT_KERNEL);
address += PMD_SIZE; address += PMD_SIZE;
pages1m++;
continue; continue;
} }
if (pmd_none(*pm_dir)) { if (pmd_none(*pm_dir)) {
...@@ -128,9 +132,13 @@ static int vmem_add_mem(unsigned long start, unsigned long size) ...@@ -128,9 +132,13 @@ static int vmem_add_mem(unsigned long start, unsigned long size)
pt_dir = pte_offset_kernel(pm_dir, address); pt_dir = pte_offset_kernel(pm_dir, address);
pte_val(*pt_dir) = address | pgprot_val(PAGE_KERNEL); pte_val(*pt_dir) = address | pgprot_val(PAGE_KERNEL);
address += PAGE_SIZE; address += PAGE_SIZE;
pages4k++;
} }
ret = 0; ret = 0;
out: out:
update_page_count(PG_DIRECT_MAP_4K, pages4k);
update_page_count(PG_DIRECT_MAP_1M, pages1m);
update_page_count(PG_DIRECT_MAP_2G, pages2g);
return ret; return ret;
} }
...@@ -140,6 +148,7 @@ static int vmem_add_mem(unsigned long start, unsigned long size) ...@@ -140,6 +148,7 @@ static int vmem_add_mem(unsigned long start, unsigned long size)
*/ */
static void vmem_remove_range(unsigned long start, unsigned long size) static void vmem_remove_range(unsigned long start, unsigned long size)
{ {
unsigned long pages4k, pages1m, pages2g;
unsigned long end = start + size; unsigned long end = start + size;
unsigned long address = start; unsigned long address = start;
pgd_t *pg_dir; pgd_t *pg_dir;
...@@ -147,6 +156,7 @@ static void vmem_remove_range(unsigned long start, unsigned long size) ...@@ -147,6 +156,7 @@ static void vmem_remove_range(unsigned long start, unsigned long size)
pmd_t *pm_dir; pmd_t *pm_dir;
pte_t *pt_dir; pte_t *pt_dir;
pages4k = pages1m = pages2g = 0;
while (address < end) { while (address < end) {
pg_dir = pgd_offset_k(address); pg_dir = pgd_offset_k(address);
if (pgd_none(*pg_dir)) { if (pgd_none(*pg_dir)) {
...@@ -161,6 +171,7 @@ static void vmem_remove_range(unsigned long start, unsigned long size) ...@@ -161,6 +171,7 @@ static void vmem_remove_range(unsigned long start, unsigned long size)
if (pud_large(*pu_dir)) { if (pud_large(*pu_dir)) {
pud_clear(pu_dir); pud_clear(pu_dir);
address += PUD_SIZE; address += PUD_SIZE;
pages2g++;
continue; continue;
} }
pm_dir = pmd_offset(pu_dir, address); pm_dir = pmd_offset(pu_dir, address);
...@@ -171,13 +182,18 @@ static void vmem_remove_range(unsigned long start, unsigned long size) ...@@ -171,13 +182,18 @@ static void vmem_remove_range(unsigned long start, unsigned long size)
if (pmd_large(*pm_dir)) { if (pmd_large(*pm_dir)) {
pmd_clear(pm_dir); pmd_clear(pm_dir);
address += PMD_SIZE; address += PMD_SIZE;
pages1m++;
continue; continue;
} }
pt_dir = pte_offset_kernel(pm_dir, address); pt_dir = pte_offset_kernel(pm_dir, address);
pte_clear(&init_mm, address, pt_dir); pte_clear(&init_mm, address, pt_dir);
address += PAGE_SIZE; address += PAGE_SIZE;
pages4k++;
} }
flush_tlb_kernel_range(start, end); flush_tlb_kernel_range(start, end);
update_page_count(PG_DIRECT_MAP_4K, -pages4k);
update_page_count(PG_DIRECT_MAP_1M, -pages1m);
update_page_count(PG_DIRECT_MAP_2G, -pages2g);
} }
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment