mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/
synced 2025-04-19 20:58:31 +09:00
selftests: ublk: support target specific command line
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>
This commit is contained in:
parent
6c62fd04e8
commit
810b88f3dc
@ -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"))
|
||||
|
@ -63,6 +63,11 @@
|
||||
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 {
|
||||
|
@ -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,
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user