--- /dev/null
+From 3751809df766c05bcce372fcfa4a886b9aaca44b Mon Sep 17 00:00:00 2001
+From: Alex Elder <elder@inktank.com>
+Date: Fri, 7 Dec 2012 19:50:07 -0600
+Subject: libceph: socket can close in any connection state
+
+From: Alex Elder <elder@inktank.com>
+
+(cherry picked from commit 7bb21d68c535ad8be38e14a715632ae398b37ac1)
+
+A connection's socket can close for any reason, independent of the
+state of the connection (and without irrespective of the connection
+mutex). As a result, the connectino can be in pretty much any state
+at the time its socket is closed.
+
+Handle those other cases at the top of con_work(). Pull this whole
+block of code into a separate function to reduce the clutter.
+
+Signed-off-by: Alex Elder <elder@inktank.com>
+Reviewed-by: Sage Weil <sage@inktank.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/ceph/messenger.c | 47 ++++++++++++++++++++++++++++++-----------------
+ 1 file changed, 30 insertions(+), 17 deletions(-)
+
+--- a/net/ceph/messenger.c
++++ b/net/ceph/messenger.c
+@@ -2262,6 +2262,35 @@ static void queue_con(struct ceph_connec
+ }
+ }
+
++static bool con_sock_closed(struct ceph_connection *con)
++{
++ if (!test_and_clear_bit(CON_FLAG_SOCK_CLOSED, &con->flags))
++ return false;
++
++#define CASE(x) \
++ case CON_STATE_ ## x: \
++ con->error_msg = "socket closed (con state " #x ")"; \
++ break;
++
++ switch (con->state) {
++ CASE(CLOSED);
++ CASE(PREOPEN);
++ CASE(CONNECTING);
++ CASE(NEGOTIATING);
++ CASE(OPEN);
++ CASE(STANDBY);
++ default:
++ pr_warning("%s con %p unrecognized state %lu\n",
++ __func__, con, con->state);
++ con->error_msg = "unrecognized con state";
++ BUG();
++ break;
++ }
++#undef CASE
++
++ return true;
++}
++
+ /*
+ * Do some work on a connection. Drop a connection ref when we're done.
+ */
+@@ -2273,24 +2302,8 @@ static void con_work(struct work_struct
+
+ mutex_lock(&con->mutex);
+ restart:
+- if (test_and_clear_bit(CON_FLAG_SOCK_CLOSED, &con->flags)) {
+- switch (con->state) {
+- case CON_STATE_CONNECTING:
+- con->error_msg = "connection failed";
+- break;
+- case CON_STATE_NEGOTIATING:
+- con->error_msg = "negotiation failed";
+- break;
+- case CON_STATE_OPEN:
+- con->error_msg = "socket closed";
+- break;
+- default:
+- dout("unrecognized con state %d\n", (int)con->state);
+- con->error_msg = "unrecognized con state";
+- BUG();
+- }
++ if (con_sock_closed(con))
+ goto fault;
+- }
+
+ if (test_and_clear_bit(CON_FLAG_BACKOFF, &con->flags)) {
+ dout("con_work %p backing off\n", con);