Commit 84486c2e authored by John Levon's avatar John Levon Committed by Linus Torvalds

[PATCH] module load notification

This implements a simple notifier so oprofile can notice removed and
added modules properly
parent d7f405c0
......@@ -24,6 +24,7 @@
#include <linux/notifier.h>
#include <linux/dcookies.h>
#include <linux/profile.h>
#include <linux/module.h>
#include <linux/fs.h>
#include "oprofile_stats.h"
......@@ -67,6 +68,19 @@ static int mm_notify(struct notifier_block * self, unsigned long val, void * dat
}
static int module_load_notify(struct notifier_block * self, unsigned long val, void * data)
{
if (val != MODULE_STATE_COMING)
return 0;
sync_cpu_buffers();
down(&buffer_sem);
add_event_entry(ESCAPE_CODE);
add_event_entry(MODULE_LOADED_CODE);
up(&buffer_sem);
return 0;
}
static struct notifier_block exit_task_nb = {
.notifier_call = exit_task_notify,
};
......@@ -79,6 +93,10 @@ static struct notifier_block exit_mmap_nb = {
.notifier_call = mm_notify,
};
static struct notifier_block module_load_nb = {
.notifier_call = module_load_notify,
};
int sync_start(void)
{
......@@ -98,9 +116,14 @@ int sync_start(void)
err = profile_event_register(EXEC_UNMAP, &exec_unmap_nb);
if (err)
goto out3;
err = register_module_notifier(&module_load_nb);
if (err)
goto out4;
out:
return err;
out4:
profile_event_unregister(EXEC_UNMAP, &exec_unmap_nb);
out3:
profile_event_unregister(EXIT_MMAP, &exit_mmap_nb);
out2:
......@@ -113,6 +136,7 @@ int sync_start(void)
void sync_stop(void)
{
unregister_module_notifier(&module_load_nb);
profile_event_unregister(EXIT_TASK, &exit_task_nb);
profile_event_unregister(EXIT_MMAP, &exit_mmap_nb);
profile_event_unregister(EXEC_UNMAP, &exec_unmap_nb);
......
......@@ -24,12 +24,13 @@ void wake_up_buffer_waiter(void);
* then one of the following codes, then the
* relevant data.
*/
#define ESCAPE_CODE ~0UL
#define ESCAPE_CODE ~0UL
#define CTX_SWITCH_CODE 1
#define CPU_SWITCH_CODE 2
#define COOKIE_SWITCH_CODE 3
#define KERNEL_ENTER_SWITCH_CODE 4
#define KERNEL_EXIT_SWITCH_CODE 5
#define MODULE_LOADED_CODE 6
/* add data to the event buffer */
void add_event_entry(unsigned long data);
......
......@@ -115,6 +115,8 @@ extern const struct gtype##_id __mod_##gtype##_table \
/* Given an address, look for it in the exception tables */
const struct exception_table_entry *search_exception_tables(unsigned long add);
struct notifier_block;
#ifdef CONFIG_MODULES
/* Get/put a kernel symbol (calls must be symmetric) */
......@@ -329,6 +331,9 @@ const char *module_address_lookup(unsigned long addr,
/* For extable.c to search modules' exception tables. */
const struct exception_table_entry *search_module_extables(unsigned long addr);
int register_module_notifier(struct notifier_block * nb);
int unregister_module_notifier(struct notifier_block * nb);
#else /* !CONFIG_MODULES... */
#define EXPORT_SYMBOL(sym)
#define EXPORT_SYMBOL_GPL(sym)
......@@ -373,6 +378,18 @@ static inline const char *module_address_lookup(unsigned long addr,
{
return NULL;
}
static inline int register_module_notifier(struct notifier_block * nb)
{
/* no events will happen anyway, so this can always succeed */
return 0;
}
static inline int unregister_module_notifier(struct notifier_block * nb)
{
return 0;
}
#endif /* CONFIG_MODULES */
#ifdef MODULE
......
......@@ -31,6 +31,7 @@
#include <linux/errno.h>
#include <linux/err.h>
#include <linux/vermagic.h>
#include <linux/notifier.h>
#include <asm/uaccess.h>
#include <asm/semaphore.h>
#include <asm/pgalloc.h>
......@@ -59,6 +60,29 @@ static spinlock_t modlist_lock = SPIN_LOCK_UNLOCKED;
static DECLARE_MUTEX(module_mutex);
static LIST_HEAD(modules);
static DECLARE_MUTEX(notify_mutex);
static struct notifier_block * module_notify_list;
int register_module_notifier(struct notifier_block * nb)
{
int err;
down(&notify_mutex);
err = notifier_chain_register(&module_notify_list, nb);
up(&notify_mutex);
return err;
}
EXPORT_SYMBOL(register_module_notifier);
int unregister_module_notifier(struct notifier_block * nb)
{
int err;
down(&notify_mutex);
err = notifier_chain_unregister(&module_notify_list, nb);
up(&notify_mutex);
return err;
}
EXPORT_SYMBOL(unregister_module_notifier);
/* We require a truly strong try_module_get() */
static inline int strong_try_module_get(struct module *mod)
{
......@@ -1373,6 +1397,10 @@ sys_init_module(void *umod,
/* Drop lock so they can recurse */
up(&module_mutex);
down(&notify_mutex);
notifier_call_chain(&module_notify_list, MODULE_STATE_COMING, mod);
up(&notify_mutex);
/* Start the module */
ret = mod->init();
if (ret < 0) {
......
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