Skip to content

Commit a51324c

Browse files
hcahcaVasily Gorbik
authored andcommitted
s390/cmma: rework no-dat handling
Rework the way physical pages are set no-dat / dat: The old way is: - Rely on that all pages are initially marked "dat" - Allocate page tables for the kernel mapping - Enable dat - Walk the whole kernel mapping and set PG_arch_1 bit in all struct pages that belong to pages of kernel page tables - Walk all struct pages and test and clear the PG_arch_1 bit. If the bit is not set, set the page state to no-dat - For all subsequent page table allocations, set the page state to dat (remove the no-dat state) on allocation time Change this rather complex logic to a simpler approach: - Set the whole physical memory (all pages) to "no-dat" - Explicitly set those page table pages to "dat" which are part of the kernel image (e.g. swapper_pg_dir) - For all subsequent page table allocations, set the page state to dat (remove the no-dat state) on allocation time In result the code is simpler, and this also allows to get rid of one odd usage of the PG_arch_1 bit. Reviewed-by: Claudio Imbrenda <imbrenda@linux.ibm.com> Signed-off-by: Heiko Carstens <hca@linux.ibm.com> Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
1 parent 65d37f1 commit a51324c

File tree

5 files changed

+21
-131
lines changed

5 files changed

+21
-131
lines changed

arch/s390/boot/vmem.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#include <linux/sched/task.h>
33
#include <linux/pgtable.h>
44
#include <linux/kasan.h>
5+
#include <asm/page-states.h>
56
#include <asm/pgalloc.h>
67
#include <asm/facility.h>
78
#include <asm/sections.h>
@@ -70,6 +71,10 @@ static void kasan_populate_shadow(void)
7071
crst_table_init((unsigned long *)kasan_early_shadow_pud, pud_val(pud_z));
7172
crst_table_init((unsigned long *)kasan_early_shadow_pmd, pmd_val(pmd_z));
7273
memset64((u64 *)kasan_early_shadow_pte, pte_val(pte_z), PTRS_PER_PTE);
74+
__arch_set_page_dat(kasan_early_shadow_p4d, 1UL << CRST_ALLOC_ORDER);
75+
__arch_set_page_dat(kasan_early_shadow_pud, 1UL << CRST_ALLOC_ORDER);
76+
__arch_set_page_dat(kasan_early_shadow_pmd, 1UL << CRST_ALLOC_ORDER);
77+
__arch_set_page_dat(kasan_early_shadow_pte, 1);
7378

