Whamcloud - gitweb
LU-56 lnet: new internal object lnet_peer_table
authorLiang Zhen <liang@whamcloud.com>
Sun, 27 May 2012 09:34:00 +0000 (17:34 +0800)
committerOleg Drokin <green@whamcloud.com>
Mon, 11 Jun 2012 13:06:19 +0000 (09:06 -0400)
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 <liang@whamcloud.com>
Change-Id: I60e6f2e564f9ab9c86278c9a08e24aaac114e89c
Reviewed-on: http://review.whamcloud.com/2923
Reviewed-by: Bobi Jam <bobijam@whamcloud.com>
Reviewed-by: Doug Oucharek <doug@whamcloud.com>
Tested-by: Hudson
Tested-by: Maloo <whamcloud.maloo@gmail.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
lnet/include/lnet/lib-lnet.h
lnet/include/lnet/lib-types.h
lnet/lnet/api-ni.c
lnet/lnet/peer.c
lnet/lnet/router_proc.c

index 3f7489d..a3556e6 100644 (file)
@@ -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__
index 58c916e..c56df4a 100644 (file)
@@ -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;
index 1829896..a84e867 100644 (file)
@@ -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
index 2d38c5e..51123f0 100644 (file)
 #include <lnet/lib-lnet.h>
 
 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
index e1c5055..258936f 100644 (file)
@@ -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 {