Blame src/perfctr-2.6.x/linux/drivers/perfctr/virtual.c

Packit Service a1973e
/* $Id: virtual.c,v 1.88.2.28 2009/06/11 08:09:12 mikpe Exp $
Packit Service a1973e
 * Virtual per-process performance counters.
Packit Service a1973e
 *
Packit Service a1973e
 * Copyright (C) 1999-2009  Mikael Pettersson
Packit Service a1973e
 */
Packit Service a1973e
#include <linux/version.h>
Packit Service a1973e
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
Packit Service a1973e
#include <linux/config.h>
Packit Service a1973e
#endif
Packit Service a1973e
#define __NO_VERSION__
Packit Service a1973e
#include <linux/module.h>
Packit Service a1973e
#include <linux/init.h>
Packit Service a1973e
#include <linux/compiler.h>
Packit Service a1973e
#include <linux/kernel.h>
Packit Service a1973e
#include <linux/mm.h>
Packit Service a1973e
#include <linux/ptrace.h>
Packit Service a1973e
#include <linux/fs.h>
Packit Service a1973e
#include <linux/file.h>
Packit Service a1973e
#include <linux/perfctr.h>
Packit Service a1973e
Packit Service a1973e
#include <asm/io.h>
Packit Service a1973e
#include <asm/uaccess.h>
Packit Service a1973e
Packit Service a1973e
#include "compat.h"
Packit Service a1973e
#include "virtual.h"
Packit Service a1973e
#include "marshal.h"
Packit Service a1973e
Packit Service a1973e
/****************************************************************
Packit Service a1973e
 *								*
Packit Service a1973e
 * Data types and macros.					*
Packit Service a1973e
 *								*
Packit Service a1973e
 ****************************************************************/
Packit Service a1973e
Packit Service a1973e
struct vperfctr {
Packit Service a1973e
/* User-visible fields: (must be first for mmap()) */
Packit Service a1973e
	struct perfctr_cpu_state cpu_state;
Packit Service a1973e
/* Kernel-private fields: */
Packit Service a1973e
	int si_signo;
Packit Service a1973e
	atomic_t count;
Packit Service a1973e
	spinlock_t owner_lock;
Packit Service a1973e
	struct task_struct *owner;
Packit Service a1973e
	/* sampling_timer and bad_cpus_allowed are frequently
Packit Service a1973e
	   accessed, so they get to share a cache line */
Packit Service a1973e
	unsigned int sampling_timer ____cacheline_aligned;
Packit Service a1973e
#ifdef CONFIG_PERFCTR_CPUS_FORBIDDEN_MASK
Packit Service a1973e
	atomic_t bad_cpus_allowed;
Packit Service a1973e
	cpumask_t cpumask;
Packit Service a1973e
#endif
Packit Service a1973e
	pid_t updater_tgid;	/* to detect self vs remote vperfctr_control races */
Packit Service a1973e
#if 0 && defined(CONFIG_PERFCTR_DEBUG)
Packit Service a1973e
	unsigned start_smp_id;
Packit Service a1973e
	unsigned suspended;
Packit Service a1973e
#endif
Packit Service a1973e
#ifdef CONFIG_PERFCTR_INTERRUPT_SUPPORT
Packit Service a1973e
	unsigned int iresume_cstatus;
Packit Service a1973e
#endif
Packit Service a1973e
	unsigned int flags;
Packit Service a1973e
};
Packit Service a1973e
#define IS_RUNNING(perfctr)	perfctr_cstatus_enabled((perfctr)->cpu_state.cstatus)
Packit Service a1973e
Packit Service a1973e
/* XXX: disabled: called from switch_to() where printk() is disallowed */
Packit Service a1973e
#if 0 && defined(CONFIG_PERFCTR_DEBUG)
Packit Service a1973e
#define debug_free(perfctr) \
Packit Service a1973e
do { \
Packit Service a1973e
	int i; \
Packit Service a1973e
	for(i = 0; i < PAGE_SIZE/sizeof(int); ++i) \
Packit Service a1973e
		((int*)(perfctr))[i] = 0xfedac0ed; \
Packit Service a1973e
} while(0)
Packit Service a1973e
#define debug_init(perfctr)	do { (perfctr)->suspended = 1; } while(0)
Packit Service a1973e
#define debug_suspend(perfctr) \
Packit Service a1973e
do { \
Packit Service a1973e
	if ((perfctr)->suspended) \
Packit Service a1973e
		printk(KERN_ERR "%s: BUG! suspending non-running perfctr (pid %d, comm %s)\n", \
Packit Service a1973e
		       __FUNCTION__, current->pid, current->comm); \
Packit Service a1973e
	(perfctr)->suspended = 1; \
Packit Service a1973e
} while(0)
Packit Service a1973e
#define debug_resume(perfctr) \
Packit Service a1973e
do { \
Packit Service a1973e
	if (!(perfctr)->suspended) \
Packit Service a1973e
		printk(KERN_ERR "%s: BUG! resuming non-suspended perfctr (pid %d, comm %s)\n", \
Packit Service a1973e
		       __FUNCTION__, current->pid, current->comm); \
Packit Service a1973e
	(perfctr)->suspended = 0; \
Packit Service a1973e
} while(0)
Packit Service a1973e
#define debug_check_smp_id(perfctr) \
Packit Service a1973e
do { \
Packit Service a1973e
	if ((perfctr)->start_smp_id != smp_processor_id()) { \
Packit Service a1973e
		printk(KERN_ERR "%s: BUG! current cpu %u differs from start cpu %u (pid %d, comm %s)\n", \
Packit Service a1973e
		       __FUNCTION__, smp_processor_id(), (perfctr)->start_smp_id, \
Packit Service a1973e
		       current->pid, current->comm); \
Packit Service a1973e
		return; \
Packit Service a1973e
	} \
Packit Service a1973e
} while(0)
Packit Service a1973e
#define debug_set_smp_id(perfctr) \
Packit Service a1973e
	do { (perfctr)->start_smp_id = smp_processor_id(); } while(0)
Packit Service a1973e
#else	/* CONFIG_PERFCTR_DEBUG */
Packit Service a1973e
#define debug_free(perfctr)		do{}while(0)
Packit Service a1973e
#define debug_init(perfctr)		do{}while(0)
Packit Service a1973e
#define debug_suspend(perfctr)		do{}while(0)
Packit Service a1973e
#define debug_resume(perfctr)		do{}while(0)
Packit Service a1973e
#define debug_check_smp_id(perfctr)	do{}while(0)
Packit Service a1973e
#define debug_set_smp_id(perfctr)	do{}while(0)
Packit Service a1973e
#endif	/* CONFIG_PERFCTR_DEBUG */
Packit Service a1973e
Packit Service a1973e
#ifdef CONFIG_PERFCTR_INTERRUPT_SUPPORT
Packit Service a1973e
Packit Service a1973e
static void vperfctr_ihandler(unsigned long pc);
Packit Service a1973e
static void vperfctr_handle_overflow(struct task_struct*, struct vperfctr*);
Packit Service a1973e
Packit Service a1973e
static inline void vperfctr_set_ihandler(void)
Packit Service a1973e
{
Packit Service a1973e
	perfctr_cpu_set_ihandler(vperfctr_ihandler);
Packit Service a1973e
}
Packit Service a1973e
Packit Service a1973e
static inline void vperfctr_clear_iresume_cstatus(struct vperfctr *perfctr)
Packit Service a1973e
{
Packit Service a1973e
	perfctr->iresume_cstatus = 0;
Packit Service a1973e
}
Packit Service a1973e
Packit Service a1973e
#else
Packit Service a1973e
static inline void vperfctr_set_ihandler(void) { }
Packit Service a1973e
static inline void vperfctr_clear_iresume_cstatus(struct vperfctr *perfctr) { }
Packit Service a1973e
#endif
Packit Service a1973e
Packit Service a1973e
#ifdef CONFIG_PERFCTR_CPUS_FORBIDDEN_MASK
Packit Service a1973e
Packit Service a1973e
static inline void vperfctr_init_bad_cpus_allowed(struct vperfctr *perfctr)
Packit Service a1973e
{
Packit Service a1973e
	atomic_set(&perfctr->bad_cpus_allowed, 0);
Packit Service a1973e
}
Packit Service a1973e
Packit Service a1973e
static inline void vperfctr_init_cpumask(struct vperfctr *perfctr)
Packit Service a1973e
{
Packit Service a1973e
	cpus_setall(perfctr->cpumask);
Packit Service a1973e
}
Packit Service a1973e
Packit Service a1973e
/* Concurrent set_cpus_allowed() is possible. The only lock it
Packit Service a1973e
   can take is the task lock, so we have to take it as well.
Packit Service a1973e
   task_lock/unlock also disables/enables preemption. */
