Whamcloud - gitweb
LU-11566 utils: improve usage/docs for lctl llog commands 04/34004/11
authorAndreas Dilger <adilger@whamcloud.com>
Thu, 10 Jan 2019 01:06:26 +0000 (18:06 -0700)
committerOleg Drokin <green@whamcloud.com>
Mon, 8 Apr 2019 05:35:26 +0000 (05:35 +0000)
Improve the usage message and man pages for the llog_print,
llog_info, llog_catlist, and llog_cancel sub-commands.  Move
them out of the obsolete section of the lctl usage message.

Reorder some man pages to be in alphabetical order in Makefile.

Add named options to the various commands to make them
consistent with each other.  The --catalog option is not
required for ease of use, but is kept for compatibility
with the previous llog_cancel interface.

The llog_cancel --log_id option is removed from the usage
message and man page, since the ability to cancel individual
records from MDT recovery logs is currently not implemented
(no IOC_LLOG_CANCEL handler in mdt_iocontrol()).  There is
also no IOC_LLOG_PRINT method for the MDS either, so these
commands are mostly useful only for the MGS configuration
logs at this time.

Add a test case for llog_cancel.

Signed-off-by: Andreas Dilger <adilger@whamcloud.com>
Change-Id: I66c95c289f161370896e6764da4fc2f5803ebbe5
Reviewed-on: https://review.whamcloud.com/34004
Tested-by: Jenkins
Reviewed-by: Joseph Gmitter <jgmitter@whamcloud.com>
Reviewed-by: Ben Evans <bevans@cray.com>
Tested-by: Maloo <maloo@whamcloud.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
lustre/doc/Makefile.am
lustre/doc/lctl-llog_cancel.8 [new file with mode: 0644]
lustre/doc/lctl-llog_catlist.8
lustre/doc/lctl-llog_info.8
lustre/doc/lctl-llog_print.8
lustre/obdclass/llog_ioctl.c
lustre/obdclass/obd_config.c
lustre/tests/conf-sanity.sh
lustre/utils/lctl.c
lustre/utils/obd.c

index 349df82..9212e98 100644 (file)
@@ -101,6 +101,7 @@ MANFILES =                                  \
        llapi_layout_get_by_fd.3                \
        llapi_layout_get_by_fid.3               \
        llapi_layout_get_by_path.3              \
+       llapi_layout_get_by_xattr.3             \
        llapi_layout_ost_index_get.3            \
        llapi_layout_ost_index_set.3            \
        llapi_layout_pattern_get.3              \
@@ -117,6 +118,7 @@ MANFILES =                                  \
        ll_decode_linkea.8                      \
        llobdstat.8                             \
        llog_reader.8                           \
+       llsom_sync.8                            \
        llstat.8                                \
        lnetctl.8                               \
        lst.8                                   \
@@ -125,16 +127,18 @@ MANFILES =                                        \
        lustre_routes_config.8                  \
        lustre_routes_conversion.8              \
        lustre_rsync.8                          \
-       llsom_sync.8                            \
        mount.lustre.8                          \
        nids.5                                  \
        plot-llstat.8                           \
        routerstat.8
 
 SERVER_MANFILES =                              \
+       lctl-barrier.8                          \
+       lctl-lcfg.8                             \
        lctl-lfsck-query.8                      \
        lctl-lfsck-start.8                      \
        lctl-lfsck-stop.8                       \
+       lctl-llog_cancel.8                      \
        lctl-llog_catlist.8                     \
        lctl-llog_info.8                        \
        lctl-llog_print.8                       \
@@ -147,12 +151,10 @@ SERVER_MANFILES =                         \
        lctl-nodemap-del-range.8                \
        lctl-nodemap-modify.8                   \
        lctl-nodemap-set-fileset.8              \
-       lctl-lcfg.8                             \
-       lctl-barrier.8                          \
        lctl-snapshot-create.8                  \
        lctl-snapshot-destroy.8                 \
-       lctl-snapshot-modify.8                  \
        lctl-snapshot-list.8                    \
