X-Git-Url: https://git.whamcloud.com/?p=fs%2Flustre-release.git;a=blobdiff_plain;f=lnet%2Flnet%2Fpeer.c;h=6a6f56b1bd3f9c0b4b257398e8c85b17ff2e5e7c;hp=236f63b633959ea0788195d3276e4f51aa133240;hb=58091af960fed0cc16e2b96e54ee6e2f8791d9c1;hpb=8cbb8cd3e771e7f7e0f99cafc19fad32770dc015 diff --git a/lnet/lnet/peer.c b/lnet/lnet/peer.c index 236f63b..6a6f56b 100644 --- a/lnet/lnet/peer.c +++ b/lnet/lnet/peer.c @@ -53,8 +53,6 @@ lnet_peer_tables_create(void) } cfs_percpt_for_each(ptable, i, the_lnet.ln_peer_tables) { - INIT_LIST_HEAD(&ptable->pt_deathrow); - LIBCFS_CPT_ALLOC(hash, lnet_cpt_table(), i, LNET_PEER_HASH_SIZE * sizeof(*hash)); if (hash == NULL) { @@ -87,8 +85,6 @@ lnet_peer_tables_destroy(void) if (hash == NULL) /* not intialized */ break; - LASSERT(list_empty(&ptable->pt_deathrow)); - ptable->pt_hash = NULL; for (j = 0; j < LNET_PEER_HASH_SIZE; j++) LASSERT(list_empty(&hash[j])); @@ -103,25 +99,25 @@ lnet_peer_tables_destroy(void) static void lnet_peer_table_cleanup_locked(lnet_ni_t *ni, struct lnet_peer_table *ptable) { - int i; - lnet_peer_t *lp; - lnet_peer_t *tmp; + int i; + struct lnet_peer_ni *lp; + struct lnet_peer_ni *tmp; for (i = 0; i < LNET_PEER_HASH_SIZE; i++) { list_for_each_entry_safe(lp, tmp, &ptable->pt_hash[i], - lp_hashlist) { - if (ni != NULL && ni->ni_net != lp->lp_net) + lpni_hashlist) { + if (ni != NULL && ni->ni_net != lp->lpni_net) continue; - list_del_init(&lp->lp_hashlist); + list_del_init(&lp->lpni_hashlist); /* Lose hash table's ref */ ptable->pt_zombies++; - lnet_peer_decref_locked(lp); + lnet_peer_ni_decref_locked(lp); } } } static void -lnet_peer_table_deathrow_wait_locked(struct lnet_peer_table *ptable, +lnet_peer_table_finalize_wait_locked(struct lnet_peer_table *ptable, int cpt_locked) { int i; @@ -144,24 +140,24 @@ static void lnet_peer_table_del_rtrs_locked(lnet_ni_t *ni, struct lnet_peer_table *ptable, int cpt_locked) { - lnet_peer_t *lp; - lnet_peer_t *tmp; - lnet_nid_t lp_nid; - int i; + struct lnet_peer_ni *lp; + struct lnet_peer_ni *tmp; + lnet_nid_t lpni_nid; + int i; for (i = 0; i < LNET_PEER_HASH_SIZE; i++) { list_for_each_entry_safe(lp, tmp, &ptable->pt_hash[i], - lp_hashlist) { - if (ni->ni_net != lp->lp_net) + lpni_hashlist) { + if (ni->ni_net != lp->lpni_net) continue; - if (lp->lp_rtr_refcount == 0) + if (lp->lpni_rtr_refcount == 0) continue; - lp_nid = lp->lp_nid; + lpni_nid = lp->lpni_nid; lnet_net_unlock(cpt_locked); - lnet_del_route(LNET_NIDNET(LNET_NID_ANY), lp_nid); + lnet_del_route(LNET_NIDNET(LNET_NID_ANY), lpni_nid); lnet_net_lock(cpt_locked); } } @@ -170,113 +166,199 @@ lnet_peer_table_del_rtrs_locked(lnet_ni_t *ni, struct lnet_peer_table *ptable, void lnet_peer_tables_cleanup(lnet_ni_t *ni) { - int i; - struct lnet_peer_table *ptable; - lnet_peer_t *lp; - struct list_head deathrow; - - INIT_LIST_HEAD(&deathrow); + int i; + struct lnet_peer_table *ptable; LASSERT(the_lnet.ln_shutdown || ni != NULL); /* If just deleting the peers for a NI, get rid of any routes these * peers are gateways for. */ cfs_percpt_for_each(ptable, i, the_lnet.ln_peer_tables) { - lnet_net_lock(i); + lnet_net_lock(LNET_LOCK_EX); lnet_peer_table_del_rtrs_locked(ni, ptable, i); - lnet_net_unlock(i); + lnet_net_unlock(LNET_LOCK_EX); } - /* Start the process of moving the applicable peers to - * deathrow. */ + /* Start the cleanup process */ cfs_percpt_for_each(ptable, i, the_lnet.ln_peer_tables) { - lnet_net_lock(i); + lnet_net_lock(LNET_LOCK_EX); lnet_peer_table_cleanup_locked(ni, ptable); - lnet_net_unlock(i); + lnet_net_unlock(LNET_LOCK_EX); } - /* Cleanup all entries on deathrow. */ + /* Wait until all peers have been destroyed. */ cfs_percpt_for_each(ptable, i, the_lnet.ln_peer_tables) { - lnet_net_lock(i); - lnet_peer_table_deathrow_wait_locked(ptable, i); - list_splice_init(&ptable->pt_deathrow, &deathrow); - lnet_net_unlock(i); + lnet_net_lock(LNET_LOCK_EX); + lnet_peer_table_finalize_wait_locked(ptable, i); + lnet_net_unlock(LNET_LOCK_EX); } +} + +static struct lnet_peer_ni * +lnet_get_peer_ni_locked(struct lnet_peer_table *ptable, lnet_nid_t nid) +{ + struct list_head *peers; + struct lnet_peer_ni *lp; + + LASSERT(!the_lnet.ln_shutdown); - while (!list_empty(&deathrow)) { - lp = list_entry(deathrow.next, lnet_peer_t, lp_hashlist); - list_del(&lp->lp_hashlist); - LIBCFS_FREE(lp, sizeof(*lp)); + peers = &ptable->pt_hash[lnet_nid2peerhash(nid)]; + list_for_each_entry(lp, peers, lpni_hashlist) { + if (lp->lpni_nid == nid) { + lnet_peer_ni_addref_locked(lp); + return lp; + } } + + return NULL; } -void -lnet_destroy_peer_locked(lnet_peer_t *lp) +struct lnet_peer_ni * +lnet_find_peer_ni_locked(lnet_nid_t nid, int cpt) { + struct lnet_peer_ni *lpni; struct lnet_peer_table *ptable; - LASSERT(lp->lp_refcount == 0); - LASSERT(lp->lp_rtr_refcount == 0); - LASSERT(list_empty(&lp->lp_txq)); - LASSERT(list_empty(&lp->lp_hashlist)); - LASSERT(lp->lp_txqnob == 0); + ptable = the_lnet.ln_peer_tables[cpt]; + lpni = lnet_get_peer_ni_locked(ptable, nid); - ptable = the_lnet.ln_peer_tables[lp->lp_cpt]; - LASSERT(ptable->pt_number > 0); - ptable->pt_number--; + return lpni; +} - lp->lp_net = NULL; +static void +lnet_try_destroy_peer_hierarchy_locked(struct lnet_peer_ni *lpni) +{ + struct lnet_peer_net *peer_net; + struct lnet_peer *peer; - list_add(&lp->lp_hashlist, &ptable->pt_deathrow); - LASSERT(ptable->pt_zombies > 0); - ptable->pt_zombies--; + /* 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)); + } + } } -lnet_peer_t * -lnet_find_peer_locked(struct lnet_peer_table *ptable, lnet_nid_t nid) +static int +lnet_build_peer_hierarchy(struct lnet_peer_ni *lpni) { - struct list_head *peers; - lnet_peer_t *lp; + struct lnet_peer *peer; + struct lnet_peer_net *peer_net; + __u32 lpni_net = LNET_NIDNET(lpni->lpni_nid); - LASSERT(!the_lnet.ln_shutdown); + peer = NULL; + peer_net = NULL; - peers = &ptable->pt_hash[lnet_nid2peerhash(nid)]; - list_for_each_entry(lp, peers, lp_hashlist) { - if (lp->lp_nid == nid) { - lnet_peer_addref_locked(lp); - return lp; - } + LIBCFS_ALLOC(peer, sizeof(*peer)); + if (peer == NULL) + return -ENOMEM; + + LIBCFS_ALLOC(peer_net, sizeof(*peer_net)); + if (peer_net == NULL) { + LIBCFS_FREE(peer, sizeof(*peer)); + return -ENOMEM; } - return NULL; + INIT_LIST_HEAD(&peer->lp_on_lnet_peer_list); + INIT_LIST_HEAD(&peer->lp_peer_nets); + INIT_LIST_HEAD(&peer_net->lpn_on_peer_list); + INIT_LIST_HEAD(&peer_net->lpn_peer_nis); + + /* build the hierarchy */ + peer_net->lpn_net_id = lpni_net; + peer_net->lpn_peer = peer; + lpni->lpni_peer_net = peer_net; + peer->lp_primary_nid = lpni->lpni_nid; + list_add_tail(&peer_net->lpn_on_peer_list, &peer->lp_peer_nets); + list_add_tail(&lpni->lpni_on_peer_net_list, &peer_net->lpn_peer_nis); + list_add_tail(&peer->lp_on_lnet_peer_list, &the_lnet.ln_peers); + + return 0; +} + +void +lnet_destroy_peer_ni_locked(struct lnet_peer_ni *lpni) +{ + struct lnet_peer_table *ptable; + + LASSERT(atomic_read(&lpni->lpni_refcount) == 0); + LASSERT(lpni->lpni_rtr_refcount == 0); + LASSERT(list_empty(&lpni->lpni_txq)); + LASSERT(list_empty(&lpni->lpni_hashlist)); + LASSERT(lpni->lpni_txqnob == 0); + LASSERT(lpni->lpni_peer_net != NULL); + LASSERT(lpni->lpni_peer_net->lpn_peer != NULL); + + ptable = the_lnet.ln_peer_tables[lpni->lpni_cpt]; + LASSERT(ptable->pt_number > 0); + ptable->pt_number--; + + lpni->lpni_net = NULL; + + lnet_try_destroy_peer_hierarchy_locked(lpni); + + LIBCFS_FREE(lpni, sizeof(*lpni)); + + LASSERT(ptable->pt_zombies > 0); + ptable->pt_zombies--; } int -lnet_nid2peer_locked(lnet_peer_t **lpp, lnet_nid_t nid, int cpt) +lnet_nid2peerni_locked(struct lnet_peer_ni **lpnip, lnet_nid_t nid, int cpt) { struct lnet_peer_table *ptable; - lnet_peer_t *lp = NULL; - lnet_peer_t *lp2; + struct lnet_peer_ni *lpni = NULL; + struct lnet_peer_ni *lpni2; int cpt2; int rc = 0; - *lpp = NULL; + *lpnip = NULL; if (the_lnet.ln_shutdown) /* it's shutting down */ return -ESHUTDOWN; - /* cpt can be LNET_LOCK_EX if it's called from router functions */ - cpt2 = cpt != LNET_LOCK_EX ? cpt : lnet_cpt_of_nid_locked(nid, NULL); + /* + * calculate cpt2 with the standard hash function + * This cpt2 becomes the slot where we'll find or create the peer. + */ + cpt2 = lnet_nid_cpt_hash(nid, LNET_CPT_NUMBER); - ptable = the_lnet.ln_peer_tables[cpt2]; - lp = lnet_find_peer_locked(ptable, nid); - if (lp != NULL) { - *lpp = lp; - return 0; + /* + * Any changes to the peer tables happen under exclusive write + * lock. Any reads to the peer tables can be done via a standard + * CPT read lock. + */ + if (cpt != LNET_LOCK_EX) { + lnet_net_unlock(cpt); + lnet_net_lock(LNET_LOCK_EX); } - if (!list_empty(&ptable->pt_deathrow)) { - lp = list_entry(ptable->pt_deathrow.next, - lnet_peer_t, lp_hashlist); - list_del(&lp->lp_hashlist); + ptable = the_lnet.ln_peer_tables[cpt2]; + lpni = lnet_get_peer_ni_locked(ptable, nid); + if (lpni != NULL) { + *lpnip = lpni; + if (cpt != LNET_LOCK_EX) { + lnet_net_unlock(LNET_LOCK_EX); + lnet_net_lock(cpt); + } + return 0; } /* @@ -284,82 +366,88 @@ lnet_nid2peer_locked(lnet_peer_t **lpp, lnet_nid_t nid, int cpt) * and destroyed locks and peer-table before I finish the allocation */ ptable->pt_number++; - lnet_net_unlock(cpt); + lnet_net_unlock(LNET_LOCK_EX); - if (lp != NULL) - memset(lp, 0, sizeof(*lp)); - else - LIBCFS_CPT_ALLOC(lp, lnet_cpt_table(), cpt2, sizeof(*lp)); + LIBCFS_CPT_ALLOC(lpni, lnet_cpt_table(), cpt2, sizeof(*lpni)); - if (lp == NULL) { + if (lpni == NULL) { rc = -ENOMEM; lnet_net_lock(cpt); goto out; } - INIT_LIST_HEAD(&lp->lp_txq); - INIT_LIST_HEAD(&lp->lp_rtrq); - INIT_LIST_HEAD(&lp->lp_routes); - - lp->lp_notify = 0; - lp->lp_notifylnd = 0; - lp->lp_notifying = 0; - lp->lp_alive_count = 0; - lp->lp_timestamp = 0; - lp->lp_alive = !lnet_peers_start_down(); /* 1 bit!! */ - lp->lp_last_alive = cfs_time_current(); /* assumes alive */ - lp->lp_last_query = 0; /* haven't asked NI yet */ - lp->lp_ping_timestamp = 0; - lp->lp_ping_feats = LNET_PING_FEAT_INVAL; - lp->lp_nid = nid; - lp->lp_cpt = cpt2; - lp->lp_refcount = 2; /* 1 for caller; 1 for hash */ - lp->lp_rtr_refcount = 0; + INIT_LIST_HEAD(&lpni->lpni_txq); + INIT_LIST_HEAD(&lpni->lpni_rtrq); + INIT_LIST_HEAD(&lpni->lpni_routes); - lnet_net_lock(cpt); + 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 = cpt2; + atomic_set(&lpni->lpni_refcount, 2); /* 1 for caller; 1 for hash */ + + rc = lnet_build_peer_hierarchy(lpni); + if (rc != 0) + goto out; + + lnet_net_lock(LNET_LOCK_EX); if (the_lnet.ln_shutdown) { rc = -ESHUTDOWN; goto out; } - lp2 = lnet_find_peer_locked(ptable, nid); - if (lp2 != NULL) { - *lpp = lp2; + lpni2 = lnet_get_peer_ni_locked(ptable, nid); + if (lpni2 != NULL) { + *lpnip = lpni2; goto out; } - lp->lp_net = lnet_get_net_locked(LNET_NIDNET(lp->lp_nid)); - lp->lp_txcredits = - lp->lp_mintxcredits = lp->lp_net->net_tunables.lct_peer_tx_credits; - lp->lp_rtrcredits = - lp->lp_minrtrcredits = lnet_peer_buffer_credits(lp->lp_net); + lpni->lpni_net = lnet_get_net_locked(LNET_NIDNET(lpni->lpni_nid)); + lpni->lpni_txcredits = + lpni->lpni_mintxcredits = + lpni->lpni_net->net_tunables.lct_peer_tx_credits; + lpni->lpni_rtrcredits = + lpni->lpni_minrtrcredits = + lnet_peer_buffer_credits(lpni->lpni_net); - list_add_tail(&lp->lp_hashlist, - &ptable->pt_hash[lnet_nid2peerhash(nid)]); + list_add_tail(&lpni->lpni_hashlist, + &ptable->pt_hash[lnet_nid2peerhash(nid)]); ptable->pt_version++; - *lpp = lp; + *lpnip = lpni; + + if (cpt != LNET_LOCK_EX) { + lnet_net_unlock(LNET_LOCK_EX); + lnet_net_lock(cpt); + } return 0; out: - if (lp != NULL) - list_add(&lp->lp_hashlist, &ptable->pt_deathrow); + if (lpni != NULL) { + lnet_try_destroy_peer_hierarchy_locked(lpni); + LIBCFS_FREE(lpni, sizeof(*lpni)); + } ptable->pt_number--; + if (cpt != LNET_LOCK_EX) { + lnet_net_unlock(LNET_LOCK_EX); + lnet_net_lock(cpt); + } return rc; } void lnet_debug_peer(lnet_nid_t nid) { - char *aliveness = "NA"; - lnet_peer_t *lp; - int rc; - int cpt; + char *aliveness = "NA"; + struct lnet_peer_ni *lp; + int rc; + int cpt; cpt = lnet_cpt_of_nid(nid, NULL); lnet_net_lock(cpt); - rc = lnet_nid2peer_locked(&lp, nid, cpt); + rc = lnet_nid2peerni_locked(&lp, nid, cpt); if (rc != 0) { lnet_net_unlock(cpt); CDEBUG(D_WARNING, "No peer %s\n", libcfs_nid2str(nid)); @@ -367,15 +455,15 @@ lnet_debug_peer(lnet_nid_t nid) } if (lnet_isrouter(lp) || lnet_peer_aliveness_enabled(lp)) - aliveness = lp->lp_alive ? "up" : "down"; + aliveness = lp->lpni_alive ? "up" : "down"; CDEBUG(D_WARNING, "%-24s %4d %5s %5d %5d %5d %5d %5d %ld\n", - libcfs_nid2str(lp->lp_nid), lp->lp_refcount, - aliveness, lp->lp_net->net_tunables.lct_peer_tx_credits, - lp->lp_rtrcredits, lp->lp_minrtrcredits, - lp->lp_txcredits, lp->lp_mintxcredits, lp->lp_txqnob); + libcfs_nid2str(lp->lpni_nid), atomic_read(&lp->lpni_refcount), + aliveness, lp->lpni_net->net_tunables.lct_peer_tx_credits, + lp->lpni_rtrcredits, lp->lpni_minrtrcredits, + lp->lpni_txcredits, lp->lpni_mintxcredits, lp->lpni_txqnob); - lnet_peer_decref_locked(lp); + lnet_peer_ni_decref_locked(lp); lnet_net_unlock(cpt); } @@ -387,11 +475,11 @@ int lnet_get_peer_info(__u32 peer_index, __u64 *nid, __u32 *peer_rtr_credits, __u32 *peer_min_rtr_credits, __u32 *peer_tx_qnob) { - struct lnet_peer_table *peer_table; - lnet_peer_t *lp; - int j; - int lncpt; - bool found = false; + struct lnet_peer_table *peer_table; + struct lnet_peer_ni *lp; + int j; + int lncpt; + bool found = false; /* get the number of CPTs */ lncpt = cfs_percpt_number(the_lnet.ln_peer_tables); @@ -413,7 +501,7 @@ int lnet_get_peer_info(__u32 peer_index, __u64 *nid, for (j = 0; j < LNET_PEER_HASH_SIZE && !found; j++) { struct list_head *peers = &peer_table->pt_hash[j]; - list_for_each_entry(lp, peers, lp_hashlist) { + list_for_each_entry(lp, peers, lpni_hashlist) { if (peer_index-- > 0) continue; @@ -421,16 +509,16 @@ int lnet_get_peer_info(__u32 peer_index, __u64 *nid, if (lnet_isrouter(lp) || lnet_peer_aliveness_enabled(lp)) snprintf(aliveness, LNET_MAX_STR_LEN, - lp->lp_alive ? "up" : "down"); + lp->lpni_alive ? "up" : "down"); - *nid = lp->lp_nid; - *refcount = lp->lp_refcount; + *nid = lp->lpni_nid; + *refcount = atomic_read(&lp->lpni_refcount); *ni_peer_tx_credits = - lp->lp_net->net_tunables.lct_peer_tx_credits; - *peer_tx_credits = lp->lp_txcredits; - *peer_rtr_credits = lp->lp_rtrcredits; - *peer_min_rtr_credits = lp->lp_mintxcredits; - *peer_tx_qnob = lp->lp_txqnob; + lp->lpni_net->net_tunables.lct_peer_tx_credits; + *peer_tx_credits = lp->lpni_txcredits; + *peer_rtr_credits = lp->lpni_rtrcredits; + *peer_min_rtr_credits = lp->lpni_mintxcredits; + *peer_tx_qnob = lp->lpni_txqnob; found = true; }