diff options
author | Guenter Roeck <linux@roeck-us.net> | 2019-02-07 00:13:49 -0500 |
---|---|---|
committer | Jens Axboe <axboe@kernel.dk> | 2019-02-08 08:46:59 -0500 |
commit | f25191bb322dec8fa2979ecb8235643aa42470e1 (patch) | |
tree | 545a511ebd6082215741301e73ecdf462afe82f4 | |
parent | 09e57403705d31b76994bc5ff0d816528fdf06c3 (diff) |
cdrom: Fix race condition in cdrom_sysctl_register
The following traceback is sometimes seen when booting an image in qemu:
[ 54.608293] cdrom: Uniform CD-ROM driver Revision: 3.20
[ 54.611085] Fusion MPT base driver 3.04.20
[ 54.611877] Copyright (c) 1999-2008 LSI Corporation
[ 54.616234] Fusion MPT SAS Host driver 3.04.20
[ 54.635139] sysctl duplicate entry: /dev/cdrom//info
[ 54.639578] CPU: 0 PID: 266 Comm: kworker/u4:5 Not tainted 5.0.0-rc5 #1
[ 54.639578] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 0.0.0 02/06/2015
[ 54.641273] Workqueue: events_unbound async_run_entry_fn
[ 54.641273] Call Trace:
[ 54.641273] dump_stack+0x67/0x90
[ 54.641273] __register_sysctl_table+0x50b/0x570
[ 54.641273] ? rcu_read_lock_sched_held+0x6f/0x80
[ 54.641273] ? kmem_cache_alloc_trace+0x1c7/0x1f0
[ 54.646814] __register_sysctl_paths+0x1c8/0x1f0
[ 54.646814] cdrom_sysctl_register.part.7+0xc/0x5f
[ 54.646814] register_cdrom.cold.24+0x2a/0x33
[ 54.646814] sr_probe+0x4bd/0x580
[ 54.646814] ? __driver_attach+0xd0/0xd0
[ 54.646814] really_probe+0xd6/0x260
[ 54.646814] ? __driver_attach+0xd0/0xd0
[ 54.646814] driver_probe_device+0x4a/0xb0
[ 54.646814] ? __driver_attach+0xd0/0xd0
[ 54.646814] bus_for_each_drv+0x73/0xc0
[ 54.646814] __device_attach+0xd6/0x130
[ 54.646814] bus_probe_device+0x9a/0xb0
[ 54.646814] device_add+0x40c/0x670
[ 54.646814] ? __pm_runtime_resume+0x4f/0x80
[ 54.646814] scsi_sysfs_add_sdev+0x81/0x290
[ 54.646814] scsi_probe_and_add_lun+0x888/0xc00
[ 54.646814] ? scsi_autopm_get_host+0x21/0x40
[ 54.646814] __scsi_add_device+0x116/0x130
[ 54.646814] ata_scsi_scan_host+0x93/0x1c0
[ 54.646814] async_run_entry_fn+0x34/0x100
[ 54.646814] process_one_work+0x237/0x5e0
[ 54.646814] worker_thread+0x37/0x380
[ 54.646814] ? rescuer_thread+0x360/0x360
[ 54.646814] kthread+0x118/0x130
[ 54.646814] ? kthread_create_on_node+0x60/0x60
[ 54.646814] ret_from_fork+0x3a/0x50
The only sensible explanation is that cdrom_sysctl_register() is called
twice, once from the module init function and once from register_cdrom().
cdrom_sysctl_register() is not mutex protected and may happily execute
twice if the second call is made before the first call is complete.
Use a static atomic to ensure that the function is executed exactly once.
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
-rw-r--r-- | drivers/cdrom/cdrom.c | 7 |
1 files changed, 3 insertions, 4 deletions
diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c index 614ecdbb4ab7..933268b8d6a5 100644 --- a/drivers/cdrom/cdrom.c +++ b/drivers/cdrom/cdrom.c | |||
@@ -265,6 +265,7 @@ | |||
265 | /* #define ERRLOGMASK (CD_WARNING|CD_OPEN|CD_COUNT_TRACKS|CD_CLOSE) */ | 265 | /* #define ERRLOGMASK (CD_WARNING|CD_OPEN|CD_COUNT_TRACKS|CD_CLOSE) */ |
266 | /* #define ERRLOGMASK (CD_WARNING|CD_REG_UNREG|CD_DO_IOCTL|CD_OPEN|CD_CLOSE|CD_COUNT_TRACKS) */ | 266 | /* #define ERRLOGMASK (CD_WARNING|CD_REG_UNREG|CD_DO_IOCTL|CD_OPEN|CD_CLOSE|CD_COUNT_TRACKS) */ |
267 | 267 | ||
268 | #include <linux/atomic.h> | ||
268 | #include <linux/module.h> | 269 | #include <linux/module.h> |
269 | #include <linux/fs.h> | 270 | #include <linux/fs.h> |
270 | #include <linux/major.h> | 271 | #include <linux/major.h> |
@@ -3692,9 +3693,9 @@ static struct ctl_table_header *cdrom_sysctl_header; | |||
3692 | 3693 | ||
3693 | static void cdrom_sysctl_register(void) | 3694 | static void cdrom_sysctl_register(void) |
3694 | { | 3695 | { |
3695 | static int initialized; | 3696 | static atomic_t initialized = ATOMIC_INIT(0); |
3696 | 3697 | ||
3697 | if (initialized == 1) | 3698 | if (!atomic_add_unless(&initialized, 1, 1)) |
3698 | return; | 3699 | return; |
3699 | 3700 | ||
3700 | cdrom_sysctl_header = register_sysctl_table(cdrom_root_table); | 3701 | cdrom_sysctl_header = register_sysctl_table(cdrom_root_table); |
@@ -3705,8 +3706,6 @@ static void cdrom_sysctl_register(void) | |||
3705 | cdrom_sysctl_settings.debug = debug; | 3706 | cdrom_sysctl_settings.debug = debug; |
3706 | cdrom_sysctl_settings.lock = lockdoor; | 3707 | cdrom_sysctl_settings.lock = lockdoor; |
3707 | cdrom_sysctl_settings.check = check_media_type; | 3708 | cdrom_sysctl_settings.check = check_media_type; |
3708 | |||
3709 | initialized = 1; | ||
3710 | } | 3709 | } |
3711 | 3710 | ||
3712 | static void cdrom_sysctl_unregister(void) | 3711 | static void cdrom_sysctl_unregister(void) |