On Mon, Jun 27, 2005 at 04:06:11PM -0700, Libor Michalek wrote:
> On Mon, Jun 27, 2005 at 02:27:54PM -0700, Tom Duffy wrote:
> > On Mon, 2005-06-27 at 11:17 -0700, Libor Michalek wrote:
> > >   The problem is that each call to sk_alloc() is grabbing a reference to
> > > the module, but it checks to make sure that there already is at least one
> > > reference, if not the top BUG is triggered. In the case of the passive
> > > connection there are no other references to the module. You can see that
> > > the problem goes away if you open just one socket, even if you don't
> > > listen on it, and then try the failing passive connect. When a socket is
> > > created it actually grabs two references to the module, one at the sock
> > > level and one at the sk level. The first reference at the sock level does
> > > not trigger the BUG since it's through another code path. (try_module_get
> > > vs. __module_get) This is why we only hit this during passive connect
> > > to a system that has no active SDP sockets.
> > 
> > Hrm.  That seems ugly.  How about a patch to upstream changing
> > sk_alloc() to use try_module_get().
> 
>   I'm thinking the listen_lookup needs to be moved earlier in the
> req_handler ahead of the sk_alloc, since it makes no sense to do
> the alloc if we are not going to queue the new incomming connection,
> since it just leads to a destroy in the same function.

  Here's a patch to reorder listen_lookup() in req_handler() and a few
other fixups, such as making a couple int return functions void.

-Libor

Index: sdp_proto.h
===================================================================
--- sdp_proto.h (revision 2731)
+++ sdp_proto.h (working copy)
@@ -282,8 +282,8 @@
 /*
  * port/queue managment
  */
-int sdp_inet_accept_q_put(struct sdp_opt *listen_conn,
-                         struct sdp_opt *accept_conn);
+void sdp_inet_accept_q_put(struct sdp_opt *listen_conn,
+                          struct sdp_opt *accept_conn);
 
 struct sdp_opt *sdp_inet_accept_q_get(struct sdp_opt *listen_conn);
 
@@ -299,7 +299,7 @@
 
 int sdp_inet_port_put(struct sdp_opt *conn);
 
-int sdp_inet_port_inherit(struct sdp_opt *parent, struct sdp_opt *child);
+void sdp_inet_port_inherit(struct sdp_opt *parent, struct sdp_opt *child);
 
 /*
  * active connect functions
Index: sdp_conn.c
===================================================================
--- sdp_conn.c  (revision 2732)
+++ sdp_conn.c  (working copy)
@@ -176,16 +176,14 @@
 /*
  * sdp_inet_accept_q_put - put a conn into a listen conn's accept Q.
  */
-int sdp_inet_accept_q_put(struct sdp_opt *listen_conn,
-                         struct sdp_opt *accept_conn)
+void sdp_inet_accept_q_put(struct sdp_opt *listen_conn,
+                          struct sdp_opt *accept_conn)
 {
        struct sdp_opt *next_conn;
 
-       if (listen_conn->parent ||
-           accept_conn->parent ||
-           !listen_conn->accept_next ||
-           !listen_conn->accept_prev)
-               return -EFAULT;
+       BUG_ON(listen_conn->parent);
+       BUG_ON(accept_conn->parent);
+       BUG_ON(!listen_conn->accept_next || !listen_conn->accept_prev);
 
        next_conn = listen_conn->accept_next;
 
@@ -200,8 +198,6 @@
         * up ref until we release. One ref for GW and one for INET.
         */
        sdp_conn_hold(accept_conn); /* AcceptQueue INET reference */
-
-       return 0;
 }
 
 /*
@@ -545,9 +541,8 @@
 /*
  * sdp_inet_port_inherit - inherit a port from another socket (accept)
  */
