#include <linux/config.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/notifier.h>
#include <linux/kmemprof.h>

MODULE_LICENSE("GPL");

#define DECLARE_KMEMPROF_FILTER(name)	\
static int filter_##name = -1;	\
MODULE_PARM(filter_##name, "i")

#define KMEMPROF_FILTER_THROUGH(name, value)	\
((filter_##name == -1) || filter_##name == (value))

#define KMEMPROF_FILTER(name) filter_##name

DECLARE_KMEMPROF_FILTER(cpu);
DECLARE_KMEMPROF_FILTER(interrupt);
DECLARE_KMEMPROF_FILTER(pid);
DECLARE_KMEMPROF_FILTER(pgrp);

static int kmemprof_filter (struct notifier_block * self, unsigned long val,
			void * arg)
{
	struct kmemprof_event * event = (struct kmemprof_event *) arg;
	int cpu = smp_processor_id();
	int is_interrupt = in_interrupt();
	pid_t pid = current->pid;
	pid_t pgrp = current->pgrp;
	int ret = NOTIFY_OK;

	if (!KMEMPROF_FILTER_THROUGH(cpu, cpu) ||
		!KMEMPROF_FILTER_THROUGH(interrupt, is_interrupt) ||
		!KMEMPROF_FILTER_THROUGH(pid, pid) ||
		!KMEMPROF_FILTER_THROUGH(pgrp, pgrp)) {

		ret |= NOTIFY_STOP_MASK;
	}

	return ret;
}

static struct notifier_block filter_nb = {
	.notifier_call = &kmemprof_filter,
	.priority = 10
};

static int __init mymodule_init(void)
{
	printk ("cpu: %d, interrupt: %d, pid: %d, pgrp: %d\n",
			KMEMPROF_FILTER(cpu),
			KMEMPROF_FILTER(interrupt),
			KMEMPROF_FILTER(pid),
			KMEMPROF_FILTER(pgrp));

	kmemprof_notifier_chain_register(&filter_nb);
	return 0;
}

static void __exit mymodule_exit(void)
{
	kmemprof_notifier_chain_unregister(&filter_nb);

	return;
}

module_init(mymodule_init);
module_exit(mymodule_exit);

