Whamcloud - gitweb
LU-12168 utils: obdfilter fix for SHORT msgs
[fs/lustre-release.git] / lustre / utils / obd.c
index 1f641ae..3825730 100644 (file)
@@ -530,16 +530,21 @@ static void shmem_snap(int total_threads, int live_threads)
         }
 
         secs = difftime(&this_time, &prev_time);
-        if (prev_valid && secs > 1.0)    /* someone screwed with the time? */
-                printf("%d/%d Total: %f/second\n", non_zero, total_threads,
-                       total / secs);
+       if (prev_valid && secs > 1.0) {   /* someone screwed with the time? */
+               printf("%d/%d Total: %f/second\n", non_zero, total_threads,
+                      total / secs);
 
-        memcpy(counter_snapshot[1], counter_snapshot[0],
-               total_threads * sizeof(counter_snapshot[0][0]));
-        prev_time = this_time;
-        if (!prev_valid &&
-            running == total_threads)
-                prev_valid = 1;
+               memcpy(counter_snapshot[1], counter_snapshot[0],
+                      total_threads * sizeof(counter_snapshot[0][0]));
+               prev_time = this_time;
+       }
+       if (!prev_valid && running == total_threads) {
+               prev_valid = 1;
+               /* drop counters when all threads were started */
+               memcpy(counter_snapshot[1], counter_snapshot[0],
+                      total_threads * sizeof(counter_snapshot[0][0]));
+               prev_time = this_time;
+       }
 }
 
 static void shmem_stop(void)
@@ -1715,6 +1720,7 @@ int jt_obd_destroy(int argc, char **argv)
         if (argc < 2 || argc > 4)
                 return CMD_HELP;
 
