Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

s390/mm: fix set_huge_pte_at() for empty ptes

On s390, the layout of normal and large ptes (i.e. pmds/puds) differs.
Therefore, set_huge_pte_at() does a conversion from a normal pte to
the corresponding large pmd/pud. So, when converting an empty pte, this
should result in an empty pmd/pud, which would return true for
pmd/pud_none().

However, after conversion we also mark the pmd/pud as large, and
therefore present. For empty ptes, this will result in an empty pmd/pud
that is also marked as large, and pmd/pud_none() would not return true.

There is currently no issue with this behaviour, as set_huge_pte_at()
does not seem to be called for empty ptes. It would be valid though, so
let's fix this by not marking empty ptes as large in set_huge_pte_at().

This was found by testing a patch from from Anshuman Khandual, which is
currently discussed on LKML ("mm/debug: Add more arch page table helper
tests").

Signed-off-by: Gerald Schaefer <gerald.schaefer@de.ibm.com>
Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>

authored by

Gerald Schaefer and committed by
Vasily Gorbik
ac8372f3 70b69054

+6 -3
+6 -3
arch/s390/mm/hugetlbpage.c
··· 159 159 rste &= ~_SEGMENT_ENTRY_NOEXEC; 160 160 161 161 /* Set correct table type for 2G hugepages */ 162 - if ((pte_val(*ptep) & _REGION_ENTRY_TYPE_MASK) == _REGION_ENTRY_TYPE_R3) 163 - rste |= _REGION_ENTRY_TYPE_R3 | _REGION3_ENTRY_LARGE; 164 - else 162 + if ((pte_val(*ptep) & _REGION_ENTRY_TYPE_MASK) == _REGION_ENTRY_TYPE_R3) { 163 + if (likely(pte_present(pte))) 164 + rste |= _REGION3_ENTRY_LARGE; 165 + rste |= _REGION_ENTRY_TYPE_R3; 166 + } else if (likely(pte_present(pte))) 165 167 rste |= _SEGMENT_ENTRY_LARGE; 168 + 166 169 clear_huge_pte_skeys(mm, rste); 167 170 pte_val(*ptep) = rste; 168 171 }