if (LNET_NIDNET(lpni->lpni_nid) == net->net_id) {
lpni->lpni_net = net;
+
+ spin_lock(&lpni->lpni_lock);
lpni->lpni_txcredits =
- lpni->lpni_mintxcredits =
lpni->lpni_net->net_tunables.lct_peer_tx_credits;
+ lpni->lpni_mintxcredits = lpni->lpni_txcredits;
lpni->lpni_rtrcredits =
- lpni->lpni_minrtrcredits =
lnet_peer_buffer_credits(lpni->lpni_net);
+ lpni->lpni_minrtrcredits = lpni->lpni_rtrcredits;
+ spin_unlock(&lpni->lpni_lock);
lnet_peer_remove_from_remote_list(lpni);
}
}
/* called with lnet_net_lock LNET_LOCK_EX held */
-static void
+static int
lnet_peer_ni_del_locked(struct lnet_peer_ni *lpni)
{
struct lnet_peer_table *ptable = NULL;
+ /* don't remove a peer_ni if it's also a gateway */
+ if (lpni->lpni_rtr_refcount > 0) {
+ CERROR("Peer NI %s is a gateway. Can not delete it\n",
+ libcfs_nid2str(lpni->lpni_nid));
+ return -EBUSY;
+ }
+
lnet_peer_remove_from_remote_list(lpni);
/* remove peer ni from the hash list. */
/* decrement reference on peer */
lnet_peer_ni_decref_locked(lpni);
+
+ return 0;
}
-void lnet_peer_uninit()
+void lnet_peer_uninit(void)
{
struct lnet_peer_ni *lpni, *tmp;
lnet_net_unlock(LNET_LOCK_EX);
}
-static void
+static int
lnet_peer_del_locked(struct lnet_peer *peer)
{
struct lnet_peer_ni *lpni = NULL, *lpni2;
+ int rc = 0, rc2 = 0;
lpni = lnet_get_next_peer_ni_locked(peer, NULL, lpni);
while (lpni != NULL) {
lpni2 = lnet_get_next_peer_ni_locked(peer, NULL, lpni);
- lnet_peer_ni_del_locked(lpni);
+ rc = lnet_peer_ni_del_locked(lpni);
+ if (rc != 0)
+ rc2 = rc;
lpni = lpni2;
}
+
+ return rc2;
}
static void
struct lnet_peer_table *ptable)
{
int i;
+ struct lnet_peer_ni *next;
struct lnet_peer_ni *lpni;
- struct lnet_peer_ni *tmp;
struct lnet_peer *peer;
for (i = 0; i < LNET_PEER_HASH_SIZE; i++) {
- list_for_each_entry_safe(lpni, tmp, &ptable->pt_hash[i],
+ list_for_each_entry_safe(lpni, next, &ptable->pt_hash[i],
lpni_hashlist) {
if (net != NULL && net != lpni->lpni_net)
continue;
- /*
- * check if by removing this peer ni we should be
- * removing the entire peer.
- */
peer = lpni->lpni_peer_net->lpn_peer;
-
- if (peer->lp_primary_nid == lpni->lpni_nid)
- lnet_peer_del_locked(peer);
- else
+ if (peer->lp_primary_nid != lpni->lpni_nid) {
lnet_peer_ni_del_locked(lpni);
+ continue;
+ }
+ /*
+ * Removing the primary NID implies removing
+ * the entire peer. Advance next beyond any
+ * peer_ni that belongs to the same peer.
+ */
+ list_for_each_entry_from(next, &ptable->pt_hash[i],
+ lpni_hashlist) {
+ if (next->lpni_peer_net->lpn_peer != peer)
+ break;
+ }
+ lnet_peer_del_locked(peer);
}
}
}
while (ptable->pt_zombies) {
spin_unlock(&ptable->pt_zombie_lock);
- if (IS_PO2(i)) {
+ if (is_power_of_2(i)) {
CDEBUG(D_WARNING,
"Waiting for %d zombies on peer table\n",
ptable->pt_zombies);
return primary_nid;
}
+lnet_nid_t
+LNetPrimaryNID(lnet_nid_t nid)
+{
+ struct lnet_peer_ni *lpni;
+ lnet_nid_t primary_nid = nid;
+ int rc = 0;
+ int cpt;
+
+ cpt = lnet_net_lock_current();
+ lpni = lnet_nid2peerni_locked(nid, cpt);
+ if (IS_ERR(lpni)) {
+ rc = PTR_ERR(lpni);
+ goto out_unlock;
+ }
+ primary_nid = lpni->lpni_peer_net->lpn_peer->lp_primary_nid;
+ lnet_peer_ni_decref_locked(lpni);
+out_unlock:
+ lnet_net_unlock(cpt);
+
+ CDEBUG(D_NET, "NID %s primary NID %s rc %d\n", libcfs_nid2str(nid),
+ libcfs_nid2str(primary_nid), rc);
+ return primary_nid;
+}
+EXPORT_SYMBOL(LNetPrimaryNID);
+
struct lnet_peer_net *
lnet_peer_get_net_locked(struct lnet_peer *peer, __u32 net_id)
{
}
static int
-lnet_add_peer_ni_to_prim_lpni(lnet_nid_t key_nid, lnet_nid_t nid)
+lnet_add_peer_ni_to_prim_lpni(lnet_nid_t prim_nid, lnet_nid_t nid)
{
struct lnet_peer *peer, *primary_peer;
struct lnet_peer_ni *lpni = NULL, *klpni = NULL;
- LASSERT(key_nid != LNET_NID_ANY && nid != LNET_NID_ANY);
+ LASSERT(prim_nid != LNET_NID_ANY && nid != LNET_NID_ANY);
/*
* key nid must be created by this point. If not then this
* operation is not permitted
*/
- klpni = lnet_find_peer_ni_locked(key_nid);
+ klpni = lnet_find_peer_ni_locked(prim_nid);
if (!klpni)
return -ENOENT;
* lpni already exists in the system but it belongs to
* a different peer. We can't re-added it
*/
- if (peer->lp_primary_nid != key_nid && peer->lp_multi_rail) {
+ if (peer->lp_primary_nid != prim_nid && peer->lp_multi_rail) {
CERROR("Cannot add NID %s owned by peer %s to peer %s\n",
libcfs_nid2str(lpni->lpni_nid),
libcfs_nid2str(peer->lp_primary_nid),
- libcfs_nid2str(key_nid));
+ libcfs_nid2str(prim_nid));
return -EEXIST;
- } else if (peer->lp_primary_nid == key_nid) {
+ } else if (peer->lp_primary_nid == prim_nid) {
/*
* found a peer_ni that is already part of the
* peer. This is a no-op operation.
}
/*
- * TODO: else if (peer->lp_primary_nid != key_nid &&
+ * TODO: else if (peer->lp_primary_nid != prim_nid &&
* !peer->lp_multi_rail)
* peer is not an MR peer and it will be moved in the next
* step to klpni, so update its flags accordingly.
/*
* This API handles the following combinations:
- * Create a primary NI if only the key_nid is provided
+ * Create a primary NI if only the prim_nid is provided
* Create or add an lpni to a primary NI. Primary NI must've already
* been created
* Create a non-MR peer.
*/
int
-lnet_add_peer_ni_to_peer(lnet_nid_t key_nid, lnet_nid_t nid, bool mr)
+lnet_add_peer_ni_to_peer(lnet_nid_t prim_nid, lnet_nid_t nid, bool mr)
{
/*
* Caller trying to setup an MR like peer hierarchy but
* specifying it to be non-MR. This is not allowed.
*/
- if (key_nid != LNET_NID_ANY &&
+ if (prim_nid != LNET_NID_ANY &&
nid != LNET_NID_ANY && !mr)
return -EPERM;
/* Add the primary NID of a peer */
- if (key_nid != LNET_NID_ANY &&
+ if (prim_nid != LNET_NID_ANY &&
nid == LNET_NID_ANY && mr)
- return lnet_add_prim_lpni(key_nid);
+ return lnet_add_prim_lpni(prim_nid);
/* Add a NID to an existing peer */
- if (key_nid != LNET_NID_ANY &&
+ if (prim_nid != LNET_NID_ANY &&
nid != LNET_NID_ANY && mr)
- return lnet_add_peer_ni_to_prim_lpni(key_nid, nid);
+ return lnet_add_peer_ni_to_prim_lpni(prim_nid, nid);
/* Add a non-MR peer NI */
- if (((key_nid != LNET_NID_ANY &&
+ if (((prim_nid != LNET_NID_ANY &&
nid == LNET_NID_ANY) ||
- (key_nid == LNET_NID_ANY &&
+ (prim_nid == LNET_NID_ANY &&
nid != LNET_NID_ANY)) && !mr)
- return lnet_peer_ni_add_non_mr(key_nid != LNET_NID_ANY ?
- key_nid : nid);
+ return lnet_peer_ni_add_non_mr(prim_nid != LNET_NID_ANY ?
+ prim_nid : nid);
return 0;
}
int
-lnet_del_peer_ni_from_peer(lnet_nid_t key_nid, lnet_nid_t nid)
+lnet_del_peer_ni_from_peer(lnet_nid_t prim_nid, lnet_nid_t nid)
{
lnet_nid_t local_nid;
struct lnet_peer *peer;
struct lnet_peer_ni *lpni;
+ int rc;
- if (key_nid == LNET_NID_ANY)
+ if (prim_nid == LNET_NID_ANY)
return -EINVAL;
- local_nid = (nid != LNET_NID_ANY) ? nid : key_nid;
+ local_nid = (nid != LNET_NID_ANY) ? nid : prim_nid;
lpni = lnet_find_peer_ni_locked(local_nid);
if (!lpni)
* entire peer
*/
lnet_net_lock(LNET_LOCK_EX);
- lnet_peer_del_locked(peer);
+ rc = lnet_peer_del_locked(peer);
lnet_net_unlock(LNET_LOCK_EX);
- return 0;
+ return rc;
}
lnet_net_lock(LNET_LOCK_EX);
- lnet_peer_ni_del_locked(lpni);
+ rc = lnet_peer_ni_del_locked(lpni);
lnet_net_unlock(LNET_LOCK_EX);
- return 0;
+ return rc;
}
void
}
struct lnet_peer_ni *
+lnet_nid2peerni_ex(lnet_nid_t nid, int cpt)
+{
+ struct lnet_peer_ni *lpni = NULL;
+ int rc;
+
+ if (the_lnet.ln_shutdown) /* it's shutting down */
+ return ERR_PTR(-ESHUTDOWN);
+
+ /*
+ * find if a peer_ni already exists.
+ * If so then just return that.
+ */
+ lpni = lnet_find_peer_ni_locked(nid);
+ if (lpni)
+ return lpni;
+
+ lnet_net_unlock(cpt);
+
+ rc = lnet_peer_ni_traffic_add(nid);
+ if (rc) {
+ lpni = ERR_PTR(rc);
+ goto out_net_relock;
+ }
+
+ lpni = lnet_find_peer_ni_locked(nid);
+ LASSERT(lpni);
+
+out_net_relock:
+ lnet_net_lock(cpt);
+
+ return lpni;
+}
+
+struct lnet_peer_ni *
lnet_nid2peerni_locked(lnet_nid_t nid, int cpt)
{
- struct lnet_peer_table *ptable;
- struct lnet_peer_ni *lpni = NULL;
- int cpt2;
- int rc;
+ struct lnet_peer_ni *lpni = NULL;
+ int rc;
if (the_lnet.ln_shutdown) /* it's shutting down */
return ERR_PTR(-ESHUTDOWN);
/*
- * calculate cpt2 with the standard hash function
- * This cpt2 is the slot where we'll find or create the peer.
+ * find if a peer_ni already exists.
+ * If so then just return that.
*/
- cpt2 = lnet_nid_cpt_hash(nid, LNET_CPT_NUMBER);
- ptable = the_lnet.ln_peer_tables[cpt2];
- lpni = lnet_get_peer_ni_locked(ptable, nid);
+ lpni = lnet_find_peer_ni_locked(nid);
if (lpni)
return lpni;
- /* Slow path: serialized using the ln_api_mutex. */
+ /*
+ * Slow path:
+ * use the lnet_api_mutex to serialize the creation of the peer_ni
+ * and the creation/deletion of the local ni/net. When a local ni is
+ * created, if there exists a set of peer_nis on that network,
+ * they need to be traversed and updated. When a local NI is
+ * deleted, which could result in a network being deleted, then
+ * all peer nis on that network need to be removed as well.
+ *
+ * Creation through traffic should also be serialized with
+ * creation through DLC.
+ */
lnet_net_unlock(cpt);
mutex_lock(&the_lnet.ln_api_mutex);
/*
* Shutdown is only set under the ln_api_lock, so a single
* check here is sufficent.
- *
- * lnet_add_nid_to_peer() also handles the case where we've
- * raced and a different thread added the NID.
*/
if (the_lnet.ln_shutdown) {
lpni = ERR_PTR(-ESHUTDOWN);
goto out_mutex_unlock;
}
- lpni = lnet_get_peer_ni_locked(ptable, nid);
+ lpni = lnet_find_peer_ni_locked(nid);
LASSERT(lpni);
out_mutex_unlock:
lpni->lpni_net->net_tunables.lct_peer_tx_credits : 0;
peer_ni_info->cr_peer_tx_credits = lpni->lpni_txcredits;
peer_ni_info->cr_peer_rtr_credits = lpni->lpni_rtrcredits;
- peer_ni_info->cr_peer_min_rtr_credits = lpni->lpni_mintxcredits;
+ peer_ni_info->cr_peer_min_rtr_credits = lpni->lpni_minrtrcredits;
+ peer_ni_info->cr_peer_min_tx_credits = lpni->lpni_mintxcredits;
peer_ni_info->cr_peer_tx_qnob = lpni->lpni_txqnob;
peer_ni_stats->send_count = atomic_read(&lpni->lpni_stats.send_count);