diff options
Diffstat (limited to 'arch/sh/mm/fault.c')
| -rw-r--r-- | arch/sh/mm/fault.c | 40 | 
1 files changed, 23 insertions, 17 deletions
| diff --git a/arch/sh/mm/fault.c b/arch/sh/mm/fault.c index 7abba2161da6..775f86cd3fe8 100644 --- a/arch/sh/mm/fault.c +++ b/arch/sh/mm/fault.c | |||
| @@ -194,10 +194,13 @@ asmlinkage int __do_page_fault(struct pt_regs *regs, unsigned long writeaccess, | |||
| 194 | unsigned long address) | 194 | unsigned long address) | 
| 195 | { | 195 | { | 
| 196 | unsigned long addrmax = P4SEG; | 196 | unsigned long addrmax = P4SEG; | 
| 197 | pgd_t *dir; | 197 | pgd_t *pgd; | 
| 198 | pmd_t *pmd; | 198 | pmd_t *pmd; | 
| 199 | pte_t *pte; | 199 | pte_t *pte; | 
| 200 | pte_t entry; | 200 | pte_t entry; | 
| 201 | struct mm_struct *mm; | ||
| 202 | spinlock_t *ptl; | ||
| 203 | int ret = 1; | ||
| 201 | 204 | ||
| 202 | #ifdef CONFIG_SH_KGDB | 205 | #ifdef CONFIG_SH_KGDB | 
| 203 | if (kgdb_nofault && kgdb_bus_err_hook) | 206 | if (kgdb_nofault && kgdb_bus_err_hook) | 
| @@ -208,28 +211,28 @@ asmlinkage int __do_page_fault(struct pt_regs *regs, unsigned long writeaccess, | |||
| 208 | addrmax = P4SEG_STORE_QUE + 0x04000000; | 211 | addrmax = P4SEG_STORE_QUE + 0x04000000; | 
| 209 | #endif | 212 | #endif | 
| 210 | 213 | ||
| 211 | if (address >= P3SEG && address < addrmax) | 214 | if (address >= P3SEG && address < addrmax) { | 
| 212 | dir = pgd_offset_k(address); | 215 | pgd = pgd_offset_k(address); | 
| 213 | else if (address >= TASK_SIZE) | 216 | mm = NULL; | 
| 217 | } else if (address >= TASK_SIZE) | ||
| 214 | return 1; | 218 | return 1; | 
| 215 | else if (!current->mm) | 219 | else if (!(mm = current->mm)) | 
| 216 | return 1; | 220 | return 1; | 
| 217 | else | 221 | else | 
| 218 | dir = pgd_offset(current->mm, address); | 222 | pgd = pgd_offset(mm, address); | 
| 219 | 223 | ||
| 220 | pmd = pmd_offset(dir, address); | 224 | pmd = pmd_offset(pgd, address); | 
| 221 | if (pmd_none(*pmd)) | 225 | if (pmd_none_or_clear_bad(pmd)) | 
| 222 | return 1; | ||
| 223 | if (pmd_bad(*pmd)) { | ||
| 224 | pmd_ERROR(*pmd); | ||
| 225 | pmd_clear(pmd); | ||
| 226 | return 1; | 226 | return 1; | 
| 227 | } | 227 | if (mm) | 
| 228 | pte = pte_offset_kernel(pmd, address); | 228 | pte = pte_offset_map_lock(mm, pmd, address, &ptl); | 
| 229 | else | ||
| 230 | pte = pte_offset_kernel(pmd, address); | ||
| 231 | |||
| 229 | entry = *pte; | 232 | entry = *pte; | 
| 230 | if (pte_none(entry) || pte_not_present(entry) | 233 | if (pte_none(entry) || pte_not_present(entry) | 
| 231 | || (writeaccess && !pte_write(entry))) | 234 | || (writeaccess && !pte_write(entry))) | 
| 232 | return 1; | 235 | goto unlock; | 
| 233 | 236 | ||
| 234 | if (writeaccess) | 237 | if (writeaccess) | 
| 235 | entry = pte_mkdirty(entry); | 238 | entry = pte_mkdirty(entry); | 
| @@ -251,8 +254,11 @@ asmlinkage int __do_page_fault(struct pt_regs *regs, unsigned long writeaccess, | |||
| 251 | 254 | ||
| 252 | set_pte(pte, entry); | 255 | set_pte(pte, entry); | 
| 253 | update_mmu_cache(NULL, address, entry); | 256 | update_mmu_cache(NULL, address, entry); | 
| 254 | 257 | ret = 0; | |
| 255 | return 0; | 258 | unlock: | 
| 259 | if (mm) | ||
| 260 | pte_unmap_unlock(pte, ptl); | ||
| 261 | return ret; | ||
| 256 | } | 262 | } | 
| 257 | 263 | ||
| 258 | void flush_tlb_page(struct vm_area_struct *vma, unsigned long page) | 264 | void flush_tlb_page(struct vm_area_struct *vma, unsigned long page) | 
