libceph: socket can close in any connection state
Alex Elder [Sat, 8 Dec 2012 01:50:07 +0000 (19:50 -0600)]
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>
(cherry picked from commit 7bb21d68c535ad8be38e14a715632ae398b37ac1)
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

net/ceph/messenger.c

index aa71a67..429f3bc 100644 (file)
@@ -2258,6 +2258,35 @@ static void queue_con(struct ceph_connection *con)
        }
 }
 
+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.
  */
@@ -2269,24 +2298,8 @@ static void con_work(struct work_struct *work)
 
        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);