]> www.infradead.org Git - nvme.git/commitdiff
selftests: ublk: support target specific command line
authorMing Lei <ming.lei@redhat.com>
Sat, 12 Apr 2025 02:30:26 +0000 (10:30 +0800)
committerJens Axboe <axboe@kernel.dk>
Thu, 17 Apr 2025 01:32:18 +0000 (19:32 -0600)
Support target specific command line for making related command line code
handling more readable & clean.

Also helps for adding new features.

Signed-off-by: Ming Lei <ming.lei@redhat.com>
Link: https://lore.kernel.org/r/20250412023035.2649275-11-ming.lei@redhat.com
Signed-off-by: Jens Axboe <axboe@kernel.dk>
tools/testing/selftests/ublk/kublk.c
tools/testing/selftests/ublk/kublk.h
tools/testing/selftests/ublk/stripe.c

index 5e805d358739f98bb6685e04d4fdf80174d68701..03b3d6427775f78e353817a4774a9f14bb0d1c2d 100644 (file)
@@ -5,6 +5,8 @@
 
 #include "kublk.h"
 
+#define MAX_NR_TGT_ARG         64
+
 unsigned int ublk_dbg_mask = UBLK_LOG;
 static const struct ublk_tgt_ops *tgt_ops_list[] = {
        &null_tgt_ops,
@@ -1202,12 +1204,25 @@ static int cmd_dev_get_features(void)
 
 static int cmd_dev_help(char *exe)
 {
-       printf("%s add -t [null|loop] [-q nr_queues] [-d depth] [-n dev_id] [backfile1] [backfile2] ...\n", exe);
-       printf("\t default: nr_queues=2(max 32), depth=128(max 1024), dev_id=-1(auto allocation)\n");
+       int i;
+
+       printf("%s add -t [null|loop|stripe] [-q nr_queues] [-d depth] [-n dev_id]\n", exe);
+       printf("\t[--foreground] [--quiet] [-z] [--debug_mask mask]\n");
+       printf("\t[target options] [backfile1] [backfile2] ...\n");
+       printf("\tdefault: nr_queues=2(max 32), depth=128(max 1024), dev_id=-1(auto allocation)\n");
+
+       for (i = 0; i < sizeof(tgt_ops_list) / sizeof(tgt_ops_list[0]); i++) {
+               const struct ublk_tgt_ops *ops = tgt_ops_list[i];
+
+               if (ops->usage)
+                       ops->usage(ops);
+       }
+       printf("\n");
+
        printf("%s del [-n dev_id] -a \n", exe);
-       printf("\t -a delete all devices -n delete specified device\n");
+       printf("\t -a delete all devices -n delete specified device\n\n");
        printf("%s list [-n dev_id] -a \n", exe);
-       printf("\t -a list all devices, -n list specified device, default -a \n");
+       printf("\t -a list all devices, -n list specified device, default -a \n\n");
        printf("%s features\n", exe);
        return 0;
 }
@@ -1224,9 +1239,9 @@ int main(int argc, char *argv[])
                { "quiet",              0,      NULL,  0  },
                { "zero_copy",          0,      NULL, 'z' },
                { "foreground",         0,      NULL,  0  },
-               { "chunk_size",         1,      NULL,  0  },
                { 0, 0, 0, 0 }
        };
+       const struct ublk_tgt_ops *ops = NULL;
        int option_idx, opt;
        const char *cmd = argv[1];
        struct dev_ctx ctx = {
@@ -1234,13 +1249,15 @@ int main(int argc, char *argv[])
                .nr_hw_queues   =       2,
                .dev_id         =       -1,
                .tgt_type       =       "unknown",
-               .chunk_size     =       65536,  /* def chunk size is 64K */
        };
        int ret = -EINVAL, i;
+       int tgt_argc = 1;
+       char *tgt_argv[MAX_NR_TGT_ARG] = { NULL };
 
        if (argc == 1)
                return ret;
 
+       opterr = 0;
        optind = 2;
        while ((opt = getopt_long(argc, argv, "t:n:d:q:az",
                                  longopts, &option_idx)) != -1) {
@@ -1271,8 +1288,26 @@ int main(int argc, char *argv[])
                                ublk_dbg_mask = 0;
                        if (!strcmp(longopts[option_idx].name, "foreground"))
                                ctx.fg = 1;
-                       if (!strcmp(longopts[option_idx].name, "chunk_size"))
-                               ctx.chunk_size = strtol(optarg, NULL, 10);
+                       break;
+               case '?':
+                       /*
+                        * target requires every option must have argument
+                        */
+                       if (argv[optind][0] == '-' || argv[optind - 1][0] != '-') {
+                               fprintf(stderr, "every target option requires argument: %s %s\n",
+                                               argv[optind - 1], argv[optind]);
+                               exit(EXIT_FAILURE);
+                       }
+
+                       if (tgt_argc < (MAX_NR_TGT_ARG - 1) / 2) {
+                               tgt_argv[tgt_argc++] = argv[optind - 1];
+                               tgt_argv[tgt_argc++] = argv[optind];
+                       } else {
+                               fprintf(stderr, "too many target options\n");
+                               exit(EXIT_FAILURE);
+                       }
+                       optind += 1;
+                       break;
                }
        }
 
@@ -1281,6 +1316,14 @@ int main(int argc, char *argv[])
                ctx.files[ctx.nr_files++] = argv[i++];
        }
 
+       ops = ublk_find_tgt(ctx.tgt_type);
+       if (ops && ops->parse_cmd_line) {
+               optind = 0;
+
+               tgt_argv[0] = ctx.tgt_type;
+               ops->parse_cmd_line(&ctx, tgt_argc, tgt_argv);
+       }
+
        if (!strcmp(cmd, "add"))
                ret = cmd_dev_add(&ctx);
        else if (!strcmp(cmd, "del"))
index 9b77137b87008b511817445b8f052337bf034d4e..7b7446359c8f11bdf3305b8d5e52f4671298c8b6 100644 (file)
 struct ublk_dev;
 struct ublk_queue;
 
+struct stripe_ctx {
+       /* stripe */
+       unsigned int    chunk_size;
+};
+
 struct dev_ctx {
        char tgt_type[16];
        unsigned long flags;
@@ -75,14 +80,15 @@ struct dev_ctx {
        unsigned int    all:1;
        unsigned int    fg:1;
 
-       /* stripe */
-       unsigned int    chunk_size;
-
        int _evtfd;
        int _shmid;
 
        /* built from shmem, only for ublk_dump_dev() */
        struct ublk_dev *shadow_dev;
+
+       union {
+               struct stripe_ctx  stripe;
+       };
 };
 
 struct ublk_ctrl_cmd_data {
@@ -119,6 +125,14 @@ struct ublk_tgt_ops {
        int (*queue_io)(struct ublk_queue *, int tag);
        void (*tgt_io_done)(struct ublk_queue *,
                        int tag, const struct io_uring_cqe *);
+
+       /*
+        * Target specific command line handling
+        *
+        * each option requires argument for target command line
+        */
+       void (*parse_cmd_line)(struct dev_ctx *ctx, int argc, char *argv[]);
+       void (*usage)(const struct ublk_tgt_ops *ops);
 };
 
 struct ublk_tgt {
index 179731c3dd6feca52afb54b40679c42e60460a79..5dbd6392d83de29faeac97b4f8e3e99afd791282 100644 (file)
@@ -281,7 +281,7 @@ static int ublk_stripe_tgt_init(const struct dev_ctx *ctx, struct ublk_dev *dev)
                        .max_sectors = dev->dev_info.max_io_buf_bytes >> 9,
                },
        };
-       unsigned chunk_size = ctx->chunk_size;
+       unsigned chunk_size = ctx->stripe.chunk_size;
        struct stripe_conf *conf;
        unsigned chunk_shift;
        loff_t bytes = 0;
@@ -344,10 +344,36 @@ static void ublk_stripe_tgt_deinit(struct ublk_dev *dev)
        backing_file_tgt_deinit(dev);
 }
 
+static void ublk_stripe_cmd_line(struct dev_ctx *ctx, int argc, char *argv[])
+{
+       static const struct option longopts[] = {
+               { "chunk_size",         1,      NULL,  0  },
+               { 0, 0, 0, 0 }
+       };
+       int option_idx, opt;
+
+       ctx->stripe.chunk_size = 65536;
+       while ((opt = getopt_long(argc, argv, "",
+                                 longopts, &option_idx)) != -1) {
+               switch (opt) {
+               case 0:
+                       if (!strcmp(longopts[option_idx].name, "chunk_size"))
+                               ctx->stripe.chunk_size = strtol(optarg, NULL, 10);
+               }
+       }
+}
+
+static void ublk_stripe_usage(const struct ublk_tgt_ops *ops)
+{
+       printf("\tstripe: [--chunk_size chunk_size (default 65536)]\n");
+}
+
 const struct ublk_tgt_ops stripe_tgt_ops = {
        .name = "stripe",
        .init_tgt = ublk_stripe_tgt_init,
        .deinit_tgt = ublk_stripe_tgt_deinit,
        .queue_io = ublk_stripe_queue_io,
        .tgt_io_done = ublk_stripe_io_done,
+       .parse_cmd_line = ublk_stripe_cmd_line,
+       .usage = ublk_stripe_usage,
 };