All of lore.kernel.org
 help / color / mirror / Atom feed
From: Mohamed Khalfella <mkhalfella@purestorage.com>
To: linux-block@vger.kernel.org
Cc: shinichiro.kawasaki@wdc.com, Keith Busch <kbusch@kernel.org>,
	Jens Axboe <axboe@kernel.dk>, Christoph Hellwig <hch@lst.de>,
	Sagi Grimberg <sagi@grimberg.me>, Hannes Reinecke <hare@suse.de>,
	John Meneghini <jmeneghi@redhat.com>,
	Jesse Taube <jtaubepe@redhat.com>,
	Randy Jennings <randyj@purestorage.com>,
	Dhaval Giani <dgiani@purestorage.com>,
	Mohamed Khalfella <mkhalfella@purestorage.com>
Subject: [PATCH blktests 3/5] src/miniublk: add the inject command
Date: Wed, 16 Sep 2026 20:06:23 -0600	[thread overview]
Message-ID: <20260917020752.1672578-4-mkhalfella@purestorage.com> (raw)
In-Reply-To: <20260917020752.1672578-1-mkhalfella@purestorage.com>

Add a CLI command which arms a delay on a running device:

    miniublk inject -n dev_id -o {read|write} -d delay -c count

It sends one INJECT_DELAY datagram to the device's control port and
waits for the reply, so it returns only once the daemon has armed the
request. A test can therefore arm a delay and start IO immediately
without racing the daemon.

Signed-off-by: Mohamed Khalfella <mkhalfella@purestorage.com>
---
 src/miniublk.c | 114 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 114 insertions(+)

diff --git a/src/miniublk.c b/src/miniublk.c
index 8dc2a56..2dbd4aa 100644
--- a/src/miniublk.c
+++ b/src/miniublk.c
@@ -48,6 +48,7 @@
 
 #define UBLK_CTRL_PORT_BASE	61000
 #define UBLK_CTRL_MSG_MAGIC	0x6b6c6275
+#define UBLK_CTRL_RCV_TIMEO	3
 
 enum {
 	UBLK_CTRL_CMD_PING		= 0,
@@ -1561,6 +1562,114 @@ static int cmd_dev_list(int argc, char *argv[])
 	return 0;
 }
 
