| From 7e1b1fc4dabd6ec8e28baa0708866e13fa93c9b3 Mon Sep 17 00:00:00 2001 |
| From: Jiri Slaby <jslaby@suse.cz> |
| Date: Fri, 10 Jun 2016 10:54:32 +0200 |
| Subject: base: make module_create_drivers_dir race-free |
| |
| From: Jiri Slaby <jslaby@suse.cz> |
| |
| commit 7e1b1fc4dabd6ec8e28baa0708866e13fa93c9b3 upstream. |
| |
| Modules which register drivers via standard path (driver_register) in |
| parallel can cause a warning: |
| WARNING: CPU: 2 PID: 3492 at ../fs/sysfs/dir.c:31 sysfs_warn_dup+0x62/0x80 |
| sysfs: cannot create duplicate filename '/module/saa7146/drivers' |
| Modules linked in: hexium_gemini(+) mxb(+) ... |
| ... |
| Call Trace: |
| ... |
| [<ffffffff812e63a2>] sysfs_warn_dup+0x62/0x80 |
| [<ffffffff812e6487>] sysfs_create_dir_ns+0x77/0x90 |
| [<ffffffff8140f2c4>] kobject_add_internal+0xb4/0x340 |
| [<ffffffff8140f5b8>] kobject_add+0x68/0xb0 |
| [<ffffffff8140f631>] kobject_create_and_add+0x31/0x70 |
| [<ffffffff8157a703>] module_add_driver+0xc3/0xd0 |
| [<ffffffff8155e5d4>] bus_add_driver+0x154/0x280 |
| [<ffffffff815604c0>] driver_register+0x60/0xe0 |
| [<ffffffff8145bed0>] __pci_register_driver+0x60/0x70 |
| [<ffffffffa0273e14>] saa7146_register_extension+0x64/0x90 [saa7146] |
| [<ffffffffa0033011>] hexium_init_module+0x11/0x1000 [hexium_gemini] |
| ... |
| |
| As can be (mostly) seen, driver_register causes this call sequence: |
| -> bus_add_driver |
| -> module_add_driver |
| -> module_create_drivers_dir |
| The last one creates "drivers" directory in /sys/module/<...>. When |
| this is done in parallel, the directory is attempted to be created |
| twice at the same time. |
| |
| This can be easily reproduced by loading mxb and hexium_gemini in |
| parallel: |
| while :; do |
| modprobe mxb & |
| modprobe hexium_gemini |
| wait |
| rmmod mxb hexium_gemini saa7146_vv saa7146 |
| done |
| |
| saa7146 calls pci_register_driver for both mxb and hexium_gemini, |
| which means /sys/module/saa7146/drivers is to be created for both of |
| them. |
| |
| Fix this by a new mutex in module_create_drivers_dir which makes the |
| test-and-create "drivers" dir atomic. |
| |
| I inverted the condition and removed 'return' to avoid multiple |
| unlocks or a goto. |
| |
| Signed-off-by: Jiri Slaby <jslaby@suse.cz> |
| Fixes: fe480a2675ed (Modules: only add drivers/ direcory if needed) |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/base/module.c | 8 +++++--- |
| 1 file changed, 5 insertions(+), 3 deletions(-) |
| |
| --- a/drivers/base/module.c |
| +++ b/drivers/base/module.c |
| @@ -24,10 +24,12 @@ static char *make_driver_name(struct dev |
| |
| static void module_create_drivers_dir(struct module_kobject *mk) |
| { |
| - if (!mk || mk->drivers_dir) |
| - return; |
| + static DEFINE_MUTEX(drivers_dir_mutex); |
| |
| - mk->drivers_dir = kobject_create_and_add("drivers", &mk->kobj); |
| + mutex_lock(&drivers_dir_mutex); |
| + if (mk && !mk->drivers_dir) |
| + mk->drivers_dir = kobject_create_and_add("drivers", &mk->kobj); |
| + mutex_unlock(&drivers_dir_mutex); |
| } |
| |
| void module_add_driver(struct module *mod, struct device_driver *drv) |