7479
/*
7580
* Current memory layout:
@@ -223,6 +228,7 @@ static void *boot_crst_alloc(unsigned long val)
223228

224229
table = (unsigned long *)physmem_alloc_top_down(RR_VMEM, size, size);
225230
crst_table_init(table, val);
231+
__arch_set_page_dat(table, 1UL << CRST_ALLOC_ORDER);
226232
return table;
227233
}
228234

@@ -238,6 +244,7 @@ static pte_t *boot_pte_alloc(void)
238244
if (!pte_leftover) {
239245
pte_leftover = (void *)physmem_alloc_top_down(RR_VMEM, PAGE_SIZE, PAGE_SIZE);
240246
pte = pte_leftover + _PAGE_TABLE_SIZE;
247+
__arch_set_page_dat(pte, 1);
241248
} else {
242249
pte = pte_leftover;
243250
pte_leftover = NULL;
@@ -418,6 +425,14 @@ void setup_vmem(unsigned long asce_limit)
418425
unsigned long asce_bits;
419426
int i;
420427

428+
/*
429+
* Mark whole memory as no-dat. This must be done before any
430+
* page tables are allocated, or kernel image builtin pages
431+
* are marked as dat tables.
432+
*/
433+
for_each_physmem_online_range(i, &start, &end)
434+
__arch_set_page_nodat((void *)start, (end - start) >> PAGE_SHIFT);
435+
421436
if (asce_limit == _REGION1_SIZE) {
422437
asce_type = _REGION2_ENTRY_EMPTY;
423438
asce_bits = _ASCE_TYPE_REGION2 | _ASCE_TABLE_LENGTH;
@@ -429,6 +444,8 @@ void setup_vmem(unsigned long asce_limit)
429444

430445
crst_table_init((unsigned long *)swapper_pg_dir, asce_type);
431446
crst_table_init((unsigned long *)invalid_pg_dir, _REGION3_ENTRY_EMPTY);
447+
__arch_set_page_dat((void *)swapper_pg_dir, 1UL << CRST_ALLOC_ORDER);
448+
__arch_set_page_dat((void *)invalid_pg_dir, 1UL << CRST_ALLOC_ORDER);
432449

433450
/*
434451
* To allow prefixing the lowcore must be mapped with 4KB pages.

arch/s390/include/asm/setup.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,6 @@ static inline void vmcp_cma_reserve(void) { }
125125

126126
void report_user_fault(struct pt_regs *regs, long signr, int is_mm_fault);
127127

128-
void cmma_init_nodat(void);
129-
130128
extern void (*_machine_restart)(char *command);
131129
extern void (*_machine_halt)(void);
132130
extern void (*_machine_power_off)(void);

arch/s390/mm/init.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -168,8 +168,6 @@ void __init mem_init(void)
168168
/* this will put all low memory onto the freelists */
169169
memblock_free_all();
170170
setup_zero_pages(); /* Setup zeroed pages. */
171-
172-
cmma_init_nodat();
173171
}
174172

175173
void free_initmem(void)

arch/s390/mm/page-states.c

Lines changed: 2 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -7,136 +7,13 @@
77
* Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
88
*/
99

10-
#include <linux/kernel.h>
11-
#include <linux/errno.h>
12-
#include <linux/types.h>
1310
#include <linux/mm.h>
14-
#include <linux/memblock.h>
15-
#include <linux/gfp.h>
16-
#include <linux/init.h>
17-
#include <asm/asm-extable.h>
18-
#include <asm/facility.h>
1911
#include <asm/page-states.h>
12+
#include <asm/sections.h>
13+
#include <asm/page.h>
2014

2115
int __bootdata_preserved(cmma_flag);
2216

