Linux block layer
 help / color / mirror / Atom feed
From: Jens Axboe <axboe@kernel.dk>
To: linux-block@vger.kernel.org
Cc: Josef Bacik <josef@toxicpanda.com>,
	Keith Busch <kbusch@kernel.org>, Christoph Hellwig <hch@lst.de>,
	Sagi Grimberg <sagi@grimberg.me>, Jens Axboe <axboe@kernel.dk>
Subject: [PATCH 55/98] nvme-tcp: don't act on PDUs for a command being sent
Date: Wed, 28 Oct 2026 10:41:58 -0600	[thread overview]
Message-ID: <20261028164415.1262013-56-axboe@kernel.dk> (raw)
In-Reply-To: <20261028164415.1262013-1-axboe@kernel.dk>

From: Josef Bacik <josef@toxicpanda.com>

A request belongs to the send path from the moment it's put on req_list
until its last byte is handed to the socket, but the receive path acts
on whatever the controller sends for it. A response completes the
request while the send side is still reading from its bio:

  BUG: KASAN: slab-use-after-free in nvme_tcp_try_send_data+0x175/0x6b0
   nvme_tcp_try_send+0x4af/0x600
   nvme_tcp_io_work+0x249/0x380

and an R2T resets and requeues it, since the queued check only looks at
the two lists and a request being sent is on neither, so it ends up
completed twice. An honest controller doesn't do that, but its answer
can legitimately overtake a sender that has handed over the last byte
and not yet cleared queue->request.

Make such a PDU wait: don't consume the bytes that complete its header,
so it's seen again by the next receive. For that nvme_tcp_req_busy()
has to find the request in one of the three places at all times, so
nvme_tcp_fetch_request() sets queue->request before taking it off the
lists. io_work reruns when the sender was io_work or the socket was
full, waits for send_mutex when the submitter was sending, and a poller
just polls again.

Fixes: 3f2304f8c6d6 ("nvme-tcp: add NVMe over TCP host driver")
Cc: Keith Busch <kbusch@kernel.org>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Sagi Grimberg <sagi@grimberg.me>
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
---
 drivers/nvme/host/tcp.c | 87 ++++++++++++++++++++++++++++++++++-------
 1 file changed, 73 insertions(+), 14 deletions(-)

diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c
index 64f563686938..06c205703cf5 100644
--- a/drivers/nvme/host/tcp.c
+++ b/drivers/nvme/host/tcp.c
@@ -123,6 +123,7 @@ struct nvme_tcp_queue {
 	size_t			data_remaining;
 	size_t			ddgst_remaining;
 	unsigned int		nr_cqe;
+	bool			rcv_parked;
 
 	/* send state */
 	struct nvme_tcp_request *request;
@@ -465,11 +466,29 @@ nvme_tcp_fetch_request(struct nvme_tcp_queue *queue)
 			return NULL;
 	}
 
+	WRITE_ONCE(queue->request, req);
+	/* nvme_tcp_req_busy() must find the request in one place at any time */
+	smp_wmb();
 	list_del_init(&req->entry);
 	init_llist_node(&req->lentry);
 	return req;
 }
 
