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