+ /* TODO: update flags */
+
+ return lpni;
+}
+
+static struct lnet_peer_net *
+lnet_peer_net_alloc(__u32 net_id)
+{
+ struct lnet_peer_net *lpn;
+
+ LIBCFS_CPT_ALLOC(lpn, lnet_cpt_table(), CFS_CPT_ANY, sizeof(*lpn));
+ if (!lpn)
+ return NULL;
+
+ INIT_LIST_HEAD(&lpn->lpn_on_peer_list);
+ INIT_LIST_HEAD(&lpn->lpn_peer_nis);
+ lpn->lpn_net_id = net_id;
+
+ return lpn;
+}
+
+static struct lnet_peer *
+lnet_peer_alloc(lnet_nid_t nid)
+{
+ struct lnet_peer *lp;
+
+ LIBCFS_CPT_ALLOC(lp, lnet_cpt_table(), CFS_CPT_ANY, sizeof(*lp));
+ if (!lp)
+ return NULL;
+
+ INIT_LIST_HEAD(&lp->lp_on_lnet_peer_list);
+ INIT_LIST_HEAD(&lp->lp_peer_nets);
+ lp->lp_primary_nid = nid;
+
+ /* TODO: update flags */
+
+ return lp;
+}
+
+
+static void
+lnet_try_destroy_peer_hierarchy_locked(struct lnet_peer_ni *lpni)
+{
+ struct lnet_peer_net *peer_net;
+ struct lnet_peer *peer;
+
+ /* TODO: could the below situation happen? accessing an already
+ * destroyed peer? */
+ if (lpni->lpni_peer_net == NULL ||
+ lpni->lpni_peer_net->lpn_peer == NULL)
+ return;
+
+ peer_net = lpni->lpni_peer_net;
+ peer = lpni->lpni_peer_net->lpn_peer;
+
+ list_del_init(&lpni->lpni_on_peer_net_list);
+ lpni->lpni_peer_net = NULL;
+
+ /* if peer_net is empty, then remove it from the peer */
+ if (list_empty(&peer_net->lpn_peer_nis)) {
+ list_del_init(&peer_net->lpn_on_peer_list);
+ peer_net->lpn_peer = NULL;
+ LIBCFS_FREE(peer_net, sizeof(*peer_net));
+
+ /* if the peer is empty then remove it from the
+ * the_lnet.ln_peers */
+ if (list_empty(&peer->lp_peer_nets)) {
+ list_del_init(&peer->lp_on_lnet_peer_list);
+ LIBCFS_FREE(peer, sizeof(*peer));
+ }
+ }
+}
+
+/* called with lnet_net_lock LNET_LOCK_EX held */
+static void
+lnet_peer_ni_del_locked(struct lnet_peer_ni *lpni)
+{
+ struct lnet_peer_table *ptable = NULL;
+
+ lnet_peer_remove_from_remote_list(lpni);
+
+ /* remove peer ni from the hash list. */
+ list_del_init(&lpni->lpni_hashlist);
+
+ /* decrement the ref count on the peer table */
+ ptable = the_lnet.ln_peer_tables[lpni->lpni_cpt];
+ LASSERT(atomic_read(&ptable->pt_number) > 0);
+ atomic_dec(&ptable->pt_number);
+
+ /*
+ * The peer_ni can no longer be found with a lookup. But there
+ * can be current users, so keep track of it on the zombie
+ * list until the reference count has gone to zero.
+ *
+ * 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
+ * has its own lock.
+ */
+ spin_lock(&ptable->pt_zombie_lock);
+ list_add(&lpni->lpni_hashlist, &ptable->pt_zombie_list);
+ ptable->pt_zombies++;
+ spin_unlock(&ptable->pt_zombie_lock);
+
+ /* no need to keep this peer on the hierarchy anymore */
+ lnet_try_destroy_peer_hierarchy_locked(lpni);
+
+ /* decrement reference on peer */
+ lnet_peer_ni_decref_locked(lpni);
+}
+
+void lnet_peer_uninit()
+{
+ struct lnet_peer_ni *lpni, *tmp;
+
+ lnet_net_lock(LNET_LOCK_EX);
+
+ /* remove all peer_nis from the remote peer and the hash list */
+ list_for_each_entry_safe(lpni, tmp, &the_lnet.ln_remote_peer_ni_list,
+ lpni_on_remote_peer_ni_list)
+ lnet_peer_ni_del_locked(lpni);
+