Packit Service a1973e
Packit Service a1973e
static inline void vperfctr_task_lock(struct task_struct *p)
Packit Service a1973e
{
Packit Service a1973e
	task_lock(p);
Packit Service a1973e
}
Packit Service a1973e
Packit Service a1973e
static inline void vperfctr_task_unlock(struct task_struct *p)
Packit Service a1973e
{
Packit Service a1973e
	task_unlock(p);
Packit Service a1973e
}
Packit Service a1973e
Packit Service a1973e
#else	/* !CONFIG_PERFCTR_CPUS_FORBIDDEN_MASK */
Packit Service a1973e
Packit Service a1973e
static inline void vperfctr_init_bad_cpus_allowed(struct vperfctr *perfctr) { }
Packit Service a1973e
Packit Service a1973e
static inline void vperfctr_init_cpumask(struct vperfctr *perfctr) { }
Packit Service a1973e
Packit Service a1973e
/* Concurrent set_cpus_allowed() is impossible or irrelevant.
Packit Service a1973e
   Disabling and enabling preemption suffices for an atomic region. */
Packit Service a1973e
Packit Service a1973e
static inline void vperfctr_task_lock(struct task_struct *p)
Packit Service a1973e
{
Packit Service a1973e
	preempt_disable();
Packit Service a1973e
}
Packit Service a1973e
Packit Service a1973e
static inline void vperfctr_task_unlock(struct task_struct *p)
Packit Service a1973e
{
Packit Service a1973e
	preempt_enable();
Packit Service a1973e
}
Packit Service a1973e
Packit Service a1973e
#endif	/* !CONFIG_PERFCTR_CPUS_FORBIDDEN_MASK */
Packit Service a1973e
Packit Service a1973e
/* How to lock around find_task_by_vpid(). The tasklist_lock always
Packit Service a1973e
   works, but it's no longer exported starting with kernel 2.6.18.
Packit Service a1973e
   For kernels 2.6.18 and newer use rcu_read_{lock,unlock}(). */
Packit Service a1973e
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18)
Packit Service a1973e
static inline void vperfctr_lock_find_task_by_vpid(void)
Packit Service a1973e
{
Packit Service a1973e
	rcu_read_lock();
Packit Service a1973e
}
Packit Service a1973e
Packit Service a1973e
static inline void vperfctr_unlock_find_task_by_vpid(void)
Packit Service a1973e
{
Packit Service a1973e
	rcu_read_unlock();
Packit Service a1973e
}
Packit Service a1973e
#else	/* < 2.6.18 */
Packit Service a1973e
static inline void vperfctr_lock_find_task_by_vpid(void)
Packit Service a1973e
{
Packit Service a1973e
	read_lock(&tasklist_lock);
Packit Service a1973e
}
Packit Service a1973e
Packit Service a1973e
static inline void vperfctr_unlock_find_task_by_vpid(void)
Packit Service a1973e
{
Packit Service a1973e
	read_unlock(&tasklist_lock);
Packit Service a1973e
}
Packit Service a1973e
#endif	/* < 2.6.18 */
Packit Service a1973e
Packit Service a1973e
/****************************************************************
Packit Service a1973e
 *								*
Packit Service a1973e
 * Resource management.						*
Packit Service a1973e
 *								*
Packit Service a1973e
 ****************************************************************/
Packit Service a1973e
Packit Service a1973e
/* XXX: perhaps relax this to number of _live_ perfctrs */
Packit Service a1973e
static DEFINE_MUTEX(nrctrs_mutex);
Packit Service a1973e
static int nrctrs;
Packit Service a1973e
static const char this_service[] = __FILE__;
Packit Service a1973e
Packit Service a1973e
static int inc_nrctrs(void)
Packit Service a1973e
{
Packit Service a1973e
	const char *other;
Packit Service a1973e
Packit Service a1973e
	other = NULL;
Packit Service a1973e
	mutex_lock(&nrctrs_mutex);
Packit Service a1973e
	if (++nrctrs == 1) {
Packit Service a1973e
		other = perfctr_cpu_reserve(this_service);
Packit Service a1973e
		if (other)
Packit Service a1973e
			nrctrs = 0;
Packit Service a1973e
	}
Packit Service a1973e
	mutex_unlock(&nrctrs_mutex);
Packit Service a1973e
	if (other) {
Packit Service a1973e
		printk(KERN_ERR __FILE__
Packit Service a1973e
		       ": cannot operate, perfctr hardware taken by '%s'\n",
Packit Service a1973e
		       other);
Packit Service a1973e
		return -EBUSY;
Packit Service a1973e
	}
Packit Service a1973e
	vperfctr_set_ihandler();
Packit Service a1973e
	return 0;
Packit Service a1973e
}
Packit Service a1973e
Packit Service a1973e
static void dec_nrctrs(void)
Packit Service a1973e
{
Packit Service a1973e
	mutex_lock(&nrctrs_mutex);
Packit Service a1973e
	if (--nrctrs == 0)
Packit Service a1973e
		perfctr_cpu_release(this_service);
Packit Service a1973e
	mutex_unlock(&nrctrs_mutex);
Packit Service a1973e
}
Packit Service a1973e
Packit Service a1973e
static struct vperfctr *vperfctr_alloc(void)
Packit Service a1973e
{
Packit Service a1973e
	unsigned long page;
Packit Service a1973e
Packit Service a1973e
	if (inc_nrctrs() != 0)
Packit Service a1973e
		return ERR_PTR(-EBUSY);
Packit Service a1973e
	page = get_zeroed_page(GFP_KERNEL);
Packit Service a1973e
	if (!page) {
Packit Service a1973e
		dec_nrctrs();
Packit Service a1973e
		return ERR_PTR(-ENOMEM);
Packit Service a1973e
	}
Packit Service a1973e
	SetPageReserved(virt_to_page(page));
Packit Service a1973e
	return (struct vperfctr*) page;
Packit Service a1973e
}
Packit Service a1973e
Packit Service a1973e
static void vperfctr_free(struct vperfctr *perfctr)
Packit Service a1973e
{
Packit Service a1973e
	debug_free(perfctr);
Packit Service a1973e
	ClearPageReserved(virt_to_page(perfctr));
Packit Service a1973e
	free_page((unsigned long)perfctr);
Packit Service a1973e
	dec_nrctrs();
Packit Service a1973e
}
Packit Service a1973e
Packit Service a1973e
static struct vperfctr *get_empty_vperfctr(void)
Packit Service a1973e
{
Packit Service a1973e
	struct vperfctr *perfctr = vperfctr_alloc();
Packit Service a1973e
	if (!IS_ERR(perfctr)) {
Packit Service a1973e
		atomic_set(&perfctr->count, 1);
Packit Service a1973e
		vperfctr_init_bad_cpus_allowed(perfctr);
Packit Service a1973e
		vperfctr_init_cpumask(perfctr);
Packit Service a1973e
		spin_lock_init(&perfctr->owner_lock);
Packit Service a1973e
		debug_init(perfctr);
Packit Service a1973e
	}
Packit Service a1973e
	return perfctr;
Packit Service a1973e
}
Packit Service a1973e
Packit Service a1973e
static void put_vperfctr(struct vperfctr *perfctr)
Packit Service a1973e
{
Packit Service a1973e
	if (atomic_dec_and_test(&perfctr->count))
Packit Service a1973e
		vperfctr_free(perfctr);
Packit Service a1973e
}
Packit Service a1973e
Packit Service a1973e
/****************************************************************
Packit Service a1973e
 *								*
Packit Service a1973e
 * Basic counter operations.					*
Packit Service a1973e
 * These must all be called by the owner process only.		*
Packit Service a1973e
 * These must all be called with preemption disabled.		*
Packit Service a1973e
 *								*
Packit Service a1973e
 ****************************************************************/
Packit Service a1973e
Packit Service a1973e
/* PRE: IS_RUNNING(perfctr)
Packit Service a1973e
 * Suspend the counters.
Packit Service a1973e
 */
Packit Service a1973e
static inline void vperfctr_suspend(struct vperfctr *perfctr)
Packit Service a1973e
{
Packit Service a1973e
	debug_suspend(perfctr);
Packit Service a1973e
	debug_check_smp_id(perfctr);
Packit Service a1973e
	perfctr_cpu_suspend(&perfctr->cpu_state);
Packit Service a1973e
}
Packit Service a1973e
Packit Service a1973e
static inline void vperfctr_reset_sampling_timer(struct vperfctr *perfctr)
Packit Service a1973e
{
Packit Service a1973e
	/* XXX: base the value on perfctr_info.cpu_khz instead! */
Packit Service a1973e
	perfctr->sampling_timer = HZ/2;
Packit Service a1973e
}
Packit Service a1973e
Packit Service a1973e
/* PRE: perfctr == current->thread.perfctr && IS_RUNNING(perfctr)
Packit Service a1973e
 * Restart the counters.
Packit Service a1973e
 */
