From 24ef92f0974bf26cf8ca949b7ae21286cbca3fd3 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 5 Mar 2009 09:39:30 +0000 Subject: Fix race in infrared polling on rmmod From: Jean Delvare The race on rmmod I just fixed in cx88-input affects 3 other drivers. Fix these the same way. Signed-off-by: Jean Delvare Signed-off-by: Mauro Carvalho Chehab --- linux/drivers/media/video/em28xx/em28xx-input.c | 25 ++++++++++++++++++++----- linux/drivers/media/video/ir-kbd-i2c.c | 21 ++++++++++++++++----- linux/drivers/media/video/saa6588.c | 25 ++++++++++++++++++++----- 3 files changed, 56 insertions(+), 15 deletions(-) (limited to 'linux/drivers') diff --git a/linux/drivers/media/video/em28xx/em28xx-input.c b/linux/drivers/media/video/em28xx/em28xx-input.c index b97a1bc85..b1344499e 100644 --- a/linux/drivers/media/video/em28xx/em28xx-input.c +++ b/linux/drivers/media/video/em28xx/em28xx-input.c @@ -69,8 +69,12 @@ struct em28xx_IR { /* poll external decoder */ int polling; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) struct work_struct work; struct timer_list timer; +#else + struct delayed_work work; +#endif unsigned int last_toggle:1; unsigned int last_readcount; unsigned int repeat_interval; @@ -298,6 +302,7 @@ static void em28xx_ir_handle_key(struct em28xx_IR *ir) return; } +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) static void ir_timer(unsigned long data) { struct em28xx_IR *ir = (struct em28xx_IR *)data; @@ -305,7 +310,6 @@ static void ir_timer(unsigned long data) schedule_work(&ir->work); } -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) static void em28xx_ir_work(void *data) #else static void em28xx_ir_work(struct work_struct *work) @@ -314,28 +318,39 @@ static void em28xx_ir_work(struct work_struct *work) #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) struct em28xx_IR *ir = data; #else - struct em28xx_IR *ir = container_of(work, struct em28xx_IR, work); + struct delayed_work *dwork = container_of(work, struct delayed_work, + work); + struct em28xx_IR *ir = container_of(dwork, struct em28xx_IR, work); #endif em28xx_ir_handle_key(ir); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) mod_timer(&ir->timer, jiffies + msecs_to_jiffies(ir->polling)); +#else + schedule_delayed_work(dwork, msecs_to_jiffies(ir->polling)); +#endif } static void em28xx_ir_start(struct em28xx_IR *ir) { - setup_timer(&ir->timer, ir_timer, (unsigned long)ir); #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) + setup_timer(&ir->timer, ir_timer, (unsigned long)ir); INIT_WORK(&ir->work, em28xx_ir_work, ir); + schedule_work(&ir->work); #else - INIT_WORK(&ir->work, em28xx_ir_work); + INIT_DELAYED_WORK(&ir->work, em28xx_ir_work); + schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling)); #endif - schedule_work(&ir->work); } static void em28xx_ir_stop(struct em28xx_IR *ir) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) del_timer_sync(&ir->timer); flush_scheduled_work(); +#else + cancel_delayed_work_sync(&ir->work); +#endif } int em28xx_ir_init(struct em28xx *dev) diff --git a/linux/drivers/media/video/ir-kbd-i2c.c b/linux/drivers/media/video/ir-kbd-i2c.c index a99aea49a..fa5480f64 100644 --- a/linux/drivers/media/video/ir-kbd-i2c.c +++ b/linux/drivers/media/video/ir-kbd-i2c.c @@ -280,13 +280,13 @@ static void ir_key_poll(struct IR_i2c *ir) } } +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) static void ir_timer(unsigned long data) { struct IR_i2c *ir = (struct IR_i2c*)data; schedule_work(&ir->work); } -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) static void ir_work(void *data) #else static void ir_work(struct work_struct *work) @@ -295,7 +295,9 @@ static void ir_work(struct work_struct *work) #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) struct IR_i2c *ir = data; #else - struct IR_i2c *ir = container_of(work, struct IR_i2c, work); + struct delayed_work *dwork = container_of(work, struct delayed_work, + work); + struct IR_i2c *ir = container_of(dwork, struct IR_i2c, work); #endif int polling_interval = 100; @@ -305,7 +307,11 @@ static void ir_work(struct work_struct *work) polling_interval = 50; ir_key_poll(ir); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) mod_timer(&ir->timer, jiffies + msecs_to_jiffies(polling_interval)); +#else + schedule_delayed_work(dwork, msecs_to_jiffies(polling_interval)); +#endif } /* ----------------------------------------------------------------------- */ @@ -463,13 +469,14 @@ static int ir_attach(struct i2c_adapter *adap, int addr, /* start polling via eventd */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) INIT_WORK(&ir->work, ir_work, ir); -#else - INIT_WORK(&ir->work, ir_work); -#endif init_timer(&ir->timer); ir->timer.function = ir_timer; ir->timer.data = (unsigned long)ir; schedule_work(&ir->work); +#else + INIT_DELAYED_WORK(&ir->work, ir_work); + schedule_delayed_work(&ir->work, msecs_to_jiffies(100)); +#endif return 0; @@ -486,8 +493,12 @@ static int ir_detach(struct i2c_client *client) struct IR_i2c *ir = i2c_get_clientdata(client); /* kill outstanding polls */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) del_timer_sync(&ir->timer); flush_scheduled_work(); +#else + cancel_delayed_work_sync(&ir->work); +#endif /* unregister devices */ input_unregister_device(ir->input); diff --git a/linux/drivers/media/video/saa6588.c b/linux/drivers/media/video/saa6588.c index ae96de5fd..4b9b51e39 100644 --- a/linux/drivers/media/video/saa6588.c +++ b/linux/drivers/media/video/saa6588.c @@ -77,8 +77,12 @@ MODULE_LICENSE("GPL"); struct saa6588 { struct v4l2_subdev sd; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) struct work_struct work; struct timer_list timer; +#else + struct delayed_work work; +#endif spinlock_t lock; unsigned char *buffer; unsigned int buf_size; @@ -323,6 +327,7 @@ static void saa6588_i2c_poll(struct saa6588 *s) wake_up_interruptible(&s->read_queue); } +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) static void saa6588_timer(unsigned long data) { struct saa6588 *s = (struct saa6588 *)data; @@ -330,7 +335,6 @@ static void saa6588_timer(unsigned long data) schedule_work(&s->work); } -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) static void saa6588_work(void *data) #else static void saa6588_work(struct work_struct *work) @@ -339,11 +343,17 @@ static void saa6588_work(struct work_struct *work) #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) struct saa6588 *s = (struct saa6588 *)data; #else - struct saa6588 *s = container_of(work, struct saa6588, work); + struct delayed_work *dwork = container_of(work, struct delayed_work, + work); + struct saa6588 *s = container_of(dwork, struct saa6588, work); #endif saa6588_i2c_poll(s); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) mod_timer(&s->timer, jiffies + msecs_to_jiffies(20)); +#else + schedule_delayed_work(dwork, msecs_to_jiffies(20)); +#endif } static int saa6588_configure(struct saa6588 *s) @@ -501,13 +511,14 @@ static int saa6588_probe(struct i2c_client *client, /* start polling via eventd */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) INIT_WORK(&s->work, saa6588_work, s); -#else - INIT_WORK(&s->work, saa6588_work); -#endif init_timer(&s->timer); s->timer.function = saa6588_timer; s->timer.data = (unsigned long)s; schedule_work(&s->work); +#else + INIT_DELAYED_WORK(&s->work, saa6588_work); + schedule_delayed_work(&s->work, msecs_to_jiffies(20)); +#endif return 0; } @@ -518,8 +529,12 @@ static int saa6588_remove(struct i2c_client *client) v4l2_device_unregister_subdev(sd); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) del_timer_sync(&s->timer); flush_scheduled_work(); +#else + cancel_delayed_work_sync(&s->work); +#endif kfree(s->buffer); kfree(s); -- cgit v1.2.3 From d7673f843f104186787be352493d8660570163ab Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 11 Mar 2009 07:51:41 -0300 Subject: Revert the last changeset, since there are a rev 2 of those changes From: Mauro Carvalho Chehab Signed-off-by: Mauro Carvalho Chehab --- linux/drivers/media/video/em28xx/em28xx-input.c | 25 +++++-------------------- linux/drivers/media/video/ir-kbd-i2c.c | 21 +++++---------------- linux/drivers/media/video/saa6588.c | 25 +++++-------------------- 3 files changed, 15 insertions(+), 56 deletions(-) (limited to 'linux/drivers') diff --git a/linux/drivers/media/video/em28xx/em28xx-input.c b/linux/drivers/media/video/em28xx/em28xx-input.c index b1344499e..b97a1bc85 100644 --- a/linux/drivers/media/video/em28xx/em28xx-input.c +++ b/linux/drivers/media/video/em28xx/em28xx-input.c @@ -69,12 +69,8 @@ struct em28xx_IR { /* poll external decoder */ int polling; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) struct work_struct work; struct timer_list timer; -#else - struct delayed_work work; -#endif unsigned int last_toggle:1; unsigned int last_readcount; unsigned int repeat_interval; @@ -302,7 +298,6 @@ static void em28xx_ir_handle_key(struct em28xx_IR *ir) return; } -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) static void ir_timer(unsigned long data) { struct em28xx_IR *ir = (struct em28xx_IR *)data; @@ -310,6 +305,7 @@ static void ir_timer(unsigned long data) schedule_work(&ir->work); } +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) static void em28xx_ir_work(void *data) #else static void em28xx_ir_work(struct work_struct *work) @@ -318,39 +314,28 @@ static void em28xx_ir_work(struct work_struct *work) #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) struct em28xx_IR *ir = data; #else - struct delayed_work *dwork = container_of(work, struct delayed_work, - work); - struct em28xx_IR *ir = container_of(dwork, struct em28xx_IR, work); + struct em28xx_IR *ir = container_of(work, struct em28xx_IR, work); #endif em28xx_ir_handle_key(ir); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) mod_timer(&ir->timer, jiffies + msecs_to_jiffies(ir->polling)); -#else - schedule_delayed_work(dwork, msecs_to_jiffies(ir->polling)); -#endif } static void em28xx_ir_start(struct em28xx_IR *ir) { -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) setup_timer(&ir->timer, ir_timer, (unsigned long)ir); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) INIT_WORK(&ir->work, em28xx_ir_work, ir); - schedule_work(&ir->work); #else - INIT_DELAYED_WORK(&ir->work, em28xx_ir_work); - schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling)); + INIT_WORK(&ir->work, em28xx_ir_work); #endif + schedule_work(&ir->work); } static void em28xx_ir_stop(struct em28xx_IR *ir) { -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) del_timer_sync(&ir->timer); flush_scheduled_work(); -#else - cancel_delayed_work_sync(&ir->work); -#endif } int em28xx_ir_init(struct em28xx *dev) diff --git a/linux/drivers/media/video/ir-kbd-i2c.c b/linux/drivers/media/video/ir-kbd-i2c.c index fa5480f64..a99aea49a 100644 --- a/linux/drivers/media/video/ir-kbd-i2c.c +++ b/linux/drivers/media/video/ir-kbd-i2c.c @@ -280,13 +280,13 @@ static void ir_key_poll(struct IR_i2c *ir) } } -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) static void ir_timer(unsigned long data) { struct IR_i2c *ir = (struct IR_i2c*)data; schedule_work(&ir->work); } +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) static void ir_work(void *data) #else static void ir_work(struct work_struct *work) @@ -295,9 +295,7 @@ static void ir_work(struct work_struct *work) #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) struct IR_i2c *ir = data; #else - struct delayed_work *dwork = container_of(work, struct delayed_work, - work); - struct IR_i2c *ir = container_of(dwork, struct IR_i2c, work); + struct IR_i2c *ir = container_of(work, struct IR_i2c, work); #endif int polling_interval = 100; @@ -307,11 +305,7 @@ static void ir_work(struct work_struct *work) polling_interval = 50; ir_key_poll(ir); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) mod_timer(&ir->timer, jiffies + msecs_to_jiffies(polling_interval)); -#else - schedule_delayed_work(dwork, msecs_to_jiffies(polling_interval)); -#endif } /* ----------------------------------------------------------------------- */ @@ -469,14 +463,13 @@ static int ir_attach(struct i2c_adapter *adap, int addr, /* start polling via eventd */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) INIT_WORK(&ir->work, ir_work, ir); +#else + INIT_WORK(&ir->work, ir_work); +#endif init_timer(&ir->timer); ir->timer.function = ir_timer; ir->timer.data = (unsigned long)ir; schedule_work(&ir->work); -#else - INIT_DELAYED_WORK(&ir->work, ir_work); - schedule_delayed_work(&ir->work, msecs_to_jiffies(100)); -#endif return 0; @@ -493,12 +486,8 @@ static int ir_detach(struct i2c_client *client) struct IR_i2c *ir = i2c_get_clientdata(client); /* kill outstanding polls */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) del_timer_sync(&ir->timer); flush_scheduled_work(); -#else - cancel_delayed_work_sync(&ir->work); -#endif /* unregister devices */ input_unregister_device(ir->input); diff --git a/linux/drivers/media/video/saa6588.c b/linux/drivers/media/video/saa6588.c index 4b9b51e39..ae96de5fd 100644 --- a/linux/drivers/media/video/saa6588.c +++ b/linux/drivers/media/video/saa6588.c @@ -77,12 +77,8 @@ MODULE_LICENSE("GPL"); struct saa6588 { struct v4l2_subdev sd; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) struct work_struct work; struct timer_list timer; -#else - struct delayed_work work; -#endif spinlock_t lock; unsigned char *buffer; unsigned int buf_size; @@ -327,7 +323,6 @@ static void saa6588_i2c_poll(struct saa6588 *s) wake_up_interruptible(&s->read_queue); } -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) static void saa6588_timer(unsigned long data) { struct saa6588 *s = (struct saa6588 *)data; @@ -335,6 +330,7 @@ static void saa6588_timer(unsigned long data) schedule_work(&s->work); } +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) static void saa6588_work(void *data) #else static void saa6588_work(struct work_struct *work) @@ -343,17 +339,11 @@ static void saa6588_work(struct work_struct *work) #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) struct saa6588 *s = (struct saa6588 *)data; #else - struct delayed_work *dwork = container_of(work, struct delayed_work, - work); - struct saa6588 *s = container_of(dwork, struct saa6588, work); + struct saa6588 *s = container_of(work, struct saa6588, work); #endif saa6588_i2c_poll(s); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) mod_timer(&s->timer, jiffies + msecs_to_jiffies(20)); -#else - schedule_delayed_work(dwork, msecs_to_jiffies(20)); -#endif } static int saa6588_configure(struct saa6588 *s) @@ -511,14 +501,13 @@ static int saa6588_probe(struct i2c_client *client, /* start polling via eventd */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) INIT_WORK(&s->work, saa6588_work, s); +#else + INIT_WORK(&s->work, saa6588_work); +#endif init_timer(&s->timer); s->timer.function = saa6588_timer; s->timer.data = (unsigned long)s; schedule_work(&s->work); -#else - INIT_DELAYED_WORK(&s->work, saa6588_work); - schedule_delayed_work(&s->work, msecs_to_jiffies(20)); -#endif return 0; } @@ -529,12 +518,8 @@ static int saa6588_remove(struct i2c_client *client) v4l2_device_unregister_subdev(sd); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) del_timer_sync(&s->timer); flush_scheduled_work(); -#else - cancel_delayed_work_sync(&s->work); -#endif kfree(s->buffer); kfree(s); -- cgit v1.2.3 From bf6a78d38280357d2cbb3d3e84ec17f52dae1370 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 7 Mar 2009 10:43:01 +0000 Subject: em28xx: Prevent general protection fault on rmmod From: Jean Delvare The removal of the timer which polls the infrared input is racy. Replacing the timer with a delayed work solves the problem. Signed-off-by: Jean Delvare Signed-off-by: Mauro Carvalho Chehab --- linux/drivers/media/video/em28xx/em28xx-input.c | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) (limited to 'linux/drivers') diff --git a/linux/drivers/media/video/em28xx/em28xx-input.c b/linux/drivers/media/video/em28xx/em28xx-input.c index b97a1bc85..5382a6064 100644 --- a/linux/drivers/media/video/em28xx/em28xx-input.c +++ b/linux/drivers/media/video/em28xx/em28xx-input.c @@ -69,8 +69,7 @@ struct em28xx_IR { /* poll external decoder */ int polling; - struct work_struct work; - struct timer_list timer; + struct delayed_work work; unsigned int last_toggle:1; unsigned int last_readcount; unsigned int repeat_interval; @@ -298,13 +297,6 @@ static void em28xx_ir_handle_key(struct em28xx_IR *ir) return; } -static void ir_timer(unsigned long data) -{ - struct em28xx_IR *ir = (struct em28xx_IR *)data; - - schedule_work(&ir->work); -} - #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) static void em28xx_ir_work(void *data) #else @@ -314,28 +306,26 @@ static void em28xx_ir_work(struct work_struct *work) #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) struct em28xx_IR *ir = data; #else - struct em28xx_IR *ir = container_of(work, struct em28xx_IR, work); + struct em28xx_IR *ir = container_of(work, struct em28xx_IR, work.work); #endif em28xx_ir_handle_key(ir); - mod_timer(&ir->timer, jiffies + msecs_to_jiffies(ir->polling)); + schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling)); } static void em28xx_ir_start(struct em28xx_IR *ir) { - setup_timer(&ir->timer, ir_timer, (unsigned long)ir); #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) - INIT_WORK(&ir->work, em28xx_ir_work, ir); + INIT_DELAYED_WORK(&ir->work, em28xx_ir_work, ir); #else - INIT_WORK(&ir->work, em28xx_ir_work); + INIT_DELAYED_WORK(&ir->work, em28xx_ir_work); #endif - schedule_work(&ir->work); + schedule_delayed_work(&ir->work, 0); } static void em28xx_ir_stop(struct em28xx_IR *ir) { - del_timer_sync(&ir->timer); - flush_scheduled_work(); + cancel_delayed_work_sync(&ir->work); } int em28xx_ir_init(struct em28xx *dev) -- cgit v1.2.3 From c698fbc627c51ba8ad0e434848499cb4412072da Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 7 Mar 2009 10:43:43 +0000 Subject: ir-kbd-i2c: Prevent general protection fault on rmmod From: Jean Delvare The removal of the timer which polls the infrared input is racy. Replacing the timer with a delayed work solves the problem. Signed-off-by: Jean Delvare Signed-off-by: Mauro Carvalho Chehab --- linux/drivers/media/video/ir-kbd-i2c.c | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) (limited to 'linux/drivers') diff --git a/linux/drivers/media/video/ir-kbd-i2c.c b/linux/drivers/media/video/ir-kbd-i2c.c index a99aea49a..a0b78706d 100644 --- a/linux/drivers/media/video/ir-kbd-i2c.c +++ b/linux/drivers/media/video/ir-kbd-i2c.c @@ -280,12 +280,6 @@ static void ir_key_poll(struct IR_i2c *ir) } } -static void ir_timer(unsigned long data) -{ - struct IR_i2c *ir = (struct IR_i2c*)data; - schedule_work(&ir->work); -} - #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) static void ir_work(void *data) #else @@ -295,7 +289,7 @@ static void ir_work(struct work_struct *work) #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) struct IR_i2c *ir = data; #else - struct IR_i2c *ir = container_of(work, struct IR_i2c, work); + struct IR_i2c *ir = container_of(work, struct IR_i2c, work.work); #endif int polling_interval = 100; @@ -305,7 +299,7 @@ static void ir_work(struct work_struct *work) polling_interval = 50; ir_key_poll(ir); - mod_timer(&ir->timer, jiffies + msecs_to_jiffies(polling_interval)); + schedule_delayed_work(&ir->work, msecs_to_jiffies(polling_interval)); } /* ----------------------------------------------------------------------- */ @@ -462,14 +456,11 @@ static int ir_attach(struct i2c_adapter *adap, int addr, /* start polling via eventd */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) - INIT_WORK(&ir->work, ir_work, ir); + INIT_DELAYED_WORK(&ir->work, ir_work, ir); #else - INIT_WORK(&ir->work, ir_work); + INIT_DELAYED_WORK(&ir->work, ir_work); #endif - init_timer(&ir->timer); - ir->timer.function = ir_timer; - ir->timer.data = (unsigned long)ir; - schedule_work(&ir->work); + schedule_delayed_work(&ir->work, 0); return 0; @@ -486,8 +477,7 @@ static int ir_detach(struct i2c_client *client) struct IR_i2c *ir = i2c_get_clientdata(client); /* kill outstanding polls */ - del_timer_sync(&ir->timer); - flush_scheduled_work(); + cancel_delayed_work_sync(&ir->work); /* unregister devices */ input_unregister_device(ir->input); -- cgit v1.2.3 From 0bf47672d2ce934563d0287172c9dbf911e8a3b3 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 7 Mar 2009 10:44:12 +0000 Subject: saa6588: Prevent general protection fault on rmmod From: Jean Delvare The removal of the timer which polls the infrared input is racy. Replacing the timer with a delayed work solves the problem. Signed-off-by: Jean Delvare Signed-off-by: Mauro Carvalho Chehab --- linux/drivers/media/video/saa6588.c | 26 +++++++------------------- 1 file changed, 7 insertions(+), 19 deletions(-) (limited to 'linux/drivers') diff --git a/linux/drivers/media/video/saa6588.c b/linux/drivers/media/video/saa6588.c index ae96de5fd..d89d70892 100644 --- a/linux/drivers/media/video/saa6588.c +++ b/linux/drivers/media/video/saa6588.c @@ -77,8 +77,7 @@ MODULE_LICENSE("GPL"); struct saa6588 { struct v4l2_subdev sd; - struct work_struct work; - struct timer_list timer; + struct delayed_work work; spinlock_t lock; unsigned char *buffer; unsigned int buf_size; @@ -323,13 +322,6 @@ static void saa6588_i2c_poll(struct saa6588 *s) wake_up_interruptible(&s->read_queue); } -static void saa6588_timer(unsigned long data) -{ - struct saa6588 *s = (struct saa6588 *)data; - - schedule_work(&s->work); -} - #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) static void saa6588_work(void *data) #else @@ -339,11 +331,11 @@ static void saa6588_work(struct work_struct *work) #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) struct saa6588 *s = (struct saa6588 *)data; #else - struct saa6588 *s = container_of(work, struct saa6588, work); + struct saa6588 *s = container_of(work, struct saa6588, work.work); #endif saa6588_i2c_poll(s); - mod_timer(&s->timer, jiffies + msecs_to_jiffies(20)); + schedule_delayed_work(&s->work, msecs_to_jiffies(20)); } static int saa6588_configure(struct saa6588 *s) @@ -500,14 +492,11 @@ static int saa6588_probe(struct i2c_client *client, /* start polling via eventd */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) - INIT_WORK(&s->work, saa6588_work, s); + INIT_DELAYED_WORK(&s->work, saa6588_work, s); #else - INIT_WORK(&s->work, saa6588_work); + INIT_DELAYED_WORK(&s->work, saa6588_work); #endif - init_timer(&s->timer); - s->timer.function = saa6588_timer; - s->timer.data = (unsigned long)s; - schedule_work(&s->work); + schedule_delayed_work(&s->work, 0); return 0; } @@ -518,8 +507,7 @@ static int saa6588_remove(struct i2c_client *client) v4l2_device_unregister_subdev(sd); - del_timer_sync(&s->timer); - flush_scheduled_work(); + cancel_delayed_work_sync(&s->work); kfree(s->buffer); kfree(s); -- cgit v1.2.3