#include <linux/ktime.h>
#include <linux/moduleparam.h>
#include <linux/uaccess.h>
+#ifdef HAVE_SCHED_HEADERS
+#include <linux/sched/signal.h>
+#endif
#include <lnet/lib-lnet.h>
"Maximum number of times to retry transmitting a message");
-unsigned lnet_lnd_timeout = LNET_LND_DEFAULT_TIMEOUT;
+#define LNET_LND_TIMEOUT_DEFAULT ((LNET_TRANSACTION_TIMEOUT_HEALTH_DEFAULT - 1) / \
+ (LNET_RETRY_COUNT_HEALTH_DEFAULT + 1))
+unsigned int lnet_lnd_timeout = LNET_LND_TIMEOUT_DEFAULT;
+static void lnet_set_lnd_timeout(void)
+{
+ lnet_lnd_timeout = (lnet_transaction_timeout - 1) /
+ (lnet_retry_count + 1);
+}
+
unsigned int lnet_current_net_count;
/*
if (*sensitivity == 0 && value != 0) {
lnet_transaction_timeout = LNET_TRANSACTION_TIMEOUT_HEALTH_DEFAULT;
lnet_retry_count = LNET_RETRY_COUNT_HEALTH_DEFAULT;
+ lnet_set_lnd_timeout();
/*
* if we're turning off health then use the no health timeout
* default.
lnet_transaction_timeout =
LNET_TRANSACTION_TIMEOUT_NO_HEALTH_DEFAULT;
lnet_retry_count = 0;
+ lnet_set_lnd_timeout();
}
*sensitivity = value;
discovery_set(const char *val, cfs_kernel_param_arg_t *kp)
{
int rc;
- unsigned *discovery = (unsigned *)kp->arg;
+ unsigned *discovery_off = (unsigned *)kp->arg;
unsigned long value;
struct lnet_ping_buffer *pbuf;
*/
mutex_lock(&the_lnet.ln_api_mutex);
- if (value == *discovery) {
+ if (value == *discovery_off) {
mutex_unlock(&the_lnet.ln_api_mutex);
return 0;
}
- *discovery = value;
-
+ /*
+ * We still want to set the discovery value even when LNet is not
+ * running. This is the case when LNet is being loaded and we want
+ * the module parameters to take effect. Otherwise if we're
+ * changing the value dynamically, we want to set it after
+ * updating the peers
+ */
if (the_lnet.ln_state != LNET_STATE_RUNNING) {
+ *discovery_off = value;
mutex_unlock(&the_lnet.ln_api_mutex);
return 0;
}
pbuf->pb_info.pi_features |= LNET_PING_FEAT_DISCOVERY;
lnet_net_unlock(LNET_LOCK_EX);
- lnet_push_update_to_peers(1);
+ /* only send a push when we're turning off discovery */
+ if (*discovery_off <= 0 && value > 0)
+ lnet_push_update_to_peers(1);
+ *discovery_off = value;
mutex_unlock(&the_lnet.ln_api_mutex);
}
*transaction_to = value;
- if (lnet_retry_count == 0)
- lnet_lnd_timeout = value;
- else
- lnet_lnd_timeout = value / lnet_retry_count;
+ /* Update the lnet_lnd_timeout now that we've modified the
+ * transaction timeout
+ */
+ lnet_set_lnd_timeout();
mutex_unlock(&the_lnet.ln_api_mutex);
*retry_count = value;
- if (value == 0)
- lnet_lnd_timeout = lnet_transaction_timeout;
- else
- lnet_lnd_timeout = lnet_transaction_timeout / value;
+ /* Update the lnet_lnd_timeout now that we've modified the
+ * retry count
+ */
+ lnet_set_lnd_timeout();
mutex_unlock(&the_lnet.ln_api_mutex);
return 0;
}
-static char *
+static const char *
lnet_get_routes(void)
{
return routes;
}
-static char *
+static const char *
lnet_get_networks(void)
{
- char *nets;
- int rc;
+ const char *nets;
+ int rc;
if (*networks != 0 && *ip2nets != 0) {
LCONSOLE_ERROR_MSG(0x101, "Please specify EITHER 'networks' or "
{
spin_lock_init(&the_lnet.ln_eq_wait_lock);
spin_lock_init(&the_lnet.ln_msg_resend_lock);
- init_waitqueue_head(&the_lnet.ln_eq_waitq);
init_completion(&the_lnet.ln_mt_wait_complete);
mutex_init(&the_lnet.ln_lnd_mutex);
}
LASSERT(the_lnet.ln_remote_nets_hash == NULL);
LASSERT(the_lnet.ln_remote_nets_hbits > 0);
- LIBCFS_ALLOC(hash, LNET_REMOTE_NETS_HASH_SIZE * sizeof(*hash));
+ CFS_ALLOC_PTR_ARRAY(hash, LNET_REMOTE_NETS_HASH_SIZE);
if (hash == NULL) {
CERROR("Failed to create remote nets hash table\n");
return -ENOMEM;
for (i = 0; i < LNET_REMOTE_NETS_HASH_SIZE; i++)
LASSERT(list_empty(&the_lnet.ln_remote_nets_hash[i]));
- LIBCFS_FREE(the_lnet.ln_remote_nets_hash,
- LNET_REMOTE_NETS_HASH_SIZE *
- sizeof(the_lnet.ln_remote_nets_hash[0]));
+ CFS_FREE_PTR_ARRAY(the_lnet.ln_remote_nets_hash,
+ LNET_REMOTE_NETS_HASH_SIZE);
the_lnet.ln_remote_nets_hash = NULL;
}
struct list_head *e = rec->rec_active.next;
list_del_init(e);
- if (rec->rec_type == LNET_COOKIE_TYPE_EQ) {
- lnet_eq_free(list_entry(e, struct lnet_eq, eq_list));
-
- } else if (rec->rec_type == LNET_COOKIE_TYPE_MD) {
+ if (rec->rec_type == LNET_COOKIE_TYPE_MD) {
lnet_md_free(list_entry(e, struct lnet_libmd, md_list));
} else { /* NB: Active MEs should be attached on portals */
}
if (rec->rec_lh_hash != NULL) {
- LIBCFS_FREE(rec->rec_lh_hash,
- LNET_LH_HASH_SIZE * sizeof(rec->rec_lh_hash[0]));
+ CFS_FREE_PTR_ARRAY(rec->rec_lh_hash, LNET_LH_HASH_SIZE);
rec->rec_lh_hash = NULL;
}
INIT_LIST_HEAD(&the_lnet.ln_mt_localNIRecovq);
INIT_LIST_HEAD(&the_lnet.ln_mt_peerNIRecovq);
init_waitqueue_head(&the_lnet.ln_dc_waitq);
- LNetInvalidateEQHandle(&the_lnet.ln_mt_eqh);
+ the_lnet.ln_mt_handler = NULL;
init_completion(&the_lnet.ln_started);
rc = lnet_slab_setup();
static int
lnet_unprepare (void)
{
- int rc;
-
/* NB no LNET_LOCK since this is the last reference. All LND instances
* have shut down already, so it is safe to unlink and free all
* descriptors, even those that appear committed to a network op (eg MD
the_lnet.ln_mt_zombie_rstqs = NULL;
}
- if (!LNetEQHandleIsInvalid(the_lnet.ln_mt_eqh)) {
- rc = LNetEQFree(the_lnet.ln_mt_eqh);
- LNetInvalidateEQHandle(&the_lnet.ln_mt_eqh);
- LASSERT(rc == 0);
- }
+ lnet_assert_handler_unused(the_lnet.ln_mt_handler);
+ the_lnet.ln_mt_handler = NULL;
lnet_portals_destroy();
LIBCFS_ALLOC_GFP(pbuf, LNET_PING_BUFFER_SIZE(nnis), gfp);
if (pbuf) {
pbuf->pb_nnis = nnis;
+ pbuf->pb_needs_post = false;
atomic_set(&pbuf->pb_refcnt, 1);
}
void
lnet_ping_buffer_free(struct lnet_ping_buffer *pbuf)
{
- LASSERT(lnet_ping_buffer_numref(pbuf) == 0);
+ LASSERT(atomic_read(&pbuf->pb_refcnt) == 0);
LIBCFS_FREE(pbuf, LNET_PING_BUFFER_SIZE(pbuf->pb_nnis));
}
/* Loopback is guaranteed to be present */
if (pinfo->pi_nnis < 1 || pinfo->pi_nnis > lnet_interfaces_max)
return -ERANGE;
- if (LNET_NETTYP(LNET_NIDNET(LNET_PING_INFO_LONI(pinfo))) != LOLND)
+ if (LNET_PING_INFO_LONI(pinfo) != LNET_NID_LO_0)
return -EPROTO;
return 0;
}
static void
lnet_ping_target_event_handler(struct lnet_event *event)
{
- struct lnet_ping_buffer *pbuf = event->md.user_ptr;
+ struct lnet_ping_buffer *pbuf = event->md_user_ptr;
if (event->unlinked)
lnet_ping_buffer_decref(pbuf);
};
struct lnet_me *me;
struct lnet_md md = { NULL };
- int rc, rc2;
+ int rc;
- if (set_eq) {
- rc = LNetEQAlloc(0, lnet_ping_target_event_handler,
- &the_lnet.ln_ping_target_eq);
- if (rc != 0) {
- CERROR("Can't allocate ping buffer EQ: %d\n", rc);
- return rc;
- }
- }
+ if (set_eq)
+ the_lnet.ln_ping_target_handler =
+ lnet_ping_target_event_handler;
*ppbuf = lnet_ping_target_create(ni_count);
if (*ppbuf == NULL) {
md.max_size = 0;
md.options = LNET_MD_OP_GET | LNET_MD_TRUNCATE |
LNET_MD_MANAGE_REMOTE;
- md.eq_handle = the_lnet.ln_ping_target_eq;
+ md.handler = the_lnet.ln_ping_target_handler;
md.user_ptr = *ppbuf;
- rc = LNetMDAttach(me, md, LNET_RETAIN, ping_mdh);
+ rc = LNetMDAttach(me, &md, LNET_RETAIN, ping_mdh);
if (rc != 0) {
CERROR("Can't attach ping target MD: %d\n", rc);
goto fail_unlink_ping_me;
fail_unlink_ping_me:
LNetMEUnlink(me);
fail_decref_ping_buffer:
- LASSERT(lnet_ping_buffer_numref(*ppbuf) == 1);
+ LASSERT(atomic_read(&(*ppbuf)->pb_refcnt) == 1);
lnet_ping_buffer_decref(*ppbuf);
*ppbuf = NULL;
fail_free_eq:
- if (set_eq) {
- rc2 = LNetEQFree(the_lnet.ln_ping_target_eq);
- LASSERT(rc2 == 0);
- }
return rc;
}
lnet_ping_md_unlink(struct lnet_ping_buffer *pbuf,
struct lnet_handle_md *ping_mdh)
{
- sigset_t blocked = cfs_block_allsigs();
-
LNetMDUnlink(*ping_mdh);
LNetInvalidateMDHandle(ping_mdh);
/* NB the MD could be busy; this just starts the unlink */
- while (lnet_ping_buffer_numref(pbuf) > 1) {
- CDEBUG(D_NET, "Still waiting for ping data MD to unlink\n");
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(cfs_time_seconds(1));
- }
-
- cfs_restore_sigs(blocked);
+ wait_var_event_warning(&pbuf->pb_refcnt,
+ atomic_read(&pbuf->pb_refcnt) <= 1,
+ "Still waiting for ping data MD to unlink\n");
}
static void
static void
lnet_ping_target_fini(void)
{
- int rc;
-
lnet_ping_md_unlink(the_lnet.ln_ping_target,
&the_lnet.ln_ping_target_md);
- rc = LNetEQFree(the_lnet.ln_ping_target_eq);
- LASSERT(rc == 0);
-
+ lnet_assert_handler_unused(the_lnet.ln_ping_target_handler);
lnet_ping_target_destroy();
}
/* Resize the push target. */
int lnet_push_target_resize(void)
{
- struct lnet_process_id id = { LNET_NID_ANY, LNET_PID_ANY };
- struct lnet_md md = { NULL };
- struct lnet_me *me;
struct lnet_handle_md mdh;
struct lnet_handle_md old_mdh;
struct lnet_ping_buffer *pbuf;
struct lnet_ping_buffer *old_pbuf;
- int nnis = the_lnet.ln_push_target_nnis;
+ int nnis;
int rc;
+again:
+ nnis = the_lnet.ln_push_target_nnis;
if (nnis <= 0) {
- rc = -EINVAL;
- goto fail_return;
+ CDEBUG(D_NET, "Invalid nnis %d\n", nnis);
+ return -EINVAL;
}
-again:
+
+ /* NB: lnet_ping_buffer_alloc() sets pbuf refcount to 1. That ref is
+ * dropped when we need to resize again (see "old_pbuf" below) or when
+ * LNet is shutdown (see lnet_push_target_fini())
+ */
pbuf = lnet_ping_buffer_alloc(nnis, GFP_NOFS);
if (!pbuf) {
- rc = -ENOMEM;
- goto fail_return;
- }
-
- me = LNetMEAttach(LNET_RESERVED_PORTAL, id,
- LNET_PROTO_PING_MATCHBITS, 0,
- LNET_UNLINK, LNET_INS_AFTER);
-
- if (IS_ERR(me)) {
- rc = PTR_ERR(me);
- CERROR("Can't create push target ME: %d\n", rc);
- goto fail_decref_pbuf;
+ CDEBUG(D_NET, "Can't allocate pbuf for nnis %d\n", nnis);
+ return -ENOMEM;
}
- /* initialize md content */
- md.start = &pbuf->pb_info;
- md.length = LNET_PING_INFO_SIZE(nnis);
- md.threshold = LNET_MD_THRESH_INF;
- md.max_size = 0;
- md.options = LNET_MD_OP_PUT | LNET_MD_TRUNCATE |
- LNET_MD_MANAGE_REMOTE;
- md.user_ptr = pbuf;
- md.eq_handle = the_lnet.ln_push_target_eq;
-
- rc = LNetMDAttach(me, md, LNET_RETAIN, &mdh);
+ rc = lnet_push_target_post(pbuf, &mdh);
if (rc) {
- CERROR("Can't attach push MD: %d\n", rc);
- goto fail_unlink_me;
+ CDEBUG(D_NET, "Failed to post push target: %d\n", rc);
+ lnet_ping_buffer_decref(pbuf);
+ return rc;
}
- lnet_ping_buffer_addref(pbuf);
lnet_net_lock(LNET_LOCK_EX);
old_pbuf = the_lnet.ln_push_target;
if (old_pbuf) {
LNetMDUnlink(old_mdh);
+ /* Drop ref set by lnet_ping_buffer_alloc() */
lnet_ping_buffer_decref(old_pbuf);
}
+ /* Received another push or reply that requires a larger buffer */
if (nnis < the_lnet.ln_push_target_nnis)
goto again;
CDEBUG(D_NET, "nnis %d success\n", nnis);
-
return 0;
+}
-fail_unlink_me:
- LNetMEUnlink(me);
-fail_decref_pbuf:
- lnet_ping_buffer_decref(pbuf);
-fail_return:
- CDEBUG(D_NET, "nnis %d error %d\n", nnis, rc);
- return rc;
+int lnet_push_target_post(struct lnet_ping_buffer *pbuf,
+ struct lnet_handle_md *mdhp)
+{
+ struct lnet_process_id id = { LNET_NID_ANY, LNET_PID_ANY };
+ struct lnet_md md = { NULL };
+ struct lnet_me *me;
+ int rc;
+
+ me = LNetMEAttach(LNET_RESERVED_PORTAL, id,
+ LNET_PROTO_PING_MATCHBITS, 0,
+ LNET_UNLINK, LNET_INS_AFTER);
+ if (IS_ERR(me)) {
+ rc = PTR_ERR(me);
+ CERROR("Can't create push target ME: %d\n", rc);
+ return rc;
+ }
+
+ pbuf->pb_needs_post = false;
+
+ /* This reference is dropped by lnet_push_target_event_handler() */
+ lnet_ping_buffer_addref(pbuf);
+
+ /* initialize md content */
+ md.start = &pbuf->pb_info;
+ md.length = LNET_PING_INFO_SIZE(pbuf->pb_nnis);
+ md.threshold = 1;
+ md.max_size = 0;
+ md.options = LNET_MD_OP_PUT | LNET_MD_TRUNCATE;
+ md.user_ptr = pbuf;
+ md.handler = the_lnet.ln_push_target_handler;
+
+ rc = LNetMDAttach(me, &md, LNET_UNLINK, mdhp);
+ if (rc) {
+ CERROR("Can't attach push MD: %d\n", rc);
+ LNetMEUnlink(me);
+ lnet_ping_buffer_decref(pbuf);
+ pbuf->pb_needs_post = true;
+ return rc;
+ }
+
+ CDEBUG(D_NET, "posted push target %p\n", pbuf);
+
+ return 0;
}
static void lnet_push_target_event_handler(struct lnet_event *ev)
{
- struct lnet_ping_buffer *pbuf = ev->md.user_ptr;
+ struct lnet_ping_buffer *pbuf = ev->md_user_ptr;
+
+ CDEBUG(D_NET, "type %d status %d unlinked %d\n", ev->type, ev->status,
+ ev->unlinked);
if (pbuf->pb_info.pi_magic == __swab32(LNET_PROTO_PING_MAGIC))
lnet_swap_pinginfo(pbuf);
+ if (ev->type == LNET_EVENT_UNLINK) {
+ /* Drop ref added by lnet_push_target_post() */
+ lnet_ping_buffer_decref(pbuf);
+ return;
+ }
+
lnet_peer_push_event(ev);
if (ev->unlinked)
+ /* Drop ref added by lnet_push_target_post */
lnet_ping_buffer_decref(pbuf);
}
if (the_lnet.ln_push_target)
return -EALREADY;
- rc = LNetEQAlloc(0, lnet_push_target_event_handler,
- &the_lnet.ln_push_target_eq);
- if (rc) {
- CERROR("Can't allocated push target EQ: %d\n", rc);
- return rc;
- }
+ the_lnet.ln_push_target_handler =
+ lnet_push_target_event_handler;
+
+ rc = LNetSetLazyPortal(LNET_RESERVED_PORTAL);
+ LASSERT(rc == 0);
/* Start at the required minimum, we'll enlarge if required. */
the_lnet.ln_push_target_nnis = LNET_INTERFACES_MIN;
rc = lnet_push_target_resize();
if (rc) {
- LNetEQFree(the_lnet.ln_push_target_eq);
- LNetInvalidateEQHandle(&the_lnet.ln_push_target_eq);
+ LNetClearLazyPortal(LNET_RESERVED_PORTAL);
+ the_lnet.ln_push_target_handler = NULL;
}
return rc;
LNetInvalidateMDHandle(&the_lnet.ln_push_target_md);
/* Wait for the unlink to complete. */
- while (lnet_ping_buffer_numref(the_lnet.ln_push_target) > 1) {
- CDEBUG(D_NET, "Still waiting for ping data MD to unlink\n");
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(cfs_time_seconds(1));
- }
+ wait_var_event_warning(&the_lnet.ln_push_target->pb_refcnt,
+ atomic_read(&the_lnet.ln_push_target->pb_refcnt) <= 1,
+ "Still waiting for ping data MD to unlink\n");
+ /* Drop ref set by lnet_ping_buffer_alloc() */
lnet_ping_buffer_decref(the_lnet.ln_push_target);
the_lnet.ln_push_target = NULL;
the_lnet.ln_push_target_nnis = 0;
- LNetEQFree(the_lnet.ln_push_target_eq);
- LNetInvalidateEQHandle(&the_lnet.ln_push_target_eq);
+ LNetClearLazyPortal(LNET_RESERVED_PORTAL);
+ lnet_assert_handler_unused(the_lnet.ln_push_target_handler);
+ the_lnet.ln_push_target_handler = NULL;
}
static int
"Waiting for zombie LNI %s\n",
libcfs_nid2str(ni->ni_nid));
}
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(cfs_time_seconds(1));
+ schedule_timeout_uninterruptible(cfs_time_seconds(1));
lnet_net_lock(LNET_LOCK_EX);
continue;
}
lnet_net_lock(LNET_LOCK_EX);
the_lnet.ln_state = LNET_STATE_STOPPING;
- while (!list_empty(&the_lnet.ln_nets)) {
- /*
- * move the nets to the zombie list to avoid them being
- * picked up for new work. LONET is also included in the
- * Nets that will be moved to the zombie list
- */
- net = list_entry(the_lnet.ln_nets.next,
- struct lnet_net, net_list);
- list_move(&net->net_list, &the_lnet.ln_net_zombie);
- }
+ /*
+ * move the nets to the zombie list to avoid them being
+ * picked up for new work. LONET is also included in the
+ * Nets that will be moved to the zombie list
+ */
+ list_splice_init(&the_lnet.ln_nets, &the_lnet.ln_net_zombie);
/* Drop the cached loopback Net. */
if (the_lnet.ln_loni != NULL) {
lnet_assert_wire_constants();
/* refer to global cfs_cpt_table for now */
- the_lnet.ln_cpt_table = cfs_cpt_table;
- the_lnet.ln_cpt_number = cfs_cpt_number(cfs_cpt_table);
+ the_lnet.ln_cpt_table = cfs_cpt_tab;
+ the_lnet.ln_cpt_number = cfs_cpt_number(cfs_cpt_tab);
LASSERT(the_lnet.ln_cpt_number > 0);
if (the_lnet.ln_cpt_number > LNET_CPT_MAX) {
lnet_ping_target_update(pbuf, ping_mdh);
- rc = LNetEQAlloc(0, lnet_mt_event_handler, &the_lnet.ln_mt_eqh);
- if (rc != 0) {
- CERROR("Can't allocate monitor thread EQ: %d\n", rc);
- goto err_stop_ping;
- }
+ the_lnet.ln_mt_handler = lnet_mt_event_handler;
rc = lnet_push_target_init();
if (rc != 0)
}
cfg_ni->lic_nid = ni->ni_nid;
- if (LNET_NETTYP(LNET_NIDNET(ni->ni_nid)) == LOLND)
+ if (ni->ni_nid == LNET_NID_LO_0)
cfg_ni->lic_status = LNET_NI_STATUS_UP;
else
cfg_ni->lic_status = ni->ni_status->ns_status;
config->cfg_config_u.cfg_net.net_peer_rtr_credits =
ni->ni_net->net_tunables.lct_peer_rtr_credits;
- if (LNET_NETTYP(LNET_NIDNET(ni->ni_nid)) == LOLND)
+ if (ni->ni_nid == LNET_NID_LO_0)
net_config->ni_status = LNET_NI_STATUS_UP;
else
net_config->ni_status = ni->ni_status->ns_status;
int rc;
struct lnet_remotenet *rnet;
int net_ni_count;
- int num_acceptor_nets;
lnet_net_lock(LNET_LOCK_EX);
rnet = lnet_find_rnet_locked(net->net_id);
else
memset(&net->net_tunables, -1, sizeof(net->net_tunables));
- /*
- * before starting this network get a count of the current TCP
- * networks which require the acceptor thread running. If that
- * count is == 0 before we start up this network, then we'd want to
- * start up the acceptor thread after starting up this network
- */
- num_acceptor_nets = lnet_count_acceptor_nets();
-
net_id = net->net_id;
rc = lnet_startup_lndnet(net,
* Start the acceptor thread if this is the first network
* being added that requires the thread.
*/
- if (net->net_lnd->lnd_accept && num_acceptor_nets == 0) {
+ if (net->net_lnd->lnd_accept) {
rc = lnet_acceptor_start();
if (rc < 0) {
/* shutdown the net that we just started */
struct lnet_ioctl_config_lnd_tunables *tun)
{
struct lnet_net *net;
- char *nets;
+ const char *nets;
int rc;
LIST_HEAD(net_head);
lnet_shutdown_lndnet(net);
- if (lnet_count_acceptor_nets() == 0)
- lnet_acceptor_stop();
+ lnet_acceptor_stop();
lnet_ping_target_update(pbuf, ping_mdh);
lnet_shutdown_lndni(ni);
- if (lnet_count_acceptor_nets() == 0)
- lnet_acceptor_stop();
+ lnet_acceptor_stop();
lnet_ping_target_update(pbuf, ping_mdh);
LIST_HEAD(net_head);
int rc;
struct lnet_ioctl_config_lnd_tunables tun;
- char *nets = conf->cfg_config_u.cfg_net.net_intf;
+ const char *nets = conf->cfg_config_u.cfg_net.net_intf;
/* Create a net/ni structures for the network string */
rc = lnet_parse_networks(&net_head, nets, use_tcp_bonding);
lnet_shutdown_lndnet(net);
- if (lnet_count_acceptor_nets() == 0)
- lnet_acceptor_stop();
+ lnet_acceptor_stop();
lnet_ping_target_update(pbuf, ping_mdh);
}
EXPORT_SYMBOL(LNetGetId);
+struct ping_data {
+ int rc;
+ int replied;
+ struct lnet_handle_md mdh;
+ struct completion completion;
+};
+
+static void
+lnet_ping_event_handler(struct lnet_event *event)
+{
+ struct ping_data *pd = event->md_user_ptr;
+
+ CDEBUG(D_NET, "ping event (%d %d)%s\n",
+ event->type, event->status,
+ event->unlinked ? " unlinked" : "");
+
+ if (event->status) {
+ if (!pd->rc)
+ pd->rc = event->status;
+ } else if (event->type == LNET_EVENT_REPLY) {
+ pd->replied = 1;
+ pd->rc = event->mlength;
+ }
+ if (event->unlinked)
+ complete(&pd->completion);
+}
+
static int lnet_ping(struct lnet_process_id id, signed long timeout,
struct lnet_process_id __user *ids, int n_ids)
{
- struct lnet_handle_eq eqh;
- struct lnet_handle_md mdh;
- struct lnet_event event;
struct lnet_md md = { NULL };
- int which;
- int unlinked = 0;
- int replied = 0;
- const signed long a_long_time = cfs_time_seconds(60);
+ struct ping_data pd = { 0 };
struct lnet_ping_buffer *pbuf;
struct lnet_process_id tmpid;
int i;
int nob;
int rc;
int rc2;
- sigset_t blocked;
/* n_ids limit is arbitrary */
if (n_ids <= 0 || id.nid == LNET_NID_ANY)
if (!pbuf)
return -ENOMEM;
- /* NB 2 events max (including any unlink event) */
- rc = LNetEQAlloc(2, LNET_EQ_HANDLER_NONE, &eqh);
- if (rc != 0) {
- CERROR("Can't allocate EQ: %d\n", rc);
- goto fail_ping_buffer_decref;
- }
-
/* initialize md content */
md.start = &pbuf->pb_info;
md.length = LNET_PING_INFO_SIZE(n_ids);
md.threshold = 2; /* GET/REPLY */
md.max_size = 0;
md.options = LNET_MD_TRUNCATE;
- md.user_ptr = NULL;
- md.eq_handle = eqh;
+ md.user_ptr = &pd;
+ md.handler = lnet_ping_event_handler;
+
+ init_completion(&pd.completion);
- rc = LNetMDBind(md, LNET_UNLINK, &mdh);
+ rc = LNetMDBind(&md, LNET_UNLINK, &pd.mdh);
if (rc != 0) {
CERROR("Can't bind MD: %d\n", rc);
- goto fail_free_eq;
+ goto fail_ping_buffer_decref;
}
- rc = LNetGet(LNET_NID_ANY, mdh, id,
+ rc = LNetGet(LNET_NID_ANY, pd.mdh, id,
LNET_RESERVED_PORTAL,
LNET_PROTO_PING_MATCHBITS, 0, false);
if (rc != 0) {
/* Don't CERROR; this could be deliberate! */
- rc2 = LNetMDUnlink(mdh);
+ rc2 = LNetMDUnlink(pd.mdh);
LASSERT(rc2 == 0);
/* NB must wait for the UNLINK event below... */
- unlinked = 1;
- timeout = a_long_time;
- }
-
- do {
- /* MUST block for unlink to complete */
- if (unlinked)
- blocked = cfs_block_allsigs();
-
- rc2 = LNetEQPoll(&eqh, 1, timeout, &event, &which);
-
- if (unlinked)
- cfs_restore_sigs(blocked);
-
- CDEBUG(D_NET, "poll %d(%d %d)%s\n", rc2,
- (rc2 <= 0) ? -1 : event.type,
- (rc2 <= 0) ? -1 : event.status,
- (rc2 > 0 && event.unlinked) ? " unlinked" : "");
-
- LASSERT(rc2 != -EOVERFLOW); /* can't miss anything */
-
- if (rc2 <= 0 || event.status != 0) {
- /* timeout or error */
- if (!replied && rc == 0)
- rc = (rc2 < 0) ? rc2 :
- (rc2 == 0) ? -ETIMEDOUT :
- event.status;
-
- if (!unlinked) {
- /* Ensure completion in finite time... */
- LNetMDUnlink(mdh);
- /* No assertion (racing with network) */
- unlinked = 1;
- timeout = a_long_time;
- } else if (rc2 == 0) {
- /* timed out waiting for unlink */
- CWARN("ping %s: late network completion\n",
- libcfs_id2str(id));
- }
- } else if (event.type == LNET_EVENT_REPLY) {
- replied = 1;
- rc = event.mlength;
- }
- } while (rc2 <= 0 || !event.unlinked);
+ }
- if (!replied) {
- if (rc >= 0)
- CWARN("%s: Unexpected rc >= 0 but no reply!\n",
- libcfs_id2str(id));
+ if (wait_for_completion_timeout(&pd.completion, timeout) == 0) {
+ /* Ensure completion in finite time... */
+ LNetMDUnlink(pd.mdh);
+ wait_for_completion(&pd.completion);
+ }
+ if (!pd.replied) {
rc = -EIO;
- goto fail_free_eq;
+ goto fail_ping_buffer_decref;
}
- nob = rc;
+ nob = pd.rc;
LASSERT(nob >= 0 && nob <= LNET_PING_INFO_SIZE(n_ids));
rc = -EPROTO; /* if I can't parse... */
if (nob < 8) {
CERROR("%s: ping info too short %d\n",
libcfs_id2str(id), nob);
- goto fail_free_eq;
+ goto fail_ping_buffer_decref;
}
if (pbuf->pb_info.pi_magic == __swab32(LNET_PROTO_PING_MAGIC)) {
} else if (pbuf->pb_info.pi_magic != LNET_PROTO_PING_MAGIC) {
CERROR("%s: Unexpected magic %08x\n",
libcfs_id2str(id), pbuf->pb_info.pi_magic);
- goto fail_free_eq;
+ goto fail_ping_buffer_decref;
}
if ((pbuf->pb_info.pi_features & LNET_PING_FEAT_NI_STATUS) == 0) {
CERROR("%s: ping w/o NI status: 0x%x\n",
libcfs_id2str(id), pbuf->pb_info.pi_features);
- goto fail_free_eq;
+ goto fail_ping_buffer_decref;
}
if (nob < LNET_PING_INFO_SIZE(0)) {
CERROR("%s: Short reply %d(%d min)\n",
libcfs_id2str(id),
nob, (int)LNET_PING_INFO_SIZE(0));
- goto fail_free_eq;
+ goto fail_ping_buffer_decref;
}
if (pbuf->pb_info.pi_nnis < n_ids)
CERROR("%s: Short reply %d(%d expected)\n",
libcfs_id2str(id),
nob, (int)LNET_PING_INFO_SIZE(n_ids));
- goto fail_free_eq;
+ goto fail_ping_buffer_decref;
}
rc = -EFAULT; /* if I segv in copy_to_user()... */
tmpid.pid = pbuf->pb_info.pi_pid;
tmpid.nid = pbuf->pb_info.pi_ni[i].ns_nid;
if (copy_to_user(&ids[i], &tmpid, sizeof(tmpid)))
- goto fail_free_eq;
+ goto fail_ping_buffer_decref;
}
rc = pbuf->pb_info.pi_nnis;
- fail_free_eq:
- rc2 = LNetEQFree(eqh);
- if (rc2 != 0)
- CERROR("rc2 %d\n", rc2);
- LASSERT(rc2 == 0);
-
fail_ping_buffer_decref:
lnet_ping_buffer_decref(pbuf);
return rc;
int cpt;
int i;
int rc;
- int max_intf = lnet_interfaces_max;
- size_t buf_size;
if (n_ids <= 0 ||
id.nid == LNET_NID_ANY)
id.pid = LNET_PID_LUSTRE;
/*
- * if the user buffer has more space than the max_intf
- * then only fill it up to max_intf
+ * If the user buffer has more space than the lnet_interfaces_max,
+ * then only fill it up to lnet_interfaces_max.
*/
- if (n_ids > max_intf)
- n_ids = max_intf;
-
- buf_size = n_ids * sizeof(*buf);
+ if (n_ids > lnet_interfaces_max)
+ n_ids = lnet_interfaces_max;
- LIBCFS_ALLOC(buf, buf_size);
+ CFS_ALLOC_PTR_ARRAY(buf, n_ids);
if (!buf)
return -ENOMEM;
if (rc)
goto out_decref;
- /* Peer may have changed. */
- lp = lpni->lpni_peer_net->lpn_peer;
- if (lp->lp_nnis < n_ids)
- n_ids = lp->lp_nnis;
-
i = 0;
p = NULL;
while ((p = lnet_get_next_peer_ni_locked(lp, NULL, p)) != NULL) {
if (++i >= n_ids)
break;
}
+ rc = i;
- lnet_net_unlock(cpt);
-
- rc = -EFAULT;
- if (copy_to_user(ids, buf, n_ids * sizeof(*buf)))
- goto out_relock;
- rc = n_ids;
-out_relock:
- lnet_net_lock(cpt);
out_decref:
lnet_peer_ni_decref_locked(lpni);
out:
lnet_net_unlock(cpt);
- LIBCFS_FREE(buf, buf_size);
+ if (rc >= 0)
+ if (copy_to_user(ids, buf, rc * sizeof(*buf)))
+ rc = -EFAULT;
+ CFS_FREE_PTR_ARRAY(buf, n_ids);
return rc;
}