Whamcloud - gitweb
LU-9480 lnet: add "lnetctl peer list" 90/25790/26
authorOlaf Weber <olaf@sgi.com>
Fri, 27 Jan 2017 15:36:47 +0000 (16:36 +0100)
committerAmir Shehata <amir.shehata@intel.com>
Tue, 22 Aug 2017 16:27:02 +0000 (16:27 +0000)
Add IOC_LIBCFS_GET_PEER_LIST to obtain a list of the primary
NIDs of all peers known to the system. The list is written
into a userspace buffer by the kernel. The typical usage is
to make a first call to determine the required buffer size,
then a second call to obtain the list.

Extend the "lnetctl peer" set of commands with a "list"
subcommand that uses this interface.

Modify the IOC_LIBCFS_GET_PEER_NI ioctl (which is new in the
Multi-Rail code) to use a NID to indicate the peer to look
up, and then pass out the data for all NIDs of that peer.

Re-implement "lnetctl peer show" to obtain the list of NIDs
using IOC_LIBCFS_GET_PEER_LIST followed by one or more
IOC_LIBCFS_GET_PEER_NI calls to get information for each
peer.

Make sure to copy the structure from kernel space to
user space even if the ioctl handler returns an error.
This is needed because if the buffer passed in by the
user space is not big enough to copy the data, we want
to pass the requested size to user space in the structure
passed in. The return code in this case is -E2BIG.

Test-Parameters: trivial
Signed-off-by: Olaf Weber <olaf@sgi.com>
Change-Id: I522c11e6ec09bec46121496d526bb258e10295f1
Reviewed-on: https://review.whamcloud.com/25790
Reviewed-by: Amir Shehata <amir.shehata@intel.com>
Tested-by: Amir Shehata <amir.shehata@intel.com>
libcfs/libcfs/module.c
lnet/include/lnet/lib-lnet.h
lnet/include/lnet/lib-types.h
lnet/include/uapi/linux/lnet/libcfs_ioctl.h
lnet/lnet/api-ni.c
lnet/lnet/peer.c
lnet/utils/lnetconfig/liblnetconfig.c
lnet/utils/lnetconfig/liblnetconfig.h
lnet/utils/lnetctl.c

index 2018789..6ec93f4 100644 (file)
@@ -140,10 +140,8 @@ int libcfs_ioctl(unsigned long cmd, void __user *uparam)
                        if (err == -EINVAL)
                                continue;
 
-                       if (err == 0) {
-                               if (copy_to_user(uparam, hdr, hdr->ioc_len))
-                                       err = -EFAULT;
-                       }
+                       if (copy_to_user(uparam, hdr, hdr->ioc_len))
+                               err = -EFAULT;
                        break;
                }
                up_read(&ioctl_list_sem);
index 2a21c1b..4f04751 100644 (file)
@@ -567,6 +567,8 @@ extern int libcfs_register_ioctl(struct libcfs_ioctl_handler *hand);
 extern int libcfs_deregister_ioctl(struct libcfs_ioctl_handler *hand);
 extern int libcfs_ioctl_getdata(struct libcfs_ioctl_hdr **hdr_pp,
                                struct libcfs_ioctl_hdr __user *uparam);
+extern int lnet_get_peer_list(__u32 *countp, __u32 *sizep,
+                             lnet_process_id_t __user *ids);
 
 void lnet_proc_init(void);
 void lnet_proc_fini(void);
@@ -885,10 +887,9 @@ bool lnet_peer_is_pref_nid_locked(struct lnet_peer_ni *lpni, lnet_nid_t nid);
 int lnet_peer_ni_set_non_mr_pref_nid(struct lnet_peer_ni *lpni, lnet_nid_t nid);
 int lnet_add_peer_ni(lnet_nid_t key_nid, lnet_nid_t nid, bool mr);
 int lnet_del_peer_ni(lnet_nid_t key_nid, lnet_nid_t nid);
