summaryrefslogtreecommitdiffstats
path: root/arch/ppc/mm/pgtable.c
diff options
context:
space:
mode:
authorEugene Surovegin <ebs@ebshome.net>2006-03-28 20:13:12 +0200
committerPaul Mackerras <paulus@samba.org>2006-03-29 04:44:15 +0200
commitbab70a4af737f623de5b034976a311055308ab86 (patch)
treef8c0e9463de01323db2cb1a62f4eb83adb5ce7ca /arch/ppc/mm/pgtable.c
parentMerge ../linux-2.6 (diff)
downloadlinux-bab70a4af737f623de5b034976a311055308ab86.tar.xz
linux-bab70a4af737f623de5b034976a311055308ab86.zip
[PATCH] lock PTE before updating it in 440/BookE page fault handler
Fix 44x and BookE page fault handler to correctly lock PTE before trying to pte_update() it, otherwise this PTE might be swapped out after pte_present() check but before pte_uptdate() call, resulting in corrupted PTE. This can happen with enabled preemption and low memory condition. Signed-off-by: Eugene Surovegin <ebs@ebshome.net> Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/ppc/mm/pgtable.c')
-rw-r--r--arch/ppc/mm/pgtable.c6
1 files changed, 4 insertions, 2 deletions
diff --git a/arch/ppc/mm/pgtable.c b/arch/ppc/mm/pgtable.c
index a1924876cad6..706bca8eb144 100644
--- a/arch/ppc/mm/pgtable.c
+++ b/arch/ppc/mm/pgtable.c
@@ -368,7 +368,7 @@ void __init io_block_mapping(unsigned long virt, phys_addr_t phys,
* the PTE pointer is unmodified if PTE is not found.
*/
int
-get_pteptr(struct mm_struct *mm, unsigned long addr, pte_t **ptep)
+get_pteptr(struct mm_struct *mm, unsigned long addr, pte_t **ptep, pmd_t **pmdp)
{
pgd_t *pgd;
pmd_t *pmd;
@@ -383,6 +383,8 @@ get_pteptr(struct mm_struct *mm, unsigned long addr, pte_t **ptep)
if (pte) {
retval = 1;
*ptep = pte;
+ if (pmdp)
+ *pmdp = pmd;
/* XXX caller needs to do pte_unmap, yuck */
}
}
@@ -420,7 +422,7 @@ unsigned long iopa(unsigned long addr)
mm = &init_mm;
pa = 0;
- if (get_pteptr(mm, addr, &pte)) {
+ if (get_pteptr(mm, addr, &pte, NULL)) {
pa = (pte_val(*pte) & PAGE_MASK) | (addr & ~PAGE_MASK);
pte_unmap(pte);
}