Commit 19bb2ab9 authored by John Levon's avatar John Levon Committed by Linus Torvalds

[PATCH] oprofile - hooks

This implements the simple hooks we need to catch unmappings, and to
make sure no stale task_struct*'s are ever used by the main oprofile
core mechanism.  If disabled, it compiles to nothing.
parent dec3735e
...@@ -1048,6 +1048,11 @@ CONFIG_DEBUG_OBSOLETE ...@@ -1048,6 +1048,11 @@ CONFIG_DEBUG_OBSOLETE
Say Y here if you want to reduce the chances of the tree compiling, Say Y here if you want to reduce the chances of the tree compiling,
and are prepared to dig into driver internals to fix compile errors. and are prepared to dig into driver internals to fix compile errors.
Profiling support
CONFIG_PROFILING
Say Y here to enable the extended profiling support mechanisms used
by profilers such as OProfile.
Software Suspend Software Suspend
CONFIG_SOFTWARE_SUSPEND CONFIG_SOFTWARE_SUSPEND
Enable the possibilty of suspendig machine. It doesn't need APM. Enable the possibilty of suspendig machine. It doesn't need APM.
......
...@@ -442,6 +442,13 @@ source drivers/usb/Config.in ...@@ -442,6 +442,13 @@ source drivers/usb/Config.in
source net/bluetooth/Config.in source net/bluetooth/Config.in
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
mainmenu_option next_comment
comment 'Profiling support'
bool 'Profiling support (EXPERIMENTAL)' CONFIG_PROFILING
endmenu
fi
mainmenu_option next_comment mainmenu_option next_comment
comment 'Kernel hacking' comment 'Kernel hacking'
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
......
#ifndef _LINUX_PROFILE_H
#define _LINUX_PROFILE_H
#ifdef __KERNEL__
#include <linux/kernel.h>
#include <linux/config.h>
#include <linux/init.h>
#include <asm/errno.h>
enum profile_type {
EXIT_TASK,
EXIT_MMAP,
EXEC_UNMAP
};
#ifdef CONFIG_PROFILING
struct notifier_block;
struct task_struct;
struct mm_struct;
/* task is in do_exit() */
void profile_exit_task(struct task_struct * task);
/* change of vma mappings */
void profile_exec_unmap(struct mm_struct * mm);
/* exit of all vmas for a task */
void profile_exit_mmap(struct mm_struct * mm);
int profile_event_register(enum profile_type, struct notifier_block * n);
int profile_event_unregister(enum profile_type, struct notifier_block * n);
#else
static inline int profile_event_register(enum profile_type t, struct notifier_block * n)
{
return -ENOSYS;
}
static inline int profile_event_unregister(enum profile_type t, struct notifier_block * n)
{
return -ENOSYS;
}
#define profile_exit_task(a) do { } while (0)
#define profile_exec_unmap(a) do { } while (0)
#define profile_exit_mmap(a) do { } while (0)
#endif /* CONFIG_PROFILING */
#endif /* __KERNEL__ */
#endif /* _LINUX_PROFILE_H */
...@@ -3,9 +3,10 @@ ...@@ -3,9 +3,10 @@
# #
export-objs = signal.o sys.o kmod.o workqueue.o ksyms.o pm.o exec_domain.o \ 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 \ module.o exit.o itimer.o time.o softirq.o resource.o \
sysctl.o capability.o ptrace.o timer.o user.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 signal.o sys.o kmod.o workqueue.o futex.o platform.o pid.o
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <linux/file.h> #include <linux/file.h>
#include <linux/binfmts.h> #include <linux/binfmts.h>
#include <linux/ptrace.h> #include <linux/ptrace.h>
#include <linux/profile.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/pgtable.h> #include <asm/pgtable.h>
...@@ -60,10 +61,11 @@ void release_task(struct task_struct * p) ...@@ -60,10 +61,11 @@ void release_task(struct task_struct * p)
struct dentry *proc_dentry; struct dentry *proc_dentry;
task_t *leader; task_t *leader;
if (p->state < TASK_ZOMBIE) BUG_ON(p->state < TASK_ZOMBIE);
BUG();
if (p != current) if (p != current)
wait_task_inactive(p); wait_task_inactive(p);
atomic_dec(&p->user->processes); atomic_dec(&p->user->processes);
security_ops->task_free_security(p); security_ops->task_free_security(p);
free_uid(p->user); free_uid(p->user);
...@@ -635,6 +637,8 @@ NORET_TYPE void do_exit(long code) ...@@ -635,6 +637,8 @@ NORET_TYPE void do_exit(long code)
current->comm, current->pid, current->comm, current->pid,
preempt_count()); preempt_count());
profile_exit_task(tsk);
fake_volatile: fake_volatile:
acct_process(code); acct_process(code);
__exit_mm(tsk); __exit_mm(tsk);
......
/*
* 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);
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/personality.h> #include <linux/personality.h>
#include <linux/security.h> #include <linux/security.h>
#include <linux/profile.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/pgalloc.h> #include <asm/pgalloc.h>
...@@ -1104,6 +1105,10 @@ int do_munmap(struct mm_struct *mm, unsigned long start, size_t len) ...@@ -1104,6 +1105,10 @@ int do_munmap(struct mm_struct *mm, unsigned long start, size_t len)
if (mpnt->vm_start >= end) if (mpnt->vm_start >= end)
return 0; return 0;
/* Something will probably happen, so notify. */
if (mpnt->vm_file && (mpnt->vm_flags & VM_EXEC))
profile_exec_unmap(mm);
/* /*
* If we need to split any vma, do it now to save pain later. * If we need to split any vma, do it now to save pain later.
*/ */
...@@ -1253,7 +1258,10 @@ void exit_mmap(struct mm_struct * mm) ...@@ -1253,7 +1258,10 @@ void exit_mmap(struct mm_struct * mm)
mmu_gather_t *tlb; mmu_gather_t *tlb;
struct vm_area_struct * mpnt; struct vm_area_struct * mpnt;
profile_exit_mmap(mm);
release_segments(mm); release_segments(mm);
spin_lock(&mm->page_table_lock); spin_lock(&mm->page_table_lock);
tlb = tlb_gather_mmu(mm, 1); tlb = tlb_gather_mmu(mm, 1);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment