Merge branch 'linus' into perf/core, to pick up fixes
authorIngo Molnar <mingo@kernel.org>
Thu, 28 Feb 2019 07:27:17 +0000 (08:27 +0100)
committerIngo Molnar <mingo@kernel.org>
Thu, 28 Feb 2019 07:27:17 +0000 (08:27 +0100)
Signed-off-by: Ingo Molnar <mingo@kernel.org>
1  2 
arch/x86/events/intel/core.c
arch/x86/events/perf_event.h
include/linux/filter.h
include/linux/perf_event.h
kernel/bpf/syscall.c
kernel/events/core.c
kernel/events/ring_buffer.c
kernel/trace/bpf_trace.c

@@@ -18,7 -18,6 +18,7 @@@
  #include <asm/hardirq.h>
  #include <asm/intel-family.h>
  #include <asm/apic.h>
 +#include <asm/cpu_device_id.h>
  
  #include "../perf_event.h"
  
@@@ -3207,27 -3206,16 +3207,27 @@@ static struct perf_guest_switch_msr *in
        arr[0].msr = MSR_CORE_PERF_GLOBAL_CTRL;
        arr[0].host = x86_pmu.intel_ctrl & ~cpuc->intel_ctrl_guest_mask;
        arr[0].guest = x86_pmu.intel_ctrl & ~cpuc->intel_ctrl_host_mask;
 -      /*
 -       * If PMU counter has PEBS enabled it is not enough to disable counter
 -       * on a guest entry since PEBS memory write can overshoot guest entry
 -       * and corrupt guest memory. Disabling PEBS solves the problem.
 -       */
 -      arr[1].msr = MSR_IA32_PEBS_ENABLE;
 -      arr[1].host = cpuc->pebs_enabled;
 -      arr[1].guest = 0;
 +      if (x86_pmu.flags & PMU_FL_PEBS_ALL)
 +              arr[0].guest &= ~cpuc->pebs_enabled;
 +      else
 +              arr[0].guest &= ~(cpuc->pebs_enabled & PEBS_COUNTER_MASK);
 +      *nr = 1;
 +
 +      if (x86_pmu.pebs && x86_pmu.pebs_no_isolation) {
 +              /*
 +               * If PMU counter has PEBS enabled it is not enough to
 +               * disable counter on a guest entry since PEBS memory
 +               * write can overshoot guest entry and corrupt guest
 +               * memory. Disabling PEBS solves the problem.
 +               *
 +               * Don't do this if the CPU already enforces it.
 +               */
 +              arr[1].msr = MSR_IA32_PEBS_ENABLE;
 +              arr[1].host = cpuc->pebs_enabled;
 +              arr[1].guest = 0;
 +              *nr = 2;
 +      }
  
 -      *nr = 2;
        return arr;
  }
  
@@@ -3599,6 -3587,11 +3599,11 @@@ static void intel_pmu_sched_task(struc
        intel_pmu_lbr_sched_task(ctx, sched_in);
  }
  
+ static int intel_pmu_check_period(struct perf_event *event, u64 value)
+ {
+       return intel_pmu_has_bts_period(event, value) ? -EINVAL : 0;
+ }
  PMU_FORMAT_ATTR(offcore_rsp, "config1:0-63");
  
  PMU_FORMAT_ATTR(ldlat, "config1:0-15");
@@@ -3679,6 -3672,8 +3684,8 @@@ static __initconst const struct x86_pm
        .cpu_starting           = intel_pmu_cpu_starting,
        .cpu_dying              = intel_pmu_cpu_dying,
        .cpu_dead               = intel_pmu_cpu_dead,
+       .check_period           = intel_pmu_check_period,
  };
  
  static struct attribute *intel_pmu_attrs[];
@@@ -3723,6 -3718,8 +3730,8 @@@ static __initconst const struct x86_pm
  
        .guest_get_msrs         = intel_guest_get_msrs,
        .sched_task             = intel_pmu_sched_task,