-int sdp_inet_port_inherit(struct sdp_opt *parent, struct sdp_opt *child)
+void sdp_inet_port_inherit(struct sdp_opt *parent, struct sdp_opt *child)
 {
-       int result;
        unsigned long flags;
 
        /*
@@ -555,13 +550,8 @@
         */
        spin_lock_irqsave(&dev_root_s.bind_lock, flags);
 
-       if (child->bind_p_next ||
-           child->src_port != parent->src_port) {
-               sdp_dbg_warn(child, "child already bound. <%d:%d>",
-                            parent->src_port, child->src_port);
-               result = -EADDRNOTAVAIL;
-               goto done;
-       }
+       BUG_ON(child->bind_p_next);
+       BUG_ON(child->src_port != parent->src_port);
        /*
         * insert into listening list.
         */
@@ -572,10 +562,7 @@
        if (child->bind_next)
                child->bind_next->bind_p_next = &child->bind_next;
 
-       result = 0;
-done:
        spin_unlock_irqrestore(&dev_root_s.bind_lock, flags);
-       return result;
 }
 
 /*
Index: sdp_pass.c
===================================================================
--- sdp_pass.c  (revision 2732)
+++ sdp_pass.c  (working copy)
@@ -229,121 +229,54 @@
        return result;
 }
 
-static int sdp_cm_listen_lookup(struct sdp_opt *conn)
+static void sdp_cm_listen_inherit(struct sdp_opt *parent,
+                                 struct sdp_opt *child)
 {
-       struct sdp_opt *listen_conn;
-       struct sock *listen_sk;
-       struct sock *sk;
-       int result;
-       /*
-        * match a listener with an incoming conn, and generate
-        * accept message and state on success.
-        */
-       sdp_dbg_ctrl(conn,
-                    "listen match for conn. src <%08x:%04x> dst <%08x:%04x>",
-                    conn->src_addr, conn->src_port, 
-                    conn->dst_addr, conn->dst_port);
-       /*
-        * first find a listening connection
-        */
-       listen_conn = sdp_inet_listen_lookup(conn->src_addr, conn->src_port);
-       if (!listen_conn) {
-               /*
-                * no connection, reject
-                */
-               sdp_dbg_warn(conn, "no listener for connection. <%08x:%04x>",
-                            conn->src_addr, conn->src_port);
-               result = -ECONNREFUSED;
-               goto lookup_err;
-       }
+       struct sock *psk;
+       struct sock *csk;
 
-       sdp_conn_lock(listen_conn);
-       /*
-        * check backlog
-        */
-       listen_sk = sk_sdp(listen_conn);
-       sk = sk_sdp(conn);
+       sdp_inet_port_inherit(parent, child);
 
-       if (listen_conn->backlog_cnt > listen_conn->backlog_max) {
-               sdp_dbg_warn(listen_conn, 
-                            "Listen backlog <%d> too big to accept new conn",
-                            listen_conn->backlog_cnt);
-               result = -ECONNREFUSED;
-               goto locked_err;
-       }
-
-       result = sdp_inet_port_inherit(listen_conn, conn);
-       if (result < 0) {
-               sdp_dbg_warn(listen_conn, "Error <%d> listen port inherit.",
-                            result);
-               result = -EFAULT;
-               goto locked_err;
-       }
+       psk = sk_sdp(parent);
+       csk = sk_sdp(child);
        /*
         * insert accept socket into listen sockets list.
         * TODO: needs to be a FIFO not a LIFO, as is now.
         */
-       inet_sk(sk)->num       = conn->src_port;
-       inet_sk(sk)->sport     = htons(conn->src_port);
-       inet_sk(sk)->rcv_saddr = htonl(conn->src_addr);
-       inet_sk(sk)->saddr     = htonl(conn->src_addr);
-       inet_sk(sk)->daddr     = htonl(conn->dst_addr);
-       inet_sk(sk)->dport     = htons(conn->dst_port);
+       inet_sk(csk)->num       = child->src_port;
+       inet_sk(csk)->sport     = htons(child->src_port);
+       inet_sk(csk)->rcv_saddr = htonl(child->src_addr);
+       inet_sk(csk)->saddr     = htonl(child->src_addr);
+       inet_sk(csk)->daddr     = htonl(child->dst_addr);
+       inet_sk(csk)->dport     = htons(child->dst_port);
        /*
         * relevant options, and others... TCP does a full copy, I'd like to
         * know what I'm inheriting.
         */
