Commit 810b88f3 authored by Ming Lei's avatar Ming Lei Committed by Jens Axboe
Browse files

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: default avatarMing Lei <ming.lei@redhat.com>
Link: https://lore.kernel.org/r/20250412023035.2649275-11-ming.lei@redhat.com


Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
parent 6c62fd04
Loading
Loading
Loading
Loading
+51 −8
Original line number Diff line number Diff line
@@ -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);
	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"))
+17 −3
Original line number Diff line number Diff line
@@ -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 {
+27 −1
Original line number Diff line number Diff line
@@ -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,
};