+static int cmd_dev_inject(int argc, char *argv[])
+{
+	static const struct option longopts[] = {
+		{ "number",		1,	NULL, 'n' },
+		{ "op",			1,	NULL, 'o' },
+		{ "delay",		1,	NULL, 'd' },
+		{ "count",		1,	NULL, 'c' },
+		{ "control_port",	1,	NULL, 0},
+		{ NULL }
+	};
+	struct timeval tv = { .tv_sec = UBLK_CTRL_RCV_TIMEO, };
+	struct ublk_ctrl_msg req = {};
+	struct ublk_ctrl_msg rsp;
+	struct sockaddr_in addr;
+	int dev_id = -1, op = -1, delay = 0, count = 1;
+	int ctrl_port = -1;
+	int fd, ret, option_idx, opt;
+
+	while ((opt = getopt_long(argc, argv, "n:o:d:c:",
+				  longopts, &option_idx)) != -1) {
+		switch (opt) {
+		case 'n':
+			dev_id = strtol(optarg, NULL, 10);
+			break;
+		case 'o':
+			if (!strcmp(optarg, "read"))
+				op = UBLK_IO_OP_READ;
+			else if (!strcmp(optarg, "write"))
+				op = UBLK_IO_OP_WRITE;
+			break;
+		case 'd':
+			delay = strtol(optarg, NULL, 10);
+			break;
+		case 'c':
+			count = strtol(optarg, NULL, 10);
+			break;
+		case 0:
+			if (!strcmp(longopts[option_idx].name, "control_port"))
+				ctrl_port = strtol(optarg, NULL, 10);
+			break;
+		}
+	}
+
+	if (dev_id < 0 || op < 0 || delay <= 0 || count <= 0) {
+		ublk_err("%s: -n dev_id -o {read|write} -d delay -c count are required\n",
+				__func__);
+		return -EINVAL;
+	}
+
+	if (ctrl_port < 0)
+		ctrl_port = UBLK_CTRL_PORT_BASE + dev_id;
+
+	fd = socket(AF_INET, SOCK_DGRAM, 0);
+	if (fd < 0) {
+		ublk_err("%s: can't create socket: %s\n", __func__,
+				strerror(errno));
+		return -errno;
+	}
+	setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
+
+	memset(&addr, 0, sizeof(addr));
+	addr.sin_family = AF_INET;
+	addr.sin_port = htons(ctrl_port);
+	addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+
+	/* connect so that a missing daemon shows up as ECONNREFUSED */
+	if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+		ublk_err("%s: can't connect to port %d: %s\n", __func__,
+				ctrl_port, strerror(errno));
+		ret = -errno;
+		goto out;
+	}
+
+	req.magic = UBLK_CTRL_MSG_MAGIC;
+	req.cmd = UBLK_CTRL_CMD_INJECT_DELAY;
+	req.data[0] = op;
+	req.data[1] = delay;
+	req.data[2] = count;
+
+	if (send(fd, &req, sizeof(req), 0) != sizeof(req)) {
+		ublk_err("%s: can't send to port %d: %s\n", __func__,
+				ctrl_port, strerror(errno));
+		ret = -errno;
+		goto out;
+	}
+
+	if (recv(fd, &rsp, sizeof(rsp), 0) != sizeof(rsp)) {
+		ublk_err("%s: no reply from dev %d on port %d: %s\n", __func__,
+				dev_id, ctrl_port, strerror(errno));
+		ret = -errno;
+		goto out;
+	}
+
+	if (rsp.magic != UBLK_CTRL_MSG_MAGIC) {
+		ublk_err("%s: bad reply from port %d\n", __func__, ctrl_port);
+		ret = -EPROTO;
+		goto out;
+	}
+
+	ret = rsp.ret;
+	if (ret)
+		ublk_err("%s: dev %d rejected the request: %d\n", __func__,
+				dev_id, ret);
+out:
+	close(fd);
+	return ret;
+}
+
 static int cmd_dev_help(int argc, char *argv[])
 {
 	printf("%s add -t {null|loop} [-q nr_queues] [-d depth] [-n dev_id] [--control_port port] \n",
@@ -1577,6 +1686,9 @@ static int cmd_dev_help(int argc, char *argv[])
 	printf("%s recover -t {null|loop} [-n dev_id] [--control_port port] \n", argv[0]);
 	printf("\t -t loop -f backing_file \n");
 	printf("\t -t null\n");
+	printf("%s inject -n dev_id -o {read|write} -d delay -c count [--control_port port] \n",
+			argv[0]);
+	printf("\t delay the next <count> <read|write> ios by <delay> seconds\n");
 	return 0;
 }
 
@@ -1915,6 +2027,8 @@ int main(int argc, char *argv[])
 		ret = cmd_dev_help(argc, argv);
 	else if (!strcmp(cmd, "recover"))
 		ret = cmd_dev_recover(argc, argv);
+	else if (!strcmp(cmd, "inject"))
+		ret = cmd_dev_inject(argc, argv);
 out:
 	if (ret)
 		cmd_dev_help(argc, argv);
-- 
2.55.0


  parent reply	other threads:[~2026-09-17  2:09 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-17  2:06 [PATCH blktests 0/5] nvme: detect ABA ghost writes on multipath fabrics Mohamed Khalfella
2026-09-17  2:06 ` [PATCH blktests 1/5] src/miniublk: add a control channel to the daemon Mohamed Khalfella
2026-09-17  2:06 ` [PATCH blktests 2/5] src/miniublk: add IO delay injection Mohamed Khalfella
2026-09-17  2:06 ` Mohamed Khalfella [this message]
2026-09-17  2:06 ` [PATCH blktests 4/5] src/nvme-ghost-write-detector: add an ABA ghost write detector Mohamed Khalfella
2026-09-21 18:38   ` Jesse Taube
2026-09-23 17:00     ` Mohamed Khalfella
2026-09-17  2:06 ` [PATCH blktests 5/5] nvme/070: test for ABA ghost writes on a multipath fabrics namespace Mohamed Khalfella
2026-09-22 17:07   ` Jesse Taube
2026-09-23 16:56     ` Mohamed Khalfella
2026-09-23  8:18 ` [PATCH blktests 0/5] nvme: detect ABA ghost writes on multipath fabrics Shin'ichiro Kawasaki
2026-09-23 17:02   ` Mohamed Khalfella
2026-10-02  3:03     ` Shin'ichiro Kawasaki

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260917020752.1672578-4-mkhalfella@purestorage.com \
    --to=mkhalfella@purestorage.com \
    --cc=axboe@kernel.dk \
    --cc=dgiani@purestorage.com \
    --cc=hare@suse.de \
    --cc=hch@lst.de \
    --cc=jmeneghi@redhat.com \
    --cc=jtaubepe@redhat.com \
    --cc=kbusch@kernel.org \
    --cc=linux-block@vger.kernel.org \
    --cc=randyj@purestorage.com \
    --cc=sagi@grimberg.me \
    --cc=shinichiro.kawasaki@wdc.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.