18cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd/** 28cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * @file oprofile.c 38cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * Main driver code 48cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * 58cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * @remark Copyright 2002 OProfile authors 68cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * @remark Read the file COPYING 78cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * 88cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * @author John Levon 98cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * @author Philippe Elie 108cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd */ 118cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 128cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include "oprofile.h" 138cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include "op_util.h" 148cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include "config.h" 158cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 168cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike DoddEXPORT_NO_SYMBOLS; 178cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 188cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike DoddMODULE_AUTHOR("John Levon (levon@movementarian.org)"); 198cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike DoddMODULE_DESCRIPTION("Continuous Profiling Module"); 208cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike DoddMODULE_LICENSE("GPL"); 218cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 228cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike DoddMODULE_PARM(allow_unload, "i"); 238cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike DoddMODULE_PARM_DESC(allow_unload, "Allow module to be unloaded."); 248cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#ifdef CONFIG_SMP 258cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstatic int allow_unload; 268cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#else 278cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstatic int allow_unload = 1; 288cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#endif 298cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 308cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd/* sysctl settables */ 318cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstruct oprof_sysctl sysctl_parms; 328cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd/* some of the sys ctl settable variable needs to be copied to protect 338cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * against user that try to change through /proc/sys/dev/oprofile/ * running 348cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * parameters during profiling */ 358cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstruct oprof_sysctl sysctl; 368cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 378cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstatic enum oprof_state state __cacheline_aligned_in_smp = STOPPED; 388cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 398cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstatic int op_major; 408cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 418cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstatic volatile ulong oprof_opened __cacheline_aligned_in_smp; 428cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstatic volatile ulong oprof_note_opened __cacheline_aligned_in_smp; 438cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstatic DECLARE_WAIT_QUEUE_HEAD(oprof_wait); 448cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 458cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstatic u32 oprof_ready[NR_CPUS] __cacheline_aligned_in_smp; 468cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstruct _oprof_data oprof_data[NR_CPUS] __cacheline_aligned; 478cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 488cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstruct op_note * note_buffer __cacheline_aligned_in_smp; 498cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddu32 note_pos __cacheline_aligned_in_smp; 508cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 518cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd// the interrupt handler ops structure to use 528cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstatic struct op_int_operations const * int_ops; 538cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 548cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstatic char const * op_version = PACKAGE " " VERSION; 558cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 568cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd/* ---------------- interrupt entry routines ------------------ */ 578cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 588cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddinline static int need_wakeup(uint cpu, struct _oprof_data * data) 598cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{ 608cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd return data->nextbuf >= (data->buf_size - data->buf_watermark) && !oprof_ready[cpu]; 618cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd} 628cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 638cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddinline static void next_sample(struct _oprof_data * data) 648cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{ 658cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if (unlikely(++data->nextbuf == data->buf_size)) 668cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd data->nextbuf = 0; 678cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd} 688cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 698cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddinline static void evict_op_entry(uint cpu, struct _oprof_data * data, long irq_enabled) 708cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{ 718cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd next_sample(data); 728cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if (likely(!need_wakeup(cpu, data))) 738cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd return; 748cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 758cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd /* locking rationale : 768cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * 778cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * other CPUs are not a race concern since we synch on oprof_wait->lock. 788cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * 798cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * for the current CPU, we might have interrupted another user of e.g. 808cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * runqueue_lock, deadlocking on SMP and racing on UP. So we check that IRQs 818cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * were not disabled (corresponding to the irqsave/restores in __wake_up(). 828cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * 838cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * Note that this requires all spinlocks taken by the full wake_up path 848cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * to have saved IRQs - otherwise we can interrupt whilst holding a spinlock 858cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * taken from some non-wake_up() path and deadlock. Currently this means only 868cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * oprof_wait->lock and runqueue_lock: all instances disable IRQs before 878cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * taking the lock. 888cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * 898cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * This will mean that approaching the end of the buffer, a number of the 908cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * evictions may fail to wake up the daemon. We simply hope this doesn't 918cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * take long; a pathological case could cause buffer overflow. 928cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * 938cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * Note that we use oprof_ready as our flag for whether we have initiated a 948cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * wake-up. Once the wake-up is received, the flag is reset as well as 958cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * data->nextbuf, preventing multiple wakeups. 968cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * 978cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * On 2.2, a global waitqueue_lock is used, so we must check it's not held 988cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * by the current CPU. We make sure that any users of the wait queue (i.e. 998cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * us and the code for wait_event_interruptible()) disable interrupts so it's 1008cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * still safe to check IF_MASK. 1018cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd */ 1028cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if (likely(irq_enabled)) { 1038cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd oprof_ready[cpu] = 1; 1048cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd wake_up(&oprof_wait); 1058cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd } 1068cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd} 1078cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 1088cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddinline static void 1098cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddfill_op_entry(struct op_sample * ops, long eip, pid_t pid, pid_t tgid, int ctr) 1108cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{ 1118cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd ops->eip = eip; 1128cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd ops->pid = pid; 1138cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd ops->tgid = tgid; 1148cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd ops->counter = ctr; 1158cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd} 1168cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 1178cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddvoid op_do_profile(uint cpu, long eip, long irq_enabled, int ctr) 1188cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{ 1198cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd struct _oprof_data * data = &oprof_data[cpu]; 1208cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd pid_t const pid = current->pid; 1218cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd pid_t const tgid = op_get_tgid(); 1228cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd struct op_sample * samples = &data->buffer[data->nextbuf]; 1238cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 1248cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd data->nr_irq++; 1258cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 1268cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd fill_op_entry(samples, eip, pid, tgid, ctr); 1278cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd evict_op_entry(cpu, data, irq_enabled); 1288cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd} 1298cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 1308cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd/* ---------------- driver routines ------------------ */ 1318cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 1328cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd/* only stop and start profiling interrupt when we are 1338cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * fully running ! 1348cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd */ 1358cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstatic void stop_cpu_perfctr(int cpu) 1368cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{ 1378cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if (state == RUNNING) 1388cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd int_ops->stop_cpu(cpu); 1398cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd} 1408cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 1418cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstatic void start_cpu_perfctr(int cpu) 1428cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{ 1438cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if (state == RUNNING) 1448cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd int_ops->start_cpu(cpu); 1458cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd} 1468cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 1478cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddspinlock_t note_lock __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED; 1488cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd/* which buffer nr. is waiting to be read ? */ 1498cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddint cpu_buffer_waiting; 1508cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 1518cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstatic int is_ready(void) 1528cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{ 1538cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd uint cpu_nr; 1548cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd for (cpu_nr = 0 ; cpu_nr < smp_num_cpus; cpu_nr++) { 1558cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if (oprof_ready[cpu_nr]) { 1568cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd cpu_buffer_waiting = cpu_nr; 1578cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd return 1; 1588cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd } 1598cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd } 1608cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd return 0; 1618cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd} 1628cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 1638cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddinline static void up_and_check_note(void) 1648cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{ 1658cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd note_pos++; 1668cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if (likely(note_pos < (sysctl.note_size - OP_PRE_NOTE_WATERMARK(sysctl.note_size)) && !is_ready())) 1678cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd return; 1688cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 1698cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd /* if we reach the end of the buffer, just pin 1708cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * to the last entry until it is read. This loses 1718cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * notes, but we have no choice. */ 1728cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if (unlikely(note_pos == sysctl.note_size)) { 1738cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd static int warned; 1748cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if (!warned) { 1758cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd printk(KERN_WARNING "note buffer overflow: restart " 1768cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd "oprofile with a larger note buffer.\n"); 1778cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd warned = 1; 1788cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd } 1798cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd sysctl.nr_note_buffer_overflow++; 1808cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd note_pos = sysctl.note_size - 1; 1818cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd } 1828cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 1838cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd /* we just use cpu 0 as a convenient one to wake up */ 1848cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd oprof_ready[0] = 2; 1858cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd oprof_wake_up(&oprof_wait); 1868cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd} 1878cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 1888cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd/* if holding note_lock */ 1898cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddvoid __oprof_put_note(struct op_note * onote) 1908cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{ 1918cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd /* ignore note if we're not up and running fully */ 1928cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if (state != RUNNING) 1938cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd return; 1948cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 1958cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd memcpy(¬e_buffer[note_pos], onote, sizeof(struct op_note)); 1968cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd up_and_check_note(); 1978cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd} 1988cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 1998cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddvoid oprof_put_note(struct op_note * onote) 2008cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{ 2018cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd spin_lock(¬e_lock); 2028cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd __oprof_put_note(onote); 2038cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd spin_unlock(¬e_lock); 2048cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd} 2058cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 2068cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstatic ssize_t oprof_note_read(char * buf, size_t count, loff_t * ppos) 2078cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{ 2088cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd struct op_note * mybuf; 2098cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd uint num; 2108cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd ssize_t max; 2118cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 2128cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd max = sizeof(struct op_note) * sysctl.note_size; 2138cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 2148cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if (*ppos || count != max) 2158cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd return -EINVAL; 2168cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 2178cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd mybuf = vmalloc(max); 2188cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if (!mybuf) 2198cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd return -EFAULT; 2208cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 2218cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd spin_lock(¬e_lock); 2228cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 2238cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd num = note_pos; 2248cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 2258cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd count = note_pos * sizeof(struct op_note); 2268cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 2278cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if (count) 2288cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd memcpy(mybuf, note_buffer, count); 2298cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 2308cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd note_pos = 0; 2318cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 2328cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd spin_unlock(¬e_lock); 2338cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 2348cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if (count && copy_to_user(buf, mybuf, count)) 2358cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd count = -EFAULT; 2368cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 2378cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd vfree(mybuf); 2388cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd return count; 2398cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd} 2408cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 2418cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstatic int oprof_note_open(void) 2428cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{ 2438cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if (test_and_set_bit(0, &oprof_note_opened)) 2448cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd return -EBUSY; 2458cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd INC_USE_COUNT_MAYBE; 2468cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd return 0; 2478cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd} 2488cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 2498cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstatic int oprof_note_release(void) 2508cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{ 2518cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd BUG_ON(!oprof_note_opened); 2528cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd clear_bit(0, &oprof_note_opened); 2538cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd DEC_USE_COUNT_MAYBE; 2548cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd return 0; 2558cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd} 2568cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 2578cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstatic int check_buffer_amount(int cpu_nr) 2588cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{ 2598cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd struct _oprof_data * data = &oprof_data[cpu_nr]; 2608cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd int size = data->buf_size; 2618cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd int num = data->nextbuf; 2628cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if (num < size - data->buf_watermark && oprof_ready[cpu_nr] != 2) { 2638cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd printk(KERN_WARNING "oprofile: Detected overflow of size %d. " 2648cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd "You must increase the module buffer size with\n" 2658cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd "opcontrol --setup --bufer-size= or reduce the " 2668cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd "interrupt frequency\n", num); 2678cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd data->nr_buffer_overflow += num; 2688cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd num = size; 2698cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd } else 2708cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd data->nextbuf = 0; 2718cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd return num; 2728cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd} 2738cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 2748cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstatic int copy_buffer(char * buf, int cpu_nr) 2758cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{ 2768cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd struct op_buffer_head head; 2778cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd int ret = -EFAULT; 2788cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 2798cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd stop_cpu_perfctr(cpu_nr); 2808cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 2818cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd head.cpu_nr = cpu_nr; 2828cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd head.count = check_buffer_amount(cpu_nr); 2838cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd head.state = state; 2848cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 2858cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd oprof_ready[cpu_nr] = 0; 2868cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 2878cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if (copy_to_user(buf, &head, sizeof(struct op_buffer_head))) 2888cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd goto out; 2898cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 2908cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if (head.count) { 2918cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd size_t const size = head.count * sizeof(struct op_sample); 2928cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if (copy_to_user(buf + sizeof(struct op_buffer_head), 2938cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd oprof_data[cpu_nr].buffer, size)) 2948cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd goto out; 2958cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd ret = size + sizeof(struct op_buffer_head); 2968cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd } else { 2978cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd ret = sizeof(struct op_buffer_head); 2988cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd } 2998cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 3008cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddout: 3018cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd start_cpu_perfctr(cpu_nr); 3028cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd return ret; 3038cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd} 3048cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 3058cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstatic ssize_t oprof_read(struct file * file, char * buf, size_t count, loff_t * ppos) 3068cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{ 3078cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd ssize_t max; 3088cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 3098cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if (!capable(CAP_SYS_PTRACE)) 3108cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd return -EPERM; 3118cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 3128cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd switch (MINOR(file->f_dentry->d_inode->i_rdev)) { 3138cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd case 2: return oprof_note_read(buf, count, ppos); 3148cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd case 0: break; 3158cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd default: return -EINVAL; 3168cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd } 3178cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 3188cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd max = sizeof(struct op_buffer_head) + sizeof(struct op_sample) * sysctl.buf_size; 3198cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 3208cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if (*ppos || count != max) 3218cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd return -EINVAL; 3228cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 3238cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd switch (state) { 3248cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd case RUNNING: 3258cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd wait_event_interruptible(oprof_wait, is_ready()); 3268cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if (signal_pending(current)) 3278cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd return -EINTR; 3288cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd break; 3298cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 3308cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd /* Non-obvious. If O_NONBLOCK is set, that means 3318cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * the daemon knows it has to quit and is asking 3328cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * for final buffer data. If it's not set, then we 3338cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * have just transitioned to STOPPING, and we must 3348cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * inform the daemon (which we can do just by a normal 3358cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * operation). 3368cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd */ 3378cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd case STOPPING: { 3388cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd int cpu; 3398cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 3408cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if (!(file->f_flags & O_NONBLOCK)) 3418cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd break; 3428cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 3438cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd for (cpu = 0; cpu < smp_num_cpus; ++cpu) { 3448cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if (oprof_data[cpu].nextbuf) { 3458cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd cpu_buffer_waiting = cpu; 3468cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd oprof_ready[cpu] = 2; 3478cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd break; 3488cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd } 3498cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd } 3508cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 3518cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if (cpu == smp_num_cpus) 3528cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd return -EAGAIN; 3538cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 3548cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd } 3558cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd break; 3568cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 3578cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd case STOPPED: BUG(); 3588cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd } 3598cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 3608cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd return copy_buffer(buf, cpu_buffer_waiting); 3618cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd} 3628cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 3638cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 3648cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstatic int oprof_start(void); 3658cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstatic int oprof_stop(void); 3668cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 3678cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstatic int oprof_open(struct inode * ino, struct file * file) 3688cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{ 3698cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd int err; 3708cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 3718cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if (!capable(CAP_SYS_PTRACE)) 3728cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd return -EPERM; 3738cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 3748cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd switch (MINOR(file->f_dentry->d_inode->i_rdev)) { 3758cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd case 1: return oprof_hash_map_open(); 3768cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd case 2: return oprof_note_open(); 3778cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd case 0: 3788cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd /* make sure the other devices are open */ 3798cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if (is_map_ready()) 3808cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd break; 3818cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd default: 3828cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd return -EINVAL; 3838cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd } 3848cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 3858cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if (test_and_set_bit(0, &oprof_opened)) 3868cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd return -EBUSY; 3878cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 3888cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd err = oprof_start(); 3898cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if (err) 3908cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd clear_bit(0, &oprof_opened); 3918cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd return err; 3928cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd} 3938cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 3948cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstatic int oprof_release(struct inode * ino, struct file * file) 3958cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{ 3968cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd switch (MINOR(file->f_dentry->d_inode->i_rdev)) { 3978cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd case 1: return oprof_hash_map_release(); 3988cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd case 2: return oprof_note_release(); 3998cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd case 0: break; 4008cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd default: return -EINVAL; 4018cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd } 4028cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 4038cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd BUG_ON(!oprof_opened); 4048cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 4058cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd clear_bit(0, &oprof_opened); 4068cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 4078cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd // FIXME: is this safe when I kill -9 the daemon ? 4088cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd return oprof_stop(); 4098cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd} 4108cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 4118cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstatic int oprof_mmap(struct file * file, struct vm_area_struct * vma) 4128cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{ 4138cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if (MINOR(file->f_dentry->d_inode->i_rdev) == 1) 4148cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd return oprof_hash_map_mmap(file, vma); 4158cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd return -EINVAL; 4168cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd} 4178cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 4188cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd/* called under spinlock, cannot sleep */ 4198cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstatic void oprof_free_mem(uint num) 4208cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{ 4218cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd uint i; 4228cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd for (i=0; i < num; i++) { 4238cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if (oprof_data[i].buffer) 4248cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd vfree(oprof_data[i].buffer); 4258cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd oprof_data[i].buffer = NULL; 4268cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd } 4278cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd vfree(note_buffer); 4288cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd note_buffer = NULL; 4298cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd} 4308cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 4318cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstatic int oprof_init_data(void) 4328cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{ 4338cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd uint i, notebufsize; 4348cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd ulong buf_size; 4358cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd struct _oprof_data * data; 4368cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 4378cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd sysctl.nr_note_buffer_overflow = 0; 4388cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd notebufsize = sizeof(struct op_note) * sysctl.note_size; 4398cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd note_buffer = vmalloc(notebufsize); 4408cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if (!note_buffer) { 4418cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd printk(KERN_ERR "oprofile: failed to allocate note buffer of %u bytes\n", 4428cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd notebufsize); 4438cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd return -EFAULT; 4448cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd } 4458cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd note_pos = 0; 4468cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 4478cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd // safe init 4488cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd for (i = 0; i < smp_num_cpus; ++i) { 4498cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd data = &oprof_data[i]; 4508cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd data->buf_size = 0; 4518cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd data->buffer = 0; 4528cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd data->buf_watermark = 0; 4538cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd data->nr_buffer_overflow = 0; 4548cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd } 4558cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 4568cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd buf_size = (sizeof(struct op_sample) * sysctl.buf_size); 4578cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 4588cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd for (i = 0 ; i < smp_num_cpus ; ++i) { 4598cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd data = &oprof_data[i]; 4608cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 4618cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd data->buffer = vmalloc(buf_size); 4628cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if (!data->buffer) { 4638cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd printk(KERN_ERR "oprofile: failed to allocate eviction buffer of %lu bytes\n", buf_size); 4648cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd oprof_free_mem(i); 4658cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd return -EFAULT; 4668cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd } 4678cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 4688cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd memset(data->buffer, 0, buf_size); 4698cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 4708cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd data->buf_size = sysctl.buf_size; 4718cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd data->buf_watermark = OP_PRE_WATERMARK(data->buf_size); 4728cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd data->nextbuf = 0; 4738cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd } 4748cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 4758cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd return 0; 4768cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd} 4778cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 4788cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstatic int parms_check(void) 4798cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{ 4808cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd int err; 4818cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 4828cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if ((err = check_range(sysctl.buf_size, OP_MIN_BUF_SIZE, OP_MAX_BUF_SIZE, 4838cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd "sysctl.buf_size value %d not in range (%d %d)\n"))) 4848cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd return err; 4858cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if ((err = check_range(sysctl.note_size, OP_MIN_NOTE_TABLE_SIZE, OP_MAX_NOTE_TABLE_SIZE, 4868cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd "sysctl.note_size value %d not in range (%d %d)\n"))) 4878cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd return err; 4888cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 4898cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if ((err = int_ops->check_params())) 4908cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd return err; 4918cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 4928cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd return 0; 4938cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd} 4948cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 4958cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 4968cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstatic DECLARE_MUTEX(sysctlsem); 4978cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 4988cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 4998cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstatic int oprof_start(void) 5008cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{ 5018cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd int err = 0; 5028cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 5038cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd down(&sysctlsem); 5048cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 5058cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd /* save the sysctl settable things to protect against change through 5068cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * systcl the profiler params */ 5078cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd sysctl_parms.cpu_type = sysctl.cpu_type; 5088cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd sysctl = sysctl_parms; 5098cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 5108cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if ((err = oprof_init_data())) 5118cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd goto out; 5128cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 5138cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if ((err = parms_check())) { 5148cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd oprof_free_mem(smp_num_cpus); 5158cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd goto out; 5168cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd } 5178cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 5188cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if ((err = int_ops->setup())) { 5198cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd oprof_free_mem(smp_num_cpus); 5208cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd goto out; 5218cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd } 5228cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 5238cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd op_intercept_syscalls(); 5248cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 5258cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd int_ops->start(); 5268cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 5278cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd state = RUNNING; 5288cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 5298cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddout: 5308cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd up(&sysctlsem); 5318cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd return err; 5328cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd} 5338cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 5348cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd/* 5358cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * stop interrupts being generated and notes arriving. 5368cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * This is idempotent. 5378cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd */ 5388cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstatic void oprof_partial_stop(void) 5398cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{ 5408cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd BUG_ON(state == STOPPED); 5418cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 5428cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if (state == RUNNING) { 5438cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd op_restore_syscalls(); 5448cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd int_ops->stop(); 5458cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd } 5468cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 5478cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd state = STOPPING; 5488cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd} 5498cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 5508cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstatic int oprof_stop(void) 5518cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{ 5528cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd uint i; 5538cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd // FIXME: err not needed 5548cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd int err = -EINVAL; 5558cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 5568cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd down(&sysctlsem); 5578cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 5588cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd BUG_ON(state == STOPPED); 5598cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 5608cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd /* here we need to : 5618cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * bring back the old system calls 5628cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * stop the perf counter 5638cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * bring back the old NMI handler 5648cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * reset the map buffer stuff and ready values 5658cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * 5668cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * Nothing will be able to write into the map buffer because 5678cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * we synchronise via the spinlocks 5688cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd */ 5698cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 5708cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd oprof_partial_stop(); 5718cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 5728cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd spin_lock(¬e_lock); 5738cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 5748cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd for (i = 0 ; i < smp_num_cpus; i++) { 5758cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd struct _oprof_data * data = &oprof_data[i]; 5768cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd oprof_ready[i] = 0; 5778cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd data->nextbuf = 0; 5788cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd } 5798cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 5808cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd oprof_free_mem(smp_num_cpus); 5818cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 5828cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd spin_unlock(¬e_lock); 5838cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd err = 0; 5848cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 5858cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd /* FIXME: can we really say this ? */ 5868cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd state = STOPPED; 5878cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd up(&sysctlsem); 5888cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd return err; 5898cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd} 5908cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 5918cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstatic struct file_operations oprof_fops = { 5928cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#ifdef HAVE_FILE_OPERATIONS_OWNER 5938cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd owner: THIS_MODULE, 5948cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#endif 5958cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd open: oprof_open, 5968cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd release: oprof_release, 5978cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd read: oprof_read, 5988cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd mmap: oprof_mmap, 5998cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd}; 6008cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 6018cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd/* 6028cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * /proc/sys/dev/oprofile/ 6038cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * bufsize 6048cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * notesize 6058cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * dump 6068cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * dump_stop 6078cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * nr_interrupts 6088cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * #ctr/ 6098cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * event 6108cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * enabled 6118cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * count 6128cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * unit_mask 6138cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * kernel 6148cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * user 6158cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * 6168cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * #ctr is in [0-1] for PPro core, [0-3] for Athlon core 6178cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * 6188cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd */ 6198cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 6208cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd/* These access routines are basically not safe on SMP for module unload. 6218cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * And there is nothing we can do about it - the API is broken. We'll just 6228cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * make a best-efforts thing. Note the sem is needed to prevent parms_check 6238cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * bypassing during oprof_start(). 6248cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd */ 6258cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 6268cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstatic void lock_sysctl(void) 6278cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{ 6288cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd MOD_INC_USE_COUNT; 6298cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd down(&sysctlsem); 6308cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd} 6318cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 6328cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstatic void unlock_sysctl(void) 6338cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{ 6348cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd up(&sysctlsem); 6358cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd MOD_DEC_USE_COUNT; 6368cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd} 6378cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 6388cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstatic int get_nr_interrupts(ctl_table * table, int write, struct file * filp, void * buffer, size_t * lenp) 6398cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{ 6408cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd uint cpu; 6418cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd int ret = -EINVAL; 6428cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 6438cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd lock_sysctl(); 6448cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 6458cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if (write) 6468cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd goto out; 6478cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 6488cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd sysctl.nr_interrupts = 0; 6498cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 6508cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd for (cpu = 0 ; cpu < smp_num_cpus; cpu++) { 6518cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd sysctl.nr_interrupts += oprof_data[cpu].nr_irq; 6528cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd oprof_data[cpu].nr_irq = 0; 6538cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd } 6548cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 6558cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd ret = proc_dointvec(table, write, filp, buffer, lenp); 6568cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddout: 6578cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd unlock_sysctl(); 6588cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd return ret; 6598cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd} 6608cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 6618cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstatic int get_nr_buffer_overflow(ctl_table * table, int write, struct file * filp, void * buffer, size_t * lenp) 6628cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{ 6638cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd uint cpu; 6648cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd int ret = -EINVAL; 6658cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 6668cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd lock_sysctl(); 6678cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 6688cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if (write) 6698cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd goto out; 6708cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 6718cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd for (cpu = 0 ; cpu < smp_num_cpus; cpu++) { 6728cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd sysctl.nr_buffer_overflow += oprof_data[cpu].nr_buffer_overflow; 6738cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd oprof_data[cpu].nr_buffer_overflow = 0; 6748cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd } 6758cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 6768cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd ret = proc_dointvec(table, write, filp, buffer, lenp); 6778cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddout: 6788cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd unlock_sysctl(); 6798cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd return ret; 6808cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd} 6818cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 6828cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddint lproc_dointvec(ctl_table * table, int write, struct file * filp, void * buffer, size_t * lenp) 6838cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{ 6848cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd int err; 6858cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 6868cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd lock_sysctl(); 6878cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd err = proc_dointvec(table, write, filp, buffer, lenp); 6888cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd unlock_sysctl(); 6898cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 6908cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd return err; 6918cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd} 6928cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 6938cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstatic void do_actual_dump(void) 6948cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{ 6958cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd uint cpu; 6968cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 6978cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd for (cpu = 0 ; cpu < smp_num_cpus; cpu++) 6988cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd oprof_ready[cpu] = 2; 6998cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd oprof_wake_up(&oprof_wait); 7008cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd} 7018cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 7028cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstatic int sysctl_do_dump(ctl_table * table, int write, struct file * filp, void * buffer, size_t * lenp) 7038cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{ 7048cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd int err = -EINVAL; 7058cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 7068cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd lock_sysctl(); 7078cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 7088cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if (state != RUNNING) 7098cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd goto out; 7108cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 7118cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if (!write) { 7128cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd err = proc_dointvec(table, write, filp, buffer, lenp); 7138cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd goto out; 7148cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd } 7158cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 7168cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd do_actual_dump(); 7178cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 7188cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd err = 0; 7198cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddout: 7208cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd unlock_sysctl(); 7218cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd return err; 7228cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd} 7238cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 7248cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstatic int sysctl_do_dump_stop(ctl_table * table, int write, struct file * filp, void * buffer, size_t * lenp) 7258cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{ 7268cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd int err = -EINVAL; 7278cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 7288cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd lock_sysctl(); 7298cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 7308cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if (state != RUNNING) 7318cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd goto out; 7328cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 7338cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if (!write) { 7348cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd err = proc_dointvec(table, write, filp, buffer, lenp); 7358cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd goto out; 7368cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd } 7378cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 7388cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd oprof_partial_stop(); 7398cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 7408cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd /* also wakes up daemon */ 7418cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd do_actual_dump(); 7428cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 7438cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd err = 0; 7448cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddout: 7458cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd unlock_sysctl(); 7468cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd return err; 7478cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd} 7488cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 7498cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstatic int const nr_oprof_static = 8; 7508cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 7518cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstatic ctl_table oprof_table[] = { 7528cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd { 1, "bufsize", &sysctl_parms.buf_size, sizeof(int), 0644, NULL, &lproc_dointvec, NULL, }, 7538cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd { 1, "dump", &sysctl_parms.dump, sizeof(int), 0666, NULL, &sysctl_do_dump, NULL, }, 7548cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd { 1, "dump_stop", &sysctl_parms.dump_stop, sizeof(int), 0644, NULL, &sysctl_do_dump_stop, NULL, }, 7558cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd { 1, "nr_interrupts", &sysctl.nr_interrupts, sizeof(int), 0444, NULL, &get_nr_interrupts, NULL, }, 7568cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd { 1, "notesize", &sysctl_parms.note_size, sizeof(int), 0644, NULL, &lproc_dointvec, NULL, }, 7578cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd { 1, "cpu_type", &sysctl.cpu_type, sizeof(int), 0444, NULL, &lproc_dointvec, NULL, }, 7588cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd { 1, "note_buffer_overflow", &sysctl.nr_note_buffer_overflow, sizeof(int), 0444, NULL, &lproc_dointvec, NULL, }, 7598cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd { 1, "buffer_overflow", &sysctl.nr_buffer_overflow, sizeof(int), 0444, NULL, &get_nr_buffer_overflow, NULL, }, 7608cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, 7618cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd { 0, }, 7628cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd}; 7638cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 7648cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstatic ctl_table oprof_root[] = { 7658cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd {1, "oprofile", NULL, 0, 0755, oprof_table}, 7668cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd {0, }, 7678cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd}; 7688cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 7698cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstatic ctl_table dev_root[] = { 7708cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd {CTL_DEV, "dev", NULL, 0, 0555, oprof_root}, 7718cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd {0, }, 7728cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd}; 7738cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 7748cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstatic struct ctl_table_header * sysctl_header; 7758cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 7768cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd/* NOTE: we do *not* support sysctl() syscall */ 7778cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 7788cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstatic int __init init_sysctl(void) 7798cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{ 7808cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd int err = 0; 7818cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd ctl_table * next = &oprof_table[nr_oprof_static]; 7828cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 7838cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd /* these sysctl parms need sensible value */ 7848cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd sysctl_parms.buf_size = OP_DEFAULT_BUF_SIZE; 7858cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd sysctl_parms.note_size = OP_DEFAULT_NOTE_SIZE; 7868cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 7878cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if ((err = int_ops->add_sysctls(next))) 7888cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd return err; 7898cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 7908cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd sysctl_header = register_sysctl_table(dev_root, 0); 7918cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd return err; 7928cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd} 7938cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 7948cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd/* not safe to mark as __exit since used from __init code */ 7958cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstatic void cleanup_sysctl(void) 7968cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{ 7978cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd ctl_table * next = &oprof_table[nr_oprof_static]; 7988cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd unregister_sysctl_table(sysctl_header); 7998cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 8008cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd int_ops->remove_sysctls(next); 8018cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 8028cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd return; 8038cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd} 8048cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 8058cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstatic int can_unload(void) 8068cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{ 8078cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd int can = -EBUSY; 8088cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd down(&sysctlsem); 8098cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 8108cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if (allow_unload && state == STOPPED && !GET_USE_COUNT(THIS_MODULE)) 8118cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd can = 0; 8128cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd up(&sysctlsem); 8138cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd return can; 8148cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd} 8158cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 8168cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddint __init oprof_init(void) 8178cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{ 8188cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd int err = 0; 8198cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 8208cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if (sysctl.cpu_type != CPU_RTC) { 8218cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd int_ops = op_int_interface(); 8228cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 8238cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd // try to init, fall back to rtc if not 8248cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if ((err = int_ops->init())) { 8258cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd int_ops = &op_rtc_ops; 8268cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if ((err = int_ops->init())) 8278cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd return err; 8288cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd sysctl.cpu_type = CPU_RTC; 8298cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd } 8308cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd } else { 8318cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd int_ops = &op_rtc_ops; 8328cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if ((err = int_ops->init())) 8338cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd return err; 8348cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd } 8358cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 8368cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if ((err = init_sysctl())) 8378cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd goto out_err; 8388cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 8398cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd err = op_major = register_chrdev(0, "oprof", &oprof_fops); 8408cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if (err < 0) 8418cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd goto out_err2; 8428cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 8438cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd err = oprof_init_hashmap(); 8448cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if (err < 0) { 8458cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd printk(KERN_ERR "oprofile: couldn't allocate hash map !\n"); 8468cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd unregister_chrdev(op_major, "oprof"); 8478cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd goto out_err2; 8488cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd } 8498cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 8508cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd /* module might not be unloadable */ 8518cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd THIS_MODULE->can_unload = can_unload; 8528cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 8538cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd /* do this now so we don't have to track save/restores later */ 8548cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd op_save_syscalls(); 8558cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 8568cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd printk(KERN_INFO "%s loaded, major %u\n", op_version, op_major); 8578cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd return 0; 8588cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 8598cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddout_err2: 8608cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd cleanup_sysctl(); 8618cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddout_err: 8628cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd int_ops->deinit(); 8638cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd return err; 8648cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd} 8658cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 8668cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddvoid __exit oprof_exit(void) 8678cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{ 8688cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd oprof_free_hashmap(); 8698cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 8708cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd unregister_chrdev(op_major, "oprof"); 8718cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 8728cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd cleanup_sysctl(); 8738cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 8748cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd int_ops->deinit(); 8758cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd} 8768cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 8778cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd/* 8788cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * "The most valuable commodity I know of is information." 8798cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * - Gordon Gekko 8808cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd */ 881