-       sk->sk_lingertime   = listen_sk->sk_lingertime;
-       sk->sk_rcvlowat     = listen_sk->sk_rcvlowat;
-       if (sock_flag(listen_sk, SOCK_DBG))
-               sock_set_flag(sk, SOCK_DBG);
-       if (sock_flag(listen_sk, SOCK_LOCALROUTE))
-               sock_set_flag(sk, SOCK_LOCALROUTE);
-       sk->sk_sndbuf       = listen_sk->sk_sndbuf;
-       sk->sk_rcvbuf       = listen_sk->sk_rcvbuf;
-       sk->sk_no_check     = listen_sk->sk_no_check;
-       sk->sk_priority     = listen_sk->sk_priority;
-       if (sock_flag(listen_sk, SOCK_RCVTSTAMP))
-               sock_set_flag(sk, SOCK_RCVTSTAMP);
-       sk->sk_rcvtimeo     = listen_sk->sk_rcvtimeo;
-       sk->sk_sndtimeo     = listen_sk->sk_sndtimeo;
-       sk->sk_reuse        = listen_sk->sk_reuse;
-       sk->sk_bound_dev_if = listen_sk->sk_bound_dev_if;
-       sk->sk_userlocks   |= (listen_sk->sk_userlocks & ~SOCK_BINDPORT_LOCK);
-       sk->sk_flags        = ((SOCK_URGINLINE|SOCK_LINGER|SOCK_BROADCAST) &
-                              listen_sk->sk_flags);
+       csk->sk_lingertime   = psk->sk_lingertime;
+       csk->sk_rcvlowat     = psk->sk_rcvlowat;
+       csk->sk_sndbuf       = psk->sk_sndbuf;
+       csk->sk_rcvbuf       = psk->sk_rcvbuf;
+       csk->sk_no_check     = psk->sk_no_check;
+       csk->sk_priority     = psk->sk_priority;
+       csk->sk_rcvtimeo     = psk->sk_rcvtimeo;
+       csk->sk_sndtimeo     = psk->sk_sndtimeo;
+       csk->sk_reuse        = psk->sk_reuse;
+       csk->sk_bound_dev_if = psk->sk_bound_dev_if;
+       csk->sk_userlocks   |= (psk->sk_userlocks & ~SOCK_BINDPORT_LOCK);
+       csk->sk_flags        = ((SOCK_URGINLINE|SOCK_LINGER|SOCK_BROADCAST) &
+                               psk->sk_flags);
 
-       conn->src_zthresh = listen_conn->src_zthresh;
-       conn->snk_zthresh = listen_conn->snk_zthresh;
-       conn->nodelay     = listen_conn->nodelay;
-       /*
-        * initiate a CM response message.
-        */
-       result = sdp_cm_accept(conn);
-       if (result < 0) {
-               sdp_dbg_warn(conn, "Error <%d> CM connect accept", result);
-               goto locked_err;
-       }
-       /*
-        * place connection into the listen connections accept queue.
-        */
-       result = sdp_inet_accept_q_put(listen_conn, conn);
-       if (result < 0) {
-               sdp_dbg_warn(conn, 
-                            "Error <%d> adding socket to accept queue",
-                            result);
-               result = -EFAULT;
-               goto locked_err;
-       }
+       if (sock_flag(psk, SOCK_DBG))
+               sock_set_flag(csk, SOCK_DBG);
+       if (sock_flag(psk, SOCK_LOCALROUTE))
+               sock_set_flag(csk, SOCK_LOCALROUTE);
+       if (sock_flag(psk, SOCK_RCVTSTAMP))
+               sock_set_flag(csk, SOCK_RCVTSTAMP);
 
-       sdp_inet_wake_recv(listen_sk, 0);
-
-       result = 0;
-locked_err:
-       sdp_conn_unlock(listen_conn);
-       sdp_conn_put(listen_conn);      /* ListenLookup reference. */
-lookup_err:
-       return result;
+       child->src_zthresh = parent->src_zthresh;
+       child->snk_zthresh = parent->snk_zthresh;
+       child->nodelay     = parent->nodelay;
 }
 
 static int sdp_cm_hello_check(struct sdp_msg_hello *msg_hello)
