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(&note_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(&note_lock);
2028cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	__oprof_put_note(onote);
2038cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	spin_unlock(&note_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(&note_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(&note_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(&note_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(&note_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