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

Packit 577717
/* $Id: virtual_stub.c,v 1.26.2.9 2009/01/23 17:21:20 mikpe Exp $
Packit 577717
 * Kernel stub used to support virtual perfctrs when the
Packit 577717
 * perfctr driver is built as a module.
Packit 577717
 *
Packit 577717
 * Copyright (C) 2000-2009  Mikael Pettersson
Packit 577717
 */
Packit 577717
#include <linux/version.h>
Packit 577717
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
Packit 577717
#include <linux/config.h>
Packit 577717
#endif
Packit 577717
#include <linux/module.h>
Packit 577717
#include <linux/kernel.h>
Packit 577717
#include <linux/sched.h>
Packit 577717
#include <linux/perfctr.h>
Packit 577717
#include "compat.h"
Packit 577717
Packit 577717
static void bug_void_perfctr(struct vperfctr *perfctr)
Packit 577717
{
Packit 577717
	current->thread.perfctr = NULL;
Packit 577717
	BUG();
Packit 577717
}
Packit 577717
Packit 577717
#ifdef CONFIG_PERFCTR_CPUS_FORBIDDEN_MASK
Packit 577717
static void bug_set_cpus_allowed(struct task_struct *owner, struct vperfctr *perfctr, cpumask_t new_mask)
Packit 577717
{
Packit 577717
	owner->thread.perfctr = NULL;
Packit 577717
	BUG();
Packit 577717
}
Packit 577717
#endif
Packit 577717
Packit 577717
struct vperfctr_stub vperfctr_stub = {
Packit 577717
	.exit = bug_void_perfctr,
Packit 577717
	.flush = bug_void_perfctr,
Packit 577717
	.suspend = bug_void_perfctr,
Packit 577717
	.resume = bug_void_perfctr,
Packit 577717
	.sample = bug_void_perfctr,
Packit 577717
#ifdef CONFIG_PERFCTR_CPUS_FORBIDDEN_MASK
Packit 577717
	.set_cpus_allowed = bug_set_cpus_allowed,
Packit 577717
#endif
Packit 577717
};
Packit 577717
Packit 577717
/*
Packit 577717
 * exit_thread() calls __vperfctr_exit() via vperfctr_stub.exit().
Packit 577717
 * If the process' reference was the last reference to this
Packit 577717
 * vperfctr object, and this was the last live vperfctr object,
Packit 577717
 * then the perfctr module's use count will drop to zero.
Packit 577717
 * This is Ok, except for the fact that code is still running
Packit 577717
 * in the module (pending returns back to exit_thread()). This
Packit 577717
 * could race with rmmod in a preemptive UP kernel, leading to
Packit 577717
 * code running in freed memory. The race also exists in SMP
Packit 577717
 * kernels, but the time window is extremely small.
Packit 577717
 *
Packit 577717
 * Since exit() isn't performance-critical, we wrap the call to
Packit 577717
 * vperfctr_stub.exit() with code to increment the module's use
Packit 577717
 * count before the call, and decrement it again afterwards. Thus,
Packit 577717
 * the final drop to zero occurs here and not in the module itself.
Packit 577717
 * (All other code paths that drop the use count do so via a file
Packit 577717
 * object, and VFS also refcounts the module.)
Packit 577717
 */
Packit 577717
void _vperfctr_exit(struct vperfctr *perfctr)
Packit 577717
{
Packit 577717
	__module_get(vperfctr_stub.owner);
Packit 577717
	vperfctr_stub.exit(perfctr);
Packit 577717
	module_put(vperfctr_stub.owner);
Packit 577717
}
Packit 577717
Packit 577717
/* __vperfctr_flush() is a conditional __vperfctr_exit(),
Packit 577717
 * so it needs the same protection.
Packit 577717
 */
Packit 577717
void _vperfctr_flush(struct vperfctr *perfctr)
Packit 577717
{
Packit 577717
	__module_get(vperfctr_stub.owner);
Packit 577717
	vperfctr_stub.flush(perfctr);
Packit 577717
	module_put(vperfctr_stub.owner);
Packit 577717
}
Packit 577717
Packit 577717
EXPORT_SYMBOL(vperfctr_stub);
Packit 577717
EXPORT_SYMBOL___put_task_struct;
Packit 577717
Packit 577717
#if !defined(CONFIG_UTRACE)
Packit 577717
#include <linux/mm.h>
Packit 577717
#include <linux/ptrace.h>
Packit 577717
EXPORT_SYMBOL(ptrace_check_attach);
Packit 577717
#endif