ev->status = 0;
ev->unlinked = 1;
ev->type = LNET_EVENT_UNLINK;
- lnet_md_deconstruct(md, &ev->md);
+ lnet_md_deconstruct(md, ev);
lnet_md2handle(&ev->md_handle, md);
EXIT;
}
/* build umd in event */
lnet_md2handle(&msg->msg_ev.md_handle, md);
- lnet_md_deconstruct(md, &msg->msg_ev.md);
+ lnet_md_deconstruct(md, &msg->msg_ev);
}
static int
msg->msg_hdr.msg.ack.match_bits = msg->msg_ev.match_bits;
msg->msg_hdr.msg.ack.mlength = cpu_to_le32(msg->msg_ev.mlength);
- /* NB: we probably want to use NID of msg::msg_from as 3rd
- * parameter (router NID) if it's routed message */
rc = lnet_send(msg->msg_ev.target.nid, msg, msg->msg_from);
lnet_net_lock(cpt);
*/
if (list_empty(&local_ni->ni_recovery) &&
atomic_read(&local_ni->ni_healthv) < LNET_MAX_HEALTH_VALUE) {
- CERROR("ni %s added to recovery queue. Health = %d\n",
+ CDEBUG(D_NET, "ni %s added to recovery queue. Health = %d\n",
libcfs_nid2str(local_ni->ni_nid),
atomic_read(&local_ni->ni_healthv));
list_add_tail(&local_ni->ni_recovery,
lnet_net_unlock(0);
}
+/* must hold net_lock/0 */
void
lnet_handle_remote_failure_locked(struct lnet_peer_ni *lpni)
{
__u32 sensitivity = lnet_health_sensitivity;
__u32 lp_sensitivity;
- /* lpni could be NULL if we're in the LOLND case */
- if (!lpni)
- return;
-
/*
* If there is a health sensitivity in the peer then use that
* instead of the globally set one.
sensitivity = lp_sensitivity;
lnet_dec_healthv_locked(&lpni->lpni_healthv, sensitivity);
+
+ /* update the peer_net's health value */
+ lnet_update_peer_net_healthv(lpni);
+
/*
* add the peer NI to the recovery queue if it's not already there
* and it's health value is actually below the maximum. It's
* value will not be reduced. In this case, there is no reason to
* invoke recovery
*/
- lnet_peer_ni_add_to_recoveryq_locked(lpni);
+ lnet_peer_ni_add_to_recoveryq_locked(lpni,
+ &the_lnet.ln_mt_peerNIRecovq,
+ ktime_get_seconds());
}
static void
}
static void
-lnet_incr_hstats(struct lnet_msg *msg, enum lnet_msg_hstatus hstatus)
+lnet_incr_hstats(struct lnet_ni *ni, struct lnet_peer_ni *lpni,
+ enum lnet_msg_hstatus hstatus)
{
- struct lnet_ni *ni = msg->msg_txni;
- struct lnet_peer_ni *lpni = msg->msg_txpeer;
struct lnet_counters_health *health;
health = &the_lnet.ln_counters[0]->lct_health;
list_add_tail(&msg->msg_list, the_lnet.ln_mt_resendqs[msg->msg_tx_cpt]);
- wake_up(&the_lnet.ln_mt_waitq);
+ complete(&the_lnet.ln_mt_wait_complete);
}
int
struct lnet_peer_ni *lpni;
struct lnet_ni *ni;
bool lo = false;
+ bool attempt_local_resend;
+ bool attempt_remote_resend;
+ bool handle_local_health;
+ bool handle_remote_health;
/* if we're shutting down no point in handling health. */
if (the_lnet.ln_mt_state != LNET_MT_STATE_RUNNING)
* if we're sending to the LOLND then the msg_txpeer will not be
* set. So no need to sanity check it.
*/
- if (msg->msg_tx_committed &&
- LNET_NETTYP(LNET_NIDNET(msg->msg_txni->ni_nid)) != LOLND)
+ if (msg->msg_tx_committed && msg->msg_txni->ni_nid != LNET_NID_LO_0)
LASSERT(msg->msg_txpeer);
else if (msg->msg_tx_committed &&
- LNET_NETTYP(LNET_NIDNET(msg->msg_txni->ni_nid)) == LOLND)
+ msg->msg_txni->ni_nid == LNET_NID_LO_0)
lo = true;
if (hstatus != LNET_MSG_STATUS_OK &&
return -1;
/*
- * stats are only incremented for errors so avoid wasting time
- * incrementing statistics if there is no error.
- */
- if (hstatus != LNET_MSG_STATUS_OK) {
- lnet_net_lock(0);
- lnet_incr_hstats(msg, hstatus);
- lnet_net_unlock(0);
- }
-
- /*
* always prefer txni/txpeer if they message is committed for both
* directions.
*/
if (msg->msg_tx_committed) {
ni = msg->msg_txni;
lpni = msg->msg_txpeer;
+ attempt_local_resend = attempt_remote_resend = true;
} else {
ni = msg->msg_rxni;
lpni = msg->msg_rxpeer;
+ attempt_local_resend = attempt_remote_resend = false;
+ }
+
+ /* Don't further decrement the health value if a recovery message
+ * failed.
+ */
+ if (msg->msg_recovery)
+ handle_local_health = handle_remote_health = false;
+ else
+ handle_local_health = handle_remote_health = true;
+
+ /* For local failures, health/recovery/resends are not needed if I only
+ * have a single (non-lolnd) interface. NB: pb_nnis includes the lolnd
+ * interface, so a single-rail node would have pb_nnis == 2.
+ */
+ if (the_lnet.ln_ping_target->pb_nnis <= 2) {
+ handle_local_health = false;
+ attempt_local_resend = false;
+ }
+
+ /* For remote failures, health/recovery/resends are not needed if the
+ * peer only has a single interface. Special case for routers where we
+ * rely on health feature to manage route aliveness. NB: unlike pb_nnis
+ * above, lp_nnis does _not_ include the lolnd, so a single-rail node
+ * would have lp_nnis == 1.
+ */
+ if (lpni && lpni->lpni_peer_net->lpn_peer->lp_nnis <= 1) {
+ attempt_remote_resend = false;
+ if (!lnet_isrouter(lpni))
+ handle_remote_health = false;
}
if (!lo)
lnet_msgtyp2str(msg->msg_type),
lnet_health_error2str(hstatus));
+ /*
+ * stats are only incremented for errors so avoid wasting time
+ * incrementing statistics if there is no error.
+ */
+ if (hstatus != LNET_MSG_STATUS_OK) {
+ lnet_net_lock(0);
+ lnet_incr_hstats(ni, lpni, hstatus);
+ lnet_net_unlock(0);
+ }
+
switch (hstatus) {
case LNET_MSG_STATUS_OK:
/*
* increment the local ni health weather we successfully
* received or sent a message on it.
*/
- lnet_inc_healthv(&ni->ni_healthv);
+ lnet_inc_healthv(&ni->ni_healthv, lnet_health_sensitivity);
/*
* It's possible msg_txpeer is NULL in the LOLND
* case. Only increment the peer's health if we're
* I'm a router, then set that lpni's health to
* maximum so we can commence communication
*/
- if (lnet_isrouter(lpni) || the_lnet.ln_routing)
- lnet_set_healthv(&lpni->lpni_healthv,
- LNET_MAX_HEALTH_VALUE);
- else
- lnet_inc_healthv(&lpni->lpni_healthv);
+ lnet_net_lock(0);
+ if (lnet_isrouter(lpni) || the_lnet.ln_routing) {
+ lnet_set_lpni_healthv_locked(lpni,
+ LNET_MAX_HEALTH_VALUE);
+ } else {
+ __u32 sensitivity = lpni->lpni_peer_net->
+ lpn_peer->lp_health_sensitivity;
+
+ lnet_inc_lpni_healthv_locked(lpni,
+ (sensitivity) ? sensitivity :
+ lnet_health_sensitivity);
+ /* This peer NI may have previously aged out
+ * of recovery. Now that we've received a
+ * message from it, we can continue recovery
+ * if its health value is still below the
+ * maximum.
+ */
+ lnet_peer_ni_add_to_recoveryq_locked(lpni,
+ &the_lnet.ln_mt_peerNIRecovq,
+ ktime_get_seconds());
+ }
+ lnet_net_unlock(0);
}
/* we can finalize this message */
case LNET_MSG_STATUS_LOCAL_ABORTED:
case LNET_MSG_STATUS_LOCAL_NO_ROUTE:
case LNET_MSG_STATUS_LOCAL_TIMEOUT:
- lnet_handle_local_failure(ni);
- if (msg->msg_tx_committed)
- /* add to the re-send queue */
+ if (handle_local_health)
+ lnet_handle_local_failure(ni);
+ if (attempt_local_resend)
return lnet_attempt_msg_resend(msg);
break;
-
- /*
- * These errors will not trigger a resend so simply
- * finalize the message
- */
case LNET_MSG_STATUS_LOCAL_ERROR:
- lnet_handle_local_failure(ni);
+ if (handle_local_health)
+ lnet_handle_local_failure(ni);
return -1;
-
- /*
- * TODO: since the remote dropped the message we can
- * attempt a resend safely.
- */
case LNET_MSG_STATUS_REMOTE_DROPPED:
- lnet_handle_remote_failure(lpni);
- if (msg->msg_tx_committed)
+ if (handle_remote_health)
+ lnet_handle_remote_failure(lpni);
+ if (attempt_remote_resend)
return lnet_attempt_msg_resend(msg);
break;
-
case LNET_MSG_STATUS_REMOTE_ERROR:
case LNET_MSG_STATUS_REMOTE_TIMEOUT:
+ if (handle_remote_health)
+ lnet_handle_remote_failure(lpni);
+ return -1;
case LNET_MSG_STATUS_NETWORK_TIMEOUT:
- lnet_handle_remote_failure(lpni);
+ if (handle_remote_health)
+ lnet_handle_remote_failure(lpni);
+ if (handle_local_health)
+ lnet_handle_local_failure(ni);
return -1;
default:
LBUG();
}
static void
-lnet_msg_detach_md(struct lnet_msg *msg, int cpt, int status)
+lnet_msg_detach_md(struct lnet_msg *msg, int status)
{
struct lnet_libmd *md = msg->msg_md;
+ lnet_handler_t handler = NULL;
+ int cpt = lnet_cpt_of_cookie(md->md_lh.lh_cookie);
int unlink;
+ lnet_res_lock(cpt);
+ while (md->md_flags & LNET_MD_FLAG_HANDLING)
+ /* An event handler is running - wait for it to
+ * complete to avoid races.
+ */
+ lnet_md_wait_handling(md, cpt);
+
/* Now it's safe to drop my caller's ref */
md->md_refcount--;
LASSERT(md->md_refcount >= 0);
unlink = lnet_md_unlinkable(md);
- if (md->md_eq != NULL) {
+ if (md->md_handler) {
if ((md->md_flags & LNET_MD_FLAG_ABORTED) && !status) {
msg->msg_ev.status = -ETIMEDOUT;
CDEBUG(D_NET, "md 0x%p already unlinked\n", md);
msg->msg_ev.status = status;
}
msg->msg_ev.unlinked = unlink;
- lnet_eq_enqueue_event(md->md_eq, &msg->msg_ev);
+ handler = md->md_handler;
+ if (!unlink)
+ md->md_flags |= LNET_MD_FLAG_HANDLING;
}
if (unlink || (md->md_refcount == 0 &&
md->md_threshold == LNET_MD_THRESH_INF))
lnet_detach_rsp_tracker(md, cpt);
+ msg->msg_md = NULL;
if (unlink)
lnet_md_unlink(md);
- msg->msg_md = NULL;
+ lnet_res_unlock(cpt);
+
+ if (handler) {
+ handler(&msg->msg_ev);
+ if (!unlink) {
+ lnet_res_lock(cpt);
+ md->md_flags &= ~LNET_MD_FLAG_HANDLING;
+ wake_up_var(md);
+ lnet_res_unlock(cpt);
+ }
+ }
}
static bool
* We're not going to resend this message so detach its MD and invoke
* the appropriate callbacks
*/
- if (msg->msg_md != NULL) {
- cpt = lnet_cpt_of_cookie(msg->msg_md->md_lh.lh_cookie);
- lnet_res_lock(cpt);
- lnet_msg_detach_md(msg, cpt, status);
- lnet_res_unlock(cpt);
- }
+ if (msg->msg_md != NULL)
+ lnet_msg_detach_md(msg, status);
again:
if (!msg->msg_tx_committed && !msg->msg_rx_committed) {
CERROR("%d active msg on exit\n", count);
if (container->msc_finalizers != NULL) {
- LIBCFS_FREE(container->msc_finalizers,
- container->msc_nfinalizers *
- sizeof(*container->msc_finalizers));
+ CFS_FREE_PTR_ARRAY(container->msc_finalizers,
+ container->msc_nfinalizers);
container->msc_finalizers = NULL;
}
if (container->msc_resenders != NULL) {
- LIBCFS_FREE(container->msc_resenders,
- container->msc_nfinalizers *
- sizeof(*container->msc_resenders));
+ CFS_FREE_PTR_ARRAY(container->msc_resenders,
+ container->msc_nfinalizers);
container->msc_resenders = NULL;
}
container->msc_init = 0;