+ INIT_LIST_HEAD(&lpni->lpni_txq);
+ INIT_LIST_HEAD(&lpni->lpni_rtrq);
+ INIT_LIST_HEAD(&lpni->lpni_routes);
+ INIT_LIST_HEAD(&lpni->lpni_hashlist);
+ INIT_LIST_HEAD(&lpni->lpni_on_peer_net_list);
+ INIT_LIST_HEAD(&lpni->lpni_on_remote_peer_ni_list);
+
+ spin_lock_init(&lpni->lpni_lock);
+
+ lpni->lpni_alive = !lnet_peers_start_down(); /* 1 bit!! */
+ lpni->lpni_last_alive = cfs_time_current(); /* assumes alive */
+ lpni->lpni_ping_feats = LNET_PING_FEAT_INVAL;
+ lpni->lpni_nid = nid;
+ lpni->lpni_cpt = cpt;
+ lnet_set_peer_ni_health_locked(lpni, true);
+
+ net = lnet_get_net_locked(LNET_NIDNET(nid));
+ lpni->lpni_net = net;
+ if (net) {
+ lpni->lpni_txcredits = net->net_tunables.lct_peer_tx_credits;
+ lpni->lpni_mintxcredits = lpni->lpni_txcredits;
+ lpni->lpni_rtrcredits = lnet_peer_buffer_credits(net);
+ lpni->lpni_minrtrcredits = lpni->lpni_rtrcredits;
+ } else {
+ /*
+ * This peer_ni is not on a local network, so we
+ * cannot add the credits here. In case the net is
+ * added later, add the peer_ni to the remote peer ni
+ * list so it can be easily found and revisited.
+ */
+ /* FIXME: per-net implementation instead? */
+ atomic_inc(&lpni->lpni_refcount);
+ list_add_tail(&lpni->lpni_on_remote_peer_ni_list,
+ &the_lnet.ln_remote_peer_ni_list);
+ }
+
+ /* 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));
+ }