summaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/Makefile5
-rw-r--r--kernel/exit.c10
-rw-r--r--kernel/profile.c91
3 files changed, 101 insertions, 5 deletions
diff --git a/kernel/Makefile b/kernel/Makefile
index b3fce6d3ac9c..8e18771791de 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -3,9 +3,10 @@
#
export-objs = signal.o sys.o kmod.o workqueue.o ksyms.o pm.o exec_domain.o \
- printk.o platform.o suspend.o dma.o module.o cpufreq.o
+ printk.o platform.o suspend.o dma.o module.o cpufreq.o \
+ profile.o
-obj-y = sched.o fork.o exec_domain.o panic.o printk.o \
+obj-y = sched.o fork.o exec_domain.o panic.o printk.o profile.o \
module.o exit.o itimer.o time.o softirq.o resource.o \
sysctl.o capability.o ptrace.o timer.o user.o \
signal.o sys.o kmod.o workqueue.o futex.o platform.o pid.o
diff --git a/kernel/exit.c b/kernel/exit.c
index 6ed07def4c62..c2b0f6eeff0f 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -19,6 +19,7 @@
#include <linux/file.h>
#include <linux/binfmts.h>
#include <linux/ptrace.h>
+#include <linux/profile.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
@@ -59,11 +60,12 @@ void release_task(struct task_struct * p)
{
struct dentry *proc_dentry;
task_t *leader;
-
- if (p->state < TASK_ZOMBIE)
- BUG();
+
+ BUG_ON(p->state < TASK_ZOMBIE);
+
if (p != current)
wait_task_inactive(p);
+
atomic_dec(&p->user->processes);
security_ops->task_free_security(p);
free_uid(p->user);
@@ -635,6 +637,8 @@ NORET_TYPE void do_exit(long code)
current->comm, current->pid,
preempt_count());
+ profile_exit_task(tsk);
+
fake_volatile:
acct_process(code);
__exit_mm(tsk);
diff --git a/kernel/profile.c b/kernel/profile.c
new file mode 100644
index 000000000000..7ebffe971ca8
--- /dev/null
+++ b/kernel/profile.c
@@ -0,0 +1,91 @@
+/*
+ * linux/kernel/profile.c
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/profile.h>
+#include <linux/bootmem.h>
+#include <linux/notifier.h>
+#include <linux/mm.h>
+
+/* Profile event notifications */
+
+#ifdef CONFIG_PROFILING
+
+static DECLARE_RWSEM(profile_rwsem);
+static struct notifier_block * exit_task_notifier;
+static struct notifier_block * exit_mmap_notifier;
+static struct notifier_block * exec_unmap_notifier;
+
+void profile_exit_task(struct task_struct * task)
+{
+ down_read(&profile_rwsem);
+ notifier_call_chain(&exit_task_notifier, 0, task);
+ up_read(&profile_rwsem);
+}
+
+void profile_exit_mmap(struct mm_struct * mm)
+{
+ down_read(&profile_rwsem);
+ notifier_call_chain(&exit_mmap_notifier, 0, mm);
+ up_read(&profile_rwsem);
+}
+
+void profile_exec_unmap(struct mm_struct * mm)
+{
+ down_read(&profile_rwsem);
+ notifier_call_chain(&exec_unmap_notifier, 0, mm);
+ up_read(&profile_rwsem);
+}
+
+int profile_event_register(enum profile_type type, struct notifier_block * n)
+{
+ int err = -EINVAL;
+
+ down_write(&profile_rwsem);
+
+ switch (type) {
+ case EXIT_TASK:
+ err = notifier_chain_register(&exit_task_notifier, n);
+ break;
+ case EXIT_MMAP:
+ err = notifier_chain_register(&exit_mmap_notifier, n);
+ break;
+ case EXEC_UNMAP:
+ err = notifier_chain_register(&exec_unmap_notifier, n);
+ break;
+ }
+
+ up_write(&profile_rwsem);
+
+ return err;
+}
+
+
+int profile_event_unregister(enum profile_type type, struct notifier_block * n)
+{
+ int err = -EINVAL;
+
+ down_write(&profile_rwsem);
+
+ switch (type) {
+ case EXIT_TASK:
+ err = notifier_chain_unregister(&exit_task_notifier, n);
+ break;
+ case EXIT_MMAP:
+ err = notifier_chain_unregister(&exit_mmap_notifier, n);
+ break;
+ case EXEC_UNMAP:
+ err = notifier_chain_unregister(&exec_unmap_notifier, n);
+ break;
+ }
+
+ up_write(&profile_rwsem);
+ return err;
+}
+
+#endif /* CONFIG_PROFILING */
+
+EXPORT_SYMBOL_GPL(profile_event_register);
+EXPORT_SYMBOL_GPL(profile_event_unregister);