Whamcloud - gitweb
LU-6142 lnet: convert kiblnd/ksocknal_thread_start to vararg
[fs/lustre-release.git] / lnet / klnds / socklnd / socklnd.c
index a0aef2d..fef2edf 100644 (file)
@@ -131,6 +131,9 @@ ksocknal_create_conn_cb(struct sockaddr *addr)
        conn_cb->ksnr_connected = 0;
        conn_cb->ksnr_deleted = 0;
        conn_cb->ksnr_conn_count = 0;
+       conn_cb->ksnr_ctrl_conn_count = 0;
+       conn_cb->ksnr_blki_conn_count = 0;
+       conn_cb->ksnr_blko_conn_count = 0;
 
        return conn_cb;
 }
@@ -363,6 +366,73 @@ out:
        return rc;
 }
 
+static unsigned int
+ksocknal_get_conn_count_by_type(struct ksock_conn_cb *conn_cb,
+                               int type)
+{
+       unsigned int count = 0;
+
+       switch (type) {
+       case SOCKLND_CONN_CONTROL:
+               count = conn_cb->ksnr_ctrl_conn_count;
+               break;
+       case SOCKLND_CONN_BULK_IN:
+               count = conn_cb->ksnr_blki_conn_count;
+               break;
+       case SOCKLND_CONN_BULK_OUT:
+               count = conn_cb->ksnr_blko_conn_count;
+               break;
+       case SOCKLND_CONN_ANY:
+               count = conn_cb->ksnr_conn_count;
+               break;
+       default:
+               LBUG();
+               break;
+       }
+
+       return count;
+}
+
+static void
+ksocknal_incr_conn_count(struct ksock_conn_cb *conn_cb,
+                        int type)
+{
+       conn_cb->ksnr_conn_count++;
+
+       /* check if all connections of the given type got created */
+       switch (type) {
+       case SOCKLND_CONN_CONTROL:
+               conn_cb->ksnr_ctrl_conn_count++;
+               /* there's a single control connection per peer */
+               conn_cb->ksnr_connected |= BIT(type);
+               break;
+       case SOCKLND_CONN_BULK_IN:
+               conn_cb->ksnr_blki_conn_count++;
+               if (conn_cb->ksnr_blki_conn_count >=
+                   *ksocknal_tunables.ksnd_conns_per_peer)
+                       conn_cb->ksnr_connected |= BIT(type);
+               break;
+       case SOCKLND_CONN_BULK_OUT:
+               conn_cb->ksnr_blko_conn_count++;
+               if (conn_cb->ksnr_blko_conn_count >=
+                   *ksocknal_tunables.ksnd_conns_per_peer)
+                       conn_cb->ksnr_connected |= BIT(type);
+               break;
+       case SOCKLND_CONN_ANY:
+               if (conn_cb->ksnr_conn_count >=
+                   *ksocknal_tunables.ksnd_conns_per_peer)
+                       conn_cb->ksnr_connected |= BIT(type);
+               break;
+       default:
+               LBUG();
+               break;
+
+       }
+
+       CDEBUG(D_NET, "Add conn type %d, ksnr_connected %x conns_per_peer %d\n",
+              type, conn_cb->ksnr_connected, *ksocknal_tunables.ksnd_conns_per_peer);
+}
+
 static void
 ksocknal_associate_cb_conn_locked(struct ksock_conn_cb *conn_cb,
                                  struct ksock_conn *conn)
@@ -404,8 +474,7 @@ ksocknal_associate_cb_conn_locked(struct ksock_conn_cb *conn_cb,
                        iface->ksni_nroutes++;
        }
 
-       conn_cb->ksnr_connected |= (1<<type);
-       conn_cb->ksnr_conn_count++;
+       ksocknal_incr_conn_count(conn_cb, type);
 
        /* Successful connection => further attempts can
         * proceed immediately
@@ -417,7 +486,6 @@ static void
 ksocknal_add_conn_cb_locked(struct ksock_peer_ni *peer_ni,
                            struct ksock_conn_cb *conn_cb)
 {
-       struct list_head *tmp;
        struct ksock_conn *conn;
        struct ksock_net *net = peer_ni->ksnp_ni->ni_data;
 
@@ -437,9 +505,7 @@ ksocknal_add_conn_cb_locked(struct ksock_peer_ni *peer_ni,
        /* peer_ni's route list takes over my ref on 'route' */
        peer_ni->ksnp_conn_cb = conn_cb;
 
