static void module_add_pdata(void *dmy, struct module *mp)
{
- dtrace_module_t *pdata = kmem_cache_alloc(dtrace_pdata_cachep,
- GFP_KERNEL | __GFP_ZERO);
+ dtrace_module_t *pdata;
+
+ /*
+ * A module may be on its way out before DTrace sets up its module
+ * handling support. Do not try to provide anything for modules being
+ * removed during startup.
+ */
+ if (mp->state == MODULE_STATE_GOING)
+ return;
+
+ pdata = kmem_cache_alloc(dtrace_pdata_cachep,
+ GFP_KERNEL | __GFP_ZERO);
pdata_init(pdata, mp);
mp->pdata = pdata;
* a pdata object. Modules loaded after this one will get their pdata
* object assigned using the module notifier hook.
*/
- module_add_pdata(NULL, dtrace_kmod);
dtrace_for_each_module(module_add_pdata, NULL);
/*
* point had their pdata object cleaned up using the module notifier
* hook.
*/
- module_del_pdata(NULL, dtrace_kmod);
dtrace_for_each_module(module_del_pdata, NULL);
/*
void dtrace_probe_provide(dtrace_probedesc_t *desc, dtrace_provider_t *prv)
{
- struct module *mod;
int all = 0;
if (prv == NULL) {
do {
prv->dtpv_pops.dtps_provide(prv->dtpv_arg, desc);
-
- /*
- * In Linux, the kernel proper is not a module and therefore is
- * not listed in the list of modules. Since the kernel proper
- * can have probe points (and e.g. has a lot of SDT ones), we
- * use a pseudo-kernel module to collect them so that there is
- * no need for code duplication in handling such probe points.
- */
- prv->dtpv_pops.dtps_provide_module(prv->dtpv_arg, dtrace_kmod);
-
- /*
- * We need to explicitly make the call for the 'dtrace' module
- * itself, because the following loop does not actually process
- * the 'dtrace' module (it is used as a sentinel).
- */
- prv->dtpv_pops.dtps_provide_module(prv->dtpv_arg, THIS_MODULE);
-
- rcu_read_lock();
-
- list_for_each_entry(mod, &(THIS_MODULE->list), list) {
- /*
- * Skip over the modules list header, because it cannot
- * validly be interpreted as a 'struct module'. It is
- * a basic list_head structure.
- */
-#ifdef MODULES_VADDR
- if ((uintptr_t)mod < MODULES_VADDR ||
- (uintptr_t)mod >= MODULES_END)
- continue;
-#else
- if ((uintptr_t)mod < VMALLOC_START ||
- (uintptr_t)mod >= VMALLOC_END)
- continue;
-#endif
-
- if (mod->state != MODULE_STATE_LIVE)
- continue;
-
- prv->dtpv_pops.dtps_provide_module(prv->dtpv_arg, mod);
- }
-
- rcu_read_unlock();
+ dtrace_for_each_module(prv->dtpv_pops.dtps_provide_module, prv->dtpv_arg);
} while (all && (prv = prv->dtpv_next) != NULL);
}
#endif
}
-void dtrace_for_each_module(for_each_module_fn *fn, void *arg)
-{
- struct module *mp;
-
- /*
- * The Linux kernel does not export the modules list explicitly, nor
- * is there an API to do so. However, when operating on a module
- * that is in the modules list, we can traverse the entire list anyway.
- * That's what we're doing here.
- *
- * The current module is the anchor and sentinel for the loop, so we
- * need to call the worker function explicitly for that module. We
- * must also identify and skip the list header because that is not a
- * valid module at all.
- */
- fn(arg, dtrace_kmod);
- fn(arg, THIS_MODULE);
-
- rcu_read_lock();
-
- list_for_each_entry_rcu(mp, &(THIS_MODULE->list), list) {
-#ifdef MODULES_VADDR
- if ((uintptr_t)mp < MODULES_VADDR ||
- (uintptr_t)mp >= MODULES_END)
- continue;
-#else
- if ((uintptr_t)mp < VMALLOC_START ||
- (uintptr_t)mp >= VMALLOC_END)
- continue;
-#endif
-
- if (mp->state != MODULE_STATE_LIVE)
- continue;
-
- fn(arg, mp);
- }
-
- rcu_read_unlock();
-}
-EXPORT_SYMBOL(dtrace_for_each_module);
/*
* Do not try to instrument DTrace itself and its modules:
- * - dtrace module
- * - ctf module
- * - all modules depending on dtrace
+ * - dtrace module
+ * - all modules depending on dtrace
*/
if (!strncmp(mp->name, "dtrace", 7))
return;
extern int dtrace_badname(const char *);
extern void dtrace_cred2priv(const cred_t *, uint32_t *, kuid_t *);
-typedef void for_each_module_fn(void *, struct module *);
-extern void dtrace_for_each_module(for_each_module_fn *fn, void *arg);
-
extern void ctf_forceload(void);
#define dtrace_membar_producer() smp_wmb()
extern dtrace_vtime_state_t dtrace_vtime_active;
+typedef void for_each_module_fn(void *, struct module *);
+extern void dtrace_for_each_module(for_each_module_fn *fn, void *arg);
+
extern void dtrace_update_time(struct timekeeper *);
extern ktime_t dtrace_get_walltime(void);
schedule_work(&psinfo_cleanup);
}
+/*---------------------------------------------------------------------------*\
+(* MODULE SUPPORT FUNCTIONS *)
+\*---------------------------------------------------------------------------*/
+extern struct list_head *dtrace_modules;
+
+/*
+ * Iterate over all loaded kernel modules. This is requried until the linux
+ * kernel receives its own module iterator.
+ */
+void dtrace_for_each_module(for_each_module_fn func, void *arg)
+{
+ struct module *mp;
+
+ if (func == NULL)
+ return;
+
+ mutex_lock(&module_mutex);
+
+ /* The dtrace fake module is not in the list. */
+ func(arg, dtrace_kmod);
+
+ list_for_each_entry(mp, dtrace_modules, list) {
+
+#ifdef MODULES_VADDR
+ if ((uintptr_t)mp < MODULES_VADDR ||
+ (uintptr_t)mp >= MODULES_END)
+ continue;
+#else
+ if ((uintptr_t)mp < VMALLOC_START ||
+ (uintptr_t)mp >= VMALLOC_END)
+ continue;
+#endif
+
+ func(arg, mp);
+ }
+
+ mutex_unlock(&module_mutex);
+}
+EXPORT_SYMBOL_GPL(dtrace_for_each_module);
+
/*---------------------------------------------------------------------------*\
(* TIME SUPPORT FUNCTIONS *)
\*---------------------------------------------------------------------------*/
#ifdef CONFIG_KGDB_KDB
struct list_head *kdb_modules = &modules; /* kdb needs the list of modules */
#endif /* CONFIG_KGDB_KDB */
+#ifdef CONFIG_DTRACE
+struct list_head *dtrace_modules = &modules;
+#endif /* CONFIG_DTRACE */
#ifdef CONFIG_MODULE_SIG
#ifdef CONFIG_MODULE_SIG_FORCE