#include <linux/notifier.h>
#include <linux/dcookies.h>
#include <linux/profile.h>
+#include <linux/module.h>
#include <linux/fs.h>
#include "oprofile_stats.h"
}
+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,
};
.notifier_call = mm_notify,
};
+static struct notifier_block module_load_nb = {
+ .notifier_call = module_load_notify,
+};
+
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:
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);
* 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);
/* 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) */
/* 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)
{
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
#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>
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(¬ify_mutex);
+ err = notifier_chain_register(&module_notify_list, nb);
+ up(¬ify_mutex);
+ return err;
+}
+EXPORT_SYMBOL(register_module_notifier);
+
+int unregister_module_notifier(struct notifier_block * nb)
+{
+ int err;
+ down(¬ify_mutex);
+ err = notifier_chain_unregister(&module_notify_list, nb);
+ up(¬ify_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)
{
/* Drop lock so they can recurse */
up(&module_mutex);
+ down(¬ify_mutex);
+ notifier_call_chain(&module_notify_list, MODULE_STATE_COMING, mod);
+ up(¬ify_mutex);
+
/* Start the module */
ret = mod->init();
if (ret < 0) {