X-Git-Url: https://git.whamcloud.com/?a=blobdiff_plain;f=lnet%2Fklnds%2Fsocklnd%2Fsocklnd.c;h=360f905895d8123a9217feb33bb18d16320b4a21;hb=6556906a665f9e88840dd20d2abcc0fa9dfcd379;hp=00a260a2f50c72dabd2bb8364091fec3f9c49402;hpb=cf814617a3151e53c30204fea07afad595b8eddc;p=fs%2Flustre-release.git diff --git a/lnet/klnds/socklnd/socklnd.c b/lnet/klnds/socklnd/socklnd.c index 00a260a..360f905 100644 --- a/lnet/klnds/socklnd/socklnd.c +++ b/lnet/klnds/socklnd/socklnd.c @@ -1,26 +1,44 @@ /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- * vim:expandtab:shiftwidth=8:tabstop=8: * - * Copyright (C) 2001, 2002 Cluster File Systems, Inc. - * Author: Zach Brown - * Author: Peter J. Braam - * Author: Phil Schwan - * Author: Eric Barton + * GPL HEADER START * - * This file is part of Portals, http://www.sf.net/projects/sandiaportals/ + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * - * Portals is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 only, + * as published by the Free Software Foundation. * - * Portals is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 for more details (a copy is included + * in the LICENSE file that accompanied this code). * - * You should have received a copy of the GNU General Public License - * along with Portals; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * You should have received a copy of the GNU General Public License + * version 2 along with this program; If not, see + * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * GPL HEADER END + */ +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved + * Use is subject to license terms. + */ +/* + * This file is part of Lustre, http://www.lustre.org/ + * Lustre is a trademark of Sun Microsystems, Inc. + * + * lnet/klnds/socklnd/socklnd.c + * + * Author: Zach Brown + * Author: Peter J. Braam + * Author: Phil Schwan + * Author: Eric Barton */ #include "socklnd.h" @@ -124,7 +142,7 @@ ksocknal_create_peer (ksock_peer_t **peerp, lnet_ni_t *ni, lnet_process_id_t id) if (net->ksnn_shutdown) { spin_unlock_bh (&net->ksnn_lock); - + LIBCFS_FREE(peer, sizeof(*peer)); CERROR("Can't create peer: network shutdown\n"); return -ESHUTDOWN; @@ -143,7 +161,7 @@ ksocknal_destroy_peer (ksock_peer_t *peer) { ksock_net_t *net = peer->ksnp_ni->ni_data; - CDEBUG (D_NET, "peer %s %p deleted\n", + CDEBUG (D_NET, "peer %s %p deleted\n", libcfs_id2str(peer->ksnp_id), peer); LASSERT (atomic_read (&peer->ksnp_refcount) == 0); @@ -185,7 +203,7 @@ ksocknal_find_peer_locked (lnet_ni_t *ni, lnet_process_id_t id) continue; CDEBUG(D_NET, "got peer [%p] -> %s (%d)\n", - peer, libcfs_id2str(id), + peer, libcfs_id2str(id), atomic_read(&peer->ksnp_refcount)); return (peer); } @@ -211,12 +229,20 @@ ksocknal_unlink_peer_locked (ksock_peer_t *peer) { int i; __u32 ip; + ksock_interface_t *iface; for (i = 0; i < peer->ksnp_n_passive_ips; i++) { LASSERT (i < LNET_MAX_INTERFACES); ip = peer->ksnp_passive_ips[i]; - ksocknal_ip2iface(peer->ksnp_ni, ip)->ksni_npeers--; + iface = ksocknal_ip2iface(peer->ksnp_ni, ip); + /* All IPs in peer->ksnp_passive_ips[] come from the + * interface list, therefore the call must succeed. */ + LASSERT (iface != NULL); + + CDEBUG(D_NET, "peer=%p iface=%p ksni_nroutes=%d\n", + peer, iface, iface->ksni_nroutes); + iface->ksni_npeers--; } LASSERT (list_empty(&peer->ksnp_conns)); @@ -229,7 +255,7 @@ ksocknal_unlink_peer_locked (ksock_peer_t *peer) } int -ksocknal_get_peer_info (lnet_ni_t *ni, int index, +ksocknal_get_peer_info (lnet_ni_t *ni, int index, lnet_process_id_t *id, __u32 *myip, __u32 *peer_ip, int *port, int *conn_count, int *share_count) { @@ -367,7 +393,7 @@ ksocknal_add_route_locked (ksock_peer_t *peer, ksock_route_t *route) if (route2->ksnr_ipaddr == route->ksnr_ipaddr) { CERROR ("Duplicate route %s %u.%u.%u.%u\n", - libcfs_id2str(peer->ksnp_id), + libcfs_id2str(peer->ksnp_id), HIPQUAD(route->ksnr_ipaddr)); LBUG(); } @@ -690,7 +716,7 @@ ksocknal_local_ipvec (lnet_ni_t *ni, __u32 *ipaddrs) read_unlock (&ksocknal_data.ksnd_global_lock); return 0; } - + for (i = 0; i < nip; i++) { ipaddrs[i] = net->ksnn_interfaces[i].ksni_ipaddr; LASSERT (ipaddrs[i] != 0); @@ -869,7 +895,7 @@ ksocknal_create_routes(ksock_peer_t *peer, int port, write_unlock_bh (global_lock); return; } - + LASSERT (npeer_ipaddrs <= LNET_MAX_INTERFACES); for (i = 0; i < npeer_ipaddrs; i++) { @@ -982,16 +1008,16 @@ ksocknal_accept (lnet_ni_t *ni, cfs_socket_t *sock) list_add_tail(&cr->ksncr_list, &ksocknal_data.ksnd_connd_connreqs); cfs_waitq_signal(&ksocknal_data.ksnd_connd_waitq); - + spin_unlock_bh (&ksocknal_data.ksnd_connd_lock); return 0; } int -ksocknal_connecting (ksock_peer_t *peer, __u32 ipaddr) +ksocknal_connecting (ksock_peer_t *peer, __u32 ipaddr) { ksock_route_t *route; - + list_for_each_entry (route, &peer->ksnp_routes, ksnr_list) { if (route->ksnr_ipaddr == ipaddr) @@ -1001,7 +1027,7 @@ ksocknal_connecting (ksock_peer_t *peer, __u32 ipaddr) } int -ksocknal_create_conn (lnet_ni_t *ni, ksock_route_t *route, +ksocknal_create_conn (lnet_ni_t *ni, ksock_route_t *route, cfs_socket_t *sock, int type) { rwlock_t *global_lock = &ksocknal_data.ksnd_global_lock; @@ -1037,7 +1063,9 @@ ksocknal_create_conn (lnet_ni_t *ni, ksock_route_t *route, conn->ksnc_peer = NULL; conn->ksnc_route = NULL; conn->ksnc_sock = sock; - atomic_set (&conn->ksnc_sock_refcount, 1); /* 1 ref for conn */ + /* 2 ref, 1 for conn, another extra ref prevents socket + * being closed before establishment of connection */ + atomic_set (&conn->ksnc_sock_refcount, 2); conn->ksnc_type = type; ksocknal_lib_save_callback(sock, conn); atomic_set (&conn->ksnc_conn_refcount, 1); /* 1 ref for me */ @@ -1080,7 +1108,7 @@ ksocknal_create_conn (lnet_ni_t *ni, ksock_route_t *route, write_lock_bh(global_lock); conn->ksnc_proto = peer->ksnp_proto; write_unlock_bh(global_lock); - + if (conn->ksnc_proto == NULL) { conn->ksnc_proto = &ksocknal_protocol_v2x; #if SOCKNAL_VERSION_DEBUG @@ -1135,7 +1163,7 @@ ksocknal_create_conn (lnet_ni_t *ni, ksock_route_t *route, /* +1 ref for me */ ksocknal_peer_addref(peer); peer->ksnp_accepting++; - + /* Am I already connecting to this guy? Resolve in * favour of higher NID... */ if (peerid.nid < ni->ni_nid && @@ -1154,13 +1182,13 @@ ksocknal_create_conn (lnet_ni_t *ni, ksock_route_t *route, goto failed_2; } - if (peer->ksnp_proto == NULL) { + if (peer->ksnp_proto == NULL) { /* Never connected before. * NB recv_hello may have returned EPROTO to signal my peer * wants a different protocol than the one I asked for. */ LASSERT (list_empty(&peer->ksnp_conns)); - + peer->ksnp_proto = conn->ksnc_proto; peer->ksnp_incarnation = incarnation; } @@ -1172,7 +1200,7 @@ ksocknal_create_conn (lnet_ni_t *ni, ksock_route_t *route, peer->ksnp_proto = NULL; rc = ESTALE; - warn = peer->ksnp_incarnation != incarnation ? + warn = peer->ksnp_incarnation != incarnation ? "peer rebooted" : "wrong proto version"; goto failed_2; @@ -1295,7 +1323,7 @@ ksocknal_create_conn (lnet_ni_t *ni, ksock_route_t *route, hello->kshm_nips); rc = ksocknal_send_hello(ni, conn, peerid.nid, hello); } - + LIBCFS_FREE(hello, offsetof(ksock_hello_msg_t, kshm_ips[LNET_MAX_INTERFACES])); @@ -1328,6 +1356,7 @@ ksocknal_create_conn (lnet_ni_t *ni, ksock_route_t *route, ksocknal_connsock_decref(conn); } + ksocknal_connsock_decref(conn); ksocknal_conn_decref(conn); return rc; @@ -1339,7 +1368,7 @@ ksocknal_create_conn (lnet_ni_t *ni, ksock_route_t *route, list_del_init(&peer->ksnp_tx_queue); ksocknal_unlink_peer_locked(peer); } - + write_unlock_bh (global_lock); if (warn != NULL) { @@ -1364,7 +1393,7 @@ ksocknal_create_conn (lnet_ni_t *ni, ksock_route_t *route, peer->ksnp_accepting--; write_unlock_bh(global_lock); } - + ksocknal_txlist_done(ni, &zombies, 1); ksocknal_peer_decref(peer); @@ -1456,7 +1485,7 @@ ksocknal_peer_failed (ksock_peer_t *peer) /* There has been a connection failure or comms error; but I'll only * tell LNET I think the peer is dead if it's to another kernel and * there are no connections or connection attempts in existance. */ - + read_lock (&ksocknal_data.ksnd_global_lock); if ((peer->ksnp_id.pid & LNET_PID_USERFLAG) == 0 && @@ -1468,7 +1497,7 @@ ksocknal_peer_failed (ksock_peer_t *peer) cfs_duration_sec(cfs_time_current() - peer->ksnp_last_alive); } - + read_unlock (&ksocknal_data.ksnd_global_lock); if (notify) @@ -1477,6 +1506,41 @@ ksocknal_peer_failed (ksock_peer_t *peer) } void +ksocknal_finalize_zcreq(ksock_conn_t *conn) +{ + ksock_peer_t *peer = conn->ksnc_peer; + ksock_tx_t *tx; + ksock_tx_t *tmp; + CFS_LIST_HEAD (zlist); + + /* NB safe to finalize TXs because closing of socket will + * abort all buffered data */ + LASSERT (conn->ksnc_sock == NULL); + + spin_lock(&peer->ksnp_lock); + + list_for_each_entry_safe(tx, tmp, &peer->ksnp_zc_req_list, tx_zc_list) { + if (tx->tx_conn != conn) + continue; + + LASSERT (tx->tx_msg.ksm_zc_req_cookie != 0); + + tx->tx_msg.ksm_zc_req_cookie = 0; + list_del(&tx->tx_zc_list); + list_add(&tx->tx_zc_list, &zlist); + } + + spin_unlock(&peer->ksnp_lock); + + while (!list_empty(&zlist)) { + tx = list_entry(zlist.next, ksock_tx_t, tx_zc_list); + + list_del(&tx->tx_zc_list); + ksocknal_tx_decref(tx); + } +} + +void ksocknal_terminate_conn (ksock_conn_t *conn) { /* This gets called by the reaper (guaranteed thread context) to @@ -1486,22 +1550,19 @@ ksocknal_terminate_conn (ksock_conn_t *conn) ksock_peer_t *peer = conn->ksnc_peer; ksock_sched_t *sched = conn->ksnc_scheduler; int failed = 0; - struct list_head *tmp; - struct list_head *nxt; - ksock_tx_t *tx; - LIST_HEAD (zlist); LASSERT(conn->ksnc_closing); /* wake up the scheduler to "send" all remaining packets to /dev/null */ spin_lock_bh (&sched->kss_lock); + /* a closing conn is always ready to tx */ + conn->ksnc_tx_ready = 1; + if (!conn->ksnc_tx_scheduled && !list_empty(&conn->ksnc_tx_queue)){ list_add_tail (&conn->ksnc_tx_list, &sched->kss_tx_conns); - /* a closing conn is always ready to tx */ - conn->ksnc_tx_ready = 1; conn->ksnc_tx_scheduled = 1; /* extra ref for scheduler */ ksocknal_conn_addref(conn); @@ -1511,30 +1572,6 @@ ksocknal_terminate_conn (ksock_conn_t *conn) spin_unlock_bh (&sched->kss_lock); - spin_lock(&peer->ksnp_lock); - - list_for_each_safe(tmp, nxt, &peer->ksnp_zc_req_list) { - tx = list_entry(tmp, ksock_tx_t, tx_zc_list); - - if (tx->tx_conn != conn) - continue; - - LASSERT (tx->tx_msg.ksm_zc_req_cookie != 0); - - tx->tx_msg.ksm_zc_req_cookie = 0; - list_del(&tx->tx_zc_list); - list_add(&tx->tx_zc_list, &zlist); - } - - spin_unlock(&peer->ksnp_lock); - - list_for_each_safe(tmp, nxt, &zlist) { - tx = list_entry(tmp, ksock_tx_t, tx_zc_list); - - list_del(&tx->tx_zc_list); - ksocknal_tx_decref(tx); - } - /* serialise with callbacks */ write_lock_bh (&ksocknal_data.ksnd_global_lock); @@ -1574,7 +1611,7 @@ ksocknal_queue_zombie_conn (ksock_conn_t *conn) list_add_tail(&conn->ksnc_list, &ksocknal_data.ksnd_zombie_conns); cfs_waitq_signal(&ksocknal_data.ksnd_reaper_waitq); - + spin_unlock_bh (&ksocknal_data.ksnd_reaper_lock); } @@ -1599,7 +1636,7 @@ ksocknal_destroy_conn (ksock_conn_t *conn) ", ip %d.%d.%d.%d:%d, with error\n", libcfs_id2str(conn->ksnc_peer->ksnp_id), HIPQUAD(conn->ksnc_ipaddr), conn->ksnc_port); - lnet_finalize (conn->ksnc_peer->ksnp_ni, + lnet_finalize (conn->ksnc_peer->ksnp_ni, conn->ksnc_cookie, -EIO); break; case SOCKNAL_RX_LNET_HEADER: @@ -1721,7 +1758,7 @@ ksocknal_notify (lnet_ni_t *ni, lnet_nid_t gw_nid, int alive) * gateway state.... */ lnet_process_id_t id = {.nid = gw_nid, .pid = LNET_PID_ANY}; - CDEBUG (D_NET, "gw %s %s\n", libcfs_nid2str(gw_nid), + CDEBUG (D_NET, "gw %s %s\n", libcfs_nid2str(gw_nid), alive ? "up" : "down"); if (!alive) { @@ -1997,7 +2034,7 @@ ksocknal_ctl(lnet_ni_t *ni, unsigned int cmd, void *arg) data->ioc_u32[1]); /* net mask */ case IOC_LIBCFS_DEL_INTERFACE: - return ksocknal_del_interface(ni, + return ksocknal_del_interface(ni, data->ioc_u32[0]); /* IP address */ case IOC_LIBCFS_GET_PEER: { @@ -2013,7 +2050,7 @@ ksocknal_ctl(lnet_ni_t *ni, unsigned int cmd, void *arg) &conn_count, &share_count); if (rc != 0) return rc; - + data->ioc_nid = id.nid; data->ioc_count = share_count; data->ioc_u32[0] = ip; @@ -2072,18 +2109,18 @@ ksocknal_ctl(lnet_ni_t *ni, unsigned int cmd, void *arg) } case IOC_LIBCFS_REGISTER_MYNID: /* Ignore if this is a noop */ - if (data->ioc_nid == ni->ni_nid) - return 0; + if (data->ioc_nid == ni->ni_nid) + return 0; - CERROR("obsolete IOC_LIBCFS_REGISTER_MYNID: %s(%s)\n", - libcfs_nid2str(data->ioc_nid), - libcfs_nid2str(ni->ni_nid)); - return -EINVAL; + CERROR("obsolete IOC_LIBCFS_REGISTER_MYNID: %s(%s)\n", + libcfs_nid2str(data->ioc_nid), + libcfs_nid2str(ni->ni_nid)); + return -EINVAL; case IOC_LIBCFS_PUSH_CONNECTION: { lnet_process_id_t id = {.nid = data->ioc_nid, .pid = LNET_PID_ANY}; - + return ksocknal_push(ni, id); } default: @@ -2286,7 +2323,7 @@ ksocknal_base_startup (void) * connecting */ if (*ksocknal_tunables.ksnd_nconnds < 2) *ksocknal_tunables.ksnd_nconnds = 2; - + for (i = 0; i < *ksocknal_tunables.ksnd_nconnds; i++) { rc = ksocknal_thread_start (ksocknal_connd, (void *)((long)i)); if (rc != 0) { @@ -2407,7 +2444,7 @@ ksocknal_shutdown (lnet_ni_t *ni) } LIBCFS_FREE(net, sizeof(*net)); - + ksocknal_data.ksnd_nnets--; if (ksocknal_data.ksnd_nnets == 0) ksocknal_base_shutdown(); @@ -2421,7 +2458,7 @@ ksocknal_enumerate_interfaces(ksock_net_t *net) int j; int rc; int n; - + n = libcfs_ipif_enumerate(&names); if (n <= 0) { CERROR("Can't enumerate interfaces: %d\n", n); @@ -2442,7 +2479,7 @@ ksocknal_enumerate_interfaces(ksock_net_t *net) names[i], rc); continue; } - + if (!up) { CWARN("Ignoring interface %s (down)\n", names[i]); @@ -2461,10 +2498,10 @@ ksocknal_enumerate_interfaces(ksock_net_t *net) } libcfs_ipif_free_enumeration(names, n); - + if (j == 0) CERROR("Can't find any usable interfaces\n"); - + return j; } @@ -2482,18 +2519,18 @@ ksocknal_startup (lnet_ni_t *ni) if (rc != 0) return rc; } - + LIBCFS_ALLOC(net, sizeof(*net)); if (net == NULL) goto fail_0; - + memset(net, 0, sizeof(*net)); spin_lock_init(&net->ksnn_lock); net->ksnn_incarnation = ksocknal_new_incarnation(); ni->ni_data = net; ni->ni_maxtxcredits = *ksocknal_tunables.ksnd_credits; ni->ni_peertxcredits = *ksocknal_tunables.ksnd_peercredits; - + if (ni->ni_interfaces[0] == NULL) { rc = ksocknal_enumerate_interfaces(net); if (rc <= 0) @@ -2511,13 +2548,13 @@ ksocknal_startup (lnet_ni_t *ni) ni->ni_interfaces[i], &up, &net->ksnn_interfaces[i].ksni_ipaddr, &net->ksnn_interfaces[i].ksni_netmask); - + if (rc != 0) { CERROR("Can't get interface %s info: %d\n", ni->ni_interfaces[i], rc); goto fail_1; } - + if (!up) { CERROR("Interface %s is down\n", ni->ni_interfaces[i]); @@ -2533,7 +2570,7 @@ ksocknal_startup (lnet_ni_t *ni) ksocknal_data.ksnd_nnets++; return 0; - + fail_1: LIBCFS_FREE(net, sizeof(*net)); fail_0: @@ -2558,7 +2595,7 @@ ksocknal_module_init (void) /* check ksnr_connected/connecting field large enough */ CLASSERT(SOCKLND_CONN_NTYPES <= 4); - + rc = ksocknal_lib_tunables_init(); if (rc != 0) return rc; @@ -2568,7 +2605,7 @@ ksocknal_module_init (void) return 0; } -MODULE_AUTHOR("Cluster File Systems, Inc. "); +MODULE_AUTHOR("Sun Microsystems, Inc. "); MODULE_DESCRIPTION("Kernel TCP Socket LND v2.0.0"); MODULE_LICENSE("GPL");