Skip to content

Commit 57834ce

Browse files
gerald-schaeferAlexander Gordeev
authored andcommitted
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 cac1db8 ("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: cac1db8 ("mm: optimize mprotect() by PTE batching") Reviewed-by: Alexander Gordeev <[email protected]> Signed-off-by: Gerald Schaefer <[email protected]> Signed-off-by: Alexander Gordeev <[email protected]>
1 parent 3868f91 commit 57834ce

File tree

1 file changed

+0
-2
lines changed

1 file changed

+0
-2
lines changed

arch/s390/mm/pgtable.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -335,7 +335,6 @@ pte_t ptep_modify_prot_start(struct vm_area_struct *vma, unsigned long addr,
335335
int nodat;
336336
struct mm_struct *mm = vma->vm_mm;
337337

338-
preempt_disable();
339338
pgste = ptep_xchg_start(mm, addr, ptep);
340339
nodat = !!(pgste_val(pgste) & _PGSTE_GPS_NODAT);
341340
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,
360359
} else {
361360
set_pte(ptep, pte);
362361
}
363-
preempt_enable();
364362
}
365363

366364
static inline void pmdp_idte_local(struct mm_struct *mm,

0 commit comments

Comments
 (0)