X-Git-Url: https://git.whamcloud.com/?p=fs%2Flustre-release.git;a=blobdiff_plain;f=lnet%2Fselftest%2Fconctl.c;fp=lnet%2Fselftest%2Fconctl.c;h=ff1352793f25a92b34afdd8bb840f4ce8c231a91;hp=185813edcad87da6cf036314198f0698048d2316;hb=a6c2d277d09ce9b33d5407dd08da7ffc42066de0;hpb=a0132a79df9b59d5d9b674665daf6cdbd79128a8 diff --git a/lnet/selftest/conctl.c b/lnet/selftest/conctl.c index 185813e..ff13527 100644 --- a/lnet/selftest/conctl.c +++ b/lnet/selftest/conctl.c @@ -35,6 +35,7 @@ * Author: Liang Zhen */ +#include #include #include #include @@ -291,86 +292,6 @@ lst_nodes_add_ioctl(struct lstio_group_nodes_args *args) } 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; @@ -815,10 +736,9 @@ lstcon_ioctl_entry(struct notifier_block *nb, 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); @@ -1101,8 +1021,344 @@ out_unlock: 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[] = { @@ -1111,6 +1367,16 @@ 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 = {