+       .check_period           = intel_pmu_check_period,
  };
  
  static __init void intel_clovertown_quirk(void)
        x86_pmu.pebs_constraints = NULL;
  }
  
 -static int intel_snb_pebs_broken(int cpu)
 +static const struct x86_cpu_desc isolation_ucodes[] = {
 +      INTEL_CPU_DESC(INTEL_FAM6_HASWELL_CORE,          3, 0x0000001f),
 +      INTEL_CPU_DESC(INTEL_FAM6_HASWELL_ULT,           1, 0x0000001e),
 +      INTEL_CPU_DESC(INTEL_FAM6_HASWELL_GT3E,          1, 0x00000015),
 +      INTEL_CPU_DESC(INTEL_FAM6_HASWELL_X,             2, 0x00000037),
 +      INTEL_CPU_DESC(INTEL_FAM6_HASWELL_X,             4, 0x0000000a),
 +      INTEL_CPU_DESC(INTEL_FAM6_BROADWELL_CORE,        4, 0x00000023),
 +      INTEL_CPU_DESC(INTEL_FAM6_BROADWELL_GT3E,        1, 0x00000014),
 +      INTEL_CPU_DESC(INTEL_FAM6_BROADWELL_XEON_D,      2, 0x00000010),
 +      INTEL_CPU_DESC(INTEL_FAM6_BROADWELL_XEON_D,      3, 0x07000009),
 +      INTEL_CPU_DESC(INTEL_FAM6_BROADWELL_XEON_D,      4, 0x0f000009),
 +      INTEL_CPU_DESC(INTEL_FAM6_BROADWELL_XEON_D,      5, 0x0e000002),
 +      INTEL_CPU_DESC(INTEL_FAM6_BROADWELL_X,           2, 0x0b000014),
 +      INTEL_CPU_DESC(INTEL_FAM6_SKYLAKE_X,             3, 0x00000021),
 +      INTEL_CPU_DESC(INTEL_FAM6_SKYLAKE_X,             4, 0x00000000),
 +      INTEL_CPU_DESC(INTEL_FAM6_SKYLAKE_MOBILE,        3, 0x0000007c),
 +      INTEL_CPU_DESC(INTEL_FAM6_SKYLAKE_DESKTOP,       3, 0x0000007c),
 +      INTEL_CPU_DESC(INTEL_FAM6_KABYLAKE_DESKTOP,      9, 0x0000004e),
 +      INTEL_CPU_DESC(INTEL_FAM6_KABYLAKE_MOBILE,       9, 0x0000004e),
 +      INTEL_CPU_DESC(INTEL_FAM6_KABYLAKE_MOBILE,      10, 0x0000004e),
 +      INTEL_CPU_DESC(INTEL_FAM6_KABYLAKE_MOBILE,      11, 0x0000004e),
 +      INTEL_CPU_DESC(INTEL_FAM6_KABYLAKE_MOBILE,      12, 0x0000004e),
 +      INTEL_CPU_DESC(INTEL_FAM6_KABYLAKE_DESKTOP,     10, 0x0000004e),
 +      INTEL_CPU_DESC(INTEL_FAM6_KABYLAKE_DESKTOP,     11, 0x0000004e),
 +      INTEL_CPU_DESC(INTEL_FAM6_KABYLAKE_DESKTOP,     12, 0x0000004e),
 +      INTEL_CPU_DESC(INTEL_FAM6_KABYLAKE_DESKTOP,     13, 0x0000004e),
 +      {}
 +};
 +
 +static void intel_check_pebs_isolation(void)
  {
 -      u32 rev = UINT_MAX; /* default to broken for unknown models */
 +      x86_pmu.pebs_no_isolation = !x86_cpu_has_min_microcode_rev(isolation_ucodes);
 +}
  
 -      switch (cpu_data(cpu).x86_model) {
 -      case INTEL_FAM6_SANDYBRIDGE:
 -              rev = 0x28;
 -              break;
 +static __init void intel_pebs_isolation_quirk(void)
 +{
 +      WARN_ON_ONCE(x86_pmu.check_microcode);
 +      x86_pmu.check_microcode = intel_check_pebs_isolation;
 +      intel_check_pebs_isolation();
 +}
  
 -      case INTEL_FAM6_SANDYBRIDGE_X:
 -              switch (cpu_data(cpu).x86_stepping) {
 -              case 6: rev = 0x618; break;
 -              case 7: rev = 0x70c; break;
 -              }
 -      }
 +static const struct x86_cpu_desc pebs_ucodes[] = {
 +      INTEL_CPU_DESC(INTEL_FAM6_SANDYBRIDGE,          7, 0x00000028),
 +      INTEL_CPU_DESC(INTEL_FAM6_SANDYBRIDGE_X,        6, 0x00000618),
 +      INTEL_CPU_DESC(INTEL_FAM6_SANDYBRIDGE_X,        7, 0x0000070c),
 +      {}
 +};
  
 -      return (cpu_data(cpu).microcode < rev);
 +static bool intel_snb_pebs_broken(void)
 +{
 +      return !x86_cpu_has_min_microcode_rev(pebs_ucodes);
  }
  
  static void intel_snb_check_microcode(void)
  {
 -      int pebs_broken = 0;
 -      int cpu;
 -
 -      for_each_online_cpu(cpu) {
 -              if ((pebs_broken = intel_snb_pebs_broken(cpu)))
 -                      break;
 -      }
 -
 -      if (pebs_broken == x86_pmu.pebs_broken)
 +      if (intel_snb_pebs_broken() == x86_pmu.pebs_broken)
                return;
  
        /*
@@@ -3923,22 -3894,23 +3932,22 @@@ static __init void intel_nehalem_quirk(
        }
  }
  
 -static bool intel_glp_counter_freezing_broken(int cpu)
 -{
 -      u32 rev = UINT_MAX; /* default to broken for unknown stepping */
 -
 -      switch (cpu_data(cpu).x86_stepping) {
 -      case 1:
 -              rev = 0x28;
 -              break;
 -      case 8:
 -              rev = 0x6;
 -              break;
 -      }
 +static const struct x86_cpu_desc counter_freezing_ucodes[] = {
 +      INTEL_CPU_DESC(INTEL_FAM6_ATOM_GOLDMONT,         2, 0x0000000e),
 +      INTEL_CPU_DESC(INTEL_FAM6_ATOM_GOLDMONT,         9, 0x0000002e),
 +      INTEL_CPU_DESC(INTEL_FAM6_ATOM_GOLDMONT,        10, 0x00000008),
 +      INTEL_CPU_DESC(INTEL_FAM6_ATOM_GOLDMONT_X,       1, 0x00000028),
 +      INTEL_CPU_DESC(INTEL_FAM6_ATOM_GOLDMONT_PLUS,    1, 0x00000028),
 +      INTEL_CPU_DESC(INTEL_FAM6_ATOM_GOLDMONT_PLUS,    8, 0x00000006),
 +      {}
 +};
  
 -      return (cpu_data(cpu).microcode < rev);
 +static bool intel_counter_freezing_broken(void)
 +{
 +      return !x86_cpu_has_min_microcode_rev(counter_freezing_ucodes);
  }
  
 -static __init void intel_glp_counter_freezing_quirk(void)
 +static __init void intel_counter_freezing_quirk(void)
  {
        /* Check if it's already disabled */
        if (disable_counter_freezing)
         * If the system starts with the wrong ucode, leave the
         * counter-freezing feature permanently disabled.
         */
 -      if (intel_glp_counter_freezing_broken(raw_smp_processor_id())) {
 +      if (intel_counter_freezing_broken()) {
                pr_info("PMU counter freezing disabled due to CPU errata,"
                        "please upgrade microcode\n");
                x86_pmu.counter_freezing = false;
@@@ -4299,7 -4271,6 +4308,7 @@@ __init int intel_pmu_init(void
  
        case INTEL_FAM6_ATOM_GOLDMONT:
        case INTEL_FAM6_ATOM_GOLDMONT_X:
 +              x86_add_quirk(intel_counter_freezing_quirk);
                memcpy(hw_cache_event_ids, glm_hw_cache_event_ids,
                       sizeof(hw_cache_event_ids));
                memcpy(hw_cache_extra_regs, glm_hw_cache_extra_regs,
                break;
  
        case INTEL_FAM6_ATOM_GOLDMONT_PLUS:
 -              x86_add_quirk(intel_glp_counter_freezing_quirk);
 +              x86_add_quirk(intel_counter_freezing_quirk);
                memcpy(hw_cache_event_ids, glp_hw_cache_event_ids,
                       sizeof(hw_cache_event_ids));
                memcpy(hw_cache_extra_regs, glp_hw_cache_extra_regs,
        case INTEL_FAM6_HASWELL_ULT:
        case INTEL_FAM6_HASWELL_GT3E:
                x86_add_quirk(intel_ht_bug);
 +              x86_add_quirk(intel_pebs_isolation_quirk);
                x86_pmu.late_ack = true;
                memcpy(hw_cache_event_ids, hsw_hw_cache_event_ids, sizeof(hw_cache_event_ids));
                memcpy(hw_cache_extra_regs, hsw_hw_cache_extra_regs, sizeof(hw_cache_extra_regs));
        case INTEL_FAM6_BROADWELL_XEON_D:
        case INTEL_FAM6_BROADWELL_GT3E:
        case INTEL_FAM6_BROADWELL_X:
 +              x86_add_quirk(intel_pebs_isolation_quirk);
                x86_pmu.late_ack = true;
                memcpy(hw_cache_event_ids, hsw_hw_cache_event_ids, sizeof(hw_cache_event_ids));
                memcpy(hw_cache_extra_regs, hsw_hw_cache_extra_regs, sizeof(hw_cache_extra_regs));
        case INTEL_FAM6_SKYLAKE_X:
        case INTEL_FAM6_KABYLAKE_MOBILE:
        case INTEL_FAM6_KABYLAKE_DESKTOP:
 +              x86_add_quirk(intel_pebs_isolation_quirk);
                x86_pmu.late_ack = true;
                memcpy(hw_cache_event_ids, skl_hw_cache_event_ids, sizeof(hw_cache_event_ids));
                memcpy(hw_cache_extra_regs, skl_hw_cache_extra_regs, sizeof(hw_cache_extra_regs));
@@@ -601,14 -601,13 +601,14 @@@ struct x86_pmu 
        /*
         * Intel DebugStore bits
         */
 -      unsigned int    bts             :1,
 -                      bts_active      :1,
 -                      pebs            :1,
 -                      pebs_active     :1,
 -                      pebs_broken     :1,
 -                      pebs_prec_dist  :1,
 -                      pebs_no_tlb     :1;
 +      unsigned int    bts                     :1,
 +                      bts_active              :1,
 +                      pebs                    :1,
 +                      pebs_active             :1,
 +                      pebs_broken             :1,
 +                      pebs_prec_dist          :1,
 +                      pebs_no_tlb             :1,
 +                      pebs_no_isolation       :1;
        int             pebs_record_size;
        int             pebs_buffer_size;
        void            (*drain_pebs)(struct pt_regs *regs);
         * Intel host/guest support (KVM)
         */
        struct perf_guest_switch_msr *(*guest_get_msrs)(int *nr);
+       /*
+        * Check period value for PERF_EVENT_IOC_PERIOD ioctl.
+        */
+       int (*check_period) (struct perf_event *event, u64 period);
  };
  
  struct x86_perf_task_context {
@@@ -858,7 -862,7 +863,7 @@@ static inline int amd_pmu_init(void
  
  #ifdef CONFIG_CPU_SUP_INTEL
  
- static inline bool intel_pmu_has_bts(struct perf_event *event)
+ static inline bool intel_pmu_has_bts_period(struct perf_event *event, u64 period)
  {
        struct hw_perf_event *hwc = &event->hw;
        unsigned int hw_event, bts_event;
        hw_event = hwc->config & INTEL_ARCH_EVENT_MASK;
        bts_event = x86_pmu.event_map(PERF_COUNT_HW_BRANCH_INSTRUCTIONS);
  
-       return hw_event == bts_event && hwc->sample_period == 1;
+       return hw_event == bts_event && period == 1;
+ }
+ static inline bool intel_pmu_has_bts(struct perf_event *event)
+ {
+       struct hw_perf_event *hwc = &event->hw;
+       return intel_pmu_has_bts_period(event, hwc->sample_period);
  }
  
  int intel_pmu_save_and_restart(struct perf_event *event);
diff --combined include/linux/filter.h
@@@ -591,8 -591,8 +591,8 @@@ static inline u8 *bpf_skb_cb(struct sk_
        return qdisc_skb_cb(skb)->data;
  }
  
- static inline u32 bpf_prog_run_save_cb(const struct bpf_prog *prog,
-                                      struct sk_buff *skb)
+ static inline u32 __bpf_prog_run_save_cb(const struct bpf_prog *prog,
+                                        struct sk_buff *skb)
  {
        u8 *cb_data = bpf_skb_cb(skb);
        u8 cb_saved[BPF_SKB_CB_LEN];
        return res;
  }
  
+ static inline u32 bpf_prog_run_save_cb(const struct bpf_prog *prog,
+                                      struct sk_buff *skb)
+ {
+       u32 res;
+       preempt_disable();
+       res = __bpf_prog_run_save_cb(prog, skb);
+       preempt_enable();
+       return res;
+ }
  static inline u32 bpf_prog_run_clear_cb(const struct bpf_prog *prog,
                                        struct sk_buff *skb)
  {
        u8 *cb_data = bpf_skb_cb(skb);
+       u32 res;
  
        if (unlikely(prog->cb_access))
                memset(cb_data, 0, BPF_SKB_CB_LEN);
  
-       return BPF_PROG_RUN(prog, skb);
+       preempt_disable();
+       res = BPF_PROG_RUN(prog, skb);
+       preempt_enable();
+       return res;
  }
  
  static __always_inline u32 bpf_prog_run_xdp(const struct bpf_prog *prog,
@@@ -951,7 -966,6 +966,7 @@@ bpf_address_lookup(unsigned long addr, 
  
  void bpf_prog_kallsyms_add(struct bpf_prog *fp);
  void bpf_prog_kallsyms_del(struct bpf_prog *fp);
 +void bpf_get_prog_name(const struct bpf_prog *prog, char *sym);
  
  #else /* CONFIG_BPF_JIT */
  
@@@ -1007,12 -1021,6 +1022,12 @@@ static inline void bpf_prog_kallsyms_ad
  static inline void bpf_prog_kallsyms_del(struct bpf_prog *fp)
  {
  }
 +
 +static inline void bpf_get_prog_name(const struct bpf_prog *prog, char *sym)
 +{
 +      sym[0] = '\0';
 +}
 +
  #endif /* CONFIG_BPF_JIT */
  
  void bpf_prog_kallsyms_del_subprogs(struct bpf_prog *fp);
@@@ -53,8 -53,8 +53,8 @@@ struct perf_guest_info_callbacks 
  #include <linux/atomic.h>
  #include <linux/sysfs.h>
  #include <linux/perf_regs.h>
 -#include <linux/workqueue.h>
  #include <linux/cgroup.h>
 +#include <linux/refcount.h>
  #include <asm/local.h>
  
  struct perf_callchain_entry {
@@@ -244,7 -244,6 +244,7 @@@ struct perf_event
  #define PERF_PMU_CAP_EXCLUSIVE                        0x10
  #define PERF_PMU_CAP_ITRACE                   0x20
  #define PERF_PMU_CAP_HETEROGENEOUS_CPUS               0x40
 +#define PERF_PMU_CAP_NO_EXCLUDE                       0x80
  
  /**
   * struct pmu - generic performance monitoring unit
@@@ -410,7 -409,7 +410,7 @@@ struct pmu 
        /*
         * Set up pmu-private data structures for an AUX area
         */
 -      void *(*setup_aux)              (int cpu, void **pages,
 +      void *(*setup_aux)              (struct perf_event *event, void **pages,
                                         int nr_pages, bool overwrite);
                                        /* optional */
  
         * Filter events for PMU-specific reasons.
         */
        int (*filter_match)             (struct perf_event *event); /* optional */
+       /*
+        * Check period value for PERF_EVENT_IOC_PERIOD ioctl.
+        */
+       int (*check_period)             (struct perf_event *event, u64 value); /* optional */
  };
  
  enum perf_addr_filter_action_t {
@@@ -738,7 -742,7 +743,7 @@@ struct perf_event_context 
        int                             nr_stat;
        int                             nr_freq;
        int                             rotate_disable;
 -      atomic_t                        refcount;
 +      refcount_t                      refcount;
        struct task_struct              *task;
  
        /*
@@@ -979,9 -983,9 +984,9 @@@ extern void perf_event_output_forward(s
  extern void perf_event_output_backward(struct perf_event *event,
                                       struct perf_sample_data *data,
                                       struct pt_regs *regs);
 -extern void perf_event_output(struct perf_event *event,
 -                            struct perf_sample_data *data,
 -                            struct pt_regs *regs);
 +extern int perf_event_output(struct perf_event *event,
 +                           struct perf_sample_data *data,
 +                           struct pt_regs *regs);
  
  static inline bool
  is_default_overflow_handler(struct perf_event *event)
@@@ -1005,15 -1009,6 +1010,15 @@@ perf_event__output_id_sample(struct per
  extern void
  perf_log_lost_samples(struct perf_event *event, u64 lost);
  
 +static inline bool event_has_any_exclude_flag(struct perf_event *event)
 +{
 +      struct perf_event_attr *attr = &event->attr;
 +
 +      return attr->exclude_idle || attr->exclude_user ||
 +             attr->exclude_kernel || attr->exclude_hv ||
 +             attr->exclude_guest || attr->exclude_host;
 +}
 +
  static inline bool is_sampling_event(struct perf_event *event)
  {
        return event->attr.sample_period != 0;
@@@ -1123,13 -1118,6 +1128,13 @@@ static inline void perf_event_task_sche
  }
  
  extern void perf_event_mmap(struct vm_area_struct *vma);
 +
 +extern void perf_event_ksymbol(u16 ksym_type, u64 addr, u32 len,
 +                             bool unregister, const char *sym);
 +extern void perf_event_bpf_event(struct bpf_prog *prog,
 +                               enum perf_bpf_event_type type,
 +                               u16 flags);
 +
  extern struct perf_guest_info_callbacks *perf_guest_cbs;
  extern int perf_register_guest_info_callbacks(struct perf_guest_info_callbacks *callbacks);
  extern int perf_unregister_guest_info_callbacks(struct perf_guest_info_callbacks *callbacks);
@@@ -1350,13 -1338,6 +1355,13 @@@ static inline int perf_unregister_guest
  (struct perf_guest_info_callbacks *callbacks)                         { return 0; }
  
  static inline void perf_event_mmap(struct vm_area_struct *vma)                { }
 +
 +typedef int (perf_ksymbol_get_name_f)(char *name, int name_len, void *data);
 +static inline void perf_event_ksymbol(u16 ksym_type, u64 addr, u32 len,
 +                                    bool unregister, const char *sym) { }
 +static inline void perf_event_bpf_event(struct bpf_prog *prog,
 +                                      enum perf_bpf_event_type type,
 +                                      u16 flags)                      { }
  static inline void perf_event_exec(void)                              { }
  static inline void perf_event_comm(struct task_struct *tsk, bool exec)        { }
  static inline void perf_event_namespaces(struct task_struct *tsk)     { }
diff --combined kernel/bpf/syscall.c
@@@ -713,8 -713,13 +713,13 @@@ static int map_lookup_elem(union bpf_at
  
        if (bpf_map_is_dev_bound(map)) {
                err = bpf_map_offload_lookup_elem(map, key, value);
-       } else if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH ||
-                  map->map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH) {
+               goto done;
+       }
+       preempt_disable();
+       this_cpu_inc(bpf_prog_active);
+       if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH ||
+           map->map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH) {
                err = bpf_percpu_hash_copy(map, key, value);
        } else if (map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY) {
                err = bpf_percpu_array_copy(map, key, value);
                }
                rcu_read_unlock();
        }
+       this_cpu_dec(bpf_prog_active);
+       preempt_enable();
  
+ done:
        if (err)
                goto free_value;
  
@@@ -1211,7 -1219,6 +1219,7 @@@ static void __bpf_prog_put_rcu(struct r
  static void __bpf_prog_put(struct bpf_prog *prog, bool do_idr_lock)
  {
        if (atomic_dec_and_test(&prog->aux->refcnt)) {
 +              perf_event_bpf_event(prog, PERF_BPF_EVENT_PROG_UNLOAD, 0);
                /* bpf_prog_free_id() must be called first */
                bpf_prog_free_id(prog, do_idr_lock);
                bpf_prog_kallsyms_del_all(prog);
@@@ -1555,7 -1562,6 +1563,7 @@@ static int bpf_prog_load(union bpf_att
        }
  
        bpf_prog_kallsyms_add(prog);
 +      perf_event_bpf_event(prog, PERF_BPF_EVENT_PROG_LOAD, 0);
        return err;
  
  free_used_maps:
diff --combined kernel/events/core.c
@@@ -1,4 -1,3 +1,4 @@@
 +// SPDX-License-Identifier: GPL-2.0
  /*
   * Performance events core code:
   *
@@@ -6,6 -5,8 +6,6 @@@
   *  Copyright (C) 2008-2011 Red Hat, Inc., Ingo Molnar
   *  Copyright (C) 2008-2011 Red Hat, Inc., Peter Zijlstra
   *  Copyright  ©  2009 Paul Mackerras, IBM Corp. <paulus@au1.ibm.com>
 - *
 - * For licensing details see kernel-base/COPYING
   */
  
  #include <linux/fs.h>
@@@ -384,8 -385,6 +384,8 @@@ static atomic_t nr_namespaces_events __
  static atomic_t nr_task_events __read_mostly;
  static atomic_t nr_freq_events __read_mostly;
  static atomic_t nr_switch_events __read_mostly;
 +static atomic_t nr_ksymbol_events __read_mostly;
 +static atomic_t nr_bpf_events __read_mostly;
  
  static LIST_HEAD(pmus);
  static DEFINE_MUTEX(pmus_lock);
@@@ -1172,7 -1171,7 +1172,7 @@@ static void perf_event_ctx_deactivate(s
  
  static void get_ctx(struct perf_event_context *ctx)
  {
 -      WARN_ON(!atomic_inc_not_zero(&ctx->refcount));
 +      refcount_inc(&ctx->refcount);
  }
  
  static void free_ctx(struct rcu_head *head)
  
  static void put_ctx(struct perf_event_context *ctx)
  {
 -      if (atomic_dec_and_test(&ctx->refcount)) {
 +      if (refcount_dec_and_test(&ctx->refcount)) {
                if (ctx->parent_ctx)
                        put_ctx(ctx->parent_ctx);
                if (ctx->task && ctx->task != TASK_TOMBSTONE)
@@@ -1268,7 -1267,7 +1268,7 @@@ perf_event_ctx_lock_nested(struct perf_
  again:
        rcu_read_lock();
        ctx = READ_ONCE(event->ctx);
 -      if (!atomic_inc_not_zero(&ctx->refcount)) {
 +      if (!refcount_inc_not_zero(&ctx->refcount)) {
                rcu_read_unlock();
                goto again;
        }
@@@ -1401,7 -1400,7 +1401,7 @@@ retry
                }
  
                if (ctx->task == TASK_TOMBSTONE ||
 -                  !atomic_inc_not_zero(&ctx->refcount)) {
 +                  !refcount_inc_not_zero(&ctx->refcount)) {
                        raw_spin_unlock(&ctx->lock);
                        ctx = NULL;
                } else {
@@@ -4057,7 -4056,7 +4057,7 @@@ static void __perf_event_init_context(s
        INIT_LIST_HEAD(&ctx->event_list);
        INIT_LIST_HEAD(&ctx->pinned_active);
        INIT_LIST_HEAD(&ctx->flexible_active);
 -      atomic_set(&ctx->refcount, 1);
 +      refcount_set(&ctx->refcount, 1);
  }
  
  static struct perf_event_context *
@@@ -4236,7 -4235,7 +4236,7 @@@ static bool is_sb_event(struct perf_eve
  
        if (attr->mmap || attr->mmap_data || attr->mmap2 ||
            attr->comm || attr->comm_exec ||
 -          attr->task ||
 +          attr->task || attr->ksymbol ||
            attr->context_switch)
                return true;
        return false;
@@@ -4306,10 -4305,6 +4306,10 @@@ static void unaccount_event(struct perf
                dec = true;
        if (has_branch_stack(event))
                dec = true;
 +      if (event->attr.ksymbol)
 +              atomic_dec(&nr_ksymbol_events);
 +      if (event->attr.bpf_event)
 +              atomic_dec(&nr_bpf_events);
  
        if (dec) {
                if (!atomic_add_unless(&perf_sched_count, -1, 1))
@@@ -4968,6 -4963,11 +4968,11 @@@ static void __perf_event_period(struct 
        }
  }
  
+ static int perf_event_check_period(struct perf_event *event, u64 value)
+ {
+       return event->pmu->check_period(event, value);
+ }
  static int perf_event_period(struct perf_event *event, u64 __user *arg)
  {
        u64 value;
        if (event->attr.freq && value > sysctl_perf_event_sample_rate)
                return -EINVAL;
  
+       if (perf_event_check_period(event, value))
+               return -EINVAL;
        event_function_call(event, __perf_event_period, &value);
  
        return 0;
@@@ -5393,7 -5396,7 +5401,7 @@@ struct ring_buffer *ring_buffer_get(str
        rcu_read_lock();
        rb = rcu_dereference(event->rb);
        if (rb) {
 -              if (!atomic_inc_not_zero(&rb->refcount))
 +              if (!refcount_inc_not_zero(&rb->refcount))
                        rb = NULL;
        }
        rcu_read_unlock();
  
  void ring_buffer_put(struct ring_buffer *rb)
  {
 -      if (!atomic_dec_and_test(&rb->refcount))
 +      if (!refcount_dec_and_test(&rb->refcount))
                return;
  
        WARN_ON_ONCE(!list_empty(&rb->event_list));
@@@ -5468,7 -5471,7 +5476,7 @@@ static void perf_mmap_close(struct vm_a
  
                /* this has to be the last one */
                rb_free_aux(rb);
 -              WARN_ON_ONCE(atomic_read(&rb->aux_refcount));
 +              WARN_ON_ONCE(refcount_read(&rb->aux_refcount));
  
                mutex_unlock(&event->mmap_mutex);
        }
@@@ -6494,7 -6497,7 +6502,7 @@@ void perf_prepare_sample(struct perf_ev
                data->phys_addr = perf_virt_to_phys(data->addr);
  }
  
 -static __always_inline void
 +static __always_inline int
  __perf_event_output(struct perf_event *event,
                    struct perf_sample_data *data,
                    struct pt_regs *regs,
  {
        struct perf_output_handle handle;
        struct perf_event_header header;
 +      int err;
  
        /* protect the callchain buffers */
        rcu_read_lock();
  
        perf_prepare_sample(&header, data, event, regs);
  
 -      if (output_begin(&handle, event, header.size))
 +      err = output_begin(&handle, event, header.size);
 +      if (err)
                goto exit;
  
        perf_output_sample(&handle, &header, data, event);
  
  exit:
        rcu_read_unlock();
 +      return err;
  }
  
  void
@@@ -6540,12 -6540,12 +6548,12 @@@ perf_event_output_backward(struct perf_
        __perf_event_output(event, data, regs, perf_output_begin_backward);
  }
  
 -void
 +int
  perf_event_output(struct perf_event *event,
                  struct perf_sample_data *data,
                  struct pt_regs *regs)
  {
 -      __perf_event_output(event, data, regs, perf_output_begin);
 +      return __perf_event_output(event, data, regs, perf_output_begin);
  }
  
  /*
@@@ -7658,207 -7658,6 +7666,207 @@@ static void perf_log_throttle(struct pe
        perf_output_end(&handle);
  }
  
 +/*
 + * ksymbol register/unregister tracking
 + */
 +
 +struct perf_ksymbol_event {
 +      const char      *name;
 +      int             name_len;
 +      struct {
 +              struct perf_event_header        header;
 +              u64                             addr;
 +              u32                             len;
 +              u16                             ksym_type;
 +              u16                             flags;
 +      } event_id;
 +};
 +
 +static int perf_event_ksymbol_match(struct perf_event *event)
 +{
 +      return event->attr.ksymbol;
 +}
 +
 +static void perf_event_ksymbol_output(struct perf_event *event, void *data)
 +{
 +      struct perf_ksymbol_event *ksymbol_event = data;
 +      struct perf_output_handle handle;
 +      struct perf_sample_data sample;
 +      int ret;
 +
 +      if (!perf_event_ksymbol_match(event))
 +              return;
 +
 +      perf_event_header__init_id(&ksymbol_event->event_id.header,
 +                                 &sample, event);
 +      ret = perf_output_begin(&handle, event,
 +                              ksymbol_event->event_id.header.size);
 +      if (ret)
 +              return;
 +
 +      perf_output_put(&handle, ksymbol_event->event_id);
 +      __output_copy(&handle, ksymbol_event->name, ksymbol_event->name_len);
 +      perf_event__output_id_sample(event, &handle, &sample);
 +
 +      perf_output_end(&handle);
 +}
 +
 +void perf_event_ksymbol(u16 ksym_type, u64 addr, u32 len, bool unregister,
 +                      const char *sym)
 +{
 +      struct perf_ksymbol_event ksymbol_event;
 +      char name[KSYM_NAME_LEN];
 +      u16 flags = 0;
 +      int name_len;
 +
 +      if (!atomic_read(&nr_ksymbol_events))
 +              return;
 +
 +      if (ksym_type >= PERF_RECORD_KSYMBOL_TYPE_MAX ||
 +          ksym_type == PERF_RECORD_KSYMBOL_TYPE_UNKNOWN)
 +              goto err;
 +
 +      strlcpy(name, sym, KSYM_NAME_LEN);
 +      name_len = strlen(name) + 1;
 +      while (!IS_ALIGNED(name_len, sizeof(u64)))
 +              name[name_len++] = '\0';
 +      BUILD_BUG_ON(KSYM_NAME_LEN % sizeof(u64));
 +
 +      if (unregister)
 +              flags |= PERF_RECORD_KSYMBOL_FLAGS_UNREGISTER;
 +
 +      ksymbol_event = (struct perf_ksymbol_event){
 +              .name = name,
 +              .name_len = name_len,
 +              .event_id = {
 +                      .header = {
 +                              .type = PERF_RECORD_KSYMBOL,
 +                              .size = sizeof(ksymbol_event.event_id) +
 +                                      name_len,
 +                      },
 +                      .addr = addr,
 +                      .len = len,
 +                      .ksym_type = ksym_type,
 +                      .flags = flags,
 +              },
 +      };
 +
 +      perf_iterate_sb(perf_event_ksymbol_output, &ksymbol_event, NULL);
 +      return;
 +err:
 +      WARN_ONCE(1, "%s: Invalid KSYMBOL type 0x%x\n", __func__, ksym_type);
 +}
 +
 +/*
 + * bpf program load/unload tracking
 + */
 +
 +struct perf_bpf_event {
 +      struct bpf_prog *prog;
 +      struct {
 +              struct perf_event_header        header;
 +              u16                             type;
 +              u16                             flags;
 +              u32                             id;
 +              u8                              tag[BPF_TAG_SIZE];
 +      } event_id;
 +};
 +
 +static int perf_event_bpf_match(struct perf_event *event)
 +{
 +      return event->attr.bpf_event;
 +}
 +
 +static void perf_event_bpf_output(struct perf_event *event, void *data)
 +{
 +      struct perf_bpf_event *bpf_event = data;
 +      struct perf_output_handle handle;
 +      struct perf_sample_data sample;
 +      int ret;
 +
 +      if (!perf_event_bpf_match(event))
 +              return;
 +
 +      perf_event_header__init_id(&bpf_event->event_id.header,
 +                                 &sample, event);
 +      ret = perf_output_begin(&handle, event,
 +                              bpf_event->event_id.header.size);
 +      if (ret)
 +              return;
 +
 +      perf_output_put(&handle, bpf_event->event_id);
 +      perf_event__output_id_sample(event, &handle, &sample);
 +
 +      perf_output_end(&handle);
 +}
 +
 +static void perf_event_bpf_emit_ksymbols(struct bpf_prog *prog,
 +                                       enum perf_bpf_event_type type)
 +{
 +      bool unregister = type == PERF_BPF_EVENT_PROG_UNLOAD;
 +      char sym[KSYM_NAME_LEN];
 +      int i;
 +
 +      if (prog->aux->func_cnt == 0) {
 +              bpf_get_prog_name(prog, sym);
 +              perf_event_ksymbol(PERF_RECORD_KSYMBOL_TYPE_BPF,
 +                                 (u64)(unsigned long)prog->bpf_func,
 +                                 prog->jited_len, unregister, sym);
 +      } else {
 +              for (i = 0; i < prog->aux->func_cnt; i++) {
 +                      struct bpf_prog *subprog = prog->aux->func[i];
 +
 +                      bpf_get_prog_name(subprog, sym);
 +                      perf_event_ksymbol(
 +                              PERF_RECORD_KSYMBOL_TYPE_BPF,
 +                              (u64)(unsigned long)subprog->bpf_func,
 +                              subprog->jited_len, unregister, sym);
 +              }
 +      }
 +}
 +
 +void perf_event_bpf_event(struct bpf_prog *prog,
 +                        enum perf_bpf_event_type type,
 +                        u16 flags)
 +{
 +      struct perf_bpf_event bpf_event;
 +
 +      if (type <= PERF_BPF_EVENT_UNKNOWN ||
 +          type >= PERF_BPF_EVENT_MAX)
 +              return;
 +
 +      switch (type) {
 +      case PERF_BPF_EVENT_PROG_LOAD:
 +      case PERF_BPF_EVENT_PROG_UNLOAD:
 +              if (atomic_read(&nr_ksymbol_events))
 +                      perf_event_bpf_emit_ksymbols(prog, type);
 +              break;
 +      default:
 +              break;
 +      }
 +
 +      if (!atomic_read(&nr_bpf_events))
 +              return;
 +
 +      bpf_event = (struct perf_bpf_event){
 +              .prog = prog,
 +              .event_id = {
 +                      .header = {
 +                              .type = PERF_RECORD_BPF_EVENT,
 +                              .size = sizeof(bpf_event.event_id),
 +                      },
 +                      .type = type,
 +                      .flags = flags,
 +                      .id = prog->aux->id,
 +              },
 +      };
 +
 +      BUILD_BUG_ON(BPF_TAG_SIZE % sizeof(u64));
 +
 +      memcpy(bpf_event.event_id.tag, prog->tag, BPF_TAG_SIZE);
 +      perf_iterate_sb(perf_event_bpf_output, &bpf_event, NULL);
 +}
 +
  void perf_event_itrace_started(struct perf_event *event)
  {
        event->attach_state |= PERF_ATTACH_ITRACE;
@@@ -9600,6 -9399,11 +9608,11 @@@ static int perf_pmu_nop_int(struct pmu 
        return 0;
  }
  
+ static int perf_event_nop_int(struct perf_event *event, u64 value)
+ {
+       return 0;
+ }
  static DEFINE_PER_CPU(unsigned int, nop_txn_flags);
  
  static void perf_pmu_start_txn(struct pmu *pmu, unsigned int flags)
@@@ -9900,6 -9704,9 +9913,9 @@@ got_cpu_context
                pmu->pmu_disable = perf_pmu_nop_void;
        }
  
+       if (!pmu->check_period)
+               pmu->check_period = perf_event_nop_int;
        if (!pmu->event_idx)
                pmu->event_idx = perf_event_idx_default;
  
@@@ -9981,15 -9788,6 +9997,15 @@@ static int perf_try_init_event(struct p
        if (ctx)
                perf_event_ctx_unlock(event->group_leader, ctx);
  
 +      if (!ret) {
 +              if (pmu->capabilities & PERF_PMU_CAP_NO_EXCLUDE &&
 +                              event_has_any_exclude_flag(event)) {
 +                      if (event->destroy)
 +                              event->destroy(event);
 +                      ret = -EINVAL;
 +              }
 +      }
 +
        if (ret)
                module_put(pmu->module);
  
@@@ -10118,10 -9916,6 +10134,10 @@@ static void account_event(struct perf_e
                inc = true;
        if (is_cgroup_event(event))
                inc = true;
 +      if (event->attr.ksymbol)
 +              atomic_inc(&nr_ksymbol_events);
 +      if (event->attr.bpf_event)
 +              atomic_inc(&nr_bpf_events);
  
        if (inc) {
                /*
@@@ -10613,7 -10407,7 +10629,7 @@@ __perf_event_ctx_lock_double(struct per
  again:
        rcu_read_lock();
        gctx = READ_ONCE(group_leader->ctx);
 -      if (!atomic_inc_not_zero(&gctx->refcount)) {
 +      if (!refcount_inc_not_zero(&gctx->refcount)) {
                rcu_read_unlock();
                goto again;
        }
@@@ -1,4 -1,3 +1,4 @@@
 +// SPDX-License-Identifier: GPL-2.0
  /*
   * Performance events ring-buffer code:
   *
@@@ -6,6 -5,8 +6,6 @@@
   *  Copyright (C) 2008-2011 Red Hat, Inc., Ingo Molnar
   *  Copyright (C) 2008-2011 Red Hat, Inc., Peter Zijlstra
   *  Copyright  ©  2009 Paul Mackerras, IBM Corp. <paulus@au1.ibm.com>
 - *
 - * For licensing details see kernel-base/COPYING
   */
  
  #include <linux/perf_event.h>
@@@ -284,7 -285,7 +284,7 @@@ ring_buffer_init(struct ring_buffer *rb
        else
                rb->overwrite = 1;
  
 -      atomic_set(&rb->refcount, 1);
 +      refcount_set(&rb->refcount, 1);
  
        INIT_LIST_HEAD(&rb->event_list);
        spin_lock_init(&rb->event_lock);
@@@ -357,7 -358,7 +357,7 @@@ void *perf_aux_output_begin(struct perf
        if (!atomic_read(&rb->aux_mmap_count))
                goto err;
  
 -      if (!atomic_inc_not_zero(&rb->aux_refcount))
 +      if (!refcount_inc_not_zero(&rb->aux_refcount))
                goto err;
  
        /*
@@@ -657,7 -658,7 +657,7 @@@ int rb_alloc_aux(struct ring_buffer *rb
                        goto out;
        }
  
 -      rb->aux_priv = event->pmu->setup_aux(event->cpu, rb->aux_pages, nr_pages,
 +      rb->aux_priv = event->pmu->setup_aux(event, rb->aux_pages, nr_pages,
                                             overwrite);
        if (!rb->aux_priv)
                goto out;
         * we keep a refcount here to make sure either of the two can
         * reference them safely.
         */
 -      atomic_set(&rb->aux_refcount, 1);
 +      refcount_set(&rb->aux_refcount, 1);
  
        rb->aux_overwrite = overwrite;
        rb->aux_watermark = watermark;
@@@ -689,7 -690,7 +689,7 @@@ out
  
  void rb_free_aux(struct ring_buffer *rb)
  {
 -      if (atomic_dec_and_test(&rb->aux_refcount))
 +      if (refcount_dec_and_test(&rb->aux_refcount))
                __rb_free_aux(rb);
  }
  
@@@ -733,7 -734,7 +733,7 @@@ struct ring_buffer *rb_alloc(int nr_pag
        size = sizeof(struct ring_buffer);
        size += nr_pages * sizeof(void *);
  
-       if (order_base_2(size) >= MAX_ORDER)
+       if (order_base_2(size) >= PAGE_SHIFT+MAX_ORDER)
                goto fail;
  
        rb = kzalloc(size, GFP_KERNEL);
diff --combined kernel/trace/bpf_trace.c
@@@ -431,7 -431,8 +431,7 @@@ __bpf_perf_event_output(struct pt_regs 
        if (unlikely(event->oncpu != cpu))
                return -EOPNOTSUPP;
  
 -      perf_event_output(event, sd, regs);
 -      return 0;
 +      return perf_event_output(event, sd, regs);
  }
  
  BPF_CALL_5(bpf_perf_event_output, struct pt_regs *, regs, struct bpf_map *, map,
@@@ -1203,22 -1204,12 +1203,12 @@@ static int __bpf_probe_register(struct 
  
  int bpf_probe_register(struct bpf_raw_event_map *btp, struct bpf_prog *prog)
  {
-       int err;
-       mutex_lock(&bpf_event_mutex);
-       err = __bpf_probe_register(btp, prog);
-       mutex_unlock(&bpf_event_mutex);
-       return err;
+       return __bpf_probe_register(btp, prog);
  }
  
  int bpf_probe_unregister(struct bpf_raw_event_map *btp, struct bpf_prog *prog)
  {
-       int err;
-       mutex_lock(&bpf_event_mutex);
-       err = tracepoint_probe_unregister(btp->tp, (void *)btp->bpf_func, prog);
-       mutex_unlock(&bpf_event_mutex);
-       return err;
+       return tracepoint_probe_unregister(btp->tp, (void *)btp->bpf_func, prog);
  }
  
  int bpf_get_perf_event_info(const struct perf_event *event, u32 *prog_id,