+ cpt = lnet_nid_cpt_hash(nid, LNET_CPT_NUMBER);
+
+ LIBCFS_CPT_ALLOC(lpni, lnet_cpt_table(), cpt, sizeof(*lpni));
+ if (!lpni)
+ return NULL;
+
+ 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)