-int lnet_get_peer_info(__u32 idx, lnet_nid_t *primary_nid, lnet_nid_t *nid,
-                      bool *mr,
-                      struct lnet_peer_ni_credit_info __user *peer_ni_info,
-                      struct lnet_ioctl_element_stats __user *peer_ni_stats);
+int lnet_get_peer_info(lnet_nid_t *primary_nid, lnet_nid_t *nid,
+                      __u32 *nnis, bool *mr, __u32 *sizep,
+                      void __user *bulk);
 int lnet_get_peer_ni_info(__u32 peer_index, __u64 *nid,
                          char alivness[LNET_MAX_STR_LEN],
                          __u32 *cpt_iter, __u32 *refcount,
index fef10de..e4cf950 100644 (file)
@@ -674,7 +674,6 @@ struct lnet_peer_net {
  *    pt_hash[...]
  *    pt_peer_list
  *    pt_peers
- *    pt_peer_nnids
  * protected by pt_zombie_lock:
  *    pt_zombie_list
  *    pt_zombies
@@ -687,7 +686,6 @@ struct lnet_peer_table {
        struct list_head        *pt_hash;       /* NID->peer hash */
        struct list_head        pt_peer_list;   /* peers */
        int                     pt_peers;       /* # peers */
-       int                     pt_peer_nnids;  /* # NIDS on listed peers */
        struct list_head        pt_zombie_list; /* zombie peer_ni */
        int                     pt_zombies;     /* # zombie peers_ni */
        spinlock_t              pt_zombie_lock; /* protect list and count */
index da490f1..95b080d 100644 (file)
@@ -145,7 +145,8 @@ struct libcfs_debug_ioctl_data {
 #define IOC_LIBCFS_GET_LOCAL_NI                   _IOWR(IOC_LIBCFS_TYPE, 97, IOCTL_CONFIG_SIZE)
 #define IOC_LIBCFS_SET_NUMA_RANGE         _IOWR(IOC_LIBCFS_TYPE, 98, IOCTL_CONFIG_SIZE)
 #define IOC_LIBCFS_GET_NUMA_RANGE         _IOWR(IOC_LIBCFS_TYPE, 99, IOCTL_CONFIG_SIZE)
-#define IOC_LIBCFS_MAX_NR                                        99
+#define IOC_LIBCFS_GET_PEER_LIST          _IOWR(IOC_LIBCFS_TYPE, 100, IOCTL_CONFIG_SIZE)
+#define IOC_LIBCFS_MAX_NR                                        100
 
 extern int libcfs_ioctl_data_adjust(struct libcfs_ioctl_data *data);
 
index 5c1de39..16d9517 100644 (file)
@@ -3189,21 +3189,30 @@ LNetCtl(unsigned int cmd, void *arg)
 
        case IOC_LIBCFS_GET_PEER_NI: {
                struct lnet_ioctl_peer_cfg *cfg = arg;
-               struct lnet_peer_ni_credit_info __user *lpni_cri;
-               struct lnet_ioctl_element_stats __user *lpni_stats;
-               size_t usr_size = sizeof(*lpni_cri) + sizeof(*lpni_stats);
 
-               if ((cfg->prcfg_hdr.ioc_len != sizeof(*cfg)) ||
-                   (cfg->prcfg_size != usr_size))
+               if (cfg->prcfg_hdr.ioc_len < sizeof(*cfg))
                        return -EINVAL;
 
-               lpni_cri = cfg->prcfg_bulk;
-               lpni_stats = cfg->prcfg_bulk + sizeof(*lpni_cri);
+               mutex_lock(&the_lnet.ln_api_mutex);
+               rc = lnet_get_peer_info(&cfg->prcfg_prim_nid,
+                                       &cfg->prcfg_cfg_nid,
+                                       &cfg->prcfg_count,
+                                       &cfg->prcfg_mr,
+                                       &cfg->prcfg_size,
+                                       (void __user *)cfg->prcfg_bulk);
+               mutex_unlock(&the_lnet.ln_api_mutex);
+               return rc;
+       }
+
+       case IOC_LIBCFS_GET_PEER_LIST: {
+               struct lnet_ioctl_peer_cfg *cfg = arg;
+
+               if (cfg->prcfg_hdr.ioc_len < sizeof(*cfg))
+                       return -EINVAL;
 
                mutex_lock(&the_lnet.ln_api_mutex);
-               rc = lnet_get_peer_info(cfg->prcfg_count, &cfg->prcfg_prim_nid,
-                                       &cfg->prcfg_cfg_nid, &cfg->prcfg_mr,
-                                       lpni_cri, lpni_stats);
+               rc = lnet_get_peer_list(&cfg->prcfg_count, &cfg->prcfg_size,
+                               (lnet_process_id_t __user *)cfg->prcfg_bulk);
                mutex_unlock(&the_lnet.ln_api_mutex);
                return rc;
        }
index 6de4eb0..2af27a1 100644 (file)
@@ -299,9 +299,7 @@ lnet_peer_detach_peer_ni_locked(struct lnet_peer_ni *lpni)
 
        /* Update peer NID count. */
        lp = lpn->lpn_peer;
-       ptable = the_lnet.ln_peer_tables[lp->lp_cpt];
        lp->lp_nnis--;
-       ptable->pt_peer_nnids--;
 
        /*
         * If there are no more peer nets, make the peer unfindable
@@ -313,6 +311,7 @@ lnet_peer_detach_peer_ni_locked(struct lnet_peer_ni *lpni)
         */
        if (list_empty(&lp->lp_peer_nets)) {
                list_del_init(&lp->lp_peer_list);
+               ptable = the_lnet.ln_peer_tables[lp->lp_cpt];
                ptable->pt_peers--;
        } else if (the_lnet.ln_dc_state != LNET_DC_STATE_RUNNING) {
                /* Discovery isn't running, nothing to do here. */
@@ -634,44 +633,6 @@ lnet_find_peer(lnet_nid_t nid)
 }
 
 struct lnet_peer_ni *
-lnet_get_peer_ni_idx_locked(int idx, struct lnet_peer_net **lpn,
-                           struct lnet_peer **lp)
-{
-       struct lnet_peer_table  *ptable;
-       struct lnet_peer_ni     *lpni;
-       int                     lncpt;
-       int                     cpt;
-
-       lncpt = cfs_percpt_number(the_lnet.ln_peer_tables);
-
-       for (cpt = 0; cpt < lncpt; cpt++) {
-               ptable = the_lnet.ln_peer_tables[cpt];
-               if (ptable->pt_peer_nnids > idx)
-                       break;
-               idx -= ptable->pt_peer_nnids;
-       }
-       if (cpt >= lncpt)
-               return NULL;
-
-       list_for_each_entry((*lp), &ptable->pt_peer_list, lp_peer_list) {
-               if ((*lp)->lp_nnis <= idx) {
-                       idx -= (*lp)->lp_nnis;
-                       continue;
-               }
-               list_for_each_entry((*lpn), &((*lp)->lp_peer_nets),
-                                   lpn_peer_nets) {
-                       list_for_each_entry(lpni, &((*lpn)->lpn_peer_nis),
-                                           lpni_peer_nis) {
-                               if (idx-- == 0)
-                                       return lpni;
-                       }
-               }
-       }
-
-       return NULL;
-}
-
-struct lnet_peer_ni *
 lnet_get_next_peer_ni_locked(struct lnet_peer *peer,
                             struct lnet_peer_net *peer_net,
                             struct lnet_peer_ni *prev)
@@ -730,6 +691,68 @@ lnet_get_next_peer_ni_locked(struct lnet_peer *peer,
        return lpni;
 }
 
+/* Call with the ln_api_mutex held */
+int
+lnet_get_peer_list(__u32 *countp, __u32 *sizep, lnet_process_id_t __user *ids)
+{
+       lnet_process_id_t id;
+       struct lnet_peer_table *ptable;
+       struct lnet_peer *lp;
+       __u32 count = 0;
+       __u32 size = 0;
+       int lncpt;
+       int cpt;
+       __u32 i;
+       int rc;
+
+       rc = -ESHUTDOWN;
+       if (the_lnet.ln_state != LNET_STATE_RUNNING)
+               goto done;
+
+       lncpt = cfs_percpt_number(the_lnet.ln_peer_tables);
+
+       /*
+        * Count the number of peers, and return E2BIG if the buffer
+        * is too small. We'll also return the desired size.
+        */
+       rc = -E2BIG;
+       for (cpt = 0; cpt < lncpt; cpt++) {
+               ptable = the_lnet.ln_peer_tables[cpt];
+               count += ptable->pt_peers;
+       }
+       size = count * sizeof(*ids);
+       if (size > *sizep)
+               goto done;
+
+       /*
+        * Walk the peer lists and copy out the primary nids.
+        * This is safe because the peer lists are only modified
+        * while the ln_api_mutex is held. So we don't need to
+        * hold the lnet_net_lock as well, and can therefore
+        * directly call copy_to_user().
+        */
+       rc = -EFAULT;
+       memset(&id, 0, sizeof(id));
+       id.pid = LNET_PID_LUSTRE;
+       i = 0;
+       for (cpt = 0; cpt < lncpt; cpt++) {
+               ptable = the_lnet.ln_peer_tables[cpt];
+               list_for_each_entry(lp, &ptable->pt_peer_list, lp_peer_list) {
+                       if (i >= count)
+                               goto done;
+                       id.nid = lp->lp_primary_nid;
+                       if (copy_to_user(&ids[i], &id, sizeof(id)))
+                               goto done;
+                       i++;
+               }
+       }
+       rc = 0;
+done:
+       *countp = count;
+       *sizep = size;
+       return rc;
+}
+
 /*
  * Start pushes to peers that need to be updated for a configuration
  * change on this node.
@@ -1130,7 +1153,6 @@ lnet_peer_attach_peer_ni(struct lnet_peer *lp,
        spin_unlock(&lp->lp_lock);
 
        lp->lp_nnis++;
-       the_lnet.ln_peer_tables[lp->lp_cpt]->pt_peer_nnids++;
        lnet_net_unlock(LNET_LOCK_EX);
 
        CDEBUG(D_NET, "peer %s NID %s flags %#x\n",
@@ -3277,56 +3299,94 @@ int lnet_get_peer_ni_info(__u32 peer_index, __u64 *nid,
 }
 
 /* ln_api_mutex is held, which keeps the peer list stable */
-int lnet_get_peer_info(__u32 idx, lnet_nid_t *primary_nid, lnet_nid_t *nid,
-                      bool *mr,
-                      struct lnet_peer_ni_credit_info __user *peer_ni_info,
-                      struct lnet_ioctl_element_stats __user *peer_ni_stats)
+int lnet_get_peer_info(lnet_nid_t *primary_nid, lnet_nid_t *nidp,
+                      __u32 *nnis, bool *mr, __u32 *sizep,
+                      void __user *bulk)
 {
-       struct lnet_peer_ni *lpni = NULL;
-       struct lnet_peer_net *lpn = NULL;
-       struct lnet_peer *lp = NULL;
-       struct lnet_peer_ni_credit_info ni_info;
-       struct lnet_ioctl_element_stats ni_stats;
+       struct lnet_ioctl_element_stats *lpni_stats;
+       struct lnet_peer_ni_credit_info *lpni_info;
+       struct lnet_peer_ni *lpni;
+       struct lnet_peer *lp;
+       lnet_nid_t nid;
+       __u32 size;
        int rc;
 
-       lpni = lnet_get_peer_ni_idx_locked(idx, &lpn, &lp);
+       lp = lnet_find_peer(*primary_nid);
 
-       if (!lpni)
-               return -ENOENT;
+       if (!lp) {
+               rc = -ENOENT;
+               goto out;
+       }
+
+       size = sizeof(nid) + sizeof(*lpni_info) + sizeof(*lpni_stats);
+       size *= lp->lp_nnis;
+       if (size > *sizep) {
+               *sizep = size;
+               rc = -E2BIG;
+               goto out_lp_decref;
+       }
 
        *primary_nid = lp->lp_primary_nid;
        *mr = lnet_peer_is_multi_rail(lp);
-       *nid = lpni->lpni_nid;
-       snprintf(ni_info.cr_aliveness, LNET_MAX_STR_LEN, "NA");
-       if (lnet_isrouter(lpni) ||
-               lnet_peer_aliveness_enabled(lpni))
-               snprintf(ni_info.cr_aliveness, LNET_MAX_STR_LEN,
-                        lpni->lpni_alive ? "up" : "down");
-
-       ni_info.cr_refcount = atomic_read(&lpni->lpni_refcount);
-       ni_info.cr_ni_peer_tx_credits = (lpni->lpni_net != NULL) ?
-               lpni->lpni_net->net_tunables.lct_peer_tx_credits : 0;
-       ni_info.cr_peer_tx_credits = lpni->lpni_txcredits;
-       ni_info.cr_peer_rtr_credits = lpni->lpni_rtrcredits;
-       ni_info.cr_peer_min_rtr_credits = lpni->lpni_minrtrcredits;
-       ni_info.cr_peer_min_tx_credits = lpni->lpni_mintxcredits;
-       ni_info.cr_peer_tx_qnob = lpni->lpni_txqnob;
-       ni_info.cr_ncpt = lpni->lpni_cpt;
-
-       ni_stats.iel_send_count = atomic_read(&lpni->lpni_stats.send_count);
-       ni_stats.iel_recv_count = atomic_read(&lpni->lpni_stats.recv_count);
-       ni_stats.iel_drop_count = atomic_read(&lpni->lpni_stats.drop_count);
-
-       /* If copy_to_user fails */
-       rc = -EFAULT;
-       if (copy_to_user(peer_ni_info, &ni_info, sizeof(ni_info)))
-               goto copy_failed;
+       *nidp = lp->lp_primary_nid;
+       *nnis = lp->lp_nnis;
+       *sizep = size;
 
-       if (copy_to_user(peer_ni_stats, &ni_stats, sizeof(ni_stats)))
-               goto copy_failed;
+       /* Allocate helper buffers. */
+       rc = -ENOMEM;
+       LIBCFS_ALLOC(lpni_info, sizeof(*lpni_info));
+       if (!lpni_info)
+               goto out_lp_decref;
+       LIBCFS_ALLOC(lpni_stats, sizeof(*lpni_stats));
+       if (!lpni_stats)
+               goto out_free_info;
 
+       lpni = NULL;
+       rc = -EFAULT;
+       while ((lpni = lnet_get_next_peer_ni_locked(lp, NULL, lpni)) != NULL) {
+               nid = lpni->lpni_nid;
+               if (copy_to_user(bulk, &nid, sizeof(nid)))
+                       goto out_free_stats;
+               bulk += sizeof(nid);
+
+               memset(lpni_info, 0, sizeof(*lpni_info));
+               snprintf(lpni_info->cr_aliveness, LNET_MAX_STR_LEN, "NA");
+               if (lnet_isrouter(lpni) ||
+                       lnet_peer_aliveness_enabled(lpni))
+                       snprintf(lpni_info->cr_aliveness, LNET_MAX_STR_LEN,
+                               lpni->lpni_alive ? "up" : "down");
+
+               lpni_info->cr_refcount = atomic_read(&lpni->lpni_refcount);
+               lpni_info->cr_ni_peer_tx_credits = (lpni->lpni_net != NULL) ?
+                       lpni->lpni_net->net_tunables.lct_peer_tx_credits : 0;
+               lpni_info->cr_peer_tx_credits = lpni->lpni_txcredits;
+               lpni_info->cr_peer_rtr_credits = lpni->lpni_rtrcredits;
+               lpni_info->cr_peer_min_rtr_credits = lpni->lpni_minrtrcredits;
+               lpni_info->cr_peer_min_tx_credits = lpni->lpni_mintxcredits;
+               lpni_info->cr_peer_tx_qnob = lpni->lpni_txqnob;
+               if (copy_to_user(bulk, lpni_info, sizeof(*lpni_info)))
+                       goto out_free_stats;
+               bulk += sizeof(*lpni_info);
+
+               memset(lpni_stats, 0, sizeof(*lpni_stats));
+               lpni_stats->iel_send_count =
+                       atomic_read(&lpni->lpni_stats.send_count);
+               lpni_stats->iel_recv_count =
+                       atomic_read(&lpni->lpni_stats.recv_count);
+               lpni_stats->iel_drop_count =
+                       atomic_read(&lpni->lpni_stats.drop_count);
+               if (copy_to_user(bulk, lpni_stats, sizeof(*lpni_stats)))
+                       goto out_free_stats;
+               bulk += sizeof(*lpni_stats);
+       }
        rc = 0;
 
-copy_failed:
+out_free_stats:
+       LIBCFS_FREE(lpni_stats, sizeof(*lpni_stats));
+out_free_info:
+       LIBCFS_FREE(lpni_info, sizeof(*lpni_info));
+out_lp_decref:
+       lnet_peer_decref_locked(lp);
+out:
        return rc;
 }
index fd7e898..bb35de5 100644 (file)
@@ -2117,22 +2117,23 @@ int lustre_lnet_show_peer(char *knid, int detail, int seq_no,
        struct lnet_ioctl_peer_cfg peer_info;
        struct lnet_peer_ni_credit_info *lpni_cri;
        struct lnet_ioctl_element_stats *lpni_stats;
-       int rc = LUSTRE_CFG_RC_OUT_OF_MEM, ncpt = 0, i = 0, j = 0;
+       lnet_nid_t *nidp;
+       int rc = LUSTRE_CFG_RC_OUT_OF_MEM;
+       int i;
+       int j;
        int l_errno = 0;
+       __u32 count;
+       __u32 size;
        struct cYAML *root = NULL, *peer = NULL, *peer_ni = NULL,
                     *first_seq = NULL, *peer_root = NULL, *tmp = NULL;
        char err_str[LNET_MAX_STR_LEN];
-       lnet_nid_t prev_primary_nid = LNET_NID_ANY, primary_nid = LNET_NID_ANY;
-       int data_size = sizeof(*lpni_cri) + sizeof(*lpni_stats);
-       char *data = malloc(data_size);
-       bool new_peer = true;
+       lnet_process_id_t *list = NULL;
+       void *data = NULL;
+       void *lpni_data;
 
        snprintf(err_str, sizeof(err_str),
                 "\"out of memory\"");
 
-       if (data == NULL)
-               goto out;
-
        /* create struct cYAML root object */
        root = cYAML_create_object(NULL, NULL);
        if (root == NULL)
@@ -2142,69 +2143,121 @@ int lustre_lnet_show_peer(char *knid, int detail, int seq_no,
        if (peer_root == NULL)
                goto out;
 
-       if (knid != NULL)
-               primary_nid = libcfs_str2nid(knid);
-
-       do {
-               for (i = 0;; i++) {
-                       memset(data, 0, data_size);
+       count = 1000;
+       size = count * sizeof(lnet_process_id_t);
+       list = malloc(size);
+       if (list == NULL) {
+               l_errno = ENOMEM;
+               goto out;
+       }
+       if (knid != NULL) {
+               list[0].nid = libcfs_str2nid(knid);
+               count = 1;
+       } else {
+               for (;;) {
                        memset(&peer_info, 0, sizeof(peer_info));
                        LIBCFS_IOC_INIT_V2(peer_info, prcfg_hdr);
                        peer_info.prcfg_hdr.ioc_len = sizeof(peer_info);
-                       peer_info.prcfg_count = i;
-                       peer_info.prcfg_bulk = (void *)data;
-                       peer_info.prcfg_size = data_size;
-
-                       rc = l_ioctl(LNET_DEV_ID,
-                                    IOC_LIBCFS_GET_PEER_NI, &peer_info);
-                       if (rc != 0) {
-                               l_errno = errno;
+                       peer_info.prcfg_size = size;
+                       peer_info.prcfg_bulk = list;
+
+                       l_errno = 0;
+                       rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_GET_PEER_LIST,
+                                    &peer_info);
+                       count = peer_info.prcfg_count;
+                       if (rc == 0)
                                break;
+                       l_errno = errno;
+                       if (l_errno != E2BIG) {
+                               snprintf(err_str,
+                                       sizeof(err_str),
+                                       "\"cannot get peer list: %s\"",
+                                       strerror(l_errno));
+                               rc = -l_errno;
+                               goto out;
                        }
+                       free(list);
+                       size = peer_info.prcfg_size;
+                       list = malloc(size);
+                       if (list == NULL) {
+                               l_errno = ENOMEM;
+                               goto out;
+                       }
+               }
+       }
 
-                       if (primary_nid != LNET_NID_ANY &&
-                           primary_nid != peer_info.prcfg_prim_nid)
-                                       continue;
+       size = 4096;
+       data = malloc(size);
+       if (data == NULL) {
+               l_errno = ENOMEM;
+               goto out;
+       }
+       for (i = 0; i < count; i++) {
+               for (;;) {
+                       memset(&peer_info, 0, sizeof(peer_info));
+                       LIBCFS_IOC_INIT_V2(peer_info, prcfg_hdr);
+                       peer_info.prcfg_hdr.ioc_len = sizeof(peer_info);
+                       peer_info.prcfg_prim_nid = list[i].nid;
+                       peer_info.prcfg_size = size;
+                       peer_info.prcfg_bulk = data;
+
+                       l_errno = 0;
+                       rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_GET_PEER_NI,
+                                    &peer_info);
+                       if (rc == 0)
+                               break;
+                       l_errno = errno;
+                       if (l_errno != E2BIG) {
+                               snprintf(err_str,
+                                       sizeof(err_str),
+                                       "\"cannot get peer information: %s\"",
+                                       strerror(l_errno));
+                               rc = -l_errno;
+                               goto out;
+                       }
+                       free(data);
+                       size = peer_info.prcfg_size;
+                       data = malloc(size);
+                       if (data == NULL) {
+                               l_errno = ENOMEM;
+                               goto out;
+                       }
+               }
 
-                       lpni_cri = peer_info.prcfg_bulk;
-                       lpni_stats = peer_info.prcfg_bulk + sizeof(*lpni_cri);
+               peer = cYAML_create_seq_item(peer_root);
+               if (peer == NULL)
+                       goto out;
 
-                       peer = cYAML_create_seq_item(peer_root);
-                       if (peer == NULL)
-                               goto out;
+               if (first_seq == NULL)
+                       first_seq = peer;
 
-                       if (peer_info.prcfg_prim_nid != prev_primary_nid) {
-                               prev_primary_nid = peer_info.prcfg_prim_nid;
-                               new_peer = true;
-                       }
+               lnet_nid_t pnid = peer_info.prcfg_prim_nid;
+               if (cYAML_create_string(peer, "primary nid",
+                                       libcfs_nid2str(pnid))
+                   == NULL)
+                       goto out;
+               if (cYAML_create_string(peer, "Multi-Rail",
+                                       peer_info.prcfg_mr ? "True" : "False")
+                   == NULL)
+                       goto out;
 
-                       if (new_peer) {
-                               lnet_nid_t pnid = peer_info.prcfg_prim_nid;
-                               if (cYAML_create_string(peer, "primary nid",
-                                                       libcfs_nid2str(pnid))
-                                   == NULL)
-                                       goto out;
-                               if (cYAML_create_string(peer, "Multi-Rail",
-                                                       peer_info.prcfg_mr ?
-                                                       "True" : "False")
-                                   == NULL)
-                                       goto out;
-                               tmp = cYAML_create_seq(peer, "peer ni");
-                               if (tmp == NULL)
-                                       goto out;
-                               new_peer = false;
-                       }
+               tmp = cYAML_create_seq(peer, "peer ni");
+               if (tmp == NULL)
+                       goto out;
 
-                       if (first_seq == NULL)
-                               first_seq = peer;
+               lpni_data = data;
+               for (j = 0; j < peer_info.prcfg_count; j++) {
+                       nidp = lpni_data;
+                       lpni_cri = (void*)nidp + sizeof(nidp);
+                       lpni_stats = (void *)lpni_cri + sizeof(*lpni_cri);
+                       lpni_data = (void *)lpni_stats + sizeof(*lpni_stats);
 
                        peer_ni = cYAML_create_seq_item(tmp);
                        if (peer_ni == NULL)
                                goto out;
 
                        if (cYAML_create_string(peer_ni, "nid",
-                                               libcfs_nid2str
-                                                (peer_info.prcfg_cfg_nid))
+                                               libcfs_nid2str(*nidp))
                            == NULL)
                                goto out;
 
@@ -2265,18 +2318,118 @@ int lustre_lnet_show_peer(char *knid, int detail, int seq_no,
                                                lpni_cri->cr_refcount) == NULL)
                                goto out;
                }
+       }
+
+       /* print output iff show_rc is not provided */
+       if (show_rc == NULL)
+               cYAML_print_tree(root);
+
+       snprintf(err_str, sizeof(err_str), "\"success\"");
+       rc = LUSTRE_CFG_RC_NO_ERR;
+
+out:
+       free(list);
+       free(data);
+       if (show_rc == NULL || rc != LUSTRE_CFG_RC_NO_ERR) {
+               cYAML_free_tree(root);
+       } else if (show_rc != NULL && *show_rc != NULL) {
+               struct cYAML *show_node;
+               /* find the peer node, if one doesn't exist then
+                * insert one.  Otherwise add to the one there
+                */
+               show_node = cYAML_get_object_item(*show_rc,
+                                                 "peer");
+               if (show_node != NULL && cYAML_is_sequence(show_node)) {
+                       cYAML_insert_child(show_node, first_seq);
+                       free(peer_root);
+                       free(root);
+               } else if (show_node == NULL) {
+                       cYAML_insert_sibling((*show_rc)->cy_child,
+                                            peer_root);
+                       free(root);
+               } else {
+                       cYAML_free_tree(root);
+               }
+       } else {
+               *show_rc = root;
+       }
+
+       cYAML_build_error(rc, seq_no, SHOW_CMD, "peer", err_str,
+                         err_rc);
+
+       return rc;
+}
+
+int lustre_lnet_list_peer(int seq_no,
+                         struct cYAML **show_rc, struct cYAML **err_rc)
+{
+       struct lnet_ioctl_peer_cfg peer_info;
+       int rc = LUSTRE_CFG_RC_OUT_OF_MEM;
+       __u32 count;
+       __u32 size;
+       int i = 0;
+       int l_errno = 0;
+       struct cYAML *root = NULL, *list_root = NULL, *first_seq = NULL;
+       char err_str[LNET_MAX_STR_LEN];
+       lnet_process_id_t *list = NULL;
+
+       snprintf(err_str, sizeof(err_str),
+                "\"out of memory\"");
+
+       memset(&peer_info, 0, sizeof(peer_info));
+
+       /* create struct cYAML root object */
+       root = cYAML_create_object(NULL, NULL);
+       if (root == NULL)
+               goto out;
+
+       list_root = cYAML_create_seq(root, "peer list");
+       if (list_root == NULL)
+               goto out;
+
+       count = 1000;
+       size = count * sizeof(lnet_process_id_t);
+       list = malloc(size);
+       if (list == NULL) {
+               l_errno = ENOMEM;
+               goto out;
+       }
+       for (;;) {
+               LIBCFS_IOC_INIT_V2(peer_info, prcfg_hdr);
+               peer_info.prcfg_hdr.ioc_len = sizeof(peer_info);
+               peer_info.prcfg_size = size;
+               peer_info.prcfg_bulk = list;
 
-               if (l_errno != ENOENT) {
+               l_errno = 0;
+               rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_GET_PEER_LIST, &peer_info);
+               count = peer_info.prcfg_count;
+               if (rc == 0)
+                       break;
+               l_errno = errno;
+               if (l_errno != E2BIG) {
                        snprintf(err_str,
                                sizeof(err_str),
-                               "\"cannot get peer information: %s\"",
+                               "\"cannot get peer list: %s\"",
                                strerror(l_errno));
                        rc = -l_errno;
                        goto out;
                }
+               free(list);
+               size = peer_info.prcfg_size;
+               list = malloc(size);
+               if (list == NULL) {
+                       l_errno = ENOMEM;
+                       goto out;
+               }
+       }
 
-               j++;
-       } while (j < ncpt);
+       /* count is now the actual number of ids in the list. */
+       for (i = 0; i < count; i++) {
+               if (cYAML_create_string(list_root, "nid",
+                                       libcfs_nid2str(list[i].nid))
+                   == NULL)
+                       goto out;
+       }
 
        /* print output iff show_rc is not provided */
        if (show_rc == NULL)
@@ -2286,6 +2439,8 @@ int lustre_lnet_show_peer(char *knid, int detail, int seq_no,
        rc = LUSTRE_CFG_RC_NO_ERR;
 
 out:
+       if (list != NULL)
+               free(list);
        if (show_rc == NULL || rc != LUSTRE_CFG_RC_NO_ERR) {
                cYAML_free_tree(root);
        } else if (show_rc != NULL && *show_rc != NULL) {
@@ -2297,11 +2452,11 @@ out:
                                                  "peer");
                if (show_node != NULL && cYAML_is_sequence(show_node)) {
                        cYAML_insert_child(show_node, first_seq);
-                       free(peer_root);
+                       free(list_root);
                        free(root);
                } else if (show_node == NULL) {
                        cYAML_insert_sibling((*show_rc)->cy_child,
-                                            peer_root);
+                                            list_root);
                        free(root);
                } else {
                        cYAML_free_tree(root);
index 627399e..68758d6 100644 (file)
@@ -357,6 +357,18 @@ int lustre_lnet_show_peer(char *knid, int detail, int seq_no,
                          struct cYAML **show_rc, struct cYAML **err_rc);
 
 /*
+ * lustre_lnet_list_peer
+ *   List the known peers.
+ *
+ *     seq_no - sequence number of the command
+ *     show_rc - YAML structure of the resultant show
+ *     err_rc - YAML strucutre of the resultant return code.
+ *
+ */
+int lustre_lnet_list_peer(int seq_no,
+                         struct cYAML **show_rc, struct cYAML **err_rc);
+
+/*
  * lustre_yaml_config
  *   Parses the provided YAML file and then calls the specific APIs
  *   to configure the entities identified in the file
index 430d91f..6bc66a2 100644 (file)
@@ -57,6 +57,7 @@ static int jt_add_peer_nid(int argc, char **argv);
 static int jt_del_peer_nid(int argc, char **argv);
 static int jt_set_max_intf(int argc, char **argv);
 static int jt_set_discovery(int argc, char **argv);
+static int jt_list_peer(int argc, char **argv);
 /*static int jt_show_peer(int argc, char **argv);*/
 static int lnetctl_list_commands(int argc, char **argv);
 
@@ -154,6 +155,7 @@ command_t peer_cmds[] = {
        {"show", jt_show_peer, 0, "show peer information\n"
         "\t--nid: NID of peer to filter on.\n"
         "\t--verbose: Include  extended  statistics\n"},
+       {"list", jt_list_peer, 0, "list all peers\n"},
        { 0, 0, 0, NULL }
 };
 
@@ -1252,7 +1254,7 @@ static int jt_del_peer_nid(int argc, char **argv)
                        rc = LUSTRE_CFG_RC_OUT_OF_MEM;
                        break;
                case 'h':
-                       print_help(peer_cmds, "peer", "del");
+                       print_help(peer_cmds, "peer", "show");
                        return 0;
                default:
                        return 0;
@@ -1321,6 +1323,41 @@ static int jt_show_peer(int argc, char **argv)
        return rc;
 }
 
+static int jt_list_peer(int argc, char **argv)
+{
+       int rc, opt;
+       struct cYAML *err_rc = NULL, *list_rc = NULL;
+
+       const char *const short_options = "h";
+       const struct option long_options[] = {
+               { "help", 0, NULL, 'h' },
+               { NULL, 0, NULL, 0 },
+       };
+
+       while ((opt = getopt_long(argc, argv, short_options,
+                                 long_options, NULL)) != -1) {
+               switch (opt) {
+               case 'h':
+                       print_help(peer_cmds, "peer", "list");
+                       return 0;
+               default:
+                       return 0;
+               }
+       }
+
+       rc = lustre_lnet_list_peer(-1, &list_rc, &err_rc);
+
+       if (rc != LUSTRE_CFG_RC_NO_ERR)
+               cYAML_print_tree2file(stderr, err_rc);
+       else if (list_rc)
+               cYAML_print_tree(list_rc);
+
+       cYAML_free_tree(err_rc);
+       cYAML_free_tree(list_rc);
+
+       return rc;
+}
+
 command_t list[] = {
        {"lnet", jt_lnet, 0, "lnet {configure | unconfigure} [--all]"},
        {"route", jt_route, 0, "route {add | del | show | help}"},