When using dynamic dependencies with dvb_attach(), which module is using
another doesn't show up with lsmod.
The problem is that when a card driver attaches the frontend with
symbol_request(), the kernel increments the use count of the frontend
module, but doesn't keep track of which module it was the called
symbol_request().
This patch will fix it so that the kernel does keep track.
One patch is for the v4l-dvb sources, the other is for the kernel.
With the patch, lsmod produces output like this:
cx88_dvb 14084 0
or51132 9988 1 cx88_dvb
dvb_pll 12292 2 cx88_dvb
Without it, this is what you get:
cx88_dvb 14084 0
or51132 9988 1
dvb_pll 12292 2 cx88_dvb
Note that dvb_pll still shows up as being used by cx88_dvb because there
are both dynamic AND static dependencies on the dvb_pll module. ie.
dvb_attach() is used on dvb_pll_attach, but there are other symbols from
dvb_pll (like dvb_pll_configure) that are referenced too.
Does this patch seem like a good idea? Should we try for 2.6.19 along
with dvb_attach()?
diff -r 34737e742674 linux/drivers/media/dvb/dvb-core/dvb_frontend.c
--- a/linux/drivers/media/dvb/dvb-core/dvb_frontend.c Thu Aug 17 15:08:01 2006 -0700
+++ b/linux/drivers/media/dvb/dvb-core/dvb_frontend.c Sat Aug 19 00:45:51 2006 -0700
@@ -1126,16 +1126,20 @@ void dvb_frontend_detach(struct dvb_fron
if (fe->ops.release_sec) {
fe->ops.release_sec(fe);
- symbol_put_addr(fe->ops.release_sec);
+ __symbol_put_addr(fe->ops.release_sec, fe->dvb->module);
}
if (fe->ops.tuner_ops.release) {
fe->ops.tuner_ops.release(fe);
- symbol_put_addr(fe->ops.tuner_ops.release);
+ printk("Calling symbol_put_addr_user for tuner\n");
+ __symbol_put_addr(fe->ops.tuner_ops.release, fe->dvb->module);
+ printk("done\n");
}
ptr = (void*)fe->ops.release;
if (ptr) {
fe->ops.release(fe);
- symbol_put_addr(ptr);
+ printk("Calling symbol_put_addr_user for FE\n");
+ __symbol_put_addr(ptr, fe->dvb->module);
+ printk("done\n");
}
}
#else
diff -r dcc321d1340a drivers/mtd/chips/gen_probe.c
--- a/drivers/mtd/chips/gen_probe.c Sun Aug 06 19:00:05 2006 +0000
+++ b/drivers/mtd/chips/gen_probe.c Sat Aug 19 00:51:05 2006 -0700
@@ -212,10 +212,10 @@ static inline struct mtd_info *cfi_cmdse
sprintf(probename, MODULE_SYMBOL_PREFIX "cfi_cmdset_%4.4X", type);
- probe_function = __symbol_get(probename);
+ probe_function = __symbol_get(probename, THIS_MODULE);
if (!probe_function) {
request_module(probename + sizeof(MODULE_SYMBOL_PREFIX) - 1);
- probe_function = __symbol_get(probename);
+ probe_function = __symbol_get(probename, THIS_MODULE);
}
if (probe_function) {
diff -r dcc321d1340a include/linux/module.h
--- a/include/linux/module.h Sun Aug 06 19:00:05 2006 +0000
+++ b/include/linux/module.h Sat Aug 19 00:51:05 2006 -0700
@@ -164,9 +164,10 @@ struct notifier_block;
#ifdef CONFIG_MODULES
/* Get/put a kernel symbol (calls must be symmetric) */
-void *__symbol_get(const char *symbol);
+void *__symbol_get(const char *symbol, struct module *user);
void *__symbol_get_gpl(const char *symbol);
-#define symbol_get(x) ((typeof(&x))(__symbol_get(MODULE_SYMBOL_PREFIX #x)))
+#define symbol_get(x) ((typeof(&x))(__symbol_get(MODULE_SYMBOL_PREFIX #x, \
+ THIS_MODULE)))
#ifndef __GENKSYMS__
#ifdef CONFIG_MODVERSIONS
@@ -376,9 +377,10 @@ extern void __module_put_and_exit(struct
#ifdef CONFIG_MODULE_UNLOAD
unsigned int module_refcount(struct module *mod);
-void __symbol_put(const char *symbol);
-#define symbol_put(x) __symbol_put(MODULE_SYMBOL_PREFIX #x)
-void symbol_put_addr(void *addr);
+void __symbol_put(const char *symbol, struct module *user);
+#define symbol_put(x) __symbol_put(MODULE_SYMBOL_PREFIX #x, THIS_MODULE)
+void __symbol_put_addr(void *addr, struct module *user);
+#define symbol_put_addr(x) __symbol_put_addr(x, THIS_MODULE)
/* Sometimes we know we already have a refcount, and it's easier not
to handle the error case (which only happens with rmmod --wait). */
diff -r dcc321d1340a kernel/module.c
--- a/kernel/module.c Sun Aug 06 19:00:05 2006 +0000
+++ b/kernel/module.c Sat Aug 19 00:51:05 2006 -0700
@@ -510,28 +510,36 @@ struct module_use
{
struct list_head list;
struct module *module_which_uses;
+ int count;
};
-/* Does a already use b? */
-static int already_uses(struct module *a, struct module *b)
+/* Does a already use b? Returns the use pointer if it does, NULL if not. */
+static struct module_use *already_uses(struct module *a, struct module *b)
{
struct module_use *use;
list_for_each_entry(use, &b->modules_which_use_me, list) {
if (use->module_which_uses == a) {
DEBUGP("%s uses %s!\n", a->name, b->name);
- return 1;
+ return use;
}
}
DEBUGP("%s does not use %s!\n", a->name, b->name);
- return 0;
+ return NULL;
}
/* Module a uses b */
-static int use_module(struct module *a, struct module *b)
+static int use_module(struct module *a, struct module *b, int get_anyway)
{
struct module_use *use;
- if (b == NULL || already_uses(a, b)) return 1;
+ if (b == NULL) return 1;
+
+ if ((use=already_uses(a, b))) {
+ use->count++;
+ if (get_anyway)
+ return strong_try_module_get(b);
+ return 1;
+ }
if (!strong_try_module_get(b))
return 0;
@@ -544,6 +552,7 @@ static int use_module(struct module *a,
return 0;
}
+ use->count = 1;
use->module_which_uses = a;
list_add(&use->list, &b->modules_which_use_me);
return 1;
@@ -745,7 +754,23 @@ static void print_unload_info(struct seq
seq_printf(m, "-");
}
-void __symbol_put(const char *symbol)
+static void __module_put_user(struct module *module, struct module *user)
+{
+ printk("module_put_user: put %s by %s\n", module->name, user->name);
+ if(user) {
+ struct module_use *use;
+ use = already_uses(user, module);
+ printk("Got use record %p, use count %d\n", use, use->count);
+ BUG_ON(!use);
+ if(! --(use->count)) {
+ list_del(&use->list);
+ kfree(use);
+ }
+ }
+ module_put(module);
+}
+
+void __symbol_put(const char *symbol, struct module *user)
{
struct module *owner;
unsigned long flags;
@@ -754,13 +779,14 @@ void __symbol_put(const char *symbol)
spin_lock_irqsave(&modlist_lock, flags);
if (!__find_symbol(symbol, &owner, &crc, 1))
BUG();
- module_put(owner);
+ __module_put_user(owner, user);
spin_unlock_irqrestore(&modlist_lock, flags);
}
EXPORT_SYMBOL(__symbol_put);
-void symbol_put_addr(void *addr)
-{
+void __symbol_put_addr(void *addr, struct module *user)
+{
+ unsigned long flags;
struct module *modaddr;
if (core_kernel_text((unsigned long)addr))
@@ -768,9 +794,12 @@ void symbol_put_addr(void *addr)
if (!(modaddr = module_text_address((unsigned long)addr)))
BUG();
- module_put(modaddr);
-}
-EXPORT_SYMBOL_GPL(symbol_put_addr);
+ printk("symbol_put_addr_user, put module %s by %s\n", modaddr->name, user->name);
+ spin_lock_irqsave(&modlist_lock, flags);
+ __module_put_user(modaddr, user);
+ spin_unlock_irqrestore(&modlist_lock, flags);
+}
+EXPORT_SYMBOL_GPL(__symbol_put_addr);
static ssize_t show_refcnt(struct module_attribute *mattr,
struct module *mod, char *buffer)
@@ -795,7 +824,7 @@ static inline void module_unload_free(st
{
}
-static inline int use_module(struct module *a, struct module *b)
+static inline int use_module(struct module *a, struct module *b, int get_anyway)
{
return strong_try_module_get(b);
}
@@ -913,7 +942,7 @@ static unsigned long resolve_symbol(Elf_
if (ret) {
/* use_module can fail due to OOM, or module unloading */
if (!check_version(sechdrs, versindex, name, mod, crc) ||
- !use_module(mod, owner))
+ !use_module(mod, owner, 0))
ret = 0;
}
return ret;
@@ -1128,18 +1157,23 @@ static void free_module(struct module *m
module_free(mod, mod->module_core);
}
-void *__symbol_get(const char *symbol)
+void *__symbol_get(const char *symbol, struct module *user)
{
struct module *owner;
unsigned long value, flags;
const unsigned long *crc;
+ printk("symbol_get_user: %s by %s\n", symbol, user->name);
spin_lock_irqsave(&modlist_lock, flags);
value = __find_symbol(symbol, &owner, &crc, 1);
- if (value && !strong_try_module_get(owner))
- value = 0;
+ printk("symbol_get_user: module %s used by %s\n", owner->name, user->name);
+ if (value) {
+ if ((user && !use_module(user, owner, 1)) ||
+ (!user && !strong_try_module_get(owner)))
+ value = 0;
+ }
+
spin_unlock_irqrestore(&modlist_lock, flags);
-
return (void *)value;
}
EXPORT_SYMBOL_GPL(__symbol_get);
_______________________________________________
linux-dvb mailing list
linux-dvb@xxxxxxxxxxx
http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb