Whamcloud - gitweb
LU-9680 utils: new llapi_param_display_value(). 91/49491/7
authorJames Simmons <jsimmons@infradead.org>
Thu, 12 Jan 2023 14:02:54 +0000 (09:02 -0500)
committerOleg Drokin <green@whamcloud.com>
Fri, 27 Jan 2023 00:31:43 +0000 (00:31 +0000)
Currently the special YAML handling is done in lustre_cfg.c
for param handling. Other functionality internal to
liblustreapi.so will use this as well so move the handling
internal to liblustreapi.so. Currently we only make the new
llapi_param_display_value() function visible only to the
liblustreapi internal code. Later when we support /sys access
we can make this available for general use.

The "lctl get_param" and "lctl list_param" generally worked
for non-root users, but not for parameters under
/sys/kernel/debug due to permission changes in the kernel.
We still lacked proper non-root access for lctl get_param and
lctl list_param. Implement full lctl get_param functionality
for non-root users. Also make lctl list_param work for
non-root users. These changes will also work with any
parameters implemented with Netlink.

Change-Id: Ifd9aad16decb0803a336314d4dea38664ff41aa4
Signed-off-by: James Simmons <jsimmons@infradead.org>
Reviewed-on: https://review.whamcloud.com/c/fs/lustre-release/+/49491
Tested-by: jenkins <devops@whamcloud.com>
Tested-by: Maloo <maloo@whamcloud.com>
Reviewed-by: Andreas Dilger <adilger@whamcloud.com>
Reviewed-by: Jian Yu <yujian@whamcloud.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
lustre/doc/Makefile.am
lustre/doc/lctl-device_list.8 [new file with mode: 0644]
lustre/doc/lctl-dl.8 [new file with mode: 0644]
lustre/doc/lctl-get_param.8
lustre/utils/Makefile.am
lustre/utils/lctl.c
lustre/utils/liblustreapi_param.c
lustre/utils/lustre_cfg.c
lustre/utils/lustreapi_internal.h
lustre/utils/obdctl.h

index 2c6e699..56dabd7 100644 (file)
@@ -33,6 +33,8 @@
 
 MANFILES =                                     \
        lctl.8                                  \
+       lctl-dl.8                               \
+       lctl-device_list.8                      \
        lctl-get_param.8                        \
        lctl-list_param.8                       \
        lctl-network.8                          \
diff --git a/lustre/doc/lctl-device_list.8 b/lustre/doc/lctl-device_list.8
new file mode 100644 (file)
index 0000000..b693b9c
--- /dev/null
@@ -0,0 +1,38 @@
+.TH lctl-device_list 8 "2023-01-09" Lustre "configuration utilities"
+.SH NAME
+lctl device_list \- show all local Lustre Object Based Devices
+.SH SYNOPSIS
+.B lctl device_list
+.RB "[ --target|-t ]"
+.RB "[ --yaml|-y ]"
+
+.B lctl dl
+is the same command.
+.SH DESCRIPTION
+.B lctl device_list
+reports details about the local Lustre OBDs. The information reported for the
+OBD are the type, name, and UUID. Also reported are the device number, status
+and reference count of the OBD device. The device number is needed for lctl
+--device argument.
+.TP
+.SH OPTIONS
+.TP
+\fB\-t\fR, \fB\-\-target\fR
+Retrieve the servers' export NID that communicates with the local OBD.
+.TP
+\fB\-y\fR, \fB\-\-yaml\fR
+An option provided so that the OBD information can be provided in YAML format
+.TP
+.SH EXAMPLES
+.TP
+.B $ lctl --device_list -t -y
+.SH AVAILABILITY
+.B lctl device_list
+is a subcommand of
+.BR lctl (8)
+and is distributed as part of the
+.BR lustre (7)
+filesystem package.
+.SH SEE ALSO
+.BR lctl (8),
+.BR lustre (7)
diff --git a/lustre/doc/lctl-dl.8 b/lustre/doc/lctl-dl.8
new file mode 100644 (file)
index 0000000..c5980e8
--- /dev/null
@@ -0,0 +1 @@
+.so man8/lctl-device_list.8
index e1c992d..97d6879 100644 (file)
@@ -47,6 +47,12 @@ useful when using patterns.
 .TP
 .B -R
 Recursively show all of the parameter names below the specified name.
+.TP
+.B -y
+Some paramters can be presented in a YAML format but are not by default. This
+will format the parameter data in YAML. If the YAML provides a source: field
+it can be suppressed with the -n option.
+
 .SH EXAMPLES
 .B $ lctl get_param osc.*.max_pages_per_rpc
 .br
@@ -73,6 +79,26 @@ osc.testfs-OST0000-osc-ffff8803c9c0f000.max_rpcs_in_flight=8
 osc.testfs-OST0001-osc-ffff8803c9c0f000.max_rpcs_in_flight=8
 .br
 osc.testfs-OST0002-osc-ffff8803c9c0f000.max_rpcs_in_flight=8