Packit Service a1973e
static inline void vperfctr_resume(struct vperfctr *perfctr)
Packit Service a1973e
{
Packit Service a1973e
	debug_resume(perfctr);
Packit Service a1973e
	perfctr_cpu_resume(&perfctr->cpu_state);
Packit Service a1973e
	vperfctr_reset_sampling_timer(perfctr);
Packit Service a1973e
	debug_set_smp_id(perfctr);
Packit Service a1973e
}
Packit Service a1973e
Packit Service a1973e
static inline void vperfctr_resume_with_overflow_check(struct vperfctr *perfctr)
Packit Service a1973e
{
Packit Service a1973e
#ifdef CONFIG_PERFCTR_INTERRUPT_SUPPORT
Packit Service a1973e
	if (perfctr_cpu_has_pending_interrupt(&perfctr->cpu_state)) {
Packit Service a1973e
		vperfctr_handle_overflow(current, perfctr);
Packit Service a1973e
		return;
Packit Service a1973e
	}
Packit Service a1973e
#endif
Packit Service a1973e
	vperfctr_resume(perfctr);
Packit Service a1973e
}
Packit Service a1973e
Packit Service a1973e
/* Sample the counters but do not suspend them. */
Packit Service a1973e
static void vperfctr_sample(struct vperfctr *perfctr)
Packit Service a1973e
{
Packit Service a1973e
	if (IS_RUNNING(perfctr)) {
Packit Service a1973e
		debug_check_smp_id(perfctr);
Packit Service a1973e
		perfctr_cpu_sample(&perfctr->cpu_state);
Packit Service a1973e
		vperfctr_reset_sampling_timer(perfctr);
Packit Service a1973e
	}
Packit Service a1973e
}
Packit Service a1973e
Packit Service a1973e
#ifdef CONFIG_PERFCTR_INTERRUPT_SUPPORT
Packit Service a1973e
/* vperfctr interrupt handler (XXX: add buffering support) */
Packit Service a1973e
/* PREEMPT note: called in IRQ context with preemption disabled. */
Packit Service a1973e
static void vperfctr_ihandler(unsigned long pc)
Packit Service a1973e
{
Packit Service a1973e
	struct task_struct *tsk = current;
Packit Service a1973e
	struct vperfctr *perfctr;
Packit Service a1973e
Packit Service a1973e
	perfctr = tsk->thread.perfctr;
Packit Service a1973e
	if (!perfctr) {
Packit Service a1973e
		printk(KERN_ERR "%s: BUG! pid %d has no vperfctr\n",
Packit Service a1973e
		       __FUNCTION__, tsk->pid);
Packit Service a1973e
		return;
Packit Service a1973e
	}
Packit Service a1973e
	if (!perfctr_cstatus_has_ictrs(perfctr->cpu_state.cstatus)) {
Packit Service a1973e
		printk(KERN_ERR "%s: BUG! vperfctr has cstatus %#x (pid %d, comm %s)\n",
Packit Service a1973e
		       __FUNCTION__, perfctr->cpu_state.cstatus, tsk->pid, tsk->comm);
Packit Service a1973e
		return;
Packit Service a1973e
	}
Packit Service a1973e
	vperfctr_suspend(perfctr);
Packit Service a1973e
	vperfctr_handle_overflow(tsk, perfctr);
Packit Service a1973e
}
Packit Service a1973e
Packit Service a1973e
static void vperfctr_handle_overflow(struct task_struct *tsk,
Packit Service a1973e
				     struct vperfctr *perfctr)
Packit Service a1973e
{
Packit Service a1973e
	unsigned int pmc_mask;
Packit Service a1973e
	siginfo_t si;
Packit Service a1973e
	sigset_t old_blocked;
Packit Service a1973e
Packit Service a1973e
	pmc_mask = perfctr_cpu_identify_overflow(&perfctr->cpu_state);
Packit Service a1973e
	if (!pmc_mask) {
Packit Service a1973e
		printk(KERN_ERR "%s: BUG! pid %d has unidentifiable overflow source\n",
Packit Service a1973e
		       __FUNCTION__, tsk->pid);
Packit Service a1973e
		return;
Packit Service a1973e
	}
Packit Service a1973e
	/* suspend a-mode and i-mode PMCs, leaving only TSC on */
Packit Service a1973e
	/* XXX: some people also want to suspend the TSC */
Packit Service a1973e
	perfctr->iresume_cstatus = perfctr->cpu_state.cstatus;
Packit Service a1973e
	if (perfctr_cstatus_has_tsc(perfctr->iresume_cstatus)) {
Packit Service a1973e
		perfctr->cpu_state.cstatus = perfctr_mk_cstatus(1, 0, 0);
Packit Service a1973e
		vperfctr_resume(perfctr);
Packit Service a1973e
	} else
Packit Service a1973e
		perfctr->cpu_state.cstatus = 0;
Packit Service a1973e
	si.si_signo = perfctr->si_signo;
Packit Service a1973e
	si.si_errno = 0;
Packit Service a1973e
	si.si_code = SI_PMC_OVF;
Packit Service a1973e
	si.si_pmc_ovf_mask = pmc_mask;
Packit Service a1973e
Packit Service a1973e
	/* deliver signal without waking up the receiver */
Packit Service a1973e
	spin_lock_irq(&task_siglock(tsk));
Packit Service a1973e
	old_blocked = tsk->blocked;
Packit Service a1973e
	sigaddset(&tsk->blocked, si.si_signo);
Packit Service a1973e
	spin_unlock_irq(&task_siglock(tsk));
Packit Service a1973e
Packit Service a1973e
	if (!send_sig_info(si.si_signo, &si, tsk))
Packit Service a1973e
		send_sig(si.si_signo, tsk, 1);
Packit Service a1973e
Packit Service a1973e
	spin_lock_irq(&task_siglock(tsk));
Packit Service a1973e
	tsk->blocked = old_blocked;
Packit Service a1973e
	recalc_sigpending();
Packit Service a1973e
	spin_unlock_irq(&task_siglock(tsk));
Packit Service a1973e
}
Packit Service a1973e
#endif
Packit Service a1973e
Packit Service a1973e
/****************************************************************
Packit Service a1973e
 *								*
Packit Service a1973e
 * Process management operations.				*
Packit Service a1973e
 * These must all, with the exception of vperfctr_unlink()	*
Packit Service a1973e
 * and __vperfctr_set_cpus_allowed(), be called by the owner	*
Packit Service a1973e
 * process only.						*
Packit Service a1973e
 *								*
Packit Service a1973e
 ****************************************************************/
Packit Service a1973e
Packit Service a1973e
/* Called from exit_thread() or sys_vperfctr_unlink().
Packit Service a1973e
 * If the counters are running, stop them and sample their final values.
Packit Service a1973e
 * Detach the vperfctr object from its owner task.
Packit Service a1973e
 * PREEMPT note: exit_thread() does not run with preemption disabled.
Packit Service a1973e
 */
Packit Service a1973e
static void vperfctr_unlink(struct task_struct *owner, struct vperfctr *perfctr)
Packit Service a1973e
{
Packit Service a1973e
	/* this synchronises with vperfctr_ioctl() */
Packit Service a1973e
	spin_lock(&perfctr->owner_lock);
Packit Service a1973e
	perfctr->owner = NULL;
Packit Service a1973e
	spin_unlock(&perfctr->owner_lock);
Packit Service a1973e
Packit Service a1973e
	/* perfctr suspend+detach must be atomic wrt process suspend */
Packit Service a1973e
	/* this also synchronises with perfctr_set_cpus_allowed() */
Packit Service a1973e
	vperfctr_task_lock(owner);
Packit Service a1973e
	if (IS_RUNNING(perfctr) && owner == current)
Packit Service a1973e
		vperfctr_suspend(perfctr);
Packit Service a1973e
	owner->thread.perfctr = NULL;
Packit Service a1973e
	vperfctr_task_unlock(owner);
Packit Service a1973e
Packit Service a1973e
	perfctr->cpu_state.cstatus = 0;
Packit Service a1973e
	vperfctr_clear_iresume_cstatus(perfctr);
Packit Service a1973e
	put_vperfctr(perfctr);
Packit Service a1973e
}
Packit Service a1973e
Packit Service a1973e
void __vperfctr_exit(struct vperfctr *perfctr)
Packit Service a1973e
{
Packit Service a1973e
	vperfctr_unlink(current, perfctr);
Packit Service a1973e
}
Packit Service a1973e
Packit Service a1973e
/* sys_execve() -> .. -> flush_old_exec() -> .. -> __vperfctr_flush().
Packit Service a1973e
 * Unlink the thread's perfctr state, if the CLOEXEC control flag is set.
Packit Service a1973e
 * PREEMPT note: flush_old_exec() does not run with preemption disabled.
Packit Service a1973e
 */
