diff options
Diffstat (limited to 'arch/arm/lib')
| -rw-r--r-- | arch/arm/lib/Makefile | 1 | ||||
| -rw-r--r-- | arch/arm/lib/bitops.h | 5 | ||||
| -rw-r--r-- | arch/arm/lib/delay-loop.S | 1 | ||||
| -rw-r--r-- | arch/arm/lib/io-shark.c | 13 | ||||
| -rw-r--r-- | arch/arm/lib/uaccess_with_memcpy.c | 41 | 
5 files changed, 44 insertions, 17 deletions
diff --git a/arch/arm/lib/Makefile b/arch/arm/lib/Makefile index bd454b09133e..47d7338561de 100644 --- a/arch/arm/lib/Makefile +++ b/arch/arm/lib/Makefile @@ -41,7 +41,6 @@ else  endif  lib-$(CONFIG_ARCH_RPC)		+= ecard.o io-acorn.o floppydma.o -lib-$(CONFIG_ARCH_SHARK)	+= io-shark.o  $(obj)/csumpartialcopy.o:	$(obj)/csumpartialcopygeneric.S  $(obj)/csumpartialcopyuser.o:	$(obj)/csumpartialcopygeneric.S diff --git a/arch/arm/lib/bitops.h b/arch/arm/lib/bitops.h index d6408d1ee543..52886b89706c 100644 --- a/arch/arm/lib/bitops.h +++ b/arch/arm/lib/bitops.h @@ -10,6 +10,11 @@ UNWIND(	.fnstart	)  	and	r3, r0, #31		@ Get bit offset  	mov	r0, r0, lsr #5  	add	r1, r1, r0, lsl #2	@ Get word offset +#if __LINUX_ARM_ARCH__ >= 7 && defined(CONFIG_SMP) +	.arch_extension	mp +	ALT_SMP(W(pldw)	[r1]) +	ALT_UP(W(nop)) +#endif  	mov	r3, r2, lsl r3  1:	ldrex	r2, [r1]  	\instr	r2, r2, r3 diff --git a/arch/arm/lib/delay-loop.S b/arch/arm/lib/delay-loop.S index 36b668d8e121..bc1033b897b4 100644 --- a/arch/arm/lib/delay-loop.S +++ b/arch/arm/lib/delay-loop.S @@ -40,6 +40,7 @@ ENTRY(__loop_const_udelay)			@ 0 <= r0 <= 0x7fffff06  /*   * loops = r0 * HZ * loops_per_jiffy / 1000000   */ +		.align 3  @ Delay routine  ENTRY(__loop_delay) diff --git a/arch/arm/lib/io-shark.c b/arch/arm/lib/io-shark.c deleted file mode 100644 index 824253948f51..000000000000 --- a/arch/arm/lib/io-shark.c +++ /dev/null @@ -1,13 +0,0 @@ -/* - *  linux/arch/arm/lib/io-shark.c - * - *  by Alexander Schulz - * - * derived from: - * linux/arch/arm/lib/io-ebsa.S - * Copyright (C) 1995, 1996 Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ diff --git a/arch/arm/lib/uaccess_with_memcpy.c b/arch/arm/lib/uaccess_with_memcpy.c index 025f742dd4df..3e58d710013c 100644 --- a/arch/arm/lib/uaccess_with_memcpy.c +++ b/arch/arm/lib/uaccess_with_memcpy.c @@ -18,6 +18,7 @@  #include <linux/hardirq.h> /* for in_atomic() */  #include <linux/gfp.h>  #include <linux/highmem.h> +#include <linux/hugetlb.h>  #include <asm/current.h>  #include <asm/page.h> @@ -40,7 +41,35 @@ pin_page_for_write(const void __user *_addr, pte_t **ptep, spinlock_t **ptlp)  		return 0;  	pmd = pmd_offset(pud, addr); -	if (unlikely(pmd_none(*pmd) || pmd_bad(*pmd))) +	if (unlikely(pmd_none(*pmd))) +		return 0; + +	/* +	 * A pmd can be bad if it refers to a HugeTLB or THP page. +	 * +	 * Both THP and HugeTLB pages have the same pmd layout +	 * and should not be manipulated by the pte functions. +	 * +	 * Lock the page table for the destination and check +	 * to see that it's still huge and whether or not we will +	 * need to fault on write, or if we have a splitting THP. +	 */ +	if (unlikely(pmd_thp_or_huge(*pmd))) { +		ptl = ¤t->mm->page_table_lock; +		spin_lock(ptl); +		if (unlikely(!pmd_thp_or_huge(*pmd) +			|| pmd_hugewillfault(*pmd) +			|| pmd_trans_splitting(*pmd))) { +			spin_unlock(ptl); +			return 0; +		} + +		*ptep = NULL; +		*ptlp = ptl; +		return 1; +	} + +	if (unlikely(pmd_bad(*pmd)))  		return 0;  	pte = pte_offset_map_lock(current->mm, pmd, addr, &ptl); @@ -94,7 +123,10 @@ __copy_to_user_memcpy(void __user *to, const void *from, unsigned long n)  		from += tocopy;  		n -= tocopy; -		pte_unmap_unlock(pte, ptl); +		if (pte) +			pte_unmap_unlock(pte, ptl); +		else +			spin_unlock(ptl);  	}  	if (!atomic)  		up_read(¤t->mm->mmap_sem); @@ -147,7 +179,10 @@ __clear_user_memset(void __user *addr, unsigned long n)  		addr += tocopy;  		n -= tocopy; -		pte_unmap_unlock(pte, ptl); +		if (pte) +			pte_unmap_unlock(pte, ptl); +		else +			spin_unlock(ptl);  	}  	up_read(¤t->mm->mmap_sem);  | 
