datapath: Avoid deadlock on dp_mutex versus kthread_stop().
authorBen Pfaff <blp@nicira.com>
Thu, 8 Jan 2009 00:57:05 +0000 (16:57 -0800)
committerBen Pfaff <blp@nicira.com>
Thu, 8 Jan 2009 21:22:56 +0000 (13:22 -0800)
When a datapath is deleted, del_dp() acquires dp_mutex and uses
kthread_stop() to wait for the dp_task to die.  Meanwhile, dp_task may
be waiting to acquire dp_mutex and won't die until it does so.

This commit fixes the problem by sending SIGKILL to dp_task before
call kthread_stop() and making dp_task give up if it receives a signal.

datapath/datapath.c
datapath/table-hash.c
datapath/table-linear.c

index 474d3ee2f0af09bfaa4124e826a06d041b88d264..efa84f9f09a30ebfeb376ae9c2252a425ddcdfdb 100644 (file)
@@ -462,6 +462,7 @@ static void del_dp(struct datapath *dp)
 {
        struct net_bridge_port *p, *n;
 
+       send_sig(SIGKILL, dp->dp_task, 0);
        kthread_stop(dp->dp_task);
 
        /* Drop references to DP. */
@@ -489,7 +490,8 @@ static int dp_maint_func(void *data)
 {
        struct datapath *dp = (struct datapath *) data;
 
-       while (!kthread_should_stop()) {
+       allow_signal(SIGKILL);
+       while (!signal_pending(current)) {
 #ifdef SUPPORT_SNAT
                struct net_bridge_port *p;
 
@@ -504,7 +506,10 @@ static int dp_maint_func(void *data)
                chain_timeout(dp->chain);
                msleep_interruptible(MAINT_SLEEP_MSECS);
        }
-               
+       while (!kthread_should_stop()) {
+               set_current_state(TASK_UNINTERRUPTIBLE);
+               schedule();
+       }
        return 0;
 }
 
index 2951722e964b6b963e9df454e3ebb19628d08f6e..588b5f56c08809572495e2d057d6a90d30966b97 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Distributed under the terms of the GNU GPL version 2.
- * Copyright (c) 2007, 2008 The Board of Trustees of The Leland 
+ * Copyright (c) 2007, 2008, 2009 The Board of Trustees of The Leland 
  * Stanford Junior University
  */
 
@@ -148,7 +148,8 @@ static int table_hash_timeout(struct datapath *dp, struct sw_table *swt)
        unsigned int i;
        int count = 0;
 
-       mutex_lock(&dp_mutex);
+       if (mutex_lock_interruptible(&dp_mutex))
+               return 0;
        for (i = 0; i <= th->bucket_mask; i++) {
                struct sw_flow **bucket = &th->buckets[i];
                struct sw_flow *flow = *bucket;
index 1d5e186d2d28e3584554dbf7e187762abeea968d..bef58a6b62f9d0b93f9c435c68aaf0fd6f0e7384 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Distributed under the terms of the GNU GPL version 2.
- * Copyright (c) 2007, 2008 The Board of Trustees of The Leland 
+ * Copyright (c) 2007, 2008, 2009 The Board of Trustees of The Leland 
  * Stanford Junior University
  */
 
@@ -124,7 +124,8 @@ static int table_linear_timeout(struct datapath *dp, struct sw_table *swt)
        struct sw_flow *flow;
        int count = 0;
 
-       mutex_lock(&dp_mutex);
+       if (mutex_lock_interruptible(&dp_mutex))
+               return 0;
        list_for_each_entry (flow, &tl->flows, node) {
                int reason = flow_timeout(flow);
                if (reason >= 0) {