Packit Service a1973e
void __vperfctr_flush(struct vperfctr *perfctr)
Packit Service a1973e
{
Packit Service a1973e
	if (perfctr->flags & VPERFCTR_CONTROL_CLOEXEC)
Packit Service a1973e
		__vperfctr_exit(perfctr);
Packit Service a1973e
}
Packit Service a1973e
Packit Service a1973e
/* schedule() --> switch_to() --> .. --> __vperfctr_suspend().
Packit Service a1973e
 * If the counters are running, suspend them.
Packit Service a1973e
 * PREEMPT note: switch_to() runs with preemption disabled.
Packit Service a1973e
 */
Packit Service a1973e
void __vperfctr_suspend(struct vperfctr *perfctr)
Packit Service a1973e
{
Packit Service a1973e
	if (IS_RUNNING(perfctr))
Packit Service a1973e
		vperfctr_suspend(perfctr);
Packit Service a1973e
}
Packit Service a1973e
Packit Service a1973e
/* schedule() --> switch_to() --> .. --> __vperfctr_resume().
Packit Service a1973e
 * PRE: perfctr == current->thread.perfctr
Packit Service a1973e
 * If the counters are runnable, resume them.
Packit Service a1973e
 * PREEMPT note: switch_to() runs with preemption disabled.
Packit Service a1973e
 */
Packit Service a1973e
void __vperfctr_resume(struct vperfctr *perfctr)
Packit Service a1973e
{
Packit Service a1973e
	if (IS_RUNNING(perfctr)) {
Packit Service a1973e
#ifdef CONFIG_PERFCTR_CPUS_FORBIDDEN_MASK
Packit Service a1973e
		if (unlikely(atomic_read(&perfctr->bad_cpus_allowed)) &&
Packit Service a1973e
		    perfctr_cstatus_nrctrs(perfctr->cpu_state.cstatus)) {
Packit Service a1973e
			perfctr->cpu_state.cstatus = 0;
Packit Service a1973e
			vperfctr_clear_iresume_cstatus(perfctr);
Packit Service a1973e
			BUG_ON(current->state != TASK_RUNNING);
Packit Service a1973e
			send_sig(SIGILL, current, 1);
Packit Service a1973e
			return;
Packit Service a1973e
		}
Packit Service a1973e
#endif
Packit Service a1973e
		vperfctr_resume_with_overflow_check(perfctr);
Packit Service a1973e
	}
Packit Service a1973e
}
Packit Service a1973e
Packit Service a1973e
/* Called from update_one_process() [triggered by timer interrupt].
Packit Service a1973e
 * PRE: perfctr == current->thread.perfctr.
Packit Service a1973e
 * Sample the counters but do not suspend them.
Packit Service a1973e
 * Needed to avoid precision loss due to multiple counter
Packit Service a1973e
 * wraparounds between resume/suspend for CPU-bound processes.
Packit Service a1973e
 * PREEMPT note: called in IRQ context with preemption disabled.
Packit Service a1973e
 */
Packit Service a1973e
void __vperfctr_sample(struct vperfctr *perfctr)
Packit Service a1973e
{
Packit Service a1973e
	if (--perfctr->sampling_timer == 0)
Packit Service a1973e
		vperfctr_sample(perfctr);
Packit Service a1973e
}
Packit Service a1973e
Packit Service a1973e
#ifdef CONFIG_PERFCTR_CPUS_FORBIDDEN_MASK
Packit Service a1973e
/* Called from set_cpus_allowed().
Packit Service a1973e
 * PRE: current holds task_lock(owner)
Packit Service a1973e
 * PRE: owner->thread.perfctr == perfctr
Packit Service a1973e
 */
Packit Service a1973e
void __vperfctr_set_cpus_allowed(struct task_struct *owner,
Packit Service a1973e
				 struct vperfctr *perfctr,
Packit Service a1973e
				 cpumask_t new_mask)
Packit Service a1973e
{
Packit Service a1973e
	if (!cpus_subset(new_mask, perfctr->cpumask)) {
Packit Service a1973e
		atomic_set(&perfctr->bad_cpus_allowed, 1);
Packit Service a1973e
		printk(KERN_WARNING "perfctr: process %d (comm %s) issued unsafe"
Packit Service a1973e
		       " set_cpus_allowed() on process %d (comm %s)\n",
Packit Service a1973e
		       current->pid, current->comm, owner->pid, owner->comm);
Packit Service a1973e
	} else
Packit Service a1973e
		atomic_set(&perfctr->bad_cpus_allowed, 0);
Packit Service a1973e
}
Packit Service a1973e
#endif
Packit Service a1973e
Packit Service a1973e
/****************************************************************
Packit Service a1973e
 *								*
Packit Service a1973e
 * Virtual perfctr "system calls".				*
Packit Service a1973e
 * These can be called by the owner process (tsk == current),	*
Packit Service a1973e
 * a monitor process which has the owner under ptrace ATTACH	*
Packit Service a1973e
 * control (tsk && tsk != current), or anyone with a handle to	*
Packit Service a1973e
 * an unlinked perfctr (!tsk).					*
Packit Service a1973e
 *								*
Packit Service a1973e
 ****************************************************************/
Packit Service a1973e
Packit Service a1973e
static int sys_vperfctr_control(struct vperfctr *perfctr,
Packit Service a1973e
				struct perfctr_struct_buf *argp,
Packit Service a1973e
				struct task_struct *tsk)
