Linux block layer
 help / color / mirror / Atom feed
From: Mohamed Khalfella <mkhalfella@purestorage.com>
To: Shin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com>
Cc: linux-block@vger.kernel.org, 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>
Subject: Re: [PATCH blktests 0/5] nvme: detect ABA ghost writes on multipath fabrics
Date: Thu, 22 Oct 2026 11:59:20 -0700	[thread overview]
Message-ID: <20261022185920.GA2931-mkhalfella@purestorage.com> (raw)
In-Reply-To: <20261020180245.GP2931-mkhalfella@purestorage.com>

On Tue 2026-10-20 11:02:47 -0700, Mohamed Khalfella wrote:
> On Fri 2026-10-02 05:03:20 +0200, Shin'ichiro Kawasaki wrote:
> > On Sep 23, 2026 / 10:02, Mohamed Khalfella wrote:
> > > On Wed 2026-09-23 17:18:21 +0900, Shin'ichiro Kawasaki wrote:
> > > > On Sep 16, 2026 / 20:06, Mohamed Khalfella wrote:
> > > > 
> > > > Mohamad, thanks for the series. Before I look in the details of the patches,
> > > > I would like make a comment below.
> > > > 
> > > > > Reproducing the race needs an IO that can be held at the target for
> > > > > longer than the host's io_timeout without being failed. The first three
> > > > > patches give miniublk that ability, since there was previously no way to
> > > > > talk to a running ublk server at all:
> > > > > 
> > > > >   1/5  adds a loopback UDP control channel to the daemon, served by a
> > > > >        detached thread, one reply datagram per request
> > > > >   2/5  adds an INJECT_DELAY command which delays a given number of reads
> > > > >        or writes as an io_uring timeout on the queue's own ring
> > > > >   3/5  exposes it as "miniublk inject", which returns only once the
> > > > >        daemon has armed the delay, so a test can start IO immediately
> > > > >        without racing it
> > > > 
> > > > It is interesting to implement the delay feature to miniublk, and use it as the
> > > > testing tool. But I'm not sure if this is the best approach because of two
> > > > points. First, scsi_debug has jdelay and ndelay options. I wonder if this
> > > > existing feature can fulfill the requirements of the new test case. Second, when
> > > > rublk [*] is available in the PATH of the test system, blktests detect it and
> > > > use it instead of miniublk. I guess the added delay feature is not available in
> > > > rublk, and the test case won't work well. What do you think of these points?
> > > > 
> > > 
> > > The two points make sense to me. Let me look at scsi_debug delay
> > > injection mechanism first and see if it can be used here. I will also
> > > look at rublk. Thanks for the pointers.
> > 
> > I've learned that now delay injection is being added to the block layer [*].
> > This looks more generic and could be the best way for this use case.
> > 
> > [*] https://lore.kernel.org/linux-block/20260928221634.43239-1-haris.iqbal@linux.dev/
> 
> Thank you for pointing me to this patchset. The change as in v3 in the
> link above is not sufficient for this case. Block layer "error_inject"
> does not support an option to set the maximum number of times a rule
> should be executed. I want only the first write to be delayed for the
> test to be deterministic.
> 
> That is said, it should not be difficult to close this gap. I will give
> it a shot.

Adding a limit to error injection rule worked.

