[PATCH] mm: i386 sh sh64 ready for split ptlock
Use pte_offset_map_lock, instead of pte_offset_map (or inappropriate pte_offset_kernel) and mm-wide page_table_lock, in sundry arch places. The i386 vm86 mark_screen_rdonly: yes, there was and is an assumption that the screen fits inside the one page table, as indeed it does. The sh __do_page_fault: which handles both kernel faults (without lock) and user mm faults (locked - though it set_pte without locking before). The sh64 flush_cache_range and helpers: which wrongly thought callers held page_table_lock before (only its tlb_start_vma did, and no longer does so); moved the flush loop down, and adjusted the large versus small range decision to consider a range which spans page tables as large. Signed-off-by: Hugh Dickins <hugh@veritas.com> Acked-by: Paul Mundt <lethal@linux-sh.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
committed by
Linus Torvalds
parent
deceb6cd17
commit
60ec558549
@ -194,10 +194,13 @@ asmlinkage int __do_page_fault(struct pt_regs *regs, unsigned long writeaccess,
|
||||
unsigned long address)
|
||||
{
|
||||
unsigned long addrmax = P4SEG;
|
||||
pgd_t *dir;
|
||||
pgd_t *pgd;
|
||||
pmd_t *pmd;
|
||||
pte_t *pte;
|
||||
pte_t entry;
|
||||
struct mm_struct *mm;
|
||||
spinlock_t *ptl;
|
||||
int ret = 1;
|
||||
|
||||
#ifdef CONFIG_SH_KGDB
|
||||
if (kgdb_nofault && kgdb_bus_err_hook)
|
||||
@ -208,28 +211,28 @@ asmlinkage int __do_page_fault(struct pt_regs *regs, unsigned long writeaccess,
|
||||
addrmax = P4SEG_STORE_QUE + 0x04000000;
|
||||
#endif
|
||||
|
||||
if (address >= P3SEG && address < addrmax)
|
||||
dir = pgd_offset_k(address);
|
||||
else if (address >= TASK_SIZE)
|
||||
if (address >= P3SEG && address < addrmax) {
|
||||
pgd = pgd_offset_k(address);
|
||||
mm = NULL;
|
||||
} else if (address >= TASK_SIZE)
|
||||
return 1;
|
||||
else if (!current->mm)
|
||||
else if (!(mm = current->mm))
|
||||
return 1;
|
||||
else
|
||||
dir = pgd_offset(current->mm, address);
|
||||
pgd = pgd_offset(mm, address);
|
||||
|
||||
pmd = pmd_offset(dir, address);
|
||||
if (pmd_none(*pmd))
|
||||
pmd = pmd_offset(pgd, address);
|
||||
if (pmd_none_or_clear_bad(pmd))
|
||||
return 1;
|
||||
if (pmd_bad(*pmd)) {
|
||||
pmd_ERROR(*pmd);
|
||||
pmd_clear(pmd);
|
||||
return 1;
|
||||
}
|
||||
pte = pte_offset_kernel(pmd, address);
|
||||
if (mm)
|
||||
pte = pte_offset_map_lock(mm, pmd, address, &ptl);
|
||||
else
|
||||
pte = pte_offset_kernel(pmd, address);
|
||||
|
||||
entry = *pte;
|
||||
if (pte_none(entry) || pte_not_present(entry)
|
||||
|| (writeaccess && !pte_write(entry)))
|
||||
return 1;
|
||||
goto unlock;
|
||||
|
||||
if (writeaccess)
|
||||
entry = pte_mkdirty(entry);
|
||||
@ -251,8 +254,11 @@ asmlinkage int __do_page_fault(struct pt_regs *regs, unsigned long writeaccess,
|
||||
|
||||
set_pte(pte, entry);
|
||||
update_mmu_cache(NULL, address, entry);
|
||||
|
||||
return 0;
|
||||
ret = 0;
|
||||
unlock:
|
||||
if (mm)
|
||||
pte_unmap_unlock(pte, ptl);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
|
||||
|
Reference in New Issue
Block a user