Packit Service a1973e
{
Packit Service a1973e
	struct vperfctr_control control;
Packit Service a1973e
	int err;
Packit Service a1973e
	unsigned int next_cstatus;
Packit Service a1973e
	unsigned int nrctrs, i;
Packit Service a1973e
	cpumask_t cpumask;
Packit Service a1973e
Packit Service a1973e
	if (!tsk)
Packit Service a1973e
		return -ESRCH;	/* attempt to update unlinked perfctr */
Packit Service a1973e
Packit Service a1973e
	err = perfctr_copy_from_user(&control, argp, &vperfctr_control_sdesc);
Packit Service a1973e
	if (err)
Packit Service a1973e
		return err;
Packit Service a1973e
Packit Service a1973e
	/* Step 1: Update the control but keep the counters disabled.
Packit Service a1973e
	   PREEMPT note: Preemption is disabled since we're updating
Packit Service a1973e
	   an active perfctr. */
Packit Service a1973e
	preempt_disable();
Packit Service a1973e
	if (IS_RUNNING(perfctr)) {
Packit Service a1973e
		if (tsk == current)
Packit Service a1973e
			vperfctr_suspend(perfctr);
Packit Service a1973e
		perfctr->cpu_state.cstatus = 0;
Packit Service a1973e
		vperfctr_clear_iresume_cstatus(perfctr);
Packit Service a1973e
	}
Packit Service a1973e
	perfctr->cpu_state.control = control.cpu_control;
Packit Service a1973e
	/* remote access note: perfctr_cpu_update_control() is ok */
Packit Service a1973e
	cpus_setall(cpumask);
Packit Service a1973e
#ifdef CONFIG_PERFCTR_CPUS_FORBIDDEN_MASK
Packit Service a1973e
	/* make a stopped vperfctr have an unconstrained cpumask */
Packit Service a1973e
	perfctr->cpumask = cpumask;
Packit Service a1973e
#endif
Packit Service a1973e
	err = perfctr_cpu_update_control(&perfctr->cpu_state, &cpumask);
Packit Service a1973e
	if (err < 0) {
Packit Service a1973e
		next_cstatus = 0;
Packit Service a1973e
	} else {
Packit Service a1973e
		next_cstatus = perfctr->cpu_state.cstatus;
Packit Service a1973e
		perfctr->cpu_state.cstatus = 0;
Packit Service a1973e
		perfctr->updater_tgid = current->tgid;
Packit Service a1973e
#ifdef CONFIG_PERFCTR_CPUS_FORBIDDEN_MASK
Packit Service a1973e
		perfctr->cpumask = cpumask;
Packit Service a1973e
#endif
Packit Service a1973e
	}
Packit Service a1973e
	preempt_enable_no_resched();
Packit Service a1973e
Packit Service a1973e
	if (!perfctr_cstatus_enabled(next_cstatus))
Packit Service a1973e
		return err;
Packit Service a1973e
Packit Service a1973e
#ifdef CONFIG_PERFCTR_CPUS_FORBIDDEN_MASK
Packit Service a1973e
	/* Step 2: Update the task's CPU affinity mask.
Packit Service a1973e
	   PREEMPT note: Preemption must be enabled for set_cpus_allowed(). */
Packit Service a1973e
	if (control.cpu_control.nractrs || control.cpu_control.nrictrs) {
Packit Service a1973e
		cpumask_t old_mask, new_mask;
Packit Service a1973e
Packit Service a1973e
		old_mask = tsk->cpus_allowed;
Packit Service a1973e
		cpus_and(new_mask, old_mask, cpumask);
Packit Service a1973e
Packit Service a1973e
		if (cpus_empty(new_mask))
Packit Service a1973e
			return -EINVAL;
Packit Service a1973e
		if (!cpus_equal(new_mask, old_mask))
Packit Service a1973e
			set_cpus_allowed(tsk, new_mask);
Packit Service a1973e
	}
Packit Service a1973e
#endif
Packit Service a1973e
Packit Service a1973e
	/* Step 3: Enable the counters with the new control and affinity.
Packit Service a1973e
	   PREEMPT note: Preemption is disabled since we're updating
Packit Service a1973e
	   an active perfctr. */
Packit Service a1973e
	preempt_disable();
Packit Service a1973e
Packit Service a1973e
	/* We had to enable preemption above for set_cpus_allowed() so we may
Packit Service a1973e
	   have lost a race with a concurrent update via the remote control
Packit Service a1973e
	   interface. If so then we must abort our update of this perfctr. */
Packit Service a1973e
	if (perfctr->updater_tgid != current->tgid) {
Packit Service a1973e
		printk(KERN_WARNING "perfctr: control update by task %d"
Packit Service a1973e
		       " was lost due to race with update by task %d\n",
Packit Service a1973e
		       current->tgid, perfctr->updater_tgid);
Packit Service a1973e
		err = -EBUSY;
Packit Service a1973e
	} else {
Packit Service a1973e
		/* XXX: validate si_signo? */
Packit Service a1973e
		perfctr->si_signo = control.si_signo;
Packit Service a1973e
Packit Service a1973e
		perfctr->cpu_state.cstatus = next_cstatus;
Packit Service a1973e
Packit Service a1973e
		if (!perfctr_cstatus_has_tsc(next_cstatus))
Packit Service a1973e
			perfctr->cpu_state.tsc_sum = 0;
Packit Service a1973e
Packit Service a1973e
		nrctrs = perfctr_cstatus_nrctrs(next_cstatus);
Packit Service a1973e
		for(i = 0; i < nrctrs; ++i)
Packit Service a1973e
			if (!(control.preserve & (1<
Packit Service a1973e
				perfctr->cpu_state.pmc[i].sum = 0;
Packit Service a1973e
Packit Service a1973e
		perfctr->flags = control.flags;
Packit Service a1973e
Packit Service a1973e
		if (tsk == current)
Packit Service a1973e
			vperfctr_resume(perfctr);
Packit Service a1973e
	}
Packit Service a1973e
Packit Service a1973e
	preempt_enable();
Packit Service a1973e
	return err;
Packit Service a1973e
}
Packit Service a1973e
Packit Service a1973e
static int sys_vperfctr_iresume(struct vperfctr *perfctr, const struct task_struct *tsk)
Packit Service a1973e
{
Packit Service a1973e
#ifdef CONFIG_PERFCTR_INTERRUPT_SUPPORT
Packit Service a1973e
	unsigned int iresume_cstatus;
Packit Service a1973e
Packit Service a1973e
	if (!tsk)
Packit Service a1973e
		return -ESRCH;	/* attempt to update unlinked perfctr */
Packit Service a1973e
Packit Service a1973e
	iresume_cstatus = perfctr->iresume_cstatus;
Packit Service a1973e
	if (!perfctr_cstatus_has_ictrs(iresume_cstatus))
Packit Service a1973e
		return -EPERM;
Packit Service a1973e
Packit Service a1973e
	/* PREEMPT note: preemption is disabled over the entire
Packit Service a1973e
	   region because we're updating an active perfctr. */
Packit Service a1973e
	preempt_disable();
Packit Service a1973e
Packit Service a1973e
	if (IS_RUNNING(perfctr) && tsk == current)
Packit Service a1973e
		vperfctr_suspend(perfctr);
Packit Service a1973e
Packit Service a1973e
	perfctr->cpu_state.cstatus = iresume_cstatus;
Packit Service a1973e
	perfctr->iresume_cstatus = 0;
Packit Service a1973e
Packit Service a1973e
	/* remote access note: perfctr_cpu_ireload() is ok */
Packit Service a1973e
	perfctr_cpu_ireload(&perfctr->cpu_state);
Packit Service a1973e
Packit Service a1973e
	if (tsk == current)
Packit Service a1973e
		vperfctr_resume(perfctr);
Packit Service a1973e
Packit Service a1973e
	preempt_enable();
Packit Service a1973e
Packit Service a1973e
	return 0;
Packit Service a1973e
#else
Packit Service a1973e
	return -ENOSYS;
Packit Service a1973e
#endif
Packit Service a1973e
}
Packit Service a1973e
Packit Service a1973e
static int sys_vperfctr_unlink(struct vperfctr *perfctr, struct task_struct *tsk)
Packit Service a1973e
{
Packit Service a1973e
	if (tsk)
Packit Service a1973e
		vperfctr_unlink(tsk, perfctr);
Packit Service a1973e
	return 0;
Packit Service a1973e
}
Packit Service a1973e
Packit Service a1973e
static int sys_vperfctr_read_sum(struct vperfctr *perfctr,
Packit Service a1973e
				 struct perfctr_struct_buf *argp,
Packit Service a1973e
				 const struct task_struct *tsk)
Packit Service a1973e
{
Packit Service a1973e
	struct perfctr_sum_ctrs sum;
Packit Service a1973e
Packit Service a1973e
	if (tsk == current) {
Packit Service a1973e
		preempt_disable();
Packit Service a1973e
		vperfctr_sample(perfctr);
Packit Service a1973e
	}
Packit Service a1973e
	//sum = perfctr->cpu_state.sum;
Packit Service a1973e
	{
Packit Service a1973e
		int j;
Packit Service a1973e
		sum.tsc = perfctr->cpu_state.tsc_sum;
Packit Service a1973e
		for(j = 0; j < ARRAY_SIZE(sum.pmc); ++j)
Packit Service a1973e
			sum.pmc[j] = perfctr->cpu_state.pmc[j].sum;
Packit Service a1973e
	}
Packit Service a1973e
	if (tsk == current)
Packit Service a1973e
		preempt_enable();
Packit Service a1973e
	return perfctr_copy_to_user(argp, &sum, &perfctr_sum_ctrs_sdesc);
Packit Service a1973e
}
Packit Service a1973e
Packit Service a1973e
static int sys_vperfctr_read_control(struct vperfctr *perfctr,
Packit Service a1973e
				     struct perfctr_struct_buf *argp,
Packit Service a1973e
				     const struct task_struct *tsk)
Packit Service a1973e
{
Packit Service a1973e
	struct vperfctr_control control;
Packit Service a1973e
Packit Service a1973e
	/* PREEMPT note: While we're reading our own control, another
Packit Service a1973e
	   process may ptrace ATTACH to us and update our control.
Packit Service a1973e
	   Disable preemption to ensure we get a consistent copy.
Packit Service a1973e
	   Not needed for other cases since the perfctr is either
Packit Service a1973e
	   unlinked or its owner is ptrace ATTACH suspended by us. */
Packit Service a1973e
	if (tsk == current)
Packit Service a1973e
		preempt_disable();
Packit Service a1973e
	control.si_signo = perfctr->si_signo;
Packit Service a1973e
	control.cpu_control = perfctr->cpu_state.control;
Packit Service a1973e
	control.flags = perfctr->flags;
Packit Service a1973e
	if (tsk == current)
Packit Service a1973e
		preempt_enable();
Packit Service a1973e
	control.preserve = 0;
Packit Service a1973e
	return perfctr_copy_to_user(argp, &control, &vperfctr_control_sdesc);
Packit Service a1973e
}
Packit Service a1973e
Packit Service a1973e
/****************************************************************
Packit Service a1973e
 *								*
Packit Service a1973e
 * Virtual perfctr file operations.				*
Packit Service a1973e
 *								*
Packit Service a1973e
 ****************************************************************/
Packit Service a1973e
Packit Service a1973e
static int vperfctr_mmap(struct file *filp, struct vm_area_struct *vma)
Packit Service a1973e
{
Packit Service a1973e
	struct vperfctr *perfctr;
Packit Service a1973e
Packit Service a1973e
#ifdef CONFIG_ARM
Packit Service a1973e
#define _PAGE_RW	L_PTE_WRITE
Packit Service a1973e
#endif
Packit Service a1973e
	/* Only allow read-only mapping of first page. */
Packit Service a1973e
	if ((vma->vm_end - vma->vm_start) != PAGE_SIZE ||
Packit Service a1973e
	    vma->vm_pgoff != 0 ||
Packit Service a1973e
	    (pgprot_val(vma->vm_page_prot) & _PAGE_RW) ||
Packit Service a1973e
	    (vma->vm_flags & (VM_WRITE | VM_MAYWRITE)))
Packit Service a1973e
		return -EPERM;
Packit Service a1973e
	perfctr = filp->private_data;
Packit Service a1973e
	if (!perfctr)
Packit Service a1973e
		return -EPERM;
Packit Service a1973e
	/* 2.6.29-rc1 changed arch/x86/mm/pat.c to WARN_ON when
Packit Service a1973e
	   remap_pfn_range() is applied to plain RAM pages.
Packit Service a1973e
	   Comments there indicate that one should set_memory_wc()
Packit Service a1973e
	   before the remap, but that doesn't silence the WARN_ON.
Packit Service a1973e
	   Luckily vm_insert_page() works without complaints. */
Packit Service a1973e
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)
Packit Service a1973e
	return vm_insert_page(vma, vma->vm_start, virt_to_page((unsigned long)perfctr));
Packit Service a1973e
#else
Packit Service a1973e
	return remap_pfn_range(vma, vma->vm_start,
Packit Service a1973e
			       virt_to_phys(perfctr) >> PAGE_SHIFT,
Packit Service a1973e
			       PAGE_SIZE, vma->vm_page_prot);
Packit Service a1973e
#endif
Packit Service a1973e
}
Packit Service a1973e
Packit Service a1973e
static int vperfctr_release(struct inode *inode, struct file *filp)
Packit Service a1973e
{
Packit Service a1973e
	struct vperfctr *perfctr = filp->private_data;
Packit Service a1973e
	filp->private_data = NULL;
Packit Service a1973e
	if (perfctr)
Packit Service a1973e
		put_vperfctr(perfctr);
Packit Service a1973e
	return 0;
Packit Service a1973e
}
Packit Service a1973e
Packit Service a1973e
static long vperfctr_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
Packit Service a1973e
{
Packit Service a1973e
	struct vperfctr *perfctr;
Packit Service a1973e
	struct task_struct *tsk;
Packit Service a1973e
	int ret;
Packit Service a1973e
Packit Service a1973e
	switch (cmd) {
Packit Service a1973e
	case PERFCTR_ABI:
Packit Service a1973e
		return sys_perfctr_abi((unsigned int*)arg);
Packit Service a1973e
	case PERFCTR_INFO:
Packit Service a1973e
		return sys_perfctr_info((struct perfctr_struct_buf*)arg);
Packit Service a1973e
	case PERFCTR_CPUS:
Packit Service a1973e
		return sys_perfctr_cpus((struct perfctr_cpu_mask*)arg);
Packit Service a1973e
	case PERFCTR_CPUS_FORBIDDEN:
Packit Service a1973e
		return sys_perfctr_cpus_forbidden((struct perfctr_cpu_mask*)arg);
Packit Service a1973e
	}
Packit Service a1973e
	perfctr = filp->private_data;
Packit Service a1973e
	if (!perfctr)
Packit Service a1973e
		return -EINVAL;
Packit Service a1973e
	tsk = current;
Packit Service a1973e
	if (perfctr != current->thread.perfctr) {
Packit Service a1973e
		/* this synchronises with vperfctr_unlink() and itself */
Packit Service a1973e
		spin_lock(&perfctr->owner_lock);
Packit Service a1973e
		tsk = perfctr->owner;
Packit Service a1973e
		if (tsk)
Packit Service a1973e
			get_task_struct(tsk);
Packit Service a1973e
		spin_unlock(&perfctr->owner_lock);
Packit Service a1973e
		if (tsk) {
Packit Service a1973e
			ret = ptrace_check_attach(tsk, 0);
Packit Service a1973e
			if (ret < 0)
Packit Service a1973e
				goto out;
Packit Service a1973e
		}
Packit Service a1973e
	}
Packit Service a1973e
	switch (cmd) {
Packit Service a1973e
	case VPERFCTR_CONTROL:
Packit Service a1973e
		ret = sys_vperfctr_control(perfctr, (struct perfctr_struct_buf*)arg, tsk);
Packit Service a1973e
		break;
Packit Service a1973e
	case VPERFCTR_UNLINK:
Packit Service a1973e
		ret = sys_vperfctr_unlink(perfctr, tsk);
Packit Service a1973e
		break;
Packit Service a1973e
	case VPERFCTR_READ_SUM:
Packit Service a1973e
		ret = sys_vperfctr_read_sum(perfctr, (struct perfctr_struct_buf*)arg, tsk);
Packit Service a1973e
		break;
Packit Service a1973e
	case VPERFCTR_IRESUME:
Packit Service a1973e
		ret = sys_vperfctr_iresume(perfctr, tsk);
Packit Service a1973e
		break;
Packit Service a1973e
	case VPERFCTR_READ_CONTROL:
Packit Service a1973e
		ret = sys_vperfctr_read_control(perfctr, (struct perfctr_struct_buf*)arg, tsk);
Packit Service a1973e
		break;
Packit Service a1973e
	default:
Packit Service a1973e
		ret = -EINVAL;
Packit Service a1973e
	}
Packit Service a1973e
 out:
Packit Service a1973e
	if (tsk && tsk != current)
Packit Service a1973e
		put_task_struct(tsk);
Packit Service a1973e
	return ret;
Packit Service a1973e
}
Packit Service a1973e
Packit Service a1973e
#if !HAVE_UNLOCKED_IOCTL
Packit Service a1973e
static int vperfctr_ioctl_oldstyle(struct inode *inode, struct file *filp,
Packit Service a1973e
				   unsigned int cmd, unsigned long arg)
Packit Service a1973e
{
Packit Service a1973e
	return vperfctr_ioctl(filp, cmd, arg);
Packit Service a1973e
}
Packit Service a1973e
#endif
Packit Service a1973e
Packit Service a1973e
static
Packit Service a1973e
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
Packit Service a1973e
const
Packit Service a1973e
#endif
Packit Service a1973e
struct file_operations vperfctr_file_ops = {
Packit Service a1973e
	.owner = THIS_MODULE,
Packit Service a1973e
	.mmap = vperfctr_mmap,
Packit Service a1973e
	.release = vperfctr_release,
Packit Service a1973e
	/* 2.6.11-rc2 introduced HAVE_UNLOCKED_IOCTL and HAVE_COMPAT_IOCTL */
Packit Service a1973e
#if HAVE_UNLOCKED_IOCTL
Packit Service a1973e
	.unlocked_ioctl = vperfctr_ioctl,
Packit Service a1973e
#else
Packit Service a1973e
	.ioctl = vperfctr_ioctl_oldstyle,
Packit Service a1973e
#endif
Packit Service a1973e
#if defined(CONFIG_IA32_EMULATION) && HAVE_COMPAT_IOCTL
Packit Service a1973e
	.compat_ioctl = vperfctr_ioctl,
Packit Service a1973e
#endif
Packit Service a1973e
};
Packit Service a1973e
Packit Service a1973e
/****************************************************************
Packit Service a1973e
 *								*
Packit Service a1973e
 * File system for virtual perfctrs. Based on pipefs.		*
Packit Service a1973e
 *								*
Packit Service a1973e
 ****************************************************************/
Packit Service a1973e
Packit Service a1973e
#define VPERFCTRFS_MAGIC (('V'<<24)|('P'<<16)|('M'<<8)|('C'))
Packit Service a1973e
Packit Service a1973e
#include <linux/mount.h>
Packit Service a1973e
Packit Service a1973e
/* 2.6 kernels prior to 2.6.11-rc1 don't EXPORT_SYMBOL() get_sb_pseudo().
Packit Service a1973e
   This is a verbatim copy, only renamed. */
Packit Service a1973e
#if defined(MODULE) && LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11)
Packit Service a1973e
static
Packit Service a1973e
struct super_block *
Packit Service a1973e
perfctr_get_sb_pseudo(struct file_system_type *fs_type, char *name,
Packit Service a1973e
	struct super_operations *ops, unsigned long magic)
Packit Service a1973e
{
Packit Service a1973e
	struct super_block *s = sget(fs_type, NULL, set_anon_super, NULL);
Packit Service a1973e
	static struct super_operations default_ops = {.statfs = simple_statfs};
Packit Service a1973e
	struct dentry *dentry;
Packit Service a1973e
	struct inode *root;
Packit Service a1973e
	struct qstr d_name = {.name = name, .len = strlen(name)};
Packit Service a1973e
Packit Service a1973e
	if (IS_ERR(s))
Packit Service a1973e
		return s;
Packit Service a1973e
Packit Service a1973e
	s->s_flags = MS_NOUSER;
Packit Service a1973e
	s->s_maxbytes = ~0ULL;
Packit Service a1973e
	s->s_blocksize = 1024;
Packit Service a1973e
	s->s_blocksize_bits = 10;
Packit Service a1973e
	s->s_magic = magic;
Packit Service a1973e
	s->s_op = ops ? ops : &default_ops;
Packit Service a1973e
	root = new_inode(s);
Packit Service a1973e
	if (!root)
Packit Service a1973e
		goto Enomem;
Packit Service a1973e
	root->i_mode = S_IFDIR | S_IRUSR | S_IWUSR;
Packit Service a1973e
	root->i_uid = root->i_gid = 0;
Packit Service a1973e
	root->i_atime = root->i_mtime = root->i_ctime = CURRENT_TIME;
Packit Service a1973e
	dentry = d_alloc(NULL, &d_name);
Packit Service a1973e
	if (!dentry) {
Packit Service a1973e
		iput(root);
Packit Service a1973e
		goto Enomem;
Packit Service a1973e
	}
Packit Service a1973e
	dentry->d_sb = s;
Packit Service a1973e
	dentry->d_parent = dentry;
Packit Service a1973e
	d_instantiate(dentry, root);
Packit Service a1973e
	s->s_root = dentry;
Packit Service a1973e
	s->s_flags |= MS_ACTIVE;
Packit Service a1973e
	return s;
Packit Service a1973e
Packit Service a1973e
Enomem:
Packit Service a1973e
	up_write(&s->s_umount);
Packit Service a1973e
	deactivate_super(s);
Packit Service a1973e
	return ERR_PTR(-ENOMEM);
Packit Service a1973e
}
Packit Service a1973e
#undef get_sb_pseudo
Packit Service a1973e
#define get_sb_pseudo perfctr_get_sb_pseudo
Packit Service a1973e
#endif	/* MODULE && VERSION < 2.6.11 */
Packit Service a1973e
Packit Service a1973e
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18)
Packit Service a1973e
static int
Packit Service a1973e
vperfctrfs_get_sb(struct file_system_type *fs_type,
Packit Service a1973e
		  int flags, const char *dev_name, void *data,
Packit Service a1973e
		  struct vfsmount *mnt)
Packit Service a1973e
{
Packit Service a1973e
	return get_sb_pseudo(fs_type, "vperfctr:", NULL, VPERFCTRFS_MAGIC, mnt);
Packit Service a1973e
}
Packit Service a1973e
#else
Packit Service a1973e
static struct super_block *
Packit Service a1973e
vperfctrfs_get_sb(struct file_system_type *fs_type,
Packit Service a1973e
		  int flags, const char *dev_name, void *data)
Packit Service a1973e
{
Packit Service a1973e
	return get_sb_pseudo(fs_type, "vperfctr:", NULL, VPERFCTRFS_MAGIC);
Packit Service a1973e
}
Packit Service a1973e
#endif
Packit Service a1973e
Packit Service a1973e
static struct file_system_type vperfctrfs_type = {
Packit Service a1973e
	.name		= "vperfctrfs",
Packit Service a1973e
	.get_sb		= vperfctrfs_get_sb,
Packit Service a1973e
	.kill_sb	= kill_anon_super,
Packit Service a1973e
};
Packit Service a1973e
Packit Service a1973e
/* XXX: check if s/vperfctr_mnt/vperfctrfs_type.kern_mnt/ would work */
Packit Service a1973e
static struct vfsmount *vperfctr_mnt;
Packit Service a1973e
Packit Service a1973e
static int __init vperfctrfs_init(void)
Packit Service a1973e
{
Packit Service a1973e
	int err = register_filesystem(&vperfctrfs_type);
Packit Service a1973e
	if (!err) {
Packit Service a1973e
		vperfctr_mnt = kern_mount(&vperfctrfs_type);
Packit Service a1973e
		if (!IS_ERR(vperfctr_mnt))
Packit Service a1973e
			return 0;
Packit Service a1973e
		err = PTR_ERR(vperfctr_mnt);
Packit Service a1973e
		unregister_filesystem(&vperfctrfs_type);
Packit Service a1973e
	}
Packit Service a1973e
	return err;
Packit Service a1973e
}
Packit Service a1973e
Packit Service a1973e
static void __exit vperfctrfs_exit(void)
Packit Service a1973e
{
Packit Service a1973e
	unregister_filesystem(&vperfctrfs_type);
Packit Service a1973e
	mntput(vperfctr_mnt);
Packit Service a1973e
}
Packit Service a1973e
Packit Service a1973e
static struct inode *vperfctr_get_inode(void)
Packit Service a1973e
{
Packit Service a1973e
	struct inode *inode;
Packit Service a1973e
Packit Service a1973e
	inode = new_inode(vperfctr_mnt->mnt_sb);
Packit Service a1973e
	if (!inode)
Packit Service a1973e
		return NULL;
Packit Service a1973e
	inode->i_fop = &vperfctr_file_ops;
Packit Service a1973e
	inode->i_state = I_DIRTY;
Packit Service a1973e
	inode->i_mode = S_IFCHR | S_IRUSR | S_IWUSR;
Packit Service a1973e
	inode->i_uid = current_fsuid();
Packit Service a1973e
	inode->i_gid = current_fsgid();
Packit Service a1973e
	inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
Packit Service a1973e
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) && !defined(DONT_HAVE_i_blksize)
Packit Service a1973e
	inode->i_blksize = 0;
Packit Service a1973e
#endif
Packit Service a1973e
	return inode;
Packit Service a1973e
}
Packit Service a1973e
Packit Service a1973e
static int vperfctrfs_delete_dentry(struct dentry *dentry)
Packit Service a1973e
{
Packit Service a1973e
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
Packit Service a1973e
	/*
Packit Service a1973e
	 * At creation time, we pretended this dentry was hashed
Packit Service a1973e
	 * (by clearing DCACHE_UNHASHED bit in d_flags)
Packit Service a1973e
	 * At delete time, we restore the truth : not hashed.
Packit Service a1973e
	 * (so that dput() can proceed correctly)
Packit Service a1973e
	 */
Packit Service a1973e
	dentry->d_flags |= DCACHE_UNHASHED;
Packit Service a1973e
	return 0;
Packit Service a1973e
#else
Packit Service a1973e
	return 1;
Packit Service a1973e
#endif
Packit Service a1973e
}
Packit Service a1973e
Packit Service a1973e
static
Packit Service a1973e
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30)
Packit Service a1973e
const
Packit Service a1973e
#endif
Packit Service a1973e
struct dentry_operations vperfctrfs_dentry_operations = {
Packit Service a1973e
	.d_delete	= vperfctrfs_delete_dentry,
Packit Service a1973e
};
Packit Service a1973e
Packit Service a1973e
static struct dentry *vperfctr_d_alloc_root(struct inode *inode)
Packit Service a1973e
{
Packit Service a1973e
	struct qstr this;
Packit Service a1973e
	char name[32];
Packit Service a1973e
	struct dentry *dentry;
Packit Service a1973e
Packit Service a1973e
	sprintf(name, "[%lu]", inode->i_ino);
Packit Service a1973e
	this.name = name;
Packit Service a1973e
	this.len = strlen(name);
Packit Service a1973e
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
Packit Service a1973e
	this.hash = 0;
Packit Service a1973e
#else
Packit Service a1973e
	this.hash = inode->i_ino; /* will go */
Packit Service a1973e
#endif
Packit Service a1973e
	dentry = d_alloc(vperfctr_mnt->mnt_sb->s_root, &this;;
Packit Service a1973e
	if (dentry) {
Packit Service a1973e
		dentry->d_op = &vperfctrfs_dentry_operations;
Packit Service a1973e
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
Packit Service a1973e
		/*
Packit Service a1973e
		 * We dont want to publish this dentry into global dentry hash table.
Packit Service a1973e
		 * We pretend dentry is already hashed, by unsetting DCACHE_UNHASHED
Packit Service a1973e
		 * This permits a working /proc/$pid/fd/XXX on vperfctrs
Packit Service a1973e
		 */
Packit Service a1973e
		dentry->d_flags &= ~DCACHE_UNHASHED;
Packit Service a1973e
		d_instantiate(dentry, inode);
Packit Service a1973e
#else
Packit Service a1973e
		d_add(dentry, inode);
Packit Service a1973e
#endif
Packit Service a1973e
	}
Packit Service a1973e
	return dentry;
Packit Service a1973e
}
Packit Service a1973e
Packit Service a1973e
static struct file *vperfctr_get_filp(void)
Packit Service a1973e
{
Packit Service a1973e
	struct file *filp;
Packit Service a1973e
	struct inode *inode;
Packit Service a1973e
	struct dentry *dentry;
Packit Service a1973e
Packit Service a1973e
	inode = vperfctr_get_inode();
Packit Service a1973e
	if (!inode)
Packit Service a1973e
		goto out;
Packit Service a1973e
	dentry = vperfctr_d_alloc_root(inode);
Packit Service a1973e
	if (!dentry)
Packit Service a1973e
		goto out_inode;
Packit Service a1973e
	/*
Packit Service a1973e
	 * Create the filp _after_ the inode and dentry, to avoid
Packit Service a1973e
	 * needing access to put_filp(), which is no longer exported
Packit Service a1973e
	 * starting with kernel 2.6.10-rc1. fput() is available but
Packit Service a1973e
	 * doesn't work on incomplete files. We now need access to
Packit Service a1973e
	 * dput() instead, but that's Ok.
Packit Service a1973e
	 */
Packit Service a1973e
	filp = get_empty_filp();
Packit Service a1973e
	if (!filp)
Packit Service a1973e
		goto out_dentry;
Packit Service a1973e
Packit Service a1973e
	filp_vfsmnt(filp) = mntget(vperfctr_mnt);
Packit Service a1973e
	filp_dentry(filp) = dentry;
Packit Service a1973e
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,2)
Packit Service a1973e
	filp->f_mapping = dentry->d_inode->i_mapping;
Packit Service a1973e
#endif
Packit Service a1973e
Packit Service a1973e
	filp->f_pos = 0;
Packit Service a1973e
	filp->f_flags = 0;
Packit Service a1973e
	filp->f_op = fops_get(&vperfctr_file_ops); /* fops_get() for MODULE */
Packit Service a1973e
	filp->f_mode = FMODE_READ;
Packit Service a1973e
	filp->f_version = 0;
Packit Service a1973e
Packit Service a1973e
	return filp;
Packit Service a1973e
Packit Service a1973e
 out_dentry:
Packit Service a1973e
	dput(dentry);
Packit Service a1973e
	goto out; /* dput() also does iput() */
Packit Service a1973e
 out_inode:
Packit Service a1973e
	iput(inode);
Packit Service a1973e
 out:
Packit Service a1973e
	return NULL;
Packit Service a1973e
}
Packit Service a1973e
Packit Service a1973e
/* tid is the actual task/thread id (née pid, stored as ->pid),
Packit Service a1973e
   pid/tgid is that 2.6 thread group id crap (stored as ->tgid) */