[ 1244.485435] run blktests nvme/070 at 2026-10-22 11:40:52.361981983
[ 1245.355103] nvmet_tcp: enabling port 0 (127.0.0.1:4420)
[ 1245.401761] nvmet_tcp: enabling port 1 (127.0.0.1:4421)
[ 1245.443655] nvmet: adding nsid 1 to subsystem blktests-subsystem-1
[ 1245.579679] nvmet: Created nvm controller 1 for subsystem blktests-subsystem-1 for NQN nqn.2014-08.org.nvmexpress:uui.
[ 1245.587802] nvme nvme4: creating 8 I/O queues.
[ 1245.599665] nvme nvme4: mapped 8/0/0 default/read/poll queues.
[ 1245.612520] nvme nvme4: new ctrl: NQN "blktests-subsystem-1", addr 127.0.0.1:4420, hostnqn: nqn.2014-08.org.nvmexpres9
[ 1245.993765] nvmet: Created nvm controller 2 for subsystem blktests-subsystem-1 for NQN nqn.2014-08.org.nvmexpress:uui.
[ 1246.001615] nvme nvme5: creating 8 I/O queues.
[ 1246.016800] nvme nvme5: mapped 8/0/0 default/read/poll queues.
[ 1246.031323] nvme nvme5: new ctrl: NQN "blktests-subsystem-1", addr 127.0.0.1:4421, hostnqn: nqn.2014-08.org.nvmexpres9
[ 1246.561862] ublkb0: delaying WRITE at sector 0:8 by 4000000us
[ 1249.908509] nvme nvme4: I/O tag 81 (0051) type 4 opcode 0x1 (Write) QID 7 timeout
[ 1249.910523] nvme nvme4: starting controller fencing
[ 1249.911588] nvme nvme4: attempting CCR, timeout 15000ms
[ 1249.913245] nvmet: ctrl 1 fatal error occurred!
[ 1250.631188] nvme nvme4: CCR succeeded using nvme5
[ 1250.647822] nvme nvme4: Reconnecting in 10 seconds...
[ 1260.710957] nvmet: Created nvm controller 1 for subsystem blktests-subsystem-1 for NQN nqn.2014-08.org.nvmexpress:uui.
[ 1260.718851] nvme nvme4: creating 8 I/O queues.
[ 1260.793810] nvme nvme4: mapped 8/0/0 default/read/poll queues.
[ 1260.805832] nvme nvme4: Successfully reconnected (attempt 1/60)
[ 1330.829938] nvme nvme5: Removing ctrl: NQN "blktests-subsystem-1"
[ 1331.316251] nvme nvme4: Removing ctrl: NQN "blktests-subsystem-1"

This full kernel logs for the test run with block layer delay injection.
A delay of 4 second injected -> io_timeout -> CCR.

