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 69251f904SBorislav Petkov * Copyright (C) 2008-2011 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com> 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> 149251f904SBorislav Petkov #include "internal.h" 159251f904SBorislav Petkov 169251f904SBorislav Petkov struct callchain_cpus_entries { 179251f904SBorislav Petkov struct rcu_head rcu_head; 189251f904SBorislav Petkov struct perf_callchain_entry *cpu_entries[0]; 199251f904SBorislav Petkov }; 209251f904SBorislav Petkov 219251f904SBorislav Petkov static DEFINE_PER_CPU(int, callchain_recursion[PERF_NR_CONTEXTS]); 229251f904SBorislav Petkov static atomic_t nr_callchain_events; 239251f904SBorislav Petkov static DEFINE_MUTEX(callchain_mutex); 249251f904SBorislav Petkov static struct callchain_cpus_entries *callchain_cpus_entries; 259251f904SBorislav Petkov 269251f904SBorislav Petkov 279251f904SBorislav Petkov __weak void perf_callchain_kernel(struct perf_callchain_entry *entry, 289251f904SBorislav Petkov struct pt_regs *regs) 299251f904SBorislav Petkov { 309251f904SBorislav Petkov } 319251f904SBorislav Petkov 329251f904SBorislav Petkov __weak void perf_callchain_user(struct perf_callchain_entry *entry, 339251f904SBorislav Petkov struct pt_regs *regs) 349251f904SBorislav Petkov { 359251f904SBorislav Petkov } 369251f904SBorislav Petkov 379251f904SBorislav Petkov static void release_callchain_buffers_rcu(struct rcu_head *head) 389251f904SBorislav Petkov { 399251f904SBorislav Petkov struct callchain_cpus_entries *entries; 409251f904SBorislav Petkov int cpu; 419251f904SBorislav Petkov 429251f904SBorislav Petkov entries = container_of(head, struct callchain_cpus_entries, rcu_head); 439251f904SBorislav Petkov 449251f904SBorislav Petkov for_each_possible_cpu(cpu) 459251f904SBorislav Petkov kfree(entries->cpu_entries[cpu]); 469251f904SBorislav Petkov 479251f904SBorislav Petkov kfree(entries); 489251f904SBorislav Petkov } 499251f904SBorislav Petkov 509251f904SBorislav Petkov static void release_callchain_buffers(void) 519251f904SBorislav Petkov { 529251f904SBorislav Petkov struct callchain_cpus_entries *entries; 539251f904SBorislav Petkov 549251f904SBorislav Petkov entries = callchain_cpus_entries; 559251f904SBorislav Petkov rcu_assign_pointer(callchain_cpus_entries, NULL); 569251f904SBorislav Petkov call_rcu(&entries->rcu_head, release_callchain_buffers_rcu); 579251f904SBorislav Petkov } 589251f904SBorislav Petkov 599251f904SBorislav Petkov static int alloc_callchain_buffers(void) 609251f904SBorislav Petkov { 619251f904SBorislav Petkov int cpu; 629251f904SBorislav Petkov int size; 639251f904SBorislav Petkov struct callchain_cpus_entries *entries; 649251f904SBorislav Petkov 659251f904SBorislav Petkov /* 669251f904SBorislav Petkov * We can't use the percpu allocation API for data that can be 679251f904SBorislav Petkov * accessed from NMI. Use a temporary manual per cpu allocation 689251f904SBorislav Petkov * until that gets sorted out. 699251f904SBorislav Petkov */ 709251f904SBorislav Petkov size = offsetof(struct callchain_cpus_entries, cpu_entries[nr_cpu_ids]); 719251f904SBorislav Petkov 729251f904SBorislav Petkov entries = kzalloc(size, GFP_KERNEL); 739251f904SBorislav Petkov if (!entries) 749251f904SBorislav Petkov return -ENOMEM; 759251f904SBorislav Petkov 769251f904SBorislav Petkov size = sizeof(struct perf_callchain_entry) * PERF_NR_CONTEXTS; 779251f904SBorislav Petkov 789251f904SBorislav Petkov for_each_possible_cpu(cpu) { 799251f904SBorislav Petkov entries->cpu_entries[cpu] = kmalloc_node(size, GFP_KERNEL, 809251f904SBorislav Petkov cpu_to_node(cpu)); 819251f904SBorislav Petkov if (!entries->cpu_entries[cpu]) 829251f904SBorislav Petkov goto fail; 839251f904SBorislav Petkov } 849251f904SBorislav Petkov 859251f904SBorislav Petkov rcu_assign_pointer(callchain_cpus_entries, entries); 869251f904SBorislav Petkov 879251f904SBorislav Petkov return 0; 889251f904SBorislav Petkov 899251f904SBorislav Petkov fail: 909251f904SBorislav Petkov for_each_possible_cpu(cpu) 919251f904SBorislav Petkov kfree(entries->cpu_entries[cpu]); 929251f904SBorislav Petkov kfree(entries); 939251f904SBorislav Petkov 949251f904SBorislav Petkov return -ENOMEM; 959251f904SBorislav Petkov } 969251f904SBorislav Petkov 979251f904SBorislav Petkov int get_callchain_buffers(void) 989251f904SBorislav Petkov { 999251f904SBorislav Petkov int err = 0; 1009251f904SBorislav Petkov int count; 1019251f904SBorislav Petkov 1029251f904SBorislav Petkov mutex_lock(&callchain_mutex); 1039251f904SBorislav Petkov 1049251f904SBorislav Petkov count = atomic_inc_return(&nr_callchain_events); 1059251f904SBorislav Petkov if (WARN_ON_ONCE(count < 1)) { 1069251f904SBorislav Petkov err = -EINVAL; 1079251f904SBorislav Petkov goto exit; 1089251f904SBorislav Petkov } 1099251f904SBorislav Petkov 1109251f904SBorislav Petkov if (count > 1) { 1119251f904SBorislav Petkov /* If the allocation failed, give up */ 1129251f904SBorislav Petkov if (!callchain_cpus_entries) 1139251f904SBorislav Petkov err = -ENOMEM; 1149251f904SBorislav Petkov goto exit; 1159251f904SBorislav Petkov } 1169251f904SBorislav Petkov 1179251f904SBorislav Petkov err = alloc_callchain_buffers(); 1189251f904SBorislav Petkov exit: 11990983b16SFrederic Weisbecker if (err) 12090983b16SFrederic Weisbecker atomic_dec(&nr_callchain_events); 1219251f904SBorislav Petkov 122*fc3b86d6SFrederic Weisbecker mutex_unlock(&callchain_mutex); 123*fc3b86d6SFrederic Weisbecker 1249251f904SBorislav Petkov return err; 1259251f904SBorislav Petkov } 1269251f904SBorislav Petkov 1279251f904SBorislav Petkov void put_callchain_buffers(void) 1289251f904SBorislav Petkov { 1299251f904SBorislav Petkov if (atomic_dec_and_mutex_lock(&nr_callchain_events, &callchain_mutex)) { 1309251f904SBorislav Petkov release_callchain_buffers(); 1319251f904SBorislav Petkov mutex_unlock(&callchain_mutex); 1329251f904SBorislav Petkov } 1339251f904SBorislav Petkov } 1349251f904SBorislav Petkov 1359251f904SBorislav Petkov static struct perf_callchain_entry *get_callchain_entry(int *rctx) 1369251f904SBorislav Petkov { 1379251f904SBorislav Petkov int cpu; 1389251f904SBorislav Petkov struct callchain_cpus_entries *entries; 1399251f904SBorislav Petkov 1409251f904SBorislav Petkov *rctx = get_recursion_context(__get_cpu_var(callchain_recursion)); 1419251f904SBorislav Petkov if (*rctx == -1) 1429251f904SBorislav Petkov return NULL; 1439251f904SBorislav Petkov 1449251f904SBorislav Petkov entries = rcu_dereference(callchain_cpus_entries); 1459251f904SBorislav Petkov if (!entries) 1469251f904SBorislav Petkov return NULL; 1479251f904SBorislav Petkov 1489251f904SBorislav Petkov cpu = smp_processor_id(); 1499251f904SBorislav Petkov 1509251f904SBorislav Petkov return &entries->cpu_entries[cpu][*rctx]; 1519251f904SBorislav Petkov } 1529251f904SBorislav Petkov 1539251f904SBorislav Petkov static void 1549251f904SBorislav Petkov put_callchain_entry(int rctx) 1559251f904SBorislav Petkov { 1569251f904SBorislav Petkov put_recursion_context(__get_cpu_var(callchain_recursion), rctx); 1579251f904SBorislav Petkov } 1589251f904SBorislav Petkov 159e6dab5ffSAndrew Vagin struct perf_callchain_entry * 160e6dab5ffSAndrew Vagin perf_callchain(struct perf_event *event, struct pt_regs *regs) 1619251f904SBorislav Petkov { 1629251f904SBorislav Petkov int rctx; 1639251f904SBorislav Petkov struct perf_callchain_entry *entry; 1649251f904SBorislav Petkov 165d0775264SFrederic Weisbecker int kernel = !event->attr.exclude_callchain_kernel; 166d0775264SFrederic Weisbecker int user = !event->attr.exclude_callchain_user; 167d0775264SFrederic Weisbecker 168d0775264SFrederic Weisbecker if (!kernel && !user) 169d0775264SFrederic Weisbecker return NULL; 1709251f904SBorislav Petkov 1719251f904SBorislav Petkov entry = get_callchain_entry(&rctx); 1729251f904SBorislav Petkov if (rctx == -1) 1739251f904SBorislav Petkov return NULL; 1749251f904SBorislav Petkov 1759251f904SBorislav Petkov if (!entry) 1769251f904SBorislav Petkov goto exit_put; 1779251f904SBorislav Petkov 1789251f904SBorislav Petkov entry->nr = 0; 1799251f904SBorislav Petkov 180d0775264SFrederic Weisbecker if (kernel && !user_mode(regs)) { 1819251f904SBorislav Petkov perf_callchain_store(entry, PERF_CONTEXT_KERNEL); 1829251f904SBorislav Petkov perf_callchain_kernel(entry, regs); 183d0775264SFrederic Weisbecker } 184d0775264SFrederic Weisbecker 185d0775264SFrederic Weisbecker if (user) { 186d0775264SFrederic Weisbecker if (!user_mode(regs)) { 1879251f904SBorislav Petkov if (current->mm) 1889251f904SBorislav Petkov regs = task_pt_regs(current); 1899251f904SBorislav Petkov else 1909251f904SBorislav Petkov regs = NULL; 1919251f904SBorislav Petkov } 1929251f904SBorislav Petkov 1939251f904SBorislav Petkov if (regs) { 194e6dab5ffSAndrew Vagin /* 195e6dab5ffSAndrew Vagin * Disallow cross-task user callchains. 196e6dab5ffSAndrew Vagin */ 197e6dab5ffSAndrew Vagin if (event->ctx->task && event->ctx->task != current) 198e6dab5ffSAndrew Vagin goto exit_put; 199e6dab5ffSAndrew Vagin 2009251f904SBorislav Petkov perf_callchain_store(entry, PERF_CONTEXT_USER); 2019251f904SBorislav Petkov perf_callchain_user(entry, regs); 2029251f904SBorislav Petkov } 203d0775264SFrederic Weisbecker } 2049251f904SBorislav Petkov 2059251f904SBorislav Petkov exit_put: 2069251f904SBorislav Petkov put_callchain_entry(rctx); 2079251f904SBorislav Petkov 2089251f904SBorislav Petkov return entry; 2099251f904SBorislav Petkov } 210