+/*
+ * Does the send path still hold @req? As long as it does the request must
+ * neither be completed nor be queued once more, whatever the controller says.
+ */
+static bool nvme_tcp_req_busy(struct nvme_tcp_queue *queue,
+			      struct nvme_tcp_request *req)
+{
+	if (llist_on_list(&req->lentry) || !list_empty(&req->entry))
+		return true;
+	/* pairs with the barrier in nvme_tcp_fetch_request() */
+	smp_rmb();
+	/* pairs with the release in nvme_tcp_done_send_req() */
+	return smp_load_acquire(&queue->request) == req;
+}
+
 #define NVME_TCP_CRC_SEED (~0)
 
 static inline void nvme_tcp_ddgst_update(u32 *crcp,
@@ -672,6 +691,9 @@ static int nvme_tcp_process_nvme_cqe(struct nvme_tcp_queue *queue,
 	}
 
 	req = blk_mq_rq_to_pdu(rq);
+	if (unlikely(nvme_tcp_req_busy(queue, req)))
+		return -EBUSY;
+
 	if (req->status == cpu_to_le16(NVME_SC_SUCCESS))
 		req->status = cqe->status;
 
@@ -707,6 +729,9 @@ static int nvme_tcp_handle_c2h_data(struct nvme_tcp_queue *queue,
 	}
 
 	req = blk_mq_rq_to_pdu(rq);
+	if (unlikely(nvme_tcp_req_busy(queue, req)))
+		return -EBUSY;
+
 	if (!blk_rq_payload_bytes(rq) || !req->curr_bio || !req->data_len) {
 		dev_err(queue->ctrl->ctrl.device,
 			"queue %d tag %#x unexpected data\n",
@@ -800,6 +825,8 @@ static int nvme_tcp_handle_r2t(struct nvme_tcp_queue *queue,
 		return -ENOENT;
 	}
 	req = blk_mq_rq_to_pdu(rq);
+	if (unlikely(nvme_tcp_req_busy(queue, req)))
+		return -EBUSY;
 
 	if (unlikely(rq_data_dir(rq) != WRITE)) {
 		dev_err(queue->ctrl->ctrl.device,
@@ -829,14 +856,6 @@ static int nvme_tcp_handle_r2t(struct nvme_tcp_queue *queue,
 		return -EPROTO;
 	}
 
-	if (llist_on_list(&req->lentry) ||
-	    !list_empty(&req->entry)) {
-		dev_err(queue->ctrl->ctrl.device,
-			"req %d unexpected r2t while processing request\n",
-			rq->tag);
-		return -EPROTO;
-	}
-
 	req->pdu_len = 0;
 	req->h2cdata_left = r2t_length;
 	req->h2cdata_offset = r2t_offset;
@@ -939,17 +958,32 @@ static int nvme_tcp_recv_pdu(struct nvme_tcp_queue *queue, struct sk_buff *skb,
 
 	switch (hdr->type) {
 	case nvme_tcp_c2h_data:
-		return nvme_tcp_handle_c2h_data(queue, (void *)queue->pdu);
+		ret = nvme_tcp_handle_c2h_data(queue, (void *)queue->pdu);
+		break;
 	case nvme_tcp_rsp:
-		nvme_tcp_init_recv_ctx(queue);
-		return nvme_tcp_handle_comp(queue, (void *)queue->pdu);
+		ret = nvme_tcp_handle_comp(queue, (void *)queue->pdu);
+		break;
 	case nvme_tcp_r2t:
-		nvme_tcp_init_recv_ctx(queue);
-		return nvme_tcp_handle_r2t(queue, (void *)queue->pdu);
+		ret = nvme_tcp_handle_r2t(queue, (void *)queue->pdu);
+		break;
 	default:
 		goto unsupported_pdu;
 	}
 
+	if (unlikely(ret == -EBUSY)) {
+		/*
+		 * The command is still being sent. Leave the end of the header
+		 * in the socket and look at it again when that is done.
+		 */
+		queue->pdu_remaining += rcv_len;
+		queue->pdu_offset -= rcv_len;
+		*offset -= rcv_len;
+		*len += rcv_len;
+	} else if (hdr->type != nvme_tcp_c2h_data) {
+		nvme_tcp_init_recv_ctx(queue);
+	}
+	return ret;
+
 unsupported_pdu:
 	dev_err(queue->ctrl->ctrl.device,
 		"unsupported pdu type (%d)\n", hdr->type);
@@ -1110,6 +1144,10 @@ static int nvme_tcp_recv_skb(read_descriptor_t *desc, struct sk_buff *skb,
 		default:
 			result = -EFAULT;
 		}
+		if (unlikely(result == -EBUSY)) {
+			queue->rcv_parked = true;
+			return consumed - len;
+		}
 		if (result) {
 			dev_err(queue->ctrl->ctrl.device,
 				"receive failed:  %d\n", result);
@@ -1182,7 +1220,8 @@ static void nvme_tcp_state_change(struct sock *sk)
 
 static inline void nvme_tcp_done_send_req(struct nvme_tcp_queue *queue)
 {
-	queue->request = NULL;
+	/* pairs with nvme_tcp_req_busy() */
+	smp_store_release(&queue->request, NULL);
 }
 
 static void nvme_tcp_fail_request(struct nvme_tcp_request *req)
@@ -1430,6 +1469,7 @@ static int nvme_tcp_read_sock(struct nvme_tcp_queue *queue)
 	rd_desc.count = 1;
 	lock_sock(sk);
 	queue->nr_cqe = 0;
+	queue->rcv_parked = false;
 	consumed = sock->ops->read_sock(sk, &rd_desc, nvme_tcp_recv_skb);
 	release_sock(sk);
 	return consumed;
@@ -1527,6 +1567,22 @@ static int nvme_tcp_try_recv(struct nvme_tcp_queue *queue)
 	return consumed == -EAGAIN ? 0 : consumed;
 }
 
+/*
+ * A PDU has been left in the socket because its command is still being sent.
+ * A sender in another context does not wake us when it is done: wait for it.
+ * If there is something left to send then, either the socket is full and tells
+ * us when it has room, or io_work has been queued.
+ */
+static bool nvme_tcp_recv_again(struct nvme_tcp_queue *queue)
+{
+	bool again;
+
+	mutex_lock(&queue->send_mutex);
+	again = !queue->request && !nvme_tcp_queue_has_pending(queue);
+	mutex_unlock(&queue->send_mutex);
+	return again;
+}
+
 static void nvme_tcp_io_work(struct work_struct *w)
 {
 	struct nvme_tcp_queue *queue =
@@ -1552,6 +1608,9 @@ static void nvme_tcp_io_work(struct work_struct *w)
 		else if (unlikely(result < 0))
 			return;
 
+		if (unlikely(queue->rcv_parked) && nvme_tcp_recv_again(queue))
+			pending = true;
+
 		/* did we get some space after spending time in recv? */
 		if (nvme_tcp_queue_has_pending(queue) &&
 		    sk_stream_is_writeable(queue->sock->sk))
-- 
2.56.0


  parent reply	other threads:[~2026-10-28 16:45 UTC|newest]

Thread overview: 148+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-28 16:41 [PATCHSET 0/98] Various block related fixes Jens Axboe
2026-10-28 16:41 ` [PATCH 01/98] blk-cgroup: keep the old blkg while reassociating a bio Jens Axboe
2026-10-28 19:52   ` Tejun Heo
2026-10-28 16:41 ` [PATCH 02/98] blk-iocost: free struct ioc after a grace period Jens Axboe
2026-10-28 20:00   ` Tejun Heo
2026-10-28 16:41 ` [PATCH 03/98] blk-throttle: don't truncate the cgroup v1 iops limits Jens Axboe
2026-10-28 20:00   ` Tejun Heo
2026-10-28 16:41 ` [PATCH 04/98] block: fix use-after-free of the disk in sync_bdevs() Jens Axboe
2026-10-28 16:41 ` [PATCH 05/98] block: don't lose the status of a failed flush request Jens Axboe
2026-10-28 16:41 ` [PATCH 06/98] blk-mq: don't batch allocate tags from an inactive hctx Jens Axboe
2026-10-28 16:41 ` [PATCH 07/98] block: keep zone write plugs with plugged BIOs alive Jens Axboe
2026-10-28 16:41 ` [PATCH 08/98] block: keep the zone write plug of a failed write Jens Axboe
2026-10-28 16:41 ` [PATCH 09/98] blk-mq: end the request if getting a keyslot fails Jens Axboe
2026-10-28 16:41 ` [PATCH 10/98] block: don't unplug a zone under a failed write Jens Axboe
2026-10-28 16:41 ` [PATCH 11/98] block: check dma alignment of bvec iters in async dio Jens Axboe
2026-10-28 16:41 ` [PATCH 12/98] drbd: stop the start_resync timer of a dying device Jens Axboe
2026-10-28 16:41 ` [PATCH 13/98] blk-cgroup: fix root io.stat byte counts on 32-bit Jens Axboe
2026-10-28 19:52   ` Tejun Heo
2026-10-28 16:41 ` [PATCH 14/98] drbd: take req_lock to skip the initial sync as peer Jens Axboe
2026-10-28 16:41 ` [PATCH 15/98] zloop: refuse zone files without read/write_iter Jens Axboe
2026-10-29  7:09   ` Johannes Thumshirn
2026-10-28 16:41 ` [PATCH 16/98] block/rnbd-srv: don't free the device on a sysfs error Jens Axboe
2026-10-28 16:41 ` [PATCH 17/98] block/rnbd-srv: drop the sess_dev kobject unlocked Jens Axboe
2026-10-28 16:41 ` [PATCH 18/98] aoe: don't free a device with its work queued Jens Axboe
2026-10-28 19:57   ` Bart Van Assche
2026-10-28 23:49   ` Bart Van Assche
2026-10-28 16:41 ` [PATCH 19/98] blk-cgroup: don't free a blkg with its punt " Jens Axboe
2026-10-28 19:52   ` Tejun Heo
2026-10-28 16:41 ` [PATCH 20/98] mtip32xx: don't mark the disk dead in the irq handler Jens Axboe
2026-10-28 19:57   ` Bart Van Assche
2026-10-28 23:49   ` Bart Van Assche
2026-10-28 16:41 ` [PATCH 21/98] mtip32xx: abort timed out commands of a removed device Jens Axboe
2026-10-28 16:41 ` [PATCH 22/98] mtip32xx: abort commands in flight on surprise removal Jens Axboe
2026-10-28 19:57   ` Bart Van Assche
2026-10-28 23:49   ` Bart Van Assche
2026-10-28 16:41 ` [PATCH 23/98] blk-iolatency: flush enable_work after going offline Jens Axboe
2026-10-28 19:52   ` Tejun Heo
2026-10-28 16:41 ` [PATCH 24/98] zram: accept lz4 dictionaries of more than 64 KiB Jens Axboe
2026-10-29  1:20   ` Sergey Senozhatsky
2026-10-29  1:54     ` Jens Axboe
2026-10-29  1:55       ` Sergey Senozhatsky
2026-10-29  2:03         ` Jens Axboe
2026-10-28 16:41 ` [PATCH 25/98] blk-throttle: pass the I/O counts of a dead group on Jens Axboe
2026-10-28 20:00   ` Tejun Heo
2026-10-28 16:41 ` [PATCH 26/98] blk-throttle: make blkio.reset_stats reset I/O counts Jens Axboe
2026-10-28 19:52   ` Tejun Heo
2026-10-28 16:41 ` [PATCH 27/98] blk-mq: don't trust the cookie in blk_mq_poll() Jens Axboe
2026-10-28 16:41 ` [PATCH 28/98] blk-iocost: check again that the disk is alive Jens Axboe
2026-10-28 19:57   ` Bart Van Assche
2026-10-28 23:49   ` Bart Van Assche
2026-10-28 16:41 ` [PATCH 29/98] blk-mq: keep sharing tags fairly after a queue update Jens Axboe
2026-10-28 16:41 ` [PATCH 30/98] blk-mq: don't bring back flags of a completed request Jens Axboe
2026-10-28 16:41 ` [PATCH 31/98] blk-mq: don't forget a timer the driver has restarted Jens Axboe
2026-10-28 16:41 ` [PATCH 32/98] blk-mq-dma: initialize the dma state for P2P, too Jens Axboe
2026-10-28 16:41 ` [PATCH 33/98] blk-mq-dma: map the metadata a passthrough request has Jens Axboe
2026-10-28 16:41 ` [PATCH 34/98] block: don't enter reclaim under rq_qos_mutex Jens Axboe
2026-10-28 20:00   ` Tejun Heo
2026-10-28 16:41 ` [PATCH 35/98] blktrace: remove the debugfs files before the channel Jens Axboe
2026-10-28 16:41 ` [PATCH 36/98] blk-mq: quiesce a queue that joins a quiesced tag set Jens Axboe
2026-10-28 16:41 ` [PATCH 37/98] blk-mq: exit the hctxs of a queue under tag_list_lock Jens Axboe
2026-10-28 16:41 ` [PATCH 38/98] blk-mq: set up " Jens Axboe
2026-10-28 16:41 ` [PATCH 39/98] rnbd-srv: fix use-after-free on two CLOSE messages Jens Axboe
2026-10-28 16:41 ` [PATCH 40/98] rnbd-srv: publish the sess_dev at the end of OPEN Jens Axboe
2026-10-28 16:41 ` [PATCH 41/98] zram: check a bio's range against the device size Jens Axboe
2026-10-28 19:57   ` Bart Van Assche
2026-10-28 23:49   ` Bart Van Assche
2026-10-28 16:41 ` [PATCH 42/98] block: partitions/mac: compute the sectors in 64 bits Jens Axboe
2026-10-28 16:41 ` [PATCH 43/98] blk-mq: free the bitmaps of tags in the SRCU callback Jens Axboe
2026-10-29  7:24   ` Hannes Reinecke
2026-10-28 16:41 ` [PATCH 44/98] block: apply the segment size to the integrity buffer Jens Axboe
2026-10-28 16:41 ` [PATCH 45/98] nvmet: don't truncate the length of big discards Jens Axboe
2026-10-29  7:25   ` Hannes Reinecke
2026-10-28 16:41 ` [PATCH 46/98] nvme-loop: delete the controller if a reset fails Jens Axboe
2026-10-28 16:41 ` [PATCH 47/98] nvme: refuse metadata sizes above 255 bytes Jens Axboe
2026-10-28 17:40   ` Keith Busch
2026-10-28 16:41 ` [PATCH 48/98] nvmet-tcp: rewind the iterator after non-data records Jens Axboe
2026-10-28 19:57   ` Bart Van Assche
2026-10-28 23:49   ` Bart Van Assche
2026-10-28 16:41 ` [PATCH 49/98] nvmet-tcp: ask for the TLS record type on every receive Jens Axboe
2026-10-29  7:38   ` Hannes Reinecke
2026-10-28 16:41 ` [PATCH 50/98] nvme-tcp: wait for an in-flight TLS handshake callback Jens Axboe
2026-10-29  7:40   ` Hannes Reinecke
2026-10-28 16:41 ` [PATCH 51/98] nvmet-tcp: look again after a short read with TLS Jens Axboe
2026-10-28 16:41 ` [PATCH 52/98] nvme-tcp: keep the socket while the queue is polled Jens Axboe
2026-10-28 16:41 ` [PATCH 53/98] nvme-tcp: don't get stuck on a TLS control record Jens Axboe
2026-10-29  7:44   ` Hannes Reinecke
2026-10-28 16:41 ` [PATCH 54/98] nvme-tcp: start error recovery after a TLS KeyUpdate Jens Axboe
2026-10-29  7:49   ` Hannes Reinecke
2026-10-28 16:41 ` Jens Axboe [this message]
2026-10-28 16:41 ` [PATCH 56/98] nvme-tcp: don't queue the AER while it is being sent Jens Axboe
2026-10-28 16:42 ` [PATCH 57/98] nvme-tcp: don't send SIGPIPE to whoever submits I/O Jens Axboe
2026-10-28 16:42 ` [PATCH 58/98] nvme-fabrics: reconnect if the association is gone Jens Axboe
2026-10-28 16:42 ` [PATCH 59/98] nvmet-auth: serialize the commands of a controller Jens Axboe
2026-10-28 16:42 ` [PATCH 60/98] nvmet-auth: keep the negotiated hash per queue Jens Axboe
2026-10-28 16:42 ` [PATCH 61/98] nvmet-auth: authenticate the I/O queues again Jens Axboe
2026-10-28 16:42 ` [PATCH 62/98] nvmet: don't mix queues with and without TLS Jens Axboe
2026-10-28 16:42 ` [PATCH 63/98] nvmet-auth: refuse a reply without a DH value Jens Axboe
2026-10-28 16:42 ` [PATCH 64/98] nvmet-auth: keep the old keys if the new ones fail Jens Axboe
2026-10-28 16:42 ` [PATCH 65/98] nvmet-auth: take only AUTH_Negotiate for a negotiation Jens Axboe
2026-10-28 16:42 ` [PATCH 66/98] nvmet-auth: free the old data on a new AUTH_Negotiate Jens Axboe
2026-10-28 16:42 ` [PATCH 67/98] nvmet-auth: fix the check of the offered DH groups Jens Axboe
2026-10-28 16:42 ` [PATCH 68/98] nvmet: accept I/O queues on the controller's port only Jens Axboe
2026-10-28 16:42 ` [PATCH 69/98] nvmet: confine fatal errors of unauthenticated queues Jens Axboe
2026-10-28 16:42 ` [PATCH 70/98] nvmet-tcp: don't wait for the host in the accept work Jens Axboe
2026-10-28 16:42 ` [PATCH 71/98] nvmet: check the host NQN against the TLS PSK identity Jens Axboe
2026-10-28 16:42 ` [PATCH 72/98] nvmet: fix NULL dereference of PCI endpoint targets Jens Axboe
2026-10-28 16:42 ` [PATCH 73/98] nvmet-tcp: stop listening when a port is removed Jens Axboe
2026-10-28 16:42 ` [PATCH 74/98] nvme-tcp: keep the page frag cache with the controller Jens Axboe
2026-10-28 16:42 ` [PATCH 75/98] nvmet-tcp: hold the queue while the TLS timer is armed Jens Axboe
2026-10-28 16:42 ` [PATCH 76/98] nvmet: fix NULL dereference in debugfs host_traddr Jens Axboe
2026-10-28 19:57   ` Bart Van Assche
2026-10-28 23:49   ` Bart Van Assche
2026-10-28 16:42 ` [PATCH 77/98] nvmet-tcp: let the accept work come to an end Jens Axboe
2026-10-28 16:42 ` [PATCH 78/98] nvmet-tcp: don't read a removed port at Connect time Jens Axboe
2026-10-28 16:42 ` [PATCH 79/98] nvme-tcp: start error recovery when a send fails Jens Axboe
2026-10-28 16:42 ` [PATCH 80/98] nvme-loop: don't BUG() if a scan runs beside a reset Jens Axboe
2026-10-28 16:42 ` [PATCH 81/98] nvmet: fix pc_ref use-after-free in preempt and abort Jens Axboe
2026-10-28 16:42 ` [PATCH 82/98] nvmet: move preempt and abort work off nvmet-wq Jens Axboe
2026-10-28 16:42 ` [PATCH 83/98] nvmet-rdma: treat a failed connect as a disconnect Jens Axboe
2026-10-28 16:42 ` [PATCH 84/98] nvmet-rdma: disconnect only established queues Jens Axboe
2026-10-28 16:42 ` [PATCH 85/98] nvmet-rdma: take a device off the list last Jens Axboe
2026-10-28 16:42 ` [PATCH 86/98] nvmet-rdma: queue the release work under the mutex Jens Axboe
2026-10-28 16:42 ` [PATCH 87/98] nvmet-rdma: disconnect a queue on device removal Jens Axboe
2026-10-28 16:42 ` [PATCH 88/98] nvmet-rdma: flush nvmet-wq on module exit Jens Axboe
2026-10-28 16:42 ` [PATCH 89/98] nvmet-rdma: reject queues larger than max_cqe Jens Axboe
2026-10-28 16:42 ` [PATCH 90/98] nvmet-rdma: disable interrupts under rsp_wr_wait_lock Jens Axboe
2026-10-28 19:57   ` Bart Van Assche
2026-10-28 23:49   ` Bart Van Assche
2026-10-28 16:42 ` [PATCH 91/98] nvmet-rdma: don't run the wait list recursively Jens Axboe
2026-10-28 16:42 ` [PATCH 92/98] nvmet-rdma: fix a lost run of the wait list Jens Axboe
2026-10-28 16:42 ` [PATCH 93/98] nvmet-fc: only send read data for successful commands Jens Axboe
2026-10-28 16:42 ` [PATCH 94/98] nvmet: wait only for executing I/O in preempt and abort Jens Axboe
2026-10-28 16:42 ` [PATCH 95/98] nvmet-rdma: fix double puts after a failed RDMA WRITE Jens Axboe
2026-10-28 16:42 ` [PATCH 96/98] nvmet: take sq->ref in nvmet_sq_fatal_error() Jens Axboe
2026-10-28 16:42 ` [PATCH 97/98] nvmet-rdma: hold sq->ref to post a T10-PI Read's SEND Jens Axboe
2026-10-28 19:57   ` Bart Van Assche
2026-10-28 23:49   ` Bart Van Assche
2026-10-28 16:42 ` [PATCH 98/98] nvmet: don't clear sq->ctrl for a Connect with sqsize 0 Jens Axboe
2026-10-28 17:11 ` [PATCHSET 0/98] Various block related fixes Keith Busch
2026-10-28 17:13   ` Jens Axboe
2026-10-28 19:12 ` Keith Busch
2026-10-28 19:22 ` Bart Van Assche
2026-10-28 19:29   ` Jens Axboe
2026-10-28 19:47     ` Bart Van Assche
2026-10-28 21:06       ` Jens Axboe
2026-10-28 23:51         ` Bart Van Assche
2026-10-28 19:52   ` Keith Busch
2026-10-28 21:41 ` (subset) " Jens Axboe

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=20261028164415.1262013-56-axboe@kernel.dk \
    --to=axboe@kernel.dk \
    --cc=hch@lst.de \
    --cc=josef@toxicpanda.com \
    --cc=kbusch@kernel.org \
    --cc=linux-block@vger.kernel.org \
    --cc=sagi@grimberg.me \
    /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