+.br
+.B $ lctl get_param -n devices
+.br
+ 0 UP osd-ldiskfs MGS-osd MGS-osd_UUID 4
+.br
+.B $ lctl get_param -y devices
+.br
+devices:
+.br
+- index: 0
+.br
+  status: UP
+.br
+  type: osd-ldiskfs
+.br
+  name: MGS-osd
+.br
+  uuid: MGS-osd_UUID
+.br
+  refcount: 4
 .SH SEE ALSO
 .BR lustre (7),
 .BR lctl (8),
index e1c078c..9dfa304 100644 (file)
@@ -111,11 +111,15 @@ liblustreapi_la_SOURCES = liblustreapi.c liblustreapi_hsm.c \
                          liblustreapi_heat.c liblustreapi_pcc.c \
                          liblustreapi_root.c \
                          liblustreapi_lseek.c liblustreapi_swap.c
+liblustreapi_la_CFLAGS = -fPIC -D_GNU_SOURCE $(LIBNL3_CFLAGS) \
+                        -I $(top_builddir)/lnet/utils \
+                        -D_LARGEFILE64_SOURCE=1 -D_FILE_OFFSET_BITS=64 \
+                        -DLUSTRE_UTILS=1
 liblustreapi_la_LDFLAGS = $(LIBREADLINE) -version-info 1:0:0 \
                          -Wl,--version-script=liblustreapi.map
 liblustreapi_la_LIBADD = $(top_builddir)/libcfs/libcfs/libcfs.la \
                         $(top_builddir)/lnet/utils/lnetconfig/liblnetconfig.la \
-                        -lpthread
+                        $(LIBNL3_LIBS) -lpthread
 
 pkgconfigdir = $(libdir)/pkgconfig
 pkgconfig_DATA = lustre.pc
