timers: Plug debugobject leaks and use del_timer_sync() in exit/teardown
Subsystems (20)
cover timers: Plug debugobject leaks and use del_timer_sync() in exit/teardown
Timers on stack must be initialized with init_timer_on_stack() which creates a tracking object if DEBUG_OBJECTS is enabled. Quite some places miss the complementary destroy_timer_on_stack(), which frees the tracking object. So we leak the tracking object in the debug objects store.
While looking at that, one affected driver also used del_timer() instead of del_timer_sync() before returning, which is wrong as well as del_timer() meriliy dequeues an armed timer, but does not wait for a callback which is executed on a different cpu.
So I started to look through del_timer() sites and fixed a bunch of obvious teardown, module exit pathes which must use del_timer_sync().
As I'm about to travel, I gave up on reviewing all the usage sites of del_timer().
Maybe Julia has an idea to automate the scan a bit. The paring for init_timer_on_stack/destroy_timer_on_stack should be easy enough, but the del_timer() one is pretty complex and definitly needs manual auditing, but having a scan assistant to identify potential places would be definitely helpful.
Thanks,
tglx
--- drivers/atm/firestream.c | 2 +- drivers/atm/idt77105.c | 6 +++--- drivers/block/cpqarray.c | 2 +- drivers/block/umem.c | 2 +- drivers/block/xsysace.c | 2 ++ drivers/bluetooth/bluecard_cs.c | 2 +- drivers/bluetooth/hci_bcsp.c | 2 +- drivers/bluetooth/hci_h5.c | 2 +- drivers/cpufreq/intel_pstate.c | 2 +- drivers/input/serio/hp_sdc.c | 2 +- drivers/s390/char/tape_std.c | 3 ++- drivers/s390/net/lcs.c | 1 + drivers/scsi/qla1280.c | 1 + drivers/thermal/intel_powerclamp.c | 1 + kernel/rcu/torture.c | 4 +++- 15 files changed, 21 insertions(+), 13 deletions(-)
PATCH 1/16 s390: tape: Use del_timer_sync()
del_timer() does not wait for a possible running callback to complete. So the call side might free request and the associated objects while on another cpu the timer handler runs.
--- drivers/s390/char/tape_std.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/s390/char/tape_std.c +1 -1
@@ -78,7 +78,7 @@ tape_std_assign(struct tape_device *devi rc =tape_do_io_interruptible (device, request); -del_timer (&timeout); +del_timer_sync (&timeout);if (rc !=0 ) { DBF_EVENT(3, "%08x: assign failed - device might be busy\n",
Heiko Carstens
AppliedRe: [patch 01/16] s390: tape: Use del_timer_sync()
Quoted 3 lines · Thomas Gleixner
del_timer()does not wait for a possible running callback to complete. So the call side might free request and the associated objects while on another cpu the timer handler runs.
[...]
drivers/s390/char/tape_std.c tape_std_assign(struct tape_device *devi · line 81
Quoted 3 lines
drivers/s390/char/tape_std.c +1
-1-del_timer (&timeout); +del_timer_sync (&timeout);
Applied, thanks.
PATCH 2/16 s390: tape: Add missing destroy_timer_on_stack()
In reply to Thomas GleixnerOtherwise we leak a tracking object when DEBUG_OBJECTS is enabled.
--- drivers/s390/char/tape_std.c | 1 + 1 file changed, 1 insertion(+)
drivers/s390/char/tape_std.c +1 -0
@@ -79,6 +79,7 @@ tape_std_assign(struct tape_device *devi rc =tape_do_io_interruptible (device, request);del_timer_sync (&timeout); +destroy_timer_on_stack (&timeout);if (rc !=0 ) { DBF_EVENT(3, "%08x: assign failed - device might be busy\n",
Heiko Carstens
AppliedRe: [patch 02/16] s390: tape: Add missing destroy_timer_on_stack()
Quoted 2 lines · Thomas Gleixner
Otherwise we leak a tracking object when
DEBUG_OBJECTSis enabled.
[...]
drivers/s390/char/tape_std.c tape_std_assign(struct tape_device *devi · line 82
Quoted 2 lines
drivers/s390/char/tape_std.c +1
-0del_timer_sync (&timeout); +destroy_timer_on_stack (&timeout);
Applied, thanks.
PATCH 3/16 s390: net: lcs: Add missing destroy_timer_on_stack()
In reply to Thomas GleixnerOtherwise we leak a tracking object when DEBUG_OBJECTS is enabled.
--- drivers/s390/net/lcs.c | 1 + 1 file changed, 1 insertion(+)
drivers/s390/net/lcs.c +1 -0
@@ -899,6 +899,7 @@ lcs_send_lancmd(struct lcs_card *card, sadd_timer (&timer);wait_event (reply->wait_q, reply->received);del_timer_sync (&timer); +destroy_timer_on_stack (&timer);LCS_DBF_TEXT_ (4 , trace,"rc:%d" ,reply->rc); rc = reply->rc;lcs_put_reply (reply);
Heiko Carstens
AppliedRe: [patch 03/16] s390: net: lcs: Add missing destroy_timer_on_stack()
Quoted 11 lines · Thomas Gleixner
Otherwise we leak a tracking object when
DEBUG_OBJECTSis enabled.drivers/s390/net/lcs.c | 1 + 1 file changed, 1 insertion(+)Index:
tip/drivers/s390/net/lcs.c
===================================================================
drivers/s390/net/lcs.c lcs_send_lancmd(struct lcs_card *card, s · line 902
Quoted 4 lines
drivers/s390/net/lcs.c +1
-0@@ -899,6 +899,7 @@ lcs_send_lancmd(struct lcs_card *card, sadd_timer (&timer);wait_event (reply->wait_q, reply->received);del_timer_sync (&timer); +destroy_timer_on_stack (&timer);
Applied, thanks.
PATCH 4/16 scsi: qla1280: Add missing destroy_timer_on_stack()
In reply to Thomas GleixnerOtherwise we leak a tracking object when DEBUG_OBJECTS is enabled.
This code should use wait_for_completion_timeout() instead, but that's a different issue.
--- drivers/scsi/qla1280.c | 1 + 1 file changed, 1 insertion(+)
drivers/scsi/qla1280.c +1 -0
@@ -2514,6 +2514,7 @@ qla1280_mailbox_command(struct scsi_qla_wait_for_completion (&wait);del_timer_sync (&timer); +destroy_timer_on_stack (&timer);spin_lock_irq (ha->host->host_lock);
PATCH 5/16 thermal: powerclamp: Add missing destroy_timer_on_stack()
In reply to Thomas GleixnerOtherwise we leak a tracking object when DEBOG_OBJECTS is enabled.
--- drivers/thermal/intel_powerclamp.c | 1 + 1 file changed, 1 insertion(+)
drivers/thermal/intel_powerclamp.c +1 -0
@@ -455,6 +455,7 @@ static int clamp_thread(void *arg)preempt_enable (); }del_timer_sync (&wakeup_timer); +destroy_timer_on_stack (&wakeup_timer);clear_bit (cpunr, cpu_clamping_mask);return 0 ;
PATCH 6/16 rcu: torture: Add missing destroy_timer_on_stack()
In reply to Thomas GleixnerOtherwise we leak a tracking object if DEBUG_OBJECTS is enabled.
--- kernel/rcu/torture.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
kernel/rcu/torture.c +3 -1
@@ -1038,8 +1038,10 @@ rcu_torture_reader(void *arg) }while (!kthread_should_stop () && fullstop ==FULLSTOP_DONTSTOP );VERBOSE_PRINTK_STRING ("rcu_torture_reader task stopping" );rcutorture_shutdown_absorb ("rcu_torture_reader" ); -if (irqreader && cur_ops->irq_capable) +if (irqreader && cur_ops->irq_capable) {del_timer_sync (&t); +destroy_timer_on_stack (&t); + }while (!kthread_should_stop ())schedule_timeout_uninterruptible (1 );return 0 ;
Re: [patch 06/16] rcu: torture: Add missing destroy_timer_on_stack()
Quoted 3 lines · Thomas Gleixner
Otherwise we leak a tracking object if
DEBUG_OBJECTSis enabled.Signed-off-by Thomas Gleixner <[email protected]>
Good catch! Queued for 3.16.
Thanx, Paul
Quoted 24 lines
Cc Josh Triplett <[email protected]>Cc "Paul E. McKenney" <[email protected]>--- kernel/rcu/torture.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)Index:
tip/kernel/rcu/torture.c
===================================================================kernel/rcu/torture.c +3
-1@@ -1038,8 +1038,10 @@ rcu_torture_reader(void *arg) }while (!kthread_should_stop () && fullstop ==FULLSTOP_DONTSTOP );VERBOSE_PRINTK_STRING ("rcu_torture_reader task stopping" );rcutorture_shutdown_absorb ("rcu_torture_reader" ); -if (irqreader && cur_ops->irq_capable) +if (irqreader && cur_ops->irq_capable) {del_timer_sync (&t); +destroy_timer_on_stack (&t); + }while (!kthread_should_stop ())schedule_timeout_uninterruptible (1 );return 0 ;
Re: [patch 06/16] rcu: torture: Add missing destroy_timer_on_stack()
In reply to Thomas GleixnerQuoted 5 lines · Thomas Gleixner
Otherwise we leak a tracking object if
DEBUG_OBJECTSis enabled.Signed-off-by Thomas Gleixner <[email protected]>Cc Josh Triplett <[email protected]>Cc "Paul E. McKenney" <[email protected]>
Quoted 21 lines
kernel/rcu/torture.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)Index:
tip/kernel/rcu/torture.c
===================================================================kernel/rcu/torture.c +3
-1@@ -1038,8 +1038,10 @@ rcu_torture_reader(void *arg) }while (!kthread_should_stop () && fullstop ==FULLSTOP_DONTSTOP );VERBOSE_PRINTK_STRING ("rcu_torture_reader task stopping" );rcutorture_shutdown_absorb ("rcu_torture_reader" ); -if (irqreader && cur_ops->irq_capable) +if (irqreader && cur_ops->irq_capable) {del_timer_sync (&t); +destroy_timer_on_stack (&t); + }while (!kthread_should_stop ())schedule_timeout_uninterruptible (1 );return 0 ;
PATCH 7/16 atm: firestream: Use del_timer_sync() in teardown path
In reply to Thomas GleixnerThe device is about to vanish. So we need to make sure that the timer is completely stopped and the callback is not running on another CPU.
--- drivers/atm/firestream.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/atm/firestream.c +1 -1
@@ -2000,7 +2000,7 @@ static void firestream_remove_one(structfs_dprintk (FS_DEBUG_CLEANUP ,"Freeing irq%d.\n" , dev->irq);free_irq (dev->irq, dev); -del_timer (&dev->timer); +del_timer_sync (&dev->timer);atm_dev_deregister (dev->atm_dev);free_queue (dev, &dev->hp_txq);
Re: [patch 07/16] atm: firestream: Use del_timer_sync() in teardown path
From: Thomas Gleixner <[email protected]>
Date: Sun, 23 Mar 2014 15:09:28 -0000
Quoted 4 lines
The device is about to vanish. So we need to make sure that the timer is completely stopped and the callback is not running on another CPU.
Signed-off-by Thomas Gleixner <[email protected]>
Applied.
PATCH 8/16 atm: idt77105: Use del_timer_sync() in exit path
In reply to Thomas GleixnerThe module is about to go away. Make sure everything is stopped safely before we pull the plug.
--- drivers/atm/idt77105.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/atm/idt77105.c +3 -3
@@ -368,9 +368,9 @@ EXPORT_SYMBOL(idt77105_init); static void __exit idt77105_exit(void) { -/* turn off timers */ -del_timer (&stats_timer); -del_timer (&restart_timer); +/* turn off timers */ +del_timer_sync (&stats_timer); +del_timer_sync (&restart_timer); }module_exit (idt77105_exit);
Re: [patch 08/16] atm: idt77105: Use del_timer_sync() in exit path
From: Thomas Gleixner <[email protected]>
Date: Sun, 23 Mar 2014 15:09:28 -0000
Quoted 4 lines
The module is about to go away. Make sure everything is stopped safely before we pull the plug.
Signed-off-by Thomas Gleixner <[email protected]>
Applied.
PATCH 9/16 block: cpqarray: Use del_timer_sync() in teardown
In reply to Thomas GleixnerThe data structure which contains the timer is about to be freed. Make sure the timer is completely stopped and no callback running anymore.
--- drivers/block/cpqarray.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/block/cpqarray.c +1 -1
@@ -336,7 +336,7 @@ static void cpqarray_remove_one(int i)free_irq (hba[i]->intr, hba[i]);iounmap (hba[i]->vaddr);unregister_blkdev (COMPAQ_SMART2_MAJOR +i, hba[i]->devname); -del_timer (&hba[i]->timer); +del_timer_sync (&hba[i]->timer);remove_proc_entry (hba[i]->devname, proc_array); pci_free_consistent(hba[i]->pci_dev, NR_CMDS * sizeof(cmdlist_t), (hba[i]->cmd_pool),
PATCH 10/16 block: umem: Use del_timer_sync() in exit path
In reply to Thomas GleixnerMake sure no callback is running before removing the module.
--- drivers/block/umem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/block/umem.c +1 -1
@@ -746,7 +746,7 @@ static void init_battery_timer(void)static void del_battery_timer (void ) { -del_timer (&battery_timer); +del_timer_sync (&battery_timer); }/*
PATCH 11/16 block: xsysace; Use del_timer_sync() in exit path
In reply to Thomas GleixnerThe data structure which contains the timer is about to be freed. Make sure no callback is running.
--- drivers/block/xsysace.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/block/xsysace.c +2 -0
@@ -1088,6 +1088,8 @@ static void ace_teardown(struct ace_deviif (ace->irq)free_irq (ace->irq, ace); +del_timer_sync (&ace->stall_timer); +iounmap (ace->baseaddr); }
PATCH 12/16 bt: bluecard: Use del_timer_sync() in teardown path
In reply to Thomas GleixnerMake sure no timer callback is running before releasing the datastructure which contains it.
--- drivers/bluetooth/bluecard_cs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/bluetooth/bluecard_cs.c +1 -1
@@ -898,7 +898,7 @@ static void bluecard_release(struct pcmcbluecard_close (info); -del_timer (&(info->timer)); +del_timer_sync (&(info->timer));pcmcia_disable_device (link); }
Marcel Holtmann
maintainerRe: [patch 12/16] bt: bluecard: Use del_timer_sync() in teardown path
Hi Thomas,
Quoted 9 lines
Make sure no timer callback is running before releasing the datastructure which contains it.
Signed-off-by Thomas Gleixner <[email protected]>Cc Marcel Holtmann <[email protected]>Cc bt <[email protected]>---
drivers/bluetooth/bluecard_cs.c| 2 +-1 file changed, 1 insertion(+), 1 deletion(-)
patch has been applied to bluetooth-next tree.
Regards
Marcel
PATCH 13/16 bt: hci-bcsp: Use del_timer_sync() in teardown path
In reply to Thomas GleixnerMake sure no timer callback is running before freeing the datastructure which contains it.
--- drivers/bluetooth/hci_bcsp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/bluetooth/hci_bcsp.c +1 -1
@@ -722,7 +722,7 @@ static int bcsp_close(struct hci_uart *hskb_queue_purge (&bcsp->unack);skb_queue_purge (&bcsp->rel);skb_queue_purge (&bcsp->unrel); -del_timer (&bcsp->tbcsp); +del_timer_sync (&bcsp->tbcsp);kfree (bcsp);return 0 ;
Marcel Holtmann
maintainerRe: [patch 13/16] bt: hci-bcsp: Use del_timer_sync() in teardown path
Hi Thomas,
Quoted 9 lines
Make sure no timer callback is running before freeing the datastructure which contains it.
Signed-off-by Thomas Gleixner <[email protected]>Cc Marcel Holtmann <[email protected]>Cc bt <[email protected]>---
drivers/bluetooth/hci_bcsp.c| 2 +-1 file changed, 1 insertion(+), 1 deletion(-)
we already fixed something similar in bluetooth-next tree. I think your patch is no longer needed.
Regards
Marcel
PATCH 14/16 bt: hci-h5: Use del_timer_sync() in exit path
In reply to Thomas GleixnerMake sure no timer callback is running before releasing the datastructure which contains it.
--- drivers/bluetooth/hci_h5.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/bluetooth/hci_h5.c +1 -1
@@ -210,7 +210,7 @@ static int h5_close(struct hci_uart *hu)skb_queue_purge (&h5->rel);skb_queue_purge (&h5->unrel); -del_timer (&h5->timer); +del_timer_sync (&h5->timer);kfree (h5);
Marcel Holtmann
maintainerRe: [patch 14/16] bt: hci-h5: Use del_timer_sync() in exit path
Hi Thomas,
Quoted 9 lines
Make sure no timer callback is running before releasing the datastructure which contains it.
Signed-off-by Thomas Gleixner <[email protected]>Cc Marcel Holtmann <[email protected]>Cc bt <[email protected]>---
drivers/bluetooth/hci_h5.c| 2 +-1 file changed, 1 insertion(+), 1 deletion(-)
we already fixed something similar in bluetooth-next tree. I think your patch is no longer needed.
Regards
Marcel
PATCH 15/16 cpufreq: intel-pstate: Use del_timer_sync in intel_pstate_cpu_exit()
In reply to Thomas GleixnerWe are about to free the data structure. Make sure no timer callback is running. I might be paranoid, but the ->exit callback can be invoked from so many places, that it is not entirely clear whether del_timer is always called on the cpu on which it is enqueued.
While looking through the call sites I noticed, that cpufreq_init_policy() can fail and invoke cpufreq_driver->exit() but it does not return the failure and the callsite happily proceeds.
---
drivers/cpufreq/intel_pstate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/cpufreq/intel_pstate.c +1 -1
@@ -777,7 +777,7 @@ static int intel_pstate_cpu_exit(struct {int cpu = policy->cpu; -del_timer (&all_cpu_data[cpu]->timer); +del_timer_sync (&all_cpu_data[cpu]->timer);kfree (all_cpu_data[cpu]); all_cpu_data[cpu] =NULL ;return 0 ;
Re: [patch 15/16] cpufreq: intel-pstate: Use del_timer_sync in intel_pstate_cpu_exit()
Quoted 5 lines · Thomas Gleixner
We are about to free the data structure. Make sure no timer callback is running. I might be paranoid, but the ->exit callback can be invoked from so many places, that it is not entirely clear whether
del_timeris always called on the cpu on which it is enqueued.
Quoted 8 lines
While looking through the call sites I noticed, that
cpufreq_init_policy()can fail and invokecpufreq_driver->exit()but it does not return the failure and the callsite happily proceeds.Signed-off-by Thomas Gleixner <[email protected]>Cc "Rafael J. Wysocki" <[email protected]>Cc cpufreq <[email protected]>Cc pm <[email protected]>
Dirk?
Quoted 20 lines
---
drivers/cpufreq/intel_pstate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)Index:
tip/drivers/cpufreq/intel_pstate.c
===================================================================drivers/cpufreq/intel_pstate.c +1
-1@@ -777,7 +777,7 @@ static int intel_pstate_cpu_exit(struct {int cpu = policy->cpu; -del_timer (&all_cpu_data[cpu]->timer); +del_timer_sync (&all_cpu_data[cpu]->timer);kfree (all_cpu_data[cpu]); all_cpu_data[cpu] =NULL ;return 0 ;
Signature · 2 lines
I speak only for myself. Rafael J. Wysocki, Intel Open Source Technology Center.
Re: [patch 15/16] cpufreq: intel-pstate: Use del_timer_sync in intel_pstate_cpu_exit()
Hi Thomas,
Quoted 10 lines · Rafael J. Wysocki
Quoted 9 lines · Thomas Gleixner
We are about to free the data structure. Make sure no timer callback is running. I might be paranoid, but the ->exit callback can be invoked from so many places, that it is not entirely clear whether
del_timeris always called on the cpu on which it is enqueued.While looking through the call sites I noticed, that
cpufreq_init_policy()can fail and invokecpufreq_driver->exit()but it does not return the failure and the callsite happily proceeds.
The call to del_timer() has been moved to a new callback in material in Rafaels pull request for v3.15.
I will send a patch adding this change to the v3.15 material.
--Dirk
Quoted 28 lines
Quoted 4 lines
Signed-off-by Thomas Gleixner <[email protected]>Cc "Rafael J. Wysocki" <[email protected]>Cc cpufreq <[email protected]>Cc pm <[email protected]>Dirk?
Quoted 20 lines
---
drivers/cpufreq/intel_pstate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)Index:
tip/drivers/cpufreq/intel_pstate.c
===================================================================drivers/cpufreq/intel_pstate.c +1
-1@@ -777,7 +777,7 @@ static int intel_pstate_cpu_exit(struct {int cpu = policy->cpu; -del_timer (&all_cpu_data[cpu]->timer); +del_timer_sync (&all_cpu_data[cpu]->timer);kfree (all_cpu_data[cpu]); all_cpu_data[cpu] =NULL ;return 0 ;
Re: [patch 15/16] cpufreq: intel-pstate: Use del_timer_sync in intel_pstate_cpu_exit()
In reply to Thomas GleixnerQuoted 4 lines · Thomas Gleixner
We are about to free the data structure. Make sure no timer callback is running. I might be paranoid, but the ->exit callback can be invoked from so many places, that it is not entirely clear whether
del_timeris always called on the cpu on which it is enqueued.
In normal cases it will be called only when CPU goes offline and I hope that isn't called on the dying CPU.
Quoted 3 lines
While looking through the call sites I noticed, that
cpufreq_init_policy()can fail and invokecpufreq_driver->exit()but it does not return the failure and the callsite happily proceeds.
Thanks for reporting this, will get it fixed.
Quoted 14 lines
Signed-off-by Thomas Gleixner <[email protected]>Cc "Rafael J. Wysocki" <[email protected]>Cc cpufreq <[email protected]>Cc pm <[email protected]>---
drivers/cpufreq/intel_pstate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)Index:
tip/drivers/cpufreq/intel_pstate.c
===================================================================
drivers/cpufreq/intel_pstate.c static int intel_pstate_cpu_exit(struct · line 780
Quoted 5 lines
drivers/cpufreq/intel_pstate.c +1
-1@@ -777,7 +777,7 @@ static int intel_pstate_cpu_exit(struct {int cpu = policy->cpu; -del_timer (&all_cpu_data[cpu]->timer); +del_timer_sync (&all_cpu_data[cpu]->timer);
PATCH 16/16 input: serio: hp_sdc: Use del_timer_sync() in exit path
In reply to Thomas GleixnerMake sure that no callback is running before we teardown the module.
--- drivers/input/serio/hp_sdc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/input/serio/hp_sdc.c +1 -1
@@ -984,7 +984,7 @@ static void hp_sdc_exit(void)free_irq (hp_sdc.irq, &hp_sdc);write_unlock_irq (&hp_sdc.lock); -del_timer (&hp_sdc.kicker); +del_timer_sync (&hp_sdc.kicker);tasklet_kill (&hp_sdc.task);
Re: [patch 16/16] input: serio: hp_sdc: Use del_timer_sync() in exit path
Quoted 2 lines · Thomas Gleixner
Make sure that no callback is running before we teardown the module.
Applied, thank you Thomas.
Quoted 22 lines
Signed-off-by Thomas Gleixner <[email protected]>Cc Dmitry Torokhov <[email protected]>Cc input <[email protected]>--- drivers/input/serio/hp_sdc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)Index:
tip/drivers/input/serio/hp_sdc.c
===================================================================drivers/input/serio/hp_sdc.c +1
-1@@ -984,7 +984,7 @@ static void hp_sdc_exit(void)free_irq (hp_sdc.irq, &hp_sdc);write_unlock_irq (&hp_sdc.lock); -del_timer (&hp_sdc.kicker); +del_timer_sync (&hp_sdc.kicker);tasklet_kill (&hp_sdc.task);
Signature · 1 line
Dmitry
As far as I could tell, (part of) the issue is that any kind of exit or close function should use del_timer_sync, because they could be called from a different CPU than the one that started up the timer?
Here is a semantic patch that takes care of the case of simple module_exit functions:
@r@
declarer name module_exit;
identifier ex;
@@
module_exit(ex);
@@
identifier r.ex;
@@
ex(...) {
<...
- del_timer
+ del_timer_sync
(...)
...>
}
The transformations it makes are below. I haven't had a chance to check which results overlap with what Thomas has already sent, but I could look into it if this is the right idea. I guess other kinds of close/exit functions would have to be identified manually, to make more rules.
In what circumstance can one be sure that two instructions are executed on the same CPU?
julia
arch/mips/lasat/picvue_proc.c +1 -1
@@ -175,7 +175,7 @@ static void pvc_proc_cleanup(void)remove_proc_entry ("scroll" , pvc_display_dir);remove_proc_entry (DISPLAY_DIR_NAME ,NULL ); -del_timer (&timer); +del_timer_sync (&timer); }static int __init pvc_proc_init (void )
drivers/tty/serial/mux.c +1 -1
@@ -613,7 +613,7 @@ static void __exit mux_exit(void) {/* Delete the Mux timer. */ if (port_cnt >0 ) { -del_timer (&mux_timer); +del_timer_sync (&mux_timer);#ifdef CONFIG_SERIAL_MUX_CONSOLE unregister_console (&mux_console);#endif
drivers/input/serio/hp_sdc.c +1 -1
@@ -984,7 +984,7 @@ static void hp_sdc_exit(void)free_irq (hp_sdc.irq, &hp_sdc);write_unlock_irq (&hp_sdc.lock); -del_timer (&hp_sdc.kicker); +del_timer_sync (&hp_sdc.kicker);tasklet_kill (&hp_sdc.task);
drivers/isdn/sc/init.c +2 -2
@@ -390,8 +390,8 @@ static void __exit sc_exit(void)/* * kill the timers */ -del_timer (&(sc_adapter[i]->reset_timer)); -del_timer (&(sc_adapter[i]->stat_timer)); +del_timer_sync (&(sc_adapter[i]->reset_timer)); +del_timer_sync (&(sc_adapter[i]->stat_timer));/* * Tell I4L we're toast
drivers/isdn/i4l/isdn_common.c +1 -1
@@ -2381,7 +2381,7 @@ static void __exit isdn_exit(void) }isdn_tty_exit ();unregister_chrdev (ISDN_MAJOR ,"isdn" ); -del_timer (&dev->timer); +del_timer_sync (&dev->timer);/* call vfree with interrupts enabled, else it will hang */ vfree (dev);printk (KERN_NOTICE "ISDN-subsystem unloaded\n" );
drivers/isdn/hardware/mISDN/hfcpci.c +1 -1
@@ -2352,7 +2352,7 @@ static void __exitHFC_cleanup (void) {if (timer_pending (&hfc_tl)) -del_timer (&hfc_tl); +del_timer_sync (&hfc_tl);pci_unregister_driver (&hfc_driver); }
drivers/isdn/act2000/module.c +1 -1
@@ -796,7 +796,7 @@ static void __exit act2000_exit(void)act2000_card *last;while (card) {unregister_card (card); -del_timer (&card->ptimer); +del_timer_sync (&card->ptimer); card = card->next; } card = cards;
drivers/net/hamradio/yam.c +1 -1
@@ -1184,7 +1184,7 @@ static void __exit yam_cleanup_driver(vostruct yam_mcs *p;int i; -del_timer (&yam_timer); +del_timer_sync (&yam_timer);for (i =0 ; i <NR_PORTS ; i++) {struct net_device *dev = yam_devs[i];if (dev) {
drivers/staging/speakup/main.c +1 -1
@@ -2218,7 +2218,7 @@ static void __exit speakup_exit(void)unregister_keyboard_notifier (&keyboard_notifier_block);unregister_vt_notifier (&vt_notifier_block);speakup_unregister_devsynth (); -del_timer (&cursor_timer); +del_timer_sync (&cursor_timer);kthread_stop (speakup_task); speakup_task =NULL ;mutex_lock (&spk_mutex);
drivers/staging/panel/panel.c +1 -1
@@ -2298,7 +2298,7 @@ static void __exit panel_cleanup_module(unregister_reboot_notifier (&panel_notifier);if (scan_timer.function !=NULL ) -del_timer (&scan_timer); +del_timer_sync (&scan_timer);if (pprt !=NULL ) {if (keypad_enabled) {
drivers/staging/lustre/lustre/llite/super25.c +1 -1
@@ -197,7 +197,7 @@ static void __exit exit_lustre_lite(void {ll_xattr_fini ();vvp_global_fini (); -del_timer (&ll_capa_timer); +del_timer_sync (&ll_capa_timer);ll_capa_thread_stop (); LASSERTF(capa_count[CAPA_SITE_CLIENT] == 0, "client remaining capa count %d\n",
drivers/atm/idt77105.c +2 -2
@@ -369,8 +369,8 @@ EXPORT_SYMBOL(idt77105_init); static void __exit idt77105_exit(void) {/* turn off timers */ -del_timer (&stats_timer); -del_timer (&restart_timer); +del_timer_sync (&stats_timer); +del_timer_sync (&restart_timer); }module_exit (idt77105_exit);
drivers/atm/nicstar.c +1 -1
@@ -306,7 +306,7 @@ static void __exit nicstar_cleanup(void) {XPRINTK ("nicstar: nicstar_cleanup() called.\n" ); -del_timer (&ns_timer); +del_timer_sync (&ns_timer);pci_unregister_driver (&nicstar_driver);
drivers/atm/iphase.c +1 -1
@@ -3289,7 +3289,7 @@ static void __exit ia_module_exit(void) {pci_unregister_driver (&ia_driver); -del_timer (&ia_timer); +del_timer_sync (&ia_timer); }module_init (ia_module_init);
net/hsr/hsr_main.c +1 -1
@@ -459,7 +459,7 @@ static int __init hsr_init(void) static void __exit hsr_exit(void) {unregister_netdevice_notifier (&hsr_nb); -del_timer (&prune_timer); +del_timer_sync (&prune_timer);hsr_netlink_exit ();dev_remove_pack (&hsr_pt); }
net/atm/mpc.c +1 -1
@@ -1492,7 +1492,7 @@ static void __exit atm_mpoa_cleanup(voidmpc_proc_clean (); -del_timer (&mpc_timer); +del_timer_sync (&mpc_timer);unregister_netdevice_notifier (&mpoa_notifier);deregister_atm_ioctl (&atm_ioctl_ops);
Quoted 22 lines · Julia Lawall
As far as I could tell, (part of) the issue is that any kind of exit or close function should use
del_timer_sync, because they could be called from a different CPU than the one that started up the timer?Here is a semantic patch that takes care of the case of simple
module_exitfunctions:@r@
declarer namemodule_exit;
identifier ex;
@@
module_exit(ex);@@
identifier r.ex;
@@ex(...) {
<...
-del_timer
+del_timer_sync
Quoted 6 lines
(...)...>
}The transformations it makes are below. I haven't had a chance to check which results overlap with what Thomas has already sent, but I could look
Minimal overlap, but as I said I did just a few conversions.
Quoted 2 lines
into it if this is the right idea. I guess other kinds of close/exit functions would have to be identified manually, to make more rules.
If you look through the examples I sent, you'll find the close() callbacks of various devices. So everything which is a function pointer to a ops->close(), ops->remove(), ops_>teardown() is dangerous if using del_timer(). There are a few exceptions, but....
Another thing I saw is
del_timer(&bla->timer); .... kfree(&bla);
That's also a potential source of trouble. You can't tell without analyzing the code, whether it's a problem or not. But making the responsible people to look at it is definitely a good thing.
Quoted 2 lines
In what circumstance can one be sure that two instructions are executed on the same CPU?
If interrupts or preemption are disabled. But that's not the issue at hand.
The del_timer vs. del_timer_sync problem is:
CPU0 CPU1
add_timer(&bla->timer);
close(bla)
timer expires del_timer(&bla->timer);
callback is invoked
kfree(bla);
derefernces blaI'll look at your findings on Tuesday, but feel free to send them to the relevant maintainers for review.
Thanks,
tglx
Quoted 62 lines · Thomas Gleixner
Quoted 22 lines · Julia Lawall
As far as I could tell, (part of) the issue is that any kind of exit or close function should use
del_timer_sync, because they could be called from a different CPU than the one that started up the timer?Here is a semantic patch that takes care of the case of simple
module_exitfunctions:@r@
declarer namemodule_exit;
identifier ex;
@@
module_exit(ex);@@
identifier r.ex;
@@ex(...) {
<...
-del_timer
+del_timer_syncQuoted 6 lines
(...)...>
}The transformations it makes are below. I haven't had a chance to check which results overlap with what Thomas has already sent, but I could look
Minimal overlap, but as I said I did just a few conversions.
Quoted 2 lines
into it if this is the right idea. I guess other kinds of close/exit functions would have to be identified manually, to make more rules.
If you look through the examples I sent, you'll find the
close()callbacks of various devices. So everything which is a function pointer to aops->close(),ops->remove(), ops_>teardown() is dangerous if usingdel_timer(). There are a few exceptions, but....Another thing I saw is
del_timer(&bla->timer); .... kfree(&bla);That's also a potential source of trouble. You can't tell without analyzing the code, whether it's a problem or not. But making the responsible people to look at it is definitely a good thing.
Quoted 2 lines
In what circumstance can one be sure that two instructions are executed on the same CPU?
If interrupts or preemption are disabled. But that's not the issue at hand.
The
del_timervs.del_timer_syncproblem is:CPU0 CPU1
add_timer(&bla->timer);
Quoted 8 lines
close(bla)
timer expiresdel_timer(&bla->timer);
callback is invokedkfree(bla); derefernces blaI'll look at your findings on Tuesday, but feel free to send them to the relevant maintainers for review.
Thanks for all of the suggestions!
julia
Quoted 5 lines
Another thing I saw is
del_timer(&bla->timer); .... kfree(&bla);
In one case I saw the following:
if (isac->dch.timer.function != NULL) {
del_timer(&isac->dch.timer);
isac->dch.timer.function = NULL;
}
kfree(isac->mon_rx);
isac->mon_rx = NULL;Is the assignment isac->dch.timer.function = NULL good enough to solve the problem?
julia
Quoted 15 lines · Julia Lawall
Quoted 5 lines
Another thing I saw is
del_timer(&bla->timer); .... kfree(&bla);In one case I saw the following:
if (isac->dch.timer.function != NULL) { del_timer(&isac->dch.timer); isac->dch.timer.function = NULL; } kfree(isac->mon_rx); isac->mon_rx = NULL;
Quoted 2 lines
Is the assignment
isac->dch.timer.function= NULL good enough to solve the problem?
No. It might lead to a NULL dereference when the other core wants to call the callback. Same situation as in the other picture.
Thanks,
tglx
arch/mips/lasat/picvue_proc.c static void pvc_proc_cleanup(void) · line 178
Quoted 9 lines · Julia Lawall
diff -u -p
a/arch/mips/lasat/picvue_proc.cb/arch/mips/lasat/picvue_proc.carch/mips/lasat/picvue_proc.c +1
-1@@ -175,7 +175,7 @@ static void pvc_proc_cleanup(void)remove_proc_entry ("scroll" , pvc_display_dir);remove_proc_entry (DISPLAY_DIR_NAME ,NULL ); -del_timer (&timer); +del_timer_sync (&timer);
Correct.
drivers/tty/serial/mux.c static void __exit mux_exit(void) · line 616
Quoted 12 lines
arch/mips/lasat/picvue_proc.c +0
-0}static int __init pvc_proc_init (void )diff -u -p
a/drivers/tty/serial/mux.cb/drivers/tty/serial/mux.cdrivers/tty/serial/mux.c +1
-1@@ -613,7 +613,7 @@ static void __exit mux_exit(void) {/* Delete the Mux timer. */ if (port_cnt >0 ) { -del_timer (&mux_timer); +del_timer_sync (&mux_timer);
Correct.
drivers/input/serio/hp_sdc.c static void hp_sdc_exit(void) · line 987
Quoted 12 lines
drivers/tty/serial/mux.c +0
-0#ifdef CONFIG_SERIAL_MUX_CONSOLE unregister_console (&mux_console);#endif diff -u -p
a/drivers/input/serio/hp_sdc.cb/drivers/input/serio/hp_sdc.cdrivers/input/serio/hp_sdc.c +1
-1@@ -984,7 +984,7 @@ static void hp_sdc_exit(void)free_irq (hp_sdc.irq, &hp_sdc);write_unlock_irq (&hp_sdc.lock); -del_timer (&hp_sdc.kicker); +del_timer_sync (&hp_sdc.kicker);
Correct.
drivers/isdn/sc/init.c static void __exit sc_exit(void) · line 394
Quoted 13 lines
drivers/input/serio/hp_sdc.c +0
-0tasklet_kill (&hp_sdc.task);diff -u -p
a/drivers/isdn/sc/init.cb/drivers/isdn/sc/init.cdrivers/isdn/sc/init.c +2
-2@@ -390,8 +390,8 @@ static void __exit sc_exit(void)/* * kill the timers */ -del_timer (&(sc_adapter[i]->reset_timer)); -del_timer (&(sc_adapter[i]->stat_timer)); +del_timer_sync (&(sc_adapter[i]->reset_timer)); +del_timer_sync (&(sc_adapter[i]->stat_timer));
Correct.
drivers/isdn/i4l/isdn_common.c static void __exit isdn_exit(void) · line 2384
Quoted 11 lines
drivers/isdn/sc/init.c +0
-0/* * Tell I4L we're toast diff -u -p
a/drivers/isdn/i4l/isdn_common.cb/drivers/isdn/i4l/isdn_common.cdrivers/isdn/i4l/isdn_common.c +1
-1@@ -2381,7 +2381,7 @@ static void __exit isdn_exit(void) }isdn_tty_exit ();unregister_chrdev (ISDN_MAJOR ,"isdn" ); -del_timer (&dev->timer); +del_timer_sync (&dev->timer);
Correct.
drivers/isdn/hardware/mISDN/hfcpci.c static void __exit · line 2355
Quoted 12 lines
drivers/isdn/i4l/isdn_common.c +0
-0/* call vfree with interrupts enabled, else it will hang */ vfree (dev);printk (KERN_NOTICE "ISDN-subsystem unloaded\n" );diff -u -p
a/drivers/isdn/hardware/mISDN/hfcpci.cb/drivers/isdn/hardware/mISDN/hfcpci.cdrivers/isdn/hardware/mISDN/hfcpci.c +1
-1@@ -2352,7 +2352,7 @@ static void __exitHFC_cleanup (void) {if (timer_pending (&hfc_tl)) -del_timer (&hfc_tl); +del_timer_sync (&hfc_tl);
That's incomplete the timer_pending() check is racy as well and the timer is rearming itself from the callback.
drivers/isdn/act2000/module.c static void __exit act2000_exit(void) · line 799
Quoted 11 lines
drivers/isdn/hardware/mISDN/hfcpci.c +0
-0pci_unregister_driver (&hfc_driver); }diff -u -p
a/drivers/isdn/act2000/module.cb/drivers/isdn/act2000/module.cdrivers/isdn/act2000/module.c +1
-1@@ -796,7 +796,7 @@ static void __exit act2000_exit(void)act2000_card *last;while (card) {unregister_card (card); -del_timer (&card->ptimer); +del_timer_sync (&card->ptimer);
Correct.
drivers/net/hamradio/yam.c static void __exit yam_cleanup_driver(vo · line 1187
Quoted 12 lines
drivers/isdn/act2000/module.c +0
-0card = card->next; } card = cards;diff -u -p
a/drivers/net/hamradio/yam.cb/drivers/net/hamradio/yam.cdrivers/net/hamradio/yam.c +1
-1@@ -1184,7 +1184,7 @@ static void __exit yam_cleanup_driver(vostruct yam_mcs *p;int i; -del_timer (&yam_timer); +del_timer_sync (&yam_timer);
Correct.
drivers/staging/speakup/main.c static void __exit speakup_exit(void) · line 2221
Quoted 12 lines
drivers/net/hamradio/yam.c +0
-0for (i =0 ; i <NR_PORTS ; i++) {struct net_device *dev = yam_devs[i];if (dev) {diff -u -p
a/drivers/staging/speakup/main.cb/drivers/staging/speakup/main.cdrivers/staging/speakup/main.c +1
-1@@ -2218,7 +2218,7 @@ static void __exit speakup_exit(void)unregister_keyboard_notifier (&keyboard_notifier_block);unregister_vt_notifier (&vt_notifier_block);speakup_unregister_devsynth (); -del_timer (&cursor_timer); +del_timer_sync (&cursor_timer);
Not sure about that one as the timer might be rearmed, so the invocation might need to be further down the cleanup path.
drivers/staging/panel/panel.c static void __exit panel_cleanup_module( · line 2301
Quoted 12 lines
drivers/staging/speakup/main.c +0
-0kthread_stop (speakup_task); speakup_task =NULL ;mutex_lock (&spk_mutex);diff -u -p
a/drivers/staging/panel/panel.cb/drivers/staging/panel/panel.cdrivers/staging/panel/panel.c +1
-1@@ -2298,7 +2298,7 @@ static void __exit panel_cleanup_module(unregister_reboot_notifier (&panel_notifier);if (scan_timer.function !=NULL ) -del_timer (&scan_timer); +del_timer_sync (&scan_timer);
Correct.
drivers/staging/lustre/lustre/llite/super25.c static void __exit exit_lustre_lite(void · line 200
Quoted 11 lines
drivers/staging/panel/panel.c +0
-0if (pprt !=NULL ) {if (keypad_enabled) {diff -u -p
a/drivers/staging/lustre/lustre/llite/super25.cb/drivers/staging/lustre/lustre/llite/super25.cdrivers/staging/lustre/lustre/llite/super25.c +1
-1@@ -197,7 +197,7 @@ static void __exit exit_lustre_lite(void {ll_xattr_fini ();vvp_global_fini (); -del_timer (&ll_capa_timer); +del_timer_sync (&ll_capa_timer);
Looks wrong, as the timer might be rearmed by the thread which is not yet stopped.
Quoted 7 lines
drivers/staging/lustre/lustre/llite/super25.c +0
-0ll_capa_thread_stop (); LASSERTF(capa_count[CAPA_SITE_CLIENT] == 0, "client remaining capa count %d\n",diff -u -p
a/drivers/atm/idt77105.cb/drivers/atm/idt77105.c
drivers/atm/idt77105.c EXPORT_SYMBOL(idt77105_init); · line 373
Quoted 7 lines
drivers/atm/idt77105.c +2
-2@@ -369,8 +369,8 @@ EXPORT_SYMBOL(idt77105_init); static void __exit idt77105_exit(void) {/* turn off timers */ -del_timer (&stats_timer); -del_timer (&restart_timer); +del_timer_sync (&stats_timer); +del_timer_sync (&restart_timer);
Yep.
drivers/atm/nicstar.c static void __exit nicstar_cleanup(void) · line 310
Quoted 13 lines
drivers/atm/idt77105.c +0
-0}module_exit (idt77105_exit);diff -u -p
a/drivers/atm/nicstar.cb/drivers/atm/nicstar.cdrivers/atm/nicstar.c +1
-1@@ -306,7 +306,7 @@ static void __exit nicstar_cleanup(void) {XPRINTK ("nicstar: nicstar_cleanup() called.\n" ); -del_timer (&ns_timer); +del_timer_sync (&ns_timer);
The driver might still be in use, as the devices are shut down via the pci_unregister_driver() call below. So while it's correct to use del_timer_sync() it's not clear w/o digging deeper into the code whether it's actually sufficient.
drivers/atm/iphase.c static void __exit ia_module_exit(void) · line 3292
Quoted 11 lines
drivers/atm/nicstar.c +0
-0pci_unregister_driver (&nicstar_driver);diff -u -p
a/drivers/atm/iphase.cb/drivers/atm/iphase.cdrivers/atm/iphase.c +1
-1@@ -3289,7 +3289,7 @@ static void __exit ia_module_exit(void) {pci_unregister_driver (&ia_driver); -del_timer (&ia_timer); +del_timer_sync (&ia_timer);
The timer is self rearming and has protection against the removal of the devices. So it should be fine.
net/hsr/hsr_main.c static int __init hsr_init(void) · line 462
Quoted 12 lines
drivers/atm/iphase.c +0
-0}module_init (ia_module_init);diff -u -p
a/net/hsr/hsr_main.cb/net/hsr/hsr_main.cnet/hsr/hsr_main.c +1
-1@@ -459,7 +459,7 @@ static int __init hsr_init(void) static void __exit hsr_exit(void) {unregister_netdevice_notifier (&hsr_nb); -del_timer (&prune_timer); +del_timer_sync (&prune_timer);
Correct as the only rearm is from the timer callback itself
net/atm/mpc.c static void __exit atm_mpoa_cleanup(void · line 1495
Quoted 12 lines
net/hsr/hsr_main.c +0
-0hsr_netlink_exit ();dev_remove_pack (&hsr_pt); }diff -u -p
a/net/atm/mpc.cb/net/atm/mpc.cnet/atm/mpc.c +1
-1@@ -1492,7 +1492,7 @@ static void __exit atm_mpoa_cleanup(voidmpc_proc_clean (); -del_timer (&mpc_timer); +del_timer_sync (&mpc_timer);
Looks correct as well. Timer is rearming no other dependencies.
net/atm/mpc.c static void __exit atm_mpoa_cleanup(void · line 1497
Quoted 2 lines
net/atm/mpc.c +0
-0unregister_netdevice_notifier (&mpoa_notifier);deregister_atm_ioctl (&atm_ioctl_ops);
Thanks,
tglx
Thanks. I haven't had time to send them out, but I could do so tomorrow afternoon.
julia
Quoted 253 lines · Thomas Gleixner
arch/mips/lasat/picvue_proc.c static void pvc_proc_cleanup(void) · line 178
Quoted 9 lines · Julia Lawall
diff -u -p
a/arch/mips/lasat/picvue_proc.cb/arch/mips/lasat/picvue_proc.carch/mips/lasat/picvue_proc.c +1
-1@@ -175,7 +175,7 @@ static void pvc_proc_cleanup(void)remove_proc_entry ("scroll" , pvc_display_dir);remove_proc_entry (DISPLAY_DIR_NAME ,NULL ); -del_timer (&timer); +del_timer_sync (&timer);Correct.
drivers/tty/serial/mux.c static void __exit mux_exit(void) · line 616
Quoted 12 lines
arch/mips/lasat/picvue_proc.c +0
-0}static int __init pvc_proc_init (void )diff -u -p
a/drivers/tty/serial/mux.cb/drivers/tty/serial/mux.cdrivers/tty/serial/mux.c +1
-1@@ -613,7 +613,7 @@ static void __exit mux_exit(void) {/* Delete the Mux timer. */ if (port_cnt >0 ) { -del_timer (&mux_timer); +del_timer_sync (&mux_timer);Correct.
drivers/input/serio/hp_sdc.c static void hp_sdc_exit(void) · line 987
Quoted 12 lines
drivers/tty/serial/mux.c +0
-0#ifdef CONFIG_SERIAL_MUX_CONSOLE unregister_console (&mux_console);#endif diff -u -p
a/drivers/input/serio/hp_sdc.cb/drivers/input/serio/hp_sdc.cdrivers/input/serio/hp_sdc.c +1
-1@@ -984,7 +984,7 @@ static void hp_sdc_exit(void)free_irq (hp_sdc.irq, &hp_sdc);write_unlock_irq (&hp_sdc.lock); -del_timer (&hp_sdc.kicker); +del_timer_sync (&hp_sdc.kicker);Correct.
drivers/isdn/sc/init.c static void __exit sc_exit(void) · line 394
Quoted 13 lines
drivers/input/serio/hp_sdc.c +0
-0tasklet_kill (&hp_sdc.task);diff -u -p
a/drivers/isdn/sc/init.cb/drivers/isdn/sc/init.cdrivers/isdn/sc/init.c +2
-2@@ -390,8 +390,8 @@ static void __exit sc_exit(void)/* * kill the timers */ -del_timer (&(sc_adapter[i]->reset_timer)); -del_timer (&(sc_adapter[i]->stat_timer)); +del_timer_sync (&(sc_adapter[i]->reset_timer)); +del_timer_sync (&(sc_adapter[i]->stat_timer));Correct.
drivers/isdn/i4l/isdn_common.c static void __exit isdn_exit(void) · line 2384
Quoted 11 lines
drivers/isdn/sc/init.c +0
-0/* * Tell I4L we're toast diff -u -p
a/drivers/isdn/i4l/isdn_common.cb/drivers/isdn/i4l/isdn_common.cdrivers/isdn/i4l/isdn_common.c +1
-1@@ -2381,7 +2381,7 @@ static void __exit isdn_exit(void) }isdn_tty_exit ();unregister_chrdev (ISDN_MAJOR ,"isdn" ); -del_timer (&dev->timer); +del_timer_sync (&dev->timer);Correct.
drivers/isdn/hardware/mISDN/hfcpci.c static void __exit · line 2355
Quoted 12 lines
drivers/isdn/i4l/isdn_common.c +0
-0/* call vfree with interrupts enabled, else it will hang */ vfree (dev);printk (KERN_NOTICE "ISDN-subsystem unloaded\n" );diff -u -p
a/drivers/isdn/hardware/mISDN/hfcpci.cb/drivers/isdn/hardware/mISDN/hfcpci.cdrivers/isdn/hardware/mISDN/hfcpci.c +1
-1@@ -2352,7 +2352,7 @@ static void __exitHFC_cleanup (void) {if (timer_pending (&hfc_tl)) -del_timer (&hfc_tl); +del_timer_sync (&hfc_tl);That's incomplete the
timer_pending()check is racy as well and the timer is rearming itself from the callback.drivers/isdn/act2000/module.c static void __exit act2000_exit(void) · line 799
Quoted 11 lines
drivers/isdn/hardware/mISDN/hfcpci.c +0
-0pci_unregister_driver (&hfc_driver); }diff -u -p
a/drivers/isdn/act2000/module.cb/drivers/isdn/act2000/module.cdrivers/isdn/act2000/module.c +1
-1@@ -796,7 +796,7 @@ static void __exit act2000_exit(void)act2000_card *last;while (card) {unregister_card (card); -del_timer (&card->ptimer); +del_timer_sync (&card->ptimer);Correct.
drivers/net/hamradio/yam.c static void __exit yam_cleanup_driver(vo · line 1187
Quoted 12 lines
drivers/isdn/act2000/module.c +0
-0card = card->next; } card = cards;diff -u -p
a/drivers/net/hamradio/yam.cb/drivers/net/hamradio/yam.cdrivers/net/hamradio/yam.c +1
-1@@ -1184,7 +1184,7 @@ static void __exit yam_cleanup_driver(vostruct yam_mcs *p;int i; -del_timer (&yam_timer); +del_timer_sync (&yam_timer);Correct.
drivers/staging/speakup/main.c static void __exit speakup_exit(void) · line 2221
Quoted 12 lines
drivers/net/hamradio/yam.c +0
-0for (i =0 ; i <NR_PORTS ; i++) {struct net_device *dev = yam_devs[i];if (dev) {diff -u -p
a/drivers/staging/speakup/main.cb/drivers/staging/speakup/main.cdrivers/staging/speakup/main.c +1
-1@@ -2218,7 +2218,7 @@ static void __exit speakup_exit(void)unregister_keyboard_notifier (&keyboard_notifier_block);unregister_vt_notifier (&vt_notifier_block);speakup_unregister_devsynth (); -del_timer (&cursor_timer); +del_timer_sync (&cursor_timer);Not sure about that one as the timer might be rearmed, so the invocation might need to be further down the cleanup path.
drivers/staging/panel/panel.c static void __exit panel_cleanup_module( · line 2301
Quoted 12 lines
drivers/staging/speakup/main.c +0
-0kthread_stop (speakup_task); speakup_task =NULL ;mutex_lock (&spk_mutex);diff -u -p
a/drivers/staging/panel/panel.cb/drivers/staging/panel/panel.cdrivers/staging/panel/panel.c +1
-1@@ -2298,7 +2298,7 @@ static void __exit panel_cleanup_module(unregister_reboot_notifier (&panel_notifier);if (scan_timer.function !=NULL ) -del_timer (&scan_timer); +del_timer_sync (&scan_timer);Correct.
drivers/staging/lustre/lustre/llite/super25.c static void __exit exit_lustre_lite(void · line 200
Quoted 11 lines
drivers/staging/panel/panel.c +0
-0if (pprt !=NULL ) {if (keypad_enabled) {diff -u -p
a/drivers/staging/lustre/lustre/llite/super25.cb/drivers/staging/lustre/lustre/llite/super25.cdrivers/staging/lustre/lustre/llite/super25.c +1
-1@@ -197,7 +197,7 @@ static void __exit exit_lustre_lite(void {ll_xattr_fini ();vvp_global_fini (); -del_timer (&ll_capa_timer); +del_timer_sync (&ll_capa_timer);Looks wrong, as the timer might be rearmed by the thread which is not yet stopped.
Quoted 7 lines
drivers/staging/lustre/lustre/llite/super25.c +0
-0ll_capa_thread_stop (); LASSERTF(capa_count[CAPA_SITE_CLIENT] == 0, "client remaining capa count %d\n",diff -u -p
a/drivers/atm/idt77105.cb/drivers/atm/idt77105.cdrivers/atm/idt77105.c EXPORT_SYMBOL(idt77105_init); · line 373
Quoted 7 lines
drivers/atm/idt77105.c +2
-2@@ -369,8 +369,8 @@ EXPORT_SYMBOL(idt77105_init); static void __exit idt77105_exit(void) {/* turn off timers */ -del_timer (&stats_timer); -del_timer (&restart_timer); +del_timer_sync (&stats_timer); +del_timer_sync (&restart_timer);Yep.
drivers/atm/nicstar.c static void __exit nicstar_cleanup(void) · line 310
Quoted 13 lines
drivers/atm/idt77105.c +0
-0}module_exit (idt77105_exit);diff -u -p
a/drivers/atm/nicstar.cb/drivers/atm/nicstar.cdrivers/atm/nicstar.c +1
-1@@ -306,7 +306,7 @@ static void __exit nicstar_cleanup(void) {XPRINTK ("nicstar: nicstar_cleanup() called.\n" ); -del_timer (&ns_timer); +del_timer_sync (&ns_timer);The driver might still be in use, as the devices are shut down via the
pci_unregister_driver()call below. So while it's correct to usedel_timer_sync()it's not clear w/o digging deeper into the code whether it's actually sufficient.drivers/atm/iphase.c static void __exit ia_module_exit(void) · line 3292
Quoted 11 lines
drivers/atm/nicstar.c +0
-0pci_unregister_driver (&nicstar_driver);diff -u -p
a/drivers/atm/iphase.cb/drivers/atm/iphase.cdrivers/atm/iphase.c +1
-1@@ -3289,7 +3289,7 @@ static void __exit ia_module_exit(void) {pci_unregister_driver (&ia_driver); -del_timer (&ia_timer); +del_timer_sync (&ia_timer);The timer is self rearming and has protection against the removal of the devices. So it should be fine.
net/hsr/hsr_main.c static int __init hsr_init(void) · line 462
Quoted 12 lines
drivers/atm/iphase.c +0
-0}module_init (ia_module_init);diff -u -p
a/net/hsr/hsr_main.cb/net/hsr/hsr_main.cnet/hsr/hsr_main.c +1
-1@@ -459,7 +459,7 @@ static int __init hsr_init(void) static void __exit hsr_exit(void) {unregister_netdevice_notifier (&hsr_nb); -del_timer (&prune_timer); +del_timer_sync (&prune_timer);Correct as the only rearm is from the timer callback itself
net/atm/mpc.c static void __exit atm_mpoa_cleanup(void · line 1495
Quoted 12 lines
net/hsr/hsr_main.c +0
-0hsr_netlink_exit ();dev_remove_pack (&hsr_pt); }diff -u -p
a/net/atm/mpc.cb/net/atm/mpc.cnet/atm/mpc.c +1
-1@@ -1492,7 +1492,7 @@ static void __exit atm_mpoa_cleanup(voidmpc_proc_clean (); -del_timer (&mpc_timer); +del_timer_sync (&mpc_timer);Looks correct as well. Timer is rearming no other dependencies.
net/atm/mpc.c static void __exit atm_mpoa_cleanup(void · line 1497
Quoted 2 lines
net/atm/mpc.c +0
-0unregister_netdevice_notifier (&mpoa_notifier);deregister_atm_ioctl (&atm_ioctl_ops);Thanks,
tglx
I was looking at some cases that are marked as possibly insufficient. Is the issue that mod_timer or add_timer is called in some function that is not the timer interrupt handler (or the function that starts the timer running in the first place)?
julia
Quoted 253 lines · Thomas Gleixner
arch/mips/lasat/picvue_proc.c static void pvc_proc_cleanup(void) · line 178
Quoted 9 lines · Julia Lawall
diff -u -p
a/arch/mips/lasat/picvue_proc.cb/arch/mips/lasat/picvue_proc.carch/mips/lasat/picvue_proc.c +1
-1@@ -175,7 +175,7 @@ static void pvc_proc_cleanup(void)remove_proc_entry ("scroll" , pvc_display_dir);remove_proc_entry (DISPLAY_DIR_NAME ,NULL ); -del_timer (&timer); +del_timer_sync (&timer);Correct.
drivers/tty/serial/mux.c static void __exit mux_exit(void) · line 616
Quoted 12 lines
arch/mips/lasat/picvue_proc.c +0
-0}static int __init pvc_proc_init (void )diff -u -p
a/drivers/tty/serial/mux.cb/drivers/tty/serial/mux.cdrivers/tty/serial/mux.c +1
-1@@ -613,7 +613,7 @@ static void __exit mux_exit(void) {/* Delete the Mux timer. */ if (port_cnt >0 ) { -del_timer (&mux_timer); +del_timer_sync (&mux_timer);Correct.
drivers/input/serio/hp_sdc.c static void hp_sdc_exit(void) · line 987
Quoted 12 lines
drivers/tty/serial/mux.c +0
-0#ifdef CONFIG_SERIAL_MUX_CONSOLE unregister_console (&mux_console);#endif diff -u -p
a/drivers/input/serio/hp_sdc.cb/drivers/input/serio/hp_sdc.cdrivers/input/serio/hp_sdc.c +1
-1@@ -984,7 +984,7 @@ static void hp_sdc_exit(void)free_irq (hp_sdc.irq, &hp_sdc);write_unlock_irq (&hp_sdc.lock); -del_timer (&hp_sdc.kicker); +del_timer_sync (&hp_sdc.kicker);Correct.
drivers/isdn/sc/init.c static void __exit sc_exit(void) · line 394
Quoted 13 lines
drivers/input/serio/hp_sdc.c +0
-0tasklet_kill (&hp_sdc.task);diff -u -p
a/drivers/isdn/sc/init.cb/drivers/isdn/sc/init.cdrivers/isdn/sc/init.c +2
-2@@ -390,8 +390,8 @@ static void __exit sc_exit(void)/* * kill the timers */ -del_timer (&(sc_adapter[i]->reset_timer)); -del_timer (&(sc_adapter[i]->stat_timer)); +del_timer_sync (&(sc_adapter[i]->reset_timer)); +del_timer_sync (&(sc_adapter[i]->stat_timer));Correct.
drivers/isdn/i4l/isdn_common.c static void __exit isdn_exit(void) · line 2384
Quoted 11 lines
drivers/isdn/sc/init.c +0
-0/* * Tell I4L we're toast diff -u -p
a/drivers/isdn/i4l/isdn_common.cb/drivers/isdn/i4l/isdn_common.cdrivers/isdn/i4l/isdn_common.c +1
-1@@ -2381,7 +2381,7 @@ static void __exit isdn_exit(void) }isdn_tty_exit ();unregister_chrdev (ISDN_MAJOR ,"isdn" ); -del_timer (&dev->timer); +del_timer_sync (&dev->timer);Correct.
drivers/isdn/hardware/mISDN/hfcpci.c static void __exit · line 2355
Quoted 12 lines
drivers/isdn/i4l/isdn_common.c +0
-0/* call vfree with interrupts enabled, else it will hang */ vfree (dev);printk (KERN_NOTICE "ISDN-subsystem unloaded\n" );diff -u -p
a/drivers/isdn/hardware/mISDN/hfcpci.cb/drivers/isdn/hardware/mISDN/hfcpci.cdrivers/isdn/hardware/mISDN/hfcpci.c +1
-1@@ -2352,7 +2352,7 @@ static void __exitHFC_cleanup (void) {if (timer_pending (&hfc_tl)) -del_timer (&hfc_tl); +del_timer_sync (&hfc_tl);That's incomplete the
timer_pending()check is racy as well and the timer is rearming itself from the callback.drivers/isdn/act2000/module.c static void __exit act2000_exit(void) · line 799
Quoted 11 lines
drivers/isdn/hardware/mISDN/hfcpci.c +0
-0pci_unregister_driver (&hfc_driver); }diff -u -p
a/drivers/isdn/act2000/module.cb/drivers/isdn/act2000/module.cdrivers/isdn/act2000/module.c +1
-1@@ -796,7 +796,7 @@ static void __exit act2000_exit(void)act2000_card *last;while (card) {unregister_card (card); -del_timer (&card->ptimer); +del_timer_sync (&card->ptimer);Correct.
drivers/net/hamradio/yam.c static void __exit yam_cleanup_driver(vo · line 1187
Quoted 12 lines
drivers/isdn/act2000/module.c +0
-0card = card->next; } card = cards;diff -u -p
a/drivers/net/hamradio/yam.cb/drivers/net/hamradio/yam.cdrivers/net/hamradio/yam.c +1
-1@@ -1184,7 +1184,7 @@ static void __exit yam_cleanup_driver(vostruct yam_mcs *p;int i; -del_timer (&yam_timer); +del_timer_sync (&yam_timer);Correct.
drivers/staging/speakup/main.c static void __exit speakup_exit(void) · line 2221
Quoted 12 lines
drivers/net/hamradio/yam.c +0
-0for (i =0 ; i <NR_PORTS ; i++) {struct net_device *dev = yam_devs[i];if (dev) {diff -u -p
a/drivers/staging/speakup/main.cb/drivers/staging/speakup/main.cdrivers/staging/speakup/main.c +1
-1@@ -2218,7 +2218,7 @@ static void __exit speakup_exit(void)unregister_keyboard_notifier (&keyboard_notifier_block);unregister_vt_notifier (&vt_notifier_block);speakup_unregister_devsynth (); -del_timer (&cursor_timer); +del_timer_sync (&cursor_timer);Not sure about that one as the timer might be rearmed, so the invocation might need to be further down the cleanup path.
drivers/staging/panel/panel.c static void __exit panel_cleanup_module( · line 2301
Quoted 12 lines
drivers/staging/speakup/main.c +0
-0kthread_stop (speakup_task); speakup_task =NULL ;mutex_lock (&spk_mutex);diff -u -p
a/drivers/staging/panel/panel.cb/drivers/staging/panel/panel.cdrivers/staging/panel/panel.c +1
-1@@ -2298,7 +2298,7 @@ static void __exit panel_cleanup_module(unregister_reboot_notifier (&panel_notifier);if (scan_timer.function !=NULL ) -del_timer (&scan_timer); +del_timer_sync (&scan_timer);Correct.
drivers/staging/lustre/lustre/llite/super25.c static void __exit exit_lustre_lite(void · line 200
Quoted 11 lines
drivers/staging/panel/panel.c +0
-0if (pprt !=NULL ) {if (keypad_enabled) {diff -u -p
a/drivers/staging/lustre/lustre/llite/super25.cb/drivers/staging/lustre/lustre/llite/super25.cdrivers/staging/lustre/lustre/llite/super25.c +1
-1@@ -197,7 +197,7 @@ static void __exit exit_lustre_lite(void {ll_xattr_fini ();vvp_global_fini (); -del_timer (&ll_capa_timer); +del_timer_sync (&ll_capa_timer);Looks wrong, as the timer might be rearmed by the thread which is not yet stopped.
Quoted 7 lines
drivers/staging/lustre/lustre/llite/super25.c +0
-0ll_capa_thread_stop (); LASSERTF(capa_count[CAPA_SITE_CLIENT] == 0, "client remaining capa count %d\n",diff -u -p
a/drivers/atm/idt77105.cb/drivers/atm/idt77105.cdrivers/atm/idt77105.c EXPORT_SYMBOL(idt77105_init); · line 373
Quoted 7 lines
drivers/atm/idt77105.c +2
-2@@ -369,8 +369,8 @@ EXPORT_SYMBOL(idt77105_init); static void __exit idt77105_exit(void) {/* turn off timers */ -del_timer (&stats_timer); -del_timer (&restart_timer); +del_timer_sync (&stats_timer); +del_timer_sync (&restart_timer);Yep.
drivers/atm/nicstar.c static void __exit nicstar_cleanup(void) · line 310
Quoted 13 lines
drivers/atm/idt77105.c +0
-0}module_exit (idt77105_exit);diff -u -p
a/drivers/atm/nicstar.cb/drivers/atm/nicstar.cdrivers/atm/nicstar.c +1
-1@@ -306,7 +306,7 @@ static void __exit nicstar_cleanup(void) {XPRINTK ("nicstar: nicstar_cleanup() called.\n" ); -del_timer (&ns_timer); +del_timer_sync (&ns_timer);The driver might still be in use, as the devices are shut down via the
pci_unregister_driver()call below. So while it's correct to usedel_timer_sync()it's not clear w/o digging deeper into the code whether it's actually sufficient.drivers/atm/iphase.c static void __exit ia_module_exit(void) · line 3292
Quoted 11 lines
drivers/atm/nicstar.c +0
-0pci_unregister_driver (&nicstar_driver);diff -u -p
a/drivers/atm/iphase.cb/drivers/atm/iphase.cdrivers/atm/iphase.c +1
-1@@ -3289,7 +3289,7 @@ static void __exit ia_module_exit(void) {pci_unregister_driver (&ia_driver); -del_timer (&ia_timer); +del_timer_sync (&ia_timer);The timer is self rearming and has protection against the removal of the devices. So it should be fine.
net/hsr/hsr_main.c static int __init hsr_init(void) · line 462
Quoted 12 lines
drivers/atm/iphase.c +0
-0}module_init (ia_module_init);diff -u -p
a/net/hsr/hsr_main.cb/net/hsr/hsr_main.cnet/hsr/hsr_main.c +1
-1@@ -459,7 +459,7 @@ static int __init hsr_init(void) static void __exit hsr_exit(void) {unregister_netdevice_notifier (&hsr_nb); -del_timer (&prune_timer); +del_timer_sync (&prune_timer);Correct as the only rearm is from the timer callback itself
net/atm/mpc.c static void __exit atm_mpoa_cleanup(void · line 1495
Quoted 12 lines
net/hsr/hsr_main.c +0
-0hsr_netlink_exit ();dev_remove_pack (&hsr_pt); }diff -u -p
a/net/atm/mpc.cb/net/atm/mpc.cnet/atm/mpc.c +1
-1@@ -1492,7 +1492,7 @@ static void __exit atm_mpoa_cleanup(voidmpc_proc_clean (); -del_timer (&mpc_timer); +del_timer_sync (&mpc_timer);Looks correct as well. Timer is rearming no other dependencies.
net/atm/mpc.c static void __exit atm_mpoa_cleanup(void · line 1497
Quoted 2 lines
net/atm/mpc.c +0
-0unregister_netdevice_notifier (&mpoa_notifier);deregister_atm_ioctl (&atm_ioctl_ops);Thanks,
tglx