19251f904SBorislav Petkov /* 29251f904SBorislav Petkov * Performance events callchain code, extracted from core.c: 39251f904SBorislav Petkov * 49251f904SBorislav Petkov * Copyright (C) 2008 Thomas Gleixner <tglx@linutronix.de> 59251f904SBorislav Petkov * Copyright (C) 2008-2011 Red Hat, Inc., Ingo Molnar 690eec103SPeter Zijlstra * Copyright (C) 2008-2011 Red Hat, Inc., Peter Zijlstra 79251f904SBorislav Petkov * Copyright � 2009 Paul Mackerras, IBM Corp. <paulus@au1.ibm.com> 89251f904SBorislav Petkov * 99251f904SBorislav Petkov * For licensing details see kernel-base/COPYING 109251f904SBorislav Petkov */ 119251f904SBorislav Petkov 129251f904SBorislav Petkov #include <linux/perf_event.h> 139251f904SBorislav Petkov #include <linux/slab.h> 14*68db0cf1SIngo Molnar #include <linux/sched/task_stack.h> 15*68db0cf1SIngo Molnar 169251f904SBorislav Petkov #include "internal.h" 179251f904SBorislav Petkov 189251f904SBorislav Petkov struct callchain_cpus_entries { 199251f904SBorislav Petkov struct rcu_head rcu_head; 209251f904SBorislav Petkov struct perf_callchain_entry *cpu_entries[0]; 219251f904SBorislav Petkov }; 229251f904SBorislav Petkov 23c5dfd78eSArnaldo Carvalho de Melo int sysctl_perf_event_max_stack __read_mostly = PERF_MAX_STACK_DEPTH; 24c85b0334SArnaldo Carvalho de Melo int sysctl_perf_event_max_contexts_per_stack __read_mostly = PERF_MAX_CONTEXTS_PER_STACK; 25c5dfd78eSArnaldo Carvalho de Melo 26c5dfd78eSArnaldo Carvalho de Melo static inline size_t perf_callchain_entry__sizeof(void) 27c5dfd78eSArnaldo Carvalho de Melo { 28c5dfd78eSArnaldo Carvalho de Melo return (sizeof(struct perf_callchain_entry) + 29c85b0334SArnaldo Carvalho de Melo sizeof(__u64) * (sysctl_perf_event_max_stack + 30c85b0334SArnaldo Carvalho de Melo sysctl_perf_event_max_contexts_per_stack)); 31c5dfd78eSArnaldo Carvalho de Melo } 32c5dfd78eSArnaldo Carvalho de Melo 339251f904SBorislav Petkov static DEFINE_PER_CPU(int, callchain_recursion[PERF_NR_CONTEXTS]); 349251f904SBorislav Petkov static atomic_t nr_callchain_events; 359251f904SBorislav Petkov static DEFINE_MUTEX(callchain_mutex); 369251f904SBorislav Petkov static struct callchain_cpus_entries *callchain_cpus_entries; 379251f904SBorislav Petkov 389251f904SBorislav Petkov 39cfbcf468SArnaldo Carvalho de Melo __weak void perf_callchain_kernel(struct perf_callchain_entry_ctx *entry, 409251f904SBorislav Petkov struct pt_regs *regs) 419251f904SBorislav Petkov { 429251f904SBorislav Petkov } 439251f904SBorislav Petkov 44cfbcf468SArnaldo Carvalho de Melo __weak void perf_callchain_user(struct perf_callchain_entry_ctx *entry, 459251f904SBorislav Petkov struct pt_regs *regs) 469251f904SBorislav Petkov { 479251f904SBorislav Petkov } 489251f904SBorislav Petkov 499251f904SBorislav Petkov static void release_callchain_buffers_rcu(struct rcu_head *head) 509251f904SBorislav Petkov { 519251f904SBorislav Petkov struct callchain_cpus_entries *entries; 529251f904SBorislav Petkov int cpu; 539251f904SBorislav Petkov 549251f904SBorislav Petkov entries = container_of(head, struct callchain_cpus_entries, rcu_head); 559251f904SBorislav Petkov 569251f904SBorislav Petkov for_each_possible_cpu(cpu) 579251f904SBorislav Petkov kfree(entries->cpu_entries[cpu]); 589251f904SBorislav Petkov 599251f904SBorislav Petkov kfree(entries); 609251f904SBorislav Petkov } 619251f904SBorislav Petkov 629251f904SBorislav Petkov static void release_callchain_buffers(void) 639251f904SBorislav Petkov { 649251f904SBorislav Petkov struct callchain_cpus_entries *entries; 659251f904SBorislav Petkov 669251f904SBorislav Petkov entries = callchain_cpus_entries; 67e0455e19SAndreea-Cristina Bernat RCU_INIT_POINTER(callchain_cpus_entries, NULL); 689251f904SBorislav Petkov call_rcu(&entries->rcu_head, release_callchain_buffers_rcu); 699251f904SBorislav Petkov } 709251f904SBorislav Petkov 719251f904SBorislav Petkov static int alloc_callchain_buffers(void) 729251f904SBorislav Petkov { 739251f904SBorislav Petkov int cpu; 749251f904SBorislav Petkov int size; 759251f904SBorislav Petkov struct callchain_cpus_entries *entries; 769251f904SBorislav Petkov 779251f904SBorislav Petkov /* 789251f904SBorislav Petkov * We can't use the percpu allocation API for data that can be 799251f904SBorislav Petkov * accessed from NMI. Use a temporary manual per cpu allocation 809251f904SBorislav Petkov * until that gets sorted out. 819251f904SBorislav Petkov */ 829251f904SBorislav Petkov size = offsetof(struct callchain_cpus_entries, cpu_entries[nr_cpu_ids]); 839251f904SBorislav Petkov 849251f904SBorislav Petkov entries = kzalloc(size, GFP_KERNEL); 859251f904SBorislav Petkov if (!entries) 869251f904SBorislav Petkov return -ENOMEM; 879251f904SBorislav Petkov 88c5dfd78eSArnaldo Carvalho de Melo size = perf_callchain_entry__sizeof() * PERF_NR_CONTEXTS; 899251f904SBorislav Petkov 909251f904SBorislav Petkov for_each_possible_cpu(cpu) { 919251f904SBorislav Petkov entries->cpu_entries[cpu] = kmalloc_node(size, GFP_KERNEL, 929251f904SBorislav Petkov cpu_to_node(cpu)); 939251f904SBorislav Petkov if (!entries->cpu_entries[cpu]) 949251f904SBorislav Petkov goto fail; 959251f904SBorislav Petkov } 969251f904SBorislav Petkov 979251f904SBorislav Petkov rcu_assign_pointer(callchain_cpus_entries, entries); 989251f904SBorislav Petkov 999251f904SBorislav Petkov return 0; 1009251f904SBorislav Petkov 1019251f904SBorislav Petkov fail: 1029251f904SBorislav Petkov for_each_possible_cpu(cpu) 1039251f904SBorislav Petkov kfree(entries->cpu_entries[cpu]); 1049251f904SBorislav Petkov kfree(entries); 1059251f904SBorislav Petkov 1069251f904SBorislav Petkov return -ENOMEM; 1079251f904SBorislav Petkov } 1089251f904SBorislav Petkov 10997c79a38SArnaldo Carvalho de Melo int get_callchain_buffers(int event_max_stack) 1109251f904SBorislav Petkov { 1119251f904SBorislav Petkov int err = 0; 1129251f904SBorislav Petkov int count; 1139251f904SBorislav Petkov 1149251f904SBorislav Petkov mutex_lock(&callchain_mutex); 1159251f904SBorislav Petkov 1169251f904SBorislav Petkov count = atomic_inc_return(&nr_callchain_events); 1179251f904SBorislav Petkov if (WARN_ON_ONCE(count < 1)) { 1189251f904SBorislav Petkov err = -EINVAL; 1199251f904SBorislav Petkov goto exit; 1209251f904SBorislav Petkov } 1219251f904SBorislav Petkov 1229251f904SBorislav Petkov if (count > 1) { 1239251f904SBorislav Petkov /* If the allocation failed, give up */ 1249251f904SBorislav Petkov if (!callchain_cpus_entries) 1259251f904SBorislav Petkov err = -ENOMEM; 12697c79a38SArnaldo Carvalho de Melo /* 12797c79a38SArnaldo Carvalho de Melo * If requesting per event more than the global cap, 12897c79a38SArnaldo Carvalho de Melo * return a different error to help userspace figure 12997c79a38SArnaldo Carvalho de Melo * this out. 13097c79a38SArnaldo Carvalho de Melo * 13197c79a38SArnaldo Carvalho de Melo * And also do it here so that we have &callchain_mutex held. 13297c79a38SArnaldo Carvalho de Melo */ 13397c79a38SArnaldo Carvalho de Melo if (event_max_stack > sysctl_perf_event_max_stack) 13497c79a38SArnaldo Carvalho de Melo err = -EOVERFLOW; 1359251f904SBorislav Petkov goto exit; 1369251f904SBorislav Petkov } 1379251f904SBorislav Petkov 1389251f904SBorislav Petkov err = alloc_callchain_buffers(); 1399251f904SBorislav Petkov exit: 14090983b16SFrederic Weisbecker if (err) 14190983b16SFrederic Weisbecker atomic_dec(&nr_callchain_events); 1429251f904SBorislav Petkov 143fc3b86d6SFrederic Weisbecker mutex_unlock(&callchain_mutex); 144fc3b86d6SFrederic Weisbecker 1459251f904SBorislav Petkov return err; 1469251f904SBorislav Petkov } 1479251f904SBorislav Petkov 1489251f904SBorislav Petkov void put_callchain_buffers(void) 1499251f904SBorislav Petkov { 1509251f904SBorislav Petkov if (atomic_dec_and_mutex_lock(&nr_callchain_events, &callchain_mutex)) { 1519251f904SBorislav Petkov release_callchain_buffers(); 1529251f904SBorislav Petkov mutex_unlock(&callchain_mutex); 1539251f904SBorislav Petkov } 1549251f904SBorislav Petkov } 1559251f904SBorislav Petkov 1569251f904SBorislav Petkov static struct perf_callchain_entry *get_callchain_entry(int *rctx) 1579251f904SBorislav Petkov { 1589251f904SBorislav Petkov int cpu; 1599251f904SBorislav Petkov struct callchain_cpus_entries *entries; 1609251f904SBorislav Petkov 1614a32fea9SChristoph Lameter *rctx = get_recursion_context(this_cpu_ptr(callchain_recursion)); 1629251f904SBorislav Petkov if (*rctx == -1) 1639251f904SBorislav Petkov return NULL; 1649251f904SBorislav Petkov 1659251f904SBorislav Petkov entries = rcu_dereference(callchain_cpus_entries); 1669251f904SBorislav Petkov if (!entries) 1679251f904SBorislav Petkov return NULL; 1689251f904SBorislav Petkov 1699251f904SBorislav Petkov cpu = smp_processor_id(); 1709251f904SBorislav Petkov 171c5dfd78eSArnaldo Carvalho de Melo return (((void *)entries->cpu_entries[cpu]) + 172c5dfd78eSArnaldo Carvalho de Melo (*rctx * perf_callchain_entry__sizeof())); 1739251f904SBorislav Petkov } 1749251f904SBorislav Petkov 1759251f904SBorislav Petkov static void 1769251f904SBorislav Petkov put_callchain_entry(int rctx) 1779251f904SBorislav Petkov { 1784a32fea9SChristoph Lameter put_recursion_context(this_cpu_ptr(callchain_recursion), rctx); 1799251f904SBorislav Petkov } 1809251f904SBorislav Petkov 181e6dab5ffSAndrew Vagin struct perf_callchain_entry * 182e6dab5ffSAndrew Vagin perf_callchain(struct perf_event *event, struct pt_regs *regs) 1839251f904SBorislav Petkov { 184568b329aSAlexei Starovoitov bool kernel = !event->attr.exclude_callchain_kernel; 185568b329aSAlexei Starovoitov bool user = !event->attr.exclude_callchain_user; 186568b329aSAlexei Starovoitov /* Disallow cross-task user callchains. */ 187568b329aSAlexei Starovoitov bool crosstask = event->ctx->task && event->ctx->task != current; 18897c79a38SArnaldo Carvalho de Melo const u32 max_stack = event->attr.sample_max_stack; 189d0775264SFrederic Weisbecker 190d0775264SFrederic Weisbecker if (!kernel && !user) 191d0775264SFrederic Weisbecker return NULL; 1929251f904SBorislav Petkov 19397c79a38SArnaldo Carvalho de Melo return get_perf_callchain(regs, 0, kernel, user, max_stack, crosstask, true); 194568b329aSAlexei Starovoitov } 195568b329aSAlexei Starovoitov 196568b329aSAlexei Starovoitov struct perf_callchain_entry * 197568b329aSAlexei Starovoitov get_perf_callchain(struct pt_regs *regs, u32 init_nr, bool kernel, bool user, 198cfbcf468SArnaldo Carvalho de Melo u32 max_stack, bool crosstask, bool add_mark) 199568b329aSAlexei Starovoitov { 200568b329aSAlexei Starovoitov struct perf_callchain_entry *entry; 201cfbcf468SArnaldo Carvalho de Melo struct perf_callchain_entry_ctx ctx; 202568b329aSAlexei Starovoitov int rctx; 203568b329aSAlexei Starovoitov 2049251f904SBorislav Petkov entry = get_callchain_entry(&rctx); 2059251f904SBorislav Petkov if (rctx == -1) 2069251f904SBorislav Petkov return NULL; 2079251f904SBorislav Petkov 2089251f904SBorislav Petkov if (!entry) 2099251f904SBorislav Petkov goto exit_put; 2109251f904SBorislav Petkov 211cfbcf468SArnaldo Carvalho de Melo ctx.entry = entry; 212cfbcf468SArnaldo Carvalho de Melo ctx.max_stack = max_stack; 2133b1fff08SArnaldo Carvalho de Melo ctx.nr = entry->nr = init_nr; 214c85b0334SArnaldo Carvalho de Melo ctx.contexts = 0; 215c85b0334SArnaldo Carvalho de Melo ctx.contexts_maxed = false; 2169251f904SBorislav Petkov 217d0775264SFrederic Weisbecker if (kernel && !user_mode(regs)) { 218568b329aSAlexei Starovoitov if (add_mark) 2193e4de4ecSArnaldo Carvalho de Melo perf_callchain_store_context(&ctx, PERF_CONTEXT_KERNEL); 220cfbcf468SArnaldo Carvalho de Melo perf_callchain_kernel(&ctx, regs); 221d0775264SFrederic Weisbecker } 222d0775264SFrederic Weisbecker 223d0775264SFrederic Weisbecker if (user) { 224d0775264SFrederic Weisbecker if (!user_mode(regs)) { 2259251f904SBorislav Petkov if (current->mm) 2269251f904SBorislav Petkov regs = task_pt_regs(current); 2279251f904SBorislav Petkov else 2289251f904SBorislav Petkov regs = NULL; 2299251f904SBorislav Petkov } 2309251f904SBorislav Petkov 2319251f904SBorislav Petkov if (regs) { 232568b329aSAlexei Starovoitov if (crosstask) 233e6dab5ffSAndrew Vagin goto exit_put; 234e6dab5ffSAndrew Vagin 235568b329aSAlexei Starovoitov if (add_mark) 2363e4de4ecSArnaldo Carvalho de Melo perf_callchain_store_context(&ctx, PERF_CONTEXT_USER); 237cfbcf468SArnaldo Carvalho de Melo perf_callchain_user(&ctx, regs); 2389251f904SBorislav Petkov } 239d0775264SFrederic Weisbecker } 2409251f904SBorislav Petkov 2419251f904SBorislav Petkov exit_put: 2429251f904SBorislav Petkov put_callchain_entry(rctx); 2439251f904SBorislav Petkov 2449251f904SBorislav Petkov return entry; 2459251f904SBorislav Petkov } 246c5dfd78eSArnaldo Carvalho de Melo 247c85b0334SArnaldo Carvalho de Melo /* 248c85b0334SArnaldo Carvalho de Melo * Used for sysctl_perf_event_max_stack and 249c85b0334SArnaldo Carvalho de Melo * sysctl_perf_event_max_contexts_per_stack. 250c85b0334SArnaldo Carvalho de Melo */ 251c5dfd78eSArnaldo Carvalho de Melo int perf_event_max_stack_handler(struct ctl_table *table, int write, 252c5dfd78eSArnaldo Carvalho de Melo void __user *buffer, size_t *lenp, loff_t *ppos) 253c5dfd78eSArnaldo Carvalho de Melo { 254a831100aSArnaldo Carvalho de Melo int *value = table->data; 255a831100aSArnaldo Carvalho de Melo int new_value = *value, ret; 256c5dfd78eSArnaldo Carvalho de Melo struct ctl_table new_table = *table; 257c5dfd78eSArnaldo Carvalho de Melo 258c5dfd78eSArnaldo Carvalho de Melo new_table.data = &new_value; 259c5dfd78eSArnaldo Carvalho de Melo ret = proc_dointvec_minmax(&new_table, write, buffer, lenp, ppos); 260c5dfd78eSArnaldo Carvalho de Melo if (ret || !write) 261c5dfd78eSArnaldo Carvalho de Melo return ret; 262c5dfd78eSArnaldo Carvalho de Melo 263c5dfd78eSArnaldo Carvalho de Melo mutex_lock(&callchain_mutex); 264c5dfd78eSArnaldo Carvalho de Melo if (atomic_read(&nr_callchain_events)) 265c5dfd78eSArnaldo Carvalho de Melo ret = -EBUSY; 266c5dfd78eSArnaldo Carvalho de Melo else 267a831100aSArnaldo Carvalho de Melo *value = new_value; 268c5dfd78eSArnaldo Carvalho de Melo 269c5dfd78eSArnaldo Carvalho de Melo mutex_unlock(&callchain_mutex); 270c5dfd78eSArnaldo Carvalho de Melo 271c5dfd78eSArnaldo Carvalho de Melo return ret; 272c5dfd78eSArnaldo Carvalho de Melo } 273