]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
s390/mm: Add PTE_MARKER support for hugetlbfs mappings
authorGerald Schaefer <gerald.schaefer@linux.ibm.com>
Thu, 21 Nov 2024 17:45:23 +0000 (18:45 +0100)
committerHeiko Carstens <hca@linux.ibm.com>
Wed, 27 Nov 2024 11:57:01 +0000 (12:57 +0100)
Commit 8a13897fb0daa ("mm: userfaultfd: support UFFDIO_POISON for
hugetlbfs") added support for PTE_MARKER_POISONED for hugetlbfs, but
PTE_MARKER also needs support for swap entries. For s390, swap entries
were only supported on PTE level, not on the PMD/PUD levels that are used
for large hugetlbfs mappings.

Therefore, when writing a PTE_MARKER_POISONED entry, the resulting entry
on PMD/PUD level would be an invalid / empty entry. Further access would
then generate a pagefault loop, instead of the expected SIGBUS. It is a
loop inside the kernel, but interruptible and uffd fault handling also
calls schedule() in between, so at least it won't completely block the
system.

Previous commits prepared support for swap entries on PMD/PUD levels.
PTE_MARKER support for hugetlbfs can now be enabled by simply adding an
extra is_pte_marker() check to huge_pte_none_mostly(). Fault handling
code also needs to be adjusted to expect the VM_FAULT_HWPOISON_LARGE
fault flag, which was not possible on s390 before.

Reviewed-by: Alexander Gordeev <agordeev@linux.ibm.com>
Signed-off-by: Gerald Schaefer <gerald.schaefer@linux.ibm.com>
Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
arch/s390/include/asm/hugetlb.h
arch/s390/mm/fault.c

index cf1b5d6fb1a6295076d148b1597dd31f0666aaf9..0f621c99b21664b8a771816709b45bba1a6aaa51 100644 (file)
@@ -91,7 +91,7 @@ static inline int huge_pte_none(pte_t pte)
 
 static inline int huge_pte_none_mostly(pte_t pte)
 {
-       return huge_pte_none(pte);
+       return huge_pte_none(pte) || is_pte_marker(pte);
 }
 
 static inline int huge_pte_write(pte_t pte)
index 94cb2e092075538aca02c484f2b4db1a32a04a78..4ca35545010f172473fd9ddaa2898931a9ea060f 100644 (file)
@@ -338,7 +338,8 @@ done:
                        handle_fault_error_nolock(regs, 0);
                else
                        do_sigsegv(regs, SEGV_MAPERR);
-       } else if (fault & (VM_FAULT_SIGBUS | VM_FAULT_HWPOISON)) {
+       } else if (fault & (VM_FAULT_SIGBUS | VM_FAULT_HWPOISON |
+                           VM_FAULT_HWPOISON_LARGE)) {
                if (!user_mode(regs))
                        handle_fault_error_nolock(regs, 0);
                else