23-
static void mark_kernel_pmd(pud_t *pud, unsigned long addr, unsigned long end)
24-
{
25-
unsigned long next;
26-
struct page *page;
27-
pmd_t *pmd;
28-
29-
pmd = pmd_offset(pud, addr);
30-
do {
31-
next = pmd_addr_end(addr, end);
32-
if (pmd_none(*pmd) || pmd_large(*pmd))
33-
continue;
34-
page = phys_to_page(pmd_val(*pmd));
35-
set_bit(PG_arch_1, &page->flags);
36-
} while (pmd++, addr = next, addr != end);
37-
}
38-
39-
static void mark_kernel_pud(p4d_t *p4d, unsigned long addr, unsigned long end)
40-
{
41-
unsigned long next;
42-
struct page *page;
43-
pud_t *pud;
44-
int i;
45-
46-
pud = pud_offset(p4d, addr);
47-
do {
48-
next = pud_addr_end(addr, end);
49-
if (pud_none(*pud) || pud_large(*pud))
50-
continue;
51-
if (!pud_folded(*pud)) {
52-
page = phys_to_page(pud_val(*pud));
53-
for (i = 0; i < 4; i++)
54-
set_bit(PG_arch_1, &page[i].flags);
55-
}
56-
mark_kernel_pmd(pud, addr, next);
57-
} while (pud++, addr = next, addr != end);
58-
}
59-
60-
static void mark_kernel_p4d(pgd_t *pgd, unsigned long addr, unsigned long end)
61-
{
62-
unsigned long next;
63-
struct page *page;
64-
p4d_t *p4d;
65-
int i;
66-
67-
p4d = p4d_offset(pgd, addr);
68-
do {
69-
next = p4d_addr_end(addr, end);
70-
if (p4d_none(*p4d))
71-
continue;
72-
if (!p4d_folded(*p4d)) {
73-
page = phys_to_page(p4d_val(*p4d));
74-
for (i = 0; i < 4; i++)
75-
set_bit(PG_arch_1, &page[i].flags);
76-
}
77-
mark_kernel_pud(p4d, addr, next);
78-
} while (p4d++, addr = next, addr != end);
79-
}
80-
81-
static void mark_kernel_pgd(void)
82-
{
83-
unsigned long addr, next, max_addr;
84-
struct page *page;
85-
pgd_t *pgd;
86-
int i;
87-
88-
addr = 0;
89-
/*
90-
* Figure out maximum virtual address accessible with the
91-
* kernel ASCE. This is required to keep the page table walker
92-
* from accessing non-existent entries.
93-
*/
94-
max_addr = (S390_lowcore.kernel_asce.val & _ASCE_TYPE_MASK) >> 2;
95-
max_addr = 1UL << (max_addr * 11 + 31);
96-
pgd = pgd_offset_k(addr);
97-
do {
98-
next = pgd_addr_end(addr, max_addr);
99-
if (pgd_none(*pgd))
100-
continue;
101-
if (!pgd_folded(*pgd)) {
102-
page = phys_to_page(pgd_val(*pgd));
103-
for (i = 0; i < 4; i++)
104-
set_bit(PG_arch_1, &page[i].flags);
105-
}
106-
mark_kernel_p4d(pgd, addr, next);
107-
} while (pgd++, addr = next, addr != max_addr);
108-
}
109-
110-
void __init cmma_init_nodat(void)
111-
{
112-
struct page *page;
113-
unsigned long start, end, ix;
114-
int i;
115-
116-
if (cmma_flag < 2)
117-
return;
118-
/* Mark pages used in kernel page tables */
119-
mark_kernel_pgd();
120-
page = virt_to_page(&swapper_pg_dir);
121-
for (i = 0; i < 4; i++)
122-
set_bit(PG_arch_1, &page[i].flags);
123-
page = virt_to_page(&invalid_pg_dir);
124-
for (i = 0; i < 4; i++)
125-
set_bit(PG_arch_1, &page[i].flags);
126-
127-
/* Set all kernel pages not used for page tables to stable/no-dat */
128-
for_each_mem_pfn_range(i, MAX_NUMNODES, &start, &end, NULL) {
129-
page = pfn_to_page(start);
130-
for (ix = start; ix < end; ix++, page++) {
131-
if (__test_and_clear_bit(PG_arch_1, &page->flags))
132-
continue; /* skip page table pages */
133-
if (!list_empty(&page->lru))
134-
continue; /* skip free pages */
135-
__set_page_stable_nodat(page_to_virt(page), 1);
136-
}
137-
}
138-
}
139-
14017
void arch_free_page(struct page *page, int order)
14118
{
14219
if (!cmma_flag)

arch/s390/mm/vmem.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,7 @@ void *vmem_crst_alloc(unsigned long val)
5050
if (!table)
5151
return NULL;
5252
crst_table_init(table, val);
53-
if (slab_is_available())
54-
__arch_set_page_dat(table, 1UL << CRST_ALLOC_ORDER);
53+
__arch_set_page_dat(table, 1UL << CRST_ALLOC_ORDER);
5554
return table;
5655
}
5756

@@ -67,6 +66,7 @@ pte_t __ref *vmem_pte_alloc(void)
6766
if (!pte)
6867
return NULL;
6968
memset64((u64 *)pte, _PAGE_INVALID, PTRS_PER_PTE);
69+
__arch_set_page_dat(pte, 1);
7070
return pte;
7171
}
7272

0 commit comments

Comments
 (0)