From 12339817903642e1c9fe444cdf48ad31388337be Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Wed, 7 Jan 2009 16:57:05 -0800 Subject: [PATCH] datapath: Avoid deadlock on dp_mutex versus kthread_stop(). 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 | 9 +++++++-- datapath/table-hash.c | 5 +++-- datapath/table-linear.c | 5 +++-- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/datapath/datapath.c b/datapath/datapath.c index 474d3ee2..efa84f9f 100644 --- a/datapath/datapath.c +++ b/datapath/datapath.c @@ -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; } diff --git a/datapath/table-hash.c b/datapath/table-hash.c index 2951722e..588b5f56 100644 --- a/datapath/table-hash.c +++ b/datapath/table-hash.c @@ -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; diff --git a/datapath/table-linear.c b/datapath/table-linear.c index 1d5e186d..bef58a6b 100644 --- a/datapath/table-linear.c +++ b/datapath/table-linear.c @@ -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) { -- 2.30.2