-       list_for_each(tmp, &peer_ni->ksnp_conns) {
-               conn = list_entry(tmp, struct ksock_conn, ksnc_list);
-
+       list_for_each_entry(conn, &peer_ni->ksnp_conns, ksnc_list) {
                if (!rpc_cmp_addr((struct sockaddr *)&conn->ksnc_peeraddr,
                                  (struct sockaddr *)&conn_cb->ksnr_addr))
                        continue;
@@ -619,7 +685,6 @@ ksocknal_get_conn_by_idx(struct lnet_ni *ni, int index)
 {
        struct ksock_peer_ni *peer_ni;
        struct ksock_conn *conn;
-       struct list_head *ctmp;
        int i;
 
        read_lock(&ksocknal_data.ksnd_global_lock);
@@ -630,12 +695,11 @@ ksocknal_get_conn_by_idx(struct lnet_ni *ni, int index)
                if (peer_ni->ksnp_ni != ni)
                        continue;
 
-               list_for_each(ctmp, &peer_ni->ksnp_conns) {
+               list_for_each_entry(conn, &peer_ni->ksnp_conns,
+                                   ksnc_list) {
                        if (index-- > 0)
                                continue;
 
-                       conn = list_entry(ctmp, struct ksock_conn,
-                                         ksnc_list);
                        ksocknal_conn_addref(conn);
                        read_unlock(&ksocknal_data.ksnd_global_lock);
                        return conn;
@@ -674,7 +738,10 @@ ksocknal_accept(struct lnet_ni *ni, struct socket *sock)
        struct sockaddr_storage peer;
 
        rc = lnet_sock_getaddr(sock, true, &peer);
-       LASSERT(rc == 0);               /* we succeeded before */
+       if (rc != 0) {
+               CERROR("Can't determine new connection's address\n");
+               return rc;
+       }
 
        LIBCFS_ALLOC(cr, sizeof(*cr));
        if (cr == NULL) {
@@ -713,7 +780,6 @@ ksocknal_create_conn(struct lnet_ni *ni, struct ksock_conn_cb *conn_cb,
        rwlock_t *global_lock = &ksocknal_data.ksnd_global_lock;
        LIST_HEAD(zombies);
        struct lnet_process_id peerid;
-       struct list_head *tmp;
        u64 incarnation;
        struct ksock_conn *conn;
        struct ksock_conn *conn2;
@@ -727,6 +793,7 @@ ksocknal_create_conn(struct lnet_ni *ni, struct ksock_conn_cb *conn_cb,
        int rc;
        int rc2;
        int active;
+       int num_dup = 0;
        char *warn = NULL;
 
        active = (conn_cb != NULL);
@@ -845,9 +912,9 @@ ksocknal_create_conn(struct lnet_ni *ni, struct ksock_conn_cb *conn_cb,
                        peer_ni = peer2;
                }
 
-                /* +1 ref for me */
-                ksocknal_peer_addref(peer_ni);
-                peer_ni->ksnp_accepting++;
+               /* +1 ref for me */
+               ksocknal_peer_addref(peer_ni);
+               peer_ni->ksnp_accepting++;
 
                /* Am I already connecting to this guy?  Resolve in
                 * favour of higher NID...
@@ -859,14 +926,14 @@ ksocknal_create_conn(struct lnet_ni *ni, struct ksock_conn_cb *conn_cb,
                        warn = "connection race resolution";
                        goto failed_2;
                }
-        }
+       }
 
-        if (peer_ni->ksnp_closing ||
+       if (peer_ni->ksnp_closing ||
            (active && conn_cb->ksnr_deleted)) {
                /* peer_ni/conn_cb got closed under me */
-                rc = -ESTALE;
+               rc = -ESTALE;
                warn = "peer_ni/conn_cb removed";
-                goto failed_2;
+               goto failed_2;
         }
 
        if (peer_ni->ksnp_proto == NULL) {
@@ -893,26 +960,24 @@ ksocknal_create_conn(struct lnet_ni *ni, struct ksock_conn_cb *conn_cb,
                goto failed_2;
        }
 
-        switch (rc) {
-        default:
-                LBUG();
-        case 0:
-                break;
-        case EALREADY:
-                warn = "lost conn race";
-                goto failed_2;
-        case EPROTO:
-                warn = "retry with different protocol version";
-                goto failed_2;
-        }
+       switch (rc) {
+       default:
+               LBUG();
+       case 0:
+               break;
+       case EALREADY:
+               warn = "lost conn race";
+               goto failed_2;
+       case EPROTO:
+               warn = "retry with different protocol version";
+               goto failed_2;
+       }
 
        /* Refuse to duplicate an existing connection, unless this is a
         * loopback connection */
        if (!rpc_cmp_addr((struct sockaddr *)&conn->ksnc_peeraddr,
                          (struct sockaddr *)&conn->ksnc_myaddr)) {
-               list_for_each(tmp, &peer_ni->ksnp_conns) {
-                       conn2 = list_entry(tmp, struct ksock_conn, ksnc_list);
-
+               list_for_each_entry(conn2, &peer_ni->ksnp_conns, ksnc_list) {
                        if (!rpc_cmp_addr(
                                    (struct sockaddr *)&conn2->ksnc_peeraddr,
                                    (struct sockaddr *)&conn->ksnc_peeraddr) ||
@@ -922,29 +987,33 @@ ksocknal_create_conn(struct lnet_ni *ni, struct ksock_conn_cb *conn_cb,
                            conn2->ksnc_type != conn->ksnc_type)
                                continue;
 
-                        /* Reply on a passive connection attempt so the peer_ni
-                         * realises we're connected. */
-                        LASSERT (rc == 0);
-                        if (!active)
-                                rc = EALREADY;
+                       num_dup++;
+                       if (num_dup < *ksocknal_tunables.ksnd_conns_per_peer)
+                               continue;
 
-                        warn = "duplicate";
-                        goto failed_2;
-                }
-        }
+                       /* Reply on a passive connection attempt so the peer_ni
+                        * realises we're connected.
+                        */
+                       LASSERT(rc == 0);
+                       if (!active)
+                               rc = EALREADY;
 
-        /* If the connection created by this route didn't bind to the IP
-         * address the route connected to, the connection/route matching
+                       warn = "duplicate";
+                       goto failed_2;
+               }
+       }
+       /* If the connection created by this route didn't bind to the IP
+        * address the route connected to, the connection/route matching
         * code below probably isn't going to work.
         */
-        if (active &&
+       if (active &&
            !rpc_cmp_addr((struct sockaddr *)&conn_cb->ksnr_addr,
                          (struct sockaddr *)&conn->ksnc_peeraddr)) {
                CERROR("Route %s %pIS connected to %pIS\n",
                       libcfs_id2str(peer_ni->ksnp_id),
                       &conn_cb->ksnr_addr,
                       &conn->ksnc_peeraddr);
-        }
+       }
 
        /* Search for a conn_cb corresponding to the new connection and
         * create an association.  This allows incoming connections created
@@ -1017,8 +1086,8 @@ ksocknal_create_conn(struct lnet_ni *ni, struct ksock_conn_cb *conn_cb,
 
        if (!active) {
                hello->kshm_nips = 0;
-                rc = ksocknal_send_hello(ni, conn, peerid.nid, hello);
-        }
+               rc = ksocknal_send_hello(ni, conn, peerid.nid, hello);
+       }
 
        LIBCFS_FREE(hello, offsetof(struct ksock_hello_msg,
                                    kshm_ips[LNET_INTERFACES_NUM]));
@@ -1126,7 +1195,6 @@ ksocknal_close_conn_locked(struct ksock_conn *conn, int error)
        struct ksock_peer_ni *peer_ni = conn->ksnc_peer;
        struct ksock_conn_cb *conn_cb;
        struct ksock_conn *conn2;
-       struct list_head *tmp;
 
        LASSERT(peer_ni->ksnp_error == 0);
        LASSERT(!conn->ksnc_closing);
@@ -1139,21 +1207,22 @@ ksocknal_close_conn_locked(struct ksock_conn *conn, int error)
        if (conn_cb != NULL) {
                /* dissociate conn from cb... */
                LASSERT(!conn_cb->ksnr_deleted);
-               LASSERT((conn_cb->ksnr_connected & BIT(conn->ksnc_type)) != 0);
 
-               conn2 = NULL;
-               list_for_each(tmp, &peer_ni->ksnp_conns) {
-                       conn2 = list_entry(tmp, struct ksock_conn, ksnc_list);
+               /* connected bit is set only if all connections
+                * of the given type got created
+                */
+               if (ksocknal_get_conn_count_by_type(conn_cb, conn->ksnc_type) ==
+                   *ksocknal_tunables.ksnd_conns_per_peer)
+                       LASSERT((conn_cb->ksnr_connected &
+                               BIT(conn->ksnc_type)) != 0);
 
+               list_for_each_entry(conn2, &peer_ni->ksnp_conns, ksnc_list) {
                        if (conn2->ksnc_conn_cb == conn_cb &&
                            conn2->ksnc_type == conn->ksnc_type)
-                               break;
-
-                       conn2 = NULL;
+                               goto conn2_found;
                }
-               if (conn2 == NULL)
-                       conn_cb->ksnr_connected &= ~BIT(conn->ksnc_type);
-
+               conn_cb->ksnr_connected &= ~BIT(conn->ksnc_type);
+conn2_found:
                conn->ksnc_conn_cb = NULL;
 
                /* drop conn's ref on conn_cb */
@@ -1242,7 +1311,8 @@ ksocknal_finalize_zcreq(struct ksock_conn *conn)
 
        spin_lock(&peer_ni->ksnp_lock);
 
-       list_for_each_entry_safe(tx, tmp, &peer_ni->ksnp_zc_req_list, tx_zc_list) {
+       list_for_each_entry_safe(tx, tmp, &peer_ni->ksnp_zc_req_list,
+                                tx_zc_list) {
                if (tx->tx_conn != conn)
                        continue;
 
@@ -1255,9 +1325,8 @@ ksocknal_finalize_zcreq(struct ksock_conn *conn)
 
        spin_unlock(&peer_ni->ksnp_lock);
 
-       while (!list_empty(&zlist)) {
-               tx = list_entry(zlist.next, struct ksock_tx, tx_zc_list);
-
+       while ((tx = list_first_entry_or_null(&zlist, struct ksock_tx,
+                                             tx_zc_list)) != NULL) {
                list_del(&tx->tx_zc_list);
                ksocknal_tx_decref(tx);
        }
@@ -1511,7 +1580,6 @@ ksocknal_push_peer(struct ksock_peer_ni *peer_ni)
 {
        int index;
        int i;
-       struct list_head *tmp;
        struct ksock_conn *conn;
 
         for (index = 0; ; index++) {
@@ -1520,10 +1588,8 @@ ksocknal_push_peer(struct ksock_peer_ni *peer_ni)
                 i = 0;
                 conn = NULL;
 
-               list_for_each(tmp, &peer_ni->ksnp_conns) {
+               list_for_each_entry(conn, &peer_ni->ksnp_conns, ksnc_list) {
                         if (i++ == index) {
-                               conn = list_entry(tmp, struct ksock_conn,
-                                                 ksnc_list);
                                 ksocknal_conn_addref(conn);
                                 break;
                         }
@@ -1531,7 +1597,7 @@ ksocknal_push_peer(struct ksock_peer_ni *peer_ni)
 
                read_unlock(&ksocknal_data.ksnd_global_lock);
 
-                if (conn == NULL)
+               if (i <= index)
                         break;
 
                 ksocknal_lib_push_conn (conn);
@@ -1606,9 +1672,9 @@ ksocknal_ctl(struct lnet_ni *ni, unsigned int cmd, void *arg)
                read_lock(&ksocknal_data.ksnd_global_lock);
 
                if (data->ioc_count >= 1) {
-                        rc = -ENOENT;
-                } else {
-                        rc = 0;
+                       rc = -ENOENT;
+               } else {
+                       rc = 0;
                        iface = &net->ksnn_interface;
 
                        sa = (void *)&iface->ksni_addr;
@@ -1741,8 +1807,8 @@ ksocknal_free_buffers (void)
                list_splice_init(&ksocknal_data.ksnd_idle_noop_txs, &zlist);
                spin_unlock(&ksocknal_data.ksnd_tx_lock);
 
-               while (!list_empty(&zlist)) {
-                       tx = list_entry(zlist.next, struct ksock_tx, tx_list);
+               while ((tx = list_first_entry_or_null(&zlist, struct ksock_tx,
+                                                     tx_list)) != NULL) {
                        list_del(&tx->tx_list);
                        LIBCFS_FREE(tx, tx->tx_desc_size);
                }
@@ -1751,6 +1817,78 @@ ksocknal_free_buffers (void)
        }
 }
 
+static int ksocknal_get_link_status(struct net_device *dev)
+{
+       int ret = -1;
+
+       LASSERT(dev);
+
+       if (!netif_running(dev))
+               ret = 0;
+       /* Some devices may not be providing link settings */
+       else if (dev->ethtool_ops->get_link)
+               ret = dev->ethtool_ops->get_link(dev);
+
+       return ret;
+}
+
+static int
+ksocknal_handle_link_state_change(struct net_device *dev,
+                                 unsigned char operstate)
+{
+       struct lnet_ni *ni;
+       struct ksock_net *net;
+       struct ksock_net *cnxt;
+       int ifindex;
+       unsigned char link_down = !(operstate == IF_OPER_UP);
+
+       ifindex = dev->ifindex;
+
+       if (!ksocknal_data.ksnd_nnets)
+               goto out;
+
+       list_for_each_entry_safe(net, cnxt, &ksocknal_data.ksnd_nets,
+                                ksnn_list) {
+               if (net->ksnn_interface.ksni_index != ifindex)
+                       continue;
+               ni = net->ksnn_ni;
+               if (link_down)
+                       atomic_set(&ni->ni_fatal_error_on, link_down);
+               else
+                       atomic_set(&ni->ni_fatal_error_on,
+                                  (ksocknal_get_link_status(dev) == 0));
+       }
+out:
+       return 0;
+}
+
+
+/************************************
+ * Net device notifier event handler
+ ************************************/
+static int ksocknal_device_event(struct notifier_block *unused,
+                                unsigned long event, void *ptr)
+{
+       struct net_device *dev = netdev_notifier_info_to_dev(ptr);
+       unsigned char operstate;
+
+       operstate = dev->operstate;
+
+       switch (event) {
+       case NETDEV_UP:
+       case NETDEV_DOWN:
+       case NETDEV_CHANGE:
+               ksocknal_handle_link_state_change(dev, operstate);
+               break;
+       }
+
+       return NOTIFY_OK;
+}
+
+static struct notifier_block ksocknal_notifier_block = {
+       .notifier_call = ksocknal_device_event,
+};
+
 static void
 ksocknal_base_shutdown(void)
 {
@@ -1762,6 +1900,9 @@ ksocknal_base_shutdown(void)
               libcfs_kmem_read());
        LASSERT (ksocknal_data.ksnd_nnets == 0);
 
+       if (ksocknal_data.ksnd_init == SOCKNAL_INIT_ALL)
+               unregister_netdevice_notifier(&ksocknal_notifier_block);
+
        switch (ksocknal_data.ksnd_init) {
        default:
                LASSERT(0);
@@ -1904,15 +2045,13 @@ ksocknal_base_startup(void)
         }
 
         for (i = 0; i < *ksocknal_tunables.ksnd_nconnds; i++) {
-               char name[16];
                spin_lock_bh(&ksocknal_data.ksnd_connd_lock);
                ksocknal_data.ksnd_connd_starting++;
                spin_unlock_bh(&ksocknal_data.ksnd_connd_lock);
 
-
-               snprintf(name, sizeof(name), "socknal_cd%02d", i);
                rc = ksocknal_thread_start(ksocknal_connd,
-                                          (void *)((uintptr_t)i), name);
+                                          (void *)((uintptr_t)i),
+                                          "socknal_cd%02d", i);
                if (rc != 0) {
                        spin_lock_bh(&ksocknal_data.ksnd_connd_lock);
                        ksocknal_data.ksnd_connd_starting--;
@@ -1928,6 +2067,8 @@ ksocknal_base_startup(void)
                 goto failed;
         }
 
+       register_netdevice_notifier(&ksocknal_notifier_block);
+
         /* flag everything initialised */
         ksocknal_data.ksnd_init = SOCKNAL_INIT_ALL;
 
@@ -2078,14 +2219,12 @@ ksocknal_start_schedulers(struct ksock_sched *sched)
 
        for (i = 0; i < nthrs; i++) {
                long id;
-               char name[20];
 
                id = KSOCK_THREAD_ID(sched->kss_cpt, sched->kss_nthreads + i);
-               snprintf(name, sizeof(name), "socknal_sd%02d_%02d",
-                        sched->kss_cpt, (int)KSOCK_THREAD_SID(id));
-
-               rc = ksocknal_thread_start(ksocknal_scheduler,
-                                          (void *)id, name);
+               rc = ksocknal_thread_start(ksocknal_scheduler, (void *)id,
+                                          "socknal_sd%02d_%02d",
+                                          sched->kss_cpt,
+                                          (int)KSOCK_THREAD_SID(id));
                if (rc == 0)
                        continue;
 
@@ -2210,6 +2349,7 @@ ksocknal_startup(struct lnet_ni *ni)
                ntohl(((struct sockaddr_in *)
                       &ksi->ksni_addr)->sin_addr.s_addr));
        list_add(&net->ksnn_list, &ksocknal_data.ksnd_nets);
+       net->ksnn_ni = ni;
        ksocknal_data.ksnd_nnets++;
 
        return 0;