libceph: socket can close in any connection state
authorAlex Elder <elder@inktank.com>
Sat, 8 Dec 2012 01:50:07 +0000 (19:50 -0600)
committerAlex Elder <elder@inktank.com>
Mon, 17 Dec 2012 18:07:32 +0000 (12:07 -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>
net/ceph/messenger.c

index 1041114..4b04ccc 100644 (file)
@@ -2273,6 +2273,35 @@ static void queue_con(struct ceph_connection *con)
        (void) queue_con_delay(con, 0);
 }
 
+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.
  */
@@ -2284,24 +2313,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);