Packit Service a1973e
int vperfctr_attach(int tid, int creat)
Packit Service a1973e
{
Packit Service a1973e
	struct file *filp;
Packit Service a1973e
	struct task_struct *tsk;
Packit Service a1973e
	struct vperfctr *perfctr;
Packit Service a1973e
	int err;
Packit Service a1973e
	int fd;
Packit Service a1973e
Packit Service a1973e
	filp = vperfctr_get_filp();
Packit Service a1973e
	if (!filp)
Packit Service a1973e
		return -ENOMEM;
Packit Service a1973e
	err = fd = get_unused_fd();
Packit Service a1973e
	if (err < 0)
Packit Service a1973e
		goto err_filp;
Packit Service a1973e
	perfctr = NULL;
Packit Service a1973e
	if (creat) {
Packit Service a1973e
		perfctr = get_empty_vperfctr(); /* may sleep */
Packit Service a1973e
		if (IS_ERR(perfctr)) {
Packit Service a1973e
			err = PTR_ERR(perfctr);
Packit Service a1973e
			goto err_fd;
Packit Service a1973e
		}
Packit Service a1973e
	}
Packit Service a1973e
	tsk = current;
Packit Service a1973e
	if (tid != 0 && tid != task_pid_vnr(tsk)) { /* remote? */
Packit Service a1973e
		vperfctr_lock_find_task_by_vpid();
Packit Service a1973e
		tsk = find_task_by_vpid(tid);
Packit Service a1973e
		if (tsk)
Packit Service a1973e
			get_task_struct(tsk);
Packit Service a1973e
		vperfctr_unlock_find_task_by_vpid();
Packit Service a1973e
		err = -ESRCH;
Packit Service a1973e
		if (!tsk)
Packit Service a1973e
			goto err_perfctr;
Packit Service a1973e
		err = ptrace_check_attach(tsk, 0);
Packit Service a1973e
		if (err < 0)
Packit Service a1973e
			goto err_tsk;
Packit Service a1973e
	}
Packit Service a1973e
	if (creat) {
Packit Service a1973e
		/* check+install must be atomic to prevent remote-control races */
Packit Service a1973e
		vperfctr_task_lock(tsk);
Packit Service a1973e
		if (!tsk->thread.perfctr) {
Packit Service a1973e
			perfctr->owner = tsk;
Packit Service a1973e
			tsk->thread.perfctr = perfctr;
Packit Service a1973e
			err = 0;
Packit Service a1973e
		} else
Packit Service a1973e
			err = -EEXIST;
Packit Service a1973e
		vperfctr_task_unlock(tsk);
Packit Service a1973e
		if (err)
Packit Service a1973e
			goto err_tsk;
Packit Service a1973e
	} else {
Packit Service a1973e
		perfctr = tsk->thread.perfctr;
Packit Service a1973e
		/* PERFCTR_ABI and PERFCTR_INFO don't need the perfctr.
Packit Service a1973e
		   Hence no non-NULL check here. */
Packit Service a1973e
	}
Packit Service a1973e
	filp->private_data = perfctr;
Packit Service a1973e
	if (perfctr)
Packit Service a1973e
		atomic_inc(&perfctr->count);
Packit Service a1973e
	if (tsk != current)
Packit Service a1973e
		put_task_struct(tsk);
Packit Service a1973e
	fd_install(fd, filp);
Packit Service a1973e
	return fd;
Packit Service a1973e
 err_tsk:
Packit Service a1973e
	if (tsk != current)
Packit Service a1973e
		put_task_struct(tsk);
Packit Service a1973e
 err_perfctr:
Packit Service a1973e
	if (perfctr)	/* can only occur if creat != 0 */
Packit Service a1973e
		put_vperfctr(perfctr);
Packit Service a1973e
 err_fd:
Packit Service a1973e
	put_unused_fd(fd);
Packit Service a1973e
 err_filp:
Packit Service a1973e
	fput(filp);
Packit Service a1973e
	return err;
Packit Service a1973e
}
Packit Service a1973e
Packit Service a1973e
/****************************************************************
Packit Service a1973e
 *								*
Packit Service a1973e
 * module_init/exit						*
Packit Service a1973e
 *								*
Packit Service a1973e
 ****************************************************************/
