#include <linux/nsproxy.h>
#include <net/net_namespace.h>
-extern unsigned int lnet_current_net_count;
-
static int local_nid_dist_zero = 1;
module_param(local_nid_dist_zero, int, 0444);
MODULE_PARM_DESC(local_nid_dist_zero, "Reserved");
if (tp->tp_threshold == 0 || /* needs culling anyway */
nid == LNET_NID_ANY || /* removing all entries */
tp->tp_nid == nid) { /* matched this one */
- list_del(&tp->tp_list);
- list_add(&tp->tp_list, &cull);
+ list_move(&tp->tp_list, &cull);
}
}
/* only cull zombies on outgoing tests,
* since we may be at interrupt priority on
* incoming messages. */
- list_del(&tp->tp_list);
- list_add(&tp->tp_list, &cull);
+ list_move(&tp->tp_list, &cull);
}
continue;
}
if (outgoing &&
tp->tp_threshold == 0) {
/* see above */
- list_del(&tp->tp_list);
- list_add(&tp->tp_list, &cull);
+ list_move(&tp->tp_list, &cull);
}
}
break;
}
static int
-lnet_compare_peers(struct lnet_peer_ni *p1, struct lnet_peer_ni *p2)
+lnet_compare_gw_lpnis(struct lnet_peer_ni *p1, struct lnet_peer_ni *p2)
{
if (p1->lpni_txqnob < p2->lpni_txqnob)
return 1;
* Prerequisite: the best_ni should already be set in the sd
*/
static inline struct lnet_peer_ni *
-lnet_find_best_lpni_on_net(struct lnet_send_data *sd, struct lnet_peer *peer,
- __u32 net_id)
+lnet_find_best_lpni_on_net(struct lnet_ni *lni, lnet_nid_t dst_nid,
+ struct lnet_peer *peer, __u32 net_id)
{
struct lnet_peer_net *peer_net;
return NULL;
}
- return lnet_select_peer_ni(sd->sd_best_ni, sd->sd_dst_nid,
- peer, peer_net);
+ return lnet_select_peer_ni(lni, dst_nid, peer, peer_net);
}
+/* Compare route priorities and hop counts */
static int
-lnet_compare_routes(struct lnet_route *r1, struct lnet_route *r2,
- struct lnet_peer_ni **best_lpni)
+lnet_compare_routes(struct lnet_route *r1, struct lnet_route *r2)
{
int r1_hops = (r1->lr_hops == LNET_UNDEFINED_HOPS) ? 1 : r1->lr_hops;
int r2_hops = (r2->lr_hops == LNET_UNDEFINED_HOPS) ? 1 : r2->lr_hops;
- struct lnet_peer *lp1 = r1->lr_gateway;
- struct lnet_peer *lp2 = r2->lr_gateway;
- struct lnet_peer_ni *lpni1;
- struct lnet_peer_ni *lpni2;
- struct lnet_send_data sd;
- int rc;
-
- sd.sd_best_ni = NULL;
- sd.sd_dst_nid = LNET_NID_ANY;
- lpni1 = lnet_find_best_lpni_on_net(&sd, lp1, r1->lr_lnet);
- lpni2 = lnet_find_best_lpni_on_net(&sd, lp2, r2->lr_lnet);
- LASSERT(lpni1 && lpni2);
- if (r1->lr_priority < r2->lr_priority) {
- *best_lpni = lpni1;
+ if (r1->lr_priority < r2->lr_priority)
return 1;
- }
- if (r1->lr_priority > r2->lr_priority) {
- *best_lpni = lpni2;
+ if (r1->lr_priority > r2->lr_priority)
return -1;
- }
- if (r1_hops < r2_hops) {
- *best_lpni = lpni1;
+ if (r1_hops < r2_hops)
return 1;
- }
- if (r1_hops > r2_hops) {
- *best_lpni = lpni2;
+ if (r1_hops > r2_hops)
return -1;
- }
-
- rc = lnet_compare_peers(lpni1, lpni2);
- if (rc == 1) {
- *best_lpni = lpni1;
- return rc;
- } else if (rc == -1) {
- *best_lpni = lpni2;
- return rc;
- }
-
- if (r1->lr_seq - r2->lr_seq <= 0) {
- *best_lpni = lpni1;
- return 1;
- }
- *best_lpni = lpni2;
- return -1;
+ return 0;
}
static struct lnet_route *
-lnet_find_route_locked(struct lnet_net *net, __u32 remote_net,
- lnet_nid_t rtr_nid, struct lnet_route **prev_route,
+lnet_find_route_locked(struct lnet_remotenet *rnet, __u32 src_net,
+ struct lnet_route **prev_route,
struct lnet_peer_ni **gwni)
{
- struct lnet_peer_ni *best_gw_ni = NULL;
+ struct lnet_peer_ni *lpni, *best_gw_ni = NULL;
struct lnet_route *best_route;
struct lnet_route *last_route;
- struct lnet_remotenet *rnet;
- struct lnet_peer *lp_best;
struct lnet_route *route;
- struct lnet_peer *lp;
int rc;
+ __u32 restrict_net;
+ __u32 any_net = LNET_NIDNET(LNET_NID_ANY);
- /* If @rtr_nid is not LNET_NID_ANY, return the gateway with
- * rtr_nid nid, otherwise find the best gateway I can use */
-
- rnet = lnet_find_rnet_locked(remote_net);
- if (rnet == NULL)
- return NULL;
-
- lp_best = NULL;
best_route = last_route = NULL;
list_for_each_entry(route, &rnet->lrn_routes, lr_list) {
- lp = route->lr_gateway;
-
if (!lnet_is_route_alive(route))
continue;
- if (lp_best == NULL) {
- best_route = last_route = route;
- lp_best = lp;
+ /* If the src_net is specified then we need to find an lpni
+ * on that network
+ */
+ restrict_net = src_net == any_net ? route->lr_lnet : src_net;
+ if (!best_route) {
+ lpni = lnet_find_best_lpni_on_net(NULL, LNET_NID_ANY,
+ route->lr_gateway,
+ restrict_net);
+ if (lpni) {
+ best_route = last_route = route;
+ best_gw_ni = lpni;
+ } else
+ CERROR("Gateway %s does not have a peer NI on net %s\n",
+ libcfs_nid2str(route->lr_gateway->lp_primary_nid),
+ libcfs_net2str(restrict_net));
+
+ continue;
}
/* no protection on below fields, but it's harmless */
if (last_route->lr_seq - route->lr_seq < 0)
last_route = route;
- rc = lnet_compare_routes(route, best_route, &best_gw_ni);
- if (rc < 0)
+ rc = lnet_compare_routes(route, best_route);
+ if (rc == -1)
+ continue;
+
+ lpni = lnet_find_best_lpni_on_net(NULL, LNET_NID_ANY,
+ route->lr_gateway,
+ restrict_net);
+ if (!lpni) {
+ CERROR("Gateway %s does not have a peer NI on net %s\n",
+ libcfs_nid2str(route->lr_gateway->lp_primary_nid),
+ libcfs_net2str(restrict_net));
+ continue;
+ }
+
+ if (rc == 1) {
+ best_route = route;
+ best_gw_ni = lpni;
+ continue;
+ }
+
+ rc = lnet_compare_gw_lpnis(lpni, best_gw_ni);
+ if (rc == -1)
continue;
- best_route = route;
- lp_best = lp;
+ if (rc == 1 || route->lr_seq <= best_route->lr_seq) {
+ best_route = route;
+ best_gw_ni = lpni;
+ continue;
+ }
}
*prev_route = last_route;
rc = lnet_post_send_locked(msg, 0);
if (!rc)
- CDEBUG(D_NET, "TRACE: %s(%s:%s) -> %s(%s:%s) : %s try# %d\n",
+ CDEBUG(D_NET, "TRACE: %s(%s:%s) -> %s(%s:%s) %s : %s try# %d\n",
libcfs_nid2str(msg->msg_hdr.src_nid),
libcfs_nid2str(msg->msg_txni->ni_nid),
libcfs_nid2str(sd->sd_src_nid),
libcfs_nid2str(msg->msg_hdr.dest_nid),
libcfs_nid2str(sd->sd_dst_nid),
libcfs_nid2str(msg->msg_txpeer->lpni_nid),
+ libcfs_nid2str(sd->sd_rtr_nid),
lnet_msgtyp2str(msg->msg_type), msg->msg_retry_count);
return rc;
* Local Destination
* MR Peer
*
- * Run the selection algorithm on the peer NIs unless we're sending
- * a response, in this case just send to the destination
+ * Don't run the selection algorithm on the peer NIs. By specifying the
+ * local NID, we're also saying that we should always use the destination NID
+ * provided. This handles the case where we should be using the same
+ * destination NID for the all the messages which belong to the same RPC
+ * request.
*/
static int
lnet_handle_spec_local_mr_dst(struct lnet_send_data *sd)
return -EINVAL;
}
- /*
- * only run the selection algorithm to pick the peer_ni if we're
- * sending a GET or a PUT. Responses are sent to the same
- * destination NID provided.
- */
- if (!(sd->sd_send_case & SND_RESP)) {
- sd->sd_best_lpni =
- lnet_find_best_lpni_on_net(sd, sd->sd_peer,
- sd->sd_best_ni->ni_net->net_id);
- }
-
if (sd->sd_best_lpni &&
sd->sd_best_lpni->lpni_nid == the_lnet.ln_loni->ni_nid)
return lnet_handle_lo_send(sd);
}
/* The peer may have changed. */
peer = lpni->lpni_peer_net->lpn_peer;
+ spin_lock(&peer->lp_lock);
+ if (lnet_peer_is_uptodate_locked(peer)) {
+ spin_unlock(&peer->lp_lock);
+ lnet_peer_ni_decref_locked(lpni);
+ return 0;
+ }
/* queue message and return */
msg->msg_rtr_nid_param = rtr_nid;
msg->msg_sending = 0;
msg->msg_txpeer = NULL;
- spin_lock(&peer->lp_lock);
list_add_tail(&msg->msg_list, &peer->lp_dc_pendq);
+ primary_nid = peer->lp_primary_nid;
spin_unlock(&peer->lp_lock);
+
lnet_peer_ni_decref_locked(lpni);
- primary_nid = peer->lp_primary_nid;
CDEBUG(D_NET, "msg %p delayed. %s pending discovery\n",
msg, libcfs_nid2str(primary_nid));
struct lnet_peer **gw_peer)
{
int rc;
+ __u32 local_lnet;
struct lnet_peer *gw;
struct lnet_peer *lp;
struct lnet_peer_net *lpn;
struct lnet_peer_net *best_lpn = NULL;
- struct lnet_remotenet *rnet;
- struct lnet_route *best_route;
- struct lnet_route *last_route;
+ struct lnet_remotenet *rnet, *best_rnet = NULL;
+ struct lnet_route *best_route = NULL;
+ struct lnet_route *last_route = NULL;
struct lnet_peer_ni *lpni = NULL;
struct lnet_peer_ni *gwni = NULL;
lnet_nid_t src_nid = sd->sd_src_nid;
- /* we've already looked up the initial lpni using dst_nid */
- lpni = sd->sd_best_lpni;
- /* the peer tree must be in existence */
- LASSERT(lpni && lpni->lpni_peer_net && lpni->lpni_peer_net->lpn_peer);
- lp = lpni->lpni_peer_net->lpn_peer;
+ /* If a router nid was specified then we are replying to a GET or
+ * sending an ACK. In this case we use the gateway associated with the
+ * specified router nid.
+ */
+ if (sd->sd_rtr_nid != LNET_NID_ANY) {
+ gwni = lnet_find_peer_ni_locked(sd->sd_rtr_nid);
+ if (!gwni) {
+ CERROR("No peer NI for gateway %s\n",
+ libcfs_nid2str(sd->sd_rtr_nid));
+ return -EHOSTUNREACH;
+ }
+ gw = gwni->lpni_peer_net->lpn_peer;
+ lnet_peer_ni_decref_locked(gwni);
+ local_lnet = LNET_NIDNET(sd->sd_rtr_nid);
+ } else {
+ /* we've already looked up the initial lpni using dst_nid */
+ lpni = sd->sd_best_lpni;
+ /* the peer tree must be in existence */
+ LASSERT(lpni && lpni->lpni_peer_net &&
+ lpni->lpni_peer_net->lpn_peer);
+ lp = lpni->lpni_peer_net->lpn_peer;
+
+ list_for_each_entry(lpn, &lp->lp_peer_nets, lpn_peer_nets) {
+ /* is this remote network reachable? */
+ rnet = lnet_find_rnet_locked(lpn->lpn_net_id);
+ if (!rnet)
+ continue;
- list_for_each_entry(lpn, &lp->lp_peer_nets, lpn_peer_nets) {
- /* is this remote network reachable? */
- rnet = lnet_find_rnet_locked(lpn->lpn_net_id);
- if (!rnet)
- continue;
+ if (!best_lpn) {
+ best_lpn = lpn;
+ best_rnet = rnet;
+ }
+
+ if (best_lpn->lpn_seq <= lpn->lpn_seq)
+ continue;
- if (!best_lpn)
best_lpn = lpn;
+ best_rnet = rnet;
+ }
- if (best_lpn->lpn_seq <= lpn->lpn_seq)
- continue;
+ if (!best_lpn) {
+ CERROR("peer %s has no available nets\n",
+ libcfs_nid2str(sd->sd_dst_nid));
+ return -EHOSTUNREACH;
+ }
- best_lpn = lpn;
- }
+ sd->sd_best_lpni = lnet_find_best_lpni_on_net(sd->sd_best_ni,
+ sd->sd_dst_nid,
+ lp,
+ best_lpn->lpn_net_id);
+ if (!sd->sd_best_lpni) {
+ CERROR("peer %s down\n",
+ libcfs_nid2str(sd->sd_dst_nid));
+ return -EHOSTUNREACH;
+ }
- if (!best_lpn) {
- CERROR("peer %s has no available nets \n",
- libcfs_nid2str(sd->sd_dst_nid));
- return -EHOSTUNREACH;
- }
+ best_route = lnet_find_route_locked(best_rnet,
+ LNET_NIDNET(src_nid),
+ &last_route, &gwni);
+ if (!best_route) {
+ CERROR("no route to %s from %s\n",
+ libcfs_nid2str(dst_nid),
+ libcfs_nid2str(src_nid));
+ return -EHOSTUNREACH;
+ }
- sd->sd_best_lpni = lnet_find_best_lpni_on_net(sd, lp, best_lpn->lpn_net_id);
- if (!sd->sd_best_lpni) {
- CERROR("peer %s down\n", libcfs_nid2str(sd->sd_dst_nid));
- return -EHOSTUNREACH;
- }
+ if (!gwni) {
+ CERROR("Internal Error. Route expected to %s from %s\n",
+ libcfs_nid2str(dst_nid),
+ libcfs_nid2str(src_nid));
+ return -EFAULT;
+ }
- best_route = lnet_find_route_locked(NULL, best_lpn->lpn_net_id,
- sd->sd_rtr_nid, &last_route,
- &gwni);
- if (!best_route) {
- CERROR("no route to %s from %s\n",
- libcfs_nid2str(dst_nid), libcfs_nid2str(src_nid));
- return -EHOSTUNREACH;
- }
+ gw = best_route->lr_gateway;
+ LASSERT(gw == gwni->lpni_peer_net->lpn_peer);
+ local_lnet = best_route->lr_lnet;
- if (!gwni) {
- CERROR("Internal Error. Route expected to %s from %s\n",
- libcfs_nid2str(dst_nid),
- libcfs_nid2str(src_nid));
- return -EFAULT;
}
- gw = best_route->lr_gateway;
- LASSERT(gw == gwni->lpni_peer_net->lpn_peer);
-
/*
* Discover this gateway if it hasn't already been discovered.
* This means we might delay the message until discovery has
if (!sd->sd_best_ni)
sd->sd_best_ni = lnet_find_best_ni_on_spec_net(NULL, gw,
lnet_peer_get_net_locked(gw,
- best_route->lr_lnet),
+ local_lnet),
sd->sd_md_cpt,
true);
if (!sd->sd_best_ni) {
- CERROR("Internal Error. Expected local ni on %s "
- "but non found :%s\n",
- libcfs_net2str(best_route->lr_lnet),
+ CERROR("Internal Error. Expected local ni on %s but non found :%s\n",
+ libcfs_net2str(local_lnet),
libcfs_nid2str(sd->sd_src_nid));
return -EFAULT;
}
* increment the sequence numbers since now we're sure we're
* going to use this path
*/
- LASSERT(best_route && last_route);
- best_route->lr_seq = last_route->lr_seq + 1;
- best_lpn->lpn_seq++;
+ if (sd->sd_rtr_nid == LNET_NID_ANY) {
+ LASSERT(best_route && last_route);
+ best_route->lr_seq = last_route->lr_seq + 1;
+ best_lpn->lpn_seq++;
+ }
return 0;
}
lnet_msg_discovery(sd->sd_msg));
if (sd->sd_best_ni) {
sd->sd_best_lpni =
- lnet_find_best_lpni_on_net(sd, sd->sd_peer,
+ lnet_find_best_lpni_on_net(sd->sd_best_ni, sd->sd_dst_nid,
+ sd->sd_peer,
sd->sd_best_ni->ni_net->net_id);
/*
msg->msg_src_nid_param = src_nid;
/*
- * Now that we have a peer_ni, check if we want to discover
- * the peer. Traffic to the LNET_RESERVED_PORTAL should not
- * trigger discovery.
+ * If necessary, perform discovery on the peer that owns this peer_ni.
+ * Note, this can result in the ownership of this peer_ni changing
+ * to another peer object.
*/
- peer = lpni->lpni_peer_net->lpn_peer;
rc = lnet_initiate_peer_discovery(lpni, msg, rtr_nid, cpt);
if (rc) {
lnet_peer_ni_decref_locked(lpni);
}
lnet_peer_ni_decref_locked(lpni);
+ peer = lpni->lpni_peer_net->lpn_peer;
+
/*
* Identify the different send cases
*/
min((unsigned int) alive_router_check_interval /
lnet_current_net_count,
lnet_transaction_timeout / 2));
- wait_event_interruptible_timeout(the_lnet.ln_mt_waitq,
- false,
- cfs_time_seconds(interval));
+ wait_for_completion_interruptible_timeout(
+ &the_lnet.ln_mt_wait_complete,
+ cfs_time_seconds(interval));
+ /* Must re-init the completion before testing anything,
+ * including ln_mt_state.
+ */
+ reinit_completion(&the_lnet.ln_mt_wait_complete);
}
/* Shutting down */
lnet_net_unlock(LNET_LOCK_EX);
/* tell the monitor thread that we're shutting down */
- wake_up(&the_lnet.ln_mt_waitq);
+ complete(&the_lnet.ln_mt_wait_complete);
/* block until monitor thread signals that it's done */
down(&the_lnet.ln_mt_signal);
lnet_clean_local_ni_recoveryq();
lnet_clean_peer_ni_recoveryq();
lnet_clean_resendqs();
-
- return;
}
void
struct lnet_libmd *md, struct lnet_handle_md mdh)
{
s64 timeout_ns;
- bool new_entry = true;
struct lnet_rsp_tracker *local_rspt;
/*
* we already have an rspt attached to the md, so we'll
* update the deadline on that one.
*/
- LIBCFS_FREE(rspt, sizeof(*rspt));
- new_entry = false;
+ lnet_rspt_free(rspt, cpt);
} else {
/* new md */
rspt->rspt_mdh = mdh;
* list in order to expire all the older entries first.
*/
lnet_net_lock(cpt);
- if (!new_entry && !list_empty(&local_rspt->rspt_on_list))
- list_del_init(&local_rspt->rspt_on_list);
- list_add_tail(&local_rspt->rspt_on_list, the_lnet.ln_mt_rstq[cpt]);
+ list_move_tail(&local_rspt->rspt_on_list, the_lnet.ln_mt_rstq[cpt]);
lnet_net_unlock(cpt);
lnet_res_unlock(cpt);
}
md->md_me->me_portal);
lnet_res_unlock(cpt);
- LIBCFS_FREE(rspt, sizeof(*rspt));
+ lnet_rspt_free(rspt, cpt);
lnet_msg_free(msg);
return -ENOENT;
}
lnet_res_unlock(cpt);
lnet_msg_free(msg);
- LIBCFS_FREE(rspt, sizeof(*rspt));
+ lnet_rspt_free(rspt, cpt);
return -ENOENT;
}
* current net namespace.
* If not, assign order above 0xffff0000,
* to make this ni not a priority. */
- if (!net_eq(ni->ni_net_ns, current->nsproxy->net_ns))
- order += 0xffff0000;
-
+ if (current->nsproxy &&
+ !net_eq(ni->ni_net_ns, current->nsproxy->net_ns))
+ order += 0xffff0000;
if (srcnidp != NULL)
*srcnidp = ni->ni_nid;
if (orderp != NULL)