]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
3.8-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 26 Feb 2013 00:43:08 +0000 (16:43 -0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 26 Feb 2013 00:43:08 +0000 (16:43 -0800)
added patches:
sparc64-fix-gfp_flags-setting-in-tsb_grow.patch
sparc64-fix-huge-pmd-to-pte-translation-for-sun4u-in-tlb-miss-handler.patch
sparc64-fix-tsb_grow-in-atomic-context.patch
sparc64-handle-hugepage-tsb-being-null.patch

queue-3.8/series
queue-3.8/sparc64-fix-gfp_flags-setting-in-tsb_grow.patch [new file with mode: 0644]
queue-3.8/sparc64-fix-huge-pmd-to-pte-translation-for-sun4u-in-tlb-miss-handler.patch [new file with mode: 0644]
queue-3.8/sparc64-fix-tsb_grow-in-atomic-context.patch [new file with mode: 0644]
queue-3.8/sparc64-handle-hugepage-tsb-being-null.patch [new file with mode: 0644]

index 515ec2f90dcf80f4f1f697333d47d879660e17a6..3468409af89072ddc1ce8df36c1afb291d1e72ff 100644 (file)
@@ -57,3 +57,7 @@ alsa-hda-workaround-for-silent-output-on-sony-vaio-vgc-ln51jgb-with-alc889.patch
 alsa-hda-fix-broken-workaround-for-hdmi-spdif-conflicts.patch
 alsa-hda-hdmi-eld-shouldn-t-be-valid-after-unplug.patch
 gfs2-get-a-block-reservation-before-resizing-a-file.patch
+sparc64-fix-gfp_flags-setting-in-tsb_grow.patch
+sparc64-handle-hugepage-tsb-being-null.patch
+sparc64-fix-tsb_grow-in-atomic-context.patch
+sparc64-fix-huge-pmd-to-pte-translation-for-sun4u-in-tlb-miss-handler.patch
diff --git a/queue-3.8/sparc64-fix-gfp_flags-setting-in-tsb_grow.patch b/queue-3.8/sparc64-fix-gfp_flags-setting-in-tsb_grow.patch
new file mode 100644 (file)
index 0000000..dc90c36
--- /dev/null
@@ -0,0 +1,31 @@
+From 4872ab9e7ca822a28ff790129a5fc96bad845572 Mon Sep 17 00:00:00 2001
+From: "David S. Miller" <davem@davemloft.net>
+Date: Tue, 19 Feb 2013 12:56:18 -0800
+Subject: sparc64: Fix gfp_flags setting in tsb_grow().
+
+
+From: "David S. Miller" <davem@davemloft.net>
+
+[ Upstream commit a55ee1ff751f88252207160087d8197bb7538d4c ]
+
+We should "|= more_flags" rather than "= more_flags".
+
+Reported-by: David Rientjes <rientjes@google.com>
+Acked-by: David Rientjes <rientjes@google.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/sparc/mm/tsb.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/sparc/mm/tsb.c
++++ b/arch/sparc/mm/tsb.c
+@@ -314,7 +314,7 @@ void tsb_grow(struct mm_struct *mm, unsi
+ retry_tsb_alloc:
+       gfp_flags = GFP_KERNEL;
+       if (new_size > (PAGE_SIZE * 2))
+-              gfp_flags = __GFP_NOWARN | __GFP_NORETRY;
++              gfp_flags |= __GFP_NOWARN | __GFP_NORETRY;
+       new_tsb = kmem_cache_alloc_node(tsb_caches[new_cache_index],
+                                       gfp_flags, numa_node_id());
diff --git a/queue-3.8/sparc64-fix-huge-pmd-to-pte-translation-for-sun4u-in-tlb-miss-handler.patch b/queue-3.8/sparc64-fix-huge-pmd-to-pte-translation-for-sun4u-in-tlb-miss-handler.patch
new file mode 100644 (file)
index 0000000..c129d31
--- /dev/null
@@ -0,0 +1,90 @@
+From 6c0464bf819d5941d7366cf564c84c9bdbc6d664 Mon Sep 17 00:00:00 2001
+From: "David S. Miller" <davem@davemloft.net>
+Date: Wed, 20 Feb 2013 12:38:40 -0800
+Subject: sparc64: Fix huge PMD to PTE translation for sun4u in TLB miss handler.
+
+
+From: "David S. Miller" <davem@davemloft.net>
+
+[ Upstream commit 76968ad2eac6456270353de168b21f04f4b3d1d3 ]
+
+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 <mroos@linux.ee>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/sparc/include/asm/tsb.h |   28 +++++++++++++++++++---------
+ 1 file changed, 19 insertions(+), 9 deletions(-)
+
+--- 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
+       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
+        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;                                      \
diff --git a/queue-3.8/sparc64-fix-tsb_grow-in-atomic-context.patch b/queue-3.8/sparc64-fix-tsb_grow-in-atomic-context.patch
new file mode 100644 (file)
index 0000000..5902226
--- /dev/null
@@ -0,0 +1,193 @@
+From 5f4c00b242a1c73474a9287223ffaa58fa220b3a Mon Sep 17 00:00:00 2001
+From: "David S. Miller" <davem@davemloft.net>
+Date: Tue, 19 Feb 2013 22:34:10 -0800
+Subject: sparc64: Fix tsb_grow() in atomic context.
+
+
+From: "David S. Miller" <davem@davemloft.net>
+
+[ Upstream commit 0fbebed682ff2788dee58e8d7f7dda46e33aa10b ]
+
+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 <mroos@ut.ee>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/sparc/include/asm/hugetlb.h |    1 -
+ arch/sparc/include/asm/page_64.h |    4 ++--
+ arch/sparc/kernel/tsb.S          |   39 +++++++++++++++++++++++++++++++++++----
+ arch/sparc/mm/fault_64.c         |    9 +++++++--
+ arch/sparc/mm/init_64.c          |   24 +++++++++++++++++++-----
+ arch/sparc/mm/tlb.c              |   11 +++++++++--
+ 6 files changed, 72 insertions(+), 16 deletions(-)
+
+--- 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_
+ 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,
+--- 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
+--- a/arch/sparc/kernel/tsb.S
++++ b/arch/sparc/kernel/tsb.S
+@@ -136,12 +136,43 @@ tsb_miss_page_table_walk_sun4v_fastpath:
+        nop
+       /* It is a huge page, use huge page TSB entry address we
+-       * calculated above.
++       * calculated above.  If the huge page TSB has not been
++       * allocated, setup a trap stack and call hugetlb_setup()
++       * to do so, then return from the trap to replay the TLB
++       * miss.
++       *
++       * This is necessary to handle the case of transparent huge
++       * pages where we don't really have a non-atomic context
++       * in which to allocate the hugepage TSB hash table.  When
++       * the 'mm' faults in the hugepage for the first time, we
++       * thus handle it here.  This also makes sure that we can
++       * allocate the TSB hash table on the correct NUMA node.
+        */
+       TRAP_LOAD_TRAP_BLOCK(%g7, %g2)
+-      ldx             [%g7 + TRAP_PER_CPU_TSB_HUGE_TEMP], %g2
+-      cmp             %g2, -1
+-      movne           %xcc, %g2, %g1
++      ldx             [%g7 + TRAP_PER_CPU_TSB_HUGE_TEMP], %g1
++      cmp             %g1, -1
++      bne,pt          %xcc, 60f
++       nop
++
++661:  rdpr            %pstate, %g5
++      wrpr            %g5, PSTATE_AG | PSTATE_MG, %pstate
++      .section        .sun4v_2insn_patch, "ax"
++      .word           661b
++      SET_GL(1)
++      nop
++      .previous
++
++      rdpr    %tl, %g3
++      cmp     %g3, 1
++      bne,pn  %xcc, winfix_trampoline
++       nop
++      ba,pt   %xcc, etrap
++       rd     %pc, %g7
++      call    hugetlb_setup
++       add    %sp, PTREGS_OFF, %o0
++      ba,pt   %xcc, rtrap
++       nop
++
+ 60:
+ #endif
+--- a/arch/sparc/mm/fault_64.c
++++ b/arch/sparc/mm/fault_64.c
+@@ -472,8 +472,13 @@ good_area:
+ #if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE)
+       mm_rss = mm->context.huge_pte_count;
+       if (unlikely(mm_rss >
+-                   mm->context.tsb_block[MM_TSB_HUGE].tsb_rss_limit))
+-              tsb_grow(mm, MM_TSB_HUGE, mm_rss);
++                   mm->context.tsb_block[MM_TSB_HUGE].tsb_rss_limit)) {
++              if (mm->context.tsb_block[MM_TSB_HUGE].tsb)
++                      tsb_grow(mm, MM_TSB_HUGE, mm_rss);
++              else
++                      hugetlb_setup(regs);
++
++      }
+ #endif
+       return;
+--- a/arch/sparc/mm/init_64.c
++++ b/arch/sparc/mm/init_64.c
+@@ -2718,14 +2718,28 @@ static void context_reload(void *__data)
+               load_secondary_context(mm);
+ }
+-void hugetlb_setup(struct mm_struct *mm)
++void hugetlb_setup(struct pt_regs *regs)
+ {
+-      struct tsb_config *tp = &mm->context.tsb_block[MM_TSB_HUGE];
++      struct mm_struct *mm = current->mm;
++      struct tsb_config *tp;
+-      if (likely(tp->tsb != NULL))
+-              return;
++      if (in_atomic() || !mm) {
++              const struct exception_table_entry *entry;
++
++              entry = search_exception_tables(regs->tpc);
++              if (entry) {
++                      regs->tpc = entry->fixup;
++                      regs->tnpc = regs->tpc + 4;
++                      return;
++              }
++              pr_alert("Unexpected HugeTLB setup in atomic context.\n");
++              die_if_kernel("HugeTSB in atomic", regs);
++      }
++
++      tp = &mm->context.tsb_block[MM_TSB_HUGE];
++      if (likely(tp->tsb == NULL))
++              tsb_grow(mm, MM_TSB_HUGE, 0);
+-      tsb_grow(mm, MM_TSB_HUGE, 0);
+       tsb_context_switch(mm);
+       smp_tsb_sync(mm);
+--- a/arch/sparc/mm/tlb.c
++++ b/arch/sparc/mm/tlb.c
+@@ -135,8 +135,15 @@ void set_pmd_at(struct mm_struct *mm, un
+                       mm->context.huge_pte_count++;
+               else
+                       mm->context.huge_pte_count--;
+-              if (mm->context.huge_pte_count == 1)
+-                      hugetlb_setup(mm);
++
++              /* Do not try to allocate the TSB hash table if we
++               * don't have one already.  We have various locks held
++               * and thus we'll end up doing a GFP_KERNEL allocation
++               * in an atomic context.
++               *
++               * Instead, we let the first TLB miss on a hugepage
++               * take care of this.
++               */
+       }
+       if (!pmd_none(orig)) {
diff --git a/queue-3.8/sparc64-handle-hugepage-tsb-being-null.patch b/queue-3.8/sparc64-handle-hugepage-tsb-being-null.patch
new file mode 100644 (file)
index 0000000..77b470d
--- /dev/null
@@ -0,0 +1,91 @@
+From aa8569cc39128e25712ff2224cbf93821ceea4d0 Mon Sep 17 00:00:00 2001
+From: "David S. Miller" <davem@davemloft.net>
+Date: Tue, 19 Feb 2013 13:20:08 -0800
+Subject: sparc64: Handle hugepage TSB being NULL.
+
+
+From: "David S. Miller" <davem@davemloft.net>
+
+[ Upstream commit bcd896bae0166b4443503482a26ecf84d9ba60ab ]
+
+Accomodate the possibility that the TSB might be NULL at
+the point that update_mmu_cache() is invoked.  This is
+necessary because we will sometimes need to defer the TSB
+allocation to the first fault that happens in the 'mm'.
+
+Seperate out the hugepage PTE test into a seperate function
+so that the logic is clearer.
+
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/sparc/mm/init_64.c |   38 ++++++++++++++++++++++----------------
+ 1 file changed, 22 insertions(+), 16 deletions(-)
+
+--- a/arch/sparc/mm/init_64.c
++++ b/arch/sparc/mm/init_64.c
+@@ -314,16 +314,31 @@ static void __update_mmu_tsb_insert(stru
+       struct tsb *tsb = mm->context.tsb_block[tsb_index].tsb;
+       unsigned long tag;
++      if (unlikely(!tsb))
++              return;
++
+       tsb += ((address >> tsb_hash_shift) &
+               (mm->context.tsb_block[tsb_index].tsb_nentries - 1UL));
+       tag = (address >> 22UL);
+       tsb_insert(tsb, tag, tte);
+ }
++#if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE)
++static inline bool is_hugetlb_pte(pte_t pte)
++{
++      if ((tlb_type == hypervisor &&
++           (pte_val(pte) & _PAGE_SZALL_4V) == _PAGE_SZHUGE_4V) ||
++          (tlb_type != hypervisor &&
++           (pte_val(pte) & _PAGE_SZALL_4U) == _PAGE_SZHUGE_4U))
++              return true;
++      return false;
++}
++#endif
++
+ void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t *ptep)
+ {
+-      unsigned long tsb_index, tsb_hash_shift, flags;
+       struct mm_struct *mm;
++      unsigned long flags;
+       pte_t pte = *ptep;
+       if (tlb_type != hypervisor) {
+@@ -335,25 +350,16 @@ void update_mmu_cache(struct vm_area_str
+       mm = vma->vm_mm;
+-      tsb_index = MM_TSB_BASE;
+-      tsb_hash_shift = PAGE_SHIFT;
+-
+       spin_lock_irqsave(&mm->context.lock, flags);
+ #if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE)
+-      if (mm->context.tsb_block[MM_TSB_HUGE].tsb != NULL) {
+-              if ((tlb_type == hypervisor &&
+-                   (pte_val(pte) & _PAGE_SZALL_4V) == _PAGE_SZHUGE_4V) ||
+-                  (tlb_type != hypervisor &&
+-                   (pte_val(pte) & _PAGE_SZALL_4U) == _PAGE_SZHUGE_4U)) {
+-                      tsb_index = MM_TSB_HUGE;
+-                      tsb_hash_shift = HPAGE_SHIFT;
+-              }
+-      }
++      if (mm->context.huge_pte_count && is_hugetlb_pte(pte))
++              __update_mmu_tsb_insert(mm, MM_TSB_HUGE, HPAGE_SHIFT,
++                                      address, pte_val(pte));
++      else
+ #endif
+-
+-      __update_mmu_tsb_insert(mm, tsb_index, tsb_hash_shift,
+-                              address, pte_val(pte));
++              __update_mmu_tsb_insert(mm, MM_TSB_BASE, PAGE_SHIFT,
++                                      address, pte_val(pte));
+       spin_unlock_irqrestore(&mm->context.lock, flags);
+ }