Skip to content

Commit 3afdfca

Browse files
committed
s390/mm: Clear skeys for newly mapped huge guest pmds
Similarly to the pte skey handling, where we set the storage key to the default key for each newly mapped pte, we have to also do that for huge pmds. With the PG_arch_1 flag we keep track if the area has already been cleared of its skeys. Signed-off-by: Janosch Frank <frankja@linux.ibm.com> Reviewed-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
1 parent 964c2c0 commit 3afdfca

File tree

3 files changed

+30
-1
lines changed

3 files changed

+30
-1
lines changed

arch/s390/include/asm/hugetlb.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,10 @@ static inline int prepare_hugepage_range(struct file *file,
3737
return 0;
3838
}
3939

40-
#define arch_clear_hugepage_flags(page) do { } while (0)
40+
static inline void arch_clear_hugepage_flags(struct page *page)
41+
{
42+
clear_bit(PG_arch_1, &page->flags);
43+
}
4144

4245
static inline void huge_pte_clear(struct mm_struct *mm, unsigned long addr,
4346
pte_t *ptep, unsigned long sz)

arch/s390/mm/gmap.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2553,6 +2553,7 @@ static int __s390_enable_skey_hugetlb(pte_t *pte, unsigned long addr,
25532553
{
25542554
pmd_t *pmd = (pmd_t *)pte;
25552555
unsigned long start, end;
2556+
struct page *page = pmd_page(*pmd);
25562557

25572558
/*
25582559
* The write check makes sure we do not set a key on shared
@@ -2567,6 +2568,7 @@ static int __s390_enable_skey_hugetlb(pte_t *pte, unsigned long addr,
25672568
start = pmd_val(*pmd) & HPAGE_MASK;
25682569
end = start + HPAGE_SIZE - 1;
25692570
__storage_key_init_range(start, end);
2571+
set_bit(PG_arch_1, &page->flags);
25702572
return 0;
25712573
}
25722574

arch/s390/mm/hugetlbpage.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,29 @@ static inline pte_t __rste_to_pte(unsigned long rste)
123123
return pte;
124124
}
125125

126+
static void clear_huge_pte_skeys(struct mm_struct *mm, unsigned long rste)
127+
{
128+
struct page *page;
129+
unsigned long size, paddr;
130+
131+
if (!mm_uses_skeys(mm) ||
132+
rste & _SEGMENT_ENTRY_INVALID)
133+
return;
134+
135+
if ((rste & _REGION_ENTRY_TYPE_MASK) == _REGION_ENTRY_TYPE_R3) {
136+
page = pud_page(__pud(rste));
137+
size = PUD_SIZE;
138+
paddr = rste & PUD_MASK;
139+
} else {
140+
page = pmd_page(__pmd(rste));
141+
size = PMD_SIZE;
142+
paddr = rste & PMD_MASK;
143+
}
144+
145+
if (!test_and_set_bit(PG_arch_1, &page->flags))
146+
__storage_key_init_range(paddr, paddr + size - 1);
147+
}
148+
126149
void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
127150
pte_t *ptep, pte_t pte)
128151
{
@@ -137,6 +160,7 @@ void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
137160
rste |= _REGION_ENTRY_TYPE_R3 | _REGION3_ENTRY_LARGE;
138161
else
139162
rste |= _SEGMENT_ENTRY_LARGE;
163+
clear_huge_pte_skeys(mm, rste);
140164
pte_val(*ptep) = rste;
141165
}
142166

0 commit comments

Comments
 (0)