diff options
| author | Gerald Schaefer <gerald.schaefer@linux.ibm.com> | 2025-08-21 19:00:03 +0200 |
|---|---|---|
| committer | Alexander Gordeev <agordeev@linux.ibm.com> | 2025-08-26 11:50:05 +0200 |
| commit | 57834ce5a6a47df282c8419019ba5495eac58fb9 (patch) | |
| tree | 7d7ac45abaecb406403ef6c999054d418b00313a | |
| parent | 3868f910440c47cd5d158776be4ba4e2186beda7 (diff) | |
s390/mm: Prevent possible preempt_count overflow
The s390 implementation of ptep_modify_prot_start() currently does
preempt_disable(), and the preempt_enable() is done later in
ptep_modify_prot_commit(). This logic is not really required, because the
PTE lock must be held over the complete prot_start/commit transaction,
as described in the comment of the generic implementation of
ptep_modify_prot_start().
That comment also mentions that this interface should be batchable,
and modify_prot_start_ptes() might start a transaction over a batch of
PTEs, implemented as a simple loop over ptep_modify_prot_start().
In this case, the preempt_disable() in ptep_modify_prot_start() would
be called multiple times, before the corresponding preempt_enable()
calls happen, and this can lead to a preempt_count overflow.
To fix this, simply remove the preempt_disable/enable() calls in
ptep_modify_prot_start/commit(), and rely on the PTE lock being held.
Commit cac1db8c3aad ("mm: optimize mprotect() by PTE batching") made use
of this PTE batching for the first time, and triggers warnings like this:
DEBUG_LOCKS_WARN_ON((preempt_count() & PREEMPT_MASK) >= PREEMPT_MASK - 10)
BUG: sleeping function called from invalid context at mm/mprotect.c:576
Hence, add a Fixes tag on that commit. Not because it is broken, but to
make sure that it won't get backported w/o also this fix for s390.
Fixes: cac1db8c3aad ("mm: optimize mprotect() by PTE batching")
Reviewed-by: Alexander Gordeev <agordeev@linux.ibm.com>
Signed-off-by: Gerald Schaefer <gerald.schaefer@linux.ibm.com>
Signed-off-by: Alexander Gordeev <agordeev@linux.ibm.com>
| -rw-r--r-- | arch/s390/mm/pgtable.c | 2 |
1 files changed, 0 insertions, 2 deletions
diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c index 60688be4e876..50eb57c976bc 100644 --- a/arch/s390/mm/pgtable.c +++ b/arch/s390/mm/pgtable.c @@ -335,7 +335,6 @@ pte_t ptep_modify_prot_start(struct vm_area_struct *vma, unsigned long addr, int nodat; struct mm_struct *mm = vma->vm_mm; - preempt_disable(); pgste = ptep_xchg_start(mm, addr, ptep); nodat = !!(pgste_val(pgste) & _PGSTE_GPS_NODAT); old = ptep_flush_lazy(mm, addr, ptep, nodat); @@ -360,7 +359,6 @@ void ptep_modify_prot_commit(struct vm_area_struct *vma, unsigned long addr, } else { set_pte(ptep, pte); } - preempt_enable(); } static inline void pmdp_idte_local(struct mm_struct *mm, |