diff --git a/tests/nvme/070 b/tests/nvme/070
index e9a4690..85604e7 100755
--- a/tests/nvme/070
+++ b/tests/nvme/070
@@ -51,7 +51,7 @@ set_io_timeout_of_subsystem() {
 test() {
        echo "Running ${TEST_NAME}"

-       local ns port nr_paths
+       local ns port nr_paths einj
        local -a ports

        if ! _init_ublk; then
@@ -84,9 +84,8 @@ test() {

        set_io_timeout_of_subsystem "${def_subsysnqn}" 2000

-       if ! ${UBLK_PROG} inject -n 0 -o write -d 4 -c 1 >> "$FULL" 2>&1; then
-               echo "FAIL: can not inject write delay"
-       fi
+       einj="/sys/kernel/debug/block/ublkb0/error_injection"
+       echo 'add,op=WRITE,status=OK,chance=1,delay_us=4000000,limit=1' > "${einj}"

        ns=$(_find_nvme_ns "${def_subsys_uuid}")
        "$SRCDIR/nvme-ghost-write-detector" "/dev/${ns}"

Changes to the test to use block layer error injection.

diff --git a/block/error-injection.c b/block/error-injection.c
index a35fe41a43e4..4d0150958cff 100644
--- a/block/error-injection.c
+++ b/block/error-injection.c
@@ -29,6 +29,9 @@ struct blk_error_inject {
 
 	/* hold the bio for this long before submitting or failing it */
 	unsigned int			delay_us;
+
+	/* maximum number of times to execute the rule, -1 no limit */
+	atomic_t			limit;
 };
 
 /*
@@ -143,6 +146,8 @@ bool __blk_error_inject(struct bio *bio)
 		if (inj->chance > 1 && (get_random_u32() % inj->chance) != 0)
 			continue;
 
+		if (atomic_dec_if_positive(&inj->limit) == -1)
+			continue;
 		status = inj->status;
 		delay_us = inj->delay_us;
 		break;
@@ -165,7 +170,7 @@ bool __blk_error_inject(struct bio *bio)
 
 static int error_inject_add(struct gendisk *disk, enum req_op op,
 		sector_t start, u64 nr_sectors, blk_status_t status,
-		unsigned int chance, unsigned int delay_us)
+		unsigned int chance, unsigned int delay_us, int limit)
 {
 	struct blk_error_inject *inj;
 	int error = -EINVAL;
@@ -194,6 +199,7 @@ static int error_inject_add(struct gendisk *disk, enum req_op op,
 	inj->status = status;
 	inj->chance = chance;
 	inj->delay_us = delay_us;
+	atomic_set(&inj->limit, limit);
 
 	pr_debug_ratelimited("%pg: adding %s injection for %s at sector %llu:%llu\n",
 			disk->part0, blk_status_to_str(status),
@@ -248,6 +254,7 @@ enum options {
 	Opt_status		= (1u << 19),
 	Opt_chance		= (1u << 20),
 	Opt_delay_us		= (1u << 21),
+	Opt_limit		= (1u << 22),
 
 	Opt_invalid,
 };
@@ -261,6 +268,7 @@ static const match_table_t opt_tokens = {
 	{ Opt_status,			"status=%s"		},
 	{ Opt_chance,			"chance=%u"		},
 	{ Opt_delay_us,			"delay_us=%u"		},
+	{ Opt_limit,			"limit=%d"		},
 	{ Opt_invalid,			NULL,			},
 };
 
@@ -302,6 +310,7 @@ static ssize_t blk_error_injection_parse_options(struct gendisk *disk,
 	u64 start = 0, nr_sectors = 0;
 	blk_status_t status = BLK_STS_OK;
 	substring_t args[MAX_OPT_ARGS];
+	int limit = -1;
 	char *p;
 
 	while ((p = strsep(&options, ",\n")) != NULL) {
@@ -343,6 +352,9 @@ static ssize_t blk_error_injection_parse_options(struct gendisk *disk,
 		case Opt_delay_us:
 			error = match_uint(args, &delay_us);
 			break;
+		case Opt_limit:
+			error = match_int(args, &limit);
+			break;
 		default:
 			pr_warn("unknown parameter or missing value '%s'\n", p);
 			error = -EINVAL;
@@ -354,7 +366,7 @@ static ssize_t blk_error_injection_parse_options(struct gendisk *disk,
 	switch (action) {
 	case Add:
 		return error_inject_add(disk, op, start, nr_sectors, status,
-				chance, delay_us);
+				chance, delay_us, limit);
 	case Removeall:
 		if (option_mask & ~Opt_removeall)
 			return -EINVAL;
@@ -390,11 +402,11 @@ static int blk_error_injection_show(struct seq_file *s, void *private)
 
 	rcu_read_lock();
 	list_for_each_entry_rcu(inj, &disk->error_injection_list, entry) {
-		seq_printf(s, "%llu:%llu op=%s,status=%s,chance=%u,delay_us=%u",
+		seq_printf(s, "%llu:%llu op=%s,status=%s,chance=%u,delay_us=%u,limit=%d",
 			   inj->start, inj->end,
 			   blk_op_str(inj->op),
 			   blk_status_to_tag(inj->status), inj->chance,
-			   inj->delay_us);
+			   inj->delay_us, atomic_read(&inj->limit));
 		seq_putc(s, '\n');
 	}
 	rcu_read_unlock();

And here is the change to block error injection to add a limit to error
injection rules. It missing documentation change but that should be
trivial to add.

Now, I need to follow with the patchset adding delay injection to see if
that can get merged.

      reply	other threads:[~2026-10-22 18:59 UTC|newest]

Thread overview: 15+ 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 ` [PATCH blktests 3/5] src/miniublk: add the inject command Mohamed Khalfella
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
2026-10-20 18:02       ` Mohamed Khalfella
2026-10-22 18:59         ` Mohamed Khalfella [this message]

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=20261022185920.GA2931-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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox