4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 only,
8 * as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License version 2 for more details (a copy is included
14 * in the LICENSE file that accompanied this code).
16 * You should have received a copy of the GNU General Public License
17 * version 2 along with this program; If not, see
18 * http://www.gnu.org/licenses/gpl-2.0.html
23 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Use is subject to license terms.
26 * Copyright (c) 2011, 2016, Intel Corporation.
29 * This file is part of Lustre, http://www.lustre.org/
31 * lustre/utils/lustre_cfg.c
33 * Author: Peter J. Braam <braam@clusterfs.com>
34 * Author: Phil Schwan <phil@clusterfs.com>
35 * Author: Andreas Dilger <adilger@clusterfs.com>
36 * Author: Robert Read <rread@clusterfs.com>
46 #include <sys/ioctl.h>
52 #include <libcfs/util/ioctl.h>
53 #include <libcfs/util/string.h>
54 #include <libcfs/util/param.h>
55 #include <libcfs/util/parser.h>
56 #include <lustre/lustreapi.h>
57 #include <linux/lnet/nidstr.h>
58 #include <linux/lnet/lnetctl.h>
59 #include <linux/lustre/lustre_cfg.h>
60 #include <linux/lustre/lustre_ioctl.h>
61 #include <linux/lustre/lustre_kernelcomm.h>
62 #include <linux/lustre/lustre_ver.h>
63 #include <lnetconfig/liblnetconfig.h>
65 #include "lctl_thread.h"
66 #include "lustreapi_internal.h"
78 static char *lcfg_devname;
80 int lcfg_set_devname(char *name)
88 /* quietly strip the unnecessary '$' */
89 if (*name == '$' || *name == '%')
93 while (*ptr != '\0') {
102 /* We can't translate from dev # to name */
105 lcfg_devname = strdup(name);
113 char *lcfg_get_devname(void)
118 int jt_lcfg_device(int argc, char **argv)
120 return jt_obd_device(argc, argv);
123 static int jt_lcfg_ioctl(struct lustre_cfg_bufs *bufs, char *arg, int cmd)
125 struct lustre_cfg *lcfg;
128 lcfg = malloc(lustre_cfg_len(bufs->lcfg_bufcount, bufs->lcfg_buflen));
132 lustre_cfg_init(lcfg, cmd, bufs);
133 rc = lcfg_ioctl(arg, OBD_DEV_ID, lcfg);
137 fprintf(stderr, "error: %s: %s\n", jt_cmdname(arg),
138 strerror(rc = errno));
142 int jt_lcfg_attach(int argc, char **argv)
144 struct lustre_cfg_bufs bufs;
150 lustre_cfg_bufs_reset(&bufs, NULL);
152 lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
153 lustre_cfg_bufs_set_string(&bufs, 0, argv[2]);
154 lustre_cfg_bufs_set_string(&bufs, 2, argv[3]);
156 rc = jt_lcfg_ioctl(&bufs, argv[0], LCFG_ATTACH);
158 lcfg_set_devname(argv[2]);
163 int jt_lcfg_setup(int argc, char **argv)
165 struct lustre_cfg_bufs bufs;
170 "%s: please use 'device name' to set the device name for config commands.\n",
171 jt_cmdname(argv[0]));
175 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
180 for (i = 1; i < argc; i++)
181 lustre_cfg_bufs_set_string(&bufs, i, argv[i]);
183 return jt_lcfg_ioctl(&bufs, argv[0], LCFG_SETUP);
186 int jt_obd_detach(int argc, char **argv)
188 struct lustre_cfg_bufs bufs;
192 "%s: please use 'device name' to set the device name for config commands.\n",
193 jt_cmdname(argv[0]));
197 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
202 return jt_lcfg_ioctl(&bufs, argv[0], LCFG_DETACH);
205 int jt_obd_cleanup(int argc, char **argv)
207 struct lustre_cfg_bufs bufs;
210 char flags[3] = { 0 };
215 "%s: please use 'device name' to set the device name for config commands.\n",
216 jt_cmdname(argv[0]));
220 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
222 if (argc < 1 || argc > 3)
226 * we are protected from overflowing our buffer by the argc
229 for (n = 1; n < argc; n++) {
230 if (strcmp(argv[n], "force") == 0) {
231 flags[flag_cnt++] = force;
232 } else if (strcmp(argv[n], "failover") == 0) {
233 flags[flag_cnt++] = failover;
235 fprintf(stderr, "unknown option: %s\n", argv[n]);
241 lustre_cfg_bufs_set_string(&bufs, 1, flags);
243 return jt_lcfg_ioctl(&bufs, argv[0], LCFG_CLEANUP);
247 int do_add_uuid(char *func, char *uuid, struct lnet_nid *nid)
250 char nidstr[LNET_NIDSTR_SIZE];
251 struct lustre_cfg_bufs bufs;
252 struct lustre_cfg *lcfg;
254 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
256 lustre_cfg_bufs_set_string(&bufs, 1, uuid);
257 if (!nid_is_nid4(nid)) {
258 libcfs_nidstr_r(nid, nidstr, sizeof(nidstr));
259 lustre_cfg_bufs_set_string(&bufs, 2, nidstr);
262 lcfg = malloc(lustre_cfg_len(bufs.lcfg_bufcount, bufs.lcfg_buflen));
266 lustre_cfg_init(lcfg, LCFG_ADD_UUID, &bufs);
267 if (nid_is_nid4(nid))
268 lcfg->lcfg_nid = lnet_nid_to_nid4(nid);
272 rc = lcfg_ioctl(func, OBD_DEV_ID, lcfg);
276 fprintf(stderr, "IOC_PORTAL_ADD_UUID failed: %s\n",
282 printf("Added uuid %s: %s\n", uuid, libcfs_nidstr(nid));
287 int jt_lcfg_add_uuid(int argc, char **argv)
294 if (libcfs_strnid(&nid, argv[2]) < 0) {
295 fprintf(stderr, "Can't parse NID %s\n", argv[2]);
299 return do_add_uuid(argv[0], argv[1], &nid);
302 int jt_lcfg_del_uuid(int argc, char **argv)
304 struct lustre_cfg_bufs bufs;
307 fprintf(stderr, "usage: %s <uuid>\n", argv[0]);
311 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
312 if (strcmp(argv[1], "_all_"))
313 lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
315 return jt_lcfg_ioctl(&bufs, argv[0], LCFG_DEL_UUID);
318 int jt_lcfg_del_mount_option(int argc, char **argv)
320 struct lustre_cfg_bufs bufs;
325 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
328 lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
330 return jt_lcfg_ioctl(&bufs, argv[0], LCFG_DEL_MOUNTOPT);
333 int jt_lcfg_set_timeout(int argc, char **argv)
336 struct lustre_cfg_bufs bufs;
337 struct lustre_cfg *lcfg;
340 "%s has been deprecated. Use conf_param instead.\ne.g. conf_param lustre-MDT0000 obd_timeout=50\n",
341 jt_cmdname(argv[0]));
347 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
349 lcfg = malloc(lustre_cfg_len(bufs.lcfg_bufcount, bufs.lcfg_buflen));
353 lustre_cfg_init(lcfg, LCFG_SET_TIMEOUT, &bufs);
354 lcfg->lcfg_num = atoi(argv[1]);
356 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
360 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
361 strerror(rc = errno));
366 int jt_lcfg_add_conn(int argc, char **argv)
368 struct lustre_cfg_bufs bufs;
369 struct lustre_cfg *lcfg;
382 "%s: please use 'device name' to set the device name for config commands.\n",
383 jt_cmdname(argv[0]));
387 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
389 lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
391 lcfg = malloc(lustre_cfg_len(bufs.lcfg_bufcount, bufs.lcfg_buflen));
395 lustre_cfg_init(lcfg, LCFG_ADD_CONN, &bufs);
396 lcfg->lcfg_num = priority;
398 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
402 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
403 strerror(rc = errno));
409 int jt_lcfg_del_conn(int argc, char **argv)
411 struct lustre_cfg_bufs bufs;
418 "%s: please use 'device name' to set the device name for config commands.\n",
419 jt_cmdname(argv[0]));
423 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
425 /* connection uuid */
426 lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
428 return jt_lcfg_ioctl(&bufs, argv[0], LCFG_DEL_MOUNTOPT);
431 /* Param set locally, directly on target */
432 int jt_lcfg_param(int argc, char **argv)
434 struct lustre_cfg_bufs bufs;
437 if (argc >= LUSTRE_CFG_MAX_BUFCOUNT)
440 lustre_cfg_bufs_reset(&bufs, NULL);
442 for (i = 1; i < argc; i++)
443 lustre_cfg_bufs_set_string(&bufs, i, argv[i]);
445 return jt_lcfg_ioctl(&bufs, argv[0], LCFG_PARAM);
448 static int lcfg_setparam_perm(char *func, char *buf)
451 struct lustre_cfg_bufs bufs;
452 struct lustre_cfg *lcfg;
454 lustre_cfg_bufs_reset(&bufs, NULL);
456 * This same command would be executed on all nodes, many
457 * of which should fail (silently) because they don't have
458 * that proc file existing locally. There would be no
459 * preprocessing on the MGS to try to figure out which
460 * parameter files to add this to, there would be nodes
461 * processing on the cluster nodes to try to figure out
462 * if they are the intended targets. They will blindly
463 * try to set the parameter, and ENOTFOUND means it wasn't
465 * Target name "general" means call on all targets. It is
466 * left here in case some filtering will be added in
469 lustre_cfg_bufs_set_string(&bufs, 0, "general");
471 lustre_cfg_bufs_set_string(&bufs, 1, buf);
473 lcfg = malloc(lustre_cfg_len(bufs.lcfg_bufcount,
477 fprintf(stderr, "error: allocating lcfg for %s: %s\n",
478 jt_cmdname(func), strerror(rc));
481 lustre_cfg_init(lcfg, LCFG_SET_PARAM, &bufs);
482 rc = lcfg_mgs_ioctl(func, OBD_DEV_ID, lcfg);
484 fprintf(stderr, "error: executing %s: %s\n",
485 jt_cmdname(func), strerror(errno));
493 * Param set to single log file, used by all clients and servers.
494 * This should be loaded after the individual config logs.
495 * Called from set param with -P option.
497 static int jt_lcfg_setparam_perm(int argc, char **argv,
498 struct param_opts *popt)
505 first_param = optind;
506 if (first_param < 0 || first_param >= argc)
509 for (i = first_param, rc = 0; i < argc; i++) {
511 if (popt->po_delete) {
516 /* Consider param ends at the first '=' in the buffer
517 * and make sure it always ends with '=' as well
519 end_pos = memchr(buf, '=', len - 1);
522 } else if (buf[len - 1] != '=') {
523 buf = malloc(len + 2);
526 sprintf(buf, "%s=", argv[i]);
530 rc = lcfg_setparam_perm(argv[0], buf);
538 static int lcfg_conf_param(char *func, char *buf)
541 struct lustre_cfg_bufs bufs;
542 struct lustre_cfg *lcfg;
544 lustre_cfg_bufs_reset(&bufs, NULL);
545 lustre_cfg_bufs_set_string(&bufs, 1, buf);
547 /* We could put other opcodes here. */
548 lcfg = malloc(lustre_cfg_len(bufs.lcfg_bufcount, bufs.lcfg_buflen));
552 lustre_cfg_init(lcfg, LCFG_PARAM, &bufs);
553 rc = lcfg_mgs_ioctl(func, OBD_DEV_ID, lcfg);
563 * Param set in config log on MGS
564 * conf_param key=value
566 * Note we can actually send mgc conf_params from clients, but currently
567 * that's only done for default file striping (see ll_send_mgc_param),
570 * After removal of a parameter (-d) Lustre will use the default
571 * AT NEXT REBOOT, not immediately.
573 int jt_lcfg_confparam(int argc, char **argv)
579 /* mgs_setparam processes only lctl buf #1 */
580 if ((argc > 3) || (argc <= 1))
583 while ((rc = getopt(argc, argv, "d")) != -1) {
598 /* for delete, make it "<param>=\0" */
599 buf = malloc(strlen(argv[optind]) + 2);
604 /* put an '=' on the end in case it doesn't have one */
605 sprintf(buf, "%s=", argv[optind]);
606 /* then truncate after the first '=' */
607 ptr = strchr(buf, '=');
611 rc = lcfg_conf_param(argv[0], buf);
613 if (buf != argv[optind])
617 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
625 * Display a parameter path in the same format as sysctl.
626 * E.g. obdfilter.lustre-OST0000.stats
628 * \param[in] filename file name of the parameter
629 * \param[in] st parameter file stats
630 * \param[in] popt set/get param options
632 * \retval allocated pointer containing modified filename
635 display_name(const char *filename, struct stat *st, struct param_opts *popt)
637 size_t suffix_len = 0;
642 if (popt->po_show_type) {
643 if (S_ISDIR(st->st_mode))
645 else if (S_ISLNK(st->st_mode))
647 else if (st->st_mode & S_IWUSR)
651 /* Take the original filename string and chop off the glob addition */
652 tmp = strstr(filename, "/lustre/");
654 tmp = strstr(filename, "/lnet/");
656 tmp += strlen("/lnet/");
658 tmp += strlen("/lustre/");
661 /* Allocate return string */
662 param_name = strdup(tmp);
666 /* replace '/' with '.' to match conf_param and sysctl */
667 for (tmp = strchr(param_name, '/'); tmp != NULL; tmp = strchr(tmp, '/'))
670 /* Append the indicator to entries if needed. */
671 if (popt->po_show_type && suffix != NULL) {
672 suffix_len = strlen(suffix);
674 tmp = realloc(param_name, suffix_len + strlen(param_name) + 1);
677 strncat(param_name, suffix,
678 strlen(param_name) + suffix_len);
686 * Turns a lctl parameter string into a procfs/sysfs subdirectory path pattern.
688 * \param[in] popt Used to control parameter usage. For this
689 * function it is used to see if the path has
691 * \param[in,out] path lctl parameter string that is turned into
692 * the subdirectory path pattern that is used
693 * to search the procfs/sysfs tree.
695 * \retval -errno on error.
698 clean_path(struct param_opts *popt, char *path)
700 char *nidstart = NULL;
704 if (popt == NULL || path == NULL || strlen(path) == 0)
707 /* If path contains a suffix we need to remove it */
708 if (popt->po_show_type) {
709 size_t path_end = strlen(path) - 1;
711 tmp = path + path_end;
722 /* get rid of '\', glob doesn't like it */
723 tmp = strrchr(path, '\\');
725 char *tail = path + strlen(path);
727 while (tmp != path) {
729 memmove(tmp, tmp + 1, tail - tmp);
736 /* Does path contain a NID string? Skip '.->/' replacement for it. */
737 tmp = strchr(path, '@');
739 /* First find the NID start. NIDs may have variable (0-4) '.',
740 * so find the common NID prefixes instead of trying to count
741 * the dots. Not great, but there are only two, and faster
742 * than multiple speculative NID parses and bad DNS lookups.
744 if ((tmp = strstr(path, ".exports.")))
745 nidstart = tmp + strlen(".exports.");
746 else if ((tmp = strstr(path, ".MGC")))
749 /* Next, find the end of the NID string. */
751 nidend = strchrnul(strchr(nidstart, '@'), '.');
754 /* replace param '.' with '/' */
755 for (tmp = strchr(path, '.'); tmp != NULL; tmp = strchr(tmp, '.')) {
759 * There exist cases where some of the subdirectories of the
760 * the parameter tree has embedded in its name a NID string.
761 * This means that it is possible that these subdirectories
762 * could have actual '.' in its name. If this is the case we
763 * don't want to blindly replace the '.' with '/', so skip
764 * over the part of the parameter containing the NID.
774 * The application lctl can perform three operations for lustre
775 * tunables. This enum defines those three operations which are
777 * 1) LIST_PARAM - list available tunables
778 * 2) GET_PARAM - report the current setting of a tunable
779 * 3) SET_PARAM - set the tunable to a new value
781 enum parameter_operation {
787 char *parameter_opname[] = {
788 [LIST_PARAM] = "list_param",
789 [GET_PARAM] = "get_param",
790 [SET_PARAM] = "set_param",
794 * Read the value of parameter
796 * \param[in] path full path to the parameter
797 * \param[in] param_name lctl parameter format of the
799 * \param[in] popt set/get param options
801 * \retval 0 on success.
802 * \retval -errno on error.
805 read_param(const char *path, const char *param_name, struct param_opts *popt)
811 rc = llapi_param_get_value(path, &buf, &buflen);
814 "error: read_param: \'%s\': %s\n",
815 path, strerror(-rc));
818 /* don't print anything for empty files */
819 if (buf[0] == '\0') {
821 printf("%s=\n", param_name);
825 if (popt->po_header) {
830 /* Split at first \n, if any */
831 next = strchrnul(oldbuf, '\n');
833 printf("%s=%.*s\n", param_name, (int)(next - oldbuf),
836 buflen -= next - oldbuf + 1;
839 } while (buflen > 0);
841 } else if (popt->po_show_path) {
842 bool multilines = memchr(buf, '\n', buflen - 1);
844 printf("%s=%s%s", param_name, multilines ? "\n" : "", buf);
855 * Set a parameter to a specified value
857 * \param[in] path full path to the parameter
858 * \param[in] param_name lctl parameter format of the parameter path
859 * \param[in] popt set/get param options
860 * \param[in] value value to set the parameter to
862 * \retval number of bytes written on success.
863 * \retval -errno on error.
866 write_param(const char *path, const char *param_name, struct param_opts *popt,
875 /* Write the new value to the file */
876 fd = open(path, O_WRONLY);
879 fprintf(stderr, "error: set_param: opening '%s': %s\n",
880 path, strerror(errno));
884 count = write(fd, value, strlen(value));
888 fprintf(stderr, "error: set_param: setting %s=%s: %s\n",
889 path, value, strerror(errno));
891 } else if (count < strlen(value)) { /* Truncate case */
894 "error: set_param: setting %s=%s: wrote only %zd\n",
896 } else if (popt->po_show_path) {
897 printf("%s=%s\n", param_name, value);
904 static void print_obd_line(char *s)
906 const char *param = "osc/%s/ost_conn_uuid";
907 char obd_name[MAX_OBD_NAME];
908 char buf[MAX_OBD_NAME];
913 /* obd device type is the first 3 characters of param name */
914 snprintf(buf, sizeof(buf), " %%*d %%*s %.3s %%%zus %%*s %%*d ",
915 param, sizeof(obd_name) - 1);
916 if (sscanf(s, buf, obd_name) == 0)
918 if (cfs_get_param_paths(&path, param, obd_name) != 0)
920 fp = fopen(path.gl_pathv[0], "r");
922 /* need to free path data before retry */
923 cfs_free_param_data(&path);
925 if (param[0] == 'o') { /* failed with osc, try mdc */
926 param = "mdc/%s/mds_conn_uuid";
933 /* should not ignore fgets(3)'s return value */
934 if (!fgets(buf, sizeof(buf), fp)) {
935 fprintf(stderr, "reading from %s: %s", buf, strerror(errno));
941 cfs_free_param_data(&path);
943 /* trim trailing newlines */
944 ptr = strrchr(buf, '\n');
948 ptr = strrchr(s, '\n');
951 printf("%s%s%s\n", s, buf[0] ? " " : "", buf);
954 static int yaml_get_device_index(char *source)
956 yaml_emitter_t request;
963 sk = nl_socket_alloc();
967 /* Setup parser to recieve Netlink packets */
968 rc = yaml_parser_initialize(&reply);
972 rc = yaml_parser_set_input_netlink(&reply, sk, false);
976 /* Create Netlink emitter to send request to kernel */
977 yaml_emitter_initialize(&request);
978 rc = yaml_emitter_set_output_netlink(&request, sk, "lustre",
980 LUSTRE_CMD_DEVICES, NLM_F_DUMP);
984 yaml_emitter_open(&request);
986 yaml_document_start_event_initialize(&event, NULL, NULL, NULL, 0);
987 rc = yaml_emitter_emit(&request, &event);
991 yaml_mapping_start_event_initialize(&event, NULL,
992 (yaml_char_t *)YAML_MAP_TAG,
993 1, YAML_ANY_MAPPING_STYLE);
994 rc = yaml_emitter_emit(&request, &event);
998 yaml_scalar_event_initialize(&event, NULL,
999 (yaml_char_t *)YAML_STR_TAG,
1000 (yaml_char_t *)"devices",
1001 strlen("devices"), 1, 0,
1002 YAML_PLAIN_SCALAR_STYLE);
1003 rc = yaml_emitter_emit(&request, &event);
1007 yaml_sequence_start_event_initialize(&event, NULL,
1008 (yaml_char_t *)YAML_SEQ_TAG,
1009 1, YAML_ANY_SEQUENCE_STYLE);
1010 rc = yaml_emitter_emit(&request, &event);
1014 yaml_mapping_start_event_initialize(&event, NULL,
1015 (yaml_char_t *)YAML_MAP_TAG,
1016 1, YAML_ANY_MAPPING_STYLE);
1017 rc = yaml_emitter_emit(&request, &event);
1021 yaml_scalar_event_initialize(&event, NULL,
1022 (yaml_char_t *)YAML_STR_TAG,
1023 (yaml_char_t *)"name",
1025 1, 0, YAML_PLAIN_SCALAR_STYLE);
1026 rc = yaml_emitter_emit(&request, &event);
1030 yaml_scalar_event_initialize(&event, NULL,
1031 (yaml_char_t *)YAML_STR_TAG,
1032 (yaml_char_t *)source,
1033 strlen(source), 1, 0,
1034 YAML_PLAIN_SCALAR_STYLE);
1035 rc = yaml_emitter_emit(&request, &event);
1039 yaml_mapping_end_event_initialize(&event);
1040 rc = yaml_emitter_emit(&request, &event);
1044 yaml_sequence_end_event_initialize(&event);
1045 rc = yaml_emitter_emit(&request, &event);
1049 yaml_mapping_end_event_initialize(&event);
1050 rc = yaml_emitter_emit(&request, &event);
1054 yaml_document_end_event_initialize(&event, 0);
1055 rc = yaml_emitter_emit(&request, &event);
1059 yaml_emitter_close(&request);
1062 yaml_emitter_log_error(&request, stderr);
1065 yaml_emitter_delete(&request);
1068 rc = yaml_parser_parse(&reply, &event);
1070 yaml_parser_log_error(&reply, stdout, "lctl: ");
1075 if (event.type == YAML_SCALAR_EVENT) {
1076 char *value = (char *)event.data.scalar.value;
1078 if (strcmp(value, "index") == 0) {
1079 yaml_event_delete(&event);
1080 rc = yaml_parser_parse(&reply, &event);
1082 value = (char *)event.data.scalar.value;
1084 rc = strtoul(value, NULL, 10);
1086 yaml_event_delete(&event);
1093 done = (event.type == YAML_STREAM_END_EVENT);
1094 yaml_event_delete(&event);
1104 * Perform a read, write or just a listing of a parameter
1106 * \param[in] popt list,set,get parameter options
1107 * \param[in] pattern search filter for the path of the parameter
1108 * \param[in] value value to set the parameter if write operation
1109 * \param[in] oper what operation to perform with the parameter
1110 * \param[out] wq the work queue to which work items will be added or NULL
1111 * if not in parallel
1113 * \retval number of bytes written on success.
1114 * \retval -errno on error and prints error message.
1117 do_param_op(struct param_opts *popt, char *pattern, char *value,
1118 enum parameter_operation oper, struct sp_workq *wq)
1123 char *opname = parameter_opname[oper];
1126 if (!wq && popt_is_parallel(*popt))
1129 rc = llapi_param_get_paths(pattern, &paths);
1132 if (!popt->po_recursive && !(rc == -ENOENT && getuid() != 0)) {
1133 fprintf(stderr, "error: %s: param_path '%s': %s\n",
1134 opname, pattern, strerror(errno));
1139 if (popt_is_parallel(*popt) && paths.gl_pathc > 1) {
1140 /* Allocate space for the glob paths in advance. */
1141 rc = spwq_expand(wq, paths.gl_pathc);
1146 dup_cache = calloc(paths.gl_pathc, sizeof(char *));
1150 "error: %s: allocating '%s' dup_cache[%zd]: %s\n",
1151 opname, pattern, paths.gl_pathc, strerror(-rc));
1155 for (i = 0; i < paths.gl_pathc; i++) {
1156 char *param_name = NULL, *tmp;
1157 char pathname[PATH_MAX], param_dir[PATH_MAX + 2];
1161 if (stat(paths.gl_pathv[i], &st) == -1) {
1162 fprintf(stderr, "error: %s: stat '%s': %s\n",
1163 opname, paths.gl_pathv[i], strerror(errno));
1169 if (popt->po_only_dir && !S_ISDIR(st.st_mode))
1172 param_name = display_name(paths.gl_pathv[i], &st, popt);
1175 "error: %s: generating name for '%s': %s\n",
1176 opname, paths.gl_pathv[i], strerror(ENOMEM));
1184 /* Read the contents of file to stdout */
1185 if (S_ISREG(st.st_mode)) {
1186 rc2 = read_param(paths.gl_pathv[i], param_name,
1193 if (S_ISREG(st.st_mode)) {
1194 if (popt_is_parallel(*popt))
1195 rc2 = spwq_add_item(wq,
1199 rc2 = write_param(paths.gl_pathv[i],
1209 * For the upstream client the parameter files locations
1210 * are split between under both /sys/kernel/debug/lustre
1211 * and /sys/fs/lustre. The parameter files containing
1212 * small amounts of data, less than a page in size, are
1213 * located under /sys/fs/lustre and in the case of large
1214 * parameter data files, think stats for example, are
1215 * located in the debugfs tree. Since the files are
1216 * split across two trees the directories are often
1217 * duplicated which means these directories are listed
1218 * twice which leads to duplicate output to the user.
1219 * To avoid scanning a directory twice we have to cache
1220 * any directory and check if a search has been
1223 for (j = 0; j < dup_count; j++) {
1224 if (!strcmp(dup_cache[j], param_name))
1227 if (j != dup_count) {
1232 dup_cache[dup_count++] = strdup(param_name);
1234 if (popt->po_show_path)
1235 printf("%s\n", param_name);
1240 * Only directories are searched recursively if
1241 * requested by the user
1243 if (!S_ISDIR(st.st_mode) || !popt->po_recursive) {
1249 /* Turn param_name into file path format */
1250 rc2 = clean_path(popt, param_name);
1252 fprintf(stderr, "error: %s: cleaning '%s': %s\n",
1253 opname, param_name, strerror(-rc2));
1261 /* Use param_name to grab subdirectory tree from full path */
1262 snprintf(param_dir, sizeof(param_dir), "/%s", param_name);
1263 tmp = strstr(paths.gl_pathv[i], param_dir);
1265 /* cleanup paramname now that we are done with it */
1268 memset(¶m_dir, '\0', sizeof(param_dir));
1270 /* Shouldn't happen but just in case */
1278 rc2 = snprintf(pathname, sizeof(pathname), "%s/*", tmp);
1281 * snprintf() should never an error, and if it does
1282 * there isn't much point trying to use fprintf()
1286 if (rc2 >= sizeof(pathname)) {
1287 fprintf(stderr, "error: %s: overflow processing '%s'\n",
1294 rc2 = do_param_op(popt, pathname, value, oper, wq);
1295 if (!rc2 && rc2 != -ENOENT) {
1296 /* errors will be printed by do_param_op() */
1303 for (i = 0; i < dup_count; i++)
1307 llapi_param_paths_free(&paths);
1311 static int listparam_cmdline(int argc, char **argv, struct param_opts *popt)
1315 popt->po_show_path = 1;
1316 popt->po_only_path = 1;
1318 while ((ch = getopt(argc, argv, "FRD")) != -1) {
1321 popt->po_show_type = 1;
1324 popt->po_recursive = 1;
1327 popt->po_only_dir = 1;
1337 int jt_lcfg_listparam(int argc, char **argv)
1339 int rc = 0, index, i;
1340 struct param_opts popt;
1343 memset(&popt, 0, sizeof(popt));
1344 index = listparam_cmdline(argc, argv, &popt);
1345 if (index < 0 || index >= argc)
1348 for (i = index; i < argc; i++) {
1353 rc2 = clean_path(&popt, path);
1355 fprintf(stderr, "error: %s: cleaning '%s': %s\n",
1356 jt_cmdname(argv[0]), path, strerror(-rc2));
1362 rc2 = do_param_op(&popt, path, NULL, LIST_PARAM, NULL);
1367 if (rc2 == -ENOENT && getuid() != 0)
1368 rc2 = llapi_param_display_value(path, 0, 0,
1371 fprintf(stderr, "error: %s: listing '%s': %s\n",
1372 jt_cmdname(argv[0]), path,
1382 static int getparam_cmdline(int argc, char **argv, struct param_opts *popt)
1386 popt->po_show_path = 1;
1388 while ((ch = getopt(argc, argv, "FHnNRy")) != -1) {
1391 popt->po_show_type = 1;
1394 popt->po_header = 1;
1397 popt->po_show_path = 0;
1400 popt->po_only_path = 1;
1403 popt->po_recursive = 1;
1416 int jt_lcfg_getparam(int argc, char **argv)
1418 int version = LUSTRE_GENL_VERSION;
1419 enum parameter_operation mode;
1420 int rc = 0, index, i;
1421 struct param_opts popt;
1425 memset(&popt, 0, sizeof(popt));
1426 index = getparam_cmdline(argc, argv, &popt);
1427 if (index < 0 || index >= argc)
1430 mode = popt.po_only_path ? LIST_PARAM : GET_PARAM;
1431 if (mode == LIST_PARAM)
1435 flags |= PARAM_FLAGS_YAML_FORMAT;
1436 if (popt.po_show_path)
1437 flags |= PARAM_FLAGS_SHOW_SOURCE;
1439 for (i = index; i < argc; i++) {
1444 rc2 = clean_path(&popt, path);
1446 fprintf(stderr, "error: %s: cleaning '%s': %s\n",
1447 jt_cmdname(argv[0]), path, strerror(-rc2));
1453 rc2 = do_param_op(&popt, path, NULL,
1454 popt.po_only_path ? LIST_PARAM : GET_PARAM,
1460 if (rc2 == -ENOENT && getuid() != 0)
1461 rc2 = llapi_param_display_value(path, version,
1470 /* get device list by netlink or debugfs */
1471 int jt_device_list(int argc, char **argv)
1473 static const struct option long_opts[] = {
1474 { .name = "target", .has_arg = no_argument, .val = 't' },
1475 { .name = "yaml", .has_arg = no_argument, .val = 'y' },
1478 struct param_opts opts;
1479 char buf[MAX_OBD_NAME];
1485 if (optind + 1 < argc)
1488 memset(&opts, 0, sizeof(opts));
1490 while ((c = getopt_long(argc, argv, "ty", long_opts, NULL)) != -1) {
1493 flags |= PARAM_FLAGS_EXTRA_DETAILS;
1494 opts.po_detail = true;
1497 flags |= PARAM_FLAGS_YAML_FORMAT;
1498 opts.po_yaml = true;
1505 if (optind < argc) {
1511 /* Use YAML to list all devices */
1512 rc = llapi_param_display_value("devices", LUSTRE_GENL_VERSION, flags,
1517 rc = llapi_param_get_paths("devices", &path);
1521 fp = fopen(path.gl_pathv[0], "r");
1523 cfs_free_param_data(&path);
1527 while (fgets(buf, sizeof(buf), fp) != NULL)
1529 print_obd_line(buf);
1533 cfs_free_param_data(&path);
1538 static int do_name2dev(char *func, char *name, int dev_id)
1540 struct obd_ioctl_data data;
1541 char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
1544 /* Use YAML to find device index */
1545 rc = yaml_get_device_index(name);
1546 if (rc >= 0 || rc != -EOPNOTSUPP)
1549 memset(&data, 0, sizeof(data));
1550 data.ioc_dev = dev_id;
1551 data.ioc_inllen1 = strlen(name) + 1;
1552 data.ioc_inlbuf1 = name;
1554 memset(buf, 0, sizeof(rawbuf));
1555 rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
1557 fprintf(stderr, "error: %s: invalid ioctl\n", jt_cmdname(func));
1560 rc = l_ioctl(OBD_DEV_ID, OBD_IOC_NAME2DEV, buf);
1563 rc = llapi_ioctl_unpack(&data, buf, sizeof(rawbuf));
1565 fprintf(stderr, "error: %s: invalid reply\n", jt_cmdname(func));
1569 return data.ioc_dev;
1573 * resolve a device name to a device number.
1574 * supports a number, $name or %uuid.
1576 int parse_devname(char *func, char *name, int dev_id)
1584 /* Test if its a pure number string */
1585 if (strspn(name, "0123456789") != strlen(name)) {
1586 if (name[0] == '$' || name[0] == '%')
1589 rc = do_name2dev(func, name, dev_id);
1594 ret = strtoul(name, NULL, 10);
1600 fprintf(stderr, "No device found for name %s: %s\n",
1601 name, strerror(rc));
1605 #ifdef HAVE_SERVER_SUPPORT
1607 * Output information about nodemaps.
1608 * \param argc number of args
1609 * \param argv[] variable string arguments
1611 * [list|nodemap_name|all] \a list will list all nodemaps (default).
1612 * Specifying a \a nodemap_name will
1613 * display info about that specific nodemap.
1614 * \a all will display info for all nodemaps.
1615 * \retval 0 on success
1617 int jt_nodemap_info(int argc, char **argv)
1619 const char usage_str[] = "usage: nodemap_info [list|nodemap_name|all]\n";
1620 struct param_opts popt;
1623 memset(&popt, 0, sizeof(popt));
1624 popt.po_show_path = 1;
1627 fprintf(stderr, usage_str);
1631 if (argc == 1 || strcmp("list", argv[1]) == 0) {
1632 popt.po_only_dir = 1;
1633 rc = do_param_op(&popt, "nodemap/*", NULL, LIST_PARAM, NULL);
1634 } else if (strcmp("all", argv[1]) == 0) {
1635 rc = do_param_op(&popt, "nodemap/*/*", NULL, GET_PARAM, NULL);
1637 char pattern[PATH_MAX];
1639 snprintf(pattern, sizeof(pattern), "nodemap/%s/*", argv[1]);
1640 rc = do_param_op(&popt, pattern, NULL, GET_PARAM, NULL);
1643 "error: nodemap_info: cannot find nodemap %s\n",
1651 * Parses the command-line options to set_param.
1653 * \param[in] argc count of arguments given to set_param
1654 * \param[in] argv array of arguments given to set_param
1655 * \param[out] popt where set_param options will be saved
1657 * \retval index in argv of the first non-option argv element (optind value)
1659 static int setparam_cmdline(int argc, char **argv, struct param_opts *popt)
1663 popt->po_show_path = 1;
1664 popt->po_only_path = 0;
1665 popt->po_show_type = 0;
1666 popt->po_recursive = 0;
1668 popt->po_delete = 0;
1670 popt->po_parallel_threads = 0;
1673 while ((ch = getopt(argc, argv, "dFnPt::")) != -1) {
1676 popt->po_show_path = 0;
1681 popt->po_parallel_threads = atoi(optarg);
1683 popt->po_parallel_threads = LCFG_THREADS_DEF;
1684 if (popt->po_parallel_threads < 2)
1689 static bool printed;
1694 "warning: set_param: no pthread support, proceeding serially.\n");
1703 popt->po_delete = 1;
1712 if (popt->po_perm && popt->po_file) {
1713 fprintf(stderr, "warning: ignoring -P option\n");
1720 * Parse the arguments to set_param and return the first parameter and value
1721 * pair and the number of arguments consumed.
1723 * \param[in] argc number of arguments remaining in argv
1724 * \param[in] argv list of param-value arguments to set_param (this function
1725 * will modify the strings by overwriting '=' with '\0')
1726 * \param[out] param the parameter name
1727 * \param[out] value the parameter value
1729 * \retval the number of args consumed from argv (1 for "param=value" format, 2
1730 * for "param value" format)
1731 * \retval -errno if unsuccessful
1733 static int sp_parse_param_value(int argc, char **argv, char **param,
1738 if (argc < 1 || !(argv && param && value))
1742 tmp = strchr(*param, '=');
1744 /* format: set_param a=b */
1753 /* format: set_param a b */
1768 #define PS_PARAM_FOUND 1
1769 #define PS_PARAM_SET 2
1770 #define PS_VAL_FOUND 4
1771 #define PS_VAL_SET 8
1772 #define PS_DEVICE_FOUND 16
1773 #define PS_DEVICE_SET 32
1775 #define PARAM_SZ 256
1777 static struct cfg_type_data {
1778 enum paramtype ptype;
1780 } cfg_type_table[] = {
1781 { PT_SETPARAM, "set_param" },
1782 { PT_CONFPARAM, "conf_param" },
1786 static struct cfg_stage_data {
1789 } cfg_stage_table[] = {
1790 { PS_PARAM_FOUND, "parameter" },
1791 { PS_VAL_FOUND, "value" },
1792 { PS_DEVICE_FOUND, "device" },
1796 static enum paramtype construct_param(enum paramtype confset, const char *param,
1797 const char *device, char *buf,
1798 int bufsize, bool convert)
1802 if (confset == PT_SETPARAM) {
1803 strncpy(buf, param, bufsize);
1807 * sys.* params are top level, we just need to trim the sys.
1809 tmp = strstr(param, "sys.");
1812 strncpy(buf, tmp, bufsize);
1818 * parameters look like type.parameter, we need to stick the
1819 * device in the middle. Example combine mdt.identity_upcall
1820 * with device lustre-MDT0000 for
1821 * mdt.lustre-MDT0000.identity_upcall
1824 tmp = strchrnul(param, '.');
1825 snprintf(buf, tmp - param + 1, "%s", param);
1827 bufsize -= tmp - param;
1828 snprintf(buf, bufsize, ".%s%s", device, tmp);
1831 /* create for conf_param */
1832 if (strlen(device)) {
1835 rc = snprintf(buf, bufsize, "%s.%s", device, param);
1843 static int lcfg_apply_param_yaml(char *func, char *filename)
1846 yaml_parser_t parser;
1848 int rc = 0, rc1 = 0;
1850 enum paramtype confset = PT_NONE;
1851 int param = PS_NONE;
1853 char parameter[PARAM_SZ + 1];
1854 char value[PARAM_SZ + 1];
1855 char device[PARAM_SZ + 1];
1858 convert = !strncmp(func, "set_param", 9);
1859 file = fopen(filename, "rb");
1865 rc = yaml_parser_initialize(&parser);
1870 yaml_parser_set_input_file(&parser, file);
1873 * Search tokens for conf_param or set_param
1874 * The token after "parameter" goes into parameter
1875 * The token after "value" goes into value
1876 * when we have all 3, create param=val and call the
1877 * appropriate function for set/conf param
1879 while (token.type != YAML_STREAM_END_TOKEN) {
1882 yaml_token_delete(&token);
1883 if (!yaml_parser_scan(&parser, &token)) {
1888 if (token.type != YAML_SCALAR_TOKEN)
1891 for (i = 0; cfg_type_table[i].ptype != PT_NONE; i++) {
1892 if (!strncmp((char *)token.data.alias.value,
1893 cfg_type_table[i].type_name,
1894 strlen(cfg_type_table[i].type_name))) {
1895 confset = cfg_type_table[i].ptype;
1900 if (confset == PT_NONE)
1903 for (i = 0; cfg_stage_table[i].pstage != PS_NONE; i++) {
1904 if (!strncmp((char *)token.data.alias.value,
1905 cfg_stage_table[i].stage_name,
1906 strlen(cfg_stage_table[i].stage_name))) {
1907 param |= cfg_stage_table[i].pstage;
1912 if (cfg_stage_table[i].pstage != PS_NONE)
1915 if (param & PS_PARAM_FOUND) {
1918 rc = construct_param(confset,
1919 (char *)token.data.alias.value,
1920 device, parameter, PARAM_SZ, convert);
1923 printf("error: conf_param without device\n");
1925 param |= PS_PARAM_SET;
1926 param &= ~PS_PARAM_FOUND;
1929 * we're getting parameter: param=val
1930 * copy val and mark that we've got it in case
1931 * there is no value: tag
1933 tmp = strchrnul(parameter, '=');
1935 strncpy(value, tmp + 1, sizeof(value) - 1);
1937 param |= PS_VAL_SET;
1941 } else if (param & PS_VAL_FOUND) {
1942 strncpy(value, (char *)token.data.alias.value,
1944 param |= PS_VAL_SET;
1945 param &= ~PS_VAL_FOUND;
1946 } else if (param & PS_DEVICE_FOUND) {
1947 strncpy(device, (char *)token.data.alias.value,
1949 param |= PS_DEVICE_SET;
1950 param &= ~PS_DEVICE_FOUND;
1953 if (confset && param & PS_VAL_SET && param & PS_PARAM_SET) {
1954 int size = strlen(parameter) + strlen(value) + 2;
1955 char *buf = malloc(size);
1961 snprintf(buf, size, "%s=%s", parameter, value);
1963 printf("%s: %s\n", confset == PT_SETPARAM ?
1964 "set_param" : "conf_param", buf);
1966 if (confset == PT_SETPARAM)
1967 rc = lcfg_setparam_perm(func, buf);
1969 rc = lcfg_conf_param(func, buf);
1971 printf("error: failed to apply parameter rc = %d, tyring next one\n",
1978 parameter[0] = '\0';
1985 yaml_parser_delete(&parser);
1992 int jt_lcfg_applyyaml(int argc, char **argv)
1995 struct param_opts popt = {0};
1997 index = setparam_cmdline(argc, argv, &popt);
1998 if (index < 0 || index >= argc)
2001 return lcfg_apply_param_yaml(argv[0], argv[index]);
2005 * Main set_param function.
2007 * \param[in] argc count of arguments given to set_param
2008 * \param[in] argv array of arguments given to set_param
2010 * \retval 0 if successful
2011 * \retval -errno if unsuccessful
2013 int jt_lcfg_setparam(int argc, char **argv)
2017 struct param_opts popt;
2019 struct sp_workq *wq_ptr = NULL;
2021 memset(&popt, 0, sizeof(popt));
2022 index = setparam_cmdline(argc, argv, &popt);
2023 if (index < 0 || index >= argc)
2028 * We can't delete parameters that were
2029 * set with old conf_param interface
2031 return jt_lcfg_setparam_perm(argc, argv, &popt);
2034 #if LUSTRE_VERSION >= OBD_OCD_VERSION(2,17,0,0)
2035 fprintf(stderr, "warning: 'lctl set_param -F' is deprecated, use 'lctl apply_yaml' instead\n");
2038 printf("This option left for backward compatibility, please use 'lctl apply_yaml' instead\n");
2039 return lcfg_apply_param_yaml(argv[0], argv[index]);
2043 if (popt_is_parallel(popt)) {
2044 rc = spwq_init(&wq, &popt);
2047 "warning: parallel %s: failed to init work queue: %s. Proceeding serially.\n",
2048 jt_cmdname(argv[0]), strerror(-rc));
2050 popt.po_parallel_threads = 0;
2056 while (index < argc) {
2060 rc = sp_parse_param_value(argc - index, argv + index,
2063 fprintf(stderr, "error: %s: setting %s: %s\n",
2064 jt_cmdname(argv[0]), path, strerror(-rc));
2067 /* Increment index by the number of arguments consumed. */
2070 rc = clean_path(&popt, path);
2074 rc = do_param_op(&popt, path, value, SET_PARAM, wq_ptr);
2076 fprintf(stderr, "error: %s: setting '%s'='%s': %s\n",
2077 jt_cmdname(argv[0]), path, value,
2081 if (popt_is_parallel(popt)) {
2083 /* Spawn threads to set the parameters which made it into the
2084 * work queue to emulate serial set_param behavior when errors
2085 * are encountered above.
2087 rc2 = sp_run_threads(&wq);
2090 "error: parallel %s: failed to run threads: %s\n",
2091 jt_cmdname(argv[0]), strerror(-rc2));
2095 rc2 = spwq_destroy(&wq);
2098 "warning: parallel %s: failed to cleanup work queue: %s\n",
2099 jt_cmdname(argv[0]), strerror(-rc2));