index 5a6db60..a149b8c 100644 (file)
@@ -182,9 +182,9 @@ command_t cmdlist[] = {
        {"cfg_device", jt_obd_device, 0,
         "set current device to <name>, same as 'device'\n"
         "usage: cfg_device <name>"},
-       {"device_list", jt_obd_list, 0, "show all devices\n"
+       {"device_list", jt_device_list, 0, "show all devices\n"
         "usage: device_list [--target|-t] [--yaml|-y]"},
-       {"dl", jt_obd_list, 0, "show all devices, same as 'device_list'\n"
+       {"dl", jt_device_list, 0, "show all devices, same as 'device_list'\n"
         "usage: dl [--target|-t] [--yaml|-y]"},
 
        /* Device operations */
index 8a8ae45..a1f52ca 100644 (file)
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <unistd.h>
+#include <yaml.h>
 
 #include <libcfs/util/param.h>
+#include <linux/lustre/lustre_kernelcomm.h>
 #include <linux/lustre/lustre_user.h>
+#include <lnetconfig/liblnetconfig.h>
 #include <lustre/lustreapi.h>
 #include "lustreapi_internal.h"
 
@@ -364,6 +367,371 @@ out:
        return rc;
 }
 
+static void print_obd_line(char *s)
+{
+       const char *param = "osc/%s/ost_conn_uuid";
+       char obd_name[MAX_OBD_NAME];
+       char buf[MAX_OBD_NAME];
+       FILE *fp = NULL;
+       glob_t path;
+       char *ptr;
+retry:
+       /* obd device type is the first 3 characters of param name */
+       snprintf(buf, sizeof(buf), " %%*d %%*s %.3s %%%zus %%*s %%*d ",
+                param, sizeof(obd_name) - 1);
+       if (sscanf(s, buf, obd_name) == 0)
+               goto try_mdc;
+       if (cfs_get_param_paths(&path, param, obd_name) != 0)
+               goto try_mdc;
+       fp = fopen(path.gl_pathv[0], "r");
+       if (!fp) {
+               /* need to free path data before retry */
+               cfs_free_param_data(&path);
+try_mdc:
+               if (param[0] == 'o') { /* failed with osc, try mdc */
+                       param = "mdc/%s/mds_conn_uuid";
+                       goto retry;
+               }
+               buf[0] = '\0';
+               goto fail_print;
+       }
+
+       /* should not ignore fgets(3)'s return value */
+       if (!fgets(buf, sizeof(buf), fp)) {
+               fprintf(stderr, "reading from %s: %s", buf, strerror(errno));
+               goto fail_close;
+       }
+
+fail_close:
+       fclose(fp);
+       cfs_free_param_data(&path);
+
+       /* trim trailing newlines */
+       ptr = strrchr(buf, '\n');
+       if (ptr)
+               *ptr = '\0';
+fail_print:
+       ptr = strrchr(s, '\n');
+       if (ptr)
+               *ptr = '\0';
+       printf("%s%s%s\n", s, buf[0] ? " " : "", buf);
+}
+
+static int print_out_devices(yaml_parser_t *reply, enum lctl_param_flags flags)
+{
+       char buf[PATH_MAX / 2], *tmp = NULL;
+       size_t buf_len = sizeof(buf);
+       yaml_event_t event;
+       bool done = false;
+       int rc;
+
+       if (flags & PARAM_FLAGS_SHOW_SOURCE) {
+               snprintf(buf, buf_len, "devices=");
+               printf("%s\n",  buf);
+       }
+       bzero(buf, sizeof(buf));
+
+       while (!done) {
+               rc = yaml_parser_parse(reply, &event);
+               if (rc == 0)
+                       break;
+
+               if (event.type == YAML_MAPPING_START_EVENT) {
+                       size_t len = strlen(buf);
+
+                       if (len > 0 && strcmp(buf, "devices=\n") != 0) {
+                               /* eat last white space */
+                               buf[len - 1] = '\0';
+                               if (flags & PARAM_FLAGS_EXTRA_DETAILS)
+                                       print_obd_line(buf);
+                               else
+                                       printf("%s\n",  buf);
+                       }
+                       bzero(buf, sizeof(buf));
+                       tmp = buf;
+               }
+
+               if (event.type == YAML_SCALAR_EVENT) {
+                       char *value = (char *)event.data.scalar.value;
+
+                       if (strcmp(value, "index") == 0) {
+                               yaml_event_delete(&event);
+                               rc = yaml_parser_parse(reply, &event);
+                               if (rc == 0)
+                                       break;
+
+                               value = (char *)event.data.scalar.value;
+                               snprintf(tmp, buf_len, "%3s ", value);
+                               buf_len -= 4;
+                               tmp += 4;
+                       }
+
+                       if (strcmp(value, "status") == 0 ||
+                           strcmp(value, "type") == 0 ||
+                           strcmp(value, "name") == 0 ||
+                           strcmp(value, "uuid") == 0 ||
+                           strcmp(value, "refcount") == 0) {
+                               yaml_event_delete(&event);
+                               rc = yaml_parser_parse(reply, &event);
+                               if (rc == 0)
+                                       break;
+
+                               value = (char *)event.data.scalar.value;
+                               snprintf(tmp, buf_len, "%s ", value);
+                               buf_len -= strlen(value) + 1;
+                               tmp += strlen(value) + 1;
+                       }
+               }
+
+               done = (event.type == YAML_DOCUMENT_END_EVENT);
+               if (done) {
+                       size_t len = strlen(buf);
+
+                       if (len > 0) {
+                               /* eat last white space */
+                               buf[len - 1] = '\0';
+                               if (flags & PARAM_FLAGS_EXTRA_DETAILS)
+                                       print_obd_line(buf);
+                               else
+                                       printf("%s\n", buf);
+                       }
+                       bzero(buf, sizeof(buf));
+                       tmp = buf;
+               }
+               yaml_event_delete(&event);
+       }
+
+       return rc;
+}
+
+int lcfg_param_get_yaml(yaml_parser_t *reply, struct nl_sock *sk,
+                       int version, char *pattern)
+{
+       char source[PATH_MAX / 2], group[GENL_NAMSIZ + 1];
+       char *family = "lustre", *tmp;
+       yaml_emitter_t request;
+       yaml_event_t event;
+       int cmd = 0;
+       int rc;
+
+       bzero(source, sizeof(source));
+       /* replace '/' with '.' to match conf_param and sysctl */
+       for (tmp = strchr(pattern, '/'); tmp != NULL;
+            tmp = strchr(tmp, '/'))
+               *tmp = '.';
+
+       tmp = strrchr(pattern, '.');
+       if (tmp) {
+               size_t len = tmp - pattern;
+
+               strncpy(group, tmp + 1, GENL_NAMSIZ);
+               strncpy(source, pattern, len);
+       } else {
+               strncpy(group, pattern, GENL_NAMSIZ);
+       }
+
+       if (strcmp(group, "devices") == 0)
+               cmd = LUSTRE_CMD_DEVICES;
+
+       if (!cmd)
+               return -EOPNOTSUPP;
+
+       /* Setup parser to recieve Netlink packets */
+       rc = yaml_parser_initialize(reply);
+       if (rc == 0)
+               return -EOPNOTSUPP;
+
+       rc = yaml_parser_set_input_netlink(reply, sk, false);
+       if (rc == 0)
+               return -EOPNOTSUPP;
+
+       /* Create Netlink emitter to send request to kernel */
+       yaml_emitter_initialize(&request);
+       rc = yaml_emitter_set_output_netlink(&request, sk,
+                                            family, version,
+                                            cmd, NLM_F_DUMP);
+       if (rc == 0)
+               goto 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 error;
+
+       yaml_mapping_start_event_initialize(&event, NULL,
+                                           (yaml_char_t *)YAML_MAP_TAG,
+                                           1, YAML_ANY_MAPPING_STYLE);
+       rc = yaml_emitter_emit(&request, &event);
+       if (rc == 0)
+               goto error;
+
+       yaml_scalar_event_initialize(&event, NULL,
+                                    (yaml_char_t *)YAML_STR_TAG,
+                                    (yaml_char_t *)group,
+                                    strlen(group), 1, 0,
+                                    YAML_PLAIN_SCALAR_STYLE);
+       rc = yaml_emitter_emit(&request, &event);
+       if (rc == 0)
+               goto error;
+
+       if (source[0]) {
+               const char *key = cmd == LUSTRE_CMD_DEVICES ? "name" : "source";
+
+               /* Now fill in 'path' filter */
+               yaml_sequence_start_event_initialize(&event, NULL,
+                                                    (yaml_char_t *)YAML_SEQ_TAG,
+                                                    1, YAML_ANY_SEQUENCE_STYLE);
+               rc = yaml_emitter_emit(&request, &event);
+               if (rc == 0)
+                       goto error;
+
+               yaml_mapping_start_event_initialize(&event, NULL,
+                                                   (yaml_char_t *)YAML_MAP_TAG,
+                                                   1, YAML_ANY_MAPPING_STYLE);
+               rc = yaml_emitter_emit(&request, &event);
+               if (rc == 0)
+                       goto error;
+
+               yaml_scalar_event_initialize(&event, NULL,
+                                            (yaml_char_t *)YAML_STR_TAG,
+                                            (yaml_char_t *)key, strlen(key),
+                                            1, 0, YAML_PLAIN_SCALAR_STYLE);
+               rc = yaml_emitter_emit(&request, &event);
+               if (rc == 0)
+                       goto error;
+
+               yaml_scalar_event_initialize(&event, NULL,
+                                            (yaml_char_t *)YAML_STR_TAG,
+                                            (yaml_char_t *)source,
+                                            strlen(source), 1, 0,
+                                            YAML_PLAIN_SCALAR_STYLE);
+               rc = yaml_emitter_emit(&request, &event);
+               if (rc == 0)
+                       goto error;
+
+               yaml_mapping_end_event_initialize(&event);
+               rc = yaml_emitter_emit(&request, &event);
+               if (rc == 0)
+                       goto error;
+
+               yaml_sequence_end_event_initialize(&event);
+               rc = yaml_emitter_emit(&request, &event);
+               if (rc == 0)
+                       goto 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 error;
+       }
+       yaml_mapping_end_event_initialize(&event);
+       rc = yaml_emitter_emit(&request, &event);
+       if (rc == 0)
+               goto error;
+
+       yaml_document_end_event_initialize(&event, 0);
+       rc = yaml_emitter_emit(&request, &event);
+       if (rc == 0)
+               goto error;
+
+       yaml_emitter_close(&request);
+error:
+       if (rc == 0) {
+               yaml_emitter_log_error(&request, stderr);
+               rc = -EINVAL;
+       }
+       yaml_emitter_delete(&request);
+
+       return rc == 1 ? 0 : -EINVAL;
+}
+
+int llapi_param_display_value(char *path, int version,
+                             enum lctl_param_flags flags, FILE *fp)
+{
+       yaml_parser_t reply;
+       struct nl_sock *sk;
+       int rc;
+
+       /* version zero means just list sources. "devices is special case */
+       if (!version && strcmp(path, "devices") == 0) {
+               fprintf(fp, "devices\n");
+               return 0;
+       }
+
+       sk = nl_socket_alloc();
+       if (!sk)
+               return -ENOMEM;
+
+       rc = lcfg_param_get_yaml(&reply, sk, version, path);
+       if (rc < 0)
+               return rc;
+
+       if (flags & PARAM_FLAGS_YAML_FORMAT) {
+               yaml_document_t results;
+               yaml_emitter_t output;
+
+               /* load the reply results */
+               rc = yaml_parser_load(&reply, &results);
+               if (rc == 0) {
+                       yaml_parser_log_error(&reply, stderr, "get_param: ");
+                       yaml_document_delete(&results);
+                       rc = -EINVAL;
+                       goto free_reply;
+               }
+
+               /* create emitter to output results */
+               rc = yaml_emitter_initialize(&output);
+               if (rc == 1) {
+                       yaml_emitter_set_output_file(&output, fp);
+
+                       rc = yaml_emitter_dump(&output, &results);
+               }
+
+               yaml_document_delete(&results);
+               if (rc == 0) {
+                       yaml_emitter_log_error(&output, stderr);
+                       rc = -EINVAL;
+               }
+               yaml_emitter_delete(&output);
+       } else {
+               yaml_event_t event;
+               bool done = false;
+
+               while (!done) {
+                       rc = yaml_parser_parse(&reply, &event);
+                       if (rc == 0)
+                               break;
+
+                       if (event.type == YAML_SCALAR_EVENT) {
+                               char *value = (char *)event.data.scalar.value;
+
+                               if (strcmp(value, "devices") == 0)
+                                       rc = print_out_devices(&reply, flags);
+                               if (rc == 0)
+                                       break;
+                       }
+
+                       done = (event.type == YAML_STREAM_END_EVENT);
+                       yaml_event_delete(&event);
+               }
+
+               if (rc == 0) {
+                       yaml_parser_log_error(&reply, stderr, "get_param: ");
+                       rc = -EINVAL;
+               }
+       }
+free_reply:
+       yaml_parser_delete(&reply);
+       nl_socket_free(sk);
+       return rc == 1 ? 0 : rc;
+}
+
 /**
  * Read the value of the file with location \a path
  * into a buffer.
index 0b2a603..8adddcd 100644 (file)
@@ -939,137 +939,33 @@ fail_print:
        printf("%s%s%s\n", s, buf[0] ? " " : "", buf);
 }
 
-static int print_out_devices(yaml_parser_t *reply, struct param_opts *popt)
+int yaml_get_device_index(char *source)
 {
-       char buf[MAX_OBD_NAME], *tmp = NULL;
-       size_t buf_len = sizeof(buf);
-       yaml_event_t event;
-       bool done = false;
-       int rc;
-
-       bzero(buf, sizeof(buf));
-
-       while (!done) {
-               rc = yaml_parser_parse(reply, &event);
-               if (rc == 0)
-                       break;
-
-               if (event.type == YAML_MAPPING_START_EVENT) {
-                       size_t len = strlen(buf);
-
-                       if (len > 0) {
-                               /* eat last white space */
-                               buf[len - 1] = '\0';
-                               if (popt->po_detail)
-                                       print_obd_line(buf);
-                               else
-                                       printf("%s\n",  buf);
-                       }
-                       bzero(buf, sizeof(buf));
-                       tmp = buf;
-               }
-
-               if (event.type == YAML_SCALAR_EVENT) {
-                       char *value = (char *)event.data.scalar.value;
-
-                       if (strcmp(value, "index") == 0) {
-                               yaml_event_delete(&event);
-                               rc = yaml_parser_parse(reply, &event);
-                               if (rc == 0)
-                                       break;
-
-                               value = (char *)event.data.scalar.value;
-
-                               snprintf(tmp, buf_len, "%3s ", value);
-                               buf_len -= 4;
-                               tmp += 4;
-                       }
-
-                       if (strcmp(value, "status") == 0 ||
-                           strcmp(value, "type") == 0 ||
-                           strcmp(value, "name") == 0 ||
-                           strcmp(value, "uuid") == 0 ||
-                           strcmp(value, "refcount") == 0) {
-                               yaml_event_delete(&event);
-                               rc = yaml_parser_parse(reply, &event);
-                               if (rc == 0)
-                                       break;
-
-                               value = (char *)event.data.scalar.value;
-
-                               snprintf(tmp, buf_len, "%s ", value);
-                               buf_len -= strlen(value) + 1;
-                               tmp += strlen(value) + 1;
-                       }
-               }
-
-               done = (event.type == YAML_DOCUMENT_END_EVENT);
-               if (done) {
-                       size_t len = strlen(buf);
-
-                       if (len > 0) {
-                               /* eat last white space */
-                               buf[len - 1] = '\0';
-                               if (popt->po_detail)
-                                       print_obd_line(buf);
-                               else
-                                       printf("%s\n", buf);
-                       }
-                       bzero(buf, sizeof(buf));
-                       tmp = buf;
-               }
-               yaml_event_delete(&event);
-       }
-
-       return rc;
-}
-
-int lcfg_param_get_yaml(yaml_parser_t *reply, struct nl_sock *sk, char *pattern)
-{
-       char source[MAX_OBD_NAME], group[GENL_NAMSIZ + 1];
-       int version = LUSTRE_GENL_VERSION;
-       char *family = "lustre", *tmp;
        yaml_emitter_t request;
+       yaml_parser_t reply;
        yaml_event_t event;
-       int cmd = 0;
+       struct nl_sock *sk;
+       bool done = false;
        int rc;
 
-       bzero(source, sizeof(source));
-       tmp = strrchr(pattern, '/');
-       if (tmp) {
-               size_t len = tmp - pattern;
-
-               strncpy(group, tmp + 1, GENL_NAMSIZ);
-               strncpy(source, pattern, len);
-
-               /* replace '/' with '.' to match conf_param and sysctl */
-               for (tmp = strchr(pattern, '/'); tmp != NULL;
-                    tmp = strchr(tmp, '/'))
-                       *tmp = '.';
-       } else {
-               strncpy(group, pattern, GENL_NAMSIZ);
-       }
-
-       if (strcmp(group, "devices") == 0)
-               cmd = LUSTRE_CMD_DEVICES;
-
-       if (!cmd)
+       sk = nl_socket_alloc();
+       if (!sk)
                return -EOPNOTSUPP;
 
        /* Setup parser to recieve Netlink packets */
-       rc = yaml_parser_initialize(reply);
+       rc = yaml_parser_initialize(&reply);
        if (rc == 0)
                return -EOPNOTSUPP;
 
-       rc = yaml_parser_set_input_netlink(reply, sk, false);
+       rc = yaml_parser_set_input_netlink(&reply, sk, false);
        if (rc == 0)
                return -EOPNOTSUPP;
 
        /* Create Netlink emitter to send request to kernel */
        yaml_emitter_initialize(&request);
-       rc = yaml_emitter_set_output_netlink(&request, sk,
-                                            family, version,
-                                            cmd, NLM_F_DUMP);
+       rc = yaml_emitter_set_output_netlink(&request, sk, "lustre",
+                                            LUSTRE_GENL_VERSION,
+                                            LUSTRE_CMD_DEVICES, NLM_F_DUMP);
        if (rc == 0)
                goto error;
 
@@ -1089,67 +985,55 @@ int lcfg_param_get_yaml(yaml_parser_t *reply, struct nl_sock *sk, char *pattern)
 
        yaml_scalar_event_initialize(&event, NULL,
                                     (yaml_char_t *)YAML_STR_TAG,
-                                    (yaml_char_t *)group,
-                                    strlen(group), 1, 0,
+                                    (yaml_char_t *)"devices",
+                                    strlen("devices"), 1, 0,
                                     YAML_PLAIN_SCALAR_STYLE);
        rc = yaml_emitter_emit(&request, &event);
        if (rc == 0)
                goto error;
 
-       if (source[0]) {
-               const char *key = "name";
+       yaml_sequence_start_event_initialize(&event, NULL,
+                                            (yaml_char_t *)YAML_SEQ_TAG,
+                                            1, YAML_ANY_SEQUENCE_STYLE);
+       rc = yaml_emitter_emit(&request, &event);
+       if (rc == 0)
+               goto error;
 
-               /* Now fill in 'path' filter */
-               yaml_sequence_start_event_initialize(&event, NULL,
-                                                    (yaml_char_t *)YAML_SEQ_TAG,
-                                                    1, YAML_ANY_SEQUENCE_STYLE);
-               rc = yaml_emitter_emit(&request, &event);
-               if (rc == 0)
-                       goto error;
+       yaml_mapping_start_event_initialize(&event, NULL,
+                                           (yaml_char_t *)YAML_MAP_TAG,
+                                           1, YAML_ANY_MAPPING_STYLE);
+       rc = yaml_emitter_emit(&request, &event);
+       if (rc == 0)
+               goto error;
 
-               yaml_mapping_start_event_initialize(&event, NULL,
-                                                   (yaml_char_t *)YAML_MAP_TAG,
-                                                   1, YAML_ANY_MAPPING_STYLE);
-               rc = yaml_emitter_emit(&request, &event);
-               if (rc == 0)
-                       goto 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 error;
 
-               yaml_scalar_event_initialize(&event, NULL,
-                                            (yaml_char_t *)YAML_STR_TAG,
-                                            (yaml_char_t *)key, strlen(key),
-                                            1, 0, YAML_PLAIN_SCALAR_STYLE);
-               rc = yaml_emitter_emit(&request, &event);
-               if (rc == 0)
-                       goto error;
-
-               yaml_scalar_event_initialize(&event, NULL,
-                                            (yaml_char_t *)YAML_STR_TAG,
-                                            (yaml_char_t *)source,
-                                            strlen(source), 1, 0,
-                                            YAML_PLAIN_SCALAR_STYLE);
-               rc = yaml_emitter_emit(&request, &event);
-               if (rc == 0)
-                       goto error;
+       yaml_scalar_event_initialize(&event, NULL,
+                                    (yaml_char_t *)YAML_STR_TAG,
+                                    (yaml_char_t *)source,
+                                    strlen(source), 1, 0,
+                                    YAML_PLAIN_SCALAR_STYLE);
+       rc = yaml_emitter_emit(&request, &event);
+       if (rc == 0)
+               goto error;
 
-               yaml_mapping_end_event_initialize(&event);
-               rc = yaml_emitter_emit(&request, &event);
-               if (rc == 0)
-                       goto error;
+       yaml_mapping_end_event_initialize(&event);
+       rc = yaml_emitter_emit(&request, &event);
+       if (rc == 0)
+               goto error;
+
+       yaml_sequence_end_event_initialize(&event);
+       rc = yaml_emitter_emit(&request, &event);
+       if (rc == 0)
+               goto error;
 
-               yaml_sequence_end_event_initialize(&event);
-               rc = yaml_emitter_emit(&request, &event);
-               if (rc == 0)
-                       goto 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 error;
-       }
        yaml_mapping_end_event_initialize(&event);
        rc = yaml_emitter_emit(&request, &event);
        if (rc == 0)
@@ -1168,81 +1052,39 @@ error:
        }
        yaml_emitter_delete(&request);
 
