diff options
| author | John Levon <levon@movementarian.org> | 2003-05-03 04:42:55 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@home.transmeta.com> | 2003-05-03 04:42:55 -0700 |
| commit | 5422b4674d7cae2c4d86bc849b2b5d7da87b8085 (patch) | |
| tree | f1bbc4451e840736239cfea0f41cb20edd699ec7 | |
| parent | 8eac54924ac0f97ca1bf23e610157c3e72ad1846 (diff) | |
[PATCH] OProfile update
Schedule work away on an unmap, instead of calling it directly. Should result
in less lost samples, and it fixes a lock ordering problem buffer_sem <-> mmap_sem
| -rw-r--r-- | drivers/oprofile/buffer_sync.c | 29 |
1 files changed, 26 insertions, 3 deletions
diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c index b2023dd9ddad..a566ba9f6e36 100644 --- a/drivers/oprofile/buffer_sync.c +++ b/drivers/oprofile/buffer_sync.c @@ -58,8 +58,8 @@ static int exit_task_notify(struct notifier_block * self, unsigned long val, voi * must concern ourselves with. First, when a task is about to * exit (exit_mmap()), we should process the buffer to deal with * any samples in the CPU buffer, before we lose the ->mmap information - * we need. Second, a task may unmap (part of) an executable mmap, - * so we want to process samples before that happens too + * we need. It is vital to get this case correct, otherwise we can + * end up trying to access a freed task_struct. */ static int mm_notify(struct notifier_block * self, unsigned long val, void * data) { @@ -67,6 +67,29 @@ static int mm_notify(struct notifier_block * self, unsigned long val, void * dat return 0; } + +/* Second, a task may unmap (part of) an executable mmap, + * so we want to process samples before that happens too. This is merely + * a QOI issue not a correctness one. + */ +static int munmap_notify(struct notifier_block * self, unsigned long val, void * data) +{ + /* Note that we cannot sync the buffers directly, because we might end up + * taking the the mmap_sem that we hold now inside of event_buffer_read() + * on a page fault, whilst holding buffer_sem - deadlock. + * + * This would mean a threaded reader of the event buffer, but we should + * prevent it anyway. + * + * Delaying the work in a context that doesn't hold the mmap_sem means + * that we won't lose samples from other mappings that current() may + * have. Note that either way, we lose any pending samples for what is + * being unmapped. + */ + schedule_work(&sync_wq); + return 0; +} + /* We need to be told about new modules so we don't attribute to a previously * loaded module, or drop the samples on the floor. @@ -92,7 +115,7 @@ static struct notifier_block exit_task_nb = { }; static struct notifier_block exec_unmap_nb = { - .notifier_call = mm_notify, + .notifier_call = munmap_notify, }; static struct notifier_block exit_mmap_nb = { |
