]> Git Repo - linux.git/commitdiff
Merge tag 'perf-core-2020-12-14' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorLinus Torvalds <[email protected]>
Tue, 15 Dec 2020 01:34:12 +0000 (17:34 -0800)
committerLinus Torvalds <[email protected]>
Tue, 15 Dec 2020 01:34:12 +0000 (17:34 -0800)
Pull perf updates from Thomas Gleixner:
 "Core:

   - Better handling of page table leaves on archictectures which have
     architectures have non-pagetable aligned huge/large pages. For such
     architectures a leaf can actually be part of a larger entry.

   - Prevent a deadlock vs exec_update_mutex

  Architectures:

   - The related updates for page size calculation of leaf entries

   - The usual churn to support new CPUs

   - Small fixes and improvements all over the place"

* tag 'perf-core-2020-12-14' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (24 commits)
  perf/x86/intel: Add Tremont Topdown support
  uprobes/x86: Fix fall-through warnings for Clang
  perf/x86: Fix fall-through warnings for Clang
  kprobes/x86: Fix fall-through warnings for Clang
  perf/x86/intel/lbr: Fix the return type of get_lbr_cycles()
  perf/x86/intel: Fix rtm_abort_event encoding on Ice Lake
  x86/kprobes: Restore BTF if the single-stepping is cancelled
  perf: Break deadlock involving exec_update_mutex
  sparc64/mm: Implement pXX_leaf_size() support
  powerpc/8xx: Implement pXX_leaf_size() support
  arm64/mm: Implement pXX_leaf_size() support
  perf/core: Fix arch_perf_get_page_size()
  mm: Introduce pXX_leaf_size()
  mm/gup: Provide gup_get_pte() more generic
  perf/x86/intel: Add event constraint for CYCLE_ACTIVITY.STALLS_MEM_ANY
  perf/x86/intel/uncore: Add Rocket Lake support
  perf/x86/msr: Add Rocket Lake CPU support
  perf/x86/cstate: Add Rocket Lake CPU support
  perf/x86/intel: Add Rocket Lake CPU support
  perf,mm: Handle non-page-table-aligned hugetlbfs
  ...

1  2 
arch/arm64/include/asm/pgtable.h
arch/x86/events/core.c
arch/x86/events/intel/ds.c
arch/x86/events/intel/lbr.c
arch/x86/kernel/uprobes.c
include/linux/pgtable.h

index 005eb035fbfa7230ba4001211ba45bb19cf9c1e2,c3b92a4503cfb6c14b7f875f150dc13bfc882a20..88a18d7f4e5994399d034c268790a41abb47fe31
@@@ -22,7 -22,7 +22,7 @@@
   *    and fixed mappings
   */
  #define VMALLOC_START         (MODULES_END)
 -#define VMALLOC_END           (- PUD_SIZE - VMEMMAP_SIZE - SZ_64K)
 +#define VMALLOC_END           (VMEMMAP_START - SZ_256M)
  
  #define vmemmap                       ((struct page *)VMEMMAP_START - (memstart_addr >> PAGE_SHIFT))
  
