*
* The last reference may be lost in a place where the
* lnet_net_lock locks only a single cpt, and that cpt may not
- * be lpni->lpni_cpt. So the zombie list of this peer_table
+ * be lpni->lpni_cpt. So the zombie list of lnet_peer_table
* has its own lock.
*/
spin_lock(&ptable->pt_zombie_lock);
return rc2;
}
+static int
+lnet_peer_del(struct lnet_peer *peer)
+{
+ lnet_net_lock(LNET_LOCK_EX);
+ lnet_peer_del_locked(peer);
+ lnet_net_unlock(LNET_LOCK_EX);
+
+ return 0;
+}
+
+/*
+ * Delete a NID from a peer.
+ * Implements a few sanity checks.
+ * Call with ln_api_mutex held.
+ */
+static int
+lnet_peer_del_nid(struct lnet_peer *lp, lnet_nid_t nid)
+{
+ struct lnet_peer *lp2;
+ struct lnet_peer_ni *lpni;
+
+ lpni = lnet_find_peer_ni_locked(nid);
+ if (!lpni) {
+ CERROR("Cannot remove unknown nid %s from peer %s\n",
+ libcfs_nid2str(nid),
+ libcfs_nid2str(lp->lp_primary_nid));
+ return -ENOENT;
+ }
+ lnet_peer_ni_decref_locked(lpni);
+ lp2 = lpni->lpni_peer_net->lpn_peer;
+ if (lp2 != lp) {
+ CERROR("Nid %s is attached to peer %s, not peer %s\n",
+ libcfs_nid2str(nid),
+ libcfs_nid2str(lp2->lp_primary_nid),
+ libcfs_nid2str(lp->lp_primary_nid));
+ return -EINVAL;
+ }
+
+ /*
+ * This function only allows deletion of the primary NID if it
+ * is the only NID.
+ */
+ if (nid == lp->lp_primary_nid && lnet_get_num_peer_nis(lp) != 1) {
+ CERROR("Cannot delete primary NID %s from multi-NID peer\n",
+ libcfs_nid2str(nid));
+ return -EINVAL;
+ }
+
+ lnet_net_lock(LNET_LOCK_EX);
+ lnet_peer_ni_del_locked(lpni);
+ lnet_net_unlock(LNET_LOCK_EX);
+
+ return 0;
+}
+
static void
lnet_peer_table_cleanup_locked(struct lnet_net *net,
struct lnet_peer_table *ptable)
* Delete a NI from a peer if both prim_nid and nid are provided.
* Delete a peer if only prim_nid is provided.
* Delete a peer if its primary nid is provided.
+ *
+ * The caller must hold ln_api_mutex. This prevents the peer from
+ * being modified/deleted by a different thread.
*/
int
lnet_del_peer_ni(lnet_nid_t prim_nid, lnet_nid_t nid)
{
- lnet_nid_t local_nid;
- struct lnet_peer *peer;
+ struct lnet_peer *lp;
struct lnet_peer_ni *lpni;
- int rc;
if (prim_nid == LNET_NID_ANY)
return -EINVAL;
- local_nid = (nid != LNET_NID_ANY) ? nid : prim_nid;
-
- lpni = lnet_find_peer_ni_locked(local_nid);
+ lpni = lnet_find_peer_ni_locked(prim_nid);
if (!lpni)
- return -EINVAL;
+ return -ENOENT;
lnet_peer_ni_decref_locked(lpni);
+ lp = lpni->lpni_peer_net->lpn_peer;
- peer = lpni->lpni_peer_net->lpn_peer;
- LASSERT(peer != NULL);
-
- if (peer->lp_primary_nid == lpni->lpni_nid) {
- /*
- * deleting the primary ni is equivalent to deleting the
- * entire peer
- */
- lnet_net_lock(LNET_LOCK_EX);
- rc = lnet_peer_del_locked(peer);
- lnet_net_unlock(LNET_LOCK_EX);
-
- return rc;
+ if (prim_nid != lp->lp_primary_nid) {
+ CDEBUG(D_NET, "prim_nid %s is not primary for peer %s\n",
+ libcfs_nid2str(prim_nid),
+ libcfs_nid2str(lp->lp_primary_nid));
+ return -ENODEV;
}
- lnet_net_lock(LNET_LOCK_EX);
- rc = lnet_peer_ni_del_locked(lpni);
- lnet_net_unlock(LNET_LOCK_EX);
+ if (nid == LNET_NID_ANY || nid == lp->lp_primary_nid)
+ return lnet_peer_del(lp);
- return rc;
+ return lnet_peer_del_nid(lp, nid);
}
void