The patch number 10935 was added via Mauro Carvalho Chehab <mche...@redhat.com>
to http://linuxtv.org/hg/v4l-dvb master development tree.

Kernel patches in this development tree may be modified to be backward
compatible with older kernels. Compatibility modifications will be
removed before inclusion into the mainstream Kernel

If anyone has any objections, please let us know by sending a message to:
        Linux Media Mailing List <linux-me...@vger.kernel.org>

------

From: Jean Delvare  <kh...@linux-fr.org>
cx88: Prevent general protection fault on rmmod


When unloading the cx8800 driver I sometimes get a general protection
fault. Analysis revealed a race in cx88_ir_stop(). It can be solved by
using a delayed work instead of a timer for infrared input polling.

This fixes kernel.org bug #12802.

Signed-off-by: Jean Delvare <kh...@linux-fr.org>
Signed-off-by: Mauro Carvalho Chehab <mche...@redhat.com>


---

 linux/drivers/media/video/cx88/cx88-input.c |   27 +++++++++++++++-----
 1 file changed, 21 insertions(+), 6 deletions(-)

diff -r 60b0989f6c7a -r 46412997b3c0 linux/drivers/media/video/cx88/cx88-input.c
--- a/linux/drivers/media/video/cx88/cx88-input.c       Tue Mar 10 19:28:33 
2009 -0700
+++ b/linux/drivers/media/video/cx88/cx88-input.c       Thu Mar 05 09:38:24 
2009 +0000
@@ -49,8 +49,12 @@ struct cx88_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
        u32 gpio_addr;
        u32 last_gpio;
        u32 mask_keycode;
@@ -144,6 +148,7 @@ static void cx88_ir_handle_key(struct cx
        }
 }
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
 static void ir_timer(unsigned long data)
 {
        struct cx88_IR *ir = (struct cx88_IR *)data;
@@ -151,7 +156,6 @@ static void ir_timer(unsigned long data)
        schedule_work(&ir->work);
 }
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
 static void cx88_ir_work(void *data)
 #else
 static void cx88_ir_work(struct work_struct *work)
@@ -160,23 +164,30 @@ static void cx88_ir_work(struct work_str
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
        struct cx88_IR *ir = data;
 #else
-       struct cx88_IR *ir = container_of(work, struct cx88_IR, work);
+       struct delayed_work *dwork = container_of(work, struct delayed_work,
+                                                 work);
+       struct cx88_IR *ir = container_of(dwork, struct cx88_IR, work);
 #endif
 
        cx88_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
 }
 
 void cx88_ir_start(struct cx88_core *core, struct cx88_IR *ir)
 {
        if (ir->polling) {
+#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, cx88_ir_work, ir);
-#else
-               INIT_WORK(&ir->work, cx88_ir_work);
-#endif
                schedule_work(&ir->work);
+#else
+               INIT_DELAYED_WORK(&ir->work, cx88_ir_work);
+               schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling));
+#endif
        }
        if (ir->sampling) {
                core->pci_irqmask |= PCI_INT_IR_SMPINT;
@@ -193,8 +204,12 @@ void cx88_ir_stop(struct cx88_core *core
        }
 
        if (ir->polling) {
+#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
        }
 }
 


---

Patch is available at: 
http://linuxtv.org/hg/v4l-dvb/rev/46412997b3c098dbb0732fb8ce6cffdd76375c98

_______________________________________________
linuxtv-commits mailing list
linuxtv-commits@linuxtv.org
http://www.linuxtv.org/cgi-bin/mailman/listinfo/linuxtv-commits

Reply via email to