From: Franck Bui-Huu <[EMAIL PROTECTED]>

When closing the device, the driver acquires/release twice the
port lock before/after waiting for the data to be completely
sent. Therefore it will dead lock.

This patch fixes it and also uses the generic scheduler services
for waiting for an event.

Signed-off-by: Franck Bui-Huu <[EMAIL PROTECTED]>
Signed-off-by: Greg Kroah-Hartman <[EMAIL PROTECTED]>
---
 drivers/usb/gadget/serial.c |   95 ++++++++-----------------------------------
 1 files changed, 17 insertions(+), 78 deletions(-)

diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c
index b992546..b58f015 100644
--- a/drivers/usb/gadget/serial.c
+++ b/drivers/usb/gadget/serial.c
@@ -51,82 +51,10 @@ #include <linux/usb_gadget.h>
 #include "gadget_chips.h"
 
 
-/* Wait Cond */
-
-#define __wait_cond_interruptible(wq, condition, lock, flags, ret)     \
-do {                                                                   \
-       wait_queue_t __wait;                                            \
-       init_waitqueue_entry(&__wait, current);                         \
-                                                                       \
-       add_wait_queue(&wq, &__wait);                                   \
-       for (;;) {                                                      \
-               set_current_state(TASK_INTERRUPTIBLE);                  \
-               if (condition)                                          \
-                       break;                                          \
-               if (!signal_pending(current)) {                         \
-                       spin_unlock_irqrestore(lock, flags);            \
-                       schedule();                                     \
-                       spin_lock_irqsave(lock, flags);                 \
-                       continue;                                       \
-               }                                                       \
-               ret = -ERESTARTSYS;                                     \
-               break;                                                  \
-       }                                                               \
-       current->state = TASK_RUNNING;                                  \
-       remove_wait_queue(&wq, &__wait);                                \
-} while (0)
-       
-#define wait_cond_interruptible(wq, condition, lock, flags)            \
-({                                                                     \
-       int __ret = 0;                                                  \
-       if (!(condition))                                               \
-               __wait_cond_interruptible(wq, condition, lock, flags,   \
-                                               __ret);                 \
-       __ret;                                                          \
-})
-
-#define __wait_cond_interruptible_timeout(wq, condition, lock, flags,  \
-                                               timeout, ret)           \
-do {                                                                   \
-       signed long __timeout = timeout;                                \
-       wait_queue_t __wait;                                            \
-       init_waitqueue_entry(&__wait, current);                         \
-                                                                       \
-       add_wait_queue(&wq, &__wait);                                   \
-       for (;;) {                                                      \
-               set_current_state(TASK_INTERRUPTIBLE);                  \
-               if (__timeout == 0)                                     \
-                       break;                                          \
-               if (condition)                                          \
-                       break;                                          \
-               if (!signal_pending(current)) {                         \
-                       spin_unlock_irqrestore(lock, flags);            \
-                       __timeout = schedule_timeout(__timeout);        \
-                       spin_lock_irqsave(lock, flags);                 \
-                       continue;                                       \
-               }                                                       \
-               ret = -ERESTARTSYS;                                     \
-               break;                                                  \
-       }                                                               \
-       current->state = TASK_RUNNING;                                  \
-       remove_wait_queue(&wq, &__wait);                                \
-} while (0)
-       
-#define wait_cond_interruptible_timeout(wq, condition, lock, flags,    \
-                                               timeout)                \
-({                                                                     \
-       int __ret = 0;                                                  \
-       if (!(condition))                                               \
-               __wait_cond_interruptible_timeout(wq, condition, lock,  \
-                                               flags, timeout, __ret); \
-       __ret;                                                          \
-})
-
-
 /* Defines */
 
-#define GS_VERSION_STR                 "v2.0"
-#define GS_VERSION_NUM                 0x0200
+#define GS_VERSION_STR                 "v2.1"
+#define GS_VERSION_NUM                 0x0201
 
 #define GS_LONG_NAME                   "Gadget Serial"
 #define GS_SHORT_NAME                  "g_serial"
@@ -843,6 +771,18 @@ exit_unlock_dev:
 /*
  * gs_close
  */
+
+#define GS_WRITE_FINISHED_EVENT_SAFELY(p)                      \
+({                                                             \
+       unsigned long flags;                                    \
+       int cond;                                               \
+                                                               \
+       spin_lock_irqsave(&(p)->port_lock, flags);              \
+       cond = !(p)->port_dev || !gs_buf_data_avail((p)->port_write_buf); \
+       spin_unlock_irqrestore(&(p)->port_lock, flags);         \
+       cond;                                                   \
+})
+
 static void gs_close(struct tty_struct *tty, struct file *file)
 {
        unsigned long flags;
@@ -888,10 +828,9 @@ static void gs_close(struct tty_struct *
        /* at most GS_CLOSE_TIMEOUT seconds */
        if (gs_buf_data_avail(port->port_write_buf) > 0) {
                spin_unlock_irqrestore(&port->port_lock, flags);
-               wait_cond_interruptible_timeout(port->port_write_wait,
-               port->port_dev == NULL
-               || gs_buf_data_avail(port->port_write_buf) == 0,
-               &port->port_lock, flags, GS_CLOSE_TIMEOUT * HZ);
+               wait_event_interruptible_timeout(port->port_write_wait,
+                                       GS_WRITE_FINISHED_EVENT_SAFELY(port),
+                                       GS_CLOSE_TIMEOUT * HZ);
                spin_lock_irqsave(&port->port_lock, flags);
        }
 
-- 
1.4.0


All the advantages of Linux Managed Hosting--Without the Cost and Risk!
Fully trained technicians. The highest number of Red Hat certifications in
the hosting industry. Fanatical Support. Click to learn more
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=107521&bid=248729&dat=121642
_______________________________________________
linux-usb-devel@lists.sourceforge.net
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to