From 0fbebed682ff2788dee58e8d7f7dda46e33aa10b Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 19 Feb 2013 22:34:10 -0800 Subject: sparc64: Fix tsb_grow() in atomic context. If our first THP installation for an MM is via the set_pmd_at() done during khugepaged's collapsing we'll end up in tsb_grow() trying to do a GFP_KERNEL allocation with several locks held. Simply using GFP_ATOMIC in this situation is not the best option because we really can't have this fail, so we'd really like to keep this an order 0 GFP_KERNEL allocation if possible. Also, doing the TSB allocation from khugepaged is a really bad idea because we'll allocate it potentially from the wrong NUMA node in that context. So what we do is defer the hugepage TSB allocation until the first TLB miss we take on a hugepage. This is slightly tricky because we have to handle two unusual cases: 1) Taking the first hugepage TLB miss in the window trap handler. We'll call the winfix_trampoline when that is detected. 2) An initial TSB allocation via TLB miss races with a hugetlb fault on another cpu running the same MM. We handle this by unconditionally loading the TSB we see into the current cpu even if it's non-NULL at hugetlb_setup time. Reported-by: Meelis Roos Signed-off-by: David S. Miller --- arch/sparc/include/asm/hugetlb.h | 1 - arch/sparc/include/asm/page_64.h | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) (limited to 'arch/sparc/include/asm') diff --git a/arch/sparc/include/asm/hugetlb.h b/arch/sparc/include/asm/hugetlb.h index 9661e9bc7bb6..7eb57d245044 100644 --- a/arch/sparc/include/asm/hugetlb.h +++ b/arch/sparc/include/asm/hugetlb.h @@ -12,7 +12,6 @@ pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, static inline void hugetlb_prefault_arch_hook(struct mm_struct *mm) { - hugetlb_setup(mm); } static inline int is_hugepage_only_range(struct mm_struct *mm, diff --git a/arch/sparc/include/asm/page_64.h b/arch/sparc/include/asm/page_64.h index 4b39f74d6ca0..e15538899f3d 100644 --- a/arch/sparc/include/asm/page_64.h +++ b/arch/sparc/include/asm/page_64.h @@ -27,8 +27,8 @@ #ifndef __ASSEMBLY__ #if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE) -struct mm_struct; -extern void hugetlb_setup(struct mm_struct *mm); +struct pt_regs; +extern void hugetlb_setup(struct pt_regs *regs); #endif #define WANT_PAGE_VIRTUAL -- cgit v1.2.3 From 76968ad2eac6456270353de168b21f04f4b3d1d3 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 20 Feb 2013 12:38:40 -0800 Subject: sparc64: Fix huge PMD to PTE translation for sun4u in TLB miss handler. When we set the sun4u version of the PTE execute bit, it's: or REG, _PAGE_EXEC_4U, REG _PAGE_EXEC_4U is 0x1000, unfortunately the immedate field of the 'or' instruction is a signed 13-bit value. So the above actually assembles into: or REG, -4096, REG completely corrupting the final PTE value. Set it with a: sethi %hi(_PAGE_EXEC_4U), TMP or REG, TMP, REG sequence instead. This fixes "git gc" crashes on sun4u machines. Reported-by: Meelis Roos Signed-off-by: David S. Miller --- arch/sparc/include/asm/tsb.h | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) (limited to 'arch/sparc/include/asm') diff --git a/arch/sparc/include/asm/tsb.h b/arch/sparc/include/asm/tsb.h index b4c258de4443..e696432b950d 100644 --- a/arch/sparc/include/asm/tsb.h +++ b/arch/sparc/include/asm/tsb.h @@ -157,17 +157,26 @@ extern struct tsb_phys_patch_entry __tsb_phys_patch, __tsb_phys_patch_end; andn REG2, 0x7, REG2; \ add REG1, REG2, REG1; - /* This macro exists only to make the PMD translator below easier - * to read. It hides the ELF section switch for the sun4v code - * patching. + /* These macros exists only to make the PMD translator below + * easier to read. It hides the ELF section switch for the + * sun4v code patching. */ -#define OR_PTE_BIT(REG, NAME) \ +#define OR_PTE_BIT_1INSN(REG, NAME) \ 661: or REG, _PAGE_##NAME##_4U, REG; \ .section .sun4v_1insn_patch, "ax"; \ .word 661b; \ or REG, _PAGE_##NAME##_4V, REG; \ .previous; +#define OR_PTE_BIT_2INSN(REG, TMP, NAME) \ +661: sethi %hi(_PAGE_##NAME##_4U), TMP; \ + or REG, TMP, REG; \ + .section .sun4v_2insn_patch, "ax"; \ + .word 661b; \ + mov -1, TMP; \ + or REG, _PAGE_##NAME##_4V, REG; \ + .previous; + /* Load into REG the PTE value for VALID, CACHE, and SZHUGE. */ #define BUILD_PTE_VALID_SZHUGE_CACHE(REG) \ 661: sethi %uhi(_PAGE_VALID|_PAGE_SZHUGE_4U), REG; \ @@ -214,12 +223,13 @@ extern struct tsb_phys_patch_entry __tsb_phys_patch, __tsb_phys_patch_end; andn REG1, PMD_HUGE_PROTBITS, REG2; \ sllx REG2, PMD_PADDR_SHIFT, REG2; \ /* REG2 now holds PFN << PAGE_SHIFT */ \ - andcc REG1, PMD_HUGE_EXEC, %g0; \ - bne,a,pt %xcc, 1f; \ - OR_PTE_BIT(REG2, EXEC); \ -1: andcc REG1, PMD_HUGE_WRITE, %g0; \ + andcc REG1, PMD_HUGE_WRITE, %g0; \ bne,a,pt %xcc, 1f; \ - OR_PTE_BIT(REG2, W); \ + OR_PTE_BIT_1INSN(REG2, W); \ +1: andcc REG1, PMD_HUGE_EXEC, %g0; \ + be,pt %xcc, 1f; \ + nop; \ + OR_PTE_BIT_2INSN(REG2, REG1, EXEC); \ /* REG1 can now be clobbered, build final PTE */ \ 1: BUILD_PTE_VALID_SZHUGE_CACHE(REG1); \ ba,pt %xcc, PTE_LABEL; \ -- cgit v1.2.3