staging: usbip: usbip_common: kill rx thread on tx thread creation error.
authorHimanshu Chauhan <hschauhan@nulltrace.org>
Fri, 4 Jun 2010 17:46:27 +0000 (23:16 +0530)
committerGreg Kroah-Hartman <gregkh@suse.de>
Wed, 30 Jun 2010 15:18:14 +0000 (08:18 -0700)
Signed-off-by: Himanshu Chauhan <hschauhan@nulltrace.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/staging/usbip/usbip_common.c

index 52408164036f3eda94b422d3b14898a26584c5f2..6a499f0eb5948426813f6a53acda1f5c6f243bd2 100644 (file)
@@ -378,47 +378,67 @@ int usbip_thread(void *param)
        complete_and_exit(&ut->thread_done, 0);
 }
 
+static void stop_rx_thread(struct usbip_device *ud)
+{
+       if (ud->tcp_rx.thread != NULL) {
+               send_sig(SIGKILL, ud->tcp_rx.thread, 1);
+               wait_for_completion(&ud->tcp_rx.thread_done);
+               usbip_udbg("rx_thread for ud %p has finished\n", ud);
+       }
+}
+
+static void stop_tx_thread(struct usbip_device *ud)
+{
+       if (ud->tcp_tx.thread != NULL) {
+               send_sig(SIGKILL, ud->tcp_tx.thread, 1);
+               wait_for_completion(&ud->tcp_tx.thread_done);
+               usbip_udbg("tx_thread for ud %p has finished\n", ud);
+       }
+}
+
 int usbip_start_threads(struct usbip_device *ud)
 {
        /*
         * threads are invoked per one device (per one connection).
         */
        struct task_struct *th;
+       int err = 0;
 
        th = kthread_run(usbip_thread, (void *)&ud->tcp_rx, "usbip");
        if (IS_ERR(th)) {
                printk(KERN_WARNING
                        "Unable to start control thread\n");
-               return PTR_ERR(th);
+               err = PTR_ERR(th);
+               goto ust_exit;
        }
+
        th = kthread_run(usbip_thread, (void *)&ud->tcp_tx, "usbip");
        if (IS_ERR(th)) {
                printk(KERN_WARNING
                        "Unable to start control thread\n");
-               return PTR_ERR(th);
+               err = PTR_ERR(th);
+               goto tx_thread_err;
        }
 
        /* confirm threads are starting */
        wait_for_completion(&ud->tcp_rx.thread_done);
        wait_for_completion(&ud->tcp_tx.thread_done);
+
        return 0;
+
+tx_thread_err:
+       stop_rx_thread(ud);
+
+ust_exit:
+       return err;
 }
 EXPORT_SYMBOL_GPL(usbip_start_threads);
 
 void usbip_stop_threads(struct usbip_device *ud)
 {
        /* kill threads related to this sdev, if v.c. exists */
-       if (ud->tcp_rx.thread != NULL) {
-               send_sig(SIGKILL, ud->tcp_rx.thread, 1);
-               wait_for_completion(&ud->tcp_rx.thread_done);
-               usbip_udbg("rx_thread for ud %p has finished\n", ud);
-       }
-
-       if (ud->tcp_tx.thread != NULL) {
-               send_sig(SIGKILL, ud->tcp_tx.thread, 1);
-               wait_for_completion(&ud->tcp_tx.thread_done);
-               usbip_udbg("tx_thread for ud %p has finished\n", ud);
-       }
+       stop_rx_thread(ud);
+       stop_tx_thread(ud);
 }
 EXPORT_SYMBOL_GPL(usbip_stop_threads);