@@ -415,8 +348,11 @@
 int sdp_cm_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event)
 {
        struct sdp_msg_hello *msg_hello = event->private_data;
+       struct sdp_opt *listen_conn;
        struct sdp_opt *conn;
        int result;
+       u16 port;
+       u32 addr;
 
        sdp_dbg_ctrl(NULL, 
                     "CM REQ. comm <%08x> SID <%016llx> ca <%s> port <%d>",
@@ -430,7 +366,36 @@
        if (result < 0) {
                sdp_dbg_warn(NULL, "Error <%d> validating hello msg. <%08x>",
                             result, cm_id->local_id);
+               goto empty;
+       }
+
+       port = SDP_SID_TO_PORT(be64_to_cpu(cm_id->service_id));
+       addr = msg_hello->hh.dst.ipv4.addr;
+       /*
+        * first find a listening connection, and check backlog
+        */
+       result = -ECONNREFUSED;
+       
+       listen_conn = sdp_inet_listen_lookup(addr, port);
+       if (!listen_conn) {
+               /*
+                * no connection, reject
+                */
+               sdp_dbg_ctrl(NULL, "no listener for connection. <%08x:%04x>",
+                            addr, port);
+               goto empty;
+       }
+
+       sdp_conn_lock(listen_conn);
+
+       if (listen_conn->state != SDP_CONN_ST_LISTEN)
                goto done;
+
+       if (listen_conn->backlog_cnt > listen_conn->backlog_max) {
+               sdp_dbg_ctrl(listen_conn, 
+                            "Listen backlog <%d> too big to accept new conn",
+                            listen_conn->backlog_cnt);
+               goto done;
        }
        /*
         * Create a connection for this request.
@@ -451,8 +416,8 @@
         */
        SDP_CONN_ST_SET(conn, SDP_CONN_ST_REQ_RECV);
 
-       conn->src_addr  = msg_hello->hh.dst.ipv4.addr;
-       conn->src_port  = SDP_SID_TO_PORT(be64_to_cpu(cm_id->service_id));
+       conn->src_addr  = addr;
+       conn->src_port  = port;
        conn->dst_addr  = msg_hello->hh.src.ipv4.addr;
        conn->dst_port  = msg_hello->hh.port;
 
@@ -473,7 +438,7 @@
               &event->param.req_rcvd.remote_ca_guid,
               sizeof(conn->d_gid));
        /*
-        * update CM context to refer to the connection.
+        * update CM context to refer to the connection, before alloc_ib()
         */
        conn->cm_id          = cm_id;
        conn->cm_id->context = hashent_arg(conn->hashent);
@@ -490,7 +455,7 @@
                goto error;
        }
        /*
-        * Save connect request info for QP modify.
+        * Save connect request info for QP modify in cm_accept().
         */
        conn->d_lid = event->param.req_rcvd.primary_path->dlid;
        conn->s_lid = event->param.req_rcvd.primary_path->slid;
@@ -498,19 +463,29 @@
 
         conn->path_mtu = event->param.req_rcvd.primary_path->mtu;
        /*
-        * Find a matching listening socket, and insert new connection 
-        * into listeners accept queue.
+        * inherit listener properties
         */
-       result = sdp_cm_listen_lookup(conn);
+       sdp_cm_listen_inherit(listen_conn, conn);
+       /*
+        * initiate a CM response message.
+        */
+       result = sdp_cm_accept(conn);
        if (result < 0) {
-               sdp_dbg_warn(conn, "Error <%d> matching listen socket queue",
-                            result);
+               sdp_dbg_warn(conn, "Error <%d> CM connect accept", result);
                goto error;
        }
        /*
+        * place connection into the listen connections accept queue.
+        */
+       sdp_inet_accept_q_put(listen_conn, conn);
+       sdp_inet_wake_recv(sk_sdp(listen_conn), 0);
+       /*
         * unlock
         */
        sdp_conn_unlock(conn);
+       sdp_conn_unlock(listen_conn);
+       sdp_conn_put(listen_conn);      /* ListenLookup reference. */
+
        return 0;
 error:
        SDP_CONN_ST_SET(conn, SDP_CONN_ST_CLOSED);
@@ -518,6 +493,9 @@
        sdp_conn_unlock(conn);
        sdp_conn_put(conn); /* CM reference */
 done:
+       sdp_conn_unlock(listen_conn);
+       sdp_conn_put(listen_conn);      /* ListenLookup reference. */
+empty:
        (void)ib_send_cm_rej(cm_id,
                             IB_CM_REJ_CONSUMER_DEFINED, 
                             NULL, 0, NULL, 0);
_______________________________________________
openib-general mailing list
[email protected]
http://openib.org/mailman/listinfo/openib-general

To unsubscribe, please visit http://openib.org/mailman/listinfo/openib-general

Reply via email to