Packit Service a1973e
Packit Service a1973e
#ifdef MODULE
Packit Service a1973e
static struct vperfctr_stub off;
Packit Service a1973e
Packit Service a1973e
static void vperfctr_stub_init(void)
Packit Service a1973e
{
Packit Service a1973e
	off = vperfctr_stub;
Packit Service a1973e
	vperfctr_stub.owner = THIS_MODULE;
Packit Service a1973e
	vperfctr_stub.exit = __vperfctr_exit;
Packit Service a1973e
	vperfctr_stub.flush = __vperfctr_flush;
Packit Service a1973e
	vperfctr_stub.suspend = __vperfctr_suspend;
Packit Service a1973e
	vperfctr_stub.resume = __vperfctr_resume;
Packit Service a1973e
	vperfctr_stub.sample = __vperfctr_sample;
Packit Service a1973e
#ifdef CONFIG_PERFCTR_CPUS_FORBIDDEN_MASK
Packit Service a1973e
	vperfctr_stub.set_cpus_allowed = __vperfctr_set_cpus_allowed;
Packit Service a1973e
#endif
Packit Service a1973e
}
Packit Service a1973e
Packit Service a1973e
static void vperfctr_stub_exit(void)
Packit Service a1973e
{
Packit Service a1973e
	vperfctr_stub = off;
Packit Service a1973e
}
Packit Service a1973e
#else
Packit Service a1973e
static inline void vperfctr_stub_init(void) { }
Packit Service a1973e
static inline void vperfctr_stub_exit(void) { }
Packit Service a1973e
#endif	/* MODULE */
Packit Service a1973e
Packit Service a1973e
int __init vperfctr_init(void)
Packit Service a1973e
{
Packit Service a1973e
	int err = vperfctrfs_init();
Packit Service a1973e
	if (err)
Packit Service a1973e
		return err;
Packit Service a1973e
	vperfctr_stub_init();
Packit Service a1973e
	return 0;
Packit Service a1973e
}
Packit Service a1973e
Packit Service a1973e
void __exit vperfctr_exit(void)
Packit Service a1973e
{
Packit Service a1973e
	vperfctrfs_exit();
Packit Service a1973e
	vperfctr_stub_exit();
Packit Service a1973e
}