+       errno = 0;
         id = strtoull(argv[1], &end, 0);
         if (*end || id == 0 || errno != 0) {
                 fprintf(stderr, "error: %s: invalid objid '%s'\n",
@@ -2280,7 +2286,7 @@ repeat:
                                desc.ld_default_stripe_count);
                printf("default_stripe_size: %ju\n",
                       (uintmax_t)desc.ld_default_stripe_size);
-               printf("default_stripe_offset: %ju\n",
+               printf("default_stripe_offset: %jd\n",
                       (uintmax_t)desc.ld_default_stripe_offset);
                 printf("default_stripe_pattern: %u\n", desc.ld_pattern);
                 printf("obd_count: %u\n", desc.ld_tgt_count);
@@ -2342,8 +2348,8 @@ static int do_activate(int argc, char **argv, int flag)
  * are skipped and recorded with new nids and uuid.
  *
  * \see mgs_replace_nids
- * \see mgs_replace_nids_log
- * \see mgs_replace_handler
+ * \see mgs_replace_log
+ * \see mgs_replace_nids_handler
  */
 int jt_replace_nids(int argc, char **argv)
 {
@@ -2378,6 +2384,52 @@ int jt_replace_nids(int argc, char **argv)
        return rc;
 }
 
+/**
+ * Clear config logs for given device or filesystem.
+ * lctl clear_conf <devicename|fsname>
+ * Command has to be run on MGS node having MGS device mounted with -o
+ * nosvc.
+ *
+ * Configuration logs for filesystem or one particular log is
+ * processed. New log is created, original log is read, its records
+ * marked SKIP do not get copied to new log. Others are copied as-is.
+ * Original file is renamed to log.${time}.bak.
+ *
+ * \see mgs_clear_configs
+ * \see mgs_replace_log
+ * \see mgs_clear_config_handler
+ **/
+int jt_lcfg_clear(int argc, char **argv)
+{
+       int rc;
+       char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
+       struct obd_ioctl_data data;
+
+       memset(&data, 0, sizeof(data));
+       data.ioc_dev = get_mgs_device();
+       if (argc != 2)
+               return CMD_HELP;
+
+       data.ioc_inllen1 = strlen(argv[1]) + 1;
+       data.ioc_inlbuf1 = argv[1];
+
+       memset(buf, 0, sizeof(rawbuf));
+       rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
+       if (rc) {
+               fprintf(stderr, "error: %s: invalid ioctl\n",
+                       jt_cmdname(argv[0]));
+               return rc;
+       }
+
+       rc = l2_ioctl(OBD_DEV_ID, OBD_IOC_CLEAR_CONFIGS, buf);
+       if (rc < 0) {
+               fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
+                       strerror(rc = errno));
+       }
+
+       return rc;
+}
+
 int jt_obd_deactivate(int argc, char **argv)
 {
         return do_activate(argc, argv, 0);
@@ -2556,7 +2608,7 @@ int jt_llog_catlist(int argc, char **argv)
 
         memset(&data, 0, sizeof(data));
         data.ioc_dev = cur_device;
-        data.ioc_inllen1 = sizeof(rawbuf) - cfs_size_round(sizeof(data));
+       data.ioc_inllen1 = sizeof(rawbuf) - __ALIGN_KERNEL(sizeof(data), 8);
         memset(buf, 0, sizeof(rawbuf));
        rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
         if (rc) {
@@ -2576,129 +2628,353 @@ int jt_llog_catlist(int argc, char **argv)
 
 int jt_llog_info(int argc, char **argv)
 {
-        struct obd_ioctl_data data;
-        char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
-        int rc;
+       const struct option long_opts[] = {
+       /* Allow optional "--catalog" for compatibility with llog commands. */
+       { .val = 'c',   .name = "catalog",      .has_arg = required_argument },
+       { .val = 'h',   .name = "help",         .has_arg = no_argument },
+       { .name = NULL } };
+       struct obd_ioctl_data data = { 0 };
+       char rawbuf[MAX_IOC_BUFLEN] = "", *buf = rawbuf;
+       char *cmd = argv[0];
+       char *catalog = NULL;
+       int rc, c;
 
-        if (argc != 2)
-                return CMD_HELP;
+       while ((c = getopt_long(argc, argv, "c:h", long_opts, NULL)) != -1) {
+               switch (c) {
+               case 'c':
+                       catalog = optarg;
+                       break;
+               case 'h':
+               default:
+                       return CMD_HELP;
+               }
+       }
+       argc -= optind;
+       argv += optind;
+       /* support "logname" positional parameter */
+       if (argc == 1) {
+               if (catalog) {
+                       fprintf(stderr,
+                               "%s: catalog is set, unknown argument '%s'\n",
+                               cmd, optarg);
+                       return CMD_HELP;
+               }
+               catalog = argv[0];
+       } else if (!catalog || argc > 1) {
+               return CMD_HELP;
+       }
 
-        memset(&data, 0, sizeof(data));
-        data.ioc_dev = cur_device;
-        data.ioc_inllen1 = strlen(argv[1]) + 1;
-        data.ioc_inlbuf1 = argv[1];
-        data.ioc_inllen2 = sizeof(rawbuf) - cfs_size_round(sizeof(data)) -
-                cfs_size_round(data.ioc_inllen1);
-        memset(buf, 0, sizeof(rawbuf));
+       data.ioc_dev = cur_device;
+       data.ioc_inllen1 = strlen(catalog) + 1;
+       data.ioc_inlbuf1 = catalog;
+       data.ioc_inllen2 = sizeof(rawbuf) - __ALIGN_KERNEL(sizeof(data), 8) -
+                          __ALIGN_KERNEL(data.ioc_inllen1, 8);
        rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
-        if (rc) {
-                fprintf(stderr, "error: %s: invalid ioctl\n",
-                        jt_cmdname(argv[0]));
-                return rc;
-        }
+       if (rc) {
+               fprintf(stderr, "%s: ioctl_pack failed for catalog '%s': %s\n",
+                       jt_cmdname(cmd), catalog, strerror(-rc));
+               return rc;
+       }
 
-        rc = l_ioctl(OBD_DEV_ID, OBD_IOC_LLOG_INFO, buf);
-        if (rc == 0)
-                fprintf(stdout, "%s", ((struct obd_ioctl_data*)buf)->ioc_bulk);
-        else
-                fprintf(stderr, "OBD_IOC_LLOG_INFO failed: %s\n",
-                        strerror(errno));
+       rc = l_ioctl(OBD_DEV_ID, OBD_IOC_LLOG_INFO, buf);
+       if (rc == 0)
+               fprintf(stdout, "%s", ((struct obd_ioctl_data *)buf)->ioc_bulk);
+       else
+               fprintf(stderr, "%s: OBD_IOC_LLOG_INFO failed: %s\n",
+                       jt_cmdname(cmd), strerror(errno));
 
-        return rc;
+       return rc;
 }
 
-int jt_llog_print(int argc, char **argv)
+int jt_llog_print_cb(const char *record, void *private)
 {
-        struct obd_ioctl_data data;
-        char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
-        int rc;
+       printf("%s\n", record);
 
-        if (argc != 2 && argc != 4)
-                return CMD_HELP;
+       return 0;
+}
 
-        memset(&data, 0, sizeof(data));
-        data.ioc_dev = cur_device;
-        data.ioc_inllen1 = strlen(argv[1]) + 1;
-        data.ioc_inlbuf1 = argv[1];
-        if (argc == 4) {
-                data.ioc_inllen2 = strlen(argv[2]) + 1;
-                data.ioc_inlbuf2 = argv[2];
-                data.ioc_inllen3 = strlen(argv[3]) + 1;
-                data.ioc_inlbuf3 = argv[3];
-        } else {
-                char from[2] = "1", to[3] = "-1";
-                data.ioc_inllen2 = strlen(from) + 1;
-                data.ioc_inlbuf2 = from;
-                data.ioc_inllen3 = strlen(to) + 1;
-                data.ioc_inlbuf3 = to;
-        }
-        data.ioc_inllen4 = sizeof(rawbuf) - cfs_size_round(sizeof(data)) -
-                cfs_size_round(data.ioc_inllen1) -
-                cfs_size_round(data.ioc_inllen2) -
-                cfs_size_round(data.ioc_inllen3);
-        memset(buf, 0, sizeof(rawbuf));
-       rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
-        if (rc) {
-                fprintf(stderr, "error: %s: invalid ioctl\n",
-                        jt_cmdname(argv[0]));
-                return rc;
-        }
+/**
+ * Iterate over llog records, typically YAML-formatted configuration logs
+ *
+ * \param logname[in]  name of llog file or FID
+ * \param start[in]    first record to process
+ * \param end[in]      last record to process (inclusive)
+ * \param cb[in]       callback for records. Return -ve error, or +ve abort.
+ * \param private[in,out] private data passed to the \a record_cb function
+ */
+int jt_llog_print_iter(char *logname, long start, long end,
+                      int (record_cb)(const char *record, void *private),
+                      void *private)
+{
+       struct obd_ioctl_data data = { 0 };
+       char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
+       char startbuf[16], endbuf[16];
+       static long inc = sizeof(rawbuf) / 128;
+       long rec;
+       int rc = 0;
 
-        rc = l_ioctl(OBD_DEV_ID, OBD_IOC_LLOG_PRINT, buf);
-        if (rc == 0)
-                fprintf(stdout, "%s", ((struct obd_ioctl_data*)buf)->ioc_bulk);
-        else
-                fprintf(stderr, "OBD_IOC_LLOG_PRINT failed: %s\n",
-                        strerror(errno));
+       if (end == -1)
+               end = 0x7fffffff;
 
-        return rc;
+       data.ioc_dev = cur_device;
+       data.ioc_inlbuf1 = logname;
+       data.ioc_inllen1 = strlen(logname) + 1;
+
+       /*
+        * Estimate about 128 characters per configuration record.  Not all
+        * records will be printed in any case, so they should easily fit.  If
+        * not, the kernel will return -EOVERFLOW and ask for fewer records.
+        *
+        * We don't want to request records from the kernel one-at-a-time, as
+        * it restarts the config llog iteration from the beginning, so we
+        * fetch multiple records from the kernel per call and split locally.
+        */
+       for (rec = start; rec < end; rec += inc) {
+               char *record = ((struct obd_ioctl_data *)buf)->ioc_bulk;
+               char *ptr;
+
+retry:
+               snprintf(startbuf, sizeof(startbuf), "%lu", rec);
+               snprintf(endbuf, sizeof(endbuf), "%lu",
+                        end < rec + inc - 1 ? end : rec + inc - 1);
+
+               /* start and end record numbers are passed as ASCII digits */
+               data.ioc_inlbuf2 = startbuf;
+               data.ioc_inllen2 = strlen(startbuf) + 1;
+               data.ioc_inlbuf3 = endbuf;
+               data.ioc_inllen3 = strlen(endbuf) + 1;
+
+               data.ioc_inllen4 = sizeof(rawbuf) -
+                       __ALIGN_KERNEL(sizeof(data), 8) -
+                       __ALIGN_KERNEL(data.ioc_inllen1, 8) -
+                       __ALIGN_KERNEL(data.ioc_inllen2, 8) -
+                       __ALIGN_KERNEL(data.ioc_inllen3, 8);
+               memset(buf, 0, sizeof(rawbuf));
+               rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
+               if (rc) {
+                       fprintf(stderr, "%s: invalid ioctl data\n", logname);
+                       goto out;
+               }
+
+               rc = l_ioctl(OBD_DEV_ID, OBD_IOC_LLOG_PRINT, buf);
+               if (rc == -EOVERFLOW && inc > 2) {
+                       inc /= 2;
+                       goto retry;
+               }
+               if (rc) {
+                       fprintf(stderr, "%s: OBD_IOC_LLOG_PRINT failed: %s\n",
+                               logname, strerror(errno));
+                       rc = -errno;
+                       goto out;
+               }
+
+               /* There is no "end of list" marker, record was not modified */
+               if (strcmp(record, logname) == 0)
+                       break;
+
+               do {
+                       ptr = strchr(record, '\n');
+                       if (ptr)
+                               *ptr = '\0';
+                       rc = record_cb(record, private);
+                       if (rc) {
+                               if (rc > 0)
+                                       rc = 0;
+                               goto out;
+                       }
+
+                       if (ptr)
+                               record = ptr + 1;
+               } while (ptr && *(ptr + 1));
+       }
+
+out:
+       return rc;
+}
+
+static int llog_parse_catalog_start_end(int *argc, char **argv[],
+                                       char **catalog, long *start, long *end)
+{
+       const struct option long_opts[] = {
+       /* the --catalog option is not required, just for consistency */
+       { .val = 'c',   .name = "catalog",      .has_arg = required_argument },
+       { .val = 'e',   .name = "end",          .has_arg = required_argument },
+       { .val = 'h',   .name = "help",         .has_arg = no_argument },
+       { .val = 's',   .name = "start",        .has_arg = required_argument },
+       { .name = NULL } };
+       char *cmd = (*argv)[0];
+       char *endp;
+       int c;
+
+       if (catalog == NULL || start == NULL || end == NULL)
+               return -EINVAL;
+
+       /* now process command line arguments*/
+       while ((c = getopt_long(*argc, *argv, "c:e:hs:",
+                               long_opts, NULL)) != -1) {
+               switch (c) {
+               case 'c':
+                       *catalog = optarg;
+                       break;
+               case 'e':
+                       *end = strtol(optarg, &endp, 0);
+                       if (*endp != '\0') {
+                               fprintf(stderr, "%s: bad end value '%s'\n",
+                                       cmd, optarg);
+                               return CMD_HELP;
+                       }
+                       break;
+               case 's':
+                       *start = strtol(optarg, &endp, 0);
+                       if (*endp != '\0') {
+                               fprintf(stderr, "%s: bad start value '%s'\n",
+                                       cmd, optarg);
+                               return CMD_HELP;
+                       }
+                       break;
+               case 'h':
+               default:
+                       return CMD_HELP;
+               }
+       }
+       *argc -= optind;
+       *argv += optind;
+
+       /* support old optional positional parameters only if they were
+        * not already specified with named arguments: logname [start [end]]
+        */
+       if (*argc >= 1) {
+               if (*catalog) {
+                       fprintf(stderr,
+                               "%s: catalog is set, unknown argument '%s'\n",
+                               cmd, (*argv)[0]);
+                       return CMD_HELP;
+               }
+               *catalog = (*argv)[0];
+               (*argc)--;
+               (*argv)++;
+       }
+
+       if (*argc >= 1) {
+               if (*start != 1) {
+                       fprintf(stderr,
+                               "%s: --start is set, unknown argument '%s'\n",
+                               cmd, (*argv)[0]);
+                       return CMD_HELP;
+               }
+
+               *start = strtol((*argv)[0], &endp, 0);
+               if (*endp != '\0') {
+                       fprintf(stderr, "%s: bad start value '%s'\n",
+                               cmd, (*argv)[0]);
+                       return CMD_HELP;
+               }
+               (*argc)--;
+               (*argv)++;
+       }
+       if (*argc >= 1) {
+               if (*end != -1) {
+                       fprintf(stderr,
+                               "%s: --end is set, unknown argument '%s'\n",
+                               cmd, (*argv)[0]);
+                       return CMD_HELP;
+               }
+
+               *end = strtol((*argv)[0], &endp, 0);
+               if (*endp != '\0') {
+                       fprintf(stderr, "%s: bad end value '%s'\n",
+                               cmd, (*argv)[0]);
+                       return CMD_HELP;
+               }
+               (*argc)--;
+               (*argv)++;
+       }
+       if (*argc > 1) {
+               fprintf(stderr, "%s: unknown argument '%s'\n", cmd, (*argv)[0]);
+               return CMD_HELP;
+       }
+
+       if (*end != -1 && *end < *start) {
+               fprintf(stderr, "%s: end '%lu' less than than start '%lu'\n",
+                       cmd, *end, *start);
+               return CMD_HELP;
+       }
+
+       return 0;
 }
 
-static int llog_cancel_parse_optional(int argc, char **argv,
-                                     struct obd_ioctl_data *data)
+int jt_llog_print(int argc, char **argv)
+{
+       char *catalog = NULL;
+       long start = 1, end = -1;
+       int rc;
+
+       rc = llog_parse_catalog_start_end(&argc, &argv, &catalog, &start, &end);
+       if (rc)
+               return rc;
+
+       rc = jt_llog_print_iter(catalog, start, end, jt_llog_print_cb, NULL);
+
+       return rc;
+}
+
+/* Parse catalog, log ID, and optionally a log index with either optional
+ * arguments or positional arguments.  Only the initial catalog argument
+ * may be positional with other optional arguments.
+ *
+ * The positional arguments option should eventually be phased out.
+ */
+static int llog_parse_catalog_log_idx(int *argc, char ***argv, const char *opts,
+                                     int max_args, struct obd_ioctl_data *data)
 {
-       int cOpt;
-       const char *const short_opts = "c:l:i:h";
        const struct option long_opts[] = {
+       /* the --catalog option is not required, just for consistency */
        { .val = 'c',   .name = "catalog",      .has_arg = required_argument },
        { .val = 'h',   .name = "help",         .has_arg = no_argument },
        { .val = 'i',   .name = "log_idx",      .has_arg = required_argument },
        { .val = 'l',   .name = "log_id",       .has_arg = required_argument },
        { .name = NULL } };
+       int c;
 
        /* sanity check */
-       if (!data || argc <= 1) {
+       if (!data || *argc <= 1)
                return -1;
-       }
 
-       /*now process command line arguments*/
-       while ((cOpt = getopt_long(argc, argv, short_opts,
-                                       long_opts, NULL)) != -1) {
-               switch (cOpt) {
+       data->ioc_dev = cur_device;
+
+       /* now process command line arguments*/
+       while ((c = getopt_long(*argc, *argv, opts, long_opts, NULL)) != -1) {
+               switch (c) {
                case 'c':
                        data->ioc_inllen1 = strlen(optarg) + 1;
                        data->ioc_inlbuf1 = optarg;
                        break;
-
-               case 'l':
-                       data->ioc_inllen2 = strlen(optarg) + 1;
-                       data->ioc_inlbuf2 = optarg;
-                       break;
-
                case 'i':
                        data->ioc_inllen3 = strlen(optarg) + 1;
                        data->ioc_inlbuf3 = optarg;
                        break;
-
+               case 'l': /* The log_id option isn't currently needed for
+                          * cancel as mdt_iocontrol() handles IOC_LLOG_CANCEL,
+                          * but we may as well keep it for now.
+                          */
+                       data->ioc_inllen2 = strlen(optarg) + 1;
+                       data->ioc_inlbuf2 = optarg;
+                       break;
                case 'h':
                default:
-                       return -1;
+                       return CMD_HELP;
                }
        }
 
-       if ((data->ioc_inlbuf1 == NULL) || (data->ioc_inlbuf3 == NULL)) {
-               /* missing mandatory parameters */
-               return -1;
+       *argc -= optind;
+       *argv += optind;
+
+       /* Allow catalog to be specified as first option without --catalog */
+       if (data->ioc_inlbuf1 == NULL && *argc > 0) {
+               data->ioc_inlbuf1 = (*argv)[0];
+               data->ioc_inllen1 = strlen((*argv)[0]) + 1;
+               (*argc)--;
+               (*argv)++;
        }
 
        return 0;
@@ -2706,60 +2982,44 @@ static int llog_cancel_parse_optional(int argc, char **argv,
 
 int jt_llog_cancel(int argc, char **argv)
 {
-       struct obd_ioctl_data data;
-       char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
-       int rc, i;
+       struct obd_ioctl_data data = { 0 };
+       char rawbuf[MAX_IOC_BUFLEN] = "", *buf = rawbuf;
+       char *cmd = argv[0];
+       int rc;
 
-       /* check that the arguments provided are either all
-        * optional or all positional.  No mixing allowed
-        *
-        * if argc is 4 or 3 then check all arguments to ensure that none
-        * of them start with a '-'.  If so then this is invalid.
-        * Otherwise if arg is > 4 then assume that this is optional
-        * arguments, and parse as such ignoring any thing that's not
-        * optional.  The result is that user must use optional arguments
-        * for all mandatory parameters.  Code will ignore all other args
-        *
-        * The positional arguments option should eventually be phased out.
-        */
-       memset(&data, 0, sizeof(data));
-       data.ioc_dev = cur_device;
+       /* Parse catalog file (in inlbuf1) and named parameters */
+       rc = llog_parse_catalog_log_idx(&argc, &argv, "c:hi:l:", 3, &data);
 
-       if (argc == 3 || argc == 4) {
-               for (i = 1; i < argc; i++) {
-                       if (argv[i][0] == '-')
-                               return CMD_HELP;
-               }
-               data.ioc_inllen1 = strlen(argv[1]) + 1;
-               data.ioc_inlbuf1 = argv[1];
-               if (argc == 4) {
-                       data.ioc_inllen2 = strlen(argv[2]) + 1;
-                       data.ioc_inlbuf2 = argv[2];
-                       data.ioc_inllen3 = strlen(argv[3]) + 1;
-                       data.ioc_inlbuf3 = argv[3];
-               } else {
-                       data.ioc_inllen3 = strlen(argv[2]) + 1;
-                       data.ioc_inlbuf3 = argv[2];
-               }
-       } else {
-               if (llog_cancel_parse_optional(argc, argv, &data) != 0)
-                       return CMD_HELP;
+       /* Handle old positional parameters if not using named parameters,
+        * either "<catalog> <log_idx>" or "<catalog> <log_id> <log_idx>".
+        * It was "inlbuf3 = log_idx", and "inlbuf2 = log_id" (ignored by
+        * config log cancel), and shows why I hate positional parameters.
+        */
+       if (argc == 1) {
+               data.ioc_inllen3 = strlen(argv[0]) + 1;
+               data.ioc_inlbuf3 = argv[0];
+       } else if (argc == 2) {
+               data.ioc_inllen2 = strlen(argv[0]) + 1;
+               data.ioc_inlbuf2 = argv[0];
+               data.ioc_inllen3 = strlen(argv[1]) + 1;
+               data.ioc_inlbuf3 = argv[1];
        }
 
-       memset(buf, 0, sizeof(rawbuf));
+       if (data.ioc_inlbuf1 == NULL || data.ioc_inlbuf3 == NULL)
+               /* missing mandatory parameters */
+               return CMD_HELP;
+
        rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
        if (rc) {
-               fprintf(stderr, "error: %s: invalid ioctl\n",
-                       jt_cmdname(argv[0]));
+               fprintf(stderr, "%s: ioctl_pack for catalog '%s' failed: %s\n",
+                       jt_cmdname(cmd), data.ioc_inlbuf1, strerror(-rc));
                return rc;
        }
 
        rc = l_ioctl(OBD_DEV_ID, OBD_IOC_LLOG_CANCEL, buf);
-       if (rc == 0)
-               fprintf(stdout, "index %s was canceled.\n",
-                       argc == 4 ? argv[3] : argv[2]);
-       else
-               fprintf(stderr, "OBD_IOC_LLOG_CANCEL failed: %s\n",
+       if (rc)
+               fprintf(stderr, "%s: cancel catalog '%s:%s' failed: %s\n",
+                       jt_cmdname(cmd), data.ioc_inlbuf1, data.ioc_inlbuf3,
                        strerror(errno));
 
        return rc;
@@ -2767,87 +3027,89 @@ int jt_llog_cancel(int argc, char **argv)
 
 int jt_llog_check(int argc, char **argv)
 {
-        struct obd_ioctl_data data;
-        char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
-        int rc;
+       struct obd_ioctl_data data = { 0 };
+       char rawbuf[MAX_IOC_BUFLEN] = "", *buf = rawbuf;
+       char *catalog = NULL;
+       char startbuf[16], endbuf[16];
+       long start = 1, end = -1;
+       char *cmd = argv[0];
+       int rc;
 
-        if (argc != 2 && argc != 4)
-                return CMD_HELP;
+       rc = llog_parse_catalog_start_end(&argc, &argv, &catalog, &start, &end);
+       if (rc)
+               return rc;
 
-        memset(&data, 0, sizeof(data));
-        data.ioc_dev = cur_device;
-        data.ioc_inllen1 = strlen(argv[1]) + 1;
-        data.ioc_inlbuf1 = argv[1];
-        if (argc == 4) {
-                data.ioc_inllen2 = strlen(argv[2]) + 1;
-                data.ioc_inlbuf2 = argv[2];
-                data.ioc_inllen3 = strlen(argv[3]) + 1;
-                data.ioc_inlbuf3 = argv[3];
-        } else {
-                char from[2] = "1", to[3] = "-1";
-                data.ioc_inllen2 = strlen(from) + 1;
-                data.ioc_inlbuf2 = from;
-                data.ioc_inllen3 = strlen(to) + 1;
-                data.ioc_inlbuf3 = to;
-        }
-        data.ioc_inllen4 = sizeof(rawbuf) - cfs_size_round(sizeof(data)) -
-                cfs_size_round(data.ioc_inllen1) -
-                cfs_size_round(data.ioc_inllen2) -
-                cfs_size_round(data.ioc_inllen3);
-        memset(buf, 0, sizeof(rawbuf));
+       if (end == -1)
+               end = 0x7fffffff;
+
+       data.ioc_dev = cur_device;
+       data.ioc_inllen1 = strlen(catalog) + 1;
+       data.ioc_inlbuf1 = catalog;
+
+       snprintf(startbuf, sizeof(startbuf), "%lu", start);
+       snprintf(endbuf, sizeof(endbuf), "%lu", end);
+       /* start and end record numbers are passed as ASCII digits */
+       data.ioc_inllen2 = strlen(startbuf) + 1;
+       data.ioc_inlbuf2 = startbuf;
+       data.ioc_inllen3 = strlen(endbuf) + 1;
+       data.ioc_inlbuf3 = endbuf;
+
+       data.ioc_inllen4 = sizeof(rawbuf) - __ALIGN_KERNEL(sizeof(data), 8) -
+                          __ALIGN_KERNEL(data.ioc_inllen1, 8) -
+                          __ALIGN_KERNEL(data.ioc_inllen2, 8) -
+                          __ALIGN_KERNEL(data.ioc_inllen3, 8);
        rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
-        if (rc) {
-                fprintf(stderr, "error: %s: invalid ioctl\n",
-                        jt_cmdname(argv[0]));
-                return rc;
-        }
+       if (rc) {
+               fprintf(stderr, "%s: ioctl_pack failed for catalog '%s': %s\n",
+                       jt_cmdname(cmd), data.ioc_inlbuf1, strerror(-rc));
+               return rc;
+       }
 
-        rc = l_ioctl(OBD_DEV_ID, OBD_IOC_LLOG_CHECK, buf);
-        if (rc == 0)
-                fprintf(stdout, "%s", ((struct obd_ioctl_data*)buf)->ioc_bulk);
-        else
-                fprintf(stderr, "OBD_IOC_LLOG_CHECK failed: %s\n",
-                        strerror(errno));
-        return rc;
+       rc = l_ioctl(OBD_DEV_ID, OBD_IOC_LLOG_CHECK, buf);
+       if (rc == 0)
+               fprintf(stdout, "%s", ((struct obd_ioctl_data *)buf)->ioc_bulk);
+       else
+               fprintf(stderr, "%s: OBD_IOC_LLOG_CHECK failed: %s\n",
+                       jt_cmdname(cmd), strerror(errno));
+       return rc;
 }
 
 int jt_llog_remove(int argc, char **argv)
 {
-        struct obd_ioctl_data data;
-        char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
-        int rc;
+       struct obd_ioctl_data data = { 0 };
+       char rawbuf[MAX_IOC_BUFLEN] = "", *buf = rawbuf;
+       char *cmd = argv[0];
+       int rc;
 
-        if (argc != 3 && argc != 2)
-                return CMD_HELP;
+       rc = llog_parse_catalog_log_idx(&argc, &argv, "c:hl:", 2, &data);
+       if (rc)
+               return rc;
 
-        memset(&data, 0, sizeof(data));
-        data.ioc_dev = cur_device;
-        data.ioc_inllen1 = strlen(argv[1]) + 1;
-        data.ioc_inlbuf1 = argv[1];
-        if (argc == 3){
-                data.ioc_inllen2 = strlen(argv[2]) + 1;
-                data.ioc_inlbuf2 = argv[2];
-        }
-        memset(buf, 0, sizeof(rawbuf));
+       if (argc == 1) {
+               if (data.ioc_inlbuf2) {
+                       fprintf(stderr,
+                               "%s: --log_id is set, unknown argument '%s'\n",
+                               jt_cmdname(cmd), argv[0]);
+                       return CMD_HELP;
+               }
+
+               data.ioc_inllen2 = strlen(argv[0]) + 1;
+               data.ioc_inlbuf2 = argv[0];
+       }
        rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
-        if (rc) {
-                fprintf(stderr, "error: %s: invalid ioctl\n",
-                        jt_cmdname(argv[0]));
-                return rc;
-        }
+       if (rc) {
+               fprintf(stderr, "%s: ioctl_pack for catalog '%s' failed: %s\n",
+                       jt_cmdname(cmd), data.ioc_inlbuf1, strerror(-rc));
+               return rc;
+       }
 
-        rc = l_ioctl(OBD_DEV_ID, OBD_IOC_LLOG_REMOVE, buf);
-        if (rc == 0) {
-                if (argc == 2)
-                       fprintf(stdout, "log %s is removed.\n", argv[1]);
-               else
-                       fprintf(stdout, "the log in catalog %s is removed. \n",
-                               argv[1]);
-        } else
-                fprintf(stderr, "OBD_IOC_LLOG_REMOVE failed: %s\n",
-                        strerror(errno));
+       rc = l_ioctl(OBD_DEV_ID, OBD_IOC_LLOG_REMOVE, buf);
+       if (rc)
+               fprintf(stderr, "%s: cancel catalog '%s:%s' failed: %s\n",
+                       jt_cmdname(cmd), data.ioc_inlbuf1, data.ioc_inlbuf2,
+                       strerror(-rc));
 
-        return rc;
+       return rc;
 }
 
 static void signal_server(int sig)
@@ -3417,6 +3679,51 @@ int jt_nodemap_test_id(int argc, char **argv)
 }
 
 /**
+ * parse nid range
+ *
+ * \param      nodemap_range   --range string
+ * \param      nid_range       nid range string, min_nid:max_nid
+ *
+ * \retval                     0 on success
+ */
+static int parse_nid_range(char *nodemap_range, char *nid_range, int range_len)
+{
+       char                    min_nid[LNET_NIDSTR_SIZE + 1];
+       char                    max_nid[LNET_NIDSTR_SIZE + 1];
+       struct list_head        nidlist;
+       int                     rc = 0;
+
+       INIT_LIST_HEAD(&nidlist);
+
+       if (cfs_parse_nidlist(nodemap_range, strlen(nodemap_range),
+                             &nidlist) <= 0) {
+               fprintf(stderr,
+                       "error: nodemap_xxx_range: can't parse nid range: %s\n",
+                       nodemap_range);
+               return -1;
+       }
+
+       rc = cfs_nidrange_find_min_max(&nidlist, &min_nid[0], &max_nid[0],
+                                      LNET_NIDSTR_SIZE);
+       if (rc < 0) {
+               if (rc == -EINVAL)
+                       fprintf(stderr,
+                               "error: nodemap_xxx_range: nid range uses "
+                               "currently unsupported features\n");
+               else if (rc == -ERANGE)
+                       fprintf(stderr,
+                               "error: nodemap_xxx_range: nodemap ranges must "
+                               "be contiguous\n");
+
+               return rc;
+       }
+
+       snprintf(nid_range, range_len, "%s:%s", min_nid, max_nid);
+
+       return rc;
+}
+
+/**
  * add an nid range to a nodemap
  *
  * \param      argc            number of args
@@ -3431,9 +3738,6 @@ int jt_nodemap_add_range(int argc, char **argv)
 {
        char                    *nodemap_name = NULL;
        char                    *nodemap_range = NULL;
-       struct list_head        nidlist;
-       char                    min_nid[LNET_NIDSTR_SIZE + 1];
-       char                    max_nid[LNET_NIDSTR_SIZE + 1];
        char                    nid_range[2 * LNET_NIDSTR_SIZE + 2];
        int                     rc = 0;
        int                     c;
@@ -3443,8 +3747,6 @@ int jt_nodemap_add_range(int argc, char **argv)
        { .val = 'r',   .name = "range",        .has_arg = required_argument },
        { .name = NULL } };
 
-       INIT_LIST_HEAD(&nidlist);
-
        while ((c = getopt_long(argc, argv, "n:r:",
                                long_opts, NULL)) != -1) {
                switch (c) {
@@ -3463,23 +3765,11 @@ int jt_nodemap_add_range(int argc, char **argv)
                return -1;
        }
 
-       if (cfs_parse_nidlist(nodemap_range, strlen(nodemap_range),
-                             &nidlist) <= 0) {
-               fprintf(stderr, "error: %s: can't parse nid range: %s\n",
-                       jt_cmdname(argv[0]), nodemap_range);
-               return -1;
-       }
-
-       if (!cfs_nidrange_is_contiguous(&nidlist)) {
-               fprintf(stderr, "error: %s: nodemap ranges must be "
-                       "contiguous\n", jt_cmdname(argv[0]));
-               return -1;
+       rc = parse_nid_range(nodemap_range, nid_range, sizeof(nid_range));
+       if (rc) {
+               errno = -rc;
+               return rc;
        }
-
-       cfs_nidrange_find_min_max(&nidlist, &min_nid[0], &max_nid[0],
-                                 LNET_NIDSTR_SIZE);
-       snprintf(nid_range, sizeof(nid_range), "%s:%s", min_nid, max_nid);
-
        rc = nodemap_cmd(LCFG_NODEMAP_ADD_RANGE, NULL, 0, argv[0],
                         nodemap_name, nid_range, NULL);
        if (rc != 0) {
@@ -3507,9 +3797,6 @@ int jt_nodemap_del_range(int argc, char **argv)
 {
        char                    *nodemap_name = NULL;
        char                    *nodemap_range = NULL;
-       struct list_head        nidlist;
-       char                    min_nid[LNET_NIDSTR_SIZE + 1];
-       char                    max_nid[LNET_NIDSTR_SIZE + 1];
        char                    nid_range[2 * LNET_NIDSTR_SIZE + 2];
        int                     rc = 0;
        int                     c;
@@ -3519,8 +3806,6 @@ int jt_nodemap_del_range(int argc, char **argv)
        { .val = 'r',   .name = "range",        .has_arg = required_argument },
        { .name = NULL } };
 
-       INIT_LIST_HEAD(&nidlist);
-
        while ((c = getopt_long(argc, argv, "n:r:",
                                long_opts, NULL)) != -1) {
                switch (c) {
@@ -3539,23 +3824,11 @@ int jt_nodemap_del_range(int argc, char **argv)
                return -1;
        }
 
-       if (cfs_parse_nidlist(nodemap_range, strlen(nodemap_range),
-                             &nidlist) <= 0) {
-               fprintf(stderr, "error: %s: can't parse nid range: %s\n",
-                       jt_cmdname(argv[0]), nodemap_range);
-               return -1;
-       }
-
-       if (!cfs_nidrange_is_contiguous(&nidlist)) {
-               fprintf(stderr, "error: %s: nodemap ranges must be "
-                       "contiguous\n", jt_cmdname(argv[0]));
-               return -1;
+       rc = parse_nid_range(nodemap_range, nid_range, sizeof(nid_range));
+       if (rc) {
+               errno = -rc;
+               return rc;
        }
-
-       cfs_nidrange_find_min_max(&nidlist, &min_nid[0], &max_nid[0],
-                                 LNET_NIDSTR_SIZE);
-       snprintf(nid_range, sizeof(nid_range), "%s:%s", min_nid, max_nid);
-
        rc = nodemap_cmd(LCFG_NODEMAP_DEL_RANGE, NULL, 0, argv[0],
                         nodemap_name, nid_range, NULL);
        if (rc != 0) {
@@ -3622,6 +3895,70 @@ int jt_nodemap_set_fileset(int argc, char **argv)
 }
 
 /**
+ * set SELinux policy info on a nodemap
+ *
+ * \param      argc            number of args
+ * \param      argv[]          variable string arguments
+ *
+ * --name                      nodemap name
+ * --sepol                     SELinux policy info
+ *
+ * \retval                     0 on success
+ */
+int jt_nodemap_set_sepol(int argc, char **argv)
+{
+       char *nodemap_name = NULL;
+       char *sepol = NULL;
+       int   rc = 0;
+       int   c;
+
+       static struct option long_options[] = {
+               {
+                       .name           = "name",
+                       .has_arg        = required_argument,
+                       .val            = 'n',
+               },
+               {
+                       .name           = "sepol",
+                       .has_arg        = required_argument,
+                       .val            = 's',
+               },
+               {
+                       .name = NULL,
+               }
+       };
+
+       while ((c = getopt_long(argc, argv, "n:s:",
+                               long_options, NULL)) != -1) {
+               switch (c) {
+               case 'n':
+                       nodemap_name = optarg;
+                       break;
+               case 's':
+                       sepol = optarg;
+                       break;
+               }
+       }
+
+       if (nodemap_name == NULL || sepol == NULL) {
+               fprintf(stderr, "usage: nodemap_set_sepol --name <name> "
+                               "--sepol <sepol>\n");
+               return -1;
+       }
+
+       rc = nodemap_cmd(LCFG_NODEMAP_SET_SEPOL, NULL, 0, argv[0],
+                        nodemap_name, sepol, NULL);
+       if (rc != 0) {
+               errno = -rc;
+               fprintf(stderr, "error: %s: cannot set sepol '%s' on nodemap "
+                               "'%s': rc = %d\n",
+                       jt_cmdname(argv[0]), sepol, nodemap_name, rc);
+       }
+
+       return rc;
+}
+
+/**
  * modify a nodemap's behavior
  *
  * \param      argc            number of args
@@ -3908,7 +4245,7 @@ static int extract_fsname_poolname(const char *arg, char *fsname,
        char *ptr;
        int rc;
 
-       strlcpy(fsname, arg, PATH_MAX + 1);
+       snprintf(fsname, PATH_MAX + 1, "%s", arg);
        ptr = strchr(fsname, '.');
        if (ptr == NULL) {
                fprintf(stderr, ". is missing in %s\n", fsname);
@@ -3933,6 +4270,11 @@ static int extract_fsname_poolname(const char *arg, char *fsname,
 
        strncpy(poolname, ptr, LOV_MAXPOOLNAME);
        poolname[LOV_MAXPOOLNAME] = '\0';
+
+       if (strncmp(poolname, "none", LOV_MAXPOOLNAME) == 0) {
+               fprintf(stderr, "poolname cannot be 'none'\n");
+               return -EINVAL;
+       }
        return 0;
 
 err: