[lkml]   [2017]   [Nov]   [22]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
Messages in this thread
Patch in this message
Subject[PATCH AUTOSEL for 4.9 38/54] tipc: fix nametbl_lock soft lockup at module exit
From: Parthasarathy Bhuvaragan <>

[ Upstream commit 9dc3abdd1f7ea524e8552e0a3ef01219892ed1f4 ]

Commit 333f796235a527 ("tipc: fix a race condition leading to
subscriber refcnt bug") reveals a soft lockup while acquiring

Before commit 333f796235a527, we call tipc_conn_shutdown() from
tipc_close_conn() in the context of tipc_topsrv_stop(). In that
context, we are allowed to grab the nametbl_lock.

Commit 333f796235a527, moved tipc_conn_release (renamed from
tipc_conn_shutdown) to the connection refcount cleanup. This allows
either tipc_nametbl_withdraw() or tipc_topsrv_stop() to the cleanup.

Since tipc_exit_net() first calls tipc_topsrv_stop() and then
tipc_nametble_withdraw() increases the chances for the later to
perform the connection cleanup.

The soft lockup occurs in the call chain of tipc_nametbl_withdraw(),
when it performs the tipc_conn_kref_release() as it tries to grab
nametbl_lock again while holding it already.
tipc_nametbl_withdraw() grabs nametbl_lock
<< if (con->flags != CF_CONNECTED) we do conn_put(),
triggering the cleanup as refcount=0. >>
tipc_nametbl_unsubscribe << Soft Lockup >>

The previous changes in this series fixes the race conditions fixed
by commit 333f796235a527. Hence we can now revert the commit.

Fixes: 333f796235a52727 ("tipc: fix a race condition leading to subscriber refcnt bug")
Reported-and-Tested-by: John Thompson <>
Acked-by: Ying Xue <>
Acked-by: Jon Maloy <>
Signed-off-by: Parthasarathy Bhuvaragan <>
Signed-off-by: David S. Miller <>
Signed-off-by: Sasha Levin <>
net/tipc/server.c | 16 +++++-----------
1 file changed, 5 insertions(+), 11 deletions(-)

diff --git a/net/tipc/server.c b/net/tipc/server.c
index f89c0c2e8c16..04ff441b8065 100644
--- a/net/tipc/server.c
+++ b/net/tipc/server.c
@@ -86,7 +86,6 @@ struct outqueue_entry {
static void tipc_recv_work(struct work_struct *work);
static void tipc_send_work(struct work_struct *work);
static void tipc_clean_outqueues(struct tipc_conn *con);
-static void tipc_sock_release(struct tipc_conn *con);

static void tipc_conn_kref_release(struct kref *kref)
@@ -104,7 +103,6 @@ static void tipc_conn_kref_release(struct kref *kref)
saddr->scope = -TIPC_NODE_SCOPE;
kernel_bind(sock, (struct sockaddr *)saddr, sizeof(*saddr));
- tipc_sock_release(con);
con->sock = NULL;

@@ -194,19 +192,15 @@ static void tipc_unregister_callbacks(struct tipc_conn *con)

-static void tipc_sock_release(struct tipc_conn *con)
+static void tipc_close_conn(struct tipc_conn *con)
struct tipc_server *s = con->server;

- if (con->conid)
- s->tipc_conn_release(con->conid, con->usr_data);
- tipc_unregister_callbacks(con);
-static void tipc_close_conn(struct tipc_conn *con)
if (test_and_clear_bit(CF_CONNECTED, &con->flags)) {
+ tipc_unregister_callbacks(con);
+ if (con->conid)
+ s->tipc_conn_release(con->conid, con->usr_data);

/* We shouldn't flush pending works as we may be in the
* thread. In fact the races with pending rx/tx work structs
 \ /
  Last update: 2017-11-22 23:26    [W:0.246 / U:9.236 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site