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;
}
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)
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
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;
/* 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;
{
struct ksock_peer_ni *peer_ni;
struct ksock_conn *conn;
- struct list_head *ctmp;
int i;
read_lock(&ksocknal_data.ksnd_global_lock);
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;
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) {
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;
int rc;
int rc2;
int active;
+ int num_dup = 0;
char *warn = NULL;
active = (conn_cb != NULL);
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...
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) {
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) ||
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
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]));
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);
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 */
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;
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);
}
{
int index;
int i;
- struct list_head *tmp;
struct ksock_conn *conn;
for (index = 0; ; index++) {
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;
}
read_unlock(&ksocknal_data.ksnd_global_lock);
- if (conn == NULL)
+ if (i <= index)
break;
ksocknal_lib_push_conn (conn);
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;
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);
}
}
}
+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)
{
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);
}
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--;
goto failed;
}
+ register_netdevice_notifier(&ksocknal_notifier_block);
+
/* flag everything initialised */
ksocknal_data.ksnd_init = SOCKNAL_INIT_ALL;
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;
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;