-       return rc == 1 ? 0 : -EINVAL;
-}
-
-int lcfg_getparam_yaml(char *path, struct param_opts *popt)
-{
-       yaml_parser_t reply;
-       struct nl_sock *sk;
-       int rc;
-
-       sk = nl_socket_alloc();
-       if (!sk)
-               return -ENOMEM;
-
-       rc = lcfg_param_get_yaml(&reply, sk, path);
-       if (rc < 0)
-               return rc;
-
-       if (popt->po_yaml) {
-               yaml_document_t results;
-               yaml_emitter_t output;
-
-               /* load the reply results */
-               rc = yaml_parser_load(&reply, &results);
+       while (!done) {
+               rc = yaml_parser_parse(&reply, &event);
                if (rc == 0) {
-                       yaml_parser_log_error(&reply, stderr, "get_param: ");
-                       yaml_document_delete(&results);
+                       yaml_parser_log_error(&reply, stdout, "lctl: ");
                        rc = -EINVAL;
-                       goto free_reply;
-               }
-
-               /* create emitter to output results */
-               rc = yaml_emitter_initialize(&output);
-               if (rc == 1) {
-                       yaml_emitter_set_output_file(&output, stdout);
-
-                       rc = yaml_emitter_dump(&output, &results);
+                       break;
                }
 
-               yaml_document_delete(&results);
-               if (rc == 0) {
-                       yaml_emitter_log_error(&output, stderr);
-                       rc = -EINVAL;
-               }
-               yaml_emitter_delete(&output);
-       } else {
-               yaml_event_t event;
-               bool done = false;
-
-               while (!done) {
-                       rc = yaml_parser_parse(&reply, &event);
-                       if (rc == 0)
-                               break;
-
-                       if (event.type == YAML_SCALAR_EVENT) {
-                               char *value = (char *)event.data.scalar.value;
+               if (event.type == YAML_SCALAR_EVENT) {
+                       char *value = (char *)event.data.scalar.value;
 
-                               if (strcmp(value, "devices") == 0)
-                                       rc = print_out_devices(&reply, popt);
-                               if (rc == 0)
-                                       break;
+                       if (strcmp(value, "index") == 0) {
+                               yaml_event_delete(&event);
+                               rc = yaml_parser_parse(&reply, &event);
+                               if (rc == 1) {
+                                       value = (char *)event.data.scalar.value;
+                                       errno = 0;
+                                       rc = strtoul(value, NULL, 10);
+                                       if (errno) {
+                                               yaml_event_delete(&event);
+                                               rc = -errno;
+                                       }
+                                       return rc;
+                               }
                        }
-
-                       done = (event.type == YAML_STREAM_END_EVENT);
-                       yaml_event_delete(&event);
-               }
-
-               if (rc == 0) {
-                       yaml_parser_log_error(&reply, stderr, "get_param: ");
-                       rc = -EINVAL;
                }
+               done = (event.type == YAML_STREAM_END_EVENT);
+               yaml_event_delete(&event);
        }
-free_reply:
-       yaml_parser_delete(&reply);
+
        nl_socket_free(sk);
-       return rc == 1 ? 0 : rc;
+
+       return rc;
 }
 
 /**
@@ -1487,10 +1329,17 @@ int jt_lcfg_listparam(int argc, char **argv)
 
                rc2 = param_display(&popt, path, NULL, LIST_PARAM);
                if (rc2 < 0) {
-                       fprintf(stderr, "error: %s: listing '%s': %s\n",
-                               jt_cmdname(argv[0]), path, strerror(-rc2));
+                       if (rc2 == -ENOENT && getuid() != 0)
+                               rc2 = llapi_param_display_value(path, 0, 0,
+                                                               stdout);
                        if (rc == 0)
                                rc = rc2;
+
+                       if (rc < 0) {
+                               fprintf(stderr, "error: %s: listing '%s': %s\n",
+                                       jt_cmdname(argv[0]), path,
+                                       strerror(-rc2));
+                       }
                        continue;
                }
        }
@@ -1504,7 +1353,7 @@ static int getparam_cmdline(int argc, char **argv, struct param_opts *popt)
 
        popt->po_show_path = 1;
 
-       while ((ch = getopt(argc, argv, "FnNR")) != -1) {
+       while ((ch = getopt(argc, argv, "FnNRy")) != -1) {
                switch (ch) {
                case 'F':
                        popt->po_show_type = 1;
@@ -1518,6 +1367,9 @@ static int getparam_cmdline(int argc, char **argv, struct param_opts *popt)
                case 'R':
                        popt->po_recursive = 1;
                        break;
+               case 'y':
+                       popt->po_yaml = 1;
+                       break;
                default:
                        return -1;
                }
@@ -1528,9 +1380,11 @@ static int getparam_cmdline(int argc, char **argv, struct param_opts *popt)
 
 int jt_lcfg_getparam(int argc, char **argv)
 {
+       int version = LUSTRE_GENL_VERSION;
        enum parameter_operation mode;
        int rc = 0, index, i;
        struct param_opts popt;
+       int flags = 0;
        char *path;
 
        memset(&popt, 0, sizeof(popt));
@@ -1539,6 +1393,14 @@ int jt_lcfg_getparam(int argc, char **argv)
                return CMD_HELP;
 
        mode = popt.po_only_path ? LIST_PARAM : GET_PARAM;
+       if (mode == LIST_PARAM)
+               version = 0;
+
+       if (popt.po_yaml)
+               flags |= PARAM_FLAGS_YAML_FORMAT;
+       if (popt.po_show_path)
+               flags |= PARAM_FLAGS_SHOW_SOURCE;
+
        for (i = index; i < argc; i++) {
                int rc2;
 
@@ -1555,10 +1417,9 @@ int jt_lcfg_getparam(int argc, char **argv)
 
                rc2 = param_display(&popt, path, NULL, mode);
                if (rc2 < 0) {
-                       if (mode == GET_PARAM && rc2 == -ENOENT &&
-                           getuid() != 0)
-                               rc2 = lcfg_getparam_yaml(path, &popt);
-
+                       if (rc2 == -ENOENT && getuid() != 0)
+                               rc2 = llapi_param_display_value(path, version,
+                                                               flags, stdout);
                        if (rc == 0)
                                rc = rc2;
                        continue;
@@ -1569,7 +1430,7 @@ int jt_lcfg_getparam(int argc, char **argv)
 }
 
 /* get device list by netlink or debugfs */
-int jt_obd_list(int argc, char **argv)
+int jt_device_list(int argc, char **argv)
 {
        static const struct option long_opts[] = {
                { .name = "target",     .has_arg = no_argument, .val = 't' },
@@ -1578,12 +1439,12 @@ int jt_obd_list(int argc, char **argv)
        };
        struct param_opts opts;
        char buf[MAX_OBD_NAME];
-       struct nl_sock *sk;
+       int flags = 0;
        glob_t path;
        int rc, c;
        FILE *fp;
 
-       if (optind < argc)
+       if (optind + 1 < argc)
                return CMD_HELP;
 
        memset(&opts, 0, sizeof(opts));
@@ -1591,9 +1452,11 @@ int jt_obd_list(int argc, char **argv)
        while ((c = getopt_long(argc, argv, "ty", long_opts, NULL)) != -1) {
                switch (c) {
                case 't':
+                       flags |= PARAM_FLAGS_EXTRA_DETAILS;
                        opts.po_detail = true;
                        break;
                case 'y':
+                       flags |= PARAM_FLAGS_YAML_FORMAT;
                        opts.po_yaml = true;
                        break;
                default:
@@ -1607,21 +1470,12 @@ int jt_obd_list(int argc, char **argv)
        }
        optind = 1;
 
-       sk = nl_socket_alloc();
-       if (!sk)
-               goto non_netlink;
-
        /* Use YAML to list all devices */
-       rc = lcfg_getparam_yaml("devices", &opts);
+       rc = llapi_param_display_value("devices", LUSTRE_GENL_VERSION, flags,
+                                      stdout);
        if (rc == 0)
                return 0;
 
-non_netlink:
-       if (sk) {
-               nl_close(sk);
-               nl_socket_free(sk);
-       }
-
        rc = llapi_param_get_paths("devices", &path);
        if (rc < 0)
                return rc;
@@ -1647,63 +1501,11 @@ static int do_name2dev(char *func, char *name, int dev_id)
 {
        struct obd_ioctl_data data;
        char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
-       yaml_parser_t output;
-       yaml_event_t event;
-       struct nl_sock *sk;
-       bool done = false;
-       int rc = 0;
-
-       memset(buf, 0, sizeof(rawbuf));
-       scnprintf(buf, sizeof(rawbuf), "%s/devices",
-                 name);
-
-       sk = nl_socket_alloc();
-       if (!sk)
-               goto ioctl;
-
-       /* Use YAML to list all devices */
-       rc = lcfg_param_get_yaml(&output, sk, buf);
-       if (rc < 0) {
-               if (rc == -EOPNOTSUPP)
-                       goto ioctl;
-               return rc;
-       }
-
-       while (!done) {
-               rc = yaml_parser_parse(&output, &event);
-               if (rc == 0) {
-                       yaml_parser_log_error(&output, stdout, "lctl: ");
-                       rc = -EINVAL;
-                       break;
-               }
-
-               if (event.type == YAML_SCALAR_EVENT) {
-                       char *value = (char *)event.data.scalar.value;
-
-                       if (strcmp(value, "index") == 0) {
-                               yaml_event_delete(&event);
-                               rc = yaml_parser_parse(&output, &event);
-                               if (rc == 1) {
-                                       value = (char *)event.data.scalar.value;
-                                       errno = 0;
-                                       rc = strtoul(value, NULL, 10);
-                                       if (errno) {
-                                               yaml_event_delete(&event);
-                                               rc = -errno;
-                                               goto ioctl;
-                                       }
-                                       return rc;
-                               }
-                       }
-               }
-               done = (event.type == YAML_STREAM_END_EVENT);
-               yaml_event_delete(&event);
-       }
-ioctl:
-       if (sk)
-               nl_socket_free(sk);
+       int rc;
 
-       if (rc > 0 || rc != -EOPNOTSUPP)
+       /* Use YAML to find device index */
+       rc = yaml_get_device_index(name);
+       if (rc >= 0 || rc != -EOPNOTSUPP)
                return rc;
 
        memset(&data, 0, sizeof(data));
index 72e2ecc..a66cee4 100644 (file)
@@ -184,6 +184,15 @@ int libcfs_ukuc_get_rfd(struct lustre_kernelcomm *link);
 int libcfs_ukuc_msg_get(struct lustre_kernelcomm *l, char *buf, int maxsize,
                        int transport);
 
+enum lctl_param_flags {
+       PARAM_FLAGS_YAML_FORMAT         = 0x0001,
+       PARAM_FLAGS_SHOW_SOURCE         = 0x0002,
+       PARAM_FLAGS_EXTRA_DETAILS       = 0x0004,
+};
+
+int llapi_param_display_value(char *path, int version,
+                             enum lctl_param_flags flags, FILE *fp);
+
 enum get_lmd_info_type {
        GET_LMD_INFO = 1,
        GET_LMD_STRIPE = 2,
index d3f5908..8ceeb5a 100644 (file)
@@ -97,7 +97,7 @@ int jt_obd_no_transno(int argc, char **argv);
 int jt_obd_set_readonly(int argc, char **argv);
 int jt_obd_abort_recovery(int argc, char **argv);
 int jt_obd_abort_recovery_mdt(int argc, char **argv);
-int jt_obd_list(int argc, char **argv);
+int jt_device_list(int argc, char **argv);
 int jt_obd_create(int argc, char **argv);
 int jt_obd_test_create(int argc, char **argv);
 int jt_obd_test_mkdir(int argc, char **argv);