@@@ -115,6 -115,8 +115,6 @@@ extern unsigned long empty_zero_page[PA
  #define pte_valid(pte)                (!!(pte_val(pte) & PTE_VALID))
  #define pte_valid_not_user(pte) \
        ((pte_val(pte) & (PTE_VALID | PTE_USER)) == PTE_VALID)
 -#define pte_valid_young(pte) \
 -      ((pte_val(pte) & (PTE_VALID | PTE_AF)) == (PTE_VALID | PTE_AF))
  #define pte_valid_user(pte) \
        ((pte_val(pte) & (PTE_VALID | PTE_USER)) == (PTE_VALID | PTE_USER))
  
   * Could the pte be present in the TLB? We must check mm_tlb_flush_pending
   * so that we don't erroneously return false for pages that have been
   * remapped as PROT_NONE but are yet to be flushed from the TLB.
 + * Note that we can't make any assumptions based on the state of the access
 + * flag, since ptep_clear_flush_young() elides a DSB when invalidating the
 + * TLB.
   */
  #define pte_accessible(mm, pte)       \
 -      (mm_tlb_flush_pending(mm) ? pte_present(pte) : pte_valid_young(pte))
 +      (mm_tlb_flush_pending(mm) ? pte_present(pte) : pte_valid(pte))
  
  /*
   * p??_access_permitted() is true for valid user mappings (subject to the
@@@ -165,6 -164,13 +165,6 @@@ static inline pmd_t set_pmd_bit(pmd_t p
        return pmd;
  }
  
 -static inline pte_t pte_wrprotect(pte_t pte)
 -{
 -      pte = clear_pte_bit(pte, __pgprot(PTE_WRITE));
 -      pte = set_pte_bit(pte, __pgprot(PTE_RDONLY));
 -      return pte;
 -}
 -
  static inline pte_t pte_mkwrite(pte_t pte)
  {
        pte = set_pte_bit(pte, __pgprot(PTE_WRITE));
@@@ -190,20 -196,6 +190,20 @@@ static inline pte_t pte_mkdirty(pte_t p
        return pte;
  }
  
 +static inline pte_t pte_wrprotect(pte_t pte)
 +{
 +      /*
 +       * If hardware-dirty (PTE_WRITE/DBM bit set and PTE_RDONLY
 +       * clear), set the PTE_DIRTY bit.
 +       */
 +      if (pte_hw_dirty(pte))
 +              pte = pte_mkdirty(pte);
 +
 +      pte = clear_pte_bit(pte, __pgprot(PTE_WRITE));
 +      pte = set_pte_bit(pte, __pgprot(PTE_RDONLY));
 +      return pte;
 +}
 +
  static inline pte_t pte_mkold(pte_t pte)
  {
        return clear_pte_bit(pte, __pgprot(PTE_AF));
@@@ -415,6 -407,7 +415,7 @@@ static inline int pmd_trans_huge(pmd_t 
  #define pmd_dirty(pmd)                pte_dirty(pmd_pte(pmd))
  #define pmd_young(pmd)                pte_young(pmd_pte(pmd))
  #define pmd_valid(pmd)                pte_valid(pmd_pte(pmd))
+ #define pmd_cont(pmd)         pte_cont(pmd_pte(pmd))
  #define pmd_wrprotect(pmd)    pte_pmd(pte_wrprotect(pmd_pte(pmd)))
  #define pmd_mkold(pmd)                pte_pmd(pte_mkold(pmd_pte(pmd)))
  #define pmd_mkwrite(pmd)      pte_pmd(pte_mkwrite(pmd_pte(pmd)))
@@@ -511,6 -504,9 +512,9 @@@ extern pgprot_t phys_mem_access_prot(st
                                 PMD_TYPE_SECT)
  #define pmd_leaf(pmd)         pmd_sect(pmd)
  
+ #define pmd_leaf_size(pmd)    (pmd_cont(pmd) ? CONT_PMD_SIZE : PMD_SIZE)
+ #define pte_leaf_size(pte)    (pte_cont(pte) ? CONT_PTE_SIZE : PAGE_SIZE)
  #if defined(CONFIG_ARM64_64K_PAGES) || CONFIG_PGTABLE_LEVELS < 3
  static inline bool pud_sect(pud_t pud) { return false; }
  static inline bool pud_table(pud_t pud) { return true; }
@@@ -527,7 -523,6 +531,7 @@@ extern pgd_t swapper_pg_dir[PTRS_PER_PG
  extern pgd_t idmap_pg_dir[PTRS_PER_PGD];
  extern pgd_t idmap_pg_end[];
  extern pgd_t tramp_pg_dir[PTRS_PER_PGD];
 +extern pgd_t reserved_pg_dir[PTRS_PER_PGD];
  
  extern void set_swapper_pgd(pgd_t *pgdp, pgd_t pgd);
  
@@@ -854,6 -849,12 +858,6 @@@ static inline void ptep_set_wrprotect(s
        pte = READ_ONCE(*ptep);
        do {
                old_pte = pte;
 -              /*
 -               * If hardware-dirty (PTE_WRITE/DBM bit set and PTE_RDONLY
 -               * clear), set the PTE_DIRTY bit.
 -               */
 -              if (pte_hw_dirty(pte))
 -                      pte = pte_mkdirty(pte);
                pte = pte_wrprotect(pte);
                pte_val(pte) = cmpxchg_relaxed(&pte_val(*ptep),
                                               pte_val(old_pte), pte_val(pte));
diff --combined arch/x86/events/core.c
index 77b963e5e70afdf45dbee54a34a3be743511b4e0,550c5e7002b90bd787b556228b6d1e6f28b3490a..e37de298a49557172747505c497f2ba6a880ee12
@@@ -1174,7 -1174,7 +1174,7 @@@ static inline void x86_assign_hw_event(
        case INTEL_PMC_IDX_METRIC_BASE ... INTEL_PMC_IDX_METRIC_END:
                /* All the metric events are mapped onto the fixed counter 3. */
                idx = INTEL_PMC_IDX_FIXED_SLOTS;
-               /* fall through */
+               fallthrough;
        case INTEL_PMC_IDX_FIXED ... INTEL_PMC_IDX_FIXED_BTS-1:
                hwc->config_base = MSR_ARCH_PERFMON_FIXED_CTR_CTRL;
                hwc->event_base = MSR_ARCH_PERFMON_FIXED_CTR0 +
@@@ -2602,7 -2602,7 +2602,7 @@@ perf_callchain_user32(struct pt_regs *r
        struct stack_frame_ia32 frame;
        const struct stack_frame_ia32 __user *fp;
  
 -      if (!test_thread_flag(TIF_IA32))
 +      if (user_64bit_mode(regs))
                return 0;
  
        cs_base = get_segment_base(regs->cs);
index a5c6ff5f1b4ccde00f1ea8f9724d888971fc3c24,afbf734e2ee3b84d304b353d43e20dfc8b36a203..67dbc91bccfee33405fe5d15e3b3237a3316a6e9
@@@ -961,7 -961,8 +961,8 @@@ static void adaptive_pebs_record_size_u
  
  #define PERF_PEBS_MEMINFO_TYPE        (PERF_SAMPLE_ADDR | PERF_SAMPLE_DATA_SRC |   \
                                PERF_SAMPLE_PHYS_ADDR | PERF_SAMPLE_WEIGHT | \
-                               PERF_SAMPLE_TRANSACTION)
+                               PERF_SAMPLE_TRANSACTION |                    \
+                               PERF_SAMPLE_DATA_PAGE_SIZE)
  
  static u64 pebs_update_adaptive_cfg(struct perf_event *event)
  {
@@@ -1261,7 -1262,7 +1262,7 @@@ static int intel_pmu_pebs_fixup_ip(stru
                old_to = to;
  
  #ifdef CONFIG_X86_64
 -              is_64bit = kernel_ip(to) || !test_thread_flag(TIF_IA32);
 +              is_64bit = kernel_ip(to) || any_64bit_mode(regs);
  #endif
                insn_init(&insn, kaddr, size, is_64bit);
                insn_get_length(&insn);
@@@ -1337,6 -1338,10 +1338,10 @@@ static u64 get_data_src(struct perf_eve
        return val;
  }
  
+ #define PERF_SAMPLE_ADDR_TYPE (PERF_SAMPLE_ADDR |             \
+                                PERF_SAMPLE_PHYS_ADDR |        \
+                                PERF_SAMPLE_DATA_PAGE_SIZE)
  static void setup_pebs_fixed_sample_data(struct perf_event *event,
                                   struct pt_regs *iregs, void *__pebs,
                                   struct perf_sample_data *data,
        }
  
  
-       if ((sample_type & (PERF_SAMPLE_ADDR | PERF_SAMPLE_PHYS_ADDR)) &&
+       if ((sample_type & PERF_SAMPLE_ADDR_TYPE) &&
            x86_pmu.intel_cap.pebs_format >= 1)
                data->addr = pebs->dla;
  
@@@ -1579,7 -1584,7 +1584,7 @@@ static void setup_pebs_adaptive_sample_
                if (sample_type & PERF_SAMPLE_DATA_SRC)
                        data->data_src.val = get_data_src(event, meminfo->aux);
  
-               if (sample_type & (PERF_SAMPLE_ADDR | PERF_SAMPLE_PHYS_ADDR))
+               if (sample_type & PERF_SAMPLE_ADDR_TYPE)
                        data->addr = meminfo->address;
  
                if (sample_type & PERF_SAMPLE_TRANSACTION)
@@@ -1916,7 -1921,7 +1921,7 @@@ static void intel_pmu_drain_pebs_nhm(st
                 * that caused the PEBS record. It's called collision.
                 * If collision happened, the record will be dropped.
                 */
 -              if (p->status != (1ULL << bit)) {
 +              if (pebs_status != (1ULL << bit)) {
                        for_each_set_bit(i, (unsigned long *)&pebs_status, size)
                                error[i]++;
                        continue;
                if (error[bit]) {
                        perf_log_lost_samples(event, error[bit]);
  
 -                      if (perf_event_account_interrupt(event))
 +                      if (iregs && perf_event_account_interrupt(event))
                                x86_pmu_stop(event, 0);
                }
  
index 1aadb253d296a2f4ec8e9f78998ee4315eee0236,e2b0efcba1017bb0382ef58aa0ab38cd1b736d8c..21890dacfcfee5f7406e5ac5b72980188ccb3997
@@@ -919,7 -919,7 +919,7 @@@ static __always_inline bool get_lbr_pre
        return !(info & LBR_INFO_MISPRED);
  }
  
- static __always_inline bool get_lbr_cycles(u64 info)
+ static __always_inline u16 get_lbr_cycles(u64 info)
  {
        if (static_cpu_has(X86_FEATURE_ARCH_LBR) &&
            !(x86_pmu.lbr_timed_lbr && info & LBR_INFO_CYC_CNT_VALID))
@@@ -1221,7 -1221,7 +1221,7 @@@ static int branch_type(unsigned long fr
         * on 64-bit systems running 32-bit apps
         */
  #ifdef CONFIG_X86_64
 -      is64 = kernel_ip((unsigned long)addr) || !test_thread_flag(TIF_IA32);
 +      is64 = kernel_ip((unsigned long)addr) || any_64bit_mode(current_pt_regs());
  #endif
        insn_init(&insn, addr, bytes_read, is64);
        insn_get_opcode(&insn);
index 138bdb1fd1360aebc3cd5cc95a0821117c9ccfe7,90f44f44c2098fadf97a48a9f963408f7c71f12e..a2b41339491714f0cc670f0a12658bb49b74248a
@@@ -255,13 -255,12 +255,13 @@@ static volatile u32 good_2byte_insns[25
  
  static bool is_prefix_bad(struct insn *insn)
  {
 +      insn_byte_t p;
        int i;
  
 -      for (i = 0; i < insn->prefixes.nbytes; i++) {
 +      for_each_insn_prefix(insn, i, p) {
                insn_attr_t attr;
  
 -              attr = inat_get_opcode_attribute(insn->prefixes.bytes[i]);
 +              attr = inat_get_opcode_attribute(p);
                switch (attr) {
                case INAT_MAKE_PREFIX(INAT_PFX_ES):
                case INAT_MAKE_PREFIX(INAT_PFX_CS):
@@@ -716,7 -715,6 +716,7 @@@ static const struct uprobe_xol_ops push
  static int branch_setup_xol_ops(struct arch_uprobe *auprobe, struct insn *insn)
  {
        u8 opc1 = OPCODE1(insn);
 +      insn_byte_t p;
        int i;
  
        switch (opc1) {
         * Intel and AMD behavior differ in 64-bit mode: Intel ignores 66 prefix.
         * No one uses these insns, reject any branch insns with such prefix.
         */
 -      for (i = 0; i < insn->prefixes.nbytes; i++) {
 -              if (insn->prefixes.bytes[i] == 0x66)
 +      for_each_insn_prefix(insn, i, p) {
 +              if (p == 0x66)
                        return -ENOTSUPP;
        }
  
@@@ -1017,6 -1015,8 +1017,8 @@@ int arch_uprobe_exception_notify(struc
                if (uprobe_post_sstep_notifier(regs))
                        ret = NOTIFY_STOP;
  
+               break;
        default:
                break;
        }
diff --combined include/linux/pgtable.h
index e237004d498d6b02702e2058076dfb165792ce15,fefbbdbbb3f34c1f2c7c06f03723ab8dad1f490e..8fcdfa52eb4be57917d6dd9acce4fcc44460b221
@@@ -258,6 -258,61 +258,61 @@@ static inline pte_t ptep_get(pte_t *pte
  }
  #endif
  
+ #ifdef CONFIG_GUP_GET_PTE_LOW_HIGH
+ /*
+  * WARNING: only to be used in the get_user_pages_fast() implementation.
+  *
+  * With get_user_pages_fast(), we walk down the pagetables without taking any
+  * locks.  For this we would like to load the pointers atomically, but sometimes
+  * that is not possible (e.g. without expensive cmpxchg8b on x86_32 PAE).  What
+  * we do have is the guarantee that a PTE will only either go from not present
+  * to present, or present to not present or both -- it will not switch to a
+  * completely different present page without a TLB flush in between; something
+  * that we are blocking by holding interrupts off.
+  *
+  * Setting ptes from not present to present goes:
+  *
+  *   ptep->pte_high = h;
+  *   smp_wmb();
+  *   ptep->pte_low = l;
+  *
+  * And present to not present goes:
+  *
+  *   ptep->pte_low = 0;
+  *   smp_wmb();
+  *   ptep->pte_high = 0;
+  *
+  * We must ensure here that the load of pte_low sees 'l' IFF pte_high sees 'h'.
+  * We load pte_high *after* loading pte_low, which ensures we don't see an older
+  * value of pte_high.  *Then* we recheck pte_low, which ensures that we haven't
+  * picked up a changed pte high. We might have gotten rubbish values from
+  * pte_low and pte_high, but we are guaranteed that pte_low will not have the
+  * present bit set *unless* it is 'l'. Because get_user_pages_fast() only
+  * operates on present ptes we're safe.
+  */
+ static inline pte_t ptep_get_lockless(pte_t *ptep)
+ {
+       pte_t pte;
+       do {
+               pte.pte_low = ptep->pte_low;
+               smp_rmb();
+               pte.pte_high = ptep->pte_high;
+               smp_rmb();
+       } while (unlikely(pte.pte_low != ptep->pte_low));
+       return pte;
+ }
+ #else /* CONFIG_GUP_GET_PTE_LOW_HIGH */
+ /*
+  * We require that the PTE can be read atomically.
+  */
+ static inline pte_t ptep_get_lockless(pte_t *ptep)
+ {
+       return ptep_get(ptep);
+ }
+ #endif /* CONFIG_GUP_GET_PTE_LOW_HIGH */
  #ifdef CONFIG_TRANSPARENT_HUGEPAGE
  #ifndef __HAVE_ARCH_PMDP_HUGE_GET_AND_CLEAR
  static inline pmd_t pmdp_huge_get_and_clear(struct mm_struct *mm,
@@@ -1427,19 -1482,6 +1482,19 @@@ typedef unsigned int pgtbl_mod_mask
  
  #endif /* !__ASSEMBLY__ */
  
 +#if !defined(MAX_POSSIBLE_PHYSMEM_BITS) && !defined(CONFIG_64BIT)
 +#ifdef CONFIG_PHYS_ADDR_T_64BIT
 +/*
 + * ZSMALLOC needs to know the highest PFN on 32-bit architectures
 + * with physical address space extension, but falls back to
 + * BITS_PER_LONG otherwise.
 + */
 +#error Missing MAX_POSSIBLE_PHYSMEM_BITS definition
 +#else
 +#define MAX_POSSIBLE_PHYSMEM_BITS 32
 +#endif
 +#endif
 +
  #ifndef has_transparent_hugepage
  #ifdef CONFIG_TRANSPARENT_HUGEPAGE
  #define has_transparent_hugepage() 1
  #define pmd_leaf(x)   0
  #endif
  
+ #ifndef pgd_leaf_size
+ #define pgd_leaf_size(x) (1ULL << PGDIR_SHIFT)
+ #endif
+ #ifndef p4d_leaf_size
+ #define p4d_leaf_size(x) P4D_SIZE
+ #endif
+ #ifndef pud_leaf_size
+ #define pud_leaf_size(x) PUD_SIZE
+ #endif
+ #ifndef pmd_leaf_size
+ #define pmd_leaf_size(x) PMD_SIZE
+ #endif
+ #ifndef pte_leaf_size
+ #define pte_leaf_size(x) PAGE_SIZE
+ #endif
  #endif /* _LINUX_PGTABLE_H */
This page took 0.109567 seconds and 4 git commands to generate.