[linux-dvb] [PATCH] Keeping track of dependencies with dvb_attach()

Trent Piepho xyzzy at speakeasy.org
Sat Aug 19 09:52:24 CEST 2006


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()?
-------------- next part --------------
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
-------------- next part --------------
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);


More information about the linux-dvb mailing list