*
* @LNET_SELFTEST_CMD_UNSPEC: unspecified command to catch errors
* @LNET_SELFTEST_CMD_SESSIONS: command to manage sessions
+ * @LNET_SELFTEST_CMD_GROUPS: command to manage selftest groups
*/
enum lnet_selftest_commands {
LNET_SELFTEST_CMD_UNSPEC = 0,
LNET_SELFTEST_CMD_SESSIONS = 1,
+ LNET_SELFTEST_CMD_GROUPS = 2,
__LNET_SELFTEST_CMD_MAX_PLUS_ONE,
};
* Author: Liang Zhen <liangzhen@clusterfs.com>
*/
+#include <linux/generic-radix-tree.h>
#include <libcfs/linux/linux-net.h>
#include <libcfs/libcfs.h>
#include <lnet/lib-lnet.h>
}
static int
-lst_group_list_ioctl(struct lstio_group_list_args *args)
-{
- if (args->lstio_grp_key != console_session.ses_key)
- return -EACCES;
-
- if (args->lstio_grp_idx < 0 ||
- args->lstio_grp_namep == NULL ||
- args->lstio_grp_nmlen <= 0 ||
- args->lstio_grp_nmlen > LST_NAME_SIZE)
- return -EINVAL;
-
- return lstcon_group_list(args->lstio_grp_idx,
- args->lstio_grp_nmlen,
- args->lstio_grp_namep);
-}
-
-static int
-lst_group_info_ioctl(struct lstio_group_info_args *args)
-{
- char *name;
- int ndent;
- int index;
- int rc;
-
- if (args->lstio_grp_key != console_session.ses_key)
- return -EACCES;
-
- if (args->lstio_grp_namep == NULL ||
- args->lstio_grp_nmlen <= 0 ||
- args->lstio_grp_nmlen > LST_NAME_SIZE)
- return -EINVAL;
-
- if (args->lstio_grp_entp == NULL && /* output: group entry */
- args->lstio_grp_dentsp == NULL) /* output: node entry */
- return -EINVAL;
-
- if (args->lstio_grp_dentsp != NULL) { /* have node entry */
- if (args->lstio_grp_idxp == NULL || /* node index */
- args->lstio_grp_ndentp == NULL) /* # of node entry */
- return -EINVAL;
-
- if (copy_from_user(&ndent, args->lstio_grp_ndentp,
- sizeof(ndent)) ||
- copy_from_user(&index, args->lstio_grp_idxp,
- sizeof(index)))
- return -EFAULT;
-
- if (ndent <= 0 || index < 0)
- return -EINVAL;
- }
-
- LIBCFS_ALLOC(name, args->lstio_grp_nmlen + 1);
- if (name == NULL)
- return -ENOMEM;
-
- if (copy_from_user(name, args->lstio_grp_namep,
- args->lstio_grp_nmlen)) {
- LIBCFS_FREE(name, args->lstio_grp_nmlen + 1);
- return -EFAULT;
- }
-
- name[args->lstio_grp_nmlen] = 0;
-
- rc = lstcon_group_info(name, args->lstio_grp_entp,
- &index, &ndent, args->lstio_grp_dentsp);
-
- LIBCFS_FREE(name, args->lstio_grp_nmlen + 1);
-
- if (rc != 0)
- return rc;
-
- if (args->lstio_grp_dentsp != NULL &&
- (copy_to_user(args->lstio_grp_idxp, &index, sizeof(index)) ||
- copy_to_user(args->lstio_grp_ndentp, &ndent, sizeof(ndent))))
- return -EFAULT;
-
- return 0;
-}
-
-static int
lst_batch_add_ioctl(struct lstio_batch_add_args *args)
{
int rc;
rc = lst_nodes_add_ioctl((struct lstio_group_nodes_args *)buf);
break;
case LSTIO_GROUP_LIST:
- rc = lst_group_list_ioctl((struct lstio_group_list_args *)buf);
- break;
+ fallthrough;
case LSTIO_GROUP_INFO:
- rc = lst_group_info_ioctl((struct lstio_group_info_args *)buf);
+ rc = -EOPNOTSUPP;
break;
case LSTIO_BATCH_ADD:
rc = lst_batch_add_ioctl((struct lstio_batch_add_args *)buf);
return rc;
}
+static char *lst_node_state2str(int state)
+{
+ if (state == LST_NODE_ACTIVE)
+ return "Active";
+ if (state == LST_NODE_BUSY)
+ return "Busy";
+ if (state == LST_NODE_DOWN)
+ return "Down";
+
+ return "Unknown";
+}
+
+int lst_node_str2state(char *str)
+{
+ int state = 0;
+
+ if (strcasecmp(str, "Active") == 0)
+ state = LST_NODE_ACTIVE;
+ else if (strcasecmp(str, "Busy") == 0)
+ state = LST_NODE_BUSY;
+ else if (strcasecmp(str, "Down") == 0)
+ state = LST_NODE_DOWN;
+ else if (strcasecmp(str, "Unknown") == 0)
+ state = LST_NODE_UNKNOWN;
+ else if (strcasecmp(str, "Invalid") == 0)
+ state = LST_NODE_UNKNOWN | LST_NODE_DOWN | LST_NODE_BUSY;
+ return state;
+}
+
+struct lst_genl_group_prop {
+ struct lstcon_group *lggp_grp;
+ int lggp_state_filter;
+};
+
+struct lst_genl_group_list {
+ GENRADIX(struct lst_genl_group_prop) lggl_groups;
+ unsigned int lggl_count;
+ unsigned int lggl_index;
+ bool lggl_verbose;
+};
+
+static inline struct lst_genl_group_list *
+lst_group_dump_ctx(struct netlink_callback *cb)
+{
+ return (struct lst_genl_group_list *)cb->args[0];
+}
+
+static int lst_groups_show_done(struct netlink_callback *cb)
+{
+ struct lst_genl_group_list *glist = lst_group_dump_ctx(cb);
+
+ if (glist) {
+ int i;
+
+ for (i = 0; i < glist->lggl_count; i++) {
+ struct lst_genl_group_prop *prop;
+
+ prop = genradix_ptr(&glist->lggl_groups, i);
+ if (!prop || !prop->lggp_grp)
+ continue;
+ lstcon_group_decref(prop->lggp_grp);
+ }
+ genradix_free(&glist->lggl_groups);
+ LIBCFS_FREE(glist, sizeof(*glist));
+ }
+ cb->args[0] = 0;
+
+ return 0;
+}
+
+/* LNet selftest groups ->start() handler for GET requests */
+static int lst_groups_show_start(struct netlink_callback *cb)
+{
+ struct genlmsghdr *gnlh = nlmsg_data(cb->nlh);
+#ifdef HAVE_NL_PARSE_WITH_EXT_ACK
+ struct netlink_ext_ack *extack = NULL;
+#endif
+ struct nlattr *params = genlmsg_data(gnlh);
+ struct lst_genl_group_list *glist;
+ int msg_len = genlmsg_len(gnlh);
+ struct lstcon_group *grp;
+ struct nlattr *groups;
+ int rem, rc = 0;
+
+ LIBCFS_ALLOC(glist, sizeof(*glist));
+ if (!glist)
+ return -ENOMEM;
+
+ genradix_init(&glist->lggl_groups);
+ cb->args[0] = (long)glist;
+
+ if (!msg_len) {
+ list_for_each_entry(grp, &console_session.ses_grp_list,
+ grp_link) {
+ struct lst_genl_group_prop *prop;
+
+ prop = genradix_ptr_alloc(&glist->lggl_groups,
+ glist->lggl_count++,
+ GFP_ATOMIC);
+ if (!prop) {
+ NL_SET_ERR_MSG(extack,
+ "failed to allocate group info");
+ GOTO(report_err, rc = -ENOMEM);
+ }
+ lstcon_group_addref(grp); /* +1 ref for caller */
+ prop->lggp_grp = grp;
+ }
+
+ if (!glist->lggl_count) {
+ NL_SET_ERR_MSG(extack, "No groups found");
+ rc = -ENOENT;
+ }
+ GOTO(report_err, rc);
+ }
+ glist->lggl_verbose = true;
+#ifdef HAVE_NL_DUMP_WITH_EXT_ACK
+ extack = cb->extack;
+#endif
+ nla_for_each_attr(groups, params, msg_len, rem) {
+ struct lst_genl_group_prop *prop = NULL;
+ struct nlattr *group;
+ int rem2;
+
+ if (nla_type(groups) != LN_SCALAR_ATTR_LIST)
+ continue;
+
+ nla_for_each_nested(group, groups, rem2) {
+ if (nla_type(group) == LN_SCALAR_ATTR_VALUE) {
+ char name[LST_NAME_SIZE];
+
+ prop = genradix_ptr_alloc(&glist->lggl_groups,
+ glist->lggl_count++,
+ GFP_ATOMIC);
+ if (!prop) {
+ NL_SET_ERR_MSG(extack,
+ "failed to allocate group info");
+ GOTO(report_err, rc = -ENOMEM);
+ }
+
+ rc = nla_strscpy(name, group, sizeof(name));
+ if (rc < 0) {
+ NL_SET_ERR_MSG(extack,
+ "failed to get name");
+ GOTO(report_err, rc);
+ }
+ rc = lstcon_group_find(name, &prop->lggp_grp);
+ if (rc < 0) {
+ /* don't stop reporting groups if one
+ * doesn't exist.
+ */
+ CWARN("LNet selftest group %s does not exit\n",
+ name);
+ rc = 0;
+ }
+ } else if (nla_type(group) == LN_SCALAR_ATTR_LIST) {
+ struct nlattr *attr;
+ int rem3;
+
+ if (!prop) {
+ NL_SET_ERR_MSG(extack,
+ "missing group information");
+ GOTO(report_err, rc = -EINVAL);
+ }
+
+ nla_for_each_nested(attr, group, rem3) {
+ char tmp[16];
+
+ if (nla_type(attr) != LN_SCALAR_ATTR_VALUE ||
+ nla_strcmp(attr, "status") != 0)
+ continue;
+
+ attr = nla_next(attr, &rem3);
+ if (nla_type(attr) !=
+ LN_SCALAR_ATTR_VALUE) {
+ NL_SET_ERR_MSG(extack,
+ "invalid config param");
+ GOTO(report_err, rc = -EINVAL);
+ }
+
+ rc = nla_strscpy(tmp, attr, sizeof(tmp));
+ if (rc < 0) {
+ NL_SET_ERR_MSG(extack,
+ "failed to get prop attr");
+ GOTO(report_err, rc);
+ }
+ rc = 0;
+ prop->lggp_state_filter |=
+ lst_node_str2state(tmp);
+ }
+ }
+ }
+ }
+ if (!glist->lggl_count) {
+ NL_SET_ERR_MSG(extack, "No groups found");
+ rc = -ENOENT;
+ }
+report_err:
+ if (rc < 0)
+ lst_groups_show_done(cb);
+
+ return rc;
+}
+
+static const struct ln_key_list lst_group_keys = {
+ .lkl_maxattr = LNET_SELFTEST_GROUP_MAX,
+ .lkl_list = {
+ [LNET_SELFTEST_GROUP_ATTR_HDR] = {
+ .lkp_value = "groups",
+ .lkp_key_format = LNKF_SEQUENCE,
+ .lkp_data_type = NLA_NUL_STRING,
+ },
+ [LNET_SELFTEST_GROUP_ATTR_NAME] = {
+ .lkp_data_type = NLA_STRING,
+ },
+ [LNET_SELFTEST_GROUP_ATTR_NODELIST] = {
+ .lkp_key_format = LNKF_MAPPING | LNKF_SEQUENCE,
+ .lkp_data_type = NLA_NESTED,
+ },
+ },
+};
+
+static const struct ln_key_list lst_group_nodelist_keys = {
+ .lkl_maxattr = LNET_SELFTEST_GROUP_NODELIST_PROP_MAX,
+ .lkl_list = {
+ [LNET_SELFTEST_GROUP_NODELIST_PROP_ATTR_NID] = {
+ .lkp_value = "nid",
+ .lkp_data_type = NLA_STRING,
+ },
+ [LNET_SELFTEST_GROUP_NODELIST_PROP_ATTR_STATUS] = {
+ .lkp_value = "status",
+ .lkp_data_type = NLA_STRING,
+ },
+ },
+};
+
+static int lst_groups_show_dump(struct sk_buff *msg,
+ struct netlink_callback *cb)
+{
+ struct lst_genl_group_list *glist = lst_group_dump_ctx(cb);
+#ifdef HAVE_NL_PARSE_WITH_EXT_ACK
+ struct netlink_ext_ack *extack = NULL;
+#endif
+ int portid = NETLINK_CB(cb->skb).portid;
+ int seq = cb->nlh->nlmsg_seq;
+ int idx = 0, rc = 0;
+
+#ifdef HAVE_NL_DUMP_WITH_EXT_ACK
+ extack = cb->extack;
+#endif
+ if (!glist->lggl_index) {
+ const struct ln_key_list *all[] = {
+ &lst_group_keys, &lst_group_nodelist_keys, NULL
+ };
+
+ rc = lnet_genl_send_scalar_list(msg, portid, seq, &lst_family,
+ NLM_F_CREATE | NLM_F_MULTI,
+ LNET_SELFTEST_CMD_GROUPS, all);
+ if (rc < 0) {
+ NL_SET_ERR_MSG(extack, "failed to send key table");
+ GOTO(send_error, rc);
+ }
+ }
+
+ for (idx = glist->lggl_index; idx < glist->lggl_count; idx++) {
+ struct lst_genl_group_prop *group;
+ struct lstcon_ndlink *ndl;
+ struct nlattr *nodelist;
+ unsigned int count = 1;
+ void *hdr;
+
+ group = genradix_ptr(&glist->lggl_groups, idx);
+ if (!group)
+ continue;
+
+ hdr = genlmsg_put(msg, portid, seq, &lst_family,
+ NLM_F_MULTI, LNET_SELFTEST_CMD_GROUPS);
+ if (!hdr) {
+ NL_SET_ERR_MSG(extack, "failed to send values");
+ GOTO(send_error, rc = -EMSGSIZE);
+ }
+
+ if (idx == 0)
+ nla_put_string(msg, LNET_SELFTEST_GROUP_ATTR_HDR, "");
+
+ nla_put_string(msg, LNET_SELFTEST_GROUP_ATTR_NAME,
+ group->lggp_grp->grp_name);
+
+ if (!glist->lggl_verbose)
+ goto skip_details;
+
+ nodelist = nla_nest_start(msg,
+ LNET_SELFTEST_GROUP_ATTR_NODELIST);
+ list_for_each_entry(ndl, &group->lggp_grp->grp_ndl_list,
+ ndl_link) {
+ struct nlattr *node = nla_nest_start(msg, count);
+ char *ndstate;
+
+ if (group->lggp_state_filter &&
+ !(group->lggp_state_filter & ndl->ndl_node->nd_state))
+ continue;
+
+ nla_put_string(msg,
+ LNET_SELFTEST_GROUP_NODELIST_PROP_ATTR_NID,
+ libcfs_id2str(ndl->ndl_node->nd_id));
+
+ ndstate = lst_node_state2str(ndl->ndl_node->nd_state);
+ nla_put_string(msg,
+ LNET_SELFTEST_GROUP_NODELIST_PROP_ATTR_STATUS,
+ ndstate);
+ nla_nest_end(msg, node);
+ }
+ nla_nest_end(msg, nodelist);
+skip_details:
+ genlmsg_end(msg, hdr);
+ }
+ glist->lggl_index = idx;
+send_error:
+ return lnet_nl_send_error(cb->skb, portid, seq, rc);
+}
+
+#ifndef HAVE_NETLINK_CALLBACK_START
+static int lst_old_groups_show_dump(struct sk_buff *msg,
+ struct netlink_callback *cb)
+{
+ if (!cb->args[0]) {
+ int rc = lst_groups_show_start(cb);
+
+ if (rc < 0)
+ return rc;
+ }
+
+ return lst_groups_show_dump(msg, cb);
+}
+#endif
+
static const struct genl_multicast_group lst_mcast_grps[] = {
{ .name = "sessions", },
+ { .name = "groups", },
};
static const struct genl_ops lst_genl_ops[] = {
.dumpit = lst_sessions_show_dump,
.doit = lst_sessions_cmd,
},
+ {
+ .cmd = LNET_SELFTEST_CMD_GROUPS,
+#ifdef HAVE_NETLINK_CALLBACK_START
+ .start = lst_groups_show_start,
+ .dumpit = lst_groups_show_dump,
+#else
+ .dumpit = lst_old_groups_show_dump,
+#endif
+ .done = lst_groups_show_done,
+ },
};
static struct genl_family lst_family = {
return 0;
}
-static void
-lstcon_group_addref(struct lstcon_group *grp)
+void lstcon_group_addref(struct lstcon_group *grp)
{
grp->grp_ref++;
}
}
}
-static void
-lstcon_group_decref(struct lstcon_group *grp)
+void lstcon_group_decref(struct lstcon_group *grp)
{
int i;
grp_ndl_hash[LST_NODE_HASHSIZE]));
}
-static int
-lstcon_group_find(const char *name, struct lstcon_group **grpp)
+int lstcon_group_find(const char *name, struct lstcon_group **grpp)
{
struct lstcon_group *grp;
return rc;
}
-int
-lstcon_group_list(int index, int len, char __user *name_up)
-{
- struct lstcon_group *grp;
-
- LASSERT(index >= 0);
- LASSERT(name_up != NULL);
-
- list_for_each_entry(grp, &console_session.ses_grp_list, grp_link) {
- if (index-- == 0) {
- return copy_to_user(name_up, grp->grp_name, len) ?
- -EFAULT : 0;
- }
- }
-
- return -ENOENT;
-}
-
static int
lstcon_nodes_getent(struct list_head *head, int *index_p,
int *count_p, struct lstcon_node_ent __user *dents_up)
struct list_head __user *result_up);
extern int lstcon_group_add(char *name);
extern int lstcon_group_del(char *name);
+void lstcon_group_addref(struct lstcon_group *grp);
+void lstcon_group_decref(struct lstcon_group *grp);
+int lstcon_group_find(const char *name, struct lstcon_group **grpp);
extern int lstcon_group_clean(char *name, int args);
extern int lstcon_group_refresh(char *name, struct list_head __user *result_up);
extern int lstcon_nodes_add(char *name, int nnd,
extern int lstcon_group_info(char *name, struct lstcon_ndlist_ent __user *gent_up,
int *index_p, int *ndent_p,
struct lstcon_node_ent __user *ndents_up);
-extern int lstcon_group_list(int idx, int len, char __user *name_up);
extern int lstcon_batch_add(char *name);
extern int lstcon_batch_run(char *name, int timeout,
struct list_head __user *result_up);
#define LNET_SELFTEST_SESSION_MAX (__LNET_SELFTEST_SESSION_MAX_PLUS_ONE - 1)
+/* enum lnet_selftest_group_attrs - LNet selftest group Netlink attributes
+ *
+ * @LNET_SELFTEST_GROUP_ATTR_UNSPEC: unspecified attribute to catch errors
+ *
+ * @LENT_SELFTEST_GROUP_ATTR_HDR: Netlink group this data is for
+ * (NLA_NUL_STRING)
+ * @LNET_SELFTEST_GROUP_ATTR_NAME: name of this group (NLA_STRING)
+ * @LNET_SELFTEST_GROUP_ATTR_NODELIST: List of nodes belonging to the group
+ * (NLA_NESTED)
+ */
+enum lnet_selftest_group_attrs {
+ LNET_SELFTEST_GROUP_ATTR_UNSPEC = 0,
+
+ LNET_SELFTEST_GROUP_ATTR_HDR,
+ LNET_SELFTEST_GROUP_ATTR_NAME,
+ LNET_SELFTEST_GROUP_ATTR_NODELIST,
+
+ __LNET_SELFTEST_GROUP_MAX_PLUS_ONE,
+};
+
+#define LNET_SELFTEST_GROUP_MAX (__LNET_SELFTEST_GROUP_MAX_PLUS_ONE - 1)
+
+/* enum lnet_selftest_group_nodelist_prop_attrs - Netlink attributes for
+ * the properties of the
+ * nodes that belong to a
+ * group
+ *
+ * @LNET_SELFTEST_GROUP_NODELIST_PROP_ATTR_UNSPEC: unspecified attribute
+ * to catch errors
+ *
+ * @LENT_SELFTEST_GROUP_NODELIST_PROP_ATTR_NID: Nodes's NID (NLA_STRING)
+ * @LNET_SELFTEST_GROUP_NODELIST_PROP_ATTR_STATUS: Status of the node
+ * (NLA_STRING)
+ */
+enum lnet_selftest_group_nodelist_prop_attrs {
+ LNET_SELFTEST_GROUP_NODELIST_PROP_ATTR_UNSPEC = 0,
+
+ LNET_SELFTEST_GROUP_NODELIST_PROP_ATTR_NID,
+ LNET_SELFTEST_GROUP_NODELIST_PROP_ATTR_STATUS,
+ __LNET_SELFTEST_GROUP_NODELIST_PROP_MAX_PLUS_ONE,
+};
+
+#define LNET_SELFTEST_GROUP_NODELIST_PROP_MAX (__LNET_SELFTEST_GROUP_NODELIST_PROP_MAX_PLUS_ONE - 1)
+
#define SWI_STATE_NEWBORN 0
#define SWI_STATE_REPLY_SUBMITTED 1
#define SWI_STATE_REPLY_SENT 2
return rc;
}
+#define LST_NODES_TITLE "\tACTIVE\tBUSY\tDOWN\tUNKNOWN\tTOTAL\n"
+
+static int lst_yaml_display_groups(yaml_parser_t *reply, char *group,
+ int states, bool print)
+{
+ yaml_event_t event;
+ int rc;
+
+ if (states) {
+ char name[LST_NAME_SIZE] = {};
+ bool done = false;
+ int count = 0;
+
+ if (print)
+ fprintf(stdout, LST_NODES_TITLE);
+
+ while (!done) {
+ rc = yaml_parser_parse(reply, &event);
+ if (rc == 0)
+ goto parser_error;
+
+ if (event.type == YAML_MAPPING_START_EVENT) {
+ char *value = NULL;
+ yaml_event_t next;
+
+ rc = yaml_parser_parse(reply, &next);
+ if (rc == 0)
+ goto parser_error;
+
+ if (next.type != YAML_SCALAR_EVENT) {
+ yaml_event_delete(&next);
+ continue;
+ }
+
+ value = (char *)next.data.scalar.value;
+ if (strcmp(value, "groups") == 0) {
+ yaml_event_delete(&next);
+ } else if (strcmp(value, "nid") == 0) {
+ yaml_event_t next;
+ char *tmp;
+
+ rc = yaml_parser_parse(reply, &next);
+ if (rc == 0)
+ goto parser_error;
+
+ fprintf(stdout, "\t%s: ",
+ (char *)next.data.scalar.value);
+
+ rc = yaml_parser_parse(reply, &next);
+ if (rc == 0)
+ goto parser_error;
+
+ tmp = (char *)next.data.scalar.value;
+ if (strcmp(tmp, "status") == 0) {
+ yaml_event_t state;
+
+ rc = yaml_parser_parse(reply, &state);
+ if (rc == 0)
+ goto parser_error;
+
+ fprintf(stdout, "%s\n",
+ (char *)state.data.scalar.value);
+ count++;
+ }
+ } else {
+ yaml_event_t next;
+
+ rc = yaml_parser_parse(reply, &next);
+ if (rc == 0)
+ goto parser_error;
+
+ strncpy(name, value, sizeof(name) - 1);
+ fprintf(stdout, "Group [ %s ]\n", name);
+ count = 0;
+
+ if (next.type != YAML_SEQUENCE_START_EVENT) {
+ fprintf(stdout,
+ "No nodes found [ %s ]\n",
+ name);
+ }
+ }
+ } else if (event.type == YAML_SEQUENCE_END_EVENT &&
+ count) {
+ fprintf(stdout, "Total %d nodes [ %s ]\n",
+ count, name);
+ count = 0;
+ }
+
+ done = (event.type == YAML_STREAM_END_EVENT);
+ yaml_event_delete(&event);
+ }
+ } else if (group) {
+ int active = 0, busy = 0, down = 0, unknown = 0;
+ char group[LST_NAME_SIZE];
+ bool done = false;
+
+ while (!done) {
+ rc = yaml_parser_parse(reply, &event);
+ if (rc == 0)
+ goto parser_error;
+
+ if (event.type == YAML_SCALAR_EVENT) {
+ char *value = (char *)event.data.scalar.value;
+ yaml_event_t next;
+
+ value = (char *)event.data.scalar.value;
+ if (strcmp(value, "groups") == 0) {
+ yaml_event_delete(&event);
+ continue;
+ }
+
+ rc = yaml_parser_parse(reply, &next);
+ if (rc == 0)
+ goto parser_error;
+
+ if (next.type == YAML_SCALAR_EVENT) {
+ int status;
+
+ status = lst_node_str2state((char *)next.data.scalar.value);
+ switch (status) {
+ case LST_NODE_ACTIVE:
+ active++;
+ break;
+ case LST_NODE_BUSY:
+ busy++;
+ break;
+ case LST_NODE_DOWN:
+ down++;
+ break;
+ case LST_NODE_UNKNOWN:
+ unknown++;
+ default:
+ break;
+ }
+ } else if (next.type == YAML_SEQUENCE_START_EVENT) {
+ strncpy(group, value, sizeof(group) - 1);
+ active = 0;
+ busy = 0;
+ down = 0;
+ unknown = 0;
+ }
+ yaml_event_delete(&next);
+ } else if (event.type == YAML_SEQUENCE_END_EVENT) {
+ if (strlen(group)) {
+ fprintf(stdout, "\t%d\t%d\t%d\t%d\t%d\t%s\n",
+ active, busy, down, unknown,
+ active + busy + down + unknown, group);
+ }
+ memset(group, 0, sizeof(group));
+ }
+ done = (event.type == YAML_STREAM_END_EVENT);
+ yaml_event_delete(&event);
+ }
+ } else {
+ bool done = false;
+ unsigned int i = 1;
+
+ while (!done) {
+ rc = yaml_parser_parse(reply, &event);
+ if (rc == 0)
+ goto parser_error;
+
+ if (event.type == YAML_SCALAR_EVENT) {
+ char *value;
+
+ value = (char *)event.data.scalar.value;
+ if (strlen(value) &&
+ strcmp(value, "groups") != 0) {
+ if (print)
+ fprintf(stdout, "%d) %s\n",
+ i, value);
+ i++;
+ }
+ }
+ done = (event.type == YAML_STREAM_END_EVENT);
+
+ yaml_event_delete(&event);
+ }
+ if (print)
+ fprintf(stdout, "Total %d groups\n", i - 1);
+ else
+ rc = i - 1;
+ }
+parser_error:
+ return rc;
+}
+
+#define LST_NODES_TITLE "\tACTIVE\tBUSY\tDOWN\tUNKNOWN\tTOTAL\n"
+
+static int lst_yaml_groups(int nlflags, char *name, int states, bool print)
+{
+ yaml_emitter_t request;
+ yaml_parser_t reply;
+ yaml_event_t event;
+ struct nl_sock *sk;
+ int rc;
+
+ sk = nl_socket_alloc();
+ if (!sk)
+ return -EOPNOTSUPP;
+
+ /* Setup reply parser to recieve Netlink packets */
+ rc = yaml_parser_initialize(&reply);
+ if (rc == 0) {
+ nl_socket_free(sk);
+ return -EOPNOTSUPP;
+ }
+
+ rc = yaml_parser_set_input_netlink(&reply, sk, false);
+ if (rc == 0)
+ goto parser_error;
+
+ /* Create Netlink emitter to send request to kernel */
+ yaml_emitter_initialize(&request);
+ rc = yaml_emitter_set_output_netlink(&request, sk,
+ LNET_SELFTEST_GENL_NAME,
+ LNET_SELFTEST_GENL_VERSION,
+ LNET_SELFTEST_CMD_GROUPS,
+ nlflags);
+ if (rc == 0)
+ goto emitter_error;
+
+ yaml_emitter_open(&request);
+ yaml_document_start_event_initialize(&event, NULL, NULL, NULL, 0);
+ rc = yaml_emitter_emit(&request, &event);
+ if (rc == 0)
+ goto emitter_error;
+
+ yaml_mapping_start_event_initialize(&event, NULL,
+ (yaml_char_t *)YAML_MAP_TAG,
+ 1, YAML_BLOCK_MAPPING_STYLE);
+ rc = yaml_emitter_emit(&request, &event);
+ if (rc == 0)
+ goto emitter_error;
+
+ yaml_scalar_event_initialize(&event, NULL,
+ (yaml_char_t *)YAML_STR_TAG,
+ (yaml_char_t *)"groups",
+ strlen("groups"), 1, 0,
+ YAML_PLAIN_SCALAR_STYLE);
+ rc = yaml_emitter_emit(&request, &event);
+ if (rc == 0)
+ goto emitter_error;
+
+ if (name) {
+ yaml_sequence_start_event_initialize(&event, NULL,
+ (yaml_char_t *)YAML_SEQ_TAG,
+ 1, YAML_BLOCK_SEQUENCE_STYLE);
+ rc = yaml_emitter_emit(&request, &event);
+ if (rc == 0)
+ goto emitter_error;
+
+ yaml_mapping_start_event_initialize(&event, NULL,
+ (yaml_char_t *)YAML_MAP_TAG,
+ 1, YAML_BLOCK_MAPPING_STYLE);
+ rc = yaml_emitter_emit(&request, &event);
+ if (rc == 0)
+ goto emitter_error;
+
+ yaml_scalar_event_initialize(&event, NULL,
+ (yaml_char_t *)YAML_STR_TAG,
+ (yaml_char_t *)name,
+ strlen(name), 1, 0,
+ YAML_PLAIN_SCALAR_STYLE);
+ rc = yaml_emitter_emit(&request, &event);
+ if (rc == 0)
+ goto emitter_error;
+
+ if (states) {
+ int max = ffs(LST_NODE_UNKNOWN) + 1, i;
+ char *state;
+
+ yaml_sequence_start_event_initialize(&event, NULL,
+ (yaml_char_t *)YAML_SEQ_TAG,
+ 1, YAML_BLOCK_SEQUENCE_STYLE);
+ rc = yaml_emitter_emit(&request, &event);
+ if (rc == 0)
+ goto emitter_error;
+
+
+ for (i = 0; i < max; i++) {
+ int mask = states & (1 << i);
+
+ state = lst_node_state2str(mask);
+ if (mask != LST_NODE_UNKNOWN && strcmp(state, "Unknown") == 0)
+ continue;
+
+ yaml_mapping_start_event_initialize(&event, NULL,
+ (yaml_char_t *)YAML_MAP_TAG,
+ 1, YAML_BLOCK_MAPPING_STYLE);
+ rc = yaml_emitter_emit(&request, &event);
+ if (rc == 0)
+ goto emitter_error;
+
+ yaml_scalar_event_initialize(&event, NULL,
+ (yaml_char_t *)YAML_STR_TAG,
+ (yaml_char_t *)"status",
+ strlen("status"), 1, 0,
+ YAML_PLAIN_SCALAR_STYLE);
+ rc = yaml_emitter_emit(&request, &event);
+ if (rc == 0)
+ goto emitter_error;
+
+ yaml_scalar_event_initialize(&event, NULL,
+ (yaml_char_t *)YAML_STR_TAG,
+ (yaml_char_t *)state,
+ strlen(state), 1, 0,
+ YAML_PLAIN_SCALAR_STYLE);
+ rc = yaml_emitter_emit(&request, &event);
+ if (rc == 0)
+ goto emitter_error;
+
+ yaml_mapping_end_event_initialize(&event);
+ rc = yaml_emitter_emit(&request, &event);
+ if (rc == 0)
+ goto emitter_error;
+ }
+
+ yaml_sequence_end_event_initialize(&event);
+ rc = yaml_emitter_emit(&request, &event);
+ if (rc == 0)
+ goto emitter_error;
+ } else {
+ yaml_scalar_event_initialize(&event, NULL,
+ (yaml_char_t *)YAML_STR_TAG,
+ (yaml_char_t *)"",
+ strlen(""), 1, 0,
+ YAML_PLAIN_SCALAR_STYLE);
+ rc = yaml_emitter_emit(&request, &event);
+ if (rc == 0)
+ goto emitter_error;
+ }
+
+ yaml_mapping_end_event_initialize(&event);
+ rc = yaml_emitter_emit(&request, &event);
+ if (rc == 0)
+ goto emitter_error;
+
+ yaml_sequence_end_event_initialize(&event);
+ rc = yaml_emitter_emit(&request, &event);
+ if (rc == 0)
+ goto emitter_error;
+ } else {
+ yaml_scalar_event_initialize(&event, NULL,
+ (yaml_char_t *)YAML_STR_TAG,
+ (yaml_char_t *)"",
+ strlen(""), 1, 0,
+ YAML_PLAIN_SCALAR_STYLE);
+ rc = yaml_emitter_emit(&request, &event);
+ if (rc == 0)
+ goto emitter_error;
+ }
+ yaml_mapping_end_event_initialize(&event);
+ rc = yaml_emitter_emit(&request, &event);
+ if (rc == 0)
+ goto emitter_error;
+
+ yaml_document_end_event_initialize(&event, 0);
+ rc = yaml_emitter_emit(&request, &event);
+ if (rc == 0)
+ goto emitter_error;
+
+ rc = yaml_emitter_close(&request);
+ if (rc == 0) {
+emitter_error:
+ yaml_emitter_log_error(&request, stderr);
+ yaml_emitter_delete(&request);
+ rc = -EINVAL;
+ goto parser_error;
+ }
+ yaml_emitter_delete(&request);
+
+ /* display output */
+ if (nlflags == NLM_F_DUMP)
+ rc = lst_yaml_display_groups(&reply, name, states, print);
+parser_error:
+ if (rc == 0)
+ yaml_parser_log_error(&reply, stderr, NULL);
+ yaml_parser_delete(&reply);
+ nl_socket_free(sk);
+
+ if (print)
+ rc = rc == 1 ? 0 : -EINVAL;
+
+ return rc;
+}
+
int
lst_ping_ioctl(char *str, int type, int timeout,
int count, struct lnet_process_id *ids, struct list_head *head)
break;
case LST_OPC_GROUP:
- rc = lst_info_group_ioctl(str, entp, NULL, NULL, NULL);
+ rc = lst_yaml_groups(NLM_F_DUMP, NULL, 0, false);
+ if (rc == -EOPNOTSUPP) {
+ rc = lst_info_group_ioctl(str, entp, NULL, NULL, NULL);
+ } else if (rc > 0) {
+ entp->nle_nnode = rc;
+ rc = 0;
+ }
break;
case LST_OPC_NODES:
return 0;
}
-#define LST_NODES_TITLE "\tACTIVE\tBUSY\tDOWN\tUNKNOWN\tTOTAL\n"
-
int
jt_lst_list_group(int argc, char **argv)
{
struct lstcon_ndlist_ent gent;
struct lstcon_node_ent *dents;
+ int states = 0;
int optidx = 0;
int verbose = 0;
int active = 0;
int j;
int c;
int rc = 0;
-
static const struct option list_group_opts[] = {
{ .name = "active", .has_arg = no_argument, .val = 'a' },
{ .name = "busy", .has_arg = no_argument, .val = 'b' },
switch (c) {
case 'a':
verbose = active = 1;
+ states |= LST_NODE_ACTIVE;
all = 0;
break;
case 'b':
verbose = busy = 1;
+ states |= LST_NODE_BUSY;
all = 0;
break;
case 'd':
verbose = down = 1;
+ states |= LST_NODE_DOWN;
all = 0;
break;
case 'u':
verbose = unknown = 1;
+ states |= LST_NODE_UNKNOWN;
all = 0;
break;
case 'l':
+ states |= LST_NODE_ACTIVE | LST_NODE_BUSY |
+ LST_NODE_DOWN | LST_NODE_UNKNOWN;
verbose = all = 1;
break;
default:
}
}
+ if (optind == argc) {
+ rc = lst_yaml_groups(NLM_F_DUMP, NULL, 0, true);
+ if (rc <= 0) {
+ if (rc == -EOPNOTSUPP)
+ goto old_api;
+ return rc;
+ }
+ } else {
+ for (i = optind; i < argc; i++) {
+ rc = lst_yaml_groups(NLM_F_DUMP, argv[i], states,
+ i == optind ? true : false);
+ if (rc < 0) {
+ if (rc == -EOPNOTSUPP)
+ goto old_api;
+ return rc;
+ }
+ }
+ return 0;
+ }
+old_api:
if (optind == argc) {
/* no group is specified, list name of all groups */
rc = lst_list_group_all();