+       lctl-snapshot-modify.8                  \
        lctl-snapshot-mount.8                   \
        lctl-snapshot-umount.8                  \
        ll_decode_filter_fid.8                  \
diff --git a/lustre/doc/lctl-llog_cancel.8 b/lustre/doc/lctl-llog_cancel.8
new file mode 100644 (file)
index 0000000..98d5a2e
--- /dev/null
@@ -0,0 +1,54 @@
+.TH lctl-llog_cancel 8 "2019 Jan 10" Lustre "configuration utilities"
+.SH NAME
+lctl llog_cancel \- cancel a record in a Lustre llog file
+.SH SYNOPSIS
+.B lctl --device
+.RI < device >
+.B llog_cancel --log_idx
+.RI < index >
+.RI < logname >
+
+.SH DESCRIPTION
+.B lctl llog_cancel
+is used to cancel the configuration record given by
+.I index
+from the
+.I logname
+configuration log, typically on the MGS.  This is useful if a persistent
+configuration record was set incorrectly or is no longer needed.  Note
+that cancelling a record does not "undo" any effect it had on currently
+mounted clients, it only prevents the record from being seen in the future.
+See
+.BR lctl-llog_catlist (8)
+for a list of configuration logs.
+.SH OPTIONS
+.TP
+.B --log_idx
+.I index
+The record
+.I index
+number to cancel, as printed by
+.B lctl llog_print
+for that log.
+.TP
+.SH EXAMPLES
+.TP
+To cancel record 15 from the \fBtestfs-client\fR conf_param log:
+.br
+# lctl --device MGS llog_cancel --log_idx=15 testfs-client
+.TP
+To cancel record 22 from the \fBparams\fR set_param log:
+.br
+# lctl --device MGS llog_cancel --log_idx=22 params
+.SH AVAILABILITY
+.B lctl llog_cancel
+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 lctl-llog_info (8),
+.BR lctl-llog_catlist (8),
+.BR lctl-llog_print (8)
index ec22a21..4c15432 100644 (file)
@@ -1,4 +1,4 @@
-.TH lctl-llog_catlist 8 "2017 Feb 24" Lustre "configuration utilities"
+.TH lctl-llog_catlist 8 "2019 Jan 10" Lustre "configuration utilities"
 .SH NAME
 lctl llog_catlist \- list Lustre configuration log files
 .SH SYNOPSIS
@@ -8,9 +8,22 @@ lctl llog_catlist \- list Lustre configuration log files
 .B lctl llog_catlist
 is used to list the configuration log files on the MGS, or other target.
 This is useful to find the names of all the configuration files available.
+The
+.IR fsname -client
+logs contains configuration records for the client nodes, the
+.IR fsname -MDT xxxx
+logs contain records for the MDT(s), the
+.IR fsname -OST xxxx
+logs contain records for the OSTs.  The
+.B lctl conf_param
+parameters are stored in these log files for the specified filesystem.  The
+.B params
+log file contains the
+.B lctl set_param -P
+parameters for all filesystems serviced by this MGS.
 .SH EXAMPLES
 .TP
-To list all of the records on the MGS:
+To list all of the configuration logs on the MGS:
 .br
 # lctl --device MGS llog_catlist
 .br
@@ -18,11 +31,22 @@ config_log: testfs-OST0000
 .br
 config_log: testfs-MDT0000
 .br
+config_log: testfs-OST0001
+.br
 config_log: testfs-client
 .br
-config_log: params-client
+config_log: params
 .br
-config_log: testfs-OST0001
+.TP
+To list all of the recovery llog files on the MGS:
+.br
+# lctl --device testfs-MDT0000 llog_catlist
+.br
+catalog_log: [0x5:0x1:0x0]:0
+.br
+catalog_log: [0x6:0x1:0x0]:0
+.br
+catalog_log: [0x7:0x1:0x0]:0
 .SH AVAILABILITY
 .B lctl llog_catlist
 is a subcommand of
@@ -31,6 +55,7 @@ and is distributed as part of the
 .BR lustre (7)
 filesystem package.
 .SH SEE ALSO
