diff options
Diffstat (limited to 'arch/arm/kernel/traps.c')
| -rw-r--r-- | arch/arm/kernel/traps.c | 47 | 
1 files changed, 29 insertions, 18 deletions
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index f6de76e0a45..45e9ea6cd2a 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c @@ -198,25 +198,16 @@ void show_stack(struct task_struct *tsk, unsigned long *sp)  	barrier();  } -DEFINE_SPINLOCK(die_lock); - -/* - * This function is protected against re-entrancy. - */ -NORET_TYPE void die(const char *str, struct pt_regs *regs, int err) +static void __die(const char *str, int err, struct thread_info *thread, struct pt_regs *regs)  { -	struct task_struct *tsk = current; +	struct task_struct *tsk = thread->task;  	static int die_counter; -	console_verbose(); -	spin_lock_irq(&die_lock); -	bust_spinlocks(1); -  	printk("Internal error: %s: %x [#%d]\n", str, err, ++die_counter);  	print_modules();  	__show_regs(regs);  	printk("Process %s (pid: %d, stack limit = 0x%p)\n", -		tsk->comm, tsk->pid, tsk->thread_info + 1); +		tsk->comm, tsk->pid, thread + 1);  	if (!user_mode(regs) || in_interrupt()) {  		dump_mem("Stack: ", regs->ARM_sp, @@ -224,7 +215,21 @@ NORET_TYPE void die(const char *str, struct pt_regs *regs, int err)  		dump_backtrace(regs, tsk);  		dump_instr(regs);  	} +} + +DEFINE_SPINLOCK(die_lock); + +/* + * This function is protected against re-entrancy. + */ +NORET_TYPE void die(const char *str, struct pt_regs *regs, int err) +{ +	struct thread_info *thread = current_thread_info(); +	console_verbose(); +	spin_lock_irq(&die_lock); +	bust_spinlocks(1); +	__die(str, err, thread, regs);  	bust_spinlocks(0);  	spin_unlock_irq(&die_lock);  	do_exit(SIGSEGV); @@ -345,7 +350,9 @@ static int bad_syscall(int n, struct pt_regs *regs)  	struct thread_info *thread = current_thread_info();  	siginfo_t info; -	if (current->personality != PER_LINUX && thread->exec_domain->handler) { +	if (current->personality != PER_LINUX && +	    current->personality != PER_LINUX_32BIT && +	    thread->exec_domain->handler) {  		thread->exec_domain->handler(n, regs);  		return regs->ARM_r0;  	} @@ -481,29 +488,33 @@ asmlinkage int arm_syscall(int no, struct pt_regs *regs)  		unsigned long addr = regs->ARM_r2;  		struct mm_struct *mm = current->mm;  		pgd_t *pgd; pmd_t *pmd; pte_t *pte; +		spinlock_t *ptl;  		regs->ARM_cpsr &= ~PSR_C_BIT; -		spin_lock(&mm->page_table_lock); +		down_read(&mm->mmap_sem);  		pgd = pgd_offset(mm, addr);  		if (!pgd_present(*pgd))  			goto bad_access;  		pmd = pmd_offset(pgd, addr);  		if (!pmd_present(*pmd))  			goto bad_access; -		pte = pte_offset_map(pmd, addr); -		if (!pte_present(*pte) || !pte_write(*pte)) +		pte = pte_offset_map_lock(mm, pmd, addr, &ptl); +		if (!pte_present(*pte) || !pte_write(*pte)) { +			pte_unmap_unlock(pte, ptl);  			goto bad_access; +		}  		val = *(unsigned long *)addr;  		val -= regs->ARM_r0;  		if (val == 0) {  			*(unsigned long *)addr = regs->ARM_r1;  			regs->ARM_cpsr |= PSR_C_BIT;  		} -		spin_unlock(&mm->page_table_lock); +		pte_unmap_unlock(pte, ptl); +		up_read(&mm->mmap_sem);  		return val;  		bad_access: -		spin_unlock(&mm->page_table_lock); +		up_read(&mm->mmap_sem);  		/* simulate a write access fault */  		do_DataAbort(addr, 15 + (1 << 11), regs);  		return -1;  | 
