isdn: pcbit: fix interruptible_sleep_on race
authorArnd Bergmann <arnd@arndb.de>
Wed, 26 Feb 2014 11:01:52 +0000 (12:01 +0100)
committerDavid S. Miller <davem@davemloft.net>
Wed, 26 Feb 2014 21:06:12 +0000 (16:06 -0500)
interruptible_sleep_on is racy and going away. In case of pcbit,
the driver would run into a timeout if the card is initialized
before we start waiting for it. This uses wait_event to fix the
race. In order to do this, the state machine handling for the
timeout case has to get trivially reorganized so we actually know
whether the timeout has occorred or not.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Cc: Karsten Keil <isdn@linux-pingi.de>
Cc: netdev@vger.kernel.org
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/isdn/pcbit/drv.c

index 1eaf622739037dc26960f4b3d2ae5ba165830d21..f02cc506fbfa795938fc9dcdfa6e8931df734575 100644 (file)
@@ -796,6 +796,7 @@ static void set_running_timeout(unsigned long ptr)
 #endif
        dev = (struct pcbit_dev *) ptr;
 
+       dev->l2_state = L2_DOWN;
        wake_up_interruptible(&dev->set_running_wq);
 }
 
@@ -818,7 +819,8 @@ static int set_protocol_running(struct pcbit_dev *dev)
 
        add_timer(&dev->set_running_timer);
 
-       interruptible_sleep_on(&dev->set_running_wq);
+       wait_event(dev->set_running_wq, dev->l2_state == L2_RUNNING ||
+                                       dev->l2_state == L2_DOWN);
 
        del_timer(&dev->set_running_timer);
 
@@ -842,8 +844,6 @@ static int set_protocol_running(struct pcbit_dev *dev)
                printk(KERN_DEBUG "pcbit: initialization failed\n");
                printk(KERN_DEBUG "pcbit: firmware not loaded\n");
 
-               dev->l2_state = L2_DOWN;
-
 #ifdef DEBUG
                printk(KERN_DEBUG "Bank3 = %02x\n",
                       readb(dev->sh_mem + BANK3));