-.BR lctl (8)
-.BR lctl-llog_info (8)
+.BR lctl (8),
+.BR lctl-llog_cancel (8),
+.BR lctl-llog_info (8),
 .BR lctl-llog_print (8)
index f5f9060..eab53db 100644 (file)
@@ -1,4 +1,4 @@
-.TH lctl-llog_info 8 "2017 Feb 24" Lustre "configuration utilities"
+.TH lctl-llog_info 8 "2019 Jan 10" Lustre "configuration utilities"
 .SH NAME
 lctl llog_info \- print information about a Lustre configuration log
 .SH SYNOPSIS
@@ -24,8 +24,11 @@ To print all of the records from the testfs-client configuration log:
 # lctl --device MGS llog_info testfs-client
 .br
 logid:            [0x4:0xa:0x0]:0
+.br
 flags:            4 (plain)
+.br
 records_count:    48
+.br
 last_index:       47
 .SH AVAILABILITY
 .B lctl llog_info
@@ -35,6 +38,7 @@ and is distributed as part of the
 .BR lustre (7)
 filesystem package.
 .SH SEE ALSO
-.BR lctl (8)
-.BR lctl-llog_catlist (8)
+.BR lctl (8),
+.BR lctl-llog_catlist (8),
+.BR lctl-llog_cancel (8),
 .BR lctl-llog_print (8)
index 515036a..ef0f208 100644 (file)
@@ -1,4 +1,4 @@
-.TH lctl-llog_print 8 "2017 Feb 24" Lustre "configuration utilities"
+.TH lctl-llog_print 8 "2019 Jan 10" Lustre "configuration utilities"
 .SH NAME
 lctl llog_print \- print the content of a configuration log
 .SH SYNOPSIS
@@ -17,7 +17,11 @@ configuration log on the MGS in YAML format.  This is useful for debugging
 configuration problems and to list any permanent configuration options
 saved via
 .B lctl conf_param
-on the MGS.
+on the MGS.  The
+.B lctl llog_catlist
+command can be used to list the different configuration logs, and the
+.B lctl llog_cancel
+command can be used to cancel configuration records.
 .SH OPTIONS
 .TP
 .B --end
@@ -45,7 +49,7 @@ The last record number in the config log to dump, including the specified
 index number.
 .SH EXAMPLES
 .TP
-To print all of the records from the testfs-client configuration log:
+To print the configuration records from the \fBtestfs-client\fR logfile:
 .br
 # lctl --device MGS llog_print testfs-client
 .br
@@ -68,6 +72,13 @@ To print all of the records from the testfs-client configuration log:
 :
 .br
 :
+.TP
+To print the first 10 \fBset_param -P\fR records from \fBparams\fR:
+# lctl --device MGS llog_print --end=10 params
+.br
+- { index: 2, event: set_param, device: general, parameter: osc.*.max_dirty_mb, value: 32 }
+.br
+- { index: 4, event: set_param, device: general, parameter: osc.*.checksum_type, value: crc32c }
 .SH AVAILABILITY
 .B lctl llog_print
 is a subcommand of
@@ -76,6 +87,7 @@ and is distributed as part of the
 .BR lustre (7)
 filesystem package.
 .SH SEE ALSO
-.BR lctl (8)
-.BR lctl-llog_info (8)
+.BR lctl (8),
+.BR lctl-llog_info (8),
+.BR lctl-llog_cancel (8),
 .BR lctl-llog_catlist (8)
index 191880a..6c88632 100644 (file)
@@ -430,7 +430,7 @@ int llog_ioctl(const struct lu_env *env, struct llog_ctxt *ctxt, int cmd,
                        GOTO(out_close, rc = -EINVAL);
                }
 
-               if (data->ioc_inlbuf2 > 0) {
+               if (data->ioc_inlbuf2) {
                        /* remove indicate log from the catalog */
                        rc = str2logid(&plain, data->ioc_inlbuf2,
                                       data->ioc_inllen2);
index 2ff2dbc..de558e7 100644 (file)
@@ -2132,7 +2132,7 @@ static int class_config_parse_rec(struct llog_rec_hdr *rec, char *buf, int size)
                char nidstr[LNET_NIDSTR_SIZE];
 
                libcfs_nid2str_r(lcfg->lcfg_nid, nidstr, sizeof(nidstr));
-               ptr += snprintf(ptr, end-ptr, "nid=%s(%#llx)\n     ",
+               ptr += snprintf(ptr, end-ptr, "nid=%s(%#llx)    ",
                                nidstr, lcfg->lcfg_nid);
        }
 
index ca26bd6..affade0 100644 (file)
@@ -8500,6 +8500,59 @@ test_123ad() { # LU-11566
 }
 run_test 123ad "llog_print shows all records"
 
+test_123ae() { # LU-11566
+       remote_mgs_nodsh && skip "remote MGS with nodsh"
+       [ -d $MOUNT/.lustre ] || setupall
+
+       local max=$($LCTL get_param -n osc.*-OST0000-*.max_dirty_mb | head -1)
+
+       if do_facet mgs "$LCTL help llog_cancel" 2>&1| grep -q -- --log_id; then
+               # save one set_param -P record in case none exist
+               do_facet mgs $LCTL set_param -P osc.*.max_dirty_mb=$max
+
+               local log=params
+               local orig=$(do_facet mgs $LCTL --device MGS llog_print $log |
+                            tail -1 | awk '{ print $4 }' | tr -d , )
+               do_facet mgs $LCTL set_param -P osc.*.max_dirty_mb=$max
+               do_facet mgs $LCTL --device MGS llog_print $log | tail -1 |
+                       grep "parameter: osc.*.max_dirty_mb" ||
+                       error "new set_param -P wasn't stored in params log"
+
+               # - { index: 71, event: set_param, device: general,
+               #     param: osc.*.max_dirty_mb, value: 256 }
+               local id=$(do_facet mgs $LCTL --device MGS llog_print $log |
+                          tail -1 | awk '{ print $4 }' | tr -d , )
+
+               do_facet mgs $LCTL --device MGS llog_cancel $log --log_idx=$id
+               local new=$(do_facet mgs $LCTL --device MGS llog_print $log |
+                           tail -1 | awk '{ print $4 }' | tr -d , )
+               (( new == orig )) ||
+                       error "new llog_cancel now $new, not at $orig records"
+       fi
+
+       # test old positional parameters for a while still
+       if [ $(lustre_version_code mgs) -le $(version_code 3.1.53) ]; then
+               log=$FSNAME-client
+               orig=$(do_facet mgs $LCTL --device MGS llog_print $log |
+                      tail -1 | awk '{ print $4 }' | tr -d , )
+               do_facet mgs $LCTL conf_param $FSNAME-OST0000.osc.max_dirty_mb=$max
+               do_facet mgs $LCTL --device MGS llog_print $log |
+                       tail -1 | grep "parameter: osc.max_dirty_mb" ||
+                       error "old conf_param wasn't stored in params log"
+
+               # - { index: 71, event: conf_param, device: testfs-OST0000-osc,
+               #     param: osc.max_dirty_mb=256 }
+               id=$(do_facet mgs $LCTL --device MGS llog_print $log |
+                    tail -1 | awk '{ print $4 }' | tr -d , )
+               do_facet mgs $LCTL --device MGS llog_cancel $log $id
+               new=$(do_facet mgs $LCTL --device MGS llog_print $log |
+                     tail -1 | awk '{ print $4 }' | tr -d , )
+               (( new == orig )) ||
+                       error "old llog_cancel now $new, not at $orig records"
+       fi
+}
+run_test 123ae "llog_cancel can cancel requested record"
+
 test_123F() {
        setupall
        local yaml_file="$TMP/$tfile.yaml"
index 65b2742..8f330d9 100644 (file)
@@ -483,45 +483,39 @@ command_t cmdlist[] = {
         "                   [-t | --type lfsck_type[,lfsck_type...]]\n"
         "                   [-w | --wait]"},
 #endif /* HAVE_SERVER_SUPPORT */
-       {"==== obsolete (DANGEROUS) ====", NULL, 0, "obsolete (DANGEROUS)"},
-       /* some test scripts still use these */
        {"cfg_device", jt_obd_device, 0,
         "set current device to <name>\n"
         "usage: device <name>"},
        {"recover", jt_obd_recover, 0,
         "try to restore a lost connection immediately\n"
         "usage: recover [MDC/OSC device]"},
-       /* saving for sanity 44a */
-       {"lov_getconfig", jt_obd_lov_getconfig, 0,
-        "read lov configuration from an mds device\n"
-        "usage: lov_getconfig <mountpoint>"},
        /* Llog operations */
        {"llog_catlist", jt_llog_catlist, 0,
-        "list all catalog logs on current device.\n"
+        "list all catalog files on current device.\n"
         "usage: llog_catlist"},
        {"llog_info", jt_llog_info, 0,
         "print log header information.\n"
-        "usage: llog_info <logname|[FID]>\n"
-        "       oid, ogr and ogen are hexadecimal."},
+        "usage: llog_info <logname|FID>\n"},
        {"llog_print", jt_llog_print, 0,
         "print log content information.\n"
         "usage: llog_print <logname|FID> [--start <index>] [--end <index>j]\n"
         "       print all records by default, or within given index range."},
+       {"llog_cancel", jt_llog_cancel, 0,
+        "cancel one record in specified log.\n"
+        "usage:llog_cancel <logname|FID> --log_idx <idx>\n"},
        {"llog_check", jt_llog_check, 0,
-        "print log content information.\n"
-        "usage: llog_check <logname|[FID]> [start_index] [end_index]\n"
+        "verify that log content is valid.\n"
+        "usage: llog_check <logname|FID> [--start <index>] [--end <index>j]\n"
         "       check all records from index 1 by default."},
-       {"llog_cancel", jt_llog_cancel, 0,
-        "cancel one record in log.\n"
-        "This command supports both positional and optional arguments\n"
-        "usage (positional args): "
-        "llog_cancel <catalog name|[FID]> [log id] <index>\n"
-        "usage (optional args): "
-        "llog_cancel --catalog <catalog id|catalog name> --log_id <log_id> "
-        "--log_idx <index>"},
        {"llog_remove", jt_llog_remove, 0,
         "remove one log from catalog or plain log, erase it from disk.\n"
-        "usage: llog_remove <catalog name|[FID]> <log id>"},
+        "usage: llog_remove <logname|FID> [--log_id <id>]"},
+       {"==== obsolete (DANGEROUS) ====", NULL, 0, "obsolete (DANGEROUS)"},
+       /* some test scripts still use these */
+       /* saving for sanity 44a */
+       {"lov_getconfig", jt_obd_lov_getconfig, 0,
+        "read lov configuration from an mds device\n"
+        "usage: lov_getconfig <mountpoint>"},
        /* network operations */
        {"add_interface", jt_ptl_add_interface, 0, "add interface entry\n"
         "usage: add_interface ip [netmask]"},
index a9e91d8..5903dca 100644 (file)
@@ -2281,7 +2281,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);
@@ -2623,35 +2623,62 @@ 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_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);
-        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;
-        }
+       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_cb(const char *record, void *private)
@@ -2886,10 +2913,17 @@ int jt_llog_print(int argc, char **argv)
        return rc;
 }
 
-static int llog_cancel_parse_optional(int argc, char **argv,
-                                     struct obd_ioctl_data *data)
+/* 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)
 {
        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 },
@@ -2898,34 +2932,44 @@ static int llog_cancel_parse_optional(int argc, char **argv,
        int c;
 
        /* sanity check */
-       if (!data || argc <= 1)
+       if (!data || *argc <= 1)
                return -1;
 
+       data->ioc_dev = cur_device;
+
        /* now process command line arguments*/
-       while ((c = getopt_long(argc, argv, "c:hi:l:",
-                               long_opts, NULL)) != -1) {
+       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;
@@ -2933,60 +2977,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))
-                       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;
@@ -2994,87 +3022,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;
-       char from[2] = "1", to[3] = "-1";
-        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;
+
+       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;
 
-        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 {
-                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) - __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, "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)