summary refs log tree commit diff
path: root/net/ceph/messenger.c
diff options
context:
space:
mode:
authorSage Weil <sage@inktank.com>2012-07-30 16:24:37 -0700
committerSage Weil <sage@inktank.com>2012-07-30 18:15:30 -0700
commit8c50c817566dfa4581f82373aac39f3e608a7dc8 (patch)
tree875162b047de3e18de801e1e6152f6d8f4810652 /net/ceph/messenger.c
parent3a140a0d5c4b9e35373b016e41dfc85f1e526bdb (diff)
downloadlinux-8c50c817566dfa4581f82373aac39f3e608a7dc8.tar.gz
libceph: fix mutex coverage for ceph_con_close
Hold the mutex while twiddling all of the state bits to avoid possible
races.  While we're here, make not of why we cannot close the socket
directly.

Signed-off-by: Sage Weil <sage@inktank.com>
Reviewed-by: Alex Elder <elder@inktank.com>
Reviewed-by: Yehuda Sadeh <yehuda@inktank.com>
Diffstat (limited to 'net/ceph/messenger.c')
-rw-r--r--net/ceph/messenger.c8
1 files changed, 7 insertions, 1 deletions
diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c
index 6e2f67816f61..e65b15d5d8b9 100644
--- a/net/ceph/messenger.c
+++ b/net/ceph/messenger.c
@@ -503,6 +503,7 @@ static void reset_connection(struct ceph_connection *con)
  */
 void ceph_con_close(struct ceph_connection *con)
 {
+	mutex_lock(&con->mutex);
 	dout("con_close %p peer %s\n", con,
 	     ceph_pr_addr(&con->peer_addr.in_addr));
 	clear_bit(NEGOTIATING, &con->state);
@@ -515,11 +516,16 @@ void ceph_con_close(struct ceph_connection *con)
 	clear_bit(KEEPALIVE_PENDING, &con->flags);
 	clear_bit(WRITE_PENDING, &con->flags);
 
-	mutex_lock(&con->mutex);
 	reset_connection(con);
 	con->peer_global_seq = 0;
 	cancel_delayed_work(&con->work);
 	mutex_unlock(&con->mutex);
+
+	/*
+	 * We cannot close the socket directly from here because the
+	 * work threads use it without holding the mutex.  Instead, let
+	 * con_work() do it.
+	 */
 	queue_con(con);
 }
 EXPORT_SYMBOL(ceph_con_close);