From 3211f6862cbbe96642db540e6593f3c614f9528c Mon Sep 17 00:00:00 2001 From: Liang Zhen Date: Sun, 27 May 2012 17:34:00 +0800 Subject: [PATCH] LU-56 lnet: new internal object lnet_peer_table Instead of attaching all peers under the big global data of LNet, we created lnet_peer_table which is just a simple container of peers. We also made another small change in this patch, when the last refcount of a peer is released, the dead peer wouldn't be released anymore, instead it will be attached on deathrow list of peer-table and released while destroying the peer-table. Peers on deathrow list can be re-used if we need create a new peer. Both changes in this patch are just preparations for other LNet SMP improvements. For example, we will create instances of lnet_peer_table for each CPT in following patches. Signed-off-by: Liang Zhen Change-Id: I60e6f2e564f9ab9c86278c9a08e24aaac114e89c Reviewed-on: http://review.whamcloud.com/2923 Reviewed-by: Bobi Jam Reviewed-by: Doug Oucharek Tested-by: Hudson Tested-by: Maloo Reviewed-by: Oleg Drokin --- lnet/include/lnet/lib-lnet.h | 14 ++- lnet/include/lnet/lib-types.h | 18 +++- lnet/lnet/api-ni.c | 8 +- lnet/lnet/peer.c | 220 ++++++++++++++++++++++++++---------------- lnet/lnet/router_proc.c | 13 +-- 5 files changed, 168 insertions(+), 105 deletions(-) diff --git a/lnet/include/lnet/lib-lnet.h b/lnet/include/lnet/lib-lnet.h index 3f7489d..a3556e6 100644 --- a/lnet/include/lnet/lib-lnet.h +++ b/lnet/include/lnet/lib-lnet.h @@ -611,12 +611,10 @@ lnet_ni_decref(lnet_ni_t *ni) LNET_UNLOCK(); } -static inline cfs_list_t * -lnet_nid2peerhash (lnet_nid_t nid) +static inline int +lnet_nid2peerhash(lnet_nid_t nid) { - unsigned int idx = LNET_NIDADDR(nid) % LNET_PEER_HASHSIZE; - - return &the_lnet.ln_peer_hash[idx]; + return cfs_hash_long(nid, LNET_PEER_HASH_BITS); } extern lnd_t the_lolnd; @@ -819,9 +817,9 @@ int lnet_parse_networks (cfs_list_t *nilist, char *networks); int lnet_nid2peer_locked(lnet_peer_t **lpp, lnet_nid_t nid); lnet_peer_t *lnet_find_peer_locked (lnet_nid_t nid); -void lnet_clear_peer_table(void); -void lnet_destroy_peer_table(void); -int lnet_create_peer_table(void); +void lnet_peer_table_cleanup(void); +void lnet_peer_table_destroy(void); +int lnet_peer_table_create(void); void lnet_debug_peer(lnet_nid_t nid); #ifndef __KERNEL__ diff --git a/lnet/include/lnet/lib-types.h b/lnet/include/lnet/lib-types.h index 58c916e..c56df4a 100644 --- a/lnet/include/lnet/lib-types.h +++ b/lnet/include/lnet/lib-types.h @@ -454,6 +454,19 @@ typedef struct lnet_peer { lnet_rc_data_t *lp_rcd; /* router checker state */ } lnet_peer_t; + +/* peer hash size */ +#define LNET_PEER_HASH_BITS 9 +#define LNET_PEER_HASH_SIZE (1 << LNET_PEER_HASH_BITS) + +/* peer hash table */ +struct lnet_peer_table { + int pt_version; /* /proc validity stamp */ + int pt_number; /* # peers extant */ + cfs_list_t pt_deathrow; /* zombie peers */ + cfs_list_t *pt_hash; /* NID->peer hash */ +}; + #define lnet_peer_aliveness_enabled(lp) ((lp)->lp_ni->ni_peertimeout > 0) typedef struct { @@ -611,10 +624,6 @@ typedef struct cfs_list_t ln_routers; /* list of all known routers */ __u64 ln_routers_version; /* validity stamp */ - cfs_list_t *ln_peer_hash; /* NID->peer hash */ - int ln_npeers; /* # peers extant */ - int ln_peertable_version; /* /proc validity stamp */ - int ln_routing; /* am I a router? */ lnet_rtrbufpool_t ln_rtrpools[LNET_NRBPOOLS]; /* router buffer pools */ @@ -628,6 +637,7 @@ typedef struct cfs_list_t ln_test_peers; /* failure simulation */ /* message container */ + struct lnet_peer_table *ln_peer_table; struct lnet_msg_container ln_msg_container; lnet_handle_md_t ln_ping_target_md; diff --git a/lnet/lnet/api-ni.c b/lnet/lnet/api-ni.c index 1829896..a84e867 100644 --- a/lnet/lnet/api-ni.c +++ b/lnet/lnet/api-ni.c @@ -644,7 +644,7 @@ lnet_prepare(lnet_pid_t requested_pid) lnet_init_rtrpools(); - rc = lnet_create_peer_table(); + rc = lnet_peer_table_create(); if (rc != 0) goto failed0; @@ -705,7 +705,7 @@ lnet_prepare(lnet_pid_t requested_pid) failed2: lnet_msg_container_cleanup(&the_lnet.ln_msg_container); failed1: - lnet_destroy_peer_table(); + lnet_peer_table_destroy(); failed0: return rc; } @@ -756,7 +756,7 @@ lnet_unprepare (void) lnet_free_rtrpools(); lnet_msg_container_cleanup(&the_lnet.ln_msg_container); - lnet_destroy_peer_table(); + lnet_peer_table_destroy(); return 0; } @@ -898,7 +898,7 @@ lnet_shutdown_lndnis (void) /* Clear the peer table and wait for all peers to go (they hold refs on * their NIs) */ - lnet_clear_peer_table(); + lnet_peer_table_cleanup(); LNET_LOCK(); /* Now wait for the NI's I just nuked to show up on ln_zombie_nis diff --git a/lnet/lnet/peer.c b/lnet/lnet/peer.c index 2d38c5e..51123f0 100644 --- a/lnet/lnet/peer.c +++ b/lnet/lnet/peer.c @@ -39,116 +39,161 @@ #include int -lnet_create_peer_table(void) +lnet_peer_table_create(void) { - cfs_list_t *hash; - int i; + struct lnet_peer_table *ptable; + cfs_list_t *hash; + int j; - LASSERT (the_lnet.ln_peer_hash == NULL); - LIBCFS_ALLOC(hash, LNET_PEER_HASHSIZE * sizeof(cfs_list_t)); - - if (hash == NULL) { - CERROR("Can't allocate peer hash table\n"); + LIBCFS_ALLOC(ptable, sizeof(*ptable)); + if (ptable == NULL) { + CERROR("Failed to allocate cpu-partition peer tables\n"); return -ENOMEM; } - for (i = 0; i < LNET_PEER_HASHSIZE; i++) - CFS_INIT_LIST_HEAD(&hash[i]); + the_lnet.ln_peer_table = ptable; + + do { /* we will have per CPT peer-tables iterate them by then */ + CFS_INIT_LIST_HEAD(&ptable->pt_deathrow); + + LIBCFS_ALLOC(hash, LNET_PEER_HASH_SIZE * sizeof(*hash)); + if (hash == NULL) { + CERROR("Failed to create peer hash table\n"); + lnet_peer_table_destroy(); + return -ENOMEM; + } + + for (j = 0; j < LNET_PEER_HASH_SIZE; j++) + CFS_INIT_LIST_HEAD(&hash[j]); + ptable->pt_hash = hash; /* sign of initialization */ + } while (0); - the_lnet.ln_peer_hash = hash; return 0; } void -lnet_destroy_peer_table(void) +lnet_peer_table_destroy(void) { - int i; + struct lnet_peer_table *ptable; + cfs_list_t *hash; + int j; - if (the_lnet.ln_peer_hash == NULL) - return; + if (the_lnet.ln_peer_table == NULL) + return; - for (i = 0; i < LNET_PEER_HASHSIZE; i++) - LASSERT (cfs_list_empty(&the_lnet.ln_peer_hash[i])); + ptable = the_lnet.ln_peer_table; - LIBCFS_FREE(the_lnet.ln_peer_hash, - LNET_PEER_HASHSIZE * sizeof (cfs_list_t)); - the_lnet.ln_peer_hash = NULL; + do { /* we will have per CPT peer-tables iterate them by then */ + hash = ptable->pt_hash; + if (hash == NULL) /* not intialized */ + break; + + LASSERT(cfs_list_empty(&ptable->pt_deathrow)); + + ptable->pt_hash = NULL; + for (j = 0; j < LNET_PEER_HASH_SIZE; j++) + LASSERT(cfs_list_empty(&hash[j])); + + LIBCFS_FREE(hash, LNET_PEER_HASH_SIZE * sizeof(*hash)); + } while (0); + + LIBCFS_FREE(ptable, sizeof(*ptable)); + the_lnet.ln_peer_table = NULL; } void -lnet_clear_peer_table(void) +lnet_peer_table_cleanup(void) { - int i; - - LASSERT (the_lnet.ln_shutdown); /* i.e. no new peers */ + struct lnet_peer_table *ptable; + int j; - for (i = 0; i < LNET_PEER_HASHSIZE; i++) { - cfs_list_t *peers = &the_lnet.ln_peer_hash[i]; + LASSERT(the_lnet.ln_shutdown); /* i.e. no new peers */ + ptable = the_lnet.ln_peer_table; + do { /* we will have per CPT peer-tables iterate them by then */ LNET_LOCK(); - while (!cfs_list_empty(peers)) { - lnet_peer_t *lp = cfs_list_entry(peers->next, - lnet_peer_t, - lp_hashlist); - cfs_list_del(&lp->lp_hashlist); - lnet_peer_decref_locked(lp); /* lose hash table's ref */ + for (j = 0; j < LNET_PEER_HASH_SIZE; j++) { + cfs_list_t *peers = &ptable->pt_hash[j]; + + while (!cfs_list_empty(peers)) { + lnet_peer_t *lp = cfs_list_entry(peers->next, + lnet_peer_t, + lp_hashlist); + cfs_list_del_init(&lp->lp_hashlist); + /* lose hash table's ref */ + lnet_peer_decref_locked(lp); + } } + LNET_UNLOCK(); - } + } while (0); - LNET_LOCK(); - for (i = 3; the_lnet.ln_npeers != 0;i++) { - LNET_UNLOCK(); + do { /* we will have per CPT peer-tables iterate them by then */ + CFS_LIST_HEAD (deathrow); + lnet_peer_t *lp; - if ((i & (i-1)) == 0) - CDEBUG(D_WARNING,"Waiting for %d peers\n", - the_lnet.ln_npeers); - cfs_pause(cfs_time_seconds(1)); + LNET_LOCK(); - LNET_LOCK(); - } - LNET_UNLOCK(); + for (j = 3; ptable->pt_number != 0; j++) { + LNET_UNLOCK(); + + if ((j & (j - 1)) == 0) { + CDEBUG(D_WARNING, + "Waiting for %d peers on peer table\n", + ptable->pt_number); + } + cfs_pause(cfs_time_seconds(1) / 2); + LNET_LOCK(); + } + cfs_list_splice_init(&ptable->pt_deathrow, &deathrow); + + LNET_UNLOCK(); + + while (!cfs_list_empty(&deathrow)) { + lp = cfs_list_entry(deathrow.next, + lnet_peer_t, lp_hashlist); + cfs_list_del(&lp->lp_hashlist); + LIBCFS_FREE(lp, sizeof(*lp)); + } + } while (0); } void -lnet_destroy_peer_locked (lnet_peer_t *lp) +lnet_destroy_peer_locked(lnet_peer_t *lp) { - lnet_ni_decref_locked(lp->lp_ni); - LNET_UNLOCK(); + struct lnet_peer_table *ptable = the_lnet.ln_peer_table; - LASSERT (lp->lp_refcount == 0); - LASSERT (lp->lp_rtr_refcount == 0); - LASSERT (cfs_list_empty(&lp->lp_txq)); - LASSERT (lp->lp_txqnob == 0); - LASSERT (lp->lp_rcd == NULL); + LASSERT(lp->lp_refcount == 0); + LASSERT(lp->lp_rtr_refcount == 0); + LASSERT(cfs_list_empty(&lp->lp_txq)); + LASSERT(cfs_list_empty(&lp->lp_hashlist)); + LASSERT(lp->lp_txqnob == 0); - LIBCFS_FREE(lp, sizeof(*lp)); + LASSERT(ptable->pt_number > 0); + ptable->pt_number--; - LNET_LOCK(); + lnet_ni_decref_locked(lp->lp_ni); + lp->lp_ni = NULL; - LASSERT(the_lnet.ln_npeers > 0); - the_lnet.ln_npeers--; + cfs_list_add(&lp->lp_hashlist, &ptable->pt_deathrow); } lnet_peer_t * -lnet_find_peer_locked (lnet_nid_t nid) +lnet_find_peer_locked(lnet_nid_t nid) { - unsigned int idx = LNET_NIDADDR(nid) % LNET_PEER_HASHSIZE; - cfs_list_t *peers = &the_lnet.ln_peer_hash[idx]; - cfs_list_t *tmp; - lnet_peer_t *lp; + cfs_list_t *peers; + lnet_peer_t *lp; if (the_lnet.ln_shutdown) - return NULL; - - cfs_list_for_each (tmp, peers) { - lp = cfs_list_entry(tmp, lnet_peer_t, lp_hashlist); + return NULL; + peers = &the_lnet.ln_peer_table->pt_hash[lnet_nid2peerhash(nid)]; + cfs_list_for_each_entry(lp, peers, lp_hashlist) { if (lp->lp_nid == nid) { - lnet_peer_addref_locked(lp); + lnet_peer_addref_locked(lp); return lp; - } + } } return NULL; @@ -157,18 +202,29 @@ lnet_find_peer_locked (lnet_nid_t nid) int lnet_nid2peer_locked(lnet_peer_t **lpp, lnet_nid_t nid) { - lnet_peer_t *lp; - lnet_peer_t *lp2; + struct lnet_peer_table *ptable = the_lnet.ln_peer_table; + lnet_peer_t *lp = NULL; + lnet_peer_t *lp2; lp = lnet_find_peer_locked(nid); if (lp != NULL) { *lpp = lp; return 0; } - - LNET_UNLOCK(); - - LIBCFS_ALLOC(lp, sizeof(*lp)); + + if (!cfs_list_empty(&ptable->pt_deathrow)) { + lp = cfs_list_entry(ptable->pt_deathrow.next, + lnet_peer_t, lp_hashlist); + cfs_list_del(&lp->lp_hashlist); + } + + LNET_UNLOCK(); + + if (lp != NULL) + memset(lp, 0, sizeof(*lp)); + else + LIBCFS_ALLOC(lp, sizeof(*lp)); + if (lp == NULL) { *lpp = NULL; LNET_LOCK(); @@ -197,9 +253,7 @@ lnet_nid2peer_locked(lnet_peer_t **lpp, lnet_nid_t nid) lp2 = lnet_find_peer_locked(nid); if (lp2 != NULL) { - LNET_UNLOCK(); - LIBCFS_FREE(lp, sizeof(*lp)); - LNET_LOCK(); + cfs_list_add(&lp->lp_hashlist, &ptable->pt_deathrow); if (the_lnet.ln_shutdown) { lnet_peer_decref_locked(lp2); @@ -213,9 +267,7 @@ lnet_nid2peer_locked(lnet_peer_t **lpp, lnet_nid_t nid) lp->lp_ni = lnet_net2ni_locked(LNET_NIDNET(nid)); if (lp->lp_ni == NULL) { - LNET_UNLOCK(); - LIBCFS_FREE(lp, sizeof(*lp)); - LNET_LOCK(); + cfs_list_add(&lp->lp_hashlist, &ptable->pt_deathrow); *lpp = NULL; return the_lnet.ln_shutdown ? -ESHUTDOWN : -EHOSTUNREACH; @@ -229,11 +281,13 @@ lnet_nid2peer_locked(lnet_peer_t **lpp, lnet_nid_t nid) /* can't add peers after shutdown starts */ LASSERT (!the_lnet.ln_shutdown); - cfs_list_add_tail(&lp->lp_hashlist, lnet_nid2peerhash(nid)); - the_lnet.ln_npeers++; - the_lnet.ln_peertable_version++; - *lpp = lp; - return 0; + cfs_list_add_tail(&lp->lp_hashlist, + &ptable->pt_hash[lnet_nid2peerhash(nid)]); + ptable->pt_version++; + ptable->pt_number++; + + *lpp = lp; + return 0; } void diff --git a/lnet/lnet/router_proc.c b/lnet/lnet/router_proc.c index e1c5055..258936f 100644 --- a/lnet/lnet/router_proc.c +++ b/lnet/lnet/router_proc.c @@ -378,6 +378,7 @@ int LL_PROC_PROTO(proc_lnet_routers) int LL_PROC_PROTO(proc_lnet_peers) { + struct lnet_peer_table *ptable = the_lnet.ln_peer_table; int rc = 0; char *tmpstr; char *s; @@ -414,7 +415,7 @@ int LL_PROC_PROTO(proc_lnet_peers) LASSERT (tmpstr + tmpsiz - s > 0); LNET_LOCK(); - ver = (unsigned int)the_lnet.ln_peertable_version; + ver = (unsigned int)ptable->pt_version; LNET_UNLOCK(); *ppos = LNET_PHASH_POS_MAKE(ver, idx, num); @@ -426,7 +427,7 @@ int LL_PROC_PROTO(proc_lnet_peers) LNET_LOCK(); - if (ver != LNET_VERSION_VALID_MASK(the_lnet.ln_peertable_version)) { + if (ver != LNET_VERSION_VALID_MASK(ptable->pt_version)) { LNET_UNLOCK(); LIBCFS_FREE(tmpstr, tmpsiz); return -ESTALE; @@ -434,9 +435,9 @@ int LL_PROC_PROTO(proc_lnet_peers) while (idx < LNET_PEER_HASHSIZE) { if (p == NULL) - p = the_lnet.ln_peer_hash[idx].next; + p = ptable->pt_hash[idx].next; - while (p != &the_lnet.ln_peer_hash[idx]) { + while (p != &ptable->pt_hash[idx]) { lnet_peer_t *lp = cfs_list_entry(p, lnet_peer_t, lp_hashlist); if (skip == 0) { @@ -445,8 +446,8 @@ int LL_PROC_PROTO(proc_lnet_peers) /* minor optimization: start from idx+1 * on next iteration if we've just * drained lp_hashlist */ - if (lp->lp_hashlist.next == - &the_lnet.ln_peer_hash[idx]) { + if (lp->lp_hashlist.next == + &ptable->pt_hash[idx]) { num = 1; idx++; } else { -- 1.8.3.1